Merge pull request #153 from YaLTeR/move

Implement the Move request
This commit is contained in:
Victor Berger 2020-02-03 14:53:06 +01:00 committed by GitHub
commit 719295931b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 254 additions and 33 deletions

View File

@ -8,14 +8,14 @@ use rand;
use smithay::{ use smithay::{
reexports::wayland_server::{ reexports::wayland_server::{
protocol::{wl_buffer, wl_shell_surface, wl_surface}, protocol::{wl_buffer, wl_pointer::ButtonState, wl_shell_surface, wl_surface},
Display, Display,
}, },
utils::Rectangle, utils::Rectangle,
wayland::{ wayland::{
compositor::{compositor_init, CompositorToken, RegionAttributes, SurfaceAttributes, SurfaceEvent}, compositor::{compositor_init, CompositorToken, RegionAttributes, SurfaceAttributes, SurfaceEvent},
data_device::DnDIconRole, data_device::DnDIconRole,
seat::CursorImageRole, seat::{AxisFrame, CursorImageRole, GrabStartData, PointerGrab, PointerInnerHandle, Seat},
shell::{ shell::{
legacy::{ legacy::{
wl_shell_init, ShellRequest, ShellState as WlShellState, ShellSurfaceKind, ShellSurfaceRole, wl_shell_init, ShellRequest, ShellState as WlShellState, ShellSurfaceKind, ShellSurfaceRole,
@ -25,6 +25,7 @@ use smithay::{
XdgSurfaceRole, XdgSurfaceRole,
}, },
}, },
SERIAL_COUNTER as SCOUNTER,
}, },
}; };
@ -45,6 +46,56 @@ pub type MyWindowMap = WindowMap<
pub type MyCompositorToken = CompositorToken<Roles>; pub type MyCompositorToken = CompositorToken<Roles>;
struct MoveSurfaceGrab {
start_data: GrabStartData,
window_map: Rc<RefCell<MyWindowMap>>,
toplevel: SurfaceKind<Roles>,
initial_window_location: (i32, i32),
}
impl PointerGrab for MoveSurfaceGrab {
fn motion(
&mut self,
_handle: &mut PointerInnerHandle<'_>,
location: (f64, f64),
_focus: Option<(wl_surface::WlSurface, (f64, f64))>,
_serial: u32,
_time: u32,
) {
let dx = location.0 - self.start_data.location.0;
let dy = location.1 - self.start_data.location.1;
let new_window_x = (self.initial_window_location.0 as f64 + dx) as i32;
let new_window_y = (self.initial_window_location.1 as f64 + dy) as i32;
self.window_map
.borrow_mut()
.set_location(&self.toplevel, (new_window_x, new_window_y));
}
fn button(
&mut self,
handle: &mut PointerInnerHandle<'_>,
button: u32,
state: ButtonState,
serial: u32,
time: u32,
) {
handle.button(button, state, serial, time);
if handle.current_pressed().is_empty() {
// No more buttons are pressed, release the grab.
handle.unset_grab(serial, time);
}
}
fn axis(&mut self, handle: &mut PointerInnerHandle<'_>, details: AxisFrame) {
handle.axis(details)
}
fn start_data(&self) -> &GrabStartData {
&self.start_data
}
}
pub fn init_shell( pub fn init_shell(
display: &mut Display, display: &mut Display,
log: ::slog::Logger, log: ::slog::Logger,
@ -100,6 +151,47 @@ pub fn init_shell(
position: (10, 10), position: (10, 10),
serial: 42, serial: 42,
}), }),
XdgRequest::Move {
surface,
seat,
serial,
} => {
let seat = Seat::from_resource(&seat).unwrap();
// TODO: touch move.
let pointer = seat.get_pointer().unwrap();
// Check that this surface has a click grab.
if !pointer.has_grab(serial) {
return;
}
let start_data = pointer.grab_start_data().unwrap();
// If the focus was for a different surface, ignore the request.
if start_data.focus.is_none()
|| !start_data
.focus
.as_ref()
.unwrap()
.0
.as_ref()
.same_client_as(surface.get_surface().unwrap().as_ref())
{
return;
}
let toplevel = SurfaceKind::Xdg(surface);
let initial_window_location = xdg_window_map.borrow().location(&toplevel).unwrap();
let grab = MoveSurfaceGrab {
start_data,
window_map: xdg_window_map.clone(),
toplevel,
initial_window_location,
};
pointer.set_grab(grab, serial);
}
_ => (), _ => (),
}, },
log.clone(), log.clone(),
@ -111,11 +203,11 @@ pub fn init_shell(
display, display,
compositor_token, compositor_token,
move |req: ShellRequest<_>| { move |req: ShellRequest<_>| {
if let ShellRequest::SetKind { match req {
ShellRequest::SetKind {
surface, surface,
kind: ShellSurfaceKind::Toplevel, kind: ShellSurfaceKind::Toplevel,
} = req } => {
{
// place the window at a random location in the [0;800]x[0;800] square // place the window at a random location in the [0;800]x[0;800] square
use rand::distributions::{Distribution, Uniform}; use rand::distributions::{Distribution, Uniform};
let range = Uniform::new(0, 800); let range = Uniform::new(0, 800);
@ -127,6 +219,49 @@ pub fn init_shell(
.borrow_mut() .borrow_mut()
.insert(SurfaceKind::Wl(surface), (x, y)); .insert(SurfaceKind::Wl(surface), (x, y));
} }
ShellRequest::Move {
surface,
seat,
serial,
} => {
let seat = Seat::from_resource(&seat).unwrap();
// TODO: touch move.
let pointer = seat.get_pointer().unwrap();
// Check that this surface has a click grab.
if !pointer.has_grab(serial) {
return;
}
let start_data = pointer.grab_start_data().unwrap();
// If the focus was for a different surface, ignore the request.
if start_data.focus.is_none()
|| !start_data
.focus
.as_ref()
.unwrap()
.0
.as_ref()
.same_client_as(surface.get_surface().unwrap().as_ref())
{
return;
}
let toplevel = SurfaceKind::Wl(surface);
let initial_window_location = shell_window_map.borrow().location(&toplevel).unwrap();
let grab = MoveSurfaceGrab {
start_data,
window_map: shell_window_map.clone(),
toplevel,
initial_window_location,
};
pointer.set_grab(grab, serial);
}
_ => (),
}
}, },
log.clone(), log.clone(),
); );

View File

@ -33,6 +33,15 @@ where
Kind::Wl(ref t) => t.get_surface(), Kind::Wl(ref t) => t.get_surface(),
} }
} }
/// Do this handle and the other one actually refer to the same toplevel surface?
pub fn equals(&self, other: &Self) -> bool {
match (self, other) {
(Kind::Xdg(a), Kind::Xdg(b)) => a.equals(b),
(Kind::Wl(a), Kind::Wl(b)) => a.equals(b),
_ => false,
}
}
} }
struct Window<R> { struct Window<R> {
@ -225,4 +234,20 @@ where
pub fn clear(&mut self) { pub fn clear(&mut self) {
self.windows.clear(); self.windows.clear();
} }
/// Returns the location of the toplevel, if it exists.
pub fn location(&self, toplevel: &Kind<R>) -> Option<(i32, i32)> {
self.windows
.iter()
.find(|w| w.toplevel.equals(toplevel))
.map(|w| w.location)
}
/// Sets the location of the toplevel, if it exists.
pub fn set_location(&mut self, toplevel: &Kind<R>, location: (i32, i32)) {
if let Some(w) = self.windows.iter_mut().find(|w| w.toplevel.equals(toplevel)) {
w.location = location;
w.self_update(self.ctoken, &self.get_size);
}
}
} }

View File

@ -8,12 +8,13 @@ use wayland_server::{
use crate::wayland::{ use crate::wayland::{
compositor::{roles::Role, CompositorToken}, compositor::{roles::Role, CompositorToken},
seat::{AxisFrame, PointerGrab, PointerInnerHandle, Seat}, seat::{AxisFrame, GrabStartData, PointerGrab, PointerInnerHandle, Seat},
}; };
use super::{with_source_metadata, DataDeviceData, DnDIconRole, SeatData}; use super::{with_source_metadata, DataDeviceData, DnDIconRole, SeatData};
pub(crate) struct DnDGrab<R> { pub(crate) struct DnDGrab<R> {
start_data: GrabStartData,
data_source: Option<wl_data_source::WlDataSource>, data_source: Option<wl_data_source::WlDataSource>,
current_focus: Option<wl_surface::WlSurface>, current_focus: Option<wl_surface::WlSurface>,
pending_offers: Vec<wl_data_offer::WlDataOffer>, pending_offers: Vec<wl_data_offer::WlDataOffer>,
@ -27,6 +28,7 @@ pub(crate) struct DnDGrab<R> {
impl<R: Role<DnDIconRole> + 'static> DnDGrab<R> { impl<R: Role<DnDIconRole> + 'static> DnDGrab<R> {
pub(crate) fn new( pub(crate) fn new(
start_data: GrabStartData,
source: Option<wl_data_source::WlDataSource>, source: Option<wl_data_source::WlDataSource>,
origin: wl_surface::WlSurface, origin: wl_surface::WlSurface,
seat: Seat, seat: Seat,
@ -35,6 +37,7 @@ impl<R: Role<DnDIconRole> + 'static> DnDGrab<R> {
callback: Rc<RefCell<dyn FnMut(super::DataDeviceEvent)>>, callback: Rc<RefCell<dyn FnMut(super::DataDeviceEvent)>>,
) -> DnDGrab<R> { ) -> DnDGrab<R> {
DnDGrab { DnDGrab {
start_data,
data_source: source, data_source: source,
current_focus: None, current_focus: None,
pending_offers: Vec::with_capacity(1), pending_offers: Vec::with_capacity(1),
@ -222,6 +225,10 @@ impl<R: Role<DnDIconRole> + 'static> PointerGrab for DnDGrab<R> {
// we just forward the axis events as is // we just forward the axis events as is
handle.axis(details); handle.axis(details);
} }
fn start_data(&self) -> &GrabStartData {
&self.start_data
}
} }
struct OfferData { struct OfferData {

View File

@ -69,7 +69,7 @@ use wayland_server::{
use crate::wayland::{ use crate::wayland::{
compositor::{roles::Role, CompositorToken}, compositor::{roles::Role, CompositorToken},
seat::Seat, seat::{GrabStartData, Seat},
}; };
mod data_source; mod data_source;
@ -354,8 +354,13 @@ pub fn set_data_device_selection(seat: &Seat, mime_types: Vec<String>) {
/// You'll receive events generated by the interaction of clients with your /// You'll receive events generated by the interaction of clients with your
/// drag'n'drop in the provided callback. See [`ServerDndEvent`] for details about /// drag'n'drop in the provided callback. See [`ServerDndEvent`] for details about
/// which events can be generated and what response is expected from you to them. /// which events can be generated and what response is expected from you to them.
pub fn start_dnd<C>(seat: &Seat, serial: u32, metadata: SourceMetadata, callback: C) pub fn start_dnd<C>(
where seat: &Seat,
serial: u32,
start_data: GrabStartData,
metadata: SourceMetadata,
callback: C,
) where
C: FnMut(ServerDndEvent) + 'static, C: FnMut(ServerDndEvent) + 'static,
{ {
// TODO: same question as in set_data_device_focus // TODO: same question as in set_data_device_focus
@ -366,7 +371,12 @@ where
}); });
if let Some(pointer) = seat.get_pointer() { if let Some(pointer) = seat.get_pointer() {
pointer.set_grab( pointer.set_grab(
server_dnd_grab::ServerDnDGrab::new(metadata, seat.clone(), Rc::new(RefCell::new(callback))), server_dnd_grab::ServerDnDGrab::new(
start_data,
metadata,
seat.clone(),
Rc::new(RefCell::new(callback)),
),
serial, serial,
); );
return; return;
@ -466,8 +476,10 @@ where
source: source.clone(), source: source.clone(),
icon: icon.clone(), icon: icon.clone(),
}); });
let start_data = pointer.grab_start_data().unwrap();
pointer.set_grab( pointer.set_grab(
dnd_grab::DnDGrab::new( dnd_grab::DnDGrab::new(
start_data,
source, source,
origin, origin,
seat.clone(), seat.clone(),

View File

@ -7,7 +7,7 @@ use wayland_server::{
NewResource, NewResource,
}; };
use crate::wayland::seat::{AxisFrame, PointerGrab, PointerInnerHandle, Seat}; use crate::wayland::seat::{AxisFrame, GrabStartData, PointerGrab, PointerInnerHandle, Seat};
use super::{DataDeviceData, SeatData}; use super::{DataDeviceData, SeatData};
@ -37,6 +37,7 @@ pub enum ServerDndEvent {
} }
pub(crate) struct ServerDnDGrab<C: 'static> { pub(crate) struct ServerDnDGrab<C: 'static> {
start_data: GrabStartData,
metadata: super::SourceMetadata, metadata: super::SourceMetadata,
current_focus: Option<wl_surface::WlSurface>, current_focus: Option<wl_surface::WlSurface>,
pending_offers: Vec<wl_data_offer::WlDataOffer>, pending_offers: Vec<wl_data_offer::WlDataOffer>,
@ -47,11 +48,13 @@ pub(crate) struct ServerDnDGrab<C: 'static> {
impl<C: 'static> ServerDnDGrab<C> { impl<C: 'static> ServerDnDGrab<C> {
pub(crate) fn new( pub(crate) fn new(
start_data: GrabStartData,
metadata: super::SourceMetadata, metadata: super::SourceMetadata,
seat: Seat, seat: Seat,
callback: Rc<RefCell<C>>, callback: Rc<RefCell<C>>,
) -> ServerDnDGrab<C> { ) -> ServerDnDGrab<C> {
ServerDnDGrab { ServerDnDGrab {
start_data,
metadata, metadata,
current_focus: None, current_focus: None,
pending_offers: Vec::with_capacity(1), pending_offers: Vec::with_capacity(1),
@ -212,6 +215,10 @@ where
// we just forward the axis events as is // we just forward the axis events as is
handle.axis(details); handle.axis(details);
} }
fn start_data(&self) -> &GrabStartData {
&self.start_data
}
} }
struct OfferData { struct OfferData {

View File

@ -49,7 +49,8 @@ mod pointer;
pub use self::{ pub use self::{
keyboard::{keysyms, Error as KeyboardError, KeyboardHandle, Keysym, ModifiersState, XkbConfig}, keyboard::{keysyms, Error as KeyboardError, KeyboardHandle, Keysym, ModifiersState, XkbConfig},
pointer::{ pointer::{
AxisFrame, CursorImageRole, CursorImageStatus, PointerGrab, PointerHandle, PointerInnerHandle, AxisFrame, CursorImageRole, CursorImageStatus, GrabStartData, PointerGrab, PointerHandle,
PointerInnerHandle,
}, },
}; };

View File

@ -166,6 +166,15 @@ impl PointerHandle {
} }
} }
/// Returns the start data for the grab, if any.
pub fn grab_start_data(&self) -> Option<GrabStartData> {
let guard = self.inner.borrow();
match &guard.grab {
GrabStatus::Active(_, g) => Some(g.start_data().clone()),
_ => None,
}
}
/// Notify that the pointer moved /// Notify that the pointer moved
/// ///
/// You provide the new location of the pointer, in the form of: /// You provide the new location of the pointer, in the form of:
@ -219,6 +228,24 @@ impl PointerHandle {
grab.axis(&mut handle, details); grab.axis(&mut handle, details);
}); });
} }
/// Access the current location of this pointer in the global space
pub fn current_location(&self) -> (f64, f64) {
self.inner.borrow().location
}
}
/// Data about the event that started the grab.
#[derive(Clone)]
pub struct GrabStartData {
/// The focused surface and its location, if any, at the start of the grab.
///
/// The location coordinates are in the global compositor space.
pub focus: Option<(WlSurface, (f64, f64))>,
/// The button that initiated the grab.
pub button: u32,
/// The location of the click that initiated the grab, in the global compositor space.
pub location: (f64, f64),
} }
/// A trait to implement a pointer grab /// A trait to implement a pointer grab
@ -257,6 +284,8 @@ pub trait PointerGrab {
); );
/// An axis scroll was reported /// An axis scroll was reported
fn axis(&mut self, handle: &mut PointerInnerHandle<'_>, details: AxisFrame); fn axis(&mut self, handle: &mut PointerInnerHandle<'_>, details: AxisFrame);
/// The data about the event that started the grab.
fn start_data(&self) -> &GrabStartData;
} }
/// This inner handle is accessed from inside a pointer grab logic, and directly /// This inner handle is accessed from inside a pointer grab logic, and directly
@ -626,18 +655,23 @@ impl PointerGrab for DefaultGrab {
time: u32, time: u32,
) { ) {
handle.button(button, state, serial, time); handle.button(button, state, serial, time);
let current_focus = handle.current_focus().cloned();
handle.set_grab( handle.set_grab(
serial, serial,
ClickGrab { ClickGrab {
current_focus, start_data: GrabStartData {
pending_focus: None, focus: handle.current_focus().cloned(),
button,
location: handle.current_location(),
},
}, },
); );
} }
fn axis(&mut self, handle: &mut PointerInnerHandle<'_>, details: AxisFrame) { fn axis(&mut self, handle: &mut PointerInnerHandle<'_>, details: AxisFrame) {
handle.axis(details); handle.axis(details);
} }
fn start_data(&self) -> &GrabStartData {
unreachable!()
}
} }
// A click grab, basic grab started when an user clicks a surface // A click grab, basic grab started when an user clicks a surface
@ -646,8 +680,7 @@ impl PointerGrab for DefaultGrab {
// In case the user maintains several simultaneous clicks, release // In case the user maintains several simultaneous clicks, release
// the grab once all are released. // the grab once all are released.
struct ClickGrab { struct ClickGrab {
current_focus: Option<(WlSurface, (f64, f64))>, start_data: GrabStartData,
pending_focus: Option<(WlSurface, (f64, f64))>,
} }
impl PointerGrab for ClickGrab { impl PointerGrab for ClickGrab {
@ -655,13 +688,11 @@ impl PointerGrab for ClickGrab {
&mut self, &mut self,
handle: &mut PointerInnerHandle<'_>, handle: &mut PointerInnerHandle<'_>,
location: (f64, f64), location: (f64, f64),
focus: Option<(WlSurface, (f64, f64))>, _focus: Option<(WlSurface, (f64, f64))>,
serial: u32, serial: u32,
time: u32, time: u32,
) { ) {
// buffer the future focus, but maintain the current one handle.motion(location, self.start_data.focus.clone(), serial, time);
self.pending_focus = focus;
handle.motion(location, self.current_focus.clone(), serial, time);
} }
fn button( fn button(
&mut self, &mut self,
@ -680,4 +711,7 @@ impl PointerGrab for ClickGrab {
fn axis(&mut self, handle: &mut PointerInnerHandle<'_>, details: AxisFrame) { fn axis(&mut self, handle: &mut PointerInnerHandle<'_>, details: AxisFrame) {
handle.axis(details); handle.axis(details);
} }
fn start_data(&self) -> &GrabStartData {
&self.start_data
}
} }