input: Use render_input_order

This commit is contained in:
Victoria Brekenfeld 2024-10-10 23:18:04 +02:00 committed by Victoria Brekenfeld
parent 51c8588f89
commit 0092dac08c
10 changed files with 712 additions and 387 deletions

View file

@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use crate::{ use crate::{
backend::render::ElementFilter,
config::{ config::{
key_bindings::{ key_bindings::{
cosmic_keystate_from_smithay, cosmic_modifiers_eq_smithay, cosmic_keystate_from_smithay, cosmic_modifiers_eq_smithay,
@ -10,7 +11,11 @@ use crate::{
}, },
input::gestures::{GestureState, SwipeAction}, input::gestures::{GestureState, SwipeAction},
shell::{ shell::{
focus::target::{KeyboardFocusTarget, PointerFocusTarget}, focus::{
render_input_order,
target::{KeyboardFocusTarget, PointerFocusTarget},
Stage,
},
grabs::{ReleaseMode, ResizeEdge}, grabs::{ReleaseMode, ResizeEdge},
layout::{ layout::{
floating::ResizeGrabMarker, floating::ResizeGrabMarker,
@ -39,10 +44,7 @@ use smithay::{
TabletToolButtonEvent, TabletToolEvent, TabletToolProximityEvent, TabletToolTipEvent, TabletToolButtonEvent, TabletToolEvent, TabletToolProximityEvent, TabletToolTipEvent,
TabletToolTipState, TouchEvent, TabletToolTipState, TouchEvent,
}, },
desktop::{ desktop::{utils::under_from_surface_tree, WindowSurfaceType},
layer_map_for_output, space::SpaceElement, utils::under_from_surface_tree,
WindowSurfaceType,
},
input::{ input::{
keyboard::{FilterResult, KeysymHandle, ModifiersState}, keyboard::{FilterResult, KeysymHandle, ModifiersState},
pointer::{ pointer::{
@ -58,15 +60,13 @@ use smithay::{
reexports::{ reexports::{
input::Device as InputDevice, wayland_server::protocol::wl_shm::Format as ShmFormat, input::Device as InputDevice, wayland_server::protocol::wl_shm::Format as ShmFormat,
}, },
utils::{Point, Serial, SERIAL_COUNTER}, utils::{Point, Rectangle, Serial, SERIAL_COUNTER},
wayland::{ wayland::{
keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitorSeat, keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitorSeat,
pointer_constraints::{with_pointer_constraint, PointerConstraint}, pointer_constraints::{with_pointer_constraint, PointerConstraint},
seat::WaylandFocus, seat::WaylandFocus,
shell::wlr_layer::Layer as WlrLayer,
tablet_manager::{TabletDescriptor, TabletSeatTrait}, tablet_manager::{TabletDescriptor, TabletSeatTrait},
}, },
xwayland::X11Surface,
}; };
use tracing::{error, trace}; use tracing::{error, trace};
use xkbcommon::xkb::{Keycode, Keysym}; use xkbcommon::xkb::{Keycode, Keysym};
@ -76,6 +76,7 @@ use std::{
borrow::Cow, borrow::Cow,
cell::RefCell, cell::RefCell,
collections::HashSet, collections::HashSet,
ops::ControlFlow,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
@ -329,9 +330,8 @@ impl State {
} else if self.common.config.cosmic_conf.focus_follows_cursor { } else if self.common.config.cosmic_conf.focus_follows_cursor {
let shell = self.common.shell.read().unwrap(); let shell = self.common.shell.read().unwrap();
let old_keyboard_target = let old_keyboard_target =
shell.keyboard_target_from_position(original_position, &current_output); State::element_under(original_position, &current_output, &*shell);
let new_keyboard_target = let new_keyboard_target = State::element_under(position, &output, &*shell);
shell.keyboard_target_from_position(position, &output);
if old_keyboard_target != new_keyboard_target if old_keyboard_target != new_keyboard_target
&& new_keyboard_target.is_some() && new_keyboard_target.is_some()
@ -497,7 +497,8 @@ impl State {
}); });
} }
let shell = self.common.shell.read().unwrap(); let mut shell = self.common.shell.write().unwrap();
shell.update_pointer_position(position.to_local(&output), &output);
if output != current_output { if output != current_output {
for session in cursor_sessions_for_output(&*shell, &current_output) { for session in cursor_sessions_for_output(&*shell, &current_output) {
@ -638,15 +639,15 @@ impl State {
let global_position = let global_position =
seat.get_pointer().unwrap().current_location().as_global(); seat.get_pointer().unwrap().current_location().as_global();
let shell = self.common.shell.write().unwrap(); let under = {
let under = shell.keyboard_target_from_position(global_position, &output); let shell = self.common.shell.read().unwrap();
// Don't check override redirect windows, because we don't set keyboard focus to them explicitly. State::element_under(global_position, &output, &shell)
// These cases are handled by the XwaylandKeyboardGrab. };
if let Some(target) = shell.element_under(global_position, &output) { if let Some(target) = under {
if seat.get_keyboard().unwrap().modifier_state().logo if let Some(surface) = target.toplevel().map(Cow::into_owned) {
&& !shortcuts_inhibited if seat.get_keyboard().unwrap().modifier_state().logo
{ && !shortcuts_inhibited
if let Some(surface) = target.toplevel().map(Cow::into_owned) { {
let seat_clone = seat.clone(); let seat_clone = seat.clone();
let mouse_button = PointerButtonEvent::button(&event); let mouse_button = PointerButtonEvent::button(&event);
@ -754,10 +755,9 @@ impl State {
} }
} }
} }
}
std::mem::drop(shell); Shell::set_focus(self, Some(&target), &seat, Some(serial), false);
Shell::set_focus(self, under.as_ref(), &seat, Some(serial), false); }
} }
} else { } else {
let mut shell = self.common.shell.write().unwrap(); let mut shell = self.common.shell.write().unwrap();
@ -1814,142 +1814,263 @@ impl State {
} }
} }
// TODO: Try to get rid of the *mutable* Shell references (needed for hovered_stack in floating_layout) pub fn element_under(
global_pos: Point<f64, Global>,
output: &Output,
shell: &Shell,
) -> Option<KeyboardFocusTarget> {
let (previous_workspace, workspace) = shell.workspaces.active(output);
let (previous_idx, idx) = shell.workspaces.active_num(output);
let previous_workspace = previous_workspace
.zip(previous_idx)
.map(|((w, start), idx)| (w.handle, idx, start));
let workspace = (workspace.handle, idx);
let element_filter = if workspace_overview_is_open(output) {
ElementFilter::LayerShellOnly
} else {
ElementFilter::All
};
render_input_order(
shell,
output,
previous_workspace,
workspace,
element_filter,
|stage| {
match stage {
Stage::SessionLock(lock_surface) => {
return ControlFlow::Break(Ok(lock_surface
.cloned()
.map(KeyboardFocusTarget::LockSurface)))
}
Stage::LayerPopup {
layer,
popup,
location,
} => {
if layer.can_receive_keyboard_focus() {
let surface = popup.wl_surface();
if under_from_surface_tree(
surface,
global_pos.as_logical(),
location.as_logical(),
WindowSurfaceType::POPUP | WindowSurfaceType::SUBSURFACE,
)
.is_some()
{
return ControlFlow::Break(Ok(Some(
KeyboardFocusTarget::LayerSurface(layer),
)));
}
}
}
Stage::LayerSurface { layer, location } => {
if layer.can_receive_keyboard_focus() {
if under_from_surface_tree(
layer.wl_surface(),
global_pos.as_logical(),
location.as_logical(),
WindowSurfaceType::TOPLEVEL | WindowSurfaceType::SUBSURFACE,
)
.is_some()
{
return ControlFlow::Break(Ok(Some(
KeyboardFocusTarget::LayerSurface(layer),
)));
}
}
}
Stage::OverrideRedirect { .. } => {
// Override redirect windows take a grab on their own via
// the Xwayland keyboard grab protocol. Don't focus them via click.
}
Stage::StickyPopups(layout) => {
if let Some(element) =
layout.popup_element_under(global_pos.to_local(output))
{
return ControlFlow::Break(Ok(Some(element)));
}
}
Stage::Sticky(layout) => {
if let Some(element) =
layout.toplevel_element_under(global_pos.to_local(output))
{
return ControlFlow::Break(Ok(Some(element)));
}
}
Stage::WorkspacePopups { workspace, offset } => {
let location = global_pos + offset.as_global().to_f64();
let output = workspace.output();
let output_geo = output.geometry().to_local(output);
if Rectangle::from_loc_and_size(offset.as_local(), output_geo.size)
.intersection(output_geo)
.is_some_and(|geometry| {
geometry.contains(global_pos.to_local(output).to_i32_round())
})
{
if let Some(element) = workspace.popup_element_under(location) {
return ControlFlow::Break(Ok(Some(element)));
}
}
}
Stage::Workspace { workspace, offset } => {
let location = global_pos + offset.as_global().to_f64();
let output = workspace.output();
let output_geo = output.geometry().to_local(output);
if Rectangle::from_loc_and_size(offset.as_local(), output_geo.size)
.intersection(output_geo)
.is_some_and(|geometry| {
geometry.contains(global_pos.to_local(output).to_i32_round())
})
{
if let Some(element) = workspace.toplevel_element_under(location) {
return ControlFlow::Break(Ok(Some(element)));
}
}
}
}
ControlFlow::Continue(())
},
)
.ok()
.flatten()
}
pub fn surface_under( pub fn surface_under(
global_pos: Point<f64, Global>, global_pos: Point<f64, Global>,
output: &Output, output: &Output,
shell: &mut Shell, shell: &Shell,
) -> Option<(PointerFocusTarget, Point<f64, Global>)> { ) -> Option<(PointerFocusTarget, Point<f64, Global>)> {
let session_lock = shell.session_lock.as_ref(); let (previous_workspace, workspace) = shell.workspaces.active(output);
let (previous_idx, idx) = shell.workspaces.active_num(output);
let previous_workspace = previous_workspace
.zip(previous_idx)
.map(|((w, start), idx)| (w.handle, idx, start));
let workspace = (workspace.handle, idx);
let element_filter = if workspace_overview_is_open(output) {
ElementFilter::LayerShellOnly
} else {
ElementFilter::All
};
let relative_pos = global_pos.to_local(output); let relative_pos = global_pos.to_local(output);
let output_geo = output.geometry(); let output_geo = output.geometry();
let overview = shell.overview_mode().0;
if let Some(session_lock) = session_lock { render_input_order(
return session_lock.surfaces.get(output).map(|surface| { shell,
( output,
PointerFocusTarget::WlSurface { previous_workspace,
surface: surface.wl_surface().clone(), workspace,
toplevel: None, element_filter,
}, |stage| {
output_geo.loc.to_f64(), match stage {
) Stage::SessionLock(lock_surface) => {
}); return ControlFlow::Break(Ok(lock_surface.map(|surface| {
} (
PointerFocusTarget::WlSurface {
if let Some(window) = shell.workspaces.active(output).1.get_fullscreen() { surface: surface.wl_surface().clone(),
let layers = layer_map_for_output(output); toplevel: None,
if let Some(layer) = layers.layer_under(WlrLayer::Overlay, relative_pos.as_logical()) { },
let layer_loc = layers.layer_geometry(layer).unwrap().loc; output_geo.loc.to_f64(),
if let Some((wl_surface, surface_loc)) = layer.surface_under( )
relative_pos.as_logical() - layer_loc.to_f64(), })));
WindowSurfaceType::ALL, }
) { Stage::LayerPopup {
return Some(( popup, location, ..
PointerFocusTarget::WlSurface { } => {
surface: wl_surface, let surface = popup.wl_surface();
toplevel: None, if let Some((surface, surface_loc)) = under_from_surface_tree(
}, surface,
(output_geo.loc + layer_loc.as_global() + surface_loc.as_global()).to_f64(), global_pos.as_logical(),
)); location.as_logical(),
} WindowSurfaceType::ALL,
} ) {
if let Some((surface, geo)) = shell return ControlFlow::Break(Ok(Some((
.override_redirect_windows PointerFocusTarget::WlSurface {
.iter() surface,
.find(|or| { toplevel: None,
or.is_in_input_region( },
&(global_pos.as_logical() - X11Surface::geometry(*or).loc.to_f64()), surface_loc.as_global().to_f64(),
) ))));
}) }
.and_then(|or| { }
or.wl_surface() Stage::LayerSurface { layer, location } => {
.map(|surface| (surface, X11Surface::geometry(or).loc.as_global().to_f64())) let surface = layer.wl_surface();
}) if let Some((surface, surface_loc)) = under_from_surface_tree(
{ surface,
return Some(( global_pos.as_logical(),
PointerFocusTarget::WlSurface { location.as_logical(),
surface, WindowSurfaceType::ALL,
toplevel: None, ) {
}, return ControlFlow::Break(Ok(Some((
geo, PointerFocusTarget::WlSurface {
)); surface,
} toplevel: None,
PointerFocusTarget::under_surface(window, relative_pos.as_logical()).map( },
|(target, surface_loc)| { surface_loc.as_global().to_f64(),
(target, (output_geo.loc + surface_loc.as_global()).to_f64()) ))));
}, }
) }
} else { Stage::OverrideRedirect { surface, location } => {
{ if let Some(surface) = surface.wl_surface() {
let layers = layer_map_for_output(output); if let Some((surface, surface_loc)) = under_from_surface_tree(
if let Some(layer) = layers &surface,
.layer_under(WlrLayer::Overlay, relative_pos.as_logical()) global_pos.as_logical(),
.or_else(|| layers.layer_under(WlrLayer::Top, relative_pos.as_logical())) location.as_logical(),
{ WindowSurfaceType::ALL,
let layer_loc = layers.layer_geometry(layer).unwrap().loc; ) {
if let Some((wl_surface, surface_loc)) = layer.surface_under( return ControlFlow::Break(Ok(Some((
relative_pos.as_logical() - layer_loc.to_f64(), PointerFocusTarget::WlSurface {
WindowSurfaceType::ALL, surface,
) { toplevel: None,
return Some(( },
PointerFocusTarget::WlSurface { surface_loc.as_global().to_f64(),
surface: wl_surface, ))));
toplevel: None, }
}, }
(output_geo.loc + layer_loc.as_global() + surface_loc.as_global()) }
.to_f64(), Stage::StickyPopups(floating_layer) => {
)); if let Some(under) = floating_layer
.popup_surface_under(relative_pos)
.map(|(target, point)| (target, point.to_global(output)))
{
return ControlFlow::Break(Ok(Some(under)));
}
}
Stage::Sticky(floating_layer) => {
if let Some(under) = floating_layer
.toplevel_surface_under(relative_pos)
.map(|(target, point)| (target, point.to_global(output)))
{
return ControlFlow::Break(Ok(Some(under)));
}
}
Stage::WorkspacePopups { workspace, offset } => {
let global_pos = global_pos + offset.to_f64().as_global();
if let Some(under) =
workspace.popup_surface_under(global_pos, overview.clone())
{
return ControlFlow::Break(Ok(Some(under)));
}
}
Stage::Workspace { workspace, offset } => {
let global_pos = global_pos + offset.to_f64().as_global();
if let Some(under) =
workspace.toplevel_surface_under(global_pos, overview.clone())
{
return ControlFlow::Break(Ok(Some(under)));
}
} }
} }
}
if let Some((surface, geo)) = shell ControlFlow::Continue(())
.override_redirect_windows },
.iter() )
.find(|or| { .ok()
or.is_in_input_region( .flatten()
&(global_pos.as_logical() - X11Surface::geometry(*or).loc.to_f64()),
)
})
.and_then(|or| {
or.wl_surface()
.map(|surface| (surface, X11Surface::geometry(or).loc.as_global().to_f64()))
})
{
return Some((
PointerFocusTarget::WlSurface {
surface,
toplevel: None,
},
geo,
));
}
if let Some((target, loc)) = shell.surface_under(global_pos, output) {
return Some((target, loc));
}
{
let layers = layer_map_for_output(output);
if let Some(layer) = layers
.layer_under(WlrLayer::Bottom, relative_pos.as_logical())
.or_else(|| layers.layer_under(WlrLayer::Background, relative_pos.as_logical()))
{
let layer_loc = layers.layer_geometry(layer).unwrap().loc;
if let Some((wl_surface, surface_loc)) = layer.surface_under(
relative_pos.as_logical() - layer_loc.to_f64(),
WindowSurfaceType::ALL,
) {
return Some((
PointerFocusTarget::WlSurface {
surface: wl_surface,
toplevel: None,
},
(output_geo.loc + layer_loc.as_global() + surface_loc.as_global())
.to_f64(),
));
}
}
}
None
}
} }
} }

View file

@ -302,10 +302,11 @@ impl CosmicMapped {
pub fn focus_under( pub fn focus_under(
&self, &self,
relative_pos: Point<f64, Logical>, relative_pos: Point<f64, Logical>,
surface_type: WindowSurfaceType,
) -> Option<(PointerFocusTarget, Point<f64, Logical>)> { ) -> Option<(PointerFocusTarget, Point<f64, Logical>)> {
match &self.element { match &self.element {
CosmicMappedInternal::Stack(stack) => stack.focus_under(relative_pos), CosmicMappedInternal::Stack(stack) => stack.focus_under(relative_pos, surface_type),
CosmicMappedInternal::Window(window) => window.focus_under(relative_pos), CosmicMappedInternal::Window(window) => window.focus_under(relative_pos, surface_type),
_ => unreachable!(), _ => unreachable!(),
} }
} }

View file

@ -420,48 +420,52 @@ impl CosmicStack {
pub fn focus_under( pub fn focus_under(
&self, &self,
mut relative_pos: Point<f64, Logical>, mut relative_pos: Point<f64, Logical>,
surface_type: WindowSurfaceType,
) -> Option<(PointerFocusTarget, Point<f64, Logical>)> { ) -> Option<(PointerFocusTarget, Point<f64, Logical>)> {
self.0.with_program(|p| { self.0.with_program(|p| {
let mut stack_ui = None; let mut stack_ui = None;
let geo = p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)].geometry(); let geo = p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)].geometry();
let point_i32 = relative_pos.to_i32_round::<i32>(); if surface_type.contains(WindowSurfaceType::TOPLEVEL) {
if (point_i32.x - geo.loc.x >= -RESIZE_BORDER && point_i32.x - geo.loc.x < 0) let point_i32 = relative_pos.to_i32_round::<i32>();
|| (point_i32.y - geo.loc.y >= -RESIZE_BORDER && point_i32.y - geo.loc.y < 0) if (point_i32.x - geo.loc.x >= -RESIZE_BORDER && point_i32.x - geo.loc.x < 0)
|| (point_i32.x - geo.loc.x >= geo.size.w || (point_i32.y - geo.loc.y >= -RESIZE_BORDER && point_i32.y - geo.loc.y < 0)
&& point_i32.x - geo.loc.x < geo.size.w + RESIZE_BORDER) || (point_i32.x - geo.loc.x >= geo.size.w
|| (point_i32.y - geo.loc.y >= geo.size.h && point_i32.x - geo.loc.x < geo.size.w + RESIZE_BORDER)
&& point_i32.y - geo.loc.y < geo.size.h + TAB_HEIGHT + RESIZE_BORDER) || (point_i32.y - geo.loc.y >= geo.size.h
{ && point_i32.y - geo.loc.y < geo.size.h + TAB_HEIGHT + RESIZE_BORDER)
stack_ui = Some(( {
PointerFocusTarget::StackUI(self.clone()), stack_ui = Some((
Point::from((0., 0.)), PointerFocusTarget::StackUI(self.clone()),
)); Point::from((0., 0.)),
} ));
}
if point_i32.y - geo.loc.y < TAB_HEIGHT { if point_i32.y - geo.loc.y < TAB_HEIGHT {
stack_ui = Some(( stack_ui = Some((
PointerFocusTarget::StackUI(self.clone()), PointerFocusTarget::StackUI(self.clone()),
Point::from((0., 0.)), Point::from((0., 0.)),
)); ));
}
} }
relative_pos.y -= TAB_HEIGHT as f64; relative_pos.y -= TAB_HEIGHT as f64;
let active_window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)]; let active_window = &p.windows.lock().unwrap()[p.active.load(Ordering::SeqCst)];
active_window stack_ui.or_else(|| {
.0 active_window
.surface_under(relative_pos, WindowSurfaceType::ALL) .0
.map(|(surface, surface_offset)| { .surface_under(relative_pos, surface_type)
( .map(|(surface, surface_offset)| {
PointerFocusTarget::WlSurface { (
surface, PointerFocusTarget::WlSurface {
toplevel: Some(active_window.clone().into()), surface,
}, toplevel: Some(active_window.clone().into()),
surface_offset.to_f64() + Point::from((0., TAB_HEIGHT as f64)), },
) surface_offset.to_f64() + Point::from((0., TAB_HEIGHT as f64)),
}) )
.or(stack_ui) })
})
}) })
} }
@ -1034,7 +1038,7 @@ impl SpaceElement for CosmicStack {
}) })
} }
fn is_in_input_region(&self, point: &Point<f64, Logical>) -> bool { fn is_in_input_region(&self, point: &Point<f64, Logical>) -> bool {
self.focus_under(*point).is_some() self.focus_under(*point, WindowSurfaceType::ALL).is_some()
} }
fn set_activate(&self, activated: bool) { fn set_activate(&self, activated: bool) {
SpaceElement::set_activate(&self.0, activated); SpaceElement::set_activate(&self.0, activated);

View file

@ -243,11 +243,12 @@ impl CosmicWindow {
pub fn focus_under( pub fn focus_under(
&self, &self,
mut relative_pos: Point<f64, Logical>, mut relative_pos: Point<f64, Logical>,
surface_type: WindowSurfaceType,
) -> Option<(PointerFocusTarget, Point<f64, Logical>)> { ) -> Option<(PointerFocusTarget, Point<f64, Logical>)> {
self.0.with_program(|p| { self.0.with_program(|p| {
let mut offset = Point::from((0., 0.)); let mut offset = Point::from((0., 0.));
let mut window_ui = None; let mut window_ui = None;
if p.has_ssd(false) { if p.has_ssd(false) && surface_type.contains(WindowSurfaceType::TOPLEVEL) {
let geo = p.window.geometry(); let geo = p.window.geometry();
let point_i32 = relative_pos.to_i32_round::<i32>(); let point_i32 = relative_pos.to_i32_round::<i32>();
@ -275,19 +276,19 @@ impl CosmicWindow {
offset.y += SSD_HEIGHT as f64; offset.y += SSD_HEIGHT as f64;
} }
p.window window_ui.or_else(|| {
.0 p.window.0.surface_under(relative_pos, surface_type).map(
.surface_under(relative_pos, WindowSurfaceType::ALL) |(surface, surface_offset)| {
.map(|(surface, surface_offset)| { (
( PointerFocusTarget::WlSurface {
PointerFocusTarget::WlSurface { surface,
surface, toplevel: Some(p.window.clone().into()),
toplevel: Some(p.window.clone().into()), },
}, (offset + surface_offset.to_f64()),
(offset + surface_offset.to_f64()), )
) },
}) )
.or(window_ui) })
}) })
} }
@ -561,7 +562,7 @@ impl SpaceElement for CosmicWindow {
}) })
} }
fn is_in_input_region(&self, point: &Point<f64, Logical>) -> bool { fn is_in_input_region(&self, point: &Point<f64, Logical>) -> bool {
self.focus_under(*point).is_some() self.focus_under(*point, WindowSurfaceType::ALL).is_some()
} }
fn set_activate(&self, activated: bool) { fn set_activate(&self, activated: bool) {
if self if self

View file

@ -232,8 +232,8 @@ fn update_focus_state(
if should_update_cursor && state.common.config.cosmic_conf.cursor_follows_focus { if should_update_cursor && state.common.config.cosmic_conf.cursor_follows_focus {
if target.is_some() { if target.is_some() {
//need to borrow mutably for surface under //need to borrow mutably for surface under
let mut shell = state.common.shell.write().unwrap(); let shell = state.common.shell.read().unwrap();
// get geometry of the target element // get the top left corner of the target element
let geometry = shell.focused_geometry(target.unwrap()); let geometry = shell.focused_geometry(target.unwrap());
if let Some(geometry) = geometry { if let Some(geometry) = geometry {
// get the center of the target element // get the center of the target element
@ -247,10 +247,9 @@ fn update_focus_state(
.cloned() .cloned()
.unwrap_or(seat.active_output()); .unwrap_or(seat.active_output());
let focus = shell let focus = State::surface_under(new_pos, &output, &*shell)
.surface_under(new_pos, &output)
.map(|(focus, loc)| (focus, loc.as_logical())); .map(|(focus, loc)| (focus, loc.as_logical()));
//drop here to avoid multiple mutable borrows //drop here to avoid multiple borrows
mem::drop(shell); mem::drop(shell);
seat.get_pointer().unwrap().motion( seat.get_pointer().unwrap().motion(
state, state,

View file

@ -27,7 +27,7 @@ use smithay::{
ImportAll, ImportMem, Renderer, ImportAll, ImportMem, Renderer,
}, },
}, },
desktop::{layer_map_for_output, space::SpaceElement}, desktop::{layer_map_for_output, space::SpaceElement, WindowSurfaceType},
input::{ input::{
pointer::{ pointer::{
AxisFrame, ButtonEvent, CursorIcon, GestureHoldBeginEvent, GestureHoldEndEvent, AxisFrame, ButtonEvent, CursorIcon, GestureHoldBeginEvent, GestureHoldEndEvent,
@ -864,7 +864,7 @@ impl Drop for MoveGrab {
let current_location = pointer.current_location(); let current_location = pointer.current_location();
if let Some((target, offset)) = if let Some((target, offset)) =
mapped.focus_under(current_location - position.as_logical().to_f64()) mapped.focus_under(current_location - position.as_logical().to_f64(), WindowSurfaceType::ALL)
{ {
pointer.motion( pointer.motion(
state, state,

View file

@ -728,16 +728,115 @@ impl FloatingLayout {
self.space.element_geometry(elem).map(RectExt::as_local) self.space.element_geometry(elem).map(RectExt::as_local)
} }
pub fn element_under(&self, location: Point<f64, Local>) -> Option<KeyboardFocusTarget> { pub fn popup_element_under(&self, location: Point<f64, Local>) -> Option<KeyboardFocusTarget> {
self.space self.space
.element_under(location.as_logical()) .elements()
.map(|(mapped, _)| mapped.clone().into()) .rev()
.map(|e| (e, self.space.element_location(e).unwrap() - e.geometry().loc))
.filter(|(e, render_location)| {
let mut bbox = e.bbox();
bbox.loc += *render_location;
bbox.to_f64().contains(location.as_logical())
})
.find_map(|(e, render_location)| {
let render_location = render_location
.as_local()
.to_f64();
let point = location - render_location;
if e.focus_under(point.as_logical(), WindowSurfaceType::POPUP | WindowSurfaceType::SUBSURFACE).is_some() {
Some(e.clone().into())
} else {
None
}
})
}
pub fn toplevel_element_under(&self, location: Point<f64, Local>) -> Option<KeyboardFocusTarget> {
self.space
.elements()
.rev()
.map(|e| (e, self.space.element_location(e).unwrap() - e.geometry().loc))
.filter(|(e, render_location)| {
let mut bbox = e.bbox();
bbox.loc += *render_location;
bbox.to_f64().contains(location.as_logical())
})
.find_map(|(e, render_location)| {
let render_location = render_location
.as_local()
.to_f64();
let point = location - render_location;
if e.focus_under(point.as_logical(), WindowSurfaceType::TOPLEVEL | WindowSurfaceType::SUBSURFACE).is_some() {
Some(e.clone().into())
} else {
None
}
})
} }
pub fn surface_under( pub fn popup_surface_under(
&mut self, &self,
location: Point<f64, Local>, location: Point<f64, Local>,
) -> Option<(PointerFocusTarget, Point<f64, Local>)> { ) -> Option<(PointerFocusTarget, Point<f64, Local>)> {
self.space
.elements()
.rev()
.map(|e| (e, self.space.element_location(e).unwrap() - e.geometry().loc))
.filter(|(e, render_location)| {
let mut bbox = e.bbox();
bbox.loc += *render_location;
bbox.to_f64().contains(location.as_logical())
})
.find_map(|(e, render_location)| {
let render_location = render_location
.as_local()
.to_f64();
let point = location - render_location;
e.focus_under(
point.as_logical(),
WindowSurfaceType::POPUP | WindowSurfaceType::SUBSURFACE,
)
.map(|(surface, surface_offset)| {
(surface, render_location + surface_offset.as_local())
})
})
}
pub fn toplevel_surface_under(
&self,
location: Point<f64, Local>,
) -> Option<(PointerFocusTarget, Point<f64, Local>)> {
self.space
.elements()
.rev()
.map(|e| (e, self.space.element_location(e).unwrap() - e.geometry().loc))
.filter(|(e, render_location)| {
let mut bbox = e.bbox();
bbox.loc += *render_location;
bbox.to_f64().contains(location.as_logical())
})
.find_map(|(e, render_location)| {
let render_location = render_location.as_local().to_f64();
let point = location - render_location;
e.focus_under(
point.as_logical(),
WindowSurfaceType::TOPLEVEL | WindowSurfaceType::SUBSURFACE,
)
.map(|(surface, surface_offset)| {
(
surface,
render_location + surface_offset.as_local(),
)
})
})
}
pub fn update_pointer_position(&mut self, location: Option<Point<f64, Local>>) {
let Some(location) = location else {
self.hovered_stack.take();
return;
};
let res = self let res = self
.space .space
.element_under(location.as_logical()) .element_under(location.as_logical())
@ -754,15 +853,6 @@ impl FloatingLayout {
} else { } else {
self.hovered_stack.take(); self.hovered_stack.take();
} }
res.and_then(|(element, space_offset)| {
let point = location - space_offset.to_f64();
element
.focus_under(point.as_logical())
.map(|(surface, surface_offset)| {
(surface, space_offset.to_f64() + surface_offset.as_local())
})
})
} }
pub fn stacking_indicator(&self) -> Option<Rectangle<i32, Local>> { pub fn stacking_indicator(&self) -> Option<Rectangle<i32, Local>> {

View file

@ -56,7 +56,7 @@ use smithay::{
glow::GlowRenderer, glow::GlowRenderer,
ImportAll, ImportMem, Renderer, ImportAll, ImportMem, Renderer,
}, },
desktop::{layer_map_for_output, space::SpaceElement, PopupKind}, desktop::{layer_map_for_output, space::SpaceElement, PopupKind, WindowSurfaceType},
input::Seat, input::Seat,
output::Output, output::Output,
reexports::wayland_server::Client, reexports::wayland_server::Client,
@ -3104,17 +3104,38 @@ impl TilingLayout {
None None
} }
pub fn element_under(&self, location_f64: Point<f64, Local>) -> Option<KeyboardFocusTarget> { pub fn popup_element_under(&self, location_f64: Point<f64, Local>) -> Option<KeyboardFocusTarget> {
let location = location_f64.to_i32_round(); let location = location_f64.to_i32_round();
for (mapped, geo) in self.mapped() { for (mapped, geo) in self.mapped() {
if !mapped.bbox().contains((location - geo.loc).as_logical()) { if !mapped.bbox().contains((location - geo.loc).as_logical()) {
continue; continue;
} }
if mapped.is_in_input_region(
&((location_f64 - geo.loc.to_f64()).as_logical() + mapped.geometry().loc.to_f64()), if mapped.focus_under(
) { (location_f64 - geo.loc.to_f64()).as_logical() + mapped.geometry().loc.to_f64(),
WindowSurfaceType::POPUP | WindowSurfaceType::SUBSURFACE,
).is_some() {
return Some(mapped.clone().into());
}
}
None
}
pub fn toplevel_element_under(&self, location_f64: Point<f64, Local>) -> Option<KeyboardFocusTarget> {
let location = location_f64.to_i32_round();
for (mapped, geo) in self.mapped() {
if !mapped.bbox().contains((location - geo.loc).as_logical()) {
continue;
}
if mapped.focus_under(
(location_f64 - geo.loc.to_f64()).as_logical() + mapped.geometry().loc.to_f64(),
WindowSurfaceType::TOPLEVEL | WindowSurfaceType::SUBSURFACE,
).is_some() {
return Some(mapped.clone().into()); return Some(mapped.clone().into());
} }
} }
@ -3122,34 +3143,13 @@ impl TilingLayout {
None None
} }
pub fn surface_under( pub fn popup_surface_under(
&mut self, &self,
location_f64: Point<f64, Local>, location_f64: Point<f64, Local>,
overview: OverviewMode, overview: OverviewMode,
) -> Option<(PointerFocusTarget, Point<f64, Local>)> { ) -> Option<(PointerFocusTarget, Point<f64, Local>)> {
let gaps = self.gaps();
let last_overview_hover = &mut self.last_overview_hover;
let placeholder_id = &self.placeholder_id;
let tree = &self.queue.trees.back().unwrap().0;
let root = tree.root_node_id()?;
let location = location_f64.to_i32_round(); let location = location_f64.to_i32_round();
{
let output_geo =
Rectangle::from_loc_and_size((0, 0), self.output.geometry().size.as_logical())
.as_local();
if !output_geo.contains(location) {
return None;
}
}
if !matches!(
overview,
OverviewMode::Started(_, _) | OverviewMode::Active(_)
) {
last_overview_hover.take();
}
if matches!(overview, OverviewMode::None) { if matches!(overview, OverviewMode::None) {
for (mapped, geo) in self.mapped() { for (mapped, geo) in self.mapped() {
if !mapped.bbox().contains((location - geo.loc).as_logical()) { if !mapped.bbox().contains((location - geo.loc).as_logical()) {
@ -3157,6 +3157,37 @@ impl TilingLayout {
} }
if let Some((target, surface_offset)) = mapped.focus_under( if let Some((target, surface_offset)) = mapped.focus_under(
(location_f64 - geo.loc.to_f64()).as_logical() + mapped.geometry().loc.to_f64(), (location_f64 - geo.loc.to_f64()).as_logical() + mapped.geometry().loc.to_f64(),
WindowSurfaceType::POPUP | WindowSurfaceType::SUBSURFACE,
) {
return Some((
target,
geo.loc.to_f64() - mapped.geometry().loc.as_local().to_f64()
+ surface_offset.as_local(),
));
}
}
}
None
}
pub fn toplevel_surface_under(
&self,
location_f64: Point<f64, Local>,
overview: OverviewMode,
) -> Option<(PointerFocusTarget, Point<f64, Local>)> {
let tree = &self.queue.trees.back().unwrap().0;
let root = tree.root_node_id()?;
let location = location_f64.to_i32_round();
if matches!(overview, OverviewMode::None) {
for (mapped, geo) in self.mapped() {
if !mapped.bbox().contains((location - geo.loc).as_logical()) {
continue;
}
if let Some((target, surface_offset)) = mapped.focus_under(
(location_f64 - geo.loc.to_f64()).as_logical() + mapped.geometry().loc.to_f64(),
WindowSurfaceType::TOPLEVEL | WindowSurfaceType::SUBSURFACE,
) { ) {
return Some(( return Some((
target, target,
@ -3204,7 +3235,10 @@ impl TilingLayout {
+ mapped.geometry().loc.to_f64().as_local()) + mapped.geometry().loc.to_f64().as_local())
.as_logical(); .as_logical();
mapped mapped
.focus_under(test_point) .focus_under(
test_point,
WindowSurfaceType::TOPLEVEL | WindowSurfaceType::SUBSURFACE,
)
.map(|(surface, surface_offset)| { .map(|(surface, surface_offset)| {
( (
surface, surface,
@ -3257,7 +3291,37 @@ impl TilingLayout {
} }
_ => None, _ => None,
} }
} else if matches!( } else {
None
}
}
pub fn update_pointer_position(
&mut self,
location_f64: Option<Point<f64, Local>>,
overview: OverviewMode,
) {
let gaps = self.gaps();
let last_overview_hover = &mut self.last_overview_hover;
let placeholder_id = &self.placeholder_id;
let tree = &self.queue.trees.back().unwrap().0;
let Some(root) = tree.root_node_id() else {
return;
};
if !matches!(
overview,
OverviewMode::Started(_, _) | OverviewMode::Active(_)
) || location_f64.is_none()
{
last_overview_hover.take();
return;
}
let location_f64 = location_f64.unwrap();
let location = location_f64.to_i32_round();
if matches!(
overview.active_trigger(), overview.active_trigger(),
Some(Trigger::Pointer(_) | Trigger::Touch(_)) Some(Trigger::Pointer(_) | Trigger::Touch(_))
) { ) {
@ -3319,7 +3383,9 @@ impl TilingLayout {
} }
if let Some(res_id) = result { if let Some(res_id) = result {
let mut last_geometry = *geometries.get(&res_id)?; let Some(mut last_geometry) = geometries.get(&res_id).copied() else {
return;
};
let node = tree.get(&res_id).unwrap(); let node = tree.get(&res_id).unwrap();
let data = node.data().clone(); let data = node.data().clone();
@ -3716,10 +3782,6 @@ impl TilingLayout {
} }
} }
} }
None
} else {
None
} }
} }

View file

@ -54,8 +54,6 @@ use smithay::{
xwayland::X11Surface, xwayland::X11Surface,
}; };
use smithay::wayland::shell::wlr_layer::Layer as WlrLayer;
use crate::{ use crate::{
backend::render::animations::spring::{Spring, SpringParams}, backend::render::animations::spring::{Spring, SpringParams},
config::Config, config::Config,
@ -1532,97 +1530,6 @@ impl Shell {
} }
} }
/// Derives a keyboard focus target from a global position, and indicates whether the
/// the shell should start a move request event. Used during cursor related focus checks
pub fn keyboard_target_from_position(
&self,
global_position: Point<f64, Global>,
output: &Output,
) -> Option<KeyboardFocusTarget> {
let relative_pos = global_position.to_local(output);
let mut under: Option<KeyboardFocusTarget> = None;
// if the lockscreen is active
if let Some(session_lock) = self.session_lock.as_ref() {
under = session_lock
.surfaces
.get(output)
.map(|lock| lock.clone().into());
// if the output can receive keyboard focus
} else if let Some(window) = self.active_space(output).get_fullscreen() {
let layers = layer_map_for_output(output);
if let Some(layer) = layers.layer_under(WlrLayer::Overlay, relative_pos.as_logical()) {
let layer_loc = layers.layer_geometry(layer).unwrap().loc;
if layer.can_receive_keyboard_focus()
&& layer
.surface_under(
relative_pos.as_logical() - layer_loc.to_f64(),
WindowSurfaceType::ALL,
)
.is_some()
{
under = Some(layer.clone().into());
}
} else {
under = Some(window.clone().into());
}
} else {
let done = {
let layers = layer_map_for_output(output);
if let Some(layer) = layers
.layer_under(WlrLayer::Overlay, relative_pos.as_logical())
.or_else(|| layers.layer_under(WlrLayer::Top, relative_pos.as_logical()))
{
let layer_loc = layers.layer_geometry(layer).unwrap().loc;
if layer.can_receive_keyboard_focus()
&& layer
.surface_under(
relative_pos.as_logical() - layer_loc.to_f64(),
WindowSurfaceType::ALL,
)
.is_some()
{
under = Some(layer.clone().into());
true
} else {
false
}
} else {
false
}
};
if !done {
// Don't check override redirect windows, because we don't set keyboard focus to them explicitly.
// These cases are handled by the XwaylandKeyboardGrab.
if let Some(target) = self.element_under(global_position, output) {
under = Some(target);
} else {
let layers = layer_map_for_output(output);
if let Some(layer) = layers
.layer_under(WlrLayer::Bottom, relative_pos.as_logical())
.or_else(|| {
layers.layer_under(WlrLayer::Background, relative_pos.as_logical())
})
{
let layer_loc = layers.layer_geometry(layer).unwrap().loc;
if layer.can_receive_keyboard_focus()
&& layer
.surface_under(
relative_pos.as_logical() - layer_loc.to_f64(),
WindowSurfaceType::ALL,
)
.is_some()
{
under = Some(layer.clone().into());
}
};
}
}
}
under
}
/// Coerce a keyboard focus target into a CosmicMapped element. This is useful when performing window specific /// Coerce a keyboard focus target into a CosmicMapped element. This is useful when performing window specific
/// actions, such as closing a window /// actions, such as closing a window
pub fn focused_element(&self, focus_target: &KeyboardFocusTarget) -> Option<CosmicMapped> { pub fn focused_element(&self, focus_target: &KeyboardFocusTarget) -> Option<CosmicMapped> {
@ -2053,6 +1960,26 @@ impl Shell {
self.pending_windows.retain(|(s, _, _)| s.alive()); self.pending_windows.retain(|(s, _, _)| s.alive());
} }
pub fn update_pointer_position(&mut self, location: Point<f64, Local>, output: &Output) {
for (o, set) in self.workspaces.sets.iter_mut() {
if o == output {
set.sticky_layer.update_pointer_position(Some(location));
for (i, workspace) in set.workspaces.iter_mut().enumerate() {
if i == set.active {
workspace.update_pointer_position(Some(location), self.overview_mode.clone());
} else {
workspace.update_pointer_position(None, self.overview_mode.clone());
}
}
} else {
set.sticky_layer.update_pointer_position(None);
for workspace in &mut set.workspaces {
workspace.update_pointer_position(None, self.overview_mode.clone());
}
}
}
}
pub fn remap_unfullscreened_window( pub fn remap_unfullscreened_window(
&mut self, &mut self,
mapped: CosmicMapped, mapped: CosmicMapped,
@ -2382,33 +2309,6 @@ impl Shell {
} }
} }
pub fn element_under(
&self,
location: Point<f64, Global>,
output: &Output,
) -> Option<KeyboardFocusTarget> {
self.workspaces.sets.get(output).and_then(|set| {
set.sticky_layer
.space
.element_under(location.to_local(output).as_logical())
.map(|(mapped, _)| mapped.clone().into())
.or_else(|| set.workspaces[set.active].element_under(location))
})
}
pub fn surface_under(
&mut self,
location: Point<f64, Global>,
output: &Output,
) -> Option<(PointerFocusTarget, Point<f64, Global>)> {
let overview = self.overview_mode.clone();
self.workspaces.sets.get_mut(output).and_then(|set| {
set.sticky_layer
.surface_under(location.to_local(output))
.map(|(target, offset)| (target, offset.to_global(output)))
.or_else(|| set.workspaces[set.active].surface_under(location, overview))
})
}
#[must_use] #[must_use]
pub fn move_window( pub fn move_window(
&mut self, &mut self,
@ -2782,7 +2682,7 @@ impl Shell {
let mapped = if move_out_of_stack { let mapped = if move_out_of_stack {
let new_mapped: CosmicMapped = let new_mapped: CosmicMapped =
CosmicWindow::new(window.clone(), evlh.clone(), self.theme.clone()).into(); CosmicWindow::new(window.clone(), evlh.clone(), self.theme.clone()).into();
start_data.set_focus(new_mapped.focus_under((0., 0.).into())); start_data.set_focus(new_mapped.focus_under((0., 0.).into(), WindowSurfaceType::ALL));
new_mapped new_mapped
} else { } else {
old_mapped.clone() old_mapped.clone()
@ -3250,7 +3150,7 @@ impl Shell {
let element_offset = (new_loc - geometry.loc).as_logical(); let element_offset = (new_loc - geometry.loc).as_logical();
let focus = mapped let focus = mapped
.focus_under(element_offset.to_f64()) .focus_under(element_offset.to_f64(), WindowSurfaceType::ALL)
.map(|(target, surface_offset)| (target, (surface_offset + element_offset.to_f64()))); .map(|(target, surface_offset)| (target, (surface_offset + element_offset.to_f64())));
start_data.set_location(new_loc.as_logical().to_f64()); start_data.set_location(new_loc.as_logical().to_f64());
start_data.set_focus(focus.clone()); start_data.set_focus(focus.clone());

View file

@ -34,7 +34,7 @@ use smithay::{
utils::{DamageSet, OpaqueRegions}, utils::{DamageSet, OpaqueRegions},
ImportAll, ImportMem, Renderer, ImportAll, ImportMem, Renderer,
}, },
desktop::{layer_map_for_output, space::SpaceElement}, desktop::{layer_map_for_output, space::SpaceElement, WindowSurfaceType},
input::Seat, input::Seat,
output::Output, output::Output,
reexports::wayland_server::{Client, Resource}, reexports::wayland_server::{Client, Resource},
@ -434,6 +434,27 @@ impl Workspace {
} }
} }
fn fullscreen_geometry(&self) -> Option<Rectangle<i32, Local>> {
self.fullscreen.as_ref().map(|fullscreen| {
let bbox = fullscreen.surface.bbox().as_local();
let mut full_geo =
Rectangle::from_loc_and_size((0, 0), self.output.geometry().size.as_local());
if bbox != full_geo {
if bbox.size.w < full_geo.size.w {
full_geo.loc.x += (full_geo.size.w - bbox.size.w) / 2;
full_geo.size.w = bbox.size.w;
}
if bbox.size.h < full_geo.size.h {
full_geo.loc.y += (full_geo.size.h - bbox.size.h) / 2;
full_geo.size.h = bbox.size.h;
}
}
full_geo
})
}
pub fn element_for_surface<S>(&self, surface: &S) -> Option<&CosmicMapped> pub fn element_for_surface<S>(&self, surface: &S) -> Option<&CosmicMapped>
where where
CosmicSurface: PartialEq<S>, CosmicSurface: PartialEq<S>,
@ -445,25 +466,151 @@ impl Workspace {
.find(|e| e.windows().any(|(w, _)| &w == surface)) .find(|e| e.windows().any(|(w, _)| &w == surface))
} }
pub fn element_under(&self, location: Point<f64, Global>) -> Option<KeyboardFocusTarget> { pub fn popup_element_under(&self, location: Point<f64, Global>) -> Option<KeyboardFocusTarget> {
if !self.output.geometry().contains(location.to_i32_round()) {
return None;
}
let location = location.to_local(&self.output); let location = location.to_local(&self.output);
if let Some(fullscreen) = self.fullscreen.as_ref() {
if !fullscreen.is_animating() {
let geometry = self.fullscreen_geometry().unwrap();
return fullscreen
.surface
.0
.surface_under(
(location + geometry.loc.to_f64()).as_logical(),
WindowSurfaceType::POPUP | WindowSurfaceType::SUBSURFACE,
)
.is_some()
.then(|| KeyboardFocusTarget::Fullscreen(fullscreen.surface.clone()));
}
}
self.floating_layer self.floating_layer
.element_under(location) .popup_element_under(location)
.or_else(|| self.tiling_layer.element_under(location)) .or_else(|| self.tiling_layer.popup_element_under(location))
} }
pub fn surface_under( pub fn toplevel_element_under(
&mut self, &self,
location: Point<f64, Global>,
) -> Option<KeyboardFocusTarget> {
if !self.output.geometry().contains(location.to_i32_round()) {
return None;
}
let location = location.to_local(&self.output);
if let Some(fullscreen) = self.fullscreen.as_ref() {
if !fullscreen.is_animating() {
let geometry = self.fullscreen_geometry().unwrap();
return fullscreen
.surface
.0
.surface_under(
(location + geometry.loc.to_f64()).as_logical(),
WindowSurfaceType::TOPLEVEL | WindowSurfaceType::SUBSURFACE,
)
.is_some()
.then(|| KeyboardFocusTarget::Fullscreen(fullscreen.surface.clone()));
}
}
self.floating_layer
.toplevel_element_under(location)
.or_else(|| self.tiling_layer.toplevel_element_under(location))
}
pub fn popup_surface_under(
&self,
location: Point<f64, Global>, location: Point<f64, Global>,
overview: OverviewMode, overview: OverviewMode,
) -> Option<(PointerFocusTarget, Point<f64, Global>)> { ) -> Option<(PointerFocusTarget, Point<f64, Global>)> {
if !self.output.geometry().contains(location.to_i32_round()) {
return None;
}
let location = location.to_local(&self.output); let location = location.to_local(&self.output);
if let Some(fullscreen) = self.fullscreen.as_ref() {
if !fullscreen.is_animating() {
let geometry = self.fullscreen_geometry().unwrap();
return fullscreen
.surface
.0
.surface_under(
(location + geometry.loc.to_f64()).as_logical(),
WindowSurfaceType::POPUP | WindowSurfaceType::SUBSURFACE,
)
.map(|(surface, surface_offset)| {
(
PointerFocusTarget::WlSurface {
surface,
toplevel: Some(fullscreen.surface.clone().into()),
},
(geometry.loc + surface_offset.as_local())
.to_global(&self.output)
.to_f64(),
)
});
}
}
self.floating_layer self.floating_layer
.surface_under(location) .popup_surface_under(location)
.or_else(|| self.tiling_layer.surface_under(location, overview)) .or_else(|| self.tiling_layer.popup_surface_under(location, overview))
.map(|(m, p)| (m, p.to_global(&self.output))) .map(|(m, p)| (m, p.to_global(&self.output)))
} }
pub fn toplevel_surface_under(
&self,
location: Point<f64, Global>,
overview: OverviewMode,
) -> Option<(PointerFocusTarget, Point<f64, Global>)> {
if !self.output.geometry().contains(location.to_i32_round()) {
return None;
}
let location = location.to_local(&self.output);
if let Some(fullscreen) = self.fullscreen.as_ref() {
if !fullscreen.is_animating() {
let geometry = self.fullscreen_geometry().unwrap();
return fullscreen
.surface
.0
.surface_under(
(location + geometry.loc.to_f64()).as_logical(),
WindowSurfaceType::TOPLEVEL | WindowSurfaceType::SUBSURFACE,
)
.map(|(surface, surface_offset)| {
(
PointerFocusTarget::WlSurface {
surface,
toplevel: Some(fullscreen.surface.clone().into()),
},
(geometry.loc + surface_offset.as_local())
.to_global(&self.output)
.to_f64(),
)
});
}
}
self.floating_layer
.toplevel_surface_under(location)
.or_else(|| self.tiling_layer.toplevel_surface_under(location, overview))
.map(|(m, p)| (m, p.to_global(&self.output)))
}
pub fn update_pointer_position(
&mut self,
location: Option<Point<f64, Local>>,
overview: OverviewMode,
) {
self.floating_layer.update_pointer_position(location);
self.tiling_layer
.update_pointer_position(location, overview);
}
pub fn element_geometry(&self, elem: &CosmicMapped) -> Option<Rectangle<i32, Local>> { pub fn element_geometry(&self, elem: &CosmicMapped) -> Option<Rectangle<i32, Local>> {
self.floating_layer self.floating_layer
.element_geometry(elem) .element_geometry(elem)