refactor(wayland): put everything in wl_surface user data
This commit is contained in:
58
Cargo.lock
generated
58
Cargo.lock
generated
@@ -602,9 +602,9 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
||||
|
||||
[[package]]
|
||||
name = "drm"
|
||||
version = "0.11.0"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e58eefd79f5173683872c0c82d0f05c2dc3c583d631259f60bb7a323756b7ff2"
|
||||
checksum = "a0f8a69e60d75ae7dab4ef26a59ca99f2a89d4c142089b537775ae0c198bdcde"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"bytemuck",
|
||||
@@ -615,9 +615,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "drm-ffi"
|
||||
version = "0.7.0"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "220dd8c12ebf2b0cbaffa19e00de02f5f090d363fb900f16ea012c077eea1174"
|
||||
checksum = "41334f8405792483e32ad05fbb9c5680ff4e84491883d2947a4757dc54cb2ac6"
|
||||
dependencies = [
|
||||
"drm-sys",
|
||||
"rustix",
|
||||
@@ -631,9 +631,9 @@ checksum = "0aafbcdb8afc29c1a7ee5fbe53b5d62f4565b35a042a662ca9fecd0b54dae6f4"
|
||||
|
||||
[[package]]
|
||||
name = "drm-sys"
|
||||
version = "0.6.0"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5115283ec60c99da8a9e5dc3c55f27680211e974c948cb6f3b51f0373190503b"
|
||||
checksum = "2d09ff881f92f118b11105ba5e34ff8f4adf27b30dae8f12e28c193af1c83176"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"linux-raw-sys 0.6.1",
|
||||
@@ -819,12 +819,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gethostname"
|
||||
version = "0.3.0"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb65d4ba3173c56a500b555b532f72c42e8d1fe64962b518897f8959fae2c177"
|
||||
checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1737,9 +1737,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.30.0"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956"
|
||||
checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -2016,7 +2016,7 @@ checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
|
||||
[[package]]
|
||||
name = "smithay"
|
||||
version = "0.3.0"
|
||||
source = "git+https://github.com/smithay/smithay.git#5c688b89fc97ade8c60c45d4a319311b7ec5292f"
|
||||
source = "git+https://github.com/smithay/smithay.git#91e61f13501f21d66803efac947bfafed43080c5"
|
||||
dependencies = [
|
||||
"appendlist",
|
||||
"bitflags 2.4.0",
|
||||
@@ -2575,13 +2575,13 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wayland-backend"
|
||||
version = "0.3.2"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19152ddd73f45f024ed4534d9ca2594e0ef252c1847695255dae47f34df9fbe4"
|
||||
checksum = "9d50fa61ce90d76474c87f5fc002828d81b32677340112b4ef08079a9d459a40"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"downcast-rs",
|
||||
"nix 0.26.4",
|
||||
"rustix",
|
||||
"scoped-tls",
|
||||
"smallvec",
|
||||
"wayland-sys",
|
||||
@@ -2627,9 +2627,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wayland-scanner"
|
||||
version = "0.31.0"
|
||||
version = "0.31.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb8e28403665c9f9513202b7e1ed71ec56fde5c107816843fb14057910b2c09c"
|
||||
checksum = "63b3a62929287001986fb58c789dce9b67604a397c15c611ad9f747300b6c283"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quick-xml",
|
||||
@@ -2689,15 +2689,6 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-wsapoll"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
@@ -2790,25 +2781,20 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "x11rb"
|
||||
version = "0.12.0"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1641b26d4dec61337c35a1b1aaf9e3cba8f46f0b43636c609ab0291a648040a"
|
||||
checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a"
|
||||
dependencies = [
|
||||
"gethostname",
|
||||
"nix 0.26.4",
|
||||
"winapi",
|
||||
"winapi-wsapoll",
|
||||
"rustix",
|
||||
"x11rb-protocol",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "x11rb-protocol"
|
||||
version = "0.12.0"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82d6c3f9a0fb6701fab8f6cea9b0c0bd5d6876f1f89f7fada07e558077c344bc"
|
||||
dependencies = [
|
||||
"nix 0.26.4",
|
||||
]
|
||||
checksum = "e63e71c4b8bd9ffec2c963173a4dc4cbde9ee96961d4fcb4429db9929b606c34"
|
||||
|
||||
[[package]]
|
||||
name = "xkbcommon"
|
||||
|
||||
@@ -68,8 +68,8 @@ ctrlc = "3.4.1"
|
||||
libc = "0.2.148"
|
||||
input-event-codes = "5.16.8"
|
||||
nix = "0.27.1"
|
||||
wayland-scanner = "0.31.0"
|
||||
wayland-backend = "0.3.2"
|
||||
wayland-scanner = "0.31.1"
|
||||
wayland-backend = "0.3.3"
|
||||
cluFlock = "1.2.7"
|
||||
fxtypemap = "0.2.0"
|
||||
|
||||
|
||||
@@ -349,8 +349,8 @@ fn adaptive_sleep(
|
||||
});
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
// #[tokio::main(flavor = "current_thread")]
|
||||
// #[tokio::main]
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn event_loop(info_sender: oneshot::Sender<EventLoopInfo>) -> color_eyre::eyre::Result<()> {
|
||||
let socket_path =
|
||||
server::get_free_socket_path().expect("Unable to find a free stardust socket path");
|
||||
|
||||
@@ -23,7 +23,7 @@ use serde::{
|
||||
};
|
||||
use stardust_xr::schemas::flex::{deserialize, serialize};
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::debug;
|
||||
use tracing::{debug, info};
|
||||
|
||||
lazy_static! {
|
||||
pub static ref ITEM_TYPE_INFO_PANEL: TypeInfo = TypeInfo {
|
||||
@@ -220,7 +220,7 @@ pub struct PanelItem<B: Backend + ?Sized> {
|
||||
pub backend: Box<B>,
|
||||
}
|
||||
impl<B: Backend + ?Sized> PanelItem<B> {
|
||||
pub fn create(backend: Box<B>, pid: Option<i32>) -> Arc<PanelItem<B>> {
|
||||
pub fn create(backend: Box<B>, pid: Option<i32>) -> (Arc<Node>, Arc<PanelItem<B>>) {
|
||||
debug!(?pid, "Create panel item");
|
||||
|
||||
let startup_settings = pid
|
||||
@@ -228,9 +228,12 @@ impl<B: Backend + ?Sized> PanelItem<B> {
|
||||
.and_then(|env| state(&env));
|
||||
|
||||
let uid = nanoid!();
|
||||
let node = Node::create_parent_name(&INTERNAL_CLIENT, "/item/panel/item", &uid, true)
|
||||
.add_to_scenegraph()
|
||||
.unwrap();
|
||||
let node = Arc::new(Node::create_parent_name(
|
||||
&INTERNAL_CLIENT,
|
||||
"/item/panel/item",
|
||||
&uid,
|
||||
true,
|
||||
));
|
||||
let spatial = Spatial::add_to(&node, None, Mat4::IDENTITY, false);
|
||||
if let Some(startup_settings) = &startup_settings {
|
||||
spatial.set_local_transform(startup_settings.root);
|
||||
@@ -266,7 +269,7 @@ impl<B: Backend + ?Sized> PanelItem<B> {
|
||||
node.add_local_signal("touch_up", Self::touch_up_flex);
|
||||
node.add_local_signal("reset_touches", Self::reset_touches_flex);
|
||||
|
||||
panel_item
|
||||
(node, panel_item)
|
||||
}
|
||||
pub fn drop_toplevel(&self) {
|
||||
let Some(node) = self.node.upgrade() else {
|
||||
@@ -593,5 +596,6 @@ impl<B: Backend + ?Sized> Backend for PanelItem<B> {
|
||||
impl<B: Backend + ?Sized> Drop for PanelItem<B> {
|
||||
fn drop(&mut self) {
|
||||
// Dropped panel item, basically just a debug breakpoint place
|
||||
info!("Dropped panel item {}", self.uid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,8 +117,13 @@ impl Dispatch<wl_drm::WlDrm, (), WaylandState> for WaylandState {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut dma = Dmabuf::builder((width, height), format, DmabufFlags::empty());
|
||||
dma.add_plane(name, 0, offset0 as u32, stride0 as u32, Modifier::Invalid);
|
||||
let mut dma = Dmabuf::builder(
|
||||
(width, height),
|
||||
format,
|
||||
Modifier::Invalid,
|
||||
DmabufFlags::empty(),
|
||||
);
|
||||
dma.add_plane(name, 0, offset0 as u32, stride0 as u32);
|
||||
match dma.build() {
|
||||
Some(dmabuf) => {
|
||||
state.dmabuf_tx.send((dmabuf.clone(), None)).unwrap();
|
||||
|
||||
@@ -6,6 +6,7 @@ mod state;
|
||||
mod surface;
|
||||
// mod xdg_activation;
|
||||
mod drm;
|
||||
mod utils;
|
||||
mod xdg_shell;
|
||||
#[cfg(feature = "xwayland_rootful")]
|
||||
pub mod xwayland_rootful;
|
||||
@@ -30,6 +31,7 @@ use smithay::backend::allocator::dmabuf::Dmabuf;
|
||||
use smithay::backend::egl::EGLContext;
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
use smithay::backend::renderer::ImportDma;
|
||||
use smithay::output::Output;
|
||||
use smithay::reexports::wayland_server::backend::ClientId;
|
||||
use smithay::reexports::wayland_server::DisplayHandle;
|
||||
use smithay::reexports::wayland_server::{Display, ListeningSocket};
|
||||
@@ -97,8 +99,8 @@ pub struct Wayland {
|
||||
pub socket_name: Option<String>,
|
||||
join_handle: JoinHandle<Result<()>>,
|
||||
renderer: GlesRenderer,
|
||||
output: Output,
|
||||
dmabuf_rx: UnboundedReceiver<(Dmabuf, Option<dmabuf::ImportNotifier>)>,
|
||||
wayland_state: Arc<Mutex<WaylandState>>,
|
||||
#[cfg(feature = "xwayland_rootful")]
|
||||
pub x_lock: X11Lock,
|
||||
#[cfg(feature = "xwayland_rootless")]
|
||||
@@ -124,6 +126,7 @@ impl Wayland {
|
||||
#[cfg(feature = "xwayland_rootless")]
|
||||
let xwayland_state = XWaylandState::create(&display_handle)?;
|
||||
let wayland_state = WaylandState::new(display_handle, &renderer, dmabuf_tx);
|
||||
let output = wayland_state.lock().output.clone();
|
||||
|
||||
let socket = ListeningSocket::bind_auto("wayland", 0..33)?;
|
||||
let socket_name = socket
|
||||
@@ -137,15 +140,14 @@ impl Wayland {
|
||||
let x_display = start_xwayland(socket.as_raw_fd())?;
|
||||
info!(socket_name, "Wayland active");
|
||||
|
||||
let join_handle = Wayland::start_loop(display.clone(), socket, wayland_state.clone())?;
|
||||
|
||||
let join_handle = Wayland::start_loop(display.clone(), socket, wayland_state)?;
|
||||
Ok(Wayland {
|
||||
display,
|
||||
socket_name,
|
||||
join_handle,
|
||||
renderer,
|
||||
output,
|
||||
dmabuf_rx,
|
||||
wayland_state,
|
||||
#[cfg(feature = "xwayland_rootful")]
|
||||
x_lock: x_display,
|
||||
#[cfg(feature = "xwayland_rootless")]
|
||||
@@ -185,7 +187,7 @@ impl Wayland {
|
||||
e = dispatch_poll_listener.readable() => { // Dispatch
|
||||
let mut guard = e?;
|
||||
debug_span!("Dispatch wayland event").in_scope(|| -> Result<(), color_eyre::Report> {
|
||||
display.dispatch_clients(&mut *state.lock())?;
|
||||
display.dispatch_clients(&mut state.lock())?;
|
||||
display.flush_clients(None);
|
||||
Ok(())
|
||||
})?;
|
||||
@@ -213,10 +215,8 @@ impl Wayland {
|
||||
}
|
||||
|
||||
pub fn frame_event(&self, sk: &impl StereoKitDraw) {
|
||||
let output = self.wayland_state.lock().output.clone();
|
||||
|
||||
for core_surface in CORE_SURFACES.get_valid_contents() {
|
||||
core_surface.frame(sk, output.clone());
|
||||
core_surface.frame(sk, self.output.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,10 @@ use smithay::{
|
||||
wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration_manager::Mode as DecorationMode,
|
||||
wayland_server::{
|
||||
backend::{ClientData, ClientId, DisconnectReason},
|
||||
protocol::{wl_buffer::WlBuffer, wl_data_device_manager::WlDataDeviceManager},
|
||||
protocol::{
|
||||
wl_buffer::WlBuffer, wl_data_device_manager::WlDataDeviceManager,
|
||||
wl_output::WlOutput,
|
||||
},
|
||||
DisplayHandle,
|
||||
},
|
||||
},
|
||||
@@ -29,6 +32,7 @@ use smithay::{
|
||||
dmabuf::{
|
||||
self, DmabufFeedback, DmabufFeedbackBuilder, DmabufGlobal, DmabufHandler, DmabufState,
|
||||
},
|
||||
output::OutputHandler,
|
||||
shell::kde::decoration::KdeDecorationState,
|
||||
shm::{ShmHandler, ShmState},
|
||||
},
|
||||
@@ -201,6 +205,9 @@ impl DmabufHandler for WaylandState {
|
||||
self.dmabuf_tx.send((dmabuf, Some(notifier))).unwrap();
|
||||
}
|
||||
}
|
||||
impl OutputHandler for WaylandState {
|
||||
fn output_bound(&mut self, _output: Output, _wl_output: WlOutput) {}
|
||||
}
|
||||
delegate_dmabuf!(WaylandState);
|
||||
delegate_shm!(WaylandState);
|
||||
delegate_output!(WaylandState);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use super::state::WaylandState;
|
||||
use super::{state::WaylandState, utils::get_data};
|
||||
use crate::{
|
||||
core::{delta::Delta, destroy_queue, registry::Registry},
|
||||
nodes::drawable::{model::ModelPart, shaders::PANEL_SHADER_BYTES},
|
||||
@@ -77,13 +77,13 @@ impl CoreSurface {
|
||||
}
|
||||
|
||||
pub fn from_wl_surface(surf: &WlSurface) -> Option<Arc<CoreSurface>> {
|
||||
compositor::with_states(surf, |data| {
|
||||
data.data_map.get::<Arc<CoreSurface>>().cloned()
|
||||
})
|
||||
get_data(surf)
|
||||
}
|
||||
|
||||
pub fn process(&self, sk: &impl StereoKitDraw, renderer: &mut GlesRenderer) {
|
||||
let Some(wl_surface) = self.wl_surface() else {return};
|
||||
let Some(wl_surface) = self.wl_surface() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let sk_tex = self
|
||||
.sk_tex
|
||||
@@ -124,13 +124,23 @@ impl CoreSurface {
|
||||
let Some(renderer_surface_state) = data
|
||||
.data_map
|
||||
.get::<RendererSurfaceStateUserData>()
|
||||
.map(RefCell::borrow) else {return};
|
||||
.map(RefCell::borrow)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let Some(smithay_tex) = renderer_surface_state
|
||||
.texture::<GlesRenderer>(renderer.id())
|
||||
.cloned() else {return};
|
||||
.cloned()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(sk_tex) = self.sk_tex.get() else {return};
|
||||
let Some(sk_mat) = self.sk_mat.get() else {return};
|
||||
let Some(sk_tex) = self.sk_tex.get() else {
|
||||
return;
|
||||
};
|
||||
let Some(sk_mat) = self.sk_mat.get() else {
|
||||
return;
|
||||
};
|
||||
unsafe {
|
||||
sk.tex_set_surface(
|
||||
sk_tex.as_ref(),
|
||||
@@ -149,7 +159,9 @@ impl CoreSurface {
|
||||
sk.material_set_queue_offset(sk_mat.as_ref().as_ref(), *material_offset as i32);
|
||||
}
|
||||
|
||||
let Some(surface_size) = renderer_surface_state.surface_size() else {return};
|
||||
let Some(surface_size) = renderer_surface_state.surface_size() else {
|
||||
return;
|
||||
};
|
||||
let new_mapped_data = CoreSurfaceData {
|
||||
size: Vector2::from([surface_size.w as u32, surface_size.h as u32]),
|
||||
wl_tex: Some(SendWrapper::new(smithay_tex)),
|
||||
@@ -164,7 +176,9 @@ impl CoreSurface {
|
||||
}
|
||||
|
||||
pub fn frame(&self, sk: &impl StereoKitDraw, output: Output) {
|
||||
let Some(wl_surface) = self.wl_surface() else {return};
|
||||
let Some(wl_surface) = self.wl_surface() else {
|
||||
return;
|
||||
};
|
||||
|
||||
send_frames_surface_tree(
|
||||
&wl_surface,
|
||||
@@ -196,10 +210,7 @@ impl CoreSurface {
|
||||
self.weak_surface.upgrade().ok()
|
||||
}
|
||||
|
||||
pub fn with_states<F, T>(&self, f: F) -> Option<T>
|
||||
where
|
||||
F: FnOnce(&SurfaceData) -> T,
|
||||
{
|
||||
pub fn with_states<T, F: FnOnce(&SurfaceData) -> T>(&self, f: F) -> Option<T> {
|
||||
self.wl_surface()
|
||||
.map(|wl_surface| compositor::with_states(&wl_surface, f))
|
||||
}
|
||||
|
||||
14
src/wayland/utils.rs
Normal file
14
src/wayland/utils.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
use smithay::{reexports::wayland_server::protocol::wl_surface::WlSurface, wayland::compositor};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub fn insert_data<T: Send + Sync + 'static>(wl_surface: &WlSurface, data: T) {
|
||||
insert_data_raw(wl_surface, Arc::new(data))
|
||||
}
|
||||
pub fn insert_data_raw<T: Send + Sync + 'static>(wl_surface: &WlSurface, data: Arc<T>) {
|
||||
compositor::with_states(wl_surface, |d| {
|
||||
d.data_map.insert_if_missing_threadsafe(move || data)
|
||||
});
|
||||
}
|
||||
pub fn get_data<T: Send + Sync + 'static>(wl_surface: &WlSurface) -> Option<Arc<T>> {
|
||||
compositor::with_states(wl_surface, |d| d.data_map.get::<Arc<T>>().cloned())
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
310
src/wayland/xdg_shell/backend.rs
Normal file
310
src/wayland/xdg_shell/backend.rs
Normal file
@@ -0,0 +1,310 @@
|
||||
use super::{popup::PopupData, surface::XdgSurfaceData, ToplevelData};
|
||||
use crate::{
|
||||
nodes::{
|
||||
data::KEYMAPS,
|
||||
drawable::model::ModelPart,
|
||||
items::panel::{Backend, ChildInfo, PanelItem, PanelItemInitData, SurfaceID},
|
||||
},
|
||||
wayland::{
|
||||
seat::{CursorInfo, KeyboardEvent, PointerEvent, SeatData},
|
||||
state::ClientState,
|
||||
surface::CoreSurface,
|
||||
utils, SERIAL_COUNTER,
|
||||
},
|
||||
};
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use mint::Vector2;
|
||||
use parking_lot::Mutex;
|
||||
use rustc_hash::FxHashMap;
|
||||
use smithay::reexports::{
|
||||
wayland_protocols::xdg::shell::server::xdg_toplevel::XdgToplevel,
|
||||
wayland_server::{protocol::wl_surface::WlSurface, Resource, Weak},
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::watch;
|
||||
use tracing::debug;
|
||||
|
||||
pub struct XdgToplevelState {
|
||||
pub fullscreen: bool,
|
||||
pub activated: bool,
|
||||
}
|
||||
|
||||
pub struct XdgBackend {
|
||||
toplevel: Weak<XdgToplevel>,
|
||||
toplevel_wl_surface: Weak<WlSurface>,
|
||||
pub toplevel_state: Mutex<XdgToplevelState>,
|
||||
popups: Mutex<FxHashMap<String, Weak<WlSurface>>>,
|
||||
pub cursor: watch::Receiver<Option<CursorInfo>>,
|
||||
pub seat: Arc<SeatData>,
|
||||
pointer_grab: Mutex<Option<SurfaceID>>,
|
||||
keyboard_grab: Mutex<Option<SurfaceID>>,
|
||||
}
|
||||
impl XdgBackend {
|
||||
pub fn create(
|
||||
toplevel_wl_surface: WlSurface,
|
||||
toplevel: XdgToplevel,
|
||||
seat: Arc<SeatData>,
|
||||
) -> Self {
|
||||
let cursor = seat.new_surface(&toplevel_wl_surface);
|
||||
XdgBackend {
|
||||
toplevel: toplevel.downgrade(),
|
||||
toplevel_wl_surface: toplevel_wl_surface.downgrade(),
|
||||
toplevel_state: Mutex::new(XdgToplevelState {
|
||||
fullscreen: false,
|
||||
activated: false,
|
||||
}),
|
||||
popups: Mutex::new(FxHashMap::default()),
|
||||
cursor,
|
||||
seat,
|
||||
pointer_grab: Mutex::new(None),
|
||||
keyboard_grab: Mutex::new(None),
|
||||
}
|
||||
}
|
||||
fn wl_surface_from_id(&self, id: &SurfaceID) -> Option<WlSurface> {
|
||||
match id {
|
||||
SurfaceID::Cursor => self.cursor.borrow().as_ref()?.surface.upgrade().ok(),
|
||||
SurfaceID::Toplevel => self.toplevel_wl_surface(),
|
||||
SurfaceID::Child(popup) => {
|
||||
let popups = self.popups.lock();
|
||||
popups.get(popup)?.upgrade().ok()
|
||||
}
|
||||
}
|
||||
}
|
||||
fn toplevel_wl_surface(&self) -> Option<WlSurface> {
|
||||
self.toplevel_wl_surface.upgrade().ok()
|
||||
}
|
||||
|
||||
pub fn configure(&self, size: Option<Vector2<u32>>) {
|
||||
let Ok(xdg_toplevel) = self.toplevel.upgrade() else {
|
||||
return;
|
||||
};
|
||||
let Some(wl_surface) = self.toplevel_wl_surface() else {
|
||||
return;
|
||||
};
|
||||
let Some(xdg_surface_data) = wl_surface.data::<XdgSurfaceData>() else {
|
||||
return;
|
||||
};
|
||||
let Some(core_surface) = CoreSurface::from_wl_surface(&wl_surface) else {
|
||||
return;
|
||||
};
|
||||
let Some(surface_size) = core_surface.size() else {
|
||||
return;
|
||||
};
|
||||
|
||||
xdg_toplevel.configure(
|
||||
size.unwrap_or(surface_size).x as i32,
|
||||
size.unwrap_or(surface_size).y as i32,
|
||||
self.states()
|
||||
.into_iter()
|
||||
.flat_map(|state| state.to_ne_bytes())
|
||||
.collect(),
|
||||
);
|
||||
xdg_surface_data.xdg_surface.configure(SERIAL_COUNTER.inc());
|
||||
self.flush_client();
|
||||
}
|
||||
fn states(&self) -> Vec<u32> {
|
||||
let mut states = vec![1, 5, 6, 7, 8]; // maximized always and tiled
|
||||
let toplevel_state = self.toplevel_state.lock();
|
||||
if toplevel_state.fullscreen {
|
||||
states.push(2);
|
||||
}
|
||||
if toplevel_state.activated {
|
||||
states.push(4);
|
||||
}
|
||||
states
|
||||
}
|
||||
|
||||
pub fn new_popup(
|
||||
&self,
|
||||
panel_item: &PanelItem<XdgBackend>,
|
||||
popup_wl_surface: &WlSurface,
|
||||
data: &PopupData,
|
||||
) {
|
||||
self.popups
|
||||
.lock()
|
||||
.insert(data.uid.clone(), popup_wl_surface.downgrade());
|
||||
|
||||
let Some(geometry) = data.geometry() else {
|
||||
return;
|
||||
};
|
||||
panel_item.new_child(
|
||||
&data.uid,
|
||||
ChildInfo {
|
||||
parent: utils::get_data::<SurfaceID>(&data.parent())
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.clone(),
|
||||
geometry,
|
||||
},
|
||||
)
|
||||
}
|
||||
pub fn reposition_popup(&self, panel_item: &PanelItem<XdgBackend>, popup_state: &PopupData) {
|
||||
let Some(geometry) = popup_state.geometry() else {
|
||||
return;
|
||||
};
|
||||
panel_item.reposition_child(&popup_state.uid, geometry)
|
||||
}
|
||||
pub fn drop_popup(&self, panel_item: &PanelItem<XdgBackend>, uid: &str) {
|
||||
panel_item.drop_child(uid);
|
||||
let Some(popup) = self.popups.lock().remove(uid) else {
|
||||
return;
|
||||
};
|
||||
let Some(wl_surface) = popup.upgrade().ok() else {
|
||||
return;
|
||||
};
|
||||
self.seat.drop_surface(&wl_surface);
|
||||
}
|
||||
|
||||
fn child_data(&self) -> FxHashMap<String, ChildInfo> {
|
||||
FxHashMap::from_iter(self.popups.lock().iter().filter_map(|(uid, v)| {
|
||||
let wl_surface = v.upgrade().ok()?;
|
||||
let popup_data = utils::get_data::<PopupData>(&wl_surface)?;
|
||||
let parent = utils::get_data::<SurfaceID>(&popup_data.parent())?
|
||||
.as_ref()
|
||||
.clone();
|
||||
let geometry = utils::get_data::<XdgSurfaceData>(&wl_surface)?
|
||||
.geometry
|
||||
.lock()
|
||||
.clone()?;
|
||||
Some((uid.clone(), ChildInfo { parent, geometry }))
|
||||
}))
|
||||
}
|
||||
|
||||
fn flush_client(&self) {
|
||||
let Some(client) = self.toplevel_wl_surface().and_then(|s| s.client()) else {
|
||||
return;
|
||||
};
|
||||
if let Some(client_state) = client.get_data::<ClientState>() {
|
||||
client_state.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Drop for XdgBackend {
|
||||
fn drop(&mut self) {
|
||||
debug!("Dropped panel item gracefully");
|
||||
}
|
||||
}
|
||||
impl Backend for XdgBackend {
|
||||
fn start_data(&self) -> Result<PanelItemInitData> {
|
||||
let toplevel = self.toplevel_wl_surface();
|
||||
let toplevel_data = toplevel.as_ref().and_then(utils::get_data::<ToplevelData>);
|
||||
let toplevel_data = toplevel_data
|
||||
.as_deref()
|
||||
.clone()
|
||||
.ok_or_else(|| eyre!("Could not get toplevel"))?;
|
||||
|
||||
let pointer_grab = self.pointer_grab.lock().clone();
|
||||
let keyboard_grab = self.keyboard_grab.lock().clone();
|
||||
|
||||
Ok(PanelItemInitData {
|
||||
cursor: self.cursor.borrow().as_ref().and_then(|c| c.cursor_data()),
|
||||
toplevel: toplevel_data.into(),
|
||||
children: self.child_data(),
|
||||
pointer_grab,
|
||||
keyboard_grab,
|
||||
})
|
||||
}
|
||||
|
||||
fn apply_surface_material(&self, surface: SurfaceID, model_part: &Arc<ModelPart>) {
|
||||
let Some(wl_surface) = self.wl_surface_from_id(&surface) else {
|
||||
return;
|
||||
};
|
||||
let Some(core_surface) = CoreSurface::from_wl_surface(&wl_surface) else {
|
||||
return;
|
||||
};
|
||||
|
||||
core_surface.apply_material(model_part);
|
||||
}
|
||||
|
||||
fn close_toplevel(&self) {
|
||||
let Ok(xdg_toplevel) = self.toplevel.upgrade() else {
|
||||
return;
|
||||
};
|
||||
xdg_toplevel.close();
|
||||
}
|
||||
fn auto_size_toplevel(&self) {
|
||||
self.configure(Some([0, 0].into()));
|
||||
}
|
||||
fn set_toplevel_size(&self, size: Vector2<u32>) {
|
||||
self.configure(Some(size));
|
||||
}
|
||||
fn set_toplevel_focused_visuals(&self, focused: bool) {
|
||||
self.toplevel_state.lock().activated = focused;
|
||||
self.configure(None);
|
||||
}
|
||||
|
||||
fn pointer_motion(&self, surface: &SurfaceID, position: Vector2<f32>) {
|
||||
let Some(surface) = self.wl_surface_from_id(surface) else {
|
||||
return;
|
||||
};
|
||||
self.seat
|
||||
.pointer_event(&surface, PointerEvent::Motion(position));
|
||||
}
|
||||
fn pointer_button(&self, surface: &SurfaceID, button: u32, pressed: bool) {
|
||||
let Some(surface) = self.wl_surface_from_id(surface) else {
|
||||
return;
|
||||
};
|
||||
self.seat.pointer_event(
|
||||
&surface,
|
||||
PointerEvent::Button {
|
||||
button,
|
||||
state: if pressed { 1 } else { 0 },
|
||||
},
|
||||
)
|
||||
}
|
||||
fn pointer_scroll(
|
||||
&self,
|
||||
surface: &SurfaceID,
|
||||
scroll_distance: Option<Vector2<f32>>,
|
||||
scroll_steps: Option<Vector2<f32>>,
|
||||
) {
|
||||
let Some(surface) = self.wl_surface_from_id(surface) else {
|
||||
return;
|
||||
};
|
||||
self.seat.pointer_event(
|
||||
&surface,
|
||||
PointerEvent::Scroll {
|
||||
axis_continuous: scroll_distance,
|
||||
axis_discrete: scroll_steps,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn keyboard_keys(&self, surface: &SurfaceID, keymap_id: &str, keys: Vec<i32>) {
|
||||
let Some(surface) = self.wl_surface_from_id(surface) else {
|
||||
return;
|
||||
};
|
||||
let keymaps = KEYMAPS.lock();
|
||||
let Some(keymap) = keymaps.get(keymap_id).cloned() else {
|
||||
return;
|
||||
};
|
||||
if self.seat.set_keymap(keymap, vec![surface.clone()]).is_err() {
|
||||
return;
|
||||
}
|
||||
for key in keys {
|
||||
self.seat.keyboard_event(
|
||||
&surface,
|
||||
KeyboardEvent::Key {
|
||||
key: key.abs() as u32,
|
||||
state: key > 0,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn touch_down(&self, surface: &SurfaceID, id: u32, position: Vector2<f32>) {
|
||||
let Some(surface) = self.wl_surface_from_id(surface) else {
|
||||
return;
|
||||
};
|
||||
self.seat.touch_down(&surface, id, position)
|
||||
}
|
||||
fn touch_move(&self, id: u32, position: Vector2<f32>) {
|
||||
self.seat.touch_move(id, position)
|
||||
}
|
||||
fn touch_up(&self, id: u32) {
|
||||
self.seat.touch_up(id)
|
||||
}
|
||||
fn reset_touches(&self) {
|
||||
self.seat.reset_touches()
|
||||
}
|
||||
}
|
||||
69
src/wayland/xdg_shell/mod.rs
Normal file
69
src/wayland/xdg_shell/mod.rs
Normal file
@@ -0,0 +1,69 @@
|
||||
use self::{backend::XdgBackend, toplevel::ToplevelData};
|
||||
use super::state::WaylandState;
|
||||
use crate::wayland::{
|
||||
utils::insert_data,
|
||||
xdg_shell::{positioner::PositionerData, surface::XdgSurfaceData},
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use smithay::reexports::{
|
||||
wayland_protocols::xdg::shell::server::xdg_wm_base::{self, XdgWmBase},
|
||||
wayland_server::{Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource},
|
||||
};
|
||||
use tracing::debug;
|
||||
|
||||
mod backend;
|
||||
mod popup;
|
||||
mod positioner;
|
||||
mod surface;
|
||||
mod toplevel;
|
||||
|
||||
impl GlobalDispatch<XdgWmBase, (), WaylandState> for WaylandState {
|
||||
fn bind(
|
||||
_state: &mut WaylandState,
|
||||
_handle: &DisplayHandle,
|
||||
_client: &Client,
|
||||
resource: New<XdgWmBase>,
|
||||
_global_data: &(),
|
||||
data_init: &mut DataInit<'_, WaylandState>,
|
||||
) {
|
||||
data_init.init(resource, ());
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<XdgWmBase, (), WaylandState> for WaylandState {
|
||||
fn request(
|
||||
_state: &mut WaylandState,
|
||||
_client: &Client,
|
||||
_resource: &XdgWmBase,
|
||||
request: xdg_wm_base::Request,
|
||||
_data: &(),
|
||||
_dhandle: &DisplayHandle,
|
||||
data_init: &mut DataInit<'_, WaylandState>,
|
||||
) {
|
||||
match request {
|
||||
xdg_wm_base::Request::CreatePositioner { id } => {
|
||||
let positioner = data_init.init(id, Mutex::new(PositionerData::default()));
|
||||
debug!(?positioner, "Create XDG positioner");
|
||||
}
|
||||
xdg_wm_base::Request::GetXdgSurface { id, surface } => {
|
||||
let xdg_surface = data_init.init(id, surface.downgrade());
|
||||
debug!(?xdg_surface, "Create XDG surface");
|
||||
insert_data(
|
||||
&surface,
|
||||
XdgSurfaceData {
|
||||
wl_surface: surface.downgrade(),
|
||||
xdg_surface,
|
||||
geometry: Mutex::new(None),
|
||||
},
|
||||
);
|
||||
}
|
||||
xdg_wm_base::Request::Pong { serial } => {
|
||||
debug!(serial, "Client pong");
|
||||
}
|
||||
xdg_wm_base::Request::Destroy => {
|
||||
debug!("Destroy XDG WM base");
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
119
src/wayland/xdg_shell/popup.rs
Normal file
119
src/wayland/xdg_shell/popup.rs
Normal file
@@ -0,0 +1,119 @@
|
||||
use super::{backend::XdgBackend, positioner::PositionerData};
|
||||
use crate::{
|
||||
nodes::items::panel::{Geometry, PanelItem, SurfaceID},
|
||||
wayland::{state::WaylandState, utils::get_data},
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use smithay::reexports::{
|
||||
wayland_protocols::xdg::shell::server::{
|
||||
xdg_popup::{self, XdgPopup},
|
||||
xdg_positioner::XdgPositioner,
|
||||
},
|
||||
wayland_server::{
|
||||
protocol::wl_surface::WlSurface, Client, DataInit, Dispatch, DisplayHandle, Resource,
|
||||
Weak as WlWeak,
|
||||
},
|
||||
};
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::{debug, error};
|
||||
use wayland_backend::server::ClientId;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PopupData {
|
||||
pub uid: String,
|
||||
grabbed: Mutex<bool>,
|
||||
parent: Mutex<WlWeak<WlSurface>>,
|
||||
panel_item: Weak<PanelItem<XdgBackend>>,
|
||||
positioner: Mutex<XdgPositioner>,
|
||||
}
|
||||
impl PopupData {
|
||||
pub fn new(
|
||||
uid: impl ToString,
|
||||
parent: WlSurface,
|
||||
panel_item: &Arc<PanelItem<XdgBackend>>,
|
||||
positioner: XdgPositioner,
|
||||
) -> Self {
|
||||
PopupData {
|
||||
uid: uid.to_string(),
|
||||
grabbed: Mutex::new(false),
|
||||
parent: Mutex::new(parent.downgrade()),
|
||||
panel_item: Arc::downgrade(panel_item),
|
||||
positioner: Mutex::new(positioner),
|
||||
}
|
||||
}
|
||||
pub fn geometry(&self) -> Option<Geometry> {
|
||||
let positioner = self.positioner.lock().clone();
|
||||
let positioner_data = positioner.data::<Mutex<PositionerData>>()?.lock();
|
||||
Some(positioner_data.clone().into())
|
||||
}
|
||||
pub fn parent(&self) -> WlSurface {
|
||||
self.parent.lock().upgrade().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<XdgPopup, WlWeak<WlSurface>, WaylandState> for WaylandState {
|
||||
fn request(
|
||||
_state: &mut WaylandState,
|
||||
_client: &Client,
|
||||
xdg_popup: &XdgPopup,
|
||||
request: xdg_popup::Request,
|
||||
wl_surface_resource: &WlWeak<WlSurface>,
|
||||
_dhandle: &DisplayHandle,
|
||||
_data_init: &mut DataInit<'_, WaylandState>,
|
||||
) {
|
||||
let Ok(wl_surface) = wl_surface_resource.upgrade() else {
|
||||
error!("Couldn't get the wayland surface of the xdg popup");
|
||||
return;
|
||||
};
|
||||
let Some(popup_data) = get_data::<PopupData>(&wl_surface) else {
|
||||
error!("Couldn't get the XdgPopup");
|
||||
return;
|
||||
};
|
||||
let Some(panel_item) = popup_data.panel_item.upgrade() else {
|
||||
error!("Couldn't get the panel item");
|
||||
return;
|
||||
};
|
||||
match request {
|
||||
xdg_popup::Request::Grab { seat, serial } => {
|
||||
*popup_data.grabbed.lock() = true;
|
||||
debug!(?xdg_popup, ?seat, serial, "XDG popup grab");
|
||||
panel_item.grab_keyboard(Some(SurfaceID::Child(popup_data.uid.clone())));
|
||||
}
|
||||
xdg_popup::Request::Reposition { positioner, token } => {
|
||||
debug!(?xdg_popup, ?positioner, token, "XDG popup reposition");
|
||||
*popup_data.positioner.lock() = positioner;
|
||||
panel_item
|
||||
.backend
|
||||
.reposition_popup(&panel_item, &popup_data);
|
||||
}
|
||||
xdg_popup::Request::Destroy => {
|
||||
debug!(?xdg_popup, "Destroy XDG popup");
|
||||
if *popup_data.grabbed.lock() {
|
||||
panel_item.grab_keyboard(None);
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn destroyed(
|
||||
_state: &mut WaylandState,
|
||||
_client: ClientId,
|
||||
_popup: &XdgPopup,
|
||||
data: &WlWeak<WlSurface>,
|
||||
) {
|
||||
let Ok(wl_surface) = data.upgrade() else {
|
||||
error!("Couldn't get the wayland surface of the xdg popup");
|
||||
return;
|
||||
};
|
||||
let Some(popup_data) = get_data::<PopupData>(&wl_surface) else {
|
||||
error!("Couldn't get the XdgPopup");
|
||||
return;
|
||||
};
|
||||
let Some(panel_item) = popup_data.panel_item.upgrade() else {
|
||||
error!("Couldn't get the panel item");
|
||||
return;
|
||||
};
|
||||
panel_item.backend.drop_popup(&panel_item, &popup_data.uid);
|
||||
}
|
||||
}
|
||||
226
src/wayland/xdg_shell/positioner.rs
Normal file
226
src/wayland/xdg_shell/positioner.rs
Normal file
@@ -0,0 +1,226 @@
|
||||
use crate::{nodes::items::panel::Geometry, wayland::state::WaylandState};
|
||||
use mint::Vector2;
|
||||
use parking_lot::Mutex;
|
||||
use smithay::reexports::{
|
||||
wayland_protocols::xdg::shell::server::xdg_positioner::{
|
||||
self, Anchor, ConstraintAdjustment, Gravity, XdgPositioner,
|
||||
},
|
||||
wayland_server::{Client, DataInit, Dispatch, DisplayHandle, Resource},
|
||||
};
|
||||
use tracing::{debug, warn};
|
||||
use wayland_backend::protocol::WEnum;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct PositionerData {
|
||||
size: Vector2<u32>,
|
||||
anchor_rect_pos: Vector2<i32>,
|
||||
anchor_rect_size: Vector2<u32>,
|
||||
anchor: Anchor,
|
||||
gravity: Gravity,
|
||||
constraint_adjustment: ConstraintAdjustment,
|
||||
offset: Vector2<i32>,
|
||||
reactive: bool,
|
||||
}
|
||||
impl Default for PositionerData {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
size: Vector2::from([0; 2]),
|
||||
anchor_rect_pos: Vector2::from([0; 2]),
|
||||
anchor_rect_size: Vector2::from([0; 2]),
|
||||
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 From<PositionerData> for Geometry {
|
||||
fn from(value: PositionerData) -> Self {
|
||||
Geometry {
|
||||
origin: value.get_pos(),
|
||||
size: value.size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<XdgPositioner, Mutex<PositionerData>, WaylandState> for WaylandState {
|
||||
fn request(
|
||||
_state: &mut WaylandState,
|
||||
_client: &Client,
|
||||
positioner: &XdgPositioner,
|
||||
request: xdg_positioner::Request,
|
||||
data: &Mutex<PositionerData>,
|
||||
_dhandle: &DisplayHandle,
|
||||
_data_init: &mut DataInit<'_, WaylandState>,
|
||||
) {
|
||||
match request {
|
||||
xdg_positioner::Request::SetSize { width, height } => {
|
||||
debug!(?positioner, width, height, "Set positioner size");
|
||||
data.lock().size = Vector2::from([width as u32, height as u32]);
|
||||
}
|
||||
xdg_positioner::Request::SetAnchorRect {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
} => {
|
||||
if width < 1 || height < 1 {
|
||||
positioner.post_error(
|
||||
xdg_positioner::Error::InvalidInput,
|
||||
"Invalid size for positioner's anchor rectangle.",
|
||||
);
|
||||
warn!(
|
||||
?positioner,
|
||||
width, height, "Invalid size for positioner's anchor rectangle"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
debug!(
|
||||
?positioner,
|
||||
x, y, width, height, "Set positioner anchor rectangle"
|
||||
);
|
||||
let mut data = data.lock();
|
||||
data.anchor_rect_pos = [x, y].into();
|
||||
data.anchor_rect_size = [width as u32, height as u32].into();
|
||||
}
|
||||
xdg_positioner::Request::SetAnchor { anchor } => {
|
||||
if let WEnum::Value(anchor) = anchor {
|
||||
debug!(?positioner, ?anchor, "Set positioner anchor");
|
||||
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;
|
||||
}
|
||||
}
|
||||
xdg_positioner::Request::SetConstraintAdjustment {
|
||||
constraint_adjustment,
|
||||
} => {
|
||||
debug!(
|
||||
?positioner,
|
||||
constraint_adjustment, "Set positioner constraint adjustment"
|
||||
);
|
||||
let Some(constraint_adjustment) =
|
||||
ConstraintAdjustment::from_bits(constraint_adjustment)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
data.lock().constraint_adjustment = constraint_adjustment;
|
||||
}
|
||||
xdg_positioner::Request::SetOffset { x, y } => {
|
||||
debug!(?positioner, x, y, "Set positioner offset");
|
||||
data.lock().offset = [x, y].into();
|
||||
}
|
||||
xdg_positioner::Request::SetReactive => {
|
||||
debug!(?positioner, "Set positioner reactive");
|
||||
data.lock().reactive = true;
|
||||
}
|
||||
xdg_positioner::Request::SetParentSize {
|
||||
parent_width,
|
||||
parent_height,
|
||||
} => {
|
||||
debug!(
|
||||
?positioner,
|
||||
parent_width, parent_height, "Set positioner parent size"
|
||||
);
|
||||
}
|
||||
xdg_positioner::Request::SetParentConfigure { serial } => {
|
||||
debug!(?positioner, serial, "Set positioner parent size");
|
||||
}
|
||||
xdg_positioner::Request::Destroy => (),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
236
src/wayland/xdg_shell/surface.rs
Normal file
236
src/wayland/xdg_shell/surface.rs
Normal file
@@ -0,0 +1,236 @@
|
||||
use crate::{
|
||||
nodes::items::panel::{Geometry, PanelItem, SurfaceID},
|
||||
wayland::{
|
||||
seat::handle_cursor,
|
||||
state::{ClientState, WaylandState},
|
||||
surface::CoreSurface,
|
||||
utils,
|
||||
xdg_shell::{popup::PopupData, toplevel::ToplevelData, XdgBackend},
|
||||
SERIAL_COUNTER,
|
||||
},
|
||||
};
|
||||
use nanoid::nanoid;
|
||||
use parking_lot::Mutex;
|
||||
use smithay::reexports::{
|
||||
wayland_protocols::xdg::shell::server::{
|
||||
xdg_surface::{self, XdgSurface},
|
||||
xdg_toplevel::{XdgToplevel, EVT_WM_CAPABILITIES_SINCE},
|
||||
},
|
||||
wayland_server::{
|
||||
protocol::wl_surface::WlSurface, Client, DataInit, Dispatch, DisplayHandle, Resource,
|
||||
Weak as WlWeak,
|
||||
},
|
||||
};
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::{debug, error};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct XdgSurfaceData {
|
||||
pub wl_surface: WlWeak<WlSurface>,
|
||||
pub xdg_surface: XdgSurface,
|
||||
pub geometry: Mutex<Option<Geometry>>,
|
||||
}
|
||||
|
||||
impl Dispatch<XdgSurface, WlWeak<WlSurface>, WaylandState> for WaylandState {
|
||||
fn request(
|
||||
state: &mut WaylandState,
|
||||
client: &Client,
|
||||
xdg_surface: &XdgSurface,
|
||||
request: xdg_surface::Request,
|
||||
wl_surface_resource: &WlWeak<WlSurface>,
|
||||
_dhandle: &DisplayHandle,
|
||||
data_init: &mut DataInit<'_, WaylandState>,
|
||||
) {
|
||||
let Ok(wl_surface) = wl_surface_resource.upgrade() else {
|
||||
error!("Couldn't get the wayland surface of the xdg surface");
|
||||
return;
|
||||
};
|
||||
let Some(xdg_surface_data) = utils::get_data::<XdgSurfaceData>(&wl_surface) else {
|
||||
error!("Couldn't get the XdgSurface");
|
||||
return;
|
||||
};
|
||||
match request {
|
||||
xdg_surface::Request::GetToplevel { id } => {
|
||||
let toplevel = data_init.init(id, wl_surface_resource.clone());
|
||||
utils::insert_data(&wl_surface, SurfaceID::Toplevel);
|
||||
utils::insert_data(&wl_surface, toplevel.clone());
|
||||
utils::insert_data(&wl_surface, ToplevelData::new(&wl_surface));
|
||||
debug!(?toplevel, ?xdg_surface, "Create XDG toplevel");
|
||||
|
||||
if toplevel.version() >= EVT_WM_CAPABILITIES_SINCE {
|
||||
toplevel.wm_capabilities(vec![3]);
|
||||
}
|
||||
toplevel.configure(
|
||||
0,
|
||||
0,
|
||||
if toplevel.version() >= 2 {
|
||||
vec![1, 5, 6, 7, 8]
|
||||
.into_iter()
|
||||
.flat_map(u32::to_ne_bytes)
|
||||
.collect()
|
||||
} else {
|
||||
vec![]
|
||||
},
|
||||
);
|
||||
xdg_surface.configure(SERIAL_COUNTER.inc());
|
||||
|
||||
let client_credentials = client.get_credentials(&state.display_handle).ok();
|
||||
let Some(seat_data) = client.get_data::<ClientState>().map(|s| s.seat.clone())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let xdg_surface = xdg_surface.clone();
|
||||
CoreSurface::add_to(
|
||||
state.display_handle.clone(),
|
||||
&wl_surface,
|
||||
{
|
||||
let wl_surface_resource = wl_surface_resource.clone();
|
||||
move || {
|
||||
let wl_surface = wl_surface_resource.upgrade().unwrap();
|
||||
|
||||
let backend = XdgBackend::create(
|
||||
wl_surface.clone(),
|
||||
toplevel.clone(),
|
||||
seat_data.clone(),
|
||||
);
|
||||
let (node, panel_item) = PanelItem::create(
|
||||
Box::new(backend),
|
||||
client_credentials.map(|c| c.pid),
|
||||
);
|
||||
utils::insert_data(&wl_surface, Arc::downgrade(&panel_item));
|
||||
utils::insert_data_raw(&wl_surface, node);
|
||||
handle_cursor(&panel_item, panel_item.backend.cursor.clone());
|
||||
}
|
||||
},
|
||||
{
|
||||
let wl_surface_resource = wl_surface_resource.clone();
|
||||
move |_| {
|
||||
let wl_surface = wl_surface_resource.upgrade().unwrap();
|
||||
|
||||
let Some(panel_item) =
|
||||
utils::get_data::<PanelItem<XdgBackend>>(&wl_surface)
|
||||
else {
|
||||
let Some(toplevel) = utils::get_data::<XdgToplevel>(&wl_surface)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
// if the wayland toplevel isn't mapped, hammer it again with a configure until it cooperates
|
||||
toplevel.configure(
|
||||
0,
|
||||
0,
|
||||
if toplevel.version() >= 2 {
|
||||
vec![5, 6, 7, 8]
|
||||
.into_iter()
|
||||
.flat_map(u32::to_ne_bytes)
|
||||
.collect()
|
||||
} else {
|
||||
vec![]
|
||||
},
|
||||
);
|
||||
xdg_surface.configure(SERIAL_COUNTER.inc());
|
||||
return;
|
||||
};
|
||||
let Some(core_surface) = CoreSurface::from_wl_surface(&wl_surface)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let Some(size) = core_surface.size() else {
|
||||
return;
|
||||
};
|
||||
panel_item.toplevel_size_changed(size);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
xdg_surface::Request::GetPopup {
|
||||
id,
|
||||
parent,
|
||||
positioner,
|
||||
} => {
|
||||
let Some(parent) = parent else { return };
|
||||
let Some(parent_wl_surface) = parent
|
||||
.data::<WlWeak<WlSurface>>()
|
||||
.map(WlWeak::upgrade)
|
||||
.map(Result::ok)
|
||||
.flatten()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let Some(panel_item) =
|
||||
utils::get_data::<Weak<PanelItem<XdgBackend>>>(&parent_wl_surface)
|
||||
.as_deref()
|
||||
.and_then(Weak::upgrade)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let uid = nanoid!();
|
||||
let popup_data = PopupData::new(
|
||||
uid.clone(),
|
||||
parent_wl_surface.clone(),
|
||||
&panel_item,
|
||||
positioner,
|
||||
);
|
||||
handle_cursor(
|
||||
&panel_item,
|
||||
panel_item.backend.seat.new_surface(&wl_surface),
|
||||
);
|
||||
let xdg_popup = data_init.init(id, wl_surface.downgrade());
|
||||
utils::insert_data(&wl_surface, SurfaceID::Child(uid));
|
||||
utils::insert_data(&wl_surface, Arc::downgrade(&panel_item));
|
||||
utils::insert_data(&wl_surface, popup_data);
|
||||
utils::insert_data(&wl_surface, xdg_popup.clone());
|
||||
debug!(?xdg_popup, ?xdg_surface, "Create XDG popup");
|
||||
|
||||
let xdg_surface = xdg_surface.downgrade();
|
||||
let popup_wl_surface = wl_surface.downgrade();
|
||||
CoreSurface::add_to(
|
||||
state.display_handle.clone(),
|
||||
&wl_surface,
|
||||
move || {
|
||||
let Ok(wl_surface) = popup_wl_surface.upgrade() else {
|
||||
return;
|
||||
};
|
||||
let Some(popup_data) = utils::get_data::<PopupData>(&wl_surface) else {
|
||||
return;
|
||||
};
|
||||
panel_item
|
||||
.backend
|
||||
.new_popup(&panel_item, &wl_surface, &*popup_data);
|
||||
},
|
||||
move |commit_count| {
|
||||
if commit_count == 0 {
|
||||
if let Ok(xdg_surface) = xdg_surface.upgrade() {
|
||||
xdg_surface.configure(SERIAL_COUNTER.inc())
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
xdg_surface::Request::SetWindowGeometry {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
} => {
|
||||
debug!(
|
||||
?xdg_surface,
|
||||
x, y, width, height, "Set XDG surface geometry"
|
||||
);
|
||||
let geometry = Geometry {
|
||||
origin: [x, y].into(),
|
||||
size: [width as u32, height as u32].into(),
|
||||
};
|
||||
xdg_surface_data.geometry.lock().replace(geometry);
|
||||
}
|
||||
xdg_surface::Request::AckConfigure { serial } => {
|
||||
debug!(?xdg_surface, serial, "Acknowledge XDG surface configure");
|
||||
}
|
||||
xdg_surface::Request::Destroy => {
|
||||
debug!(?xdg_surface, "Destroy XDG surface");
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
239
src/wayland/xdg_shell/toplevel.rs
Normal file
239
src/wayland/xdg_shell/toplevel.rs
Normal file
@@ -0,0 +1,239 @@
|
||||
use super::{backend::XdgBackend, surface::XdgSurfaceData};
|
||||
use crate::{
|
||||
nodes::items::panel::{Geometry, PanelItem, ToplevelInfo},
|
||||
wayland::{
|
||||
state::WaylandState,
|
||||
surface::CoreSurface,
|
||||
utils::{self, get_data},
|
||||
},
|
||||
};
|
||||
use mint::Vector2;
|
||||
use once_cell::sync::OnceCell;
|
||||
use parking_lot::Mutex;
|
||||
use smithay::reexports::{
|
||||
wayland_protocols::xdg::shell::server::xdg_toplevel::{self, ResizeEdge, XdgToplevel},
|
||||
wayland_server::{
|
||||
protocol::wl_surface::WlSurface, Client, DataInit, Dispatch, DisplayHandle, Resource,
|
||||
Weak as WlWeak,
|
||||
},
|
||||
};
|
||||
use std::sync::Weak;
|
||||
use tracing::{debug, error};
|
||||
use wayland_backend::protocol::WEnum;
|
||||
|
||||
pub struct ToplevelData {
|
||||
panel_item: OnceCell<Weak<PanelItem<XdgBackend>>>,
|
||||
wl_surface: WlWeak<WlSurface>,
|
||||
parent: Mutex<Option<WlWeak<WlSurface>>>,
|
||||
title: Mutex<Option<String>>,
|
||||
app_id: Mutex<Option<String>>,
|
||||
max_size: Mutex<Option<Vector2<u32>>>,
|
||||
min_size: Mutex<Option<Vector2<u32>>>,
|
||||
}
|
||||
impl ToplevelData {
|
||||
pub fn new(wl_surface: &WlSurface) -> Self {
|
||||
ToplevelData {
|
||||
panel_item: OnceCell::new(),
|
||||
wl_surface: wl_surface.downgrade(),
|
||||
parent: Mutex::new(None),
|
||||
title: Mutex::new(None),
|
||||
app_id: Mutex::new(None),
|
||||
max_size: Mutex::new(None),
|
||||
min_size: Mutex::new(None),
|
||||
}
|
||||
}
|
||||
pub fn parent(&self) -> Option<WlSurface> {
|
||||
self.parent
|
||||
.lock()
|
||||
.as_ref()
|
||||
.map(WlWeak::upgrade)
|
||||
.map(Result::ok)
|
||||
.flatten()
|
||||
}
|
||||
}
|
||||
impl From<&ToplevelData> for ToplevelInfo {
|
||||
fn from(value: &ToplevelData) -> Self {
|
||||
let wl_surface = value.wl_surface.upgrade().ok();
|
||||
let size = CoreSurface::from_wl_surface(wl_surface.as_ref().unwrap())
|
||||
.unwrap()
|
||||
.size()
|
||||
.unwrap();
|
||||
let logical_rectangle = wl_surface
|
||||
.as_ref()
|
||||
.and_then(utils::get_data::<XdgSurfaceData>)
|
||||
.and_then(|d| d.geometry.lock().clone())
|
||||
.unwrap_or_else(|| Geometry {
|
||||
origin: [0, 0].into(),
|
||||
size,
|
||||
});
|
||||
let parent = value
|
||||
.parent()
|
||||
.as_ref()
|
||||
.and_then(utils::get_data::<Weak<PanelItem<XdgBackend>>>)
|
||||
.as_deref()
|
||||
.and_then(Weak::upgrade)
|
||||
.map(|i| i.uid.clone());
|
||||
ToplevelInfo {
|
||||
parent,
|
||||
title: value.title.lock().clone(),
|
||||
app_id: value.app_id.lock().clone(),
|
||||
size,
|
||||
min_size: value.min_size.lock().clone(),
|
||||
max_size: value.max_size.lock().clone(),
|
||||
logical_rectangle,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Drop for ToplevelData {
|
||||
fn drop(&mut self) {
|
||||
// let Some(panel_item) = self.panel_item.get().and_then(Weak::upgrade) else {
|
||||
// return;
|
||||
// };
|
||||
// panel_item.drop_toplevel();
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<XdgToplevel, WlWeak<WlSurface>, WaylandState> for WaylandState {
|
||||
fn request(
|
||||
_state: &mut WaylandState,
|
||||
_client: &Client,
|
||||
xdg_toplevel: &XdgToplevel,
|
||||
request: xdg_toplevel::Request,
|
||||
wl_surface_resource: &WlWeak<WlSurface>,
|
||||
_dhandle: &DisplayHandle,
|
||||
_data_init: &mut DataInit<'_, WaylandState>,
|
||||
) {
|
||||
let Ok(wl_surface) = wl_surface_resource.upgrade() else {
|
||||
error!("Couldn't get the wayland surface of the xdg toplevel");
|
||||
return;
|
||||
};
|
||||
let Some(toplevel_data) = utils::get_data::<ToplevelData>(&wl_surface) else {
|
||||
error!("Couldn't get the XdgToplevel");
|
||||
return;
|
||||
};
|
||||
match request {
|
||||
xdg_toplevel::Request::SetParent { parent } => {
|
||||
debug!(?xdg_toplevel, ?parent, "Set XDG Toplevel parent");
|
||||
let Some(parent_xdg_toplevel) = parent else {
|
||||
*toplevel_data.parent.lock() = None;
|
||||
return;
|
||||
};
|
||||
let Some(parent_toplevel_data) = parent_xdg_toplevel.data::<ToplevelData>() else {
|
||||
error!("Couldn't get XDG toplevel parent data");
|
||||
return;
|
||||
};
|
||||
let Ok(parent_wl_surface) = parent_toplevel_data.wl_surface.upgrade() else {
|
||||
error!("Couldn't get XDG toplevel parent wl surface");
|
||||
return;
|
||||
};
|
||||
*toplevel_data.parent.lock() = Some(parent_wl_surface.downgrade());
|
||||
let Some(parent_panel_item) = parent_toplevel_data
|
||||
.panel_item
|
||||
.get()
|
||||
.and_then(Weak::upgrade)
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let Some(panel_item) = get_data::<PanelItem<XdgBackend>>(&wl_surface) else {
|
||||
error!("Couldn't get the panel item");
|
||||
return;
|
||||
};
|
||||
panel_item.toplevel_parent_changed(&parent_panel_item.uid);
|
||||
}
|
||||
xdg_toplevel::Request::SetTitle { title } => {
|
||||
debug!(?xdg_toplevel, ?title, "Set XDG Toplevel title");
|
||||
*toplevel_data.title.lock() = (!title.is_empty()).then_some(title.clone());
|
||||
let Some(panel_item) = get_data::<PanelItem<XdgBackend>>(&wl_surface) else {
|
||||
error!("Couldn't get the panel item");
|
||||
return;
|
||||
};
|
||||
panel_item.toplevel_title_changed(&title);
|
||||
}
|
||||
xdg_toplevel::Request::SetAppId { app_id } => {
|
||||
debug!(?xdg_toplevel, ?app_id, "Set XDG Toplevel app ID");
|
||||
*toplevel_data.app_id.lock() = (!app_id.is_empty()).then_some(app_id.clone());
|
||||
let Some(panel_item) = get_data::<PanelItem<XdgBackend>>(&wl_surface) else {
|
||||
error!("Couldn't get the panel item");
|
||||
return;
|
||||
};
|
||||
panel_item.toplevel_app_id_changed(&app_id);
|
||||
}
|
||||
xdg_toplevel::Request::Move { seat, serial } => {
|
||||
debug!(?xdg_toplevel, ?seat, serial, "XDG Toplevel move request");
|
||||
let Some(panel_item) = get_data::<PanelItem<XdgBackend>>(&wl_surface) else {
|
||||
error!("Couldn't get the panel item");
|
||||
return;
|
||||
};
|
||||
panel_item.toplevel_move_request();
|
||||
}
|
||||
xdg_toplevel::Request::Resize {
|
||||
seat,
|
||||
serial,
|
||||
edges,
|
||||
} => {
|
||||
let WEnum::Value(edges) = edges else { return };
|
||||
debug!(
|
||||
?xdg_toplevel,
|
||||
?seat,
|
||||
serial,
|
||||
?edges,
|
||||
"XDG Toplevel resize request"
|
||||
);
|
||||
let (up, down, left, right) = match edges {
|
||||
ResizeEdge::Top => (true, false, false, false),
|
||||
ResizeEdge::Bottom => (false, true, false, false),
|
||||
ResizeEdge::Left => (false, false, true, false),
|
||||
ResizeEdge::TopLeft => (true, false, true, false),
|
||||
ResizeEdge::BottomLeft => (false, true, true, false),
|
||||
ResizeEdge::Right => (false, false, false, true),
|
||||
ResizeEdge::TopRight => (true, false, false, true),
|
||||
ResizeEdge::BottomRight => (false, true, false, true),
|
||||
_ => (false, false, false, false),
|
||||
};
|
||||
let Some(panel_item) = get_data::<PanelItem<XdgBackend>>(&wl_surface) else {
|
||||
error!("Couldn't get the panel item");
|
||||
return;
|
||||
};
|
||||
panel_item.toplevel_resize_request(up, down, left, right)
|
||||
}
|
||||
xdg_toplevel::Request::SetMaxSize { width, height } => {
|
||||
debug!(?xdg_toplevel, width, height, "Set XDG Toplevel max size");
|
||||
*toplevel_data.max_size.lock() = (width > 1 || height > 1)
|
||||
.then_some(Vector2::from([width as u32, height as u32]));
|
||||
}
|
||||
xdg_toplevel::Request::SetMinSize { width, height } => {
|
||||
debug!(?xdg_toplevel, width, height, "Set XDG Toplevel min size");
|
||||
*toplevel_data.min_size.lock() = (width > 1 || height > 1)
|
||||
.then_some(Vector2::from([width as u32, height as u32]));
|
||||
}
|
||||
xdg_toplevel::Request::SetFullscreen { output: _ } => {
|
||||
let Some(panel_item) = get_data::<PanelItem<XdgBackend>>(&wl_surface) else {
|
||||
error!("Couldn't get the panel item");
|
||||
return;
|
||||
};
|
||||
panel_item.backend.toplevel_state.lock().fullscreen = true;
|
||||
panel_item.backend.configure(None);
|
||||
panel_item.toplevel_fullscreen_active(true);
|
||||
}
|
||||
xdg_toplevel::Request::UnsetFullscreen => {
|
||||
let Some(panel_item) = get_data::<PanelItem<XdgBackend>>(&wl_surface) else {
|
||||
error!("Couldn't get the panel item");
|
||||
return;
|
||||
};
|
||||
panel_item.backend.toplevel_state.lock().fullscreen = false;
|
||||
panel_item.backend.configure(None);
|
||||
panel_item.toplevel_fullscreen_active(false);
|
||||
}
|
||||
xdg_toplevel::Request::Destroy => {
|
||||
debug!(?xdg_toplevel, "Destroy XDG Toplevel");
|
||||
let Some(panel_item) = get_data::<PanelItem<XdgBackend>>(&wl_surface) else {
|
||||
error!("Couldn't get the panel item");
|
||||
return;
|
||||
};
|
||||
panel_item.backend.seat.drop_surface(&wl_surface);
|
||||
panel_item.drop_toplevel();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user