mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-24 06:11:30 +11:00
Fix x11 Window::get_position wrong values (#386)
Some window managers like i3wm will actually nest application windows (like those opened by winit) within other windows to, for example, add decorations. Initially when debugging this method on i3, the x and y positions were always returned as "2". The solution that other xlib abstractions use is to climb up the window hierarchy until just below the root window, and that window must be used to determine the appropriate position. This patch doesn't take into account borders or the window's offset within its parent, but it's much more usable than the original implementation on certain WMs.
This commit is contained in:
parent
7d38ed2fab
commit
150d2706f9
|
@ -3,7 +3,7 @@ use CreationError;
|
|||
use CreationError::OsError;
|
||||
use libc;
|
||||
use std::borrow::Borrow;
|
||||
use std::{mem, cmp};
|
||||
use std::{mem, cmp, ptr};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::os::raw::{c_int, c_long, c_uchar, c_ulong, c_void};
|
||||
use std::thread;
|
||||
|
@ -53,6 +53,42 @@ pub struct XWindow {
|
|||
screen_id: i32,
|
||||
}
|
||||
|
||||
impl XWindow {
|
||||
/// Get parent window of `child`
|
||||
///
|
||||
/// This method can return None if underlying xlib call fails.
|
||||
///
|
||||
/// # Unsafety
|
||||
///
|
||||
/// `child` must be a valid `Window`.
|
||||
unsafe fn get_parent_window(&self, child: ffi::Window) -> Option<ffi::Window> {
|
||||
let mut root: ffi::Window = mem::uninitialized();
|
||||
let mut parent: ffi::Window = mem::uninitialized();
|
||||
let mut children: *mut ffi::Window = ptr::null_mut();
|
||||
let mut nchildren: libc::c_uint = mem::uninitialized();
|
||||
|
||||
let res = (self.display.xlib.XQueryTree)(
|
||||
self.display.display,
|
||||
child,
|
||||
&mut root,
|
||||
&mut parent,
|
||||
&mut children,
|
||||
&mut nchildren
|
||||
);
|
||||
|
||||
if res == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
// The list of children isn't used
|
||||
if children != ptr::null_mut() {
|
||||
(self.display.xlib.XFree)(children as *mut _);
|
||||
}
|
||||
|
||||
Some(parent)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for XWindow {}
|
||||
unsafe impl Sync for XWindow {}
|
||||
|
||||
|
@ -497,7 +533,29 @@ impl Window2 {
|
|||
let mut border: libc::c_uint = mem::uninitialized();
|
||||
let mut depth: libc::c_uint = mem::uninitialized();
|
||||
|
||||
if (self.x.display.xlib.XGetGeometry)(self.x.display.display, self.x.window,
|
||||
|
||||
// Some window managers like i3wm will actually nest application
|
||||
// windows (like those opened by winit) within other windows to, for
|
||||
// example, add decorations. Initially when debugging this method on
|
||||
// i3, the x and y positions were always returned as "2".
|
||||
//
|
||||
// The solution that other xlib abstractions use is to climb up the
|
||||
// window hierarchy until just below the root window, and that
|
||||
// window must be used to determine the appropriate position.
|
||||
let window = {
|
||||
let root = self.x.root;
|
||||
let mut window = self.x.window;
|
||||
loop {
|
||||
let candidate = self.x.get_parent_window(window).unwrap();
|
||||
if candidate == root {
|
||||
break window;
|
||||
}
|
||||
|
||||
window = candidate;
|
||||
}
|
||||
};
|
||||
|
||||
if (self.x.display.xlib.XGetGeometry)(self.x.display.display, window,
|
||||
&mut root, &mut x, &mut y, &mut width, &mut height,
|
||||
&mut border, &mut depth) == 0
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue