srdusr
aboutsummaryrefslogtreecommitdiffstats
path: root/crates/platform
diff options
context:
space:
mode:
authorsrdusr <[email protected]>2024-04-02 00:58:00 +0200
committersrdusr <[email protected]>2024-04-02 00:58:00 +0200
commit8110bb2773b6c841029a51eca7971f42a36f480c (patch)
treeb3b364a6c0231fe408229e94dc9e25ce4562ad02 /crates/platform
parentd1f856edc516047575cf46f12fad2b59006363c8 (diff)
downloadsrdwm-8110bb2773b6c841029a51eca7971f42a36f480c.tar.gz
srdwm-8110bb2773b6c841029a51eca7971f42a36f480c.zip
Rewrite srdwm in Rust: working X11 and Wayland backends, Lua config
The C++ prototype (moved to legacy-cpp/) was mostly a design skeleton: X11 and Windows backends were partially real, Wayland created the wlroots object graph but never wired a single event listener, macOS was stub except monitor enumeration, and the Lua engine's srd.bind() stored a key-combo string but never the actual closure. See docs/PRIOR_ART.md for the full audit. This replaces it with a Cargo workspace: - srdwm-core: platform-independent window/workspace/monitor state, a real master-stack tiling layout, and SmartPlacement grid/cascade/ snap-to-edge placement - fixing several bugs in the C++ version (hardcoded 2-column grid, cascade that never cascaded, snap-to-edge that always returned a fixed rect). 35 unit tests. - srdwm-config: the srd Lua API via mlua, implementing the surface docs/DEFAULTS.md always documented but the C++ engine never actually built (srd.window.close()/focus(direction), srd.workspace.next(), real keybinding closures, require("srd") support). 10 unit tests. - srdwm-x11: a real reparenting WM with a drawn title bar (buttons, drag, resize), verified live under Xephyr - frame placement and client offset match srdwm-core's computed geometry exactly, and the decoration renders correctly on screen. - srdwm-wayland: a from-scratch smithay compositor (the C++ version had nothing working to port from) - runs via the winit backend, tracks xdg-shell toplevels through the same WindowManager and hit-testing code X11 uses, verified to start/render/run without crashing. Decorations are solid-color (no text yet); see docs/IMPLEMENTATION_STATUS.md for exact scope. - srdwm-windows / srdwm-macos: structured, cfg-gated designs informed by komorebi/glazewm and yabai/AeroSpace respectively (see docs/PRIOR_ART.md), honestly marked as unbuilt/unverified since this sandbox has no Windows or macOS target.
Diffstat (limited to 'crates/platform')
-rw-r--r--crates/platform/Cargo.toml11
-rw-r--r--crates/platform/src/lib.rs99
2 files changed, 110 insertions, 0 deletions
diff --git a/crates/platform/Cargo.toml b/crates/platform/Cargo.toml
new file mode 100644
index 0000000..d94723e
--- /dev/null
+++ b/crates/platform/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "srdwm-platform"
+version.workspace = true
+edition.workspace = true
+license.workspace = true
+description = "Platform abstraction trait shared by all srdwm backends"
+
+[dependencies]
+srdwm-core.workspace = true
+log.workspace = true
+thiserror.workspace = true
diff --git a/crates/platform/src/lib.rs b/crates/platform/src/lib.rs
new file mode 100644
index 0000000..fdad291
--- /dev/null
+++ b/crates/platform/src/lib.rs
@@ -0,0 +1,99 @@
+//! Platform abstraction: the trait every backend (X11, Wayland, Windows,
+//! macOS) implements, plus auto-detection of which backend to use.
+//!
+//! This mirrors the intent of the legacy C++ `Platform` interface
+//! (see docs/PRIOR_ART.md) with one deliberate change: `poll_events` is the
+//! only place backends need to bridge their native event model (X11's
+//! blocking `XNextEvent`, Wayland's callback-driven dispatch, Win32's message
+//! pump, macOS's event taps) into the common [`srdwm_core::Event`] queue -
+//! everything downstream of that is platform-independent.
+
+use srdwm_core::{Monitor, Rect, Window, WindowId};
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum PlatformKind {
+ X11,
+ Wayland,
+ Windows,
+ MacOS,
+}
+
+impl PlatformKind {
+ pub fn name(self) -> &'static str {
+ match self {
+ PlatformKind::X11 => "x11",
+ PlatformKind::Wayland => "wayland",
+ PlatformKind::Windows => "windows",
+ PlatformKind::MacOS => "macos",
+ }
+ }
+}
+
+/// Chooses a backend the way the legacy `PlatformFactory` did: prefer
+/// Wayland when a compositor is reachable, fall back to X11, otherwise use
+/// the compile-time native backend on Windows/macOS.
+pub fn detect() -> PlatformKind {
+ #[cfg(target_os = "windows")]
+ {
+ return PlatformKind::Windows;
+ }
+ #[cfg(target_os = "macos")]
+ {
+ return PlatformKind::MacOS;
+ }
+ #[cfg(all(unix, not(target_os = "macos")))]
+ {
+ let wayland = std::env::var_os("WAYLAND_DISPLAY").is_some()
+ || std::env::var("XDG_SESSION_TYPE").map(|v| v == "wayland").unwrap_or(false);
+ if wayland {
+ PlatformKind::Wayland
+ } else {
+ PlatformKind::X11
+ }
+ }
+}
+
+#[derive(thiserror::Error, Debug)]
+pub enum PlatformError {
+ #[error("failed to connect to display server: {0}")]
+ ConnectionFailed(String),
+ #[error("another window manager is already running")]
+ AnotherWmRunning,
+ #[error("unsupported operation on this platform: {0}")]
+ Unsupported(&'static str),
+ #[error("{0}")]
+ Other(String),
+}
+
+pub type Result<T> = std::result::Result<T, PlatformError>;
+
+/// A platform backend: owns the connection to the display server and
+/// translates between real surfaces/windows and srdwm-core's `Window` state.
+pub trait Platform {
+ fn kind(&self) -> PlatformKind;
+
+ /// Blocks until at least one event is available (or a short timeout
+ /// elapses), then drains everything currently pending.
+ fn poll_events(&mut self) -> Result<Vec<srdwm_core::Event>>;
+
+ fn monitors(&mut self) -> Result<Vec<Monitor>>;
+
+ fn apply_geometry(&mut self, window: WindowId, geometry: Rect) -> Result<()>;
+ fn set_title(&mut self, window: WindowId, title: &str) -> Result<()>;
+ fn focus(&mut self, window: WindowId) -> Result<()>;
+ fn minimize(&mut self, window: WindowId) -> Result<()>;
+ fn restore(&mut self, window: WindowId) -> Result<()>;
+ fn close(&mut self, window: WindowId) -> Result<()>;
+
+ fn set_decorated(&mut self, window: WindowId, decorated: bool) -> Result<()>;
+ fn set_border_color(&mut self, window: WindowId, rgb: (u8, u8, u8)) -> Result<()>;
+ fn set_border_width(&mut self, window: WindowId, width: u32) -> Result<()>;
+
+ /// Redraws the decoration (titlebar + buttons) for `window`, e.g. after
+ /// a focus change or resize. No-op on platforms with native
+ /// decorations (Windows/macOS).
+ fn redraw_decoration(&mut self, window: WindowId, win: &Window, focused: bool) -> Result<()>;
+
+ fn grab_keyboard(&mut self) -> Result<()>;
+ fn ungrab_keyboard(&mut self) -> Result<()>;
+}