From 16fff3f7e3cbc0be766d7b22bab050ab8fd6f594 Mon Sep 17 00:00:00 2001 From: Ottatop Date: Thu, 29 Feb 2024 16:28:25 -0600 Subject: [PATCH 1/3] Update Smithay --- Cargo.lock | 8 +-- Cargo.toml | 4 +- src/api.rs | 6 ++- src/backend/udev.rs | 33 +++++------- src/focus.rs | 101 +++++++++++++++++++++++++--------- src/grab/resize_grab.rs | 32 +++++++---- src/handlers.rs | 5 +- src/handlers/xdg_shell.rs | 4 +- src/handlers/xwayland.rs | 4 +- src/input.rs | 4 +- src/layout.rs | 13 +++-- src/render.rs | 1 + src/window.rs | 108 +++++++++++++++++++++++++++++-------- src/window/window_state.rs | 76 +++++++++++++++----------- 14 files changed, 268 insertions(+), 131 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 62a28f4..65cc27f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -831,9 +831,9 @@ dependencies = [ [[package]] name = "gbm" -version = "0.14.1" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f177420f6650dcd50042121adf7ff7ab265abdaf4862fe2624066e36e3a9ef34" +checksum = "313702b30cdeb83ddc72bc14dcee67803cd0ae2d12282ea06e368c25a900c844" dependencies = [ "bitflags 1.3.2", "drm", @@ -2053,7 +2053,7 @@ checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "smithay" version = "0.3.0" -source = "git+https://github.com/Smithay/smithay?rev=1074914#1074914492783b25a4c2c49ce49a126d39994596" +source = "git+https://github.com/Smithay/smithay?rev=418190e#418190e4992ce642e6bac873307d4fc4fa9a1e89" dependencies = [ "appendlist", "ash", @@ -2128,7 +2128,7 @@ dependencies = [ [[package]] name = "smithay-drm-extras" version = "0.1.0" -source = "git+https://github.com/Smithay/smithay?rev=1074914#1074914492783b25a4c2c49ce49a126d39994596" +source = "git+https://github.com/Smithay/smithay?rev=418190e#418190e4992ce642e6bac873307d4fc4fa9a1e89" dependencies = [ "drm", "edid-rs", diff --git a/Cargo.toml b/Cargo.toml index ebc15eb..35042a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,8 +34,8 @@ repository.workspace = true keywords = ["wayland", "compositor", "smithay", "lua"] [dependencies] -smithay = { git = "https://github.com/Smithay/smithay", rev = "1074914", default-features = false, features = ["desktop", "wayland_frontend"] } -smithay-drm-extras = { git = "https://github.com/Smithay/smithay", rev = "1074914" } +smithay = { git = "https://github.com/Smithay/smithay", rev = "418190e", default-features = false, features = ["desktop", "wayland_frontend"] } +smithay-drm-extras = { git = "https://github.com/Smithay/smithay", rev = "418190e" } tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter", "registry"] } diff --git a/src/api.rs b/src/api.rs index 13c06cc..6bd1b88 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1123,7 +1123,9 @@ impl window_service_server::WindowService for WindowService { let Some(window) = window_id.window(state) else { return }; match window { - WindowElement::Wayland(window) => window.toplevel().send_close(), + WindowElement::Wayland(window) => { + window.toplevel().expect("in wayland enum").send_close() + } WindowElement::X11(surface) => surface.close().expect("failed to close x11 win"), WindowElement::X11OverrideRedirect(_) => { tracing::warn!("tried to close override redirect window"); @@ -1431,7 +1433,7 @@ impl window_service_server::WindowService for WindowService { for window in state.space.elements() { if let WindowElement::Wayland(window) = window { - window.toplevel().send_configure(); + window.toplevel().expect("in wayland enum").send_configure(); } } diff --git a/src/backend/udev.rs b/src/backend/udev.rs index 8112493..89cdd5f 100644 --- a/src/backend/udev.rs +++ b/src/backend/udev.rs @@ -91,8 +91,12 @@ const SUPPORTED_FORMATS: &[Fourcc] = &[ const SUPPORTED_FORMATS_8BIT_ONLY: &[Fourcc] = &[Fourcc::Abgr8888, Fourcc::Argb8888]; /// A [`MultiRenderer`] that uses the [`GbmGlesBackend`]. -type UdevRenderer<'a, 'b> = - MultiRenderer<'a, 'a, 'b, GbmGlesBackend, GbmGlesBackend>; +type UdevRenderer<'a> = MultiRenderer< + 'a, + 'a, + GbmGlesBackend, + GbmGlesBackend, +>; /// Udev state attached to each [`Output`]. #[derive(Debug, PartialEq)] @@ -110,7 +114,7 @@ pub struct Udev { pub(super) dmabuf_state: Option<(DmabufState, DmabufGlobal)>, pub(super) primary_gpu: DrmNode, allocator: Option>>, - pub(super) gpu_manager: GpuManager>, + pub(super) gpu_manager: GpuManager>, backends: HashMap, pointer_images: Vec<(xcursor::parser::Image, TextureBuffer)>, pointer_element: PointerElement, @@ -226,10 +230,7 @@ impl BackendData for Udev { } fn early_import(&mut self, surface: &WlSurface) { - if let Err(err) = - self.gpu_manager - .early_import(Some(self.primary_gpu), self.primary_gpu, surface) - { + if let Err(err) = self.gpu_manager.early_import(self.primary_gpu, surface) { tracing::warn!("early buffer import failed: {}", err); } } @@ -556,7 +557,7 @@ enum DeviceAddError { fn get_surface_dmabuf_feedback( primary_gpu: DrmNode, render_node: DrmNode, - gpu_manager: &mut GpuManager>, + gpu_manager: &mut GpuManager>, composition: &GbmDrmCompositor, ) -> Option { let primary_formats = gpu_manager @@ -1210,18 +1211,8 @@ impl State { udev.gpu_manager.single_renderer(&render_node) } else { let format = surface.compositor.format(); - udev.gpu_manager.renderer( - &primary_gpu, - &render_node, - udev - .allocator - .as_mut() - // TODO: We could build some kind of `GLAllocator` using Renderbuffers in theory for this case. - // That would work for memcpy's of offscreen contents. - .expect("We need an allocator for multigpu systems") - .as_mut(), - format, - ) + udev.gpu_manager + .renderer(&primary_gpu, &render_node, format) } .expect("failed to create MultiRenderer"); @@ -1294,7 +1285,7 @@ fn render_surface_for_output<'a>( #[allow(clippy::too_many_arguments)] fn render_surface( surface: &mut RenderSurface, - renderer: &mut UdevRenderer<'_, '_>, + renderer: &mut UdevRenderer<'_>, output: &Output, space: &Space, diff --git a/src/focus.rs b/src/focus.rs index fd950b7..6ffcf3b 100644 --- a/src/focus.rs +++ b/src/focus.rs @@ -5,11 +5,12 @@ use smithay::{ input::{ keyboard::KeyboardTarget, pointer::{MotionEvent, PointerTarget}, + touch::{self, TouchTarget}, Seat, }, output::Output, reexports::wayland_server::{protocol::wl_surface::WlSurface, Resource}, - utils::{IsAlive, SERIAL_COUNTER}, + utils::{IsAlive, Serial, SERIAL_COUNTER}, wayland::seat::WaylandFocus, }; @@ -56,7 +57,7 @@ impl State { assert!(!win.is_x11_override_redirect()); if let WindowElement::Wayland(w) = win { - w.toplevel().send_configure(); + w.toplevel().expect("in wayland enum").send_configure(); } } @@ -140,9 +141,9 @@ impl TryFrom for WlSurface { impl PointerTarget for FocusTarget { fn frame(&self, seat: &Seat, data: &mut State) { match self { - FocusTarget::Window(window) => window.frame(seat, data), - FocusTarget::Popup(popup) => popup.wl_surface().frame(seat, data), - FocusTarget::LayerSurface(surf) => surf.frame(seat, data), + FocusTarget::Window(window) => PointerTarget::frame(window, seat, data), + FocusTarget::Popup(popup) => PointerTarget::frame(popup.wl_surface(), seat, data), + FocusTarget::LayerSurface(surf) => PointerTarget::frame(surf.wl_surface(), seat, data), } } @@ -152,7 +153,9 @@ impl PointerTarget for FocusTarget { FocusTarget::Popup(popup) => { PointerTarget::enter(popup.wl_surface(), seat, data, event); } - FocusTarget::LayerSurface(surf) => PointerTarget::enter(surf, seat, data, event), + FocusTarget::LayerSurface(surf) => { + PointerTarget::enter(surf.wl_surface(), seat, data, event) + } } } @@ -162,7 +165,9 @@ impl PointerTarget for FocusTarget { FocusTarget::Popup(popup) => { PointerTarget::motion(popup.wl_surface(), seat, data, event); } - FocusTarget::LayerSurface(surf) => PointerTarget::motion(surf, seat, data, event), + FocusTarget::LayerSurface(surf) => { + PointerTarget::motion(surf.wl_surface(), seat, data, event) + } } } @@ -180,7 +185,7 @@ impl PointerTarget for FocusTarget { PointerTarget::relative_motion(popup.wl_surface(), seat, data, event); } FocusTarget::LayerSurface(surf) => { - PointerTarget::relative_motion(surf, seat, data, event); + PointerTarget::relative_motion(surf.wl_surface(), seat, data, event); } } } @@ -196,7 +201,9 @@ impl PointerTarget for FocusTarget { FocusTarget::Popup(popup) => { PointerTarget::button(popup.wl_surface(), seat, data, event); } - FocusTarget::LayerSurface(surf) => PointerTarget::button(surf, seat, data, event), + FocusTarget::LayerSurface(surf) => { + PointerTarget::button(surf.wl_surface(), seat, data, event) + } } } @@ -209,23 +216,21 @@ impl PointerTarget for FocusTarget { match self { FocusTarget::Window(window) => PointerTarget::axis(window, seat, data, frame), FocusTarget::Popup(popup) => PointerTarget::axis(popup.wl_surface(), seat, data, frame), - FocusTarget::LayerSurface(surf) => PointerTarget::axis(surf, seat, data, frame), + FocusTarget::LayerSurface(surf) => { + PointerTarget::axis(surf.wl_surface(), seat, data, frame) + } } } - fn leave( - &self, - seat: &Seat, - data: &mut State, - serial: smithay::utils::Serial, - time: u32, - ) { + fn leave(&self, seat: &Seat, data: &mut State, serial: Serial, time: u32) { match self { FocusTarget::Window(window) => PointerTarget::leave(window, seat, data, serial, time), FocusTarget::Popup(popup) => { PointerTarget::leave(popup.wl_surface(), seat, data, serial, time); } - FocusTarget::LayerSurface(surf) => PointerTarget::leave(surf, seat, data, serial, time), + FocusTarget::LayerSurface(surf) => { + PointerTarget::leave(surf.wl_surface(), seat, data, serial, time) + } } } @@ -308,7 +313,7 @@ impl KeyboardTarget for FocusTarget { seat: &Seat, data: &mut State, keys: Vec>, - serial: smithay::utils::Serial, + serial: Serial, ) { match self { FocusTarget::Window(window) => KeyboardTarget::enter(window, seat, data, keys, serial), @@ -316,18 +321,20 @@ impl KeyboardTarget for FocusTarget { KeyboardTarget::enter(popup.wl_surface(), seat, data, keys, serial); } FocusTarget::LayerSurface(surf) => { - KeyboardTarget::enter(surf, seat, data, keys, serial); + KeyboardTarget::enter(surf.wl_surface(), seat, data, keys, serial); } } } - fn leave(&self, seat: &Seat, data: &mut State, serial: smithay::utils::Serial) { + fn leave(&self, seat: &Seat, data: &mut State, serial: Serial) { match self { FocusTarget::Window(window) => KeyboardTarget::leave(window, seat, data, serial), FocusTarget::Popup(popup) => { KeyboardTarget::leave(popup.wl_surface(), seat, data, serial); } - FocusTarget::LayerSurface(surf) => KeyboardTarget::leave(surf, seat, data, serial), + FocusTarget::LayerSurface(surf) => { + KeyboardTarget::leave(surf.wl_surface(), seat, data, serial) + } } } @@ -337,7 +344,7 @@ impl KeyboardTarget for FocusTarget { data: &mut State, key: smithay::input::keyboard::KeysymHandle<'_>, state: smithay::backend::input::KeyState, - serial: smithay::utils::Serial, + serial: Serial, time: u32, ) { match self { @@ -348,7 +355,7 @@ impl KeyboardTarget for FocusTarget { KeyboardTarget::key(popup.wl_surface(), seat, data, key, state, serial, time); } FocusTarget::LayerSurface(surf) => { - KeyboardTarget::key(surf, seat, data, key, state, serial, time); + KeyboardTarget::key(surf.wl_surface(), seat, data, key, state, serial, time); } } } @@ -358,7 +365,7 @@ impl KeyboardTarget for FocusTarget { seat: &Seat, data: &mut State, modifiers: smithay::input::keyboard::ModifiersState, - serial: smithay::utils::Serial, + serial: Serial, ) { match self { FocusTarget::Window(window) => { @@ -368,12 +375,54 @@ impl KeyboardTarget for FocusTarget { KeyboardTarget::modifiers(popup.wl_surface(), seat, data, modifiers, serial); } FocusTarget::LayerSurface(surf) => { - KeyboardTarget::modifiers(surf, seat, data, modifiers, serial); + KeyboardTarget::modifiers(surf.wl_surface(), seat, data, modifiers, serial); } } } } +impl TouchTarget for FocusTarget { + fn down(&self, seat: &Seat, data: &mut State, event: &touch::DownEvent, seq: Serial) { + todo!() + } + + fn up(&self, seat: &Seat, data: &mut State, event: &touch::UpEvent, seq: Serial) { + todo!() + } + + fn motion( + &self, + seat: &Seat, + data: &mut State, + event: &touch::MotionEvent, + seq: Serial, + ) { + todo!() + } + + fn frame(&self, seat: &Seat, data: &mut State, seq: Serial) { + todo!() + } + + fn cancel(&self, seat: &Seat, data: &mut State, seq: Serial) { + todo!() + } + + fn shape(&self, seat: &Seat, data: &mut State, event: &touch::ShapeEvent, seq: Serial) { + todo!() + } + + fn orientation( + &self, + seat: &Seat, + data: &mut State, + event: &touch::OrientationEvent, + seq: Serial, + ) { + todo!() + } +} + impl WaylandFocus for FocusTarget { fn wl_surface(&self) -> Option { match self { diff --git a/src/grab/resize_grab.rs b/src/grab/resize_grab.rs index f4b4f24..4e84321 100644 --- a/src/grab/resize_grab.rs +++ b/src/grab/resize_grab.rs @@ -160,7 +160,7 @@ impl PointerGrab for ResizeSurfaceGrab { match &self.window { WindowElement::Wayland(window) => { - let toplevel_surface = window.toplevel(); + let toplevel_surface = window.toplevel().expect("in wayland enum"); toplevel_surface.with_pending_state(|state| { state.states.set(xdg_toplevel::State::Resizing); @@ -210,7 +210,7 @@ impl PointerGrab for ResizeSurfaceGrab { match &self.window { WindowElement::Wayland(window) => { - let toplevel_surface = window.toplevel(); + let toplevel_surface = window.toplevel().expect("in wayland enum"); toplevel_surface.with_pending_state(|state| { state.states.unset(xdg_toplevel::State::Resizing); state.size = Some(self.last_window_size); @@ -459,11 +459,17 @@ pub fn resize_request_client( let initial_window_size = window.geometry().size; if let Some(WindowElement::Wayland(window)) = state.window_for_surface(surface) { - window.toplevel().with_pending_state(|state| { - state.states.set(xdg_toplevel::State::Resizing); - }); + window + .toplevel() + .expect("in wayland enum") + .with_pending_state(|state| { + state.states.set(xdg_toplevel::State::Resizing); + }); - window.toplevel().send_pending_configure(); + window + .toplevel() + .expect("in wayland enum") + .send_pending_configure(); } let grab = ResizeSurfaceGrab::start( @@ -507,11 +513,17 @@ pub fn resize_request_server( let initial_window_size = window.geometry().size; if let Some(WindowElement::Wayland(window)) = state.window_for_surface(surface) { - window.toplevel().with_pending_state(|state| { - state.states.set(xdg_toplevel::State::Resizing); - }); + window + .toplevel() + .expect("in wayland enum") + .with_pending_state(|state| { + state.states.set(xdg_toplevel::State::Resizing); + }); - window.toplevel().send_pending_configure(); + window + .toplevel() + .expect("in wayland enum") + .send_pending_configure(); } let start_data = smithay::input::pointer::GrabStartData { diff --git a/src/handlers.rs b/src/handlers.rs index cc3b819..a958c08 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -194,7 +194,7 @@ impl CompositorHandler for State { if !initial_configure_sent { tracing::debug!("Initial configure"); - window.toplevel().send_configure(); + window.toplevel().expect("in wayland enum").send_configure(); } } @@ -280,7 +280,7 @@ fn ensure_initial_configure(surface: &WlSurface, state: &mut State) { if !initial_configure_sent { tracing::debug!("Initial configure"); - window.toplevel().send_configure(); + window.toplevel().expect("in wayland enum").send_configure(); } } return; @@ -406,6 +406,7 @@ delegate_data_control!(State); impl SeatHandler for State { type KeyboardFocus = FocusTarget; type PointerFocus = FocusTarget; + type TouchFocus = FocusTarget; fn seat_state(&mut self) -> &mut SeatState { &mut self.seat_state diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs index f2a02a5..5fe8309 100644 --- a/src/handlers/xdg_shell.rs +++ b/src/handlers/xdg_shell.rs @@ -41,7 +41,7 @@ impl XdgShellHandler for State { state.states.set(xdg_toplevel::State::TiledRight); }); - let window = WindowElement::Wayland(Window::new(surface.clone())); + let window = WindowElement::Wayland(Window::new_wayland_window(surface.clone())); self.new_windows.push(window); // if let (Some(output), _) | (None, Some(output)) = ( @@ -139,7 +139,7 @@ impl XdgShellHandler for State { self.space.raise_element(win, true); self.z_index_stack.set_focus(win.clone()); if let WindowElement::Wayland(win) = &win { - win.toplevel().send_configure(); + win.toplevel().expect("in wayland enum").send_configure(); } } self.seat diff --git a/src/handlers/xwayland.rs b/src/handlers/xwayland.rs index 310cfc9..4e5a4f5 100644 --- a/src/handlers/xwayland.rs +++ b/src/handlers/xwayland.rs @@ -179,7 +179,7 @@ impl XwmHandler for State { self.space.raise_element(win, true); self.z_index_stack.set_focus(win.clone()); if let WindowElement::Wayland(win) = &win { - win.toplevel().send_configure(); + win.toplevel().expect("in wayland enum").send_configure(); } } @@ -242,7 +242,7 @@ impl XwmHandler for State { self.space.raise_element(win, true); self.z_index_stack.set_focus(win.clone()); if let WindowElement::Wayland(win) = &win { - win.toplevel().send_configure(); + win.toplevel().expect("in wayland enum").send_configure(); } } diff --git a/src/input.rs b/src/input.rs index c6a1d5c..e40d2e4 100644 --- a/src/input.rs +++ b/src/input.rs @@ -358,7 +358,7 @@ impl State { for window in self.space.elements() { if let WindowElement::Wayland(window) = window { - window.toplevel().send_configure(); + window.toplevel().expect("in wayland enum").send_configure(); } } } else { @@ -368,7 +368,7 @@ impl State { for window in state.focus_stack.stack.iter() { window.set_activate(false); if let WindowElement::Wayland(window) = window { - window.toplevel().send_configure(); + window.toplevel().expect("in wayland enum").send_configure(); } } }); diff --git a/src/layout.rs b/src/layout.rs index ab16be6..5bacc9e 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -117,8 +117,9 @@ impl State { if win.with_state(|state| state.target_loc.is_some()) { match win { WindowElement::Wayland(wl_win) => { - let pending = - compositor::with_states(wl_win.toplevel().wl_surface(), |states| { + let pending = compositor::with_states( + wl_win.toplevel().expect("in wayland enum").wl_surface(), + |states| { states .data_map .get::() @@ -126,10 +127,14 @@ impl State { .lock() .expect("Failed to lock Mutex") .has_pending_changes() - }); + }, + ); if pending { - pending_wins.push((win.clone(), wl_win.toplevel().send_configure())) + pending_wins.push(( + win.clone(), + wl_win.toplevel().expect("in wayland enum").send_configure(), + )) } else { let loc = win.with_state(|state| state.target_loc.take()); if let Some(loc) = loc { diff --git a/src/render.rs b/src/render.rs index a6190e9..849aebd 100644 --- a/src/render.rs +++ b/src/render.rs @@ -310,6 +310,7 @@ where if let WindowElement::Wayland(window) = win { window .toplevel() + .expect("in wayland enum") .current_state() .states .contains(xdg_toplevel::State::Fullscreen) diff --git a/src/window.rs b/src/window.rs index c20f973..eeff825 100644 --- a/src/window.rs +++ b/src/window.rs @@ -193,9 +193,12 @@ impl WindowElement { pub fn change_geometry(&self, new_geo: Rectangle) { match self { WindowElement::Wayland(window) => { - window.toplevel().with_pending_state(|state| { - state.size = Some(new_geo.size); - }); + window + .toplevel() + .expect("in wayland enum") + .with_pending_state(|state| { + state.size = Some(new_geo.size); + }); } WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { // TODO: maybe move this check elsewhere idk @@ -217,8 +220,9 @@ impl WindowElement { pub fn class(&self) -> Option { match self { - WindowElement::Wayland(window) => { - compositor::with_states(window.toplevel().wl_surface(), |states| { + WindowElement::Wayland(window) => compositor::with_states( + window.toplevel().expect("in wayland enum").wl_surface(), + |states| { states .data_map .get::() @@ -227,8 +231,8 @@ impl WindowElement { .expect("Failed to lock Mutex") .app_id .clone() - }) - } + }, + ), WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { Some(surface.class()) } @@ -238,8 +242,9 @@ impl WindowElement { pub fn title(&self) -> Option { match self { - WindowElement::Wayland(window) => { - compositor::with_states(window.toplevel().wl_surface(), |states| { + WindowElement::Wayland(window) => compositor::with_states( + window.toplevel().expect("in wayland enum").wl_surface(), + |states| { states .data_map .get::() @@ -248,8 +253,8 @@ impl WindowElement { .expect("Failed to lock Mutex") .title .clone() - }) - } + }, + ), WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { Some(surface.title()) } @@ -335,7 +340,10 @@ impl WindowElement { impl PointerTarget for WindowElement { fn frame(&self, seat: &Seat, state: &mut State) { match self { - WindowElement::Wayland(window) => window.frame(seat, state), + WindowElement::Wayland(window) => window + .wl_surface() + .expect("in wayland enum") + .frame(seat, state), WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { surface.frame(seat, state) } @@ -346,7 +354,12 @@ impl PointerTarget for WindowElement { fn enter(&self, seat: &Seat, state: &mut State, event: &MotionEvent) { // TODO: ssd match self { - WindowElement::Wayland(window) => PointerTarget::enter(window, seat, state, event), + WindowElement::Wayland(window) => PointerTarget::enter( + &window.wl_surface().expect("in wayland enum"), + seat, + state, + event, + ), WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { PointerTarget::enter(surface, seat, state, event) } @@ -364,7 +377,12 @@ impl PointerTarget for WindowElement { fn motion(&self, seat: &Seat, state: &mut State, event: &MotionEvent) { // TODO: ssd match self { - WindowElement::Wayland(window) => PointerTarget::motion(window, seat, state, event), + WindowElement::Wayland(window) => PointerTarget::motion( + &window.wl_surface().expect("in wayland enum"), + seat, + state, + event, + ), WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { PointerTarget::motion(surface, seat, state, event) } @@ -381,7 +399,12 @@ impl PointerTarget for WindowElement { // TODO: ssd match self { WindowElement::Wayland(window) => { - PointerTarget::relative_motion(window, seat, state, event); + PointerTarget::relative_motion( + &window.wl_surface().expect("in wayland enum"), + seat, + state, + event, + ); } WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { PointerTarget::relative_motion(surface, seat, state, event); @@ -398,7 +421,12 @@ impl PointerTarget for WindowElement { ) { // TODO: ssd match self { - WindowElement::Wayland(window) => PointerTarget::button(window, seat, state, event), + WindowElement::Wayland(window) => PointerTarget::button( + &window.wl_surface().expect("in wayland enum"), + seat, + state, + event, + ), WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { PointerTarget::button(surface, seat, state, event) } @@ -409,7 +437,12 @@ impl PointerTarget for WindowElement { fn axis(&self, seat: &Seat, state: &mut State, frame: AxisFrame) { // TODO: ssd match self { - WindowElement::Wayland(window) => PointerTarget::axis(window, seat, state, frame), + WindowElement::Wayland(window) => PointerTarget::axis( + &window.wl_surface().expect("in wayland enum"), + seat, + state, + frame, + ), WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { PointerTarget::axis(surface, seat, state, frame) } @@ -421,7 +454,13 @@ impl PointerTarget for WindowElement { // TODO: ssd match self { WindowElement::Wayland(window) => { - PointerTarget::leave(window, seat, state, serial, time); + PointerTarget::leave( + &window.wl_surface().expect("in wayland enum"), + seat, + state, + serial, + time, + ); } WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { PointerTarget::leave(surface, seat, state, serial, time) @@ -520,7 +559,13 @@ impl KeyboardTarget for WindowElement { ) { match self { WindowElement::Wayland(window) => { - KeyboardTarget::enter(window, seat, state, keys, serial); + KeyboardTarget::enter( + &window.wl_surface().expect("in wayland enum"), + seat, + state, + keys, + serial, + ); } WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { KeyboardTarget::enter(surface, seat, state, keys, serial) @@ -531,7 +576,12 @@ impl KeyboardTarget for WindowElement { fn leave(&self, seat: &Seat, state: &mut State, serial: Serial) { match self { - WindowElement::Wayland(window) => KeyboardTarget::leave(window, seat, state, serial), + WindowElement::Wayland(window) => KeyboardTarget::leave( + &window.wl_surface().expect("in wayland enum"), + seat, + state, + serial, + ), WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { KeyboardTarget::leave(surface, seat, state, serial) } @@ -550,7 +600,15 @@ impl KeyboardTarget for WindowElement { ) { match self { WindowElement::Wayland(window) => { - KeyboardTarget::key(window, seat, state, key, key_state, serial, time); + KeyboardTarget::key( + &window.wl_surface().expect("in wayland enum"), + seat, + state, + key, + key_state, + serial, + time, + ); } WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { KeyboardTarget::key(surface, seat, state, key, key_state, serial, time); @@ -568,7 +626,13 @@ impl KeyboardTarget for WindowElement { ) { match self { WindowElement::Wayland(window) => { - KeyboardTarget::modifiers(window, seat, state, modifiers, serial); + KeyboardTarget::modifiers( + &window.wl_surface().expect("in wayland enum"), + seat, + state, + modifiers, + serial, + ); } WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { KeyboardTarget::modifiers(surface, seat, state, modifiers, serial); diff --git a/src/window/window_state.rs b/src/window/window_state.rs index e9db349..6df4710 100644 --- a/src/window/window_state.rs +++ b/src/window/window_state.rs @@ -83,14 +83,17 @@ impl WindowElement { match self { WindowElement::Wayland(window) => { - window.toplevel().with_pending_state(|state| { - state.states.unset(xdg_toplevel::State::Maximized); - state.states.set(xdg_toplevel::State::Fullscreen); - state.states.set(xdg_toplevel::State::TiledTop); - state.states.set(xdg_toplevel::State::TiledLeft); - state.states.set(xdg_toplevel::State::TiledBottom); - state.states.set(xdg_toplevel::State::TiledRight); - }); + window + .toplevel() + .expect("in wayland enum") + .with_pending_state(|state| { + state.states.unset(xdg_toplevel::State::Maximized); + state.states.set(xdg_toplevel::State::Fullscreen); + state.states.set(xdg_toplevel::State::TiledTop); + state.states.set(xdg_toplevel::State::TiledLeft); + state.states.set(xdg_toplevel::State::TiledBottom); + state.states.set(xdg_toplevel::State::TiledRight); + }); } WindowElement::X11(surface) => { surface @@ -130,14 +133,17 @@ impl WindowElement { match self { WindowElement::Wayland(window) => { - window.toplevel().with_pending_state(|state| { - state.states.set(xdg_toplevel::State::Maximized); - state.states.unset(xdg_toplevel::State::Fullscreen); - state.states.set(xdg_toplevel::State::TiledTop); - state.states.set(xdg_toplevel::State::TiledLeft); - state.states.set(xdg_toplevel::State::TiledBottom); - state.states.set(xdg_toplevel::State::TiledRight); - }); + window + .toplevel() + .expect("in wayland enum") + .with_pending_state(|state| { + state.states.set(xdg_toplevel::State::Maximized); + state.states.unset(xdg_toplevel::State::Fullscreen); + state.states.set(xdg_toplevel::State::TiledTop); + state.states.set(xdg_toplevel::State::TiledLeft); + state.states.set(xdg_toplevel::State::TiledBottom); + state.states.set(xdg_toplevel::State::TiledRight); + }); } WindowElement::X11(surface) => { surface @@ -172,14 +178,17 @@ impl WindowElement { fn set_floating_states(&self) { match self { WindowElement::Wayland(window) => { - window.toplevel().with_pending_state(|state| { - state.states.unset(xdg_toplevel::State::Maximized); - state.states.unset(xdg_toplevel::State::Fullscreen); - state.states.unset(xdg_toplevel::State::TiledTop); - state.states.unset(xdg_toplevel::State::TiledLeft); - state.states.unset(xdg_toplevel::State::TiledBottom); - state.states.unset(xdg_toplevel::State::TiledRight); - }); + window + .toplevel() + .expect("in wayland enum") + .with_pending_state(|state| { + state.states.unset(xdg_toplevel::State::Maximized); + state.states.unset(xdg_toplevel::State::Fullscreen); + state.states.unset(xdg_toplevel::State::TiledTop); + state.states.unset(xdg_toplevel::State::TiledLeft); + state.states.unset(xdg_toplevel::State::TiledBottom); + state.states.unset(xdg_toplevel::State::TiledRight); + }); } WindowElement::X11(surface) => { surface @@ -199,14 +208,17 @@ impl WindowElement { fn set_tiled_states(&self) { match self { WindowElement::Wayland(window) => { - window.toplevel().with_pending_state(|state| { - state.states.unset(xdg_toplevel::State::Maximized); - state.states.unset(xdg_toplevel::State::Fullscreen); - state.states.set(xdg_toplevel::State::TiledTop); - state.states.set(xdg_toplevel::State::TiledLeft); - state.states.set(xdg_toplevel::State::TiledBottom); - state.states.set(xdg_toplevel::State::TiledRight); - }); + window + .toplevel() + .expect("in wayland enum") + .with_pending_state(|state| { + state.states.unset(xdg_toplevel::State::Maximized); + state.states.unset(xdg_toplevel::State::Fullscreen); + state.states.set(xdg_toplevel::State::TiledTop); + state.states.set(xdg_toplevel::State::TiledLeft); + state.states.set(xdg_toplevel::State::TiledBottom); + state.states.set(xdg_toplevel::State::TiledRight); + }); } WindowElement::X11(surface) => { surface From 48cd3d0df989c27e20ee234a89007a733d014300 Mon Sep 17 00:00:00 2001 From: Ottatop Date: Thu, 29 Feb 2024 20:10:23 -0600 Subject: [PATCH 2/3] Remove `space_elements!` so uh when you impl SpaceElement you gotta actually remember to impl the geometry fn, which is why Alacritty was 44 pixels off in the other attempt at this --- src/api.rs | 88 +++----- src/focus.rs | 10 +- src/grab/move_grab.rs | 31 +-- src/grab/resize_grab.rs | 96 ++++---- src/handlers.rs | 40 ++-- src/handlers/xdg_shell.rs | 91 +------- src/handlers/xwayland.rs | 69 +++--- src/input.rs | 12 +- src/layout.rs | 36 ++- src/render.rs | 22 +- src/window.rs | 451 +++++++++++-------------------------- src/window/window_state.rs | 166 +++++++------- 12 files changed, 379 insertions(+), 733 deletions(-) diff --git a/src/api.rs b/src/api.rs index 6bd1b88..499c7cc 100644 --- a/src/api.rs +++ b/src/api.rs @@ -34,11 +34,11 @@ use pinnacle_api_defs::pinnacle::{ }, }; use smithay::{ - desktop::space::SpaceElement, + desktop::{space::SpaceElement, WindowSurface}, input::keyboard::XkbConfig, reexports::{calloop, input as libinput, wayland_protocols::xdg::shell::server}, utils::{Point, Rectangle, SERIAL_COUNTER}, - wayland::{compositor, shell::xdg::XdgToplevelSurfaceData}, + wayland::seat::WaylandFocus, }; use sysinfo::ProcessRefreshKind; use tokio::{ @@ -48,6 +48,7 @@ use tokio::{ }; use tokio_stream::{Stream, StreamExt}; use tonic::{Request, Response, Status, Streaming}; +use tracing::{error, warn}; use crate::{ config::ConnectorSavedState, @@ -56,7 +57,7 @@ use crate::{ output::OutputName, state::{State, WithState}, tag::{Tag, TagId}, - window::{window_state::WindowId, WindowElement}, + window::window_state::WindowId, }; type ResponseStream = Pin> + Send>>; @@ -316,7 +317,7 @@ impl input_service_server::InputService for InputService { }; if let Some(kb) = state.seat.get_keyboard() { if let Err(err) = kb.set_xkb_config(state, new_config) { - tracing::error!("Failed to set xkbconfig: {err}"); + error!("Failed to set xkbconfig: {err}"); } } }) @@ -557,7 +558,7 @@ impl process_service_server::ProcessService for ProcessService { .args(command) .spawn() else { - tracing::warn!("Tried to run {arg0}, but it doesn't exist",); + warn!("Tried to run {arg0}, but it doesn't exist",); return; }; @@ -584,7 +585,7 @@ impl process_service_server::ProcessService for ProcessService { match sender.send(response) { Ok(_) => (), Err(err) => { - tracing::error!(err = ?err); + error!(err = ?err); break; } } @@ -608,7 +609,7 @@ impl process_service_server::ProcessService for ProcessService { match sender.send(response) { Ok(_) => (), Err(err) => { - tracing::error!(err = ?err); + error!(err = ?err); break; } } @@ -627,7 +628,7 @@ impl process_service_server::ProcessService for ProcessService { // TODO: handle error let _ = sender.send(response); } - Err(err) => tracing::warn!("child wait() err: {err}"), + Err(err) => warn!("child wait() err: {err}"), } }); }) @@ -1122,15 +1123,17 @@ impl window_service_server::WindowService for WindowService { run_unary_no_response(&self.sender, move |state| { let Some(window) = window_id.window(state) else { return }; - match window { - WindowElement::Wayland(window) => { - window.toplevel().expect("in wayland enum").send_close() + match window.underlying_surface() { + WindowSurface::Wayland(toplevel) => toplevel.send_close(), + WindowSurface::X11(surface) => { + if !surface.is_override_redirect() { + if let Err(err) = surface.close() { + error!("failed to close x11 window: {err}"); + } + } else { + warn!("tried to close OR window"); + } } - WindowElement::X11(surface) => surface.close().expect("failed to close x11 win"), - WindowElement::X11OverrideRedirect(_) => { - tracing::warn!("tried to close override redirect window"); - } - _ => unreachable!(), } }) .await @@ -1356,32 +1359,14 @@ impl window_service_server::WindowService for WindowService { return; }; + if window.is_x11_override_redirect() { + return; + } + let Some(output) = window.output(state) else { return; }; - // if !matches!( - // &focus, - // FocusTarget::Window(WindowElement::X11OverrideRedirect(_)) - // ) { - // keyboard.set_focus(self, Some(focus.clone()), serial); - // } - // - // self.space.elements().for_each(|window| { - // if let WindowElement::Wayland(window) = window { - // window.toplevel().send_configure(); - // } - // }); - // } else { - // self.space.elements().for_each(|window| { - // window.set_activate(false); - // if let WindowElement::Wayland(window) = window { - // window.toplevel().send_configure(); - // } - // }); - // keyboard.set_focus(self, None, serial); - // } - for win in state.space.elements() { win.set_activate(false); } @@ -1432,8 +1417,8 @@ impl window_service_server::WindowService for WindowService { } for window in state.space.elements() { - if let WindowElement::Wayland(window) = window { - window.toplevel().expect("in wayland enum").send_configure(); + if let Some(toplevel) = window.toplevel() { + toplevel.send_configure(); } } @@ -1677,27 +1662,8 @@ impl window_service_server::WindowService for WindowService { }) }; - let (class, title) = window.as_ref().map_or((None, None), |win| match &win { - WindowElement::Wayland(_) => { - if let Some(wl_surf) = win.wl_surface() { - compositor::with_states(&wl_surf, |states| { - let lock = states - .data_map - .get::() - .expect("XdgToplevelSurfaceData wasn't in surface's data map") - .lock() - .expect("failed to acquire lock"); - (lock.app_id.clone(), lock.title.clone()) - }) - } else { - (None, None) - } - } - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - (Some(surface.class()), Some(surface.title())) - } - _ => unreachable!(), - }); + let class = window.as_ref().and_then(|win| win.class()); + let title = window.as_ref().and_then(|win| win.title()); let focused = window.as_ref().and_then(|win| { state diff --git a/src/focus.rs b/src/focus.rs index 6ffcf3b..62fb430 100644 --- a/src/focus.rs +++ b/src/focus.rs @@ -56,8 +56,8 @@ impl State { if let Some(win) = ¤t_focus { assert!(!win.is_x11_override_redirect()); - if let WindowElement::Wayland(w) = win { - w.toplevel().expect("in wayland enum").send_configure(); + if let Some(toplevel) = win.toplevel() { + toplevel.send_configure(); } } @@ -437,13 +437,9 @@ impl WaylandFocus for FocusTarget { object_id: &smithay::reexports::wayland_server::backend::ObjectId, ) -> bool { match self { - FocusTarget::Window(WindowElement::Wayland(window)) => window.same_client_as(object_id), - FocusTarget::Window( - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface), - ) => surface.same_client_as(object_id), + FocusTarget::Window(window) => window.same_client_as(object_id), FocusTarget::Popup(popup) => popup.wl_surface().id().same_client_as(object_id), FocusTarget::LayerSurface(surf) => surf.wl_surface().id().same_client_as(object_id), - _ => unreachable!(), } } } diff --git a/src/grab/move_grab.rs b/src/grab/move_grab.rs index d826d74..579b767 100644 --- a/src/grab/move_grab.rs +++ b/src/grab/move_grab.rs @@ -51,13 +51,16 @@ impl PointerGrab for MoveSurfaceGrab { } state.space.raise_element(&self.window, false); - if let WindowElement::X11(surface) = &self.window { - state - .xwm - .as_mut() - .expect("no xwm") - .raise_window(surface) - .expect("failed to raise x11 win"); + if let Some(surface) = self.window.x11_surface() { + // INFO: can you raise OR windows or no idk + if !surface.is_override_redirect() { + state + .xwm + .as_mut() + .expect("no xwm") + .raise_window(surface) + .expect("failed to raise x11 win"); + } } let is_tiled = self @@ -136,12 +139,14 @@ impl PointerGrab for MoveSurfaceGrab { } }); - if let WindowElement::X11(surface) = &self.window { - let geo = surface.geometry(); - let new_geo = Rectangle::from_loc_and_size(new_loc, geo.size); - surface - .configure(new_geo) - .expect("failed to configure x11 win"); + if let Some(surface) = self.window.x11_surface() { + if !surface.is_override_redirect() { + let geo = surface.geometry(); + let new_geo = Rectangle::from_loc_and_size(new_loc, geo.size); + surface + .configure(new_geo) + .expect("failed to configure x11 win"); + } } let outputs = state.space.outputs_for_element(&self.window); diff --git a/src/grab/resize_grab.rs b/src/grab/resize_grab.rs index 4e84321..09d9552 100644 --- a/src/grab/resize_grab.rs +++ b/src/grab/resize_grab.rs @@ -1,17 +1,17 @@ // SPDX-License-Identifier: GPL-3.0-or-later use smithay::{ - desktop::space::SpaceElement, + desktop::{space::SpaceElement, utils::bbox_from_surface_tree, WindowSurface}, input::{ pointer::{AxisFrame, ButtonEvent, Focus, GrabStartData, PointerGrab, PointerInnerHandle}, Seat, SeatHandler, }, reexports::{ - wayland_protocols::xdg::shell::server::xdg_toplevel::{self}, + wayland_protocols::xdg::shell::server::xdg_toplevel, wayland_server::protocol::wl_surface::WlSurface, }, utils::{IsAlive, Logical, Point, Rectangle, Size}, - wayland::{compositor, shell::xdg::SurfaceCachedState}, + wayland::{compositor, seat::WaylandFocus, shell::xdg::SurfaceCachedState}, xwayland, }; @@ -158,28 +158,26 @@ impl PointerGrab for ResizeSurfaceGrab { new_window_height.clamp(min_height, max_height), )); - match &self.window { - WindowElement::Wayland(window) => { - let toplevel_surface = window.toplevel().expect("in wayland enum"); - - toplevel_surface.with_pending_state(|state| { + match self.window.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + toplevel.with_pending_state(|state| { state.states.set(xdg_toplevel::State::Resizing); state.size = Some(self.last_window_size); }); - toplevel_surface.send_pending_configure(); + toplevel.send_pending_configure(); } - WindowElement::X11(surface) => { - let loc = data - .space - .element_location(&self.window) - .expect("failed to get x11 win loc"); - surface - .configure(Rectangle::from_loc_and_size(loc, self.last_window_size)) - .expect("failed to configure x11 win"); + WindowSurface::X11(surface) => { + if !surface.is_override_redirect() { + let loc = data + .space + .element_location(&self.window) + .expect("failed to get x11 win loc"); + surface + .configure(Rectangle::from_loc_and_size(loc, self.last_window_size)) + .expect("failed to configure x11 win"); + } } - WindowElement::X11OverrideRedirect(_) => (), - _ => unreachable!(), } } @@ -208,17 +206,16 @@ impl PointerGrab for ResizeSurfaceGrab { return; } - match &self.window { - WindowElement::Wayland(window) => { - let toplevel_surface = window.toplevel().expect("in wayland enum"); - toplevel_surface.with_pending_state(|state| { + match self.window.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + toplevel.with_pending_state(|state| { state.states.unset(xdg_toplevel::State::Resizing); state.size = Some(self.last_window_size); }); - toplevel_surface.send_pending_configure(); + toplevel.send_pending_configure(); - toplevel_surface.wl_surface().with_state(|state| { + toplevel.wl_surface().with_state(|state| { // TODO: validate resize state state.resize_state = ResizeSurfaceState::WaitingForLastCommit { edges: self.edges, @@ -226,7 +223,10 @@ impl PointerGrab for ResizeSurfaceGrab { }; }); } - WindowElement::X11(surface) => { + WindowSurface::X11(surface) => { + if surface.is_override_redirect() { + return; + } let Some(surface) = surface.wl_surface() else { return }; surface.with_state(|state| { state.resize_state = ResizeSurfaceState::WaitingForLastCommit { @@ -235,8 +235,6 @@ impl PointerGrab for ResizeSurfaceGrab { }; }); } - WindowElement::X11OverrideRedirect(_) => (), - _ => unreachable!(), } } } @@ -418,12 +416,14 @@ pub fn handle_commit(state: &mut State, surface: &WlSurface) -> Option<()> { if new_loc.x.is_some() || new_loc.y.is_some() { state.space.map_element(window.clone(), window_loc, false); - if let WindowElement::X11(surface) = window { - let geo = surface.geometry(); - let new_geo = Rectangle::from_loc_and_size(window_loc, geo.size); - surface - .configure(new_geo) - .expect("failed to configure x11 win"); + if let Some(surface) = window.x11_surface() { + if !surface.is_override_redirect() { + let geo = surface.geometry(); + let new_geo = Rectangle::from_loc_and_size(window_loc, geo.size); + surface + .configure(new_geo) + .expect("failed to configure x11 win"); + } } } @@ -458,18 +458,14 @@ pub fn resize_request_client( .expect("resize request called on unmapped window"); let initial_window_size = window.geometry().size; - if let Some(WindowElement::Wayland(window)) = state.window_for_surface(surface) { - window - .toplevel() - .expect("in wayland enum") - .with_pending_state(|state| { + if let Some(window) = state.window_for_surface(surface) { + if let Some(toplevel) = window.toplevel() { + toplevel.with_pending_state(|state| { state.states.set(xdg_toplevel::State::Resizing); }); - window - .toplevel() - .expect("in wayland enum") - .send_pending_configure(); + toplevel.send_pending_configure(); + } } let grab = ResizeSurfaceGrab::start( @@ -512,18 +508,14 @@ pub fn resize_request_server( .expect("resize request called on unmapped window"); let initial_window_size = window.geometry().size; - if let Some(WindowElement::Wayland(window)) = state.window_for_surface(surface) { - window - .toplevel() - .expect("in wayland enum") - .with_pending_state(|state| { + if let Some(window) = state.window_for_surface(surface) { + if let Some(toplevel) = window.toplevel() { + toplevel.with_pending_state(|state| { state.states.set(xdg_toplevel::State::Resizing); }); - window - .toplevel() - .expect("in wayland enum") - .send_pending_configure(); + toplevel.send_pending_configure(); + } } let start_data = smithay::input::pointer::GrabStartData { diff --git a/src/handlers.rs b/src/handlers.rs index a958c08..e7177f2 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -60,7 +60,6 @@ use smithay::{ use crate::{ focus::FocusTarget, state::{ClientState, State, WithState}, - window::WindowElement, }; impl BufferHandler for State { @@ -107,9 +106,10 @@ impl CompositorHandler for State { fn commit(&mut self, surface: &WlSurface) { tracing::trace!("commit on surface {surface:?}"); + utils::on_commit_buffer_handler::(surface); + X11Wm::commit_hook::(surface); - utils::on_commit_buffer_handler::(surface); self.backend.early_import(surface); let mut root = surface.clone(); @@ -118,10 +118,10 @@ impl CompositorHandler for State { } if !compositor::is_sync_subsurface(surface) { - if let Some(win @ WindowElement::Wayland(window)) = &self.window_for_surface(&root) { + if let Some(window) = self.window_for_surface(&root) { window.on_commit(); - if let Some(loc) = win.with_state(|state| state.target_loc.take()) { - self.space.map_element(win.clone(), loc, false); + if let Some(loc) = window.with_state(|state| state.target_loc.take()) { + self.space.map_element(window.clone(), loc, false); } } }; @@ -149,7 +149,7 @@ impl CompositorHandler for State { self.output_focus_stack.current_focus(), self.space.outputs().next(), ) { - tracing::debug!("PLACING TOPLEVEL"); + tracing::debug!("Placing toplevel"); new_window.place_on_output(output); output.with_state(|state| state.focus_stack.set_focus(new_window.clone())); } @@ -180,22 +180,9 @@ impl CompositorHandler for State { SERIAL_COUNTER.next_serial(), ); }); - } else if let WindowElement::Wayland(window) = &new_window { - window.on_commit(); - let initial_configure_sent = compositor::with_states(surface, |states| { - states - .data_map - .get::() - .expect("XdgToplevelSurfaceData wasn't in surface's data map") - .lock() - .expect("Failed to lock Mutex") - .initial_configure_sent - }); - - if !initial_configure_sent { - tracing::debug!("Initial configure"); - window.toplevel().expect("in wayland enum").send_configure(); - } + } else if new_window.toplevel().is_some() { + new_window.on_commit(); + ensure_initial_configure(surface, self); } return; @@ -266,8 +253,11 @@ impl CompositorHandler for State { delegate_compositor!(State); fn ensure_initial_configure(surface: &WlSurface, state: &mut State) { - if let Some(window) = state.window_for_surface(surface) { - if let WindowElement::Wayland(window) = &window { + if let (Some(window), _) | (None, Some(window)) = ( + state.window_for_surface(surface), + state.new_window_for_surface(surface), + ) { + if let Some(toplevel) = window.toplevel() { let initial_configure_sent = compositor::with_states(surface, |states| { states .data_map @@ -280,7 +270,7 @@ fn ensure_initial_configure(surface: &WlSurface, state: &mut State) { if !initial_configure_sent { tracing::debug!("Initial configure"); - window.toplevel().expect("in wayland enum").send_configure(); + toplevel.send_configure(); } } return; diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs index 5fe8309..c0dd80a 100644 --- a/src/handlers/xdg_shell.rs +++ b/src/handlers/xdg_shell.rs @@ -17,8 +17,11 @@ use smithay::{ }, }, utils::{Logical, Point, Rectangle, Serial, SERIAL_COUNTER}, - wayland::shell::xdg::{ - PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState, + wayland::{ + seat::WaylandFocus, + shell::xdg::{ + PopupSurface, PositionerState, ToplevelSurface, XdgShellHandler, XdgShellState, + }, }, }; @@ -41,65 +44,8 @@ impl XdgShellHandler for State { state.states.set(xdg_toplevel::State::TiledRight); }); - let window = WindowElement::Wayland(Window::new_wayland_window(surface.clone())); + let window = WindowElement::new(Window::new_wayland_window(surface.clone())); self.new_windows.push(window); - - // if let (Some(output), _) | (None, Some(output)) = ( - // &self.focus_state.focused_output, - // self.space.outputs().next(), - // ) { - // tracing::debug!("PLACING TOPLEVEL"); - // window.place_on_output(output); - // } - // - // // note to self: don't reorder this - // // TODO: fix it so that reordering this doesn't break stuff - // self.windows.push(window.clone()); - // - // self.space.map_element(window.clone(), (0, 0), true); - // - // let win_clone = window.clone(); - // - // // Let the initial configure happen before updating the windows - // self.schedule( - // move |_data| { - // if let WindowElement::Wayland(window) = &win_clone { - // let initial_configure_sent = - // compositor::with_states(window.toplevel().wl_surface(), |states| { - // states - // .data_map - // .get::() - // .expect("XdgToplevelSurfaceData wasn't in surface's data map") - // .lock() - // .expect("Failed to lock Mutex") - // .initial_configure_sent - // }); - // - // initial_configure_sent - // } else { - // true - // } - // }, - // |data| { - // data.state.apply_window_rules(&window); - // - // if let Some(focused_output) = data.state.focus_state.focused_output.clone() { - // data.state.update_windows(&focused_output); - // } - // - // data.state.loop_handle.insert_idle(move |data| { - // data.state - // .seat - // .get_keyboard() - // .expect("Seat had no keyboard") // FIXME: actually handle error - // .set_focus( - // &mut data.state, - // Some(FocusTarget::Window(window)), - // SERIAL_COUNTER.next_serial(), - // ); - // }); - // }, - // ); } fn toplevel_destroyed(&mut self, surface: ToplevelSurface) { @@ -138,8 +84,8 @@ impl XdgShellHandler for State { // TODO: self.space.raise_element(win, true); self.z_index_stack.set_focus(win.clone()); - if let WindowElement::Wayland(win) = &win { - win.toplevel().expect("in wayland enum").send_configure(); + if let Some(toplevel) = win.toplevel() { + toplevel.send_configure(); } } self.seat @@ -733,27 +679,6 @@ impl XdgShellHandler for State { } } - // fn ack_configure(&mut self, surface: WlSurface, configure: Configure) { - // if let Some(window) = self.window_for_surface(&surface) { - // if let LocationRequestState::Requested(serial, new_loc) = - // window.with_state(|state| state.loc_request_state.clone()) - // { - // match &configure { - // Configure::Toplevel(configure) => { - // if configure.serial >= serial { - // tracing::debug!("acked configure, new loc is {:?}", new_loc); - // window.with_state(|state| { - // state.loc_request_state = - // LocationRequestState::Acknowledged(new_loc); - // }); - // } - // } - // Configure::Popup(_) => todo!(), - // } - // } - // } - // } - fn fullscreen_request(&mut self, surface: ToplevelSurface, mut wl_output: Option) { if !surface .current_state() diff --git a/src/handlers/xwayland.rs b/src/handlers/xwayland.rs index 4e5a4f5..37f4c78 100644 --- a/src/handlers/xwayland.rs +++ b/src/handlers/xwayland.rs @@ -1,13 +1,15 @@ // SPDX-License-Identifier: GPL-3.0-or-later use smithay::{ + desktop::Window, utils::{Logical, Point, Rectangle, SERIAL_COUNTER}, wayland::{ - selection::data_device::{ - clear_data_device_selection, current_data_device_selection_userdata, - request_data_device_client_selection, set_data_device_selection, - }, + seat::WaylandFocus, selection::{ + data_device::{ + clear_data_device_selection, current_data_device_selection_userdata, + request_data_device_client_selection, set_data_device_selection, + }, primary_selection::{ clear_primary_selection, current_primary_selection_userdata, request_primary_client_selection, set_primary_selection, @@ -36,12 +38,12 @@ impl XwmHandler for State { fn new_override_redirect_window(&mut self, _xwm: XwmId, _window: X11Surface) {} - fn map_window_request(&mut self, _xwm: XwmId, window: X11Surface) { + fn map_window_request(&mut self, _xwm: XwmId, surface: X11Surface) { tracing::trace!("map_window_request"); - assert!(!window.is_override_redirect()); + assert!(!surface.is_override_redirect()); - let window = WindowElement::X11(window); + let window = WindowElement::new(Window::new_x11_window(surface)); self.space.map_element(window.clone(), (0, 0), true); let bbox = self .space @@ -70,7 +72,7 @@ impl XwmHandler for State { ) .into(); - let WindowElement::X11(surface) = &window else { + let Some(surface) = window.x11_surface() else { unreachable!() }; @@ -122,14 +124,14 @@ impl XwmHandler for State { }); } - fn mapped_override_redirect_window(&mut self, _xwm: XwmId, window: X11Surface) { + fn mapped_override_redirect_window(&mut self, _xwm: XwmId, surface: X11Surface) { tracing::trace!("mapped_override_redirect_window"); - assert!(window.is_override_redirect()); + assert!(surface.is_override_redirect()); - let loc = window.geometry().loc; + let loc = surface.geometry().loc; - let window = WindowElement::X11OverrideRedirect(window); + let window = WindowElement::new(Window::new_x11_window(surface)); self.windows.push(window.clone()); self.z_index_stack.set_focus(window.clone()); @@ -139,18 +141,20 @@ impl XwmHandler for State { self.space.outputs().next(), ) { window.place_on_output(output); + // FIXME: setting focus here may possibly muck things up + // | or maybe they won't idk output.with_state(|state| state.focus_stack.set_focus(window.clone())) } self.space.map_element(window, loc, true); } - fn unmapped_window(&mut self, _xwm: XwmId, window: X11Surface) { + fn unmapped_window(&mut self, _xwm: XwmId, surface: X11Surface) { for output in self.space.outputs() { output.with_state(|state| { state.focus_stack.stack.retain(|win| { win.wl_surface() - .is_some_and(|surf| Some(surf) != window.wl_surface()) + .is_some_and(|surf| Some(surf) != surface.wl_surface()) }) }); } @@ -158,7 +162,7 @@ impl XwmHandler for State { let win = self .space .elements() - .find(|elem| matches!(elem, WindowElement::X11(surface) if surface == &window)) + .find(|elem| matches!(elem.x11_surface(), Some(surf) if surf == &surface)) .cloned(); if let Some(win) = win { @@ -178,8 +182,8 @@ impl XwmHandler for State { if let Some(FocusTarget::Window(win)) = &focus { self.space.raise_element(win, true); self.z_index_stack.set_focus(win.clone()); - if let WindowElement::Wayland(win) = &win { - win.toplevel().expect("in wayland enum").send_configure(); + if let Some(toplevel) = win.toplevel() { + toplevel.send_configure(); } } @@ -192,18 +196,18 @@ impl XwmHandler for State { } } - if !window.is_override_redirect() { + if !surface.is_override_redirect() { tracing::debug!("set mapped to false"); - window.set_mapped(false).expect("failed to unmap x11 win"); + surface.set_mapped(false).expect("failed to unmap x11 win"); } } - fn destroyed_window(&mut self, _xwm: XwmId, window: X11Surface) { + fn destroyed_window(&mut self, _xwm: XwmId, surface: X11Surface) { for output in self.space.outputs() { output.with_state(|state| { state.focus_stack.stack.retain(|win| { win.wl_surface() - .is_some_and(|surf| Some(surf) != window.wl_surface()) + .is_some_and(|surf| Some(surf) != surface.wl_surface()) }) }); } @@ -213,10 +217,8 @@ impl XwmHandler for State { .iter() .find(|elem| { matches!( - elem, - WindowElement::X11(surface) - | WindowElement::X11OverrideRedirect(surface) - if surface.wl_surface() == window.wl_surface() + elem.x11_surface(), + Some(surf) if surf.wl_surface() == surface.wl_surface() ) }) .cloned(); @@ -241,8 +243,8 @@ impl XwmHandler for State { if let Some(FocusTarget::Window(win)) = &focus { self.space.raise_element(win, true); self.z_index_stack.set_focus(win.clone()); - if let WindowElement::Wayland(win) = &win { - win.toplevel().expect("in wayland enum").send_configure(); + if let Some(toplevel) = win.toplevel() { + toplevel.send_configure(); } } @@ -283,14 +285,14 @@ impl XwmHandler for State { fn configure_notify( &mut self, _xwm: XwmId, - window: X11Surface, + surface: X11Surface, geometry: Rectangle, _above: Option, ) { let Some(win) = self .space .elements() - .find(|elem| matches!(elem, WindowElement::X11(surface) if surface == &window)) + .find(|elem| matches!(elem.x11_surface(), Some(surf) if surf == &surface)) .cloned() else { return; @@ -409,11 +411,12 @@ impl XwmHandler for State { .get_keyboard() .and_then(|kb| kb.current_focus()) .is_some_and(|focus| { - if let FocusTarget::Window(WindowElement::X11(surface)) = focus { - surface.xwm_id().expect("x11surface had no xwm id") == xwm - } else { - false + if let FocusTarget::Window(window) = focus { + if let Some(surface) = window.x11_surface() { + return surface.xwm_id().expect("x11surface had no xwm id") == xwm; + } } + false }) } diff --git a/src/input.rs b/src/input.rs index e40d2e4..d669aff 100644 --- a/src/input.rs +++ b/src/input.rs @@ -4,7 +4,7 @@ pub mod libinput; use std::{collections::HashMap, mem::Discriminant}; -use crate::{focus::FocusTarget, state::WithState, window::WindowElement}; +use crate::{focus::FocusTarget, state::WithState}; use pinnacle_api_defs::pinnacle::input::v0alpha1::{ set_libinput_setting_request::Setting, set_mousebind_request, SetKeybindResponse, SetMousebindResponse, @@ -351,14 +351,14 @@ impl State { if !matches!( &focus, - FocusTarget::Window(WindowElement::X11OverrideRedirect(_)) + FocusTarget::Window(window) if window.is_x11_override_redirect() ) { keyboard.set_focus(self, Some(focus.clone()), serial); } for window in self.space.elements() { - if let WindowElement::Wayland(window) = window { - window.toplevel().expect("in wayland enum").send_configure(); + if let Some(toplevel) = window.toplevel() { + toplevel.send_configure(); } } } else { @@ -367,8 +367,8 @@ impl State { state.focus_stack.unset_focus(); for window in state.focus_stack.stack.iter() { window.set_activate(false); - if let WindowElement::Wayland(window) = window { - window.toplevel().expect("in wayland enum").send_configure(); + if let Some(toplevel) = window.toplevel() { + toplevel.send_configure(); } } }); diff --git a/src/layout.rs b/src/layout.rs index 5bacc9e..f806fa7 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later use smithay::{ - desktop::layer_map_for_output, + desktop::{layer_map_for_output, WindowSurface}, output::Output, utils::{Logical, Point, Rectangle, Serial, Size}, wayland::{compositor, shell::xdg::XdgToplevelSurfaceData}, @@ -115,26 +115,20 @@ impl State { for win in windows_on_foc_tags.iter() { if win.with_state(|state| state.target_loc.is_some()) { - match win { - WindowElement::Wayland(wl_win) => { - let pending = compositor::with_states( - wl_win.toplevel().expect("in wayland enum").wl_surface(), - |states| { - states - .data_map - .get::() - .expect("XdgToplevelSurfaceData wasn't in surface's data map") - .lock() - .expect("Failed to lock Mutex") - .has_pending_changes() - }, - ); + match win.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + let pending = compositor::with_states(toplevel.wl_surface(), |states| { + states + .data_map + .get::() + .expect("XdgToplevelSurfaceData wasn't in surface's data map") + .lock() + .expect("Failed to lock Mutex") + .has_pending_changes() + }); if pending { - pending_wins.push(( - win.clone(), - wl_win.toplevel().expect("in wayland enum").send_configure(), - )) + pending_wins.push((win.clone(), toplevel.send_configure())) } else { let loc = win.with_state(|state| state.target_loc.take()); if let Some(loc) = loc { @@ -142,14 +136,12 @@ impl State { } } } - WindowElement::X11(_) => { + WindowSurface::X11(_) => { let loc = win.with_state(|state| state.target_loc.take()); if let Some(loc) = loc { self.space.map_element(win.clone(), loc, false); } } - WindowElement::X11OverrideRedirect(_) => (), - _ => unreachable!(), } } } diff --git a/src/render.rs b/src/render.rs index 849aebd..d09ea5c 100644 --- a/src/render.rs +++ b/src/render.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-or-later -use std::sync::Mutex; +use std::{ops::Deref, sync::Mutex}; use smithay::{ backend::renderer::{ @@ -71,18 +71,8 @@ where scale: Scale, alpha: f32, ) -> Vec { - match self { - WindowElement::Wayland(window) => { - window.render_elements(renderer, location, scale, alpha) - } - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - surface.render_elements(renderer, location, scale, alpha) - } - _ => unreachable!(), - } - .into_iter() - .map(C::from) - .collect() + self.deref() + .render_elements(renderer, location, scale, alpha) } } @@ -307,10 +297,8 @@ where let top_fullscreen_window = windows.iter().rev().find(|win| { let is_wayland_actually_fullscreen = { - if let WindowElement::Wayland(window) = win { - window - .toplevel() - .expect("in wayland enum") + if let Some(toplevel) = win.toplevel() { + toplevel .current_state() .states .contains(xdg_toplevel::State::Fullscreen) diff --git a/src/window.rs b/src/window.rs index eeff825..149cee6 100644 --- a/src/window.rs +++ b/src/window.rs @@ -2,40 +2,23 @@ pub mod rules; -use std::{cell::RefCell, time::Duration}; +use std::{cell::RefCell, ops::Deref}; use pinnacle_api_defs::pinnacle::signal::v0alpha1::{ WindowPointerEnterResponse, WindowPointerLeaveResponse, }; use smithay::{ backend::input::KeyState, - desktop::{ - utils::{ - send_dmabuf_feedback_surface_tree, send_frames_surface_tree, - take_presentation_feedback_surface_tree, with_surfaces_surface_tree, - OutputPresentationFeedback, - }, - Window, - }, + desktop::{space::SpaceElement, Window, WindowSurface}, input::{ keyboard::{KeyboardTarget, KeysymHandle, ModifiersState}, pointer::{AxisFrame, MotionEvent, PointerTarget}, Seat, }, output::Output, - reexports::{ - wayland_protocols::wp::presentation_time::server::wp_presentation_feedback, - wayland_server::protocol::wl_surface::WlSurface, - }, - space_elements, - utils::{user_data::UserDataMap, Logical, Rectangle, Serial}, - wayland::{ - compositor::{self, SurfaceData}, - dmabuf::DmabufFeedback, - seat::WaylandFocus, - shell::xdg::XdgToplevelSurfaceData, - }, - xwayland::X11Surface, + reexports::wayland_server::protocol::wl_surface::WlSurface, + utils::{IsAlive, Logical, Point, Rectangle, Serial}, + wayland::{compositor, seat::WaylandFocus, shell::xdg::XdgToplevelSurfaceData}, }; use crate::state::{State, WithState}; @@ -44,143 +27,20 @@ use self::window_state::WindowElementState; pub mod window_state; -space_elements! { - /// The different types of windows. - #[derive(Debug, Clone, PartialEq)] - pub WindowElement; - /// This is a native Wayland window. - Wayland = Window, - /// This is an Xwayland window. - X11 = X11Surface, - /// This is an Xwayland override redirect window, which should not be messed with. - X11OverrideRedirect = X11Surface, +#[derive(Debug, Clone, PartialEq)] +pub struct WindowElement(Window); + +impl Deref for WindowElement { + type Target = Window; + + fn deref(&self) -> &Self::Target { + &self.0 + } } impl WindowElement { - pub fn with_surfaces(&self, processor: F) - where - F: FnMut(&WlSurface, &SurfaceData) + Copy, - { - match self { - WindowElement::Wayland(window) => window.with_surfaces(processor), - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - if let Some(surface) = surface.wl_surface() { - with_surfaces_surface_tree(&surface, processor); - } - } - _ => unreachable!(), - } - } - - pub fn send_frame( - &self, - output: &Output, - time: T, - throttle: Option, - primary_scan_out_output: F, - ) where - T: Into, - F: FnMut(&WlSurface, &SurfaceData) -> Option + Copy, - { - match self { - WindowElement::Wayland(window) => { - window.send_frame(output, time, throttle, primary_scan_out_output) - } - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - if let Some(surface) = surface.wl_surface() { - send_frames_surface_tree( - &surface, - output, - time, - throttle, - primary_scan_out_output, - ); - } - } - _ => unreachable!(), - } - } - - pub fn send_dmabuf_feedback<'a, P, F>( - &self, - output: &Output, - primary_scan_out_output: P, - select_dmabuf_feedback: F, - ) where - P: FnMut(&WlSurface, &SurfaceData) -> Option + Copy, - F: Fn(&WlSurface, &SurfaceData) -> &'a DmabufFeedback + Copy, - { - match self { - WindowElement::Wayland(window) => { - window.send_dmabuf_feedback( - output, - primary_scan_out_output, - select_dmabuf_feedback, - ); - } - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - if let Some(surface) = surface.wl_surface() { - send_dmabuf_feedback_surface_tree( - &surface, - output, - primary_scan_out_output, - select_dmabuf_feedback, - ); - } - } - _ => unreachable!(), - } - } - - pub fn take_presentation_feedback( - &self, - output_feedback: &mut OutputPresentationFeedback, - primary_scan_out_output: F1, - presentation_feedback_flags: F2, - ) where - F1: FnMut(&WlSurface, &SurfaceData) -> Option + Copy, - F2: FnMut(&WlSurface, &SurfaceData) -> wp_presentation_feedback::Kind + Copy, - { - match self { - WindowElement::Wayland(window) => { - window.take_presentation_feedback( - output_feedback, - primary_scan_out_output, - presentation_feedback_flags, - ); - } - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - if let Some(surface) = surface.wl_surface() { - take_presentation_feedback_surface_tree( - &surface, - output_feedback, - primary_scan_out_output, - presentation_feedback_flags, - ); - } - } - _ => unreachable!(), - } - } - - pub fn wl_surface(&self) -> Option { - match self { - WindowElement::Wayland(window) => window.wl_surface(), - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - surface.wl_surface() - } - _ => unreachable!(), - } - } - - pub fn user_data(&self) -> &UserDataMap { - match self { - WindowElement::Wayland(window) => window.user_data(), - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - surface.user_data() - } - _ => unreachable!(), - } + pub fn new(window: Window) -> Self { + Self(window) } /// Send a geometry change without mapping windows or sending @@ -191,16 +51,13 @@ impl WindowElement { /// RefCell Safety: This method uses a [`RefCell`] on this window. // TODO: ^ does that make things flicker? pub fn change_geometry(&self, new_geo: Rectangle) { - match self { - WindowElement::Wayland(window) => { - window - .toplevel() - .expect("in wayland enum") - .with_pending_state(|state| { - state.size = Some(new_geo.size); - }); + match self.0.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + toplevel.with_pending_state(|state| { + state.size = Some(new_geo.size); + }); } - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { + WindowSurface::X11(surface) => { // TODO: maybe move this check elsewhere idk if !surface.is_override_redirect() { surface @@ -208,21 +65,16 @@ impl WindowElement { .expect("failed to configure x11 win"); } } - _ => unreachable!(), } self.with_state(|state| { state.target_loc = Some(new_geo.loc); }); - // self.with_state(|state| { - // state.loc_request_state = LocationRequestState::Sent(new_geo.loc); - // }); } pub fn class(&self) -> Option { - match self { - WindowElement::Wayland(window) => compositor::with_states( - window.toplevel().expect("in wayland enum").wl_surface(), - |states| { + match self.0.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + compositor::with_states(toplevel.wl_surface(), |states| { states .data_map .get::() @@ -231,20 +83,16 @@ impl WindowElement { .expect("Failed to lock Mutex") .app_id .clone() - }, - ), - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - Some(surface.class()) + }) } - _ => unreachable!(), + WindowSurface::X11(surface) => Some(surface.class()), } } pub fn title(&self) -> Option { - match self { - WindowElement::Wayland(window) => compositor::with_states( - window.toplevel().expect("in wayland enum").wl_surface(), - |states| { + match self.0.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + compositor::with_states(toplevel.wl_surface(), |states| { states .data_map .get::() @@ -253,12 +101,9 @@ impl WindowElement { .expect("Failed to lock Mutex") .title .clone() - }, - ), - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - Some(surface.title()) + }) } - _ => unreachable!(), + WindowSurface::X11(surface) => Some(surface.title()), } } @@ -312,58 +157,67 @@ impl WindowElement { }); } - /// Returns `true` if the window element is [`Wayland`]. - /// - /// [`Wayland`]: WindowElement::Wayland - #[must_use] - pub fn is_wayland(&self) -> bool { - matches!(self, Self::Wayland(..)) - } - - /// Returns `true` if the window element is [`X11`]. - /// - /// [`X11`]: WindowElement::X11 - #[must_use] - pub fn is_x11(&self) -> bool { - matches!(self, Self::X11(..)) - } - - /// Returns `true` if the window element is [`X11OverrideRedirect`]. - /// - /// [`X11OverrideRedirect`]: WindowElement::X11OverrideRedirect - #[must_use] pub fn is_x11_override_redirect(&self) -> bool { - matches!(self, Self::X11OverrideRedirect(..)) + matches!(self.x11_surface(), Some(surface) if surface.is_override_redirect()) + } +} + +impl SpaceElement for WindowElement { + fn bbox(&self) -> Rectangle { + self.0.bbox() + } + + fn is_in_input_region(&self, point: &Point) -> bool { + self.0.is_in_input_region(point) + } + + fn set_activate(&self, activated: bool) { + self.0.set_activate(activated) + } + + fn output_enter(&self, output: &Output, overlap: Rectangle) { + self.0.output_enter(output, overlap) + } + + fn output_leave(&self, output: &Output) { + self.0.output_leave(output) + } + + fn geometry(&self) -> Rectangle { + self.0.geometry() + } + + fn z_index(&self) -> u8 { + self.0.z_index() + } + + fn refresh(&self) { + self.0.refresh(); + } +} + +impl IsAlive for WindowElement { + fn alive(&self) -> bool { + self.0.alive() } } impl PointerTarget for WindowElement { fn frame(&self, seat: &Seat, state: &mut State) { - match self { - WindowElement::Wayland(window) => window - .wl_surface() - .expect("in wayland enum") - .frame(seat, state), - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - surface.frame(seat, state) + match self.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + PointerTarget::frame(toplevel.wl_surface(), seat, state); } - _ => unreachable!(), + WindowSurface::X11(surface) => PointerTarget::frame(surface, seat, state), } } fn enter(&self, seat: &Seat, state: &mut State, event: &MotionEvent) { - // TODO: ssd - match self { - WindowElement::Wayland(window) => PointerTarget::enter( - &window.wl_surface().expect("in wayland enum"), - seat, - state, - event, - ), - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - PointerTarget::enter(surface, seat, state, event) + match self.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + PointerTarget::enter(toplevel.wl_surface(), seat, state, event); } - _ => unreachable!(), + WindowSurface::X11(surface) => PointerTarget::enter(surface, seat, state, event), } let window_id = Some(self.with_state(|state| state.id.0)); @@ -375,18 +229,11 @@ impl PointerTarget for WindowElement { } fn motion(&self, seat: &Seat, state: &mut State, event: &MotionEvent) { - // TODO: ssd - match self { - WindowElement::Wayland(window) => PointerTarget::motion( - &window.wl_surface().expect("in wayland enum"), - seat, - state, - event, - ), - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - PointerTarget::motion(surface, seat, state, event) + match self.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + PointerTarget::motion(toplevel.wl_surface(), seat, state, event); } - _ => unreachable!(), + WindowSurface::X11(surface) => PointerTarget::motion(surface, seat, state, event), } } @@ -396,20 +243,13 @@ impl PointerTarget for WindowElement { state: &mut State, event: &smithay::input::pointer::RelativeMotionEvent, ) { - // TODO: ssd - match self { - WindowElement::Wayland(window) => { - PointerTarget::relative_motion( - &window.wl_surface().expect("in wayland enum"), - seat, - state, - event, - ); + match self.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + PointerTarget::relative_motion(toplevel.wl_surface(), seat, state, event); } - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { + WindowSurface::X11(surface) => { PointerTarget::relative_motion(surface, seat, state, event); } - _ => unreachable!(), } } @@ -419,53 +259,29 @@ impl PointerTarget for WindowElement { state: &mut State, event: &smithay::input::pointer::ButtonEvent, ) { - // TODO: ssd - match self { - WindowElement::Wayland(window) => PointerTarget::button( - &window.wl_surface().expect("in wayland enum"), - seat, - state, - event, - ), - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - PointerTarget::button(surface, seat, state, event) + match self.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + PointerTarget::button(toplevel.wl_surface(), seat, state, event); } - _ => unreachable!(), + WindowSurface::X11(surface) => PointerTarget::button(surface, seat, state, event), } } fn axis(&self, seat: &Seat, state: &mut State, frame: AxisFrame) { - // TODO: ssd - match self { - WindowElement::Wayland(window) => PointerTarget::axis( - &window.wl_surface().expect("in wayland enum"), - seat, - state, - frame, - ), - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - PointerTarget::axis(surface, seat, state, frame) + match self.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + PointerTarget::axis(toplevel.wl_surface(), seat, state, frame); } - _ => unreachable!(), + WindowSurface::X11(surface) => PointerTarget::axis(surface, seat, state, frame), } } fn leave(&self, seat: &Seat, state: &mut State, serial: Serial, time: u32) { - // TODO: ssd - match self { - WindowElement::Wayland(window) => { - PointerTarget::leave( - &window.wl_surface().expect("in wayland enum"), - seat, - state, - serial, - time, - ); + match self.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + PointerTarget::leave(toplevel.wl_surface(), seat, state, serial, time); } - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - PointerTarget::leave(surface, seat, state, serial, time) - } - _ => unreachable!(), + WindowSurface::X11(surface) => PointerTarget::leave(surface, seat, state, serial, time), } let window_id = Some(self.with_state(|state| state.id.0)); @@ -557,35 +373,22 @@ impl KeyboardTarget for WindowElement { keys: Vec>, serial: Serial, ) { - match self { - WindowElement::Wayland(window) => { - KeyboardTarget::enter( - &window.wl_surface().expect("in wayland enum"), - seat, - state, - keys, - serial, - ); + match self.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + KeyboardTarget::enter(toplevel.wl_surface(), seat, state, keys, serial); } - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - KeyboardTarget::enter(surface, seat, state, keys, serial) + WindowSurface::X11(surface) => { + KeyboardTarget::enter(surface, seat, state, keys, serial); } - _ => unreachable!(), } } fn leave(&self, seat: &Seat, state: &mut State, serial: Serial) { - match self { - WindowElement::Wayland(window) => KeyboardTarget::leave( - &window.wl_surface().expect("in wayland enum"), - seat, - state, - serial, - ), - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - KeyboardTarget::leave(surface, seat, state, serial) + match self.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + KeyboardTarget::leave(toplevel.wl_surface(), seat, state, serial); } - _ => unreachable!(), + WindowSurface::X11(surface) => KeyboardTarget::leave(surface, seat, state, serial), } } @@ -598,10 +401,10 @@ impl KeyboardTarget for WindowElement { serial: Serial, time: u32, ) { - match self { - WindowElement::Wayland(window) => { + match self.underlying_surface() { + WindowSurface::Wayland(toplevel) => { KeyboardTarget::key( - &window.wl_surface().expect("in wayland enum"), + toplevel.wl_surface(), seat, state, key, @@ -610,10 +413,9 @@ impl KeyboardTarget for WindowElement { time, ); } - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { + WindowSurface::X11(surface) => { KeyboardTarget::key(surface, seat, state, key, key_state, serial, time); } - _ => unreachable!(), } } @@ -624,20 +426,13 @@ impl KeyboardTarget for WindowElement { modifiers: ModifiersState, serial: Serial, ) { - match self { - WindowElement::Wayland(window) => { - KeyboardTarget::modifiers( - &window.wl_surface().expect("in wayland enum"), - seat, - state, - modifiers, - serial, - ); + match self.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + KeyboardTarget::modifiers(toplevel.wl_surface(), seat, state, modifiers, serial); } - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { + WindowSurface::X11(surface) => { KeyboardTarget::modifiers(surface, seat, state, modifiers, serial); } - _ => unreachable!(), } } } @@ -663,12 +458,18 @@ impl State { self.space .elements() .find(|window| window.wl_surface().map(|s| s == *surface).unwrap_or(false)) - .cloned() .or_else(|| { self.windows .iter() .find(|&win| win.wl_surface().is_some_and(|surf| &surf == surface)) - .cloned() }) + .cloned() + } + + pub fn new_window_for_surface(&self, surface: &WlSurface) -> Option { + self.new_windows + .iter() + .find(|&win| win.wl_surface().is_some_and(|surf| &surf == surface)) + .cloned() } } diff --git a/src/window/window_state.rs b/src/window/window_state.rs index 6df4710..9284bcf 100644 --- a/src/window/window_state.rs +++ b/src/window/window_state.rs @@ -3,7 +3,7 @@ use std::sync::atomic::{AtomicU32, Ordering}; use smithay::{ - desktop::space::SpaceElement, + desktop::{space::SpaceElement, WindowSurface}, reexports::wayland_protocols::xdg::shell::server::xdg_toplevel, utils::{Logical, Point, Rectangle}, }; @@ -81,30 +81,27 @@ impl WindowElement { state.fullscreen_or_maximized = FullscreenOrMaximized::Fullscreen; }); - match self { - WindowElement::Wayland(window) => { - window - .toplevel() - .expect("in wayland enum") - .with_pending_state(|state| { - state.states.unset(xdg_toplevel::State::Maximized); - state.states.set(xdg_toplevel::State::Fullscreen); - state.states.set(xdg_toplevel::State::TiledTop); - state.states.set(xdg_toplevel::State::TiledLeft); - state.states.set(xdg_toplevel::State::TiledBottom); - state.states.set(xdg_toplevel::State::TiledRight); - }); + match self.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + toplevel.with_pending_state(|state| { + state.states.unset(xdg_toplevel::State::Maximized); + state.states.set(xdg_toplevel::State::Fullscreen); + state.states.set(xdg_toplevel::State::TiledTop); + state.states.set(xdg_toplevel::State::TiledLeft); + state.states.set(xdg_toplevel::State::TiledBottom); + state.states.set(xdg_toplevel::State::TiledRight); + }); } - WindowElement::X11(surface) => { - surface - .set_maximized(false) - .expect("failed to set x11 win to maximized"); - surface - .set_fullscreen(true) - .expect("failed to set x11 win to not fullscreen"); + WindowSurface::X11(surface) => { + if !surface.is_override_redirect() { + surface + .set_maximized(false) + .expect("failed to set x11 win to maximized"); + surface + .set_fullscreen(true) + .expect("failed to set x11 win to not fullscreen"); + } } - WindowElement::X11OverrideRedirect(_) => (), - _ => unreachable!(), } } FullscreenOrMaximized::Fullscreen => { @@ -131,30 +128,27 @@ impl WindowElement { state.fullscreen_or_maximized = FullscreenOrMaximized::Maximized; }); - match self { - WindowElement::Wayland(window) => { - window - .toplevel() - .expect("in wayland enum") - .with_pending_state(|state| { - state.states.set(xdg_toplevel::State::Maximized); - state.states.unset(xdg_toplevel::State::Fullscreen); - state.states.set(xdg_toplevel::State::TiledTop); - state.states.set(xdg_toplevel::State::TiledLeft); - state.states.set(xdg_toplevel::State::TiledBottom); - state.states.set(xdg_toplevel::State::TiledRight); - }); + match self.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + toplevel.with_pending_state(|state| { + state.states.set(xdg_toplevel::State::Maximized); + state.states.unset(xdg_toplevel::State::Fullscreen); + state.states.set(xdg_toplevel::State::TiledTop); + state.states.set(xdg_toplevel::State::TiledLeft); + state.states.set(xdg_toplevel::State::TiledBottom); + state.states.set(xdg_toplevel::State::TiledRight); + }); } - WindowElement::X11(surface) => { - surface - .set_maximized(true) - .expect("failed to set x11 win to maximized"); - surface - .set_fullscreen(false) - .expect("failed to set x11 win to not fullscreen"); + WindowSurface::X11(surface) => { + if !surface.is_override_redirect() { + surface + .set_maximized(true) + .expect("failed to set x11 win to maximized"); + surface + .set_fullscreen(false) + .expect("failed to set x11 win to not fullscreen"); + } } - WindowElement::X11OverrideRedirect(_) => (), - _ => unreachable!(), } } FullscreenOrMaximized::Maximized => { @@ -176,60 +170,54 @@ impl WindowElement { /// Unsets maximized and fullscreen states for both wayland and xwayland windows /// and unsets tiled states for wayland windows. fn set_floating_states(&self) { - match self { - WindowElement::Wayland(window) => { - window - .toplevel() - .expect("in wayland enum") - .with_pending_state(|state| { - state.states.unset(xdg_toplevel::State::Maximized); - state.states.unset(xdg_toplevel::State::Fullscreen); - state.states.unset(xdg_toplevel::State::TiledTop); - state.states.unset(xdg_toplevel::State::TiledLeft); - state.states.unset(xdg_toplevel::State::TiledBottom); - state.states.unset(xdg_toplevel::State::TiledRight); - }); + match self.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + toplevel.with_pending_state(|state| { + state.states.unset(xdg_toplevel::State::Maximized); + state.states.unset(xdg_toplevel::State::Fullscreen); + state.states.unset(xdg_toplevel::State::TiledTop); + state.states.unset(xdg_toplevel::State::TiledLeft); + state.states.unset(xdg_toplevel::State::TiledBottom); + state.states.unset(xdg_toplevel::State::TiledRight); + }); } - WindowElement::X11(surface) => { - surface - .set_maximized(false) - .expect("failed to set x11 win to maximized"); - surface - .set_fullscreen(false) - .expect("failed to set x11 win to not fullscreen"); + WindowSurface::X11(surface) => { + if !surface.is_override_redirect() { + surface + .set_maximized(false) + .expect("failed to set x11 win to maximized"); + surface + .set_fullscreen(false) + .expect("failed to set x11 win to not fullscreen"); + } } - WindowElement::X11OverrideRedirect(_) => (), - _ => unreachable!(), } } /// Unsets maximized and fullscreen states for both wayland and xwayland windows /// and sets tiled states for wayland windows. fn set_tiled_states(&self) { - match self { - WindowElement::Wayland(window) => { - window - .toplevel() - .expect("in wayland enum") - .with_pending_state(|state| { - state.states.unset(xdg_toplevel::State::Maximized); - state.states.unset(xdg_toplevel::State::Fullscreen); - state.states.set(xdg_toplevel::State::TiledTop); - state.states.set(xdg_toplevel::State::TiledLeft); - state.states.set(xdg_toplevel::State::TiledBottom); - state.states.set(xdg_toplevel::State::TiledRight); - }); + match self.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + toplevel.with_pending_state(|state| { + state.states.unset(xdg_toplevel::State::Maximized); + state.states.unset(xdg_toplevel::State::Fullscreen); + state.states.set(xdg_toplevel::State::TiledTop); + state.states.set(xdg_toplevel::State::TiledLeft); + state.states.set(xdg_toplevel::State::TiledBottom); + state.states.set(xdg_toplevel::State::TiledRight); + }); } - WindowElement::X11(surface) => { - surface - .set_maximized(false) - .expect("failed to set x11 win to maximized"); - surface - .set_fullscreen(false) - .expect("failed to set x11 win to not fullscreen"); + WindowSurface::X11(surface) => { + if !surface.is_override_redirect() { + surface + .set_maximized(false) + .expect("failed to set x11 win to maximized"); + surface + .set_fullscreen(false) + .expect("failed to set x11 win to not fullscreen"); + } } - WindowElement::X11OverrideRedirect(_) => (), - _ => unreachable!(), } } } From 8c429f4077da898fedfd3438cc227d237e6a17c3 Mon Sep 17 00:00:00 2001 From: Ottatop Date: Fri, 1 Mar 2024 00:07:01 -0600 Subject: [PATCH 3/3] Split `FocusTarget` into keyboard and pointer variants --- src/api.rs | 28 ++- src/focus.rs | 367 +------------------------------- src/focus/keyboard.rs | 230 ++++++++++++++++++++ src/focus/pointer.rs | 428 ++++++++++++++++++++++++++++++++++++++ src/grab.rs | 16 +- src/grab/move_grab.rs | 11 +- src/grab/resize_grab.rs | 2 +- src/handlers.rs | 10 +- src/handlers/xdg_shell.rs | 12 +- src/handlers/xwayland.rs | 18 +- src/input.rs | 71 +++++-- src/window.rs | 246 +--------------------- 12 files changed, 768 insertions(+), 671 deletions(-) create mode 100644 src/focus/keyboard.rs create mode 100644 src/focus/pointer.rs diff --git a/src/api.rs b/src/api.rs index 499c7cc..5e96b94 100644 --- a/src/api.rs +++ b/src/api.rs @@ -52,7 +52,7 @@ use tracing::{error, warn}; use crate::{ config::ConnectorSavedState, - focus::FocusTarget, + focus::keyboard::KeyboardFocusTarget, input::ModifierMask, output::OutputName, state::{State, WithState}, @@ -1379,7 +1379,7 @@ impl window_service_server::WindowService for WindowService { if let Some(keyboard) = state.seat.get_keyboard() { keyboard.set_focus( state, - Some(FocusTarget::Window(window)), + Some(KeyboardFocusTarget::Window(window)), SERIAL_COUNTER.next_serial(), ); } @@ -1407,7 +1407,7 @@ impl window_service_server::WindowService for WindowService { if let Some(keyboard) = state.seat.get_keyboard() { keyboard.set_focus( state, - Some(FocusTarget::Window(window)), + Some(KeyboardFocusTarget::Window(window)), SERIAL_COUNTER.next_serial(), ); } @@ -1518,12 +1518,17 @@ impl window_service_server::WindowService for WindowService { .ok_or_else(|| Status::invalid_argument("no button specified"))?; run_unary_no_response(&self.sender, move |state| { - let Some((FocusTarget::Window(window), _)) = - state.focus_target_under(state.pointer_location) + let Some((pointer_focus, _)) = state.pointer_focus_target_under(state.pointer_location) else { return; }; - let Some(wl_surf) = window.wl_surface() else { return }; + let Some(window) = pointer_focus.window_for(state) else { + tracing::info!("Move grabs are currently not implemented for non-windows"); + return; + }; + let Some(wl_surf) = window.wl_surface() else { + return; + }; let seat = state.seat.clone(); crate::grab::move_grab::move_request_server( @@ -1549,12 +1554,17 @@ impl window_service_server::WindowService for WindowService { run_unary_no_response(&self.sender, move |state| { let pointer_loc = state.pointer_location; - let Some((FocusTarget::Window(window), window_loc)) = - state.focus_target_under(pointer_loc) + let Some((pointer_focus, window_loc)) = state.pointer_focus_target_under(pointer_loc) else { return; }; - let Some(wl_surf) = window.wl_surface() else { return }; + let Some(window) = pointer_focus.window_for(state) else { + tracing::info!("Move grabs are currently not implemented for non-windows"); + return; + }; + let Some(wl_surf) = window.wl_surface() else { + return; + }; let window_geometry = window.geometry(); let window_x = window_loc.x as f64; diff --git a/src/focus.rs b/src/focus.rs index 62fb430..ad6f46b 100644 --- a/src/focus.rs +++ b/src/focus.rs @@ -1,24 +1,15 @@ // SPDX-License-Identifier: GPL-3.0-or-later -use smithay::{ - desktop::{LayerSurface, PopupKind}, - input::{ - keyboard::KeyboardTarget, - pointer::{MotionEvent, PointerTarget}, - touch::{self, TouchTarget}, - Seat, - }, - output::Output, - reexports::wayland_server::{protocol::wl_surface::WlSurface, Resource}, - utils::{IsAlive, Serial, SERIAL_COUNTER}, - wayland::seat::WaylandFocus, -}; +use smithay::{output::Output, utils::SERIAL_COUNTER}; use crate::{ state::{State, WithState}, window::WindowElement, }; +pub mod keyboard; +pub mod pointer; + impl State { /// Get the currently focused window on `output` /// that isn't an override redirect window, if any. @@ -111,353 +102,3 @@ impl FocusStack { self.focused.then(|| self.stack.last())? } } - -/// Different focusable objects. -#[derive(Debug, Clone, PartialEq)] -pub enum FocusTarget { - Window(WindowElement), - Popup(PopupKind), - LayerSurface(LayerSurface), -} - -impl IsAlive for FocusTarget { - fn alive(&self) -> bool { - match self { - FocusTarget::Window(window) => window.alive(), - FocusTarget::Popup(popup) => popup.alive(), - FocusTarget::LayerSurface(surf) => surf.alive(), - } - } -} - -impl TryFrom for WlSurface { - type Error = (); - - fn try_from(value: FocusTarget) -> Result { - value.wl_surface().ok_or(()) - } -} - -impl PointerTarget for FocusTarget { - fn frame(&self, seat: &Seat, data: &mut State) { - match self { - FocusTarget::Window(window) => PointerTarget::frame(window, seat, data), - FocusTarget::Popup(popup) => PointerTarget::frame(popup.wl_surface(), seat, data), - FocusTarget::LayerSurface(surf) => PointerTarget::frame(surf.wl_surface(), seat, data), - } - } - - fn enter(&self, seat: &Seat, data: &mut State, event: &MotionEvent) { - match self { - FocusTarget::Window(window) => PointerTarget::enter(window, seat, data, event), - FocusTarget::Popup(popup) => { - PointerTarget::enter(popup.wl_surface(), seat, data, event); - } - FocusTarget::LayerSurface(surf) => { - PointerTarget::enter(surf.wl_surface(), seat, data, event) - } - } - } - - fn motion(&self, seat: &Seat, data: &mut State, event: &MotionEvent) { - match self { - FocusTarget::Window(window) => PointerTarget::motion(window, seat, data, event), - FocusTarget::Popup(popup) => { - PointerTarget::motion(popup.wl_surface(), seat, data, event); - } - FocusTarget::LayerSurface(surf) => { - PointerTarget::motion(surf.wl_surface(), seat, data, event) - } - } - } - - fn relative_motion( - &self, - seat: &Seat, - data: &mut State, - event: &smithay::input::pointer::RelativeMotionEvent, - ) { - match self { - FocusTarget::Window(window) => { - PointerTarget::relative_motion(window, seat, data, event); - } - FocusTarget::Popup(popup) => { - PointerTarget::relative_motion(popup.wl_surface(), seat, data, event); - } - FocusTarget::LayerSurface(surf) => { - PointerTarget::relative_motion(surf.wl_surface(), seat, data, event); - } - } - } - - fn button( - &self, - seat: &Seat, - data: &mut State, - event: &smithay::input::pointer::ButtonEvent, - ) { - match self { - FocusTarget::Window(window) => PointerTarget::button(window, seat, data, event), - FocusTarget::Popup(popup) => { - PointerTarget::button(popup.wl_surface(), seat, data, event); - } - FocusTarget::LayerSurface(surf) => { - PointerTarget::button(surf.wl_surface(), seat, data, event) - } - } - } - - fn axis( - &self, - seat: &Seat, - data: &mut State, - frame: smithay::input::pointer::AxisFrame, - ) { - match self { - FocusTarget::Window(window) => PointerTarget::axis(window, seat, data, frame), - FocusTarget::Popup(popup) => PointerTarget::axis(popup.wl_surface(), seat, data, frame), - FocusTarget::LayerSurface(surf) => { - PointerTarget::axis(surf.wl_surface(), seat, data, frame) - } - } - } - - fn leave(&self, seat: &Seat, data: &mut State, serial: Serial, time: u32) { - match self { - FocusTarget::Window(window) => PointerTarget::leave(window, seat, data, serial, time), - FocusTarget::Popup(popup) => { - PointerTarget::leave(popup.wl_surface(), seat, data, serial, time); - } - FocusTarget::LayerSurface(surf) => { - PointerTarget::leave(surf.wl_surface(), seat, data, serial, time) - } - } - } - - fn gesture_swipe_begin( - &self, - _seat: &Seat, - _data: &mut State, - _event: &smithay::input::pointer::GestureSwipeBeginEvent, - ) { - todo!() - } - - fn gesture_swipe_update( - &self, - _seat: &Seat, - _data: &mut State, - _event: &smithay::input::pointer::GestureSwipeUpdateEvent, - ) { - todo!() - } - - fn gesture_swipe_end( - &self, - _seat: &Seat, - _data: &mut State, - _event: &smithay::input::pointer::GestureSwipeEndEvent, - ) { - todo!() - } - - fn gesture_pinch_begin( - &self, - _seat: &Seat, - _data: &mut State, - _event: &smithay::input::pointer::GesturePinchBeginEvent, - ) { - todo!() - } - - fn gesture_pinch_update( - &self, - _seat: &Seat, - _data: &mut State, - _event: &smithay::input::pointer::GesturePinchUpdateEvent, - ) { - todo!() - } - - fn gesture_pinch_end( - &self, - _seat: &Seat, - _data: &mut State, - _event: &smithay::input::pointer::GesturePinchEndEvent, - ) { - todo!() - } - - fn gesture_hold_begin( - &self, - _seat: &Seat, - _data: &mut State, - _event: &smithay::input::pointer::GestureHoldBeginEvent, - ) { - todo!() - } - - fn gesture_hold_end( - &self, - _seat: &Seat, - _data: &mut State, - _event: &smithay::input::pointer::GestureHoldEndEvent, - ) { - todo!() - } -} - -impl KeyboardTarget for FocusTarget { - fn enter( - &self, - seat: &Seat, - data: &mut State, - keys: Vec>, - serial: Serial, - ) { - match self { - FocusTarget::Window(window) => KeyboardTarget::enter(window, seat, data, keys, serial), - FocusTarget::Popup(popup) => { - KeyboardTarget::enter(popup.wl_surface(), seat, data, keys, serial); - } - FocusTarget::LayerSurface(surf) => { - KeyboardTarget::enter(surf.wl_surface(), seat, data, keys, serial); - } - } - } - - fn leave(&self, seat: &Seat, data: &mut State, serial: Serial) { - match self { - FocusTarget::Window(window) => KeyboardTarget::leave(window, seat, data, serial), - FocusTarget::Popup(popup) => { - KeyboardTarget::leave(popup.wl_surface(), seat, data, serial); - } - FocusTarget::LayerSurface(surf) => { - KeyboardTarget::leave(surf.wl_surface(), seat, data, serial) - } - } - } - - fn key( - &self, - seat: &Seat, - data: &mut State, - key: smithay::input::keyboard::KeysymHandle<'_>, - state: smithay::backend::input::KeyState, - serial: Serial, - time: u32, - ) { - match self { - FocusTarget::Window(window) => { - KeyboardTarget::key(window, seat, data, key, state, serial, time); - } - FocusTarget::Popup(popup) => { - KeyboardTarget::key(popup.wl_surface(), seat, data, key, state, serial, time); - } - FocusTarget::LayerSurface(surf) => { - KeyboardTarget::key(surf.wl_surface(), seat, data, key, state, serial, time); - } - } - } - - fn modifiers( - &self, - seat: &Seat, - data: &mut State, - modifiers: smithay::input::keyboard::ModifiersState, - serial: Serial, - ) { - match self { - FocusTarget::Window(window) => { - KeyboardTarget::modifiers(window, seat, data, modifiers, serial); - } - FocusTarget::Popup(popup) => { - KeyboardTarget::modifiers(popup.wl_surface(), seat, data, modifiers, serial); - } - FocusTarget::LayerSurface(surf) => { - KeyboardTarget::modifiers(surf.wl_surface(), seat, data, modifiers, serial); - } - } - } -} - -impl TouchTarget for FocusTarget { - fn down(&self, seat: &Seat, data: &mut State, event: &touch::DownEvent, seq: Serial) { - todo!() - } - - fn up(&self, seat: &Seat, data: &mut State, event: &touch::UpEvent, seq: Serial) { - todo!() - } - - fn motion( - &self, - seat: &Seat, - data: &mut State, - event: &touch::MotionEvent, - seq: Serial, - ) { - todo!() - } - - fn frame(&self, seat: &Seat, data: &mut State, seq: Serial) { - todo!() - } - - fn cancel(&self, seat: &Seat, data: &mut State, seq: Serial) { - todo!() - } - - fn shape(&self, seat: &Seat, data: &mut State, event: &touch::ShapeEvent, seq: Serial) { - todo!() - } - - fn orientation( - &self, - seat: &Seat, - data: &mut State, - event: &touch::OrientationEvent, - seq: Serial, - ) { - todo!() - } -} - -impl WaylandFocus for FocusTarget { - fn wl_surface(&self) -> Option { - match self { - FocusTarget::Window(window) => window.wl_surface(), - FocusTarget::Popup(popup) => Some(popup.wl_surface().clone()), - FocusTarget::LayerSurface(surf) => Some(surf.wl_surface().clone()), - } - } - - fn same_client_as( - &self, - object_id: &smithay::reexports::wayland_server::backend::ObjectId, - ) -> bool { - match self { - FocusTarget::Window(window) => window.same_client_as(object_id), - FocusTarget::Popup(popup) => popup.wl_surface().id().same_client_as(object_id), - FocusTarget::LayerSurface(surf) => surf.wl_surface().id().same_client_as(object_id), - } - } -} - -impl From for FocusTarget { - fn from(value: WindowElement) -> Self { - FocusTarget::Window(value) - } -} - -impl From for FocusTarget { - fn from(value: PopupKind) -> Self { - FocusTarget::Popup(value) - } -} - -impl From for FocusTarget { - fn from(value: LayerSurface) -> Self { - FocusTarget::LayerSurface(value) - } -} diff --git a/src/focus/keyboard.rs b/src/focus/keyboard.rs new file mode 100644 index 0000000..63363e9 --- /dev/null +++ b/src/focus/keyboard.rs @@ -0,0 +1,230 @@ +use smithay::{ + backend::input::KeyState, + desktop::{LayerSurface, PopupKind, WindowSurface}, + input::{ + keyboard::{KeyboardTarget, KeysymHandle, ModifiersState}, + Seat, + }, + reexports::wayland_server::{protocol::wl_surface::WlSurface, Resource}, + utils::{IsAlive, Serial}, + wayland::seat::WaylandFocus, +}; + +use crate::{state::State, window::WindowElement}; + +/// Keyboard focusable objects +#[derive(Debug, Clone, PartialEq)] +pub enum KeyboardFocusTarget { + Window(WindowElement), + Popup(PopupKind), + LayerSurface(LayerSurface), +} + +impl KeyboardTarget for KeyboardFocusTarget { + fn enter( + &self, + seat: &Seat, + data: &mut State, + keys: Vec>, + serial: Serial, + ) { + match self { + KeyboardFocusTarget::Window(window) => { + KeyboardTarget::enter(window, seat, data, keys, serial) + } + KeyboardFocusTarget::Popup(popup) => { + KeyboardTarget::enter(popup.wl_surface(), seat, data, keys, serial); + } + KeyboardFocusTarget::LayerSurface(surf) => { + KeyboardTarget::enter(surf.wl_surface(), seat, data, keys, serial); + } + } + } + + fn leave(&self, seat: &Seat, data: &mut State, serial: Serial) { + match self { + KeyboardFocusTarget::Window(window) => { + KeyboardTarget::leave(window, seat, data, serial) + } + KeyboardFocusTarget::Popup(popup) => { + KeyboardTarget::leave(popup.wl_surface(), seat, data, serial); + } + KeyboardFocusTarget::LayerSurface(surf) => { + KeyboardTarget::leave(surf.wl_surface(), seat, data, serial) + } + } + } + + fn key( + &self, + seat: &Seat, + data: &mut State, + key: KeysymHandle<'_>, + state: smithay::backend::input::KeyState, + serial: Serial, + time: u32, + ) { + match self { + KeyboardFocusTarget::Window(window) => { + KeyboardTarget::key(window, seat, data, key, state, serial, time); + } + KeyboardFocusTarget::Popup(popup) => { + KeyboardTarget::key(popup.wl_surface(), seat, data, key, state, serial, time); + } + KeyboardFocusTarget::LayerSurface(surf) => { + KeyboardTarget::key(surf.wl_surface(), seat, data, key, state, serial, time); + } + } + } + + fn modifiers( + &self, + seat: &Seat, + data: &mut State, + modifiers: smithay::input::keyboard::ModifiersState, + serial: Serial, + ) { + match self { + KeyboardFocusTarget::Window(window) => { + KeyboardTarget::modifiers(window, seat, data, modifiers, serial); + } + KeyboardFocusTarget::Popup(popup) => { + KeyboardTarget::modifiers(popup.wl_surface(), seat, data, modifiers, serial); + } + KeyboardFocusTarget::LayerSurface(surf) => { + KeyboardTarget::modifiers(surf.wl_surface(), seat, data, modifiers, serial); + } + } + } +} + +impl IsAlive for KeyboardFocusTarget { + fn alive(&self) -> bool { + match self { + KeyboardFocusTarget::Window(window) => window.alive(), + KeyboardFocusTarget::Popup(popup) => popup.alive(), + KeyboardFocusTarget::LayerSurface(surf) => surf.alive(), + } + } +} + +impl WaylandFocus for KeyboardFocusTarget { + fn wl_surface(&self) -> Option { + match self { + KeyboardFocusTarget::Window(window) => window.wl_surface(), + KeyboardFocusTarget::Popup(popup) => Some(popup.wl_surface().clone()), + KeyboardFocusTarget::LayerSurface(surf) => Some(surf.wl_surface().clone()), + } + } + + fn same_client_as( + &self, + object_id: &smithay::reexports::wayland_server::backend::ObjectId, + ) -> bool { + match self { + KeyboardFocusTarget::Window(window) => window.same_client_as(object_id), + KeyboardFocusTarget::Popup(popup) => popup.wl_surface().id().same_client_as(object_id), + KeyboardFocusTarget::LayerSurface(surf) => { + surf.wl_surface().id().same_client_as(object_id) + } + } + } +} + +impl TryFrom for WlSurface { + type Error = (); + + fn try_from(value: KeyboardFocusTarget) -> Result { + value.wl_surface().ok_or(()) + } +} + +impl From for KeyboardFocusTarget { + fn from(value: WindowElement) -> Self { + KeyboardFocusTarget::Window(value) + } +} + +impl From for KeyboardFocusTarget { + fn from(value: PopupKind) -> Self { + KeyboardFocusTarget::Popup(value) + } +} + +impl From for KeyboardFocusTarget { + fn from(value: LayerSurface) -> Self { + KeyboardFocusTarget::LayerSurface(value) + } +} + +impl KeyboardTarget for WindowElement { + fn enter( + &self, + seat: &Seat, + state: &mut State, + keys: Vec>, + serial: Serial, + ) { + match self.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + KeyboardTarget::enter(toplevel.wl_surface(), seat, state, keys, serial); + } + WindowSurface::X11(surface) => { + KeyboardTarget::enter(surface, seat, state, keys, serial); + } + } + } + + fn leave(&self, seat: &Seat, state: &mut State, serial: Serial) { + match self.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + KeyboardTarget::leave(toplevel.wl_surface(), seat, state, serial); + } + WindowSurface::X11(surface) => KeyboardTarget::leave(surface, seat, state, serial), + } + } + + fn key( + &self, + seat: &Seat, + state: &mut State, + key: KeysymHandle<'_>, + key_state: KeyState, + serial: Serial, + time: u32, + ) { + match self.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + KeyboardTarget::key( + toplevel.wl_surface(), + seat, + state, + key, + key_state, + serial, + time, + ); + } + WindowSurface::X11(surface) => { + KeyboardTarget::key(surface, seat, state, key, key_state, serial, time); + } + } + } + + fn modifiers( + &self, + seat: &Seat, + state: &mut State, + modifiers: ModifiersState, + serial: Serial, + ) { + match self.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + KeyboardTarget::modifiers(toplevel.wl_surface(), seat, state, modifiers, serial); + } + WindowSurface::X11(surface) => { + KeyboardTarget::modifiers(surface, seat, state, modifiers, serial); + } + } + } +} diff --git a/src/focus/pointer.rs b/src/focus/pointer.rs new file mode 100644 index 0000000..b507782 --- /dev/null +++ b/src/focus/pointer.rs @@ -0,0 +1,428 @@ +use pinnacle_api_defs::pinnacle::signal::v0alpha1::{ + WindowPointerEnterResponse, WindowPointerLeaveResponse, +}; +use smithay::{ + desktop::{ + layer_map_for_output, utils::with_surfaces_surface_tree, LayerSurface, PopupKind, + WindowSurface, + }, + input::{ + pointer::{self, PointerTarget}, + touch::{self, TouchTarget}, + Seat, + }, + reexports::wayland_server::{backend::ObjectId, protocol::wl_surface::WlSurface}, + utils::{IsAlive, Serial}, + wayland::seat::WaylandFocus, + xwayland::X11Surface, +}; + +use crate::{ + state::{State, WithState}, + window::WindowElement, +}; + +use super::keyboard::KeyboardFocusTarget; + +#[derive(Debug, Clone, PartialEq)] +pub enum PointerFocusTarget { + WlSurface(WlSurface), + X11Surface(X11Surface), +} + +impl PointerFocusTarget { + /// If the pointer focus's surface is owned by a window, get that window. + pub fn window_for(&self, state: &State) -> Option { + match self { + PointerFocusTarget::WlSurface(surf) => state + .windows + .iter() + .find(|win| { + let Some(surface) = win.wl_surface() else { + return false; + }; + let mut found = false; + with_surfaces_surface_tree(&surface, |surface, _| { + if surface == surf { + found = true; + } + }); + found + }) + .cloned(), + PointerFocusTarget::X11Surface(surf) => state + .windows + .iter() + .find(|win| win.x11_surface() == Some(surf)) + .cloned(), + } + } + + pub fn layer_for(&self, state: &State) -> Option { + match self { + PointerFocusTarget::WlSurface(surf) => { + for output in state.space.outputs() { + let map = layer_map_for_output(output); + for layer in map.layers() { + let mut found = false; + with_surfaces_surface_tree(layer.wl_surface(), |surface, _| { + if surface == surf { + found = true; + } + }); + if found { + return Some(layer.clone()); + } + } + } + None + } + PointerFocusTarget::X11Surface(_) => None, + } + } + + pub fn popup_for(&self, state: &State) -> Option { + match self { + PointerFocusTarget::WlSurface(surf) => state.popup_manager.find_popup(surf), + PointerFocusTarget::X11Surface(_) => None, + } + } + + pub fn to_keyboard_focus_target(&self, state: &State) -> Option { + #[allow(clippy::manual_map)] // screw off clippy + if let Some(window) = self.window_for(state) { + Some(KeyboardFocusTarget::Window(window)) + } else if let Some(layer) = self.layer_for(state) { + Some(KeyboardFocusTarget::LayerSurface(layer)) + } else if let Some(popup) = self.popup_for(state) { + Some(KeyboardFocusTarget::Popup(popup)) + } else { + None + } + } +} + +impl IsAlive for PointerFocusTarget { + fn alive(&self) -> bool { + match self { + PointerFocusTarget::WlSurface(surf) => surf.alive(), + PointerFocusTarget::X11Surface(surf) => surf.alive(), + } + } +} + +impl PointerTarget for PointerFocusTarget { + fn enter(&self, seat: &Seat, data: &mut State, event: &pointer::MotionEvent) { + match self { + PointerFocusTarget::WlSurface(surf) => PointerTarget::enter(surf, seat, data, event), + PointerFocusTarget::X11Surface(surf) => PointerTarget::enter(surf, seat, data, event), + } + + if let Some(window) = self.window_for(data) { + let window_id = Some(window.with_state(|state| state.id.0)); + + data.signal_state + .window_pointer_enter + .signal(|buffer| buffer.push_back(WindowPointerEnterResponse { window_id })); + } + } + + fn motion(&self, seat: &Seat, data: &mut State, event: &pointer::MotionEvent) { + match self { + PointerFocusTarget::WlSurface(surf) => PointerTarget::motion(surf, seat, data, event), + PointerFocusTarget::X11Surface(surf) => PointerTarget::motion(surf, seat, data, event), + } + } + + fn relative_motion( + &self, + seat: &Seat, + data: &mut State, + event: &pointer::RelativeMotionEvent, + ) { + match self { + PointerFocusTarget::WlSurface(surf) => { + PointerTarget::relative_motion(surf, seat, data, event); + } + PointerFocusTarget::X11Surface(surf) => { + PointerTarget::relative_motion(surf, seat, data, event); + } + } + } + + fn button(&self, seat: &Seat, data: &mut State, event: &pointer::ButtonEvent) { + match self { + PointerFocusTarget::WlSurface(surf) => PointerTarget::button(surf, seat, data, event), + PointerFocusTarget::X11Surface(surf) => PointerTarget::button(surf, seat, data, event), + } + } + + fn axis(&self, seat: &Seat, data: &mut State, frame: pointer::AxisFrame) { + match self { + PointerFocusTarget::WlSurface(surf) => PointerTarget::axis(surf, seat, data, frame), + PointerFocusTarget::X11Surface(surf) => PointerTarget::axis(surf, seat, data, frame), + } + } + + fn frame(&self, seat: &Seat, data: &mut State) { + match self { + PointerFocusTarget::WlSurface(surf) => PointerTarget::frame(surf, seat, data), + PointerFocusTarget::X11Surface(surf) => PointerTarget::frame(surf, seat, data), + } + } + + fn gesture_swipe_begin( + &self, + seat: &Seat, + data: &mut State, + event: &pointer::GestureSwipeBeginEvent, + ) { + match self { + PointerFocusTarget::WlSurface(surf) => { + PointerTarget::gesture_swipe_begin(surf, seat, data, event); + } + PointerFocusTarget::X11Surface(surf) => { + PointerTarget::gesture_swipe_begin(surf, seat, data, event); + } + } + } + + fn gesture_swipe_update( + &self, + seat: &Seat, + data: &mut State, + event: &pointer::GestureSwipeUpdateEvent, + ) { + match self { + PointerFocusTarget::WlSurface(surf) => { + PointerTarget::gesture_swipe_update(surf, seat, data, event); + } + PointerFocusTarget::X11Surface(surf) => { + PointerTarget::gesture_swipe_update(surf, seat, data, event); + } + } + } + + fn gesture_swipe_end( + &self, + seat: &Seat, + data: &mut State, + event: &pointer::GestureSwipeEndEvent, + ) { + match self { + PointerFocusTarget::WlSurface(surf) => { + PointerTarget::gesture_swipe_end(surf, seat, data, event); + } + PointerFocusTarget::X11Surface(surf) => { + PointerTarget::gesture_swipe_end(surf, seat, data, event); + } + } + } + + fn gesture_pinch_begin( + &self, + seat: &Seat, + data: &mut State, + event: &pointer::GesturePinchBeginEvent, + ) { + match self { + PointerFocusTarget::WlSurface(surf) => { + PointerTarget::gesture_pinch_begin(surf, seat, data, event); + } + PointerFocusTarget::X11Surface(surf) => { + PointerTarget::gesture_pinch_begin(surf, seat, data, event); + } + } + } + + fn gesture_pinch_update( + &self, + seat: &Seat, + data: &mut State, + event: &pointer::GesturePinchUpdateEvent, + ) { + match self { + PointerFocusTarget::WlSurface(surf) => { + PointerTarget::gesture_pinch_update(surf, seat, data, event); + } + PointerFocusTarget::X11Surface(surf) => { + PointerTarget::gesture_pinch_update(surf, seat, data, event); + } + } + } + + fn gesture_pinch_end( + &self, + seat: &Seat, + data: &mut State, + event: &pointer::GesturePinchEndEvent, + ) { + match self { + PointerFocusTarget::WlSurface(surf) => { + PointerTarget::gesture_pinch_end(surf, seat, data, event); + } + PointerFocusTarget::X11Surface(surf) => { + PointerTarget::gesture_pinch_end(surf, seat, data, event); + } + } + } + + fn gesture_hold_begin( + &self, + seat: &Seat, + data: &mut State, + event: &pointer::GestureHoldBeginEvent, + ) { + match self { + PointerFocusTarget::WlSurface(surf) => { + PointerTarget::gesture_hold_begin(surf, seat, data, event); + } + PointerFocusTarget::X11Surface(surf) => { + PointerTarget::gesture_hold_begin(surf, seat, data, event); + } + } + } + + fn gesture_hold_end( + &self, + seat: &Seat, + data: &mut State, + event: &pointer::GestureHoldEndEvent, + ) { + match self { + PointerFocusTarget::WlSurface(surf) => { + PointerTarget::gesture_hold_end(surf, seat, data, event); + } + PointerFocusTarget::X11Surface(surf) => { + PointerTarget::gesture_hold_end(surf, seat, data, event); + } + } + } + + fn leave(&self, seat: &Seat, data: &mut State, serial: Serial, time: u32) { + match self { + PointerFocusTarget::WlSurface(surf) => { + PointerTarget::leave(surf, seat, data, serial, time); + } + PointerFocusTarget::X11Surface(surf) => { + PointerTarget::leave(surf, seat, data, serial, time); + } + } + + if let Some(window) = self.window_for(data) { + let window_id = Some(window.with_state(|state| state.id.0)); + + data.signal_state + .window_pointer_leave + .signal(|buffer| buffer.push_back(WindowPointerLeaveResponse { window_id })); + } + } +} + +impl TouchTarget for PointerFocusTarget { + fn down(&self, seat: &Seat, data: &mut State, event: &touch::DownEvent, seq: Serial) { + match self { + PointerFocusTarget::WlSurface(surf) => TouchTarget::down(surf, seat, data, event, seq), + PointerFocusTarget::X11Surface(surf) => TouchTarget::down(surf, seat, data, event, seq), + } + } + + fn up(&self, seat: &Seat, data: &mut State, event: &touch::UpEvent, seq: Serial) { + match self { + PointerFocusTarget::WlSurface(surf) => TouchTarget::up(surf, seat, data, event, seq), + PointerFocusTarget::X11Surface(surf) => TouchTarget::up(surf, seat, data, event, seq), + } + } + + fn motion( + &self, + seat: &Seat, + data: &mut State, + event: &touch::MotionEvent, + seq: Serial, + ) { + match self { + PointerFocusTarget::WlSurface(surf) => { + TouchTarget::motion(surf, seat, data, event, seq); + } + PointerFocusTarget::X11Surface(surf) => { + TouchTarget::motion(surf, seat, data, event, seq); + } + } + } + + fn frame(&self, seat: &Seat, data: &mut State, seq: Serial) { + match self { + PointerFocusTarget::WlSurface(surf) => TouchTarget::frame(surf, seat, data, seq), + PointerFocusTarget::X11Surface(surf) => TouchTarget::frame(surf, seat, data, seq), + } + } + + fn cancel(&self, seat: &Seat, data: &mut State, seq: Serial) { + match self { + PointerFocusTarget::WlSurface(surf) => TouchTarget::cancel(surf, seat, data, seq), + PointerFocusTarget::X11Surface(surf) => TouchTarget::cancel(surf, seat, data, seq), + } + } + + fn shape(&self, seat: &Seat, data: &mut State, event: &touch::ShapeEvent, seq: Serial) { + match self { + PointerFocusTarget::WlSurface(surf) => TouchTarget::shape(surf, seat, data, event, seq), + PointerFocusTarget::X11Surface(surf) => { + TouchTarget::shape(surf, seat, data, event, seq); + } + } + } + + fn orientation( + &self, + seat: &Seat, + data: &mut State, + event: &touch::OrientationEvent, + seq: Serial, + ) { + match self { + PointerFocusTarget::WlSurface(surf) => { + TouchTarget::orientation(surf, seat, data, event, seq); + } + PointerFocusTarget::X11Surface(surf) => { + TouchTarget::orientation(surf, seat, data, event, seq); + } + } + } +} + +impl WaylandFocus for PointerFocusTarget { + fn wl_surface(&self) -> Option { + match self { + PointerFocusTarget::WlSurface(surf) => Some(surf.clone()), + PointerFocusTarget::X11Surface(surf) => surf.wl_surface(), + } + } + + fn same_client_as(&self, object_id: &ObjectId) -> bool { + match self { + PointerFocusTarget::WlSurface(surf) => surf.same_client_as(object_id), + PointerFocusTarget::X11Surface(surf) => surf.same_client_as(object_id), + } + } +} + +impl From for PointerFocusTarget { + fn from(target: KeyboardFocusTarget) -> Self { + match target { + KeyboardFocusTarget::Window(window) => match window.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + PointerFocusTarget::WlSurface(toplevel.wl_surface().clone()) + } + WindowSurface::X11(surface) => PointerFocusTarget::X11Surface(surface.clone()), + }, + KeyboardFocusTarget::Popup(popup) => { + PointerFocusTarget::WlSurface(popup.wl_surface().clone()) + } + KeyboardFocusTarget::LayerSurface(layer) => { + PointerFocusTarget::WlSurface(layer.wl_surface().clone()) + } + } + } +} diff --git a/src/grab.rs b/src/grab.rs index 2aa97f5..4cd5117 100644 --- a/src/grab.rs +++ b/src/grab.rs @@ -4,26 +4,20 @@ pub mod move_grab; pub mod resize_grab; use smithay::{ - input::{ - pointer::{GrabStartData, PointerHandle}, - SeatHandler, - }, + input::pointer::{GrabStartData, PointerHandle}, reexports::wayland_server::{protocol::wl_surface::WlSurface, Resource}, utils::Serial, wayland::seat::WaylandFocus, }; -use crate::focus::FocusTarget; +use crate::state::State; /// Returns the [GrabStartData] from a pointer grab, if any. -pub fn pointer_grab_start_data( - pointer: &PointerHandle, +pub fn pointer_grab_start_data( + pointer: &PointerHandle, surface: &WlSurface, serial: Serial, -) -> Option> -where - S: SeatHandler + 'static, -{ +) -> Option> { tracing::debug!("start of pointer_grab_start_data"); if !pointer.has_grab(serial) { tracing::debug!("pointer doesn't have grab"); diff --git a/src/grab/move_grab.rs b/src/grab/move_grab.rs index 579b767..5aa2aa2 100644 --- a/src/grab/move_grab.rs +++ b/src/grab/move_grab.rs @@ -6,14 +6,13 @@ use smithay::{ // | input::keyboard input::{ pointer::{ - AxisFrame, ButtonEvent, GrabStartData, MotionEvent, PointerInnerHandle, - RelativeMotionEvent, + AxisFrame, ButtonEvent, Focus, GrabStartData, MotionEvent, PointerGrab, + PointerInnerHandle, RelativeMotionEvent, }, - pointer::{Focus, PointerGrab}, Seat, SeatHandler, }, reexports::wayland_server::protocol::wl_surface::WlSurface, - utils::{IsAlive, Logical, Point, Rectangle}, + utils::{IsAlive, Logical, Point, Rectangle, Serial}, }; use crate::{ @@ -270,7 +269,7 @@ pub fn move_request_client( state: &mut State, surface: &WlSurface, seat: &Seat, - serial: smithay::utils::Serial, + serial: Serial, button_used: u32, ) { let pointer = seat.get_pointer().expect("seat had no pointer"); @@ -303,7 +302,7 @@ pub fn move_request_server( state: &mut State, surface: &WlSurface, seat: &Seat, - serial: smithay::utils::Serial, + serial: Serial, button_used: u32, ) { let pointer = seat.get_pointer().expect("seat had no pointer"); diff --git a/src/grab/resize_grab.rs b/src/grab/resize_grab.rs index 09d9552..3516e0f 100644 --- a/src/grab/resize_grab.rs +++ b/src/grab/resize_grab.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later use smithay::{ - desktop::{space::SpaceElement, utils::bbox_from_surface_tree, WindowSurface}, + desktop::{space::SpaceElement, WindowSurface}, input::{ pointer::{AxisFrame, ButtonEvent, Focus, GrabStartData, PointerGrab, PointerInnerHandle}, Seat, SeatHandler, diff --git a/src/handlers.rs b/src/handlers.rs index e7177f2..1f5903a 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -58,7 +58,7 @@ use smithay::{ }; use crate::{ - focus::FocusTarget, + focus::{keyboard::KeyboardFocusTarget, pointer::PointerFocusTarget}, state::{ClientState, State, WithState}, }; @@ -176,7 +176,7 @@ impl CompositorHandler for State { .expect("Seat had no keyboard") // FIXME: actually handle error .set_focus( state, - Some(FocusTarget::Window(new_window)), + Some(KeyboardFocusTarget::Window(new_window)), SERIAL_COUNTER.next_serial(), ); }); @@ -394,9 +394,9 @@ impl DataControlHandler for State { delegate_data_control!(State); impl SeatHandler for State { - type KeyboardFocus = FocusTarget; - type PointerFocus = FocusTarget; - type TouchFocus = FocusTarget; + type KeyboardFocus = KeyboardFocusTarget; + type PointerFocus = PointerFocusTarget; + type TouchFocus = PointerFocusTarget; fn seat_state(&mut self) -> &mut SeatState { &mut self.seat_state diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs index c0dd80a..e9714e9 100644 --- a/src/handlers/xdg_shell.rs +++ b/src/handlers/xdg_shell.rs @@ -26,7 +26,7 @@ use smithay::{ }; use crate::{ - focus::FocusTarget, + focus::keyboard::KeyboardFocusTarget, state::{State, WithState}, window::WindowElement, }; @@ -78,8 +78,10 @@ impl XdgShellHandler for State { if let Some(output) = window.output(self) { self.update_windows(&output); - let focus = self.focused_window(&output).map(FocusTarget::Window); - if let Some(FocusTarget::Window(win)) = &focus { + let focus = self + .focused_window(&output) + .map(KeyboardFocusTarget::Window); + if let Some(KeyboardFocusTarget::Window(win)) = &focus { tracing::debug!("Focusing on prev win"); // TODO: self.space.raise_element(win, true); @@ -638,13 +640,13 @@ impl XdgShellHandler for State { let popup_kind = PopupKind::Xdg(surface); if let Some(root) = find_popup_root_surface(&popup_kind).ok().and_then(|root| { self.window_for_surface(&root) - .map(FocusTarget::Window) + .map(KeyboardFocusTarget::Window) .or_else(|| { self.space.outputs().find_map(|op| { layer_map_for_output(op) .layer_for_surface(&root, WindowSurfaceType::TOPLEVEL) .cloned() - .map(FocusTarget::LayerSurface) + .map(KeyboardFocusTarget::LayerSurface) }) }) }) { diff --git a/src/handlers/xwayland.rs b/src/handlers/xwayland.rs index 37f4c78..04ef4b2 100644 --- a/src/handlers/xwayland.rs +++ b/src/handlers/xwayland.rs @@ -24,7 +24,7 @@ use smithay::{ }; use crate::{ - focus::FocusTarget, + focus::keyboard::KeyboardFocusTarget, state::{State, WithState}, window::{window_state::FloatingOrTiled, WindowElement}, }; @@ -118,7 +118,7 @@ impl XwmHandler for State { .expect("Seat had no keyboard") // FIXME: actually handle error .set_focus( state, - Some(FocusTarget::Window(window)), + Some(KeyboardFocusTarget::Window(window)), SERIAL_COUNTER.next_serial(), ); }); @@ -177,9 +177,11 @@ impl XwmHandler for State { if let Some(output) = win.output(self) { self.update_windows(&output); - let focus = self.focused_window(&output).map(FocusTarget::Window); + let focus = self + .focused_window(&output) + .map(KeyboardFocusTarget::Window); - if let Some(FocusTarget::Window(win)) = &focus { + if let Some(KeyboardFocusTarget::Window(win)) = &focus { self.space.raise_element(win, true); self.z_index_stack.set_focus(win.clone()); if let Some(toplevel) = win.toplevel() { @@ -238,9 +240,11 @@ impl XwmHandler for State { if let Some(output) = win.output(self) { self.update_windows(&output); - let focus = self.focused_window(&output).map(FocusTarget::Window); + let focus = self + .focused_window(&output) + .map(KeyboardFocusTarget::Window); - if let Some(FocusTarget::Window(win)) = &focus { + if let Some(KeyboardFocusTarget::Window(win)) = &focus { self.space.raise_element(win, true); self.z_index_stack.set_focus(win.clone()); if let Some(toplevel) = win.toplevel() { @@ -411,7 +415,7 @@ impl XwmHandler for State { .get_keyboard() .and_then(|kb| kb.current_focus()) .is_some_and(|focus| { - if let FocusTarget::Window(window) = focus { + if let KeyboardFocusTarget::Window(window) = focus { if let Some(surface) = window.x11_surface() { return surface.xwm_id().expect("x11surface had no xwm id") == xwm; } diff --git a/src/input.rs b/src/input.rs index d669aff..e8a1fb4 100644 --- a/src/input.rs +++ b/src/input.rs @@ -4,7 +4,7 @@ pub mod libinput; use std::{collections::HashMap, mem::Discriminant}; -use crate::{focus::FocusTarget, state::WithState}; +use crate::{focus::pointer::PointerFocusTarget, state::WithState}; use pinnacle_api_defs::pinnacle::input::v0alpha1::{ set_libinput_setting_request::Setting, set_mousebind_request, SetKeybindResponse, SetMousebindResponse, @@ -14,7 +14,7 @@ use smithay::{ AbsolutePositionEvent, Axis, AxisSource, ButtonState, Event, InputBackend, InputEvent, KeyState, KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent, PointerMotionEvent, }, - desktop::{layer_map_for_output, space::SpaceElement}, + desktop::{layer_map_for_output, space::SpaceElement, WindowSurfaceType}, input::{ keyboard::{keysyms, FilterResult, ModifiersState}, pointer::{AxisFrame, ButtonEvent, MotionEvent, RelativeMotionEvent}, @@ -148,8 +148,11 @@ impl State { } } - /// Get the [`FocusTarget`] under `point`. - pub fn focus_target_under

(&self, point: P) -> Option<(FocusTarget, Point)> + /// Get the [`PointerFocusTarget`] under `point` along with its origin in the global space. + pub fn pointer_focus_target_under

( + &self, + point: P, + ) -> Option<(PointerFocusTarget, Point)> where P: Into>, { @@ -185,14 +188,33 @@ impl State { }); if let Some(window) = top_fullscreen_window { - Some((FocusTarget::from(window.clone()), output_geo.loc)) + let loc = self + .space + .element_location(&window) + .expect("called elem loc on unmapped win") + - window.geometry().loc; + + window + .surface_under(point - loc.to_f64(), WindowSurfaceType::ALL) + .map(|(surf, surf_loc)| (PointerFocusTarget::WlSurface(surf), surf_loc + loc)) } else if let (Some(layer), _) | (None, Some(layer)) = ( layers.layer_under(wlr_layer::Layer::Overlay, point), layers.layer_under(wlr_layer::Layer::Top, point), ) { let layer_loc = layers.layer_geometry(layer).expect("no layer geo").loc; - Some((FocusTarget::from(layer.clone()), output_geo.loc + layer_loc)) - } else if let Some(ret) = self + + layer + .surface_under( + point - layer_loc.to_f64() - output_geo.loc.to_f64(), + WindowSurfaceType::ALL, + ) + .map(|(surf, surf_loc)| { + ( + PointerFocusTarget::WlSurface(surf), + surf_loc + layer_loc + output_geo.loc, + ) + }) + } else if let Some((surface, loc)) = self .space .elements() .rev() @@ -204,17 +226,28 @@ impl State { .expect("called elem loc on unmapped win") - win.geometry().loc; - win.is_in_input_region(&(point - loc.to_f64())) - .then(|| (win.clone().into(), loc)) + win.surface_under(point - loc.to_f64(), WindowSurfaceType::ALL) + .map(|(surf, surf_loc)| (surf, surf_loc + loc)) }) { - Some(ret) + Some((PointerFocusTarget::WlSurface(surface), loc)) } else if let (Some(layer), _) | (None, Some(layer)) = ( layers.layer_under(wlr_layer::Layer::Overlay, point), layers.layer_under(wlr_layer::Layer::Top, point), ) { let layer_loc = layers.layer_geometry(layer).expect("no layer geo").loc; - Some((FocusTarget::from(layer.clone()), output_geo.loc + layer_loc)) + + layer + .surface_under( + point - layer_loc.to_f64() - output_geo.loc.to_f64(), + WindowSurfaceType::ALL, + ) + .map(|(surf, surf_loc)| { + ( + PointerFocusTarget::WlSurface(surf), + surf_loc + layer_loc + output_geo.loc, + ) + }) } else { None } @@ -334,15 +367,15 @@ impl State { // If the button was clicked, focus on the window below if exists, else // unfocus on windows. if button_state == ButtonState::Pressed { - if let Some((focus, _)) = self.focus_target_under(pointer_loc) { + if let Some((focus, _)) = self.pointer_focus_target_under(pointer_loc) { // NOTE: *Do not* set keyboard focus to an override redirect window. This leads // | to wonky things like right-click menus not correctly getting pointer // | clicks or showing up at all. // TODO: use update_keyboard_focus from anvil - if let FocusTarget::Window(window) = &focus { - self.space.raise_element(window, true); + if let Some(window) = focus.window_for(self) { + self.space.raise_element(&window, true); self.z_index_stack.set_focus(window.clone()); if let Some(output) = window.output(self) { output.with_state(|state| state.focus_stack.set_focus(window.clone())); @@ -350,10 +383,10 @@ impl State { } if !matches!( - &focus, - FocusTarget::Window(window) if window.is_x11_override_redirect() + focus.window_for(self), + Some(window) if window.is_x11_override_redirect() ) { - keyboard.set_focus(self, Some(focus.clone()), serial); + keyboard.set_focus(self, focus.to_keyboard_focus_target(self), serial); } for window in self.space.elements() { @@ -496,7 +529,7 @@ impl State { pointer.motion( self, - self.focus_target_under(pointer_loc), + self.pointer_focus_target_under(pointer_loc), &MotionEvent { location: pointer_loc, serial, @@ -533,7 +566,7 @@ impl State { } } - let surface_under = self.focus_target_under(self.pointer_location); + let surface_under = self.pointer_focus_target_under(self.pointer_location); if let Some(pointer) = self.seat.get_pointer() { pointer.motion( diff --git a/src/window.rs b/src/window.rs index 149cee6..78554a7 100644 --- a/src/window.rs +++ b/src/window.rs @@ -4,20 +4,11 @@ pub mod rules; use std::{cell::RefCell, ops::Deref}; -use pinnacle_api_defs::pinnacle::signal::v0alpha1::{ - WindowPointerEnterResponse, WindowPointerLeaveResponse, -}; use smithay::{ - backend::input::KeyState, desktop::{space::SpaceElement, Window, WindowSurface}, - input::{ - keyboard::{KeyboardTarget, KeysymHandle, ModifiersState}, - pointer::{AxisFrame, MotionEvent, PointerTarget}, - Seat, - }, output::Output, reexports::wayland_server::protocol::wl_surface::WlSurface, - utils::{IsAlive, Logical, Point, Rectangle, Serial}, + utils::{IsAlive, Logical, Point, Rectangle}, wayland::{compositor, seat::WaylandFocus, shell::xdg::XdgToplevelSurfaceData}, }; @@ -202,241 +193,6 @@ impl IsAlive for WindowElement { } } -impl PointerTarget for WindowElement { - fn frame(&self, seat: &Seat, state: &mut State) { - match self.underlying_surface() { - WindowSurface::Wayland(toplevel) => { - PointerTarget::frame(toplevel.wl_surface(), seat, state); - } - WindowSurface::X11(surface) => PointerTarget::frame(surface, seat, state), - } - } - - fn enter(&self, seat: &Seat, state: &mut State, event: &MotionEvent) { - match self.underlying_surface() { - WindowSurface::Wayland(toplevel) => { - PointerTarget::enter(toplevel.wl_surface(), seat, state, event); - } - WindowSurface::X11(surface) => PointerTarget::enter(surface, seat, state, event), - } - - let window_id = Some(self.with_state(|state| state.id.0)); - - state - .signal_state - .window_pointer_enter - .signal(|buffer| buffer.push_back(WindowPointerEnterResponse { window_id })); - } - - fn motion(&self, seat: &Seat, state: &mut State, event: &MotionEvent) { - match self.underlying_surface() { - WindowSurface::Wayland(toplevel) => { - PointerTarget::motion(toplevel.wl_surface(), seat, state, event); - } - WindowSurface::X11(surface) => PointerTarget::motion(surface, seat, state, event), - } - } - - fn relative_motion( - &self, - seat: &Seat, - state: &mut State, - event: &smithay::input::pointer::RelativeMotionEvent, - ) { - match self.underlying_surface() { - WindowSurface::Wayland(toplevel) => { - PointerTarget::relative_motion(toplevel.wl_surface(), seat, state, event); - } - WindowSurface::X11(surface) => { - PointerTarget::relative_motion(surface, seat, state, event); - } - } - } - - fn button( - &self, - seat: &Seat, - state: &mut State, - event: &smithay::input::pointer::ButtonEvent, - ) { - match self.underlying_surface() { - WindowSurface::Wayland(toplevel) => { - PointerTarget::button(toplevel.wl_surface(), seat, state, event); - } - WindowSurface::X11(surface) => PointerTarget::button(surface, seat, state, event), - } - } - - fn axis(&self, seat: &Seat, state: &mut State, frame: AxisFrame) { - match self.underlying_surface() { - WindowSurface::Wayland(toplevel) => { - PointerTarget::axis(toplevel.wl_surface(), seat, state, frame); - } - WindowSurface::X11(surface) => PointerTarget::axis(surface, seat, state, frame), - } - } - - fn leave(&self, seat: &Seat, state: &mut State, serial: Serial, time: u32) { - match self.underlying_surface() { - WindowSurface::Wayland(toplevel) => { - PointerTarget::leave(toplevel.wl_surface(), seat, state, serial, time); - } - WindowSurface::X11(surface) => PointerTarget::leave(surface, seat, state, serial, time), - } - - let window_id = Some(self.with_state(|state| state.id.0)); - - state - .signal_state - .window_pointer_leave - .signal(|buffer| buffer.push_back(WindowPointerLeaveResponse { window_id })); - } - - fn gesture_swipe_begin( - &self, - _seat: &Seat, - _state: &mut State, - _event: &smithay::input::pointer::GestureSwipeBeginEvent, - ) { - todo!() - } - - fn gesture_swipe_update( - &self, - _seat: &Seat, - _state: &mut State, - _event: &smithay::input::pointer::GestureSwipeUpdateEvent, - ) { - todo!() - } - - fn gesture_swipe_end( - &self, - _seat: &Seat, - _state: &mut State, - _event: &smithay::input::pointer::GestureSwipeEndEvent, - ) { - todo!() - } - - fn gesture_pinch_begin( - &self, - _seat: &Seat, - _state: &mut State, - _event: &smithay::input::pointer::GesturePinchBeginEvent, - ) { - todo!() - } - - fn gesture_pinch_update( - &self, - _seat: &Seat, - _state: &mut State, - _event: &smithay::input::pointer::GesturePinchUpdateEvent, - ) { - todo!() - } - - fn gesture_pinch_end( - &self, - _seat: &Seat, - _state: &mut State, - _event: &smithay::input::pointer::GesturePinchEndEvent, - ) { - todo!() - } - - fn gesture_hold_begin( - &self, - _seat: &Seat, - _state: &mut State, - _event: &smithay::input::pointer::GestureHoldBeginEvent, - ) { - todo!() - } - - fn gesture_hold_end( - &self, - _seat: &Seat, - _state: &mut State, - _event: &smithay::input::pointer::GestureHoldEndEvent, - ) { - todo!() - } -} - -impl KeyboardTarget for WindowElement { - fn enter( - &self, - seat: &Seat, - state: &mut State, - keys: Vec>, - serial: Serial, - ) { - match self.underlying_surface() { - WindowSurface::Wayland(toplevel) => { - KeyboardTarget::enter(toplevel.wl_surface(), seat, state, keys, serial); - } - WindowSurface::X11(surface) => { - KeyboardTarget::enter(surface, seat, state, keys, serial); - } - } - } - - fn leave(&self, seat: &Seat, state: &mut State, serial: Serial) { - match self.underlying_surface() { - WindowSurface::Wayland(toplevel) => { - KeyboardTarget::leave(toplevel.wl_surface(), seat, state, serial); - } - WindowSurface::X11(surface) => KeyboardTarget::leave(surface, seat, state, serial), - } - } - - fn key( - &self, - seat: &Seat, - state: &mut State, - key: KeysymHandle<'_>, - key_state: KeyState, - serial: Serial, - time: u32, - ) { - match self.underlying_surface() { - WindowSurface::Wayland(toplevel) => { - KeyboardTarget::key( - toplevel.wl_surface(), - seat, - state, - key, - key_state, - serial, - time, - ); - } - WindowSurface::X11(surface) => { - KeyboardTarget::key(surface, seat, state, key, key_state, serial, time); - } - } - } - - fn modifiers( - &self, - seat: &Seat, - state: &mut State, - modifiers: ModifiersState, - serial: Serial, - ) { - match self.underlying_surface() { - WindowSurface::Wayland(toplevel) => { - KeyboardTarget::modifiers(toplevel.wl_surface(), seat, state, modifiers, serial); - } - WindowSurface::X11(surface) => { - KeyboardTarget::modifiers(surface, seat, state, modifiers, serial); - } - } - } -} - impl WithState for WindowElement { type State = WindowElementState;