refactor(wayland): replace popups with child surfaces

This commit is contained in:
Nova
2023-08-06 18:32:43 -04:00
parent 2c979c84c4
commit 8c2c1b0c14
3 changed files with 119 additions and 28 deletions

View File

@@ -44,9 +44,9 @@ lazy_static! {
"commit_toplevel", "commit_toplevel",
"recommend_toplevel_state", "recommend_toplevel_state",
"set_cursor", "set_cursor",
"new_popup", "new_child",
"reposition_popup", "reposition_child",
"drop_popup", "drop_child",
], ],
ui: Default::default(), ui: Default::default(),
items: Registry::new(), items: Registry::new(),
@@ -60,7 +60,7 @@ lazy_static! {
pub enum SurfaceID { pub enum SurfaceID {
Cursor, Cursor,
Toplevel, Toplevel,
Popup(String), Child(String),
} }
impl Default for SurfaceID { impl Default for SurfaceID {
fn default() -> Self { fn default() -> Self {
@@ -94,15 +94,15 @@ impl<'de> Visitor<'de> for SurfaceIDVisitor {
match discrim { match discrim {
"Cursor" => Ok(SurfaceID::Cursor), "Cursor" => Ok(SurfaceID::Cursor),
"Toplevel" => Ok(SurfaceID::Toplevel), "Toplevel" => Ok(SurfaceID::Toplevel),
"Popup" => { "Child" => {
let Some(text) = seq.next_element()? else { 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( _ => Err(A::Error::unknown_variant(
discrim, discrim,
&["Cursor", "Toplevel", "Popup"], &["Cursor", "Toplevel", "Child"],
)), )),
} }
} }
@@ -113,7 +113,7 @@ impl serde::Serialize for SurfaceID {
match self { match self {
Self::Cursor => ["Cursor"].serialize(serializer), Self::Cursor => ["Cursor"].serialize(serializer),
Self::Toplevel => ["Toplevel"].serialize(serializer), Self::Toplevel => ["Toplevel"].serialize(serializer),
Self::Popup(text) => ["Popup", text].serialize(serializer), Self::Child(text) => ["Child", text].serialize(serializer),
} }
} }
} }

View File

@@ -82,14 +82,14 @@ impl Dispatch<XdgWmBase, (), WaylandState> for WaylandState {
} }
} }
#[derive(Debug, Serialize, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct PositionerData { pub struct PositionerData {
size: Vector2<u32>, size: Vector2<u32>,
anchor_rect_pos: Vector2<i32>, anchor_rect_pos: Vector2<i32>,
anchor_rect_size: Vector2<u32>, anchor_rect_size: Vector2<u32>,
anchor: u32, anchor: Anchor,
gravity: u32, gravity: Gravity,
constraint_adjustment: u32, constraint_adjustment: ConstraintAdjustment,
offset: Vector2<i32>, offset: Vector2<i32>,
reactive: bool, reactive: bool,
} }
@@ -99,15 +99,103 @@ impl Default for PositionerData {
size: Vector2::from([0; 2]), size: Vector2::from([0; 2]),
anchor_rect_pos: Vector2::from([0; 2]), anchor_rect_pos: Vector2::from([0; 2]),
anchor_rect_size: Vector2::from([0; 2]), anchor_rect_size: Vector2::from([0; 2]),
anchor: Anchor::None as u32, anchor: Anchor::None,
gravity: Gravity::None as u32, gravity: Gravity::None,
constraint_adjustment: ConstraintAdjustment::None.bits(), constraint_adjustment: ConstraintAdjustment::None,
offset: Vector2::from([0; 2]), offset: Vector2::from([0; 2]),
reactive: false, 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<i32> {
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<XdgPositioner, Mutex<PositionerData>, WaylandState> for WaylandState { impl Dispatch<XdgPositioner, Mutex<PositionerData>, WaylandState> for WaylandState {
fn request( fn request(
_state: &mut WaylandState, _state: &mut WaylandState,
@@ -152,13 +240,13 @@ impl Dispatch<XdgPositioner, Mutex<PositionerData>, WaylandState> for WaylandSta
xdg_positioner::Request::SetAnchor { anchor } => { xdg_positioner::Request::SetAnchor { anchor } => {
if let WEnum::Value(anchor) = anchor { if let WEnum::Value(anchor) = anchor {
debug!(?positioner, ?anchor, "Set positioner anchor"); debug!(?positioner, ?anchor, "Set positioner anchor");
data.lock().anchor = anchor as u32; data.lock().anchor = anchor;
} }
} }
xdg_positioner::Request::SetGravity { gravity } => { xdg_positioner::Request::SetGravity { gravity } => {
if let WEnum::Value(gravity) = gravity { if let WEnum::Value(gravity) = gravity {
debug!(?positioner, ?gravity, "Set positioner gravity"); debug!(?positioner, ?gravity, "Set positioner gravity");
data.lock().gravity = gravity as u32; data.lock().gravity = gravity;
} }
} }
xdg_positioner::Request::SetConstraintAdjustment { xdg_positioner::Request::SetConstraintAdjustment {
@@ -168,7 +256,8 @@ impl Dispatch<XdgPositioner, Mutex<PositionerData>, WaylandState> for WaylandSta
?positioner, ?positioner,
constraint_adjustment, "Set positioner constraint adjustment" 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 } => { xdg_positioner::Request::SetOffset { x, y } => {
debug!(?positioner, x, y, "Set positioner offset"); debug!(?positioner, x, y, "Set positioner offset");
@@ -353,7 +442,7 @@ impl Dispatch<XdgSurface, Mutex<XdgSurfaceData>, WaylandState> for WaylandState
positioner, positioner,
)); ));
let xdg_popup = data_init.init(id, popup_data); 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(); let panel_item = parent_data.panel_item().unwrap();
xdg_surface_data.lock().panel_item = Arc::downgrade(&panel_item); xdg_surface_data.lock().panel_item = Arc::downgrade(&panel_item);
debug!(?xdg_popup, ?xdg_surface, "Create XDG popup"); debug!(?xdg_popup, ?xdg_surface, "Create XDG popup");
@@ -640,7 +729,8 @@ impl Serialize for PopupData {
let mut seq = serializer.serialize_seq(None)?; let mut seq = serializer.serialize_seq(None)?;
seq.serialize_element(&self.uid)?; seq.serialize_element(&self.uid)?;
seq.serialize_element(&self.parent_id)?; 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() seq.end()
} }
} }
@@ -669,7 +759,7 @@ impl Dispatch<XdgPopup, Mutex<PopupData>, WaylandState> for WaylandState {
data.grabbed = true; data.grabbed = true;
debug!(?xdg_popup, ?seat, serial, "XDG popup grab"); debug!(?xdg_popup, ?seat, serial, "XDG popup grab");
let Some(panel_item) = data.panel_item() else {return}; 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 } => { xdg_popup::Request::Reposition { positioner, token } => {
let mut data = data.lock(); let mut data = data.lock();
@@ -735,7 +825,7 @@ impl XDGBackend {
match id { match id {
SurfaceID::Cursor => self.cursor.borrow().as_ref()?.surface.upgrade().ok(), SurfaceID::Cursor => self.cursor.borrow().as_ref()?.surface.upgrade().ok(),
SurfaceID::Toplevel => self.toplevel_wl_surface(), SurfaceID::Toplevel => self.toplevel_wl_surface(),
SurfaceID::Popup(popup) => { SurfaceID::Child(popup) => {
let popups = self.popups.lock(); let popups = self.popups.lock();
let popup = popups.get(popup)?.upgrade().ok()?; let popup = popups.get(popup)?.upgrade().ok()?;
let wl_surface = PopupData::get(&popup)?.lock().wl_surface(); let wl_surface = PopupData::get(&popup)?.lock().wl_surface();
@@ -781,14 +871,15 @@ impl XDGBackend {
let Some(node) = panel_item.node() else {return}; let Some(node) = panel_item.node() else {return};
let Ok(message) = serialize(&(&uid, data)) 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<XDGBackend>, popup_state: &PopupData) { pub fn reposition_popup(&self, panel_item: &PanelItem<XDGBackend>, popup_state: &PopupData) {
let Some(node) = panel_item.node() else {return}; let Some(node) = panel_item.node() else {return};
let Some(positioner_data) = popup_state.positioner_data() else {return};
let _ = node.send_remote_signal( let _ = node.send_remote_signal(
"reposition_popup", "reposition_child",
serialize(popup_state.positioner_data().unwrap()).unwrap(), serialize((positioner_data.get_pos(), positioner_data.size)).unwrap(),
); );
} }
pub fn drop_popup(&self, panel_item: &PanelItem<XDGBackend>, uid: &str) { pub fn drop_popup(&self, panel_item: &PanelItem<XDGBackend>, uid: &str) {
@@ -805,7 +896,7 @@ impl XDGBackend {
let Some(node) = panel_item.node() else {return}; let Some(node) = panel_item.node() else {return};
let Ok(message) = serialize(uid) 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<PopupData> { fn popups_data(&self) -> Vec<PopupData> {

View File

@@ -268,7 +268,7 @@ impl X11Backend {
match id { match id {
SurfaceID::Cursor => None, SurfaceID::Cursor => None,
SurfaceID::Toplevel => self.toplevel.wl_surface(), SurfaceID::Toplevel => self.toplevel.wl_surface(),
SurfaceID::Popup(_) => None, SurfaceID::Child(_) => None,
} }
} }