// SPDX-License-Identifier: LGPL-2.1-only // Copyright (C) 2026 Liberux Labs, S. L. //! Platform backends: what ties the runtime to a windowing system. //! //! The runtime (`event_loop/`, `input/`, `draw/`) holds the app, the widget tree, focus, gestures, text editing and every `App` callback, and is the same on every platform. A backend feeds it input through the entry points of [`crate::input::event`], keeps its own half of every surface in `SurfaceState::platform`, and carries out the requests of [`Platform`]. //! //! A backend also owns the run loop: it connects to the system, builds `AppData` with `AppData::new`, installs the shared event sources with `AppData::install_sources`, and on every wake-up calls `AppData::before_draw`, `AppData::draw_due` and `AppData::after_draw` around its own work. //! //! The backends are `wayland`, `android` and `web`, each behind the feature of its name; `build.rs` refuses more than one. Each backend sets the two aliases below and `run` / `try_run` under its own `cfg`, and `build.rs` sets `cfg( backend )`, which builds the runtime, when one is enabled. #[ cfg( feature = "android" ) ] pub( crate ) mod android; #[ cfg( feature = "wayland" ) ] pub( crate ) mod wayland; #[ cfg( feature = "web" ) ] pub( crate ) mod web; #[ cfg( test ) ] pub( crate ) mod mock; #[ cfg( feature = "android" ) ] pub( crate ) use android::run::{ run, try_run }; #[ cfg( feature = "wayland" ) ] pub( crate ) use wayland::run::{ run, try_run }; #[ cfg( feature = "web" ) ] pub( crate ) use web::run::{ run, try_run }; use crate::event_loop::SurfaceFocus; use crate::event_loop::cursor_shape::ResizeEdge; use crate::osk::Purpose; use crate::render::Canvas; use crate::types::{ Color, CursorShape, Rect }; /// The backend the runtime runs on, held by `AppData::platform`. #[ cfg( feature = "wayland" ) ] pub( crate ) type NativePlatform = wayland::WaylandPlatform; #[ cfg( feature = "android" ) ] pub( crate ) type NativePlatform = android::AndroidPlatform; #[ cfg( feature = "web" ) ] pub( crate ) type NativePlatform = web::WebPlatform; /// The backend's half of every surface, held by `SurfaceState::platform`. #[ cfg( feature = "wayland" ) ] pub( crate ) type NativeSurface = wayland::WaylandSurfaceState; #[ cfg( feature = "android" ) ] pub( crate ) type NativeSurface = android::AndroidSurfaceState; #[ cfg( feature = "web" ) ] pub( crate ) type NativeSurface = web::WebSurfaceState; /// The user's language as `LANG` gives it (`es_ES.UTF-8`), or in a browser as the page does (`es-ES`). #[ cfg( not( feature = "web" ) ) ] pub( crate ) fn language() -> String { std::env::var( "LANG" ).unwrap_or_default() } #[ cfg( feature = "web" ) ] pub( crate ) fn language() -> String { web_sys::window().and_then( |w| w.navigator().language() ).unwrap_or_default() } /// What [`Platform::present`] needs to know about a painted frame. Rects are in physical pixels, top-left origin. pub( crate ) struct Presentation<'a> { /// What changed since the last frame; empty for the whole surface. pub damage: &'a [Rect], /// The surface is opaque where `bg` is, and elsewhere over `opaque_region`. pub bg: Color, pub opaque_region: Option<&'a [Rect]>, /// Where the surface takes input; `None` everywhere, empty nowhere. pub input_region: Option<&'a [Rect]>, /// Logical size and the physical pixels per logical one. pub width: u32, pub height: u32, pub scale: f32, /// Report the next frame to the runtime as one of this surface; `None` for a surface that is not paced by frames. pub frame: Option, } /// What the runtime asks of the windowing system. `AppData::platform` implements it. /// /// Drawing a surface takes three calls: [`Self::prepare_canvas`], then the runtime paints the widget tree on the canvas, then [`Self::present`]. The canvas is the surface's own and keeps its pixels between frames, so a partial repaint only touches the damaged rects, and presenting adds no copy beyond the one into the system's buffer that a software canvas always needs. pub( crate ) trait Platform: 'static { /// The backend's half of a surface, held by `SurfaceState::platform`. type Surface; /// A display that one of `AppData::secondaries` covers. type Output; /// Whether a full repaint of `surface` should report the rects that changed rather than the whole surface. fn precise_damage( &self, surface: &Self::Surface ) -> bool; /// Make `canvas` ready to paint `surface` at `pw × ph` physical pixels, creating it on the first frame; `false` when the surface cannot be drawn now. fn prepare_canvas( &self, surface: &mut Self::Surface, canvas: &mut Option, pw: u32, ph: u32, scale: f32 ) -> bool; /// Show what was painted on `canvas` since [`Self::prepare_canvas`]; `false` when nothing reached the screen. fn present( &self, surface: &mut Self::Surface, canvas: &mut Canvas, frame: &Presentation<'_> ) -> bool; /// Offer `text`, which the runtime also keeps in `AppData::clipboard`, to other applications as the clipboard. fn publish_clipboard( &mut self, text: &str ); /// Offer `text`, which the runtime also keeps in `AppData::primary_selection`, to other applications as the selection the middle button pastes; no-op where there is none. fn publish_primary_selection( &mut self, text: &str ); /// Whether `main` is an application window the user can move, resize and minimise, rather than a shell or lock surface. fn is_toplevel( &self, main: &Self::Surface ) -> bool; /// Whether back with nothing left to go back to may minimise or close `main`, as [`crate::app::BackAtRoot`] says: an application's window or activity, not a shell or lock surface. fn back_leaves( &self, main: &Self::Surface ) -> bool; /// Let the system move the window with the pointer whose left button was just pressed. fn begin_window_move( &self, main: &Self::Surface ); /// Let the system resize the window from `edge` with the pointer whose left button was just pressed. fn begin_window_resize( &self, main: &Self::Surface, edge: ResizeEdge ); fn minimize_window( &self, main: &Self::Surface ); /// `false` when `main` is not a window, so the runtime asks again later. fn set_fullscreen( &self, main: &Self::Surface, fullscreen: bool ) -> bool; /// Ask for a frame of `surface`, reported as one of `focus`, without presenting a new buffer; `false` while the surface does not exist yet. fn request_frame( &self, surface: &Self::Surface, focus: SurfaceFocus ) -> bool; /// `false` when the system lets the app set no cursor shape. fn set_cursor_shape( &mut self, shape: CursorShape ) -> bool; /// Whether the input method is serving a text field or the app. fn text_input_active( &self ) -> bool; /// Ask the input method for text, or renew the request so a keyboard the system folded comes back. fn activate_text_input( &mut self, secure: bool, purpose: Purpose ); fn deactivate_text_input( &mut self ); /// Send an active request again with a new purpose; no-op when none is active. fn reenable_text_input( &self, secure: bool, purpose: Purpose ); }