mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2025-01-23 10:26:34 +11:00
Implement DPI Usability Upgrades for X11 and Wayland (#1098)
* Fix compile errors * Use `mio` for the X11 event loop * Removes `calloop` from the X11 event loop, as the method of draining a source using a closure provided to the `calloop::EventLoop` instance conflicts with the need to deliver events directly to the callback provided to `EventLoop::run`, in order to respond to the value provided by `WindowEvent::HiDpiFactorChanged`. * Implement interactive `HiDpiFactorChanged` event for X11 * Implement interactive `HiDpiFactorChanged` event for Wayland * Run cargo fmt * Fix Wayland not processing events from EventQueue * Backport #981
This commit is contained in:
parent
6bb7db7c11
commit
7b43b0bc94
12 changed files with 563 additions and 627 deletions
|
@ -75,7 +75,8 @@ 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.23.0", features = [ "dlopen", "egl", "cursor", "eventloop"] }
|
wayland-client = { version = "0.23.0", features = [ "dlopen", "egl", "cursor", "eventloop"] }
|
||||||
calloop = "0.4.2"
|
mio = "0.6"
|
||||||
|
mio-extras = "2.0"
|
||||||
smithay-client-toolkit = "0.6"
|
smithay-client-toolkit = "0.6"
|
||||||
x11-dl = "2.18.3"
|
x11-dl = "2.18.3"
|
||||||
percent-encoding = "2.0"
|
percent-encoding = "2.0"
|
||||||
|
|
|
@ -7,11 +7,9 @@ use raw_window_handle::RawWindowHandle;
|
||||||
use smithay_client_toolkit::reexports::client::ConnectError;
|
use smithay_client_toolkit::reexports::client::ConnectError;
|
||||||
|
|
||||||
pub use self::x11::XNotSupported;
|
pub use self::x11::XNotSupported;
|
||||||
use self::x11::{
|
use self::x11::{ffi::XVisualInfo, util::WindowType as XWindowType, XConnection, XError};
|
||||||
ffi::XVisualInfo, get_xtarget, util::WindowType as XWindowType, XConnection, XError,
|
|
||||||
};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize},
|
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
||||||
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||||
event::Event,
|
event::Event,
|
||||||
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW},
|
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW},
|
||||||
|
@ -248,7 +246,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn outer_position(&self) -> Result<LogicalPosition, NotSupportedError> {
|
pub fn outer_position(&self) -> Result<PhysicalPosition, NotSupportedError> {
|
||||||
match self {
|
match self {
|
||||||
&Window::X(ref w) => w.outer_position(),
|
&Window::X(ref w) => w.outer_position(),
|
||||||
&Window::Wayland(ref w) => w.outer_position(),
|
&Window::Wayland(ref w) => w.outer_position(),
|
||||||
|
@ -256,7 +254,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn inner_position(&self) -> Result<LogicalPosition, NotSupportedError> {
|
pub fn inner_position(&self) -> Result<PhysicalPosition, NotSupportedError> {
|
||||||
match self {
|
match self {
|
||||||
&Window::X(ref m) => m.inner_position(),
|
&Window::X(ref m) => m.inner_position(),
|
||||||
&Window::Wayland(ref m) => m.inner_position(),
|
&Window::Wayland(ref m) => m.inner_position(),
|
||||||
|
@ -264,7 +262,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_outer_position(&self, position: LogicalPosition) {
|
pub fn set_outer_position(&self, position: Position) {
|
||||||
match self {
|
match self {
|
||||||
&Window::X(ref w) => w.set_outer_position(position),
|
&Window::X(ref w) => w.set_outer_position(position),
|
||||||
&Window::Wayland(ref w) => w.set_outer_position(position),
|
&Window::Wayland(ref w) => w.set_outer_position(position),
|
||||||
|
@ -272,7 +270,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn inner_size(&self) -> LogicalSize {
|
pub fn inner_size(&self) -> PhysicalSize {
|
||||||
match self {
|
match self {
|
||||||
&Window::X(ref w) => w.inner_size(),
|
&Window::X(ref w) => w.inner_size(),
|
||||||
&Window::Wayland(ref w) => w.inner_size(),
|
&Window::Wayland(ref w) => w.inner_size(),
|
||||||
|
@ -280,7 +278,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn outer_size(&self) -> LogicalSize {
|
pub fn outer_size(&self) -> PhysicalSize {
|
||||||
match self {
|
match self {
|
||||||
&Window::X(ref w) => w.outer_size(),
|
&Window::X(ref w) => w.outer_size(),
|
||||||
&Window::Wayland(ref w) => w.outer_size(),
|
&Window::Wayland(ref w) => w.outer_size(),
|
||||||
|
@ -288,7 +286,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_inner_size(&self, size: LogicalSize) {
|
pub fn set_inner_size(&self, size: Size) {
|
||||||
match self {
|
match self {
|
||||||
&Window::X(ref w) => w.set_inner_size(size),
|
&Window::X(ref w) => w.set_inner_size(size),
|
||||||
&Window::Wayland(ref w) => w.set_inner_size(size),
|
&Window::Wayland(ref w) => w.set_inner_size(size),
|
||||||
|
@ -296,7 +294,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_min_inner_size(&self, dimensions: Option<LogicalSize>) {
|
pub fn set_min_inner_size(&self, dimensions: Option<Size>) {
|
||||||
match self {
|
match self {
|
||||||
&Window::X(ref w) => w.set_min_inner_size(dimensions),
|
&Window::X(ref w) => w.set_min_inner_size(dimensions),
|
||||||
&Window::Wayland(ref w) => w.set_min_inner_size(dimensions),
|
&Window::Wayland(ref w) => w.set_min_inner_size(dimensions),
|
||||||
|
@ -304,7 +302,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_max_inner_size(&self, dimensions: Option<LogicalSize>) {
|
pub fn set_max_inner_size(&self, dimensions: Option<Size>) {
|
||||||
match self {
|
match self {
|
||||||
&Window::X(ref w) => w.set_max_inner_size(dimensions),
|
&Window::X(ref w) => w.set_max_inner_size(dimensions),
|
||||||
&Window::Wayland(ref w) => w.set_max_inner_size(dimensions),
|
&Window::Wayland(ref w) => w.set_max_inner_size(dimensions),
|
||||||
|
@ -352,7 +350,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_cursor_position(&self, position: LogicalPosition) -> Result<(), ExternalError> {
|
pub fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> {
|
||||||
match self {
|
match self {
|
||||||
&Window::X(ref w) => w.set_cursor_position(position),
|
&Window::X(ref w) => w.set_cursor_position(position),
|
||||||
&Window::Wayland(ref w) => w.set_cursor_position(position),
|
&Window::Wayland(ref w) => w.set_cursor_position(position),
|
||||||
|
@ -416,7 +414,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_ime_position(&self, position: LogicalPosition) {
|
pub fn set_ime_position(&self, position: Position) {
|
||||||
match self {
|
match self {
|
||||||
&Window::X(ref w) => w.set_ime_position(position),
|
&Window::X(ref w) => w.set_ime_position(position),
|
||||||
&Window::Wayland(_) => (),
|
&Window::Wayland(_) => (),
|
||||||
|
@ -603,7 +601,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(MonitorHandle::Wayland)
|
.map(MonitorHandle::Wayland)
|
||||||
.collect(),
|
.collect(),
|
||||||
EventLoop::X(ref evlp) => get_xtarget(&evlp.target)
|
EventLoop::X(ref evlp) => evlp
|
||||||
.x_connection()
|
.x_connection()
|
||||||
.available_monitors()
|
.available_monitors()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -616,9 +614,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
pub fn primary_monitor(&self) -> MonitorHandle {
|
pub fn primary_monitor(&self) -> MonitorHandle {
|
||||||
match *self {
|
match *self {
|
||||||
EventLoop::Wayland(ref evlp) => MonitorHandle::Wayland(evlp.primary_monitor()),
|
EventLoop::Wayland(ref evlp) => MonitorHandle::Wayland(evlp.primary_monitor()),
|
||||||
EventLoop::X(ref evlp) => {
|
EventLoop::X(ref evlp) => MonitorHandle::X(evlp.x_connection().primary_monitor()),
|
||||||
MonitorHandle::X(get_xtarget(&evlp.target).x_connection().primary_monitor())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -631,7 +627,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
|
|
||||||
pub fn run_return<F>(&mut self, callback: F)
|
pub fn run_return<F>(&mut self, callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
|
F: FnMut(crate::event::Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
match *self {
|
match *self {
|
||||||
EventLoop::Wayland(ref mut evlp) => evlp.run_return(callback),
|
EventLoop::Wayland(ref mut evlp) => evlp.run_return(callback),
|
||||||
|
@ -641,7 +637,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
|
|
||||||
pub fn run<F>(self, callback: F) -> !
|
pub fn run<F>(self, callback: F) -> !
|
||||||
where
|
where
|
||||||
F: 'static + FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
|
F: 'static + FnMut(crate::event::Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
EventLoop::Wayland(evlp) => evlp.run(callback),
|
EventLoop::Wayland(evlp) => evlp.run(callback),
|
||||||
|
@ -682,12 +678,12 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sticky_exit_callback<T, F>(
|
fn sticky_exit_callback<T, F>(
|
||||||
evt: Event<T>,
|
evt: Event<'_, T>,
|
||||||
target: &RootELW<T>,
|
target: &RootELW<T>,
|
||||||
control_flow: &mut ControlFlow,
|
control_flow: &mut ControlFlow,
|
||||||
callback: &mut F,
|
callback: &mut F,
|
||||||
) where
|
) where
|
||||||
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
|
F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
// make ControlFlow::Exit sticky by providing a dummy
|
// make ControlFlow::Exit sticky by providing a dummy
|
||||||
// control flow reference if it is already Exit.
|
// control flow reference if it is already Exit.
|
||||||
|
|
|
@ -2,11 +2,16 @@ use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
collections::VecDeque,
|
collections::VecDeque,
|
||||||
fmt,
|
fmt,
|
||||||
|
io::ErrorKind,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
time::Instant,
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use mio::{Events, Poll, PollOpt, Ready, Token};
|
||||||
|
|
||||||
|
use mio_extras::channel::{channel, Receiver, SendError, Sender};
|
||||||
|
|
||||||
use smithay_client_toolkit::reexports::protocols::unstable::pointer_constraints::v1::client::{
|
use smithay_client_toolkit::reexports::protocols::unstable::pointer_constraints::v1::client::{
|
||||||
zwp_locked_pointer_v1::ZwpLockedPointerV1, zwp_pointer_constraints_v1::ZwpPointerConstraintsV1,
|
zwp_locked_pointer_v1::ZwpLockedPointerV1, zwp_pointer_constraints_v1::ZwpPointerConstraintsV1,
|
||||||
};
|
};
|
||||||
|
@ -21,15 +26,17 @@ use smithay_client_toolkit::reexports::client::protocol::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
dpi::{PhysicalPosition, PhysicalSize},
|
dpi::{LogicalSize, PhysicalPosition, PhysicalSize},
|
||||||
event::ModifiersState,
|
event::{
|
||||||
|
DeviceEvent, DeviceId as RootDeviceId, Event, ModifiersState, StartCause, WindowEvent,
|
||||||
|
},
|
||||||
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW},
|
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW},
|
||||||
monitor::{MonitorHandle as RootMonitorHandle, VideoMode as RootVideoMode},
|
monitor::{MonitorHandle as RootMonitorHandle, VideoMode as RootVideoMode},
|
||||||
platform_impl::platform::{
|
platform_impl::platform::{
|
||||||
sticky_exit_callback, MonitorHandle as PlatformMonitorHandle,
|
sticky_exit_callback, DeviceId as PlatformDeviceId, MonitorHandle as PlatformMonitorHandle,
|
||||||
VideoMode as PlatformVideoMode,
|
VideoMode as PlatformVideoMode, WindowId as PlatformWindowId,
|
||||||
},
|
},
|
||||||
window::CursorIcon,
|
window::{CursorIcon, WindowId as RootWindowId},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{window::WindowStore, DeviceId, WindowId};
|
use super::{window::WindowStore, DeviceId, WindowId};
|
||||||
|
@ -43,43 +50,37 @@ use smithay_client_toolkit::{
|
||||||
Environment,
|
Environment,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct WindowEventsSink<T> {
|
const KBD_TOKEN: Token = Token(0);
|
||||||
buffer: VecDeque<crate::event::Event<T>>,
|
const USER_TOKEN: Token = Token(1);
|
||||||
|
const EVQ_TOKEN: Token = Token(2);
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct EventsSink {
|
||||||
|
sender: Sender<Event<'static, ()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> WindowEventsSink<T> {
|
impl EventsSink {
|
||||||
pub fn new() -> WindowEventsSink<T> {
|
pub fn new(sender: Sender<Event<'static, ()>>) -> EventsSink {
|
||||||
WindowEventsSink {
|
EventsSink { sender }
|
||||||
buffer: VecDeque::new(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_event(&mut self, evt: crate::event::Event<T>) {
|
pub fn send_event(&self, event: Event<'static, ()>) {
|
||||||
self.buffer.push_back(evt);
|
self.sender.send(event).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_window_event(&mut self, evt: crate::event::WindowEvent, wid: WindowId) {
|
pub fn send_device_event(&self, event: DeviceEvent, device_id: DeviceId) {
|
||||||
self.buffer.push_back(crate::event::Event::WindowEvent {
|
self.send_event(Event::DeviceEvent {
|
||||||
event: evt,
|
event,
|
||||||
window_id: crate::window::WindowId(crate::platform_impl::WindowId::Wayland(wid)),
|
device_id: RootDeviceId(PlatformDeviceId::Wayland(device_id)),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_device_event(&mut self, evt: crate::event::DeviceEvent, dev_id: DeviceId) {
|
pub fn send_window_event(&self, event: WindowEvent<'static>, window_id: WindowId) {
|
||||||
self.buffer.push_back(crate::event::Event::DeviceEvent {
|
self.send_event(Event::WindowEvent {
|
||||||
event: evt,
|
event,
|
||||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(dev_id)),
|
window_id: RootWindowId(PlatformWindowId::Wayland(window_id)),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn empty_with<F>(&mut self, mut callback: F)
|
|
||||||
where
|
|
||||||
F: FnMut(crate::event::Event<T>),
|
|
||||||
{
|
|
||||||
for evt in self.buffer.drain(..) {
|
|
||||||
callback(evt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CursorManager {
|
pub struct CursorManager {
|
||||||
|
@ -230,21 +231,17 @@ impl CursorManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventLoop<T: 'static> {
|
pub struct EventLoop<T: 'static> {
|
||||||
// The loop
|
// Poll instance
|
||||||
inner_loop: ::calloop::EventLoop<()>,
|
poll: Poll,
|
||||||
// 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
|
|
||||||
sink: Arc<Mutex<WindowEventsSink<T>>>,
|
|
||||||
pending_user_events: Rc<RefCell<VecDeque<T>>>,
|
|
||||||
// The cursor manager
|
// The cursor manager
|
||||||
cursor_manager: Arc<Mutex<CursorManager>>,
|
cursor_manager: Arc<Mutex<CursorManager>>,
|
||||||
// Utility for grabbing the cursor and changing visibility
|
kbd_channel: Receiver<Event<'static, ()>>,
|
||||||
_user_source: ::calloop::Source<::calloop::channel::Channel<T>>,
|
user_channel: Receiver<T>,
|
||||||
user_sender: ::calloop::channel::Sender<T>,
|
user_sender: Sender<T>,
|
||||||
_kbd_source: ::calloop::Source<::calloop::channel::Channel<crate::event::Event<()>>>,
|
|
||||||
window_target: RootELW<T>,
|
window_target: RootELW<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -252,12 +249,12 @@ 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: 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<EventQueue>,
|
||||||
// The window store
|
// The window store
|
||||||
pub store: Arc<Mutex<WindowStore>>,
|
pub store: Arc<Mutex<WindowStore>>,
|
||||||
// The cursor manager
|
// The cursor manager
|
||||||
|
@ -284,7 +281,7 @@ impl<T: 'static> Clone for EventLoopProxy<T> {
|
||||||
impl<T: 'static> EventLoopProxy<T> {
|
impl<T: 'static> EventLoopProxy<T> {
|
||||||
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
||||||
self.user_sender.send(event).map_err(|e| {
|
self.user_sender.send(event).map_err(|e| {
|
||||||
EventLoopClosed(if let ::calloop::channel::SendError::Disconnected(x) = e {
|
EventLoopClosed(if let SendError::Disconnected(x) = e {
|
||||||
x
|
x
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
@ -298,33 +295,26 @@ impl<T: 'static> EventLoop<T> {
|
||||||
let (display, mut event_queue) = Display::connect_to_env()?;
|
let (display, mut event_queue) = Display::connect_to_env()?;
|
||||||
|
|
||||||
let display = Arc::new(display);
|
let display = Arc::new(display);
|
||||||
let sink = Arc::new(Mutex::new(WindowEventsSink::new()));
|
|
||||||
let store = Arc::new(Mutex::new(WindowStore::new()));
|
let store = Arc::new(Mutex::new(WindowStore::new()));
|
||||||
let seats = Arc::new(Mutex::new(Vec::new()));
|
let seats = Arc::new(Mutex::new(Vec::new()));
|
||||||
|
|
||||||
let inner_loop = ::calloop::EventLoop::new().unwrap();
|
let poll = Poll::new().unwrap();
|
||||||
|
|
||||||
let (kbd_sender, kbd_channel) = ::calloop::channel::channel::<crate::event::Event<()>>();
|
let (kbd_sender, kbd_channel) = channel();
|
||||||
let kbd_sink = sink.clone();
|
|
||||||
let kbd_source = inner_loop
|
let sink = EventsSink::new(kbd_sender);
|
||||||
.handle()
|
|
||||||
.insert_source(kbd_channel, move |evt, &mut ()| {
|
poll.register(&kbd_channel, KBD_TOKEN, Ready::readable(), PollOpt::level())
|
||||||
if let ::calloop::channel::Event::Msg(evt) = evt {
|
|
||||||
let evt = evt.map_nonuser_event().ok().unwrap();
|
|
||||||
kbd_sink.lock().unwrap().send_event(evt);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let pointer_constraints_proxy = Arc::new(Mutex::new(None));
|
let pointer_constraints_proxy = Arc::new(Mutex::new(None));
|
||||||
|
|
||||||
let mut seat_manager = SeatManager {
|
let mut seat_manager = SeatManager {
|
||||||
sink: sink.clone(),
|
sink,
|
||||||
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,
|
relative_pointer_manager_proxy: Rc::new(RefCell::new(None)),
|
||||||
|
pointer_constraints_proxy: pointer_constraints_proxy.clone(),
|
||||||
cursor_manager: Arc::new(Mutex::new(CursorManager::new(pointer_constraints_proxy))),
|
cursor_manager: Arc::new(Mutex::new(CursorManager::new(pointer_constraints_proxy))),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -404,39 +394,31 @@ impl<T: 'static> EventLoop<T> {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let source = inner_loop
|
poll.register(&event_queue, EVQ_TOKEN, Ready::readable(), PollOpt::level())
|
||||||
.handle()
|
|
||||||
.insert_source(event_queue, |(), &mut ()| {})
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let pending_user_events = Rc::new(RefCell::new(VecDeque::new()));
|
let (user_sender, user_channel) = channel();
|
||||||
let pending_user_events2 = pending_user_events.clone();
|
|
||||||
|
|
||||||
let (user_sender, user_channel) = ::calloop::channel::channel();
|
poll.register(
|
||||||
|
&user_channel,
|
||||||
let user_source = inner_loop
|
USER_TOKEN,
|
||||||
.handle()
|
Ready::readable(),
|
||||||
.insert_source(user_channel, move |evt, &mut ()| {
|
PollOpt::level(),
|
||||||
if let ::calloop::channel::Event::Msg(msg) = evt {
|
)
|
||||||
pending_user_events2.borrow_mut().push_back(msg);
|
.unwrap();
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let cursor_manager_clone = cursor_manager.clone();
|
let cursor_manager_clone = cursor_manager.clone();
|
||||||
Ok(EventLoop {
|
Ok(EventLoop {
|
||||||
inner_loop,
|
poll,
|
||||||
sink,
|
|
||||||
pending_user_events,
|
|
||||||
display: display.clone(),
|
display: display.clone(),
|
||||||
outputs: env.outputs.clone(),
|
outputs: env.outputs.clone(),
|
||||||
_user_source: user_source,
|
|
||||||
user_sender,
|
user_sender,
|
||||||
|
user_channel,
|
||||||
|
kbd_channel,
|
||||||
cursor_manager,
|
cursor_manager,
|
||||||
_kbd_source: kbd_source,
|
|
||||||
window_target: RootELW {
|
window_target: RootELW {
|
||||||
p: crate::platform_impl::EventLoopWindowTarget::Wayland(EventLoopWindowTarget {
|
p: crate::platform_impl::EventLoopWindowTarget::Wayland(EventLoopWindowTarget {
|
||||||
evq: RefCell::new(source),
|
evq: RefCell::new(event_queue),
|
||||||
store,
|
store,
|
||||||
env,
|
env,
|
||||||
cursor_manager: cursor_manager_clone,
|
cursor_manager: cursor_manager_clone,
|
||||||
|
@ -458,7 +440,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
|
|
||||||
pub fn run<F>(mut self, callback: F) -> !
|
pub fn run<F>(mut self, callback: F) -> !
|
||||||
where
|
where
|
||||||
F: 'static + FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
|
F: 'static + FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
self.run_return(callback);
|
self.run_return(callback);
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
|
@ -466,53 +448,60 @@ impl<T: 'static> EventLoop<T> {
|
||||||
|
|
||||||
pub fn run_return<F>(&mut self, mut callback: F)
|
pub fn run_return<F>(&mut self, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
|
F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
// send pending events to the server
|
// send pending events to the server
|
||||||
self.display.flush().expect("Wayland connection lost.");
|
self.display.flush().expect("Wayland connection lost.");
|
||||||
|
|
||||||
let mut control_flow = ControlFlow::default();
|
let mut control_flow = ControlFlow::default();
|
||||||
|
let mut events = Events::with_capacity(8);
|
||||||
let sink = self.sink.clone();
|
|
||||||
let user_events = self.pending_user_events.clone();
|
|
||||||
|
|
||||||
callback(
|
callback(
|
||||||
crate::event::Event::NewEvents(crate::event::StartCause::Init),
|
Event::NewEvents(StartCause::Init),
|
||||||
&self.window_target,
|
&self.window_target,
|
||||||
&mut control_flow,
|
&mut control_flow,
|
||||||
);
|
);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
self.post_dispatch_triggers();
|
// Read events from the event queue
|
||||||
|
{
|
||||||
|
let mut evq = get_target(&self.window_target).evq.borrow_mut();
|
||||||
|
|
||||||
// empty buffer of events
|
evq.dispatch_pending()
|
||||||
{
|
.expect("failed to dispatch wayland events");
|
||||||
let mut guard = sink.lock().unwrap();
|
|
||||||
guard.empty_with(|evt| {
|
if let Some(read) = evq.prepare_read() {
|
||||||
sticky_exit_callback(
|
if let Err(e) = read.read_events() {
|
||||||
evt,
|
if e.kind() != ErrorKind::WouldBlock {
|
||||||
&self.window_target,
|
panic!("failed to read wayland events: {}", e);
|
||||||
&mut control_flow,
|
}
|
||||||
&mut callback,
|
}
|
||||||
);
|
|
||||||
});
|
evq.dispatch_pending()
|
||||||
}
|
.expect("failed to dispatch wayland events");
|
||||||
// empty user events
|
|
||||||
{
|
|
||||||
let mut guard = user_events.borrow_mut();
|
|
||||||
for evt in guard.drain(..) {
|
|
||||||
sticky_exit_callback(
|
|
||||||
crate::event::Event::UserEvent(evt),
|
|
||||||
&self.window_target,
|
|
||||||
&mut control_flow,
|
|
||||||
&mut callback,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.post_dispatch_triggers(&mut callback, &mut control_flow);
|
||||||
|
|
||||||
|
while let Ok(event) = self.kbd_channel.try_recv() {
|
||||||
|
let event = event.map_nonuser_event().unwrap();
|
||||||
|
sticky_exit_callback(event, &self.window_target, &mut control_flow, &mut callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
while let Ok(event) = self.user_channel.try_recv() {
|
||||||
|
sticky_exit_callback(
|
||||||
|
Event::UserEvent(event),
|
||||||
|
&self.window_target,
|
||||||
|
&mut control_flow,
|
||||||
|
&mut callback,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// send Events cleared
|
// send Events cleared
|
||||||
{
|
{
|
||||||
sticky_exit_callback(
|
sticky_exit_callback(
|
||||||
crate::event::Event::MainEventsCleared,
|
Event::MainEventsCleared,
|
||||||
&self.window_target,
|
&self.window_target,
|
||||||
&mut control_flow,
|
&mut control_flow,
|
||||||
&mut callback,
|
&mut callback,
|
||||||
|
@ -523,7 +512,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
{
|
{
|
||||||
self.redraw_triggers(|wid, window_target| {
|
self.redraw_triggers(|wid, window_target| {
|
||||||
sticky_exit_callback(
|
sticky_exit_callback(
|
||||||
crate::event::Event::RedrawRequested(crate::window::WindowId(
|
Event::RedrawRequested(crate::window::WindowId(
|
||||||
crate::platform_impl::WindowId::Wayland(wid),
|
crate::platform_impl::WindowId::Wayland(wid),
|
||||||
)),
|
)),
|
||||||
window_target,
|
window_target,
|
||||||
|
@ -536,7 +525,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
// send RedrawEventsCleared
|
// send RedrawEventsCleared
|
||||||
{
|
{
|
||||||
sticky_exit_callback(
|
sticky_exit_callback(
|
||||||
crate::event::Event::RedrawEventsCleared,
|
Event::RedrawEventsCleared,
|
||||||
&self.window_target,
|
&self.window_target,
|
||||||
&mut control_flow,
|
&mut control_flow,
|
||||||
&mut callback,
|
&mut callback,
|
||||||
|
@ -569,24 +558,25 @@ impl<T: 'static> EventLoop<T> {
|
||||||
ControlFlow::Exit => break,
|
ControlFlow::Exit => break,
|
||||||
ControlFlow::Poll => {
|
ControlFlow::Poll => {
|
||||||
// non-blocking dispatch
|
// non-blocking dispatch
|
||||||
self.inner_loop
|
self.poll
|
||||||
.dispatch(Some(::std::time::Duration::from_millis(0)), &mut ())
|
.poll(&mut events, Some(Duration::from_millis(0)))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
events.clear();
|
||||||
|
|
||||||
callback(
|
callback(
|
||||||
crate::event::Event::NewEvents(crate::event::StartCause::Poll),
|
Event::NewEvents(StartCause::Poll),
|
||||||
&self.window_target,
|
&self.window_target,
|
||||||
&mut control_flow,
|
&mut control_flow,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
ControlFlow::Wait => {
|
ControlFlow::Wait => {
|
||||||
let timeout = if instant_wakeup {
|
if !instant_wakeup {
|
||||||
Some(::std::time::Duration::from_millis(0))
|
self.poll.poll(&mut events, None).unwrap();
|
||||||
} else {
|
events.clear();
|
||||||
None
|
}
|
||||||
};
|
|
||||||
self.inner_loop.dispatch(timeout, &mut ()).unwrap();
|
|
||||||
callback(
|
callback(
|
||||||
crate::event::Event::NewEvents(crate::event::StartCause::WaitCancelled {
|
Event::NewEvents(StartCause::WaitCancelled {
|
||||||
start: Instant::now(),
|
start: Instant::now(),
|
||||||
requested_resume: None,
|
requested_resume: None,
|
||||||
}),
|
}),
|
||||||
|
@ -600,29 +590,27 @@ impl<T: 'static> EventLoop<T> {
|
||||||
let duration = if deadline > start && !instant_wakeup {
|
let duration = if deadline > start && !instant_wakeup {
|
||||||
deadline - start
|
deadline - start
|
||||||
} else {
|
} else {
|
||||||
::std::time::Duration::from_millis(0)
|
Duration::from_millis(0)
|
||||||
};
|
};
|
||||||
self.inner_loop.dispatch(Some(duration), &mut ()).unwrap();
|
self.poll.poll(&mut events, Some(duration)).unwrap();
|
||||||
|
events.clear();
|
||||||
|
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
if now < deadline {
|
if now < deadline {
|
||||||
callback(
|
callback(
|
||||||
crate::event::Event::NewEvents(
|
Event::NewEvents(StartCause::WaitCancelled {
|
||||||
crate::event::StartCause::WaitCancelled {
|
start,
|
||||||
start,
|
requested_resume: Some(deadline),
|
||||||
requested_resume: Some(deadline),
|
}),
|
||||||
},
|
|
||||||
),
|
|
||||||
&self.window_target,
|
&self.window_target,
|
||||||
&mut control_flow,
|
&mut control_flow,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
callback(
|
callback(
|
||||||
crate::event::Event::NewEvents(
|
Event::NewEvents(StartCause::ResumeTimeReached {
|
||||||
crate::event::StartCause::ResumeTimeReached {
|
start,
|
||||||
start,
|
requested_resume: deadline,
|
||||||
requested_resume: deadline,
|
}),
|
||||||
},
|
|
||||||
),
|
|
||||||
&self.window_target,
|
&self.window_target,
|
||||||
&mut control_flow,
|
&mut control_flow,
|
||||||
);
|
);
|
||||||
|
@ -631,11 +619,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(
|
callback(Event::LoopDestroyed, &self.window_target, &mut control_flow);
|
||||||
crate::event::Event::LoopDestroyed,
|
|
||||||
&self.window_target,
|
|
||||||
&mut control_flow,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn primary_monitor(&self) -> MonitorHandle {
|
pub fn primary_monitor(&self) -> MonitorHandle {
|
||||||
|
@ -687,12 +671,19 @@ impl<T> EventLoop<T> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn post_dispatch_triggers(&mut self) {
|
fn post_dispatch_triggers<F>(&mut self, mut callback: F, control_flow: &mut ControlFlow)
|
||||||
let mut sink = self.sink.lock().unwrap();
|
where
|
||||||
|
F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
||||||
|
{
|
||||||
let window_target = match self.window_target.p {
|
let window_target = match self.window_target.p {
|
||||||
crate::platform_impl::EventLoopWindowTarget::Wayland(ref wt) => wt,
|
crate::platform_impl::EventLoopWindowTarget::Wayland(ref wt) => wt,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut callback = |event: Event<'_, T>| {
|
||||||
|
sticky_exit_callback(event, &self.window_target, control_flow, &mut callback);
|
||||||
|
};
|
||||||
|
|
||||||
// prune possible dead windows
|
// prune possible dead windows
|
||||||
{
|
{
|
||||||
let mut cleanup_needed = window_target.cleanup_needed.lock().unwrap();
|
let mut cleanup_needed = window_target.cleanup_needed.lock().unwrap();
|
||||||
|
@ -700,41 +691,67 @@ impl<T> EventLoop<T> {
|
||||||
let pruned = window_target.store.lock().unwrap().cleanup();
|
let pruned = window_target.store.lock().unwrap().cleanup();
|
||||||
*cleanup_needed = false;
|
*cleanup_needed = false;
|
||||||
for wid in pruned {
|
for wid in pruned {
|
||||||
sink.send_window_event(crate::event::WindowEvent::Destroyed, wid);
|
callback(Event::WindowEvent {
|
||||||
|
window_id: crate::window::WindowId(
|
||||||
|
crate::platform_impl::WindowId::Wayland(wid),
|
||||||
|
),
|
||||||
|
event: WindowEvent::Destroyed,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// process pending resize/refresh
|
// process pending resize/refresh
|
||||||
window_target.store.lock().unwrap().for_each(|window| {
|
window_target.store.lock().unwrap().for_each(|window| {
|
||||||
|
let window_id =
|
||||||
|
crate::window::WindowId(crate::platform_impl::WindowId::Wayland(window.wid));
|
||||||
if let Some(frame) = window.frame {
|
if let Some(frame) = window.frame {
|
||||||
if let Some(newsize) = window.newsize {
|
if let Some((w, h)) = window.newsize {
|
||||||
let (w, h) = newsize;
|
|
||||||
// mutter (GNOME Wayland) relies on `set_geometry` to reposition window in case
|
// mutter (GNOME Wayland) relies on `set_geometry` to reposition window in case
|
||||||
// it overlaps mutter's `bounding box`, so we can't avoid this resize call,
|
// it overlaps mutter's `bounding box`, so we can't avoid this resize call,
|
||||||
// which calls `set_geometry` under the hood, for now.
|
// which calls `set_geometry` under the hood, for now.
|
||||||
frame.resize(w, h);
|
frame.resize(w, h);
|
||||||
frame.refresh();
|
frame.refresh();
|
||||||
|
|
||||||
// Don't send resize event downstream if the new size is identical to the
|
// Don't send resize event downstream if the new size is identical to the
|
||||||
// current one.
|
// current one.
|
||||||
if newsize != *window.size {
|
if (w, h) != *window.size {
|
||||||
let logical_size = crate::dpi::LogicalSize::new(w as f64, h as f64);
|
let logical_size = crate::dpi::LogicalSize::new(w as f64, h as f64);
|
||||||
sink.send_window_event(
|
let physical_size = logical_size
|
||||||
crate::event::WindowEvent::Resized(logical_size),
|
.to_physical(window.new_dpi.unwrap_or(window.prev_dpi) as f64);
|
||||||
window.wid,
|
|
||||||
);
|
|
||||||
|
|
||||||
|
callback(Event::WindowEvent {
|
||||||
|
window_id,
|
||||||
|
event: WindowEvent::Resized(physical_size),
|
||||||
|
});
|
||||||
|
*window.size = (w, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(dpi) = window.new_dpi {
|
||||||
|
let dpi = dpi as f64;
|
||||||
|
let logical_size = LogicalSize::from(*window.size);
|
||||||
|
let mut new_inner_size = Some(logical_size.to_physical(dpi));
|
||||||
|
|
||||||
|
callback(Event::WindowEvent {
|
||||||
|
window_id,
|
||||||
|
event: WindowEvent::HiDpiFactorChanged {
|
||||||
|
hidpi_factor: dpi,
|
||||||
|
new_inner_size: &mut new_inner_size,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(new_size) = new_inner_size {
|
||||||
|
let (w, h) = new_size.to_logical(dpi).into();
|
||||||
|
frame.resize(w, h);
|
||||||
*window.size = (w, h);
|
*window.size = (w, h);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(dpi) = window.new_dpi {
|
|
||||||
sink.send_window_event(
|
|
||||||
crate::event::WindowEvent::HiDpiFactorChanged(dpi as f64),
|
|
||||||
window.wid,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if window.closed {
|
if window.closed {
|
||||||
sink.send_window_event(crate::event::WindowEvent::CloseRequested, window.wid);
|
callback(Event::WindowEvent {
|
||||||
|
window_id,
|
||||||
|
event: WindowEvent::CloseRequested,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(grab_cursor) = window.grab_cursor {
|
if let Some(grab_cursor) = window.grab_cursor {
|
||||||
|
@ -749,21 +766,27 @@ impl<T> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_target<T>(target: &RootELW<T>) -> &EventLoopWindowTarget<T> {
|
||||||
|
match target.p {
|
||||||
|
crate::platform_impl::EventLoopWindowTarget::Wayland(ref wt) => wt,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wayland protocol implementations
|
* Wayland protocol implementations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct SeatManager<T: 'static> {
|
struct SeatManager {
|
||||||
sink: Arc<Mutex<WindowEventsSink<T>>>,
|
sink: EventsSink,
|
||||||
store: Arc<Mutex<WindowStore>>,
|
store: Arc<Mutex<WindowStore>>,
|
||||||
seats: Arc<Mutex<Vec<(u32, wl_seat::WlSeat)>>>,
|
seats: Arc<Mutex<Vec<(u32, wl_seat::WlSeat)>>>,
|
||||||
kbd_sender: ::calloop::channel::Sender<crate::event::Event<()>>,
|
|
||||||
relative_pointer_manager_proxy: Rc<RefCell<Option<ZwpRelativePointerManagerV1>>>,
|
relative_pointer_manager_proxy: Rc<RefCell<Option<ZwpRelativePointerManagerV1>>>,
|
||||||
pointer_constraints_proxy: Arc<Mutex<Option<ZwpPointerConstraintsV1>>>,
|
pointer_constraints_proxy: Arc<Mutex<Option<ZwpPointerConstraintsV1>>>,
|
||||||
cursor_manager: Arc<Mutex<CursorManager>>,
|
cursor_manager: Arc<Mutex<CursorManager>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> SeatManager<T> {
|
impl SeatManager {
|
||||||
fn add_seat(&mut self, id: u32, version: u32, registry: wl_registry::WlRegistry) {
|
fn add_seat(&mut self, id: u32, version: u32, registry: wl_registry::WlRegistry) {
|
||||||
use std::cmp::min;
|
use std::cmp::min;
|
||||||
|
|
||||||
|
@ -775,7 +798,6 @@ impl<T: 'static> SeatManager<T> {
|
||||||
relative_pointer_manager_proxy: self.relative_pointer_manager_proxy.clone(),
|
relative_pointer_manager_proxy: self.relative_pointer_manager_proxy.clone(),
|
||||||
keyboard: None,
|
keyboard: None,
|
||||||
touch: None,
|
touch: None,
|
||||||
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(),
|
cursor_manager: self.cursor_manager.clone(),
|
||||||
};
|
};
|
||||||
|
@ -799,10 +821,9 @@ impl<T: 'static> SeatManager<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SeatData<T> {
|
struct SeatData {
|
||||||
sink: Arc<Mutex<WindowEventsSink<T>>>,
|
sink: EventsSink,
|
||||||
store: Arc<Mutex<WindowStore>>,
|
store: Arc<Mutex<WindowStore>>,
|
||||||
kbd_sender: ::calloop::channel::Sender<crate::event::Event<()>>,
|
|
||||||
pointer: Option<wl_pointer::WlPointer>,
|
pointer: Option<wl_pointer::WlPointer>,
|
||||||
relative_pointer: Option<ZwpRelativePointerV1>,
|
relative_pointer: Option<ZwpRelativePointerV1>,
|
||||||
relative_pointer_manager_proxy: Rc<RefCell<Option<ZwpRelativePointerManagerV1>>>,
|
relative_pointer_manager_proxy: Rc<RefCell<Option<ZwpRelativePointerManagerV1>>>,
|
||||||
|
@ -812,7 +833,7 @@ struct SeatData<T> {
|
||||||
cursor_manager: Arc<Mutex<CursorManager>>,
|
cursor_manager: Arc<Mutex<CursorManager>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> SeatData<T> {
|
impl SeatData {
|
||||||
fn receive(&mut self, evt: wl_seat::Event, seat: wl_seat::WlSeat) {
|
fn receive(&mut self, evt: wl_seat::Event, seat: wl_seat::WlSeat) {
|
||||||
match evt {
|
match evt {
|
||||||
wl_seat::Event::Name { .. } => (),
|
wl_seat::Event::Name { .. } => (),
|
||||||
|
@ -858,7 +879,7 @@ impl<T: 'static> SeatData<T> {
|
||||||
if capabilities.contains(wl_seat::Capability::Keyboard) && self.keyboard.is_none() {
|
if capabilities.contains(wl_seat::Capability::Keyboard) && self.keyboard.is_none() {
|
||||||
self.keyboard = Some(super::keyboard::init_keyboard(
|
self.keyboard = Some(super::keyboard::init_keyboard(
|
||||||
&seat,
|
&seat,
|
||||||
self.kbd_sender.clone(),
|
self.sink.clone(),
|
||||||
self.modifiers_tracker.clone(),
|
self.modifiers_tracker.clone(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -892,7 +913,7 @@ impl<T: 'static> SeatData<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Drop for SeatData<T> {
|
impl Drop for SeatData {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Some(pointer) = self.pointer.take() {
|
if let Some(pointer) = self.pointer.take() {
|
||||||
if pointer.as_ref().version() >= 3 {
|
if pointer.as_ref().version() >= 3 {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use super::{make_wid, DeviceId};
|
use super::{event_loop::EventsSink, make_wid, DeviceId};
|
||||||
use smithay_client_toolkit::{
|
use smithay_client_toolkit::{
|
||||||
keyboard::{
|
keyboard::{
|
||||||
self, map_keyboard_auto_with_repeat, Event as KbEvent, KeyRepeatEvent, KeyRepeatKind,
|
self, map_keyboard_auto_with_repeat, Event as KbEvent, KeyRepeatEvent, KeyRepeatKind,
|
||||||
|
@ -9,12 +9,12 @@ use smithay_client_toolkit::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::event::{
|
use crate::event::{
|
||||||
DeviceEvent, ElementState, Event, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent,
|
DeviceEvent, ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init_keyboard(
|
pub fn init_keyboard(
|
||||||
seat: &wl_seat::WlSeat,
|
seat: &wl_seat::WlSeat,
|
||||||
sink: ::calloop::channel::Sender<crate::event::Event<()>>,
|
sink: EventsSink,
|
||||||
modifiers_tracker: Arc<Mutex<ModifiersState>>,
|
modifiers_tracker: Arc<Mutex<ModifiersState>>,
|
||||||
) -> wl_keyboard::WlKeyboard {
|
) -> wl_keyboard::WlKeyboard {
|
||||||
// { variables to be captured by the closures
|
// { variables to be captured by the closures
|
||||||
|
@ -31,22 +31,12 @@ pub fn init_keyboard(
|
||||||
match evt {
|
match evt {
|
||||||
KbEvent::Enter { surface, .. } => {
|
KbEvent::Enter { surface, .. } => {
|
||||||
let wid = make_wid(&surface);
|
let wid = make_wid(&surface);
|
||||||
my_sink
|
my_sink.send_window_event(WindowEvent::Focused(true), wid);
|
||||||
.send(Event::WindowEvent {
|
|
||||||
window_id: mk_root_wid(wid),
|
|
||||||
event: WindowEvent::Focused(true),
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
*target.lock().unwrap() = Some(wid);
|
*target.lock().unwrap() = Some(wid);
|
||||||
}
|
}
|
||||||
KbEvent::Leave { surface, .. } => {
|
KbEvent::Leave { surface, .. } => {
|
||||||
let wid = make_wid(&surface);
|
let wid = make_wid(&surface);
|
||||||
my_sink
|
my_sink.send_window_event(WindowEvent::Focused(false), wid);
|
||||||
.send(Event::WindowEvent {
|
|
||||||
window_id: mk_root_wid(wid),
|
|
||||||
event: WindowEvent::Focused(false),
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
*target.lock().unwrap() = None;
|
*target.lock().unwrap() = None;
|
||||||
}
|
}
|
||||||
KbEvent::Key {
|
KbEvent::Key {
|
||||||
|
@ -63,33 +53,28 @@ pub fn init_keyboard(
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let vkcode = key_to_vkey(rawkey, keysym);
|
let vkcode = key_to_vkey(rawkey, keysym);
|
||||||
my_sink
|
my_sink.send_window_event(
|
||||||
.send(Event::WindowEvent {
|
WindowEvent::KeyboardInput {
|
||||||
window_id: mk_root_wid(wid),
|
device_id: crate::event::DeviceId(
|
||||||
event: WindowEvent::KeyboardInput {
|
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||||
device_id: device_id(),
|
),
|
||||||
input: KeyboardInput {
|
input: KeyboardInput {
|
||||||
state,
|
state,
|
||||||
scancode: rawkey,
|
scancode: rawkey,
|
||||||
virtual_keycode: vkcode,
|
virtual_keycode: vkcode,
|
||||||
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
||||||
},
|
|
||||||
is_synthetic: false,
|
|
||||||
},
|
},
|
||||||
})
|
is_synthetic: false,
|
||||||
.unwrap();
|
},
|
||||||
|
wid,
|
||||||
|
);
|
||||||
// send char event only on key press, not release
|
// send char event only on key press, not release
|
||||||
if let ElementState::Released = state {
|
if let ElementState::Released = state {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(txt) = utf8 {
|
if let Some(txt) = utf8 {
|
||||||
for chr in txt.chars() {
|
for chr in txt.chars() {
|
||||||
my_sink
|
my_sink.send_window_event(WindowEvent::ReceivedCharacter(chr), wid);
|
||||||
.send(Event::WindowEvent {
|
|
||||||
window_id: mk_root_wid(wid),
|
|
||||||
event: WindowEvent::ReceivedCharacter(chr),
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,12 +87,7 @@ pub fn init_keyboard(
|
||||||
|
|
||||||
*modifiers_tracker.lock().unwrap() = modifiers;
|
*modifiers_tracker.lock().unwrap() = modifiers;
|
||||||
|
|
||||||
my_sink
|
my_sink.send_device_event(DeviceEvent::ModifiersChanged(modifiers), DeviceId);
|
||||||
.send(Event::DeviceEvent {
|
|
||||||
device_id: device_id(),
|
|
||||||
event: DeviceEvent::ModifiersChanged(modifiers),
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -115,29 +95,24 @@ pub fn init_keyboard(
|
||||||
if let Some(wid) = *repeat_target.lock().unwrap() {
|
if let Some(wid) = *repeat_target.lock().unwrap() {
|
||||||
let state = ElementState::Pressed;
|
let state = ElementState::Pressed;
|
||||||
let vkcode = key_to_vkey(repeat_event.rawkey, repeat_event.keysym);
|
let vkcode = key_to_vkey(repeat_event.rawkey, repeat_event.keysym);
|
||||||
repeat_sink
|
repeat_sink.send_window_event(
|
||||||
.send(Event::WindowEvent {
|
WindowEvent::KeyboardInput {
|
||||||
window_id: mk_root_wid(wid),
|
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(
|
||||||
event: WindowEvent::KeyboardInput {
|
DeviceId,
|
||||||
device_id: device_id(),
|
)),
|
||||||
input: KeyboardInput {
|
input: KeyboardInput {
|
||||||
state,
|
state,
|
||||||
scancode: repeat_event.rawkey,
|
scancode: repeat_event.rawkey,
|
||||||
virtual_keycode: vkcode,
|
virtual_keycode: vkcode,
|
||||||
modifiers: my_modifiers.lock().unwrap().clone(),
|
modifiers: my_modifiers.lock().unwrap().clone(),
|
||||||
},
|
|
||||||
is_synthetic: false,
|
|
||||||
},
|
},
|
||||||
})
|
is_synthetic: false,
|
||||||
.unwrap();
|
},
|
||||||
|
wid,
|
||||||
|
);
|
||||||
if let Some(txt) = repeat_event.utf8 {
|
if let Some(txt) = repeat_event.utf8 {
|
||||||
for chr in txt.chars() {
|
for chr in txt.chars() {
|
||||||
repeat_sink
|
repeat_sink.send_window_event(WindowEvent::ReceivedCharacter(chr), wid);
|
||||||
.send(Event::WindowEvent {
|
|
||||||
window_id: mk_root_wid(wid),
|
|
||||||
event: WindowEvent::ReceivedCharacter(chr),
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,22 +139,12 @@ pub fn init_keyboard(
|
||||||
move |evt, _| match evt {
|
move |evt, _| match evt {
|
||||||
wl_keyboard::Event::Enter { surface, .. } => {
|
wl_keyboard::Event::Enter { surface, .. } => {
|
||||||
let wid = make_wid(&surface);
|
let wid = make_wid(&surface);
|
||||||
my_sink
|
my_sink.send_window_event(WindowEvent::Focused(true), wid);
|
||||||
.send(Event::WindowEvent {
|
|
||||||
window_id: mk_root_wid(wid),
|
|
||||||
event: WindowEvent::Focused(true),
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
target = Some(wid);
|
target = Some(wid);
|
||||||
}
|
}
|
||||||
wl_keyboard::Event::Leave { surface, .. } => {
|
wl_keyboard::Event::Leave { surface, .. } => {
|
||||||
let wid = make_wid(&surface);
|
let wid = make_wid(&surface);
|
||||||
my_sink
|
my_sink.send_window_event(WindowEvent::Focused(false), wid);
|
||||||
.send(Event::WindowEvent {
|
|
||||||
window_id: mk_root_wid(wid),
|
|
||||||
event: WindowEvent::Focused(false),
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
target = None;
|
target = None;
|
||||||
}
|
}
|
||||||
wl_keyboard::Event::Key { key, state, .. } => {
|
wl_keyboard::Event::Key { key, state, .. } => {
|
||||||
|
@ -189,21 +154,21 @@ pub fn init_keyboard(
|
||||||
wl_keyboard::KeyState::Released => ElementState::Released,
|
wl_keyboard::KeyState::Released => ElementState::Released,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
my_sink
|
my_sink.send_window_event(
|
||||||
.send(Event::WindowEvent {
|
WindowEvent::KeyboardInput {
|
||||||
window_id: mk_root_wid(wid),
|
device_id: crate::event::DeviceId(
|
||||||
event: WindowEvent::KeyboardInput {
|
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||||
device_id: device_id(),
|
),
|
||||||
input: KeyboardInput {
|
input: KeyboardInput {
|
||||||
state,
|
state,
|
||||||
scancode: key,
|
scancode: key,
|
||||||
virtual_keycode: None,
|
virtual_keycode: None,
|
||||||
modifiers: ModifiersState::default(),
|
modifiers: ModifiersState::default(),
|
||||||
},
|
|
||||||
is_synthetic: false,
|
|
||||||
},
|
},
|
||||||
})
|
is_synthetic: false,
|
||||||
.unwrap();
|
},
|
||||||
|
wid,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
@ -412,11 +377,3 @@ impl ModifiersState {
|
||||||
m
|
m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn device_id() -> crate::event::DeviceId {
|
|
||||||
crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mk_root_wid(wid: crate::platform_impl::wayland::WindowId) -> crate::window::WindowId {
|
|
||||||
crate::window::WindowId(crate::platform_impl::WindowId::Wayland(wid))
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,10 +2,7 @@
|
||||||
target_os = "netbsd", target_os = "openbsd"))]
|
target_os = "netbsd", target_os = "openbsd"))]
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
event_loop::{
|
event_loop::{EventLoop, EventLoopProxy, EventLoopWindowTarget, MonitorHandle, VideoMode},
|
||||||
EventLoop, EventLoopProxy, EventLoopWindowTarget, MonitorHandle, VideoMode,
|
|
||||||
WindowEventsSink,
|
|
||||||
},
|
|
||||||
window::Window,
|
window::Window,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::event::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
event_loop::{CursorManager, WindowEventsSink},
|
event_loop::{CursorManager, EventsSink},
|
||||||
window::WindowStore,
|
window::WindowStore,
|
||||||
DeviceId,
|
DeviceId,
|
||||||
};
|
};
|
||||||
|
@ -28,9 +28,9 @@ use smithay_client_toolkit::reexports::protocols::unstable::pointer_constraints:
|
||||||
|
|
||||||
use smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface;
|
use smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface;
|
||||||
|
|
||||||
pub fn implement_pointer<T: 'static>(
|
pub fn implement_pointer(
|
||||||
seat: &wl_seat::WlSeat,
|
seat: &wl_seat::WlSeat,
|
||||||
sink: Arc<Mutex<WindowEventsSink<T>>>,
|
sink: EventsSink,
|
||||||
store: Arc<Mutex<WindowStore>>,
|
store: Arc<Mutex<WindowStore>>,
|
||||||
modifiers_tracker: Arc<Mutex<ModifiersState>>,
|
modifiers_tracker: Arc<Mutex<ModifiersState>>,
|
||||||
cursor_manager: Arc<Mutex<CursorManager>>,
|
cursor_manager: Arc<Mutex<CursorManager>>,
|
||||||
|
@ -43,7 +43,6 @@ pub fn implement_pointer<T: 'static>(
|
||||||
|
|
||||||
pointer.implement_closure(
|
pointer.implement_closure(
|
||||||
move |evt, pointer| {
|
move |evt, pointer| {
|
||||||
let mut sink = sink.lock().unwrap();
|
|
||||||
let store = store.lock().unwrap();
|
let store = store.lock().unwrap();
|
||||||
let mut cursor_manager = cursor_manager.lock().unwrap();
|
let mut cursor_manager = cursor_manager.lock().unwrap();
|
||||||
match evt {
|
match evt {
|
||||||
|
@ -242,20 +241,18 @@ pub fn implement_pointer<T: 'static>(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn implement_relative_pointer<T: 'static>(
|
pub fn implement_relative_pointer(
|
||||||
sink: Arc<Mutex<WindowEventsSink<T>>>,
|
sink: EventsSink,
|
||||||
pointer: &WlPointer,
|
pointer: &WlPointer,
|
||||||
manager: &ZwpRelativePointerManagerV1,
|
manager: &ZwpRelativePointerManagerV1,
|
||||||
) -> Result<ZwpRelativePointerV1, ()> {
|
) -> Result<ZwpRelativePointerV1, ()> {
|
||||||
manager.get_relative_pointer(pointer, |rel_pointer| {
|
manager.get_relative_pointer(pointer, |rel_pointer| {
|
||||||
rel_pointer.implement_closure(
|
rel_pointer.implement_closure(
|
||||||
move |evt, _rel_pointer| {
|
move |evt, _rel_pointer| match evt {
|
||||||
let mut sink = sink.lock().unwrap();
|
Event::RelativeMotion { dx, dy, .. } => {
|
||||||
match evt {
|
sink.send_device_event(DeviceEvent::MouseMotion { delta: (dx, dy) }, DeviceId)
|
||||||
Event::RelativeMotion { dx, dy, .. } => sink
|
|
||||||
.send_device_event(DeviceEvent::MouseMotion { delta: (dx, dy) }, DeviceId),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use crate::event::{TouchPhase, WindowEvent};
|
use crate::event::{TouchPhase, WindowEvent};
|
||||||
|
|
||||||
use super::{event_loop::WindowEventsSink, window::WindowStore, DeviceId, WindowId};
|
use super::{event_loop::EventsSink, window::WindowStore, DeviceId, WindowId};
|
||||||
|
|
||||||
use smithay_client_toolkit::reexports::client::protocol::{
|
use smithay_client_toolkit::reexports::client::protocol::{
|
||||||
wl_seat,
|
wl_seat,
|
||||||
|
@ -15,16 +15,15 @@ struct TouchPoint {
|
||||||
id: i32,
|
id: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn implement_touch<T: 'static>(
|
pub(crate) fn implement_touch(
|
||||||
seat: &wl_seat::WlSeat,
|
seat: &wl_seat::WlSeat,
|
||||||
sink: Arc<Mutex<WindowEventsSink<T>>>,
|
sink: EventsSink,
|
||||||
store: Arc<Mutex<WindowStore>>,
|
store: Arc<Mutex<WindowStore>>,
|
||||||
) -> WlTouch {
|
) -> WlTouch {
|
||||||
let mut pending_ids = Vec::new();
|
let mut pending_ids = Vec::new();
|
||||||
seat.get_touch(|touch| {
|
seat.get_touch(|touch| {
|
||||||
touch.implement_closure(
|
touch.implement_closure(
|
||||||
move |evt, _| {
|
move |evt, _| {
|
||||||
let mut sink = sink.lock().unwrap();
|
|
||||||
let store = store.lock().unwrap();
|
let store = store.lock().unwrap();
|
||||||
match evt {
|
match evt {
|
||||||
TouchEvent::Down {
|
TouchEvent::Down {
|
||||||
|
|
|
@ -6,7 +6,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
dpi::{LogicalPosition, LogicalSize},
|
dpi::{LogicalSize, PhysicalPosition, PhysicalSize, Position, Size},
|
||||||
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||||
monitor::MonitorHandle as RootMonitorHandle,
|
monitor::MonitorHandle as RootMonitorHandle,
|
||||||
platform_impl::{
|
platform_impl::{
|
||||||
|
@ -49,11 +49,7 @@ impl Window {
|
||||||
attributes: WindowAttributes,
|
attributes: WindowAttributes,
|
||||||
pl_attribs: PlAttributes,
|
pl_attribs: PlAttributes,
|
||||||
) -> Result<Window, RootOsError> {
|
) -> Result<Window, RootOsError> {
|
||||||
let (width, height) = attributes.inner_size.map(Into::into).unwrap_or((800, 600));
|
// Create the surface first to get initial DPI
|
||||||
// Create the window
|
|
||||||
let size = Arc::new(Mutex::new((width, height)));
|
|
||||||
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 cursor_manager = evlp.cursor_manager.clone();
|
||||||
let surface = evlp.env.create_surface(move |dpi, surface| {
|
let surface = evlp.env.create_surface(move |dpi, surface| {
|
||||||
|
@ -61,7 +57,18 @@ impl Window {
|
||||||
surface.set_buffer_scale(dpi);
|
surface.set_buffer_scale(dpi);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let dpi = get_dpi_factor(&surface) as f64;
|
||||||
|
let (width, height) = attributes
|
||||||
|
.inner_size
|
||||||
|
.map(|size| size.to_logical(dpi).into())
|
||||||
|
.unwrap_or((800, 600));
|
||||||
|
|
||||||
|
// Create the window
|
||||||
|
let size = Arc::new(Mutex::new((width, height)));
|
||||||
|
let fullscreen = Arc::new(Mutex::new(false));
|
||||||
|
|
||||||
let window_store = evlp.store.clone();
|
let window_store = evlp.store.clone();
|
||||||
|
|
||||||
let my_surface = surface.clone();
|
let my_surface = surface.clone();
|
||||||
let mut frame = SWindow::<ConceptFrame>::init_from_env(
|
let mut frame = SWindow::<ConceptFrame>::init_from_env(
|
||||||
&evlp.env,
|
&evlp.env,
|
||||||
|
@ -137,8 +144,16 @@ impl Window {
|
||||||
frame.set_title(attributes.title);
|
frame.set_title(attributes.title);
|
||||||
|
|
||||||
// min-max dimensions
|
// min-max dimensions
|
||||||
frame.set_min_size(attributes.min_inner_size.map(Into::into));
|
frame.set_min_size(
|
||||||
frame.set_max_size(attributes.max_inner_size.map(Into::into));
|
attributes
|
||||||
|
.min_inner_size
|
||||||
|
.map(|size| size.to_logical(dpi).into()),
|
||||||
|
);
|
||||||
|
frame.set_max_size(
|
||||||
|
attributes
|
||||||
|
.max_inner_size
|
||||||
|
.map(|size| size.to_logical(dpi).into()),
|
||||||
|
);
|
||||||
|
|
||||||
let kill_switch = Arc::new(Mutex::new(false));
|
let kill_switch = Arc::new(Mutex::new(false));
|
||||||
let need_frame_refresh = Arc::new(Mutex::new(true));
|
let need_frame_refresh = Arc::new(Mutex::new(true));
|
||||||
|
@ -191,22 +206,24 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn outer_position(&self) -> Result<LogicalPosition, NotSupportedError> {
|
pub fn outer_position(&self) -> Result<PhysicalPosition, NotSupportedError> {
|
||||||
Err(NotSupportedError::new())
|
Err(NotSupportedError::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn inner_position(&self) -> Result<LogicalPosition, NotSupportedError> {
|
pub fn inner_position(&self) -> Result<PhysicalPosition, NotSupportedError> {
|
||||||
Err(NotSupportedError::new())
|
Err(NotSupportedError::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_outer_position(&self, _pos: LogicalPosition) {
|
pub fn set_outer_position(&self, _pos: Position) {
|
||||||
// Not possible with wayland
|
// Not possible with wayland
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner_size(&self) -> LogicalSize {
|
pub fn inner_size(&self) -> PhysicalSize {
|
||||||
self.size.lock().unwrap().clone().into()
|
let dpi = self.hidpi_factor() as f64;
|
||||||
|
let size = LogicalSize::from(*self.size.lock().unwrap());
|
||||||
|
size.to_physical(dpi)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request_redraw(&self) {
|
pub fn request_redraw(&self) {
|
||||||
|
@ -214,34 +231,39 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn outer_size(&self) -> LogicalSize {
|
pub fn outer_size(&self) -> PhysicalSize {
|
||||||
|
let dpi = self.hidpi_factor() as f64;
|
||||||
let (w, h) = self.size.lock().unwrap().clone();
|
let (w, h) = self.size.lock().unwrap().clone();
|
||||||
// let (w, h) = super::wayland_window::add_borders(w as i32, h as i32);
|
// let (w, h) = super::wayland_window::add_borders(w as i32, h as i32);
|
||||||
(w, h).into()
|
let size = LogicalSize::from((w, h));
|
||||||
|
size.to_physical(dpi)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
// NOTE: This will only resize the borders, the contents must be updated by the user
|
// NOTE: This will only resize the borders, the contents must be updated by the user
|
||||||
pub fn set_inner_size(&self, size: LogicalSize) {
|
pub fn set_inner_size(&self, size: Size) {
|
||||||
let (w, h) = size.into();
|
let dpi = self.hidpi_factor() as f64;
|
||||||
|
let (w, h) = size.to_logical(dpi).into();
|
||||||
self.frame.lock().unwrap().resize(w, h);
|
self.frame.lock().unwrap().resize(w, h);
|
||||||
*(self.size.lock().unwrap()) = (w, h);
|
*(self.size.lock().unwrap()) = (w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_min_inner_size(&self, dimensions: Option<LogicalSize>) {
|
pub fn set_min_inner_size(&self, dimensions: Option<Size>) {
|
||||||
|
let dpi = self.hidpi_factor() as f64;
|
||||||
self.frame
|
self.frame
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_min_size(dimensions.map(Into::into));
|
.set_min_size(dimensions.map(|dim| dim.to_logical(dpi).into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_max_inner_size(&self, dimensions: Option<LogicalSize>) {
|
pub fn set_max_inner_size(&self, dimensions: Option<Size>) {
|
||||||
|
let dpi = self.hidpi_factor() as f64;
|
||||||
self.frame
|
self.frame
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_max_size(dimensions.map(Into::into));
|
.set_max_size(dimensions.map(|dim| dim.to_logical(dpi).into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -325,7 +347,7 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_cursor_position(&self, _pos: LogicalPosition) -> Result<(), ExternalError> {
|
pub fn set_cursor_position(&self, _pos: Position) -> Result<(), ExternalError> {
|
||||||
Err(ExternalError::NotSupported(NotSupportedError::new()))
|
Err(ExternalError::NotSupported(NotSupportedError::new()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,6 +397,7 @@ impl Drop for Window {
|
||||||
|
|
||||||
struct InternalWindow {
|
struct InternalWindow {
|
||||||
surface: wl_surface::WlSurface,
|
surface: wl_surface::WlSurface,
|
||||||
|
// TODO: CONVERT TO LogicalSize<u32>s
|
||||||
newsize: Option<(u32, u32)>,
|
newsize: Option<(u32, u32)>,
|
||||||
size: Arc<Mutex<(u32, u32)>>,
|
size: Arc<Mutex<(u32, u32)>>,
|
||||||
need_refresh: Arc<Mutex<bool>>,
|
need_refresh: Arc<Mutex<bool>>,
|
||||||
|
@ -395,6 +418,7 @@ pub struct WindowStore {
|
||||||
pub struct WindowStoreForEach<'a> {
|
pub struct WindowStoreForEach<'a> {
|
||||||
pub newsize: Option<(u32, u32)>,
|
pub newsize: Option<(u32, u32)>,
|
||||||
pub size: &'a mut (u32, u32),
|
pub size: &'a mut (u32, u32),
|
||||||
|
pub prev_dpi: i32,
|
||||||
pub new_dpi: Option<i32>,
|
pub new_dpi: Option<i32>,
|
||||||
pub closed: bool,
|
pub closed: bool,
|
||||||
pub grab_cursor: Option<bool>,
|
pub grab_cursor: Option<bool>,
|
||||||
|
@ -460,6 +484,7 @@ impl WindowStore {
|
||||||
f(WindowStoreForEach {
|
f(WindowStoreForEach {
|
||||||
newsize: window.newsize.take(),
|
newsize: window.newsize.take(),
|
||||||
size: &mut *(window.size.lock().unwrap()),
|
size: &mut *(window.size.lock().unwrap()),
|
||||||
|
prev_dpi: window.current_dpi,
|
||||||
new_dpi: window.new_dpi,
|
new_dpi: window.new_dpi,
|
||||||
closed: window.closed,
|
closed: window.closed,
|
||||||
grab_cursor: window.cursor_grab_changed.lock().unwrap().take(),
|
grab_cursor: window.cursor_grab_changed.lock().unwrap().take(),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{cell::RefCell, collections::HashMap, rc::Rc, slice};
|
use std::{cell::RefCell, collections::HashMap, rc::Rc, slice, sync::Arc};
|
||||||
|
|
||||||
use libc::{c_char, c_int, c_long, c_uint, c_ulong};
|
use libc::{c_char, c_int, c_long, c_uint, c_ulong};
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ use super::{
|
||||||
use util::modifiers::{ModifierKeyState, ModifierKeymap};
|
use util::modifiers::{ModifierKeyState, ModifierKeymap};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
dpi::{LogicalPosition, LogicalSize},
|
dpi::{PhysicalPosition, PhysicalSize},
|
||||||
event::{
|
event::{
|
||||||
DeviceEvent, ElementState, Event, KeyboardInput, ModifiersState, TouchPhase, WindowEvent,
|
DeviceEvent, ElementState, Event, KeyboardInput, ModifiersState, TouchPhase, WindowEvent,
|
||||||
},
|
},
|
||||||
|
@ -45,7 +45,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
|
|
||||||
fn with_window<F, Ret>(&self, window_id: ffi::Window, callback: F) -> Option<Ret>
|
fn with_window<F, Ret>(&self, window_id: ffi::Window, callback: F) -> Option<Ret>
|
||||||
where
|
where
|
||||||
F: Fn(&UnownedWindow) -> Ret,
|
F: Fn(&Arc<UnownedWindow>) -> Ret,
|
||||||
{
|
{
|
||||||
let mut deleted = false;
|
let mut deleted = false;
|
||||||
let window_id = WindowId(window_id);
|
let window_id = WindowId(window_id);
|
||||||
|
@ -59,7 +59,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
deleted = arc.is_none();
|
deleted = arc.is_none();
|
||||||
arc
|
arc
|
||||||
})
|
})
|
||||||
.map(|window| callback(&*window));
|
.map(|window| callback(&window));
|
||||||
if deleted {
|
if deleted {
|
||||||
// Garbage collection
|
// Garbage collection
|
||||||
wt.windows.borrow_mut().remove(&window_id);
|
wt.windows.borrow_mut().remove(&window_id);
|
||||||
|
@ -107,7 +107,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
|
|
||||||
pub(super) fn process_event<F>(&mut self, xev: &mut ffi::XEvent, mut callback: F)
|
pub(super) fn process_event<F>(&mut self, xev: &mut ffi::XEvent, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(Event<T>),
|
F: FnMut(Event<'_, T>),
|
||||||
{
|
{
|
||||||
let wt = get_xtarget(&self.target);
|
let wt = get_xtarget(&self.target);
|
||||||
// XFilterEvent tells us when an event has been discarded by the input method.
|
// XFilterEvent tells us when an event has been discarded by the input method.
|
||||||
|
@ -321,16 +321,11 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
ffi::ConfigureNotify => {
|
ffi::ConfigureNotify => {
|
||||||
#[derive(Debug, Default)]
|
|
||||||
struct Events {
|
|
||||||
resized: Option<WindowEvent>,
|
|
||||||
moved: Option<WindowEvent>,
|
|
||||||
dpi_changed: Option<WindowEvent>,
|
|
||||||
}
|
|
||||||
|
|
||||||
let xev: &ffi::XConfigureEvent = xev.as_ref();
|
let xev: &ffi::XConfigureEvent = xev.as_ref();
|
||||||
let xwindow = xev.window;
|
let xwindow = xev.window;
|
||||||
let events = self.with_window(xwindow, |window| {
|
let window_id = mkwid(xwindow);
|
||||||
|
|
||||||
|
if let Some(window) = self.with_window(xwindow, Arc::clone) {
|
||||||
// So apparently...
|
// So apparently...
|
||||||
// `XSendEvent` (synthetic `ConfigureNotify`) -> position relative to root
|
// `XSendEvent` (synthetic `ConfigureNotify`) -> position relative to root
|
||||||
// `XConfigureNotify` (real `ConfigureNotify`) -> position relative to parent
|
// `XConfigureNotify` (real `ConfigureNotify`) -> position relative to parent
|
||||||
|
@ -344,7 +339,6 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
let new_inner_size = (xev.width as u32, xev.height as u32);
|
let new_inner_size = (xev.width as u32, xev.height as u32);
|
||||||
let new_inner_position = (xev.x as i32, xev.y as i32);
|
let new_inner_position = (xev.x as i32, xev.y as i32);
|
||||||
|
|
||||||
let mut monitor = window.current_monitor(); // This must be done *before* locking!
|
|
||||||
let mut shared_state_lock = window.shared_state.lock();
|
let mut shared_state_lock = window.shared_state.lock();
|
||||||
|
|
||||||
let (mut resized, moved) = {
|
let (mut resized, moved) = {
|
||||||
|
@ -374,8 +368,6 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
(resized, moved)
|
(resized, moved)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut events = Events::default();
|
|
||||||
|
|
||||||
let new_outer_position = if moved || shared_state_lock.position.is_none() {
|
let new_outer_position = if moved || shared_state_lock.position.is_none() {
|
||||||
// We need to convert client area position to window position.
|
// We need to convert client area position to window position.
|
||||||
let frame_extents = shared_state_lock
|
let frame_extents = shared_state_lock
|
||||||
|
@ -392,9 +384,10 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
.inner_pos_to_outer(new_inner_position.0, new_inner_position.1);
|
.inner_pos_to_outer(new_inner_position.0, new_inner_position.1);
|
||||||
shared_state_lock.position = Some(outer);
|
shared_state_lock.position = Some(outer);
|
||||||
if moved {
|
if moved {
|
||||||
let logical_position =
|
callback(Event::WindowEvent {
|
||||||
LogicalPosition::from_physical(outer, monitor.hidpi_factor);
|
window_id,
|
||||||
events.moved = Some(WindowEvent::Moved(logical_position));
|
event: WindowEvent::Moved(outer.into()),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
outer
|
outer
|
||||||
} else {
|
} else {
|
||||||
|
@ -406,36 +399,46 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
// resizing by dragging across monitors *without* dropping the window.
|
// resizing by dragging across monitors *without* dropping the window.
|
||||||
let (width, height) = shared_state_lock
|
let (width, height) = shared_state_lock
|
||||||
.dpi_adjusted
|
.dpi_adjusted
|
||||||
.unwrap_or_else(|| (xev.width as f64, xev.height as f64));
|
.unwrap_or_else(|| (xev.width as u32, xev.height as u32));
|
||||||
|
|
||||||
let last_hidpi_factor = shared_state_lock.last_monitor.hidpi_factor;
|
let last_hidpi_factor = shared_state_lock.last_monitor.hidpi_factor;
|
||||||
let new_hidpi_factor = {
|
let new_hidpi_factor = {
|
||||||
let window_rect = util::AaRect::new(new_outer_position, new_inner_size);
|
let window_rect = util::AaRect::new(new_outer_position, new_inner_size);
|
||||||
let new_monitor = wt.xconn.get_monitor_for_window(Some(window_rect));
|
let monitor = wt.xconn.get_monitor_for_window(Some(window_rect));
|
||||||
|
|
||||||
if new_monitor.is_dummy() {
|
if monitor.is_dummy() {
|
||||||
// Avoid updating monitor using a dummy monitor handle
|
// Avoid updating monitor using a dummy monitor handle
|
||||||
last_hidpi_factor
|
last_hidpi_factor
|
||||||
} else {
|
} else {
|
||||||
monitor = new_monitor;
|
|
||||||
shared_state_lock.last_monitor = monitor.clone();
|
shared_state_lock.last_monitor = monitor.clone();
|
||||||
monitor.hidpi_factor
|
monitor.hidpi_factor
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if last_hidpi_factor != new_hidpi_factor {
|
if last_hidpi_factor != new_hidpi_factor {
|
||||||
events.dpi_changed =
|
let (new_width, new_height) = window.adjust_for_dpi(
|
||||||
Some(WindowEvent::HiDpiFactorChanged(new_hidpi_factor));
|
|
||||||
let (new_width, new_height, flusher) = window.adjust_for_dpi(
|
|
||||||
last_hidpi_factor,
|
last_hidpi_factor,
|
||||||
new_hidpi_factor,
|
new_hidpi_factor,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
);
|
);
|
||||||
flusher.queue();
|
|
||||||
shared_state_lock.dpi_adjusted = Some((new_width, new_height));
|
let mut new_inner_size = Some(PhysicalSize::new(new_width, new_height));
|
||||||
// if the DPI factor changed, force a resize event to ensure the logical
|
|
||||||
// size is computed with the right DPI factor
|
callback(Event::WindowEvent {
|
||||||
resized = true;
|
window_id,
|
||||||
|
event: WindowEvent::HiDpiFactorChanged {
|
||||||
|
hidpi_factor: new_hidpi_factor,
|
||||||
|
new_inner_size: &mut new_inner_size,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(new_size) = new_inner_size {
|
||||||
|
window.set_inner_size_physical(new_size.width, new_size.height);
|
||||||
|
shared_state_lock.dpi_adjusted = Some(new_size.into());
|
||||||
|
// if the DPI factor changed, force a resize event to ensure the logical
|
||||||
|
// size is computed with the right DPI factor
|
||||||
|
resized = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,44 +447,19 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
// WMs constrain the window size, making the resize fail. This would cause an endless stream of
|
// WMs constrain the window size, making the resize fail. This would cause an endless stream of
|
||||||
// XResizeWindow requests, making Xorg, the winit client, and the WM consume 100% of CPU.
|
// XResizeWindow requests, making Xorg, the winit client, and the WM consume 100% of CPU.
|
||||||
if let Some(adjusted_size) = shared_state_lock.dpi_adjusted {
|
if let Some(adjusted_size) = shared_state_lock.dpi_adjusted {
|
||||||
let rounded_size = (
|
if new_inner_size == adjusted_size || !util::wm_name_is_one_of(&["Xfwm4"]) {
|
||||||
adjusted_size.0.round() as u32,
|
|
||||||
adjusted_size.1.round() as u32,
|
|
||||||
);
|
|
||||||
if new_inner_size == rounded_size || !util::wm_name_is_one_of(&["Xfwm4"]) {
|
|
||||||
// When this finally happens, the event will not be synthetic.
|
// When this finally happens, the event will not be synthetic.
|
||||||
shared_state_lock.dpi_adjusted = None;
|
shared_state_lock.dpi_adjusted = None;
|
||||||
} else {
|
} else {
|
||||||
unsafe {
|
window.set_inner_size_physical(adjusted_size.0, adjusted_size.1);
|
||||||
(wt.xconn.xlib.XResizeWindow)(
|
|
||||||
wt.xconn.display,
|
|
||||||
xwindow,
|
|
||||||
rounded_size.0 as c_uint,
|
|
||||||
rounded_size.1 as c_uint,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if resized {
|
if resized {
|
||||||
let logical_size =
|
callback(Event::WindowEvent {
|
||||||
LogicalSize::from_physical(new_inner_size, monitor.hidpi_factor);
|
window_id,
|
||||||
events.resized = Some(WindowEvent::Resized(logical_size));
|
event: WindowEvent::Resized(new_inner_size.into()),
|
||||||
}
|
});
|
||||||
|
|
||||||
events
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(events) = events {
|
|
||||||
let window_id = mkwid(xwindow);
|
|
||||||
if let Some(event) = events.dpi_changed {
|
|
||||||
callback(Event::WindowEvent { window_id, event });
|
|
||||||
}
|
|
||||||
if let Some(event) = events.resized {
|
|
||||||
callback(Event::WindowEvent { window_id, event });
|
|
||||||
}
|
|
||||||
if let Some(event) = events.moved {
|
|
||||||
callback(Event::WindowEvent { window_id, event });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -728,24 +706,17 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
util::maybe_change(&mut shared_state_lock.cursor_pos, new_cursor_pos)
|
util::maybe_change(&mut shared_state_lock.cursor_pos, new_cursor_pos)
|
||||||
});
|
});
|
||||||
if cursor_moved == Some(true) {
|
if cursor_moved == Some(true) {
|
||||||
let dpi_factor =
|
let position =
|
||||||
self.with_window(xev.event, |window| window.hidpi_factor());
|
PhysicalPosition::new(xev.event_x as f64, xev.event_y as f64);
|
||||||
if let Some(dpi_factor) = dpi_factor {
|
|
||||||
let position = LogicalPosition::from_physical(
|
callback(Event::WindowEvent {
|
||||||
(xev.event_x as f64, xev.event_y as f64),
|
window_id,
|
||||||
dpi_factor,
|
event: CursorMoved {
|
||||||
);
|
device_id,
|
||||||
callback(Event::WindowEvent {
|
position,
|
||||||
window_id,
|
modifiers,
|
||||||
event: CursorMoved {
|
},
|
||||||
device_id,
|
});
|
||||||
position,
|
|
||||||
modifiers,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else if cursor_moved.is_none() {
|
} else if cursor_moved.is_none() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -836,18 +807,14 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(dpi_factor) =
|
if self.window_exists(xev.event) {
|
||||||
self.with_window(xev.event, |window| window.hidpi_factor())
|
|
||||||
{
|
|
||||||
callback(Event::WindowEvent {
|
callback(Event::WindowEvent {
|
||||||
window_id,
|
window_id,
|
||||||
event: CursorEntered { device_id },
|
event: CursorEntered { device_id },
|
||||||
});
|
});
|
||||||
|
|
||||||
let position = LogicalPosition::from_physical(
|
let position =
|
||||||
(xev.event_x as f64, xev.event_y as f64),
|
PhysicalPosition::new(xev.event_x as f64, xev.event_y as f64);
|
||||||
dpi_factor,
|
|
||||||
);
|
|
||||||
|
|
||||||
// The mods field on this event isn't actually populated, so query the
|
// The mods field on this event isn't actually populated, so query the
|
||||||
// pointer device. In the future, we can likely remove this round-trip by
|
// pointer device. In the future, we can likely remove this round-trip by
|
||||||
|
@ -890,11 +857,6 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
ffi::XI_FocusIn => {
|
ffi::XI_FocusIn => {
|
||||||
let xev: &ffi::XIFocusInEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &ffi::XIFocusInEvent = unsafe { &*(xev.data as *const _) };
|
||||||
|
|
||||||
let dpi_factor =
|
|
||||||
match self.with_window(xev.event, |window| window.hidpi_factor()) {
|
|
||||||
Some(dpi_factor) => dpi_factor,
|
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
let window_id = mkwid(xev.event);
|
let window_id = mkwid(xev.event);
|
||||||
|
|
||||||
wt.ime
|
wt.ime
|
||||||
|
@ -920,10 +882,9 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
.map(|device| device.attachment)
|
.map(|device| device.attachment)
|
||||||
.unwrap_or(2);
|
.unwrap_or(2);
|
||||||
|
|
||||||
let position = LogicalPosition::from_physical(
|
let position =
|
||||||
(xev.event_x as f64, xev.event_y as f64),
|
PhysicalPosition::new(xev.event_x as f64, xev.event_y as f64);
|
||||||
dpi_factor,
|
|
||||||
);
|
|
||||||
callback(Event::WindowEvent {
|
callback(Event::WindowEvent {
|
||||||
window_id,
|
window_id,
|
||||||
event: CursorMoved {
|
event: CursorMoved {
|
||||||
|
@ -966,15 +927,11 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
ffi::XI_TouchEnd => TouchPhase::Ended,
|
ffi::XI_TouchEnd => TouchPhase::Ended,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let dpi_factor =
|
if self.window_exists(xev.event) {
|
||||||
self.with_window(xev.event, |window| window.hidpi_factor());
|
|
||||||
if let Some(dpi_factor) = dpi_factor {
|
|
||||||
let id = xev.detail as u64;
|
let id = xev.detail as u64;
|
||||||
let modifiers = self.device_mod_state.modifiers();
|
let modifiers = self.device_mod_state.modifiers();
|
||||||
let location = LogicalPosition::from_physical(
|
let location =
|
||||||
(xev.event_x as f64, xev.event_y as f64),
|
PhysicalPosition::new(xev.event_x as f64, xev.event_y as f64);
|
||||||
dpi_factor,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Mouse cursor position changes when touch events are received.
|
// Mouse cursor position changes when touch events are received.
|
||||||
// Only the first concurrently active touch ID moves the mouse cursor.
|
// Only the first concurrently active touch ID moves the mouse cursor.
|
||||||
|
@ -1163,21 +1120,40 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
// Check if the window is on this monitor
|
// Check if the window is on this monitor
|
||||||
let monitor = window.current_monitor();
|
let monitor = window.current_monitor();
|
||||||
if monitor.name == new_monitor.name {
|
if monitor.name == new_monitor.name {
|
||||||
callback(Event::WindowEvent {
|
|
||||||
window_id: mkwid(window_id.0),
|
|
||||||
event: WindowEvent::HiDpiFactorChanged(
|
|
||||||
new_monitor.hidpi_factor,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
let (width, height) =
|
let (width, height) =
|
||||||
window.inner_size_physical();
|
window.inner_size_physical();
|
||||||
let (_, _, flusher) = window.adjust_for_dpi(
|
let (new_width, new_height) = window
|
||||||
prev_monitor.hidpi_factor,
|
.adjust_for_dpi(
|
||||||
new_monitor.hidpi_factor,
|
prev_monitor.hidpi_factor,
|
||||||
width as f64,
|
new_monitor.hidpi_factor,
|
||||||
height as f64,
|
width,
|
||||||
|
height,
|
||||||
|
);
|
||||||
|
|
||||||
|
let window_id = crate::window::WindowId(
|
||||||
|
crate::platform_impl::platform::WindowId::X(
|
||||||
|
*window_id,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
flusher.queue();
|
let mut new_inner_size = Some(
|
||||||
|
PhysicalSize::new(new_width, new_height),
|
||||||
|
);
|
||||||
|
|
||||||
|
callback(Event::WindowEvent {
|
||||||
|
window_id,
|
||||||
|
event: WindowEvent::HiDpiFactorChanged {
|
||||||
|
hidpi_factor: new_monitor.hidpi_factor,
|
||||||
|
new_inner_size: &mut new_inner_size,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(new_size) = new_inner_size {
|
||||||
|
let (new_width, new_height) =
|
||||||
|
new_size.into();
|
||||||
|
window.set_inner_size_physical(
|
||||||
|
new_width, new_height,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1203,7 +1179,7 @@ impl<T: 'static> EventProcessor<T> {
|
||||||
state: ElementState,
|
state: ElementState,
|
||||||
callback: &mut F,
|
callback: &mut F,
|
||||||
) where
|
) where
|
||||||
F: FnMut(Event<T>),
|
F: FnMut(Event<'_, T>),
|
||||||
{
|
{
|
||||||
let wt = get_xtarget(&self.target);
|
let wt = get_xtarget(&self.target);
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ pub use self::{
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
collections::{HashMap, HashSet, VecDeque},
|
collections::{HashMap, HashSet},
|
||||||
ffi::CStr,
|
ffi::CStr,
|
||||||
mem::{self, MaybeUninit},
|
mem::{self, MaybeUninit},
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
|
@ -37,6 +37,10 @@ use std::{
|
||||||
|
|
||||||
use libc::{self, setlocale, LC_CTYPE};
|
use libc::{self, setlocale, LC_CTYPE};
|
||||||
|
|
||||||
|
use mio::{unix::EventedFd, Events, Poll, PollOpt, Ready, Token};
|
||||||
|
|
||||||
|
use mio_extras::channel::{channel, Receiver, SendError, Sender};
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
dnd::{Dnd, DndState},
|
dnd::{Dnd, DndState},
|
||||||
event_processor::EventProcessor,
|
event_processor::EventProcessor,
|
||||||
|
@ -51,6 +55,9 @@ use crate::{
|
||||||
window::WindowAttributes,
|
window::WindowAttributes,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const X_TOKEN: Token = Token(0);
|
||||||
|
const USER_TOKEN: Token = Token(1);
|
||||||
|
|
||||||
pub struct EventLoopWindowTarget<T> {
|
pub struct EventLoopWindowTarget<T> {
|
||||||
xconn: Arc<XConnection>,
|
xconn: Arc<XConnection>,
|
||||||
wm_delete_window: ffi::Atom,
|
wm_delete_window: ffi::Atom,
|
||||||
|
@ -64,18 +71,15 @@ pub struct EventLoopWindowTarget<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventLoop<T: 'static> {
|
pub struct EventLoop<T: 'static> {
|
||||||
inner_loop: ::calloop::EventLoop<()>,
|
poll: Poll,
|
||||||
_x11_source: ::calloop::Source<::calloop::generic::Generic<::calloop::generic::EventedRawFd>>,
|
event_processor: EventProcessor<T>,
|
||||||
_user_source: ::calloop::Source<::calloop::channel::Channel<T>>,
|
user_channel: Receiver<T>,
|
||||||
pending_user_events: Rc<RefCell<VecDeque<T>>>,
|
user_sender: Sender<T>,
|
||||||
event_processor: Rc<RefCell<EventProcessor<T>>>,
|
target: Rc<RootELW<T>>,
|
||||||
user_sender: ::calloop::channel::Sender<T>,
|
|
||||||
pending_events: Rc<RefCell<VecDeque<Event<T>>>>,
|
|
||||||
pub(crate) target: Rc<RootELW<T>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EventLoopProxy<T: 'static> {
|
pub struct EventLoopProxy<T: 'static> {
|
||||||
user_sender: ::calloop::channel::Sender<T>,
|
user_sender: Sender<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> Clone for EventLoopProxy<T> {
|
impl<T: 'static> Clone for EventLoopProxy<T> {
|
||||||
|
@ -171,28 +175,27 @@ impl<T: 'static> EventLoop<T> {
|
||||||
_marker: ::std::marker::PhantomData,
|
_marker: ::std::marker::PhantomData,
|
||||||
});
|
});
|
||||||
|
|
||||||
// A calloop event loop to drive us
|
let poll = Poll::new().unwrap();
|
||||||
let inner_loop = ::calloop::EventLoop::new().unwrap();
|
|
||||||
|
|
||||||
// Handle user events
|
let (user_sender, user_channel) = channel();
|
||||||
let pending_user_events = Rc::new(RefCell::new(VecDeque::new()));
|
|
||||||
let pending_user_events2 = pending_user_events.clone();
|
|
||||||
|
|
||||||
let (user_sender, user_channel) = ::calloop::channel::channel();
|
poll.register(
|
||||||
|
&EventedFd(&get_xtarget(&target).xconn.x11_fd),
|
||||||
|
X_TOKEN,
|
||||||
|
Ready::readable(),
|
||||||
|
PollOpt::level(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let _user_source = inner_loop
|
poll.register(
|
||||||
.handle()
|
&user_channel,
|
||||||
.insert_source(user_channel, move |evt, &mut ()| {
|
USER_TOKEN,
|
||||||
if let ::calloop::channel::Event::Msg(msg) = evt {
|
Ready::readable(),
|
||||||
pending_user_events2.borrow_mut().push_back(msg);
|
PollOpt::level(),
|
||||||
}
|
)
|
||||||
})
|
.unwrap();
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Handle X11 events
|
let event_processor = EventProcessor {
|
||||||
let pending_events: Rc<RefCell<VecDeque<_>>> = Default::default();
|
|
||||||
|
|
||||||
let processor = EventProcessor {
|
|
||||||
target: target.clone(),
|
target: target.clone(),
|
||||||
dnd,
|
dnd,
|
||||||
devices: Default::default(),
|
devices: Default::default(),
|
||||||
|
@ -212,38 +215,12 @@ impl<T: 'static> EventLoop<T> {
|
||||||
.select_xinput_events(root, ffi::XIAllDevices, ffi::XI_HierarchyChangedMask)
|
.select_xinput_events(root, ffi::XIAllDevices, ffi::XI_HierarchyChangedMask)
|
||||||
.queue();
|
.queue();
|
||||||
|
|
||||||
processor.init_device(ffi::XIAllDevices);
|
event_processor.init_device(ffi::XIAllDevices);
|
||||||
|
|
||||||
let processor = Rc::new(RefCell::new(processor));
|
|
||||||
let event_processor = processor.clone();
|
|
||||||
|
|
||||||
// Setup the X11 event source
|
|
||||||
let mut x11_events =
|
|
||||||
::calloop::generic::Generic::from_raw_fd(get_xtarget(&target).xconn.x11_fd);
|
|
||||||
x11_events.set_interest(::calloop::mio::Ready::readable());
|
|
||||||
let _x11_source = inner_loop
|
|
||||||
.handle()
|
|
||||||
.insert_source(x11_events, {
|
|
||||||
let pending_events = pending_events.clone();
|
|
||||||
move |evt, &mut ()| {
|
|
||||||
if evt.readiness.is_readable() {
|
|
||||||
let mut processor = processor.borrow_mut();
|
|
||||||
let mut pending_events = pending_events.borrow_mut();
|
|
||||||
let mut pending_redraws = pending_redraws.lock().unwrap();
|
|
||||||
|
|
||||||
drain_events(&mut processor, &mut pending_events, &mut pending_redraws);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let result = EventLoop {
|
let result = EventLoop {
|
||||||
inner_loop,
|
poll,
|
||||||
pending_events,
|
user_channel,
|
||||||
_x11_source,
|
|
||||||
_user_source,
|
|
||||||
user_sender,
|
user_sender,
|
||||||
pending_user_events,
|
|
||||||
event_processor,
|
event_processor,
|
||||||
target,
|
target,
|
||||||
};
|
};
|
||||||
|
@ -261,12 +238,16 @@ impl<T: 'static> EventLoop<T> {
|
||||||
&self.target
|
&self.target
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn x_connection(&self) -> &Arc<XConnection> {
|
||||||
|
get_xtarget(&self.target).x_connection()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run_return<F>(&mut self, mut callback: F)
|
pub fn run_return<F>(&mut self, mut callback: F)
|
||||||
where
|
where
|
||||||
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
|
F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
let mut control_flow = ControlFlow::default();
|
let mut control_flow = ControlFlow::default();
|
||||||
let wt = get_xtarget(&self.target);
|
let mut events = Events::with_capacity(8);
|
||||||
|
|
||||||
callback(
|
callback(
|
||||||
crate::event::Event::NewEvents(crate::event::StartCause::Init),
|
crate::event::Event::NewEvents(crate::event::StartCause::Init),
|
||||||
|
@ -275,22 +256,16 @@ impl<T: 'static> EventLoop<T> {
|
||||||
);
|
);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
self.drain_events();
|
// Process all pending events
|
||||||
|
self.drain_events(&mut callback, &mut control_flow);
|
||||||
|
|
||||||
// Empty the event buffer
|
let wt = get_xtarget(&self.target);
|
||||||
{
|
|
||||||
let mut guard = self.pending_events.borrow_mut();
|
|
||||||
for evt in guard.drain(..) {
|
|
||||||
sticky_exit_callback(evt, &self.target, &mut control_flow, &mut callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Empty the user event buffer
|
// Empty the user event buffer
|
||||||
{
|
{
|
||||||
let mut guard = self.pending_user_events.borrow_mut();
|
while let Ok(event) = self.user_channel.try_recv() {
|
||||||
for evt in guard.drain(..) {
|
|
||||||
sticky_exit_callback(
|
sticky_exit_callback(
|
||||||
crate::event::Event::UserEvent(evt),
|
crate::event::Event::UserEvent(event),
|
||||||
&self.target,
|
&self.target,
|
||||||
&mut control_flow,
|
&mut control_flow,
|
||||||
&mut callback,
|
&mut callback,
|
||||||
|
@ -331,7 +306,7 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let (mut cause, deadline, mut timeout);
|
let (mut cause, deadline, timeout);
|
||||||
|
|
||||||
match control_flow {
|
match control_flow {
|
||||||
ControlFlow::Exit => break,
|
ControlFlow::Exit => break,
|
||||||
|
@ -362,26 +337,39 @@ impl<T: 'static> EventLoop<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.events_waiting() {
|
if self.event_processor.poll() {
|
||||||
timeout = Some(Duration::from_millis(0));
|
// If the XConnection already contains buffered events, we don't
|
||||||
}
|
// need to wait for data on the socket.
|
||||||
|
// However, we still need to check for user events.
|
||||||
|
self.poll
|
||||||
|
.poll(&mut events, Some(Duration::from_millis(0)))
|
||||||
|
.unwrap();
|
||||||
|
events.clear();
|
||||||
|
|
||||||
self.inner_loop.dispatch(timeout, &mut ()).unwrap();
|
callback(
|
||||||
|
crate::event::Event::NewEvents(cause),
|
||||||
|
&self.target,
|
||||||
|
&mut control_flow,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
self.poll.poll(&mut events, timeout).unwrap();
|
||||||
|
events.clear();
|
||||||
|
|
||||||
if let Some(deadline) = deadline {
|
let wait_cancelled = deadline.map_or(false, |deadline| Instant::now() < deadline);
|
||||||
if deadline > Instant::now() {
|
|
||||||
|
if wait_cancelled {
|
||||||
cause = StartCause::WaitCancelled {
|
cause = StartCause::WaitCancelled {
|
||||||
start,
|
start,
|
||||||
requested_resume: Some(deadline),
|
requested_resume: deadline,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
callback(
|
callback(
|
||||||
crate::event::Event::NewEvents(cause),
|
crate::event::Event::NewEvents(cause),
|
||||||
&self.target,
|
&self.target,
|
||||||
&mut control_flow,
|
&mut control_flow,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(
|
callback(
|
||||||
|
@ -393,44 +381,42 @@ impl<T: 'static> EventLoop<T> {
|
||||||
|
|
||||||
pub fn run<F>(mut self, callback: F) -> !
|
pub fn run<F>(mut self, callback: F) -> !
|
||||||
where
|
where
|
||||||
F: 'static + FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
|
F: 'static + FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
||||||
{
|
{
|
||||||
self.run_return(callback);
|
self.run_return(callback);
|
||||||
::std::process::exit(0);
|
::std::process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drain_events(&self) {
|
fn drain_events<F>(&mut self, callback: &mut F, control_flow: &mut ControlFlow)
|
||||||
let mut processor = self.event_processor.borrow_mut();
|
where
|
||||||
let mut pending_events = self.pending_events.borrow_mut();
|
F: FnMut(Event<'_, T>, &RootELW<T>, &mut ControlFlow),
|
||||||
|
{
|
||||||
|
let target = &self.target;
|
||||||
|
let mut xev = MaybeUninit::uninit();
|
||||||
|
|
||||||
let wt = get_xtarget(&self.target);
|
let wt = get_xtarget(&self.target);
|
||||||
let mut pending_redraws = wt.pending_redraws.lock().unwrap();
|
let mut pending_redraws = wt.pending_redraws.lock().unwrap();
|
||||||
|
|
||||||
drain_events(&mut processor, &mut pending_events, &mut pending_redraws);
|
while unsafe { self.event_processor.poll_one_event(xev.as_mut_ptr()) } {
|
||||||
}
|
let mut xev = unsafe { xev.assume_init() };
|
||||||
|
self.event_processor.process_event(&mut xev, |event| {
|
||||||
fn events_waiting(&self) -> bool {
|
sticky_exit_callback(
|
||||||
!self.pending_events.borrow().is_empty() || self.event_processor.borrow().poll()
|
event,
|
||||||
}
|
target,
|
||||||
}
|
control_flow,
|
||||||
|
&mut |event, window_target, control_flow| {
|
||||||
fn drain_events<T: 'static>(
|
if let Event::RedrawRequested(crate::window::WindowId(
|
||||||
processor: &mut EventProcessor<T>,
|
super::WindowId::X(wid),
|
||||||
pending_events: &mut VecDeque<Event<T>>,
|
)) = event
|
||||||
pending_redraws: &mut HashSet<WindowId>,
|
{
|
||||||
) {
|
pending_redraws.insert(wid);
|
||||||
let mut callback = |event| {
|
} else {
|
||||||
if let Event::RedrawRequested(crate::window::WindowId(super::WindowId::X(wid))) = event {
|
callback(event, window_target, control_flow);
|
||||||
pending_redraws.insert(wid);
|
}
|
||||||
} else {
|
},
|
||||||
pending_events.push_back(event);
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// process all pending events
|
|
||||||
let mut xev = MaybeUninit::uninit();
|
|
||||||
while unsafe { processor.poll_one_event(xev.as_mut_ptr()) } {
|
|
||||||
let mut xev = unsafe { xev.assume_init() };
|
|
||||||
processor.process_event(&mut xev, &mut callback);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,7 +438,7 @@ impl<T> EventLoopWindowTarget<T> {
|
||||||
impl<T: 'static> EventLoopProxy<T> {
|
impl<T: 'static> EventLoopProxy<T> {
|
||||||
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
||||||
self.user_sender.send(event).map_err(|e| {
|
self.user_sender.send(event).map_err(|e| {
|
||||||
EventLoopClosed(if let ::calloop::channel::SendError::Disconnected(x) = e {
|
EventLoopClosed(if let SendError::Disconnected(x) = e {
|
||||||
x
|
x
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
|
|
@ -15,7 +15,7 @@ use libc;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
dpi::{LogicalPosition, LogicalSize},
|
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
||||||
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||||
monitor::{MonitorHandle as RootMonitorHandle, VideoMode as RootVideoMode},
|
monitor::{MonitorHandle as RootMonitorHandle, VideoMode as RootVideoMode},
|
||||||
platform_impl::{
|
platform_impl::{
|
||||||
|
@ -36,7 +36,7 @@ pub struct SharedState {
|
||||||
pub inner_position: Option<(i32, i32)>,
|
pub inner_position: Option<(i32, i32)>,
|
||||||
pub inner_position_rel_parent: Option<(i32, i32)>,
|
pub inner_position_rel_parent: Option<(i32, i32)>,
|
||||||
pub last_monitor: X11MonitorHandle,
|
pub last_monitor: X11MonitorHandle,
|
||||||
pub dpi_adjusted: Option<(f64, f64)>,
|
pub dpi_adjusted: Option<(u32, u32)>,
|
||||||
pub fullscreen: Option<Fullscreen>,
|
pub fullscreen: Option<Fullscreen>,
|
||||||
// Set when application calls `set_fullscreen` when window is not visible
|
// Set when application calls `set_fullscreen` when window is not visible
|
||||||
pub desired_fullscreen: Option<Option<Fullscreen>>,
|
pub desired_fullscreen: Option<Option<Fullscreen>>,
|
||||||
|
@ -45,8 +45,8 @@ pub struct SharedState {
|
||||||
// Used to restore video mode after exiting fullscreen
|
// Used to restore video mode after exiting fullscreen
|
||||||
pub desktop_video_mode: Option<(ffi::RRCrtc, ffi::RRMode)>,
|
pub desktop_video_mode: Option<(ffi::RRCrtc, ffi::RRMode)>,
|
||||||
pub frame_extents: Option<util::FrameExtentsHeuristic>,
|
pub frame_extents: Option<util::FrameExtentsHeuristic>,
|
||||||
pub min_inner_size: Option<LogicalSize>,
|
pub min_inner_size: Option<Size>,
|
||||||
pub max_inner_size: Option<LogicalSize>,
|
pub max_inner_size: Option<Size>,
|
||||||
pub visibility: Visibility,
|
pub visibility: Visibility,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,8 +148,8 @@ impl UnownedWindow {
|
||||||
// by the user, so we have to manually apply the initial constraints
|
// by the user, so we have to manually apply the initial constraints
|
||||||
let mut dimensions: (u32, u32) = window_attrs
|
let mut dimensions: (u32, u32) = window_attrs
|
||||||
.inner_size
|
.inner_size
|
||||||
.or_else(|| Some((800, 600).into()))
|
|
||||||
.map(|size| size.to_physical(dpi_factor))
|
.map(|size| size.to_physical(dpi_factor))
|
||||||
|
.or_else(|| Some((800, 600).into()))
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
if let Some(max) = max_inner_size {
|
if let Some(max) = max_inner_size {
|
||||||
|
@ -440,16 +440,6 @@ impl UnownedWindow {
|
||||||
.map_err(|x_err| os_error!(OsError::XError(x_err)))
|
.map_err(|x_err| os_error!(OsError::XError(x_err)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn logicalize_coords(&self, (x, y): (i32, i32)) -> LogicalPosition {
|
|
||||||
let dpi = self.hidpi_factor();
|
|
||||||
LogicalPosition::from_physical((x, y), dpi)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn logicalize_size(&self, (width, height): (u32, u32)) -> LogicalSize {
|
|
||||||
let dpi = self.hidpi_factor();
|
|
||||||
LogicalSize::from_physical((width, height), dpi)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_pid(&self) -> Option<util::Flusher<'_>> {
|
fn set_pid(&self) -> Option<util::Flusher<'_>> {
|
||||||
let pid_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_PID\0") };
|
let pid_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_PID\0") };
|
||||||
let client_machine_atom = unsafe { self.xconn.get_atom_unchecked(b"WM_CLIENT_MACHINE\0") };
|
let client_machine_atom = unsafe { self.xconn.get_atom_unchecked(b"WM_CLIENT_MACHINE\0") };
|
||||||
|
@ -951,11 +941,11 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn outer_position(&self) -> Result<LogicalPosition, NotSupportedError> {
|
pub fn outer_position(&self) -> Result<PhysicalPosition, NotSupportedError> {
|
||||||
let extents = (*self.shared_state.lock()).frame_extents.clone();
|
let extents = (*self.shared_state.lock()).frame_extents.clone();
|
||||||
if let Some(extents) = extents {
|
if let Some(extents) = extents {
|
||||||
let logical = self.inner_position().unwrap();
|
let (x, y) = self.inner_position_physical();
|
||||||
Ok(extents.inner_pos_to_outer_logical(logical, self.hidpi_factor()))
|
Ok(extents.inner_pos_to_outer(x, y).into())
|
||||||
} else {
|
} else {
|
||||||
self.update_cached_frame_extents();
|
self.update_cached_frame_extents();
|
||||||
self.outer_position()
|
self.outer_position()
|
||||||
|
@ -972,8 +962,8 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn inner_position(&self) -> Result<LogicalPosition, NotSupportedError> {
|
pub fn inner_position(&self) -> Result<PhysicalPosition, NotSupportedError> {
|
||||||
Ok(self.logicalize_coords(self.inner_position_physical()))
|
Ok(self.inner_position_physical().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_position_inner(&self, mut x: i32, mut y: i32) -> util::Flusher<'_> {
|
pub(crate) fn set_position_inner(&self, mut x: i32, mut y: i32) -> util::Flusher<'_> {
|
||||||
|
@ -1002,8 +992,8 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_outer_position(&self, logical_position: LogicalPosition) {
|
pub fn set_outer_position(&self, position: Position) {
|
||||||
let (x, y) = logical_position.to_physical(self.hidpi_factor()).into();
|
let (x, y) = position.to_physical(self.hidpi_factor()).into();
|
||||||
self.set_position_physical(x, y);
|
self.set_position_physical(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1017,16 +1007,16 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn inner_size(&self) -> LogicalSize {
|
pub fn inner_size(&self) -> PhysicalSize {
|
||||||
self.logicalize_size(self.inner_size_physical())
|
self.inner_size_physical().into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn outer_size(&self) -> LogicalSize {
|
pub fn outer_size(&self) -> PhysicalSize {
|
||||||
let extents = self.shared_state.lock().frame_extents.clone();
|
let extents = self.shared_state.lock().frame_extents.clone();
|
||||||
if let Some(extents) = extents {
|
if let Some(extents) = extents {
|
||||||
let logical = self.inner_size();
|
let (width, height) = self.inner_size_physical();
|
||||||
extents.inner_size_to_outer_logical(logical, self.hidpi_factor())
|
extents.inner_size_to_outer(width, height).into()
|
||||||
} else {
|
} else {
|
||||||
self.update_cached_frame_extents();
|
self.update_cached_frame_extents();
|
||||||
self.outer_size()
|
self.outer_size()
|
||||||
|
@ -1047,9 +1037,9 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_inner_size(&self, logical_size: LogicalSize) {
|
pub fn set_inner_size(&self, size: Size) {
|
||||||
let dpi_factor = self.hidpi_factor();
|
let dpi_factor = self.hidpi_factor();
|
||||||
let (width, height) = logical_size.to_physical(dpi_factor).into();
|
let (width, height) = size.to_physical(dpi_factor).into();
|
||||||
self.set_inner_size_physical(width, height);
|
self.set_inner_size_physical(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1070,10 +1060,10 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_min_inner_size(&self, logical_dimensions: Option<LogicalSize>) {
|
pub fn set_min_inner_size(&self, dimensions: Option<Size>) {
|
||||||
self.shared_state.lock().min_inner_size = logical_dimensions;
|
self.shared_state.lock().min_inner_size = dimensions;
|
||||||
let physical_dimensions = logical_dimensions
|
let physical_dimensions =
|
||||||
.map(|logical_dimensions| logical_dimensions.to_physical(self.hidpi_factor()).into());
|
dimensions.map(|dimensions| dimensions.to_physical(self.hidpi_factor()).into());
|
||||||
self.set_min_inner_size_physical(physical_dimensions);
|
self.set_min_inner_size_physical(physical_dimensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1083,10 +1073,10 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_max_inner_size(&self, logical_dimensions: Option<LogicalSize>) {
|
pub fn set_max_inner_size(&self, dimensions: Option<Size>) {
|
||||||
self.shared_state.lock().max_inner_size = logical_dimensions;
|
self.shared_state.lock().max_inner_size = dimensions;
|
||||||
let physical_dimensions = logical_dimensions
|
let physical_dimensions =
|
||||||
.map(|logical_dimensions| logical_dimensions.to_physical(self.hidpi_factor()).into());
|
dimensions.map(|dimensions| dimensions.to_physical(self.hidpi_factor()).into());
|
||||||
self.set_max_inner_size_physical(physical_dimensions);
|
self.set_max_inner_size_physical(physical_dimensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1094,12 +1084,10 @@ impl UnownedWindow {
|
||||||
&self,
|
&self,
|
||||||
old_dpi_factor: f64,
|
old_dpi_factor: f64,
|
||||||
new_dpi_factor: f64,
|
new_dpi_factor: f64,
|
||||||
width: f64,
|
width: u32,
|
||||||
height: f64,
|
height: u32,
|
||||||
) -> (f64, f64, util::Flusher<'_>) {
|
) -> (u32, u32) {
|
||||||
let scale_factor = new_dpi_factor / old_dpi_factor;
|
let scale_factor = new_dpi_factor / old_dpi_factor;
|
||||||
let new_width = width * scale_factor;
|
|
||||||
let new_height = height * scale_factor;
|
|
||||||
self.update_normal_hints(|normal_hints| {
|
self.update_normal_hints(|normal_hints| {
|
||||||
let dpi_adjuster = |(width, height): (u32, u32)| -> (u32, u32) {
|
let dpi_adjuster = |(width, height): (u32, u32)| -> (u32, u32) {
|
||||||
let new_width = width as f64 * scale_factor;
|
let new_width = width as f64 * scale_factor;
|
||||||
|
@ -1116,15 +1104,11 @@ impl UnownedWindow {
|
||||||
normal_hints.set_base_size(base_size);
|
normal_hints.set_base_size(base_size);
|
||||||
})
|
})
|
||||||
.expect("Failed to update normal hints");
|
.expect("Failed to update normal hints");
|
||||||
unsafe {
|
|
||||||
(self.xconn.xlib.XResizeWindow)(
|
let new_width = (width as f64 * scale_factor).round() as u32;
|
||||||
self.xconn.display,
|
let new_height = (height as f64 * scale_factor).round() as u32;
|
||||||
self.xwindow,
|
|
||||||
new_width.round() as c_uint,
|
(new_width, new_height)
|
||||||
new_height.round() as c_uint,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
(new_width, new_height, util::Flusher::new(&self.xconn))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_resizable(&self, resizable: bool) {
|
pub fn set_resizable(&self, resizable: bool) {
|
||||||
|
@ -1136,25 +1120,25 @@ impl UnownedWindow {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let (logical_min, logical_max) = if resizable {
|
let (min_size, max_size) = if resizable {
|
||||||
let shared_state_lock = self.shared_state.lock();
|
let shared_state_lock = self.shared_state.lock();
|
||||||
(
|
(
|
||||||
shared_state_lock.min_inner_size,
|
shared_state_lock.min_inner_size,
|
||||||
shared_state_lock.max_inner_size,
|
shared_state_lock.max_inner_size,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let window_size = Some(self.inner_size());
|
let window_size = Some(Size::from(self.inner_size()));
|
||||||
(window_size.clone(), window_size)
|
(window_size.clone(), window_size)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.set_maximizable_inner(resizable).queue();
|
self.set_maximizable_inner(resizable).queue();
|
||||||
|
|
||||||
let dpi_factor = self.hidpi_factor();
|
let dpi_factor = self.hidpi_factor();
|
||||||
let min_inner_size = logical_min
|
let min_inner_size = min_size
|
||||||
.map(|logical_size| logical_size.to_physical(dpi_factor))
|
.map(|size| size.to_physical(dpi_factor))
|
||||||
.map(Into::into);
|
.map(Into::into);
|
||||||
let max_inner_size = logical_max
|
let max_inner_size = max_size
|
||||||
.map(|logical_size| logical_size.to_physical(dpi_factor))
|
.map(|size| size.to_physical(dpi_factor))
|
||||||
.map(Into::into);
|
.map(Into::into);
|
||||||
self.update_normal_hints(|normal_hints| {
|
self.update_normal_hints(|normal_hints| {
|
||||||
normal_hints.set_min_size(min_inner_size);
|
normal_hints.set_min_size(min_inner_size);
|
||||||
|
@ -1289,11 +1273,8 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_cursor_position(
|
pub fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> {
|
||||||
&self,
|
let (x, y) = position.to_physical(self.hidpi_factor()).into();
|
||||||
logical_position: LogicalPosition,
|
|
||||||
) -> Result<(), ExternalError> {
|
|
||||||
let (x, y) = logical_position.to_physical(self.hidpi_factor()).into();
|
|
||||||
self.set_cursor_position_physical(x, y)
|
self.set_cursor_position_physical(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1305,8 +1286,8 @@ impl UnownedWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_ime_position(&self, logical_spot: LogicalPosition) {
|
pub fn set_ime_position(&self, spot: Position) {
|
||||||
let (x, y) = logical_spot.to_physical(self.hidpi_factor()).into();
|
let (x, y) = spot.to_physical(self.hidpi_factor()).into();
|
||||||
self.set_ime_position_physical(x, y);
|
self.set_ime_position_physical(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -459,7 +459,7 @@ impl Window {
|
||||||
self.window.set_outer_position(position.into())
|
self.window.set_outer_position(position.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the logical size of the window's client area.
|
/// Returns the physical size of the window's client area.
|
||||||
///
|
///
|
||||||
/// The client area is the content of the window, excluding the title bar and borders.
|
/// The client area is the content of the window, excluding the title bar and borders.
|
||||||
///
|
///
|
||||||
|
@ -488,7 +488,7 @@ impl Window {
|
||||||
self.window.set_inner_size(size.into())
|
self.window.set_inner_size(size.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the logical size of the entire window.
|
/// Returns the physical size of the entire window.
|
||||||
///
|
///
|
||||||
/// These dimensions include the title bar and borders. If you don't want that (and you usually don't),
|
/// These dimensions include the title bar and borders. If you don't want that (and you usually don't),
|
||||||
/// use `inner_size` instead.
|
/// use `inner_size` instead.
|
||||||
|
|
Loading…
Add table
Reference in a new issue