Add dragging window with cursor feature (#1840)

* X11 implementation.

* Introduce example.

* Wayland implementation.

* Windows implementation.

* Improve Wayland seat passing.

* MacOS implementation.

* Correct windows implementation per specification.

* Update dependency smithay-client-toolkit from branch to master.

* Fixed blocking thread in windows implementation.

* Add multi-window example.

* Move Wayland to a different PR.

* Fix CHANGELOG.

* Improve example.

Co-authored-by: Markus Røyset <maroider@protonmail.com>

* Rename `set_drag_window` to `begin_drag`.

* Improve example.

* Fix CHANGELOG.

* Fix CHANGELOG.

Co-authored-by: Markus Røyset <maroider@protonmail.com>

* Rename to `drag_window`.

* Fix typo.

* Re-introduce Wayland implementation.

* Fixing Wayland build.

* Fixing Wayland build.

* Move SCTK to 0.12.3.

Co-authored-by: Markus Røyset <maroider@protonmail.com>
This commit is contained in:
daxpedda 2021-03-07 10:43:23 +01:00 committed by GitHub
parent 4192d04a53
commit 98470393d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 233 additions and 5 deletions

View file

@ -556,6 +556,12 @@ impl Window {
pub fn set_cursor_visible(&self, _: bool) {}
pub fn drag_window(&self) -> Result<(), error::ExternalError> {
Err(error::ExternalError::NotSupported(
error::NotSupportedError::new(),
))
}
pub fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
let a_native_window = if let Some(native_window) = ndk_glue::native_window().as_ref() {
unsafe { native_window.ptr().as_mut() as *mut _ as *mut _ }

View file

@ -182,6 +182,10 @@ impl Inner {
debug!("`Window::set_cursor_visible` is ignored on iOS")
}
pub fn drag_window(&self) -> Result<(), ExternalError> {
Err(ExternalError::NotSupported(NotSupportedError::new()))
}
pub fn set_minimized(&self, _minimized: bool) {
warn!("`Window::set_minimized` is ignored on iOS")
}

View file

@ -358,6 +358,11 @@ impl Window {
x11_or_wayland!(match self; Window(window) => window.set_cursor_visible(visible))
}
#[inline]
pub fn drag_window(&self) -> Result<(), ExternalError> {
x11_or_wayland!(match self; Window(window) => window.drag_window())
}
#[inline]
pub fn scale_factor(&self) -> f64 {
x11_or_wayland!(match self; Window(w) => w.scale_factor() as f64)

View file

@ -4,6 +4,7 @@ use std::cell::RefCell;
use std::rc::Rc;
use sctk::reexports::client::protocol::wl_pointer::{self, Event as PointerEvent};
use sctk::reexports::client::protocol::wl_seat::WlSeat;
use sctk::reexports::protocols::unstable::relative_pointer::v1::client::zwp_relative_pointer_v1::Event as RelativePointerEvent;
use sctk::seat::pointer::ThemedPointer;
@ -28,6 +29,7 @@ pub(super) fn handle_pointer(
event: PointerEvent,
pointer_data: &Rc<RefCell<PointerData>>,
winit_state: &mut WinitState,
seat: WlSeat,
) {
let event_sink = &mut winit_state.event_sink;
let mut pointer_data = pointer_data.borrow_mut();
@ -59,6 +61,7 @@ pub(super) fn handle_pointer(
confined_pointer: Rc::downgrade(&pointer_data.confined_pointer),
pointer_constraints: pointer_data.pointer_constraints.clone(),
latest_serial: pointer_data.latest_serial.clone(),
seat,
};
window_handle.pointer_entered(winit_pointer);
@ -101,6 +104,7 @@ pub(super) fn handle_pointer(
confined_pointer: Rc::downgrade(&pointer_data.confined_pointer),
pointer_constraints: pointer_data.pointer_constraints.clone(),
latest_serial: pointer_data.latest_serial.clone(),
seat,
};
window_handle.pointer_left(winit_pointer);

View file

@ -13,6 +13,7 @@ use sctk::reexports::protocols::unstable::pointer_constraints::v1::client::zwp_p
use sctk::reexports::protocols::unstable::pointer_constraints::v1::client::zwp_confined_pointer_v1::ZwpConfinedPointerV1;
use sctk::seat::pointer::{ThemeManager, ThemedPointer};
use sctk::window::{ConceptFrame, Window};
use crate::event::ModifiersState;
use crate::platform_impl::wayland::event_loop::WinitState;
@ -35,6 +36,9 @@ pub struct WinitPointer {
/// Latest observed serial in pointer events.
latest_serial: Rc<Cell<u32>>,
/// Seat.
seat: WlSeat,
}
impl PartialEq for WinitPointer {
@ -144,6 +148,10 @@ impl WinitPointer {
confined_pointer.destroy();
}
}
pub fn drag_window(&self, window: &Window<ConceptFrame>) {
window.start_interactive_move(&self.seat, self.latest_serial.get());
}
}
/// A pointer wrapper for easy releasing and managing pointers.
@ -172,11 +180,18 @@ impl Pointers {
pointer_constraints.clone(),
modifiers_state,
)));
let pointer_seat = seat.detach();
let pointer = theme_manager.theme_pointer_with_impl(
seat,
move |event, pointer, mut dispatch_data| {
let winit_state = dispatch_data.get::<WinitState>().unwrap();
handlers::handle_pointer(pointer, event, &pointer_data, winit_state);
handlers::handle_pointer(
pointer,
event,
&pointer_data,
winit_state,
pointer_seat.clone(),
);
},
);

View file

@ -586,6 +586,18 @@ impl Window {
Err(ExternalError::NotSupported(NotSupportedError::new()))
}
#[inline]
pub fn drag_window(&self) -> Result<(), ExternalError> {
let drag_window_request = WindowRequest::DragWindow;
self.window_requests
.lock()
.unwrap()
.push(drag_window_request);
self.event_loop_awakener.ping();
Ok(())
}
#[inline]
pub fn set_ime_position(&self, position: Position) {
let scale_factor = self.scale_factor() as f64;

View file

@ -34,6 +34,9 @@ pub enum WindowRequest {
/// Grab cursor.
GrabCursor(bool),
/// Drag window.
DragWindow,
/// Maximize the window.
Maximize(bool),
@ -268,6 +271,12 @@ impl WindowHandle {
pointer.set_cursor(Some(cursor_icon));
}
}
pub fn drag_window(&self) {
for pointer in self.pointers.iter() {
pointer.drag_window(&self.window);
}
}
}
#[inline]
@ -299,6 +308,9 @@ pub fn handle_window_requests(winit_state: &mut WinitState) {
WindowRequest::GrabCursor(grab) => {
window_handle.set_cursor_grab(grab);
}
WindowRequest::DragWindow => {
window_handle.drag_window();
}
WindowRequest::Maximize(maximize) => {
if maximize {
window_handle.window.set_maximized();

View file

@ -1276,6 +1276,46 @@ impl UnownedWindow {
self.set_cursor_position_physical(x, y)
}
pub fn drag_window(&self) -> Result<(), ExternalError> {
let pointer = self
.xconn
.query_pointer(self.xwindow, util::VIRTUAL_CORE_POINTER)
.map_err(|err| ExternalError::Os(os_error!(OsError::XError(err))))?;
let window = self.inner_position().map_err(ExternalError::NotSupported)?;
let message = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_MOVERESIZE\0") };
// we can't use `set_cursor_grab(false)` here because it doesn't run `XUngrabPointer`
// if the cursor isn't currently grabbed
let mut grabbed_lock = self.cursor_grabbed.lock();
unsafe {
(self.xconn.xlib.XUngrabPointer)(self.xconn.display, ffi::CurrentTime);
}
self.xconn
.flush_requests()
.map_err(|err| ExternalError::Os(os_error!(OsError::XError(err))))?;
*grabbed_lock = false;
// we keep the lock until we are done
self.xconn
.send_client_msg(
self.xwindow,
self.root,
message,
Some(ffi::SubstructureRedirectMask | ffi::SubstructureNotifyMask),
[
(window.x as c_long + pointer.win_x as c_long),
(window.y as c_long + pointer.win_y as c_long),
8, // _NET_WM_MOVERESIZE_MOVE
ffi::Button1 as c_long,
1,
],
)
.flush()
.map_err(|err| ExternalError::Os(os_error!(OsError::XError(err))))
}
pub(crate) fn set_ime_position_physical(&self, x: i32, y: i32) {
let _ = self
.ime_sender

View file

@ -636,6 +636,16 @@ impl UnownedWindow {
Ok(())
}
#[inline]
pub fn drag_window(&self) -> Result<(), ExternalError> {
unsafe {
let event: id = msg_send![NSApp(), currentEvent];
let _: () = msg_send![*self.ns_window, performWindowDragWithEvent: event];
}
Ok(())
}
pub(crate) fn is_zoomed(&self) -> bool {
// because `isZoomed` doesn't work if the window's borderless,
// we make it resizable temporalily.

View file

@ -222,6 +222,11 @@ impl Window {
}
}
#[inline]
pub fn drag_window(&self) -> Result<(), ExternalError> {
Err(ExternalError::NotSupported(NotSupportedError::new()))
}
#[inline]
pub fn set_minimized(&self, _minimized: bool) {
// Intentionally a no-op, as canvases cannot be 'minimized'

View file

@ -14,8 +14,8 @@ use std::{
use winapi::{
ctypes::c_int,
shared::{
minwindef::{HINSTANCE, UINT},
windef::{HWND, POINT, RECT},
minwindef::{HINSTANCE, LPARAM, UINT, WPARAM},
windef::{HWND, POINT, POINTS, RECT},
},
um::{
combaseapi, dwmapi,
@ -26,7 +26,7 @@ use winapi::{
oleidl::LPDROPTARGET,
shobjidl_core::{CLSID_TaskbarList, ITaskbarList2},
wingdi::{CreateRectRgn, DeleteObject},
winnt::LPCWSTR,
winnt::{LPCWSTR, SHORT},
winuser,
},
};
@ -357,6 +357,30 @@ impl Window {
Ok(())
}
#[inline]
pub fn drag_window(&self) -> Result<(), ExternalError> {
unsafe {
let points = {
let mut pos = mem::zeroed();
winuser::GetCursorPos(&mut pos);
pos
};
let points = POINTS {
x: points.x as SHORT,
y: points.y as SHORT,
};
winuser::ReleaseCapture();
winuser::PostMessageW(
self.window.0,
winuser::WM_NCLBUTTONDOWN,
winuser::HTCAPTION as WPARAM,
&points as *const _ as LPARAM,
);
}
Ok(())
}
#[inline]
pub fn id(&self) -> WindowId {
WindowId(self.window.0)