use std::{ borrow::Cow, sync::{Arc, Weak}, time::Duration, }; use crate::{ shell::{ CosmicSurface, CursorGeometry, SeatExt, element::{CosmicMapped, CosmicStack, CosmicWindow}, layout::tiling::ResizeForkTarget, zoom::ZoomFocusTarget, }, utils::prelude::*, wayland::handlers::{image_copy_capture::SessionHolder, xdg_shell::popup::get_popup_toplevel}, }; use id_tree::NodeId; use smithay::{ backend::input::{InputTime, KeyState, TabletToolDescriptor}, desktop::{LayerSurface, PopupKind, WindowSurface, WindowSurfaceType, space::SpaceElement}, input::{ Seat, dnd::{DndFocus, OfferData, Source}, keyboard::{KeyboardTarget, KeysymHandle, ModifiersState}, pointer::{ AxisFrame as PointerAxisFrame, ButtonEvent as PointerButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent, GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent as PointerMotionEvent, PointerTarget, RelativeMotionEvent, }, tablet::{ Tablet, tool::{ AxisFrame as ToolAxisFrame, ButtonEvent as ToolButtonEvent, DownEvent as ToolDownEvent, MotionEvent as ToolMotionEvent, TabletToolHandle, TabletToolTarget, UpEvent as ToolUpEvent, }, }, touch::{ DownEvent as TouchDownEvent, FrameMarker, MotionEvent as TouchMotionEvent, OrientationEvent, ShapeEvent, TouchTarget, UpEvent as TouchUpEvent, }, }, reexports::wayland_server::{ Client, DisplayHandle, Resource, backend::ObjectId, protocol::wl_surface::WlSurface, }, utils::{IsAlive, Logical, Point, Serial, Transform}, wayland::{ compositor::with_states, seat::WaylandFocus, selection::data_device::WlOfferData, session_lock::LockSurface, shell::xdg::SurfaceCachedState, }, xwayland::{ X11Surface, xwm::{XwmId, XwmOfferData}, }, }; #[derive(Debug, Clone, PartialEq)] pub enum PointerFocusTarget { WlSurface { surface: WlSurface, toplevel: Option, }, X11Surface { surface: X11Surface, toplevel: Option, }, StackUI(CosmicStack), WindowUI(CosmicWindow), ResizeFork(ResizeForkTarget), ZoomUI(ZoomFocusTarget), } #[derive(Debug, Clone, PartialEq)] #[allow(clippy::large_enum_variant)] pub enum PointerFocusToplevel { Surface(CosmicSurface), Popup(PopupKind), } impl From for PointerFocusToplevel { fn from(value: CosmicSurface) -> Self { PointerFocusToplevel::Surface(value) } } impl From for PointerFocusToplevel { fn from(value: PopupKind) -> Self { PointerFocusToplevel::Popup(value) } } #[derive(Debug, Clone, PartialEq)] pub enum KeyboardFocusTarget { Element(CosmicMapped), Fullscreen(CosmicSurface), Group(WindowGroup), LayerSurface(LayerSurface), Popup(PopupKind), LockSurface(LockSurface), } // TODO: This should be TryFrom, but PopupGrab needs to be able to convert. Fix this in smithay impl From for PointerFocusTarget { fn from(target: KeyboardFocusTarget) -> Self { match target { KeyboardFocusTarget::Element(elem) => { let window = elem.active_window(); if let Some(xsurface) = window.x11_surface() { PointerFocusTarget::X11Surface { surface: xsurface.clone(), toplevel: Some(window), } } else { PointerFocusTarget::WlSurface { surface: window.wl_surface().unwrap().into_owned(), toplevel: Some(window.into()), } } } KeyboardFocusTarget::Fullscreen(elem) => { if let Some(xsurface) = elem.x11_surface() { PointerFocusTarget::X11Surface { surface: xsurface.clone(), toplevel: Some(elem), } } else { PointerFocusTarget::WlSurface { surface: elem.wl_surface().unwrap().into_owned(), toplevel: Some(elem.into()), } } } KeyboardFocusTarget::LayerSurface(layer) => PointerFocusTarget::WlSurface { surface: layer.wl_surface().clone(), toplevel: None, }, KeyboardFocusTarget::Popup(popup) => PointerFocusTarget::WlSurface { surface: popup.wl_surface().clone(), toplevel: Some(popup.into()), }, KeyboardFocusTarget::LockSurface(lock) => PointerFocusTarget::WlSurface { surface: lock.wl_surface().clone(), toplevel: None, }, _ => unreachable!("A group cannot start a popup grab"), } } } impl PointerFocusTarget { fn inner_pointer_target(&self) -> &dyn PointerTarget { match self { PointerFocusTarget::WlSurface { surface, .. } => surface, PointerFocusTarget::X11Surface { surface, .. } => surface, PointerFocusTarget::StackUI(u) => u, PointerFocusTarget::WindowUI(u) => u, PointerFocusTarget::ResizeFork(f) => f, PointerFocusTarget::ZoomUI(e) => e, } } fn inner_touch_target(&self) -> &dyn TouchTarget { match self { PointerFocusTarget::WlSurface { surface, .. } => surface, PointerFocusTarget::X11Surface { surface, .. } => surface, PointerFocusTarget::StackUI(u) => u, PointerFocusTarget::WindowUI(u) => u, PointerFocusTarget::ResizeFork(f) => f, PointerFocusTarget::ZoomUI(e) => e, } } fn inner_tablet_tool_target(&self) -> &dyn TabletToolTarget { match self { PointerFocusTarget::WlSurface { surface, .. } => surface, PointerFocusTarget::X11Surface { surface, .. } => surface, PointerFocusTarget::StackUI(u) => u, PointerFocusTarget::WindowUI(u) => u, PointerFocusTarget::ResizeFork(f) => f, PointerFocusTarget::ZoomUI(e) => e, } } pub fn under_surface>>( surface: &CosmicSurface, point: P, ) -> Option<(Self, Point)> { match surface.0.underlying_surface() { WindowSurface::Wayland(_toplevel) => surface .0 .surface_under(point, WindowSurfaceType::ALL) .map(|(wl_surface, point)| { ( Self::WlSurface { surface: wl_surface, toplevel: Some(surface.clone().into()), }, point, ) }), WindowSurface::X11(x11_surface) => Some(( Self::X11Surface { surface: x11_surface.clone(), toplevel: Some(surface.clone()), }, Point::default(), )), } } pub fn toplevel(&self, shell: &Shell) -> Option { match &self { PointerFocusTarget::WlSurface { toplevel: Some(PointerFocusToplevel::Surface(surface)), .. } => Some(surface.clone()), PointerFocusTarget::WlSurface { toplevel: Some(PointerFocusToplevel::Popup(PopupKind::Xdg(popup))), .. } => get_popup_toplevel(&PopupKind::Xdg(popup.clone())) .and_then(|s| shell.element_for_surface(&s).map(|mapped| (mapped, s))) .and_then(|(m, s)| { m.windows() .find(|(w, _)| w.wl_surface().map(|s2| s == *s2).unwrap_or(false)) .map(|(s, _)| s) }), PointerFocusTarget::X11Surface { toplevel: Some(surface), .. } => Some(surface.clone()), PointerFocusTarget::StackUI(stack) => Some(stack.active()), PointerFocusTarget::WindowUI(window) => Some(window.surface()), _ => None, } } pub fn is_client(&self, client: &Client) -> bool { match self { PointerFocusTarget::WlSurface { surface, .. } => { surface.client().is_some_and(|c| c == *client) } PointerFocusTarget::X11Surface { surface, .. } => surface .wl_surface() .is_some_and(|s| s.client().is_some_and(|c| c == *client)), _ => false, } } // Update image copy cursor position/hotspot for enter/motion event fn update_image_copy_cursor_position( &self, seat: &Seat, data: &mut State, event: &PointerMotionEvent, ) { let Some(toplevel) = self.toplevel(&data.common.shell.read()) else { return; }; let cursor_sessions = toplevel.cursor_sessions(); if cursor_sessions.is_empty() { return; } let cursor_pos = if let Some(wl_surface) = self.wl_surface() { let surface_offset = toplevel .surface_offset(&wl_surface) .unwrap_or(Point::from((0, 0))) .to_f64(); let geometry_loc = toplevel .wl_surface() .and_then(|s| { with_states(&s, |states| { states .cached_state .get::() .current() .geometry .map(|g| g.loc.to_f64()) }) }) .unwrap_or_default(); Some( (event.location - geometry_loc + surface_offset) .to_buffer(1.0, Transform::Normal, &toplevel.geometry().size.to_f64()) .to_i32_round(), ) } else { // If cursor is in SSD, instead of a `wl_surface`, it is outside the captured bounds None }; let cursor_hotspot = if let Some(CursorGeometry { hotspot, .. }) = seat.cursor_geometry( (0.0, 0.0), Duration::from_millis(event.time.millis() as u64).into(), ) { hotspot } else { Point::from((0, 0)) }; for session in cursor_sessions { session.set_cursor_pos(cursor_pos); session.set_cursor_hotspot(cursor_hotspot); } } pub fn supports_tool(&self, tool_handle: &TabletToolHandle) -> bool { match self { Self::WlSurface { surface, .. } if surface.client().is_some() => tool_handle .client_tools(&surface.client().unwrap()) .next() .is_some(), _ => true, } } } impl KeyboardFocusTarget { fn inner_keyboard_target(&self) -> Option<&dyn KeyboardTarget> { match self { KeyboardFocusTarget::Element(w) => Some(w), KeyboardFocusTarget::Fullscreen(w) => Some(w), KeyboardFocusTarget::Group(_) => None, KeyboardFocusTarget::LayerSurface(l) => Some(l.wl_surface()), KeyboardFocusTarget::Popup(p) => Some(p.wl_surface()), KeyboardFocusTarget::LockSurface(l) => Some(l.wl_surface()), } } pub fn toplevel(&self) -> Option> { match self { KeyboardFocusTarget::Element(mapped) => mapped.wl_surface(), KeyboardFocusTarget::Popup(PopupKind::Xdg(xdg)) => { get_popup_toplevel(&PopupKind::Xdg(xdg.clone())).map(Cow::Owned) } _ => None, } } pub fn windows(&self) -> impl Iterator + '_ { match self { KeyboardFocusTarget::Element(mapped) => Box::new(mapped.windows().map(|(s, _)| s)) as Box>, KeyboardFocusTarget::Fullscreen(surface) => Box::new(std::iter::once(surface.clone())), _ => Box::new(std::iter::empty()), } } pub fn active_window(&self) -> Option { match self { KeyboardFocusTarget::Element(mapped) => Some(mapped.active_window()), KeyboardFocusTarget::Fullscreen(surface) => Some(surface.clone()), _ => None, } } pub fn x11_surface(&self) -> Option { match self { KeyboardFocusTarget::Element(mapped) => mapped.active_window().x11_surface().cloned(), KeyboardFocusTarget::Fullscreen(surface) => surface.x11_surface().cloned(), _ => None, } } pub fn is_xwm(&self, xwm: XwmId) -> bool { if let Some(surface) = self.x11_surface() { surface.xwm_id().unwrap() == xwm } else { false } } pub fn has_surface(&self, shell: &Shell, surface: &WlSurface) -> bool { if let Some(fe) = shell.focused_element(self) { fe.has_surface(surface, WindowSurfaceType::ALL) } else if let KeyboardFocusTarget::Fullscreen(s) = self { s.has_surface(surface, WindowSurfaceType::ALL) } else if let Some(root) = WaylandFocus::wl_surface(self) { CosmicSurface::surface_tree_offset(&root, surface).is_some() } else { false } } } #[derive(Debug, Clone)] pub struct WindowGroup { pub node: NodeId, pub alive: Weak<()>, pub focus_stack: Vec, } impl PartialEq for WindowGroup { fn eq(&self, other: &Self) -> bool { self.node == other.node && Weak::ptr_eq(&self.alive, &other.alive) } } impl IsAlive for PointerFocusTarget { fn alive(&self) -> bool { match self { // XXX? does this change anything PointerFocusTarget::WlSurface { surface, .. } => surface.alive(), PointerFocusTarget::X11Surface { surface, .. } => surface.alive(), PointerFocusTarget::StackUI(e) => e.alive(), PointerFocusTarget::WindowUI(e) => e.alive(), PointerFocusTarget::ResizeFork(f) => f.alive(), PointerFocusTarget::ZoomUI(_) => true, } } } impl IsAlive for KeyboardFocusTarget { fn alive(&self) -> bool { match self { KeyboardFocusTarget::Element(e) => e.alive(), KeyboardFocusTarget::Fullscreen(f) => f.alive(), KeyboardFocusTarget::Group(g) => g.alive.upgrade().is_some(), KeyboardFocusTarget::LayerSurface(l) => l.alive(), KeyboardFocusTarget::Popup(p) => p.alive(), KeyboardFocusTarget::LockSurface(l) => l.alive(), } } } impl PointerTarget for PointerFocusTarget { fn enter(&self, seat: &Seat, data: &mut State, event: &PointerMotionEvent) { self.update_image_copy_cursor_position(seat, data, event); self.inner_pointer_target().enter(seat, data, event); } fn motion(&self, seat: &Seat, data: &mut State, event: &PointerMotionEvent) { self.update_image_copy_cursor_position(seat, data, event); self.inner_pointer_target().motion(seat, data, event); } fn relative_motion(&self, seat: &Seat, data: &mut State, event: &RelativeMotionEvent) { self.inner_pointer_target() .relative_motion(seat, data, event); } fn button(&self, seat: &Seat, data: &mut State, event: &PointerButtonEvent) { self.inner_pointer_target().button(seat, data, event); } fn axis(&self, seat: &Seat, data: &mut State, frame: PointerAxisFrame) { self.inner_pointer_target().axis(seat, data, frame); } fn frame(&self, seat: &Seat, data: &mut State) { self.inner_pointer_target().frame(seat, data); } fn leave(&self, seat: &Seat, data: &mut State, serial: Serial, time: InputTime) { let toplevel = self.toplevel(&data.common.shell.read()); if let Some(element) = toplevel { for session in element.cursor_sessions() { session.set_cursor_pos(None); session.set_cursor_hotspot((0, 0)); } } self.inner_pointer_target().leave(seat, data, serial, time); } fn gesture_swipe_begin( &self, seat: &Seat, data: &mut State, event: &GestureSwipeBeginEvent, ) { self.inner_pointer_target() .gesture_swipe_begin(seat, data, event); } fn gesture_swipe_update( &self, seat: &Seat, data: &mut State, event: &GestureSwipeUpdateEvent, ) { self.inner_pointer_target() .gesture_swipe_update(seat, data, event); } fn gesture_swipe_end( &self, seat: &Seat, data: &mut State, event: &GestureSwipeEndEvent, ) { self.inner_pointer_target() .gesture_swipe_end(seat, data, event); } fn gesture_pinch_begin( &self, seat: &Seat, data: &mut State, event: &GesturePinchBeginEvent, ) { self.inner_pointer_target() .gesture_pinch_begin(seat, data, event); } fn gesture_pinch_update( &self, seat: &Seat, data: &mut State, event: &GesturePinchUpdateEvent, ) { self.inner_pointer_target() .gesture_pinch_update(seat, data, event); } fn gesture_pinch_end( &self, seat: &Seat, data: &mut State, event: &GesturePinchEndEvent, ) { self.inner_pointer_target() .gesture_pinch_end(seat, data, event); } fn gesture_hold_begin( &self, seat: &Seat, data: &mut State, event: &GestureHoldBeginEvent, ) { self.inner_pointer_target() .gesture_hold_begin(seat, data, event); } fn gesture_hold_end(&self, seat: &Seat, data: &mut State, event: &GestureHoldEndEvent) { self.inner_pointer_target() .gesture_hold_end(seat, data, event); } } impl TabletToolTarget for PointerFocusTarget { fn proximity_in( &self, seat: &Seat, data: &mut State, tool_descriptor: &TabletToolDescriptor, tablet: &Tablet, serial: Serial, ) { self.inner_tablet_tool_target() .proximity_in(seat, data, tool_descriptor, tablet, serial); } fn proximity_out( &self, seat: &Seat, data: &mut State, tool_descriptor: &TabletToolDescriptor, ) { self.inner_tablet_tool_target() .proximity_out(seat, data, tool_descriptor); } fn down( &self, seat: &Seat, data: &mut State, tool_descriptor: &TabletToolDescriptor, event: &ToolDownEvent, ) { self.inner_tablet_tool_target() .down(seat, data, tool_descriptor, event); } fn up( &self, seat: &Seat, data: &mut State, tool_descriptor: &TabletToolDescriptor, event: &ToolUpEvent, ) { self.inner_tablet_tool_target() .up(seat, data, tool_descriptor, event); } fn motion( &self, seat: &Seat, data: &mut State, tool_descriptor: &TabletToolDescriptor, event: &ToolMotionEvent, ) { self.inner_tablet_tool_target() .motion(seat, data, tool_descriptor, event); } fn axis( &self, seat: &Seat, data: &mut State, tool_descriptor: &TabletToolDescriptor, frame: ToolAxisFrame, ) { self.inner_tablet_tool_target() .axis(seat, data, tool_descriptor, frame); } fn button( &self, seat: &Seat, data: &mut State, tool_descriptor: &TabletToolDescriptor, event: &ToolButtonEvent, ) { self.inner_tablet_tool_target() .button(seat, data, tool_descriptor, event); } fn frame( &self, seat: &Seat, data: &mut State, tool_descriptor: &TabletToolDescriptor, time: InputTime, ) { self.inner_tablet_tool_target() .frame(seat, data, tool_descriptor, time); } } impl TouchTarget for PointerFocusTarget { fn down(&self, seat: &Seat, data: &mut State, event: &TouchDownEvent) { self.inner_touch_target().down(seat, data, event); } fn up(&self, seat: &Seat, data: &mut State, event: &TouchUpEvent) { self.inner_touch_target().up(seat, data, event); } fn motion(&self, seat: &Seat, data: &mut State, event: &TouchMotionEvent) { self.inner_touch_target().motion(seat, data, event); } fn frame(&self, seat: &Seat, data: &mut State, frame: FrameMarker) { self.inner_touch_target().frame(seat, data, frame); } fn cancel(&self, seat: &Seat, data: &mut State, frame: FrameMarker) { self.inner_touch_target().cancel(seat, data, frame); } fn shape(&self, seat: &Seat, data: &mut State, event: &ShapeEvent) { self.inner_touch_target().shape(seat, data, event); } fn orientation(&self, seat: &Seat, data: &mut State, event: &OrientationEvent) { self.inner_touch_target().orientation(seat, data, event); } fn last_frame(&self, seat: &Seat, data: &mut State) -> Option { self.inner_touch_target().last_frame(seat, data) } } pub enum CosmicOfferData { Wl(WlOfferData), X11(XwmOfferData), } impl OfferData for CosmicOfferData { fn disable(&self) { match self { CosmicOfferData::Wl(data) => data.disable(), CosmicOfferData::X11(data) => data.disable(), } } fn drop(&self) { match self { CosmicOfferData::Wl(data) => data.drop(), CosmicOfferData::X11(data) => data.drop(), } } fn validated(&self) -> bool { match self { CosmicOfferData::Wl(data) => data.validated(), CosmicOfferData::X11(data) => data.validated(), } } } impl DndFocus for PointerFocusTarget { type OfferData = CosmicOfferData where S: Source; fn enter( &self, data: &mut State, dh: &DisplayHandle, source: Arc, seat: &Seat, location: Point, serial: &Serial, ) -> Option> { match self { PointerFocusTarget::WlSurface { surface, .. } => { DndFocus::enter(surface, data, dh, source, seat, location, serial) .map(CosmicOfferData::Wl) } PointerFocusTarget::X11Surface { surface, .. } => { DndFocus::enter(surface, data, dh, source, seat, location, serial) .map(CosmicOfferData::X11) } _ => None, } } fn motion( &self, data: &mut State, offer: Option<&mut CosmicOfferData>, seat: &Seat, location: Point, time: InputTime, ) { match self { PointerFocusTarget::WlSurface { surface, .. } => { let offer = match offer { Some(CosmicOfferData::Wl(offer)) => Some(offer), None => None, _ => return, }; DndFocus::motion(surface, data, offer, seat, location, time) } PointerFocusTarget::X11Surface { surface, .. } => { let offer = match offer { Some(CosmicOfferData::X11(offer)) => Some(offer), None => None, _ => return, }; DndFocus::motion(surface, data, offer, seat, location, time) } _ => {} } } fn leave( &self, data: &mut State, offer: Option<&mut CosmicOfferData>, seat: &Seat, ) { match self { PointerFocusTarget::WlSurface { surface, .. } => { let offer = match offer { Some(CosmicOfferData::Wl(offer)) => Some(offer), None => None, _ => return, }; DndFocus::leave(surface, data, offer, seat) } PointerFocusTarget::X11Surface { surface, .. } => { let offer = match offer { Some(CosmicOfferData::X11(offer)) => Some(offer), None => None, _ => return, }; DndFocus::leave(surface, data, offer, seat) } _ => {} } } fn drop( &self, data: &mut State, offer: Option<&mut CosmicOfferData>, seat: &Seat, ) { match self { PointerFocusTarget::WlSurface { surface, .. } => { let offer = match offer { Some(CosmicOfferData::Wl(offer)) => Some(offer), None => None, _ => return, }; DndFocus::drop(surface, data, offer, seat) } PointerFocusTarget::X11Surface { surface, .. } => { let offer = match offer { Some(CosmicOfferData::X11(offer)) => Some(offer), None => None, _ => return, }; DndFocus::drop(surface, data, offer, seat) } _ => {} } } } impl KeyboardTarget for KeyboardFocusTarget { fn enter( &self, seat: &Seat, data: &mut State, keys: Vec>, serial: Serial, ) { if let Some(inner) = self.inner_keyboard_target() { inner.enter(seat, data, keys, serial); } } fn leave(&self, seat: &Seat, data: &mut State, serial: Serial) { if let Some(inner) = self.inner_keyboard_target() { inner.leave(seat, data, serial); } } fn key( &self, seat: &Seat, data: &mut State, key: KeysymHandle<'_>, state: KeyState, serial: Serial, time: InputTime, ) { if let Some(inner) = self.inner_keyboard_target() { inner.key(seat, data, key, state, serial, time); } } fn modifiers( &self, seat: &Seat, data: &mut State, modifiers: ModifiersState, serial: Serial, ) { if let Some(inner) = self.inner_keyboard_target() { inner.modifiers(seat, data, modifiers, serial); } } fn replace( &self, replaced: Self, seat: &Seat, data: &mut State, keys: Vec>, modifiers: ModifiersState, serial: Serial, ) { if !replaced .wl_surface() .is_some_and(|s| Some(s) == self.wl_surface()) && !replaced .x11_surface() .is_some_and(|s| Some(s) == self.x11_surface()) { KeyboardTarget::leave(&replaced, seat, data, serial); KeyboardTarget::enter(self, seat, data, keys, serial); KeyboardTarget::modifiers(self, seat, data, modifiers, serial); } } } impl WaylandFocus for KeyboardFocusTarget { fn wl_surface(&self) -> Option> { match self { KeyboardFocusTarget::Element(w) => WaylandFocus::wl_surface(w), KeyboardFocusTarget::Fullscreen(w) => WaylandFocus::wl_surface(w), KeyboardFocusTarget::Group(_) => None, KeyboardFocusTarget::LayerSurface(l) => Some(Cow::Borrowed(l.wl_surface())), KeyboardFocusTarget::Popup(p) => Some(Cow::Borrowed(p.wl_surface())), KeyboardFocusTarget::LockSurface(l) => Some(Cow::Borrowed(l.wl_surface())), } } fn same_client_as(&self, object_id: &ObjectId) -> bool { match self { KeyboardFocusTarget::Element(w) => WaylandFocus::same_client_as(w, object_id), KeyboardFocusTarget::Fullscreen(w) => WaylandFocus::same_client_as(w, object_id), KeyboardFocusTarget::Group(_) => false, KeyboardFocusTarget::LayerSurface(l) => l.wl_surface().id().same_client_as(object_id), KeyboardFocusTarget::Popup(p) => p.wl_surface().id().same_client_as(object_id), KeyboardFocusTarget::LockSurface(l) => l.wl_surface().id().same_client_as(object_id), } } } impl WaylandFocus for PointerFocusTarget { fn wl_surface(&self) -> Option> { Some(match self { PointerFocusTarget::WlSurface { surface, .. } => Cow::Borrowed(surface), PointerFocusTarget::X11Surface { surface, .. } => Cow::Owned(surface.wl_surface()?), PointerFocusTarget::ResizeFork(_) | PointerFocusTarget::StackUI(_) | PointerFocusTarget::WindowUI(_) | PointerFocusTarget::ZoomUI(_) => { return None; } }) } fn same_client_as(&self, object_id: &ObjectId) -> bool { match self { PointerFocusTarget::WlSurface { surface, .. } => surface.id().same_client_as(object_id), PointerFocusTarget::X11Surface { surface, .. } => surface .wl_surface() .is_some_and(|s| s.id().same_client_as(object_id)), PointerFocusTarget::StackUI(stack) => stack .active() .wl_surface() .is_some_and(|s| s.id().same_client_as(object_id)), PointerFocusTarget::WindowUI(window) => window .wl_surface() .is_some_and(|s| s.id().same_client_as(object_id)), PointerFocusTarget::ResizeFork(_) | PointerFocusTarget::ZoomUI(_) => false, } } } impl From for PointerFocusTarget { fn from(p: PopupKind) -> Self { PointerFocusTarget::WlSurface { surface: p.wl_surface().clone(), toplevel: None, } } } impl From for PointerFocusTarget { fn from(f: ResizeForkTarget) -> Self { PointerFocusTarget::ResizeFork(f) } } impl From for PointerFocusTarget { fn from(l: LockSurface) -> Self { PointerFocusTarget::WlSurface { surface: l.wl_surface().clone(), toplevel: None, } } } impl From for KeyboardFocusTarget { fn from(w: CosmicMapped) -> Self { KeyboardFocusTarget::Element(w) } } impl From for KeyboardFocusTarget { fn from(s: CosmicSurface) -> Self { KeyboardFocusTarget::Fullscreen(s) } } impl From for KeyboardFocusTarget { fn from(w: WindowGroup) -> Self { KeyboardFocusTarget::Group(w) } } impl From for KeyboardFocusTarget { fn from(l: LayerSurface) -> Self { KeyboardFocusTarget::LayerSurface(l) } } impl From for KeyboardFocusTarget { fn from(p: PopupKind) -> Self { KeyboardFocusTarget::Popup(p) } } impl From for KeyboardFocusTarget { fn from(l: LockSurface) -> Self { KeyboardFocusTarget::LockSurface(l) } }