Commit 783f8b1b03c5
tarball5 files changed+101-19
@@ -154,7 +154,6 @@ impl State {
154154
let Some(pointer) = self.input.seat.get_pointer() else {155155
return;156156
};157
- let grabbed = self.keyboard_grabbed();158157
pointer.button(159158
self,160159
&ButtonEvent {@@ -164,9 +163,7 @@ impl State {
164163
time,165164
},166165
);167
- if grabbed {168
- self.sync_focus();169
- }166
+ self.reap_popup_grab();170167
}171168
172169
pub fn pointer_axis(&mut self, frame: AxisFrame) {@@ -4,6 +4,7 @@
44
use crate::scene::Draw;55
use crate::state::State;66
use monolith_render_vk::VulkanRenderer;7
+use smithay::backend::input::InputTime;78
use smithay::backend::renderer::element::Kind;89
use smithay::backend::renderer::element::surface::render_elements_from_surface_tree;910
use smithay::desktop::WindowSurfaceType;@@ -11,11 +12,12 @@ use smithay::desktop::utils::{
1112
OutputPresentationFeedback, send_frames_surface_tree, take_presentation_feedback_surface_tree,1213
under_from_surface_tree,1314
};15
+use smithay::input::pointer::MotionEvent;1416
use smithay::output::Output;1517
use smithay::reexports::wayland_server::protocol::wl_output::WlOutput;1618
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;1719
use smithay::reexports::wayland_protocols::wp::presentation_time::server::wp_presentation_feedback::Kind as PresentationKind;18
-use smithay::utils::{Logical, Point};20
+use smithay::utils::{Logical, Point, SERIAL_COUNTER};1921
use smithay::wayland::compositor::SurfaceData;2022
use smithay::wayland::session_lock::{2123
LockSurface, SessionLockHandler, SessionLockManagerState, SessionLocker,@@ -83,7 +85,12 @@ impl SessionLockHandler for State {
8385
self.services.lock.pending = Some(confirmation);8486
self.services.lock.blanked.clear();8587
self.input.drag = None;86
- self.wm.resizing = None;88
+ self.end_popup_grab();89
+ self.cancel_dnd();90
+ if self.wm.resizing.take().is_some() {91
+ self.apply_layout();92
+ }93
+ self.refocus_pointer();8794
self.sync_focus();8895
self.dirty.redraw = true;8996
}@@ -126,6 +133,21 @@ fn configure(surface: &LockSurface, output: &Output) {
126133
}127134
128135
impl State {136
+ fn refocus_pointer(&mut self) {137
+ let Some(pointer) = self.input.seat.get_pointer() else {138
+ return;139
+ };140
+ let location = self.input.pointer_pos;141
+ let under = self.surface_under(location);142
+ let event = MotionEvent {143
+ location,144
+ serial: SERIAL_COUNTER.next_serial(),145
+ time: InputTime::now(),146
+ };147
+ pointer.motion(self, under, &event);148
+ pointer.frame(self);149
+ }150
+129151
/// Confirms a pending lock once every output has drawn without the130152
/// windows, so nothing private is left on screen when the locker is told131153
/// it holds the session.@@ -5,6 +5,7 @@ use crate::scene::Draw;
55
use crate::state::State;66
use monolith_layout::{Rect, WindowId};77
use monolith_render_vk::VulkanRenderer;8
+use smithay::backend::input::InputTime;89
use smithay::backend::renderer::element::Kind;910
use smithay::backend::renderer::element::surface::render_elements_from_surface_tree;1011
use smithay::desktop::utils::under_from_surface_tree;@@ -16,18 +17,54 @@ use smithay::input::Seat;
1617
use smithay::input::pointer::Focus as GrabFocus;1718
use smithay::reexports::wayland_server::protocol::wl_seat::WlSeat;1819
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;19
-use smithay::utils::{Logical, Physical, Point, Rectangle, Serial};20
+use smithay::utils::{Logical, Physical, Point, Rectangle, SERIAL_COUNTER, Serial};21
+use smithay::wayland::seat::WaylandFocus;2022
use smithay::wayland::shell::xdg::PopupSurface;2123
2224
impl State {23
- /// Popup grabs are the only keyboard grabs, and they hand the focus back24
- /// to the grab's root, not to whatever the layout has focused, so the25
- /// callers resync once one may have ended.26
- pub fn keyboard_grabbed(&self) -> bool {27
- self.input28
- .seat29
- .get_keyboard()30
- .is_some_and(|k| k.is_grabbed())25
+ /// Ends the popup grab if it has run its course, and hands the keyboard26
+ /// back to the layout, since a finished grab restores the focus to its own27
+ /// root and not to whatever the layout has focused.28
+ pub fn reap_popup_grab(&mut self) {29
+ if self30
+ .input31
+ .popup_grab32
+ .take_if(|grab| grab.has_ended())33
+ .is_some()34
+ {35
+ self.sync_focus();36
+ }37
+ }38
+39
+ /// Whether the popup grab is rooted at `target`, or nothing is grabbed.40
+ pub fn popup_grab_roots(&self, target: Option<&Focus>) -> bool {41
+ let Some(grab) = &self.input.popup_grab else {42
+ return true;43
+ };44
+ let root = grab.keyboard_grab_start_data().focus.as_ref();45
+ let wl = |f: &Focus| f.wl_surface().map(|s| s.into_owned());46
+ root.and_then(wl) == target.and_then(wl)47
+ }48
+49
+ /// Dismisses the popup grab and every popup in it, and releases the seat50
+ /// grabs it holds without moving the focus, which the caller sets next.51
+ pub fn end_popup_grab(&mut self) {52
+ let Some(mut grab) = self.input.popup_grab.take() else {53
+ return;54
+ };55
+ grab.ungrab(PopupUngrabStrategy::All);56
+ let serials = [Some(grab.serial()), grab.previous_serial()];57
+ let seat = self.input.seat.clone();58
+ if let Some(keyboard) = seat.get_keyboard()59
+ && keyboard.is_grabbed()60
+ {61
+ keyboard.unset_grab(self);62
+ }63
+ if let Some(pointer) = seat.get_pointer()64
+ && serials.into_iter().flatten().any(|s| pointer.has_grab(s))65
+ {66
+ pointer.unset_grab(self, SERIAL_COUNTER.next_serial(), InputTime::now());67
+ }3168
}3269
3370
/// Gives an explicit popup grab the keyboard and pointer, so clicking@@ -63,6 +100,7 @@ impl State {
63100
keyboard.set_focus(self, grab.current_grab(), serial);64101
keyboard.set_grab(self, PopupKeyboardGrab::new(&grab), serial);65102
}103
+ self.input.popup_grab = Some(grab.clone());66104
if let Some(pointer) = seat.get_pointer() {67105
if pointer.is_grabbed()68106
&& !(pointer.has_grab(serial)@@ -1,11 +1,12 @@
11
use crate::cursor::DndIcon;22
use crate::state::State;3
+use smithay::backend::input::InputTime;34
use smithay::input::dnd::{DnDGrab, DndGrabHandler, DndTarget, GrabType, Source};45
use smithay::input::pointer::{CursorImageStatus, Focus};56
use smithay::input::{Seat, SeatHandler, SeatState};67
use smithay::reexports::wayland_server::Resource;78
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;8
-use smithay::utils::{Logical, Point, Serial};9
+use smithay::utils::{Logical, Point, SERIAL_COUNTER, Serial};910
use smithay::wayland::seat::WaylandFocus;1011
use smithay::wayland::selection::data_device::{1112
DataDeviceHandler, DataDeviceState, WaylandDndGrabHandler, set_data_device_focus,@@ -122,6 +123,17 @@ impl DndGrabHandler for State {
122123
}123124
124125
impl State {126
+ /// Drops whatever holds the pointer, which once popup grabs are gone is127
+ /// a drag and drop or a client's button press.128
+ pub fn cancel_dnd(&mut self) {129
+ if let Some(pointer) = self.input.seat.get_pointer()130
+ && pointer.is_grabbed()131
+ {132
+ pointer.unset_grab(self, SERIAL_COUNTER.next_serial(), InputTime::now());133
+ }134
+ self.end_dnd();135
+ }136
+125137
fn end_dnd(&mut self) {126138
self.input.dnd_icon = None;127139
self.dirty.redraw = true;@@ -141,6 +153,10 @@ impl WaylandDndGrabHandler for State {
141153
serial: Serial,142154
type_: GrabType,143155
) {156
+ if self.services.lock.active() {157
+ source.cancel();158
+ return;159
+ }144160
self.input.dnd_icon = icon.map(|surface| DndIcon {145161
surface,146162
offset: Point::default(),@@ -70,6 +70,10 @@ pub struct Input {
7070
/// one yields a relative delta even while the pointer is held in place.7171
pub absolute: Option<Point<f64, Logical>>,7272
pub inhibitor: Option<smithay::wayland::keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitor>,73
+ /// The explicit popup grab holding the keyboard and pointer, if any.74
+ pub popup_grab: Option<smithay::desktop::PopupGrab<State>>,75
+ /// What the layout last wanted the keyboard on, which a popup grab may be hiding.76
+ pub focus_target: Option<Focus>,7377
}7478
7579
/// What needs doing after this batch of events.@@ -208,6 +212,8 @@ impl State {
208212
pointer_output: None,209213
absolute: None,210214
inhibitor: None,215
+ popup_grab: None,216
+ focus_target: None,211217
},212218
dirty: Dirty {213219
redraw: true,@@ -234,9 +240,7 @@ impl State {
234240
pub fn after_dispatch(&mut self) {235241
self.wm.space.refresh();236242
self.wm.popups.cleanup();237
- if self.keyboard_grabbed() {238
- self.sync_focus();239
- }243
+ self.reap_popup_grab();240244
match self.backend {241245
crate::backend::Backend::Drm(_) => crate::drm::render(self),242246
crate::backend::Backend::Nested(_) => crate::nested::render(self),@@ -497,6 +501,11 @@ impl State {
497501
}498502
})499503
};504
+ if std::mem::replace(&mut self.input.focus_target, target.clone()) != target505
+ && !self.popup_grab_roots(target.as_ref())506
+ {507
+ self.end_popup_grab();508
+ }500509
if let Some(keyboard) = self.input.seat.get_keyboard()501510
&& keyboard.current_focus() != target502511
{