refactor(wayland): replace popups with child surfaces
This commit is contained in:
@@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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> {
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user