ltk/platform/wayland/
mod.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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>

//! The Wayland backend.
//!
//! | File | What it does for the runtime |
//! | --- | --- |
//! | `state.rs` | [`WaylandPlatform`], the protocol state and the EGL context `AppData::platform` holds |
//! | `surface.rs` | [`WaylandSurfaceState`], each surface's role object, SHM pool or EGL window surface, held by `SurfaceState::platform`; configuring it |
//! | `handlers.rs` | The compositor, shell, output, seat, session-lock, foreign-toplevel, frame-callback and text-input handlers |
//! | `data_device.rs`, `primary_selection.rs` | The clipboard and the primary selection shared with other clients, and drops from them |
//! | `present.rs` | Putting a painted canvas on screen through an SHM buffer or `eglSwapBuffers`, with its damage, opaque and input regions and frame callback |
//! | `input.rs` | `wl_keyboard`, `wl_pointer` and `wl_touch` turned into [`crate::input::event`] |
//! | `window.rs` | Interactive move and resize, minimise, fullscreen and a bare frame request on the main xdg-toplevel |
//! | `cursor.rs` | The cursor's shape through `wp_cursor_shape_v1` |
//! | `text_input.rs` | The input method through `zwp_text_input_v3` |
//! | `run.rs` | `ltk::run`: connecting, binding the globals, creating the main surface and the loop that dispatches Wayland events around the runtime's steps |
//! | `overlays_reconcile.rs` | Creating and destroying the layer surfaces, popups and windows of [`App::overlays`] as the list changes |
//! | `subsurface.rs` | The input-transparent `wl_subsurface`s of [`App::subsurfaces`], each drawn and presented on its own |
//! | `session.rs` | `xdg-session-management-v1`, the periodic save of [`App::save_state`] and the signal source that ends the loop on `SIGTERM` |
//! | `output_probe.rs`, `window_fit.rs` | The size of the first output before the first commit, and a size hint shrunk to fit it |

mod cursor;
pub( crate ) mod data_device;
mod handlers;
mod input;
mod output_probe;
mod overlays_reconcile;
pub( crate ) mod present;
pub( crate ) mod primary_selection;
pub( crate ) mod run;
mod session;
mod state;
mod subsurface;
mod surface;
mod text_input;
mod window;
mod window_fit;

pub( crate ) use state::WaylandPlatform;
pub( crate ) use surface::{ LayerConfig, SurfaceKind, WaylandSurfaceState };

use smithay_client_toolkit::reexports::client::protocol::wl_output::WlOutput;

use crate::app::App;
use crate::event_loop::SurfaceFocus;
use crate::event_loop::cursor_shape::ResizeEdge;
use crate::osk::Purpose;
use crate::render::Canvas;
use crate::types::CursorShape;

use super::{ Platform, Presentation };

impl<A: App> Platform for WaylandPlatform<A>
{
	type Surface = WaylandSurfaceState;
	type Output  = WlOutput;

	fn is_toplevel( &self, main: &WaylandSurfaceState ) -> bool
	{
		window::window( main ).is_some()
	}

	fn back_leaves( &self, main: &WaylandSurfaceState ) -> bool
	{
		self.is_toplevel( main )
	}

	fn begin_window_move( &self, main: &WaylandSurfaceState )
	{
		window::begin_move( self, main );
	}

	fn begin_window_resize( &self, main: &WaylandSurfaceState, edge: ResizeEdge )
	{
		window::begin_resize( self, main, edge );
	}

	fn minimize_window( &self, main: &WaylandSurfaceState )
	{
		if let Some( window ) = window::window( main ) { window.set_minimized(); }
	}

	fn set_fullscreen( &self, main: &WaylandSurfaceState, fullscreen: bool ) -> bool
	{
		window::set_fullscreen( main, fullscreen )
	}

	fn request_frame( &self, surface: &WaylandSurfaceState, focus: SurfaceFocus ) -> bool
	{
		window::request_frame( self, surface, focus )
	}

	fn precise_damage( &self, surface: &WaylandSurfaceState ) -> bool
	{
		self.egl_context.is_none() || surface.egl_surface.is_none()
	}

	fn prepare_canvas( &self, surface: &mut WaylandSurfaceState, canvas: &mut Option<Canvas>, pw: u32, ph: u32, scale: f32 ) -> bool
	{
		present::prepare_canvas( self, surface, canvas, pw, ph, scale )
	}

	fn present( &self, surface: &mut WaylandSurfaceState, canvas: &mut Canvas, frame: &Presentation<'_> ) -> bool
	{
		present::present( self, surface, canvas, frame )
	}

	fn publish_clipboard( &mut self, _text: &str )
	{
		data_device::publish_clipboard( self );
	}

	fn publish_primary_selection( &mut self, _text: &str )
	{
		primary_selection::publish( self );
	}

	fn primary_selection_pending( &self ) -> bool
	{
		self.primary.pending()
	}

	fn set_cursor_shape( &mut self, shape: CursorShape ) -> bool
	{
		cursor::set_shape( self, shape )
	}

	fn text_input_active( &self ) -> bool
	{
		self.text_input.is_some()
	}

	fn activate_text_input( &mut self, secure: bool, purpose: Purpose )
	{
		text_input::activate( self, secure, purpose );
	}

	fn deactivate_text_input( &mut self )
	{
		text_input::deactivate( self );
	}

	fn reenable_text_input( &self, secure: bool, purpose: Purpose )
	{
		text_input::reenable( self, secure, purpose );
	}
}