mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2024-12-25 06:41:31 +11:00
x11: Set window title prior to mapping window (#362)
Fixes #282 Some tiling window managers (i3, dwm, etc.) determine how a window should behave based on its name. If the name is set after mapping, then window managers will check the name before we set it, followed by them detecting it as a change when the name is actually set. That results in the window briefly behaving in an unexpected way, followed by a rapid switch to the expected behavior. In accordance to section 4.1.2 of ICCCM, the name, decorations, size hints, and window deletion redirection have all been moved up to be set before mapping.
This commit is contained in:
parent
d18db208ff
commit
9698d0a8d8
|
@ -125,6 +125,24 @@ impl Window2 {
|
||||||
win
|
win
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let window = Window2 {
|
||||||
|
x: Arc::new(XWindow {
|
||||||
|
display: display.clone(),
|
||||||
|
window,
|
||||||
|
root,
|
||||||
|
screen_id,
|
||||||
|
}),
|
||||||
|
cursor_state: Mutex::new(CursorState::Normal),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Title must be set before mapping, lest some tiling window managers briefly pick up on
|
||||||
|
// the initial un-titled window state
|
||||||
|
window.set_title(&window_attrs.title);
|
||||||
|
window.set_decorations(window_attrs.decorations);
|
||||||
|
|
||||||
|
{
|
||||||
|
let ref x_window: &XWindow = window.x.borrow();
|
||||||
|
|
||||||
// Enable drag and drop
|
// Enable drag and drop
|
||||||
unsafe {
|
unsafe {
|
||||||
let atom_name: *const libc::c_char = b"XdndAware\0".as_ptr() as _;
|
let atom_name: *const libc::c_char = b"XdndAware\0".as_ptr() as _;
|
||||||
|
@ -132,7 +150,7 @@ impl Window2 {
|
||||||
let version = &5; // Latest version; hasn't changed since 2002
|
let version = &5; // Latest version; hasn't changed since 2002
|
||||||
(display.xlib.XChangeProperty)(
|
(display.xlib.XChangeProperty)(
|
||||||
display.display,
|
display.display,
|
||||||
window,
|
x_window.window,
|
||||||
atom,
|
atom,
|
||||||
ffi::XA_ATOM,
|
ffi::XA_ATOM,
|
||||||
32,
|
32,
|
||||||
|
@ -150,39 +168,12 @@ impl Window2 {
|
||||||
let hint = (display.xlib.XAllocClassHint)();
|
let hint = (display.xlib.XAllocClassHint)();
|
||||||
(*hint).res_name = c_name as *mut libc::c_char;
|
(*hint).res_name = c_name as *mut libc::c_char;
|
||||||
(*hint).res_class = c_name as *mut libc::c_char;
|
(*hint).res_class = c_name as *mut libc::c_char;
|
||||||
(display.xlib.XSetClassHint)(display.display, window, hint);
|
(display.xlib.XSetClassHint)(display.display, x_window.window, hint);
|
||||||
display.check_errors().expect("Failed to call XSetClassHint");
|
display.check_errors().expect("Failed to call XSetClassHint");
|
||||||
(display.xlib.XFree)(hint as *mut _);
|
(display.xlib.XFree)(hint as *mut _);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// set visibility
|
|
||||||
if window_attrs.visible {
|
|
||||||
unsafe {
|
|
||||||
(display.xlib.XMapRaised)(display.display, window);
|
|
||||||
(display.xlib.XFlush)(display.display);
|
|
||||||
}
|
|
||||||
|
|
||||||
display.check_errors().expect("Failed to set window visibility");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Opt into handling window close
|
|
||||||
unsafe {
|
|
||||||
(display.xlib.XSetWMProtocols)(display.display, window, &ctx.wm_delete_window as *const _ as *mut _, 1);
|
|
||||||
display.check_errors().expect("Failed to call XSetWMProtocols");
|
|
||||||
(display.xlib.XFlush)(display.display);
|
|
||||||
display.check_errors().expect("Failed to call XFlush");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to make keyboard input repeat detectable
|
|
||||||
unsafe {
|
|
||||||
let mut supported_ptr = ffi::False;
|
|
||||||
(display.xlib.XkbSetDetectableAutoRepeat)(display.display, ffi::True, &mut supported_ptr);
|
|
||||||
if supported_ptr == ffi::False {
|
|
||||||
return Err(OsError(format!("XkbSetDetectableAutoRepeat failed")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// set size hints
|
// set size hints
|
||||||
let mut size_hints: ffi::XSizeHints = unsafe { mem::zeroed() };
|
let mut size_hints: ffi::XSizeHints = unsafe { mem::zeroed() };
|
||||||
size_hints.flags = ffi::PSize;
|
size_hints.flags = ffi::PSize;
|
||||||
|
@ -199,10 +190,37 @@ impl Window2 {
|
||||||
size_hints.max_height = dimensions.1 as i32;
|
size_hints.max_height = dimensions.1 as i32;
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
(display.xlib.XSetNormalHints)(display.display, window, &mut size_hints);
|
(display.xlib.XSetNormalHints)(display.display, x_window.window, &mut size_hints);
|
||||||
display.check_errors().expect("Failed to call XSetNormalHints");
|
display.check_errors().expect("Failed to call XSetNormalHints");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Opt into handling window close
|
||||||
|
unsafe {
|
||||||
|
(display.xlib.XSetWMProtocols)(display.display, x_window.window, &ctx.wm_delete_window as *const _ as *mut _, 1);
|
||||||
|
display.check_errors().expect("Failed to call XSetWMProtocols");
|
||||||
|
(display.xlib.XFlush)(display.display);
|
||||||
|
display.check_errors().expect("Failed to call XFlush");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set visibility (map window)
|
||||||
|
if window_attrs.visible {
|
||||||
|
unsafe {
|
||||||
|
(display.xlib.XMapRaised)(display.display, x_window.window);
|
||||||
|
(display.xlib.XFlush)(display.display);
|
||||||
|
}
|
||||||
|
|
||||||
|
display.check_errors().expect("Failed to set window visibility");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to make keyboard input repeat detectable
|
||||||
|
unsafe {
|
||||||
|
let mut supported_ptr = ffi::False;
|
||||||
|
(display.xlib.XkbSetDetectableAutoRepeat)(display.display, ffi::True, &mut supported_ptr);
|
||||||
|
if supported_ptr == ffi::False {
|
||||||
|
return Err(OsError(format!("XkbSetDetectableAutoRepeat failed")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Select XInput2 events
|
// Select XInput2 events
|
||||||
{
|
{
|
||||||
let mask = ffi::XI_MotionMask
|
let mask = ffi::XI_MotionMask
|
||||||
|
@ -217,30 +235,17 @@ impl Window2 {
|
||||||
mask: mem::transmute::<*const i32, *mut c_uchar>(&mask as *const i32),
|
mask: mem::transmute::<*const i32, *mut c_uchar>(&mask as *const i32),
|
||||||
mask_len: mem::size_of_val(&mask) as c_int,
|
mask_len: mem::size_of_val(&mask) as c_int,
|
||||||
};
|
};
|
||||||
(display.xinput2.XISelectEvents)(display.display, window,
|
(display.xinput2.XISelectEvents)(display.display, x_window.window,
|
||||||
&mut event_mask as *mut ffi::XIEventMask, 1);
|
&mut event_mask as *mut ffi::XIEventMask, 1);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
let window = Window2 {
|
// These properties must be set after mapping
|
||||||
x: Arc::new(XWindow {
|
|
||||||
display: display.clone(),
|
|
||||||
window,
|
|
||||||
root,
|
|
||||||
screen_id,
|
|
||||||
}),
|
|
||||||
cursor_state: Mutex::new(CursorState::Normal),
|
|
||||||
};
|
|
||||||
|
|
||||||
window.set_title(&window_attrs.title);
|
|
||||||
window.set_decorations(window_attrs.decorations);
|
|
||||||
window.set_maximized(window_attrs.maximized);
|
window.set_maximized(window_attrs.maximized);
|
||||||
window.set_fullscreen(window_attrs.fullscreen.clone());
|
window.set_fullscreen(window_attrs.fullscreen.clone());
|
||||||
|
|
||||||
if window_attrs.visible {
|
if window_attrs.visible {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ref x_window: &XWindow = window.x.borrow();
|
|
||||||
|
|
||||||
// XSetInputFocus generates an error if the window is not visible,
|
// XSetInputFocus generates an error if the window is not visible,
|
||||||
// therefore we wait until it's the case.
|
// therefore we wait until it's the case.
|
||||||
loop {
|
loop {
|
||||||
|
@ -264,6 +269,7 @@ impl Window2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// returning
|
// returning
|
||||||
Ok(window)
|
Ok(window)
|
||||||
|
|
Loading…
Reference in a new issue