mirror of
https://github.com/YaLTeR/niri.git
synced 2025-12-23 05:36:51 +00:00
wip look into Keyboard/PointerTarget
Decided not to pursue this for now. The idea was to extract input handling from input/mod.rs into the respective modules, plus get rid of manual cursor shape resetting, but there are some roadblocks: - The pointer is locked when those methods are called, meaning you can't get the current location (have to store from enter/motion) and, more crucially, can't set grabs—we need this for the Overview. - Gesture begin/end is handled at the Wayland object level, meaning PointerTargets get to deal with "improper" events themselves, reducing their utility. cosmic-comp spawns an idle callback for this which seems awkward and is asking for problems. - We're not actually removing much code at all, only adding more code for the blanket wrappers and such.
This commit is contained in:
parent
34b05e8671
commit
bf4e8cd233
7 changed files with 472 additions and 56 deletions
253
src/focus.rs
Normal file
253
src/focus.rs
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use smithay::backend::input::KeyState;
|
||||
use smithay::desktop::PopupKind;
|
||||
use smithay::input::keyboard::{KeyboardTarget, KeysymHandle, ModifiersState};
|
||||
use smithay::input::pointer::{self, PointerTarget};
|
||||
use smithay::input::Seat;
|
||||
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
|
||||
use smithay::utils::{IsAlive, Serial};
|
||||
use smithay::wayland::seat::WaylandFocus;
|
||||
|
||||
use crate::niri::State;
|
||||
use crate::ui::screenshot_ui::ScreenshotUiFocusTarget;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum KeyboardFocusTarget {
|
||||
Surface(WlSurface),
|
||||
ScreenshotUi(ScreenshotUiFocusTarget),
|
||||
Overview,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum PointerFocusTarget {
|
||||
Surface(WlSurface),
|
||||
ScreenshotUi(ScreenshotUiFocusTarget),
|
||||
Overview,
|
||||
}
|
||||
|
||||
impl KeyboardFocusTarget {
|
||||
fn inner(&self) -> &dyn KeyboardTarget<State> {
|
||||
match self {
|
||||
Self::Surface(surface) => surface,
|
||||
Self::ScreenshotUi(x) => x,
|
||||
Self::Overview => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PointerFocusTarget {
|
||||
fn inner(&self) -> &dyn PointerTarget<State> {
|
||||
match self {
|
||||
Self::Surface(surface) => surface,
|
||||
Self::ScreenshotUi(x) => x,
|
||||
Self::Overview => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn surface(&self) -> Option<&WlSurface> {
|
||||
match self {
|
||||
PointerFocusTarget::Surface(surface) => Some(surface),
|
||||
PointerFocusTarget::ScreenshotUi(_) => None,
|
||||
PointerFocusTarget::Overview => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<KeyboardFocusTarget> for PointerFocusTarget {
|
||||
fn from(value: KeyboardFocusTarget) -> Self {
|
||||
match value {
|
||||
KeyboardFocusTarget::Surface(surface) => Self::Surface(surface),
|
||||
KeyboardFocusTarget::ScreenshotUi(x) => Self::ScreenshotUi(x),
|
||||
KeyboardFocusTarget::Overview => Self::Overview,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<PopupKind> for KeyboardFocusTarget {
|
||||
fn from(value: PopupKind) -> Self {
|
||||
Self::Surface(value.wl_surface().clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl WaylandFocus for KeyboardFocusTarget {
|
||||
fn wl_surface(&self) -> Option<Cow<'_, WlSurface>> {
|
||||
match self {
|
||||
Self::Surface(surface) => Some(surface),
|
||||
Self::ScreenshotUi(_) => None,
|
||||
Self::Overview => None,
|
||||
}
|
||||
.map(Cow::Borrowed)
|
||||
}
|
||||
}
|
||||
|
||||
impl WaylandFocus for PointerFocusTarget {
|
||||
fn wl_surface(&self) -> Option<Cow<'_, WlSurface>> {
|
||||
self.surface().map(Cow::Borrowed)
|
||||
}
|
||||
}
|
||||
|
||||
impl IsAlive for KeyboardFocusTarget {
|
||||
fn alive(&self) -> bool {
|
||||
match self {
|
||||
Self::Surface(surface) => surface.alive(),
|
||||
Self::ScreenshotUi(_) => true,
|
||||
Self::Overview => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IsAlive for PointerFocusTarget {
|
||||
fn alive(&self) -> bool {
|
||||
match self {
|
||||
Self::Surface(surface) => surface.alive(),
|
||||
Self::ScreenshotUi(_) => true,
|
||||
Self::Overview => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyboardTarget<State> for KeyboardFocusTarget {
|
||||
fn enter(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
keys: Vec<KeysymHandle<'_>>,
|
||||
serial: Serial,
|
||||
) {
|
||||
self.inner().enter(seat, data, keys, serial);
|
||||
}
|
||||
|
||||
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial) {
|
||||
self.inner().leave(seat, data, serial);
|
||||
}
|
||||
|
||||
fn key(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
key: KeysymHandle<'_>,
|
||||
state: KeyState,
|
||||
serial: Serial,
|
||||
time: u32,
|
||||
) {
|
||||
self.inner().key(seat, data, key, state, serial, time);
|
||||
}
|
||||
|
||||
fn modifiers(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
modifiers: ModifiersState,
|
||||
serial: Serial,
|
||||
) {
|
||||
self.inner().modifiers(seat, data, modifiers, serial);
|
||||
}
|
||||
}
|
||||
|
||||
impl PointerTarget<State> for PointerFocusTarget {
|
||||
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &pointer::MotionEvent) {
|
||||
self.inner().enter(seat, data, event);
|
||||
}
|
||||
|
||||
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &pointer::MotionEvent) {
|
||||
self.inner().motion(seat, data, event);
|
||||
}
|
||||
|
||||
fn relative_motion(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
event: &pointer::RelativeMotionEvent,
|
||||
) {
|
||||
self.inner().relative_motion(seat, data, event);
|
||||
}
|
||||
|
||||
fn button(&self, seat: &Seat<State>, data: &mut State, event: &pointer::ButtonEvent) {
|
||||
self.inner().button(seat, data, event);
|
||||
}
|
||||
|
||||
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: pointer::AxisFrame) {
|
||||
self.inner().axis(seat, data, frame);
|
||||
}
|
||||
|
||||
fn frame(&self, seat: &Seat<State>, data: &mut State) {
|
||||
self.inner().frame(seat, data);
|
||||
}
|
||||
|
||||
fn gesture_swipe_begin(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
event: &pointer::GestureSwipeBeginEvent,
|
||||
) {
|
||||
self.inner().gesture_swipe_begin(seat, data, event);
|
||||
}
|
||||
|
||||
fn gesture_swipe_update(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
event: &pointer::GestureSwipeUpdateEvent,
|
||||
) {
|
||||
self.inner().gesture_swipe_update(seat, data, event);
|
||||
}
|
||||
|
||||
fn gesture_swipe_end(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
event: &pointer::GestureSwipeEndEvent,
|
||||
) {
|
||||
self.inner().gesture_swipe_end(seat, data, event);
|
||||
}
|
||||
|
||||
fn gesture_pinch_begin(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
event: &pointer::GesturePinchBeginEvent,
|
||||
) {
|
||||
self.inner().gesture_pinch_begin(seat, data, event);
|
||||
}
|
||||
|
||||
fn gesture_pinch_update(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
event: &pointer::GesturePinchUpdateEvent,
|
||||
) {
|
||||
self.inner().gesture_pinch_update(seat, data, event);
|
||||
}
|
||||
|
||||
fn gesture_pinch_end(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
event: &pointer::GesturePinchEndEvent,
|
||||
) {
|
||||
self.inner().gesture_pinch_end(seat, data, event);
|
||||
}
|
||||
|
||||
fn gesture_hold_begin(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
event: &pointer::GestureHoldBeginEvent,
|
||||
) {
|
||||
self.inner().gesture_hold_begin(seat, data, event);
|
||||
}
|
||||
|
||||
fn gesture_hold_end(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
event: &pointer::GestureHoldEndEvent,
|
||||
) {
|
||||
self.inner().gesture_hold_end(seat, data, event);
|
||||
}
|
||||
|
||||
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) {
|
||||
self.inner().leave(seat, data, serial, time);
|
||||
}
|
||||
}
|
||||
|
|
@ -40,6 +40,7 @@ use smithay::wayland::keyboard_shortcuts_inhibit::{
|
|||
};
|
||||
use smithay::wayland::output::OutputHandler;
|
||||
use smithay::wayland::pointer_constraints::{with_pointer_constraint, PointerConstraintsHandler};
|
||||
use smithay::wayland::seat::WaylandFocus;
|
||||
use smithay::wayland::security_context::{
|
||||
SecurityContext, SecurityContextHandler, SecurityContextListenerSource,
|
||||
};
|
||||
|
|
@ -75,6 +76,7 @@ use smithay::{
|
|||
delegate_viewporter, delegate_virtual_keyboard_manager, delegate_xdg_activation,
|
||||
};
|
||||
|
||||
use crate::focus::{KeyboardFocusTarget, PointerFocusTarget};
|
||||
pub use crate::handlers::xdg_shell::KdeDecorationsModeState;
|
||||
use crate::layout::workspace::WorkspaceId;
|
||||
use crate::layout::ActivateWindow;
|
||||
|
|
@ -102,8 +104,8 @@ use crate::{
|
|||
pub const XDG_ACTIVATION_TOKEN_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
|
||||
impl SeatHandler for State {
|
||||
type KeyboardFocus = WlSurface;
|
||||
type PointerFocus = WlSurface;
|
||||
type KeyboardFocus = KeyboardFocusTarget;
|
||||
type PointerFocus = PointerFocusTarget;
|
||||
type TouchFocus = WlSurface;
|
||||
|
||||
fn seat_state(&mut self) -> &mut SeatState<State> {
|
||||
|
|
@ -111,19 +113,16 @@ impl SeatHandler for State {
|
|||
}
|
||||
|
||||
fn cursor_image(&mut self, _seat: &Seat<Self>, mut image: CursorImageStatus) {
|
||||
// FIXME: this hack should be removable once the screenshot UI is tracked with a
|
||||
// PointerFocus properly.
|
||||
if self.niri.screenshot_ui.is_open() {
|
||||
image = CursorImageStatus::Named(CursorIcon::Crosshair);
|
||||
}
|
||||
self.niri.cursor_manager.set_cursor_image(image);
|
||||
// FIXME: more granular
|
||||
self.niri.queue_redraw_all();
|
||||
}
|
||||
|
||||
fn focus_changed(&mut self, seat: &Seat<Self>, focused: Option<&WlSurface>) {
|
||||
fn focus_changed(&mut self, seat: &Seat<Self>, focused: Option<&KeyboardFocusTarget>) {
|
||||
let dh = &self.niri.display_handle;
|
||||
let client = focused.and_then(|s| dh.get_client(s.id()).ok());
|
||||
let client = focused
|
||||
.and_then(|t| t.wl_surface())
|
||||
.and_then(|s| dh.get_client(s.id()).ok());
|
||||
set_data_device_focus(dh, seat, client.clone());
|
||||
set_primary_focus(dh, seat, client);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ use smithay::{
|
|||
};
|
||||
use tracing::field::Empty;
|
||||
|
||||
use crate::focus::KeyboardFocusTarget;
|
||||
use crate::input::move_grab::MoveGrab;
|
||||
use crate::input::resize_grab::ResizeGrab;
|
||||
use crate::input::touch_move_grab::TouchMoveGrab;
|
||||
|
|
@ -83,14 +84,16 @@ impl XdgShellHandler for State {
|
|||
if grab_serial == serial {
|
||||
let start_data = grab.start_data();
|
||||
if let Some((focus, _)) = &start_data.focus {
|
||||
if focus.id().same_client_as(&wl_surface.id()) {
|
||||
// Deny move requests from DnD grabs to work around
|
||||
// https://gitlab.gnome.org/GNOME/gtk/-/issues/7113
|
||||
let is_dnd_grab = grab.as_any().is::<DnDGrab<Self>>();
|
||||
if let Some(focus) = focus.surface() {
|
||||
if focus.id().same_client_as(&wl_surface.id()) {
|
||||
// Deny move requests from DnD grabs to work around
|
||||
// https://gitlab.gnome.org/GNOME/gtk/-/issues/7113
|
||||
let is_dnd_grab = grab.as_any().is::<DnDGrab<Self>>();
|
||||
|
||||
if !is_dnd_grab {
|
||||
grab_start_data =
|
||||
Some(PointerOrTouchStartData::Pointer(start_data.clone()));
|
||||
if !is_dnd_grab {
|
||||
grab_start_data =
|
||||
Some(PointerOrTouchStartData::Pointer(start_data.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -182,8 +185,10 @@ impl XdgShellHandler for State {
|
|||
if pointer.has_grab(serial) {
|
||||
if let Some(start_data) = pointer.grab_start_data() {
|
||||
if let Some((focus, _)) = &start_data.focus {
|
||||
if focus.id().same_client_as(&wl_surface.id()) {
|
||||
grab_start_data = Some(PointerOrTouchStartData::Pointer(start_data));
|
||||
if let Some(focus) = focus.surface() {
|
||||
if focus.id().same_client_as(&wl_surface.id()) {
|
||||
grab_start_data = Some(PointerOrTouchStartData::Pointer(start_data));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -372,11 +377,12 @@ impl XdgShellHandler for State {
|
|||
}
|
||||
|
||||
let seat = &self.niri.seat;
|
||||
let mut grab = match self
|
||||
.niri
|
||||
.popups
|
||||
.grab_popup(root.clone(), popup, seat, serial)
|
||||
{
|
||||
let mut grab = match self.niri.popups.grab_popup(
|
||||
KeyboardFocusTarget::Surface(root.clone()),
|
||||
popup,
|
||||
seat,
|
||||
serial,
|
||||
) {
|
||||
Ok(grab) => grab,
|
||||
Err(err) => {
|
||||
trace!("ignoring popup grab: {err:?}");
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ use touch_overview_grab::TouchOverviewGrab;
|
|||
use self::move_grab::MoveGrab;
|
||||
use self::resize_grab::ResizeGrab;
|
||||
use self::spatial_movement_grab::SpatialMovementGrab;
|
||||
use crate::focus::PointerFocusTarget;
|
||||
use crate::layout::scrolling::ScrollDirection;
|
||||
use crate::layout::{ActivateWindow, LayoutElement as _};
|
||||
use crate::niri::{CastTarget, PointerVisibility, State};
|
||||
|
|
@ -626,9 +627,6 @@ impl State {
|
|||
}
|
||||
|
||||
self.niri.screenshot_ui.close();
|
||||
self.niri
|
||||
.cursor_manager
|
||||
.set_cursor_image(CursorImageStatus::default_named());
|
||||
self.niri.queue_redraw_all();
|
||||
}
|
||||
Action::ScreenshotTogglePointer => {
|
||||
|
|
@ -2152,14 +2150,16 @@ impl State {
|
|||
//
|
||||
// FIXME: ideally this should use the pointer focus with up-to-date global location.
|
||||
let mut pointer_confined = None;
|
||||
if let Some(under) = &self.niri.pointer_contents.surface {
|
||||
if let Some(under @ (PointerFocusTarget::Surface(surface), _)) =
|
||||
&self.niri.pointer_contents.target
|
||||
{
|
||||
// No need to check if the pointer focus surface matches, because here we're checking
|
||||
// for an already-active constraint, and the constraint is deactivated when the focused
|
||||
// surface changes.
|
||||
let pos_within_surface = pos - under.1;
|
||||
|
||||
let mut pointer_locked = false;
|
||||
with_pointer_constraint(&under.0, &pointer, |constraint| {
|
||||
with_pointer_constraint(surface, &pointer, |constraint| {
|
||||
let Some(constraint) = constraint else { return };
|
||||
if !constraint.is_active() {
|
||||
return;
|
||||
|
|
@ -2251,7 +2251,7 @@ impl State {
|
|||
let mut prevent = false;
|
||||
|
||||
// Prevent the pointer from leaving the focused surface.
|
||||
if Some(&focus_surface.0) != under.surface.as_ref().map(|(s, _)| s) {
|
||||
if Some(&focus_surface.0) != under.target.as_ref().map(|(s, _)| s) {
|
||||
prevent = true;
|
||||
}
|
||||
|
||||
|
|
@ -2286,7 +2286,7 @@ impl State {
|
|||
|
||||
pointer.motion(
|
||||
self,
|
||||
under.surface.clone(),
|
||||
under.target.clone(),
|
||||
&MotionEvent {
|
||||
location: new_pos,
|
||||
serial,
|
||||
|
|
@ -2296,7 +2296,7 @@ impl State {
|
|||
|
||||
pointer.relative_motion(
|
||||
self,
|
||||
under.surface,
|
||||
under.target,
|
||||
&RelativeMotionEvent {
|
||||
delta: event.delta(),
|
||||
delta_unaccel: event.delta_unaccel(),
|
||||
|
|
@ -2385,7 +2385,7 @@ impl State {
|
|||
|
||||
pointer.motion(
|
||||
self,
|
||||
under.surface,
|
||||
under.target,
|
||||
&MotionEvent {
|
||||
location: pos,
|
||||
serial,
|
||||
|
|
@ -2761,7 +2761,9 @@ impl State {
|
|||
// updating the pointer contents.
|
||||
pointer
|
||||
.current_focus()
|
||||
.map(|surface| self.niri.find_root_shell_surface(&surface))
|
||||
.as_ref()
|
||||
.and_then(|target| target.surface())
|
||||
.map(|surface| self.niri.find_root_shell_surface(surface))
|
||||
.map_or(true, |root| {
|
||||
!self
|
||||
.niri
|
||||
|
|
@ -3102,7 +3104,9 @@ impl State {
|
|||
// Get window-specific scroll factor
|
||||
let window_scroll_factor = pointer
|
||||
.current_focus()
|
||||
.map(|focused| self.niri.find_root_shell_surface(&focused))
|
||||
.as_ref()
|
||||
.and_then(|target| target.surface())
|
||||
.map(|focused| self.niri.find_root_shell_surface(focused))
|
||||
.and_then(|root| self.niri.layout.find_window_and_output(&root).unzip().0)
|
||||
.and_then(|window| window.rules().scroll_factor)
|
||||
.unwrap_or(1.);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ pub mod cli;
|
|||
pub mod cursor;
|
||||
#[cfg(feature = "dbus")]
|
||||
pub mod dbus;
|
||||
pub mod focus;
|
||||
pub mod frame_clock;
|
||||
pub mod handlers;
|
||||
pub mod input;
|
||||
|
|
|
|||
58
src/niri.rs
58
src/niri.rs
|
|
@ -122,6 +122,7 @@ use crate::dbus::gnome_shell_introspect::{self, IntrospectToNiri, NiriToIntrospe
|
|||
use crate::dbus::gnome_shell_screenshot::{NiriToScreenshot, ScreenshotToNiri};
|
||||
#[cfg(feature = "xdp-gnome-screencast")]
|
||||
use crate::dbus::mutter_screen_cast::{self, ScreenCastToNiri};
|
||||
use crate::focus::{KeyboardFocusTarget, PointerFocusTarget};
|
||||
use crate::frame_clock::FrameClock;
|
||||
use crate::handlers::{configure_lock_surface, XDG_ACTIVATION_TOKEN_TIMEOUT};
|
||||
use crate::input::pick_color_grab::PickColorGrab;
|
||||
|
|
@ -161,7 +162,9 @@ use crate::ui::config_error_notification::ConfigErrorNotification;
|
|||
use crate::ui::exit_confirm_dialog::ExitConfirmDialog;
|
||||
use crate::ui::hotkey_overlay::HotkeyOverlay;
|
||||
use crate::ui::screen_transition::{self, ScreenTransition};
|
||||
use crate::ui::screenshot_ui::{OutputScreenshot, ScreenshotUi, ScreenshotUiRenderElement};
|
||||
use crate::ui::screenshot_ui::{
|
||||
OutputScreenshot, ScreenshotUi, ScreenshotUiFocusTarget, ScreenshotUiRenderElement,
|
||||
};
|
||||
use crate::utils::scale::{closest_representable_scale, guess_monitor_scale};
|
||||
use crate::utils::spawning::{CHILD_DISPLAY, CHILD_ENV};
|
||||
use crate::utils::watcher::Watcher;
|
||||
|
|
@ -524,6 +527,7 @@ pub struct PointContents {
|
|||
// Can be `None` even when `window` is set, for example when the pointer is over the niri
|
||||
// border around the window.
|
||||
pub surface: Option<(WlSurface, Point<f64, Logical>)>,
|
||||
pub target: Option<(PointerFocusTarget, Point<f64, Logical>)>,
|
||||
// If surface belongs to a window, this is that window.
|
||||
pub window: Option<(Window, HitType)>,
|
||||
// If surface belongs to a layer surface, this is that layer surface.
|
||||
|
|
@ -630,6 +634,18 @@ impl KeyboardFocus {
|
|||
pub fn is_overview(&self) -> bool {
|
||||
matches!(self, KeyboardFocus::Overview)
|
||||
}
|
||||
|
||||
pub fn into_target(self) -> Option<KeyboardFocusTarget> {
|
||||
match self {
|
||||
KeyboardFocus::Layout { surface } => surface.map(KeyboardFocusTarget::Surface),
|
||||
KeyboardFocus::LayerShell { surface } => Some(KeyboardFocusTarget::Surface(surface)),
|
||||
KeyboardFocus::LockScreen { surface } => surface.map(KeyboardFocusTarget::Surface),
|
||||
KeyboardFocus::ScreenshotUi => {
|
||||
Some(KeyboardFocusTarget::ScreenshotUi(ScreenshotUiFocusTarget))
|
||||
}
|
||||
KeyboardFocus::Overview => Some(KeyboardFocusTarget::Overview),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct State {
|
||||
|
|
@ -787,7 +803,7 @@ impl State {
|
|||
let pointer = &self.niri.seat.get_pointer().unwrap();
|
||||
pointer.motion(
|
||||
self,
|
||||
under.surface,
|
||||
under.target,
|
||||
&MotionEvent {
|
||||
location,
|
||||
serial: SERIAL_COUNTER.next_serial(),
|
||||
|
|
@ -998,7 +1014,7 @@ impl State {
|
|||
|
||||
pointer.motion(
|
||||
self,
|
||||
under.surface,
|
||||
under.target,
|
||||
&MotionEvent {
|
||||
location,
|
||||
serial: SERIAL_COUNTER.next_serial(),
|
||||
|
|
@ -1276,7 +1292,7 @@ impl State {
|
|||
}
|
||||
|
||||
self.niri.keyboard_focus.clone_from(&focus);
|
||||
keyboard.set_focus(self, focus.into_surface(), SERIAL_COUNTER.next_serial());
|
||||
keyboard.set_focus(self, focus.into_target(), SERIAL_COUNTER.next_serial());
|
||||
|
||||
// FIXME: can be more granular.
|
||||
self.niri.queue_redraw_all();
|
||||
|
|
@ -1810,9 +1826,6 @@ impl State {
|
|||
.open(renderer, screenshots, default_output, show_pointer)
|
||||
});
|
||||
|
||||
self.niri
|
||||
.cursor_manager
|
||||
.set_cursor_image(CursorImageStatus::Named(CursorIcon::Crosshair));
|
||||
self.niri.queue_redraw_all();
|
||||
}
|
||||
|
||||
|
|
@ -1851,9 +1864,6 @@ impl State {
|
|||
});
|
||||
|
||||
self.niri.screenshot_ui.close();
|
||||
self.niri
|
||||
.cursor_manager
|
||||
.set_cursor_image(CursorImageStatus::default_named());
|
||||
self.niri.queue_redraw_all();
|
||||
}
|
||||
|
||||
|
|
@ -2997,8 +3007,6 @@ impl Niri {
|
|||
}
|
||||
|
||||
if self.screenshot_ui.close() {
|
||||
self.cursor_manager
|
||||
.set_cursor_image(CursorImageStatus::default_named());
|
||||
self.queue_redraw_all();
|
||||
}
|
||||
}
|
||||
|
|
@ -3044,8 +3052,6 @@ impl Niri {
|
|||
// physical coordinates.
|
||||
if old_size != size || old_scale != scale || old_transform != transform {
|
||||
self.screenshot_ui.close();
|
||||
self.cursor_manager
|
||||
.set_cursor_image(CursorImageStatus::default_named());
|
||||
self.queue_redraw_all();
|
||||
return;
|
||||
}
|
||||
|
|
@ -3303,11 +3309,19 @@ impl Niri {
|
|||
(pos_within_output + output_pos_in_global_space).to_f64(),
|
||||
)
|
||||
});
|
||||
rv.target = rv
|
||||
.surface
|
||||
.as_ref()
|
||||
.map(|(surface, pos)| (PointerFocusTarget::Surface(surface.clone()), *pos));
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
if self.screenshot_ui.is_open() {
|
||||
rv.target = Some((
|
||||
PointerFocusTarget::ScreenshotUi(ScreenshotUiFocusTarget),
|
||||
Point::new(0., 0.),
|
||||
));
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
|
@ -3417,6 +3431,10 @@ impl Niri {
|
|||
.or_else(|| layer_popup_under(Layer::Top))
|
||||
.or_else(|| layer_toplevel_under(Layer::Top));
|
||||
|
||||
if is_overview_open && under.is_none() {
|
||||
rv.target = Some((PointerFocusTarget::Overview, Point::new(0., 0.)));
|
||||
}
|
||||
|
||||
under = under.or_else(interactive_moved_window_under);
|
||||
|
||||
if !is_overview_open {
|
||||
|
|
@ -3445,6 +3463,12 @@ impl Niri {
|
|||
rv.surface = surface_and_pos;
|
||||
rv.window = window;
|
||||
rv.layer = layer;
|
||||
if rv.target.is_none() {
|
||||
rv.target = rv
|
||||
.surface
|
||||
.as_ref()
|
||||
.map(|(surface, pos)| (PointerFocusTarget::Surface(surface.clone()), *pos));
|
||||
}
|
||||
rv
|
||||
}
|
||||
|
||||
|
|
@ -5686,8 +5710,6 @@ impl Niri {
|
|||
if self.output_state.is_empty() {
|
||||
// There are no outputs, lock the session right away.
|
||||
self.screenshot_ui.close();
|
||||
self.cursor_manager
|
||||
.set_cursor_image(CursorImageStatus::default_named());
|
||||
|
||||
let lock = confirmation.ext_session_lock().clone();
|
||||
confirmation.lock();
|
||||
|
|
@ -5746,8 +5768,6 @@ impl Niri {
|
|||
self.event_loop.remove(deadline_token);
|
||||
|
||||
self.screenshot_ui.close();
|
||||
self.cursor_manager
|
||||
.set_cursor_image(CursorImageStatus::default_named());
|
||||
|
||||
if self.output_state.is_empty() {
|
||||
// There are no outputs, lock the session right away.
|
||||
|
|
@ -5893,7 +5913,7 @@ impl Niri {
|
|||
};
|
||||
|
||||
let pointer = self.seat.get_pointer().unwrap();
|
||||
if Some(surface) != pointer.current_focus().as_ref() {
|
||||
if Some(surface) != pointer.current_focus().as_ref().and_then(|x| x.surface()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,17 +12,20 @@ use niri_ipc::SizeChange;
|
|||
use pango::{Alignment, FontDescription};
|
||||
use pangocairo::cairo::{self, ImageSurface};
|
||||
use smithay::backend::allocator::Fourcc;
|
||||
use smithay::backend::input::TouchSlot;
|
||||
use smithay::backend::input::{KeyState, TouchSlot};
|
||||
use smithay::backend::renderer::element::utils::{Relocate, RelocateRenderElement};
|
||||
use smithay::backend::renderer::element::Kind;
|
||||
use smithay::backend::renderer::gles::{GlesRenderer, GlesTexture};
|
||||
use smithay::backend::renderer::{ExportMem, Texture as _};
|
||||
use smithay::input::keyboard::{Keysym, ModifiersState};
|
||||
use smithay::input::keyboard::{KeyboardTarget, Keysym, KeysymHandle, ModifiersState};
|
||||
use smithay::input::pointer::{self, CursorIcon, CursorImageStatus, PointerTarget};
|
||||
use smithay::input::{Seat, SeatHandler};
|
||||
use smithay::output::{Output, WeakOutput};
|
||||
use smithay::utils::{Buffer, Physical, Point, Rectangle, Scale, Size, Transform};
|
||||
use smithay::utils::{Buffer, IsAlive, Physical, Point, Rectangle, Scale, Serial, Size, Transform};
|
||||
|
||||
use crate::animation::{Animation, Clock};
|
||||
use crate::layout::floating::DIRECTIONAL_MOVE_PX;
|
||||
use crate::niri::State;
|
||||
use crate::niri_render_elements;
|
||||
use crate::render_helpers::primary_gpu_texture::PrimaryGpuTextureRenderElement;
|
||||
use crate::render_helpers::solid_color::{SolidColorBuffer, SolidColorRenderElement};
|
||||
|
|
@ -1204,3 +1207,133 @@ fn render_panel(
|
|||
|
||||
Ok(buffer)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct ScreenshotUiFocusTarget;
|
||||
|
||||
impl IsAlive for ScreenshotUiFocusTarget {
|
||||
fn alive(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyboardTarget<State> for ScreenshotUiFocusTarget {
|
||||
fn enter(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
keys: Vec<KeysymHandle<'_>>,
|
||||
serial: Serial,
|
||||
) {
|
||||
}
|
||||
|
||||
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial) {}
|
||||
|
||||
fn key(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
key: KeysymHandle<'_>,
|
||||
state: KeyState,
|
||||
serial: Serial,
|
||||
time: u32,
|
||||
) {
|
||||
}
|
||||
|
||||
fn modifiers(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
modifiers: ModifiersState,
|
||||
serial: Serial,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
impl PointerTarget<State> for ScreenshotUiFocusTarget {
|
||||
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &pointer::MotionEvent) {
|
||||
data.cursor_image(seat, CursorImageStatus::Named(CursorIcon::Crosshair));
|
||||
}
|
||||
|
||||
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &pointer::MotionEvent) {}
|
||||
|
||||
fn relative_motion(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
event: &pointer::RelativeMotionEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn button(&self, seat: &Seat<State>, data: &mut State, event: &pointer::ButtonEvent) {}
|
||||
|
||||
fn axis(&self, seat: &Seat<State>, data: &mut State, frame: pointer::AxisFrame) {}
|
||||
|
||||
fn frame(&self, seat: &Seat<State>, data: &mut State) {}
|
||||
|
||||
fn gesture_swipe_begin(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
event: &pointer::GestureSwipeBeginEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn gesture_swipe_update(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
event: &pointer::GestureSwipeUpdateEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn gesture_swipe_end(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
event: &pointer::GestureSwipeEndEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn gesture_pinch_begin(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
event: &pointer::GesturePinchBeginEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn gesture_pinch_update(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
event: &pointer::GesturePinchUpdateEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn gesture_pinch_end(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
event: &pointer::GesturePinchEndEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn gesture_hold_begin(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
event: &pointer::GestureHoldBeginEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn gesture_hold_end(
|
||||
&self,
|
||||
seat: &Seat<State>,
|
||||
data: &mut State,
|
||||
event: &pointer::GestureHoldEndEvent,
|
||||
) {
|
||||
}
|
||||
|
||||
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) {}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue