refactor(wayland): separate backend from panel item
This commit is contained in:
@@ -151,24 +151,195 @@ pub enum RecommendedState {
|
|||||||
Resize(u32),
|
Resize(u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct WaylandBackend {
|
||||||
|
toplevel: WlWeak<XdgToplevel>,
|
||||||
|
popups: Mutex<FxHashMap<String, WlWeak<XdgPopup>>>,
|
||||||
|
cursor: Mutex<Option<WlWeak<WlSurface>>>,
|
||||||
|
}
|
||||||
|
impl WaylandBackend {
|
||||||
|
pub fn create(toplevel: XdgToplevel) -> Self {
|
||||||
|
WaylandBackend {
|
||||||
|
toplevel: toplevel.downgrade(),
|
||||||
|
popups: Mutex::new(FxHashMap::default()),
|
||||||
|
cursor: Mutex::new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn toplevel(&self) -> XdgToplevel {
|
||||||
|
self.toplevel.upgrade().unwrap()
|
||||||
|
}
|
||||||
|
fn toplevel_xdg_surface(&self) -> XdgSurface {
|
||||||
|
let toplevel = self.toplevel();
|
||||||
|
let data = ToplevelData::get(&toplevel).lock();
|
||||||
|
data.xdg_surface()
|
||||||
|
}
|
||||||
|
fn toplevel_wl_surface(&self) -> WlSurface {
|
||||||
|
XdgSurfaceData::get(&self.toplevel_xdg_surface())
|
||||||
|
.lock()
|
||||||
|
.wl_surface()
|
||||||
|
}
|
||||||
|
fn wl_surface_from_id(&self, id: &SurfaceID) -> Option<WlSurface> {
|
||||||
|
match id {
|
||||||
|
SurfaceID::Cursor => self.cursor.lock().clone()?.upgrade().ok(),
|
||||||
|
SurfaceID::Toplevel => Some(self.toplevel_wl_surface()),
|
||||||
|
SurfaceID::Popup(popup) => {
|
||||||
|
let popups = self.popups.lock();
|
||||||
|
let popup = popups.get(popup)?.upgrade().ok()?;
|
||||||
|
let surf = PopupData::get(&popup).lock().wl_surface();
|
||||||
|
Some(surf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn input_surfaces(&self) -> Vec<WlSurface> {
|
||||||
|
let mut surfaces = vec![self.toplevel_wl_surface()];
|
||||||
|
surfaces.extend(self.popups.lock().values().filter_map(|p| {
|
||||||
|
let popup = p.upgrade().ok()?;
|
||||||
|
let popup_data = PopupData::get(&popup).lock();
|
||||||
|
let xdg_surface = popup_data.xdg_surface();
|
||||||
|
let xdg_surface_data = XdgSurfaceData::get(&xdg_surface).lock();
|
||||||
|
Some(xdg_surface_data.wl_surface())
|
||||||
|
}));
|
||||||
|
surfaces
|
||||||
|
}
|
||||||
|
|
||||||
|
fn configure_toplevel(
|
||||||
|
&self,
|
||||||
|
size: Option<Vector2<u32>>,
|
||||||
|
states: Vec<u32>,
|
||||||
|
bounds: Option<Vector2<u32>>,
|
||||||
|
) {
|
||||||
|
let Ok(xdg_toplevel) = self.toplevel.upgrade() else {return};
|
||||||
|
let xdg_surface = self.toplevel_xdg_surface();
|
||||||
|
debug!(?size, ?states, ?bounds, "Configure toplevel info");
|
||||||
|
if let Some(bounds) = bounds {
|
||||||
|
if xdg_toplevel.version() > EVT_CONFIGURE_BOUNDS_SINCE {
|
||||||
|
xdg_toplevel.configure_bounds(bounds.x as i32, bounds.y as i32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let size = size.unwrap_or(Vector2::from([0; 2]));
|
||||||
|
xdg_toplevel.configure(
|
||||||
|
size.x as i32,
|
||||||
|
size.y as i32,
|
||||||
|
states
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|state| state.to_ne_bytes())
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
);
|
||||||
|
xdg_surface.configure(SERIAL_COUNTER.inc());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_toplevel(&self) -> Result<Vec<u8>> {
|
||||||
|
let toplevel = self.toplevel();
|
||||||
|
let state = ToplevelData::get(&toplevel);
|
||||||
|
let data = serialize(&state.lock().clone())?;
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_toplevel_capabilities(&self, capabilities: Vec<u8>) {
|
||||||
|
self.toplevel().wm_capabilities(capabilities);
|
||||||
|
self.toplevel_xdg_surface().configure(SERIAL_COUNTER.inc());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_popup(&self, panel_item: &PanelItem, popup: &XdgPopup, data: &PopupData) {
|
||||||
|
let uid = data.uid.clone();
|
||||||
|
|
||||||
|
self.popups.lock().insert(uid.clone(), popup.downgrade());
|
||||||
|
|
||||||
|
let Some(node) = panel_item.node.upgrade() else { return };
|
||||||
|
let _ = node.send_remote_signal("new_popup", &serialize(&(&uid, data)).unwrap());
|
||||||
|
}
|
||||||
|
pub fn reposition_popup(&self, panel_item: &PanelItem, popup_state: &PopupData) {
|
||||||
|
let Some(node) = panel_item.node.upgrade() else { return };
|
||||||
|
|
||||||
|
let _ = node.send_remote_signal(
|
||||||
|
"reposition_popup",
|
||||||
|
&serialize(popup_state.positioner_data().unwrap()).unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
pub fn drop_popup(&self, panel_item: &PanelItem, uid: &str) {
|
||||||
|
if let Some(popup) = self
|
||||||
|
.popups
|
||||||
|
.lock()
|
||||||
|
.remove(uid)
|
||||||
|
.and_then(|popup| popup.upgrade().ok()?.data::<Arc<PopupData>>().cloned())
|
||||||
|
{
|
||||||
|
panel_item.seat_data.drop_surface(&popup.wl_surface());
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(node) = panel_item.node.upgrade() else { return };
|
||||||
|
let _ = node.send_remote_signal("drop_popup", &serialize(uid).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn popups_data(&self) -> Vec<PopupData> {
|
||||||
|
self.popups
|
||||||
|
.lock()
|
||||||
|
.values()
|
||||||
|
.filter_map(|v| Some(v.upgrade().ok()?.data::<Mutex<PopupData>>()?.lock().clone()))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
}
|
||||||
|
fn cursor_data(&self) -> Option<(Vector2<u32>, Vector2<i32>)> {
|
||||||
|
let cursor = self.cursor.lock().as_ref().and_then(|c| c.upgrade().ok());
|
||||||
|
let cursor_size = cursor
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|c| CoreSurface::from_wl_surface(&c))
|
||||||
|
.and_then(|c| c.size());
|
||||||
|
let cursor_hotspot = cursor
|
||||||
|
.and_then(|c| {
|
||||||
|
compositor::with_states(&c, |data| data.data_map.get::<Arc<Cursor>>().cloned())
|
||||||
|
})
|
||||||
|
.map(|cursor| cursor.hotspot);
|
||||||
|
|
||||||
|
cursor_size.zip(cursor_hotspot)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_cursor(
|
||||||
|
&self,
|
||||||
|
panel_item: &PanelItem,
|
||||||
|
surface: Option<&WlSurface>,
|
||||||
|
hotspot_x: i32,
|
||||||
|
hotspot_y: i32,
|
||||||
|
) {
|
||||||
|
let Some(node) = panel_item.node.upgrade() else { return };
|
||||||
|
debug!(?surface, hotspot_x, hotspot_y, "Set cursor size");
|
||||||
|
let mut data = serialize(()).unwrap();
|
||||||
|
|
||||||
|
let cursor_size = surface
|
||||||
|
.and_then(|c| CoreSurface::from_wl_surface(c))
|
||||||
|
.and_then(|c| c.size());
|
||||||
|
|
||||||
|
if let Some(size) = cursor_size {
|
||||||
|
data = serialize((size, (hotspot_x, hotspot_y))).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = node.send_remote_signal("set_cursor", &data);
|
||||||
|
*self.cursor.lock() = surface.map(|surf| surf.downgrade());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct X11Backend;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Backend {
|
||||||
|
Wayland(WaylandBackend),
|
||||||
|
X11(X11Backend),
|
||||||
|
}
|
||||||
|
|
||||||
pub struct PanelItem {
|
pub struct PanelItem {
|
||||||
pub uid: String,
|
pub uid: String,
|
||||||
node: Weak<Node>,
|
node: Weak<Node>,
|
||||||
cursor: Mutex<Option<WlWeak<WlSurface>>>,
|
|
||||||
pub seat_data: Arc<SeatData>,
|
pub seat_data: Arc<SeatData>,
|
||||||
toplevel: WlWeak<XdgToplevel>,
|
pub backend: Backend,
|
||||||
popups: Mutex<FxHashMap<String, WlWeak<XdgPopup>>>,
|
|
||||||
pointer_grab: Mutex<Option<SurfaceID>>,
|
pointer_grab: Mutex<Option<SurfaceID>>,
|
||||||
keyboard_grab: Mutex<Option<SurfaceID>>,
|
keyboard_grab: Mutex<Option<SurfaceID>>,
|
||||||
}
|
}
|
||||||
impl PanelItem {
|
impl PanelItem {
|
||||||
pub fn create(
|
pub fn create(
|
||||||
toplevel: XdgToplevel,
|
|
||||||
wl_surface: WlSurface,
|
wl_surface: WlSurface,
|
||||||
|
backend: Backend,
|
||||||
client_credentials: Option<Credentials>,
|
client_credentials: Option<Credentials>,
|
||||||
seat_data: Arc<SeatData>,
|
seat_data: Arc<SeatData>,
|
||||||
) -> (Arc<Node>, Arc<PanelItem>) {
|
) -> (Arc<Node>, Arc<PanelItem>) {
|
||||||
debug!(?toplevel, ?client_credentials, "Create panel item");
|
debug!(?backend, ?client_credentials, "Create panel item");
|
||||||
|
|
||||||
let startup_settings = client_credentials
|
let startup_settings = client_credentials
|
||||||
.and_then(|cred| get_env(cred.pid).ok())
|
.and_then(|cred| get_env(cred.pid).ok())
|
||||||
@@ -185,10 +356,8 @@ impl PanelItem {
|
|||||||
let panel_item = Arc::new(PanelItem {
|
let panel_item = Arc::new(PanelItem {
|
||||||
uid: uid.clone(),
|
uid: uid.clone(),
|
||||||
node: Arc::downgrade(&node),
|
node: Arc::downgrade(&node),
|
||||||
cursor: Mutex::new(None),
|
|
||||||
seat_data,
|
seat_data,
|
||||||
toplevel: toplevel.downgrade(),
|
backend,
|
||||||
popups: Mutex::new(FxHashMap::default()),
|
|
||||||
pointer_grab: Mutex::new(None),
|
pointer_grab: Mutex::new(None),
|
||||||
keyboard_grab: Mutex::new(None),
|
keyboard_grab: Mutex::new(None),
|
||||||
});
|
});
|
||||||
@@ -250,18 +419,11 @@ impl PanelItem {
|
|||||||
Some(panel_item.clone())
|
Some(panel_item.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toplevel(&self) -> XdgToplevel {
|
|
||||||
self.toplevel.upgrade().unwrap()
|
|
||||||
}
|
|
||||||
fn toplevel_xdg_surface(&self) -> XdgSurface {
|
|
||||||
let toplevel = self.toplevel();
|
|
||||||
let data = ToplevelData::get(&toplevel).lock();
|
|
||||||
data.xdg_surface()
|
|
||||||
}
|
|
||||||
fn toplevel_wl_surface(&self) -> WlSurface {
|
fn toplevel_wl_surface(&self) -> WlSurface {
|
||||||
XdgSurfaceData::get(&self.toplevel_xdg_surface())
|
match &self.backend {
|
||||||
.lock()
|
Backend::Wayland(w) => w.toplevel_wl_surface(),
|
||||||
.wl_surface()
|
Backend::X11(_) => todo!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn core_surface(&self) -> Option<Arc<CoreSurface>> {
|
fn core_surface(&self) -> Option<Arc<CoreSurface>> {
|
||||||
compositor::with_states(&self.toplevel_wl_surface(), |data| {
|
compositor::with_states(&self.toplevel_wl_surface(), |data| {
|
||||||
@@ -274,15 +436,9 @@ impl PanelItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn wl_surface_from_id(&self, id: &SurfaceID) -> Option<WlSurface> {
|
fn wl_surface_from_id(&self, id: &SurfaceID) -> Option<WlSurface> {
|
||||||
match id {
|
match &self.backend {
|
||||||
SurfaceID::Cursor => self.cursor.lock().clone()?.upgrade().ok(),
|
Backend::Wayland(w) => w.wl_surface_from_id(id),
|
||||||
SurfaceID::Toplevel => Some(self.toplevel_wl_surface()),
|
Backend::X11(_) => todo!(),
|
||||||
SurfaceID::Popup(popup) => {
|
|
||||||
let popups = self.popups.lock();
|
|
||||||
let popup = popups.get(popup)?.upgrade().ok()?;
|
|
||||||
let surf = PopupData::get(&popup).lock().wl_surface();
|
|
||||||
Some(surf)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn wl_surface_from_id_result(&self, id: &SurfaceID) -> Result<WlSurface> {
|
fn wl_surface_from_id_result(&self, id: &SurfaceID) -> Result<WlSurface> {
|
||||||
@@ -416,19 +572,15 @@ impl PanelItem {
|
|||||||
}
|
}
|
||||||
fn keyboard_set_keymap_flex(node: &Node, keymap: &Keymap) -> Result<()> {
|
fn keyboard_set_keymap_flex(node: &Node, keymap: &Keymap) -> Result<()> {
|
||||||
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
|
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
|
||||||
let toplevel = panel_item.toplevel_wl_surface();
|
debug!("Keyboard set keymap");
|
||||||
debug!(?toplevel, "Keyboard set keymap");
|
|
||||||
|
|
||||||
let mut surfaces = vec![toplevel];
|
panel_item.seat_data.set_keymap(
|
||||||
surfaces.extend(panel_item.popups.lock().values().filter_map(|p| {
|
keymap,
|
||||||
let popup = p.upgrade().ok()?;
|
match &panel_item.backend {
|
||||||
let popup_data = PopupData::get(&popup).lock();
|
Backend::Wayland(w) => w.input_surfaces(),
|
||||||
let xdg_surface = popup_data.xdg_surface();
|
Backend::X11(_) => todo!(),
|
||||||
let xdg_surface_data = XdgSurfaceData::get(&xdg_surface).lock();
|
},
|
||||||
Some(xdg_surface_data.wl_surface())
|
);
|
||||||
}));
|
|
||||||
|
|
||||||
panel_item.seat_data.set_keymap(keymap, surfaces);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -453,8 +605,6 @@ impl PanelItem {
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
|
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
|
||||||
let Some(core_surface) = panel_item.core_surface() else { return Ok(()) };
|
let Some(core_surface) = panel_item.core_surface() else { return Ok(()) };
|
||||||
let Ok(xdg_toplevel) = panel_item.toplevel.upgrade() else { return Ok(()) };
|
|
||||||
let xdg_surface = panel_item.toplevel_xdg_surface();
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct ConfigureToplevelInfo {
|
struct ConfigureToplevelInfo {
|
||||||
@@ -462,13 +612,11 @@ impl PanelItem {
|
|||||||
states: Vec<u32>,
|
states: Vec<u32>,
|
||||||
bounds: Option<Vector2<u32>>,
|
bounds: Option<Vector2<u32>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
let info: ConfigureToplevelInfo = deserialize(data)?;
|
let info: ConfigureToplevelInfo = deserialize(data)?;
|
||||||
debug!(info = ?&info, "Configure toplevel info");
|
|
||||||
if let Some(bounds) = info.bounds {
|
match &panel_item.backend {
|
||||||
if xdg_toplevel.version() > EVT_CONFIGURE_BOUNDS_SINCE {
|
Backend::Wayland(w) => w.configure_toplevel(info.size, info.states, info.bounds),
|
||||||
xdg_toplevel.configure_bounds(bounds.x as i32, bounds.y as i32);
|
Backend::X11(_) => todo!(),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let zero_size = Vector2::from([0; 2]);
|
let zero_size = Vector2::from([0; 2]);
|
||||||
let size = info.size.unwrap_or(zero_size);
|
let size = info.size.unwrap_or(zero_size);
|
||||||
@@ -500,38 +648,31 @@ impl PanelItem {
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
|
let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) };
|
||||||
let Some(core_surface) = panel_item.core_surface() else { return Ok(()) };
|
let Some(core_surface) = panel_item.core_surface() else { return Ok(()) };
|
||||||
let Ok(xdg_toplevel) = panel_item.toplevel.upgrade() else { return Ok(()) };
|
if let Backend::Wayland(w) = &panel_item.backend {
|
||||||
if xdg_toplevel.version() < EVT_WM_CAPABILITIES_SINCE {
|
if w.toplevel().version() < EVT_WM_CAPABILITIES_SINCE {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let xdg_surface = panel_item.toplevel_xdg_surface();
|
}
|
||||||
|
|
||||||
let capabilities: Vec<u8> = deserialize(data)?;
|
let capabilities: Vec<u8> = deserialize(data)?;
|
||||||
debug!("Set toplevel capabilities");
|
debug!("Set toplevel capabilities");
|
||||||
xdg_toplevel.wm_capabilities(capabilities);
|
match &panel_item.backend {
|
||||||
xdg_surface.configure(SERIAL_COUNTER.inc());
|
Backend::Wayland(w) => w.set_toplevel_capabilities(capabilities),
|
||||||
|
Backend::X11(_) => todo!(),
|
||||||
|
}
|
||||||
core_surface.flush_clients();
|
core_surface.flush_clients();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn commit_toplevel(&self) {
|
pub fn commit_toplevel(&self) {
|
||||||
// let mapped_size = self.core_surface().and_then(|c| c.size());
|
debug!("Commit toplevel");
|
||||||
let toplevel = self.toplevel();
|
|
||||||
let state = ToplevelData::get(&toplevel);
|
|
||||||
let state = state.lock();
|
|
||||||
// let mut queued_state = state.queued_state.take().unwrap();
|
|
||||||
// queued_state.mapped = mapped_size.is_some();
|
|
||||||
// if let Some(size) = mapped_size {
|
|
||||||
// queued_state.size = size;
|
|
||||||
// queued_state.geometry.update_to_surface_size(size);
|
|
||||||
// }
|
|
||||||
// *state = (*queued_state).clone();
|
|
||||||
// state.queued_state = Some(queued_state);
|
|
||||||
|
|
||||||
debug!(state = ?&*state, "Commit toplevel");
|
|
||||||
let Some(node) = self.node.upgrade() else { return };
|
let Some(node) = self.node.upgrade() else { return };
|
||||||
let _ = node.send_remote_signal("commit_toplevel", &serialize(&*state).unwrap());
|
let Ok(data) = (match &self.backend {
|
||||||
|
Backend::Wayland(w) => w.serialize_toplevel(),
|
||||||
|
Backend::X11(_) => todo!(),
|
||||||
|
}) else {return};
|
||||||
|
let _ = node.send_remote_signal("commit_toplevel", &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recommend_toplevel_state(&self, state: RecommendedState) {
|
pub fn recommend_toplevel_state(&self, state: RecommendedState) {
|
||||||
@@ -542,72 +683,11 @@ impl PanelItem {
|
|||||||
let _ = node.send_remote_signal("recommend_toplevel_state", &data);
|
let _ = node.send_remote_signal("recommend_toplevel_state", &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_popup(&self, popup: &XdgPopup, data: &PopupData) {
|
|
||||||
let uid = data.uid.clone();
|
|
||||||
|
|
||||||
self.popups.lock().insert(uid.clone(), popup.downgrade());
|
|
||||||
|
|
||||||
let Some(node) = self.node.upgrade() else { return };
|
|
||||||
let _ = node.send_remote_signal("new_popup", &serialize(&(&uid, data)).unwrap());
|
|
||||||
}
|
|
||||||
// pub fn commit_popup(&self, data: &PopupData) {
|
|
||||||
// let xdg_surf = data.xdg_surface.upgrade().unwrap();
|
|
||||||
// let surf = xdg_surf
|
|
||||||
// .data::<XdgSurfaceData>()
|
|
||||||
// .unwrap()
|
|
||||||
// .wl_surface
|
|
||||||
// .upgrade()
|
|
||||||
// .unwrap();
|
|
||||||
|
|
||||||
// let core_surface =
|
|
||||||
// compositor::with_states(&surf, |s| s.data_map.get::<Arc<CoreSurface>>().cloned())
|
|
||||||
// .unwrap();
|
|
||||||
// let mut popup_state = data.state.lock();
|
|
||||||
// popup_state.mapped = core_surface.size().is_some();
|
|
||||||
// }
|
|
||||||
pub fn reposition_popup(&self, popup_state: &PopupData) {
|
|
||||||
let Some(node) = self.node.upgrade() else { return };
|
|
||||||
|
|
||||||
let _ = node.send_remote_signal(
|
|
||||||
"reposition_popup",
|
|
||||||
&serialize(popup_state.positioner_data().unwrap()).unwrap(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
pub fn drop_popup(&self, uid: &str) {
|
|
||||||
if let Some(popup) = self
|
|
||||||
.popups
|
|
||||||
.lock()
|
|
||||||
.remove(uid)
|
|
||||||
.and_then(|popup| popup.upgrade().ok()?.data::<Arc<PopupData>>().cloned())
|
|
||||||
{
|
|
||||||
self.seat_data.drop_surface(&popup.wl_surface());
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some(node) = self.node.upgrade() else { return };
|
|
||||||
let _ = node.send_remote_signal("drop_popup", &serialize(uid).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn grab_keyboard(&self, sid: Option<SurfaceID>) {
|
pub fn grab_keyboard(&self, sid: Option<SurfaceID>) {
|
||||||
let Some(node) = self.node.upgrade() else { return };
|
let Some(node) = self.node.upgrade() else { return };
|
||||||
|
|
||||||
let _ = node.send_remote_signal("grab_keyboard", &serialize(sid).unwrap());
|
let _ = node.send_remote_signal("grab_keyboard", &serialize(sid).unwrap());
|
||||||
}
|
}
|
||||||
pub fn set_cursor(&self, surface: Option<&WlSurface>, hotspot_x: i32, hotspot_y: i32) {
|
|
||||||
let Some(node) = self.node.upgrade() else { return };
|
|
||||||
debug!(?surface, hotspot_x, hotspot_y, "Set cursor size");
|
|
||||||
let mut data = serialize(()).unwrap();
|
|
||||||
|
|
||||||
let cursor_size = surface
|
|
||||||
.and_then(|c| CoreSurface::from_wl_surface(c))
|
|
||||||
.and_then(|c| c.size());
|
|
||||||
|
|
||||||
if let Some(size) = cursor_size {
|
|
||||||
data = serialize((size, (hotspot_x, hotspot_y))).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
let _ = node.send_remote_signal("set_cursor", &data);
|
|
||||||
*self.cursor.lock() = surface.map(|surf| surf.downgrade());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn on_drop(&self) {
|
pub fn on_drop(&self) {
|
||||||
let toplevel = self.toplevel_wl_surface();
|
let toplevel = self.toplevel_wl_surface();
|
||||||
@@ -618,43 +698,30 @@ impl PanelItem {
|
|||||||
}
|
}
|
||||||
impl ItemSpecialization for PanelItem {
|
impl ItemSpecialization for PanelItem {
|
||||||
fn serialize_start_data(&self, id: &str) -> Vec<u8> {
|
fn serialize_start_data(&self, id: &str) -> Vec<u8> {
|
||||||
let cursor = self.cursor.lock().as_ref().and_then(|c| c.upgrade().ok());
|
match &self.backend {
|
||||||
let cursor_size = cursor
|
Backend::Wayland(w) => {
|
||||||
.as_ref()
|
let toplevel = w.toplevel();
|
||||||
.and_then(|c| CoreSurface::from_wl_surface(&c))
|
|
||||||
.and_then(|c| c.size());
|
|
||||||
let cursor_hotspot = cursor
|
|
||||||
.and_then(|c| {
|
|
||||||
compositor::with_states(&c, |data| data.data_map.get::<Arc<Cursor>>().cloned())
|
|
||||||
})
|
|
||||||
.map(|cursor| cursor.hotspot);
|
|
||||||
|
|
||||||
let toplevel = self.toplevel();
|
|
||||||
let toplevel_state = ToplevelData::get(&toplevel);
|
let toplevel_state = ToplevelData::get(&toplevel);
|
||||||
let toplevel_state = toplevel_state.lock().clone();
|
let toplevel_state = toplevel_state.lock().clone();
|
||||||
|
|
||||||
let popups = self
|
|
||||||
.popups
|
|
||||||
.lock()
|
|
||||||
.values()
|
|
||||||
.filter_map(|v| Some(v.upgrade().ok()?.data::<Mutex<PopupData>>()?.lock().clone()))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let pointer_grab = self.pointer_grab.lock().clone();
|
let pointer_grab = self.pointer_grab.lock().clone();
|
||||||
let keyboard_grab = self.keyboard_grab.lock().clone();
|
let keyboard_grab = self.keyboard_grab.lock().clone();
|
||||||
|
|
||||||
serialize((
|
serialize((
|
||||||
id,
|
id,
|
||||||
(
|
(
|
||||||
cursor_size.zip(cursor_hotspot),
|
w.cursor_data(),
|
||||||
toplevel_state,
|
toplevel_state,
|
||||||
popups,
|
w.popups_data(),
|
||||||
pointer_grab,
|
pointer_grab,
|
||||||
keyboard_grab,
|
keyboard_grab,
|
||||||
),
|
),
|
||||||
))
|
))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
Backend::X11(_) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl Drop for PanelItem {
|
impl Drop for PanelItem {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
use super::{
|
use super::{
|
||||||
panel_item::PanelItem, state::WaylandState, surface::CoreSurface, GLOBAL_DESTROY_QUEUE,
|
panel_item::{Backend, PanelItem},
|
||||||
SERIAL_COUNTER,
|
state::WaylandState,
|
||||||
|
surface::CoreSurface,
|
||||||
|
GLOBAL_DESTROY_QUEUE, SERIAL_COUNTER,
|
||||||
};
|
};
|
||||||
use crate::core::task;
|
use crate::core::task;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
@@ -482,7 +484,9 @@ impl Dispatch<WlPointer, Arc<SeatData>, WaylandState> for WaylandState {
|
|||||||
let surfaces = seat_data.surfaces.lock();
|
let surfaces = seat_data.surfaces.lock();
|
||||||
let Some(surface_info) = surfaces.get(&focus) else {return};
|
let Some(surface_info) = surfaces.get(&focus) else {return};
|
||||||
let Some(panel_item) = surface_info.panel_item.upgrade() else {return};
|
let Some(panel_item) = surface_info.panel_item.upgrade() else {return};
|
||||||
panel_item.set_cursor(surface.as_ref(), hotspot_x, hotspot_y);
|
if let Backend::Wayland(w) = &panel_item.backend {
|
||||||
|
w.set_cursor(&panel_item, surface.as_ref(), hotspot_x, hotspot_y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
wl_pointer::Request::Release => (),
|
wl_pointer::Request::Release => (),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use crate::nodes::Node;
|
use crate::{
|
||||||
|
nodes::Node,
|
||||||
|
wayland::panel_item::{Backend, WaylandBackend},
|
||||||
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
panel_item::{PanelItem, RecommendedState, SurfaceID},
|
panel_item::{PanelItem, RecommendedState, SurfaceID},
|
||||||
@@ -285,9 +288,10 @@ impl Dispatch<XdgSurface, Mutex<XdgSurfaceData>, WaylandState> for WaylandState
|
|||||||
let wl_surface = xdg_surface_data.lock().wl_surface();
|
let wl_surface = xdg_surface_data.lock().wl_surface();
|
||||||
|
|
||||||
xdg_surface_data.lock().surface_id = SurfaceID::Toplevel;
|
xdg_surface_data.lock().surface_id = SurfaceID::Toplevel;
|
||||||
|
let toplevel = toplevel_weak.upgrade().unwrap();
|
||||||
let (node, panel_item) = PanelItem::create(
|
let (node, panel_item) = PanelItem::create(
|
||||||
toplevel.clone(),
|
|
||||||
wl_surface.clone(),
|
wl_surface.clone(),
|
||||||
|
Backend::Wayland(WaylandBackend::create(toplevel)),
|
||||||
client_credentials,
|
client_credentials,
|
||||||
seat_data.clone(),
|
seat_data.clone(),
|
||||||
);
|
);
|
||||||
@@ -669,8 +673,10 @@ impl Dispatch<XdgPopup, Mutex<PopupData>, WaylandState> for WaylandState {
|
|||||||
debug!(?xdg_popup, ?positioner, token, "XDG popup reposition");
|
debug!(?xdg_popup, ?positioner, token, "XDG popup reposition");
|
||||||
data.positioner = positioner;
|
data.positioner = positioner;
|
||||||
let Some(panel_item) = data.panel_item() else {return};
|
let Some(panel_item) = data.panel_item() else {return};
|
||||||
panel_item.reposition_popup(&*data);
|
|
||||||
// xdg_popup.popup_done(); // temporary hack to avoid apps locking up before popups are implemented
|
if let Backend::Wayland(w) = &panel_item.backend {
|
||||||
|
w.reposition_popup(&panel_item, &*data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
xdg_popup::Request::Destroy => {
|
xdg_popup::Request::Destroy => {
|
||||||
let data = data.lock();
|
let data = data.lock();
|
||||||
@@ -692,6 +698,9 @@ impl Dispatch<XdgPopup, Mutex<PopupData>, WaylandState> for WaylandState {
|
|||||||
) {
|
) {
|
||||||
let data = data.lock();
|
let data = data.lock();
|
||||||
let Some(panel_item) = data.panel_item() else {return};
|
let Some(panel_item) = data.panel_item() else {return};
|
||||||
panel_item.drop_popup(&data.uid);
|
|
||||||
|
if let Backend::Wayland(w) = &panel_item.backend {
|
||||||
|
w.drop_popup(&panel_item, &data.uid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user