fix: wayland inconsistencies

This commit is contained in:
Nova
2025-01-25 14:02:03 -08:00
parent f3b9394c68
commit 4e99fcf6fc
5 changed files with 68 additions and 42 deletions

View File

@@ -8,18 +8,20 @@ use crate::{
wayland::surface::CoreSurface,
};
use parking_lot::Mutex;
use portable_atomic::{AtomicU32, Ordering};
use rand::Rng;
use smithay::{
backend::renderer::utils::{on_commit_buffer_handler, RendererSurfaceStateUserData},
delegate_compositor,
desktop::PopupKind,
reexports::wayland_server::{protocol::wl_surface::WlSurface, Client},
wayland::compositor::{
self, add_post_commit_hook, CompositorClientState, CompositorHandler, CompositorState,
add_post_commit_hook, CompositorClientState, CompositorHandler, CompositorState,
},
};
use std::sync::Arc;
use tracing::debug;
use tracing::{debug, warn};
pub struct ConfiguredSurface;
impl CompositorHandler for WaylandState {
fn compositor_state(&mut self) -> &mut CompositorState {
@@ -30,19 +32,27 @@ impl CompositorHandler for WaylandState {
debug!(?surface, "Surface commit");
on_commit_buffer_handler::<WaylandState>(surface);
let mut count = 0;
compositor::with_states(surface, |data| {
let count_new = data
.data_map
.insert_if_missing_threadsafe(|| AtomicU32::new(0));
if !count_new {
if let Some(stored_count) = data.data_map.get::<AtomicU32>() {
count = stored_count.fetch_add(1, Ordering::Relaxed);
}
}
data.data_map.get::<Arc<CoreSurface>>().cloned()
});
if let Some(toplevel) = self
.xdg_shell
.toplevel_surfaces()
.iter()
.find(|s| s.wl_surface() == surface)
{
if !toplevel.is_initial_configure_sent() {
debug!("Sending initial configure for toplevel surface");
toplevel.send_configure();
surface.insert_data(ConfiguredSurface);
}
}
self.popup_manager.commit(surface);
if let Some(PopupKind::Xdg(popup)) = self.popup_manager.find_popup(surface) {
if surface.insert_data(ConfiguredSurface) {
debug!("Configuring popup surface");
let _ = popup.send_configure();
}
}
}
fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState {
@@ -54,6 +64,7 @@ impl CompositorHandler for WaylandState {
surface.insert_data(SurfaceId::Child(id));
CoreSurface::add_to(surface);
let Some(parent_surface_id) = parent.get_data::<SurfaceId>() else {
warn!("Parent surface has no SurfaceId");
return;
};
surface.insert_data(Mutex::new(ChildInfo {
@@ -68,6 +79,7 @@ impl CompositorHandler for WaylandState {
}));
let Some(panel_item) = surface_panel_item(parent) else {
warn!("Parent has no panel item");
return;
};
let panel_item_weak = Arc::downgrade(&panel_item);
@@ -75,11 +87,19 @@ impl CompositorHandler for WaylandState {
if surface_panel_item(surf).is_some() {
return;
}
debug!("Linking surface to panel item");
surf.insert_data(panel_item_weak.clone());
let Some(panel_item) = surface_panel_item(surf) else {
warn!("Failed to link surface to panel item");
return;
};
surf.with_child_info(|_info| {
panel_item.backend.reposition_child(surf);
});
debug!("Adding new child to panel item");
panel_item.backend.new_child(surf);
});
@@ -88,6 +108,7 @@ impl CompositorHandler for WaylandState {
.get_data_raw::<RendererSurfaceStateUserData, _, _>(|s| s.lock().ok()?.view())
.flatten()
else {
debug!("No view data for surface");
return;
};
let mut changed = false;
@@ -96,11 +117,13 @@ impl CompositorHandler for WaylandState {
&& info.geometry.origin.y != view.offset.y
{
changed = true;
debug!("Surface position changed");
}
if info.geometry.size.x != view.dst.w as u32
&& info.geometry.size.y != view.dst.h as u32
{
changed = true;
debug!("Surface size changed");
}
info.geometry.size = [view.dst.w as u32, view.dst.h as u32].into();
});
@@ -109,6 +132,7 @@ impl CompositorHandler for WaylandState {
return;
};
if changed {
debug!("Repositioning child due to geometry change");
panel_item.backend.reposition_child(surf);
}
});
@@ -119,6 +143,7 @@ impl CompositorHandler for WaylandState {
return;
};
if surface.get_child_info().is_some() {
debug!("Dropping destroyed child surface");
panel_item.backend.drop_child(surface);
}
}

View File

@@ -225,7 +225,7 @@ impl SeatWrapper {
}
keyboard.input(
&mut state.lock(),
key,
key.into(),
if pressed {
KeyState::Pressed
} else {

View File

@@ -9,6 +9,7 @@ use smithay::{
renderer::gles::GlesRenderer,
},
delegate_dmabuf, delegate_output, delegate_shm,
desktop::PopupManager,
input::{keyboard::XkbConfig, SeatState},
output::{Mode, Output, Scale, Subpixel},
reexports::{
@@ -76,6 +77,7 @@ pub struct WaylandState {
pub seat_state: SeatState<Self>,
pub seat: Arc<SeatWrapper>,
pub xdg_shell: XdgShellState,
pub popup_manager: PopupManager,
pub output: Output,
}
@@ -158,6 +160,7 @@ impl WaylandState {
output.set_preferred(mode);
let mut xdg_shell = XdgShellState::new::<Self>(&display_handle);
let popup_manager = PopupManager::default();
let mut capabilities = WmCapabilitySet::default();
capabilities.set(WmCapabilities::Maximize);
capabilities.set(WmCapabilities::Fullscreen);
@@ -182,6 +185,7 @@ impl WaylandState {
seat_state,
seat: Arc::new(SeatWrapper::new(weak.clone(), seat)),
xdg_shell,
popup_manager,
output,
})
})

View File

@@ -20,6 +20,7 @@ use rand::Rng;
use rustc_hash::FxHashMap;
use smithay::{
delegate_xdg_shell,
desktop::PopupKind,
reexports::{
wayland_protocols::xdg::{
decoration::zv1::server::zxdg_toplevel_decoration_v1::Mode,
@@ -90,7 +91,6 @@ impl XdgShellHandler for WaylandState {
s.states.set(State::Maximized);
s.states.unset(State::Fullscreen);
});
toplevel.send_configure();
let initial_size = toplevel
.wl_surface()
@@ -225,14 +225,17 @@ impl XdgShellHandler for WaylandState {
};
panel_item.toplevel_title_changed(&title)
}
fn new_popup(&mut self, popup: PopupSurface, positioner: PositionerState) {
self.popup_manager
.track_popup(PopupKind::Xdg(popup.clone()))
.unwrap();
let id = rand::thread_rng().gen_range(0..u64::MAX);
popup.wl_surface().insert_data(SurfaceId::Child(id));
let Some(parent) = popup.get_parent_surface() else {
warn!("No parent surface found for popup");
return;
};
let _ = popup.send_configure();
CoreSurface::add_to(popup.wl_surface());
popup.wl_surface().insert_data(Mutex::new(ChildInfo {
@@ -244,6 +247,7 @@ impl XdgShellHandler for WaylandState {
}));
let Some(panel_item) = surface_panel_item(&parent) else {
warn!("No panel item found for popup parent");
return;
};
let panel_item_weak = Arc::downgrade(&panel_item);
@@ -255,6 +259,7 @@ impl XdgShellHandler for WaylandState {
}
surf.insert_data(panel_item_weak.clone());
let Some(panel) = surface_panel_item(surf) else {
warn!("Failed to get panel item for popup surface");
return;
};
panel.backend.new_child(surf);