From ce8877b67e87561415d636789720abd6a2be2f63 Mon Sep 17 00:00:00 2001 From: Nova Date: Sun, 6 Aug 2023 18:32:43 -0400 Subject: [PATCH] refactor(wayland): replace popups with child surfaces --- src/nodes/items/panel.rs | 18 +++--- src/wayland/xdg_shell.rs | 127 +++++++++++++++++++++++++++++++++------ src/wayland/xwayland.rs | 2 +- 3 files changed, 119 insertions(+), 28 deletions(-) diff --git a/src/nodes/items/panel.rs b/src/nodes/items/panel.rs index b58fd21..a92cc45 100644 --- a/src/nodes/items/panel.rs +++ b/src/nodes/items/panel.rs @@ -44,9 +44,9 @@ lazy_static! { "commit_toplevel", "recommend_toplevel_state", "set_cursor", - "new_popup", - "reposition_popup", - "drop_popup", + "new_child", + "reposition_child", + "drop_child", ], ui: Default::default(), items: Registry::new(), @@ -60,7 +60,7 @@ lazy_static! { pub enum SurfaceID { Cursor, Toplevel, - Popup(String), + Child(String), } impl Default for SurfaceID { fn default() -> Self { @@ -94,15 +94,15 @@ impl<'de> Visitor<'de> for SurfaceIDVisitor { match discrim { "Cursor" => Ok(SurfaceID::Cursor), "Toplevel" => Ok(SurfaceID::Toplevel), - "Popup" => { + "Child" => { let Some(text) = seq.next_element()? else { - return Err(A::Error::missing_field("popup_text")); + return Err(A::Error::missing_field("child_text")); }; - Ok(SurfaceID::Popup(text)) + Ok(SurfaceID::Child(text)) } _ => Err(A::Error::unknown_variant( discrim, - &["Cursor", "Toplevel", "Popup"], + &["Cursor", "Toplevel", "Child"], )), } } @@ -113,7 +113,7 @@ impl serde::Serialize for SurfaceID { match self { Self::Cursor => ["Cursor"].serialize(serializer), Self::Toplevel => ["Toplevel"].serialize(serializer), - Self::Popup(text) => ["Popup", text].serialize(serializer), + Self::Child(text) => ["Child", text].serialize(serializer), } } } diff --git a/src/wayland/xdg_shell.rs b/src/wayland/xdg_shell.rs index 682bcb0..38a0b9a 100644 --- a/src/wayland/xdg_shell.rs +++ b/src/wayland/xdg_shell.rs @@ -82,14 +82,14 @@ impl Dispatch for WaylandState { } } -#[derive(Debug, Serialize, Clone, Copy)] +#[derive(Debug, Clone, Copy)] pub struct PositionerData { size: Vector2, anchor_rect_pos: Vector2, anchor_rect_size: Vector2, - anchor: u32, - gravity: u32, - constraint_adjustment: u32, + anchor: Anchor, + gravity: Gravity, + constraint_adjustment: ConstraintAdjustment, offset: Vector2, reactive: bool, } @@ -99,15 +99,103 @@ impl Default for PositionerData { size: Vector2::from([0; 2]), anchor_rect_pos: Vector2::from([0; 2]), anchor_rect_size: Vector2::from([0; 2]), - anchor: Anchor::None as u32, - gravity: Gravity::None as u32, - constraint_adjustment: ConstraintAdjustment::None.bits(), + anchor: Anchor::None, + gravity: Gravity::None, + constraint_adjustment: ConstraintAdjustment::None, offset: Vector2::from([0; 2]), reactive: false, } } } +impl PositionerData { + fn anchor_has_edge(&self, edge: Anchor) -> bool { + match edge { + Anchor::Top => { + self.anchor == Anchor::Top + || self.anchor == Anchor::TopLeft + || self.anchor == Anchor::TopRight + } + Anchor::Bottom => { + self.anchor == Anchor::Bottom + || self.anchor == Anchor::BottomLeft + || self.anchor == Anchor::BottomRight + } + Anchor::Left => { + self.anchor == Anchor::Left + || self.anchor == Anchor::TopLeft + || self.anchor == Anchor::BottomLeft + } + Anchor::Right => { + self.anchor == Anchor::Right + || self.anchor == Anchor::TopRight + || self.anchor == Anchor::BottomRight + } + _ => unreachable!(), + } + } + + fn gravity_has_edge(&self, edge: Gravity) -> bool { + match edge { + Gravity::Top => { + self.gravity == Gravity::Top + || self.gravity == Gravity::TopLeft + || self.gravity == Gravity::TopRight + } + Gravity::Bottom => { + self.gravity == Gravity::Bottom + || self.gravity == Gravity::BottomLeft + || self.gravity == Gravity::BottomRight + } + Gravity::Left => { + self.gravity == Gravity::Left + || self.gravity == Gravity::TopLeft + || self.gravity == Gravity::BottomLeft + } + Gravity::Right => { + self.gravity == Gravity::Right + || self.gravity == Gravity::TopRight + || self.gravity == Gravity::BottomRight + } + _ => unreachable!(), + } + } + + pub fn get_pos(&self) -> Vector2 { + let mut pos = self.offset; + + if self.anchor_has_edge(Anchor::Top) { + pos.y += self.anchor_rect_pos.y; + } else if self.anchor_has_edge(Anchor::Bottom) { + pos.y += self.anchor_rect_pos.y + self.anchor_rect_size.y as i32; + } else { + pos.y += self.anchor_rect_pos.y + self.anchor_rect_size.y as i32 / 2; + } + + if self.anchor_has_edge(Anchor::Left) { + pos.x += self.anchor_rect_pos.x; + } else if self.anchor_has_edge(Anchor::Right) { + pos.x += self.anchor_rect_pos.x + self.anchor_rect_size.x as i32; + } else { + pos.x += self.anchor_rect_pos.x + self.anchor_rect_size.x as i32 / 2; + } + + if self.gravity_has_edge(Gravity::Top) { + pos.y -= self.size.y as i32; + } else if !self.gravity_has_edge(Gravity::Bottom) { + pos.y -= self.size.y as i32 / 2; + } + + if self.gravity_has_edge(Gravity::Left) { + pos.x -= self.size.x as i32; + } else if !self.gravity_has_edge(Gravity::Right) { + pos.x -= self.size.x as i32 / 2; + } + + pos + } +} + impl Dispatch, WaylandState> for WaylandState { fn request( _state: &mut WaylandState, @@ -152,13 +240,13 @@ impl Dispatch, WaylandState> for WaylandSta xdg_positioner::Request::SetAnchor { anchor } => { if let WEnum::Value(anchor) = anchor { debug!(?positioner, ?anchor, "Set positioner anchor"); - data.lock().anchor = anchor as u32; + data.lock().anchor = anchor; } } xdg_positioner::Request::SetGravity { gravity } => { if let WEnum::Value(gravity) = gravity { debug!(?positioner, ?gravity, "Set positioner gravity"); - data.lock().gravity = gravity as u32; + data.lock().gravity = gravity; } } xdg_positioner::Request::SetConstraintAdjustment { @@ -168,7 +256,8 @@ impl Dispatch, WaylandState> for WaylandSta ?positioner, constraint_adjustment, "Set positioner constraint adjustment" ); - data.lock().constraint_adjustment = constraint_adjustment; + data.lock().constraint_adjustment = + ConstraintAdjustment::from_bits(constraint_adjustment).unwrap(); } xdg_positioner::Request::SetOffset { x, y } => { debug!(?positioner, x, y, "Set positioner offset"); @@ -353,7 +442,7 @@ impl Dispatch, WaylandState> for WaylandState positioner, )); let xdg_popup = data_init.init(id, popup_data); - xdg_surface_data.lock().surface_id = SurfaceID::Popup(uid); + xdg_surface_data.lock().surface_id = SurfaceID::Child(uid); let panel_item = parent_data.panel_item().unwrap(); xdg_surface_data.lock().panel_item = Arc::downgrade(&panel_item); debug!(?xdg_popup, ?xdg_surface, "Create XDG popup"); @@ -640,7 +729,8 @@ impl Serialize for PopupData { let mut seq = serializer.serialize_seq(None)?; seq.serialize_element(&self.uid)?; seq.serialize_element(&self.parent_id)?; - seq.serialize_element(&positioner_data)?; + seq.serialize_element(&positioner_data.get_pos())?; + seq.serialize_element(&positioner_data.size)?; seq.end() } } @@ -669,7 +759,7 @@ impl Dispatch, WaylandState> for WaylandState { data.grabbed = true; debug!(?xdg_popup, ?seat, serial, "XDG popup grab"); let Some(panel_item) = data.panel_item() else {return}; - panel_item.grab_keyboard(Some(SurfaceID::Popup(data.uid.clone()))); + panel_item.grab_keyboard(Some(SurfaceID::Child(data.uid.clone()))); } xdg_popup::Request::Reposition { positioner, token } => { let mut data = data.lock(); @@ -735,7 +825,7 @@ impl XDGBackend { match id { SurfaceID::Cursor => self.cursor.borrow().as_ref()?.surface.upgrade().ok(), SurfaceID::Toplevel => self.toplevel_wl_surface(), - SurfaceID::Popup(popup) => { + SurfaceID::Child(popup) => { let popups = self.popups.lock(); let popup = popups.get(popup)?.upgrade().ok()?; let wl_surface = PopupData::get(&popup)?.lock().wl_surface(); @@ -781,14 +871,15 @@ impl XDGBackend { let Some(node) = panel_item.node() else {return}; let Ok(message) = serialize(&(&uid, data)) else {return}; - let _ = node.send_remote_signal("new_popup", message); + let _ = node.send_remote_signal("new_child", message); } pub fn reposition_popup(&self, panel_item: &PanelItem, popup_state: &PopupData) { let Some(node) = panel_item.node() else {return}; + let Some(positioner_data) = popup_state.positioner_data() else {return}; let _ = node.send_remote_signal( - "reposition_popup", - serialize(popup_state.positioner_data().unwrap()).unwrap(), + "reposition_child", + serialize((positioner_data.get_pos(), positioner_data.size)).unwrap(), ); } pub fn drop_popup(&self, panel_item: &PanelItem, uid: &str) { @@ -805,7 +896,7 @@ impl XDGBackend { let Some(node) = panel_item.node() else {return}; let Ok(message) = serialize(uid) else {return}; - let _ = node.send_remote_signal("drop_popup", message); + let _ = node.send_remote_signal("drop_child", message); } fn popups_data(&self) -> Vec { diff --git a/src/wayland/xwayland.rs b/src/wayland/xwayland.rs index e4d6350..3437139 100644 --- a/src/wayland/xwayland.rs +++ b/src/wayland/xwayland.rs @@ -268,7 +268,7 @@ impl X11Backend { match id { SurfaceID::Cursor => None, SurfaceID::Toplevel => self.toplevel.wl_surface(), - SurfaceID::Popup(_) => None, + SurfaceID::Child(_) => None, } }