Format everything and add rustfmt to travis (#951)
* Format everything and add rustfmt to travis * Remove extern crate winit from examples and add force_multiline_blocks * Format the code properly * Fix inconsistent period in PULL_REQUEST_TEMPLATE.md * Only run rustfmt on nightly * Travis fixings
This commit is contained in:
parent
b1b5aefc4b
commit
e2c84725de
109 changed files with 4787 additions and 3679 deletions
|
|
@ -1,13 +1,13 @@
|
|||
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::os::raw::{c_void, c_char, c_int};
|
||||
use std::os::raw::{c_char, c_int, c_void};
|
||||
|
||||
pub const RTLD_LAZY: c_int = 0x001;
|
||||
pub const RTLD_NOW: c_int = 0x002;
|
||||
|
||||
#[link(name ="dl")]
|
||||
extern {
|
||||
#[link(name = "dl")]
|
||||
extern "C" {
|
||||
pub fn dlopen(filename: *const c_char, flag: c_int) -> *mut c_void;
|
||||
pub fn dlerror() -> *mut c_char;
|
||||
pub fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void;
|
||||
|
|
|
|||
|
|
@ -1,24 +1,21 @@
|
|||
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::{env, mem, fmt};
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::*;
|
||||
use std::sync::Arc;
|
||||
use std::{collections::VecDeque, env, ffi::CStr, fmt, mem, os::raw::*, sync::Arc};
|
||||
|
||||
use parking_lot::Mutex;
|
||||
use smithay_client_toolkit::reexports::client::ConnectError;
|
||||
|
||||
use crate::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize};
|
||||
use crate::icon::Icon;
|
||||
use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError};
|
||||
use crate::event::Event;
|
||||
use crate::event_loop::{EventLoopClosed, ControlFlow, EventLoopWindowTarget as RootELW};
|
||||
use crate::monitor::{MonitorHandle as RootMonitorHandle, VideoMode};
|
||||
use crate::window::{WindowAttributes, CursorIcon};
|
||||
use self::x11::{XConnection, XError};
|
||||
use self::x11::ffi::XVisualInfo;
|
||||
pub use self::x11::XNotSupported;
|
||||
use self::x11::{ffi::XVisualInfo, XConnection, XError};
|
||||
use crate::{
|
||||
dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize},
|
||||
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||
event::Event,
|
||||
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW},
|
||||
icon::Icon,
|
||||
monitor::{MonitorHandle as RootMonitorHandle, VideoMode},
|
||||
window::{CursorIcon, WindowAttributes},
|
||||
};
|
||||
|
||||
mod dlopen;
|
||||
pub mod wayland;
|
||||
|
|
@ -43,14 +40,13 @@ pub struct PlatformSpecificWindowBuilderAttributes {
|
|||
pub override_redirect: bool,
|
||||
pub x11_window_type: x11::util::WindowType,
|
||||
pub gtk_theme_variant: Option<String>,
|
||||
pub app_id: Option<String>
|
||||
pub app_id: Option<String>,
|
||||
}
|
||||
|
||||
lazy_static!(
|
||||
pub static ref X11_BACKEND: Mutex<Result<Arc<XConnection>, XNotSupported>> = {
|
||||
Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new))
|
||||
};
|
||||
);
|
||||
lazy_static! {
|
||||
pub static ref X11_BACKEND: Mutex<Result<Arc<XConnection>, XNotSupported>> =
|
||||
{ Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new)) };
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum OsError {
|
||||
|
|
@ -269,7 +265,7 @@ impl Window {
|
|||
pub fn set_cursor_icon(&self, cursor: CursorIcon) {
|
||||
match self {
|
||||
&Window::X(ref w) => w.set_cursor_icon(cursor),
|
||||
&Window::Wayland(ref w) => w.set_cursor_icon(cursor)
|
||||
&Window::Wayland(ref w) => w.set_cursor_icon(cursor),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -291,7 +287,7 @@ impl Window {
|
|||
|
||||
#[inline]
|
||||
pub fn hidpi_factor(&self) -> f64 {
|
||||
match self {
|
||||
match self {
|
||||
&Window::X(ref w) => w.hidpi_factor(),
|
||||
&Window::Wayland(ref w) => w.hidpi_factor() as f64,
|
||||
}
|
||||
|
|
@ -317,8 +313,13 @@ impl Window {
|
|||
pub fn fullscreen(&self) -> Option<RootMonitorHandle> {
|
||||
match self {
|
||||
&Window::X(ref w) => w.fullscreen(),
|
||||
&Window::Wayland(ref w) => w.fullscreen()
|
||||
.map(|monitor_id| RootMonitorHandle { inner: MonitorHandle::Wayland(monitor_id) })
|
||||
&Window::Wayland(ref w) => {
|
||||
w.fullscreen().map(|monitor_id| {
|
||||
RootMonitorHandle {
|
||||
inner: MonitorHandle::Wayland(monitor_id),
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -326,7 +327,7 @@ impl Window {
|
|||
pub fn set_fullscreen(&self, monitor: Option<RootMonitorHandle>) {
|
||||
match self {
|
||||
&Window::X(ref w) => w.set_fullscreen(monitor),
|
||||
&Window::Wayland(ref w) => w.set_fullscreen(monitor)
|
||||
&Window::Wayland(ref w) => w.set_fullscreen(monitor),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -334,7 +335,7 @@ impl Window {
|
|||
pub fn set_decorations(&self, decorations: bool) {
|
||||
match self {
|
||||
&Window::X(ref w) => w.set_decorations(decorations),
|
||||
&Window::Wayland(ref w) => w.set_decorations(decorations)
|
||||
&Window::Wayland(ref w) => w.set_decorations(decorations),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -373,22 +374,36 @@ impl Window {
|
|||
#[inline]
|
||||
pub fn current_monitor(&self) -> RootMonitorHandle {
|
||||
match self {
|
||||
&Window::X(ref window) => RootMonitorHandle { inner: MonitorHandle::X(window.current_monitor()) },
|
||||
&Window::Wayland(ref window) => RootMonitorHandle { inner: MonitorHandle::Wayland(window.current_monitor()) },
|
||||
&Window::X(ref window) => {
|
||||
RootMonitorHandle {
|
||||
inner: MonitorHandle::X(window.current_monitor()),
|
||||
}
|
||||
},
|
||||
&Window::Wayland(ref window) => {
|
||||
RootMonitorHandle {
|
||||
inner: MonitorHandle::Wayland(window.current_monitor()),
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
||||
match self {
|
||||
&Window::X(ref window) => window.available_monitors()
|
||||
.into_iter()
|
||||
.map(MonitorHandle::X)
|
||||
.collect(),
|
||||
&Window::Wayland(ref window) => window.available_monitors()
|
||||
.into_iter()
|
||||
.map(MonitorHandle::Wayland)
|
||||
.collect(),
|
||||
&Window::X(ref window) => {
|
||||
window
|
||||
.available_monitors()
|
||||
.into_iter()
|
||||
.map(MonitorHandle::X)
|
||||
.collect()
|
||||
},
|
||||
&Window::Wayland(ref window) => {
|
||||
window
|
||||
.available_monitors()
|
||||
.into_iter()
|
||||
.map(MonitorHandle::Wayland)
|
||||
.collect()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -401,7 +416,6 @@ impl Window {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
unsafe extern "C" fn x_error_callback(
|
||||
display: *mut x11::ffi::Display,
|
||||
event: *mut x11::ffi::XErrorEvent,
|
||||
|
|
@ -432,10 +446,9 @@ unsafe extern "C" fn x_error_callback(
|
|||
0
|
||||
}
|
||||
|
||||
|
||||
pub enum EventLoop<T: 'static> {
|
||||
Wayland(wayland::EventLoop<T>),
|
||||
X(x11::EventLoop<T>)
|
||||
X(x11::EventLoop<T>),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -444,7 +457,7 @@ pub enum EventLoopProxy<T: 'static> {
|
|||
Wayland(wayland::EventLoopProxy<T>),
|
||||
}
|
||||
|
||||
impl<T:'static> EventLoop<T> {
|
||||
impl<T: 'static> EventLoop<T> {
|
||||
pub fn new() -> EventLoop<T> {
|
||||
if let Ok(env_var) = env::var(BACKEND_PREFERENCE_ENV_VAR) {
|
||||
match env_var.as_str() {
|
||||
|
|
@ -453,13 +466,14 @@ impl<T:'static> EventLoop<T> {
|
|||
return EventLoop::new_x11().expect("Failed to initialize X11 backend");
|
||||
},
|
||||
"wayland" => {
|
||||
return EventLoop::new_wayland()
|
||||
.expect("Failed to initialize Wayland backend");
|
||||
return EventLoop::new_wayland().expect("Failed to initialize Wayland backend");
|
||||
},
|
||||
_ => {
|
||||
panic!(
|
||||
"Unknown environment variable value for {}, try one of `x11`,`wayland`",
|
||||
BACKEND_PREFERENCE_ENV_VAR,
|
||||
)
|
||||
},
|
||||
_ => panic!(
|
||||
"Unknown environment variable value for {}, try one of `x11`,`wayland`",
|
||||
BACKEND_PREFERENCE_ENV_VAR,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -475,15 +489,13 @@ impl<T:'static> EventLoop<T> {
|
|||
|
||||
let err_string = format!(
|
||||
"Failed to initialize any backend! Wayland status: {:?} X11 status: {:?}",
|
||||
wayland_err,
|
||||
x11_err,
|
||||
wayland_err, x11_err,
|
||||
);
|
||||
panic!(err_string);
|
||||
}
|
||||
|
||||
pub fn new_wayland() -> Result<EventLoop<T>, ConnectError> {
|
||||
wayland::EventLoop::new()
|
||||
.map(EventLoop::Wayland)
|
||||
wayland::EventLoop::new().map(EventLoop::Wayland)
|
||||
}
|
||||
|
||||
pub fn new_x11() -> Result<EventLoop<T>, XNotSupported> {
|
||||
|
|
@ -499,17 +511,19 @@ impl<T:'static> EventLoop<T> {
|
|||
#[inline]
|
||||
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
||||
match *self {
|
||||
EventLoop::Wayland(ref evlp) => evlp
|
||||
.available_monitors()
|
||||
.into_iter()
|
||||
.map(MonitorHandle::Wayland)
|
||||
.collect(),
|
||||
EventLoop::X(ref evlp) => evlp
|
||||
.x_connection()
|
||||
.available_monitors()
|
||||
.into_iter()
|
||||
.map(MonitorHandle::X)
|
||||
.collect(),
|
||||
EventLoop::Wayland(ref evlp) => {
|
||||
evlp.available_monitors()
|
||||
.into_iter()
|
||||
.map(MonitorHandle::Wayland)
|
||||
.collect()
|
||||
},
|
||||
EventLoop::X(ref evlp) => {
|
||||
evlp.x_connection()
|
||||
.available_monitors()
|
||||
.into_iter()
|
||||
.map(MonitorHandle::X)
|
||||
.collect()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -529,20 +543,22 @@ impl<T:'static> EventLoop<T> {
|
|||
}
|
||||
|
||||
pub fn run_return<F>(&mut self, callback: F)
|
||||
where F: FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow)
|
||||
where
|
||||
F: FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||
{
|
||||
match *self {
|
||||
EventLoop::Wayland(ref mut evlp) => evlp.run_return(callback),
|
||||
EventLoop::X(ref mut evlp) => evlp.run_return(callback)
|
||||
EventLoop::X(ref mut evlp) => evlp.run_return(callback),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run<F>(self, callback: F) -> !
|
||||
where F: 'static + FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow)
|
||||
where
|
||||
F: 'static + FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||
{
|
||||
match self {
|
||||
EventLoop::Wayland(evlp) => evlp.run(callback),
|
||||
EventLoop::X(evlp) => evlp.run(callback)
|
||||
EventLoop::X(evlp) => evlp.run(callback),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -557,7 +573,7 @@ impl<T:'static> EventLoop<T> {
|
|||
pub fn window_target(&self) -> &crate::event_loop::EventLoopWindowTarget<T> {
|
||||
match *self {
|
||||
EventLoop::Wayland(ref evl) => evl.window_target(),
|
||||
EventLoop::X(ref evl) => evl.window_target()
|
||||
EventLoop::X(ref evl) => evl.window_target(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -573,12 +589,16 @@ impl<T: 'static> EventLoopProxy<T> {
|
|||
|
||||
pub enum EventLoopWindowTarget<T> {
|
||||
Wayland(wayland::EventLoopWindowTarget<T>),
|
||||
X(x11::EventLoopWindowTarget<T>)
|
||||
X(x11::EventLoopWindowTarget<T>),
|
||||
}
|
||||
|
||||
fn sticky_exit_callback<T, F>(
|
||||
evt: Event<T>, target: &RootELW<T>, control_flow: &mut ControlFlow, callback: &mut F
|
||||
) where F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow)
|
||||
evt: Event<T>,
|
||||
target: &RootELW<T>,
|
||||
control_flow: &mut ControlFlow,
|
||||
callback: &mut F,
|
||||
) where
|
||||
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||
{
|
||||
// make ControlFlow::Exit sticky by providing a dummy
|
||||
// control flow reference if it is already Exit.
|
||||
|
|
|
|||
|
|
@ -1,25 +1,30 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW};
|
||||
use crate::event::ModifiersState;
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
||||
use crate::platform_impl::platform::sticky_exit_callback;
|
||||
use crate::monitor::VideoMode;
|
||||
|
||||
use super::window::WindowStore;
|
||||
use super::WindowId;
|
||||
|
||||
use smithay_client_toolkit::output::OutputMgr;
|
||||
use smithay_client_toolkit::reexports::client::protocol::{
|
||||
wl_keyboard, wl_output, wl_pointer, wl_registry, wl_seat, wl_touch,
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
collections::VecDeque,
|
||||
fmt,
|
||||
rc::Rc,
|
||||
sync::{Arc, Mutex},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
dpi::{PhysicalPosition, PhysicalSize},
|
||||
event::ModifiersState,
|
||||
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW},
|
||||
monitor::VideoMode,
|
||||
platform_impl::platform::sticky_exit_callback,
|
||||
};
|
||||
|
||||
use super::{window::WindowStore, WindowId};
|
||||
|
||||
use smithay_client_toolkit::{
|
||||
output::OutputMgr,
|
||||
reexports::client::{
|
||||
protocol::{wl_keyboard, wl_output, wl_pointer, wl_registry, wl_seat, wl_touch},
|
||||
ConnectError, Display, EventQueue, GlobalEvent,
|
||||
},
|
||||
Environment,
|
||||
};
|
||||
use smithay_client_toolkit::reexports::client::{ConnectError, Display, EventQueue, GlobalEvent};
|
||||
use smithay_client_toolkit::Environment;
|
||||
|
||||
pub struct WindowEventsSink {
|
||||
buffer: VecDeque<(crate::event::WindowEvent, crate::window::WindowId)>,
|
||||
|
|
@ -33,7 +38,10 @@ impl WindowEventsSink {
|
|||
}
|
||||
|
||||
pub fn send_event(&mut self, evt: crate::event::WindowEvent, wid: WindowId) {
|
||||
self.buffer.push_back((evt, crate::window::WindowId(crate::platform_impl::WindowId::Wayland(wid))));
|
||||
self.buffer.push_back((
|
||||
evt,
|
||||
crate::window::WindowId(crate::platform_impl::WindowId::Wayland(wid)),
|
||||
));
|
||||
}
|
||||
|
||||
fn empty_with<F, T>(&mut self, mut callback: F)
|
||||
|
|
@ -41,7 +49,10 @@ impl WindowEventsSink {
|
|||
F: FnMut(crate::event::Event<T>),
|
||||
{
|
||||
for (evt, wid) in self.buffer.drain(..) {
|
||||
callback(crate::event::Event::WindowEvent { event: evt, window_id: wid})
|
||||
callback(crate::event::Event::WindowEvent {
|
||||
event: evt,
|
||||
window_id: wid,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -58,8 +69,10 @@ pub struct EventLoop<T: 'static> {
|
|||
pending_user_events: Rc<RefCell<VecDeque<T>>>,
|
||||
_user_source: ::calloop::Source<::calloop::channel::Channel<T>>,
|
||||
user_sender: ::calloop::channel::Sender<T>,
|
||||
_kbd_source: ::calloop::Source<::calloop::channel::Channel<(crate::event::WindowEvent, super::WindowId)>>,
|
||||
window_target: RootELW<T>
|
||||
_kbd_source: ::calloop::Source<
|
||||
::calloop::channel::Channel<(crate::event::WindowEvent, super::WindowId)>,
|
||||
>,
|
||||
window_target: RootELW<T>,
|
||||
}
|
||||
|
||||
// A handle that can be sent across threads and used to wake up the `EventLoop`.
|
||||
|
|
@ -67,7 +80,7 @@ pub struct EventLoop<T: 'static> {
|
|||
// We should only try and wake up the `EventLoop` if it still exists, so we hold Weak ptrs.
|
||||
#[derive(Clone)]
|
||||
pub struct EventLoopProxy<T: 'static> {
|
||||
user_sender: ::calloop::channel::Sender<T>
|
||||
user_sender: ::calloop::channel::Sender<T>,
|
||||
}
|
||||
|
||||
pub struct EventLoopWindowTarget<T> {
|
||||
|
|
@ -83,7 +96,7 @@ pub struct EventLoopWindowTarget<T> {
|
|||
pub display: Arc<Display>,
|
||||
// The list of seats
|
||||
pub seats: Arc<Mutex<Vec<(u32, wl_seat::WlSeat)>>>,
|
||||
_marker: ::std::marker::PhantomData<T>
|
||||
_marker: ::std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: 'static> EventLoopProxy<T> {
|
||||
|
|
@ -105,11 +118,14 @@ impl<T: 'static> EventLoop<T> {
|
|||
|
||||
let (kbd_sender, kbd_channel) = ::calloop::channel::channel();
|
||||
let kbd_sink = sink.clone();
|
||||
let kbd_source = inner_loop.handle().insert_source(kbd_channel, move |evt, &mut()| {
|
||||
if let ::calloop::channel::Event::Msg((evt, wid)) = evt {
|
||||
kbd_sink.lock().unwrap().send_event(evt, wid);
|
||||
}
|
||||
}).unwrap();
|
||||
let kbd_source = inner_loop
|
||||
.handle()
|
||||
.insert_source(kbd_channel, move |evt, &mut ()| {
|
||||
if let ::calloop::channel::Event::Msg((evt, wid)) = evt {
|
||||
kbd_sink.lock().unwrap().send_event(evt, wid);
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let mut seat_manager = SeatManager {
|
||||
sink: sink.clone(),
|
||||
|
|
@ -123,7 +139,11 @@ impl<T: 'static> EventLoop<T> {
|
|||
&mut event_queue,
|
||||
move |event, registry| {
|
||||
match event {
|
||||
GlobalEvent::New { id, ref interface, version } => {
|
||||
GlobalEvent::New {
|
||||
id,
|
||||
ref interface,
|
||||
version,
|
||||
} => {
|
||||
if interface == "wl_seat" {
|
||||
seat_manager.add_seat(id, version, registry)
|
||||
}
|
||||
|
|
@ -135,20 +155,27 @@ impl<T: 'static> EventLoop<T> {
|
|||
},
|
||||
}
|
||||
},
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let source = inner_loop.handle().insert_source(event_queue, |(), &mut ()| {}).unwrap();
|
||||
let source = inner_loop
|
||||
.handle()
|
||||
.insert_source(event_queue, |(), &mut ()| {})
|
||||
.unwrap();
|
||||
|
||||
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();
|
||||
|
||||
let user_source = inner_loop.handle().insert_source(user_channel, move |evt, &mut()| {
|
||||
if let ::calloop::channel::Event::Msg(msg) = evt {
|
||||
pending_user_events2.borrow_mut().push_back(msg);
|
||||
}
|
||||
}).unwrap();
|
||||
let user_source = inner_loop
|
||||
.handle()
|
||||
.insert_source(user_channel, move |evt, &mut ()| {
|
||||
if let ::calloop::channel::Event::Msg(msg) = evt {
|
||||
pending_user_events2.borrow_mut().push_back(msg);
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
Ok(EventLoop {
|
||||
inner_loop,
|
||||
|
|
@ -167,28 +194,30 @@ impl<T: 'static> EventLoop<T> {
|
|||
cleanup_needed: Arc::new(Mutex::new(false)),
|
||||
seats,
|
||||
display,
|
||||
_marker: ::std::marker::PhantomData
|
||||
_marker: ::std::marker::PhantomData,
|
||||
}),
|
||||
_marker: ::std::marker::PhantomData
|
||||
}
|
||||
_marker: ::std::marker::PhantomData,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
||||
EventLoopProxy {
|
||||
user_sender: self.user_sender.clone()
|
||||
user_sender: self.user_sender.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run<F>(mut self, callback: F) -> !
|
||||
where F: 'static + FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow)
|
||||
where
|
||||
F: 'static + FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||
{
|
||||
self.run_return(callback);
|
||||
::std::process::exit(0);
|
||||
}
|
||||
|
||||
pub fn run_return<F>(&mut self, mut callback: F)
|
||||
where F: FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow)
|
||||
where
|
||||
F: FnMut(crate::event::Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||
{
|
||||
// send pending events to the server
|
||||
self.display.flush().expect("Wayland connection lost.");
|
||||
|
|
@ -198,7 +227,11 @@ impl<T: 'static> EventLoop<T> {
|
|||
let sink = self.sink.clone();
|
||||
let user_events = self.pending_user_events.clone();
|
||||
|
||||
callback(crate::event::Event::NewEvents(crate::event::StartCause::Init), &self.window_target, &mut control_flow);
|
||||
callback(
|
||||
crate::event::Event::NewEvents(crate::event::StartCause::Init),
|
||||
&self.window_target,
|
||||
&mut control_flow,
|
||||
);
|
||||
|
||||
loop {
|
||||
self.post_dispatch_triggers();
|
||||
|
|
@ -207,7 +240,12 @@ impl<T: 'static> EventLoop<T> {
|
|||
{
|
||||
let mut guard = sink.lock().unwrap();
|
||||
guard.empty_with(|evt| {
|
||||
sticky_exit_callback(evt, &self.window_target, &mut control_flow, &mut callback);
|
||||
sticky_exit_callback(
|
||||
evt,
|
||||
&self.window_target,
|
||||
&mut control_flow,
|
||||
&mut callback,
|
||||
);
|
||||
});
|
||||
}
|
||||
// empty user events
|
||||
|
|
@ -218,7 +256,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
crate::event::Event::UserEvent(evt),
|
||||
&self.window_target,
|
||||
&mut control_flow,
|
||||
&mut callback
|
||||
&mut callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -228,7 +266,12 @@ impl<T: 'static> EventLoop<T> {
|
|||
{
|
||||
let mut guard = sink.lock().unwrap();
|
||||
guard.empty_with(|evt| {
|
||||
sticky_exit_callback(evt, &self.window_target, &mut control_flow, &mut callback);
|
||||
sticky_exit_callback(
|
||||
evt,
|
||||
&self.window_target,
|
||||
&mut control_flow,
|
||||
&mut callback,
|
||||
);
|
||||
});
|
||||
}
|
||||
// send Events cleared
|
||||
|
|
@ -237,7 +280,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
crate::event::Event::EventsCleared,
|
||||
&self.window_target,
|
||||
&mut control_flow,
|
||||
&mut callback
|
||||
&mut callback,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -248,18 +291,24 @@ impl<T: 'static> EventLoop<T> {
|
|||
ControlFlow::Exit => break,
|
||||
ControlFlow::Poll => {
|
||||
// non-blocking dispatch
|
||||
self.inner_loop.dispatch(Some(::std::time::Duration::from_millis(0)), &mut ()).unwrap();
|
||||
callback(crate::event::Event::NewEvents(crate::event::StartCause::Poll), &self.window_target, &mut control_flow);
|
||||
self.inner_loop
|
||||
.dispatch(Some(::std::time::Duration::from_millis(0)), &mut ())
|
||||
.unwrap();
|
||||
callback(
|
||||
crate::event::Event::NewEvents(crate::event::StartCause::Poll),
|
||||
&self.window_target,
|
||||
&mut control_flow,
|
||||
);
|
||||
},
|
||||
ControlFlow::Wait => {
|
||||
self.inner_loop.dispatch(None, &mut ()).unwrap();
|
||||
callback(
|
||||
crate::event::Event::NewEvents(crate::event::StartCause::WaitCancelled {
|
||||
start: Instant::now(),
|
||||
requested_resume: None
|
||||
requested_resume: None,
|
||||
}),
|
||||
&self.window_target,
|
||||
&mut control_flow
|
||||
&mut control_flow,
|
||||
);
|
||||
},
|
||||
ControlFlow::WaitUntil(deadline) => {
|
||||
|
|
@ -274,28 +323,36 @@ impl<T: 'static> EventLoop<T> {
|
|||
let now = Instant::now();
|
||||
if now < deadline {
|
||||
callback(
|
||||
crate::event::Event::NewEvents(crate::event::StartCause::WaitCancelled {
|
||||
start,
|
||||
requested_resume: Some(deadline)
|
||||
}),
|
||||
crate::event::Event::NewEvents(
|
||||
crate::event::StartCause::WaitCancelled {
|
||||
start,
|
||||
requested_resume: Some(deadline),
|
||||
},
|
||||
),
|
||||
&self.window_target,
|
||||
&mut control_flow
|
||||
&mut control_flow,
|
||||
);
|
||||
} else {
|
||||
callback(
|
||||
crate::event::Event::NewEvents(crate::event::StartCause::ResumeTimeReached {
|
||||
start,
|
||||
requested_resume: deadline
|
||||
}),
|
||||
crate::event::Event::NewEvents(
|
||||
crate::event::StartCause::ResumeTimeReached {
|
||||
start,
|
||||
requested_resume: deadline,
|
||||
},
|
||||
),
|
||||
&self.window_target,
|
||||
&mut control_flow
|
||||
&mut control_flow,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
callback(crate::event::Event::LoopDestroyed, &self.window_target, &mut control_flow);
|
||||
callback(
|
||||
crate::event::Event::LoopDestroyed,
|
||||
&self.window_target,
|
||||
&mut control_flow,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn primary_monitor(&self) -> MonitorHandle {
|
||||
|
|
@ -324,7 +381,7 @@ impl<T> EventLoop<T> {
|
|||
let mut sink = self.sink.lock().unwrap();
|
||||
let window_target = match self.window_target.p {
|
||||
crate::platform_impl::EventLoopWindowTarget::Wayland(ref wt) => wt,
|
||||
_ => unreachable!()
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// prune possible dead windows
|
||||
{
|
||||
|
|
@ -355,7 +412,10 @@ impl<T> EventLoop<T> {
|
|||
}
|
||||
}
|
||||
if let Some(dpi) = new_dpi {
|
||||
sink.send_event(crate::event::WindowEvent::HiDpiFactorChanged(dpi as f64), wid);
|
||||
sink.send_event(
|
||||
crate::event::WindowEvent::HiDpiFactorChanged(dpi as f64),
|
||||
wid,
|
||||
);
|
||||
}
|
||||
if refresh {
|
||||
sink.send_event(crate::event::WindowEvent::RedrawRequested, wid);
|
||||
|
|
@ -376,7 +436,7 @@ struct SeatManager {
|
|||
sink: Arc<Mutex<WindowEventsSink>>,
|
||||
store: Arc<Mutex<WindowStore>>,
|
||||
seats: Arc<Mutex<Vec<(u32, wl_seat::WlSeat)>>>,
|
||||
kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>
|
||||
kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>,
|
||||
}
|
||||
|
||||
impl SeatManager {
|
||||
|
|
@ -394,9 +454,7 @@ impl SeatManager {
|
|||
};
|
||||
let seat = registry
|
||||
.bind(min(version, 5), id, move |seat| {
|
||||
seat.implement_closure(move |event, seat| {
|
||||
seat_data.receive(event, seat)
|
||||
}, ())
|
||||
seat.implement_closure(move |event, seat| seat_data.receive(event, seat), ())
|
||||
})
|
||||
.unwrap();
|
||||
self.store.lock().unwrap().new_seat(&seat);
|
||||
|
|
@ -479,7 +537,7 @@ impl SeatData {
|
|||
}
|
||||
}
|
||||
},
|
||||
_ => unreachable!()
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -566,7 +624,8 @@ impl MonitorHandle {
|
|||
}) {
|
||||
Some(Some((w, h))) => (w as u32, h as u32),
|
||||
_ => (0, 0),
|
||||
}.into()
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn position(&self) -> PhysicalPosition {
|
||||
|
|
@ -584,16 +643,17 @@ impl MonitorHandle {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn video_modes(&self) -> impl Iterator<Item = VideoMode>
|
||||
{
|
||||
pub fn video_modes(&self) -> impl Iterator<Item = VideoMode> {
|
||||
self.mgr
|
||||
.with_info(&self.proxy, |_, info| info.modes.clone())
|
||||
.unwrap_or(vec![])
|
||||
.into_iter()
|
||||
.map(|x| VideoMode {
|
||||
size: (x.dimensions.0 as u32, x.dimensions.1 as u32),
|
||||
refresh_rate: (x.refresh_rate as f32 / 1000.0).round() as u16,
|
||||
bit_depth: 32
|
||||
.map(|x| {
|
||||
VideoMode {
|
||||
size: (x.dimensions.0 as u32, x.dimensions.1 as u32),
|
||||
refresh_rate: (x.refresh_rate as f32 / 1000.0).round() as u16,
|
||||
bit_depth: 32,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -614,9 +674,11 @@ pub fn primary_monitor(outputs: &OutputMgr) -> MonitorHandle {
|
|||
pub fn available_monitors(outputs: &OutputMgr) -> VecDeque<MonitorHandle> {
|
||||
outputs.with_all(|list| {
|
||||
list.iter()
|
||||
.map(|&(_, ref proxy, _)| MonitorHandle {
|
||||
proxy: proxy.clone(),
|
||||
mgr: outputs.clone(),
|
||||
.map(|&(_, ref proxy, _)| {
|
||||
MonitorHandle {
|
||||
proxy: proxy.clone(),
|
||||
mgr: outputs.clone(),
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use super::{make_wid, DeviceId};
|
||||
use smithay_client_toolkit::keyboard::{
|
||||
self, map_keyboard_auto_with_repeat, Event as KbEvent, KeyRepeatEvent, KeyRepeatKind,
|
||||
use smithay_client_toolkit::{
|
||||
keyboard::{
|
||||
self, map_keyboard_auto_with_repeat, Event as KbEvent, KeyRepeatEvent, KeyRepeatKind,
|
||||
},
|
||||
reexports::client::protocol::{wl_keyboard, wl_seat},
|
||||
};
|
||||
use smithay_client_toolkit::reexports::client::protocol::{wl_keyboard, wl_seat};
|
||||
|
||||
use crate::event::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent};
|
||||
|
||||
|
|
@ -23,78 +25,92 @@ pub fn init_keyboard(
|
|||
let ret = map_keyboard_auto_with_repeat(
|
||||
seat,
|
||||
KeyRepeatKind::System,
|
||||
move |evt: KbEvent<'_>, _| match evt {
|
||||
KbEvent::Enter { surface, .. } => {
|
||||
let wid = make_wid(&surface);
|
||||
my_sink.send((WindowEvent::Focused(true), wid)).unwrap();
|
||||
*target.lock().unwrap() = Some(wid);
|
||||
}
|
||||
KbEvent::Leave { surface, .. } => {
|
||||
let wid = make_wid(&surface);
|
||||
my_sink.send((WindowEvent::Focused(false), wid)).unwrap();
|
||||
*target.lock().unwrap() = None;
|
||||
}
|
||||
KbEvent::Key {
|
||||
rawkey,
|
||||
keysym,
|
||||
state,
|
||||
utf8,
|
||||
..
|
||||
} => {
|
||||
if let Some(wid) = *target.lock().unwrap() {
|
||||
let state = match state {
|
||||
wl_keyboard::KeyState::Pressed => ElementState::Pressed,
|
||||
wl_keyboard::KeyState::Released => ElementState::Released,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let vkcode = key_to_vkey(rawkey, keysym);
|
||||
my_sink.send(
|
||||
(WindowEvent::KeyboardInput {
|
||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
||||
input: KeyboardInput {
|
||||
state: state,
|
||||
scancode: rawkey,
|
||||
virtual_keycode: vkcode,
|
||||
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
||||
},
|
||||
},
|
||||
wid)
|
||||
).unwrap();
|
||||
// send char event only on key press, not release
|
||||
if let ElementState::Released = state {
|
||||
return;
|
||||
}
|
||||
if let Some(txt) = utf8 {
|
||||
for chr in txt.chars() {
|
||||
my_sink.send((WindowEvent::ReceivedCharacter(chr), wid)).unwrap();
|
||||
move |evt: KbEvent<'_>, _| {
|
||||
match evt {
|
||||
KbEvent::Enter { surface, .. } => {
|
||||
let wid = make_wid(&surface);
|
||||
my_sink.send((WindowEvent::Focused(true), wid)).unwrap();
|
||||
*target.lock().unwrap() = Some(wid);
|
||||
},
|
||||
KbEvent::Leave { surface, .. } => {
|
||||
let wid = make_wid(&surface);
|
||||
my_sink.send((WindowEvent::Focused(false), wid)).unwrap();
|
||||
*target.lock().unwrap() = None;
|
||||
},
|
||||
KbEvent::Key {
|
||||
rawkey,
|
||||
keysym,
|
||||
state,
|
||||
utf8,
|
||||
..
|
||||
} => {
|
||||
if let Some(wid) = *target.lock().unwrap() {
|
||||
let state = match state {
|
||||
wl_keyboard::KeyState::Pressed => ElementState::Pressed,
|
||||
wl_keyboard::KeyState::Released => ElementState::Released,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let vkcode = key_to_vkey(rawkey, keysym);
|
||||
my_sink
|
||||
.send((
|
||||
WindowEvent::KeyboardInput {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
),
|
||||
input: KeyboardInput {
|
||||
state,
|
||||
scancode: rawkey,
|
||||
virtual_keycode: vkcode,
|
||||
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
||||
},
|
||||
},
|
||||
wid,
|
||||
))
|
||||
.unwrap();
|
||||
// send char event only on key press, not release
|
||||
if let ElementState::Released = state {
|
||||
return;
|
||||
}
|
||||
if let Some(txt) = utf8 {
|
||||
for chr in txt.chars() {
|
||||
my_sink
|
||||
.send((WindowEvent::ReceivedCharacter(chr), wid))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
KbEvent::RepeatInfo { .. } => { /* Handled by smithay client toolkit */ },
|
||||
KbEvent::Modifiers {
|
||||
modifiers: event_modifiers,
|
||||
} => *modifiers_tracker.lock().unwrap() = event_modifiers.into(),
|
||||
}
|
||||
KbEvent::RepeatInfo { .. } => { /* Handled by smithay client toolkit */ }
|
||||
KbEvent::Modifiers { modifiers: event_modifiers } => {
|
||||
*modifiers_tracker.lock().unwrap() = event_modifiers.into()
|
||||
},
|
||||
},
|
||||
move |repeat_event: KeyRepeatEvent, _| {
|
||||
if let Some(wid) = *repeat_target.lock().unwrap() {
|
||||
let state = ElementState::Pressed;
|
||||
let vkcode = key_to_vkey(repeat_event.rawkey, repeat_event.keysym);
|
||||
repeat_sink.send((
|
||||
WindowEvent::KeyboardInput {
|
||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
||||
input: KeyboardInput {
|
||||
state: state,
|
||||
scancode: repeat_event.rawkey,
|
||||
virtual_keycode: vkcode,
|
||||
modifiers: my_modifiers.lock().unwrap().clone(),
|
||||
repeat_sink
|
||||
.send((
|
||||
WindowEvent::KeyboardInput {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
),
|
||||
input: KeyboardInput {
|
||||
state,
|
||||
scancode: repeat_event.rawkey,
|
||||
virtual_keycode: vkcode,
|
||||
modifiers: my_modifiers.lock().unwrap().clone(),
|
||||
},
|
||||
},
|
||||
},
|
||||
wid)
|
||||
).unwrap();
|
||||
wid,
|
||||
))
|
||||
.unwrap();
|
||||
if let Some(txt) = repeat_event.utf8 {
|
||||
for chr in txt.chars() {
|
||||
repeat_sink.send((WindowEvent::ReceivedCharacter(chr), wid)).unwrap();
|
||||
repeat_sink
|
||||
.send((WindowEvent::ReceivedCharacter(chr), wid))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -116,42 +132,54 @@ pub fn init_keyboard(
|
|||
let my_sink = sink;
|
||||
// }
|
||||
seat.get_keyboard(|keyboard| {
|
||||
keyboard.implement_closure(move |evt, _| match evt {
|
||||
wl_keyboard::Event::Enter { surface, .. } => {
|
||||
let wid = make_wid(&surface);
|
||||
my_sink.send((WindowEvent::Focused(true), wid)).unwrap();
|
||||
target = Some(wid);
|
||||
}
|
||||
wl_keyboard::Event::Leave { surface, .. } => {
|
||||
let wid = make_wid(&surface);
|
||||
my_sink.send((WindowEvent::Focused(false), wid)).unwrap();
|
||||
target = None;
|
||||
}
|
||||
wl_keyboard::Event::Key { key, state, .. } => {
|
||||
if let Some(wid) = target {
|
||||
let state = match state {
|
||||
wl_keyboard::KeyState::Pressed => ElementState::Pressed,
|
||||
wl_keyboard::KeyState::Released => ElementState::Released,
|
||||
_ => unreachable!()
|
||||
};
|
||||
my_sink.send((
|
||||
WindowEvent::KeyboardInput {
|
||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
||||
input: KeyboardInput {
|
||||
state: state,
|
||||
scancode: key,
|
||||
virtual_keycode: None,
|
||||
modifiers: ModifiersState::default(),
|
||||
},
|
||||
},
|
||||
wid,
|
||||
)).unwrap();
|
||||
keyboard.implement_closure(
|
||||
move |evt, _| {
|
||||
match evt {
|
||||
wl_keyboard::Event::Enter { surface, .. } => {
|
||||
let wid = make_wid(&surface);
|
||||
my_sink.send((WindowEvent::Focused(true), wid)).unwrap();
|
||||
target = Some(wid);
|
||||
},
|
||||
wl_keyboard::Event::Leave { surface, .. } => {
|
||||
let wid = make_wid(&surface);
|
||||
my_sink.send((WindowEvent::Focused(false), wid)).unwrap();
|
||||
target = None;
|
||||
},
|
||||
wl_keyboard::Event::Key { key, state, .. } => {
|
||||
if let Some(wid) = target {
|
||||
let state = match state {
|
||||
wl_keyboard::KeyState::Pressed => ElementState::Pressed,
|
||||
wl_keyboard::KeyState::Released => ElementState::Released,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
my_sink
|
||||
.send((
|
||||
WindowEvent::KeyboardInput {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(
|
||||
DeviceId,
|
||||
),
|
||||
),
|
||||
input: KeyboardInput {
|
||||
state,
|
||||
scancode: key,
|
||||
virtual_keycode: None,
|
||||
modifiers: ModifiersState::default(),
|
||||
},
|
||||
},
|
||||
wid,
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}, ())
|
||||
}).unwrap()
|
||||
}
|
||||
},
|
||||
(),
|
||||
)
|
||||
})
|
||||
.unwrap()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,19 @@
|
|||
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd",
|
||||
target_os = "netbsd", target_os = "openbsd"))]
|
||||
|
||||
pub use self::window::Window;
|
||||
pub use self::event_loop::{EventLoop, EventLoopWindowTarget, EventLoopProxy, WindowEventsSink, MonitorHandle};
|
||||
pub use self::{
|
||||
event_loop::{
|
||||
EventLoop, EventLoopProxy, EventLoopWindowTarget, MonitorHandle, WindowEventsSink,
|
||||
},
|
||||
window::Window,
|
||||
};
|
||||
|
||||
use smithay_client_toolkit::reexports::client::protocol::wl_surface;
|
||||
|
||||
mod event_loop;
|
||||
mod keyboard;
|
||||
mod pointer;
|
||||
mod touch;
|
||||
mod keyboard;
|
||||
mod window;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::event::{ElementState, MouseButton, MouseScrollDelta, TouchPhase, WindowEvent, ModifiersState};
|
||||
use crate::event::{
|
||||
ElementState, ModifiersState, MouseButton, MouseScrollDelta, TouchPhase, WindowEvent,
|
||||
};
|
||||
|
||||
use super::DeviceId;
|
||||
use super::event_loop::WindowEventsSink;
|
||||
use super::window::WindowStore;
|
||||
use super::{event_loop::WindowEventsSink, window::WindowStore, DeviceId};
|
||||
|
||||
use smithay_client_toolkit::reexports::client::protocol::wl_pointer::{self, Event as PtrEvent, WlPointer};
|
||||
use smithay_client_toolkit::reexports::client::protocol::wl_seat;
|
||||
use smithay_client_toolkit::reexports::client::protocol::{
|
||||
wl_pointer::{self, Event as PtrEvent, WlPointer},
|
||||
wl_seat,
|
||||
};
|
||||
|
||||
pub fn implement_pointer(
|
||||
seat: &wl_seat::WlSeat,
|
||||
|
|
@ -21,171 +23,195 @@ pub fn implement_pointer(
|
|||
let mut axis_state = TouchPhase::Ended;
|
||||
|
||||
seat.get_pointer(|pointer| {
|
||||
pointer.implement_closure(move |evt, pointer| {
|
||||
let mut sink = sink.lock().unwrap();
|
||||
let store = store.lock().unwrap();
|
||||
match evt {
|
||||
PtrEvent::Enter {
|
||||
surface,
|
||||
surface_x,
|
||||
surface_y,
|
||||
..
|
||||
} => {
|
||||
let wid = store.find_wid(&surface);
|
||||
if let Some(wid) = wid {
|
||||
mouse_focus = Some(wid);
|
||||
sink.send_event(
|
||||
WindowEvent::CursorEntered {
|
||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
||||
},
|
||||
wid,
|
||||
);
|
||||
sink.send_event(
|
||||
WindowEvent::CursorMoved {
|
||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
||||
position: (surface_x, surface_y).into(),
|
||||
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
||||
},
|
||||
wid,
|
||||
);
|
||||
}
|
||||
}
|
||||
PtrEvent::Leave { surface, .. } => {
|
||||
mouse_focus = None;
|
||||
let wid = store.find_wid(&surface);
|
||||
if let Some(wid) = wid {
|
||||
sink.send_event(
|
||||
WindowEvent::CursorLeft {
|
||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
||||
},
|
||||
wid,
|
||||
);
|
||||
}
|
||||
}
|
||||
PtrEvent::Motion {
|
||||
surface_x,
|
||||
surface_y,
|
||||
..
|
||||
} => {
|
||||
if let Some(wid) = mouse_focus {
|
||||
sink.send_event(
|
||||
WindowEvent::CursorMoved {
|
||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
||||
position: (surface_x, surface_y).into(),
|
||||
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
||||
},
|
||||
wid,
|
||||
);
|
||||
}
|
||||
}
|
||||
PtrEvent::Button { button, state, .. } => {
|
||||
if let Some(wid) = mouse_focus {
|
||||
let state = match state {
|
||||
wl_pointer::ButtonState::Pressed => ElementState::Pressed,
|
||||
wl_pointer::ButtonState::Released => ElementState::Released,
|
||||
_ => unreachable!()
|
||||
};
|
||||
let button = match button {
|
||||
0x110 => MouseButton::Left,
|
||||
0x111 => MouseButton::Right,
|
||||
0x112 => MouseButton::Middle,
|
||||
// TODO figure out the translation ?
|
||||
_ => return,
|
||||
};
|
||||
sink.send_event(
|
||||
WindowEvent::MouseInput {
|
||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
||||
state: state,
|
||||
button: button,
|
||||
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
||||
},
|
||||
wid,
|
||||
);
|
||||
}
|
||||
}
|
||||
PtrEvent::Axis { axis, value, .. } => {
|
||||
if let Some(wid) = mouse_focus {
|
||||
if pointer.as_ref().version() < 5 {
|
||||
let (mut x, mut y) = (0.0, 0.0);
|
||||
// old seat compatibility
|
||||
match axis {
|
||||
// wayland vertical sign convention is the inverse of winit
|
||||
wl_pointer::Axis::VerticalScroll => y -= value as f32,
|
||||
wl_pointer::Axis::HorizontalScroll => x += value as f32,
|
||||
_ => unreachable!()
|
||||
}
|
||||
pointer.implement_closure(
|
||||
move |evt, pointer| {
|
||||
let mut sink = sink.lock().unwrap();
|
||||
let store = store.lock().unwrap();
|
||||
match evt {
|
||||
PtrEvent::Enter {
|
||||
surface,
|
||||
surface_x,
|
||||
surface_y,
|
||||
..
|
||||
} => {
|
||||
let wid = store.find_wid(&surface);
|
||||
if let Some(wid) = wid {
|
||||
mouse_focus = Some(wid);
|
||||
sink.send_event(
|
||||
WindowEvent::MouseWheel {
|
||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
||||
delta: MouseScrollDelta::PixelDelta((x as f64, y as f64).into()),
|
||||
phase: TouchPhase::Moved,
|
||||
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
||||
WindowEvent::CursorEntered {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
),
|
||||
},
|
||||
wid,
|
||||
);
|
||||
} else {
|
||||
let (mut x, mut y) = axis_buffer.unwrap_or((0.0, 0.0));
|
||||
match axis {
|
||||
// wayland vertical sign convention is the inverse of winit
|
||||
wl_pointer::Axis::VerticalScroll => y -= value as f32,
|
||||
wl_pointer::Axis::HorizontalScroll => x += value as f32,
|
||||
_ => unreachable!()
|
||||
}
|
||||
axis_buffer = Some((x, y));
|
||||
axis_state = match axis_state {
|
||||
TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved,
|
||||
_ => TouchPhase::Started,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PtrEvent::Frame => {
|
||||
let axis_buffer = axis_buffer.take();
|
||||
let axis_discrete_buffer = axis_discrete_buffer.take();
|
||||
if let Some(wid) = mouse_focus {
|
||||
if let Some((x, y)) = axis_discrete_buffer {
|
||||
sink.send_event(
|
||||
WindowEvent::MouseWheel {
|
||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
||||
delta: MouseScrollDelta::LineDelta(x as f32, y as f32),
|
||||
phase: axis_state,
|
||||
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
||||
},
|
||||
wid,
|
||||
);
|
||||
} else if let Some((x, y)) = axis_buffer {
|
||||
sink.send_event(
|
||||
WindowEvent::MouseWheel {
|
||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
||||
delta: MouseScrollDelta::PixelDelta((x as f64, y as f64).into()),
|
||||
phase: axis_state,
|
||||
WindowEvent::CursorMoved {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
),
|
||||
position: (surface_x, surface_y).into(),
|
||||
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
||||
},
|
||||
wid,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
PtrEvent::Leave { surface, .. } => {
|
||||
mouse_focus = None;
|
||||
let wid = store.find_wid(&surface);
|
||||
if let Some(wid) = wid {
|
||||
sink.send_event(
|
||||
WindowEvent::CursorLeft {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
),
|
||||
},
|
||||
wid,
|
||||
);
|
||||
}
|
||||
},
|
||||
PtrEvent::Motion {
|
||||
surface_x,
|
||||
surface_y,
|
||||
..
|
||||
} => {
|
||||
if let Some(wid) = mouse_focus {
|
||||
sink.send_event(
|
||||
WindowEvent::CursorMoved {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
),
|
||||
position: (surface_x, surface_y).into(),
|
||||
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
||||
},
|
||||
wid,
|
||||
);
|
||||
}
|
||||
},
|
||||
PtrEvent::Button { button, state, .. } => {
|
||||
if let Some(wid) = mouse_focus {
|
||||
let state = match state {
|
||||
wl_pointer::ButtonState::Pressed => ElementState::Pressed,
|
||||
wl_pointer::ButtonState::Released => ElementState::Released,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let button = match button {
|
||||
0x110 => MouseButton::Left,
|
||||
0x111 => MouseButton::Right,
|
||||
0x112 => MouseButton::Middle,
|
||||
// TODO figure out the translation ?
|
||||
_ => return,
|
||||
};
|
||||
sink.send_event(
|
||||
WindowEvent::MouseInput {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
),
|
||||
state,
|
||||
button,
|
||||
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
||||
},
|
||||
wid,
|
||||
);
|
||||
}
|
||||
},
|
||||
PtrEvent::Axis { axis, value, .. } => {
|
||||
if let Some(wid) = mouse_focus {
|
||||
if pointer.as_ref().version() < 5 {
|
||||
let (mut x, mut y) = (0.0, 0.0);
|
||||
// old seat compatibility
|
||||
match axis {
|
||||
// wayland vertical sign convention is the inverse of winit
|
||||
wl_pointer::Axis::VerticalScroll => y -= value as f32,
|
||||
wl_pointer::Axis::HorizontalScroll => x += value as f32,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
sink.send_event(
|
||||
WindowEvent::MouseWheel {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
),
|
||||
delta: MouseScrollDelta::PixelDelta(
|
||||
(x as f64, y as f64).into(),
|
||||
),
|
||||
phase: TouchPhase::Moved,
|
||||
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
||||
},
|
||||
wid,
|
||||
);
|
||||
} else {
|
||||
let (mut x, mut y) = axis_buffer.unwrap_or((0.0, 0.0));
|
||||
match axis {
|
||||
// wayland vertical sign convention is the inverse of winit
|
||||
wl_pointer::Axis::VerticalScroll => y -= value as f32,
|
||||
wl_pointer::Axis::HorizontalScroll => x += value as f32,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
axis_buffer = Some((x, y));
|
||||
axis_state = match axis_state {
|
||||
TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved,
|
||||
_ => TouchPhase::Started,
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
PtrEvent::Frame => {
|
||||
let axis_buffer = axis_buffer.take();
|
||||
let axis_discrete_buffer = axis_discrete_buffer.take();
|
||||
if let Some(wid) = mouse_focus {
|
||||
if let Some((x, y)) = axis_discrete_buffer {
|
||||
sink.send_event(
|
||||
WindowEvent::MouseWheel {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
),
|
||||
delta: MouseScrollDelta::LineDelta(x as f32, y as f32),
|
||||
phase: axis_state,
|
||||
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
||||
},
|
||||
wid,
|
||||
);
|
||||
} else if let Some((x, y)) = axis_buffer {
|
||||
sink.send_event(
|
||||
WindowEvent::MouseWheel {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
),
|
||||
delta: MouseScrollDelta::PixelDelta(
|
||||
(x as f64, y as f64).into(),
|
||||
),
|
||||
phase: axis_state,
|
||||
modifiers: modifiers_tracker.lock().unwrap().clone(),
|
||||
},
|
||||
wid,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
PtrEvent::AxisSource { .. } => (),
|
||||
PtrEvent::AxisStop { .. } => {
|
||||
axis_state = TouchPhase::Ended;
|
||||
},
|
||||
PtrEvent::AxisDiscrete { axis, discrete } => {
|
||||
let (mut x, mut y) = axis_discrete_buffer.unwrap_or((0, 0));
|
||||
match axis {
|
||||
// wayland vertical sign convention is the inverse of winit
|
||||
wl_pointer::Axis::VerticalScroll => y -= discrete,
|
||||
wl_pointer::Axis::HorizontalScroll => x += discrete,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
axis_discrete_buffer = Some((x, y));
|
||||
axis_state = match axis_state {
|
||||
TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved,
|
||||
_ => TouchPhase::Started,
|
||||
}
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
PtrEvent::AxisSource { .. } => (),
|
||||
PtrEvent::AxisStop { .. } => {
|
||||
axis_state = TouchPhase::Ended;
|
||||
}
|
||||
PtrEvent::AxisDiscrete { axis, discrete } => {
|
||||
let (mut x, mut y) = axis_discrete_buffer.unwrap_or((0, 0));
|
||||
match axis {
|
||||
// wayland vertical sign convention is the inverse of winit
|
||||
wl_pointer::Axis::VerticalScroll => y -= discrete,
|
||||
wl_pointer::Axis::HorizontalScroll => x += discrete,
|
||||
_ => unreachable!()
|
||||
}
|
||||
axis_discrete_buffer = Some((x, y));
|
||||
axis_state = match axis_state {
|
||||
TouchPhase::Started | TouchPhase::Moved => TouchPhase::Moved,
|
||||
_ => TouchPhase::Started,
|
||||
}
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
}, ())
|
||||
}).unwrap()
|
||||
},
|
||||
(),
|
||||
)
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ use std::sync::{Arc, Mutex};
|
|||
|
||||
use crate::event::{TouchPhase, WindowEvent};
|
||||
|
||||
use super::{DeviceId, WindowId};
|
||||
use super::event_loop::WindowEventsSink;
|
||||
use super::window::WindowStore;
|
||||
use super::{event_loop::WindowEventsSink, window::WindowStore, DeviceId, WindowId};
|
||||
|
||||
use smithay_client_toolkit::reexports::client::protocol::wl_touch::{Event as TouchEvent, WlTouch};
|
||||
use smithay_client_toolkit::reexports::client::protocol::wl_seat;
|
||||
use smithay_client_toolkit::reexports::client::protocol::{
|
||||
wl_seat,
|
||||
wl_touch::{Event as TouchEvent, WlTouch},
|
||||
};
|
||||
|
||||
struct TouchPoint {
|
||||
wid: WindowId,
|
||||
|
|
@ -22,75 +22,89 @@ pub(crate) fn implement_touch(
|
|||
) -> WlTouch {
|
||||
let mut pending_ids = Vec::new();
|
||||
seat.get_touch(|touch| {
|
||||
touch.implement_closure(move |evt, _| {
|
||||
let mut sink = sink.lock().unwrap();
|
||||
let store = store.lock().unwrap();
|
||||
match evt {
|
||||
TouchEvent::Down {
|
||||
surface, id, x, y, ..
|
||||
} => {
|
||||
let wid = store.find_wid(&surface);
|
||||
if let Some(wid) = wid {
|
||||
sink.send_event(
|
||||
WindowEvent::Touch(crate::event::Touch {
|
||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
||||
phase: TouchPhase::Started,
|
||||
location: (x, y).into(),
|
||||
id: id as u64,
|
||||
}),
|
||||
wid,
|
||||
);
|
||||
pending_ids.push(TouchPoint {
|
||||
wid: wid,
|
||||
location: (x, y),
|
||||
id: id,
|
||||
});
|
||||
}
|
||||
touch.implement_closure(
|
||||
move |evt, _| {
|
||||
let mut sink = sink.lock().unwrap();
|
||||
let store = store.lock().unwrap();
|
||||
match evt {
|
||||
TouchEvent::Down {
|
||||
surface, id, x, y, ..
|
||||
} => {
|
||||
let wid = store.find_wid(&surface);
|
||||
if let Some(wid) = wid {
|
||||
sink.send_event(
|
||||
WindowEvent::Touch(crate::event::Touch {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
),
|
||||
phase: TouchPhase::Started,
|
||||
location: (x, y).into(),
|
||||
id: id as u64,
|
||||
}),
|
||||
wid,
|
||||
);
|
||||
pending_ids.push(TouchPoint {
|
||||
wid,
|
||||
location: (x, y),
|
||||
id,
|
||||
});
|
||||
}
|
||||
},
|
||||
TouchEvent::Up { id, .. } => {
|
||||
let idx = pending_ids.iter().position(|p| p.id == id);
|
||||
if let Some(idx) = idx {
|
||||
let pt = pending_ids.remove(idx);
|
||||
sink.send_event(
|
||||
WindowEvent::Touch(crate::event::Touch {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
),
|
||||
phase: TouchPhase::Ended,
|
||||
location: pt.location.into(),
|
||||
id: id as u64,
|
||||
}),
|
||||
pt.wid,
|
||||
);
|
||||
}
|
||||
},
|
||||
TouchEvent::Motion { id, x, y, .. } => {
|
||||
let pt = pending_ids.iter_mut().find(|p| p.id == id);
|
||||
if let Some(pt) = pt {
|
||||
pt.location = (x, y);
|
||||
sink.send_event(
|
||||
WindowEvent::Touch(crate::event::Touch {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
),
|
||||
phase: TouchPhase::Moved,
|
||||
location: (x, y).into(),
|
||||
id: id as u64,
|
||||
}),
|
||||
pt.wid,
|
||||
);
|
||||
}
|
||||
},
|
||||
TouchEvent::Frame => (),
|
||||
TouchEvent::Cancel => {
|
||||
for pt in pending_ids.drain(..) {
|
||||
sink.send_event(
|
||||
WindowEvent::Touch(crate::event::Touch {
|
||||
device_id: crate::event::DeviceId(
|
||||
crate::platform_impl::DeviceId::Wayland(DeviceId),
|
||||
),
|
||||
phase: TouchPhase::Cancelled,
|
||||
location: pt.location.into(),
|
||||
id: pt.id as u64,
|
||||
}),
|
||||
pt.wid,
|
||||
);
|
||||
}
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
TouchEvent::Up { id, .. } => {
|
||||
let idx = pending_ids.iter().position(|p| p.id == id);
|
||||
if let Some(idx) = idx {
|
||||
let pt = pending_ids.remove(idx);
|
||||
sink.send_event(
|
||||
WindowEvent::Touch(crate::event::Touch {
|
||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
||||
phase: TouchPhase::Ended,
|
||||
location: pt.location.into(),
|
||||
id: id as u64,
|
||||
}),
|
||||
pt.wid,
|
||||
);
|
||||
}
|
||||
}
|
||||
TouchEvent::Motion { id, x, y, .. } => {
|
||||
let pt = pending_ids.iter_mut().find(|p| p.id == id);
|
||||
if let Some(pt) = pt {
|
||||
pt.location = (x, y);
|
||||
sink.send_event(
|
||||
WindowEvent::Touch(crate::event::Touch {
|
||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
||||
phase: TouchPhase::Moved,
|
||||
location: (x, y).into(),
|
||||
id: id as u64,
|
||||
}),
|
||||
pt.wid,
|
||||
);
|
||||
}
|
||||
}
|
||||
TouchEvent::Frame => (),
|
||||
TouchEvent::Cancel => for pt in pending_ids.drain(..) {
|
||||
sink.send_event(
|
||||
WindowEvent::Touch(crate::event::Touch {
|
||||
device_id: crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)),
|
||||
phase: TouchPhase::Cancelled,
|
||||
location: pt.location.into(),
|
||||
id: pt.id as u64,
|
||||
}),
|
||||
pt.wid,
|
||||
);
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
}, ())
|
||||
}).unwrap()
|
||||
},
|
||||
(),
|
||||
)
|
||||
})
|
||||
.unwrap()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,29 @@
|
|||
use std::collections::VecDeque;
|
||||
use std::io::{Seek, SeekFrom, Write};
|
||||
use std::sync::{Arc, Mutex, Weak};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
io::{Seek, SeekFrom, Write},
|
||||
sync::{Arc, Mutex, Weak},
|
||||
};
|
||||
|
||||
use crate::dpi::{LogicalPosition, LogicalSize};
|
||||
use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError};
|
||||
use crate::platform_impl::{MonitorHandle as PlatformMonitorHandle, PlatformSpecificWindowBuilderAttributes as PlAttributes};
|
||||
use crate::monitor::MonitorHandle as RootMonitorHandle;
|
||||
use crate::window::{WindowAttributes, CursorIcon};
|
||||
use crate::{
|
||||
dpi::{LogicalPosition, LogicalSize},
|
||||
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||
monitor::MonitorHandle as RootMonitorHandle,
|
||||
platform_impl::{
|
||||
MonitorHandle as PlatformMonitorHandle,
|
||||
PlatformSpecificWindowBuilderAttributes as PlAttributes,
|
||||
},
|
||||
window::{CursorIcon, WindowAttributes},
|
||||
};
|
||||
|
||||
use smithay_client_toolkit::surface::{get_dpi_factor, get_outputs};
|
||||
use smithay_client_toolkit::window::{ConceptFrame, Event as WEvent, State as WState, Window as SWindow, Theme};
|
||||
use smithay_client_toolkit::reexports::client::{Display, NewProxy};
|
||||
use smithay_client_toolkit::reexports::client::protocol::{wl_seat, wl_surface, wl_subsurface, wl_shm};
|
||||
use smithay_client_toolkit::output::OutputMgr;
|
||||
use smithay_client_toolkit::{
|
||||
output::OutputMgr,
|
||||
reexports::client::{
|
||||
protocol::{wl_seat, wl_shm, wl_subsurface, wl_surface},
|
||||
Display, NewProxy,
|
||||
},
|
||||
surface::{get_dpi_factor, get_outputs},
|
||||
window::{ConceptFrame, Event as WEvent, State as WState, Theme, Window as SWindow},
|
||||
};
|
||||
|
||||
use super::{make_wid, EventLoopWindowTarget, MonitorHandle, WindowId};
|
||||
use crate::platform_impl::platform::wayland::event_loop::{available_monitors, primary_monitor};
|
||||
|
|
@ -32,7 +43,11 @@ pub struct Window {
|
|||
}
|
||||
|
||||
impl Window {
|
||||
pub fn new<T>(evlp: &EventLoopWindowTarget<T>, attributes: WindowAttributes, pl_attribs: PlAttributes) -> Result<Window, RootOsError> {
|
||||
pub fn new<T>(
|
||||
evlp: &EventLoopWindowTarget<T>,
|
||||
attributes: WindowAttributes,
|
||||
pl_attribs: PlAttributes,
|
||||
) -> Result<Window, RootOsError> {
|
||||
let (width, height) = attributes.inner_size.map(Into::into).unwrap_or((800, 600));
|
||||
// Create the window
|
||||
let size = Arc::new(Mutex::new((width, height)));
|
||||
|
|
@ -71,47 +86,50 @@ impl Window {
|
|||
&evlp.env,
|
||||
bg_surface.clone(),
|
||||
(width, height),
|
||||
move |event| match event {
|
||||
WEvent::Configure { new_size, states } => {
|
||||
let mut store = window_store.lock().unwrap();
|
||||
let is_fullscreen = states.contains(&WState::Fullscreen);
|
||||
move |event| {
|
||||
match event {
|
||||
WEvent::Configure { new_size, states } => {
|
||||
let mut store = window_store.lock().unwrap();
|
||||
let is_fullscreen = states.contains(&WState::Fullscreen);
|
||||
|
||||
for window in &mut store.windows {
|
||||
if window.surface.as_ref().equals(&my_surface.as_ref()) {
|
||||
window.newsize = new_size;
|
||||
*(window.need_refresh.lock().unwrap()) = true;
|
||||
*(window.fullscreen.lock().unwrap()) = is_fullscreen;
|
||||
*(window.need_frame_refresh.lock().unwrap()) = true;
|
||||
if !window.configured {
|
||||
// this is our first configure event, display ourselves !
|
||||
window.configured = true;
|
||||
my_bg_surface.attach(Some(&buffer), 0, 0);
|
||||
my_bg_surface.commit();
|
||||
for window in &mut store.windows {
|
||||
if window.surface.as_ref().equals(&my_surface.as_ref()) {
|
||||
window.newsize = new_size;
|
||||
*(window.need_refresh.lock().unwrap()) = true;
|
||||
*(window.fullscreen.lock().unwrap()) = is_fullscreen;
|
||||
*(window.need_frame_refresh.lock().unwrap()) = true;
|
||||
if !window.configured {
|
||||
// this is our first configure event, display ourselves !
|
||||
window.configured = true;
|
||||
my_bg_surface.attach(Some(&buffer), 0, 0);
|
||||
my_bg_surface.commit();
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
WEvent::Refresh => {
|
||||
let store = window_store.lock().unwrap();
|
||||
for window in &store.windows {
|
||||
if window.surface.as_ref().equals(&my_surface.as_ref()) {
|
||||
*(window.need_frame_refresh.lock().unwrap()) = true;
|
||||
return;
|
||||
},
|
||||
WEvent::Refresh => {
|
||||
let store = window_store.lock().unwrap();
|
||||
for window in &store.windows {
|
||||
if window.surface.as_ref().equals(&my_surface.as_ref()) {
|
||||
*(window.need_frame_refresh.lock().unwrap()) = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
WEvent::Close => {
|
||||
let mut store = window_store.lock().unwrap();
|
||||
for window in &mut store.windows {
|
||||
if window.surface.as_ref().equals(&my_surface.as_ref()) {
|
||||
window.closed = true;
|
||||
return;
|
||||
},
|
||||
WEvent::Close => {
|
||||
let mut store = window_store.lock().unwrap();
|
||||
for window in &mut store.windows {
|
||||
if window.surface.as_ref().equals(&my_surface.as_ref()) {
|
||||
window.closed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
if let Some(app_id) = pl_attribs.app_id {
|
||||
frame.set_app_id(app_id);
|
||||
|
|
@ -166,11 +184,11 @@ impl Window {
|
|||
Ok(Window {
|
||||
display: evlp.display.clone(),
|
||||
_bg_surface: bg_surface,
|
||||
user_surface: user_surface,
|
||||
user_surface,
|
||||
_user_subsurface: user_subsurface,
|
||||
frame: frame,
|
||||
frame,
|
||||
outputs: evlp.env.outputs.clone(),
|
||||
size: size,
|
||||
size,
|
||||
kill_switch: (kill_switch, evlp.cleanup_needed.clone()),
|
||||
need_frame_refresh,
|
||||
need_refresh,
|
||||
|
|
@ -231,12 +249,18 @@ impl Window {
|
|||
|
||||
#[inline]
|
||||
pub fn set_min_inner_size(&self, dimensions: Option<LogicalSize>) {
|
||||
self.frame.lock().unwrap().set_min_size(dimensions.map(Into::into));
|
||||
self.frame
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_min_size(dimensions.map(Into::into));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_max_inner_size(&self, dimensions: Option<LogicalSize>) {
|
||||
self.frame.lock().unwrap().set_max_size(dimensions.map(Into::into));
|
||||
self.frame
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_max_size(dimensions.map(Into::into));
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -412,7 +436,16 @@ impl WindowStore {
|
|||
|
||||
pub fn for_each<F>(&mut self, mut f: F)
|
||||
where
|
||||
F: FnMut(Option<(u32, u32)>, &mut (u32, u32), Option<i32>, bool, bool, bool, WindowId, Option<&mut SWindow<ConceptFrame>>),
|
||||
F: FnMut(
|
||||
Option<(u32, u32)>,
|
||||
&mut (u32, u32),
|
||||
Option<i32>,
|
||||
bool,
|
||||
bool,
|
||||
bool,
|
||||
WindowId,
|
||||
Option<&mut SWindow<ConceptFrame>>,
|
||||
),
|
||||
{
|
||||
for window in &mut self.windows {
|
||||
let opt_arc = window.frame.upgrade();
|
||||
|
|
@ -435,4 +468,3 @@ impl WindowStore {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
use std::io;
|
||||
use std::sync::Arc;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::str::Utf8Error;
|
||||
use std::os::raw::*;
|
||||
use std::{
|
||||
io,
|
||||
os::raw::*,
|
||||
path::{Path, PathBuf},
|
||||
str::Utf8Error,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use percent_encoding::percent_decode;
|
||||
|
||||
|
|
@ -127,13 +129,15 @@ impl Dnd {
|
|||
DndState::Accepted => (1, self.atoms.action_private as c_long),
|
||||
DndState::Rejected => (0, self.atoms.none as c_long),
|
||||
};
|
||||
self.xconn.send_client_msg(
|
||||
target_window,
|
||||
target_window,
|
||||
self.atoms.status,
|
||||
None,
|
||||
[this_window as c_long, accepted, 0, 0, action],
|
||||
).flush()
|
||||
self.xconn
|
||||
.send_client_msg(
|
||||
target_window,
|
||||
target_window,
|
||||
self.atoms.status,
|
||||
None,
|
||||
[this_window as c_long, accepted, 0, 0, action],
|
||||
)
|
||||
.flush()
|
||||
}
|
||||
|
||||
pub unsafe fn send_finished(
|
||||
|
|
@ -146,24 +150,23 @@ impl Dnd {
|
|||
DndState::Accepted => (1, self.atoms.action_private as c_long),
|
||||
DndState::Rejected => (0, self.atoms.none as c_long),
|
||||
};
|
||||
self.xconn.send_client_msg(
|
||||
target_window,
|
||||
target_window,
|
||||
self.atoms.finished,
|
||||
None,
|
||||
[this_window as c_long, accepted, action, 0, 0],
|
||||
).flush()
|
||||
self.xconn
|
||||
.send_client_msg(
|
||||
target_window,
|
||||
target_window,
|
||||
self.atoms.finished,
|
||||
None,
|
||||
[this_window as c_long, accepted, action, 0, 0],
|
||||
)
|
||||
.flush()
|
||||
}
|
||||
|
||||
pub unsafe fn get_type_list(
|
||||
&self,
|
||||
source_window: c_ulong,
|
||||
) -> Result<Vec<ffi::Atom>, util::GetPropertyError> {
|
||||
self.xconn.get_property(
|
||||
source_window,
|
||||
self.atoms.type_list,
|
||||
ffi::XA_ATOM,
|
||||
)
|
||||
self.xconn
|
||||
.get_property(source_window, self.atoms.type_list, ffi::XA_ATOM)
|
||||
}
|
||||
|
||||
pub unsafe fn convert_selection(&self, window: c_ulong, time: c_ulong) {
|
||||
|
|
@ -181,11 +184,8 @@ impl Dnd {
|
|||
&self,
|
||||
window: c_ulong,
|
||||
) -> Result<Vec<c_uchar>, util::GetPropertyError> {
|
||||
self.xconn.get_property(
|
||||
window,
|
||||
self.atoms.selection,
|
||||
self.atoms.uri_list,
|
||||
)
|
||||
self.xconn
|
||||
.get_property(window, self.atoms.selection, self.atoms.uri_list)
|
||||
}
|
||||
|
||||
pub fn parse_data(&self, data: &mut Vec<c_uchar>) -> Result<Vec<PathBuf>, DndDataParseError> {
|
||||
|
|
|
|||
|
|
@ -1,20 +1,18 @@
|
|||
use std::cell::RefCell;
|
||||
use std::collections::HashMap;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
use std::slice;
|
||||
use std::{cell::RefCell, collections::HashMap, ptr, rc::Rc, slice};
|
||||
|
||||
use libc::{c_int, c_uint, c_ulong, c_char, c_long};
|
||||
use libc::{c_char, c_int, c_long, c_uint, c_ulong};
|
||||
|
||||
use super::{
|
||||
mkdid, mkwid, get_xtarget, DeviceId, WindowId, Device, ImeReceiver, XExtension,
|
||||
monitor, ffi, UnownedWindow, ScrollOrientation, GenericEventCookie,
|
||||
events, util, DndState, Dnd, DeviceInfo
|
||||
events, ffi, get_xtarget, mkdid, mkwid, monitor, util, Device, DeviceId, DeviceInfo, Dnd,
|
||||
DndState, GenericEventCookie, ImeReceiver, ScrollOrientation, UnownedWindow, WindowId,
|
||||
XExtension,
|
||||
};
|
||||
|
||||
use crate::event_loop::EventLoopWindowTarget as RootELW;
|
||||
use crate::event::{DeviceEvent, Event, KeyboardInput, ModifiersState, WindowEvent};
|
||||
use crate::dpi::{LogicalPosition,LogicalSize};
|
||||
use crate::{
|
||||
dpi::{LogicalPosition, LogicalSize},
|
||||
event::{DeviceEvent, Event, KeyboardInput, ModifiersState, WindowEvent},
|
||||
event_loop::EventLoopWindowTarget as RootELW,
|
||||
};
|
||||
|
||||
pub(super) struct EventProcessor<T: 'static> {
|
||||
pub(super) dnd: Dnd,
|
||||
|
|
@ -22,7 +20,7 @@ pub(super) struct EventProcessor<T: 'static> {
|
|||
pub(super) randr_event_offset: c_int,
|
||||
pub(super) devices: RefCell<HashMap<DeviceId, Device>>,
|
||||
pub(super) xi2ext: XExtension,
|
||||
pub(super) target: Rc<RootELW<T>>
|
||||
pub(super) target: Rc<RootELW<T>>,
|
||||
}
|
||||
|
||||
impl<T: 'static> EventProcessor<T> {
|
||||
|
|
@ -37,12 +35,14 @@ impl<T: 'static> EventProcessor<T> {
|
|||
}
|
||||
|
||||
fn with_window<F, Ret>(&self, window_id: ffi::Window, callback: F) -> Option<Ret>
|
||||
where F: Fn(&UnownedWindow) -> Ret
|
||||
where
|
||||
F: Fn(&UnownedWindow) -> Ret,
|
||||
{
|
||||
let mut deleted = false;
|
||||
let window_id = WindowId(window_id);
|
||||
let wt = get_xtarget(&self.target);
|
||||
let result = wt.windows
|
||||
let result = wt
|
||||
.windows
|
||||
.borrow()
|
||||
.get(&window_id)
|
||||
.and_then(|window| {
|
||||
|
|
@ -62,7 +62,7 @@ impl<T: 'static> EventProcessor<T> {
|
|||
self.with_window(window_id, |_| ()).is_some()
|
||||
}
|
||||
|
||||
pub(super) unsafe fn poll_one_event(&mut self, event_ptr : *mut ffi::XEvent) -> bool {
|
||||
pub(super) unsafe fn poll_one_event(&mut self, event_ptr: *mut ffi::XEvent) -> bool {
|
||||
let wt = get_xtarget(&self.target);
|
||||
// This function is used to poll and remove a single event
|
||||
// from the Xlib event queue in a non-blocking, atomic way.
|
||||
|
|
@ -73,7 +73,8 @@ impl<T: 'static> EventProcessor<T> {
|
|||
unsafe extern "C" fn predicate(
|
||||
_display: *mut ffi::Display,
|
||||
_event: *mut ffi::XEvent,
|
||||
_arg : *mut c_char) -> c_int {
|
||||
_arg: *mut c_char,
|
||||
) -> c_int {
|
||||
// This predicate always returns "true" (1) to accept all events
|
||||
1
|
||||
}
|
||||
|
|
@ -82,32 +83,42 @@ impl<T: 'static> EventProcessor<T> {
|
|||
wt.xconn.display,
|
||||
event_ptr,
|
||||
Some(predicate),
|
||||
std::ptr::null_mut());
|
||||
std::ptr::null_mut(),
|
||||
);
|
||||
|
||||
result != 0
|
||||
}
|
||||
|
||||
pub(super) fn process_event<F>(&mut self, xev: &mut ffi::XEvent, mut callback: F)
|
||||
where F: FnMut(Event<T>)
|
||||
where
|
||||
F: FnMut(Event<T>),
|
||||
{
|
||||
let wt = get_xtarget(&self.target);
|
||||
// XFilterEvent tells us when an event has been discarded by the input method.
|
||||
// Specifically, this involves all of the KeyPress events in compose/pre-edit sequences,
|
||||
// along with an extra copy of the KeyRelease events. This also prevents backspace and
|
||||
// arrow keys from being detected twice.
|
||||
if ffi::True == unsafe { (wt.xconn.xlib.XFilterEvent)(
|
||||
xev,
|
||||
{ let xev: &ffi::XAnyEvent = xev.as_ref(); xev.window }
|
||||
) } {
|
||||
if ffi::True
|
||||
== unsafe {
|
||||
(wt.xconn.xlib.XFilterEvent)(xev, {
|
||||
let xev: &ffi::XAnyEvent = xev.as_ref();
|
||||
xev.window
|
||||
})
|
||||
}
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let event_type = xev.get_type();
|
||||
match event_type {
|
||||
ffi::MappingNotify => {
|
||||
unsafe { (wt.xconn.xlib.XRefreshKeyboardMapping)(xev.as_mut()); }
|
||||
wt.xconn.check_errors().expect("Failed to call XRefreshKeyboardMapping");
|
||||
}
|
||||
unsafe {
|
||||
(wt.xconn.xlib.XRefreshKeyboardMapping)(xev.as_mut());
|
||||
}
|
||||
wt.xconn
|
||||
.check_errors()
|
||||
.expect("Failed to call XRefreshKeyboardMapping");
|
||||
},
|
||||
|
||||
ffi::ClientMessage => {
|
||||
let client_msg: &ffi::XClientMessageEvent = xev.as_ref();
|
||||
|
|
@ -116,7 +127,10 @@ impl<T: 'static> EventProcessor<T> {
|
|||
let window_id = mkwid(window);
|
||||
|
||||
if client_msg.data.get_long(0) as ffi::Atom == wt.wm_delete_window {
|
||||
callback(Event::WindowEvent { window_id, event: WindowEvent::CloseRequested });
|
||||
callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::CloseRequested,
|
||||
});
|
||||
} else if client_msg.message_type == self.dnd.atoms.enter {
|
||||
let source_window = client_msg.data.get_long(0) as c_ulong;
|
||||
let flags = client_msg.data.get_long(1);
|
||||
|
|
@ -127,10 +141,11 @@ impl<T: 'static> EventProcessor<T> {
|
|||
let type_list = vec![
|
||||
client_msg.data.get_long(2) as c_ulong,
|
||||
client_msg.data.get_long(3) as c_ulong,
|
||||
client_msg.data.get_long(4) as c_ulong
|
||||
client_msg.data.get_long(4) as c_ulong,
|
||||
];
|
||||
self.dnd.type_list = Some(type_list);
|
||||
} else if let Ok(more_types) = unsafe { self.dnd.get_type_list(source_window) } {
|
||||
} else if let Ok(more_types) = unsafe { self.dnd.get_type_list(source_window) }
|
||||
{
|
||||
self.dnd.type_list = Some(more_types);
|
||||
}
|
||||
} else if client_msg.message_type == self.dnd.atoms.position {
|
||||
|
|
@ -178,18 +193,21 @@ impl<T: 'static> EventProcessor<T> {
|
|||
// This results in the `SelectionNotify` event below
|
||||
self.dnd.convert_selection(window, time);
|
||||
}
|
||||
self.dnd.send_status(window, source_window, DndState::Accepted)
|
||||
self.dnd
|
||||
.send_status(window, source_window, DndState::Accepted)
|
||||
.expect("Failed to send `XdndStatus` message.");
|
||||
}
|
||||
} else {
|
||||
unsafe {
|
||||
self.dnd.send_status(window, source_window, DndState::Rejected)
|
||||
self.dnd
|
||||
.send_status(window, source_window, DndState::Rejected)
|
||||
.expect("Failed to send `XdndStatus` message.");
|
||||
}
|
||||
self.dnd.reset();
|
||||
}
|
||||
} else if client_msg.message_type == self.dnd.atoms.drop {
|
||||
let (source_window, state) = if let Some(source_window) = self.dnd.source_window {
|
||||
let (source_window, state) = if let Some(source_window) = self.dnd.source_window
|
||||
{
|
||||
if let Some(Ok(ref path_list)) = self.dnd.result {
|
||||
for path in path_list {
|
||||
callback(Event::WindowEvent {
|
||||
|
|
@ -206,7 +224,8 @@ impl<T: 'static> EventProcessor<T> {
|
|||
(source_window, DndState::Rejected)
|
||||
};
|
||||
unsafe {
|
||||
self.dnd.send_finished(window, source_window, state)
|
||||
self.dnd
|
||||
.send_finished(window, source_window, state)
|
||||
.expect("Failed to send `XdndFinished` message.");
|
||||
}
|
||||
self.dnd.reset();
|
||||
|
|
@ -217,7 +236,7 @@ impl<T: 'static> EventProcessor<T> {
|
|||
event: WindowEvent::HoveredFileCancelled,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ffi::SelectionNotify => {
|
||||
let xsel: &ffi::XSelectionEvent = xev.as_ref();
|
||||
|
|
@ -244,7 +263,7 @@ impl<T: 'static> EventProcessor<T> {
|
|||
|
||||
self.dnd.result = result;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ffi::ConfigureNotify => {
|
||||
#[derive(Debug, Default)]
|
||||
|
|
@ -274,15 +293,22 @@ impl<T: 'static> EventProcessor<T> {
|
|||
let mut shared_state_lock = window.shared_state.lock();
|
||||
|
||||
let (mut resized, moved) = {
|
||||
let resized = util::maybe_change(&mut shared_state_lock.size, new_inner_size);
|
||||
let resized =
|
||||
util::maybe_change(&mut shared_state_lock.size, new_inner_size);
|
||||
let moved = if is_synthetic {
|
||||
util::maybe_change(&mut shared_state_lock.inner_position, new_inner_position)
|
||||
util::maybe_change(
|
||||
&mut shared_state_lock.inner_position,
|
||||
new_inner_position,
|
||||
)
|
||||
} else {
|
||||
// Detect when frame extents change.
|
||||
// Since this isn't synthetic, as per the notes above, this position is relative to the
|
||||
// parent window.
|
||||
let rel_parent = new_inner_position;
|
||||
if util::maybe_change(&mut shared_state_lock.inner_position_rel_parent, rel_parent) {
|
||||
if util::maybe_change(
|
||||
&mut shared_state_lock.inner_position_rel_parent,
|
||||
rel_parent,
|
||||
) {
|
||||
// This ensures we process the next `Moved`.
|
||||
shared_state_lock.inner_position = None;
|
||||
// Extra insurance against stale frame extents.
|
||||
|
|
@ -297,18 +323,22 @@ impl<T: 'static> EventProcessor<T> {
|
|||
|
||||
let new_outer_position = if moved || shared_state_lock.position.is_none() {
|
||||
// We need to convert client area position to window position.
|
||||
let frame_extents = shared_state_lock.frame_extents
|
||||
let frame_extents = shared_state_lock
|
||||
.frame_extents
|
||||
.as_ref()
|
||||
.cloned()
|
||||
.unwrap_or_else(|| {
|
||||
let frame_extents = wt.xconn.get_frame_extents_heuristic(xwindow, wt.root);
|
||||
let frame_extents =
|
||||
wt.xconn.get_frame_extents_heuristic(xwindow, wt.root);
|
||||
shared_state_lock.frame_extents = Some(frame_extents.clone());
|
||||
frame_extents
|
||||
});
|
||||
let outer = frame_extents.inner_pos_to_outer(new_inner_position.0, new_inner_position.1);
|
||||
let outer = frame_extents
|
||||
.inner_pos_to_outer(new_inner_position.0, new_inner_position.1);
|
||||
shared_state_lock.position = Some(outer);
|
||||
if moved {
|
||||
let logical_position = LogicalPosition::from_physical(outer, monitor.hidpi_factor);
|
||||
let logical_position =
|
||||
LogicalPosition::from_physical(outer, monitor.hidpi_factor);
|
||||
events.moved = Some(WindowEvent::Moved(logical_position));
|
||||
}
|
||||
outer
|
||||
|
|
@ -319,12 +349,13 @@ impl<T: 'static> EventProcessor<T> {
|
|||
if is_synthetic {
|
||||
// If we don't use the existing adjusted value when available, then the user can screw up the
|
||||
// resizing by dragging across monitors *without* dropping the window.
|
||||
let (width, height) = shared_state_lock.dpi_adjusted
|
||||
let (width, height) = shared_state_lock
|
||||
.dpi_adjusted
|
||||
.unwrap_or_else(|| (xev.width as f64, xev.height as f64));
|
||||
let last_hidpi_factor = shared_state_lock.guessed_dpi
|
||||
.take()
|
||||
.unwrap_or_else(|| {
|
||||
shared_state_lock.last_monitor
|
||||
let last_hidpi_factor =
|
||||
shared_state_lock.guessed_dpi.take().unwrap_or_else(|| {
|
||||
shared_state_lock
|
||||
.last_monitor
|
||||
.as_ref()
|
||||
.map(|last_monitor| last_monitor.hidpi_factor)
|
||||
.unwrap_or(1.0)
|
||||
|
|
@ -337,7 +368,8 @@ impl<T: 'static> EventProcessor<T> {
|
|||
new_hidpi_factor
|
||||
};
|
||||
if last_hidpi_factor != new_hidpi_factor {
|
||||
events.dpi_changed = Some(WindowEvent::HiDpiFactorChanged(new_hidpi_factor));
|
||||
events.dpi_changed =
|
||||
Some(WindowEvent::HiDpiFactorChanged(new_hidpi_factor));
|
||||
let (new_width, new_height, flusher) = window.adjust_for_dpi(
|
||||
last_hidpi_factor,
|
||||
new_hidpi_factor,
|
||||
|
|
@ -357,7 +389,10 @@ impl<T: 'static> EventProcessor<T> {
|
|||
// 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.
|
||||
if let Some(adjusted_size) = shared_state_lock.dpi_adjusted {
|
||||
let rounded_size = (adjusted_size.0.round() as u32, adjusted_size.1.round() as u32);
|
||||
let rounded_size = (
|
||||
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.
|
||||
shared_state_lock.dpi_adjusted = None;
|
||||
|
|
@ -374,7 +409,8 @@ impl<T: 'static> EventProcessor<T> {
|
|||
}
|
||||
|
||||
if resized {
|
||||
let logical_size = LogicalSize::from_physical(new_inner_size, monitor.hidpi_factor);
|
||||
let logical_size =
|
||||
LogicalSize::from_physical(new_inner_size, monitor.hidpi_factor);
|
||||
events.resized = Some(WindowEvent::Resized(logical_size));
|
||||
}
|
||||
|
||||
|
|
@ -393,7 +429,7 @@ impl<T: 'static> EventProcessor<T> {
|
|||
callback(Event::WindowEvent { window_id, event });
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ffi::ReparentNotify => {
|
||||
let xev: &ffi::XReparentEvent = xev.as_ref();
|
||||
|
|
@ -408,7 +444,7 @@ impl<T: 'static> EventProcessor<T> {
|
|||
self.with_window(xev.window, |window| {
|
||||
window.invalidate_cached_frame_extents();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
ffi::DestroyNotify => {
|
||||
let xev: &ffi::XDestroyWindowEvent = xev.as_ref();
|
||||
|
|
@ -427,8 +463,11 @@ impl<T: 'static> EventProcessor<T> {
|
|||
.remove_context(window)
|
||||
.expect("Failed to destroy input context");
|
||||
|
||||
callback(Event::WindowEvent { window_id, event: WindowEvent::Destroyed });
|
||||
}
|
||||
callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::Destroyed,
|
||||
});
|
||||
},
|
||||
|
||||
ffi::Expose => {
|
||||
let xev: &ffi::XExposeEvent = xev.as_ref();
|
||||
|
|
@ -436,8 +475,11 @@ impl<T: 'static> EventProcessor<T> {
|
|||
let window = xev.window;
|
||||
let window_id = mkwid(window);
|
||||
|
||||
callback(Event::WindowEvent { window_id, event: WindowEvent::RedrawRequested });
|
||||
}
|
||||
callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: WindowEvent::RedrawRequested,
|
||||
});
|
||||
},
|
||||
|
||||
ffi::KeyPress | ffi::KeyRelease => {
|
||||
use crate::event::ElementState::{Pressed, Released};
|
||||
|
|
@ -493,7 +535,7 @@ impl<T: 'static> EventProcessor<T> {
|
|||
virtual_keycode,
|
||||
modifiers,
|
||||
},
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -512,20 +554,29 @@ impl<T: 'static> EventProcessor<T> {
|
|||
callback(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ffi::GenericEvent => {
|
||||
let guard = if let Some(e) = GenericEventCookie::from_event(&wt.xconn, *xev) { e } else { return };
|
||||
let guard = if let Some(e) = GenericEventCookie::from_event(&wt.xconn, *xev) {
|
||||
e
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
let xev = &guard.cookie;
|
||||
if self.xi2ext.opcode != xev.extension {
|
||||
return;
|
||||
}
|
||||
|
||||
use crate::event::WindowEvent::{Focused, CursorEntered, MouseInput, CursorLeft, CursorMoved, MouseWheel, AxisMotion};
|
||||
use crate::event::ElementState::{Pressed, Released};
|
||||
use crate::event::MouseButton::{Left, Right, Middle, Other};
|
||||
use crate::event::MouseScrollDelta::LineDelta;
|
||||
use crate::event::{Touch, TouchPhase};
|
||||
use crate::event::{
|
||||
ElementState::{Pressed, Released},
|
||||
MouseButton::{Left, Middle, Other, Right},
|
||||
MouseScrollDelta::LineDelta,
|
||||
Touch, TouchPhase,
|
||||
WindowEvent::{
|
||||
AxisMotion, CursorEntered, CursorLeft, CursorMoved, Focused, MouseInput,
|
||||
MouseWheel,
|
||||
},
|
||||
};
|
||||
|
||||
match xev.evtype {
|
||||
ffi::XI_ButtonPress | ffi::XI_ButtonRelease => {
|
||||
|
|
@ -545,66 +596,76 @@ impl<T: 'static> EventProcessor<T> {
|
|||
Released
|
||||
};
|
||||
match xev.detail as u32 {
|
||||
ffi::Button1 => callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: Left,
|
||||
modifiers,
|
||||
},
|
||||
}),
|
||||
ffi::Button2 => callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: Middle,
|
||||
modifiers,
|
||||
},
|
||||
}),
|
||||
ffi::Button3 => callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: Right,
|
||||
modifiers,
|
||||
},
|
||||
}),
|
||||
ffi::Button1 => {
|
||||
callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: Left,
|
||||
modifiers,
|
||||
},
|
||||
})
|
||||
},
|
||||
ffi::Button2 => {
|
||||
callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: Middle,
|
||||
modifiers,
|
||||
},
|
||||
})
|
||||
},
|
||||
ffi::Button3 => {
|
||||
callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: Right,
|
||||
modifiers,
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
// Suppress emulated scroll wheel clicks, since we handle the real motion events for those.
|
||||
// In practice, even clicky scroll wheels appear to be reported by evdev (and XInput2 in
|
||||
// turn) as axis motion, so we don't otherwise special-case these button presses.
|
||||
4 | 5 | 6 | 7 => if xev.flags & ffi::XIPointerEmulated == 0 {
|
||||
callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: MouseWheel {
|
||||
device_id,
|
||||
delta: match xev.detail {
|
||||
4 => LineDelta(0.0, 1.0),
|
||||
5 => LineDelta(0.0, -1.0),
|
||||
6 => LineDelta(-1.0, 0.0),
|
||||
7 => LineDelta(1.0, 0.0),
|
||||
_ => unreachable!(),
|
||||
4 | 5 | 6 | 7 => {
|
||||
if xev.flags & ffi::XIPointerEmulated == 0 {
|
||||
callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: MouseWheel {
|
||||
device_id,
|
||||
delta: match xev.detail {
|
||||
4 => LineDelta(0.0, 1.0),
|
||||
5 => LineDelta(0.0, -1.0),
|
||||
6 => LineDelta(-1.0, 0.0),
|
||||
7 => LineDelta(1.0, 0.0),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
phase: TouchPhase::Moved,
|
||||
modifiers,
|
||||
},
|
||||
phase: TouchPhase::Moved,
|
||||
modifiers,
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
x => callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: Other(x as u8),
|
||||
modifiers,
|
||||
},
|
||||
}),
|
||||
x => {
|
||||
callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: MouseInput {
|
||||
device_id,
|
||||
state,
|
||||
button: Other(x as u8),
|
||||
modifiers,
|
||||
},
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
ffi::XI_Motion => {
|
||||
let xev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) };
|
||||
let device_id = mkdid(xev.deviceid);
|
||||
|
|
@ -618,9 +679,8 @@ impl<T: 'static> EventProcessor<T> {
|
|||
util::maybe_change(&mut shared_state_lock.cursor_pos, new_cursor_pos)
|
||||
});
|
||||
if cursor_moved == Some(true) {
|
||||
let dpi_factor = self.with_window(xev.event, |window| {
|
||||
window.hidpi_factor()
|
||||
});
|
||||
let dpi_factor =
|
||||
self.with_window(xev.event, |window| window.hidpi_factor());
|
||||
if let Some(dpi_factor) = dpi_factor {
|
||||
let position = LogicalPosition::from_physical(
|
||||
(xev.event_x as f64, xev.event_y as f64),
|
||||
|
|
@ -644,7 +704,12 @@ impl<T: 'static> EventProcessor<T> {
|
|||
// More gymnastics, for self.devices
|
||||
let mut events = Vec::new();
|
||||
{
|
||||
let mask = unsafe { slice::from_raw_parts(xev.valuators.mask, xev.valuators.mask_len as usize) };
|
||||
let mask = unsafe {
|
||||
slice::from_raw_parts(
|
||||
xev.valuators.mask,
|
||||
xev.valuators.mask_len as usize,
|
||||
)
|
||||
};
|
||||
let mut devices = self.devices.borrow_mut();
|
||||
let physical_device = match devices.get_mut(&DeviceId(xev.sourceid)) {
|
||||
Some(device) => device,
|
||||
|
|
@ -652,10 +717,14 @@ impl<T: 'static> EventProcessor<T> {
|
|||
};
|
||||
|
||||
let mut value = xev.valuators.values;
|
||||
for i in 0..xev.valuators.mask_len*8 {
|
||||
for i in 0..xev.valuators.mask_len * 8 {
|
||||
if ffi::XIMaskIsSet(mask, i) {
|
||||
let x = unsafe { *value };
|
||||
if let Some(&mut (_, ref mut info)) = physical_device.scroll_axes.iter_mut().find(|&&mut (axis, _)| axis == i) {
|
||||
if let Some(&mut (_, ref mut info)) = physical_device
|
||||
.scroll_axes
|
||||
.iter_mut()
|
||||
.find(|&&mut (axis, _)| axis == i)
|
||||
{
|
||||
let delta = (x - info.position) / info.increment;
|
||||
info.position = x;
|
||||
events.push(Event::WindowEvent {
|
||||
|
|
@ -663,9 +732,13 @@ impl<T: 'static> EventProcessor<T> {
|
|||
event: MouseWheel {
|
||||
device_id,
|
||||
delta: match info.orientation {
|
||||
ScrollOrientation::Horizontal => LineDelta(delta as f32, 0.0),
|
||||
ScrollOrientation::Horizontal => {
|
||||
LineDelta(delta as f32, 0.0)
|
||||
},
|
||||
// X11 vertical scroll coordinates are opposite to winit's
|
||||
ScrollOrientation::Vertical => LineDelta(0.0, -delta as f32),
|
||||
ScrollOrientation::Vertical => {
|
||||
LineDelta(0.0, -delta as f32)
|
||||
},
|
||||
},
|
||||
phase: TouchPhase::Moved,
|
||||
modifiers,
|
||||
|
|
@ -688,7 +761,7 @@ impl<T: 'static> EventProcessor<T> {
|
|||
for event in events {
|
||||
callback(event);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ffi::XI_Enter => {
|
||||
let xev: &ffi::XIEnterEvent = unsafe { &*(xev.data as *const _) };
|
||||
|
|
@ -704,7 +777,8 @@ impl<T: 'static> EventProcessor<T> {
|
|||
// presumably some other WMs. On those, `XI_Enter` doesn't include
|
||||
// the physical device ID, so both `sourceid` and `deviceid` are
|
||||
// the virtual device.
|
||||
|| device_info.attachment == xev.sourceid {
|
||||
|| device_info.attachment == xev.sourceid
|
||||
{
|
||||
let device_id = DeviceId(device_info.deviceid);
|
||||
if let Some(device) = devices.get_mut(&device_id) {
|
||||
device.reset_scroll_position(device_info);
|
||||
|
|
@ -717,9 +791,9 @@ impl<T: 'static> EventProcessor<T> {
|
|||
event: CursorEntered { device_id },
|
||||
});
|
||||
|
||||
if let Some(dpi_factor) = self.with_window(xev.event, |window| {
|
||||
window.hidpi_factor()
|
||||
}) {
|
||||
if let Some(dpi_factor) =
|
||||
self.with_window(xev.event, |window| window.hidpi_factor())
|
||||
{
|
||||
let position = LogicalPosition::from_physical(
|
||||
(xev.event_x as f64, xev.event_y as f64),
|
||||
dpi_factor,
|
||||
|
|
@ -732,7 +806,8 @@ impl<T: 'static> EventProcessor<T> {
|
|||
// This needs to only be done after confirming the window still exists,
|
||||
// since otherwise we risk getting a `BadWindow` error if the window was
|
||||
// dropped with queued events.
|
||||
let modifiers = wt.xconn
|
||||
let modifiers = wt
|
||||
.xconn
|
||||
.query_pointer(xev.event, xev.deviceid)
|
||||
.expect("Failed to query pointer device")
|
||||
.get_modifier_state();
|
||||
|
|
@ -746,7 +821,7 @@ impl<T: 'static> EventProcessor<T> {
|
|||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
ffi::XI_Leave => {
|
||||
let xev: &ffi::XILeaveEvent = unsafe { &*(xev.data as *const _) };
|
||||
|
||||
|
|
@ -756,19 +831,20 @@ impl<T: 'static> EventProcessor<T> {
|
|||
if !window_closed {
|
||||
callback(Event::WindowEvent {
|
||||
window_id: mkwid(xev.event),
|
||||
event: CursorLeft { device_id: mkdid(xev.deviceid) },
|
||||
event: CursorLeft {
|
||||
device_id: mkdid(xev.deviceid),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
ffi::XI_FocusIn => {
|
||||
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 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);
|
||||
|
||||
wt.ime
|
||||
|
|
@ -776,11 +852,15 @@ impl<T: 'static> EventProcessor<T> {
|
|||
.focus(xev.event)
|
||||
.expect("Failed to focus input context");
|
||||
|
||||
callback(Event::WindowEvent { window_id, event: Focused(true) });
|
||||
callback(Event::WindowEvent {
|
||||
window_id,
|
||||
event: Focused(true),
|
||||
});
|
||||
|
||||
// The deviceid for this event is for a keyboard instead of a pointer,
|
||||
// so we have to do a little extra work.
|
||||
let pointer_id = self.devices
|
||||
let pointer_id = self
|
||||
.devices
|
||||
.borrow()
|
||||
.get(&DeviceId(xev.deviceid))
|
||||
.map(|device| device.attachment)
|
||||
|
|
@ -796,12 +876,14 @@ impl<T: 'static> EventProcessor<T> {
|
|||
device_id: mkdid(pointer_id),
|
||||
position,
|
||||
modifiers: ModifiersState::from(xev.mods),
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
ffi::XI_FocusOut => {
|
||||
let xev: &ffi::XIFocusOutEvent = unsafe { &*(xev.data as *const _) };
|
||||
if !self.window_exists(xev.event) { return; }
|
||||
if !self.window_exists(xev.event) {
|
||||
return;
|
||||
}
|
||||
wt.ime
|
||||
.borrow_mut()
|
||||
.unfocus(xev.event)
|
||||
|
|
@ -810,7 +892,7 @@ impl<T: 'static> EventProcessor<T> {
|
|||
window_id: mkwid(xev.event),
|
||||
event: Focused(false),
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
ffi::XI_TouchBegin | ffi::XI_TouchUpdate | ffi::XI_TouchEnd => {
|
||||
let xev: &ffi::XIDeviceEvent = unsafe { &*(xev.data as *const _) };
|
||||
|
|
@ -819,11 +901,10 @@ impl<T: 'static> EventProcessor<T> {
|
|||
ffi::XI_TouchBegin => TouchPhase::Started,
|
||||
ffi::XI_TouchUpdate => TouchPhase::Moved,
|
||||
ffi::XI_TouchEnd => TouchPhase::Ended,
|
||||
_ => unreachable!()
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let dpi_factor = self.with_window(xev.event, |window| {
|
||||
window.hidpi_factor()
|
||||
});
|
||||
let dpi_factor =
|
||||
self.with_window(xev.event, |window| window.hidpi_factor());
|
||||
if let Some(dpi_factor) = dpi_factor {
|
||||
let location = LogicalPosition::from_physical(
|
||||
(xev.event_x as f64, xev.event_y as f64),
|
||||
|
|
@ -839,31 +920,39 @@ impl<T: 'static> EventProcessor<T> {
|
|||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ffi::XI_RawButtonPress | ffi::XI_RawButtonRelease => {
|
||||
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
|
||||
if xev.flags & ffi::XIPointerEmulated == 0 {
|
||||
callback(Event::DeviceEvent { device_id: mkdid(xev.deviceid), event: DeviceEvent::Button {
|
||||
button: xev.detail as u32,
|
||||
state: match xev.evtype {
|
||||
ffi::XI_RawButtonPress => Pressed,
|
||||
ffi::XI_RawButtonRelease => Released,
|
||||
_ => unreachable!(),
|
||||
callback(Event::DeviceEvent {
|
||||
device_id: mkdid(xev.deviceid),
|
||||
event: DeviceEvent::Button {
|
||||
button: xev.detail as u32,
|
||||
state: match xev.evtype {
|
||||
ffi::XI_RawButtonPress => Pressed,
|
||||
ffi::XI_RawButtonRelease => Released,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
},
|
||||
}});
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ffi::XI_RawMotion => {
|
||||
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
|
||||
let did = mkdid(xev.deviceid);
|
||||
|
||||
let mask = unsafe { slice::from_raw_parts(xev.valuators.mask, xev.valuators.mask_len as usize) };
|
||||
let mask = unsafe {
|
||||
slice::from_raw_parts(
|
||||
xev.valuators.mask,
|
||||
xev.valuators.mask_len as usize,
|
||||
)
|
||||
};
|
||||
let mut value = xev.raw_values;
|
||||
let mut mouse_delta = (0.0, 0.0);
|
||||
let mut scroll_delta = (0.0, 0.0);
|
||||
for i in 0..xev.valuators.mask_len*8 {
|
||||
for i in 0..xev.valuators.mask_len * 8 {
|
||||
if ffi::XIMaskIsSet(mask, i) {
|
||||
let x = unsafe { *value };
|
||||
// We assume that every XInput2 device with analog axes is a pointing device emitting
|
||||
|
|
@ -875,24 +964,31 @@ impl<T: 'static> EventProcessor<T> {
|
|||
3 => scroll_delta.1 = x as f32,
|
||||
_ => {},
|
||||
}
|
||||
callback(Event::DeviceEvent { device_id: did, event: DeviceEvent::Motion {
|
||||
axis: i as u32,
|
||||
value: x,
|
||||
}});
|
||||
callback(Event::DeviceEvent {
|
||||
device_id: did,
|
||||
event: DeviceEvent::Motion {
|
||||
axis: i as u32,
|
||||
value: x,
|
||||
},
|
||||
});
|
||||
value = unsafe { value.offset(1) };
|
||||
}
|
||||
}
|
||||
if mouse_delta != (0.0, 0.0) {
|
||||
callback(Event::DeviceEvent { device_id: did, event: DeviceEvent::MouseMotion {
|
||||
delta: mouse_delta,
|
||||
}});
|
||||
callback(Event::DeviceEvent {
|
||||
device_id: did,
|
||||
event: DeviceEvent::MouseMotion { delta: mouse_delta },
|
||||
});
|
||||
}
|
||||
if scroll_delta != (0.0, 0.0) {
|
||||
callback(Event::DeviceEvent { device_id: did, event: DeviceEvent::MouseWheel {
|
||||
delta: LineDelta(scroll_delta.0, scroll_delta.1),
|
||||
}});
|
||||
callback(Event::DeviceEvent {
|
||||
device_id: did,
|
||||
event: DeviceEvent::MouseWheel {
|
||||
delta: LineDelta(scroll_delta.0, scroll_delta.1),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ffi::XI_RawKeyPress | ffi::XI_RawKeyRelease => {
|
||||
let xev: &ffi::XIRawEvent = unsafe { &*(xev.data as *const _) };
|
||||
|
|
@ -905,7 +1001,9 @@ impl<T: 'static> EventProcessor<T> {
|
|||
|
||||
let device_id = xev.sourceid;
|
||||
let keycode = xev.detail;
|
||||
if keycode < 8 { return; }
|
||||
if keycode < 8 {
|
||||
return;
|
||||
}
|
||||
let scancode = (keycode - 8) as u32;
|
||||
|
||||
let keysym = unsafe {
|
||||
|
|
@ -915,7 +1013,9 @@ impl<T: 'static> EventProcessor<T> {
|
|||
0,
|
||||
)
|
||||
};
|
||||
wt.xconn.check_errors().expect("Failed to lookup raw keysym");
|
||||
wt.xconn
|
||||
.check_errors()
|
||||
.expect("Failed to lookup raw keysym");
|
||||
|
||||
let virtual_keycode = events::keysym_to_element(keysym as c_uint);
|
||||
|
||||
|
|
@ -933,23 +1033,32 @@ impl<T: 'static> EventProcessor<T> {
|
|||
modifiers: ModifiersState::default(),
|
||||
}),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
ffi::XI_HierarchyChanged => {
|
||||
let xev: &ffi::XIHierarchyEvent = unsafe { &*(xev.data as *const _) };
|
||||
for info in unsafe { slice::from_raw_parts(xev.info, xev.num_info as usize) } {
|
||||
for info in
|
||||
unsafe { slice::from_raw_parts(xev.info, xev.num_info as usize) }
|
||||
{
|
||||
if 0 != info.flags & (ffi::XISlaveAdded | ffi::XIMasterAdded) {
|
||||
self.init_device(info.deviceid);
|
||||
callback(Event::DeviceEvent { device_id: mkdid(info.deviceid), event: DeviceEvent::Added });
|
||||
} else if 0 != info.flags & (ffi::XISlaveRemoved | ffi::XIMasterRemoved) {
|
||||
callback(Event::DeviceEvent { device_id: mkdid(info.deviceid), event: DeviceEvent::Removed });
|
||||
callback(Event::DeviceEvent {
|
||||
device_id: mkdid(info.deviceid),
|
||||
event: DeviceEvent::Added,
|
||||
});
|
||||
} else if 0 != info.flags & (ffi::XISlaveRemoved | ffi::XIMasterRemoved)
|
||||
{
|
||||
callback(Event::DeviceEvent {
|
||||
device_id: mkdid(info.deviceid),
|
||||
event: DeviceEvent::Removed,
|
||||
});
|
||||
let mut devices = self.devices.borrow_mut();
|
||||
devices.remove(&DeviceId(info.deviceid));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_ => {}
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
|
|
@ -972,10 +1081,11 @@ impl<T: 'static> EventProcessor<T> {
|
|||
callback(Event::WindowEvent {
|
||||
window_id: mkwid(window_id.0),
|
||||
event: WindowEvent::HiDpiFactorChanged(
|
||||
new_monitor.hidpi_factor
|
||||
new_monitor.hidpi_factor,
|
||||
),
|
||||
});
|
||||
let (width, height) = window.inner_size_physical();
|
||||
let (width, height) =
|
||||
window.inner_size_physical();
|
||||
let (_, _, flusher) = window.adjust_for_dpi(
|
||||
prev_monitor.hidpi_factor,
|
||||
new_monitor.hidpi_factor,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use libc;
|
||||
use super::ffi;
|
||||
use crate::event::VirtualKeyCode;
|
||||
use libc;
|
||||
|
||||
pub fn keysym_to_element(keysym: libc::c_uint) -> Option<VirtualKeyCode> {
|
||||
Some(match keysym {
|
||||
|
|
@ -1003,6 +1003,6 @@ pub fn keysym_to_element(keysym: libc::c_uint) -> Option<VirtualKeyCode> {
|
|||
ffi::XF86XK_Copy => VirtualKeyCode::Copy,
|
||||
ffi::XF86XK_Paste => VirtualKeyCode::Paste,
|
||||
ffi::XF86XK_Cut => VirtualKeyCode::Cut,
|
||||
_ => return None
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,4 @@
|
|||
pub use x11_dl::keysym::*;
|
||||
pub use x11_dl::xcursor::*;
|
||||
pub use x11_dl::xlib::*;
|
||||
pub use x11_dl::xinput::*;
|
||||
pub use x11_dl::xinput2::*;
|
||||
pub use x11_dl::xlib_xcb::*;
|
||||
pub use x11_dl::error::OpenError;
|
||||
pub use x11_dl::xrandr::*;
|
||||
pub use x11_dl::xrender::*;
|
||||
pub use x11_dl::{
|
||||
error::OpenError, keysym::*, xcursor::*, xinput::*, xinput2::*, xlib::*, xlib_xcb::*,
|
||||
xrandr::*, xrender::*,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
use std::os::raw::c_char;
|
||||
use std::{collections::HashMap, os::raw::c_char, ptr, sync::Arc};
|
||||
|
||||
use super::{ffi, XConnection, XError};
|
||||
|
||||
use super::inner::{close_im, ImeInner};
|
||||
use super::input_method::PotentialInputMethods;
|
||||
use super::context::{ImeContextCreationError, ImeContext};
|
||||
use super::{
|
||||
context::{ImeContext, ImeContextCreationError},
|
||||
inner::{close_im, ImeInner},
|
||||
input_method::PotentialInputMethods,
|
||||
};
|
||||
|
||||
pub unsafe fn xim_set_callback(
|
||||
xconn: &Arc<XConnection>,
|
||||
|
|
@ -17,12 +16,7 @@ pub unsafe fn xim_set_callback(
|
|||
) -> Result<(), XError> {
|
||||
// It's advisable to wrap variadic FFI functions in our own functions, as we want to minimize
|
||||
// access that isn't type-checked.
|
||||
(xconn.xlib.XSetIMValues)(
|
||||
xim,
|
||||
field,
|
||||
callback,
|
||||
ptr::null_mut::<()>(),
|
||||
);
|
||||
(xconn.xlib.XSetIMValues)(xim, field, callback, ptr::null_mut::<()>());
|
||||
xconn.check_errors()
|
||||
}
|
||||
|
||||
|
|
@ -107,18 +101,14 @@ unsafe fn replace_im(inner: *mut ImeInner) -> Result<(), ReplaceImError> {
|
|||
let _ = close_im(xconn, new_im.im);
|
||||
}
|
||||
result
|
||||
}.map_err(ReplaceImError::SetDestroyCallbackFailed)?;
|
||||
}
|
||||
.map_err(ReplaceImError::SetDestroyCallbackFailed)?;
|
||||
|
||||
let mut new_contexts = HashMap::new();
|
||||
for (window, old_context) in (*inner).contexts.iter() {
|
||||
let spot = old_context.as_ref().map(|old_context| old_context.ic_spot);
|
||||
let new_context = {
|
||||
let result = ImeContext::new(
|
||||
xconn,
|
||||
new_im.im,
|
||||
*window,
|
||||
spot,
|
||||
);
|
||||
let result = ImeContext::new(xconn, new_im.im, *window, spot);
|
||||
if result.is_err() {
|
||||
let _ = close_im(xconn, new_im.im);
|
||||
}
|
||||
|
|
@ -137,7 +127,7 @@ unsafe fn replace_im(inner: *mut ImeInner) -> Result<(), ReplaceImError> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub unsafe extern fn xim_instantiate_callback(
|
||||
pub unsafe extern "C" fn xim_instantiate_callback(
|
||||
_display: *mut ffi::Display,
|
||||
client_data: ffi::XPointer,
|
||||
// This field is unsupplied.
|
||||
|
|
@ -160,7 +150,7 @@ pub unsafe extern fn xim_instantiate_callback(
|
|||
// This callback is triggered when the input method is closed on the server end. When this
|
||||
// happens, XCloseIM/XDestroyIC doesn't need to be called, as the resources have already been
|
||||
// free'd (attempting to do so causes our connection to freeze).
|
||||
pub unsafe extern fn xim_destroy_callback(
|
||||
pub unsafe extern "C" fn xim_destroy_callback(
|
||||
_xim: ffi::XIM,
|
||||
client_data: ffi::XPointer,
|
||||
// This field is unsupplied.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use std::os::raw::{c_short, c_void};
|
||||
use std::{
|
||||
os::raw::{c_short, c_void},
|
||||
ptr,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use super::{ffi, util, XConnection, XError};
|
||||
|
||||
|
|
@ -22,7 +24,8 @@ unsafe fn create_pre_edit_attr<'a>(
|
|||
ic_spot,
|
||||
ptr::null_mut::<()>(),
|
||||
),
|
||||
).expect("XVaCreateNestedList returned NULL")
|
||||
)
|
||||
.expect("XVaCreateNestedList returned NULL")
|
||||
}
|
||||
|
||||
// WARNING: this struct doesn't destroy its XIC resource when dropped.
|
||||
|
|
@ -49,7 +52,9 @@ impl ImeContext {
|
|||
};
|
||||
|
||||
let ic = ic.ok_or(ImeContextCreationError::Null)?;
|
||||
xconn.check_errors().map_err(ImeContextCreationError::XError)?;
|
||||
xconn
|
||||
.check_errors()
|
||||
.map_err(ImeContextCreationError::XError)?;
|
||||
|
||||
Ok(ImeContext {
|
||||
ic,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,8 @@
|
|||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, mem, ptr, sync::Arc};
|
||||
|
||||
use super::{ffi, XConnection, XError};
|
||||
|
||||
use super::input_method::PotentialInputMethods;
|
||||
use super::context::ImeContext;
|
||||
use super::{context::ImeContext, input_method::PotentialInputMethods};
|
||||
|
||||
pub unsafe fn close_im(xconn: &Arc<XConnection>, im: ffi::XIM) -> Result<(), XError> {
|
||||
(xconn.xlib.XCloseIM)(im);
|
||||
|
|
@ -33,10 +29,7 @@ pub struct ImeInner {
|
|||
}
|
||||
|
||||
impl ImeInner {
|
||||
pub fn new(
|
||||
xconn: Arc<XConnection>,
|
||||
potential_input_methods: PotentialInputMethods,
|
||||
) -> Self {
|
||||
pub fn new(xconn: Arc<XConnection>, potential_input_methods: PotentialInputMethods) -> Self {
|
||||
ImeInner {
|
||||
xconn,
|
||||
im: ptr::null_mut(),
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
use std::env;
|
||||
use std::fmt;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
use std::os::raw::c_char;
|
||||
use std::ffi::{CStr, CString, IntoStringError};
|
||||
use std::{
|
||||
env,
|
||||
ffi::{CStr, CString, IntoStringError},
|
||||
fmt,
|
||||
os::raw::c_char,
|
||||
ptr,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use parking_lot::Mutex;
|
||||
|
||||
|
|
@ -13,10 +15,7 @@ lazy_static! {
|
|||
static ref GLOBAL_LOCK: Mutex<()> = Default::default();
|
||||
}
|
||||
|
||||
unsafe fn open_im(
|
||||
xconn: &Arc<XConnection>,
|
||||
locale_modifiers: &CStr,
|
||||
) -> Option<ffi::XIM> {
|
||||
unsafe fn open_im(xconn: &Arc<XConnection>, locale_modifiers: &CStr) -> Option<ffi::XIM> {
|
||||
let _lock = GLOBAL_LOCK.lock();
|
||||
|
||||
// XSetLocaleModifiers returns...
|
||||
|
|
@ -97,11 +96,9 @@ unsafe fn get_xim_servers(xconn: &Arc<XConnection>) -> Result<Vec<String>, GetXi
|
|||
|
||||
let root = (xconn.xlib.XDefaultRootWindow)(xconn.display);
|
||||
|
||||
let mut atoms: Vec<ffi::Atom> = xconn.get_property(
|
||||
root,
|
||||
servers_atom,
|
||||
ffi::XA_ATOM,
|
||||
).map_err(GetXimServersError::GetPropertyError)?;
|
||||
let mut atoms: Vec<ffi::Atom> = xconn
|
||||
.get_property(root, servers_atom, ffi::XA_ATOM)
|
||||
.map_err(GetXimServersError::GetPropertyError)?;
|
||||
|
||||
let mut names: Vec<*const c_char> = Vec::with_capacity(atoms.len());
|
||||
(xconn.xlib.XGetAtomNames)(
|
||||
|
|
@ -135,15 +132,12 @@ impl InputMethodName {
|
|||
pub fn from_string(string: String) -> Self {
|
||||
let c_string = CString::new(string.clone())
|
||||
.expect("String used to construct CString contained null byte");
|
||||
InputMethodName {
|
||||
c_string,
|
||||
string,
|
||||
}
|
||||
InputMethodName { c_string, string }
|
||||
}
|
||||
|
||||
pub fn from_str(string: &str) -> Self {
|
||||
let c_string = CString::new(string)
|
||||
.expect("String used to construct CString contained null byte");
|
||||
let c_string =
|
||||
CString::new(string).expect("String used to construct CString contained null byte");
|
||||
InputMethodName {
|
||||
c_string,
|
||||
string: string.to_owned(),
|
||||
|
|
|
|||
|
|
@ -1,20 +1,24 @@
|
|||
// Important: all XIM calls need to happen from the same thread!
|
||||
|
||||
mod callbacks;
|
||||
mod context;
|
||||
mod inner;
|
||||
mod input_method;
|
||||
mod context;
|
||||
mod callbacks;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::mpsc::{Receiver, Sender};
|
||||
use std::sync::{
|
||||
mpsc::{Receiver, Sender},
|
||||
Arc,
|
||||
};
|
||||
|
||||
use super::{ffi, util, XConnection, XError};
|
||||
|
||||
use self::inner::{close_im, ImeInner};
|
||||
use self::input_method::PotentialInputMethods;
|
||||
use self::context::ImeContext;
|
||||
use self::callbacks::*;
|
||||
pub use self::context::ImeContextCreationError;
|
||||
use self::{
|
||||
callbacks::*,
|
||||
context::ImeContext,
|
||||
inner::{close_im, ImeInner},
|
||||
input_method::PotentialInputMethods,
|
||||
};
|
||||
|
||||
pub type ImeReceiver = Receiver<(ffi::Window, i16, i16)>;
|
||||
pub type ImeSender = Sender<(ffi::Window, i16, i16)>;
|
||||
|
|
@ -37,10 +41,7 @@ impl Ime {
|
|||
let potential_input_methods = PotentialInputMethods::new(&xconn);
|
||||
|
||||
let (mut inner, client_data) = {
|
||||
let mut inner = Box::new(ImeInner::new(
|
||||
xconn,
|
||||
potential_input_methods,
|
||||
));
|
||||
let mut inner = Box::new(ImeInner::new(xconn, potential_input_methods));
|
||||
let inner_ptr = Box::into_raw(inner);
|
||||
let client_data = inner_ptr as _;
|
||||
let destroy_callback = ffi::XIMCallback {
|
||||
|
|
@ -54,9 +55,12 @@ impl Ime {
|
|||
|
||||
let xconn = Arc::clone(&inner.xconn);
|
||||
|
||||
let input_method = inner.potential_input_methods.open_im(&xconn, Some(&|| {
|
||||
let _ = unsafe { set_instantiate_callback(&xconn, client_data) };
|
||||
}));
|
||||
let input_method = inner.potential_input_methods.open_im(
|
||||
&xconn,
|
||||
Some(&|| {
|
||||
let _ = unsafe { set_instantiate_callback(&xconn, client_data) };
|
||||
}),
|
||||
);
|
||||
|
||||
let is_fallback = input_method.is_fallback();
|
||||
if let Some(input_method) = input_method.ok() {
|
||||
|
|
@ -84,19 +88,12 @@ impl Ime {
|
|||
// Ok(_) indicates that nothing went wrong internally
|
||||
// Ok(true) indicates that the action was actually performed
|
||||
// Ok(false) indicates that the action is not presently applicable
|
||||
pub fn create_context(&mut self, window: ffi::Window)
|
||||
-> Result<bool, ImeContextCreationError>
|
||||
{
|
||||
pub fn create_context(&mut self, window: ffi::Window) -> Result<bool, ImeContextCreationError> {
|
||||
let context = if self.is_destroyed() {
|
||||
// Create empty entry in map, so that when IME is rebuilt, this window has a context.
|
||||
None
|
||||
} else {
|
||||
Some(unsafe { ImeContext::new(
|
||||
&self.inner.xconn,
|
||||
self.inner.im,
|
||||
window,
|
||||
None,
|
||||
) }?)
|
||||
Some(unsafe { ImeContext::new(&self.inner.xconn, self.inner.im, window, None) }?)
|
||||
};
|
||||
self.inner.contexts.insert(window, context);
|
||||
Ok(!self.is_destroyed())
|
||||
|
|
|
|||
|
|
@ -1,39 +1,47 @@
|
|||
#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
|
||||
|
||||
pub mod ffi;
|
||||
mod dnd;
|
||||
mod event_processor;
|
||||
mod events;
|
||||
pub mod ffi;
|
||||
mod ime;
|
||||
mod monitor;
|
||||
pub mod util;
|
||||
mod window;
|
||||
mod xdisplay;
|
||||
mod dnd;
|
||||
mod ime;
|
||||
pub mod util;
|
||||
mod event_processor;
|
||||
|
||||
pub use self::monitor::MonitorHandle;
|
||||
pub use self::window::UnownedWindow;
|
||||
pub use self::xdisplay::{XConnection, XNotSupported, XError};
|
||||
pub use self::{
|
||||
monitor::MonitorHandle,
|
||||
window::UnownedWindow,
|
||||
xdisplay::{XConnection, XError, XNotSupported},
|
||||
};
|
||||
|
||||
use std::{mem, slice};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{VecDeque, HashMap, HashSet};
|
||||
use std::ffi::CStr;
|
||||
use std::ops::Deref;
|
||||
use std::os::raw::*;
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, mpsc, Weak, Mutex};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
collections::{HashMap, HashSet, VecDeque},
|
||||
ffi::CStr,
|
||||
mem,
|
||||
ops::Deref,
|
||||
os::raw::*,
|
||||
rc::Rc,
|
||||
slice,
|
||||
sync::{mpsc, Arc, Mutex, Weak},
|
||||
};
|
||||
|
||||
use libc::{self, setlocale, LC_CTYPE};
|
||||
|
||||
use crate::error::OsError as RootOsError;
|
||||
use crate::event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW};
|
||||
use crate::event::{WindowEvent, Event};
|
||||
use crate::platform_impl::PlatformSpecificWindowBuilderAttributes;
|
||||
use crate::platform_impl::platform::sticky_exit_callback;
|
||||
use crate::window::{WindowAttributes};
|
||||
use self::dnd::{Dnd, DndState};
|
||||
use self::ime::{ImeReceiver, ImeSender, ImeCreationError, Ime};
|
||||
use self::event_processor::EventProcessor;
|
||||
use self::{
|
||||
dnd::{Dnd, DndState},
|
||||
event_processor::EventProcessor,
|
||||
ime::{Ime, ImeCreationError, ImeReceiver, ImeSender},
|
||||
};
|
||||
use crate::{
|
||||
error::OsError as RootOsError,
|
||||
event::{Event, WindowEvent},
|
||||
event_loop::{ControlFlow, EventLoopClosed, EventLoopWindowTarget as RootELW},
|
||||
platform_impl::{platform::sticky_exit_callback, PlatformSpecificWindowBuilderAttributes},
|
||||
window::WindowAttributes,
|
||||
};
|
||||
|
||||
pub struct EventLoopWindowTarget<T> {
|
||||
xconn: Arc<XConnection>,
|
||||
|
|
@ -43,7 +51,7 @@ pub struct EventLoopWindowTarget<T> {
|
|||
ime: RefCell<Ime>,
|
||||
windows: RefCell<HashMap<WindowId, Weak<UnownedWindow>>>,
|
||||
pending_redraws: Arc<Mutex<HashSet<WindowId>>>,
|
||||
_marker: ::std::marker::PhantomData<T>
|
||||
_marker: ::std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
pub struct EventLoop<T: 'static> {
|
||||
|
|
@ -53,7 +61,7 @@ pub struct EventLoop<T: 'static> {
|
|||
pending_user_events: Rc<RefCell<VecDeque<T>>>,
|
||||
user_sender: ::calloop::channel::Sender<T>,
|
||||
pending_events: Rc<RefCell<VecDeque<Event<T>>>>,
|
||||
target: Rc<RootELW<T>>
|
||||
target: Rc<RootELW<T>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -73,7 +81,9 @@ impl<T: 'static> EventLoop<T> {
|
|||
let (ime_sender, ime_receiver) = mpsc::channel();
|
||||
// Input methods will open successfully without setting the locale, but it won't be
|
||||
// possible to actually commit pre-edit sequences.
|
||||
unsafe { setlocale(LC_CTYPE, b"\0".as_ptr() as *const _); }
|
||||
unsafe {
|
||||
setlocale(LC_CTYPE, b"\0".as_ptr() as *const _);
|
||||
}
|
||||
let ime = RefCell::new({
|
||||
let result = Ime::new(Arc::clone(&xconn));
|
||||
if let Err(ImeCreationError::OpenFailure(ref state)) = result {
|
||||
|
|
@ -82,7 +92,8 @@ impl<T: 'static> EventLoop<T> {
|
|||
result.expect("Failed to set input method destruction callback")
|
||||
});
|
||||
|
||||
let randr_event_offset = xconn.select_xrandr_input(root)
|
||||
let randr_event_offset = xconn
|
||||
.select_xrandr_input(root)
|
||||
.expect("Failed to query XRandR extension");
|
||||
|
||||
let xi2ext = unsafe {
|
||||
|
|
@ -96,7 +107,8 @@ impl<T: 'static> EventLoop<T> {
|
|||
b"XInputExtension\0".as_ptr() as *const c_char,
|
||||
&mut result.opcode as *mut c_int,
|
||||
&mut result.first_event_id as *mut c_int,
|
||||
&mut result.first_error_id as *mut c_int);
|
||||
&mut result.first_error_id as *mut c_int,
|
||||
);
|
||||
if res == ffi::False {
|
||||
panic!("X server missing XInput extension");
|
||||
}
|
||||
|
|
@ -110,18 +122,18 @@ impl<T: 'static> EventLoop<T> {
|
|||
xconn.display,
|
||||
&mut xinput_major_ver,
|
||||
&mut xinput_minor_ver,
|
||||
) != ffi::Success as libc::c_int {
|
||||
) != ffi::Success as libc::c_int
|
||||
{
|
||||
panic!(
|
||||
"X server has XInput extension {}.{} but does not support XInput2",
|
||||
xinput_major_ver,
|
||||
xinput_minor_ver,
|
||||
xinput_major_ver, xinput_minor_ver,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
xconn.update_cached_wm_info(root);
|
||||
|
||||
let target = Rc::new(RootELW{
|
||||
let target = Rc::new(RootELW {
|
||||
p: super::EventLoopWindowTarget::X(EventLoopWindowTarget {
|
||||
ime,
|
||||
root,
|
||||
|
|
@ -132,7 +144,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
wm_delete_window,
|
||||
pending_redraws: Default::default(),
|
||||
}),
|
||||
_marker: ::std::marker::PhantomData
|
||||
_marker: ::std::marker::PhantomData,
|
||||
});
|
||||
|
||||
// A calloop event loop to drive us
|
||||
|
|
@ -144,11 +156,14 @@ impl<T: 'static> EventLoop<T> {
|
|||
|
||||
let (user_sender, user_channel) = ::calloop::channel::channel();
|
||||
|
||||
let _user_source = inner_loop.handle().insert_source(user_channel, move |evt, &mut()| {
|
||||
if let ::calloop::channel::Event::Msg(msg) = evt {
|
||||
pending_user_events2.borrow_mut().push_back(msg);
|
||||
}
|
||||
}).unwrap();
|
||||
let _user_source = inner_loop
|
||||
.handle()
|
||||
.insert_source(user_channel, move |evt, &mut ()| {
|
||||
if let ::calloop::channel::Event::Msg(msg) = evt {
|
||||
pending_user_events2.borrow_mut().push_back(msg);
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
// Handle X11 events
|
||||
let pending_events: Rc<RefCell<VecDeque<_>>> = Default::default();
|
||||
|
|
@ -164,20 +179,20 @@ impl<T: 'static> EventLoop<T> {
|
|||
|
||||
// Register for device hotplug events
|
||||
// (The request buffer is flushed during `init_device`)
|
||||
get_xtarget(&target).xconn.select_xinput_events(
|
||||
root,
|
||||
ffi::XIAllDevices,
|
||||
ffi::XI_HierarchyChangedMask,
|
||||
).queue();
|
||||
get_xtarget(&target)
|
||||
.xconn
|
||||
.select_xinput_events(root, ffi::XIAllDevices, ffi::XI_HierarchyChangedMask)
|
||||
.queue();
|
||||
|
||||
processor.init_device(ffi::XIAllDevices);
|
||||
|
||||
// Setup the X11 event source
|
||||
let mut x11_events = ::calloop::generic::Generic::from_raw_fd(get_xtarget(&target).xconn.x11_fd);
|
||||
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 _x11_source = inner_loop
|
||||
.handle()
|
||||
.insert_source(x11_events, {
|
||||
let pending_events = pending_events.clone();
|
||||
let mut callback = move |event| {
|
||||
pending_events.borrow_mut().push_back(event);
|
||||
|
|
@ -191,8 +206,8 @@ impl<T: 'static> EventLoop<T> {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
).unwrap();
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let result = EventLoop {
|
||||
inner_loop,
|
||||
|
|
@ -201,7 +216,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
_user_source,
|
||||
user_sender,
|
||||
pending_user_events,
|
||||
target
|
||||
target,
|
||||
};
|
||||
|
||||
result
|
||||
|
|
@ -224,7 +239,8 @@ impl<T: 'static> EventLoop<T> {
|
|||
}
|
||||
|
||||
pub fn run_return<F>(&mut self, mut callback: F)
|
||||
where F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow)
|
||||
where
|
||||
F: FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||
{
|
||||
let mut control_flow = ControlFlow::default();
|
||||
let wt = get_xtarget(&self.target);
|
||||
|
|
@ -246,7 +262,7 @@ impl<T: 'static> EventLoop<T> {
|
|||
crate::event::Event::UserEvent(evt),
|
||||
&self.target,
|
||||
&mut control_flow,
|
||||
&mut callback
|
||||
&mut callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -257,11 +273,11 @@ impl<T: 'static> EventLoop<T> {
|
|||
sticky_exit_callback(
|
||||
Event::WindowEvent {
|
||||
window_id: crate::window::WindowId(super::WindowId::X(wid)),
|
||||
event: WindowEvent::RedrawRequested
|
||||
event: WindowEvent::RedrawRequested,
|
||||
},
|
||||
&self.target,
|
||||
&mut control_flow,
|
||||
&mut callback
|
||||
&mut callback,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -271,29 +287,37 @@ impl<T: 'static> EventLoop<T> {
|
|||
crate::event::Event::EventsCleared,
|
||||
&self.target,
|
||||
&mut control_flow,
|
||||
&mut callback
|
||||
&mut callback,
|
||||
);
|
||||
}
|
||||
|
||||
// flush the X11 connection
|
||||
unsafe { (wt.xconn.xlib.XFlush)(wt.xconn.display); }
|
||||
unsafe {
|
||||
(wt.xconn.xlib.XFlush)(wt.xconn.display);
|
||||
}
|
||||
|
||||
match control_flow {
|
||||
ControlFlow::Exit => break,
|
||||
ControlFlow::Poll => {
|
||||
// non-blocking dispatch
|
||||
self.inner_loop.dispatch(Some(::std::time::Duration::from_millis(0)), &mut ()).unwrap();
|
||||
callback(crate::event::Event::NewEvents(crate::event::StartCause::Poll), &self.target, &mut control_flow);
|
||||
self.inner_loop
|
||||
.dispatch(Some(::std::time::Duration::from_millis(0)), &mut ())
|
||||
.unwrap();
|
||||
callback(
|
||||
crate::event::Event::NewEvents(crate::event::StartCause::Poll),
|
||||
&self.target,
|
||||
&mut control_flow,
|
||||
);
|
||||
},
|
||||
ControlFlow::Wait => {
|
||||
self.inner_loop.dispatch(None, &mut ()).unwrap();
|
||||
callback(
|
||||
crate::event::Event::NewEvents(crate::event::StartCause::WaitCancelled {
|
||||
start: ::std::time::Instant::now(),
|
||||
requested_resume: None
|
||||
requested_resume: None,
|
||||
}),
|
||||
&self.target,
|
||||
&mut control_flow
|
||||
&mut control_flow,
|
||||
);
|
||||
},
|
||||
ControlFlow::WaitUntil(deadline) => {
|
||||
|
|
@ -308,32 +332,41 @@ impl<T: 'static> EventLoop<T> {
|
|||
let now = std::time::Instant::now();
|
||||
if now < deadline {
|
||||
callback(
|
||||
crate::event::Event::NewEvents(crate::event::StartCause::WaitCancelled {
|
||||
start,
|
||||
requested_resume: Some(deadline)
|
||||
}),
|
||||
crate::event::Event::NewEvents(
|
||||
crate::event::StartCause::WaitCancelled {
|
||||
start,
|
||||
requested_resume: Some(deadline),
|
||||
},
|
||||
),
|
||||
&self.target,
|
||||
&mut control_flow
|
||||
&mut control_flow,
|
||||
);
|
||||
} else {
|
||||
callback(
|
||||
crate::event::Event::NewEvents(crate::event::StartCause::ResumeTimeReached {
|
||||
start,
|
||||
requested_resume: deadline
|
||||
}),
|
||||
crate::event::Event::NewEvents(
|
||||
crate::event::StartCause::ResumeTimeReached {
|
||||
start,
|
||||
requested_resume: deadline,
|
||||
},
|
||||
),
|
||||
&self.target,
|
||||
&mut control_flow
|
||||
&mut control_flow,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
callback(crate::event::Event::LoopDestroyed, &self.target, &mut control_flow);
|
||||
callback(
|
||||
crate::event::Event::LoopDestroyed,
|
||||
&self.target,
|
||||
&mut control_flow,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn run<F>(mut self, callback: F) -> !
|
||||
where F: 'static + FnMut(Event<T>, &RootELW<T>, &mut ControlFlow)
|
||||
where
|
||||
F: 'static + FnMut(Event<T>, &RootELW<T>, &mut ControlFlow),
|
||||
{
|
||||
self.run_return(callback);
|
||||
::std::process::exit(0);
|
||||
|
|
@ -342,10 +375,10 @@ impl<T: 'static> EventLoop<T> {
|
|||
|
||||
fn get_xtarget<T>(rt: &RootELW<T>) -> &EventLoopWindowTarget<T> {
|
||||
if let super::EventLoopWindowTarget::X(ref target) = rt.p {
|
||||
target
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
target
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> EventLoopProxy<T> {
|
||||
|
|
@ -365,19 +398,17 @@ impl<'a> DeviceInfo<'a> {
|
|||
unsafe {
|
||||
let mut count = mem::uninitialized();
|
||||
let info = (xconn.xinput2.XIQueryDevice)(xconn.display, device, &mut count);
|
||||
xconn.check_errors()
|
||||
.ok()
|
||||
.and_then(|_| {
|
||||
if info.is_null() || count == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(DeviceInfo {
|
||||
xconn,
|
||||
info,
|
||||
count: count as usize,
|
||||
})
|
||||
}
|
||||
})
|
||||
xconn.check_errors().ok().and_then(|_| {
|
||||
if info.is_null() || count == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(DeviceInfo {
|
||||
xconn,
|
||||
info,
|
||||
count: count as usize,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -428,10 +459,11 @@ impl Window {
|
|||
pub fn new<T>(
|
||||
event_loop: &EventLoopWindowTarget<T>,
|
||||
attribs: WindowAttributes,
|
||||
pl_attribs: PlatformSpecificWindowBuilderAttributes
|
||||
pl_attribs: PlatformSpecificWindowBuilderAttributes,
|
||||
) -> Result<Self, RootOsError> {
|
||||
let window = Arc::new(UnownedWindow::new(&event_loop, attribs, pl_attribs)?);
|
||||
event_loop.windows
|
||||
event_loop
|
||||
.windows
|
||||
.borrow_mut()
|
||||
.insert(window.id(), Arc::downgrade(&window));
|
||||
Ok(Window(window))
|
||||
|
|
@ -454,11 +486,14 @@ impl Drop for Window {
|
|||
/// extract the cookie from a GenericEvent XEvent and release the cookie data once it has been processed
|
||||
struct GenericEventCookie<'a> {
|
||||
xconn: &'a XConnection,
|
||||
cookie: ffi::XGenericEventCookie
|
||||
cookie: ffi::XGenericEventCookie,
|
||||
}
|
||||
|
||||
impl<'a> GenericEventCookie<'a> {
|
||||
fn from_event<'b>(xconn: &'b XConnection, event: ffi::XEvent) -> Option<GenericEventCookie<'b>> {
|
||||
fn from_event<'b>(
|
||||
xconn: &'b XConnection,
|
||||
event: ffi::XEvent,
|
||||
) -> Option<GenericEventCookie<'b>> {
|
||||
unsafe {
|
||||
let mut cookie: ffi::XGenericEventCookie = From::from(event);
|
||||
if (xconn.xlib.XGetEventData)(xconn.display, &mut cookie) == ffi::True {
|
||||
|
|
@ -485,8 +520,12 @@ struct XExtension {
|
|||
first_error_id: c_int,
|
||||
}
|
||||
|
||||
fn mkwid(w: ffi::Window) -> crate::window::WindowId { crate::window::WindowId(crate::platform_impl::WindowId::X(WindowId(w))) }
|
||||
fn mkdid(w: c_int) -> crate::event::DeviceId { crate::event::DeviceId(crate::platform_impl::DeviceId::X(DeviceId(w))) }
|
||||
fn mkwid(w: ffi::Window) -> crate::window::WindowId {
|
||||
crate::window::WindowId(crate::platform_impl::WindowId::X(WindowId(w)))
|
||||
}
|
||||
fn mkdid(w: c_int) -> crate::event::DeviceId {
|
||||
crate::event::DeviceId(crate::platform_impl::DeviceId::X(DeviceId(w)))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Device {
|
||||
|
|
@ -525,32 +564,39 @@ impl Device {
|
|||
| ffi::XI_RawKeyPressMask
|
||||
| ffi::XI_RawKeyReleaseMask;
|
||||
// The request buffer is flushed when we poll for events
|
||||
wt.xconn.select_xinput_events(wt.root, info.deviceid, mask).queue();
|
||||
wt.xconn
|
||||
.select_xinput_events(wt.root, info.deviceid, mask)
|
||||
.queue();
|
||||
|
||||
// Identify scroll axes
|
||||
for class_ptr in Device::classes(info) {
|
||||
let class = unsafe { &**class_ptr };
|
||||
match class._type {
|
||||
ffi::XIScrollClass => {
|
||||
let info = unsafe { mem::transmute::<&ffi::XIAnyClassInfo, &ffi::XIScrollClassInfo>(class) };
|
||||
scroll_axes.push((info.number, ScrollAxis {
|
||||
increment: info.increment,
|
||||
orientation: match info.scroll_type {
|
||||
ffi::XIScrollTypeHorizontal => ScrollOrientation::Horizontal,
|
||||
ffi::XIScrollTypeVertical => ScrollOrientation::Vertical,
|
||||
_ => { unreachable!() }
|
||||
let info = unsafe {
|
||||
mem::transmute::<&ffi::XIAnyClassInfo, &ffi::XIScrollClassInfo>(class)
|
||||
};
|
||||
scroll_axes.push((
|
||||
info.number,
|
||||
ScrollAxis {
|
||||
increment: info.increment,
|
||||
orientation: match info.scroll_type {
|
||||
ffi::XIScrollTypeHorizontal => ScrollOrientation::Horizontal,
|
||||
ffi::XIScrollTypeVertical => ScrollOrientation::Vertical,
|
||||
_ => unreachable!(),
|
||||
},
|
||||
position: 0.0,
|
||||
},
|
||||
position: 0.0,
|
||||
}));
|
||||
}
|
||||
_ => {}
|
||||
));
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut device = Device {
|
||||
name: name.into_owned(),
|
||||
scroll_axes: scroll_axes,
|
||||
scroll_axes,
|
||||
attachment: info.attachment,
|
||||
};
|
||||
device.reset_scroll_position(info);
|
||||
|
|
@ -563,12 +609,18 @@ impl Device {
|
|||
let class = unsafe { &**class_ptr };
|
||||
match class._type {
|
||||
ffi::XIValuatorClass => {
|
||||
let info = unsafe { mem::transmute::<&ffi::XIAnyClassInfo, &ffi::XIValuatorClassInfo>(class) };
|
||||
if let Some(&mut (_, ref mut axis)) = self.scroll_axes.iter_mut().find(|&&mut (axis, _)| axis == info.number) {
|
||||
let info = unsafe {
|
||||
mem::transmute::<&ffi::XIAnyClassInfo, &ffi::XIValuatorClassInfo>(class)
|
||||
};
|
||||
if let Some(&mut (_, ref mut axis)) = self
|
||||
.scroll_axes
|
||||
.iter_mut()
|
||||
.find(|&&mut (axis, _)| axis == info.number)
|
||||
{
|
||||
axis.position = info.value;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -576,11 +628,18 @@ impl Device {
|
|||
|
||||
#[inline]
|
||||
fn physical_device(info: &ffi::XIDeviceInfo) -> bool {
|
||||
info._use == ffi::XISlaveKeyboard || info._use == ffi::XISlavePointer || info._use == ffi::XIFloatingSlave
|
||||
info._use == ffi::XISlaveKeyboard
|
||||
|| info._use == ffi::XISlavePointer
|
||||
|| info._use == ffi::XIFloatingSlave
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn classes(info: &ffi::XIDeviceInfo) -> &[*const ffi::XIAnyClassInfo] {
|
||||
unsafe { slice::from_raw_parts(info.classes as *const *const ffi::XIAnyClassInfo, info.num_classes as usize) }
|
||||
unsafe {
|
||||
slice::from_raw_parts(
|
||||
info.classes as *const *const ffi::XIAnyClassInfo,
|
||||
info.num_classes as usize,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,16 +2,16 @@ use std::os::raw::*;
|
|||
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use crate::dpi::{PhysicalPosition, PhysicalSize};
|
||||
use crate::monitor::VideoMode;
|
||||
use super::{util, XConnection, XError};
|
||||
use super::ffi::{
|
||||
RRCrtcChangeNotifyMask,
|
||||
RROutputPropertyNotifyMask,
|
||||
RRScreenChangeNotifyMask,
|
||||
True,
|
||||
Window,
|
||||
XRRScreenResources,
|
||||
use super::{
|
||||
ffi::{
|
||||
RRCrtcChangeNotifyMask, RROutputPropertyNotifyMask, RRScreenChangeNotifyMask, True, Window,
|
||||
XRRScreenResources,
|
||||
},
|
||||
util, XConnection, XError,
|
||||
};
|
||||
use crate::{
|
||||
dpi::{PhysicalPosition, PhysicalSize},
|
||||
monitor::VideoMode,
|
||||
};
|
||||
|
||||
// Used to test XRandR < 1.5 code path. This should always be committed as false.
|
||||
|
|
@ -160,7 +160,8 @@ impl XConnection {
|
|||
// videowalls.
|
||||
let xrandr_1_5 = self.xrandr_1_5.as_ref().unwrap();
|
||||
let mut monitor_count = 0;
|
||||
let monitors = (xrandr_1_5.XRRGetMonitors)(self.display, root, 1, &mut monitor_count);
|
||||
let monitors =
|
||||
(xrandr_1_5.XRRGetMonitors)(self.display, root, 1, &mut monitor_count);
|
||||
assert!(monitor_count >= 0);
|
||||
available = Vec::with_capacity(monitor_count as usize);
|
||||
for monitor_index in 0..monitor_count {
|
||||
|
|
@ -173,7 +174,8 @@ impl XConnection {
|
|||
monitor_index as u32,
|
||||
monitor.into(),
|
||||
is_primary,
|
||||
).map(|monitor_id| available.push(monitor_id));
|
||||
)
|
||||
.map(|monitor_id| available.push(monitor_id));
|
||||
}
|
||||
(xrandr_1_5.XRRFreeMonitors)(monitors);
|
||||
} else {
|
||||
|
|
@ -190,13 +192,8 @@ impl XConnection {
|
|||
let crtc = util::MonitorRepr::from(crtc);
|
||||
let is_primary = crtc.get_output() == primary;
|
||||
has_primary |= is_primary;
|
||||
MonitorHandle::from_repr(
|
||||
self,
|
||||
resources,
|
||||
crtc_id as u32,
|
||||
crtc,
|
||||
is_primary,
|
||||
).map(|monitor_id| available.push(monitor_id));
|
||||
MonitorHandle::from_repr(self, resources, crtc_id as u32, crtc, is_primary)
|
||||
.map(|monitor_id| available.push(monitor_id));
|
||||
}
|
||||
(self.xrandr.XRRFreeCrtcInfo)(crtc);
|
||||
}
|
||||
|
|
@ -244,13 +241,8 @@ impl XConnection {
|
|||
if version_lock.is_none() {
|
||||
let mut major = 0;
|
||||
let mut minor = 0;
|
||||
let has_extension = unsafe {
|
||||
(self.xrandr.XRRQueryVersion)(
|
||||
self.display,
|
||||
&mut major,
|
||||
&mut minor,
|
||||
)
|
||||
};
|
||||
let has_extension =
|
||||
unsafe { (self.xrandr.XRRQueryVersion)(self.display, &mut major, &mut minor) };
|
||||
if has_extension != True {
|
||||
panic!("[winit] XRandR extension not available.");
|
||||
}
|
||||
|
|
@ -261,11 +253,7 @@ impl XConnection {
|
|||
let mut event_offset = 0;
|
||||
let mut error_offset = 0;
|
||||
let status = unsafe {
|
||||
(self.xrandr.XRRQueryExtension)(
|
||||
self.display,
|
||||
&mut event_offset,
|
||||
&mut error_offset,
|
||||
)
|
||||
(self.xrandr.XRRQueryExtension)(self.display, &mut event_offset, &mut error_offset)
|
||||
};
|
||||
|
||||
if status != True {
|
||||
|
|
@ -273,9 +261,7 @@ impl XConnection {
|
|||
unreachable!("[winit] `XRRQueryExtension` failed but no error was received.");
|
||||
}
|
||||
|
||||
let mask = RRCrtcChangeNotifyMask
|
||||
| RROutputPropertyNotifyMask
|
||||
| RRScreenChangeNotifyMask;
|
||||
let mask = RRCrtcChangeNotifyMask | RROutputPropertyNotifyMask | RRScreenChangeNotifyMask;
|
||||
unsafe { (self.xrandr.XRRSelectInput)(self.display, root, mask) };
|
||||
|
||||
Ok(event_offset)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
use std::collections::HashMap;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::fmt::Debug;
|
||||
use std::os::raw::*;
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
ffi::{CStr, CString},
|
||||
fmt::Debug,
|
||||
os::raw::*,
|
||||
};
|
||||
|
||||
use parking_lot::Mutex;
|
||||
|
||||
|
|
@ -21,11 +23,9 @@ impl XConnection {
|
|||
if let Some(atom) = cached_atom {
|
||||
atom
|
||||
} else {
|
||||
let atom = unsafe { (self.xlib.XInternAtom)(
|
||||
self.display,
|
||||
name.as_ptr() as *const c_char,
|
||||
ffi::False,
|
||||
) };
|
||||
let atom = unsafe {
|
||||
(self.xlib.XInternAtom)(self.display, name.as_ptr() as *const c_char, ffi::False)
|
||||
};
|
||||
if atom == 0 {
|
||||
let msg = format!(
|
||||
"`XInternAtom` failed, which really shouldn't happen. Atom: {:?}, Error: {:#?}",
|
||||
|
|
@ -52,7 +52,7 @@ impl XConnection {
|
|||
|
||||
// Note: this doesn't use caching, for the sake of simplicity.
|
||||
// If you're dealing with this many atoms, you'll usually want to cache them locally anyway.
|
||||
pub unsafe fn get_atoms(&self, names: &[*mut c_char]) -> Result<Vec<ffi::Atom>, XError> {
|
||||
pub unsafe fn get_atoms(&self, names: &[*mut c_char]) -> Result<Vec<ffi::Atom>, XError> {
|
||||
let mut atoms = Vec::with_capacity(names.len());
|
||||
(self.xlib.XInternAtoms)(
|
||||
self.display,
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ impl XConnection {
|
|||
|
||||
pub fn send_client_msg(
|
||||
&self,
|
||||
window: c_ulong, // The window this is "about"; not necessarily this window
|
||||
window: c_ulong, // The window this is "about"; not necessarily this window
|
||||
target_window: c_ulong, // The window we're sending to
|
||||
message_type: ffi::Atom,
|
||||
event_mask: Option<c_long>,
|
||||
|
|
@ -45,7 +45,7 @@ impl XConnection {
|
|||
// to send more than one message worth of data.
|
||||
pub fn send_client_msg_multi<T: Formattable>(
|
||||
&self,
|
||||
window: c_ulong, // The window this is "about"; not necessarily this window
|
||||
window: c_ulong, // The window this is "about"; not necessarily this window
|
||||
target_window: c_ulong, // The window we're sending to
|
||||
message_type: ffi::Atom,
|
||||
event_mask: Option<c_long>,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
use std::fmt::Debug;
|
||||
use std::mem;
|
||||
use std::os::raw::*;
|
||||
use std::{fmt::Debug, mem, os::raw::*};
|
||||
|
||||
// This isn't actually the number of the bits in the format.
|
||||
// X11 does a match on this value to determine which type to call sizeof on.
|
||||
|
|
@ -50,9 +48,21 @@ pub trait Formattable: Debug + Clone + Copy + PartialEq + PartialOrd {
|
|||
}
|
||||
|
||||
// You might be surprised by the absence of c_int, but not as surprised as X11 would be by the presence of it.
|
||||
impl Formattable for c_schar { const FORMAT: Format = Format::Char; }
|
||||
impl Formattable for c_uchar { const FORMAT: Format = Format::Char; }
|
||||
impl Formattable for c_short { const FORMAT: Format = Format::Short; }
|
||||
impl Formattable for c_ushort { const FORMAT: Format = Format::Short; }
|
||||
impl Formattable for c_long { const FORMAT: Format = Format::Long; }
|
||||
impl Formattable for c_ulong { const FORMAT: Format = Format::Long; }
|
||||
impl Formattable for c_schar {
|
||||
const FORMAT: Format = Format::Char;
|
||||
}
|
||||
impl Formattable for c_uchar {
|
||||
const FORMAT: Format = Format::Char;
|
||||
}
|
||||
impl Formattable for c_short {
|
||||
const FORMAT: Format = Format::Short;
|
||||
}
|
||||
impl Formattable for c_ushort {
|
||||
const FORMAT: Format = Format::Short;
|
||||
}
|
||||
impl Formattable for c_long {
|
||||
const FORMAT: Format = Format::Long;
|
||||
}
|
||||
impl Formattable for c_ulong {
|
||||
const FORMAT: Format = Format::Long;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,12 @@ impl AaRect {
|
|||
pub fn new((x, y): (i32, i32), (width, height): (u32, u32)) -> Self {
|
||||
let (x, y) = (x as i64, y as i64);
|
||||
let (width, height) = (width as i64, height as i64);
|
||||
AaRect { x, y, width, height }
|
||||
AaRect {
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains_point(&self, x: i64, y: i64) -> bool {
|
||||
|
|
@ -73,7 +78,12 @@ pub struct FrameExtents {
|
|||
|
||||
impl FrameExtents {
|
||||
pub fn new(left: c_ulong, right: c_ulong, top: c_ulong, bottom: c_ulong) -> Self {
|
||||
FrameExtents { left, right, top, bottom }
|
||||
FrameExtents {
|
||||
left,
|
||||
right,
|
||||
top,
|
||||
bottom,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_border(border: c_ulong) -> Self {
|
||||
|
|
@ -116,13 +126,20 @@ impl FrameExtentsHeuristic {
|
|||
pub fn inner_pos_to_outer(&self, x: i32, y: i32) -> (i32, i32) {
|
||||
use self::FrameExtentsHeuristicPath::*;
|
||||
if self.heuristic_path != UnsupportedBordered {
|
||||
(x - self.frame_extents.left as i32, y - self.frame_extents.top as i32)
|
||||
(
|
||||
x - self.frame_extents.left as i32,
|
||||
y - self.frame_extents.top as i32,
|
||||
)
|
||||
} else {
|
||||
(x, y)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inner_pos_to_outer_logical(&self, mut logical: LogicalPosition, factor: f64) -> LogicalPosition {
|
||||
pub fn inner_pos_to_outer_logical(
|
||||
&self,
|
||||
mut logical: LogicalPosition,
|
||||
factor: f64,
|
||||
) -> LogicalPosition {
|
||||
use self::FrameExtentsHeuristicPath::*;
|
||||
if self.heuristic_path != UnsupportedBordered {
|
||||
let frame_extents = self.frame_extents.as_logical(factor);
|
||||
|
|
@ -135,15 +152,23 @@ impl FrameExtentsHeuristic {
|
|||
pub fn inner_size_to_outer(&self, width: u32, height: u32) -> (u32, u32) {
|
||||
(
|
||||
width.saturating_add(
|
||||
self.frame_extents.left.saturating_add(self.frame_extents.right) as u32
|
||||
self.frame_extents
|
||||
.left
|
||||
.saturating_add(self.frame_extents.right) as u32,
|
||||
),
|
||||
height.saturating_add(
|
||||
self.frame_extents.top.saturating_add(self.frame_extents.bottom) as u32
|
||||
self.frame_extents
|
||||
.top
|
||||
.saturating_add(self.frame_extents.bottom) as u32,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn inner_size_to_outer_logical(&self, mut logical: LogicalSize, factor: f64) -> LogicalSize {
|
||||
pub fn inner_size_to_outer_logical(
|
||||
&self,
|
||||
mut logical: LogicalSize,
|
||||
factor: f64,
|
||||
) -> LogicalSize {
|
||||
let frame_extents = self.frame_extents.as_logical(factor);
|
||||
logical.width += frame_extents.left + frame_extents.right;
|
||||
logical.height += frame_extents.top + frame_extents.bottom;
|
||||
|
|
@ -153,7 +178,11 @@ impl FrameExtentsHeuristic {
|
|||
|
||||
impl XConnection {
|
||||
// This is adequate for inner_position
|
||||
pub fn translate_coords(&self, window: ffi::Window, root: ffi::Window) -> Result<TranslatedCoords, XError> {
|
||||
pub fn translate_coords(
|
||||
&self,
|
||||
window: ffi::Window,
|
||||
root: ffi::Window,
|
||||
) -> Result<TranslatedCoords, XError> {
|
||||
let mut translated_coords: TranslatedCoords = unsafe { mem::uninitialized() };
|
||||
unsafe {
|
||||
(self.xlib.XTranslateCoordinates)(
|
||||
|
|
@ -201,11 +230,9 @@ impl XConnection {
|
|||
// Of the WMs tested, xmonad, i3, dwm, IceWM (1.3.x and earlier), and blackbox don't
|
||||
// support this. As this is part of EWMH (Extended Window Manager Hints), it's likely to
|
||||
// be unsupported by many smaller WMs.
|
||||
let extents: Option<Vec<c_ulong>> = self.get_property(
|
||||
window,
|
||||
extents_atom,
|
||||
ffi::XA_CARDINAL,
|
||||
).ok();
|
||||
let extents: Option<Vec<c_ulong>> = self
|
||||
.get_property(window, extents_atom, ffi::XA_CARDINAL)
|
||||
.ok();
|
||||
|
||||
extents.and_then(|extents| {
|
||||
if extents.len() >= 4 {
|
||||
|
|
@ -228,11 +255,9 @@ impl XConnection {
|
|||
return None;
|
||||
}
|
||||
|
||||
let client_list: Option<Vec<ffi::Window>> = self.get_property(
|
||||
root,
|
||||
client_list_atom,
|
||||
ffi::XA_WINDOW,
|
||||
).ok();
|
||||
let client_list: Option<Vec<ffi::Window>> = self
|
||||
.get_property(root, client_list_atom, ffi::XA_WINDOW)
|
||||
.ok();
|
||||
|
||||
client_list.map(|client_list| client_list.contains(&window))
|
||||
}
|
||||
|
|
@ -264,7 +289,11 @@ impl XConnection {
|
|||
self.check_errors().map(|_| parent)
|
||||
}
|
||||
|
||||
fn climb_hierarchy(&self, window: ffi::Window, root: ffi::Window) -> Result<ffi::Window, XError> {
|
||||
fn climb_hierarchy(
|
||||
&self,
|
||||
window: ffi::Window,
|
||||
root: ffi::Window,
|
||||
) -> Result<ffi::Window, XError> {
|
||||
let mut outer_window = window;
|
||||
loop {
|
||||
let candidate = self.get_parent_window(outer_window)?;
|
||||
|
|
@ -276,7 +305,11 @@ impl XConnection {
|
|||
Ok(outer_window)
|
||||
}
|
||||
|
||||
pub fn get_frame_extents_heuristic(&self, window: ffi::Window, root: ffi::Window) -> FrameExtentsHeuristic {
|
||||
pub fn get_frame_extents_heuristic(
|
||||
&self,
|
||||
window: ffi::Window,
|
||||
root: ffi::Window,
|
||||
) -> FrameExtentsHeuristic {
|
||||
use self::FrameExtentsHeuristicPath::*;
|
||||
|
||||
// Position relative to root window.
|
||||
|
|
@ -284,15 +317,16 @@ impl XConnection {
|
|||
// isn't nested are outlined in the comments throghout this function, but in addition to
|
||||
// that, fullscreen windows often aren't nested.
|
||||
let (inner_y_rel_root, child) = {
|
||||
let coords = self.translate_coords(window, root).expect("Failed to translate window coordinates");
|
||||
(
|
||||
coords.y_rel_root,
|
||||
coords.child,
|
||||
)
|
||||
let coords = self
|
||||
.translate_coords(window, root)
|
||||
.expect("Failed to translate window coordinates");
|
||||
(coords.y_rel_root, coords.child)
|
||||
};
|
||||
|
||||
let (width, height, border) = {
|
||||
let inner_geometry = self.get_geometry(window).expect("Failed to get inner window geometry");
|
||||
let inner_geometry = self
|
||||
.get_geometry(window)
|
||||
.expect("Failed to get inner window geometry");
|
||||
(
|
||||
inner_geometry.width,
|
||||
inner_geometry.height,
|
||||
|
|
@ -343,9 +377,13 @@ impl XConnection {
|
|||
// If the position value we have is for a nested window used as the client area, we'll
|
||||
// just climb up the hierarchy and get the geometry of the outermost window we're
|
||||
// nested in.
|
||||
let outer_window = self.climb_hierarchy(window, root).expect("Failed to climb window hierarchy");
|
||||
let outer_window = self
|
||||
.climb_hierarchy(window, root)
|
||||
.expect("Failed to climb window hierarchy");
|
||||
let (outer_y, outer_width, outer_height) = {
|
||||
let outer_geometry = self.get_geometry(outer_window).expect("Failed to get outer window geometry");
|
||||
let outer_geometry = self
|
||||
.get_geometry(outer_window)
|
||||
.expect("Failed to get outer window geometry");
|
||||
(
|
||||
outer_geometry.y_rel_parent,
|
||||
outer_geometry.width,
|
||||
|
|
@ -364,12 +402,8 @@ impl XConnection {
|
|||
let top = offset_y;
|
||||
let bottom = diff_y.saturating_sub(offset_y);
|
||||
|
||||
let frame_extents = FrameExtents::new(
|
||||
left.into(),
|
||||
right.into(),
|
||||
top.into(),
|
||||
bottom.into(),
|
||||
);
|
||||
let frame_extents =
|
||||
FrameExtents::new(left.into(), right.into(), top.into(), bottom.into());
|
||||
FrameExtentsHeuristic {
|
||||
frame_extents,
|
||||
heuristic_path: UnsupportedNested,
|
||||
|
|
|
|||
|
|
@ -99,7 +99,9 @@ pub struct NormalHints<'a> {
|
|||
|
||||
impl<'a> NormalHints<'a> {
|
||||
pub fn new(xconn: &'a XConnection) -> Self {
|
||||
NormalHints { size_hints: xconn.alloc_size_hints() }
|
||||
NormalHints {
|
||||
size_hints: xconn.alloc_size_hints(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn has_flag(&self, flag: c_long) -> bool {
|
||||
|
|
@ -130,7 +132,11 @@ impl<'a> NormalHints<'a> {
|
|||
}
|
||||
|
||||
pub fn get_max_size(&self) -> Option<(u32, u32)> {
|
||||
self.getter(ffi::PMaxSize, &self.size_hints.max_width, &self.size_hints.max_height)
|
||||
self.getter(
|
||||
ffi::PMaxSize,
|
||||
&self.size_hints.max_width,
|
||||
&self.size_hints.max_height,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_max_size(&mut self, max_size: Option<(u32, u32)>) {
|
||||
|
|
@ -144,7 +150,11 @@ impl<'a> NormalHints<'a> {
|
|||
}
|
||||
|
||||
pub fn get_min_size(&self) -> Option<(u32, u32)> {
|
||||
self.getter(ffi::PMinSize, &self.size_hints.min_width, &self.size_hints.min_height)
|
||||
self.getter(
|
||||
ffi::PMinSize,
|
||||
&self.size_hints.min_width,
|
||||
&self.size_hints.min_height,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_min_size(&mut self, min_size: Option<(u32, u32)>) {
|
||||
|
|
@ -158,7 +168,11 @@ impl<'a> NormalHints<'a> {
|
|||
}
|
||||
|
||||
pub fn get_resize_increments(&self) -> Option<(u32, u32)> {
|
||||
self.getter(ffi::PResizeInc, &self.size_hints.width_inc, &self.size_hints.height_inc)
|
||||
self.getter(
|
||||
ffi::PResizeInc,
|
||||
&self.size_hints.width_inc,
|
||||
&self.size_hints.height_inc,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_resize_increments(&mut self, resize_increments: Option<(u32, u32)>) {
|
||||
|
|
@ -172,7 +186,11 @@ impl<'a> NormalHints<'a> {
|
|||
}
|
||||
|
||||
pub fn get_base_size(&self) -> Option<(u32, u32)> {
|
||||
self.getter(ffi::PBaseSize, &self.size_hints.base_width, &self.size_hints.base_height)
|
||||
self.getter(
|
||||
ffi::PBaseSize,
|
||||
&self.size_hints.base_width,
|
||||
&self.size_hints.base_height,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn set_base_size(&mut self, base_size: Option<(u32, u32)>) {
|
||||
|
|
@ -187,7 +205,10 @@ impl<'a> NormalHints<'a> {
|
|||
}
|
||||
|
||||
impl XConnection {
|
||||
pub fn get_wm_hints(&self, window: ffi::Window) -> Result<XSmartPointer<'_, ffi::XWMHints>, XError> {
|
||||
pub fn get_wm_hints(
|
||||
&self,
|
||||
window: ffi::Window,
|
||||
) -> Result<XSmartPointer<'_, ffi::XWMHints>, XError> {
|
||||
let wm_hints = unsafe { (self.xlib.XGetWMHints)(self.display, window) };
|
||||
self.check_errors()?;
|
||||
let wm_hints = if wm_hints.is_null() {
|
||||
|
|
@ -198,13 +219,13 @@ impl XConnection {
|
|||
Ok(wm_hints)
|
||||
}
|
||||
|
||||
pub fn set_wm_hints(&self, window: ffi::Window, wm_hints: XSmartPointer<'_, ffi::XWMHints>) -> Flusher<'_> {
|
||||
pub fn set_wm_hints(
|
||||
&self,
|
||||
window: ffi::Window,
|
||||
wm_hints: XSmartPointer<'_, ffi::XWMHints>,
|
||||
) -> Flusher<'_> {
|
||||
unsafe {
|
||||
(self.xlib.XSetWMHints)(
|
||||
self.display,
|
||||
window,
|
||||
wm_hints.ptr,
|
||||
);
|
||||
(self.xlib.XSetWMHints)(self.display, window, wm_hints.ptr);
|
||||
}
|
||||
Flusher::new(self)
|
||||
}
|
||||
|
|
@ -223,13 +244,13 @@ impl XConnection {
|
|||
self.check_errors().map(|_| NormalHints { size_hints })
|
||||
}
|
||||
|
||||
pub fn set_normal_hints(&self, window: ffi::Window, normal_hints: NormalHints<'_>) -> Flusher<'_> {
|
||||
pub fn set_normal_hints(
|
||||
&self,
|
||||
window: ffi::Window,
|
||||
normal_hints: NormalHints<'_>,
|
||||
) -> Flusher<'_> {
|
||||
unsafe {
|
||||
(self.xlib.XSetWMNormalHints)(
|
||||
self.display,
|
||||
window,
|
||||
normal_hints.size_hints.ptr,
|
||||
);
|
||||
(self.xlib.XSetWMNormalHints)(self.display, window, normal_hints.size_hints.ptr);
|
||||
}
|
||||
Flusher::new(self)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::window::{Icon, Pixel, PIXEL_SIZE};
|
||||
use super::*;
|
||||
use crate::window::{Icon, Pixel, PIXEL_SIZE};
|
||||
|
||||
impl Pixel {
|
||||
pub fn to_packed_argb(&self) -> Cardinal {
|
||||
|
|
|
|||
|
|
@ -55,7 +55,12 @@ impl<'a> Drop for PointerState<'a> {
|
|||
}
|
||||
|
||||
impl XConnection {
|
||||
pub fn select_xinput_events(&self, window: c_ulong, device_id: c_int, mask: i32) -> Flusher<'_> {
|
||||
pub fn select_xinput_events(
|
||||
&self,
|
||||
window: c_ulong,
|
||||
device_id: c_int,
|
||||
mask: i32,
|
||||
) -> Flusher<'_> {
|
||||
let mut event_mask = ffi::XIEventMask {
|
||||
deviceid: device_id,
|
||||
mask: &mask as *const _ as *mut c_uchar,
|
||||
|
|
@ -74,14 +79,7 @@ impl XConnection {
|
|||
|
||||
#[allow(dead_code)]
|
||||
pub fn select_xkb_events(&self, device_id: c_uint, mask: c_ulong) -> Option<Flusher<'_>> {
|
||||
let status = unsafe {
|
||||
(self.xlib.XkbSelectEvents)(
|
||||
self.display,
|
||||
device_id,
|
||||
mask,
|
||||
mask,
|
||||
)
|
||||
};
|
||||
let status = unsafe { (self.xlib.XkbSelectEvents)(self.display, device_id, mask, mask) };
|
||||
if status == ffi::True {
|
||||
Some(Flusher::new(self))
|
||||
} else {
|
||||
|
|
@ -89,7 +87,11 @@ impl XConnection {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn query_pointer(&self, window: ffi::Window, device_id: c_int) -> Result<PointerState<'_>, XError> {
|
||||
pub fn query_pointer(
|
||||
&self,
|
||||
window: ffi::Window,
|
||||
device_id: c_int,
|
||||
) -> Result<PointerState<'_>, XError> {
|
||||
unsafe {
|
||||
let mut pointer_state: PointerState<'_> = mem::uninitialized();
|
||||
pointer_state.xconn = self;
|
||||
|
|
|
|||
|
|
@ -12,10 +12,7 @@ impl<'a, T> XSmartPointer<'a, T> {
|
|||
// Returns None if ptr is null.
|
||||
pub fn new(xconn: &'a XConnection, ptr: *mut T) -> Option<Self> {
|
||||
if !ptr.is_null() {
|
||||
Some(XSmartPointer {
|
||||
xconn,
|
||||
ptr,
|
||||
})
|
||||
Some(XSmartPointer { xconn, ptr })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,22 +13,12 @@ mod randr;
|
|||
mod window_property;
|
||||
mod wm;
|
||||
|
||||
pub use self::atom::*;
|
||||
pub use self::client_msg::*;
|
||||
pub use self::format::*;
|
||||
pub use self::geometry::*;
|
||||
pub use self::hint::*;
|
||||
pub use self::icon::*;
|
||||
pub use self::input::*;
|
||||
pub use self::memory::*;
|
||||
pub use self::randr::*;
|
||||
pub use self::window_property::*;
|
||||
pub use self::wm::*;
|
||||
pub use self::{
|
||||
atom::*, client_msg::*, format::*, geometry::*, hint::*, icon::*, input::*, memory::*,
|
||||
randr::*, window_property::*, wm::*,
|
||||
};
|
||||
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
use std::ops::BitAnd;
|
||||
use std::os::raw::*;
|
||||
use std::{mem, ops::BitAnd, os::raw::*, ptr};
|
||||
|
||||
use super::{ffi, XConnection, XError};
|
||||
|
||||
|
|
@ -48,8 +38,8 @@ pub fn maybe_change<T: PartialEq>(field: &mut Option<T>, value: T) -> bool {
|
|||
}
|
||||
|
||||
pub fn has_flag<T>(bitset: T, flag: T) -> bool
|
||||
where T:
|
||||
Copy + PartialEq + BitAnd<T, Output = T>
|
||||
where
|
||||
T: Copy + PartialEq + BitAnd<T, Output = T>,
|
||||
{
|
||||
bitset & flag == flag
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
use std::{env, slice};
|
||||
use std::str::FromStr;
|
||||
use std::{env, slice, str::FromStr};
|
||||
|
||||
use crate::monitor::VideoMode;
|
||||
use crate::dpi::validate_hidpi_factor;
|
||||
use super::*;
|
||||
use crate::{dpi::validate_hidpi_factor, monitor::VideoMode};
|
||||
|
||||
pub fn calc_dpi_factor(
|
||||
(width_px, height_px): (u32, u32),
|
||||
|
|
@ -29,9 +27,7 @@ pub fn calc_dpi_factor(
|
|||
return 1.0;
|
||||
}
|
||||
|
||||
let ppmm = (
|
||||
(width_px as f64 * height_px as f64) / (width_mm as f64 * height_mm as f64)
|
||||
).sqrt();
|
||||
let ppmm = ((width_px as f64 * height_px as f64) / (width_mm as f64 * height_mm as f64)).sqrt();
|
||||
// Quantize 1/12 step size
|
||||
let dpi_factor = ((ppmm * (12.0 * 25.4 / 96.0)).round() / 12.0).max(1.0);
|
||||
assert!(validate_hidpi_factor(dpi_factor));
|
||||
|
|
@ -88,7 +84,7 @@ impl XConnection {
|
|||
return None;
|
||||
}
|
||||
if let Ok(res) = ::std::ffi::CStr::from_ptr(resource_manager_str).to_str() {
|
||||
let name : &str = "Xft.dpi:\t";
|
||||
let name: &str = "Xft.dpi:\t";
|
||||
for pair in res.split("\n") {
|
||||
if pair.starts_with(&name) {
|
||||
let res = &pair[name.len()..];
|
||||
|
|
@ -103,11 +99,8 @@ impl XConnection {
|
|||
resources: *mut ffi::XRRScreenResources,
|
||||
repr: &MonitorRepr,
|
||||
) -> Option<(String, f64, Vec<VideoMode>)> {
|
||||
let output_info = (self.xrandr.XRRGetOutputInfo)(
|
||||
self.display,
|
||||
resources,
|
||||
repr.get_output(),
|
||||
);
|
||||
let output_info =
|
||||
(self.xrandr.XRRGetOutputInfo)(self.display, resources, repr.get_output());
|
||||
if output_info.is_null() {
|
||||
// When calling `XRRGetOutputInfo` on a virtual monitor (versus a physical display)
|
||||
// it's possible for it to return null.
|
||||
|
|
@ -152,7 +145,10 @@ impl XConnection {
|
|||
} else {
|
||||
calc_dpi_factor(
|
||||
repr.size(),
|
||||
((*output_info).mm_width as u64, (*output_info).mm_height as u64),
|
||||
(
|
||||
(*output_info).mm_width as u64,
|
||||
(*output_info).mm_height as u64,
|
||||
),
|
||||
)
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -84,10 +84,8 @@ impl XConnection {
|
|||
|
||||
if !buf.is_null() {
|
||||
offset += PROPERTY_BUFFER_SIZE;
|
||||
let new_data = std::slice::from_raw_parts(
|
||||
buf as *mut T,
|
||||
quantity_returned as usize,
|
||||
);
|
||||
let new_data =
|
||||
std::slice::from_raw_parts(buf as *mut T, quantity_returned as usize);
|
||||
/*println!(
|
||||
"XGetWindowProperty prop:{:?} fmt:{:02} len:{:02} off:{:02} out:{:02}, buf:{:?}",
|
||||
property,
|
||||
|
|
|
|||
|
|
@ -28,11 +28,8 @@ impl XConnection {
|
|||
|
||||
fn get_supported_hints(&self, root: ffi::Window) -> Vec<ffi::Atom> {
|
||||
let supported_atom = unsafe { self.get_atom_unchecked(b"_NET_SUPPORTED\0") };
|
||||
self.get_property(
|
||||
root,
|
||||
supported_atom,
|
||||
ffi::XA_ATOM,
|
||||
).unwrap_or_else(|_| Vec::with_capacity(0))
|
||||
self.get_property(root, supported_atom, ffi::XA_ATOM)
|
||||
.unwrap_or_else(|_| Vec::with_capacity(0))
|
||||
}
|
||||
|
||||
fn get_wm_name(&self, root: ffi::Window) -> Option<String> {
|
||||
|
|
@ -61,15 +58,9 @@ impl XConnection {
|
|||
// Querying this property on the root window will give us the ID of a child window created by
|
||||
// the WM.
|
||||
let root_window_wm_check = {
|
||||
let result = self.get_property(
|
||||
root,
|
||||
check_atom,
|
||||
ffi::XA_WINDOW,
|
||||
);
|
||||
let result = self.get_property(root, check_atom, ffi::XA_WINDOW);
|
||||
|
||||
let wm_check = result
|
||||
.ok()
|
||||
.and_then(|wm_check| wm_check.get(0).cloned());
|
||||
let wm_check = result.ok().and_then(|wm_check| wm_check.get(0).cloned());
|
||||
|
||||
if let Some(wm_check) = wm_check {
|
||||
wm_check
|
||||
|
|
@ -81,15 +72,9 @@ impl XConnection {
|
|||
// Querying the same property on the child window we were given, we should get this child
|
||||
// window's ID again.
|
||||
let child_window_wm_check = {
|
||||
let result = self.get_property(
|
||||
root_window_wm_check,
|
||||
check_atom,
|
||||
ffi::XA_WINDOW,
|
||||
);
|
||||
let result = self.get_property(root_window_wm_check, check_atom, ffi::XA_WINDOW);
|
||||
|
||||
let wm_check = result
|
||||
.ok()
|
||||
.and_then(|wm_check| wm_check.get(0).cloned());
|
||||
let wm_check = result.ok().and_then(|wm_check| wm_check.get(0).cloned());
|
||||
|
||||
if let Some(wm_check) = wm_check {
|
||||
wm_check
|
||||
|
|
@ -107,11 +92,7 @@ impl XConnection {
|
|||
let wm_name = {
|
||||
let utf8_string_atom = unsafe { self.get_atom_unchecked(b"UTF8_STRING\0") };
|
||||
|
||||
let result = self.get_property(
|
||||
root_window_wm_check,
|
||||
wm_name_atom,
|
||||
utf8_string_atom,
|
||||
);
|
||||
let result = self.get_property(root_window_wm_check, wm_name_atom, utf8_string_atom);
|
||||
|
||||
// IceWM requires this. IceWM was also the only WM tested that returns a null-terminated
|
||||
// string. For more fun trivia, IceWM is also unique in including version and uname
|
||||
|
|
@ -126,15 +107,12 @@ impl XConnection {
|
|||
};
|
||||
|
||||
if no_utf8 {
|
||||
self.get_property(
|
||||
root_window_wm_check,
|
||||
wm_name_atom,
|
||||
ffi::XA_STRING,
|
||||
)
|
||||
self.get_property(root_window_wm_check, wm_name_atom, ffi::XA_STRING)
|
||||
} else {
|
||||
result
|
||||
}
|
||||
}.ok();
|
||||
}
|
||||
.ok();
|
||||
|
||||
wm_name.and_then(|wm_name| String::from_utf8(wm_name).ok())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,20 @@
|
|||
use std::{cmp, env, mem};
|
||||
use std::collections::HashSet;
|
||||
use std::ffi::CString;
|
||||
use std::os::raw::*;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::{cmp, collections::HashSet, env, ffi::CString, mem, os::raw::*, path::Path, sync::Arc};
|
||||
|
||||
use libc;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use crate::error::{ExternalError, NotSupportedError, OsError as RootOsError};
|
||||
use crate::window::{Icon, CursorIcon, WindowAttributes};
|
||||
use crate::dpi::{LogicalPosition, LogicalSize};
|
||||
use crate::platform_impl::MonitorHandle as PlatformMonitorHandle;
|
||||
use crate::platform_impl::{OsError, PlatformSpecificWindowBuilderAttributes};
|
||||
use crate::platform_impl::x11::ime::ImeContextCreationError;
|
||||
use crate::platform_impl::x11::MonitorHandle as X11MonitorHandle;
|
||||
use crate::monitor::MonitorHandle as RootMonitorHandle;
|
||||
use crate::{
|
||||
dpi::{LogicalPosition, LogicalSize},
|
||||
error::{ExternalError, NotSupportedError, OsError as RootOsError},
|
||||
monitor::MonitorHandle as RootMonitorHandle,
|
||||
platform_impl::{
|
||||
x11::{ime::ImeContextCreationError, MonitorHandle as X11MonitorHandle},
|
||||
MonitorHandle as PlatformMonitorHandle, OsError, PlatformSpecificWindowBuilderAttributes,
|
||||
},
|
||||
window::{CursorIcon, Icon, WindowAttributes},
|
||||
};
|
||||
|
||||
use super::{ffi, util, ImeSender, XConnection, XError, WindowId, EventLoopWindowTarget};
|
||||
use super::{ffi, util, EventLoopWindowTarget, ImeSender, WindowId, XConnection, XError};
|
||||
|
||||
unsafe extern "C" fn visibility_predicate(
|
||||
_display: *mut ffi::Display,
|
||||
|
|
@ -60,9 +57,9 @@ unsafe impl Sync for UnownedWindow {}
|
|||
|
||||
pub struct UnownedWindow {
|
||||
pub xconn: Arc<XConnection>, // never changes
|
||||
xwindow: ffi::Window, // never changes
|
||||
root: ffi::Window, // never changes
|
||||
screen_id: i32, // never changes
|
||||
xwindow: ffi::Window, // never changes
|
||||
root: ffi::Window, // never changes
|
||||
screen_id: i32, // never changes
|
||||
cursor: Mutex<CursorIcon>,
|
||||
cursor_grabbed: Mutex<bool>,
|
||||
cursor_visible: Mutex<bool>,
|
||||
|
|
@ -89,7 +86,8 @@ impl UnownedWindow {
|
|||
}
|
||||
}
|
||||
dpi_factor.unwrap_or_else(|| {
|
||||
xconn.query_pointer(root, util::VIRTUAL_CORE_POINTER)
|
||||
xconn
|
||||
.query_pointer(root, util::VIRTUAL_CORE_POINTER)
|
||||
.ok()
|
||||
.and_then(|pointer_state| {
|
||||
let (x, y) = (pointer_state.root_x as i64, pointer_state.root_y as i64);
|
||||
|
|
@ -110,17 +108,18 @@ impl UnownedWindow {
|
|||
|
||||
info!("Guessed window DPI factor: {}", dpi_factor);
|
||||
|
||||
let max_inner_size: Option<(u32, u32)> = window_attrs.max_inner_size.map(|size| {
|
||||
size.to_physical(dpi_factor).into()
|
||||
});
|
||||
let min_inner_size: Option<(u32, u32)> = window_attrs.min_inner_size.map(|size| {
|
||||
size.to_physical(dpi_factor).into()
|
||||
});
|
||||
let max_inner_size: Option<(u32, u32)> = window_attrs
|
||||
.max_inner_size
|
||||
.map(|size| size.to_physical(dpi_factor).into());
|
||||
let min_inner_size: Option<(u32, u32)> = window_attrs
|
||||
.min_inner_size
|
||||
.map(|size| size.to_physical(dpi_factor).into());
|
||||
|
||||
let dimensions = {
|
||||
// x11 only applies constraints when the window is actively resized
|
||||
// by the user, so we have to manually apply the initial constraints
|
||||
let mut dimensions: (u32, u32) = window_attrs.inner_size
|
||||
let mut dimensions: (u32, u32) = window_attrs
|
||||
.inner_size
|
||||
.or_else(|| Some((800, 600).into()))
|
||||
.map(|size| size.to_physical(dpi_factor))
|
||||
.map(Into::into)
|
||||
|
|
@ -133,7 +132,10 @@ impl UnownedWindow {
|
|||
dimensions.0 = cmp::max(dimensions.0, min.0);
|
||||
dimensions.1 = cmp::max(dimensions.1, min.1);
|
||||
}
|
||||
debug!("Calculated physical dimensions: {}x{}", dimensions.0, dimensions.1);
|
||||
debug!(
|
||||
"Calculated physical dimensions: {}x{}",
|
||||
dimensions.0, dimensions.1
|
||||
);
|
||||
dimensions
|
||||
};
|
||||
|
||||
|
|
@ -150,7 +152,9 @@ impl UnownedWindow {
|
|||
let visual = vi.visual;
|
||||
(xconn.xlib.XCreateColormap)(xconn.display, root, visual, ffi::AllocNone)
|
||||
}
|
||||
} else { 0 };
|
||||
} else {
|
||||
0
|
||||
};
|
||||
swa.event_mask = ffi::ExposureMask
|
||||
| ffi::StructureNotifyMask
|
||||
| ffi::VisibilityChangeMask
|
||||
|
|
@ -220,7 +224,9 @@ impl UnownedWindow {
|
|||
// title to determine placement/etc., so doing this after mapping would cause the WM to
|
||||
// act on the wrong title state.
|
||||
window.set_title_inner(&window_attrs.title).queue();
|
||||
window.set_decorations_inner(window_attrs.decorations).queue();
|
||||
window
|
||||
.set_decorations_inner(window_attrs.decorations)
|
||||
.queue();
|
||||
|
||||
{
|
||||
// Enable drag and drop (TODO: extend API to make this toggleable)
|
||||
|
|
@ -234,15 +240,16 @@ impl UnownedWindow {
|
|||
util::PropMode::Replace,
|
||||
version,
|
||||
)
|
||||
}.queue();
|
||||
}
|
||||
.queue();
|
||||
|
||||
// WM_CLASS must be set *before* mapping the window, as per ICCCM!
|
||||
{
|
||||
let (class, instance) = if let Some((instance, class)) = pl_attribs.class {
|
||||
let instance = CString::new(instance.as_str())
|
||||
.expect("`WM_CLASS` instance contained null byte");
|
||||
let class = CString::new(class.as_str())
|
||||
.expect("`WM_CLASS` class contained null byte");
|
||||
let class =
|
||||
CString::new(class.as_str()).expect("`WM_CLASS` class contained null byte");
|
||||
(instance, class)
|
||||
} else {
|
||||
let class = env::args()
|
||||
|
|
@ -269,12 +276,8 @@ impl UnownedWindow {
|
|||
(*class_hint).res_class = instance.as_ptr() as *mut c_char;
|
||||
|
||||
unsafe {
|
||||
(xconn.xlib.XSetClassHint)(
|
||||
xconn.display,
|
||||
window.xwindow,
|
||||
class_hint.ptr,
|
||||
);
|
||||
}//.queue();
|
||||
(xconn.xlib.XSetClassHint)(xconn.display, window.xwindow, class_hint.ptr);
|
||||
} //.queue();
|
||||
}
|
||||
|
||||
window.set_pid().map(|flusher| flusher.queue());
|
||||
|
|
@ -289,9 +292,11 @@ impl UnownedWindow {
|
|||
|
||||
// set size hints
|
||||
{
|
||||
let mut min_inner_size = window_attrs.min_inner_size
|
||||
let mut min_inner_size = window_attrs
|
||||
.min_inner_size
|
||||
.map(|size| size.to_physical(dpi_factor));
|
||||
let mut max_inner_size = window_attrs.max_inner_size
|
||||
let mut max_inner_size = window_attrs
|
||||
.max_inner_size
|
||||
.map(|size| size.to_physical(dpi_factor));
|
||||
if !window_attrs.resizable {
|
||||
if util::wm_name_is_one_of(&["Xfwm4"]) {
|
||||
|
|
@ -328,13 +333,13 @@ impl UnownedWindow {
|
|||
&event_loop.wm_delete_window as *const ffi::Atom as *mut ffi::Atom,
|
||||
1,
|
||||
);
|
||||
}//.queue();
|
||||
} //.queue();
|
||||
|
||||
// Set visibility (map window)
|
||||
if window_attrs.visible {
|
||||
unsafe {
|
||||
(xconn.xlib.XMapRaised)(xconn.display, window.xwindow);
|
||||
}//.queue();
|
||||
} //.queue();
|
||||
}
|
||||
|
||||
// Attempt to make keyboard input repeat detectable
|
||||
|
|
@ -346,7 +351,9 @@ impl UnownedWindow {
|
|||
&mut supported_ptr,
|
||||
);
|
||||
if supported_ptr == ffi::False {
|
||||
return Err(os_error!(OsError::XMisc("`XkbSetDetectableAutoRepeat` failed")));
|
||||
return Err(os_error!(OsError::XMisc(
|
||||
"`XkbSetDetectableAutoRepeat` failed"
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -366,16 +373,18 @@ impl UnownedWindow {
|
|||
| ffi::XI_TouchEndMask;
|
||||
mask
|
||||
};
|
||||
xconn.select_xinput_events(window.xwindow, ffi::XIAllMasterDevices, mask).queue();
|
||||
xconn
|
||||
.select_xinput_events(window.xwindow, ffi::XIAllMasterDevices, mask)
|
||||
.queue();
|
||||
|
||||
{
|
||||
let result = event_loop.ime
|
||||
.borrow_mut()
|
||||
.create_context(window.xwindow);
|
||||
let result = event_loop.ime.borrow_mut().create_context(window.xwindow);
|
||||
if let Err(err) = result {
|
||||
let e = match err {
|
||||
ImeContextCreationError::XError(err) => OsError::XError(err),
|
||||
ImeContextCreationError::Null => OsError::XMisc("IME Context creation failed"),
|
||||
ImeContextCreationError::Null => {
|
||||
OsError::XMisc("IME Context creation failed")
|
||||
},
|
||||
};
|
||||
return Err(os_error!(e));
|
||||
}
|
||||
|
|
@ -386,10 +395,14 @@ impl UnownedWindow {
|
|||
window.set_maximized_inner(window_attrs.maximized).queue();
|
||||
}
|
||||
if window_attrs.fullscreen.is_some() {
|
||||
window.set_fullscreen_inner(window_attrs.fullscreen.clone()).queue();
|
||||
window
|
||||
.set_fullscreen_inner(window_attrs.fullscreen.clone())
|
||||
.queue();
|
||||
}
|
||||
if window_attrs.always_on_top {
|
||||
window.set_always_on_top_inner(window_attrs.always_on_top).queue();
|
||||
window
|
||||
.set_always_on_top_inner(window_attrs.always_on_top)
|
||||
.queue();
|
||||
}
|
||||
|
||||
if window_attrs.visible {
|
||||
|
|
@ -397,7 +410,8 @@ impl UnownedWindow {
|
|||
// XSetInputFocus generates an error if the window is not visible, so we wait
|
||||
// until we receive VisibilityNotify.
|
||||
let mut event = mem::uninitialized();
|
||||
(xconn.xlib.XIfEvent)( // This will flush the request buffer IF it blocks.
|
||||
(xconn.xlib.XIfEvent)(
|
||||
// This will flush the request buffer IF it blocks.
|
||||
xconn.display,
|
||||
&mut event as *mut ffi::XEvent,
|
||||
Some(visibility_predicate),
|
||||
|
|
@ -414,7 +428,8 @@ impl UnownedWindow {
|
|||
}
|
||||
|
||||
// We never want to give the user a broken window, since by then, it's too late to handle.
|
||||
xconn.sync_with_server()
|
||||
xconn
|
||||
.sync_with_server()
|
||||
.map(|_| window)
|
||||
.map_err(|x_err| os_error!(OsError::XError(x_err)))
|
||||
}
|
||||
|
|
@ -439,18 +454,22 @@ impl UnownedWindow {
|
|||
const MAXHOSTNAMELEN: usize = 256;
|
||||
let mut hostname: [c_char; MAXHOSTNAMELEN] = mem::uninitialized();
|
||||
let status = libc::gethostname(hostname.as_mut_ptr(), hostname.len());
|
||||
if status != 0 { return None; }
|
||||
if status != 0 {
|
||||
return None;
|
||||
}
|
||||
hostname[MAXHOSTNAMELEN - 1] = '\0' as c_char; // a little extra safety
|
||||
let hostname_length = libc::strlen(hostname.as_ptr());
|
||||
(hostname, hostname_length as usize)
|
||||
};
|
||||
self.xconn.change_property(
|
||||
self.xwindow,
|
||||
pid_atom,
|
||||
ffi::XA_CARDINAL,
|
||||
util::PropMode::Replace,
|
||||
&[libc::getpid() as util::Cardinal],
|
||||
).queue();
|
||||
self.xconn
|
||||
.change_property(
|
||||
self.xwindow,
|
||||
pid_atom,
|
||||
ffi::XA_CARDINAL,
|
||||
util::PropMode::Replace,
|
||||
&[libc::getpid() as util::Cardinal],
|
||||
)
|
||||
.queue();
|
||||
let flusher = self.xconn.change_property(
|
||||
self.xwindow,
|
||||
client_machine_atom,
|
||||
|
|
@ -489,13 +508,19 @@ impl UnownedWindow {
|
|||
|
||||
#[inline]
|
||||
pub fn set_urgent(&self, is_urgent: bool) {
|
||||
let mut wm_hints = self.xconn.get_wm_hints(self.xwindow).expect("`XGetWMHints` failed");
|
||||
let mut wm_hints = self
|
||||
.xconn
|
||||
.get_wm_hints(self.xwindow)
|
||||
.expect("`XGetWMHints` failed");
|
||||
if is_urgent {
|
||||
(*wm_hints).flags |= ffi::XUrgencyHint;
|
||||
} else {
|
||||
(*wm_hints).flags &= !ffi::XUrgencyHint;
|
||||
}
|
||||
self.xconn.set_wm_hints(self.xwindow, wm_hints).flush().expect("Failed to set urgency hint");
|
||||
self.xconn
|
||||
.set_wm_hints(self.xwindow, wm_hints)
|
||||
.flush()
|
||||
.expect("Failed to set urgency hint");
|
||||
}
|
||||
|
||||
fn set_netwm(
|
||||
|
|
@ -520,7 +545,8 @@ impl UnownedWindow {
|
|||
}
|
||||
|
||||
fn set_fullscreen_hint(&self, fullscreen: bool) -> util::Flusher<'_> {
|
||||
let fullscreen_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE_FULLSCREEN\0") };
|
||||
let fullscreen_atom =
|
||||
unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE_FULLSCREEN\0") };
|
||||
self.set_netwm(fullscreen.into(), (fullscreen_atom as c_long, 0, 0, 0))
|
||||
}
|
||||
|
||||
|
|
@ -533,13 +559,16 @@ impl UnownedWindow {
|
|||
}
|
||||
flusher
|
||||
},
|
||||
Some(RootMonitorHandle { inner: PlatformMonitorHandle::X(monitor) }) => {
|
||||
Some(RootMonitorHandle {
|
||||
inner: PlatformMonitorHandle::X(monitor),
|
||||
}) => {
|
||||
let window_position = self.outer_position_physical();
|
||||
self.shared_state.lock().restore_position = Some(window_position);
|
||||
let monitor_origin: (i32, i32) = monitor.position().into();
|
||||
self.set_position_inner(monitor_origin.0, monitor_origin.1).queue();
|
||||
self.set_position_inner(monitor_origin.0, monitor_origin.1)
|
||||
.queue();
|
||||
self.set_fullscreen_hint(true)
|
||||
}
|
||||
},
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
|
@ -567,17 +596,15 @@ impl UnownedWindow {
|
|||
|
||||
#[inline]
|
||||
pub fn current_monitor(&self) -> X11MonitorHandle {
|
||||
let monitor = self.shared_state
|
||||
.lock()
|
||||
.last_monitor
|
||||
.as_ref()
|
||||
.cloned();
|
||||
monitor
|
||||
.unwrap_or_else(|| {
|
||||
let monitor = self.xconn.get_monitor_for_window(Some(self.get_rect())).to_owned();
|
||||
self.shared_state.lock().last_monitor = Some(monitor.clone());
|
||||
monitor
|
||||
})
|
||||
let monitor = self.shared_state.lock().last_monitor.as_ref().cloned();
|
||||
monitor.unwrap_or_else(|| {
|
||||
let monitor = self
|
||||
.xconn
|
||||
.get_monitor_for_window(Some(self.get_rect()))
|
||||
.to_owned();
|
||||
self.shared_state.lock().last_monitor = Some(monitor.clone());
|
||||
monitor
|
||||
})
|
||||
}
|
||||
|
||||
pub fn available_monitors(&self) -> Vec<X11MonitorHandle> {
|
||||
|
|
@ -589,9 +616,18 @@ impl UnownedWindow {
|
|||
}
|
||||
|
||||
fn set_maximized_inner(&self, maximized: bool) -> util::Flusher<'_> {
|
||||
let horz_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE_MAXIMIZED_HORZ\0") };
|
||||
let vert_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE_MAXIMIZED_VERT\0") };
|
||||
self.set_netwm(maximized.into(), (horz_atom as c_long, vert_atom as c_long, 0, 0))
|
||||
let horz_atom = unsafe {
|
||||
self.xconn
|
||||
.get_atom_unchecked(b"_NET_WM_STATE_MAXIMIZED_HORZ\0")
|
||||
};
|
||||
let vert_atom = unsafe {
|
||||
self.xconn
|
||||
.get_atom_unchecked(b"_NET_WM_STATE_MAXIMIZED_VERT\0")
|
||||
};
|
||||
self.set_netwm(
|
||||
maximized.into(),
|
||||
(horz_atom as c_long, vert_atom as c_long, 0, 0),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -638,10 +674,10 @@ impl UnownedWindow {
|
|||
util::PropMode::Replace,
|
||||
&[
|
||||
util::MWM_HINTS_DECORATIONS, // flags
|
||||
0, // functions
|
||||
decorations as c_ulong, // decorations
|
||||
0, // input mode
|
||||
0, // status
|
||||
0, // functions
|
||||
decorations as c_ulong, // decorations
|
||||
0, // input mode
|
||||
0, // status
|
||||
],
|
||||
)
|
||||
}
|
||||
|
|
@ -695,7 +731,9 @@ impl UnownedWindow {
|
|||
match icon {
|
||||
Some(icon) => self.set_icon_inner(icon),
|
||||
None => self.unset_icon_inner(),
|
||||
}.flush().expect("Failed to set icons");
|
||||
}
|
||||
.flush()
|
||||
.expect("Failed to set icons");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -703,19 +741,23 @@ impl UnownedWindow {
|
|||
match visible {
|
||||
true => unsafe {
|
||||
(self.xconn.xlib.XMapRaised)(self.xconn.display, self.xwindow);
|
||||
self.xconn.flush_requests()
|
||||
self.xconn
|
||||
.flush_requests()
|
||||
.expect("Failed to call XMapRaised");
|
||||
},
|
||||
false => unsafe {
|
||||
(self.xconn.xlib.XUnmapWindow)(self.xconn.display, self.xwindow);
|
||||
self.xconn.flush_requests()
|
||||
self.xconn
|
||||
.flush_requests()
|
||||
.expect("Failed to call XUnmapWindow");
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn update_cached_frame_extents(&self) {
|
||||
let extents = self.xconn.get_frame_extents_heuristic(self.xwindow, self.root);
|
||||
let extents = self
|
||||
.xconn
|
||||
.get_frame_extents_heuristic(self.xwindow, self.root);
|
||||
(*self.shared_state.lock()).frame_extents = Some(extents);
|
||||
}
|
||||
|
||||
|
|
@ -749,7 +791,8 @@ impl UnownedWindow {
|
|||
pub(crate) fn inner_position_physical(&self) -> (i32, i32) {
|
||||
// This should be okay to unwrap since the only error XTranslateCoordinates can return
|
||||
// is BadWindow, and if the window handle is bad we have bigger problems.
|
||||
self.xconn.translate_coords(self.xwindow, self.root)
|
||||
self.xconn
|
||||
.translate_coords(self.xwindow, self.root)
|
||||
.map(|coords| (coords.x_rel_root, coords.y_rel_root))
|
||||
.unwrap()
|
||||
}
|
||||
|
|
@ -773,12 +816,7 @@ impl UnownedWindow {
|
|||
}
|
||||
}
|
||||
unsafe {
|
||||
(self.xconn.xlib.XMoveWindow)(
|
||||
self.xconn.display,
|
||||
self.xwindow,
|
||||
x as c_int,
|
||||
y as c_int,
|
||||
);
|
||||
(self.xconn.xlib.XMoveWindow)(self.xconn.display, self.xwindow, x as c_int, y as c_int);
|
||||
}
|
||||
util::Flusher::new(&self.xconn)
|
||||
}
|
||||
|
|
@ -798,7 +836,8 @@ impl UnownedWindow {
|
|||
pub(crate) fn inner_size_physical(&self) -> (u32, u32) {
|
||||
// This should be okay to unwrap since the only error XGetGeometry can return
|
||||
// is BadWindow, and if the window handle is bad we have bigger problems.
|
||||
self.xconn.get_geometry(self.xwindow)
|
||||
self.xconn
|
||||
.get_geometry(self.xwindow)
|
||||
.map(|geo| (geo.width, geo.height))
|
||||
.unwrap()
|
||||
}
|
||||
|
|
@ -840,7 +879,8 @@ impl UnownedWindow {
|
|||
height as c_uint,
|
||||
);
|
||||
self.xconn.flush_requests()
|
||||
}.expect("Failed to call `XResizeWindow`");
|
||||
}
|
||||
.expect("Failed to call `XResizeWindow`");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -851,11 +891,14 @@ impl UnownedWindow {
|
|||
}
|
||||
|
||||
fn update_normal_hints<F>(&self, callback: F) -> Result<(), XError>
|
||||
where F: FnOnce(&mut util::NormalHints<'_>) -> ()
|
||||
where
|
||||
F: FnOnce(&mut util::NormalHints<'_>) -> (),
|
||||
{
|
||||
let mut normal_hints = self.xconn.get_normal_hints(self.xwindow)?;
|
||||
callback(&mut normal_hints);
|
||||
self.xconn.set_normal_hints(self.xwindow, normal_hints).flush()
|
||||
self.xconn
|
||||
.set_normal_hints(self.xwindow, normal_hints)
|
||||
.flush()
|
||||
}
|
||||
|
||||
pub(crate) fn set_min_inner_size_physical(&self, dimensions: Option<(u32, u32)>) {
|
||||
|
|
@ -866,9 +909,8 @@ impl UnownedWindow {
|
|||
#[inline]
|
||||
pub fn set_min_inner_size(&self, logical_dimensions: Option<LogicalSize>) {
|
||||
self.shared_state.lock().min_inner_size = logical_dimensions;
|
||||
let physical_dimensions = logical_dimensions.map(|logical_dimensions| {
|
||||
logical_dimensions.to_physical(self.hidpi_factor()).into()
|
||||
});
|
||||
let physical_dimensions = logical_dimensions
|
||||
.map(|logical_dimensions| logical_dimensions.to_physical(self.hidpi_factor()).into());
|
||||
self.set_min_inner_size_physical(physical_dimensions);
|
||||
}
|
||||
|
||||
|
|
@ -880,9 +922,8 @@ impl UnownedWindow {
|
|||
#[inline]
|
||||
pub fn set_max_inner_size(&self, logical_dimensions: Option<LogicalSize>) {
|
||||
self.shared_state.lock().max_inner_size = logical_dimensions;
|
||||
let physical_dimensions = logical_dimensions.map(|logical_dimensions| {
|
||||
logical_dimensions.to_physical(self.hidpi_factor()).into()
|
||||
});
|
||||
let physical_dimensions = logical_dimensions
|
||||
.map(|logical_dimensions| logical_dimensions.to_physical(self.hidpi_factor()).into());
|
||||
self.set_max_inner_size_physical(physical_dimensions);
|
||||
}
|
||||
|
||||
|
|
@ -910,7 +951,8 @@ impl UnownedWindow {
|
|||
normal_hints.set_min_size(min_size);
|
||||
normal_hints.set_resize_increments(resize_increments);
|
||||
normal_hints.set_base_size(base_size);
|
||||
}).expect("Failed to update normal hints");
|
||||
})
|
||||
.expect("Failed to update normal hints");
|
||||
unsafe {
|
||||
(self.xconn.xlib.XResizeWindow)(
|
||||
self.xconn.display,
|
||||
|
|
@ -933,7 +975,10 @@ impl UnownedWindow {
|
|||
|
||||
let (logical_min, logical_max) = if resizable {
|
||||
let shared_state_lock = self.shared_state.lock();
|
||||
(shared_state_lock.min_inner_size, shared_state_lock.max_inner_size)
|
||||
(
|
||||
shared_state_lock.min_inner_size,
|
||||
shared_state_lock.max_inner_size,
|
||||
)
|
||||
} else {
|
||||
let window_size = Some(self.inner_size());
|
||||
(window_size.clone(), window_size)
|
||||
|
|
@ -949,7 +994,8 @@ impl UnownedWindow {
|
|||
self.update_normal_hints(|normal_hints| {
|
||||
normal_hints.set_min_size(min_inner_size);
|
||||
normal_hints.set_max_size(max_inner_size);
|
||||
}).expect("Failed to call `XSetWMNormalHints`");
|
||||
})
|
||||
.expect("Failed to call `XSetWMNormalHints`");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -974,9 +1020,7 @@ impl UnownedWindow {
|
|||
|
||||
#[inline]
|
||||
pub fn xcb_connection(&self) -> *mut c_void {
|
||||
unsafe {
|
||||
(self.xconn.xlib_xcb.XGetXCBConnection)(self.xconn.display) as *mut _
|
||||
}
|
||||
unsafe { (self.xconn.xlib_xcb.XGetXCBConnection)(self.xconn.display) as *mut _ }
|
||||
}
|
||||
|
||||
fn load_cursor(&self, name: &[u8]) -> ffi::Cursor {
|
||||
|
|
@ -999,13 +1043,9 @@ impl UnownedWindow {
|
|||
}
|
||||
|
||||
fn get_cursor(&self, cursor: CursorIcon) -> ffi::Cursor {
|
||||
let load = |name: &[u8]| {
|
||||
self.load_cursor(name)
|
||||
};
|
||||
let load = |name: &[u8]| self.load_cursor(name);
|
||||
|
||||
let loadn = |names: &[&[u8]]| {
|
||||
self.load_first_existing_cursor(names)
|
||||
};
|
||||
let loadn = |names: &[&[u8]]| self.load_first_existing_cursor(names);
|
||||
|
||||
// Try multiple names in some cases where the name
|
||||
// differs on the desktop environments or themes.
|
||||
|
|
@ -1030,7 +1070,6 @@ impl UnownedWindow {
|
|||
CursorIcon::NoDrop => loadn(&[b"no-drop\0", b"circle\0"]),
|
||||
CursorIcon::NotAllowed => load(b"crossed_circle\0"),
|
||||
|
||||
|
||||
// Resize cursors
|
||||
CursorIcon::EResize => load(b"right_side\0"),
|
||||
CursorIcon::NResize => load(b"top_side\0"),
|
||||
|
|
@ -1063,7 +1102,9 @@ impl UnownedWindow {
|
|||
if cursor != 0 {
|
||||
(self.xconn.xlib.XFreeCursor)(self.xconn.display, cursor);
|
||||
}
|
||||
self.xconn.flush_requests().expect("Failed to set or free the cursor");
|
||||
self.xconn
|
||||
.flush_requests()
|
||||
.expect("Failed to set or free the cursor");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1081,13 +1122,7 @@ impl UnownedWindow {
|
|||
fn create_empty_cursor(&self) -> Option<ffi::Cursor> {
|
||||
let data = 0;
|
||||
let pixmap = unsafe {
|
||||
(self.xconn.xlib.XCreateBitmapFromData)(
|
||||
self.xconn.display,
|
||||
self.xwindow,
|
||||
&data,
|
||||
1,
|
||||
1,
|
||||
)
|
||||
(self.xconn.xlib.XCreateBitmapFromData)(self.xconn.display, self.xwindow, &data, 1, 1)
|
||||
};
|
||||
if pixmap == 0 {
|
||||
// Failed to allocate
|
||||
|
|
@ -1116,7 +1151,9 @@ impl UnownedWindow {
|
|||
#[inline]
|
||||
pub fn set_cursor_grab(&self, grab: bool) -> Result<(), ExternalError> {
|
||||
let mut grabbed_lock = self.cursor_grabbed.lock();
|
||||
if grab == *grabbed_lock { return Ok(()); }
|
||||
if grab == *grabbed_lock {
|
||||
return Ok(());
|
||||
}
|
||||
unsafe {
|
||||
// We ungrab before grabbing to prevent passive grabs from causing `AlreadyGrabbed`.
|
||||
// Therefore, this is common to both codepaths.
|
||||
|
|
@ -1128,8 +1165,7 @@ impl UnownedWindow {
|
|||
self.xconn.display,
|
||||
self.xwindow,
|
||||
ffi::True,
|
||||
(
|
||||
ffi::ButtonPressMask
|
||||
(ffi::ButtonPressMask
|
||||
| ffi::ButtonReleaseMask
|
||||
| ffi::EnterWindowMask
|
||||
| ffi::LeaveWindowMask
|
||||
|
|
@ -1141,8 +1177,7 @@ impl UnownedWindow {
|
|||
| ffi::Button4MotionMask
|
||||
| ffi::Button5MotionMask
|
||||
| ffi::ButtonMotionMask
|
||||
| ffi::KeymapStateMask
|
||||
) as c_uint,
|
||||
| ffi::KeymapStateMask) as c_uint,
|
||||
ffi::GrabModeAsync,
|
||||
ffi::GrabModeAsync,
|
||||
self.xwindow,
|
||||
|
|
@ -1153,14 +1188,20 @@ impl UnownedWindow {
|
|||
|
||||
match result {
|
||||
ffi::GrabSuccess => Ok(()),
|
||||
ffi::AlreadyGrabbed => Err("Cursor could not be grabbed: already grabbed by another client"),
|
||||
ffi::AlreadyGrabbed => {
|
||||
Err("Cursor could not be grabbed: already grabbed by another client")
|
||||
},
|
||||
ffi::GrabInvalidTime => Err("Cursor could not be grabbed: invalid time"),
|
||||
ffi::GrabNotViewable => Err("Cursor could not be grabbed: grab location not viewable"),
|
||||
ffi::GrabNotViewable => {
|
||||
Err("Cursor could not be grabbed: grab location not viewable")
|
||||
},
|
||||
ffi::GrabFrozen => Err("Cursor could not be grabbed: frozen by another client"),
|
||||
_ => unreachable!(),
|
||||
}.map_err(|err| ExternalError::Os(os_error!(OsError::XMisc(err))))
|
||||
}
|
||||
.map_err(|err| ExternalError::Os(os_error!(OsError::XMisc(err))))
|
||||
} else {
|
||||
self.xconn.flush_requests()
|
||||
self.xconn
|
||||
.flush_requests()
|
||||
.map_err(|err| ExternalError::Os(os_error!(OsError::XError(err))))
|
||||
};
|
||||
if result.is_ok() {
|
||||
|
|
@ -1172,11 +1213,14 @@ impl UnownedWindow {
|
|||
#[inline]
|
||||
pub fn set_cursor_visible(&self, visible: bool) {
|
||||
let mut visible_lock = self.cursor_visible.lock();
|
||||
if visible == *visible_lock {return; }
|
||||
if visible == *visible_lock {
|
||||
return;
|
||||
}
|
||||
let cursor = if visible {
|
||||
self.get_cursor(*self.cursor.lock())
|
||||
} else {
|
||||
self.create_empty_cursor().expect("Failed to create empty cursor")
|
||||
self.create_empty_cursor()
|
||||
.expect("Failed to create empty cursor")
|
||||
};
|
||||
*visible_lock = visible;
|
||||
drop(visible_lock);
|
||||
|
|
@ -1190,29 +1234,25 @@ impl UnownedWindow {
|
|||
|
||||
pub fn set_cursor_position_physical(&self, x: i32, y: i32) -> Result<(), ExternalError> {
|
||||
unsafe {
|
||||
(self.xconn.xlib.XWarpPointer)(
|
||||
self.xconn.display,
|
||||
0,
|
||||
self.xwindow,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
x,
|
||||
y,
|
||||
);
|
||||
self.xconn.flush_requests().map_err(|e| ExternalError::Os(os_error!(OsError::XError(e))))
|
||||
(self.xconn.xlib.XWarpPointer)(self.xconn.display, 0, self.xwindow, 0, 0, 0, 0, x, y);
|
||||
self.xconn
|
||||
.flush_requests()
|
||||
.map_err(|e| ExternalError::Os(os_error!(OsError::XError(e))))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_cursor_position(&self, logical_position: LogicalPosition) -> Result<(), ExternalError> {
|
||||
pub fn set_cursor_position(
|
||||
&self,
|
||||
logical_position: LogicalPosition,
|
||||
) -> Result<(), ExternalError> {
|
||||
let (x, y) = logical_position.to_physical(self.hidpi_factor()).into();
|
||||
self.set_cursor_position_physical(x, y)
|
||||
}
|
||||
|
||||
pub(crate) fn set_ime_position_physical(&self, x: i32, y: i32) {
|
||||
let _ = self.ime_sender
|
||||
let _ = self
|
||||
.ime_sender
|
||||
.lock()
|
||||
.send((self.xwindow, x as i16, y as i16));
|
||||
}
|
||||
|
|
@ -1224,10 +1264,15 @@ impl UnownedWindow {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn id(&self) -> WindowId { WindowId(self.xwindow) }
|
||||
pub fn id(&self) -> WindowId {
|
||||
WindowId(self.xwindow)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn request_redraw(&self) {
|
||||
self.pending_redraws.lock().unwrap().insert(WindowId(self.xwindow));
|
||||
self.pending_redraws
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(WindowId(self.xwindow));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
use std::ptr;
|
||||
use std::fmt;
|
||||
use std::error::Error;
|
||||
use std::os::raw::c_int;
|
||||
use std::{error::Error, fmt, os::raw::c_int, ptr};
|
||||
|
||||
use libc;
|
||||
use parking_lot::Mutex;
|
||||
|
|
@ -27,7 +24,8 @@ pub struct XConnection {
|
|||
unsafe impl Send for XConnection {}
|
||||
unsafe impl Sync for XConnection {}
|
||||
|
||||
pub type XErrorHandler = Option<unsafe extern fn(*mut ffi::Display, *mut ffi::XErrorEvent) -> libc::c_int>;
|
||||
pub type XErrorHandler =
|
||||
Option<unsafe extern "C" fn(*mut ffi::Display, *mut ffi::XErrorEvent) -> libc::c_int>;
|
||||
|
||||
impl XConnection {
|
||||
pub fn new(error_handler: XErrorHandler) -> Result<XConnection, XNotSupported> {
|
||||
|
|
@ -53,9 +51,7 @@ impl XConnection {
|
|||
};
|
||||
|
||||
// Get X11 socket file descriptor
|
||||
let fd = unsafe {
|
||||
(xlib.XConnectionNumber)(display)
|
||||
};
|
||||
let fd = unsafe { (xlib.XConnectionNumber)(display) };
|
||||
|
||||
Ok(XConnection {
|
||||
xlib,
|
||||
|
|
@ -120,8 +116,11 @@ impl Error for XError {
|
|||
|
||||
impl fmt::Display for XError {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
write!(formatter, "X error: {} (code: {}, request code: {}, minor code: {})",
|
||||
self.description, self.error_code, self.request_code, self.minor_code)
|
||||
write!(
|
||||
formatter,
|
||||
"X error: {} (code: {}, request code: {}, minor code: {})",
|
||||
self.description, self.error_code, self.request_code, self.minor_code
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -131,7 +130,7 @@ pub enum XNotSupported {
|
|||
/// Failed to load one or several shared libraries.
|
||||
LibraryOpenError(ffi::OpenError),
|
||||
/// Connecting to the X server with `XOpenDisplay` failed.
|
||||
XOpenDisplayFailed, // TODO: add better message
|
||||
XOpenDisplayFailed, // TODO: add better message
|
||||
}
|
||||
|
||||
impl From<ffi::OpenError> for XNotSupported {
|
||||
|
|
@ -154,7 +153,7 @@ impl Error for XNotSupported {
|
|||
fn cause(&self) -> Option<&dyn Error> {
|
||||
match *self {
|
||||
XNotSupported::LibraryOpenError(ref err) => Some(err),
|
||||
_ => None
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue