aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/handlers/mod.rs4
-rw-r--r--src/input/mod.rs24
-rw-r--r--src/niri.rs48
3 files changed, 49 insertions, 27 deletions
diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs
index d9b029c5..f2613d19 100644
--- a/src/handlers/mod.rs
+++ b/src/handlers/mod.rs
@@ -211,7 +211,7 @@ impl PointerConstraintsHandler for State {
pointer.set_location(target);
// Redraw to update the cursor position if it's visible.
- if !self.niri.pointer_hidden {
+ if self.niri.pointer_visibility.is_visible() {
// FIXME: redraw only outputs overlapping the cursor.
self.niri.queue_redraw_all();
}
@@ -369,7 +369,7 @@ impl ClientDndGrabHandler for State {
// parameters from Smithay I guess.
//
// Assume that hidden pointer means touch DnD.
- if !self.niri.pointer_hidden {
+ if self.niri.pointer_visibility.is_visible() {
// We can't even get the current pointer location because it's locked (we're deep
// in the grab call stack here). So use the last known one.
if let Some(output) = &self.niri.pointer_contents.output {
diff --git a/src/input/mod.rs b/src/input/mod.rs
index e7c2e38f..b5213351 100644
--- a/src/input/mod.rs
+++ b/src/input/mod.rs
@@ -42,7 +42,7 @@ use self::resize_grab::ResizeGrab;
use self::spatial_movement_grab::SpatialMovementGrab;
use crate::layout::scrolling::ScrollDirection;
use crate::layout::{ActivateWindow, LayoutElement as _};
-use crate::niri::{CastTarget, State};
+use crate::niri::{CastTarget, PointerVisibility, State};
use crate::ui::screenshot_ui::ScreenshotUi;
use crate::utils::spawning::spawn;
use crate::utils::{center, get_monotonic_time, ResizeEdge};
@@ -477,13 +477,13 @@ impl State {
}
// niri keeps this set only while actively using a tablet, which means the cursor position
- // is likely to change almost immediately, causing pointer_hidden to just flicker back and
- // forth.
+ // is likely to change almost immediately, causing pointer_visibility to just flicker back
+ // and forth.
if self.niri.tablet_cursor_location.is_some() {
return;
}
- self.niri.pointer_hidden = true;
+ self.niri.pointer_visibility = PointerVisibility::Hidden;
self.niri.queue_redraw_all();
}
@@ -2014,7 +2014,7 @@ impl State {
let mut new_pos = pos + event.delta();
// We received an event for the regular pointer, so show it now.
- self.niri.pointer_hidden = false;
+ self.niri.pointer_visibility = PointerVisibility::Visible;
self.niri.tablet_cursor_location = None;
// Check if we have an active pointer constraint.
@@ -2283,7 +2283,7 @@ impl State {
self.niri.maybe_activate_pointer_constraint();
// We moved the pointer, show it.
- self.niri.pointer_hidden = false;
+ self.niri.pointer_visibility = PointerVisibility::Visible;
// We moved the regular pointer, so show it now.
self.niri.tablet_cursor_location = None;
@@ -2348,7 +2348,7 @@ impl State {
}
// We received an event for the regular pointer, so show it now.
- self.niri.pointer_hidden = false;
+ self.niri.pointer_visibility = PointerVisibility::Visible;
self.niri.tablet_cursor_location = None;
let is_overview_open = self.niri.layout.is_overview_open();
@@ -2608,7 +2608,7 @@ impl State {
// We received an event for the regular pointer, so show it now. This is also needed for
// update_pointer_contents() below to return the real contents, necessary for the pointer
// axis event to reach the window.
- self.niri.pointer_hidden = false;
+ self.niri.pointer_visibility = PointerVisibility::Visible;
self.niri.tablet_cursor_location = None;
let timestamp = Duration::from_micros(event.time());
@@ -3053,7 +3053,7 @@ impl State {
event.time_msec(),
);
- self.niri.pointer_hidden = false;
+ self.niri.pointer_visibility = PointerVisibility::Visible;
self.niri.tablet_cursor_location = Some(pos);
}
@@ -3145,7 +3145,7 @@ impl State {
event.time_msec(),
);
}
- self.niri.pointer_hidden = false;
+ self.niri.pointer_visibility = PointerVisibility::Visible;
self.niri.tablet_cursor_location = Some(pos);
}
ProximityState::Out => {
@@ -3159,7 +3159,7 @@ impl State {
self.move_cursor(pos);
}
- self.niri.pointer_hidden = false;
+ self.niri.pointer_visibility = PointerVisibility::Visible;
self.niri.tablet_cursor_location = None;
}
}
@@ -3591,7 +3591,7 @@ impl State {
);
// We're using touch, hide the pointer.
- self.niri.pointer_hidden = true;
+ self.niri.pointer_visibility = PointerVisibility::Disabled;
}
fn on_touch_up<I: InputBackend>(&mut self, evt: I::TouchUpEvent) {
let Some(handle) = self.niri.seat.get_touch() else {
diff --git a/src/niri.rs b/src/niri.rs
index f33bb74d..28fac293 100644
--- a/src/niri.rs
+++ b/src/niri.rs
@@ -331,11 +331,7 @@ pub struct Niri {
/// taking grabs into account is expected, because we pass the information to pointer.motion()
/// which passes it down through grabs, which decide what to do with it as they see fit.
pub pointer_contents: PointContents,
- /// Whether the pointer is hidden, for example due to a previous touch input.
- ///
- /// When this happens, the pointer also loses any focus. This is so that touch can prevent
- /// various tooltips from sticking around.
- pub pointer_hidden: bool,
+ pub pointer_visibility: PointerVisibility,
pub pointer_inactivity_timer: Option<RegistrationToken>,
/// Whether the pointer inactivity timer got reset this event loop iteration.
///
@@ -395,6 +391,28 @@ pub struct Niri {
pub dynamic_cast_id_for_portal: MappedId,
}
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum PointerVisibility {
+ /// The pointer is visible.
+ Visible,
+ /// The pointer is invisible, but retains its focus.
+ ///
+ /// This state is set temporarily after auto-hiding the pointer to keep tooltips open and grabs
+ /// ongoing.
+ Hidden,
+ /// The pointer is invisible and cannot focus.
+ ///
+ /// Corresponds to a fully disabled pointer, for example after a touchscreen input, or after
+ /// the pointer contents changed in a Hidden state.
+ Disabled,
+}
+
+impl PointerVisibility {
+ pub fn is_visible(&self) -> bool {
+ matches!(self, Self::Visible)
+ }
+}
+
#[derive(Debug)]
pub struct DndIcon {
pub surface: WlSurface,
@@ -911,10 +929,9 @@ impl State {
let pointer = &self.niri.seat.get_pointer().unwrap();
let location = pointer.current_location();
- let under = if self.niri.pointer_hidden {
- PointContents::default()
- } else {
- self.niri.contents_under(location)
+ let under = match self.niri.pointer_visibility {
+ PointerVisibility::Disabled => PointContents::default(),
+ _ => self.niri.contents_under(location),
};
// We're not changing the global cursor location here, so if the contents did not change,
@@ -923,6 +940,11 @@ impl State {
return false;
}
+ // Disable the hidden pointer if the contents underneath have changed.
+ if !self.niri.pointer_visibility.is_visible() {
+ self.niri.pointer_visibility = PointerVisibility::Disabled;
+ }
+
self.niri.pointer_contents.clone_from(&under);
pointer.motion(
@@ -2424,7 +2446,7 @@ impl Niri {
cursor_shape_manager_state,
dnd_icon: None,
pointer_contents: PointContents::default(),
- pointer_hidden: false,
+ pointer_visibility: PointerVisibility::Visible,
pointer_inactivity_timer: None,
pointer_inactivity_timer_got_reset: false,
notified_activity_this_iteration: false,
@@ -3420,7 +3442,7 @@ impl Niri {
renderer: &mut R,
output: &Output,
) -> Vec<OutputRenderElements<R>> {
- if self.pointer_hidden {
+ if !self.pointer_visibility.is_visible() {
return vec![];
}
@@ -3507,7 +3529,7 @@ impl Niri {
}
pub fn refresh_pointer_outputs(&mut self) {
- if self.pointer_hidden {
+ if !self.pointer_visibility.is_visible() {
return;
}
@@ -5850,7 +5872,7 @@ impl Niri {
.event_loop
.insert_source(timer, move |_, _, state| {
state.niri.pointer_inactivity_timer = None;
- state.niri.pointer_hidden = true;
+ state.niri.pointer_visibility = PointerVisibility::Hidden;
state.niri.queue_redraw_all();
TimeoutAction::Drop