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..5e96b94 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,15 +48,16 @@ use tokio::{ }; use tokio_stream::{Stream, StreamExt}; use tonic::{Request, Response, Status, Streaming}; +use tracing::{error, warn}; use crate::{ config::ConnectorSavedState, - focus::FocusTarget, + focus::keyboard::KeyboardFocusTarget, input::ModifierMask, 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,13 +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().send_close(), - WindowElement::X11(surface) => surface.close().expect("failed to close x11 win"), - WindowElement::X11OverrideRedirect(_) => { - tracing::warn!("tried to close override redirect window"); + 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"); + } } - _ => unreachable!(), } }) .await @@ -1354,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); } @@ -1392,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(), ); } @@ -1420,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(), ); } @@ -1430,8 +1417,8 @@ impl window_service_server::WindowService for WindowService { } for window in state.space.elements() { - if let WindowElement::Wayland(window) = window { - window.toplevel().send_configure(); + if let Some(toplevel) = window.toplevel() { + toplevel.send_configure(); } } @@ -1531,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( @@ -1562,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; @@ -1675,27 +1672,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/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..ad6f46b 100644 --- a/src/focus.rs +++ b/src/focus.rs @@ -1,23 +1,15 @@ // SPDX-License-Identifier: GPL-3.0-or-later -use smithay::{ - desktop::{LayerSurface, PopupKind}, - input::{ - keyboard::KeyboardTarget, - pointer::{MotionEvent, PointerTarget}, - Seat, - }, - output::Output, - reexports::wayland_server::{protocol::wl_surface::WlSurface, Resource}, - utils::{IsAlive, 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. @@ -55,8 +47,8 @@ impl State { if let Some(win) = ¤t_focus { assert!(!win.is_x11_override_redirect()); - if let WindowElement::Wayland(w) = win { - w.toplevel().send_configure(); + if let Some(toplevel) = win.toplevel() { + toplevel.send_configure(); } } @@ -110,309 +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) => window.frame(seat, data), - FocusTarget::Popup(popup) => popup.wl_surface().frame(seat, data), - FocusTarget::LayerSurface(surf) => surf.frame(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, 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, 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, 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, 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, seat, data, frame), - } - } - - fn leave( - &self, - seat: &Seat, - data: &mut State, - serial: smithay::utils::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), - } - } - - 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: smithay::utils::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, seat, data, keys, serial); - } - } - } - - fn leave(&self, seat: &Seat, data: &mut State, serial: smithay::utils::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), - } - } - - fn key( - &self, - seat: &Seat, - data: &mut State, - key: smithay::input::keyboard::KeysymHandle<'_>, - state: smithay::backend::input::KeyState, - serial: smithay::utils::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, seat, data, key, state, serial, time); - } - } - } - - fn modifiers( - &self, - seat: &Seat, - data: &mut State, - modifiers: smithay::input::keyboard::ModifiersState, - serial: smithay::utils::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, seat, data, modifiers, serial); - } - } - } -} - -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(WindowElement::Wayland(window)) => window.same_client_as(object_id), - FocusTarget::Window( - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface), - ) => surface.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!(), - } - } -} - -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 d826d74..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::{ @@ -51,13 +50,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 +138,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); @@ -265,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"); @@ -298,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 f4b4f24..3516e0f 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, 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(); - - 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(); - 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,12 +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().with_pending_state(|state| { - state.states.set(xdg_toplevel::State::Resizing); - }); + 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().send_pending_configure(); + toplevel.send_pending_configure(); + } } let grab = ResizeSurfaceGrab::start( @@ -506,12 +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().with_pending_state(|state| { - state.states.set(xdg_toplevel::State::Resizing); - }); + 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().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 cc3b819..1f5903a 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -58,9 +58,8 @@ use smithay::{ }; use crate::{ - focus::FocusTarget, + focus::{keyboard::KeyboardFocusTarget, pointer::PointerFocusTarget}, 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())); } @@ -176,26 +176,13 @@ 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(), ); }); - } 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().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().send_configure(); + toplevel.send_configure(); } } return; @@ -404,8 +394,9 @@ impl DataControlHandler for State { delegate_data_control!(State); impl SeatHandler for State { - type KeyboardFocus = FocusTarget; - type PointerFocus = 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 f2a02a5..e9714e9 100644 --- a/src/handlers/xdg_shell.rs +++ b/src/handlers/xdg_shell.rs @@ -17,13 +17,16 @@ 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, + }, }, }; use crate::{ - focus::FocusTarget, + focus::keyboard::KeyboardFocusTarget, state::{State, WithState}, window::WindowElement, }; @@ -41,65 +44,8 @@ impl XdgShellHandler for State { state.states.set(xdg_toplevel::State::TiledRight); }); - let window = WindowElement::Wayland(Window::new(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) { @@ -132,14 +78,16 @@ 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); self.z_index_stack.set_focus(win.clone()); - if let WindowElement::Wayland(win) = &win { - win.toplevel().send_configure(); + if let Some(toplevel) = win.toplevel() { + toplevel.send_configure(); } } self.seat @@ -692,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) }) }) }) { @@ -733,27 +681,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 310cfc9..04ef4b2 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, @@ -22,7 +24,7 @@ use smithay::{ }; use crate::{ - focus::FocusTarget, + focus::keyboard::KeyboardFocusTarget, state::{State, WithState}, window::{window_state::FloatingOrTiled, WindowElement}, }; @@ -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!() }; @@ -116,20 +118,20 @@ 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(), ); }); } - 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 { @@ -173,13 +177,15 @@ 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 WindowElement::Wayland(win) = &win { - win.toplevel().send_configure(); + if let Some(toplevel) = win.toplevel() { + toplevel.send_configure(); } } @@ -192,18 +198,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 +219,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(); @@ -236,13 +240,15 @@ 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 WindowElement::Wayland(win) = &win { - win.toplevel().send_configure(); + if let Some(toplevel) = win.toplevel() { + toplevel.send_configure(); } } @@ -283,14 +289,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 +415,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 KeyboardFocusTarget::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 c6a1d5c..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, window::WindowElement}; +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,15 +383,15 @@ impl State { } if !matches!( - &focus, - FocusTarget::Window(WindowElement::X11OverrideRedirect(_)) + 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() { - if let WindowElement::Wayland(window) = window { - window.toplevel().send_configure(); + if let Some(toplevel) = window.toplevel() { + toplevel.send_configure(); } } } else { @@ -367,8 +400,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().send_configure(); + if let Some(toplevel) = window.toplevel() { + toplevel.send_configure(); } } }); @@ -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/layout.rs b/src/layout.rs index ab16be6..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,21 +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().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().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 { @@ -137,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 a6190e9..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,9 +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() + 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 c20f973..78554a7 100644 --- a/src/window.rs +++ b/src/window.rs @@ -2,40 +2,14 @@ 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, - }, - input::{ - keyboard::{KeyboardTarget, KeysymHandle, ModifiersState}, - pointer::{AxisFrame, MotionEvent, PointerTarget}, - Seat, - }, + desktop::{space::SpaceElement, Window, WindowSurface}, 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}, + wayland::{compositor, seat::WaylandFocus, shell::xdg::XdgToplevelSurfaceData}, }; use crate::state::{State, WithState}; @@ -44,143 +18,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,13 +42,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().with_pending_state(|state| { + 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 @@ -205,20 +56,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().wl_surface(), |states| { + match self.0.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + compositor::with_states(toplevel.wl_surface(), |states| { states .data_map .get::() @@ -229,17 +76,14 @@ impl WindowElement { .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().wl_surface(), |states| { + match self.0.underlying_surface() { + WindowSurface::Wayland(toplevel) => { + compositor::with_states(toplevel.wl_surface(), |states| { states .data_map .get::() @@ -250,10 +94,7 @@ impl WindowElement { .clone() }) } - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - Some(surface.title()) - } - _ => unreachable!(), + WindowSurface::X11(surface) => Some(surface.title()), } } @@ -307,274 +148,48 @@ 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 PointerTarget for WindowElement { - fn frame(&self, seat: &Seat, state: &mut State) { - match self { - WindowElement::Wayland(window) => window.frame(seat, state), - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - surface.frame(seat, state) - } - _ => unreachable!(), - } +impl SpaceElement for WindowElement { + fn bbox(&self) -> Rectangle { + self.0.bbox() } - fn enter(&self, seat: &Seat, state: &mut State, event: &MotionEvent) { - // TODO: ssd - match self { - WindowElement::Wayland(window) => PointerTarget::enter(window, seat, state, event), - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - PointerTarget::enter(surface, seat, state, event) - } - _ => unreachable!(), - } - - 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 is_in_input_region(&self, point: &Point) -> bool { + self.0.is_in_input_region(point) } - fn motion(&self, seat: &Seat, state: &mut State, event: &MotionEvent) { - // TODO: ssd - match self { - WindowElement::Wayland(window) => PointerTarget::motion(window, seat, state, event), - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - PointerTarget::motion(surface, seat, state, event) - } - _ => unreachable!(), - } + fn set_activate(&self, activated: bool) { + self.0.set_activate(activated) } - fn relative_motion( - &self, - seat: &Seat, - state: &mut State, - event: &smithay::input::pointer::RelativeMotionEvent, - ) { - // TODO: ssd - match self { - WindowElement::Wayland(window) => { - PointerTarget::relative_motion(window, seat, state, event); - } - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - PointerTarget::relative_motion(surface, seat, state, event); - } - _ => unreachable!(), - } + fn output_enter(&self, output: &Output, overlap: Rectangle) { + self.0.output_enter(output, overlap) } - fn button( - &self, - seat: &Seat, - state: &mut State, - event: &smithay::input::pointer::ButtonEvent, - ) { - // TODO: ssd - match self { - WindowElement::Wayland(window) => PointerTarget::button(window, seat, state, event), - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - PointerTarget::button(surface, seat, state, event) - } - _ => unreachable!(), - } + fn output_leave(&self, output: &Output) { + self.0.output_leave(output) } - fn axis(&self, seat: &Seat, state: &mut State, frame: AxisFrame) { - // TODO: ssd - match self { - WindowElement::Wayland(window) => PointerTarget::axis(window, seat, state, frame), - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - PointerTarget::axis(surface, seat, state, frame) - } - _ => unreachable!(), - } + fn geometry(&self) -> Rectangle { + self.0.geometry() } - fn leave(&self, seat: &Seat, state: &mut State, serial: Serial, time: u32) { - // TODO: ssd - match self { - WindowElement::Wayland(window) => { - PointerTarget::leave(window, seat, state, serial, time); - } - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - PointerTarget::leave(surface, seat, state, serial, time) - } - _ => unreachable!(), - } - - 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 z_index(&self) -> u8 { + self.0.z_index() } - 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!() + fn refresh(&self) { + self.0.refresh(); } } -impl KeyboardTarget for WindowElement { - fn enter( - &self, - seat: &Seat, - state: &mut State, - keys: Vec>, - serial: Serial, - ) { - match self { - WindowElement::Wayland(window) => { - KeyboardTarget::enter(window, seat, state, keys, serial); - } - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(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, seat, state, serial), - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - KeyboardTarget::leave(surface, seat, state, serial) - } - _ => unreachable!(), - } - } - - fn key( - &self, - seat: &Seat, - state: &mut State, - key: KeysymHandle<'_>, - key_state: KeyState, - serial: Serial, - time: u32, - ) { - match self { - WindowElement::Wayland(window) => { - KeyboardTarget::key(window, seat, state, key, key_state, serial, time); - } - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - KeyboardTarget::key(surface, seat, state, key, key_state, serial, time); - } - _ => unreachable!(), - } - } - - fn modifiers( - &self, - seat: &Seat, - state: &mut State, - modifiers: ModifiersState, - serial: Serial, - ) { - match self { - WindowElement::Wayland(window) => { - KeyboardTarget::modifiers(window, seat, state, modifiers, serial); - } - WindowElement::X11(surface) | WindowElement::X11OverrideRedirect(surface) => { - KeyboardTarget::modifiers(surface, seat, state, modifiers, serial); - } - _ => unreachable!(), - } +impl IsAlive for WindowElement { + fn alive(&self) -> bool { + self.0.alive() } } @@ -599,12 +214,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 e9db349..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,9 +81,9 @@ impl WindowElement { state.fullscreen_or_maximized = FullscreenOrMaximized::Fullscreen; }); - match self { - WindowElement::Wayland(window) => { - window.toplevel().with_pending_state(|state| { + 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); @@ -92,16 +92,16 @@ impl WindowElement { 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 => { @@ -128,9 +128,9 @@ impl WindowElement { state.fullscreen_or_maximized = FullscreenOrMaximized::Maximized; }); - match self { - WindowElement::Wayland(window) => { - window.toplevel().with_pending_state(|state| { + 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); @@ -139,16 +139,16 @@ impl WindowElement { 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 => { @@ -170,9 +170,9 @@ 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().with_pending_state(|state| { + 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); @@ -181,25 +181,25 @@ impl WindowElement { 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().with_pending_state(|state| { + 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); @@ -208,16 +208,16 @@ impl WindowElement { 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!(), } } }