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
|
# Unreleased
|
||||||
|
|
||||||
- Add web support via the 'stdweb' or 'web-sys' features
|
- Add web support via the 'stdweb' or 'web-sys' features
|
||||||
|
- On Windows, implemented function to get HINSTANCE
|
||||||
- On macOS, implement `run_return`.
|
- On macOS, implement `run_return`.
|
||||||
- On iOS, fix inverted parameter in `set_prefers_home_indicator_hidden`.
|
- On iOS, fix inverted parameter in `set_prefers_home_indicator_hidden`.
|
||||||
- On X11, performance is improved when rapidly calling `Window::set_cursor_icon`.
|
- 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, return dummy monitor data to avoid panicking when no monitors exist.
|
||||||
- On X11, prevent stealing input focus when creating a new window.
|
- On X11, prevent stealing input focus when creating a new window.
|
||||||
Only steal input focus when entering fullscreen mode.
|
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)
|
# 0.20.0 Alpha 3 (2019-08-14)
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,7 @@ lazy_static = "1"
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
serde = { version = "1", optional = true, features = ["serde_derive"] }
|
serde = { version = "1", optional = true, features = ["serde_derive"] }
|
||||||
derivative = "1.0.2"
|
raw-window-handle = "0.3"
|
||||||
raw-window-handle = "0.2"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
image = "0.21"
|
image = "0.21"
|
||||||
|
|
|
@ -4,6 +4,6 @@ fn main() {
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
||||||
|
|
||||||
dbg!(window.available_monitors());
|
dbg!(window.available_monitors().collect::<Vec<_>>());
|
||||||
dbg!(window.primary_monitor());
|
dbg!(window.primary_monitor());
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,7 @@ use instant::Instant;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::{error, fmt};
|
use std::{error, fmt};
|
||||||
|
|
||||||
use crate::event::Event;
|
use crate::{event::Event, monitor::MonitorHandle, platform_impl};
|
||||||
use crate::monitor::{AvailableMonitorsIter, MonitorHandle};
|
|
||||||
use crate::platform_impl;
|
|
||||||
|
|
||||||
/// Provides a way to retrieve events from the system and from the windows that were registered to
|
/// Provides a way to retrieve events from the system and from the windows that were registered to
|
||||||
/// the events loop.
|
/// the events loop.
|
||||||
|
@ -150,10 +148,10 @@ impl<T> EventLoop<T> {
|
||||||
/// Returns the list of all the monitors available on the system.
|
/// Returns the list of all the monitors available on the system.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
|
pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
|
||||||
let data = self.event_loop.available_monitors();
|
self.event_loop
|
||||||
AvailableMonitorsIter {
|
.available_monitors()
|
||||||
data: data.into_iter(),
|
.into_iter()
|
||||||
}
|
.map(|inner| MonitorHandle { inner })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the primary monitor of the system.
|
/// Returns the primary monitor of the system.
|
||||||
|
|
|
@ -121,8 +121,6 @@ extern crate log;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate derivative;
|
|
||||||
#[macro_use]
|
|
||||||
#[cfg(any(target_os = "ios", target_os = "windows"))]
|
#[cfg(any(target_os = "ios", target_os = "windows"))]
|
||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||||
|
|
|
@ -1,63 +1,36 @@
|
||||||
//! Types useful for interacting with a user's monitors.
|
//! 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]
|
//! 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
|
//! type. This is retreived from one of the following methods, which return an iterator of
|
||||||
//! with:
|
//! [`MonitorHandle`][monitor_id]:
|
||||||
//! - [`EventLoop::available_monitors`][loop_get]
|
//! - [`EventLoop::available_monitors`][loop_get]
|
||||||
//! - [`Window::available_monitors`][window_get].
|
//! - [`Window::available_monitors`][window_get].
|
||||||
//!
|
//!
|
||||||
//! [monitor_id]: ./struct.MonitorHandle.html
|
//! [monitor_id]: ./struct.MonitorHandle.html
|
||||||
//! [monitor_iter]: ./struct.AvailableMonitorsIter.html
|
|
||||||
//! [loop_get]: ../event_loop/struct.EventLoop.html#method.available_monitors
|
//! [loop_get]: ../event_loop/struct.EventLoop.html#method.available_monitors
|
||||||
//! [window_get]: ../window/struct.Window.html#method.available_monitors
|
//! [window_get]: ../window/struct.Window.html#method.available_monitors
|
||||||
use std::collections::vec_deque::IntoIter as VecDequeIter;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
dpi::{PhysicalPosition, PhysicalSize},
|
dpi::{PhysicalPosition, PhysicalSize},
|
||||||
platform_impl,
|
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.
|
/// Describes a fullscreen video mode of a monitor.
|
||||||
///
|
///
|
||||||
/// Can be acquired with:
|
/// Can be acquired with:
|
||||||
/// - [`MonitorHandle::video_modes`][monitor_get].
|
/// - [`MonitorHandle::video_modes`][monitor_get].
|
||||||
///
|
///
|
||||||
/// [monitor_get]: ../monitor/struct.MonitorHandle.html#method.video_modes
|
/// [monitor_get]: ../monitor/struct.MonitorHandle.html#method.video_modes
|
||||||
#[derive(Derivative)]
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
#[derivative(Clone, Debug = "transparent", PartialEq, Eq, Hash)]
|
|
||||||
pub struct VideoMode {
|
pub struct VideoMode {
|
||||||
pub(crate) video_mode: platform_impl::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 {
|
impl PartialOrd for VideoMode {
|
||||||
fn partial_cmp(&self, other: &VideoMode) -> Option<std::cmp::Ordering> {
|
fn partial_cmp(&self, other: &VideoMode) -> Option<std::cmp::Ordering> {
|
||||||
Some(self.cmp(other))
|
Some(self.cmp(other))
|
||||||
|
|
|
@ -34,6 +34,8 @@ impl<T> EventLoopExtWindows for EventLoop<T> {
|
||||||
|
|
||||||
/// Additional methods on `Window` that are specific to Windows.
|
/// Additional methods on `Window` that are specific to Windows.
|
||||||
pub trait WindowExtWindows {
|
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.
|
/// Returns the native handle that is used by this window.
|
||||||
///
|
///
|
||||||
/// The pointer will become invalid when the native window was destroyed.
|
/// The pointer will become invalid when the native window was destroyed.
|
||||||
|
@ -44,6 +46,11 @@ pub trait WindowExtWindows {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowExtWindows for Window {
|
impl WindowExtWindows for Window {
|
||||||
|
#[inline]
|
||||||
|
fn hinstance(&self) -> *mut libc::c_void {
|
||||||
|
self.window.hinstance() as *mut _
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn hwnd(&self) -> *mut libc::c_void {
|
fn hwnd(&self) -> *mut libc::c_void {
|
||||||
self.window.hwnd() as *mut _
|
self.window.hwnd() as *mut _
|
||||||
|
|
|
@ -7,11 +7,19 @@ use std::{
|
||||||
time::Instant,
|
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::{
|
use smithay_client_toolkit::reexports::protocols::unstable::relative_pointer::v1::client::{
|
||||||
zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1,
|
zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1,
|
||||||
zwp_relative_pointer_v1::ZwpRelativePointerV1,
|
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::{
|
use crate::{
|
||||||
dpi::{PhysicalPosition, PhysicalSize},
|
dpi::{PhysicalPosition, PhysicalSize},
|
||||||
event::ModifiersState,
|
event::ModifiersState,
|
||||||
|
@ -21,6 +29,7 @@ use crate::{
|
||||||
sticky_exit_callback, MonitorHandle as PlatformMonitorHandle,
|
sticky_exit_callback, MonitorHandle as PlatformMonitorHandle,
|
||||||
VideoMode as PlatformVideoMode,
|
VideoMode as PlatformVideoMode,
|
||||||
},
|
},
|
||||||
|
window::CursorIcon,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{window::WindowStore, DeviceId, WindowId};
|
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> {
|
pub struct EventLoop<T: 'static> {
|
||||||
// The loop
|
// The loop
|
||||||
inner_loop: ::calloop::EventLoop<()>,
|
inner_loop: ::calloop::EventLoop<()>,
|
||||||
// The wayland display
|
// The wayland display
|
||||||
pub display: Arc<Display>,
|
pub display: Arc<Display>,
|
||||||
// the output manager
|
// The output manager
|
||||||
pub outputs: OutputMgr,
|
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>>>,
|
sink: Arc<Mutex<WindowEventsSink<T>>>,
|
||||||
pending_user_events: Rc<RefCell<VecDeque<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_source: ::calloop::Source<::calloop::channel::Channel<T>>,
|
||||||
user_sender: ::calloop::channel::Sender<T>,
|
user_sender: ::calloop::channel::Sender<T>,
|
||||||
_kbd_source: ::calloop::Source<
|
_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.
|
// We should only try and wake up the `EventLoop` if it still exists, so we hold Weak ptrs.
|
||||||
pub struct EventLoopProxy<T: 'static> {
|
pub struct EventLoopProxy<T: 'static> {
|
||||||
user_sender: ::calloop::channel::Sender<T>,
|
user_sender: calloop::channel::Sender<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventLoopWindowTarget<T> {
|
pub struct EventLoopWindowTarget<T> {
|
||||||
// the event queue
|
// The event queue
|
||||||
pub evq: RefCell<::calloop::Source<EventQueue>>,
|
pub evq: RefCell<::calloop::Source<EventQueue>>,
|
||||||
// The window store
|
// The window store
|
||||||
pub store: Arc<Mutex<WindowStore>>,
|
pub store: Arc<Mutex<WindowStore>>,
|
||||||
// the env
|
// The cursor manager
|
||||||
|
pub cursor_manager: Arc<Mutex<CursorManager>>,
|
||||||
|
// The env
|
||||||
pub env: Environment,
|
pub env: Environment,
|
||||||
// a cleanup switch to prune dead windows
|
// A cleanup switch to prune dead windows
|
||||||
pub cleanup_needed: Arc<Mutex<bool>>,
|
pub cleanup_needed: Arc<Mutex<bool>>,
|
||||||
// The wayland display
|
// The wayland display
|
||||||
pub display: Arc<Display>,
|
pub display: Arc<Display>,
|
||||||
|
@ -146,14 +300,24 @@ impl<T: 'static> EventLoop<T> {
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let pointer_constraints_proxy = Arc::new(Mutex::new(None));
|
||||||
|
|
||||||
let mut seat_manager = SeatManager {
|
let mut seat_manager = SeatManager {
|
||||||
sink: sink.clone(),
|
sink: sink.clone(),
|
||||||
relative_pointer_manager_proxy: Rc::new(RefCell::new(None)),
|
relative_pointer_manager_proxy: Rc::new(RefCell::new(None)),
|
||||||
|
pointer_constraints_proxy: pointer_constraints_proxy.clone(),
|
||||||
store: store.clone(),
|
store: store.clone(),
|
||||||
seats: seats.clone(),
|
seats: seats.clone(),
|
||||||
kbd_sender,
|
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(
|
let env = Environment::from_display_with_cb(
|
||||||
&display,
|
&display,
|
||||||
&mut event_queue,
|
&mut event_queue,
|
||||||
|
@ -175,6 +339,42 @@ impl<T: 'static> EventLoop<T> {
|
||||||
.try_borrow_mut()
|
.try_borrow_mut()
|
||||||
.unwrap() = Some(relative_pointer_manager_proxy);
|
.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" {
|
if interface == "wl_seat" {
|
||||||
seat_manager.add_seat(id, version, registry)
|
seat_manager.add_seat(id, version, registry)
|
||||||
}
|
}
|
||||||
|
@ -207,6 +407,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let cursor_manager_clone = cursor_manager.clone();
|
||||||
Ok(EventLoop {
|
Ok(EventLoop {
|
||||||
inner_loop,
|
inner_loop,
|
||||||
sink,
|
sink,
|
||||||
|
@ -221,6 +422,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
evq: RefCell::new(source),
|
evq: RefCell::new(source),
|
||||||
store,
|
store,
|
||||||
env,
|
env,
|
||||||
|
cursor_manager: cursor_manager_clone,
|
||||||
cleanup_needed: Arc::new(Mutex::new(false)),
|
cleanup_needed: Arc::new(Mutex::new(false)),
|
||||||
seats,
|
seats,
|
||||||
display,
|
display,
|
||||||
|
@ -242,7 +444,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
F: 'static + FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
|
F: 'static + FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
self.run_return(callback);
|
self.run_return(callback);
|
||||||
::std::process::exit(0);
|
std::process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_return<F>(&mut self, mut callback: F)
|
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)>>>,
|
seats: Arc<Mutex<Vec<(u32, wl_seat::WlSeat)>>>,
|
||||||
kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>,
|
kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>,
|
||||||
relative_pointer_manager_proxy: Rc<RefCell<Option<ZwpRelativePointerManagerV1>>>,
|
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> {
|
impl<T: 'static> SeatManager<T> {
|
||||||
|
@ -513,6 +717,7 @@ impl<T: 'static> SeatManager<T> {
|
||||||
touch: None,
|
touch: None,
|
||||||
kbd_sender: self.kbd_sender.clone(),
|
kbd_sender: self.kbd_sender.clone(),
|
||||||
modifiers_tracker: Arc::new(Mutex::new(ModifiersState::default())),
|
modifiers_tracker: Arc::new(Mutex::new(ModifiersState::default())),
|
||||||
|
cursor_manager: self.cursor_manager.clone(),
|
||||||
};
|
};
|
||||||
let seat = registry
|
let seat = registry
|
||||||
.bind(min(version, 5), id, move |seat| {
|
.bind(min(version, 5), id, move |seat| {
|
||||||
|
@ -544,6 +749,7 @@ struct SeatData<T> {
|
||||||
keyboard: Option<wl_keyboard::WlKeyboard>,
|
keyboard: Option<wl_keyboard::WlKeyboard>,
|
||||||
touch: Option<wl_touch::WlTouch>,
|
touch: Option<wl_touch::WlTouch>,
|
||||||
modifiers_tracker: Arc<Mutex<ModifiersState>>,
|
modifiers_tracker: Arc<Mutex<ModifiersState>>,
|
||||||
|
cursor_manager: Arc<Mutex<CursorManager>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> SeatData<T> {
|
impl<T: 'static> SeatData<T> {
|
||||||
|
@ -558,8 +764,14 @@ impl<T: 'static> SeatData<T> {
|
||||||
self.sink.clone(),
|
self.sink.clone(),
|
||||||
self.store.clone(),
|
self.store.clone(),
|
||||||
self.modifiers_tracker.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
|
self.relative_pointer = self
|
||||||
.relative_pointer_manager_proxy
|
.relative_pointer_manager_proxy
|
||||||
.try_borrow()
|
.try_borrow()
|
||||||
|
|
|
@ -5,7 +5,11 @@ use crate::event::{
|
||||||
WindowEvent,
|
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::{
|
use smithay_client_toolkit::reexports::client::protocol::{
|
||||||
wl_pointer::{self, Event as PtrEvent, WlPointer},
|
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,
|
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>(
|
pub fn implement_pointer<T: 'static>(
|
||||||
seat: &wl_seat::WlSeat,
|
seat: &wl_seat::WlSeat,
|
||||||
sink: Arc<Mutex<WindowEventsSink<T>>>,
|
sink: Arc<Mutex<WindowEventsSink<T>>>,
|
||||||
store: Arc<Mutex<WindowStore>>,
|
store: Arc<Mutex<WindowStore>>,
|
||||||
modifiers_tracker: Arc<Mutex<ModifiersState>>,
|
modifiers_tracker: Arc<Mutex<ModifiersState>>,
|
||||||
|
cursor_manager: Arc<Mutex<CursorManager>>,
|
||||||
) -> WlPointer {
|
) -> WlPointer {
|
||||||
seat.get_pointer(|pointer| {
|
seat.get_pointer(|pointer| {
|
||||||
let mut mouse_focus = None;
|
let mut mouse_focus = None;
|
||||||
|
@ -33,6 +45,7 @@ pub fn implement_pointer<T: 'static>(
|
||||||
move |evt, pointer| {
|
move |evt, pointer| {
|
||||||
let mut sink = sink.lock().unwrap();
|
let mut sink = sink.lock().unwrap();
|
||||||
let store = store.lock().unwrap();
|
let store = store.lock().unwrap();
|
||||||
|
let mut cursor_manager = cursor_manager.lock().unwrap();
|
||||||
match evt {
|
match evt {
|
||||||
PtrEvent::Enter {
|
PtrEvent::Enter {
|
||||||
surface,
|
surface,
|
||||||
|
@ -62,6 +75,8 @@ pub fn implement_pointer<T: 'static>(
|
||||||
wid,
|
wid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cursor_manager.reload_cursor_style();
|
||||||
}
|
}
|
||||||
PtrEvent::Leave { surface, .. } => {
|
PtrEvent::Leave { surface, .. } => {
|
||||||
mouse_focus = None;
|
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 raw_window_handle::unix::WaylandHandle;
|
||||||
use std::{
|
use std::{
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
|
mem::replace,
|
||||||
sync::{Arc, Mutex, Weak},
|
sync::{Arc, Mutex, Weak},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -26,11 +27,12 @@ use smithay_client_toolkit::{
|
||||||
window::{ConceptFrame, Event as WEvent, State as WState, Theme, Window as SWindow},
|
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 {
|
pub struct Window {
|
||||||
surface: wl_surface::WlSurface,
|
surface: wl_surface::WlSurface,
|
||||||
frame: Arc<Mutex<SWindow<ConceptFrame>>>,
|
frame: Arc<Mutex<SWindow<ConceptFrame>>>,
|
||||||
|
cursor_manager: Arc<Mutex<CursorManager>>,
|
||||||
outputs: OutputMgr, // Access to info for all monitors
|
outputs: OutputMgr, // Access to info for all monitors
|
||||||
size: Arc<Mutex<(u32, u32)>>,
|
size: Arc<Mutex<(u32, u32)>>,
|
||||||
kill_switch: (Arc<Mutex<bool>>, Arc<Mutex<bool>>),
|
kill_switch: (Arc<Mutex<bool>>, Arc<Mutex<bool>>),
|
||||||
|
@ -52,6 +54,7 @@ impl Window {
|
||||||
let fullscreen = Arc::new(Mutex::new(false));
|
let fullscreen = Arc::new(Mutex::new(false));
|
||||||
|
|
||||||
let window_store = evlp.store.clone();
|
let window_store = evlp.store.clone();
|
||||||
|
let cursor_manager = evlp.cursor_manager.clone();
|
||||||
let surface = evlp.env.create_surface(move |dpi, surface| {
|
let surface = evlp.env.create_surface(move |dpi, surface| {
|
||||||
window_store.lock().unwrap().dpi_change(&surface, dpi);
|
window_store.lock().unwrap().dpi_change(&surface, dpi);
|
||||||
surface.set_buffer_scale(dpi);
|
surface.set_buffer_scale(dpi);
|
||||||
|
@ -165,6 +168,7 @@ impl Window {
|
||||||
kill_switch: (kill_switch, evlp.cleanup_needed.clone()),
|
kill_switch: (kill_switch, evlp.cleanup_needed.clone()),
|
||||||
need_frame_refresh,
|
need_frame_refresh,
|
||||||
need_refresh,
|
need_refresh,
|
||||||
|
cursor_manager,
|
||||||
fullscreen,
|
fullscreen,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -292,18 +296,26 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_cursor_icon(&self, _cursor: CursorIcon) {
|
pub fn set_cursor_icon(&self, cursor: CursorIcon) {
|
||||||
// TODO
|
let mut cursor_manager = self.cursor_manager.lock().unwrap();
|
||||||
|
cursor_manager.set_cursor_icon(cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_cursor_visible(&self, _visible: bool) {
|
pub fn set_cursor_visible(&self, visible: bool) {
|
||||||
// TODO: This isn't possible on Wayland yet
|
let mut cursor_manager = self.cursor_manager.lock().unwrap();
|
||||||
|
cursor_manager.set_cursor_visible(visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_cursor_grab(&self, _grab: bool) -> Result<(), ExternalError> {
|
pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> {
|
||||||
Err(ExternalError::NotSupported(NotSupportedError::new()))
|
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]
|
#[inline]
|
||||||
|
@ -440,8 +452,8 @@ impl WindowStore {
|
||||||
window.newsize.take(),
|
window.newsize.take(),
|
||||||
&mut *(window.size.lock().unwrap()),
|
&mut *(window.size.lock().unwrap()),
|
||||||
window.new_dpi,
|
window.new_dpi,
|
||||||
::std::mem::replace(&mut *window.need_refresh.lock().unwrap(), false),
|
replace(&mut *window.need_refresh.lock().unwrap(), false),
|
||||||
::std::mem::replace(&mut *window.need_frame_refresh.lock().unwrap(), false),
|
replace(&mut *window.need_frame_refresh.lock().unwrap(), false),
|
||||||
window.closed,
|
window.closed,
|
||||||
make_wid(&window.surface),
|
make_wid(&window.surface),
|
||||||
opt_mutex_lock.as_mut().map(|m| &mut **m),
|
opt_mutex_lock.as_mut().map(|m| &mut **m),
|
||||||
|
|
|
@ -99,7 +99,8 @@ impl XConnection {
|
||||||
// video mode is returned to the user
|
// video mode is returned to the user
|
||||||
monitor: None,
|
monitor: None,
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
let name_slice = slice::from_raw_parts(
|
let name_slice = slice::from_raw_parts(
|
||||||
(*output_info).name as *mut u8,
|
(*output_info).name as *mut u8,
|
||||||
|
@ -119,7 +120,7 @@ impl XConnection {
|
||||||
};
|
};
|
||||||
|
|
||||||
(self.xrandr.XRRFreeOutputInfo)(output_info);
|
(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<(), ()> {
|
pub fn set_crtc_config(&self, crtc_id: RRCrtc, mode_id: RRMode) -> Result<(), ()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -22,17 +22,46 @@ use core_video_sys::{
|
||||||
CVDisplayLinkGetNominalOutputVideoRefreshPeriod, CVDisplayLinkRelease,
|
CVDisplayLinkGetNominalOutputVideoRefreshPeriod, CVDisplayLinkRelease,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Derivative)]
|
#[derive(Clone)]
|
||||||
#[derivative(Debug, Clone, PartialEq, Hash)]
|
|
||||||
pub struct VideoMode {
|
pub struct VideoMode {
|
||||||
pub(crate) size: (u32, u32),
|
pub(crate) size: (u32, u32),
|
||||||
pub(crate) bit_depth: u16,
|
pub(crate) bit_depth: u16,
|
||||||
pub(crate) refresh_rate: u16,
|
pub(crate) refresh_rate: u16,
|
||||||
pub(crate) monitor: MonitorHandle,
|
pub(crate) monitor: MonitorHandle,
|
||||||
#[derivative(Debug = "ignore", PartialEq = "ignore", Hash = "ignore")]
|
|
||||||
pub(crate) native_mode: NativeDisplayMode,
|
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);
|
pub struct NativeDisplayMode(pub ffi::CGDisplayModeRef);
|
||||||
|
|
||||||
unsafe impl Send for NativeDisplayMode {}
|
unsafe impl Send for NativeDisplayMode {}
|
||||||
|
|
|
@ -402,7 +402,24 @@ extern "C" fn window_will_enter_fullscreen(this: &Object, _: Sel, _: id) {
|
||||||
with_state(this, |state| {
|
with_state(this, |state| {
|
||||||
state.with_window(|window| {
|
state.with_window(|window| {
|
||||||
trace!("Locked shared state in `window_will_enter_fullscreen`");
|
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`");
|
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) {
|
extern "C" fn window_did_enter_fullscreen(this: &Object, _: Sel, _: id) {
|
||||||
trace!("Triggered `windowDidEnterFullscreen:`");
|
trace!("Triggered `windowDidEnterFullscreen:`");
|
||||||
with_state(this, |state| {
|
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;
|
state.initial_fullscreen = false;
|
||||||
});
|
});
|
||||||
trace!("Completed `windowDidEnterFullscreen:`");
|
trace!("Completed `windowDidEnterFullscreen:`");
|
||||||
|
|
|
@ -54,13 +54,14 @@ use crate::{
|
||||||
},
|
},
|
||||||
drop_handler::FileDropHandler,
|
drop_handler::FileDropHandler,
|
||||||
event::{self, handle_extended_keys, process_key_params, vkey_to_winit_vkey},
|
event::{self, handle_extended_keys, process_key_params, vkey_to_winit_vkey},
|
||||||
|
monitor,
|
||||||
raw_input::{get_raw_input_data, get_raw_mouse_button_state},
|
raw_input::{get_raw_input_data, get_raw_mouse_button_state},
|
||||||
util,
|
util,
|
||||||
window::adjust_size,
|
window::adjust_size,
|
||||||
window_state::{CursorFlags, WindowFlags, WindowState},
|
window_state::{CursorFlags, WindowFlags, WindowState},
|
||||||
wrap_device_id, WindowId, DEVICE_ID,
|
wrap_device_id, WindowId, DEVICE_ID,
|
||||||
},
|
},
|
||||||
window::WindowId as RootWindowId,
|
window::{Fullscreen, WindowId as RootWindowId},
|
||||||
};
|
};
|
||||||
|
|
||||||
type GetPointerFrameInfoHistory = unsafe extern "system" fn(
|
type GetPointerFrameInfoHistory = unsafe extern "system" fn(
|
||||||
|
@ -982,6 +983,51 @@ unsafe extern "system" fn public_window_callback<T>(
|
||||||
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
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.
|
// WM_MOVE supplies client area positions, so we send Moved here instead.
|
||||||
winuser::WM_WINDOWPOSCHANGED => {
|
winuser::WM_WINDOWPOSCHANGED => {
|
||||||
use crate::event::WindowEvent::Moved;
|
use crate::event::WindowEvent::Moved;
|
||||||
|
|
|
@ -21,17 +21,46 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Derivative)]
|
#[derive(Clone)]
|
||||||
#[derivative(Debug, Clone, Eq, PartialEq, Hash)]
|
|
||||||
pub struct VideoMode {
|
pub struct VideoMode {
|
||||||
pub(crate) size: (u32, u32),
|
pub(crate) size: (u32, u32),
|
||||||
pub(crate) bit_depth: u16,
|
pub(crate) bit_depth: u16,
|
||||||
pub(crate) refresh_rate: u16,
|
pub(crate) refresh_rate: u16,
|
||||||
pub(crate) monitor: MonitorHandle,
|
pub(crate) monitor: MonitorHandle,
|
||||||
#[derivative(Debug = "ignore", PartialEq = "ignore", Hash = "ignore")]
|
|
||||||
pub(crate) native_video_mode: wingdi::DEVMODEW,
|
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 {
|
impl VideoMode {
|
||||||
pub fn size(&self) -> PhysicalSize {
|
pub fn size(&self) -> PhysicalSize {
|
||||||
self.size.into()
|
self.size.into()
|
||||||
|
|
|
@ -14,7 +14,7 @@ use std::{
|
||||||
use winapi::{
|
use winapi::{
|
||||||
ctypes::c_int,
|
ctypes::c_int,
|
||||||
shared::{
|
shared::{
|
||||||
minwindef::{DWORD, LPARAM, UINT, WORD, WPARAM},
|
minwindef::{DWORD, HINSTANCE, LPARAM, UINT, WORD, WPARAM},
|
||||||
windef::{HWND, POINT, RECT},
|
windef::{HWND, POINT, RECT},
|
||||||
},
|
},
|
||||||
um::{
|
um::{
|
||||||
|
@ -358,10 +358,16 @@ impl Window {
|
||||||
self.window.0
|
self.window.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn hinstance(&self) -> HINSTANCE {
|
||||||
|
unsafe { winuser::GetWindowLongW(self.hwnd(), winuser::GWL_HINSTANCE) as *mut _ }
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn raw_window_handle(&self) -> RawWindowHandle {
|
pub fn raw_window_handle(&self) -> RawWindowHandle {
|
||||||
let handle = WindowsHandle {
|
let handle = WindowsHandle {
|
||||||
hwnd: self.window.0 as *mut _,
|
hwnd: self.window.0 as *mut _,
|
||||||
|
hinstance: self.hinstance() as *mut _,
|
||||||
..WindowsHandle::empty()
|
..WindowsHandle::empty()
|
||||||
};
|
};
|
||||||
RawWindowHandle::Windows(handle)
|
RawWindowHandle::Windows(handle)
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
||||||
dpi::{LogicalPosition, LogicalSize},
|
dpi::{LogicalPosition, LogicalSize},
|
||||||
error::{ExternalError, NotSupportedError, OsError},
|
error::{ExternalError, NotSupportedError, OsError},
|
||||||
event_loop::EventLoopWindowTarget,
|
event_loop::EventLoopWindowTarget,
|
||||||
monitor::{AvailableMonitorsIter, MonitorHandle, VideoMode},
|
monitor::{MonitorHandle, VideoMode},
|
||||||
platform_impl,
|
platform_impl,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -674,6 +674,8 @@ impl Window {
|
||||||
///
|
///
|
||||||
/// - **macOS:** This presently merely locks the cursor in a fixed location, which looks visually
|
/// - **macOS:** This presently merely locks the cursor in a fixed location, which looks visually
|
||||||
/// awkward.
|
/// awkward.
|
||||||
|
/// - **Wayland:** This presently merely locks the cursor in a fixed location, which looks visually
|
||||||
|
/// awkward.
|
||||||
/// - **Android:** Has no effect.
|
/// - **Android:** Has no effect.
|
||||||
/// - **iOS:** Always returns an Err.
|
/// - **iOS:** Always returns an Err.
|
||||||
/// - **Web:** Has no effect.
|
/// - **Web:** Has no effect.
|
||||||
|
@ -690,6 +692,7 @@ impl Window {
|
||||||
///
|
///
|
||||||
/// - **Windows:** The cursor is only hidden within the confines of the 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.
|
/// - **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
|
/// - **macOS:** The cursor is hidden as long as the window has input focus, even if the cursor is
|
||||||
/// outside of the window.
|
/// outside of the window.
|
||||||
/// - **iOS:** Has no effect.
|
/// - **iOS:** Has no effect.
|
||||||
|
@ -720,11 +723,11 @@ impl Window {
|
||||||
///
|
///
|
||||||
/// **iOS:** Can only be called on the main thread.
|
/// **iOS:** Can only be called on the main thread.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn available_monitors(&self) -> AvailableMonitorsIter {
|
pub fn available_monitors(&self) -> impl Iterator<Item = MonitorHandle> {
|
||||||
let data = self.window.available_monitors();
|
self.window
|
||||||
AvailableMonitorsIter {
|
.available_monitors()
|
||||||
data: data.into_iter(),
|
.into_iter()
|
||||||
}
|
.map(|inner| MonitorHandle { inner })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the primary monitor of the system.
|
/// Returns the primary monitor of the system.
|
||||||
|
|
Loading…
Reference in a new issue