mirror of
https://github.com/italicsjenga/winit-sonoma-fix.git
synced 2025-01-11 13:31:29 +11:00
parent
f51f7c0ca8
commit
cebd15bfd1
|
@ -21,6 +21,8 @@
|
|||
- On Windows, using `CursorState::Hide` when the cursor is grabbed now ungrabs the cursor first.
|
||||
- Implemented `MouseCursor::NoneCursor` on Windows.
|
||||
- Added `WindowBuilder::with_always_on_top` and `Window::set_always_on_top`. Implemented on Windows, macOS, and X11.
|
||||
- On X11, `WindowBuilderExt` now has `with_class`, `with_override_redirect`, and `with_x11_window_type` to allow for more control over window creation. `WindowExt` additionally has `set_urgent`.
|
||||
- More hints are set by default on X11, including `_NET_WM_PID` and `WM_CLIENT_MACHINE`. Note that prior to this, the `WM_CLASS` hint was automatically set to whatever value was passed to `with_title`. It's now set to the executable name to better conform to expectations and the specification; if this is undesirable, you must explicitly use `WindowBuilderExt::with_class`.
|
||||
|
||||
# Version 0.14.0 (2018-05-09)
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
//! - Calling `Window::new(&events_loop)`.
|
||||
//! - Calling `let builder = WindowBuilder::new()` then `builder.build(&events_loop)`.
|
||||
//!
|
||||
//! The first way is the simpliest way and will give you default values for everything.
|
||||
//! The first way is the simplest way and will give you default values for everything.
|
||||
//!
|
||||
//! The second way allows you to customize the way your window will look and behave by modifying
|
||||
//! the fields of the `WindowBuilder` object before you create the window.
|
||||
|
|
|
@ -17,6 +17,7 @@ use platform::x11::ffi::XVisualInfo;
|
|||
pub use platform::x11;
|
||||
|
||||
pub use platform::XNotSupported;
|
||||
pub use platform::x11::util::WindowType as XWindowType;
|
||||
|
||||
/// Additional methods on `EventsLoop` that are specific to Linux.
|
||||
pub trait EventsLoopExt {
|
||||
|
@ -94,6 +95,9 @@ pub trait WindowExt {
|
|||
|
||||
fn get_xlib_xconnection(&self) -> Option<Arc<XConnection>>;
|
||||
|
||||
/// Set window urgency hint (`XUrgencyHint`). Only relevant on X.
|
||||
fn set_urgent(&self, is_urgent: bool);
|
||||
|
||||
/// This function returns the underlying `xcb_connection_t` of an xlib `Display`.
|
||||
///
|
||||
/// Returns `None` if the window doesn't use xlib (if it uses wayland for example).
|
||||
|
@ -142,6 +146,7 @@ impl WindowExt for Window {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_xlib_screen_id(&self) -> Option<raw::c_int> {
|
||||
match self.window {
|
||||
LinuxWindow::X(ref w) => Some(w.get_xlib_screen_id()),
|
||||
|
@ -149,6 +154,7 @@ impl WindowExt for Window {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_xlib_xconnection(&self) -> Option<Arc<XConnection>> {
|
||||
match self.window {
|
||||
LinuxWindow::X(ref w) => Some(w.get_xlib_xconnection()),
|
||||
|
@ -156,6 +162,7 @@ impl WindowExt for Window {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_xcb_connection(&self) -> Option<*mut raw::c_void> {
|
||||
match self.window {
|
||||
LinuxWindow::X(ref w) => Some(w.get_xcb_connection()),
|
||||
|
@ -163,6 +170,13 @@ impl WindowExt for Window {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_urgent(&self, is_urgent: bool) {
|
||||
if let LinuxWindow::X(ref w) = self.window {
|
||||
w.set_urgent(is_urgent);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_wayland_surface(&self) -> Option<*mut raw::c_void> {
|
||||
match self.window {
|
||||
|
@ -190,6 +204,12 @@ pub trait WindowBuilderExt {
|
|||
fn with_x11_visual<T>(self, visual_infos: *const T) -> WindowBuilder;
|
||||
fn with_x11_screen(self, screen_id: i32) -> WindowBuilder;
|
||||
|
||||
/// Build window with `WM_CLASS` hint; defaults to the name of the binary. Only relevant on X11.
|
||||
fn with_class(self, class: String, instance: String) -> WindowBuilder;
|
||||
/// Build window with override-redirect flag; defaults to false. Only relevant on X11.
|
||||
fn with_override_redirect(self, override_redirect: bool) -> WindowBuilder;
|
||||
/// Build window with `_NET_WM_WINDOW_TYPE` hint; defaults to `Normal`. Only relevant on X11.
|
||||
fn with_x11_window_type(self, x11_window_type: XWindowType) -> WindowBuilder;
|
||||
/// Build window with resize increment hint. Only implemented on X11.
|
||||
fn with_resize_increments(self, width_inc: u32, height_inc: u32) -> WindowBuilder;
|
||||
/// Build window with base size hint. Only implemented on X11.
|
||||
|
@ -211,6 +231,24 @@ impl WindowBuilderExt for WindowBuilder {
|
|||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_class(mut self, instance: String, class: String) -> WindowBuilder {
|
||||
self.platform_specific.class = Some((instance, class));
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_override_redirect(mut self, override_redirect: bool) -> WindowBuilder {
|
||||
self.platform_specific.override_redirect = override_redirect;
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_x11_window_type(mut self, x11_window_type: XWindowType) -> WindowBuilder {
|
||||
self.platform_specific.x11_window_type = x11_window_type;
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_resize_increments(mut self, width_inc: u32, height_inc: u32) -> WindowBuilder {
|
||||
self.platform_specific.resize_increments = Some((width_inc, height_inc));
|
||||
|
|
|
@ -44,6 +44,9 @@ pub struct PlatformSpecificWindowBuilderAttributes {
|
|||
pub screen_id: Option<i32>,
|
||||
pub resize_increments: Option<(u32, u32)>,
|
||||
pub base_size: Option<(u32, u32)>,
|
||||
pub class: Option<(String, String)>,
|
||||
pub override_redirect: bool,
|
||||
pub x11_window_type: x11::util::WindowType,
|
||||
}
|
||||
|
||||
lazy_static!(
|
||||
|
|
|
@ -7,7 +7,7 @@ mod window;
|
|||
mod xdisplay;
|
||||
mod dnd;
|
||||
mod ime;
|
||||
mod util;
|
||||
pub mod util;
|
||||
|
||||
pub use self::monitor::{
|
||||
MonitorId,
|
||||
|
|
|
@ -18,3 +18,51 @@ impl From<bool> for StateOperation {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// X window type. Maps directly to
|
||||
/// [`_NET_WM_WINDOW_TYPE`](https://specifications.freedesktop.org/wm-spec/1.3/ar01s05.html).
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum WindowType {
|
||||
/// A desktop feature. This can include a single window containing desktop icons with the same dimensions as the
|
||||
/// screen, allowing the desktop environment to have full control of the desktop, without the need for proxying
|
||||
/// root window clicks.
|
||||
Desktop,
|
||||
/// A dock or panel feature. Typically a Window Manager would keep such windows on top of all other windows.
|
||||
Dock,
|
||||
/// Toolbar windows. "Torn off" from the main application.
|
||||
Toolbar,
|
||||
/// Pinnable menu windows. "Torn off" from the main application.
|
||||
Menu,
|
||||
/// A small persistent utility window, such as a palette or toolbox.
|
||||
Utility,
|
||||
/// The window is a splash screen displayed as an application is starting up.
|
||||
Splash,
|
||||
/// This is a dialog window.
|
||||
Dialog,
|
||||
/// This is a normal, top-level window.
|
||||
Normal,
|
||||
}
|
||||
|
||||
impl Default for WindowType {
|
||||
fn default() -> Self {
|
||||
WindowType::Normal
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowType {
|
||||
pub(crate) fn as_atom(&self, xconn: &Arc<XConnection>) -> ffi::Atom {
|
||||
use self::WindowType::*;
|
||||
let atom_name: &[u8] = match self {
|
||||
Desktop => b"_NET_WM_WINDOW_TYPE_DESKTOP\0",
|
||||
Dock => b"_NET_WM_WINDOW_TYPE_DOCK\0",
|
||||
Toolbar => b"_NET_WM_WINDOW_TYPE_TOOLBAR\0",
|
||||
Menu => b"_NET_WM_WINDOW_TYPE_MENU\0",
|
||||
Utility => b"_NET_WM_WINDOW_TYPE_UTILITY\0",
|
||||
Splash => b"_NET_WM_WINDOW_TYPE_SPLASH\0",
|
||||
Dialog => b"_NET_WM_WINDOW_TYPE_DIALOG\0",
|
||||
Normal => b"_NET_WM_WINDOW_TYPE_NORMAL\0",
|
||||
};
|
||||
unsafe { get_atom(xconn, atom_name) }
|
||||
.expect("Failed to get atom for `WindowType`")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use std::{cmp, mem};
|
||||
use std::{cmp, env, mem};
|
||||
use std::borrow::Borrow;
|
||||
use std::ffi::CString;
|
||||
use std::os::raw::*;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use libc;
|
||||
|
@ -115,6 +116,10 @@ impl Window2 {
|
|||
window_attributes |= ffi::CWBackPixel;
|
||||
}
|
||||
|
||||
if pl_attribs.override_redirect {
|
||||
window_attributes |= ffi::CWOverrideRedirect;
|
||||
}
|
||||
|
||||
// finally creating the window
|
||||
let window = unsafe {
|
||||
(xconn.xlib.XCreateWindow)(
|
||||
|
@ -127,12 +132,12 @@ impl Window2 {
|
|||
0,
|
||||
match pl_attribs.visual_infos {
|
||||
Some(vi) => vi.depth,
|
||||
None => ffi::CopyFromParent
|
||||
None => ffi::CopyFromParent,
|
||||
},
|
||||
ffi::InputOutput as c_uint,
|
||||
match pl_attribs.visual_infos {
|
||||
Some(vi) => vi.visual,
|
||||
None => ffi::CopyFromParent as *mut _
|
||||
None => ffi::CopyFromParent as *mut ffi::Visual,
|
||||
},
|
||||
window_attributes,
|
||||
&mut set_win_attr,
|
||||
|
@ -178,17 +183,42 @@ impl Window2 {
|
|||
)
|
||||
}.queue();
|
||||
|
||||
// Set ICCCM WM_CLASS property based on initial window title
|
||||
// Must be done *before* mapping the window by ICCCM 4.1.2.5
|
||||
// WM_CLASS must be set *before* mapping the window, as per ICCCM!
|
||||
{
|
||||
let name = CString::new(window_attrs.title.as_str())
|
||||
.expect("Window title contained null byte");
|
||||
let mut class_hints = {
|
||||
let class_hints = unsafe { (xconn.xlib.XAllocClassHint)() };
|
||||
util::XSmartPointer::new(xconn, class_hints)
|
||||
}.expect("XAllocClassHint returned null; out of memory");
|
||||
(*class_hints).res_name = name.as_ptr() as *mut c_char;
|
||||
(*class_hints).res_class = name.as_ptr() as *mut c_char;
|
||||
}.expect("`XAllocClassHint` returned null; out of memory");
|
||||
|
||||
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");
|
||||
(instance, class)
|
||||
} else {
|
||||
let class = env::args()
|
||||
.next()
|
||||
.as_ref()
|
||||
// Default to the name of the binary (via argv[0])
|
||||
.and_then(|path| Path::new(path).file_name())
|
||||
.and_then(|bin_name| bin_name.to_str())
|
||||
.map(|bin_name| bin_name.to_owned())
|
||||
.or_else(|| Some(window_attrs.title.clone()))
|
||||
.and_then(|string| CString::new(string.as_str()).ok())
|
||||
.expect("Default `WM_CLASS` class contained null byte");
|
||||
// This environment variable is extraordinarily unlikely to actually be used...
|
||||
let instance = env::var("RESOURCE_NAME")
|
||||
.ok()
|
||||
.and_then(|instance| CString::new(instance.as_str()).ok())
|
||||
.or_else(|| Some(class.clone()))
|
||||
.expect("Default `WM_CLASS` instance contained null byte");
|
||||
(instance, class)
|
||||
};
|
||||
|
||||
(*class_hints).res_name = class.as_ptr() as *mut c_char;
|
||||
(*class_hints).res_class = instance.as_ptr() as *mut c_char;
|
||||
|
||||
unsafe {
|
||||
(xconn.xlib.XSetClassHint)(
|
||||
xconn.display,
|
||||
|
@ -198,6 +228,17 @@ impl Window2 {
|
|||
}//.queue();
|
||||
}
|
||||
|
||||
Window2::set_pid(xconn, x_window.window)
|
||||
.map(|flusher| flusher.queue());
|
||||
|
||||
if pl_attribs.x11_window_type != Default::default() {
|
||||
Window2::set_window_type(
|
||||
xconn,
|
||||
x_window.window,
|
||||
pl_attribs.x11_window_type,
|
||||
).queue();
|
||||
}
|
||||
|
||||
// set size hints
|
||||
{
|
||||
let mut size_hints = {
|
||||
|
@ -338,6 +379,96 @@ impl Window2 {
|
|||
))
|
||||
}
|
||||
|
||||
fn set_pid(xconn: &Arc<XConnection>, window: ffi::Window) -> Option<util::Flusher> {
|
||||
let pid_atom = unsafe { util::get_atom(xconn, b"_NET_WM_PID\0") }
|
||||
.expect("Failed to call XInternAtom (_NET_WM_PID)");
|
||||
let client_machine_atom = unsafe { util::get_atom(xconn, b"WM_CLIENT_MACHINE\0") }
|
||||
.expect("Failed to call XInternAtom (WM_CLIENT_MACHINE)");
|
||||
unsafe {
|
||||
let (hostname, hostname_length) = {
|
||||
// 64 would suffice for Linux, but 256 will be enough everywhere (as per SUSv2). For instance, this is
|
||||
// the limit defined by OpenBSD.
|
||||
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; }
|
||||
hostname[MAXHOSTNAMELEN - 1] = '\0' as c_char; // a little extra safety
|
||||
let hostname_length = libc::strlen(hostname.as_ptr());
|
||||
(hostname, hostname_length as usize)
|
||||
};
|
||||
util::change_property(
|
||||
xconn,
|
||||
window,
|
||||
pid_atom,
|
||||
ffi::XA_CARDINAL,
|
||||
util::Format::Long,
|
||||
util::PropMode::Replace,
|
||||
&[libc::getpid() as util::Cardinal],
|
||||
).queue();
|
||||
let flusher = util::change_property(
|
||||
xconn,
|
||||
window,
|
||||
client_machine_atom,
|
||||
ffi::XA_STRING,
|
||||
util::Format::Char,
|
||||
util::PropMode::Replace,
|
||||
&hostname[0..hostname_length],
|
||||
);
|
||||
Some(flusher)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_window_type(
|
||||
xconn: &Arc<XConnection>,
|
||||
window: ffi::Window,
|
||||
window_type: util::WindowType,
|
||||
) -> util::Flusher {
|
||||
let hint_atom = unsafe { util::get_atom(xconn, b"_NET_WM_WINDOW_TYPE\0") }
|
||||
.expect("Failed to call XInternAtom (_NET_WM_WINDOW_TYPE)");
|
||||
let window_type_atom = window_type.as_atom(xconn);
|
||||
unsafe {
|
||||
util::change_property(
|
||||
xconn,
|
||||
window,
|
||||
hint_atom,
|
||||
ffi::XA_ATOM,
|
||||
util::Format::Long,
|
||||
util::PropMode::Replace,
|
||||
&[window_type_atom],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_urgent(&self, is_urgent: bool) {
|
||||
let xconn = &self.x.display;
|
||||
|
||||
let mut wm_hints = {
|
||||
let mut wm_hints = unsafe {
|
||||
(xconn.xlib.XGetWMHints)(xconn.display, self.x.window)
|
||||
};
|
||||
xconn.check_errors().expect("`XGetWMHints` failed");
|
||||
if wm_hints.is_null() {
|
||||
wm_hints = unsafe { (xconn.xlib.XAllocWMHints)() };
|
||||
}
|
||||
util::XSmartPointer::new(xconn, wm_hints)
|
||||
}.expect("`XAllocWMHints` returned null; out of memory");
|
||||
|
||||
if is_urgent {
|
||||
(*wm_hints).flags |= ffi::XUrgencyHint;
|
||||
} else {
|
||||
(*wm_hints).flags &= !ffi::XUrgencyHint;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
(xconn.xlib.XSetWMHints)(
|
||||
xconn.display,
|
||||
self.x.window,
|
||||
wm_hints.ptr,
|
||||
);
|
||||
util::flush_requests(xconn).expect("Failed to set urgency hint");
|
||||
}
|
||||
}
|
||||
|
||||
fn set_netwm(
|
||||
xconn: &Arc<XConnection>,
|
||||
window: ffi::Window,
|
||||
|
|
|
@ -389,7 +389,7 @@ impl Window {
|
|||
self.window.set_window_icon(window_icon)
|
||||
}
|
||||
|
||||
//// Sets location of IME candidate box in client area coordinates relative to the top left.
|
||||
/// Sets location of IME candidate box in client area coordinates relative to the top left.
|
||||
#[inline]
|
||||
pub fn set_ime_spot(&self, x: i32, y: i32) {
|
||||
self.window.set_ime_spot(x, y)
|
||||
|
|
Loading…
Reference in a new issue