Commit a748589d3821
tarball3 files changed+53-2
@@ -57,6 +57,7 @@ impl WlrLayerShellHandler for State {
5757
}5858
5959
fn new_popup(&mut self, _parent: WlrLayerSurface, popup: PopupSurface) {60
+ self.unconstrain_popup(&popup);6061
let _ = self.wm.popups.track_popup(PopupKind::Xdg(popup));6162
}6263
@@ -2,13 +2,16 @@
22
33
use crate::focus::Focus;44
use crate::state::State;5
+use monolith_layout::Rect;56
use smithay::desktop::{6
- PopupKeyboardGrab, PopupKind, PopupPointerGrab, PopupUngrabStrategy, find_popup_root_surface,7
+ PopupKeyboardGrab, PopupKind, PopupPointerGrab, PopupUngrabStrategy, WindowSurfaceType,8
+ find_popup_root_surface, get_popup_toplevel_coords, layer_map_for_output,79
};810
use smithay::input::Seat;911
use smithay::input::pointer::Focus as GrabFocus;1012
use smithay::reexports::wayland_server::protocol::wl_seat::WlSeat;11
-use smithay::utils::Serial;13
+use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;14
+use smithay::utils::{Logical, Point, Rectangle, Serial};1215
use smithay::wayland::shell::xdg::PopupSurface;1316
1417
impl State {@@ -67,3 +70,48 @@ impl State {
6770
}6871
}6972
}73
+74
+fn whole(r: Rect) -> Rectangle<i32, Logical> {75
+ let (x, y) = (r.x.round() as i32, r.y.round() as i32);76
+ Rectangle::new(77
+ (x, y).into(),78
+ (r.right().round() as i32 - x, r.bottom().round() as i32 - y).into(),79
+ )80
+}81
+82
+impl State {83
+ /// The global position of the popup root's geometry origin, and the output84
+ /// area the popup has to stay inside.85
+ fn popup_frame(86
+ &self,87
+ root: &WlSurface,88
+ ) -> Option<(Point<i32, Logical>, Rectangle<i32, Logical>)> {89
+ if let Some(id) = self.window_id(root) {90
+ let (_, rect, o) = self.wm.get(id)?.placed?;91
+ let area = self.wm.layout.output(o)?.area;92
+ return Some((whole(rect).loc, whole(area)));93
+ }94
+ self.wm.space.outputs().find_map(|output| {95
+ let map = layer_map_for_output(output);96
+ let layer = map.layer_for_surface(root, WindowSurfaceType::TOPLEVEL)?;97
+ let at = map.layer_geometry(layer)?.loc;98
+ let out = self.wm.space.output_geometry(output)?;99
+ Some((out.loc + at, out))100
+ })101
+ }102
+103
+ /// Slides or flips the popup's pending geometry to keep it on the output104
+ /// its root is on, as the positioner allows.105
+ pub fn unconstrain_popup(&self, popup: &PopupSurface) {106
+ let kind = PopupKind::Xdg(popup.clone());107
+ let Ok(root) = find_popup_root_surface(&kind) else {108
+ return;109
+ };110
+ let Some((origin, area)) = self.popup_frame(&root) else {111
+ return;112
+ };113
+ let mut target = area;114
+ target.loc -= origin + get_popup_toplevel_coords(&kind);115
+ popup.with_pending_state(|s| s.geometry = s.positioner.get_unconstrained_geometry(target));116
+ }117
+}@@ -56,6 +56,7 @@ impl XdgShellHandler for State {
5656
5757
fn new_popup(&mut self, surface: PopupSurface, positioner: PositionerState) {5858
surface.with_pending_state(|s| s.geometry = positioner.get_geometry());59
+ self.unconstrain_popup(&surface);5960
let _ = self.wm.popups.track_popup(PopupKind::Xdg(surface));6061
}6162
@@ -69,6 +70,7 @@ impl XdgShellHandler for State {
6970
s.geometry = positioner.get_geometry();7071
s.positioner = positioner;7172
});73
+ self.unconstrain_popup(&surface);7274
surface.send_repositioned(token);7375
}