Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git
fix(cce-server): scale resize deltas by desk_zoom to fix resizing choppiness
src/server/window.rs | 53 +++++++++++++++++++++++++++++++++++++++++++-
src/server/window_manager.rs | 17 ++++++++------
src/server/xdg_toplevel.rs | 2 +-
3 files changed, 63 insertions(+), 9 deletions(-)
diff --git a/src/server/window.rs b/src/server/window.rs
index 6480e47..2b90d4c 100644
--- a/src/server/window.rs
+++ b/src/server/window.rs
@@ -230,6 +230,11 @@ pub struct Window {
pub resize_start_h: u32,
pub resize_edges: Option<Edges>,
pub commit: ffi::wl_listener,
+ pub was_fullscreen: bool,
+ pub saved_width: i32,
+ pub saved_height: i32,
+ pub saved_virtual_x: f64,
+ pub saved_virtual_y: f64,
pub wm_scheduled: WmScheduledState,
pub wm_sent: WmSentState,
@@ -392,6 +397,11 @@ impl Window {
resize_start_h: 0,
resize_edges: None,
commit: std::mem::zeroed(),
+ was_fullscreen: false,
+ saved_width: 0,
+ saved_height: 0,
+ saved_virtual_x: 0.0,
+ saved_virtual_y: 0.0,
wm_scheduled: WmScheduledState {
dimensions_hint: DimensionsHint { min_width: 0, min_height: 0, max_width: 0, max_height: 0 },
decoration_hint: ffi::zcce_window_v1_decoration_hint_ZCCE_WINDOW_V1_DECORATION_HINT_ONLY_SUPPORTS_CSD,
@@ -735,13 +745,22 @@ impl Window {
Ok(())
}
+ pub unsafe fn set_closing(&mut self) {
+ if self.state != WindowState::Closing {
+ self.state = WindowState::Closing;
+ wl_list_remove(&mut self.node.link as *mut ffi::wl_list as *mut WlList);
+ self.node.link.prev = &mut self.node.link;
+ self.node.link.next = &mut self.node.link;
+ }
+ }
+
pub unsafe fn unmap(&mut self) {
log::debug!("window '{:?}' unmapped", self.get_title());
wl_listener_remove_safe(&mut self.commit);
self.surfaces.save();
assert!(!matches!(self.impl_type, WindowImpl::Destroying));
assert_eq!(self.state, WindowState::Mapped);
- self.state = WindowState::Closing;
+ self.set_closing();
(*self.server).wm.dirty_windowing();
if !self.foreign_toplevel_handle.is_null() {
@@ -1281,6 +1300,38 @@ impl Window {
std::ptr::null_mut()
};
+ let new_fullscreen = !output.is_null();
+ if new_fullscreen && !self.was_fullscreen {
+ if self.box_geom.width > 0 && self.box_geom.height > 0 {
+ self.saved_width = self.box_geom.width;
+ self.saved_height = self.box_geom.height;
+ self.saved_virtual_x = self.virtual_x;
+ self.saved_virtual_y = self.virtual_y;
+ self.was_fullscreen = true;
+ log::info!("[Fullscreen] Saved window {:?} geometry: {}x{} at ({}, {})", self.get_title_string().as_deref().unwrap_or(""), self.saved_width, self.saved_height, self.saved_virtual_x, self.saved_virtual_y);
+ }
+ } else if !new_fullscreen && self.was_fullscreen {
+ if self.saved_width > 0 && self.saved_height > 0 {
+ self.box_geom.width = self.saved_width;
+ self.box_geom.height = self.saved_height;
+ self.virtual_x = self.saved_virtual_x;
+ self.virtual_y = self.saved_virtual_y;
+ self.was_fullscreen = false;
+
+ self.wm_requested.dimensions = Some(crate::window::Dimensions {
+ width: self.saved_width as u32,
+ height: self.saved_height as u32,
+ });
+ self.wm_requested.bounds = crate::window::Dimensions {
+ width: self.saved_width as u32,
+ height: self.saved_height as u32,
+ };
+
+ (*self.server).wm.dirty_windowing();
+ log::info!("[Fullscreen] Restored window {:?} geometry: {}x{} at ({}, {})", self.get_title_string().as_deref().unwrap_or(""), self.saved_width, self.saved_height, self.saved_virtual_x, self.saved_virtual_y);
+ }
+ }
+
let (width, height) = if !output.is_null() {
let (w, h) = (*output).sent.dimensions();
if self.configure_sent.width != Some(w as u32) || self.configure_sent.height != Some(h as u32) {
diff --git a/src/server/window_manager.rs b/src/server/window_manager.rs
index 781f64f..c510d26 100644
--- a/src/server/window_manager.rs
+++ b/src/server/window_manager.rs
@@ -803,21 +803,24 @@ impl WindowManager {
if let Some(ref op) = (*seat).op {
if op.window_ptr == win_ptr {
if let crate::seat::PointerOpType::Resize { edges } = op.op_type {
+ let scale = self.desk_zoom;
let dx = op.x - op.start_x;
let dy = op.y - op.start_y;
+ let virtual_dx = dx as f64 / scale;
+ let virtual_dy = dy as f64 / scale;
let mut new_w = op.start_win_w;
let mut new_h = op.start_win_h;
if edges.left {
- new_w = std::cmp::max(50, op.start_win_w as i32 - dx) as u32;
+ new_w = std::cmp::max(50, (op.start_win_w as f64 - virtual_dx) as i32) as u32;
} else if edges.right {
- new_w = std::cmp::max(50, op.start_win_w as i32 + dx) as u32;
+ new_w = std::cmp::max(50, (op.start_win_w as f64 + virtual_dx) as i32) as u32;
}
if edges.top {
- new_h = std::cmp::max(50, op.start_win_h as i32 - dy) as u32;
+ new_h = std::cmp::max(50, (op.start_win_h as f64 - virtual_dy) as i32) as u32;
} else if edges.bottom {
- new_h = std::cmp::max(50, op.start_win_h as i32 + dy) as u32;
+ new_h = std::cmp::max(50, (op.start_win_h as f64 + virtual_dy) as i32) as u32;
}
return Some((new_w, new_h));
}
@@ -1985,7 +1988,7 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
// Try to match by numerical window index first
if let Ok(id) = query.parse::<u32>() {
for &w in self.windows.iter() {
- if !w.is_null() && !(*w).closed && (*w).ref_key.index == id {
+ if !w.is_null() && !(*w).closed && matches!((*w).state, crate::window::WindowState::Mapped) && (*w).ref_key.index == id {
best_target = w;
break;
}
@@ -1995,9 +1998,9 @@ fn get_closest_tag(x: f64, y: f64) -> i32 {
// Fallback to matching by app_id
if best_target.is_null() {
for &w in self.windows.iter() {
- if !w.is_null() && !(*w).closed {
+ if !w.is_null() && !(*w).closed && matches!((*w).state, crate::window::WindowState::Mapped) {
let aid = (*w).get_app_id_string();
-
+
let mut score = 0;
if let Some(ref aid_str) = aid {
let aid_lower = aid_str.to_lowercase();
diff --git a/src/server/xdg_toplevel.rs b/src/server/xdg_toplevel.rs
index 85b8236..7168ec9 100644
--- a/src/server/xdg_toplevel.rs
+++ b/src/server/xdg_toplevel.rs
@@ -350,7 +350,7 @@ unsafe extern "C" fn handle_destroy(listener: *mut ffi::wl_listener, _data: *mut
match (*window).state {
crate::window::WindowState::Init | crate::window::WindowState::Closing => {}
crate::window::WindowState::Ready | crate::window::WindowState::Initialized | crate::window::WindowState::Mapped => {
- (*window).state = crate::window::WindowState::Closing;
+ (*window).set_closing();
(*(*window).server).wm.dirty_windowing();
}
}