Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overhaul resizing #1153

Merged
merged 7 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/shell/element/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,14 @@ impl CosmicMapped {
}
}

pub fn latest_size_committed(&self) -> bool {
match &self.element {
CosmicMappedInternal::Stack(s) => s.surfaces().any(|s| s.latest_size_committed()),
CosmicMappedInternal::Window(w) => w.surface().latest_size_committed(),
_ => unreachable!(),
}
}

pub fn configure(&self) -> Option<Serial> {
match &self.element {
CosmicMappedInternal::Stack(s) => {
Expand Down
55 changes: 55 additions & 0 deletions src/shell/element/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ use smithay::{
},
xwayland::{xwm::X11Relatable, X11Surface},
};
use tracing::trace;

use crate::{
state::{State, SurfaceDmabufFeedback},
Expand Down Expand Up @@ -499,6 +500,60 @@ impl CosmicSurface {
}
}

pub fn serial_past(&self, serial: &Serial) -> bool {
match self.0.underlying_surface() {
WindowSurface::Wayland(toplevel) => with_states(toplevel.wl_surface(), |states| {
let attrs = states
.data_map
.get::<XdgToplevelSurfaceData>()
.unwrap()
.lock()
.unwrap();
attrs
.current_serial
.as_ref()
.map(|s| s >= serial)
.unwrap_or(false)
}),
WindowSurface::X11(_surface) => true,
}
}

pub fn latest_size_committed(&self) -> bool {
match self.0.underlying_surface() {
WindowSurface::Wayland(toplevel) => {
with_states(toplevel.wl_surface(), |states| {
let attributes = states
.data_map
.get::<XdgToplevelSurfaceData>()
.unwrap()
.lock()
.unwrap();

let current_server = attributes.current_server_state();
if attributes.current.size == current_server.size {
// The window had committed for our previous size change, so we can
// change the size again.
trace!(
"current size matches server size: {:?}",
attributes.current.size
);
true
} else {
// The window had not committed for our previous size change yet.
// This throttling is done because some clients do not batch size requests,
// leading to bad behavior with very fast input devices (i.e. a 1000 Hz
// mouse). This throttling also helps interactive resize transactions
// preserve visual consistency.
trace!("throttling resize");
false
}
})
}
WindowSurface::X11(_) => true,
}
}

pub fn force_configure(&self) -> Option<Serial> {
match self.0.underlying_surface() {
WindowSurface::Wayland(toplevel) => Some(toplevel.send_configure()),
Expand Down
28 changes: 11 additions & 17 deletions src/shell/layout/floating/grabs/resize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use smithay::{
},
Seat,
},
output::Output,
utils::{IsAlive, Logical, Point, Rectangle, Serial, Size},
};

Expand Down Expand Up @@ -56,6 +57,7 @@ pub struct ResizeSurfaceGrab {
seat: Seat<State>,
window: CosmicMapped,
edges: ResizeEdge,
output: Output,
initial_window_size: Size<i32, Logical>,
last_window_size: Size<i32, Logical>,
release: ReleaseMode,
Expand Down Expand Up @@ -111,16 +113,14 @@ impl ResizeSurfaceGrab {

self.last_window_size = (new_window_width, new_window_height).into();

let mut win_loc = location.as_local().to_global(&self.output).to_i32_round();
win_loc.y += self.window.ssd_height(false).unwrap_or(0);
self.window.set_resizing(true);
self.window.set_geometry(Rectangle::new(
if let Some(s) = self.window.active_window().x11_surface() {
s.geometry().loc.as_global()
} else {
(0, 0).into()
},
self.last_window_size.as_global(),
));
self.window.configure();
self.window
.set_geometry(Rectangle::new(win_loc, self.last_window_size.as_global()));
if self.window.latest_size_committed() {
self.window.configure();
}

false
}
Expand Down Expand Up @@ -374,6 +374,7 @@ impl ResizeSurfaceGrab {
start_data: GrabStartData,
mapped: CosmicMapped,
edges: ResizeEdge,
output: Output,
initial_window_location: Point<i32, Local>,
initial_window_size: Size<i32, Logical>,
seat: &Seat<State>,
Expand Down Expand Up @@ -412,6 +413,7 @@ impl ResizeSurfaceGrab {
seat: seat.clone(),
window: mapped,
edges,
output,
initial_window_size,
last_window_size: initial_window_size,
release,
Expand Down Expand Up @@ -523,14 +525,6 @@ impl ResizeSurfaceGrab {
}

self.window.set_resizing(false);
self.window.set_geometry(Rectangle::new(
if let Some(x11_surface) = self.window.active_window().x11_surface() {
x11_surface.geometry().loc.as_global()
} else {
(0, 0).into()
},
self.last_window_size.as_global(),
));
self.window.configure();

let mut resize_state = self.window.resize_state.lock().unwrap();
Expand Down
5 changes: 4 additions & 1 deletion src/shell/layout/floating/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,7 @@ impl FloatingLayout {
start_data,
mapped.clone(),
edges,
self.space.outputs().next().cloned().unwrap(),
location,
size,
seat,
Expand Down Expand Up @@ -990,7 +991,9 @@ impl FloatingLayout {
geo.as_local()
.to_global(self.space.outputs().next().unwrap()),
);
mapped.configure();
if mapped.latest_size_committed() {
mapped.configure();
}

true
}
Expand Down
24 changes: 8 additions & 16 deletions src/shell/layout/tiling/blocker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,18 @@ use smithay::{
};
use std::{
collections::HashMap,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
time::{Duration, Instant},
};

#[derive(Debug, Clone)]
pub struct TilingBlocker {
pub necessary_acks: Vec<(CosmicSurface, Serial)>,
ready: Arc<AtomicBool>,
signaled: Arc<AtomicBool>,
start: Instant,
}

impl Blocker for TilingBlocker {
fn state(&self) -> BlockerState {
self.signaled.store(true, Ordering::SeqCst);
if self.ready.load(Ordering::SeqCst) {
if self.is_ready() {
BlockerState::Released
} else {
BlockerState::Pending
Expand All @@ -39,8 +32,6 @@ impl TilingBlocker {
pub fn new(configures: impl IntoIterator<Item = (CosmicSurface, Serial)>) -> Self {
TilingBlocker {
necessary_acks: configures.into_iter().collect(),
ready: Arc::new(AtomicBool::new(false)),
signaled: Arc::new(AtomicBool::new(false)),
start: Instant::now(),
}
}
Expand All @@ -53,14 +44,15 @@ impl TilingBlocker {
.all(|(surf, serial)| !surf.alive() || surf.serial_acked(serial))
}

pub fn is_signaled(&self) -> bool {
self.signaled.load(Ordering::SeqCst)
|| !self.necessary_acks.iter().any(|(surf, _)| surf.alive())
pub fn is_processed(&self) -> bool {
Instant::now().duration_since(self.start) >= Duration::from_millis(500)
|| self
.necessary_acks
.iter()
.all(|(surf, serial)| !surf.alive() || surf.serial_past(serial))
}

#[must_use]
pub fn signal_ready(&self) -> HashMap<ClientId, Client> {
self.ready.swap(true, Ordering::SeqCst);
pub fn clients(&self) -> HashMap<ClientId, Client> {
self.necessary_acks
.iter()
.flat_map(|(surface, _)| surface.wl_surface().and_then(|s| s.client()))
Expand Down
43 changes: 33 additions & 10 deletions src/shell/layout/tiling/grabs/resize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,14 @@ impl ResizeForkGrab {

impl ResizeForkGrab {
// Returns `true` if grab should be unset
fn update_location(&mut self, data: &mut State, location: Point<f64, Logical>) -> bool {
fn update_location(
&mut self,
data: &mut State,
location: Point<f64, Logical>,
force: bool,
) -> bool {
let delta = location - self.last_loc.as_logical();
self.last_loc = location.as_global();

if let Some(output) = self.output.upgrade() {
let mut shell = data.common.shell.write().unwrap();
Expand All @@ -228,7 +234,7 @@ impl ResizeForkGrab {
let tiling_layer = &mut workspace.tiling_layer;
let gaps = tiling_layer.gaps();

let tree = &mut tiling_layer.queue.trees.back_mut().unwrap().0;
let mut tree = tiling_layer.queue.trees.back().unwrap().0.copy_clone();
match &mut self.old_tree {
Some(old_tree) => {
// it would be so nice to just `zip` here, but `zip` just returns `None` once either returns `None`.
Expand Down Expand Up @@ -258,7 +264,7 @@ impl ResizeForkGrab {
*old_tree = tree.copy_clone();
self.accumulated_delta = 0.0;
} else {
*tree = old_tree.copy_clone();
tree = old_tree.copy_clone();
}
}
x @ None => {
Expand All @@ -284,6 +290,10 @@ impl ResizeForkGrab {
return true;
};

if self.accumulated_delta.round() as i32 == 0 {
return false;
}

match tree.get_mut(&self.node).unwrap().data_mut() {
Data::Group {
sizes, orientation, ..
Expand Down Expand Up @@ -319,9 +329,18 @@ impl ResizeForkGrab {
_ => unreachable!(),
}

self.last_loc = location.as_global();
let blocker = TilingLayout::update_positions(&output, tree, gaps);
tiling_layer.pending_blockers.extend(blocker);
let should_configure = force
|| tree
.traverse_pre_order(&self.node)
.unwrap()
.all(|node| match node.data() {
Data::Mapped { mapped, .. } => mapped.latest_size_committed(),
_ => true,
});
if should_configure {
let blocker = TilingLayout::update_positions(&output, &mut tree, gaps);
tiling_layer.queue.push_tree(tree, None, blocker);
}
} else {
return true;
}
Expand All @@ -348,7 +367,7 @@ impl PointerGrab<State> for ResizeForkGrab {
// While the grab is active, no client has pointer focus
handle.motion(data, None, event);

if self.update_location(data, event.location) {
if self.update_location(data, event.location, false) {
handle.unset_grab(self, data, event.serial, event.time, true);
}
}
Expand Down Expand Up @@ -477,7 +496,9 @@ impl PointerGrab<State> for ResizeForkGrab {
}
}

fn unset(&mut self, _data: &mut State) {}
fn unset(&mut self, data: &mut State) {
self.update_location(data, self.last_loc.as_logical(), true);
}
}

impl TouchGrab<State> for ResizeForkGrab {
Expand Down Expand Up @@ -515,7 +536,7 @@ impl TouchGrab<State> for ResizeForkGrab {
seq: Serial,
) {
if event.slot == <Self as TouchGrab<State>>::start_data(self).slot {
if self.update_location(data, event.location) {
if self.update_location(data, event.location, false) {
handle.unset_grab(self, data);
}
}
Expand Down Expand Up @@ -558,5 +579,7 @@ impl TouchGrab<State> for ResizeForkGrab {
handle.orientation(data, event, seq)
}

fn unset(&mut self, _data: &mut State) {}
fn unset(&mut self, data: &mut State) {
self.update_location(data, self.last_loc.as_logical(), true);
}
}
Loading
Loading