mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2024-12-27 21:58:18 +01:00
Start simplifying popup logic
So uh when did Smithay have all these popup helpers, did I just not read the docs hard enough
This commit is contained in:
parent
220be6d505
commit
97efdb854c
1 changed files with 25 additions and 498 deletions
|
@ -12,7 +12,7 @@ use smithay::{
|
||||||
xdg_toplevel::{self, ResizeEdge},
|
xdg_toplevel::{self, ResizeEdge},
|
||||||
},
|
},
|
||||||
wayland_server::{
|
wayland_server::{
|
||||||
protocol::{wl_output::WlOutput, wl_seat::WlSeat},
|
protocol::{wl_output::WlOutput, wl_seat::WlSeat, wl_surface::WlSurface},
|
||||||
Resource,
|
Resource,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -99,512 +99,39 @@ impl XdgShellHandler for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is 500 lines there has to be a shorter way to do this
|
// this is 500 lines there has to be a shorter way to do this
|
||||||
fn new_popup(&mut self, surface: PopupSurface, mut positioner: PositionerState) {
|
fn new_popup(&mut self, surface: PopupSurface, positioner: PositionerState) {
|
||||||
tracing::debug!(?positioner.constraint_adjustment, ?positioner.gravity);
|
tracing::info!("XdgShellHandler::new_popup");
|
||||||
let output_rect = self
|
|
||||||
.focused_output()
|
|
||||||
.and_then(|op| self.space.output_geometry(op));
|
|
||||||
|
|
||||||
/// Horizontal direction
|
let popup_geo = (|| -> Option<Rectangle<i32, Logical>> {
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
let root = find_popup_root_surface(&PopupKind::Xdg(surface.clone())).ok()?;
|
||||||
enum DirH {
|
let parent = surface.get_parent_surface()?;
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Vertical direction
|
let win = self.window_for_surface(&root)?;
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
let win_loc = self.space.element_geometry(&win)?.loc;
|
||||||
enum DirV {
|
let parent_loc = if root == parent {
|
||||||
Top,
|
win_loc
|
||||||
Bottom,
|
} else {
|
||||||
}
|
match self.popup_manager.find_popup(&parent)? {
|
||||||
|
PopupKind::Xdg(surf) => {
|
||||||
let mut is_subpopup = false;
|
surf.with_pending_state(|state| state.geometry.loc) + win_loc
|
||||||
|
|
||||||
// We have to go through this really verbose way of getting the location of the popup in
|
|
||||||
// the global space.
|
|
||||||
//
|
|
||||||
// The location from PopupSurface.with_pending_state's state.geometry.loc is relative to
|
|
||||||
// its parent. When its parent is a window, we can simply add the window's location to the
|
|
||||||
// popup's to get its global location.
|
|
||||||
//
|
|
||||||
// However, if its parent is another popup, we need to step upwards and grab the location
|
|
||||||
// from each popup, aggregating them into one global space location.
|
|
||||||
let global_loc = {
|
|
||||||
let mut surf = surface.get_parent_surface();
|
|
||||||
let mut loc = surface.with_pending_state(|state| state.geometry.loc);
|
|
||||||
tracing::debug!(?loc);
|
|
||||||
|
|
||||||
while let Some(s) = &surf {
|
|
||||||
if let Some(popup) = self.popup_manager.find_popup(s) {
|
|
||||||
// popup.geometry() doesn't return the right location, so we dive into the
|
|
||||||
// PopupSurface's state to grab it.
|
|
||||||
let PopupKind::Xdg(popup_surf) = &popup else { return }; // TODO:
|
|
||||||
let l = popup_surf.with_pending_state(|state| state.geometry.loc);
|
|
||||||
tracing::debug!(loc = ?l, "parent is popup");
|
|
||||||
loc += l;
|
|
||||||
is_subpopup = true;
|
|
||||||
surf = popup_surf.get_parent_surface();
|
|
||||||
} else if let Some(win) = self.window_for_surface(s) {
|
|
||||||
// Once we reach a window, we can stop as windows are already in the global space.
|
|
||||||
tracing::debug!("parent is window");
|
|
||||||
loc += self
|
|
||||||
.space
|
|
||||||
.element_location(&win)
|
|
||||||
.unwrap_or_else(|| (0, 0).into());
|
|
||||||
tracing::debug!(?loc);
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
// Or a layer
|
|
||||||
let layer_and_op = self.space.outputs().find_map(|op| {
|
|
||||||
let layer_map = layer_map_for_output(op);
|
|
||||||
|
|
||||||
let ret = layer_map
|
|
||||||
.layers()
|
|
||||||
.find(|l| l.wl_surface() == s)
|
|
||||||
.cloned()
|
|
||||||
.map(|layer| {
|
|
||||||
(
|
|
||||||
layer_map.layer_geometry(&layer).unwrap_or_default(),
|
|
||||||
op.clone(),
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
ret
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some((layer_geo, op)) = layer_and_op {
|
|
||||||
let op_loc = self.space.output_geometry(&op).unwrap_or_default().loc;
|
|
||||||
loc += layer_geo.loc + op_loc;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
PopupKind::InputMethod(_) => return None,
|
||||||
}
|
|
||||||
|
|
||||||
loc
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut popup_rect_global = {
|
|
||||||
let mut rect = positioner.get_geometry();
|
|
||||||
rect.loc = global_loc;
|
|
||||||
rect
|
|
||||||
};
|
|
||||||
|
|
||||||
tracing::debug!(?global_loc);
|
|
||||||
|
|
||||||
// The final rectangle that the popup is set to needs to be relative to its parent,
|
|
||||||
// so we store its old location here and subtract it at the end.
|
|
||||||
let loc_diff = global_loc - surface.with_pending_state(|state| state.geometry.loc);
|
|
||||||
|
|
||||||
if let Some(output_rect) = output_rect {
|
|
||||||
// Check if the rect is constrained horizontally, and if so, which side.
|
|
||||||
let constrained_x = |rect: Rectangle<i32, Logical>| -> Option<DirH> {
|
|
||||||
tracing::debug!(?rect, ?output_rect);
|
|
||||||
|
|
||||||
if rect.loc.x < output_rect.loc.x {
|
|
||||||
Some(DirH::Left)
|
|
||||||
} else if rect.loc.x + rect.size.w > output_rect.loc.x + output_rect.size.w {
|
|
||||||
Some(DirH::Right)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if the rect is constrained vertically, and if so, which side.
|
let mut output_geo = win
|
||||||
let constrained_y = |rect: Rectangle<i32, Logical>| -> Option<DirV> {
|
.output(self)
|
||||||
tracing::debug!(?rect, ?output_rect);
|
.and_then(|op| self.space.output_geometry(&op))?;
|
||||||
|
|
||||||
if rect.loc.y < output_rect.loc.y {
|
// Make local to parent
|
||||||
Some(DirV::Top)
|
output_geo.loc -= dbg!(parent_loc);
|
||||||
} else if rect.loc.y + rect.size.h > output_rect.loc.y + output_rect.size.h {
|
Some(positioner.get_unconstrained_geometry(output_geo))
|
||||||
Some(DirV::Bottom)
|
})()
|
||||||
} else {
|
.unwrap_or_else(|| positioner.get_geometry());
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// We're going to need to position popups such that they stay fully onscreen.
|
dbg!(popup_geo);
|
||||||
// We can use the provided `positioner.constraint_adjustment` to get hints on how
|
|
||||||
// the popups want to be relocated.
|
|
||||||
|
|
||||||
let output_left_x = output_rect.loc.x;
|
surface.with_pending_state(|state| state.geometry = popup_geo);
|
||||||
let output_right_x = output_rect.loc.x + output_rect.size.w;
|
|
||||||
let output_top_y = output_rect.loc.y;
|
|
||||||
let output_bottom_y = output_rect.loc.y + output_rect.size.h;
|
|
||||||
|
|
||||||
// The popup is flowing offscreen in the horizontal direction.
|
|
||||||
if let Some(constrain_dir) = constrained_x(popup_rect_global) {
|
|
||||||
tracing::debug!("Popup was constrained on the x axis, repositioning");
|
|
||||||
let gravity = match positioner.gravity {
|
|
||||||
Gravity::Left | Gravity::TopLeft | Gravity::BottomLeft => DirH::Left,
|
|
||||||
_ => DirH::Right,
|
|
||||||
};
|
|
||||||
|
|
||||||
tracing::debug!(?gravity);
|
|
||||||
tracing::debug!(?constrain_dir);
|
|
||||||
|
|
||||||
'block: {
|
|
||||||
// If the constraint_adjustment has SlideX, we attempt to slide the popup
|
|
||||||
// towards the direction specified by positioner.gravity until TODO:
|
|
||||||
if positioner
|
|
||||||
.constraint_adjustment
|
|
||||||
.contains(ConstraintAdjustment::SlideX)
|
|
||||||
&& !is_subpopup
|
|
||||||
// If it's a subpopup, flip instead of slide. This makes
|
|
||||||
// stuff like Firefox nested dropdowns more intuitive.
|
|
||||||
{
|
|
||||||
tracing::debug!("Attempting to slide popup X");
|
|
||||||
// Slide towards the gravity until the opposite edge is unconstrained or the
|
|
||||||
// same edge is constrained
|
|
||||||
match (&constrain_dir, &gravity) {
|
|
||||||
(DirH::Left, DirH::Right) => {
|
|
||||||
let len_until_same_edge_constrained = output_right_x
|
|
||||||
- (popup_rect_global.loc.x + popup_rect_global.size.w);
|
|
||||||
let len_until_opp_edge_unconstrained =
|
|
||||||
output_left_x - popup_rect_global.loc.x;
|
|
||||||
|
|
||||||
popup_rect_global.loc.x += i32::min(
|
|
||||||
len_until_same_edge_constrained,
|
|
||||||
len_until_opp_edge_unconstrained,
|
|
||||||
)
|
|
||||||
.max(0);
|
|
||||||
tracing::debug!(
|
|
||||||
?popup_rect_global,
|
|
||||||
"Constrained SlideX left right"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
(DirH::Right, DirH::Left) => {
|
|
||||||
let len_until_same_edge_constrained =
|
|
||||||
popup_rect_global.loc.x - output_left_x;
|
|
||||||
let len_until_opp_edge_unconstrained = (popup_rect_global.loc.x
|
|
||||||
+ popup_rect_global.size.w)
|
|
||||||
- output_right_x;
|
|
||||||
|
|
||||||
popup_rect_global.loc.x -= i32::min(
|
|
||||||
len_until_opp_edge_unconstrained,
|
|
||||||
len_until_same_edge_constrained,
|
|
||||||
)
|
|
||||||
.max(0);
|
|
||||||
tracing::debug!(
|
|
||||||
?popup_rect_global,
|
|
||||||
"Constrained SlideX right left"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
};
|
|
||||||
|
|
||||||
if constrained_x(popup_rect_global).is_none() {
|
|
||||||
break 'block;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do the same but in the other direction
|
|
||||||
match (constrain_dir, gravity) {
|
|
||||||
(DirH::Right, DirH::Right) => {
|
|
||||||
let len_until_same_edge_unconstrained =
|
|
||||||
popup_rect_global.loc.x - output_left_x;
|
|
||||||
let len_until_opp_edge_constrained = (popup_rect_global.loc.x
|
|
||||||
+ popup_rect_global.size.w)
|
|
||||||
- output_right_x;
|
|
||||||
|
|
||||||
popup_rect_global.loc.x -= i32::min(
|
|
||||||
len_until_opp_edge_constrained,
|
|
||||||
len_until_same_edge_unconstrained,
|
|
||||||
)
|
|
||||||
.max(0);
|
|
||||||
tracing::debug!(
|
|
||||||
?popup_rect_global,
|
|
||||||
"Constrained SlideX right right"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
(DirH::Left, DirH::Left) => {
|
|
||||||
let len_until_same_edge_unconstrained = output_right_x
|
|
||||||
- (popup_rect_global.loc.x + popup_rect_global.size.w);
|
|
||||||
let len_until_opp_edge_constrained =
|
|
||||||
output_left_x - popup_rect_global.loc.x;
|
|
||||||
|
|
||||||
popup_rect_global.loc.x += i32::min(
|
|
||||||
len_until_same_edge_unconstrained,
|
|
||||||
len_until_opp_edge_constrained,
|
|
||||||
)
|
|
||||||
.max(0);
|
|
||||||
tracing::debug!(?popup_rect_global, "Constrained SlideX left left");
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
};
|
|
||||||
|
|
||||||
if constrained_x(popup_rect_global).is_none() {
|
|
||||||
break 'block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the above didn't bring the popup onscreen or if it's a nested popup, flip it.
|
|
||||||
if positioner
|
|
||||||
.constraint_adjustment
|
|
||||||
.contains(ConstraintAdjustment::FlipX)
|
|
||||||
{
|
|
||||||
tracing::debug!("Attempting to flip popup X");
|
|
||||||
let old_gravity = positioner.gravity;
|
|
||||||
positioner.gravity = match positioner.gravity {
|
|
||||||
Gravity::Left => Gravity::Right,
|
|
||||||
Gravity::Right => Gravity::Left,
|
|
||||||
Gravity::TopLeft => Gravity::TopRight,
|
|
||||||
Gravity::BottomLeft => Gravity::BottomRight,
|
|
||||||
Gravity::TopRight => Gravity::TopLeft,
|
|
||||||
Gravity::BottomRight => Gravity::BottomLeft,
|
|
||||||
rest => rest,
|
|
||||||
};
|
|
||||||
|
|
||||||
let old_anchor = positioner.anchor_edges;
|
|
||||||
positioner.anchor_edges = match positioner.anchor_edges {
|
|
||||||
Anchor::Left => Anchor::Right,
|
|
||||||
Anchor::Right => Anchor::Left,
|
|
||||||
Anchor::TopLeft => Anchor::TopRight,
|
|
||||||
Anchor::BottomLeft => Anchor::BottomRight,
|
|
||||||
Anchor::TopRight => Anchor::TopLeft,
|
|
||||||
Anchor::BottomRight => Anchor::BottomLeft,
|
|
||||||
rest => rest,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut relative_geo = positioner.get_geometry();
|
|
||||||
relative_geo.loc += loc_diff;
|
|
||||||
tracing::debug!(?relative_geo, "FlipX");
|
|
||||||
if constrained_x(relative_geo).is_none() {
|
|
||||||
popup_rect_global = relative_geo;
|
|
||||||
break 'block;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The protocol states that if flipping it didn't bring it onscreen,
|
|
||||||
// then it should just stay at its unflipped state.
|
|
||||||
positioner.gravity = old_gravity;
|
|
||||||
positioner.anchor_edges = old_anchor;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, if flipping it failed, resize it to fit.
|
|
||||||
if positioner
|
|
||||||
.constraint_adjustment
|
|
||||||
.contains(ConstraintAdjustment::ResizeX)
|
|
||||||
{
|
|
||||||
tracing::debug!("Resizing popup X");
|
|
||||||
// Slice off the left side
|
|
||||||
if popup_rect_global.loc.x < output_left_x {
|
|
||||||
let len_to_slice = output_left_x - popup_rect_global.loc.x;
|
|
||||||
let new_top_left: Point<i32, Logical> = (
|
|
||||||
popup_rect_global.loc.x + len_to_slice,
|
|
||||||
popup_rect_global.loc.y,
|
|
||||||
)
|
|
||||||
.into();
|
|
||||||
let bottom_right: Point<i32, Logical> = (
|
|
||||||
popup_rect_global.loc.x + popup_rect_global.size.w,
|
|
||||||
popup_rect_global.loc.y + popup_rect_global.size.h,
|
|
||||||
)
|
|
||||||
.into();
|
|
||||||
popup_rect_global =
|
|
||||||
Rectangle::from_extemities(new_top_left, bottom_right);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slice off the right side
|
|
||||||
if popup_rect_global.loc.x + popup_rect_global.size.w > output_right_x {
|
|
||||||
let len_to_slice = (popup_rect_global.loc.x + popup_rect_global.size.w)
|
|
||||||
- output_right_x;
|
|
||||||
let top_left = popup_rect_global.loc;
|
|
||||||
let new_bottom_right: Point<i32, Logical> = (
|
|
||||||
popup_rect_global.loc.x + popup_rect_global.size.w - len_to_slice,
|
|
||||||
popup_rect_global.loc.y + popup_rect_global.size.h,
|
|
||||||
)
|
|
||||||
.into();
|
|
||||||
popup_rect_global =
|
|
||||||
Rectangle::from_extemities(top_left, new_bottom_right);
|
|
||||||
}
|
|
||||||
|
|
||||||
if constrained_x(popup_rect_global).is_none() {
|
|
||||||
break 'block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The popup is flowing offscreen in the vertical direction.
|
|
||||||
if let Some(constrain_dir) = constrained_y(popup_rect_global) {
|
|
||||||
tracing::debug!("Popup was constrained on the y axis, repositioning");
|
|
||||||
let gravity = match positioner.gravity {
|
|
||||||
Gravity::Top | Gravity::TopLeft | Gravity::TopRight => DirV::Top,
|
|
||||||
_ => DirV::Bottom,
|
|
||||||
};
|
|
||||||
|
|
||||||
tracing::debug!(?gravity);
|
|
||||||
tracing::debug!(?constrain_dir);
|
|
||||||
|
|
||||||
'block: {
|
|
||||||
// If the constraint_adjustment has SlideY, we attempt to slide the popup
|
|
||||||
// towards the direction specified by positioner.gravity until TODO:
|
|
||||||
if positioner
|
|
||||||
.constraint_adjustment
|
|
||||||
.contains(ConstraintAdjustment::SlideY)
|
|
||||||
&& !is_subpopup
|
|
||||||
// If it's a subpopup, flip instead of slide. This makes
|
|
||||||
// stuff like Firefox nested dropdowns more intuitive.
|
|
||||||
{
|
|
||||||
// Slide towards the gravity until the opposite edge is unconstrained or the
|
|
||||||
// same edge is constrained
|
|
||||||
match (&constrain_dir, &gravity) {
|
|
||||||
(DirV::Top, DirV::Bottom) => {
|
|
||||||
let len_until_same_edge_constrained = output_bottom_y
|
|
||||||
- (popup_rect_global.loc.y + popup_rect_global.size.h);
|
|
||||||
let len_until_opp_edge_unconstrained =
|
|
||||||
output_top_y - popup_rect_global.loc.y;
|
|
||||||
|
|
||||||
popup_rect_global.loc.y += i32::min(
|
|
||||||
len_until_same_edge_constrained,
|
|
||||||
len_until_opp_edge_unconstrained,
|
|
||||||
)
|
|
||||||
.max(0);
|
|
||||||
}
|
|
||||||
(DirV::Bottom, DirV::Top) => {
|
|
||||||
let len_until_same_edge_constrained =
|
|
||||||
popup_rect_global.loc.y - output_top_y;
|
|
||||||
let len_until_opp_edge_unconstrained = (popup_rect_global.loc.y
|
|
||||||
+ popup_rect_global.size.h)
|
|
||||||
- output_bottom_y;
|
|
||||||
|
|
||||||
popup_rect_global.loc.y -= i32::min(
|
|
||||||
len_until_opp_edge_unconstrained,
|
|
||||||
len_until_same_edge_constrained,
|
|
||||||
)
|
|
||||||
.max(0);
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
};
|
|
||||||
|
|
||||||
if constrained_y(popup_rect_global).is_none() {
|
|
||||||
break 'block;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do the same but in the other direction
|
|
||||||
match (constrain_dir, gravity) {
|
|
||||||
(DirV::Bottom, DirV::Bottom) => {
|
|
||||||
let len_until_same_edge_unconstrained =
|
|
||||||
popup_rect_global.loc.y - output_top_y;
|
|
||||||
let len_until_opp_edge_constrained = (popup_rect_global.loc.y
|
|
||||||
+ popup_rect_global.size.h)
|
|
||||||
- output_bottom_y;
|
|
||||||
|
|
||||||
popup_rect_global.loc.y -= i32::min(
|
|
||||||
len_until_opp_edge_constrained,
|
|
||||||
len_until_same_edge_unconstrained,
|
|
||||||
)
|
|
||||||
.max(0);
|
|
||||||
}
|
|
||||||
(DirV::Top, DirV::Top) => {
|
|
||||||
let len_until_same_edge_unconstrained = output_bottom_y
|
|
||||||
- (popup_rect_global.loc.y + popup_rect_global.size.h);
|
|
||||||
let len_until_opp_edge_constrained =
|
|
||||||
output_top_y - popup_rect_global.loc.y;
|
|
||||||
|
|
||||||
popup_rect_global.loc.y += i32::min(
|
|
||||||
len_until_same_edge_unconstrained,
|
|
||||||
len_until_opp_edge_constrained,
|
|
||||||
)
|
|
||||||
.max(0);
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
};
|
|
||||||
|
|
||||||
if constrained_y(popup_rect_global).is_none() {
|
|
||||||
break 'block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the above didn't bring the popup onscreen or if it's a nested popup, flip it.
|
|
||||||
if positioner
|
|
||||||
.constraint_adjustment
|
|
||||||
.contains(ConstraintAdjustment::FlipY)
|
|
||||||
{
|
|
||||||
let old_gravity = positioner.gravity;
|
|
||||||
positioner.gravity = match positioner.gravity {
|
|
||||||
Gravity::Top => Gravity::Bottom,
|
|
||||||
Gravity::Bottom => Gravity::Top,
|
|
||||||
Gravity::TopLeft => Gravity::BottomLeft,
|
|
||||||
Gravity::BottomLeft => Gravity::TopLeft,
|
|
||||||
Gravity::TopRight => Gravity::BottomRight,
|
|
||||||
Gravity::BottomRight => Gravity::TopRight,
|
|
||||||
rest => rest,
|
|
||||||
};
|
|
||||||
|
|
||||||
let old_anchor = positioner.anchor_edges;
|
|
||||||
positioner.anchor_edges = match positioner.anchor_edges {
|
|
||||||
Anchor::Top => Anchor::Bottom,
|
|
||||||
Anchor::Bottom => Anchor::Top,
|
|
||||||
Anchor::TopLeft => Anchor::BottomLeft,
|
|
||||||
Anchor::BottomLeft => Anchor::TopLeft,
|
|
||||||
Anchor::TopRight => Anchor::BottomRight,
|
|
||||||
Anchor::BottomRight => Anchor::TopRight,
|
|
||||||
rest => rest,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut geo = positioner.get_geometry();
|
|
||||||
tracing::debug!(?geo, "Flipped Y geo");
|
|
||||||
geo.loc += loc_diff;
|
|
||||||
geo.loc.x = popup_rect_global.loc.x;
|
|
||||||
tracing::debug!(?geo, "Flipped Y geo global");
|
|
||||||
if constrained_y(geo).is_none() {
|
|
||||||
popup_rect_global = geo;
|
|
||||||
break 'block;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The protocol states that if flipping it didn't bring it onscreen,
|
|
||||||
// then it should just stay at its unflipped state.
|
|
||||||
positioner.gravity = old_gravity;
|
|
||||||
positioner.anchor_edges = old_anchor;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finally, if flipping it failed, resize it to fit.
|
|
||||||
if positioner
|
|
||||||
.constraint_adjustment
|
|
||||||
.contains(ConstraintAdjustment::ResizeY)
|
|
||||||
{
|
|
||||||
// Slice off the top side
|
|
||||||
if popup_rect_global.loc.y < output_top_y {
|
|
||||||
let len_to_slice = output_top_y - popup_rect_global.loc.y;
|
|
||||||
let new_top_left: Point<i32, Logical> = (
|
|
||||||
popup_rect_global.loc.x,
|
|
||||||
popup_rect_global.loc.y + len_to_slice,
|
|
||||||
)
|
|
||||||
.into();
|
|
||||||
let bottom_right: Point<i32, Logical> = (
|
|
||||||
popup_rect_global.loc.x + popup_rect_global.size.w,
|
|
||||||
popup_rect_global.loc.y + popup_rect_global.size.h,
|
|
||||||
)
|
|
||||||
.into();
|
|
||||||
popup_rect_global =
|
|
||||||
Rectangle::from_extemities(new_top_left, bottom_right);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slice off the right side
|
|
||||||
if popup_rect_global.loc.y + popup_rect_global.size.h > output_bottom_y {
|
|
||||||
let len_to_slice = (popup_rect_global.loc.y + popup_rect_global.size.h)
|
|
||||||
- output_bottom_y;
|
|
||||||
let top_left = popup_rect_global.loc;
|
|
||||||
let new_bottom_right: Point<i32, Logical> = (
|
|
||||||
popup_rect_global.loc.x + popup_rect_global.size.w,
|
|
||||||
popup_rect_global.loc.y + popup_rect_global.size.h - len_to_slice,
|
|
||||||
)
|
|
||||||
.into();
|
|
||||||
popup_rect_global =
|
|
||||||
Rectangle::from_extemities(top_left, new_bottom_right);
|
|
||||||
}
|
|
||||||
|
|
||||||
if constrained_y(popup_rect_global).is_none() {
|
|
||||||
break 'block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tracing::debug!(?popup_rect_global, "New popup");
|
|
||||||
popup_rect_global.loc -= loc_diff;
|
|
||||||
|
|
||||||
surface.with_pending_state(|state| state.geometry = popup_rect_global);
|
|
||||||
|
|
||||||
if let Err(err) = self.popup_manager.track_popup(PopupKind::from(surface)) {
|
if let Err(err) = self.popup_manager.track_popup(PopupKind::from(surface)) {
|
||||||
tracing::warn!("failed to track popup: {}", err);
|
tracing::warn!("failed to track popup: {}", err);
|
||||||
|
|
Loading…
Reference in a new issue