mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-23 22:01:31 +11:00
Merge branch 'master' into web
This commit is contained in:
commit
f62bb33317
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -1,6 +1,7 @@
|
|||
# Unreleased
|
||||
|
||||
- Add web support via the 'stdweb' or 'web-sys' features
|
||||
- On Windows, implemented function to get HINSTANCE
|
||||
- On macOS, implement `run_return`.
|
||||
- On iOS, fix inverted parameter in `set_prefers_home_indicator_hidden`.
|
||||
- On X11, performance is improved when rapidly calling `Window::set_cursor_icon`.
|
||||
|
@ -21,7 +22,17 @@
|
|||
- On X11, return dummy monitor data to avoid panicking when no monitors exist.
|
||||
- On X11, prevent stealing input focus when creating a new window.
|
||||
Only steal input focus when entering fullscreen mode.
|
||||
- On Wayland, fixed DeviceEvents for relative mouse movement is not always produced
|
||||
- On Wayland, add support for set_cursor_visible and set_cursor_grab.
|
||||
- On Wayland, fixed DeviceEvents for relative mouse movement is not always produced.
|
||||
- Removed `derivative` crate dependency.
|
||||
- On Wayland, add support for set_cursor_icon.
|
||||
- Use `impl Iterator<Item = MonitorHandle>` instead of `AvailableMonitorsIter` consistently.
|
||||
- On macOS, fix fullscreen state being updated after entering fullscreen instead of before,
|
||||
resulting in `Window::fullscreen` returning the old state in `Resized` events instead of
|
||||
reflecting the new fullscreen state
|
||||
- On X11, fix use-after-free during window creation
|
||||
- On Windows, disable monitor change keyboard shortcut while in exclusive fullscreen.
|
||||
- On Windows, ensure that changing a borderless fullscreen window's monitor via keyboard shortcuts keeps the window fullscreen on the new monitor.
|
||||
|
||||
# 0.20.0 Alpha 3 (2019-08-14)
|
||||
|
||||
|
|
|
@ -24,8 +24,7 @@ lazy_static = "1"
|
|||
libc = "0.2"
|
||||
log = "0.4"
|
||||
serde = { version = "1", optional = true, features = ["serde_derive"] }
|
||||
derivative = "1.0.2"
|
||||
raw-window-handle = "0.2"
|
||||
raw-window-handle = "0.3"
|
||||
|
||||
[dev-dependencies]
|
||||
image = "0.21"
|
||||
|
|
|
@ -4,6 +4,6 @@ fn main() {
|
|||
let event_loop = EventLoop::new();
|
||||
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
||||
|
||||
dbg!(window.available_monitors());
|
||||
dbg!(window.available_monitors().collect::<Vec<_>>());
|
||||
dbg!(window.primary_monitor());
|
||||
}
|
||||
|
|
|
@ -13,9 +13,7 @@ use instant::Instant;
|
|||
use std::ops::Deref;
|
||||
use std::{error, fmt};
|
||||
|
||||
use crate::event::Event;
|
||||
use crate::monitor::{AvailableMonitorsIter, MonitorHandle};
|
||||
use crate::platform_impl;
|
||||
use crate::{event::Event, monitor::MonitorHandle, platform_impl};
|
||||
|
||||
/// Provides a way to retrieve events from the system and from the windows that were registered to
|
||||
/// the events loop.
|
||||
|
@ -150,10 +148,10 @@ impl<T> EventLoop<T> {
|
|||
/// Returns the list of all the monitors available on the system.
|
||||
#[inline]
|
||||
pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
|
||||
let data = self.event_loop.available_monitors();
|
||||
AvailableMonitorsIter {
|
||||
data: data.into_iter(),
|
||||
}
|
||||
self.event_loop
|
||||
.available_monitors()
|
||||
.into_iter()
|
||||
.map(|inner| MonitorHandle { inner })
|
||||
}
|
||||
|
||||
/// Returns the primary monitor of the system.
|
||||
|
|
|
@ -121,8 +121,6 @@ extern crate log;
|
|||
#[macro_use]
|
||||
extern crate serde;
|
||||
#[macro_use]
|
||||
extern crate derivative;
|
||||
#[macro_use]
|
||||
#[cfg(any(target_os = "ios", target_os = "windows"))]
|
||||
extern crate bitflags;
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
|
|
|
@ -1,63 +1,36 @@
|
|||
//! Types useful for interacting with a user's monitors.
|
||||
//!
|
||||
//! If you want to get basic information about a monitor, you can use the [`MonitorHandle`][monitor_id]
|
||||
//! type. This is retreived from an [`AvailableMonitorsIter`][monitor_iter], which can be acquired
|
||||
//! with:
|
||||
//! type. This is retreived from one of the following methods, which return an iterator of
|
||||
//! [`MonitorHandle`][monitor_id]:
|
||||
//! - [`EventLoop::available_monitors`][loop_get]
|
||||
//! - [`Window::available_monitors`][window_get].
|
||||
//!
|
||||
//! [monitor_id]: ./struct.MonitorHandle.html
|
||||
//! [monitor_iter]: ./struct.AvailableMonitorsIter.html
|
||||
//! [loop_get]: ../event_loop/struct.EventLoop.html#method.available_monitors
|
||||
//! [window_get]: ../window/struct.Window.html#method.available_monitors
|
||||
use std::collections::vec_deque::IntoIter as VecDequeIter;
|
||||
|
||||
use crate::{
|
||||
dpi::{PhysicalPosition, PhysicalSize},
|
||||
platform_impl,
|
||||
};
|
||||
|
||||
/// An iterator over all available monitors.
|
||||
///
|
||||
/// Can be acquired with:
|
||||
/// - [`EventLoop::available_monitors`][loop_get]
|
||||
/// - [`Window::available_monitors`][window_get].
|
||||
///
|
||||
/// [loop_get]: ../event_loop/struct.EventLoop.html#method.available_monitors
|
||||
/// [window_get]: ../window/struct.Window.html#method.available_monitors
|
||||
// Implementation note: we retrieve the list once, then serve each element by one by one.
|
||||
// This may change in the future.
|
||||
#[derive(Debug)]
|
||||
pub struct AvailableMonitorsIter {
|
||||
pub(crate) data: VecDequeIter<platform_impl::MonitorHandle>,
|
||||
}
|
||||
|
||||
impl Iterator for AvailableMonitorsIter {
|
||||
type Item = MonitorHandle;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<MonitorHandle> {
|
||||
self.data.next().map(|id| MonitorHandle { inner: id })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.data.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes a fullscreen video mode of a monitor.
|
||||
///
|
||||
/// Can be acquired with:
|
||||
/// - [`MonitorHandle::video_modes`][monitor_get].
|
||||
///
|
||||
/// [monitor_get]: ../monitor/struct.MonitorHandle.html#method.video_modes
|
||||
#[derive(Derivative)]
|
||||
#[derivative(Clone, Debug = "transparent", PartialEq, Eq, Hash)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub struct VideoMode {
|
||||
pub(crate) video_mode: platform_impl::VideoMode,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for VideoMode {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.video_mode.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for VideoMode {
|
||||
fn partial_cmp(&self, other: &VideoMode) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
|
|
|
@ -34,6 +34,8 @@ impl<T> EventLoopExtWindows for EventLoop<T> {
|
|||
|
||||
/// Additional methods on `Window` that are specific to Windows.
|
||||
pub trait WindowExtWindows {
|
||||
/// Returns the HINSTANCE of the window
|
||||
fn hinstance(&self) -> *mut libc::c_void;
|
||||
/// Returns the native handle that is used by this window.
|
||||
///
|
||||
/// The pointer will become invalid when the native window was destroyed.
|
||||
|
@ -44,6 +46,11 @@ pub trait WindowExtWindows {
|
|||
}
|
||||
|
||||
impl WindowExtWindows for Window {
|
||||
#[inline]
|
||||
fn hinstance(&self) -> *mut libc::c_void {
|
||||
self.window.hinstance() as *mut _
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn hwnd(&self) -> *mut libc::c_void {
|
||||
self.window.hwnd() as *mut _
|
||||
|
|
|
@ -7,11 +7,19 @@ use std::{
|
|||
time::Instant,
|
||||
};
|
||||
|
||||
use smithay_client_toolkit::reexports::protocols::unstable::pointer_constraints::v1::client::{
|
||||
zwp_locked_pointer_v1::ZwpLockedPointerV1, zwp_pointer_constraints_v1::ZwpPointerConstraintsV1,
|
||||
};
|
||||
use smithay_client_toolkit::reexports::protocols::unstable::relative_pointer::v1::client::{
|
||||
zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1,
|
||||
zwp_relative_pointer_v1::ZwpRelativePointerV1,
|
||||
};
|
||||
|
||||
use smithay_client_toolkit::pointer::{AutoPointer, AutoThemer};
|
||||
use smithay_client_toolkit::reexports::client::protocol::{
|
||||
wl_compositor::WlCompositor, wl_shm::WlShm, wl_surface::WlSurface,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
dpi::{PhysicalPosition, PhysicalSize},
|
||||
event::ModifiersState,
|
||||
|
@ -21,6 +29,7 @@ use crate::{
|
|||
sticky_exit_callback, MonitorHandle as PlatformMonitorHandle,
|
||||
VideoMode as PlatformVideoMode,
|
||||
},
|
||||
window::CursorIcon,
|
||||
};
|
||||
|
||||
use super::{window::WindowStore, DeviceId, WindowId};
|
||||
|
@ -69,16 +78,159 @@ impl<T> WindowEventsSink<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct CursorManager {
|
||||
pointer_constraints_proxy: Arc<Mutex<Option<ZwpPointerConstraintsV1>>>,
|
||||
auto_themer: Option<AutoThemer>,
|
||||
pointers: Vec<AutoPointer>,
|
||||
locked_pointers: Vec<ZwpLockedPointerV1>,
|
||||
cursor_visible: bool,
|
||||
current_cursor: CursorIcon,
|
||||
}
|
||||
|
||||
impl CursorManager {
|
||||
fn new(constraints: Arc<Mutex<Option<ZwpPointerConstraintsV1>>>) -> CursorManager {
|
||||
CursorManager {
|
||||
pointer_constraints_proxy: constraints,
|
||||
auto_themer: None,
|
||||
pointers: Vec::new(),
|
||||
locked_pointers: Vec::new(),
|
||||
cursor_visible: true,
|
||||
current_cursor: CursorIcon::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn register_pointer(&mut self, pointer: wl_pointer::WlPointer) {
|
||||
let auto_themer = self
|
||||
.auto_themer
|
||||
.as_ref()
|
||||
.expect("AutoThemer not initialized. Server did not advertise shm or compositor?");
|
||||
self.pointers.push(auto_themer.theme_pointer(pointer));
|
||||
}
|
||||
|
||||
fn set_auto_themer(&mut self, auto_themer: AutoThemer) {
|
||||
self.auto_themer = Some(auto_themer);
|
||||
}
|
||||
|
||||
pub fn set_cursor_visible(&mut self, visible: bool) {
|
||||
if !visible {
|
||||
for pointer in self.pointers.iter() {
|
||||
(**pointer).set_cursor(0, None, 0, 0);
|
||||
}
|
||||
} else {
|
||||
self.set_cursor_icon_impl(self.current_cursor);
|
||||
}
|
||||
self.cursor_visible = visible;
|
||||
}
|
||||
|
||||
/// A helper function to restore cursor styles on PtrEvent::Enter.
|
||||
pub fn reload_cursor_style(&mut self) {
|
||||
if !self.cursor_visible {
|
||||
self.set_cursor_visible(false);
|
||||
} else {
|
||||
self.set_cursor_icon_impl(self.current_cursor);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_cursor_icon(&mut self, cursor: CursorIcon) {
|
||||
if self.cursor_visible && cursor != self.current_cursor {
|
||||
self.current_cursor = cursor;
|
||||
|
||||
self.set_cursor_icon_impl(cursor);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_cursor_icon_impl(&mut self, cursor: CursorIcon) {
|
||||
let cursor = match cursor {
|
||||
CursorIcon::Alias => "link",
|
||||
CursorIcon::Arrow => "arrow",
|
||||
CursorIcon::Cell => "plus",
|
||||
CursorIcon::Copy => "copy",
|
||||
CursorIcon::Crosshair => "crosshair",
|
||||
CursorIcon::Default => "left_ptr",
|
||||
CursorIcon::Hand => "hand",
|
||||
CursorIcon::Help => "question_arrow",
|
||||
CursorIcon::Move => "move",
|
||||
CursorIcon::Grab => "grab",
|
||||
CursorIcon::Grabbing => "grabbing",
|
||||
CursorIcon::Progress => "progress",
|
||||
CursorIcon::AllScroll => "all-scroll",
|
||||
CursorIcon::ContextMenu => "context-menu",
|
||||
|
||||
CursorIcon::NoDrop => "no-drop",
|
||||
CursorIcon::NotAllowed => "crossed_circle",
|
||||
|
||||
// Resize cursors
|
||||
CursorIcon::EResize => "right_side",
|
||||
CursorIcon::NResize => "top_side",
|
||||
CursorIcon::NeResize => "top_right_corner",
|
||||
CursorIcon::NwResize => "top_left_corner",
|
||||
CursorIcon::SResize => "bottom_side",
|
||||
CursorIcon::SeResize => "bottom_right_corner",
|
||||
CursorIcon::SwResize => "bottom_left_corner",
|
||||
CursorIcon::WResize => "left_side",
|
||||
CursorIcon::EwResize => "h_double_arrow",
|
||||
CursorIcon::NsResize => "v_double_arrow",
|
||||
CursorIcon::NwseResize => "bd_double_arrow",
|
||||
CursorIcon::NeswResize => "fd_double_arrow",
|
||||
CursorIcon::ColResize => "h_double_arrow",
|
||||
CursorIcon::RowResize => "v_double_arrow",
|
||||
|
||||
CursorIcon::Text => "text",
|
||||
CursorIcon::VerticalText => "vertical-text",
|
||||
|
||||
CursorIcon::Wait => "watch",
|
||||
|
||||
CursorIcon::ZoomIn => "zoom-in",
|
||||
CursorIcon::ZoomOut => "zoom-out",
|
||||
};
|
||||
|
||||
for pointer in self.pointers.iter() {
|
||||
// Ignore erros, since we don't want to fail hard in case we can't find a proper cursor
|
||||
// in a given theme.
|
||||
let _ = pointer.set_cursor(cursor, None);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn grab_pointer(&mut self, surface: Option<&WlSurface>) {
|
||||
for locked_pointer in self.locked_pointers.drain(..) {
|
||||
locked_pointer.destroy();
|
||||
}
|
||||
|
||||
if let Some(surface) = surface {
|
||||
for pointer in self.pointers.iter() {
|
||||
let locked_pointer = self
|
||||
.pointer_constraints_proxy
|
||||
.try_lock()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.and_then(|pointer_constraints| {
|
||||
super::pointer::implement_locked_pointer(
|
||||
surface,
|
||||
&**pointer,
|
||||
pointer_constraints,
|
||||
)
|
||||
.ok()
|
||||
});
|
||||
|
||||
if let Some(locked_pointer) = locked_pointer {
|
||||
self.locked_pointers.push(locked_pointer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct EventLoop<T: 'static> {
|
||||
// The loop
|
||||
inner_loop: ::calloop::EventLoop<()>,
|
||||
// The wayland display
|
||||
pub display: Arc<Display>,
|
||||
// the output manager
|
||||
// The output manager
|
||||
pub outputs: OutputMgr,
|
||||
// our sink, shared with some handlers, buffering the events
|
||||
// Our sink, shared with some handlers, buffering the events
|
||||
sink: Arc<Mutex<WindowEventsSink<T>>>,
|
||||
pending_user_events: Rc<RefCell<VecDeque<T>>>,
|
||||
// Utility for grabbing the cursor and changing visibility
|
||||
_user_source: ::calloop::Source<::calloop::channel::Channel<T>>,
|
||||
user_sender: ::calloop::channel::Sender<T>,
|
||||
_kbd_source: ::calloop::Source<
|
||||
|
@ -91,17 +243,19 @@ pub struct EventLoop<T: 'static> {
|
|||
//
|
||||
// We should only try and wake up the `EventLoop` if it still exists, so we hold Weak ptrs.
|
||||
pub struct EventLoopProxy<T: 'static> {
|
||||
user_sender: ::calloop::channel::Sender<T>,
|
||||
user_sender: calloop::channel::Sender<T>,
|
||||
}
|
||||
|
||||
pub struct EventLoopWindowTarget<T> {
|
||||
// the event queue
|
||||
// The event queue
|
||||
pub evq: RefCell<::calloop::Source<EventQueue>>,
|
||||
// The window store
|
||||
pub store: Arc<Mutex<WindowStore>>,
|
||||
// the env
|
||||
// The cursor manager
|
||||
pub cursor_manager: Arc<Mutex<CursorManager>>,
|
||||
// The env
|
||||
pub env: Environment,
|
||||
// a cleanup switch to prune dead windows
|
||||
// A cleanup switch to prune dead windows
|
||||
pub cleanup_needed: Arc<Mutex<bool>>,
|
||||
// The wayland display
|
||||
pub display: Arc<Display>,
|
||||
|
@ -146,14 +300,24 @@ impl<T: 'static> EventLoop<T> {
|
|||
})
|
||||
.unwrap();
|
||||
|
||||
let pointer_constraints_proxy = Arc::new(Mutex::new(None));
|
||||
|
||||
let mut seat_manager = SeatManager {
|
||||
sink: sink.clone(),
|
||||
relative_pointer_manager_proxy: Rc::new(RefCell::new(None)),
|
||||
pointer_constraints_proxy: pointer_constraints_proxy.clone(),
|
||||
store: store.clone(),
|
||||
seats: seats.clone(),
|
||||
kbd_sender,
|
||||
cursor_manager: Arc::new(Mutex::new(CursorManager::new(pointer_constraints_proxy))),
|
||||
};
|
||||
|
||||
let cursor_manager = seat_manager.cursor_manager.clone();
|
||||
let cursor_manager_clone = cursor_manager.clone();
|
||||
|
||||
let shm_cell = Rc::new(RefCell::new(None));
|
||||
let compositor_cell = Rc::new(RefCell::new(None));
|
||||
|
||||
let env = Environment::from_display_with_cb(
|
||||
&display,
|
||||
&mut event_queue,
|
||||
|
@ -175,6 +339,42 @@ impl<T: 'static> EventLoop<T> {
|
|||
.try_borrow_mut()
|
||||
.unwrap() = Some(relative_pointer_manager_proxy);
|
||||
}
|
||||
if interface == "zwp_pointer_constraints_v1" {
|
||||
let pointer_constraints_proxy = registry
|
||||
.bind(version, id, move |pointer_constraints| {
|
||||
pointer_constraints.implement_closure(|_, _| (), ())
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
*seat_manager.pointer_constraints_proxy.lock().unwrap() =
|
||||
Some(pointer_constraints_proxy);
|
||||
}
|
||||
if interface == "wl_shm" {
|
||||
let shm: WlShm = registry
|
||||
.bind(version, id, move |shm| shm.implement_closure(|_, _| (), ()))
|
||||
.unwrap();
|
||||
|
||||
(*shm_cell.borrow_mut()) = Some(shm);
|
||||
}
|
||||
if interface == "wl_compositor" {
|
||||
let compositor: WlCompositor = registry
|
||||
.bind(version, id, move |compositor| {
|
||||
compositor.implement_closure(|_, _| (), ())
|
||||
})
|
||||
.unwrap();
|
||||
(*compositor_cell.borrow_mut()) = Some(compositor);
|
||||
}
|
||||
|
||||
if compositor_cell.borrow().is_some() && shm_cell.borrow().is_some() {
|
||||
let compositor = compositor_cell.borrow_mut().take().unwrap();
|
||||
let shm = shm_cell.borrow_mut().take().unwrap();
|
||||
let auto_themer = AutoThemer::init(None, compositor, &shm);
|
||||
cursor_manager_clone
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_auto_themer(auto_themer);
|
||||
}
|
||||
|
||||
if interface == "wl_seat" {
|
||||
seat_manager.add_seat(id, version, registry)
|
||||
}
|
||||
|
@ -207,6 +407,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
})
|
||||
.unwrap();
|
||||
|
||||
let cursor_manager_clone = cursor_manager.clone();
|
||||
Ok(EventLoop {
|
||||
inner_loop,
|
||||
sink,
|
||||
|
@ -221,6 +422,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
evq: RefCell::new(source),
|
||||
store,
|
||||
env,
|
||||
cursor_manager: cursor_manager_clone,
|
||||
cleanup_needed: Arc::new(Mutex::new(false)),
|
||||
seats,
|
||||
display,
|
||||
|
@ -242,7 +444,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
F: 'static + FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||
{
|
||||
self.run_return(callback);
|
||||
::std::process::exit(0);
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
pub fn run_return<F>(&mut self, mut callback: F)
|
||||
|
@ -497,6 +699,8 @@ struct SeatManager<T: 'static> {
|
|||
seats: Arc<Mutex<Vec<(u32, wl_seat::WlSeat)>>>,
|
||||
kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>,
|
||||
relative_pointer_manager_proxy: Rc<RefCell<Option<ZwpRelativePointerManagerV1>>>,
|
||||
pointer_constraints_proxy: Arc<Mutex<Option<ZwpPointerConstraintsV1>>>,
|
||||
cursor_manager: Arc<Mutex<CursorManager>>,
|
||||
}
|
||||
|
||||
impl<T: 'static> SeatManager<T> {
|
||||
|
@ -513,6 +717,7 @@ impl<T: 'static> SeatManager<T> {
|
|||
touch: None,
|
||||
kbd_sender: self.kbd_sender.clone(),
|
||||
modifiers_tracker: Arc::new(Mutex::new(ModifiersState::default())),
|
||||
cursor_manager: self.cursor_manager.clone(),
|
||||
};
|
||||
let seat = registry
|
||||
.bind(min(version, 5), id, move |seat| {
|
||||
|
@ -544,6 +749,7 @@ struct SeatData<T> {
|
|||
keyboard: Option<wl_keyboard::WlKeyboard>,
|
||||
touch: Option<wl_touch::WlTouch>,
|
||||
modifiers_tracker: Arc<Mutex<ModifiersState>>,
|
||||
cursor_manager: Arc<Mutex<CursorManager>>,
|
||||
}
|
||||
|
||||
impl<T: 'static> SeatData<T> {
|
||||
|
@ -558,8 +764,14 @@ impl<T: 'static> SeatData<T> {
|
|||
self.sink.clone(),
|
||||
self.store.clone(),
|
||||
self.modifiers_tracker.clone(),
|
||||
self.cursor_manager.clone(),
|
||||
));
|
||||
|
||||
self.cursor_manager
|
||||
.lock()
|
||||
.unwrap()
|
||||
.register_pointer(self.pointer.as_ref().unwrap().clone());
|
||||
|
||||
self.relative_pointer = self
|
||||
.relative_pointer_manager_proxy
|
||||
.try_borrow()
|
||||
|
|
|
@ -5,7 +5,11 @@ use crate::event::{
|
|||
WindowEvent,
|
||||
};
|
||||
|
||||
use super::{event_loop::WindowEventsSink, window::WindowStore, DeviceId};
|
||||
use super::{
|
||||
event_loop::{CursorManager, WindowEventsSink},
|
||||
window::WindowStore,
|
||||
DeviceId,
|
||||
};
|
||||
|
||||
use smithay_client_toolkit::reexports::client::protocol::{
|
||||
wl_pointer::{self, Event as PtrEvent, WlPointer},
|
||||
|
@ -17,11 +21,19 @@ use smithay_client_toolkit::reexports::protocols::unstable::relative_pointer::v1
|
|||
zwp_relative_pointer_v1::ZwpRelativePointerV1,
|
||||
};
|
||||
|
||||
use smithay_client_toolkit::reexports::protocols::unstable::pointer_constraints::v1::client::{
|
||||
zwp_locked_pointer_v1::ZwpLockedPointerV1, zwp_pointer_constraints_v1::Lifetime,
|
||||
zwp_pointer_constraints_v1::ZwpPointerConstraintsV1,
|
||||
};
|
||||
|
||||
use smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface;
|
||||
|
||||
pub fn implement_pointer<T: 'static>(
|
||||
seat: &wl_seat::WlSeat,
|
||||
sink: Arc<Mutex<WindowEventsSink<T>>>,
|
||||
store: Arc<Mutex<WindowStore>>,
|
||||
modifiers_tracker: Arc<Mutex<ModifiersState>>,
|
||||
cursor_manager: Arc<Mutex<CursorManager>>,
|
||||
) -> WlPointer {
|
||||
seat.get_pointer(|pointer| {
|
||||
let mut mouse_focus = None;
|
||||
|
@ -33,6 +45,7 @@ pub fn implement_pointer<T: 'static>(
|
|||
move |evt, pointer| {
|
||||
let mut sink = sink.lock().unwrap();
|
||||
let store = store.lock().unwrap();
|
||||
let mut cursor_manager = cursor_manager.lock().unwrap();
|
||||
match evt {
|
||||
PtrEvent::Enter {
|
||||
surface,
|
||||
|
@ -62,6 +75,8 @@ pub fn implement_pointer<T: 'static>(
|
|||
wid,
|
||||
);
|
||||
}
|
||||
|
||||
cursor_manager.reload_cursor_style();
|
||||
}
|
||||
PtrEvent::Leave { surface, .. } => {
|
||||
mouse_focus = None;
|
||||
|
@ -241,3 +256,13 @@ pub fn implement_relative_pointer<T: 'static>(
|
|||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn implement_locked_pointer(
|
||||
surface: &WlSurface,
|
||||
pointer: &WlPointer,
|
||||
constraints: &ZwpPointerConstraintsV1,
|
||||
) -> Result<ZwpLockedPointerV1, ()> {
|
||||
constraints.lock_pointer(surface, pointer, None, Lifetime::Persistent.to_raw(), |c| {
|
||||
c.implement_closure(|_, _| (), ())
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use raw_window_handle::unix::WaylandHandle;
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
mem::replace,
|
||||
sync::{Arc, Mutex, Weak},
|
||||
};
|
||||
|
||||
|
@ -26,11 +27,12 @@ use smithay_client_toolkit::{
|
|||
window::{ConceptFrame, Event as WEvent, State as WState, Theme, Window as SWindow},
|
||||
};
|
||||
|
||||
use super::{make_wid, EventLoopWindowTarget, MonitorHandle, WindowId};
|
||||
use super::{event_loop::CursorManager, make_wid, EventLoopWindowTarget, MonitorHandle, WindowId};
|
||||
|
||||
pub struct Window {
|
||||
surface: wl_surface::WlSurface,
|
||||
frame: Arc<Mutex<SWindow<ConceptFrame>>>,
|
||||
cursor_manager: Arc<Mutex<CursorManager>>,
|
||||
outputs: OutputMgr, // Access to info for all monitors
|
||||
size: Arc<Mutex<(u32, u32)>>,
|
||||
kill_switch: (Arc<Mutex<bool>>, Arc<Mutex<bool>>),
|
||||
|
@ -52,6 +54,7 @@ impl Window {
|
|||
let fullscreen = Arc::new(Mutex::new(false));
|
||||
|
||||
let window_store = evlp.store.clone();
|
||||
let cursor_manager = evlp.cursor_manager.clone();
|
||||
let surface = evlp.env.create_surface(move |dpi, surface| {
|
||||
window_store.lock().unwrap().dpi_change(&surface, dpi);
|
||||
surface.set_buffer_scale(dpi);
|
||||
|
@ -165,6 +168,7 @@ impl Window {
|
|||
kill_switch: (kill_switch, evlp.cleanup_needed.clone()),
|
||||
need_frame_refresh,
|
||||
need_refresh,
|
||||
cursor_manager,
|
||||
fullscreen,
|
||||
})
|
||||
}
|
||||
|
@ -292,18 +296,26 @@ impl Window {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_icon(&self, _cursor: CursorIcon) {
|
||||
// TODO
|
||||
pub fn set_cursor_icon(&self, cursor: CursorIcon) {
|
||||
let mut cursor_manager = self.cursor_manager.lock().unwrap();
|
||||
cursor_manager.set_cursor_icon(cursor);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_visible(&self, _visible: bool) {
|
||||
// TODO: This isn't possible on Wayland yet
|
||||
pub fn set_cursor_visible(&self, visible: bool) {
|
||||
let mut cursor_manager = self.cursor_manager.lock().unwrap();
|
||||
cursor_manager.set_cursor_visible(visible);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_grab(&self, _grab: bool) -> Result<(), ExternalError> {
|
||||
Err(ExternalError::NotSupported(NotSupportedError::new()))
|
||||
pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> {
|
||||
let mut cursor_manager = self.cursor_manager.lock().unwrap();
|
||||
if grab {
|
||||
cursor_manager.grab_pointer(Some(&self.surface));
|
||||
} else {
|
||||
cursor_manager.grab_pointer(None);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -440,8 +452,8 @@ impl WindowStore {
|
|||
window.newsize.take(),
|
||||
&mut *(window.size.lock().unwrap()),
|
||||
window.new_dpi,
|
||||
::std::mem::replace(&mut *window.need_refresh.lock().unwrap(), false),
|
||||
::std::mem::replace(&mut *window.need_frame_refresh.lock().unwrap(), false),
|
||||
replace(&mut *window.need_refresh.lock().unwrap(), false),
|
||||
replace(&mut *window.need_frame_refresh.lock().unwrap(), false),
|
||||
window.closed,
|
||||
make_wid(&window.surface),
|
||||
opt_mutex_lock.as_mut().map(|m| &mut **m),
|
||||
|
|
|
@ -99,7 +99,8 @@ impl XConnection {
|
|||
// video mode is returned to the user
|
||||
monitor: None,
|
||||
}
|
||||
});
|
||||
})
|
||||
.collect();
|
||||
|
||||
let name_slice = slice::from_raw_parts(
|
||||
(*output_info).name as *mut u8,
|
||||
|
@ -119,7 +120,7 @@ impl XConnection {
|
|||
};
|
||||
|
||||
(self.xrandr.XRRFreeOutputInfo)(output_info);
|
||||
Some((name, hidpi_factor, modes.collect()))
|
||||
Some((name, hidpi_factor, modes))
|
||||
}
|
||||
pub fn set_crtc_config(&self, crtc_id: RRCrtc, mode_id: RRMode) -> Result<(), ()> {
|
||||
unsafe {
|
||||
|
|
|
@ -22,17 +22,46 @@ use core_video_sys::{
|
|||
CVDisplayLinkGetNominalOutputVideoRefreshPeriod, CVDisplayLinkRelease,
|
||||
};
|
||||
|
||||
#[derive(Derivative)]
|
||||
#[derivative(Debug, Clone, PartialEq, Hash)]
|
||||
#[derive(Clone)]
|
||||
pub struct VideoMode {
|
||||
pub(crate) size: (u32, u32),
|
||||
pub(crate) bit_depth: u16,
|
||||
pub(crate) refresh_rate: u16,
|
||||
pub(crate) monitor: MonitorHandle,
|
||||
#[derivative(Debug = "ignore", PartialEq = "ignore", Hash = "ignore")]
|
||||
pub(crate) native_mode: NativeDisplayMode,
|
||||
}
|
||||
|
||||
impl PartialEq for VideoMode {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.size == other.size
|
||||
&& self.bit_depth == other.bit_depth
|
||||
&& self.refresh_rate == other.refresh_rate
|
||||
&& self.monitor == other.monitor
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for VideoMode {}
|
||||
|
||||
impl std::hash::Hash for VideoMode {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.size.hash(state);
|
||||
self.bit_depth.hash(state);
|
||||
self.refresh_rate.hash(state);
|
||||
self.monitor.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for VideoMode {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("VideoMode")
|
||||
.field("size", &self.size)
|
||||
.field("bit_depth", &self.bit_depth)
|
||||
.field("refresh_rate", &self.refresh_rate)
|
||||
.field("monitor", &self.monitor)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NativeDisplayMode(pub ffi::CGDisplayModeRef);
|
||||
|
||||
unsafe impl Send for NativeDisplayMode {}
|
||||
|
|
|
@ -402,7 +402,24 @@ extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) {
|
|||
with_state(this, |state| {
|
||||
state.with_window(|window| {
|
||||
trace!("Locked shared state in `window_will_enter_fullscreen`");
|
||||
window.shared_state.lock().unwrap().maximized = window.is_zoomed();
|
||||
let mut shared_state = window.shared_state.lock().unwrap();
|
||||
shared_state.maximized = window.is_zoomed();
|
||||
match shared_state.fullscreen {
|
||||
// Exclusive mode sets the state in `set_fullscreen` as the user
|
||||
// can't enter exclusive mode by other means (like the
|
||||
// fullscreen button on the window decorations)
|
||||
Some(Fullscreen::Exclusive(_)) => (),
|
||||
// `window_will_enter_fullscreen` was triggered and we're already
|
||||
// in fullscreen, so we must've reached here by `set_fullscreen`
|
||||
// as it updates the state
|
||||
Some(Fullscreen::Borderless(_)) => (),
|
||||
// Otherwise, we must've reached fullscreen by the user clicking
|
||||
// on the green fullscreen button. Update state!
|
||||
None => {
|
||||
shared_state.fullscreen = Some(Fullscreen::Borderless(window.current_monitor()))
|
||||
}
|
||||
}
|
||||
|
||||
trace!("Unlocked shared state in `window_will_enter_fullscreen`");
|
||||
})
|
||||
});
|
||||
|
@ -433,25 +450,6 @@ extern "C" fn window_will_use_fullscreen_presentation_options(
|
|||
extern "C" fn window_did_enter_fullscreen(this: &Object, _: Sel, _: id) {
|
||||
trace!("Triggered `windowDidEnterFullscreen:`");
|
||||
with_state(this, |state| {
|
||||
state.with_window(|window| {
|
||||
let monitor = window.current_monitor();
|
||||
trace!("Locked shared state in `window_did_enter_fullscreen`");
|
||||
let mut shared_state = window.shared_state.lock().unwrap();
|
||||
match shared_state.fullscreen {
|
||||
// Exclusive mode sets the state in `set_fullscreen` as the user
|
||||
// can't enter exclusive mode by other means (like the
|
||||
// fullscreen button on the window decorations)
|
||||
Some(Fullscreen::Exclusive(_)) => (),
|
||||
// `window_did_enter_fullscreen` was triggered and we're already
|
||||
// in fullscreen, so we must've reached here by `set_fullscreen`
|
||||
// as it updates the state
|
||||
Some(Fullscreen::Borderless(_)) => (),
|
||||
// Otherwise, we must've reached fullscreen by the user clicking
|
||||
// on the green fullscreen button. Update state!
|
||||
None => shared_state.fullscreen = Some(Fullscreen::Borderless(monitor)),
|
||||
}
|
||||
trace!("Unlocked shared state in `window_did_enter_fullscreen`");
|
||||
});
|
||||
state.initial_fullscreen = false;
|
||||
});
|
||||
trace!("Completed `windowDidEnterFullscreen:`");
|
||||
|
|
|
@ -54,13 +54,14 @@ use crate::{
|
|||
},
|
||||
drop_handler::FileDropHandler,
|
||||
event::{self, handle_extended_keys, process_key_params, vkey_to_winit_vkey},
|
||||
monitor,
|
||||
raw_input::{get_raw_input_data, get_raw_mouse_button_state},
|
||||
util,
|
||||
window::adjust_size,
|
||||
window_state::{CursorFlags, WindowFlags, WindowState},
|
||||
wrap_device_id, WindowId, DEVICE_ID,
|
||||
},
|
||||
window::WindowId as RootWindowId,
|
||||
window::{Fullscreen, WindowId as RootWindowId},
|
||||
};
|
||||
|
||||
type GetPointerFrameInfoHistory = unsafe extern "system" fn(
|
||||
|
@ -982,6 +983,51 @@ unsafe extern "system" fn public_window_callback<T>(
|
|||
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
||||
}
|
||||
|
||||
winuser::WM_WINDOWPOSCHANGING => {
|
||||
let mut window_state = subclass_input.window_state.lock();
|
||||
if let Some(ref mut fullscreen) = window_state.fullscreen {
|
||||
let window_pos = &mut *(lparam as *mut winuser::WINDOWPOS);
|
||||
let new_rect = RECT {
|
||||
left: window_pos.x,
|
||||
top: window_pos.y,
|
||||
right: window_pos.x + window_pos.cx,
|
||||
bottom: window_pos.y + window_pos.cy,
|
||||
};
|
||||
let new_monitor =
|
||||
winuser::MonitorFromRect(&new_rect, winuser::MONITOR_DEFAULTTONULL);
|
||||
match fullscreen {
|
||||
Fullscreen::Borderless(ref mut fullscreen_monitor) => {
|
||||
if new_monitor != fullscreen_monitor.inner.hmonitor()
|
||||
&& new_monitor != ptr::null_mut()
|
||||
{
|
||||
if let Ok(new_monitor_info) = monitor::get_monitor_info(new_monitor) {
|
||||
let new_monitor_rect = new_monitor_info.rcMonitor;
|
||||
window_pos.x = new_monitor_rect.left;
|
||||
window_pos.y = new_monitor_rect.top;
|
||||
window_pos.cx = new_monitor_rect.right - new_monitor_rect.left;
|
||||
window_pos.cy = new_monitor_rect.bottom - new_monitor_rect.top;
|
||||
}
|
||||
*fullscreen_monitor = crate::monitor::MonitorHandle {
|
||||
inner: monitor::MonitorHandle::new(new_monitor),
|
||||
};
|
||||
}
|
||||
}
|
||||
Fullscreen::Exclusive(ref video_mode) => {
|
||||
let old_monitor = video_mode.video_mode.monitor.hmonitor();
|
||||
if let Ok(old_monitor_info) = monitor::get_monitor_info(old_monitor) {
|
||||
let old_monitor_rect = old_monitor_info.rcMonitor;
|
||||
window_pos.x = old_monitor_rect.left;
|
||||
window_pos.y = old_monitor_rect.top;
|
||||
window_pos.cx = old_monitor_rect.right - old_monitor_rect.left;
|
||||
window_pos.cy = old_monitor_rect.bottom - old_monitor_rect.top;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
// WM_MOVE supplies client area positions, so we send Moved here instead.
|
||||
winuser::WM_WINDOWPOSCHANGED => {
|
||||
use crate::event::WindowEvent::Moved;
|
||||
|
|
|
@ -21,17 +21,46 @@ use crate::{
|
|||
},
|
||||
};
|
||||
|
||||
#[derive(Derivative)]
|
||||
#[derivative(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
#[derive(Clone)]
|
||||
pub struct VideoMode {
|
||||
pub(crate) size: (u32, u32),
|
||||
pub(crate) bit_depth: u16,
|
||||
pub(crate) refresh_rate: u16,
|
||||
pub(crate) monitor: MonitorHandle,
|
||||
#[derivative(Debug = "ignore", PartialEq = "ignore", Hash = "ignore")]
|
||||
pub(crate) native_video_mode: wingdi::DEVMODEW,
|
||||
}
|
||||
|
||||
impl PartialEq for VideoMode {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.size == other.size
|
||||
&& self.bit_depth == other.bit_depth
|
||||
&& self.refresh_rate == other.refresh_rate
|
||||
&& self.monitor == other.monitor
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for VideoMode {}
|
||||
|
||||
impl std::hash::Hash for VideoMode {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.size.hash(state);
|
||||
self.bit_depth.hash(state);
|
||||
self.refresh_rate.hash(state);
|
||||
self.monitor.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for VideoMode {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("VideoMode")
|
||||
.field("size", &self.size)
|
||||
.field("bit_depth", &self.bit_depth)
|
||||
.field("refresh_rate", &self.refresh_rate)
|
||||
.field("monitor", &self.monitor)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl VideoMode {
|
||||
pub fn size(&self) -> PhysicalSize {
|
||||
self.size.into()
|
||||
|
|
|
@ -14,7 +14,7 @@ use std::{
|
|||
use winapi::{
|
||||
ctypes::c_int,
|
||||
shared::{
|
||||
minwindef::{DWORD, LPARAM, UINT, WORD, WPARAM},
|
||||
minwindef::{DWORD, HINSTANCE, LPARAM, UINT, WORD, WPARAM},
|
||||
windef::{HWND, POINT, RECT},
|
||||
},
|
||||
um::{
|
||||
|
@ -358,10 +358,16 @@ impl Window {
|
|||
self.window.0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn hinstance(&self) -> HINSTANCE {
|
||||
unsafe { winuser::GetWindowLongW(self.hwnd(), winuser::GWL_HINSTANCE) as *mut _ }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn raw_window_handle(&self) -> RawWindowHandle {
|
||||
let handle = WindowsHandle {
|
||||
hwnd: self.window.0 as *mut _,
|
||||
hinstance: self.hinstance() as *mut _,
|
||||
..WindowsHandle::empty()
|
||||
};
|
||||
RawWindowHandle::Windows(handle)
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
dpi::{LogicalPosition, LogicalSize},
|
||||
error::{ExternalError, NotSupportedError, OsError},
|
||||
event_loop::EventLoopWindowTarget,
|
||||
monitor::{AvailableMonitorsIter, MonitorHandle, VideoMode},
|
||||
monitor::{MonitorHandle, VideoMode},
|
||||
platform_impl,
|
||||
};
|
||||
|
||||
|
@ -674,6 +674,8 @@ impl Window {
|
|||
///
|
||||
/// - **macOS:** This presently merely locks the cursor in a fixed location, which looks visually
|
||||
/// awkward.
|
||||
/// - **Wayland:** This presently merely locks the cursor in a fixed location, which looks visually
|
||||
/// awkward.
|
||||
/// - **Android:** Has no effect.
|
||||
/// - **iOS:** Always returns an Err.
|
||||
/// - **Web:** Has no effect.
|
||||
|
@ -690,6 +692,7 @@ impl Window {
|
|||
///
|
||||
/// - **Windows:** The cursor is only hidden within the confines of the window.
|
||||
/// - **X11:** The cursor is only hidden within the confines of the window.
|
||||
/// - **Wayland:** The cursor is only hidden within the confines of the window.
|
||||
/// - **macOS:** The cursor is hidden as long as the window has input focus, even if the cursor is
|
||||
/// outside of the window.
|
||||
/// - **iOS:** Has no effect.
|
||||
|
@ -720,11 +723,11 @@ impl Window {
|
|||
///
|
||||
/// **iOS:** Can only be called on the main thread.
|
||||
#[inline]
|
||||
pub fn available_monitors(&self) -> AvailableMonitorsIter {
|
||||
let data = self.window.available_monitors();
|
||||
AvailableMonitorsIter {
|
||||
data: data.into_iter(),
|
||||
}
|
||||
pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
|
||||
self.window
|
||||
.available_monitors()
|
||||
.into_iter()
|
||||
.map(|inner| MonitorHandle { inner })
|
||||
}
|
||||
|
||||
/// Returns the primary monitor of the system.
|
||||
|
|
Loading…
Reference in a new issue