srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/wayland/src/winit/mod.rs
blob: 5a08a9ac2e51f74d91a8232fc8b845189c4f5892 (plain) (blame)
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
//! Nested ("winit") backend: srdwm as a window on an existing
//! compositor/X server, the Wayland analogue of running the X11 backend
//! under Xephyr. Used for development and for the case where srdwm is
//! started from inside another session; the real bare-TTY path is
//! [`crate::udev`].
//!
//! Both backends share all protocol state ([`crate::state::CompState`]),
//! input routing ([`crate::input`]) and lock behaviour ([`crate::lock`]);
//! what differs is only how a frame reaches a screen.

use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::rc::Rc;
use std::time::{Duration, Instant};

use smithay::backend::allocator::Fourcc;
use smithay::backend::input::{
    AbsolutePositionEvent, Axis, AxisSource, ButtonState as BackendButtonState, Event as InputEventTrait, InputEvent, PointerAxisEvent, PointerButtonEvent,
};
use smithay::backend::renderer::damage::OutputDamageTracker;
use smithay::backend::renderer::element::memory::MemoryRenderBufferRenderElement;
use smithay::backend::renderer::element::Kind;
use smithay::backend::renderer::gles::GlesRenderer;
use smithay::backend::renderer::ImportDma;
use smithay::backend::winit::{self, WinitEvent, WinitEventLoop, WinitGraphicsBackend};
use smithay::reexports::winit::dpi::LogicalSize as WinitLogicalSize;
use smithay::reexports::winit::window::Window as WinitWindow;
use smithay::desktop::{layer_map_for_output, PopupManager, Space};
use smithay::wayland::shell::wlr_layer::Layer;
use smithay::input::SeatState;
use smithay::output::{Mode as OutputMode, Output, PhysicalProperties, Subpixel};
use smithay::reexports::calloop::EventLoop as CalloopEventLoop;
use smithay::reexports::wayland_server::{Client, Display, ListeningSocket};
use smithay::reexports::winit::platform::pump_events::PumpStatus;
use smithay::utils::{Physical, Point, Rectangle, Scale, Size, Transform};
use smithay::wayland::compositor::CompositorState;
use smithay::wayland::dmabuf::DmabufState;
use smithay::wayland::selection::data_device::DataDeviceState;
use smithay::wayland::selection::primary_selection::PrimarySelectionState;
use smithay::wayland::selection::wlr_data_control::DataControlState;
use smithay::wayland::session_lock::SessionLockManagerState;
use smithay::wayland::shell::wlr_layer::WlrLayerShellState;
use smithay::wayland::shell::xdg::decoration::XdgDecorationState;
use smithay::wayland::shell::xdg::XdgShellState;
use smithay::wayland::shm::ShmState;
use smithay::wayland::xdg_activation::XdgActivationState;

use srdwm_core::{Event as CoreEvent, Window as CoreWindow, WindowId, WindowManager};
use srdwm_platform::{Platform, PlatformError, PlatformKind, Result as PlatformResult};

use crate::input::{handle_keyboard_key_event, handle_pointer_button, handle_pointer_position, last_pointer_pos};
use crate::lock::{lock_render_elements, send_lock_frame};
use crate::lock::SessionLock;
use srdwm_platform::IpcServer;
use crate::state::{ClientState, CompState, OutputEntry};
use crate::{decoration, err, screencopy};

pub struct WaylandPlatform {
    display: Display<CompState>,
    state: CompState,
    backend: WinitGraphicsBackend<GlesRenderer>,
    winit_events: WinitEventLoop,
    damage_tracker: OutputDamageTracker,
    output: Output,
    listener: ListeningSocket,
    clients: Vec<Client>,
    pending: Rc<RefCell<Vec<CoreEvent>>>,
    wm: Rc<RefCell<WindowManager>>,
    ipc: Option<IpcServer>,
    /// Exists solely to host `IdleNotifierState`'s internal per-notification
    /// timers - this backend otherwise has no `calloop` loop of its own at
    /// all (see `ipc.rs`'s module doc comment), drawing everything instead
    /// from `winit_events`'s manual poll and this struct's own per-tick
    /// work. `ext_idle_notify_v1` needs a real `LoopHandle` to construct
    /// (`smithay::wayland::idle_notify::IdleNotifierState::new`), and the
    /// alternative - constructing the global without ever dispatching the
    /// loop backing it - would advertise a protocol whose `idled`/`resumed`
    /// events then simply never fire, a worse trap than the small addition
    /// of a second, narrowly-scoped loop dispatched non-blocking once per
    /// tick in `poll_events`.
    idle_event_loop: CalloopEventLoop<'static, CompState>,
    /// When the last frame was rendered - see `poll_events`' doc comment
    /// on why this backend has to pace itself.
    last_frame: Instant,
}

/// Target frame budget for the winit (nested) backend's self-imposed pacing
/// - see `poll_events`' doc comment. 60fps to match `OutputMode`'s own
/// `refresh: 60_000` a few lines below, not because either number is
/// special.
const TARGET_FRAME_TIME: Duration = Duration::from_micros(1_000_000 / 60);


mod capture;
mod connect;
mod events;
mod nested_platform;
mod render;
mod run;