ltk/platform/wayland/
state.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>

use smithay_client_toolkit::
{
	activation::ActivationState,
	compositor::CompositorState,
	data_device_manager::{ DataDeviceManagerState, data_device::DataDevice, data_source::CopyPasteSource },
	foreign_toplevel_list::ForeignToplevelList,
	output::OutputState,
	registry::RegistryState,
	seat::{ SeatState, pointer::cursor_shape::CursorShapeManager },
	shell::{ wlr_layer::LayerShell, xdg::XdgShell },
	shm::Shm,
	session_lock::SessionLock,
	subcompositor::SubcompositorState,
};
use smithay_client_toolkit::reexports::client::
{
	protocol::{ wl_keyboard::WlKeyboard, wl_output::WlOutput, wl_pointer::WlPointer, wl_touch::WlTouch },
	QueueHandle,
};
use smithay_client_toolkit::reexports::protocols::wp::cursor_shape::v1::client::wp_cursor_shape_device_v1::WpCursorShapeDeviceV1;
use wayland_protocols::wp::text_input::zv3::client::
{
	zwp_text_input_manager_v3::ZwpTextInputManagerV3,
	zwp_text_input_v3::ZwpTextInputV3,
};

use std::collections::HashMap;
use std::sync::Arc;

use crate::app::App;
use crate::egl_context::EglContext;
use crate::app::SubsurfaceId;
use crate::event_loop::AppData;
use crate::render::Canvas;

use super::data_device::DropPayload;
use super::primary_selection::PrimarySelection;
use super::session::SessionRuntime;
use super::subsurface::SubsurfaceSlot;

/// The Wayland protocol state the runtime's requests go through: globals, seat devices, the serials later requests quote and the queue new objects are created on.
pub( crate ) struct WaylandPlatform<A: App>
{
	pub registry_state:     RegistryState,
	pub seat_state:         SeatState,
	pub output_state:       OutputState,
	pub compositor_state:   CompositorState,
	/// `None` when the compositor does not advertise `wl_subcompositor`.
	pub subcompositor:      Option<SubcompositorState>,
	pub shm:                Shm,
	/// Process-wide EGL context. `None` when EGL failed to initialise or `LTK_FORCE_SOFTWARE=1`; every surface then draws through the SHM pool.
	pub egl_context:        Option<Arc<EglContext>>,
	pub session_lock:       Option<SessionLock>,
	#[ allow( dead_code ) ]
	pub xdg_shell:          Option<XdgShell>,
	/// Shared by the main surface and every overlay; `None` when the compositor does not advertise the protocol.
	pub layer_shell:        Option<LayerShell>,
	pub keyboard:           Option<WlKeyboard>,
	pub pointer:            Option<WlPointer>,
	pub touch:              Option<WlTouch>,
	/// `None` when the compositor does not advertise `wp_cursor_shape_v1`; the compositor's default cursor then stays.
	pub cursor_shape_manager: Option<CursorShapeManager>,
	/// Present once the compositor supports cursor shapes and the seat has a pointer.
	pub cursor_shape_device:  Option<WpCursorShapeDeviceV1>,
	/// Last `wl_pointer.enter` serial, which every `set_shape` must quote.
	pub last_pointer_enter_serial: u32,
	/// Last left or middle press, which an interactive move or resize quotes.
	pub last_pointer_serial: u32,
	/// Last serial of any input event, which `xdg_popup.grab` and setting a selection quote.
	pub last_input_serial:   u32,
	pub text_input_manager: Option<ZwpTextInputManagerV3>,
	pub text_input:         Option<ZwpTextInputV3>,
	/// `xdg-activation-v1`, used on the first configure to honour `XDG_ACTIVATION_TOKEN` and for [`App::request_activation_token`].
	pub activation_state:   Option<ActivationState>,
	/// Honoured once, after the first configure of the main surface.
	pub activation_token_pending: Option<String>,
	/// `xdg-session-management-v1` proxies and the on-disk store; the store is `None` when persistence is off (layer or lock surfaces, unusable app id, concurrent instance, or after `replaced`).
	pub session:            SessionRuntime,
	/// `None` when the compositor does not advertise `wl_data_device_manager`; copy and paste then stay within the process.
	pub data_device_manager: Option<DataDeviceManagerState>,
	/// Created with the first seat that has a keyboard or a pointer.
	pub data_device:        Option<DataDevice>,
	/// The selection we publish, held so each paste from another client can be served the clipboard text.
	pub clipboard_source:   Option<CopyPasteSource>,
	pub primary:            PrimarySelection,
	/// Selections other clients set, read by a worker thread and drained into `AppData::clipboard` once per iteration.
	pub clipboard_inbox_tx: std::sync::mpsc::Sender<String>,
	pub clipboard_inbox_rx: std::sync::mpsc::Receiver<String>,
	/// A drag from another client: where it is over our surface, in logical coordinates, and the type negotiated on `enter`. Cleared on `leave` and after the drop.
	pub drop_position:      Option<( f64, f64 )>,
	pub drop_mime:          Option<String>,
	/// What other clients drop on our surfaces, read by a worker thread.
	pub drop_inbox_tx:      std::sync::mpsc::Sender<DropPayload>,
	pub drop_inbox_rx:      std::sync::mpsc::Receiver<DropPayload>,
	/// First-configure latch for `App::start_fullscreen`: Mutter ignores a fullscreen request sent before the window is mapped.
	pub pending_fullscreen: bool,
	/// First-configure latch: clears `max_size` once the compositor has honoured the pinned initial size.
	pub pending_size_hint_unpin: bool,
	/// First-configure latch: check the size hint against the screen.
	pub pending_size_hint_fit:   bool,
	/// The size hint once shrunk to fit the screen; replaces the app's.
	pub fitted_size_hint:   Option<( u32, u32 )>,
	/// GLES canvases of destroyed overlays, reused by the next overlay.
	pub canvas_pool:        Vec<Canvas>,
	/// `ext-foreign-toplevel-list-v1`; yields no toplevels when the compositor does not advertise it.
	pub foreign_toplevel_list: ForeignToplevelList,
	/// Output the main surface was created on, so a later `new_output` for the same output does not add a duplicate secondary surface.
	pub main_output:        Option<WlOutput>,
	/// Input-transparent child surfaces keyed by their stable [`SubsurfaceId`], reconciled each frame from [`App::subsurfaces`].
	pub subsurfaces:        HashMap<SubsurfaceId, SubsurfaceSlot>,
	/// One GLES canvas for every subsurface raster, so a subsurface dropped and re-created (a lazily emitted sliding panel) does not recompile the shader programs, hundreds of ms on a mobile GPU, each time it reappears.
	pub subsurface_gles_canvas: Option<Canvas>,
	pub qh:                 QueueHandle<AppData<A>>,
}