mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 22:01:31 +11:00
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:
parent
4192d04a53
commit
98470393d1
|
@ -13,6 +13,7 @@
|
||||||
- On Android, bump `ndk` and `ndk-glue` to 0.3: use predefined constants for event `ident`.
|
- On Android, bump `ndk` and `ndk-glue` to 0.3: use predefined constants for event `ident`.
|
||||||
- On Windows, fixed `WindowEvent::ThemeChanged` not properly firing and fixed `Window::theme` returning the wrong theme.
|
- On Windows, fixed `WindowEvent::ThemeChanged` not properly firing and fixed `Window::theme` returning the wrong theme.
|
||||||
- On Web, added support for `DeviceEvent::MouseMotion` to listen for relative mouse movements.
|
- On Web, added support for `DeviceEvent::MouseMotion` to listen for relative mouse movements.
|
||||||
|
- Added `Window::drag_window`. Implemented on Windows, macOS, X11 and Wayland.
|
||||||
|
|
||||||
# 0.24.0 (2020-12-09)
|
# 0.24.0 (2020-12-09)
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ features = [
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies]
|
[target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies]
|
||||||
wayland-client = { version = "0.28", features = [ "dlopen"] , optional = true }
|
wayland-client = { version = "0.28", features = [ "dlopen"] , optional = true }
|
||||||
sctk = { package = "smithay-client-toolkit", version = "0.12", optional = true }
|
sctk = { package = "smithay-client-toolkit", version = "0.12.3", optional = true }
|
||||||
mio = { version = "0.6", optional = true }
|
mio = { version = "0.6", optional = true }
|
||||||
mio-extras = { version = "2.0", optional = true }
|
mio-extras = { version = "2.0", optional = true }
|
||||||
x11-dl = { version = "2.18.5", optional = true }
|
x11-dl = { version = "2.18.5", optional = true }
|
||||||
|
|
|
@ -209,6 +209,7 @@ Legend:
|
||||||
|Raw Device Events |▢[#750] |▢[#750] |▢[#750] |❌ |❌ |❌ |❓ |
|
|Raw Device Events |▢[#750] |▢[#750] |▢[#750] |❌ |❌ |❌ |❓ |
|
||||||
|Gamepad/Joystick events |❌[#804] |❌ |❌ |❌ |❌ |❌ |❓ |
|
|Gamepad/Joystick events |❌[#804] |❌ |❌ |❌ |❌ |❌ |❓ |
|
||||||
|Device movement events |❓ |❓ |❓ |❓ |❌ |❌ |❓ |
|
|Device movement events |❓ |❓ |❓ |❓ |❌ |❌ |❓ |
|
||||||
|
|Drag window with cursor |✔️ |✔️ |✔️ |✔️ |**N/A**|**N/A**|**N/A** |
|
||||||
|
|
||||||
### Pending API Reworks
|
### Pending API Reworks
|
||||||
Changes in the API that have been agreed upon but aren't implemented across all platforms.
|
Changes in the API that have been agreed upon but aren't implemented across all platforms.
|
||||||
|
|
73
examples/drag_window.rs
Normal file
73
examples/drag_window.rs
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
use simple_logger::SimpleLogger;
|
||||||
|
use winit::{
|
||||||
|
event::{
|
||||||
|
ElementState, Event, KeyboardInput, MouseButton, StartCause, VirtualKeyCode, WindowEvent,
|
||||||
|
},
|
||||||
|
event_loop::{ControlFlow, EventLoop},
|
||||||
|
window::{Window, WindowBuilder, WindowId},
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
SimpleLogger::new().init().unwrap();
|
||||||
|
let event_loop = EventLoop::new();
|
||||||
|
|
||||||
|
let window_1 = WindowBuilder::new().build(&event_loop).unwrap();
|
||||||
|
let window_2 = WindowBuilder::new().build(&event_loop).unwrap();
|
||||||
|
|
||||||
|
let mut switched = false;
|
||||||
|
let mut entered_id = window_2.id();
|
||||||
|
|
||||||
|
event_loop.run(move |event, _, control_flow| match event {
|
||||||
|
Event::NewEvents(StartCause::Init) => {
|
||||||
|
eprintln!("Switch which window is to be dragged by pressing \"x\".")
|
||||||
|
}
|
||||||
|
Event::WindowEvent { event, window_id } => match event {
|
||||||
|
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
|
||||||
|
WindowEvent::MouseInput {
|
||||||
|
state: ElementState::Pressed,
|
||||||
|
button: MouseButton::Left,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let window = if (window_id == window_1.id() && switched)
|
||||||
|
|| (window_id == window_2.id() && !switched)
|
||||||
|
{
|
||||||
|
&window_2
|
||||||
|
} else {
|
||||||
|
&window_1
|
||||||
|
};
|
||||||
|
|
||||||
|
window.drag_window().unwrap()
|
||||||
|
}
|
||||||
|
WindowEvent::CursorEntered { .. } => {
|
||||||
|
entered_id = window_id;
|
||||||
|
name_windows(entered_id, switched, &window_1, &window_2)
|
||||||
|
}
|
||||||
|
WindowEvent::KeyboardInput {
|
||||||
|
input:
|
||||||
|
KeyboardInput {
|
||||||
|
state: ElementState::Released,
|
||||||
|
virtual_keycode: Some(VirtualKeyCode::X),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
switched = !switched;
|
||||||
|
name_windows(entered_id, switched, &window_1, &window_2);
|
||||||
|
println!("Switched!")
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name_windows(window_id: WindowId, switched: bool, window_1: &Window, window_2: &Window) {
|
||||||
|
let (drag_target, other) =
|
||||||
|
if (window_id == window_1.id() && switched) || (window_id == window_2.id() && !switched) {
|
||||||
|
(&window_2, &window_1)
|
||||||
|
} else {
|
||||||
|
(&window_1, &window_2)
|
||||||
|
};
|
||||||
|
drag_target.set_title("drag target");
|
||||||
|
other.set_title("winit window");
|
||||||
|
}
|
|
@ -556,6 +556,12 @@ impl Window {
|
||||||
|
|
||||||
pub fn set_cursor_visible(&self, _: bool) {}
|
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 {
|
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() {
|
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 _ }
|
unsafe { native_window.ptr().as_mut() as *mut _ as *mut _ }
|
||||||
|
|
|
@ -182,6 +182,10 @@ impl Inner {
|
||||||
debug!("`Window::set_cursor_visible` is ignored on iOS")
|
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) {
|
pub fn set_minimized(&self, _minimized: bool) {
|
||||||
warn!("`Window::set_minimized` is ignored on iOS")
|
warn!("`Window::set_minimized` is ignored on iOS")
|
||||||
}
|
}
|
||||||
|
|
|
@ -358,6 +358,11 @@ impl Window {
|
||||||
x11_or_wayland!(match self; Window(window) => window.set_cursor_visible(visible))
|
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]
|
#[inline]
|
||||||
pub fn scale_factor(&self) -> f64 {
|
pub fn scale_factor(&self) -> f64 {
|
||||||
x11_or_wayland!(match self; Window(w) => w.scale_factor() as f64)
|
x11_or_wayland!(match self; Window(w) => w.scale_factor() as f64)
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use sctk::reexports::client::protocol::wl_pointer::{self, Event as PointerEvent};
|
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::reexports::protocols::unstable::relative_pointer::v1::client::zwp_relative_pointer_v1::Event as RelativePointerEvent;
|
||||||
|
|
||||||
use sctk::seat::pointer::ThemedPointer;
|
use sctk::seat::pointer::ThemedPointer;
|
||||||
|
@ -28,6 +29,7 @@ pub(super) fn handle_pointer(
|
||||||
event: PointerEvent,
|
event: PointerEvent,
|
||||||
pointer_data: &Rc<RefCell<PointerData>>,
|
pointer_data: &Rc<RefCell<PointerData>>,
|
||||||
winit_state: &mut WinitState,
|
winit_state: &mut WinitState,
|
||||||
|
seat: WlSeat,
|
||||||
) {
|
) {
|
||||||
let event_sink = &mut winit_state.event_sink;
|
let event_sink = &mut winit_state.event_sink;
|
||||||
let mut pointer_data = pointer_data.borrow_mut();
|
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),
|
confined_pointer: Rc::downgrade(&pointer_data.confined_pointer),
|
||||||
pointer_constraints: pointer_data.pointer_constraints.clone(),
|
pointer_constraints: pointer_data.pointer_constraints.clone(),
|
||||||
latest_serial: pointer_data.latest_serial.clone(),
|
latest_serial: pointer_data.latest_serial.clone(),
|
||||||
|
seat,
|
||||||
};
|
};
|
||||||
window_handle.pointer_entered(winit_pointer);
|
window_handle.pointer_entered(winit_pointer);
|
||||||
|
|
||||||
|
@ -101,6 +104,7 @@ pub(super) fn handle_pointer(
|
||||||
confined_pointer: Rc::downgrade(&pointer_data.confined_pointer),
|
confined_pointer: Rc::downgrade(&pointer_data.confined_pointer),
|
||||||
pointer_constraints: pointer_data.pointer_constraints.clone(),
|
pointer_constraints: pointer_data.pointer_constraints.clone(),
|
||||||
latest_serial: pointer_data.latest_serial.clone(),
|
latest_serial: pointer_data.latest_serial.clone(),
|
||||||
|
seat,
|
||||||
};
|
};
|
||||||
window_handle.pointer_left(winit_pointer);
|
window_handle.pointer_left(winit_pointer);
|
||||||
|
|
||||||
|
|
|
@ -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::reexports::protocols::unstable::pointer_constraints::v1::client::zwp_confined_pointer_v1::ZwpConfinedPointerV1;
|
||||||
|
|
||||||
use sctk::seat::pointer::{ThemeManager, ThemedPointer};
|
use sctk::seat::pointer::{ThemeManager, ThemedPointer};
|
||||||
|
use sctk::window::{ConceptFrame, Window};
|
||||||
|
|
||||||
use crate::event::ModifiersState;
|
use crate::event::ModifiersState;
|
||||||
use crate::platform_impl::wayland::event_loop::WinitState;
|
use crate::platform_impl::wayland::event_loop::WinitState;
|
||||||
|
@ -35,6 +36,9 @@ pub struct WinitPointer {
|
||||||
|
|
||||||
/// Latest observed serial in pointer events.
|
/// Latest observed serial in pointer events.
|
||||||
latest_serial: Rc<Cell<u32>>,
|
latest_serial: Rc<Cell<u32>>,
|
||||||
|
|
||||||
|
/// Seat.
|
||||||
|
seat: WlSeat,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for WinitPointer {
|
impl PartialEq for WinitPointer {
|
||||||
|
@ -144,6 +148,10 @@ impl WinitPointer {
|
||||||
confined_pointer.destroy();
|
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.
|
/// A pointer wrapper for easy releasing and managing pointers.
|
||||||
|
@ -172,11 +180,18 @@ impl Pointers {
|
||||||
pointer_constraints.clone(),
|
pointer_constraints.clone(),
|
||||||
modifiers_state,
|
modifiers_state,
|
||||||
)));
|
)));
|
||||||
|
let pointer_seat = seat.detach();
|
||||||
let pointer = theme_manager.theme_pointer_with_impl(
|
let pointer = theme_manager.theme_pointer_with_impl(
|
||||||
seat,
|
seat,
|
||||||
move |event, pointer, mut dispatch_data| {
|
move |event, pointer, mut dispatch_data| {
|
||||||
let winit_state = dispatch_data.get::<WinitState>().unwrap();
|
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(),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -586,6 +586,18 @@ impl Window {
|
||||||
Err(ExternalError::NotSupported(NotSupportedError::new()))
|
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]
|
#[inline]
|
||||||
pub fn set_ime_position(&self, position: Position) {
|
pub fn set_ime_position(&self, position: Position) {
|
||||||
let scale_factor = self.scale_factor() as f64;
|
let scale_factor = self.scale_factor() as f64;
|
||||||
|
|
|
@ -34,6 +34,9 @@ pub enum WindowRequest {
|
||||||
/// Grab cursor.
|
/// Grab cursor.
|
||||||
GrabCursor(bool),
|
GrabCursor(bool),
|
||||||
|
|
||||||
|
/// Drag window.
|
||||||
|
DragWindow,
|
||||||
|
|
||||||
/// Maximize the window.
|
/// Maximize the window.
|
||||||
Maximize(bool),
|
Maximize(bool),
|
||||||
|
|
||||||
|
@ -268,6 +271,12 @@ impl WindowHandle {
|
||||||
pointer.set_cursor(Some(cursor_icon));
|
pointer.set_cursor(Some(cursor_icon));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn drag_window(&self) {
|
||||||
|
for pointer in self.pointers.iter() {
|
||||||
|
pointer.drag_window(&self.window);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -299,6 +308,9 @@ pub fn handle_window_requests(winit_state: &mut WinitState) {
|
||||||
WindowRequest::GrabCursor(grab) => {
|
WindowRequest::GrabCursor(grab) => {
|
||||||
window_handle.set_cursor_grab(grab);
|
window_handle.set_cursor_grab(grab);
|
||||||
}
|
}
|
||||||
|
WindowRequest::DragWindow => {
|
||||||
|
window_handle.drag_window();
|
||||||
|
}
|
||||||
WindowRequest::Maximize(maximize) => {
|
WindowRequest::Maximize(maximize) => {
|
||||||
if maximize {
|
if maximize {
|
||||||
window_handle.window.set_maximized();
|
window_handle.window.set_maximized();
|
||||||
|
|
|
@ -1276,6 +1276,46 @@ impl UnownedWindow {
|
||||||
self.set_cursor_position_physical(x, y)
|
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) {
|
pub(crate) fn set_ime_position_physical(&self, x: i32, y: i32) {
|
||||||
let _ = self
|
let _ = self
|
||||||
.ime_sender
|
.ime_sender
|
||||||
|
|
|
@ -636,6 +636,16 @@ impl UnownedWindow {
|
||||||
Ok(())
|
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 {
|
pub(crate) fn is_zoomed(&self) -> bool {
|
||||||
// because `isZoomed` doesn't work if the window's borderless,
|
// because `isZoomed` doesn't work if the window's borderless,
|
||||||
// we make it resizable temporalily.
|
// we make it resizable temporalily.
|
||||||
|
|
|
@ -222,6 +222,11 @@ impl Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn drag_window(&self) -> Result<(), ExternalError> {
|
||||||
|
Err(ExternalError::NotSupported(NotSupportedError::new()))
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_minimized(&self, _minimized: bool) {
|
pub fn set_minimized(&self, _minimized: bool) {
|
||||||
// Intentionally a no-op, as canvases cannot be 'minimized'
|
// Intentionally a no-op, as canvases cannot be 'minimized'
|
||||||
|
|
|
@ -14,8 +14,8 @@ use std::{
|
||||||
use winapi::{
|
use winapi::{
|
||||||
ctypes::c_int,
|
ctypes::c_int,
|
||||||
shared::{
|
shared::{
|
||||||
minwindef::{HINSTANCE, UINT},
|
minwindef::{HINSTANCE, LPARAM, UINT, WPARAM},
|
||||||
windef::{HWND, POINT, RECT},
|
windef::{HWND, POINT, POINTS, RECT},
|
||||||
},
|
},
|
||||||
um::{
|
um::{
|
||||||
combaseapi, dwmapi,
|
combaseapi, dwmapi,
|
||||||
|
@ -26,7 +26,7 @@ use winapi::{
|
||||||
oleidl::LPDROPTARGET,
|
oleidl::LPDROPTARGET,
|
||||||
shobjidl_core::{CLSID_TaskbarList, ITaskbarList2},
|
shobjidl_core::{CLSID_TaskbarList, ITaskbarList2},
|
||||||
wingdi::{CreateRectRgn, DeleteObject},
|
wingdi::{CreateRectRgn, DeleteObject},
|
||||||
winnt::LPCWSTR,
|
winnt::{LPCWSTR, SHORT},
|
||||||
winuser,
|
winuser,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -357,6 +357,30 @@ impl Window {
|
||||||
Ok(())
|
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]
|
#[inline]
|
||||||
pub fn id(&self) -> WindowId {
|
pub fn id(&self) -> WindowId {
|
||||||
WindowId(self.window.0)
|
WindowId(self.window.0)
|
||||||
|
|
|
@ -764,6 +764,22 @@ impl Window {
|
||||||
pub fn set_cursor_visible(&self, visible: bool) {
|
pub fn set_cursor_visible(&self, visible: bool) {
|
||||||
self.window.set_cursor_visible(visible)
|
self.window.set_cursor_visible(visible)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Moves the window with the left mouse button until the button is released.
|
||||||
|
///
|
||||||
|
/// There's no guarantee that this will work unless the left mouse button was pressed
|
||||||
|
/// immediately before this function is called.
|
||||||
|
///
|
||||||
|
/// ## Platform-specific
|
||||||
|
///
|
||||||
|
/// - **X11:** Un-grabs the cursor.
|
||||||
|
/// - **Wayland:** Requires the cursor to be inside the window to be dragged.
|
||||||
|
/// - **macOS:** May prevent the button release event to be triggered.
|
||||||
|
/// - **iOS / Android / Web:** Always returns an [`ExternalError::NotSupported`].
|
||||||
|
#[inline]
|
||||||
|
pub fn drag_window(&self) -> Result<(), ExternalError> {
|
||||||
|
self.window.drag_window()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Monitor info functions.
|
/// Monitor info functions.
|
||||||
|
|
Loading…
Reference in a new issue