mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2025-01-11 13:31:29 +11:00
X11: Flatten window model (#536)
This commit is contained in:
parent
30f798b246
commit
4372f6fdac
|
@ -1,5 +1,8 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
- On X11, the `Moved` event is no longer sent when the window is resized without changing position.
|
||||||
|
- `MouseCursor` and `CursorState` now implement `Default`.
|
||||||
|
|
||||||
# Version 0.15.0 (2018-05-22)
|
# Version 0.15.0 (2018-05-22)
|
||||||
|
|
||||||
- `Icon::to_cardinals` is no longer public, since it was never supposed to be.
|
- `Icon::to_cardinals` is no longer public, since it was never supposed to be.
|
||||||
|
|
12
src/lib.rs
12
src/lib.rs
|
@ -374,6 +374,12 @@ pub enum MouseCursor {
|
||||||
RowResize,
|
RowResize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for MouseCursor {
|
||||||
|
fn default() -> Self {
|
||||||
|
MouseCursor::Default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Describes how winit handles the cursor.
|
/// Describes how winit handles the cursor.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub enum CursorState {
|
pub enum CursorState {
|
||||||
|
@ -391,6 +397,12 @@ pub enum CursorState {
|
||||||
Grab,
|
Grab,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for CursorState {
|
||||||
|
fn default() -> Self {
|
||||||
|
CursorState::Normal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Attributes to use when creating a window.
|
/// Attributes to use when creating a window.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct WindowAttributes {
|
pub struct WindowAttributes {
|
||||||
|
|
|
@ -14,17 +14,19 @@ pub use self::monitor::{
|
||||||
get_available_monitors,
|
get_available_monitors,
|
||||||
get_monitor_for_window,
|
get_monitor_for_window,
|
||||||
get_primary_monitor,
|
get_primary_monitor,
|
||||||
|
invalidate_cached_monitor_list,
|
||||||
};
|
};
|
||||||
pub use self::window::{Window2, XWindow};
|
pub use self::window::UnownedWindow;
|
||||||
pub use self::xdisplay::{XConnection, XNotSupported, XError};
|
pub use self::xdisplay::{XConnection, XNotSupported, XError};
|
||||||
|
|
||||||
use std::{mem, ptr, slice};
|
use std::{mem, ptr, slice};
|
||||||
use std::sync::{Arc, mpsc, Weak};
|
|
||||||
use std::sync::atomic::{self, AtomicBool};
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::os::raw::*;
|
use std::os::raw::*;
|
||||||
|
use std::sync::{Arc, mpsc, Weak};
|
||||||
|
use std::sync::atomic::{self, AtomicBool};
|
||||||
|
|
||||||
use libc::{self, setlocale, LC_CTYPE};
|
use libc::{self, setlocale, LC_CTYPE};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
@ -45,16 +47,14 @@ use self::dnd::{Dnd, DndState};
|
||||||
use self::ime::{ImeReceiver, ImeSender, ImeCreationError, Ime};
|
use self::ime::{ImeReceiver, ImeSender, ImeCreationError, Ime};
|
||||||
|
|
||||||
pub struct EventsLoop {
|
pub struct EventsLoop {
|
||||||
display: Arc<XConnection>,
|
xconn: Arc<XConnection>,
|
||||||
wm_delete_window: ffi::Atom,
|
wm_delete_window: ffi::Atom,
|
||||||
dnd: Dnd,
|
dnd: Dnd,
|
||||||
ime_receiver: ImeReceiver,
|
ime_receiver: ImeReceiver,
|
||||||
ime_sender: ImeSender,
|
ime_sender: ImeSender,
|
||||||
ime: RefCell<Ime>,
|
ime: RefCell<Ime>,
|
||||||
randr_event_offset: c_int,
|
randr_event_offset: c_int,
|
||||||
windows: Arc<Mutex<HashMap<WindowId, WindowData>>>,
|
windows: RefCell<HashMap<WindowId, Weak<UnownedWindow>>>,
|
||||||
// Please don't laugh at this type signature
|
|
||||||
shared_state: RefCell<HashMap<WindowId, Weak<Mutex<window::SharedState>>>>,
|
|
||||||
devices: RefCell<HashMap<DeviceId, Device>>,
|
devices: RefCell<HashMap<DeviceId, Device>>,
|
||||||
xi2ext: XExtension,
|
xi2ext: XExtension,
|
||||||
pending_wakeup: Arc<AtomicBool>,
|
pending_wakeup: Arc<AtomicBool>,
|
||||||
|
@ -67,17 +67,17 @@ pub struct EventsLoop {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct EventsLoopProxy {
|
pub struct EventsLoopProxy {
|
||||||
pending_wakeup: Weak<AtomicBool>,
|
pending_wakeup: Weak<AtomicBool>,
|
||||||
display: Weak<XConnection>,
|
xconn: Weak<XConnection>,
|
||||||
wakeup_dummy_window: ffi::Window,
|
wakeup_dummy_window: ffi::Window,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventsLoop {
|
impl EventsLoop {
|
||||||
pub fn new(display: Arc<XConnection>) -> EventsLoop {
|
pub fn new(xconn: Arc<XConnection>) -> EventsLoop {
|
||||||
let root = unsafe { (display.xlib.XDefaultRootWindow)(display.display) };
|
let root = unsafe { (xconn.xlib.XDefaultRootWindow)(xconn.display) };
|
||||||
|
|
||||||
let wm_delete_window = unsafe { display.get_atom_unchecked(b"WM_DELETE_WINDOW\0") };
|
let wm_delete_window = unsafe { xconn.get_atom_unchecked(b"WM_DELETE_WINDOW\0") };
|
||||||
|
|
||||||
let dnd = Dnd::new(Arc::clone(&display))
|
let dnd = Dnd::new(Arc::clone(&xconn))
|
||||||
.expect("Failed to call XInternAtoms when initializing drag and drop");
|
.expect("Failed to call XInternAtoms when initializing drag and drop");
|
||||||
|
|
||||||
let (ime_sender, ime_receiver) = mpsc::channel();
|
let (ime_sender, ime_receiver) = mpsc::channel();
|
||||||
|
@ -85,14 +85,14 @@ impl EventsLoop {
|
||||||
// possible to actually commit pre-edit sequences.
|
// 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 ime = RefCell::new({
|
||||||
let result = Ime::new(Arc::clone(&display));
|
let result = Ime::new(Arc::clone(&xconn));
|
||||||
if let Err(ImeCreationError::OpenFailure(ref state)) = result {
|
if let Err(ImeCreationError::OpenFailure(ref state)) = result {
|
||||||
panic!(format!("Failed to open input method: {:#?}", state));
|
panic!(format!("Failed to open input method: {:#?}", state));
|
||||||
}
|
}
|
||||||
result.expect("Failed to set input method destruction callback")
|
result.expect("Failed to set input method destruction callback")
|
||||||
});
|
});
|
||||||
|
|
||||||
let randr_event_offset = monitor::select_input(&display, root)
|
let randr_event_offset = monitor::select_input(&xconn, root)
|
||||||
.expect("Failed to query XRandR extension");
|
.expect("Failed to query XRandR extension");
|
||||||
|
|
||||||
let xi2ext = unsafe {
|
let xi2ext = unsafe {
|
||||||
|
@ -101,8 +101,8 @@ impl EventsLoop {
|
||||||
first_event_id: mem::uninitialized(),
|
first_event_id: mem::uninitialized(),
|
||||||
first_error_id: mem::uninitialized(),
|
first_error_id: mem::uninitialized(),
|
||||||
};
|
};
|
||||||
let res = (display.xlib.XQueryExtension)(
|
let res = (xconn.xlib.XQueryExtension)(
|
||||||
display.display,
|
xconn.display,
|
||||||
b"XInputExtension\0".as_ptr() as *const c_char,
|
b"XInputExtension\0".as_ptr() as *const c_char,
|
||||||
&mut result.opcode as *mut c_int,
|
&mut result.opcode as *mut c_int,
|
||||||
&mut result.first_event_id as *mut c_int,
|
&mut result.first_event_id as *mut c_int,
|
||||||
|
@ -116,8 +116,8 @@ impl EventsLoop {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut xinput_major_ver = ffi::XI_2_Major;
|
let mut xinput_major_ver = ffi::XI_2_Major;
|
||||||
let mut xinput_minor_ver = ffi::XI_2_Minor;
|
let mut xinput_minor_ver = ffi::XI_2_Minor;
|
||||||
if (display.xinput2.XIQueryVersion)(
|
if (xconn.xinput2.XIQueryVersion)(
|
||||||
display.display,
|
xconn.display,
|
||||||
&mut xinput_major_ver,
|
&mut xinput_major_ver,
|
||||||
&mut xinput_minor_ver,
|
&mut xinput_minor_ver,
|
||||||
) != ffi::Success as libc::c_int {
|
) != ffi::Success as libc::c_int {
|
||||||
|
@ -129,13 +129,13 @@ impl EventsLoop {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
display.update_cached_wm_info(root);
|
xconn.update_cached_wm_info(root);
|
||||||
|
|
||||||
let wakeup_dummy_window = unsafe {
|
let wakeup_dummy_window = unsafe {
|
||||||
let (x, y, w, h) = (10, 10, 10, 10);
|
let (x, y, w, h) = (10, 10, 10, 10);
|
||||||
let (border_w, border_px, background_px) = (0, 0, 0);
|
let (border_w, border_px, background_px) = (0, 0, 0);
|
||||||
(display.xlib.XCreateSimpleWindow)(
|
(xconn.xlib.XCreateSimpleWindow)(
|
||||||
display.display,
|
xconn.display,
|
||||||
root,
|
root,
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
|
@ -148,25 +148,28 @@ impl EventsLoop {
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = EventsLoop {
|
let result = EventsLoop {
|
||||||
pending_wakeup: Arc::new(AtomicBool::new(false)),
|
xconn,
|
||||||
display,
|
|
||||||
wm_delete_window,
|
wm_delete_window,
|
||||||
dnd,
|
dnd,
|
||||||
ime_receiver,
|
ime_receiver,
|
||||||
ime_sender,
|
ime_sender,
|
||||||
ime,
|
ime,
|
||||||
randr_event_offset,
|
randr_event_offset,
|
||||||
windows: Arc::new(Mutex::new(HashMap::new())),
|
windows: Default::default(),
|
||||||
shared_state: RefCell::new(HashMap::new()),
|
devices: Default::default(),
|
||||||
devices: RefCell::new(HashMap::new()),
|
|
||||||
xi2ext,
|
xi2ext,
|
||||||
|
pending_wakeup: Default::default(),
|
||||||
root,
|
root,
|
||||||
wakeup_dummy_window,
|
wakeup_dummy_window,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Register for device hotplug events
|
// Register for device hotplug events
|
||||||
// (The request buffer is flushed during `init_device`)
|
// (The request buffer is flushed during `init_device`)
|
||||||
result.display.select_xinput_events(root, ffi::XIAllDevices, ffi::XI_HierarchyChangedMask).queue();
|
result.xconn.select_xinput_events(
|
||||||
|
root,
|
||||||
|
ffi::XIAllDevices,
|
||||||
|
ffi::XI_HierarchyChangedMask,
|
||||||
|
).queue();
|
||||||
|
|
||||||
result.init_device(ffi::XIAllDevices);
|
result.init_device(ffi::XIAllDevices);
|
||||||
|
|
||||||
|
@ -176,13 +179,13 @@ impl EventsLoop {
|
||||||
/// Returns the `XConnection` of this events loop.
|
/// Returns the `XConnection` of this events loop.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn x_connection(&self) -> &Arc<XConnection> {
|
pub fn x_connection(&self) -> &Arc<XConnection> {
|
||||||
&self.display
|
&self.xconn
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_proxy(&self) -> EventsLoopProxy {
|
pub fn create_proxy(&self) -> EventsLoopProxy {
|
||||||
EventsLoopProxy {
|
EventsLoopProxy {
|
||||||
pending_wakeup: Arc::downgrade(&self.pending_wakeup),
|
pending_wakeup: Arc::downgrade(&self.pending_wakeup),
|
||||||
display: Arc::downgrade(&self.display),
|
xconn: Arc::downgrade(&self.xconn),
|
||||||
wakeup_dummy_window: self.wakeup_dummy_window,
|
wakeup_dummy_window: self.wakeup_dummy_window,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,12 +198,12 @@ impl EventsLoop {
|
||||||
// Get next event
|
// Get next event
|
||||||
unsafe {
|
unsafe {
|
||||||
// Ensure XNextEvent won't block
|
// Ensure XNextEvent won't block
|
||||||
let count = (self.display.xlib.XPending)(self.display.display);
|
let count = (self.xconn.xlib.XPending)(self.xconn.display);
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
(self.display.xlib.XNextEvent)(self.display.display, &mut xev);
|
(self.xconn.xlib.XNextEvent)(self.xconn.display, &mut xev);
|
||||||
}
|
}
|
||||||
self.process_event(&mut xev, &mut callback);
|
self.process_event(&mut xev, &mut callback);
|
||||||
}
|
}
|
||||||
|
@ -212,7 +215,7 @@ impl EventsLoop {
|
||||||
let mut xev = unsafe { mem::uninitialized() };
|
let mut xev = unsafe { mem::uninitialized() };
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
unsafe { (self.display.xlib.XNextEvent)(self.display.display, &mut xev) }; // Blocks as necessary
|
unsafe { (self.xconn.xlib.XNextEvent)(self.xconn.display, &mut xev) }; // Blocks as necessary
|
||||||
|
|
||||||
let mut control_flow = ControlFlow::Continue;
|
let mut control_flow = ControlFlow::Continue;
|
||||||
|
|
||||||
|
@ -236,13 +239,11 @@ impl EventsLoop {
|
||||||
fn process_event<F>(&mut self, xev: &mut ffi::XEvent, mut callback: F)
|
fn process_event<F>(&mut self, xev: &mut ffi::XEvent, mut callback: F)
|
||||||
where F: FnMut(Event)
|
where F: FnMut(Event)
|
||||||
{
|
{
|
||||||
let xlib = &self.display.xlib;
|
|
||||||
|
|
||||||
// XFilterEvent tells us when an event has been discarded by the input method.
|
// XFilterEvent tells us when an event has been discarded by the input method.
|
||||||
// Specifically, this involves all of the KeyPress events in compose/pre-edit sequences,
|
// 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
|
// along with an extra copy of the KeyRelease events. This also prevents backspace and
|
||||||
// arrow keys from being detected twice.
|
// arrow keys from being detected twice.
|
||||||
if ffi::True == unsafe { (self.display.xlib.XFilterEvent)(
|
if ffi::True == unsafe { (self.xconn.xlib.XFilterEvent)(
|
||||||
xev,
|
xev,
|
||||||
{ let xev: &ffi::XAnyEvent = xev.as_ref(); xev.window }
|
{ let xev: &ffi::XAnyEvent = xev.as_ref(); xev.window }
|
||||||
) } {
|
) } {
|
||||||
|
@ -252,8 +253,8 @@ impl EventsLoop {
|
||||||
let event_type = xev.get_type();
|
let event_type = xev.get_type();
|
||||||
match event_type {
|
match event_type {
|
||||||
ffi::MappingNotify => {
|
ffi::MappingNotify => {
|
||||||
unsafe { (xlib.XRefreshKeyboardMapping)(xev.as_mut()); }
|
unsafe { (self.xconn.xlib.XRefreshKeyboardMapping)(xev.as_mut()); }
|
||||||
self.display.check_errors().expect("Failed to call XRefreshKeyboardMapping");
|
self.xconn.check_errors().expect("Failed to call XRefreshKeyboardMapping");
|
||||||
}
|
}
|
||||||
|
|
||||||
ffi::ClientMessage => {
|
ffi::ClientMessage => {
|
||||||
|
@ -394,124 +395,92 @@ impl EventsLoop {
|
||||||
|
|
||||||
ffi::ConfigureNotify => {
|
ffi::ConfigureNotify => {
|
||||||
let xev: &ffi::XConfigureEvent = xev.as_ref();
|
let xev: &ffi::XConfigureEvent = xev.as_ref();
|
||||||
|
let xwindow = xev.window;
|
||||||
|
let events = self.with_window(xwindow, |window| {
|
||||||
|
// So apparently...
|
||||||
|
// `XSendEvent` (synthetic `ConfigureNotify`) -> position relative to root
|
||||||
|
// `XConfigureNotify` (real `ConfigureNotify`) -> position relative to parent
|
||||||
|
// https://tronche.com/gui/x/icccm/sec-4.html#s-4.1.5
|
||||||
|
// We don't want to send `Moved` when this is false, since then every `Resized`
|
||||||
|
// (whether the window moved or not) is accompanied by an extraneous `Moved` event
|
||||||
|
// that has a position relative to the parent window.
|
||||||
|
let is_synthetic = xev.send_event == ffi::True;
|
||||||
|
|
||||||
// So apparently...
|
let new_inner_size = (xev.width as u32, xev.height as u32);
|
||||||
// XSendEvent (synthetic ConfigureNotify) -> position relative to root
|
let new_inner_position = (xev.x as i32, xev.y as i32);
|
||||||
// XConfigureNotify (real ConfigureNotify) -> position relative to parent
|
|
||||||
// https://tronche.com/gui/x/icccm/sec-4.html#s-4.1.5
|
|
||||||
// We don't want to send Moved when this is true, since then every Resized
|
|
||||||
// (whether the window moved or not) is accompanied by an extraneous Moved event
|
|
||||||
// that has a position relative to the parent window.
|
|
||||||
let is_synthetic = xev.send_event == ffi::True;
|
|
||||||
|
|
||||||
let window = xev.window;
|
let mut shared_state_lock = window.shared_state.lock();
|
||||||
let window_id = mkwid(window);
|
|
||||||
|
|
||||||
let new_size = (xev.width, xev.height);
|
let (resized, moved) = {
|
||||||
let new_position = (xev.x, xev.y);
|
let resized = util::maybe_change(&mut shared_state_lock.size, new_inner_size);
|
||||||
|
let moved = if is_synthetic {
|
||||||
let (resized, moved) = {
|
util::maybe_change(&mut shared_state_lock.inner_position, new_inner_position)
|
||||||
let mut windows = self.windows.lock();
|
} else {
|
||||||
if let Some(window_data) = windows.get_mut(&WindowId(window)) {
|
// Detect when frame extents change.
|
||||||
let (mut resized, mut moved) = (false, false);
|
// Since this isn't synthetic, as per the notes above, this position is relative to the
|
||||||
|
// parent window.
|
||||||
if window_data.config.size.is_none() {
|
let rel_parent = new_inner_position;
|
||||||
window_data.config.size = Some(new_size);
|
if util::maybe_change(&mut shared_state_lock.inner_position_rel_parent, rel_parent) {
|
||||||
resized = true;
|
// This ensures we process the next `Moved`.
|
||||||
}
|
shared_state_lock.inner_position = None;
|
||||||
if window_data.config.size.is_none() && is_synthetic {
|
// Extra insurance against stale frame extents.
|
||||||
window_data.config.position = Some(new_position);
|
shared_state_lock.frame_extents = None;
|
||||||
moved = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !resized {
|
|
||||||
if window_data.config.size != Some(new_size) {
|
|
||||||
window_data.config.size = Some(new_size);
|
|
||||||
resized = true;
|
|
||||||
}
|
}
|
||||||
}
|
false
|
||||||
if !moved && is_synthetic {
|
};
|
||||||
if window_data.config.position != Some(new_position) {
|
|
||||||
window_data.config.position = Some(new_position);
|
|
||||||
moved = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !is_synthetic
|
|
||||||
&& window_data.config.inner_position != Some(new_position) {
|
|
||||||
window_data.config.inner_position = Some(new_position);
|
|
||||||
// This way, we get sent Moved when the decorations are toggled.
|
|
||||||
window_data.config.position = None;
|
|
||||||
self.shared_state.borrow().get(&WindowId(window)).map(|window_state| {
|
|
||||||
if let Some(window_state) = window_state.upgrade() {
|
|
||||||
// Extra insurance against stale frame extents
|
|
||||||
(*window_state.lock()).frame_extents.take();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
(resized, moved)
|
(resized, moved)
|
||||||
} else {
|
};
|
||||||
return;
|
|
||||||
|
let capacity = resized as usize + moved as usize;
|
||||||
|
let mut events = Vec::with_capacity(capacity);
|
||||||
|
|
||||||
|
if resized {
|
||||||
|
events.push(WindowEvent::Resized(new_inner_size.0, new_inner_size.1));
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
if resized {
|
if moved || shared_state_lock.position.is_none() {
|
||||||
let (width, height) = (xev.width as u32, xev.height as u32);
|
// We need to convert client area position to window position.
|
||||||
callback(Event::WindowEvent {
|
let frame_extents = shared_state_lock.frame_extents
|
||||||
window_id,
|
.as_ref()
|
||||||
event: WindowEvent::Resized(width, height),
|
.cloned()
|
||||||
});
|
.unwrap_or_else(|| {
|
||||||
}
|
let frame_extents = self.xconn.get_frame_extents_heuristic(xwindow, self.root);
|
||||||
|
shared_state_lock.frame_extents = Some(frame_extents.clone());
|
||||||
if moved {
|
frame_extents
|
||||||
// We need to convert client area position to window position.
|
|
||||||
self.shared_state.borrow().get(&WindowId(window)).map(|window_state| {
|
|
||||||
if let Some(window_state) = window_state.upgrade() {
|
|
||||||
let (x, y) = {
|
|
||||||
let (inner_x, inner_y) = (xev.x as i32, xev.y as i32);
|
|
||||||
let mut window_state_lock = window_state.lock();
|
|
||||||
if (*window_state_lock).frame_extents.is_some() {
|
|
||||||
(*window_state_lock).frame_extents
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.inner_pos_to_outer(inner_x, inner_y)
|
|
||||||
} else {
|
|
||||||
let extents = self.display.get_frame_extents_heuristic(window, self.root);
|
|
||||||
let outer_pos = extents.inner_pos_to_outer(inner_x, inner_y);
|
|
||||||
(*window_state_lock).frame_extents = Some(extents);
|
|
||||||
outer_pos
|
|
||||||
}
|
|
||||||
};
|
|
||||||
callback(Event::WindowEvent {
|
|
||||||
window_id,
|
|
||||||
event: WindowEvent::Moved(x, y),
|
|
||||||
});
|
});
|
||||||
|
let outer = frame_extents.inner_pos_to_outer(new_inner_position.0, new_inner_position.1);
|
||||||
|
shared_state_lock.position = Some(outer);
|
||||||
|
if moved {
|
||||||
|
events.push(WindowEvent::Moved(outer.0, outer.1));
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
events
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(events) = events {
|
||||||
|
for event in events {
|
||||||
|
callback(Event::WindowEvent {
|
||||||
|
window_id: mkwid(xwindow),
|
||||||
|
event,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ffi::ReparentNotify => {
|
ffi::ReparentNotify => {
|
||||||
let xev: &ffi::XReparentEvent = xev.as_ref();
|
let xev: &ffi::XReparentEvent = xev.as_ref();
|
||||||
|
|
||||||
let window = xev.window;
|
|
||||||
|
|
||||||
// This is generally a reliable way to detect when the window manager's been
|
// This is generally a reliable way to detect when the window manager's been
|
||||||
// replaced, though this event is only fired by reparenting window managers
|
// replaced, though this event is only fired by reparenting window managers
|
||||||
// (which is almost all of them). Failing to correctly update WM info doesn't
|
// (which is almost all of them). Failing to correctly update WM info doesn't
|
||||||
// really have much impact, since on the WMs affected (xmonad, dwm, etc.) the only
|
// really have much impact, since on the WMs affected (xmonad, dwm, etc.) the only
|
||||||
// effect is that we waste some time trying to query unsupported properties.
|
// effect is that we waste some time trying to query unsupported properties.
|
||||||
self.display.update_cached_wm_info(self.root);
|
self.xconn.update_cached_wm_info(self.root);
|
||||||
|
|
||||||
self.shared_state
|
self.with_window(xev.window, |window| {
|
||||||
.borrow()
|
window.invalidate_cached_frame_extents();
|
||||||
.get(&WindowId(window))
|
});
|
||||||
.map(|window_state| {
|
|
||||||
if let Some(window_state) = window_state.upgrade() {
|
|
||||||
(*window_state.lock()).frame_extents.take();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ffi::DestroyNotify => {
|
ffi::DestroyNotify => {
|
||||||
|
@ -522,7 +491,7 @@ impl EventsLoop {
|
||||||
|
|
||||||
// In the event that the window's been destroyed without being dropped first, we
|
// In the event that the window's been destroyed without being dropped first, we
|
||||||
// cleanup again here.
|
// cleanup again here.
|
||||||
self.windows.lock().remove(&WindowId(window));
|
self.windows.borrow_mut().remove(&WindowId(window));
|
||||||
|
|
||||||
// Since all XIM stuff needs to happen from the same thread, we destroy the input
|
// Since all XIM stuff needs to happen from the same thread, we destroy the input
|
||||||
// context here instead of when dropping the window.
|
// context here instead of when dropping the window.
|
||||||
|
@ -575,14 +544,14 @@ impl EventsLoop {
|
||||||
|
|
||||||
let keysym = unsafe {
|
let keysym = unsafe {
|
||||||
let mut keysym = 0;
|
let mut keysym = 0;
|
||||||
(self.display.xlib.XLookupString)(
|
(self.xconn.xlib.XLookupString)(
|
||||||
xkev,
|
xkev,
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
0,
|
0,
|
||||||
&mut keysym,
|
&mut keysym,
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
);
|
);
|
||||||
self.display.check_errors().expect("Failed to lookup keysym");
|
self.xconn.check_errors().expect("Failed to lookup keysym");
|
||||||
keysym
|
keysym
|
||||||
};
|
};
|
||||||
let virtual_keycode = events::keysym_to_element(keysym as c_uint);
|
let virtual_keycode = events::keysym_to_element(keysym as c_uint);
|
||||||
|
@ -603,7 +572,7 @@ impl EventsLoop {
|
||||||
|
|
||||||
if state == Pressed {
|
if state == Pressed {
|
||||||
let written = if let Some(ic) = self.ime.borrow().get_context(window) {
|
let written = if let Some(ic) = self.ime.borrow().get_context(window) {
|
||||||
self.display.lookup_utf8(ic, xkev)
|
self.xconn.lookup_utf8(ic, xkev)
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -619,7 +588,7 @@ impl EventsLoop {
|
||||||
}
|
}
|
||||||
|
|
||||||
ffi::GenericEvent => {
|
ffi::GenericEvent => {
|
||||||
let guard = if let Some(e) = GenericEventCookie::from_event(&self.display, *xev) { e } else { return };
|
let guard = if let Some(e) = GenericEventCookie::from_event(&self.xconn, *xev) { e } else { return };
|
||||||
let xev = &guard.cookie;
|
let xev = &guard.cookie;
|
||||||
if self.xi2ext.opcode != xev.extension {
|
if self.xi2ext.opcode != xev.extension {
|
||||||
return;
|
return;
|
||||||
|
@ -637,15 +606,11 @@ impl EventsLoop {
|
||||||
let window_id = mkwid(xev.event);
|
let window_id = mkwid(xev.event);
|
||||||
let device_id = mkdid(xev.deviceid);
|
let device_id = mkdid(xev.deviceid);
|
||||||
if (xev.flags & ffi::XIPointerEmulated) != 0 {
|
if (xev.flags & ffi::XIPointerEmulated) != 0 {
|
||||||
let windows = self.windows.lock();
|
// Deliver multi-touch events instead of emulated mouse events.
|
||||||
if let Some(window_data) = windows.get(&WindowId(xev.event)) {
|
let return_now = self
|
||||||
if window_data.multitouch {
|
.with_window(xev.event, |window| window.multitouch)
|
||||||
// Deliver multi-touch events instead of emulated mouse events.
|
.unwrap_or(true);
|
||||||
return;
|
if return_now { return; }
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let modifiers = ModifiersState::from(xev.mods);
|
let modifiers = ModifiersState::from(xev.mods);
|
||||||
|
@ -724,21 +689,11 @@ impl EventsLoop {
|
||||||
|
|
||||||
let modifiers = ModifiersState::from(xev.mods);
|
let modifiers = ModifiersState::from(xev.mods);
|
||||||
|
|
||||||
// Gymnastics to ensure self.windows isn't locked when we invoke callback
|
let cursor_moved = self.with_window(xev.event, |window| {
|
||||||
if {
|
let mut shared_state_lock = window.shared_state.lock();
|
||||||
let mut windows = self.windows.lock();
|
util::maybe_change(&mut shared_state_lock.cursor_pos, new_cursor_pos)
|
||||||
let window_data = {
|
});
|
||||||
if let Some(window_data) = windows.get_mut(&WindowId(xev.event)) {
|
if cursor_moved == Some(true) {
|
||||||
window_data
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if Some(new_cursor_pos) != window_data.cursor_pos {
|
|
||||||
window_data.cursor_pos = Some(new_cursor_pos);
|
|
||||||
true
|
|
||||||
} else { false }
|
|
||||||
} {
|
|
||||||
callback(Event::WindowEvent {
|
callback(Event::WindowEvent {
|
||||||
window_id,
|
window_id,
|
||||||
event: CursorMoved {
|
event: CursorMoved {
|
||||||
|
@ -747,6 +702,8 @@ impl EventsLoop {
|
||||||
modifiers,
|
modifiers,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
} else if cursor_moved.is_none() {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// More gymnastics, for self.devices
|
// More gymnastics, for self.devices
|
||||||
|
@ -804,7 +761,7 @@ impl EventsLoop {
|
||||||
let window_id = mkwid(xev.event);
|
let window_id = mkwid(xev.event);
|
||||||
let device_id = mkdid(xev.deviceid);
|
let device_id = mkdid(xev.deviceid);
|
||||||
|
|
||||||
if let Some(all_info) = DeviceInfo::get(&self.display, ffi::XIAllDevices) {
|
if let Some(all_info) = DeviceInfo::get(&self.xconn, ffi::XIAllDevices) {
|
||||||
let mut devices = self.devices.borrow_mut();
|
let mut devices = self.devices.borrow_mut();
|
||||||
for device_info in all_info.iter() {
|
for device_info in all_info.iter() {
|
||||||
if device_info.deviceid == xev.sourceid
|
if device_info.deviceid == xev.sourceid
|
||||||
|
@ -830,7 +787,7 @@ impl EventsLoop {
|
||||||
// The mods field on this event isn't actually populated, so query the
|
// The mods field on this event isn't actually populated, so query the
|
||||||
// pointer device. In the future, we can likely remove this round-trip by
|
// pointer device. In the future, we can likely remove this round-trip by
|
||||||
// relying on Xkb for modifier values.
|
// relying on Xkb for modifier values.
|
||||||
let modifiers = self.display.query_pointer(xev.event, xev.deviceid)
|
let modifiers = self.xconn.query_pointer(xev.event, xev.deviceid)
|
||||||
.expect("Failed to query pointer device").get_modifier_state();
|
.expect("Failed to query pointer device").get_modifier_state();
|
||||||
|
|
||||||
callback(Event::WindowEvent { window_id, event: CursorMoved {
|
callback(Event::WindowEvent { window_id, event: CursorMoved {
|
||||||
|
@ -844,11 +801,7 @@ impl EventsLoop {
|
||||||
|
|
||||||
// Leave, FocusIn, and FocusOut can be received by a window that's already
|
// Leave, FocusIn, and FocusOut can be received by a window that's already
|
||||||
// been destroyed, which the user presumably doesn't want to deal with.
|
// been destroyed, which the user presumably doesn't want to deal with.
|
||||||
let window_closed = self.windows
|
let window_closed = !self.window_exists(xev.event);
|
||||||
.lock()
|
|
||||||
.get(&WindowId(xev.event))
|
|
||||||
.is_none();
|
|
||||||
|
|
||||||
if !window_closed {
|
if !window_closed {
|
||||||
callback(Event::WindowEvent {
|
callback(Event::WindowEvent {
|
||||||
window_id: mkwid(xev.event),
|
window_id: mkwid(xev.event),
|
||||||
|
@ -859,11 +812,9 @@ impl EventsLoop {
|
||||||
ffi::XI_FocusIn => {
|
ffi::XI_FocusIn => {
|
||||||
let xev: &ffi::XIFocusInEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &ffi::XIFocusInEvent = unsafe { &*(xev.data as *const _) };
|
||||||
|
|
||||||
|
if !self.window_exists(xev.event) { return; }
|
||||||
let window_id = mkwid(xev.event);
|
let window_id = mkwid(xev.event);
|
||||||
|
|
||||||
if let None = self.windows.lock().get(&WindowId(xev.event)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.ime
|
self.ime
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.focus(xev.event)
|
.focus(xev.event)
|
||||||
|
@ -890,15 +841,11 @@ impl EventsLoop {
|
||||||
}
|
}
|
||||||
ffi::XI_FocusOut => {
|
ffi::XI_FocusOut => {
|
||||||
let xev: &ffi::XIFocusOutEvent = unsafe { &*(xev.data as *const _) };
|
let xev: &ffi::XIFocusOutEvent = unsafe { &*(xev.data as *const _) };
|
||||||
|
if !self.window_exists(xev.event) { return; }
|
||||||
if let None = self.windows.lock().get(&WindowId(xev.event)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.ime
|
self.ime
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.unfocus(xev.event)
|
.unfocus(xev.event)
|
||||||
.expect("Failed to unfocus input context");
|
.expect("Failed to unfocus input context");
|
||||||
|
|
||||||
callback(Event::WindowEvent {
|
callback(Event::WindowEvent {
|
||||||
window_id: mkwid(xev.event),
|
window_id: mkwid(xev.event),
|
||||||
event: Focused(false),
|
event: Focused(false),
|
||||||
|
@ -993,13 +940,13 @@ impl EventsLoop {
|
||||||
let scancode = (keycode - 8) as u32;
|
let scancode = (keycode - 8) as u32;
|
||||||
|
|
||||||
let keysym = unsafe {
|
let keysym = unsafe {
|
||||||
(self.display.xlib.XKeycodeToKeysym)(
|
(self.xconn.xlib.XKeycodeToKeysym)(
|
||||||
self.display.display,
|
self.xconn.display,
|
||||||
xev.detail as ffi::KeyCode,
|
xev.detail as ffi::KeyCode,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
self.display.check_errors().expect("Failed to lookup raw keysym");
|
self.xconn.check_errors().expect("Failed to lookup raw keysym");
|
||||||
|
|
||||||
let virtual_keycode = events::keysym_to_element(keysym as c_uint);
|
let virtual_keycode = events::keysym_to_element(keysym as c_uint);
|
||||||
|
|
||||||
|
@ -1054,18 +1001,43 @@ impl EventsLoop {
|
||||||
|
|
||||||
fn init_device(&self, device: c_int) {
|
fn init_device(&self, device: c_int) {
|
||||||
let mut devices = self.devices.borrow_mut();
|
let mut devices = self.devices.borrow_mut();
|
||||||
if let Some(info) = DeviceInfo::get(&self.display, device) {
|
if let Some(info) = DeviceInfo::get(&self.xconn, device) {
|
||||||
for info in info.iter() {
|
for info in info.iter() {
|
||||||
devices.insert(DeviceId(info.deviceid), Device::new(&self, info));
|
devices.insert(DeviceId(info.deviceid), Device::new(&self, info));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn with_window<F, T>(&self, window_id: ffi::Window, callback: F) -> Option<T>
|
||||||
|
where F: Fn(&UnownedWindow) -> T
|
||||||
|
{
|
||||||
|
let mut deleted = false;
|
||||||
|
let window_id = WindowId(window_id);
|
||||||
|
let result = self.windows
|
||||||
|
.borrow()
|
||||||
|
.get(&window_id)
|
||||||
|
.and_then(|window| {
|
||||||
|
let arc = window.upgrade();
|
||||||
|
deleted = arc.is_none();
|
||||||
|
arc
|
||||||
|
})
|
||||||
|
.map(|window| callback(&*window));
|
||||||
|
if deleted {
|
||||||
|
// Garbage collection
|
||||||
|
self.windows.borrow_mut().remove(&window_id);
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn window_exists(&self, window_id: ffi::Window) -> bool {
|
||||||
|
self.with_window(window_id, |_| ()).is_some()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventsLoopProxy {
|
impl EventsLoopProxy {
|
||||||
pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
|
pub fn wakeup(&self) -> Result<(), EventsLoopClosed> {
|
||||||
// Update the `EventsLoop`'s `pending_wakeup` flag.
|
// Update the `EventsLoop`'s `pending_wakeup` flag.
|
||||||
let display = match (self.pending_wakeup.upgrade(), self.display.upgrade()) {
|
let display = match (self.pending_wakeup.upgrade(), self.xconn.upgrade()) {
|
||||||
(Some(wakeup), Some(display)) => {
|
(Some(wakeup), Some(display)) => {
|
||||||
wakeup.store(true, atomic::Ordering::Relaxed);
|
wakeup.store(true, atomic::Ordering::Relaxed);
|
||||||
display
|
display
|
||||||
|
@ -1091,24 +1063,24 @@ impl EventsLoopProxy {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DeviceInfo<'a> {
|
struct DeviceInfo<'a> {
|
||||||
display: &'a XConnection,
|
xconn: &'a XConnection,
|
||||||
info: *const ffi::XIDeviceInfo,
|
info: *const ffi::XIDeviceInfo,
|
||||||
count: usize,
|
count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> DeviceInfo<'a> {
|
impl<'a> DeviceInfo<'a> {
|
||||||
fn get(display: &'a XConnection, device: c_int) -> Option<Self> {
|
fn get(xconn: &'a XConnection, device: c_int) -> Option<Self> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut count = mem::uninitialized();
|
let mut count = mem::uninitialized();
|
||||||
let info = (display.xinput2.XIQueryDevice)(display.display, device, &mut count);
|
let info = (xconn.xinput2.XIQueryDevice)(xconn.display, device, &mut count);
|
||||||
display.check_errors()
|
xconn.check_errors()
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|_| {
|
.and_then(|_| {
|
||||||
if info.is_null() || count == 0 {
|
if info.is_null() || count == 0 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(DeviceInfo {
|
Some(DeviceInfo {
|
||||||
display,
|
xconn,
|
||||||
info,
|
info,
|
||||||
count: count as usize,
|
count: count as usize,
|
||||||
})
|
})
|
||||||
|
@ -1121,11 +1093,11 @@ impl<'a> DeviceInfo<'a> {
|
||||||
impl<'a> Drop for DeviceInfo<'a> {
|
impl<'a> Drop for DeviceInfo<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
assert!(!self.info.is_null());
|
assert!(!self.info.is_null());
|
||||||
unsafe { (self.display.xinput2.XIFreeDeviceInfo)(self.info as *mut _) };
|
unsafe { (self.xconn.xinput2.XIFreeDeviceInfo)(self.info as *mut _) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ::std::ops::Deref for DeviceInfo<'a> {
|
impl<'a> Deref for DeviceInfo<'a> {
|
||||||
type Target = [ffi::XIDeviceInfo];
|
type Target = [ffi::XIDeviceInfo];
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
unsafe { slice::from_raw_parts(self.info, self.count) }
|
unsafe { slice::from_raw_parts(self.info, self.count) }
|
||||||
|
@ -1139,57 +1111,41 @@ pub struct WindowId(ffi::Window);
|
||||||
pub struct DeviceId(c_int);
|
pub struct DeviceId(c_int);
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
pub window: Arc<Window2>,
|
pub window: Arc<UnownedWindow>,
|
||||||
display: Weak<XConnection>,
|
|
||||||
windows: Weak<Mutex<HashMap<WindowId, WindowData>>>,
|
|
||||||
ime_sender: Mutex<ImeSender>,
|
ime_sender: Mutex<ImeSender>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::std::ops::Deref for Window {
|
impl Deref for Window {
|
||||||
type Target = Window2;
|
type Target = UnownedWindow;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref(&self) -> &Window2 {
|
fn deref(&self) -> &UnownedWindow {
|
||||||
&*self.window
|
&*self.window
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
x_events_loop: &EventsLoop,
|
event_loop: &EventsLoop,
|
||||||
attribs: WindowAttributes,
|
attribs: WindowAttributes,
|
||||||
pl_attribs: PlatformSpecificWindowBuilderAttributes
|
pl_attribs: PlatformSpecificWindowBuilderAttributes
|
||||||
) -> Result<Self, CreationError> {
|
) -> Result<Self, CreationError> {
|
||||||
let multitouch = attribs.multitouch;
|
let window = Arc::new(UnownedWindow::new(&event_loop, attribs, pl_attribs)?);
|
||||||
let win = Arc::new(Window2::new(&x_events_loop, attribs, pl_attribs)?);
|
|
||||||
|
|
||||||
x_events_loop.shared_state
|
event_loop.windows
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.insert(win.id(), Arc::downgrade(&win.shared_state));
|
.insert(window.id(), Arc::downgrade(&window));
|
||||||
|
|
||||||
x_events_loop.ime
|
event_loop.ime
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.create_context(win.id().0)
|
.create_context(window.id().0)
|
||||||
.expect("Failed to create input context");
|
.expect("Failed to create input context");
|
||||||
|
|
||||||
x_events_loop.windows.lock().insert(win.id(), WindowData {
|
|
||||||
config: Default::default(),
|
|
||||||
multitouch,
|
|
||||||
cursor_pos: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(Window {
|
Ok(Window {
|
||||||
window: win,
|
window,
|
||||||
windows: Arc::downgrade(&x_events_loop.windows),
|
ime_sender: Mutex::new(event_loop.ime_sender.clone()),
|
||||||
display: Arc::downgrade(&x_events_loop.display),
|
|
||||||
ime_sender: Mutex::new(x_events_loop.ime_sender.clone()),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn id(&self) -> WindowId {
|
|
||||||
self.window.id()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn send_xim_spot(&self, x: i16, y: i16) {
|
pub fn send_xim_spot(&self, x: i16, y: i16) {
|
||||||
let _ = self.ime_sender
|
let _ = self.ime_sender
|
||||||
|
@ -1200,47 +1156,28 @@ impl Window {
|
||||||
|
|
||||||
impl Drop for Window {
|
impl Drop for Window {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let (Some(windows), Some(display)) = (self.windows.upgrade(), self.display.upgrade()) {
|
let xconn = &self.window.xconn;
|
||||||
if let Some(_) = windows.lock().remove(&self.window.id()) {
|
unsafe {
|
||||||
unsafe {
|
(xconn.xlib.XDestroyWindow)(xconn.display, self.window.id().0);
|
||||||
(display.xlib.XDestroyWindow)(display.display, self.window.id().0);
|
// If the window was somehow already destroyed, we'll get a `BadWindow` error, which we don't care about.
|
||||||
}
|
let _ = xconn.check_errors();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// State maintained for translating window-related events
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct WindowData {
|
|
||||||
config: WindowConfig,
|
|
||||||
multitouch: bool,
|
|
||||||
cursor_pos: Option<(f64, f64)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Required by ffi members
|
|
||||||
unsafe impl Send for WindowData {}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
|
||||||
struct WindowConfig {
|
|
||||||
pub size: Option<(c_int, c_int)>,
|
|
||||||
pub position: Option<(c_int, c_int)>,
|
|
||||||
pub inner_position: Option<(c_int, c_int)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// XEvents of type GenericEvent store their actual data in an XGenericEventCookie data structure. This is a wrapper to
|
/// XEvents of type GenericEvent store their actual data in an XGenericEventCookie data structure. This is a wrapper to
|
||||||
/// extract the cookie from a GenericEvent XEvent and release the cookie data once it has been processed
|
/// extract the cookie from a GenericEvent XEvent and release the cookie data once it has been processed
|
||||||
struct GenericEventCookie<'a> {
|
struct GenericEventCookie<'a> {
|
||||||
display: &'a XConnection,
|
xconn: &'a XConnection,
|
||||||
cookie: ffi::XGenericEventCookie
|
cookie: ffi::XGenericEventCookie
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> GenericEventCookie<'a> {
|
impl<'a> GenericEventCookie<'a> {
|
||||||
fn from_event<'b>(display: &'b XConnection, event: ffi::XEvent) -> Option<GenericEventCookie<'b>> {
|
fn from_event<'b>(xconn: &'b XConnection, event: ffi::XEvent) -> Option<GenericEventCookie<'b>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut cookie: ffi::XGenericEventCookie = From::from(event);
|
let mut cookie: ffi::XGenericEventCookie = From::from(event);
|
||||||
if (display.xlib.XGetEventData)(display.display, &mut cookie) == ffi::True {
|
if (xconn.xlib.XGetEventData)(xconn.display, &mut cookie) == ffi::True {
|
||||||
Some(GenericEventCookie{display: display, cookie: cookie})
|
Some(GenericEventCookie { xconn, cookie })
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -1251,8 +1188,7 @@ impl<'a> GenericEventCookie<'a> {
|
||||||
impl<'a> Drop for GenericEventCookie<'a> {
|
impl<'a> Drop for GenericEventCookie<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let xlib = &self.display.xlib;
|
(self.xconn.xlib.XFreeEventData)(self.xconn.display, &mut self.cookie);
|
||||||
(xlib.XFreeEventData)(self.display.display, &mut self.cookie);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1302,7 +1238,7 @@ impl Device {
|
||||||
| ffi::XI_RawKeyPressMask
|
| ffi::XI_RawKeyPressMask
|
||||||
| ffi::XI_RawKeyReleaseMask;
|
| ffi::XI_RawKeyReleaseMask;
|
||||||
// The request buffer is flushed when we poll for events
|
// The request buffer is flushed when we poll for events
|
||||||
el.display.select_xinput_events(el.root, info.deviceid, mask).queue();
|
el.xconn.select_xinput_events(el.root, info.deviceid, mask).queue();
|
||||||
|
|
||||||
// Identify scroll axes
|
// Identify scroll axes
|
||||||
for class_ptr in Device::classes(info) {
|
for class_ptr in Device::classes(info) {
|
||||||
|
|
|
@ -31,6 +31,16 @@ use std::os::raw::*;
|
||||||
|
|
||||||
use super::{ffi, XConnection, XError};
|
use super::{ffi, XConnection, XError};
|
||||||
|
|
||||||
|
pub fn maybe_change<T: PartialEq>(field: &mut Option<T>, value: T) -> bool {
|
||||||
|
let wrapped = Some(value);
|
||||||
|
if *field != wrapped {
|
||||||
|
*field = wrapped;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use = "This request was made asynchronously, and is still in the output buffer. You must explicitly choose to either `.flush()` (empty the output buffer, sending the request now) or `.queue()` (wait to send the request, allowing you to continue to add more requests without additional round-trips). For more information, see the documentation for `util::flush_requests`."]
|
#[must_use = "This request was made asynchronously, and is still in the output buffer. You must explicitly choose to either `.flush()` (empty the output buffer, sending the request now) or `.queue()` (wait to send the request, allowing you to continue to add more requests without additional round-trips). For more information, see the documentation for `util::flush_requests`."]
|
||||||
pub struct Flusher<'a> {
|
pub struct Flusher<'a> {
|
||||||
xconn: &'a XConnection,
|
xconn: &'a XConnection,
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use std::{cmp, env, mem};
|
use std::{cmp, env, mem};
|
||||||
use std::borrow::Borrow;
|
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::os::raw::*;
|
use std::os::raw::*;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
@ -28,38 +27,41 @@ unsafe extern "C" fn visibility_predicate(
|
||||||
(event.window == window && event.type_ == ffi::VisibilityNotify) as _
|
(event.window == window && event.type_ == ffi::VisibilityNotify) as _
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct XWindow {
|
|
||||||
pub display: Arc<XConnection>,
|
|
||||||
pub window: ffi::Window,
|
|
||||||
pub root: ffi::Window,
|
|
||||||
pub screen_id: i32,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Send for XWindow {}
|
|
||||||
unsafe impl Sync for XWindow {}
|
|
||||||
|
|
||||||
unsafe impl Send for Window2 {}
|
|
||||||
unsafe impl Sync for Window2 {}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct SharedState {
|
pub struct SharedState {
|
||||||
|
pub multitouch: bool,
|
||||||
|
pub cursor_pos: Option<(f64, f64)>,
|
||||||
|
pub size: Option<(u32, u32)>,
|
||||||
|
pub position: Option<(i32, i32)>,
|
||||||
|
pub inner_position: Option<(i32, i32)>,
|
||||||
|
pub inner_position_rel_parent: Option<(i32, i32)>,
|
||||||
|
pub last_monitor: Option<X11MonitorId>,
|
||||||
|
pub dpi_adjusted: Option<(f64, f64)>,
|
||||||
pub frame_extents: Option<util::FrameExtentsHeuristic>,
|
pub frame_extents: Option<util::FrameExtentsHeuristic>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Window2 {
|
unsafe impl Send for UnownedWindow {}
|
||||||
pub x: Arc<XWindow>,
|
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
|
||||||
cursor: Mutex<MouseCursor>,
|
cursor: Mutex<MouseCursor>,
|
||||||
cursor_state: Mutex<CursorState>,
|
cursor_state: Mutex<CursorState>,
|
||||||
pub shared_state: Arc<Mutex<SharedState>>,
|
pub multitouch: bool, // never changes
|
||||||
|
pub shared_state: Mutex<SharedState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window2 {
|
impl UnownedWindow {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
ctx: &EventsLoop,
|
event_loop: &EventsLoop,
|
||||||
window_attrs: WindowAttributes,
|
window_attrs: WindowAttributes,
|
||||||
pl_attribs: PlatformSpecificWindowBuilderAttributes,
|
pl_attribs: PlatformSpecificWindowBuilderAttributes,
|
||||||
) -> Result<Window2, CreationError> {
|
) -> Result<UnownedWindow, CreationError> {
|
||||||
let xconn = &ctx.display;
|
let xconn = &event_loop.xconn;
|
||||||
|
let root = event_loop.root;
|
||||||
|
|
||||||
let dimensions = {
|
let dimensions = {
|
||||||
// x11 only applies constraints when the window is actively resized
|
// x11 only applies constraints when the window is actively resized
|
||||||
|
@ -81,9 +83,6 @@ impl Window2 {
|
||||||
None => unsafe { (xconn.xlib.XDefaultScreen)(xconn.display) },
|
None => unsafe { (xconn.xlib.XDefaultScreen)(xconn.display) },
|
||||||
};
|
};
|
||||||
|
|
||||||
// getting the root window
|
|
||||||
let root = ctx.root;
|
|
||||||
|
|
||||||
// creating
|
// creating
|
||||||
let mut set_win_attr = {
|
let mut set_win_attr = {
|
||||||
let mut swa: ffi::XSetWindowAttributes = unsafe { mem::zeroed() };
|
let mut swa: ffi::XSetWindowAttributes = unsafe { mem::zeroed() };
|
||||||
|
@ -121,7 +120,7 @@ impl Window2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally creating the window
|
// finally creating the window
|
||||||
let window = unsafe {
|
let xwindow = unsafe {
|
||||||
(xconn.xlib.XCreateWindow)(
|
(xconn.xlib.XCreateWindow)(
|
||||||
xconn.display,
|
xconn.display,
|
||||||
root,
|
root,
|
||||||
|
@ -144,18 +143,15 @@ impl Window2 {
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let x_window = Arc::new(XWindow {
|
let window = UnownedWindow {
|
||||||
display: Arc::clone(xconn),
|
xconn: Arc::clone(xconn),
|
||||||
window,
|
xwindow,
|
||||||
root,
|
root,
|
||||||
screen_id,
|
screen_id,
|
||||||
});
|
cursor: Default::default(),
|
||||||
|
cursor_state: Default::default(),
|
||||||
let window = Window2 {
|
multitouch: window_attrs.multitouch,
|
||||||
x: x_window,
|
shared_state: Default::default(),
|
||||||
cursor: Mutex::new(MouseCursor::Default),
|
|
||||||
cursor_state: Mutex::new(CursorState::Normal),
|
|
||||||
shared_state: Arc::new(Mutex::new(SharedState::default())),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Title must be set before mapping. Some tiling window managers (i.e. i3) use the window
|
// Title must be set before mapping. Some tiling window managers (i.e. i3) use the window
|
||||||
|
@ -165,14 +161,12 @@ impl Window2 {
|
||||||
window.set_decorations_inner(window_attrs.decorations).queue();
|
window.set_decorations_inner(window_attrs.decorations).queue();
|
||||||
|
|
||||||
{
|
{
|
||||||
let ref x_window: &XWindow = window.x.borrow();
|
|
||||||
|
|
||||||
// Enable drag and drop (TODO: extend API to make this toggleable)
|
// Enable drag and drop (TODO: extend API to make this toggleable)
|
||||||
unsafe {
|
unsafe {
|
||||||
let dnd_aware_atom = xconn.get_atom_unchecked(b"XdndAware\0");
|
let dnd_aware_atom = xconn.get_atom_unchecked(b"XdndAware\0");
|
||||||
let version = &[5 as c_ulong]; // Latest version; hasn't changed since 2002
|
let version = &[5 as c_ulong]; // Latest version; hasn't changed since 2002
|
||||||
xconn.change_property(
|
xconn.change_property(
|
||||||
x_window.window,
|
window.xwindow,
|
||||||
dnd_aware_atom,
|
dnd_aware_atom,
|
||||||
ffi::XA_ATOM,
|
ffi::XA_ATOM,
|
||||||
util::PropMode::Replace,
|
util::PropMode::Replace,
|
||||||
|
@ -215,21 +209,16 @@ impl Window2 {
|
||||||
unsafe {
|
unsafe {
|
||||||
(xconn.xlib.XSetClassHint)(
|
(xconn.xlib.XSetClassHint)(
|
||||||
xconn.display,
|
xconn.display,
|
||||||
x_window.window,
|
window.xwindow,
|
||||||
class_hint.ptr,
|
class_hint.ptr,
|
||||||
);
|
);
|
||||||
}//.queue();
|
}//.queue();
|
||||||
}
|
}
|
||||||
|
|
||||||
Window2::set_pid(xconn, x_window.window)
|
window.set_pid().map(|flusher| flusher.queue());
|
||||||
.map(|flusher| flusher.queue());
|
|
||||||
|
|
||||||
if pl_attribs.x11_window_type != Default::default() {
|
if pl_attribs.x11_window_type != Default::default() {
|
||||||
Window2::set_window_type(
|
window.set_window_type(pl_attribs.x11_window_type).queue();
|
||||||
xconn,
|
|
||||||
x_window.window,
|
|
||||||
pl_attribs.x11_window_type,
|
|
||||||
).queue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set size hints
|
// set size hints
|
||||||
|
@ -261,7 +250,7 @@ impl Window2 {
|
||||||
unsafe {
|
unsafe {
|
||||||
(xconn.xlib.XSetWMNormalHints)(
|
(xconn.xlib.XSetWMNormalHints)(
|
||||||
xconn.display,
|
xconn.display,
|
||||||
x_window.window,
|
window.xwindow,
|
||||||
size_hints.ptr,
|
size_hints.ptr,
|
||||||
);
|
);
|
||||||
}//.queue();
|
}//.queue();
|
||||||
|
@ -276,8 +265,8 @@ impl Window2 {
|
||||||
unsafe {
|
unsafe {
|
||||||
(xconn.xlib.XSetWMProtocols)(
|
(xconn.xlib.XSetWMProtocols)(
|
||||||
xconn.display,
|
xconn.display,
|
||||||
x_window.window,
|
window.xwindow,
|
||||||
&ctx.wm_delete_window as *const _ as *mut _,
|
&event_loop.wm_delete_window as *const ffi::Atom as *mut ffi::Atom,
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
}//.queue();
|
}//.queue();
|
||||||
|
@ -285,7 +274,7 @@ impl Window2 {
|
||||||
// Set visibility (map window)
|
// Set visibility (map window)
|
||||||
if window_attrs.visible {
|
if window_attrs.visible {
|
||||||
unsafe {
|
unsafe {
|
||||||
(xconn.xlib.XMapRaised)(xconn.display, x_window.window);
|
(xconn.xlib.XMapRaised)(xconn.display, window.xwindow);
|
||||||
}//.queue();
|
}//.queue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,7 +309,7 @@ impl Window2 {
|
||||||
}
|
}
|
||||||
mask
|
mask
|
||||||
};
|
};
|
||||||
xconn.select_xinput_events(x_window.window, ffi::XIAllMasterDevices, mask).queue();
|
xconn.select_xinput_events(window.xwindow, ffi::XIAllMasterDevices, mask).queue();
|
||||||
|
|
||||||
// These properties must be set after mapping
|
// These properties must be set after mapping
|
||||||
if window_attrs.maximized {
|
if window_attrs.maximized {
|
||||||
|
@ -342,11 +331,11 @@ impl Window2 {
|
||||||
xconn.display,
|
xconn.display,
|
||||||
&mut event as *mut ffi::XEvent,
|
&mut event as *mut ffi::XEvent,
|
||||||
Some(visibility_predicate),
|
Some(visibility_predicate),
|
||||||
x_window.window as _,
|
window.xwindow as _,
|
||||||
);
|
);
|
||||||
(xconn.xlib.XSetInputFocus)(
|
(xconn.xlib.XSetInputFocus)(
|
||||||
xconn.display,
|
xconn.display,
|
||||||
x_window.window,
|
window.xwindow,
|
||||||
ffi::RevertToParent,
|
ffi::RevertToParent,
|
||||||
ffi::CurrentTime,
|
ffi::CurrentTime,
|
||||||
);
|
);
|
||||||
|
@ -362,9 +351,9 @@ impl Window2 {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_pid(xconn: &Arc<XConnection>, window: ffi::Window) -> Option<util::Flusher> {
|
fn set_pid(&self) -> Option<util::Flusher> {
|
||||||
let pid_atom = unsafe { xconn.get_atom_unchecked(b"_NET_WM_PID\0") };
|
let pid_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_PID\0") };
|
||||||
let client_machine_atom = unsafe { xconn.get_atom_unchecked(b"WM_CLIENT_MACHINE\0") };
|
let client_machine_atom = unsafe { self.xconn.get_atom_unchecked(b"WM_CLIENT_MACHINE\0") };
|
||||||
unsafe {
|
unsafe {
|
||||||
let (hostname, hostname_length) = {
|
let (hostname, hostname_length) = {
|
||||||
// 64 would suffice for Linux, but 256 will be enough everywhere (as per SUSv2). For instance, this is
|
// 64 would suffice for Linux, but 256 will be enough everywhere (as per SUSv2). For instance, this is
|
||||||
|
@ -377,15 +366,15 @@ impl Window2 {
|
||||||
let hostname_length = libc::strlen(hostname.as_ptr());
|
let hostname_length = libc::strlen(hostname.as_ptr());
|
||||||
(hostname, hostname_length as usize)
|
(hostname, hostname_length as usize)
|
||||||
};
|
};
|
||||||
xconn.change_property(
|
self.xconn.change_property(
|
||||||
window,
|
self.xwindow,
|
||||||
pid_atom,
|
pid_atom,
|
||||||
ffi::XA_CARDINAL,
|
ffi::XA_CARDINAL,
|
||||||
util::PropMode::Replace,
|
util::PropMode::Replace,
|
||||||
&[libc::getpid() as util::Cardinal],
|
&[libc::getpid() as util::Cardinal],
|
||||||
).queue();
|
).queue();
|
||||||
let flusher = xconn.change_property(
|
let flusher = self.xconn.change_property(
|
||||||
window,
|
self.xwindow,
|
||||||
client_machine_atom,
|
client_machine_atom,
|
||||||
ffi::XA_STRING,
|
ffi::XA_STRING,
|
||||||
util::PropMode::Replace,
|
util::PropMode::Replace,
|
||||||
|
@ -395,15 +384,11 @@ impl Window2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_window_type(
|
fn set_window_type(&self, window_type: util::WindowType) -> util::Flusher {
|
||||||
xconn: &Arc<XConnection>,
|
let hint_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_WINDOW_TYPE\0") };
|
||||||
window: ffi::Window,
|
let window_type_atom = window_type.as_atom(&self.xconn);
|
||||||
window_type: util::WindowType,
|
self.xconn.change_property(
|
||||||
) -> util::Flusher {
|
self.xwindow,
|
||||||
let hint_atom = unsafe { xconn.get_atom_unchecked(b"_NET_WM_WINDOW_TYPE\0") };
|
|
||||||
let window_type_atom = window_type.as_atom(xconn);
|
|
||||||
xconn.change_property(
|
|
||||||
window,
|
|
||||||
hint_atom,
|
hint_atom,
|
||||||
ffi::XA_ATOM,
|
ffi::XA_ATOM,
|
||||||
util::PropMode::Replace,
|
util::PropMode::Replace,
|
||||||
|
@ -412,27 +397,24 @@ impl Window2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_urgent(&self, is_urgent: bool) {
|
pub fn set_urgent(&self, is_urgent: bool) {
|
||||||
let xconn = &self.x.display;
|
let mut wm_hints = self.xconn.get_wm_hints(self.xwindow).expect("`XGetWMHints` failed");
|
||||||
let mut wm_hints = xconn.get_wm_hints(self.x.window).expect("`XGetWMHints` failed");
|
|
||||||
if is_urgent {
|
if is_urgent {
|
||||||
(*wm_hints).flags |= ffi::XUrgencyHint;
|
(*wm_hints).flags |= ffi::XUrgencyHint;
|
||||||
} else {
|
} else {
|
||||||
(*wm_hints).flags &= !ffi::XUrgencyHint;
|
(*wm_hints).flags &= !ffi::XUrgencyHint;
|
||||||
}
|
}
|
||||||
xconn.set_wm_hints(self.x.window, 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(
|
fn set_netwm(
|
||||||
xconn: &Arc<XConnection>,
|
&self,
|
||||||
window: ffi::Window,
|
operation: util::StateOperation,
|
||||||
root: ffi::Window,
|
|
||||||
properties: (c_long, c_long, c_long, c_long),
|
properties: (c_long, c_long, c_long, c_long),
|
||||||
operation: util::StateOperation
|
|
||||||
) -> util::Flusher {
|
) -> util::Flusher {
|
||||||
let state_atom = unsafe { xconn.get_atom_unchecked(b"_NET_WM_STATE\0") };
|
let state_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE\0") };
|
||||||
xconn.send_client_msg(
|
self.xconn.send_client_msg(
|
||||||
window,
|
self.xwindow,
|
||||||
root,
|
self.root,
|
||||||
state_atom,
|
state_atom,
|
||||||
Some(ffi::SubstructureRedirectMask | ffi::SubstructureNotifyMask),
|
Some(ffi::SubstructureRedirectMask | ffi::SubstructureNotifyMask),
|
||||||
[
|
[
|
||||||
|
@ -446,15 +428,8 @@ impl Window2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_fullscreen_hint(&self, fullscreen: bool) -> util::Flusher {
|
fn set_fullscreen_hint(&self, fullscreen: bool) -> util::Flusher {
|
||||||
let xconn = &self.x.display;
|
let fullscreen_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE_FULLSCREEN\0") };
|
||||||
let fullscreen_atom = unsafe { xconn.get_atom_unchecked(b"_NET_WM_STATE_FULLSCREEN\0") };
|
self.set_netwm(fullscreen.into(), (fullscreen_atom as c_long, 0, 0, 0))
|
||||||
Window2::set_netwm(
|
|
||||||
xconn,
|
|
||||||
self.x.window,
|
|
||||||
self.x.root,
|
|
||||||
(fullscreen_atom as c_long, 0, 0, 0),
|
|
||||||
fullscreen.into(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_fullscreen_inner(&self, monitor: Option<RootMonitorId>) -> util::Flusher {
|
fn set_fullscreen_inner(&self, monitor: Option<RootMonitorId>) -> util::Flusher {
|
||||||
|
@ -488,20 +463,13 @@ impl Window2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_current_monitor(&self) -> X11MonitorId {
|
pub fn get_current_monitor(&self) -> X11MonitorId {
|
||||||
get_monitor_for_window(&self.x.display, self.get_rect()).to_owned()
|
get_monitor_for_window(&self.xconn, self.get_rect()).to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_maximized_inner(&self, maximized: bool) -> util::Flusher {
|
fn set_maximized_inner(&self, maximized: bool) -> util::Flusher {
|
||||||
let xconn = &self.x.display;
|
let horz_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE_MAXIMIZED_HORZ\0") };
|
||||||
let horz_atom = unsafe { 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") };
|
||||||
let vert_atom = unsafe { 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))
|
||||||
Window2::set_netwm(
|
|
||||||
xconn,
|
|
||||||
self.x.window,
|
|
||||||
self.x.root,
|
|
||||||
(horz_atom as c_long, vert_atom as c_long, 0, 0),
|
|
||||||
maximized.into(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_maximized(&self, maximized: bool) {
|
pub fn set_maximized(&self, maximized: bool) {
|
||||||
|
@ -512,18 +480,17 @@ impl Window2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_title_inner(&self, title: &str) -> util::Flusher {
|
fn set_title_inner(&self, title: &str) -> util::Flusher {
|
||||||
let xconn = &self.x.display;
|
let wm_name_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_NAME\0") };
|
||||||
let wm_name_atom = unsafe { xconn.get_atom_unchecked(b"_NET_WM_NAME\0") };
|
let utf8_atom = unsafe { self.xconn.get_atom_unchecked(b"UTF8_STRING\0") };
|
||||||
let utf8_atom = unsafe { xconn.get_atom_unchecked(b"UTF8_STRING\0") };
|
|
||||||
let title = CString::new(title).expect("Window title contained null byte");
|
let title = CString::new(title).expect("Window title contained null byte");
|
||||||
unsafe {
|
unsafe {
|
||||||
(xconn.xlib.XStoreName)(
|
(self.xconn.xlib.XStoreName)(
|
||||||
xconn.display,
|
self.xconn.display,
|
||||||
self.x.window,
|
self.xwindow,
|
||||||
title.as_ptr() as *const c_char,
|
title.as_ptr() as *const c_char,
|
||||||
);
|
);
|
||||||
xconn.change_property(
|
self.xconn.change_property(
|
||||||
self.x.window,
|
self.xwindow,
|
||||||
wm_name_atom,
|
wm_name_atom,
|
||||||
utf8_atom,
|
utf8_atom,
|
||||||
util::PropMode::Replace,
|
util::PropMode::Replace,
|
||||||
|
@ -539,10 +506,9 @@ impl Window2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_decorations_inner(&self, decorations: bool) -> util::Flusher {
|
fn set_decorations_inner(&self, decorations: bool) -> util::Flusher {
|
||||||
let xconn = &self.x.display;
|
let wm_hints = unsafe { self.xconn.get_atom_unchecked(b"_MOTIF_WM_HINTS\0") };
|
||||||
let wm_hints = unsafe { xconn.get_atom_unchecked(b"_MOTIF_WM_HINTS\0") };
|
self.xconn.change_property(
|
||||||
xconn.change_property(
|
self.xwindow,
|
||||||
self.x.window,
|
|
||||||
wm_hints,
|
wm_hints,
|
||||||
wm_hints,
|
wm_hints,
|
||||||
util::PropMode::Replace,
|
util::PropMode::Replace,
|
||||||
|
@ -564,15 +530,8 @@ impl Window2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_always_on_top_inner(&self, always_on_top: bool) -> util::Flusher {
|
fn set_always_on_top_inner(&self, always_on_top: bool) -> util::Flusher {
|
||||||
let xconn = &self.x.display;
|
let above_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_STATE_ABOVE\0") };
|
||||||
let above_atom = unsafe { xconn.get_atom_unchecked(b"_NET_WM_STATE_ABOVE\0") };
|
self.set_netwm(always_on_top.into(), (above_atom as c_long, 0, 0, 0))
|
||||||
Window2::set_netwm(
|
|
||||||
xconn,
|
|
||||||
self.x.window,
|
|
||||||
self.x.root,
|
|
||||||
(above_atom as c_long, 0, 0, 0),
|
|
||||||
always_on_top.into(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_always_on_top(&self, always_on_top: bool) {
|
pub fn set_always_on_top(&self, always_on_top: bool) {
|
||||||
|
@ -582,11 +541,10 @@ impl Window2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_icon_inner(&self, icon: Icon) -> util::Flusher {
|
fn set_icon_inner(&self, icon: Icon) -> util::Flusher {
|
||||||
let xconn = &self.x.display;
|
let icon_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_ICON\0") };
|
||||||
let icon_atom = unsafe { xconn.get_atom_unchecked(b"_NET_WM_ICON\0") };
|
|
||||||
let data = icon.to_cardinals();
|
let data = icon.to_cardinals();
|
||||||
xconn.change_property(
|
self.xconn.change_property(
|
||||||
self.x.window,
|
self.xwindow,
|
||||||
icon_atom,
|
icon_atom,
|
||||||
ffi::XA_CARDINAL,
|
ffi::XA_CARDINAL,
|
||||||
util::PropMode::Replace,
|
util::PropMode::Replace,
|
||||||
|
@ -595,11 +553,10 @@ impl Window2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unset_icon_inner(&self) -> util::Flusher {
|
fn unset_icon_inner(&self) -> util::Flusher {
|
||||||
let xconn = &self.x.display;
|
let icon_atom = unsafe { self.xconn.get_atom_unchecked(b"_NET_WM_ICON\0") };
|
||||||
let icon_atom = unsafe { xconn.get_atom_unchecked(b"_NET_WM_ICON\0") };
|
|
||||||
let empty_data: [util::Cardinal; 0] = [];
|
let empty_data: [util::Cardinal; 0] = [];
|
||||||
xconn.change_property(
|
self.xconn.change_property(
|
||||||
self.x.window,
|
self.xwindow,
|
||||||
icon_atom,
|
icon_atom,
|
||||||
ffi::XA_CARDINAL,
|
ffi::XA_CARDINAL,
|
||||||
util::PropMode::Replace,
|
util::PropMode::Replace,
|
||||||
|
@ -616,26 +573,26 @@ impl Window2 {
|
||||||
|
|
||||||
pub fn show(&self) {
|
pub fn show(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
(self.x.display.xlib.XMapRaised)(self.x.display.display, self.x.window);
|
(self.xconn.xlib.XMapRaised)(self.xconn.display, self.xwindow);
|
||||||
self.x.display.flush_requests()
|
self.xconn.flush_requests()
|
||||||
.expect("Failed to call XMapRaised");
|
.expect("Failed to call XMapRaised");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hide(&self) {
|
pub fn hide(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
(self.x.display.xlib.XUnmapWindow)(self.x.display.display, self.x.window);
|
(self.xconn.xlib.XUnmapWindow)(self.xconn.display, self.xwindow);
|
||||||
self.x.display.flush_requests()
|
self.xconn.flush_requests()
|
||||||
.expect("Failed to call XUnmapWindow");
|
.expect("Failed to call XUnmapWindow");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_cached_frame_extents(&self) {
|
fn update_cached_frame_extents(&self) {
|
||||||
let extents = self.x.display.get_frame_extents_heuristic(self.x.window, self.x.root);
|
let extents = self.xconn.get_frame_extents_heuristic(self.xwindow, self.root);
|
||||||
(*self.shared_state.lock()).frame_extents = Some(extents);
|
(*self.shared_state.lock()).frame_extents = Some(extents);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invalidate_cached_frame_extents(&self) {
|
pub fn invalidate_cached_frame_extents(&self) {
|
||||||
(*self.shared_state.lock()).frame_extents.take();
|
(*self.shared_state.lock()).frame_extents.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,7 +611,7 @@ impl Window2 {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_inner_position(&self) -> Option<(i32, i32)> {
|
pub fn get_inner_position(&self) -> Option<(i32, i32)> {
|
||||||
self.x.display.translate_coords(self.x.window, self.x.root )
|
self.xconn.translate_coords(self.xwindow, self.root )
|
||||||
.ok()
|
.ok()
|
||||||
.map(|coords| (coords.x_rel_root, coords.y_rel_root))
|
.map(|coords| (coords.x_rel_root, coords.y_rel_root))
|
||||||
}
|
}
|
||||||
|
@ -673,19 +630,19 @@ impl Window2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
(self.x.display.xlib.XMoveWindow)(
|
(self.xconn.xlib.XMoveWindow)(
|
||||||
self.x.display.display,
|
self.xconn.display,
|
||||||
self.x.window,
|
self.xwindow,
|
||||||
x as c_int,
|
x as c_int,
|
||||||
y as c_int,
|
y as c_int,
|
||||||
);
|
);
|
||||||
self.x.display.flush_requests()
|
self.xconn.flush_requests()
|
||||||
}.expect("Failed to call XMoveWindow");
|
}.expect("Failed to call XMoveWindow");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_inner_size(&self) -> Option<(u32, u32)> {
|
pub fn get_inner_size(&self) -> Option<(u32, u32)> {
|
||||||
self.x.display.get_geometry(self.x.window)
|
self.xconn.get_geometry(self.xwindow)
|
||||||
.ok()
|
.ok()
|
||||||
.map(|geo| (geo.width, geo.height))
|
.map(|geo| (geo.width, geo.height))
|
||||||
}
|
}
|
||||||
|
@ -706,39 +663,37 @@ impl Window2 {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_inner_size(&self, width: u32, height: u32) {
|
pub fn set_inner_size(&self, width: u32, height: u32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
(self.x.display.xlib.XResizeWindow)(
|
(self.xconn.xlib.XResizeWindow)(
|
||||||
self.x.display.display,
|
self.xconn.display,
|
||||||
self.x.window,
|
self.xwindow,
|
||||||
width as c_uint,
|
width as c_uint,
|
||||||
height as c_uint,
|
height as c_uint,
|
||||||
);
|
);
|
||||||
self.x.display.flush_requests()
|
self.xconn.flush_requests()
|
||||||
}.expect("Failed to call XResizeWindow");
|
}.expect("Failed to call XResizeWindow");
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn update_normal_hints<F>(&self, callback: F) -> Result<(), XError>
|
unsafe fn update_normal_hints<F>(&self, callback: F) -> Result<(), XError>
|
||||||
where F: FnOnce(*mut ffi::XSizeHints) -> ()
|
where F: FnOnce(*mut ffi::XSizeHints) -> ()
|
||||||
{
|
{
|
||||||
let xconn = &self.x.display;
|
let size_hints = self.xconn.alloc_size_hints();
|
||||||
|
|
||||||
let size_hints = xconn.alloc_size_hints();
|
|
||||||
let mut flags: c_long = mem::uninitialized();
|
let mut flags: c_long = mem::uninitialized();
|
||||||
(xconn.xlib.XGetWMNormalHints)(
|
(self.xconn.xlib.XGetWMNormalHints)(
|
||||||
xconn.display,
|
self.xconn.display,
|
||||||
self.x.window,
|
self.xwindow,
|
||||||
size_hints.ptr,
|
size_hints.ptr,
|
||||||
&mut flags,
|
&mut flags,
|
||||||
);
|
);
|
||||||
xconn.check_errors()?;
|
self.xconn.check_errors()?;
|
||||||
|
|
||||||
callback(size_hints.ptr);
|
callback(size_hints.ptr);
|
||||||
|
|
||||||
(xconn.xlib.XSetWMNormalHints)(
|
(self.xconn.xlib.XSetWMNormalHints)(
|
||||||
xconn.display,
|
self.xconn.display,
|
||||||
self.x.window,
|
self.xwindow,
|
||||||
size_hints.ptr,
|
size_hints.ptr,
|
||||||
);
|
);
|
||||||
xconn.flush_requests()?;
|
self.xconn.flush_requests()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -773,44 +728,44 @@ impl Window2 {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_xlib_display(&self) -> *mut c_void {
|
pub fn get_xlib_display(&self) -> *mut c_void {
|
||||||
self.x.display.display as _
|
self.xconn.display as _
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_xlib_screen_id(&self) -> c_int {
|
pub fn get_xlib_screen_id(&self) -> c_int {
|
||||||
self.x.screen_id
|
self.screen_id
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_xlib_xconnection(&self) -> Arc<XConnection> {
|
pub fn get_xlib_xconnection(&self) -> Arc<XConnection> {
|
||||||
self.x.display.clone()
|
Arc::clone(&self.xconn)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn platform_display(&self) -> *mut libc::c_void {
|
pub fn platform_display(&self) -> *mut libc::c_void {
|
||||||
self.x.display.display as _
|
self.xconn.display as _
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_xlib_window(&self) -> c_ulong {
|
pub fn get_xlib_window(&self) -> c_ulong {
|
||||||
self.x.window
|
self.xwindow
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn platform_window(&self) -> *mut libc::c_void {
|
pub fn platform_window(&self) -> *mut libc::c_void {
|
||||||
self.x.window as _
|
self.xwindow as _
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_xcb_connection(&self) -> *mut c_void {
|
pub fn get_xcb_connection(&self) -> *mut c_void {
|
||||||
unsafe {
|
unsafe {
|
||||||
(self.x.display.xlib_xcb.XGetXCBConnection)(self.x.display.display) as *mut _
|
(self.xconn.xlib_xcb.XGetXCBConnection)(self.xconn.display) as *mut _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_cursor(&self, name: &[u8]) -> ffi::Cursor {
|
fn load_cursor(&self, name: &[u8]) -> ffi::Cursor {
|
||||||
unsafe {
|
unsafe {
|
||||||
(self.x.display.xcursor.XcursorLibraryLoadCursor)(
|
(self.xconn.xcursor.XcursorLibraryLoadCursor)(
|
||||||
self.x.display.display,
|
self.xconn.display,
|
||||||
name.as_ptr() as *const c_char,
|
name.as_ptr() as *const c_char,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -890,19 +845,18 @@ impl Window2 {
|
||||||
|
|
||||||
fn update_cursor(&self, cursor: ffi::Cursor) {
|
fn update_cursor(&self, cursor: ffi::Cursor) {
|
||||||
unsafe {
|
unsafe {
|
||||||
(self.x.display.xlib.XDefineCursor)(self.x.display.display, self.x.window, cursor);
|
(self.xconn.xlib.XDefineCursor)(self.xconn.display, self.xwindow, cursor);
|
||||||
if cursor != 0 {
|
if cursor != 0 {
|
||||||
(self.x.display.xlib.XFreeCursor)(self.x.display.display, cursor);
|
(self.xconn.xlib.XFreeCursor)(self.xconn.display, cursor);
|
||||||
}
|
}
|
||||||
self.x.display.flush_requests().expect("Failed to set or free the cursor");
|
self.xconn.flush_requests().expect("Failed to set or free the cursor");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_cursor(&self, cursor: MouseCursor) {
|
pub fn set_cursor(&self, cursor: MouseCursor) {
|
||||||
let mut current_cursor = self.cursor.lock();
|
*self.cursor.lock() = cursor;
|
||||||
*current_cursor = cursor;
|
|
||||||
if *self.cursor_state.lock() != CursorState::Hide {
|
if *self.cursor_state.lock() != CursorState::Hide {
|
||||||
self.update_cursor(self.get_cursor(*current_cursor));
|
self.update_cursor(self.get_cursor(cursor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -912,9 +866,9 @@ impl Window2 {
|
||||||
fn create_empty_cursor(&self) -> Option<ffi::Cursor> {
|
fn create_empty_cursor(&self) -> Option<ffi::Cursor> {
|
||||||
let data = 0;
|
let data = 0;
|
||||||
let pixmap = unsafe {
|
let pixmap = unsafe {
|
||||||
(self.x.display.xlib.XCreateBitmapFromData)(
|
(self.xconn.xlib.XCreateBitmapFromData)(
|
||||||
self.x.display.display,
|
self.xconn.display,
|
||||||
self.x.window,
|
self.xwindow,
|
||||||
&data,
|
&data,
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
|
@ -929,8 +883,8 @@ impl Window2 {
|
||||||
// We don't care about this color, since it only fills bytes
|
// We don't care about this color, since it only fills bytes
|
||||||
// in the pixmap which are not 0 in the mask.
|
// in the pixmap which are not 0 in the mask.
|
||||||
let dummy_color: ffi::XColor = mem::uninitialized();
|
let dummy_color: ffi::XColor = mem::uninitialized();
|
||||||
let cursor = (self.x.display.xlib.XCreatePixmapCursor)(
|
let cursor = (self.xconn.xlib.XCreatePixmapCursor)(
|
||||||
self.x.display.display,
|
self.xconn.display,
|
||||||
pixmap,
|
pixmap,
|
||||||
pixmap,
|
pixmap,
|
||||||
&dummy_color as *const _ as *mut _,
|
&dummy_color as *const _ as *mut _,
|
||||||
|
@ -938,26 +892,27 @@ impl Window2 {
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
(self.x.display.xlib.XFreePixmap)(self.x.display.display, pixmap);
|
(self.xconn.xlib.XFreePixmap)(self.xconn.display, pixmap);
|
||||||
cursor
|
cursor
|
||||||
};
|
};
|
||||||
Some(cursor)
|
Some(cursor)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
|
pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
|
||||||
use CursorState::{ Grab, Normal, Hide };
|
use CursorState::*;
|
||||||
|
|
||||||
let mut cursor_state = self.cursor_state.lock();
|
let mut cursor_state_lock = self.cursor_state.lock();
|
||||||
match (state, *cursor_state) {
|
|
||||||
|
match (state, *cursor_state_lock) {
|
||||||
(Normal, Normal) | (Hide, Hide) | (Grab, Grab) => return Ok(()),
|
(Normal, Normal) | (Hide, Hide) | (Grab, Grab) => return Ok(()),
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
match *cursor_state {
|
match *cursor_state_lock {
|
||||||
Grab => {
|
Grab => {
|
||||||
unsafe {
|
unsafe {
|
||||||
(self.x.display.xlib.XUngrabPointer)(self.x.display.display, ffi::CurrentTime);
|
(self.xconn.xlib.XUngrabPointer)(self.xconn.display, ffi::CurrentTime);
|
||||||
self.x.display.flush_requests().expect("Failed to call XUngrabPointer");
|
self.xconn.flush_requests().expect("Failed to call XUngrabPointer");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Normal => {},
|
Normal => {},
|
||||||
|
@ -966,11 +921,11 @@ impl Window2 {
|
||||||
|
|
||||||
match state {
|
match state {
|
||||||
Normal => {
|
Normal => {
|
||||||
*cursor_state = state;
|
*cursor_state_lock = state;
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
Hide => {
|
Hide => {
|
||||||
*cursor_state = state;
|
*cursor_state_lock = state;
|
||||||
self.update_cursor(
|
self.update_cursor(
|
||||||
self.create_empty_cursor().expect("Failed to create empty cursor")
|
self.create_empty_cursor().expect("Failed to create empty cursor")
|
||||||
);
|
);
|
||||||
|
@ -980,20 +935,20 @@ impl Window2 {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Ungrab before grabbing to prevent passive grabs
|
// Ungrab before grabbing to prevent passive grabs
|
||||||
// from causing AlreadyGrabbed
|
// from causing AlreadyGrabbed
|
||||||
(self.x.display.xlib.XUngrabPointer)(self.x.display.display, ffi::CurrentTime);
|
(self.xconn.xlib.XUngrabPointer)(self.xconn.display, ffi::CurrentTime);
|
||||||
|
|
||||||
match (self.x.display.xlib.XGrabPointer)(
|
match (self.xconn.xlib.XGrabPointer)(
|
||||||
self.x.display.display, self.x.window, ffi::True,
|
self.xconn.display, self.xwindow, ffi::True,
|
||||||
(ffi::ButtonPressMask | ffi::ButtonReleaseMask | ffi::EnterWindowMask |
|
(ffi::ButtonPressMask | ffi::ButtonReleaseMask | ffi::EnterWindowMask |
|
||||||
ffi::LeaveWindowMask | ffi::PointerMotionMask | ffi::PointerMotionHintMask |
|
ffi::LeaveWindowMask | ffi::PointerMotionMask | ffi::PointerMotionHintMask |
|
||||||
ffi::Button1MotionMask | ffi::Button2MotionMask | ffi::Button3MotionMask |
|
ffi::Button1MotionMask | ffi::Button2MotionMask | ffi::Button3MotionMask |
|
||||||
ffi::Button4MotionMask | ffi::Button5MotionMask | ffi::ButtonMotionMask |
|
ffi::Button4MotionMask | ffi::Button5MotionMask | ffi::ButtonMotionMask |
|
||||||
ffi::KeymapStateMask) as c_uint,
|
ffi::KeymapStateMask) as c_uint,
|
||||||
ffi::GrabModeAsync, ffi::GrabModeAsync,
|
ffi::GrabModeAsync, ffi::GrabModeAsync,
|
||||||
self.x.window, 0, ffi::CurrentTime
|
self.xwindow, 0, ffi::CurrentTime
|
||||||
) {
|
) {
|
||||||
ffi::GrabSuccess => {
|
ffi::GrabSuccess => {
|
||||||
*cursor_state = state;
|
*cursor_state_lock = state;
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
ffi::AlreadyGrabbed | ffi::GrabInvalidTime |
|
ffi::AlreadyGrabbed | ffi::GrabInvalidTime |
|
||||||
|
@ -1012,10 +967,10 @@ impl Window2 {
|
||||||
|
|
||||||
pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
|
pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
(self.x.display.xlib.XWarpPointer)(
|
(self.xconn.xlib.XWarpPointer)(
|
||||||
self.x.display.display,
|
self.xconn.display,
|
||||||
0,
|
0,
|
||||||
self.x.window,
|
self.xwindow,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
@ -1023,10 +978,10 @@ impl Window2 {
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
);
|
);
|
||||||
self.x.display.flush_requests().map_err(|_| ())
|
self.xconn.flush_requests().map_err(|_| ())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn id(&self) -> WindowId { WindowId(self.x.window) }
|
pub fn id(&self) -> WindowId { WindowId(self.xwindow) }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue