refactor(wayland): replace popups with child surfaces

This commit is contained in:
Nova
2023-08-06 18:32:43 -04:00
parent 74a2f7a249
commit ce8877b67e
3 changed files with 119 additions and 28 deletions

View File

@@ -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),
}
}
}

View File

@@ -82,14 +82,14 @@ impl Dispatch<XdgWmBase, (), WaylandState> for WaylandState {
}
}
#[derive(Debug, Serialize, Clone, Copy)]
#[derive(Debug, Clone, Copy)]
pub struct PositionerData {
size: Vector2<u32>,
anchor_rect_pos: Vector2<i32>,
anchor_rect_size: Vector2<u32>,
anchor: u32,
gravity: u32,
constraint_adjustment: u32,
anchor: Anchor,
gravity: Gravity,
constraint_adjustment: ConstraintAdjustment,
offset: Vector2<i32>,
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<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 {
fn request(
_state: &mut WaylandState,
@@ -152,13 +240,13 @@ impl Dispatch<XdgPositioner, Mutex<PositionerData>, 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<XdgPositioner, Mutex<PositionerData>, 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<XdgSurface, Mutex<XdgSurfaceData>, 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<XdgPopup, Mutex<PopupData>, 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<XDGBackend>, 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<XDGBackend>, 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<PopupData> {

View File

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