window-management: allow moving/resizing popups
This commit is contained in:
parent
8d5ac9a2b7
commit
15e6ab2b8a
7 changed files with 268 additions and 38 deletions
|
|
@ -1146,6 +1146,10 @@ impl WlSeatGlobal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn cancel_popup_move(self: &Rc<Self>) {
|
||||||
|
self.pointer_owner.grab_node_removed(self);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn cancel_dnd(self: &Rc<Self>) {
|
pub fn cancel_dnd(self: &Rc<Self>) {
|
||||||
self.pointer_owner.cancel_dnd(self);
|
self.pointer_owner.cancel_dnd(self);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,11 @@ use {
|
||||||
BTN_LEFT, BTN_RIGHT, CHANGE_CURSOR_MOVED, CHANGE_TREE, Dnd, DroppedDnd,
|
BTN_LEFT, BTN_RIGHT, CHANGE_CURSOR_MOVED, CHANGE_TREE, Dnd, DroppedDnd,
|
||||||
NodeSeatState, WlSeatError, WlSeatGlobal, wl_pointer::PendingScroll,
|
NodeSeatState, WlSeatError, WlSeatGlobal, wl_pointer::PendingScroll,
|
||||||
},
|
},
|
||||||
wl_surface::{WlSurface, dnd_icon::DndIcon},
|
wl_surface::{
|
||||||
|
WlSurface,
|
||||||
|
dnd_icon::DndIcon,
|
||||||
|
xdg_surface::{xdg_popup::XdgPopup, xdg_toplevel::ResizeEdges},
|
||||||
|
},
|
||||||
xdg_toplevel_drag_v1::XdgToplevelDragV1,
|
xdg_toplevel_drag_v1::XdgToplevelDragV1,
|
||||||
},
|
},
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
|
|
@ -20,7 +24,7 @@ use {
|
||||||
PlaceholderNode, TddType, ToplevelNode, WorkspaceDragDestination, WorkspaceNode,
|
PlaceholderNode, TddType, ToplevelNode, WorkspaceDragDestination, WorkspaceNode,
|
||||||
WsMoveConfig, move_ws_to_output, toplevel_set_workspace,
|
WsMoveConfig, move_ws_to_output, toplevel_set_workspace,
|
||||||
},
|
},
|
||||||
utils::{clonecell::CloneCell, smallmap::SmallMap},
|
utils::{bitflags::BitflagsExt, clonecell::CloneCell, smallmap::SmallMap},
|
||||||
},
|
},
|
||||||
linearize::LinearizeExt,
|
linearize::LinearizeExt,
|
||||||
std::{
|
std::{
|
||||||
|
|
@ -944,7 +948,7 @@ impl<S: ?Sized> Drop for SelectWorkspaceUsecase<S> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SimplePointerOwnerUsecase for WindowManagementUsecase {
|
impl SimplePointerOwnerUsecase for WindowManagementUsecase {
|
||||||
const FIND_TREE_USECASE: FindTreeUsecase = FindTreeUsecase::SelectToplevel;
|
const FIND_TREE_USECASE: FindTreeUsecase = FindTreeUsecase::SelectToplevelOrPopup;
|
||||||
const IS_DEFAULT: bool = false;
|
const IS_DEFAULT: bool = false;
|
||||||
|
|
||||||
fn default_button(
|
fn default_button(
|
||||||
|
|
@ -954,33 +958,42 @@ impl SimplePointerOwnerUsecase for WindowManagementUsecase {
|
||||||
button: u32,
|
button: u32,
|
||||||
pn: &Rc<dyn Node>,
|
pn: &Rc<dyn Node>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let Some(tl) = pn.clone().node_into_toplevel() else {
|
let pos = pn.node_absolute_position();
|
||||||
return false;
|
|
||||||
};
|
|
||||||
let pos = tl.node_absolute_position();
|
|
||||||
let (x, y) = seat.pointer_cursor.position();
|
let (x, y) = seat.pointer_cursor.position();
|
||||||
let (x, y) = (x.round_down(), y.round_down());
|
let (x, y) = (x.round_down(), y.round_down());
|
||||||
let (mut dx, mut dy) = pos.translate(x, y);
|
let (mut dx, mut dy) = pos.translate(x, y);
|
||||||
let owner: Rc<dyn PointerOwner> = if button == BTN_LEFT {
|
let owner: Rc<dyn PointerOwner> = if button == BTN_LEFT {
|
||||||
seat.pointer_cursor.set_known(KnownCursor::Move);
|
if let Some(tl) = pn.clone().node_into_toplevel() {
|
||||||
if tl.tl_data().is_fullscreen.get() {
|
seat.pointer_cursor.set_known(KnownCursor::Move);
|
||||||
Rc::new(ToplevelGrabPointerOwner {
|
if tl.tl_data().is_fullscreen.get() {
|
||||||
tl,
|
Rc::new(ToplevelGrabPointerOwner {
|
||||||
usecase: MoveFullscreenToplevelGrabPointerOwner,
|
|
||||||
})
|
|
||||||
} else if tl.tl_data().float.is_none() {
|
|
||||||
Rc::new(ToplevelGrabPointerOwner {
|
|
||||||
tl: tl.clone(),
|
|
||||||
usecase: TileDragUsecase {
|
|
||||||
tl,
|
tl,
|
||||||
destination: Default::default(),
|
usecase: MoveFullscreenToplevelGrabPointerOwner,
|
||||||
},
|
})
|
||||||
|
} else if tl.tl_data().float.is_none() {
|
||||||
|
Rc::new(ToplevelGrabPointerOwner {
|
||||||
|
tl: tl.clone(),
|
||||||
|
usecase: TileDragUsecase {
|
||||||
|
tl,
|
||||||
|
destination: Default::default(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Rc::new(ToplevelGrabPointerOwner {
|
||||||
|
tl,
|
||||||
|
usecase: MoveToplevelGrabPointerOwner { dx, dy },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else if let Some(popup) = pn.clone().node_into_popup() {
|
||||||
|
popup.add_interactive_move(seat);
|
||||||
|
seat.pointer_cursor.set_known(KnownCursor::Move);
|
||||||
|
Rc::new(PopupPointerOwner {
|
||||||
|
popup,
|
||||||
|
button,
|
||||||
|
usecase: PopupPointerOwnerMoveUsecase { dx, dy },
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Rc::new(ToplevelGrabPointerOwner {
|
return false;
|
||||||
tl,
|
|
||||||
usecase: MoveToplevelGrabPointerOwner { dx, dy },
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} else if button == BTN_RIGHT {
|
} else if button == BTN_RIGHT {
|
||||||
let mut top = false;
|
let mut top = false;
|
||||||
|
|
@ -1006,18 +1019,39 @@ impl SimplePointerOwnerUsecase for WindowManagementUsecase {
|
||||||
(true, false, false, true) => KnownCursor::NwResize,
|
(true, false, false, true) => KnownCursor::NwResize,
|
||||||
_ => KnownCursor::Move,
|
_ => KnownCursor::Move,
|
||||||
};
|
};
|
||||||
seat.pointer_cursor.set_known(cursor);
|
if let Some(tl) = pn.clone().node_into_toplevel() {
|
||||||
Rc::new(ToplevelGrabPointerOwner {
|
seat.pointer_cursor.set_known(cursor);
|
||||||
tl,
|
Rc::new(ToplevelGrabPointerOwner {
|
||||||
usecase: ResizeToplevelGrabPointerOwner {
|
tl,
|
||||||
top,
|
usecase: ResizeToplevelGrabPointerOwner {
|
||||||
right,
|
top,
|
||||||
bottom,
|
right,
|
||||||
left,
|
bottom,
|
||||||
dx,
|
left,
|
||||||
dy,
|
dx,
|
||||||
},
|
dy,
|
||||||
})
|
},
|
||||||
|
})
|
||||||
|
} else if let Some(popup) = pn.clone().node_into_popup() {
|
||||||
|
popup.add_interactive_move(seat);
|
||||||
|
seat.pointer_cursor.set_known(cursor);
|
||||||
|
Rc::new(PopupPointerOwner {
|
||||||
|
popup,
|
||||||
|
button,
|
||||||
|
usecase: PopupPointerOwnerResizeUsecase {
|
||||||
|
edges: ResizeEdges {
|
||||||
|
top,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
bottom,
|
||||||
|
},
|
||||||
|
dx,
|
||||||
|
dy,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
@ -1458,3 +1492,122 @@ impl UiDragUsecase for WorkspaceDragUsecase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct PopupPointerOwner<T> {
|
||||||
|
popup: Rc<XdgPopup>,
|
||||||
|
button: u32,
|
||||||
|
usecase: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
trait PopupPointerOwnerUsecase: Sized + 'static {
|
||||||
|
fn apply_changes(&self, popup: &Rc<XdgPopup>, seat: &Rc<WlSeatGlobal>);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PopupPointerOwner<T>
|
||||||
|
where
|
||||||
|
T: PopupPointerOwnerUsecase,
|
||||||
|
{
|
||||||
|
fn revert_to_window_management(&self, seat: &Rc<WlSeatGlobal>) {
|
||||||
|
self.popup.remove_interactive_move(seat);
|
||||||
|
self.popup.node_seat_state().remove_pointer_grab(seat);
|
||||||
|
seat.pointer_cursor.set_known(KnownCursor::Default);
|
||||||
|
seat.pointer_owner.owner.set(Rc::new(SimplePointerOwner {
|
||||||
|
usecase: WindowManagementUsecase,
|
||||||
|
}));
|
||||||
|
seat.changes.or_assign(CHANGE_CURSOR_MOVED);
|
||||||
|
seat.apply_changes();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn revert_to_previous(&self, seat: &Rc<WlSeatGlobal>) {
|
||||||
|
self.revert_to_window_management(seat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> PointerOwner for PopupPointerOwner<T>
|
||||||
|
where
|
||||||
|
T: PopupPointerOwnerUsecase,
|
||||||
|
{
|
||||||
|
fn button(&self, seat: &Rc<WlSeatGlobal>, _time_usec: u64, button: u32, state: ButtonState) {
|
||||||
|
if button != self.button || state != ButtonState::Released {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.revert_to_previous(seat);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_changes(&self, seat: &Rc<WlSeatGlobal>) {
|
||||||
|
if seat.changes.get().not_contains(CHANGE_CURSOR_MOVED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.usecase.apply_changes(&self.popup, seat);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn revert_to_default(&self, seat: &Rc<WlSeatGlobal>) {
|
||||||
|
self.popup.remove_interactive_move(seat);
|
||||||
|
self.popup.node_seat_state().remove_pointer_grab(seat);
|
||||||
|
seat.pointer_owner.set_default_pointer_owner(seat);
|
||||||
|
seat.tree_changed.trigger();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn grab_node_removed(&self, seat: &Rc<WlSeatGlobal>) {
|
||||||
|
self.revert_to_previous(seat);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn disable_window_management(&self, seat: &Rc<WlSeatGlobal>) {
|
||||||
|
self.revert_to_default(seat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PopupPointerOwnerMoveUsecase {
|
||||||
|
dx: i32,
|
||||||
|
dy: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PopupPointerOwnerUsecase for PopupPointerOwnerMoveUsecase {
|
||||||
|
fn apply_changes(&self, popup: &Rc<XdgPopup>, seat: &Rc<WlSeatGlobal>) {
|
||||||
|
let (x, y) = seat.pointer_cursor.position();
|
||||||
|
let (x, y) = (x.round_down(), y.round_down());
|
||||||
|
let pos = popup.node_absolute_position();
|
||||||
|
let (x, y) = pos.translate(x, y);
|
||||||
|
if (x, y) != (self.dx, self.dy) {
|
||||||
|
popup.move_(x - self.dx, y - self.dy);
|
||||||
|
seat.tree_changed.trigger();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PopupPointerOwnerResizeUsecase {
|
||||||
|
edges: ResizeEdges,
|
||||||
|
dx: i32,
|
||||||
|
dy: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PopupPointerOwnerUsecase for PopupPointerOwnerResizeUsecase {
|
||||||
|
fn apply_changes(&self, popup: &Rc<XdgPopup>, seat: &Rc<WlSeatGlobal>) {
|
||||||
|
let (x, y) = seat.pointer_cursor.position();
|
||||||
|
let (x, y) = (x.round_down(), y.round_down());
|
||||||
|
let pos = popup.node_absolute_position();
|
||||||
|
let (x, y) = pos.translate(x, y);
|
||||||
|
let mut dx1 = 0;
|
||||||
|
let mut dx2 = 0;
|
||||||
|
let mut dy1 = 0;
|
||||||
|
let mut dy2 = 0;
|
||||||
|
if self.edges.left {
|
||||||
|
dx1 = x - self.dx;
|
||||||
|
dx1 = dx1.min(pos.width().saturating_sub(1));
|
||||||
|
} else if self.edges.right {
|
||||||
|
dx2 = self.dx - (pos.width() - x);
|
||||||
|
dx2 = dx2.max(-pos.width().saturating_sub(1));
|
||||||
|
}
|
||||||
|
if self.edges.top {
|
||||||
|
dy1 = y - self.dy;
|
||||||
|
dy1 = dy1.min(pos.height().saturating_sub(1));
|
||||||
|
} else if self.edges.bottom {
|
||||||
|
dy2 = self.dy - (pos.height() - y);
|
||||||
|
dy2 = dy2.max(-pos.height().saturating_sub(1));
|
||||||
|
}
|
||||||
|
if dx1 != 0 || dx2 != 0 || dy1 != 0 || dy2 != 0 {
|
||||||
|
popup.resize(dx1, dy1, dx2, dy2);
|
||||||
|
seat.tree_changed.trigger();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -399,6 +399,7 @@ impl Node for Xwindow {
|
||||||
match usecase {
|
match usecase {
|
||||||
FindTreeUsecase::None => {}
|
FindTreeUsecase::None => {}
|
||||||
FindTreeUsecase::SelectToplevel => return FindTreeResult::AcceptsInput,
|
FindTreeUsecase::SelectToplevel => return FindTreeResult::AcceptsInput,
|
||||||
|
FindTreeUsecase::SelectToplevelOrPopup => return FindTreeResult::AcceptsInput,
|
||||||
FindTreeUsecase::SelectWorkspace => return FindTreeResult::Other,
|
FindTreeUsecase::SelectWorkspace => return FindTreeResult::Other,
|
||||||
}
|
}
|
||||||
let rect = self.x.surface.buffer_abs_pos.get();
|
let rect = self.x.surface.buffer_abs_pos.get();
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use {
|
||||||
cursor::KnownCursor,
|
cursor::KnownCursor,
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
ifs::{
|
ifs::{
|
||||||
wl_seat::{NodeSeatState, WlSeatGlobal, tablet::TabletTool},
|
wl_seat::{NodeSeatState, SeatId, WlSeatGlobal, tablet::TabletTool},
|
||||||
wl_surface::{
|
wl_surface::{
|
||||||
tray::TrayItemId,
|
tray::TrayItemId,
|
||||||
xdg_surface::{XdgSurface, XdgSurfaceExt},
|
xdg_surface::{XdgSurface, XdgSurfaceExt},
|
||||||
|
|
@ -22,7 +22,7 @@ use {
|
||||||
Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeLayerLink,
|
Direction, FindTreeResult, FindTreeUsecase, FoundNode, Node, NodeId, NodeLayerLink,
|
||||||
NodeLocation, NodeVisitor, OutputNode, StackedNode,
|
NodeLocation, NodeVisitor, OutputNode, StackedNode,
|
||||||
},
|
},
|
||||||
utils::clonecell::CloneCell,
|
utils::{clonecell::CloneCell, smallmap::SmallMap},
|
||||||
wire::{XdgPopupId, xdg_popup::*},
|
wire::{XdgPopupId, xdg_popup::*},
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
|
|
@ -65,6 +65,7 @@ pub struct XdgPopup {
|
||||||
pub tracker: Tracker<Self>,
|
pub tracker: Tracker<Self>,
|
||||||
seat_state: NodeSeatState,
|
seat_state: NodeSeatState,
|
||||||
set_visible_prepared: Cell<bool>,
|
set_visible_prepared: Cell<bool>,
|
||||||
|
interactive_moves: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for XdgPopup {
|
impl Debug for XdgPopup {
|
||||||
|
|
@ -93,6 +94,7 @@ impl XdgPopup {
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
seat_state: Default::default(),
|
seat_state: Default::default(),
|
||||||
set_visible_prepared: Cell::new(false),
|
set_visible_prepared: Cell::new(false),
|
||||||
|
interactive_moves: Default::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -222,6 +224,43 @@ impl XdgPopup {
|
||||||
.set_absolute_desired_extents(&rel.move_(parent.x1(), parent.y1()));
|
.set_absolute_desired_extents(&rel.move_(parent.x1(), parent.y1()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_relative_position(&self, rel: Rect) {
|
||||||
|
self.relative_position.set(rel);
|
||||||
|
self.update_absolute_position();
|
||||||
|
self.send_configure(rel.x1(), rel.y1(), rel.width(), rel.height());
|
||||||
|
self.xdg.schedule_configure();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_(&self, dx: i32, dy: i32) {
|
||||||
|
let rel = self.relative_position.get().move_(dx, dy);
|
||||||
|
self.set_relative_position(rel);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resize(&self, dx1: i32, dy1: i32, dx2: i32, dy2: i32) {
|
||||||
|
let rel = self.relative_position.get();
|
||||||
|
let rel = Rect::new(
|
||||||
|
rel.x1() + dx1,
|
||||||
|
rel.y1() + dy1,
|
||||||
|
rel.x2() + dx2,
|
||||||
|
rel.y2() + dy2,
|
||||||
|
);
|
||||||
|
let Some(rel) = rel else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if rel.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.set_relative_position(rel);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_interactive_move(&self, seat: &Rc<WlSeatGlobal>) {
|
||||||
|
self.interactive_moves.insert(seat.id(), seat.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_interactive_move(&self, seat: &Rc<WlSeatGlobal>) {
|
||||||
|
self.interactive_moves.remove(&seat.id());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl XdgPopupRequestHandler for XdgPopup {
|
impl XdgPopupRequestHandler for XdgPopup {
|
||||||
|
|
@ -240,6 +279,9 @@ impl XdgPopupRequestHandler for XdgPopup {
|
||||||
|
|
||||||
fn reposition(&self, req: Reposition, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
fn reposition(&self, req: Reposition, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
*self.pos.borrow_mut() = self.xdg.surface.client.lookup(req.positioner)?.value();
|
*self.pos.borrow_mut() = self.xdg.surface.client.lookup(req.positioner)?.value();
|
||||||
|
while let Some((_, seat)) = self.interactive_moves.pop() {
|
||||||
|
seat.cancel_popup_move();
|
||||||
|
}
|
||||||
if let Some(parent) = self.parent.get() {
|
if let Some(parent) = self.parent.get() {
|
||||||
self.update_position(&*parent);
|
self.update_position(&*parent);
|
||||||
let rel = self.relative_position.get();
|
let rel = self.relative_position.get();
|
||||||
|
|
@ -343,6 +385,12 @@ impl Node for XdgPopup {
|
||||||
match usecase {
|
match usecase {
|
||||||
FindTreeUsecase::None => {}
|
FindTreeUsecase::None => {}
|
||||||
FindTreeUsecase::SelectToplevel => return FindTreeResult::Other,
|
FindTreeUsecase::SelectToplevel => return FindTreeResult::Other,
|
||||||
|
FindTreeUsecase::SelectToplevelOrPopup => {
|
||||||
|
let len = tree.len();
|
||||||
|
let res = self.xdg.find_tree_at(x, y, tree);
|
||||||
|
tree.truncate(len);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
FindTreeUsecase::SelectWorkspace => return FindTreeResult::Other,
|
FindTreeUsecase::SelectWorkspace => return FindTreeResult::Other,
|
||||||
}
|
}
|
||||||
self.xdg.find_tree_at(x, y, tree)
|
self.xdg.find_tree_at(x, y, tree)
|
||||||
|
|
@ -380,6 +428,10 @@ impl Node for XdgPopup {
|
||||||
) {
|
) {
|
||||||
tool.cursor().set_known(KnownCursor::Default)
|
tool.cursor().set_known(KnownCursor::Default)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn node_into_popup(self: Rc<Self>) -> Option<Rc<XdgPopup>> {
|
||||||
|
Some(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StackedNode for XdgPopup {
|
impl StackedNode for XdgPopup {
|
||||||
|
|
|
||||||
|
|
@ -601,6 +601,7 @@ impl Node for XdgToplevel {
|
||||||
match usecase {
|
match usecase {
|
||||||
FindTreeUsecase::None => {}
|
FindTreeUsecase::None => {}
|
||||||
FindTreeUsecase::SelectToplevel => return FindTreeResult::AcceptsInput,
|
FindTreeUsecase::SelectToplevel => return FindTreeResult::AcceptsInput,
|
||||||
|
FindTreeUsecase::SelectToplevelOrPopup => return FindTreeResult::AcceptsInput,
|
||||||
FindTreeUsecase::SelectWorkspace => return FindTreeResult::Other,
|
FindTreeUsecase::SelectWorkspace => return FindTreeResult::Other,
|
||||||
}
|
}
|
||||||
self.xdg.find_tree_at(x, y, tree)
|
self.xdg.find_tree_at(x, y, tree)
|
||||||
|
|
@ -832,3 +833,11 @@ pub enum XdgToplevelError {
|
||||||
NonNegative,
|
NonNegative,
|
||||||
}
|
}
|
||||||
efrom!(XdgToplevelError, ClientError);
|
efrom!(XdgToplevelError, ClientError);
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub struct ResizeEdges {
|
||||||
|
pub top: bool,
|
||||||
|
pub left: bool,
|
||||||
|
pub right: bool,
|
||||||
|
pub bottom: bool,
|
||||||
|
}
|
||||||
|
|
|
||||||
10
src/tree.rs
10
src/tree.rs
|
|
@ -13,7 +13,10 @@ use {
|
||||||
},
|
},
|
||||||
wl_pointer::PendingScroll,
|
wl_pointer::PendingScroll,
|
||||||
},
|
},
|
||||||
wl_surface::{WlSurface, tray::TrayItemId, zwlr_layer_surface_v1::ZwlrLayerSurfaceV1},
|
wl_surface::{
|
||||||
|
WlSurface, tray::TrayItemId, xdg_surface::xdg_popup::XdgPopup,
|
||||||
|
zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
keyboard::KeyboardState,
|
keyboard::KeyboardState,
|
||||||
rect::Rect,
|
rect::Rect,
|
||||||
|
|
@ -113,6 +116,7 @@ impl FindTreeResult {
|
||||||
pub enum FindTreeUsecase {
|
pub enum FindTreeUsecase {
|
||||||
None,
|
None,
|
||||||
SelectToplevel,
|
SelectToplevel,
|
||||||
|
SelectToplevelOrPopup,
|
||||||
SelectWorkspace,
|
SelectWorkspace,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -642,6 +646,10 @@ pub trait Node: 'static {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn node_into_popup(self: Rc<Self>) -> Option<Rc<XdgPopup>> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
// TYPE CHECKERS
|
// TYPE CHECKERS
|
||||||
|
|
||||||
fn node_is_container(&self) -> bool {
|
fn node_is_container(&self) -> bool {
|
||||||
|
|
|
||||||
|
|
@ -1076,6 +1076,7 @@ impl OutputNode {
|
||||||
match usecase {
|
match usecase {
|
||||||
FindTreeUsecase::None => {}
|
FindTreeUsecase::None => {}
|
||||||
FindTreeUsecase::SelectToplevel => return FindTreeResult::Other,
|
FindTreeUsecase::SelectToplevel => return FindTreeResult::Other,
|
||||||
|
FindTreeUsecase::SelectToplevelOrPopup => return FindTreeResult::Other,
|
||||||
FindTreeUsecase::SelectWorkspace => return FindTreeResult::Other,
|
FindTreeUsecase::SelectWorkspace => return FindTreeResult::Other,
|
||||||
}
|
}
|
||||||
let len = tree.len();
|
let len = tree.len();
|
||||||
|
|
@ -1639,6 +1640,7 @@ impl Node for OutputNode {
|
||||||
let allow_surface = match usecase {
|
let allow_surface = match usecase {
|
||||||
FindTreeUsecase::None => true,
|
FindTreeUsecase::None => true,
|
||||||
FindTreeUsecase::SelectToplevel => false,
|
FindTreeUsecase::SelectToplevel => false,
|
||||||
|
FindTreeUsecase::SelectToplevelOrPopup => false,
|
||||||
FindTreeUsecase::SelectWorkspace => false,
|
FindTreeUsecase::SelectWorkspace => false,
|
||||||
};
|
};
|
||||||
if allow_surface && let Some(ls) = self.lock_surface.get() {
|
if allow_surface && let Some(ls) = self.lock_surface.get() {
|
||||||
|
|
@ -1655,6 +1657,7 @@ impl Node for OutputNode {
|
||||||
let select_workspace = match usecase {
|
let select_workspace = match usecase {
|
||||||
FindTreeUsecase::None => false,
|
FindTreeUsecase::None => false,
|
||||||
FindTreeUsecase::SelectToplevel => false,
|
FindTreeUsecase::SelectToplevel => false,
|
||||||
|
FindTreeUsecase::SelectToplevelOrPopup => false,
|
||||||
FindTreeUsecase::SelectWorkspace => true,
|
FindTreeUsecase::SelectWorkspace => true,
|
||||||
};
|
};
|
||||||
if select_workspace && ws_rect_rel.contains(x, y) {
|
if select_workspace && ws_rect_rel.contains(x, y) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue