anvil.shell: update location on top-left resizing

This commit is contained in:
Ivan Molodetskikh 2020-02-08 08:46:15 +03:00
parent 09d7f597d4
commit adbab32bd8
No known key found for this signature in database
GPG Key ID: 02CE38DA47E9D691
1 changed files with 151 additions and 2 deletions

View File

@ -100,6 +100,7 @@ impl PointerGrab for MoveSurfaceGrab {
struct ResizeSurfaceGrab { struct ResizeSurfaceGrab {
start_data: GrabStartData, start_data: GrabStartData,
ctoken: MyCompositorToken,
toplevel: SurfaceKind<Roles>, toplevel: SurfaceKind<Roles>,
edges: wl_shell_surface::Resize, edges: wl_shell_surface::Resize,
initial_window_size: (i32, i32), initial_window_size: (i32, i32),
@ -174,6 +175,26 @@ impl PointerGrab for ResizeSurfaceGrab {
states: vec![], states: vec![],
serial, serial,
}); });
self.ctoken
.with_surface_data(self.toplevel.get_surface().unwrap(), |attrs| {
let data = attrs.user_data.get_mut::<SurfaceData>().unwrap();
if let ResizeState::Resizing(resize_data) = data.resize_state {
data.resize_state = ResizeState::WaitingForFinalAck(resize_data, serial);
} else {
panic!("invalid resize state: {:?}", data.resize_state);
}
});
} else {
self.ctoken
.with_surface_data(self.toplevel.get_surface().unwrap(), |attrs| {
let data = attrs.user_data.get_mut::<SurfaceData>().unwrap();
if let ResizeState::Resizing(resize_data) = data.resize_state {
data.resize_state = ResizeState::WaitingForCommit(resize_data);
} else {
panic!("invalid resize state: {:?}", data.resize_state);
}
});
} }
} }
} }
@ -319,7 +340,7 @@ pub fn init_shell(
return; return;
} }
let toplevel = SurfaceKind::Xdg(surface); let toplevel = SurfaceKind::Xdg(surface.clone());
let initial_window_location = xdg_window_map.borrow().location(&toplevel).unwrap(); let initial_window_location = xdg_window_map.borrow().location(&toplevel).unwrap();
let geometry = xdg_window_map.borrow().geometry(&toplevel).unwrap(); let geometry = xdg_window_map.borrow().geometry(&toplevel).unwrap();
let initial_window_size = (geometry.width, geometry.height); let initial_window_size = (geometry.width, geometry.height);
@ -336,8 +357,18 @@ pub fn init_shell(
_ => return, _ => return,
}; };
compositor_token.with_surface_data(surface.get_surface().unwrap(), move |attrs| {
attrs.user_data.get_mut::<SurfaceData>().unwrap().resize_state =
ResizeState::Resizing(ResizeData {
edges,
initial_window_location,
initial_window_size,
});
});
let grab = ResizeSurfaceGrab { let grab = ResizeSurfaceGrab {
start_data, start_data,
ctoken: compositor_token,
toplevel, toplevel,
edges, edges,
initial_window_size, initial_window_size,
@ -346,6 +377,36 @@ pub fn init_shell(
pointer.set_grab(grab, serial); pointer.set_grab(grab, serial);
} }
XdgRequest::AckConfigure { surface, .. } => {
let waiting_for_serial = compositor_token.with_surface_data(&surface, |attrs| {
if let Some(data) = attrs.user_data.get_mut::<SurfaceData>() {
if let ResizeState::WaitingForFinalAck(_, serial) = data.resize_state {
return Some(serial);
}
}
None
});
if let Some(serial) = waiting_for_serial {
let acked = compositor_token
.with_role_data(&surface, |role: &mut XdgSurfaceRole| {
!role.pending_configures.contains(&serial)
})
.unwrap();
if acked {
compositor_token.with_surface_data(&surface, |attrs| {
let data = attrs.user_data.get_mut::<SurfaceData>().unwrap();
if let ResizeState::WaitingForFinalAck(resize_data, _) = data.resize_state {
data.resize_state = ResizeState::WaitingForCommit(resize_data);
} else {
unreachable!()
}
})
}
}
}
_ => (), _ => (),
}, },
log.clone(), log.clone(),
@ -444,13 +505,23 @@ pub fn init_shell(
return; return;
} }
let toplevel = SurfaceKind::Wl(surface); let toplevel = SurfaceKind::Wl(surface.clone());
let initial_window_location = shell_window_map.borrow().location(&toplevel).unwrap(); let initial_window_location = shell_window_map.borrow().location(&toplevel).unwrap();
let geometry = shell_window_map.borrow().geometry(&toplevel).unwrap(); let geometry = shell_window_map.borrow().geometry(&toplevel).unwrap();
let initial_window_size = (geometry.width, geometry.height); let initial_window_size = (geometry.width, geometry.height);
compositor_token.with_surface_data(surface.get_surface().unwrap(), move |attrs| {
attrs.user_data.get_mut::<SurfaceData>().unwrap().resize_state =
ResizeState::Resizing(ResizeData {
edges,
initial_window_location,
initial_window_size,
});
});
let grab = ResizeSurfaceGrab { let grab = ResizeSurfaceGrab {
start_data, start_data,
ctoken: compositor_token,
toplevel, toplevel,
edges, edges,
initial_window_size, initial_window_size,
@ -468,6 +539,36 @@ pub fn init_shell(
(compositor_token, xdg_shell_state, wl_shell_state, window_map) (compositor_token, xdg_shell_state, wl_shell_state, window_map)
} }
/// Information about the resize operation.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub struct ResizeData {
/// The edges the surface is being resized with.
edges: wl_shell_surface::Resize,
/// The initial window location.
initial_window_location: (i32, i32),
/// The initial window size (geometry width and height).
initial_window_size: (i32, i32),
}
/// State of the resize operation.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum ResizeState {
/// The surface is not being resized.
NotResizing,
/// The surface is currently being resized.
Resizing(ResizeData),
/// The resize has finished, and the surface needs to ack the final configure.
WaitingForFinalAck(ResizeData, u32),
/// The resize has finished, and the surface needs to commit its final state.
WaitingForCommit(ResizeData),
}
impl Default for ResizeState {
fn default() -> Self {
ResizeState::NotResizing
}
}
#[derive(Default)] #[derive(Default)]
pub struct SurfaceData { pub struct SurfaceData {
pub buffer: Option<wl_buffer::WlBuffer>, pub buffer: Option<wl_buffer::WlBuffer>,
@ -475,6 +576,7 @@ pub struct SurfaceData {
pub dimensions: Option<(i32, i32)>, pub dimensions: Option<(i32, i32)>,
pub geometry: Option<Rectangle>, pub geometry: Option<Rectangle>,
pub input_region: Option<RegionAttributes>, pub input_region: Option<RegionAttributes>,
pub resize_state: ResizeState,
} }
impl SurfaceData { impl SurfaceData {
@ -560,5 +662,52 @@ fn surface_commit(
if let Some(toplevel) = refresh { if let Some(toplevel) = refresh {
let mut window_map = window_map.borrow_mut(); let mut window_map = window_map.borrow_mut();
window_map.refresh_toplevel(&toplevel); window_map.refresh_toplevel(&toplevel);
// Get the geometry outside since it uses the token, and so would block inside.
let Rectangle { width, height, .. } = window_map.geometry(&toplevel).unwrap();
let new_location = token.with_surface_data(surface, |attributes| {
let data = attributes.user_data.get_mut::<SurfaceData>().unwrap();
let mut new_location = None;
// If the window is being resized by top or left, its location must be adjusted
// accordingly.
match data.resize_state {
ResizeState::Resizing(resize_data)
| ResizeState::WaitingForFinalAck(resize_data, _)
| ResizeState::WaitingForCommit(resize_data) => {
let ResizeData {
edges,
initial_window_location,
initial_window_size,
} = resize_data;
if edges.intersects(wl_shell_surface::Resize::TopLeft) {
let mut location = window_map.location(&toplevel).unwrap();
if edges.intersects(wl_shell_surface::Resize::Left) {
location.0 = initial_window_location.0 + (initial_window_size.0 - width);
}
if edges.intersects(wl_shell_surface::Resize::Top) {
location.1 = initial_window_location.1 + (initial_window_size.1 - height);
}
new_location = Some(location);
}
}
ResizeState::NotResizing => (),
}
// Finish resizing.
if let ResizeState::WaitingForCommit(_) = data.resize_state {
data.resize_state = ResizeState::NotResizing;
}
new_location
});
if let Some(location) = new_location {
window_map.set_location(&toplevel, location);
}
} }
} }