Compare commits

...

20 Commits

Author SHA1 Message Date
Victor Timofei 6fc7503698
Merge branch 'Smithay:master' into master 2022-02-06 17:08:39 +02:00
Victoria Brekenfeld 5da3a62929
Merge pull request #488 from i509VCB/drm/node-changes
drm: Replace inner Option on DrmNode and use mem::forget
2022-02-02 16:46:40 +01:00
Victoria Brekenfeld 134f726dfb
Merge pull request #490 from Smithay/vberger/fix-grabs
wayland.seat: Fix pointer grab API
2022-02-02 16:44:58 +01:00
Victoria Brekenfeld 8c92e5f720
Merge pull request #486 from Smithay/fix/dnd_seat
data_device: Pass seat to DnD events
2022-02-02 16:40:28 +01:00
Victor Berger d797cdcdcb wayland.seat: Fix pointer grab API
The pointer grab mecanism had a few inconsistencies in its behavior when
a grab is set or unset. THis commit uniformizes the behavior, and also
introduces a synthetic motion event when the grab is set, allowing the
newly set grab to change the focus or the pointer location if needed.

Also adjust the DnDGrab, as well as the resize and move grabs from anvil
to unset the focus while they are active, matching weston's behavior.
2022-02-01 19:42:01 +01:00
i509VCB 0c8cb49129 drm: Replace inner Option on DrmNode and use mem::forget 2022-01-31 14:17:01 -06:00
Victoria Brekenfeld 11ab4c7f92 data_device: Pass seat to DnD events 2022-01-30 16:45:51 +01:00
Victor Timofei bf515da51a
Merge branch 'Smithay:master' into master 2022-01-29 00:31:44 +02:00
Victor Timofei 264299a6a4
Merge branch 'Smithay:master' into master 2022-01-16 19:24:16 +02:00
Victor Timofei 2fb1f93160
Merge branch 'Smithay:master' into master 2022-01-16 13:42:21 +02:00
Victor Timofei 77fdd1883e
Merge branch 'Smithay:master' into master 2022-01-05 20:59:38 +02:00
Victor Timofei 2a9a4decab
Fix format 2021-12-19 03:20:18 +02:00
Victor Timofei d08f9e2a98
Remove window decorator 2021-12-19 03:17:04 +02:00
Victor Timofei 67daf0d433
Merge branch 'Smithay:master' into master 2021-12-18 23:11:49 +02:00
Victor Timofei 05924dc2ff
Merge branch 'Smithay:master' into master 2021-12-17 18:11:39 +02:00
Victor Timofei 51ad2d060f
Merge branch 'Smithay:master' into master 2021-12-13 18:07:22 +02:00
Victor Timofei fa14d56b2a
Try add manual dispatch event 2021-12-11 16:26:48 +02:00
Victor Timofei 89399181b0
Format file 2021-12-11 14:21:51 +02:00
Victor Timofei 44b8a88de6
Use ctrl as mod key for debugging purposes 2021-12-11 14:14:50 +02:00
Victor Timofei 145c0bc2df
Focus window on mouse hover 2021-12-11 14:14:12 +02:00
8 changed files with 165 additions and 124 deletions

View File

@ -5,6 +5,7 @@ on:
branches:
- master
pull_request:
workflow_dispatch:
jobs:
format:

View File

@ -112,18 +112,7 @@ impl<Backend> AnvilState<Backend> {
let serial = SCOUNTER.next_serial();
let button = evt.button_code();
let state = match evt.state() {
input::ButtonState::Pressed => {
// change the keyboard focus unless the pointer is grabbed
if !self.pointer.is_grabbed() {
let under = self
.window_map
.borrow_mut()
.get_surface_and_bring_to_top(self.pointer_location);
self.keyboard
.set_focus(under.as_ref().map(|&(ref s, _)| s), serial);
}
wl_pointer::ButtonState::Pressed
}
input::ButtonState::Pressed => wl_pointer::ButtonState::Pressed,
input::ButtonState::Released => wl_pointer::ButtonState::Released,
};
self.pointer.button(button, state, serial, evt.time());
@ -236,7 +225,15 @@ impl<Backend> AnvilState<Backend> {
let pos = evt.position_transformed(output_size);
self.pointer_location = pos;
let serial = SCOUNTER.next_serial();
let under = self.window_map.borrow().get_surface_under(pos);
let under;
// set focus for this window
if !self.pointer.is_grabbed() {
under = self.window_map.borrow_mut().get_surface_and_bring_to_top(pos);
self.keyboard
.set_focus(under.as_ref().map(|&(ref s, _)| s), serial);
} else {
under = self.window_map.borrow().get_surface_under(pos);
}
self.pointer.motion(pos, under, serial, evt.time());
}
}
@ -358,7 +355,18 @@ impl AnvilState<UdevData> {
// this event is never generated by winit
self.pointer_location = self.clamp_coords(self.pointer_location);
let under = self.window_map.borrow().get_surface_under(self.pointer_location);
let under;
// set focus for this window
if !self.pointer.is_grabbed() {
under = self
.window_map
.borrow_mut()
.get_surface_and_bring_to_top(self.pointer_location);
self.keyboard
.set_focus(under.as_ref().map(|&(ref s, _)| s), serial);
} else {
under = self.window_map.borrow().get_surface_under(self.pointer_location);
}
self.pointer
.motion(self.pointer_location, under, serial, evt.time());
}
@ -521,9 +529,8 @@ enum KeyAction {
}
fn process_keyboard_shortcut(modifiers: ModifiersState, keysym: Keysym) -> Option<KeyAction> {
if modifiers.ctrl && modifiers.alt && keysym == xkb::KEY_BackSpace
|| modifiers.logo && keysym == xkb::KEY_q
{
let modkey = modifiers.ctrl;
if modkey && keysym == xkb::KEY_q {
// ctrl+alt+backspace = quit
// logo + q = quit
Some(KeyAction::Quit)
@ -532,14 +539,14 @@ fn process_keyboard_shortcut(modifiers: ModifiersState, keysym: Keysym) -> Optio
Some(KeyAction::VtSwitch(
(keysym - xkb::KEY_XF86Switch_VT_1 + 1) as i32,
))
} else if modifiers.logo && keysym == xkb::KEY_Return {
} else if modkey && keysym == xkb::KEY_Return {
// run terminal
Some(KeyAction::Run("weston-terminal".into()))
} else if modifiers.logo && keysym >= xkb::KEY_1 && keysym <= xkb::KEY_9 {
Some(KeyAction::Run("alacritty".into()))
} else if modkey && keysym >= xkb::KEY_1 && keysym <= xkb::KEY_9 {
Some(KeyAction::Screen((keysym - xkb::KEY_1) as usize))
} else if modifiers.logo && modifiers.shift && keysym == xkb::KEY_M {
} else if modkey && modifiers.shift && keysym == xkb::KEY_M {
Some(KeyAction::ScaleDown)
} else if modifiers.logo && modifiers.shift && keysym == xkb::KEY_P {
} else if modkey && modifiers.shift && keysym == xkb::KEY_P {
Some(KeyAction::ScaleUp)
} else {
None

View File

@ -48,12 +48,15 @@ struct MoveSurfaceGrab {
impl PointerGrab for MoveSurfaceGrab {
fn motion(
&mut self,
_handle: &mut PointerInnerHandle<'_>,
handle: &mut PointerInnerHandle<'_>,
location: Point<f64, Logical>,
_focus: Option<(wl_surface::WlSurface, Point<i32, Logical>)>,
_serial: Serial,
_time: u32,
serial: Serial,
time: u32,
) {
// While the grab is active, no client has pointer focus
handle.motion(location, None, serial, time);
let delta = location - self.start_data.location;
let new_location = self.initial_window_location.to_f64() + delta;
@ -152,6 +155,9 @@ impl PointerGrab for ResizeSurfaceGrab {
return;
}
// While the grab is active, no client has pointer focus
handle.motion(location, None, serial, time);
let (mut dx, mut dy) = (location - self.start_data.location).into();
let mut new_window_width = self.initial_window_size.w;
@ -479,7 +485,7 @@ pub fn init_shell<BackendData: 'static>(display: Rc<RefCell<Display>>, log: ::sl
initial_window_location,
};
pointer.set_grab(grab, serial);
pointer.set_grab(grab, serial, 0);
}
XdgRequest::Resize {
@ -539,7 +545,7 @@ pub fn init_shell<BackendData: 'static>(display: Rc<RefCell<Display>>, log: ::sl
last_window_size: initial_window_size,
};
pointer.set_grab(grab, serial);
pointer.set_grab(grab, serial, 0);
}
XdgRequest::AckConfigure {
@ -806,7 +812,7 @@ pub fn init_shell<BackendData: 'static>(display: Rc<RefCell<Display>>, log: ::sl
initial_window_location,
};
pointer.set_grab(grab, serial);
pointer.set_grab(grab, serial, 0);
}
ShellRequest::Resize {
@ -866,7 +872,7 @@ pub fn init_shell<BackendData: 'static>(display: Rc<RefCell<Display>>, log: ::sl
last_window_size: initial_window_size,
};
pointer.set_grab(grab, serial);
pointer.set_grab(grab, serial, 0);
}
_ => (),
}

View File

@ -10,7 +10,6 @@ use std::{
use smithay::{
reexports::{
calloop::{generic::Generic, Interest, LoopHandle, Mode, PostAction},
wayland_protocols::unstable::xdg_decoration,
wayland_server::{protocol::wl_surface::WlSurface, Display},
},
utils::{Logical, Point},
@ -18,7 +17,7 @@ use smithay::{
data_device::{default_action_chooser, init_data_device, set_data_device_focus, DataDeviceEvent},
output::xdg::init_xdg_output_manager,
seat::{CursorImageStatus, KeyboardHandle, PointerHandle, Seat, XkbConfig},
shell::xdg::decoration::{init_xdg_decoration_manager, XdgDecorationRequest},
shell::xdg::decoration::init_xdg_decoration_manager,
shm::init_shm_global,
tablet_manager::{init_tablet_manager_global, TabletSeatTrait},
xdg_activation::{init_xdg_activation_global, XdgActivationEvent},
@ -122,25 +121,7 @@ impl<BackendData: Backend + 'static> AnvilState<BackendData> {
log.clone(),
);
init_xdg_decoration_manager(
&mut display.borrow_mut(),
|req, _ddata| match req {
XdgDecorationRequest::NewToplevelDecoration { toplevel } => {
use xdg_decoration::v1::server::zxdg_toplevel_decoration_v1::Mode;
let res = toplevel.with_pending_state(|state| {
state.decoration_mode = Some(Mode::ClientSide);
});
if res.is_ok() {
toplevel.send_configure();
}
}
XdgDecorationRequest::SetMode { .. } => {}
XdgDecorationRequest::UnsetMode { .. } => {}
},
log.clone(),
);
init_xdg_decoration_manager(&mut display.borrow_mut(), |_, _| {}, log.clone());
let socket_name = if listen_on_socket {
let socket_name = display
@ -167,7 +148,7 @@ impl<BackendData: Backend + 'static> AnvilState<BackendData> {
DataDeviceEvent::DnDStarted { icon, .. } => {
*dnd_icon2.lock().unwrap() = icon;
}
DataDeviceEvent::DnDDropped => {
DataDeviceEvent::DnDDropped { .. } => {
*dnd_icon2.lock().unwrap() = None;
}
_ => {}

View File

@ -7,7 +7,7 @@ use libc::dev_t;
use std::{
fmt::{self, Display, Formatter},
fs, io,
fs, io, mem,
os::unix::prelude::{AsRawFd, IntoRawFd, RawFd},
path::{Path, PathBuf},
};
@ -20,8 +20,7 @@ use nix::{
/// A node which refers to a DRM device.
#[derive(Debug)]
pub struct DrmNode {
// Always `Some`, None variant is used when taking ownership
fd: Option<RawFd>,
fd: RawFd,
dev: dev_t,
ty: NodeType,
}
@ -56,11 +55,7 @@ impl DrmNode {
_ => return Err(CreateDrmNodeError::NotDrmNode),
};
Ok(DrmNode {
fd: Some(fd),
dev,
ty,
})
Ok(DrmNode { fd, dev, ty })
}
/// Returns the type of the DRM node.
@ -120,22 +115,22 @@ impl Display for DrmNode {
}
impl IntoRawFd for DrmNode {
fn into_raw_fd(mut self) -> RawFd {
self.fd.take().unwrap()
fn into_raw_fd(self) -> RawFd {
let fd = self.fd;
mem::forget(self);
fd
}
}
impl AsRawFd for DrmNode {
fn as_raw_fd(&self) -> RawFd {
self.fd.unwrap()
self.fd
}
}
impl Drop for DrmNode {
fn drop(&mut self) {
if let Some(fd) = self.fd {
let _ = close(fd);
}
let _ = close(self.fd);
}
}

View File

@ -53,12 +53,15 @@ impl DnDGrab {
impl PointerGrab for DnDGrab {
fn motion(
&mut self,
_handle: &mut PointerInnerHandle<'_>,
handle: &mut PointerInnerHandle<'_>,
location: Point<f64, Logical>,
focus: Option<(wl_surface::WlSurface, Point<i32, Logical>)>,
serial: Serial,
time: u32,
) {
// While the grab is active, no client has pointer focus
handle.motion(location, None, serial, time);
let seat_data = self
.seat
.user_data()
@ -209,7 +212,9 @@ impl PointerGrab for DnDGrab {
source.cancelled();
}
}
(&mut *self.callback.borrow_mut())(super::DataDeviceEvent::DnDDropped);
(&mut *self.callback.borrow_mut())(super::DataDeviceEvent::DnDDropped {
seat: self.seat.clone(),
});
self.icon = None;
// in all cases abandon the drop
// no more buttons are pressed, release the grab

View File

@ -88,13 +88,18 @@ pub enum DataDeviceEvent {
/// The icon the client requested to be used to be associated with the cursor icon
/// during the drag'n'drop.
icon: Option<wl_surface::WlSurface>,
/// The seat on which the DnD operation was started
seat: Seat,
},
/// The drag'n'drop action was finished by the user releasing the buttons
///
/// At this point, any pointer icon should be removed.
///
/// Note that this event will only be generated for client-initiated drag'n'drop session.
DnDDropped,
DnDDropped {
/// The seat on which the DnD action was finished.
seat: Seat,
},
/// A client requested to read the server-set selection
SendSelection {
/// the requested mime type
@ -356,6 +361,7 @@ pub fn start_dnd<C>(
Rc::new(RefCell::new(callback)),
),
serial,
0,
);
}
}
@ -445,6 +451,7 @@ where
(&mut *callback.borrow_mut())(DataDeviceEvent::DnDStarted {
source: source.clone(),
icon: icon.clone(),
seat: seat.clone(),
});
let start_data = pointer.grab_start_data().unwrap();
pointer.set_grab(
@ -457,6 +464,7 @@ where
callback.clone(),
),
serial,
0,
);
return;
}

View File

@ -91,6 +91,76 @@ impl PointerInternal {
}
}
fn set_grab<G: PointerGrab + 'static>(&mut self, serial: Serial, grab: G, time: u32) {
self.grab = GrabStatus::Active(serial, Box::new(grab));
// generate a move to let the grab change the focus or move the pointer as result of its initialization
let location = self.location;
let focus = self.focus.clone();
self.motion(location, focus, serial, time);
}
fn unset_grab(&mut self, serial: Serial, time: u32) {
self.grab = GrabStatus::None;
// restore the focus
let location = self.location;
let focus = self.pending_focus.clone();
self.motion(location, focus, serial, time);
}
fn motion(
&mut self,
location: Point<f64, Logical>,
focus: Option<(WlSurface, Point<i32, Logical>)>,
serial: Serial,
time: u32,
) {
// do we leave a surface ?
let mut leave = true;
self.location = location;
if let Some((ref current_focus, _)) = self.focus {
if let Some((ref surface, _)) = focus {
if current_focus.as_ref().equals(surface.as_ref()) {
leave = false;
}
}
}
if leave {
self.with_focused_pointers(|pointer, surface| {
pointer.leave(serial.into(), surface);
if pointer.as_ref().version() >= 5 {
pointer.frame();
}
});
self.focus = None;
(self.image_callback)(CursorImageStatus::Default);
}
// do we enter one ?
if let Some((surface, surface_location)) = focus {
let entered = self.focus.is_none();
// in all cases, update the focus, the coordinates of the surface
// might have changed
self.focus = Some((surface, surface_location));
let (x, y) = (location - surface_location.to_f64()).into();
if entered {
self.with_focused_pointers(|pointer, surface| {
pointer.enter(serial.into(), surface, x, y);
if pointer.as_ref().version() >= 5 {
pointer.frame();
}
})
} else {
// we were on top of a surface and remained on it
self.with_focused_pointers(|pointer, _| {
pointer.motion(time, x, y);
if pointer.as_ref().version() >= 5 {
pointer.frame();
}
})
}
}
}
fn with_focused_pointers<F>(&self, mut f: F)
where
F: FnMut(&WlPointer, &WlSurface),
@ -160,13 +230,13 @@ impl PointerHandle {
/// Change the current grab on this pointer to the provided grab
///
/// Overwrites any current grab.
pub fn set_grab<G: PointerGrab + 'static>(&self, grab: G, serial: Serial) {
self.inner.borrow_mut().grab = GrabStatus::Active(serial, Box::new(grab));
pub fn set_grab<G: PointerGrab + 'static>(&self, grab: G, serial: Serial, time: u32) {
self.inner.borrow_mut().set_grab(serial, grab, time);
}
/// Remove any current grab on this pointer, resetting it to the default behavior
pub fn unset_grab(&self) {
self.inner.borrow_mut().grab = GrabStatus::None;
pub fn unset_grab(&self, serial: Serial, time: u32) {
self.inner.borrow_mut().unset_grab(serial, time);
}
/// Check if this pointer is currently grabbed with this serial
@ -283,6 +353,13 @@ pub struct GrabStartData {
/// rather than trying to guess when the grab will end.
pub trait PointerGrab {
/// A motion was reported
///
/// This method allows you attach additional behavior to a motion event, possibly altering it.
/// You generally will want to invoke `PointerInnerHandle::motion()` as part of your processing. If you
/// don't, the rest of the compositor will behave as if the motion event never occurred.
///
/// Some grabs (such as drag'n'drop, shell resize and motion) unset the focus while they are active,
/// this is achieved by just setting the focus to `None` when invoking `PointerInnerHandle::motion()`.
fn motion(
&mut self,
handle: &mut PointerInnerHandle<'_>,
@ -292,6 +369,10 @@ pub trait PointerGrab {
time: u32,
);
/// A button press was reported
///
/// This method allows you attach additional behavior to a button event, possibly altering it.
/// You generally will want to invoke `PointerInnerHandle::button()` as part of your processing. If you
/// don't, the rest of the compositor will behave as if the button event never occurred.
fn button(
&mut self,
handle: &mut PointerInnerHandle<'_>,
@ -301,6 +382,10 @@ pub trait PointerGrab {
time: u32,
);
/// An axis scroll was reported
///
/// This method allows you attach additional behavior to an axis event, possibly altering it.
/// You generally will want to invoke `PointerInnerHandle::axis()` as part of your processing. If you
/// don't, the rest of the compositor will behave as if the axis event never occurred.
fn axis(&mut self, handle: &mut PointerInnerHandle<'_>, details: AxisFrame);
/// The data about the event that started the grab.
fn start_data(&self) -> &GrabStartData;
@ -317,19 +402,15 @@ impl<'a> PointerInnerHandle<'a> {
/// Change the current grab on this pointer to the provided grab
///
/// Overwrites any current grab.
pub fn set_grab<G: PointerGrab + 'static>(&mut self, serial: Serial, grab: G) {
self.inner.grab = GrabStatus::Active(serial, Box::new(grab));
pub fn set_grab<G: PointerGrab + 'static>(&mut self, serial: Serial, grab: G, time: u32) {
self.inner.set_grab(serial, grab, time);
}
/// Remove any current grab on this pointer, resetting it to the default behavior
///
/// This will also restore the focus of the underlying pointer
pub fn unset_grab(&mut self, serial: Serial, time: u32) {
self.inner.grab = GrabStatus::None;
// restore the focus
let location = self.current_location();
let focus = self.inner.pending_focus.clone();
self.motion(location, focus, serial, time);
self.inner.unset_grab(serial, time);
}
/// Access the current focus of this pointer
@ -368,51 +449,7 @@ impl<'a> PointerInnerHandle<'a> {
serial: Serial,
time: u32,
) {
// do we leave a surface ?
let mut leave = true;
self.inner.location = location;
if let Some((ref current_focus, _)) = self.inner.focus {
if let Some((ref surface, _)) = focus {
if current_focus.as_ref().equals(surface.as_ref()) {
leave = false;
}
}
}
if leave {
self.inner.with_focused_pointers(|pointer, surface| {
pointer.leave(serial.into(), surface);
if pointer.as_ref().version() >= 5 {
pointer.frame();
}
});
self.inner.focus = None;
(self.inner.image_callback)(CursorImageStatus::Default);
}
// do we enter one ?
if let Some((surface, surface_location)) = focus {
let entered = self.inner.focus.is_none();
// in all cases, update the focus, the coordinates of the surface
// might have changed
self.inner.focus = Some((surface, surface_location));
let (x, y) = (location - surface_location.to_f64()).into();
if entered {
self.inner.with_focused_pointers(|pointer, surface| {
pointer.enter(serial.into(), surface, x, y);
if pointer.as_ref().version() >= 5 {
pointer.frame();
}
})
} else {
// we were on top of a surface and remained on it
self.inner.with_focused_pointers(|pointer, _| {
pointer.motion(time, x, y);
if pointer.as_ref().version() >= 5 {
pointer.frame();
}
})
}
}
self.inner.motion(location, focus, serial, time);
}
/// Notify that a button was pressed
@ -687,6 +724,7 @@ impl PointerGrab for DefaultGrab {
location: handle.current_location(),
},
},
time,
);
}
}