2022-12-25 09:57:27 +02:00
|
|
|
#![cfg(free_unix)]
|
|
|
|
|
|
|
|
|
|
#[cfg(all(not(x11_platform), not(wayland_platform)))]
|
2020-06-15 09:15:27 +02:00
|
|
|
compile_error!("Please select a feature to build for unix: `x11`, `wayland`");
|
|
|
|
|
|
2023-10-15 20:31:29 +04:00
|
|
|
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
2023-08-13 23:20:09 +04:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
use std::time::Duration;
|
2020-06-15 09:15:27 +02:00
|
|
|
use std::{collections::VecDeque, env, fmt};
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2023-08-13 23:20:09 +04:00
|
|
|
use std::{ffi::CStr, mem::MaybeUninit, os::raw::*, sync::Mutex};
|
2020-06-15 09:15:27 +02:00
|
|
|
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2022-06-08 11:50:26 -07:00
|
|
|
use once_cell::sync::Lazy;
|
2023-05-28 20:02:59 +02:00
|
|
|
use smol_str::SmolStr;
|
2019-06-18 02:27:00 +08:00
|
|
|
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2024-01-04 12:54:35 +01:00
|
|
|
use self::x11::{X11Error, XConnection, XError, XNotSupported};
|
|
|
|
|
#[cfg(x11_platform)]
|
|
|
|
|
use crate::platform::x11::{WindowType as XWindowType, XlibErrorHook};
|
2019-06-21 11:33:15 -04:00
|
|
|
use crate::{
|
2020-01-04 01:31:23 -05:00
|
|
|
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
|
2023-08-13 23:20:09 +04:00
|
|
|
error::{EventLoopError, ExternalError, NotSupportedError, OsError as RootOsError},
|
2023-07-20 13:16:51 +00:00
|
|
|
event_loop::{
|
|
|
|
|
AsyncRequestSerial, ControlFlow, DeviceEvents, EventLoopClosed,
|
|
|
|
|
EventLoopWindowTarget as RootELW,
|
|
|
|
|
},
|
2019-06-21 11:33:15 -04:00
|
|
|
icon::Icon,
|
2024-01-04 12:54:35 +01:00
|
|
|
keyboard::Key,
|
|
|
|
|
platform::pump_events::PumpStatus,
|
2022-11-29 12:03:51 +02:00
|
|
|
window::{
|
2023-12-25 07:20:52 +01:00
|
|
|
ActivationToken, Cursor, CursorGrabMode, ImePurpose, ResizeDirection, Theme,
|
2023-07-20 13:16:51 +00:00
|
|
|
UserAttentionType, WindowAttributes, WindowButtons, WindowLevel,
|
2022-11-29 12:03:51 +02:00
|
|
|
},
|
2019-06-21 11:33:15 -04:00
|
|
|
};
|
2017-09-01 11:04:57 +02:00
|
|
|
|
2024-01-04 12:54:35 +01:00
|
|
|
pub(crate) use self::common::keymap::{physicalkey_to_scancode, scancode_to_physicalkey};
|
2023-12-23 16:12:29 +01:00
|
|
|
pub(crate) use crate::cursor::OnlyCursorImageBuilder as PlatformCustomCursorBuilder;
|
2020-03-07 19:42:21 +00:00
|
|
|
pub(crate) use crate::icon::RgbaIcon as PlatformIcon;
|
2023-07-31 00:39:01 +04:00
|
|
|
pub(crate) use crate::platform_impl::Fullscreen;
|
2020-03-07 19:42:21 +00:00
|
|
|
|
2024-01-04 12:54:35 +01:00
|
|
|
pub(crate) mod common;
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(wayland_platform)]
|
2024-01-04 12:54:35 +01:00
|
|
|
pub(crate) mod wayland;
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2024-01-04 12:54:35 +01:00
|
|
|
pub(crate) mod x11;
|
2017-03-03 20:56:27 +01:00
|
|
|
|
2022-06-10 13:43:33 +03:00
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
2022-02-16 22:09:03 +01:00
|
|
|
pub(crate) enum Backend {
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2022-02-16 22:09:03 +01:00
|
|
|
X,
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(wayland_platform)]
|
2022-02-16 22:09:03 +01:00
|
|
|
Wayland,
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-10 13:43:33 +03:00
|
|
|
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)]
|
2022-02-16 22:09:03 +01:00
|
|
|
pub(crate) struct PlatformSpecificEventLoopAttributes {
|
|
|
|
|
pub(crate) forced_backend: Option<Backend>,
|
|
|
|
|
pub(crate) any_thread: bool,
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-10 13:43:33 +03:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
2022-04-20 01:56:56 +03:00
|
|
|
pub struct ApplicationName {
|
|
|
|
|
pub general: String,
|
|
|
|
|
pub instance: String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ApplicationName {
|
|
|
|
|
pub fn new(general: String, instance: String) -> Self {
|
|
|
|
|
Self { general, instance }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-17 23:37:28 +01:00
|
|
|
#[derive(Clone, Debug)]
|
2017-01-28 13:03:17 +01:00
|
|
|
pub struct PlatformSpecificWindowBuilderAttributes {
|
2022-04-20 01:56:56 +03:00
|
|
|
pub name: Option<ApplicationName>,
|
2023-07-20 13:16:51 +00:00
|
|
|
pub activation_token: Option<ActivationToken>,
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2023-08-11 02:30:55 -07:00
|
|
|
pub x11: X11WindowBuilderAttributes,
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-17 23:37:28 +01:00
|
|
|
#[derive(Clone, Debug)]
|
2023-08-11 02:30:55 -07:00
|
|
|
#[cfg(x11_platform)]
|
|
|
|
|
pub struct X11WindowBuilderAttributes {
|
2023-08-05 14:58:23 -07:00
|
|
|
pub visual_id: Option<x11rb::protocol::xproto::Visualid>,
|
2017-01-28 13:03:17 +01:00
|
|
|
pub screen_id: Option<i32>,
|
2020-01-03 23:14:11 -07:00
|
|
|
pub base_size: Option<Size>,
|
2018-05-20 10:47:22 -04:00
|
|
|
pub override_redirect: bool,
|
2019-09-24 00:10:33 +10:00
|
|
|
pub x11_window_types: Vec<XWindowType>,
|
2023-08-11 02:30:55 -07:00
|
|
|
|
|
|
|
|
/// The parent window to embed this window into.
|
|
|
|
|
pub embed_window: Option<x11rb::protocol::xproto::Window>,
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
|
|
|
|
|
2019-09-24 00:10:33 +10:00
|
|
|
impl Default for PlatformSpecificWindowBuilderAttributes {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self {
|
2022-04-20 01:56:56 +03:00
|
|
|
name: None,
|
2023-07-20 13:16:51 +00:00
|
|
|
activation_token: None,
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2023-08-11 02:30:55 -07:00
|
|
|
x11: X11WindowBuilderAttributes {
|
|
|
|
|
visual_id: None,
|
|
|
|
|
screen_id: None,
|
|
|
|
|
base_size: None,
|
|
|
|
|
override_redirect: false,
|
|
|
|
|
x11_window_types: vec![XWindowType::Normal],
|
|
|
|
|
embed_window: None,
|
|
|
|
|
},
|
2019-09-24 00:10:33 +10:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2023-01-10 08:46:48 +00:00
|
|
|
pub(crate) static X11_BACKEND: Lazy<Mutex<Result<Arc<XConnection>, XNotSupported>>> =
|
2022-06-08 11:50:26 -07:00
|
|
|
Lazy::new(|| Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new)));
|
2017-01-28 13:03:17 +01:00
|
|
|
|
2019-05-29 21:29:54 -04:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub enum OsError {
|
2023-08-13 23:20:09 +04:00
|
|
|
Misc(&'static str),
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2023-07-12 00:59:12 -07:00
|
|
|
XError(Arc<X11Error>),
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(wayland_platform)]
|
2023-08-13 23:20:09 +04:00
|
|
|
WaylandError(Arc<wayland::WaylandError>),
|
2019-05-29 21:29:54 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl fmt::Display for OsError {
|
2020-06-15 09:15:27 +02:00
|
|
|
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
|
|
|
|
match *self {
|
2023-08-13 23:20:09 +04:00
|
|
|
OsError::Misc(e) => _f.pad(e),
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2023-07-12 00:59:12 -07:00
|
|
|
OsError::XError(ref e) => fmt::Display::fmt(e, _f),
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(wayland_platform)]
|
2023-08-13 23:20:09 +04:00
|
|
|
OsError::WaylandError(ref e) => fmt::Display::fmt(e, _f),
|
2019-05-29 21:29:54 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-10 08:46:48 +00:00
|
|
|
pub(crate) enum Window {
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2019-04-27 18:06:51 +02:00
|
|
|
X(x11::Window),
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(wayland_platform)]
|
2018-06-14 19:42:18 -04:00
|
|
|
Wayland(wayland::Window),
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
|
|
|
|
|
2017-03-03 21:41:51 +01:00
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
2022-07-02 14:27:19 +03:00
|
|
|
pub struct WindowId(u64);
|
|
|
|
|
|
|
|
|
|
impl From<WindowId> for u64 {
|
|
|
|
|
fn from(window_id: WindowId) -> Self {
|
|
|
|
|
window_id.0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl From<u64> for WindowId {
|
|
|
|
|
fn from(raw_id: u64) -> Self {
|
|
|
|
|
Self(raw_id)
|
|
|
|
|
}
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
|
|
|
|
|
2018-12-21 09:51:48 -07:00
|
|
|
impl WindowId {
|
2021-08-30 19:40:02 +02:00
|
|
|
pub const unsafe fn dummy() -> Self {
|
2022-07-02 14:27:19 +03:00
|
|
|
Self(0)
|
2018-12-21 09:51:48 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-22 13:52:35 -07:00
|
|
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
|
|
|
pub enum DeviceId {
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2019-04-27 18:06:51 +02:00
|
|
|
X(x11::DeviceId),
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(wayland_platform)]
|
2018-06-14 19:42:18 -04:00
|
|
|
Wayland(wayland::DeviceId),
|
2017-04-22 13:52:35 -07:00
|
|
|
}
|
|
|
|
|
|
2018-12-21 09:51:48 -07:00
|
|
|
impl DeviceId {
|
2021-08-30 19:40:02 +02:00
|
|
|
pub const unsafe fn dummy() -> Self {
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(wayland_platform)]
|
2023-09-30 21:43:41 +02:00
|
|
|
return DeviceId::Wayland(unsafe { wayland::DeviceId::dummy() });
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(all(not(wayland_platform), x11_platform))]
|
2023-09-30 21:43:41 +02:00
|
|
|
return DeviceId::X(unsafe { x11::DeviceId::dummy() });
|
2018-12-21 09:51:48 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-29 21:16:14 +03:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
2019-02-05 10:30:33 -05:00
|
|
|
pub enum MonitorHandle {
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2019-04-27 18:06:51 +02:00
|
|
|
X(x11::MonitorHandle),
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(wayland_platform)]
|
2019-02-05 10:30:33 -05:00
|
|
|
Wayland(wayland::MonitorHandle),
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
|
|
|
|
|
2020-06-15 09:15:27 +02:00
|
|
|
/// `x11_or_wayland!(match expr; Enum(foo) => foo.something())`
|
|
|
|
|
/// expands to the equivalent of
|
|
|
|
|
/// ```ignore
|
|
|
|
|
/// match self {
|
|
|
|
|
/// Enum::X(foo) => foo.something(),
|
|
|
|
|
/// Enum::Wayland(foo) => foo.something(),
|
|
|
|
|
/// }
|
|
|
|
|
/// ```
|
|
|
|
|
/// The result can be converted to another enum by adding `; as AnotherEnum`
|
|
|
|
|
macro_rules! x11_or_wayland {
|
|
|
|
|
(match $what:expr; $enum:ident ( $($c1:tt)* ) => $x:expr; as $enum2:ident ) => {
|
|
|
|
|
match $what {
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2020-06-15 09:15:27 +02:00
|
|
|
$enum::X($($c1)*) => $enum2::X($x),
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(wayland_platform)]
|
2020-06-15 09:15:27 +02:00
|
|
|
$enum::Wayland($($c1)*) => $enum2::Wayland($x),
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
(match $what:expr; $enum:ident ( $($c1:tt)* ) => $x:expr) => {
|
|
|
|
|
match $what {
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2020-06-15 09:15:27 +02:00
|
|
|
$enum::X($($c1)*) => $x,
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(wayland_platform)]
|
2020-06-15 09:15:27 +02:00
|
|
|
$enum::Wayland($($c1)*) => $x,
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-05 10:30:33 -05:00
|
|
|
impl MonitorHandle {
|
2017-01-28 13:03:17 +01:00
|
|
|
#[inline]
|
2019-05-29 21:29:54 -04:00
|
|
|
pub fn name(&self) -> Option<String> {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; MonitorHandle(m) => m.name())
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2019-05-29 21:29:54 -04:00
|
|
|
pub fn native_identifier(&self) -> u32 {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; MonitorHandle(m) => m.native_identifier())
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn size(&self) -> PhysicalSize<u32> {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; MonitorHandle(m) => m.size())
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
2017-09-07 09:33:46 +01:00
|
|
|
|
|
|
|
|
#[inline]
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn position(&self) -> PhysicalPosition<i32> {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; MonitorHandle(m) => m.position())
|
2017-09-07 09:33:46 +01:00
|
|
|
}
|
2017-10-17 14:56:38 +03:00
|
|
|
|
2022-07-08 13:25:56 +03:00
|
|
|
#[inline]
|
|
|
|
|
pub fn refresh_rate_millihertz(&self) -> Option<u32> {
|
|
|
|
|
x11_or_wayland!(match self; MonitorHandle(m) => m.refresh_rate_millihertz())
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-17 14:56:38 +03:00
|
|
|
#[inline]
|
2020-01-03 14:52:27 -05:00
|
|
|
pub fn scale_factor(&self) -> f64 {
|
2022-12-22 21:35:33 +02:00
|
|
|
x11_or_wayland!(match self; MonitorHandle(m) => m.scale_factor() as _)
|
2017-10-17 14:56:38 +03:00
|
|
|
}
|
2019-06-12 21:07:25 +03:00
|
|
|
|
|
|
|
|
#[inline]
|
2023-12-26 22:12:33 +01:00
|
|
|
pub fn video_modes(&self) -> Box<dyn Iterator<Item = VideoModeHandle>> {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; MonitorHandle(m) => Box::new(m.video_modes()))
|
2019-06-12 21:07:25 +03:00
|
|
|
}
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
|
|
|
|
|
2019-07-29 21:16:14 +03:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
2023-12-26 22:12:33 +01:00
|
|
|
pub enum VideoModeHandle {
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2023-12-26 22:12:33 +01:00
|
|
|
X(x11::VideoModeHandle),
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(wayland_platform)]
|
2023-12-26 22:12:33 +01:00
|
|
|
Wayland(wayland::VideoModeHandle),
|
2019-07-29 21:16:14 +03:00
|
|
|
}
|
|
|
|
|
|
2023-12-26 22:12:33 +01:00
|
|
|
impl VideoModeHandle {
|
2019-07-29 21:16:14 +03:00
|
|
|
#[inline]
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn size(&self) -> PhysicalSize<u32> {
|
2023-12-26 22:12:33 +01:00
|
|
|
x11_or_wayland!(match self; VideoModeHandle(m) => m.size())
|
2019-07-29 21:16:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn bit_depth(&self) -> u16 {
|
2023-12-26 22:12:33 +01:00
|
|
|
x11_or_wayland!(match self; VideoModeHandle(m) => m.bit_depth())
|
2019-07-29 21:16:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2022-07-08 13:25:56 +03:00
|
|
|
pub fn refresh_rate_millihertz(&self) -> u32 {
|
2023-12-26 22:12:33 +01:00
|
|
|
x11_or_wayland!(match self; VideoModeHandle(m) => m.refresh_rate_millihertz())
|
2019-07-29 21:16:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2022-09-21 10:04:28 +02:00
|
|
|
pub fn monitor(&self) -> MonitorHandle {
|
2023-12-26 22:12:33 +01:00
|
|
|
x11_or_wayland!(match self; VideoModeHandle(m) => m.monitor(); as MonitorHandle)
|
2019-07-29 21:16:14 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-06 17:32:24 +02:00
|
|
|
impl Window {
|
2017-01-28 13:03:17 +01:00
|
|
|
#[inline]
|
2024-01-13 21:36:53 +01:00
|
|
|
pub(crate) fn new(
|
|
|
|
|
window_target: &EventLoopWindowTarget,
|
2018-05-07 17:36:21 -04:00
|
|
|
attribs: WindowAttributes,
|
2019-05-29 21:29:54 -04:00
|
|
|
) -> Result<Self, RootOsError> {
|
2019-02-21 10:51:43 +01:00
|
|
|
match *window_target {
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(wayland_platform)]
|
2019-02-21 10:51:43 +01:00
|
|
|
EventLoopWindowTarget::Wayland(ref window_target) => {
|
2024-01-17 23:37:28 +01:00
|
|
|
wayland::Window::new(window_target, attribs).map(Window::Wayland)
|
2019-06-24 12:14:55 -04:00
|
|
|
}
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2019-04-27 18:06:51 +02:00
|
|
|
EventLoopWindowTarget::X(ref window_target) => {
|
2024-01-17 23:37:28 +01:00
|
|
|
x11::Window::new(window_target, attribs).map(Window::X)
|
2019-06-24 12:14:55 -04:00
|
|
|
}
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-14 21:19:57 +02:00
|
|
|
pub(crate) fn maybe_queue_on_main(&self, f: impl FnOnce(&Self) + Send + 'static) {
|
|
|
|
|
f(self)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn maybe_wait_on_main<R: Send>(&self, f: impl FnOnce(&Self) -> R + Send) -> R {
|
|
|
|
|
f(self)
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-03 21:41:51 +01:00
|
|
|
#[inline]
|
|
|
|
|
pub fn id(&self) -> WindowId {
|
2023-09-01 23:14:16 +02:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.id())
|
2017-03-03 21:41:51 +01:00
|
|
|
}
|
|
|
|
|
|
2017-01-28 13:03:17 +01:00
|
|
|
#[inline]
|
|
|
|
|
pub fn set_title(&self, title: &str) {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_title(title));
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
|
|
|
|
|
2023-01-15 23:39:36 +03:00
|
|
|
#[inline]
|
|
|
|
|
pub fn set_transparent(&self, transparent: bool) {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_transparent(transparent));
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-08 22:53:15 +03:00
|
|
|
#[inline]
|
|
|
|
|
pub fn set_blur(&self, blur: bool) {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_blur(blur));
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-28 13:03:17 +01:00
|
|
|
#[inline]
|
2019-05-29 21:29:54 -04:00
|
|
|
pub fn set_visible(&self, visible: bool) {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_visible(visible))
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-17 20:44:14 +02:00
|
|
|
#[inline]
|
|
|
|
|
pub fn is_visible(&self) -> Option<bool> {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.is_visible())
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-28 13:03:17 +01:00
|
|
|
#[inline]
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn outer_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.outer_position())
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn inner_position(&self) -> Result<PhysicalPosition<i32>, NotSupportedError> {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.inner_position())
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-16 21:40:30 -04:00
|
|
|
#[inline]
|
2020-01-04 01:31:23 -05:00
|
|
|
pub fn set_outer_position(&self, position: Position) {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_outer_position(position))
|
2018-04-16 21:40:30 -04:00
|
|
|
}
|
|
|
|
|
|
2017-01-28 13:03:17 +01:00
|
|
|
#[inline]
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn inner_size(&self) -> PhysicalSize<u32> {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.inner_size())
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2020-01-04 01:33:07 -05:00
|
|
|
pub fn outer_size(&self) -> PhysicalSize<u32> {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.outer_size())
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2023-07-10 04:02:26 +00:00
|
|
|
pub fn request_inner_size(&self, size: Size) -> Option<PhysicalSize<u32>> {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.request_inner_size(size))
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
|
|
|
|
|
2023-07-20 13:16:51 +00:00
|
|
|
#[inline]
|
|
|
|
|
pub(crate) fn request_activation_token(&self) -> Result<AsyncRequestSerial, NotSupportedError> {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.request_activation_token())
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-23 05:35:35 -04:00
|
|
|
#[inline]
|
2020-01-04 01:31:23 -05:00
|
|
|
pub fn set_min_inner_size(&self, dimensions: Option<Size>) {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_min_inner_size(dimensions))
|
2018-03-23 05:35:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2020-01-04 01:31:23 -05:00
|
|
|
pub fn set_max_inner_size(&self, dimensions: Option<Size>) {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_max_inner_size(dimensions))
|
2018-03-23 05:35:35 -04:00
|
|
|
}
|
2018-06-14 19:42:18 -04:00
|
|
|
|
2022-09-03 21:50:22 +03:00
|
|
|
#[inline]
|
|
|
|
|
pub fn resize_increments(&self) -> Option<PhysicalSize<u32>> {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.resize_increments())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_resize_increments(&self, increments: Option<Size>) {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_resize_increments(increments))
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-11 16:47:50 -06:00
|
|
|
#[inline]
|
|
|
|
|
pub fn set_resizable(&self, resizable: bool) {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_resizable(resizable))
|
2018-06-11 16:47:50 -06:00
|
|
|
}
|
2018-03-23 05:35:35 -04:00
|
|
|
|
2022-02-17 17:03:17 +02:00
|
|
|
#[inline]
|
|
|
|
|
pub fn is_resizable(&self) -> bool {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.is_resizable())
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-29 12:03:51 +02:00
|
|
|
#[inline]
|
|
|
|
|
pub fn set_enabled_buttons(&self, buttons: WindowButtons) {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_enabled_buttons(buttons))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn enabled_buttons(&self) -> WindowButtons {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.enabled_buttons())
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-28 13:03:17 +01:00
|
|
|
#[inline]
|
2023-12-25 07:20:52 +01:00
|
|
|
pub fn set_cursor(&self, cursor: Cursor) {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_cursor(cursor))
|
2023-12-16 22:02:17 +02:00
|
|
|
}
|
|
|
|
|
|
2017-01-28 13:03:17 +01:00
|
|
|
#[inline]
|
2022-06-13 09:43:14 +03:00
|
|
|
pub fn set_cursor_grab(&self, mode: CursorGrabMode) -> Result<(), ExternalError> {
|
|
|
|
|
x11_or_wayland!(match self; Window(window) => window.set_cursor_grab(mode))
|
2018-06-18 12:32:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2019-05-29 21:29:54 -04:00
|
|
|
pub fn set_cursor_visible(&self, visible: bool) {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; Window(window) => window.set_cursor_visible(visible))
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
|
|
|
|
|
2021-03-07 10:43:23 +01:00
|
|
|
#[inline]
|
|
|
|
|
pub fn drag_window(&self) -> Result<(), ExternalError> {
|
|
|
|
|
x11_or_wayland!(match self; Window(window) => window.drag_window())
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-11 18:07:09 +01:00
|
|
|
#[inline]
|
|
|
|
|
pub fn drag_resize_window(&self, direction: ResizeDirection) -> Result<(), ExternalError> {
|
|
|
|
|
x11_or_wayland!(match self; Window(window) => window.drag_resize_window(direction))
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-11 01:16:16 +03:30
|
|
|
#[inline]
|
2023-10-15 06:49:57 +04:00
|
|
|
pub fn show_window_menu(&self, position: Position) {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.show_window_menu(position))
|
|
|
|
|
}
|
2023-10-11 01:16:16 +03:30
|
|
|
|
2022-04-12 19:10:46 +02:00
|
|
|
#[inline]
|
|
|
|
|
pub fn set_cursor_hittest(&self, hittest: bool) -> Result<(), ExternalError> {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_cursor_hittest(hittest))
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-28 13:03:17 +01:00
|
|
|
#[inline]
|
2020-01-03 14:52:27 -05:00
|
|
|
pub fn scale_factor(&self) -> f64 {
|
2023-01-20 00:02:16 +03:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.scale_factor())
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2020-01-04 01:31:23 -05:00
|
|
|
pub fn set_cursor_position(&self, position: Position) -> Result<(), ExternalError> {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_cursor_position(position))
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
2017-08-28 00:19:26 +01:00
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_maximized(&self, maximized: bool) {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_maximized(maximized))
|
2017-08-28 00:19:26 +01:00
|
|
|
}
|
2017-08-28 00:22:26 +01:00
|
|
|
|
2021-01-27 20:01:17 +02:00
|
|
|
#[inline]
|
|
|
|
|
pub fn is_maximized(&self) -> bool {
|
2021-06-10 16:43:27 +09:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.is_maximized())
|
2021-01-27 20:01:17 +02:00
|
|
|
}
|
|
|
|
|
|
2019-12-22 01:04:11 -05:00
|
|
|
#[inline]
|
|
|
|
|
pub fn set_minimized(&self, minimized: bool) {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_minimized(minimized))
|
2019-12-22 01:04:11 -05:00
|
|
|
}
|
|
|
|
|
|
2023-01-19 23:39:04 +02:00
|
|
|
#[inline]
|
|
|
|
|
pub fn is_minimized(&self) -> Option<bool> {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.is_minimized())
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-26 03:09:32 +10:00
|
|
|
#[inline]
|
2022-09-21 10:04:28 +02:00
|
|
|
pub(crate) fn fullscreen(&self) -> Option<Fullscreen> {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.fullscreen())
|
2019-04-26 03:09:32 +10:00
|
|
|
}
|
|
|
|
|
|
2017-08-28 00:22:26 +01:00
|
|
|
#[inline]
|
2022-09-21 10:04:28 +02:00
|
|
|
pub(crate) fn set_fullscreen(&self, monitor: Option<Fullscreen>) {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_fullscreen(monitor))
|
2017-12-22 07:50:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn set_decorations(&self, decorations: bool) {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_decorations(decorations))
|
2017-08-28 00:22:26 +01:00
|
|
|
}
|
2017-09-07 09:33:46 +01:00
|
|
|
|
2022-02-17 15:31:13 +02:00
|
|
|
#[inline]
|
|
|
|
|
pub fn is_decorated(&self) -> bool {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.is_decorated())
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-20 10:24:05 -04:00
|
|
|
#[inline]
|
2023-09-01 23:14:16 +02:00
|
|
|
pub fn set_window_level(&self, level: WindowLevel) {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_window_level(level))
|
2018-05-20 10:24:05 -04:00
|
|
|
}
|
|
|
|
|
|
2018-05-07 17:36:21 -04:00
|
|
|
#[inline]
|
2023-09-01 23:14:16 +02:00
|
|
|
pub fn set_window_icon(&self, window_icon: Option<Icon>) {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_window_icon(window_icon.map(|icon| icon.inner)))
|
2018-05-07 17:36:21 -04:00
|
|
|
}
|
|
|
|
|
|
2018-05-17 21:28:30 -04:00
|
|
|
#[inline]
|
2023-06-22 19:12:14 +00:00
|
|
|
pub fn set_ime_cursor_area(&self, position: Position, size: Size) {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_ime_cursor_area(position, size))
|
2018-05-17 21:28:30 -04:00
|
|
|
}
|
|
|
|
|
|
2023-05-28 20:02:59 +02:00
|
|
|
#[inline]
|
|
|
|
|
pub fn reset_dead_keys(&self) {
|
|
|
|
|
common::xkb_state::reset_dead_keys()
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-07 05:29:25 +03:00
|
|
|
#[inline]
|
|
|
|
|
pub fn set_ime_allowed(&self, allowed: bool) {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_ime_allowed(allowed))
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-29 16:46:46 +01:00
|
|
|
#[inline]
|
|
|
|
|
pub fn set_ime_purpose(&self, purpose: ImePurpose) {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.set_ime_purpose(purpose))
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-27 03:03:08 +01:00
|
|
|
#[inline]
|
2021-05-19 18:39:53 +02:00
|
|
|
pub fn focus_window(&self) {
|
2023-09-01 23:14:16 +02:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.focus_window())
|
2021-05-19 18:39:53 +02:00
|
|
|
}
|
2021-08-17 07:59:57 +03:00
|
|
|
pub fn request_user_attention(&self, request_type: Option<UserAttentionType>) {
|
2023-06-22 08:08:53 +04:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.request_user_attention(request_type))
|
2020-11-27 03:03:08 +01:00
|
|
|
}
|
|
|
|
|
|
2019-02-21 10:51:43 +01:00
|
|
|
#[inline]
|
|
|
|
|
pub fn request_redraw(&self) {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; Window(w) => w.request_redraw())
|
2019-02-21 10:51:43 +01:00
|
|
|
}
|
|
|
|
|
|
2023-06-22 08:08:53 +04:00
|
|
|
#[inline]
|
|
|
|
|
pub fn pre_present_notify(&self) {
|
|
|
|
|
x11_or_wayland!(match self; Window(w) => w.pre_present_notify())
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-07 09:33:46 +01:00
|
|
|
#[inline]
|
2022-09-21 10:04:28 +02:00
|
|
|
pub fn current_monitor(&self) -> Option<MonitorHandle> {
|
2023-09-01 23:14:16 +02:00
|
|
|
Some(x11_or_wayland!(match self; Window(w) => w.current_monitor()?; as MonitorHandle))
|
2018-06-16 10:14:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2019-05-29 21:29:54 -04:00
|
|
|
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
2018-06-16 10:14:12 -04:00
|
|
|
match self {
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2021-08-15 22:31:59 +03:00
|
|
|
Window::X(ref window) => window
|
2019-06-24 12:14:55 -04:00
|
|
|
.available_monitors()
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(MonitorHandle::X)
|
|
|
|
|
.collect(),
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(wayland_platform)]
|
2021-08-15 22:31:59 +03:00
|
|
|
Window::Wayland(ref window) => window
|
2019-06-24 12:14:55 -04:00
|
|
|
.available_monitors()
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(MonitorHandle::Wayland)
|
|
|
|
|
.collect(),
|
2018-06-16 10:14:12 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2022-09-21 10:04:28 +02:00
|
|
|
pub fn primary_monitor(&self) -> Option<MonitorHandle> {
|
2023-09-01 23:14:16 +02:00
|
|
|
Some(x11_or_wayland!(match self; Window(w) => w.primary_monitor()?; as MonitorHandle))
|
2017-09-07 09:33:46 +01:00
|
|
|
}
|
2019-08-14 07:57:16 -04:00
|
|
|
|
2023-10-14 19:07:39 -07:00
|
|
|
#[cfg(feature = "rwh_04")]
|
2022-07-21 22:22:36 +03:00
|
|
|
#[inline]
|
2023-10-14 19:07:39 -07:00
|
|
|
pub fn raw_window_handle_rwh_04(&self) -> rwh_04::RawWindowHandle {
|
|
|
|
|
x11_or_wayland!(match self; Window(window) => window.raw_window_handle_rwh_04())
|
2022-07-21 22:22:36 +03:00
|
|
|
}
|
|
|
|
|
|
2023-10-14 19:07:39 -07:00
|
|
|
#[cfg(feature = "rwh_05")]
|
2022-07-21 22:22:36 +03:00
|
|
|
#[inline]
|
2023-10-14 19:07:39 -07:00
|
|
|
pub fn raw_window_handle_rwh_05(&self) -> rwh_05::RawWindowHandle {
|
|
|
|
|
x11_or_wayland!(match self; Window(window) => window.raw_window_handle_rwh_05())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "rwh_05")]
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle {
|
|
|
|
|
x11_or_wayland!(match self; Window(window) => window.raw_display_handle_rwh_05())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "rwh_06")]
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn raw_window_handle_rwh_06(&self) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {
|
|
|
|
|
x11_or_wayland!(match self; Window(window) => window.raw_window_handle_rwh_06())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "rwh_06")]
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn raw_display_handle_rwh_06(
|
|
|
|
|
&self,
|
|
|
|
|
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
|
|
|
|
|
x11_or_wayland!(match self; Window(window) => window.raw_display_handle_rwh_06())
|
2019-08-14 07:57:16 -04:00
|
|
|
}
|
2022-10-19 03:34:36 +09:00
|
|
|
|
2022-11-29 11:05:51 +02:00
|
|
|
#[inline]
|
|
|
|
|
pub fn set_theme(&self, theme: Option<Theme>) {
|
|
|
|
|
x11_or_wayland!(match self; Window(window) => window.set_theme(theme))
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-19 03:34:36 +09:00
|
|
|
#[inline]
|
|
|
|
|
pub fn theme(&self) -> Option<Theme> {
|
|
|
|
|
x11_or_wayland!(match self; Window(window) => window.theme())
|
|
|
|
|
}
|
2022-11-03 10:11:37 -07:00
|
|
|
|
2023-09-01 23:14:16 +02:00
|
|
|
pub fn set_content_protected(&self, protected: bool) {
|
|
|
|
|
x11_or_wayland!(match self; Window(window) => window.set_content_protected(protected))
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-03 10:11:37 -07:00
|
|
|
#[inline]
|
2023-01-17 03:30:14 +02:00
|
|
|
pub fn has_focus(&self) -> bool {
|
|
|
|
|
x11_or_wayland!(match self; Window(window) => window.has_focus())
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-03 10:11:37 -07:00
|
|
|
pub fn title(&self) -> String {
|
|
|
|
|
x11_or_wayland!(match self; Window(window) => window.title())
|
|
|
|
|
}
|
2017-01-28 13:03:17 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-28 20:02:59 +02:00
|
|
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
|
|
|
|
pub struct KeyEventExtra {
|
|
|
|
|
pub text_with_all_modifiers: Option<SmolStr>,
|
2024-01-04 12:54:35 +01:00
|
|
|
pub key_without_modifiers: Key,
|
2023-05-28 20:02:59 +02:00
|
|
|
}
|
|
|
|
|
|
2024-01-17 18:17:49 +01:00
|
|
|
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
|
|
|
|
pub(crate) enum PlatformCustomCursor {
|
|
|
|
|
#[cfg(wayland_platform)]
|
|
|
|
|
Wayland(wayland::CustomCursor),
|
|
|
|
|
#[cfg(x11_platform)]
|
|
|
|
|
X(x11::CustomCursor),
|
|
|
|
|
}
|
|
|
|
|
impl PlatformCustomCursor {
|
|
|
|
|
pub(crate) fn build(
|
|
|
|
|
builder: PlatformCustomCursorBuilder,
|
|
|
|
|
p: &EventLoopWindowTarget,
|
|
|
|
|
) -> PlatformCustomCursor {
|
|
|
|
|
match p {
|
|
|
|
|
#[cfg(wayland_platform)]
|
|
|
|
|
EventLoopWindowTarget::Wayland(_) => {
|
|
|
|
|
Self::Wayland(wayland::CustomCursor::build(builder, p))
|
|
|
|
|
}
|
|
|
|
|
#[cfg(x11_platform)]
|
|
|
|
|
EventLoopWindowTarget::X(p) => Self::X(x11::CustomCursor::build(builder, p)),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-22 20:21:28 +03:00
|
|
|
/// Hooks for X11 errors.
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2022-07-29 14:39:41 +03:00
|
|
|
pub(crate) static mut XLIB_ERROR_HOOKS: Lazy<Mutex<Vec<XlibErrorHook>>> =
|
|
|
|
|
Lazy::new(|| Mutex::new(Vec::new()));
|
2022-07-22 20:21:28 +03:00
|
|
|
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
X11: General cleanup (#491)
* X11: General cleanup
This is almost entirely internal changes, and as usual, doesn't actually
fix any problems people have complained about.
- `XSetInputFocus` can't be called before the window is visible. This
was previously handled by looping (with a sleep) and querying for the
window's state until it was visible. Now we use `XIfEvent`, which blocks
until we receive `VisibilityNotify`. Note that this can't be replaced
with an `XSync` (I tried).
- We now call `XSync` at the end of window creation and check for
errors, assuring that broken windows are never returned. When creating
invisible windows, this is the only time the output buffer is flushed
during the entire window creation process (AFAIK). For visible windows,
`XIfEvent` will generally flush, but window creation has overall been
reduced to the minimum number of flushes.
- `check_errors().expect()` has been a common pattern throughout the
backend, but it seems that people (myself included) didn't make a
distinction between using it after synchronous requests and asynchronous
requests. Now we only use it after async requests if we flush first,
though this still isn't correct (since the request likely hasn't been
processed yet). The only real solution (besides forcing a sync *every
time*) is to handle asynchronous errors *asynchronously*. For future
work, I plan on adding logging, though I don't plan on actually
*handling* those errors; that's more of something to hope for in the
hypothetical async/await XCB paradise.
- We now flush whenever it makes sense to. `util::Flusher` was added to
force contributors to be aware of the output buffer.
- `Window::get_position`, `Window::get_inner_position`,
`Window::get_inner_size`, and `Window::get_outer_size` previously all
required *several* round-trips. On my machine, it took an average of
around 80µs. They've now been reduced to one round-trip each, which
reduces my measurement to 16µs. This was accomplished simply by caching
the frame extents, which are expensive to calculate (due to various
queries and heuristics), but change infrequently and predictably. I
still recommend that application developers use these methods sparingly
and generally prefer storing the values from `Resized`/`Moved`, as
that's zero overhead.
- The above change enabled me to change the `Moved` event to supply
window positions, rather than client area positions. Additionally, we no
longer generate `Moved` for real (as in, not synthetic)
`ConfigureNotify` events. Real `ConfigureNotify` events contain
positions relative to the parent window, which are typically constant
and useless. Since that position would be completely different from the
root-relative positions supplied by synthetic `ConfigureNotify` events
(which are the vast majority of them), that meant real `ConfigureNotify`
events would *always* be detected as the position having changed, so the
resultant `Moved` was multiple levels of misleading. In practice, this
meant a garbage `Moved` would be sent every time the window was resized;
now a resize has to actually change the window's position to be
accompanied by `Moved`.
- Every time we processed an `XI_Enter` event, we would leak 4 bytes via
`util::query_pointer` (`XIQueryPointer`). `XIButtonState` contains a
dynamically-allocated mask field which we weren't freeing. As this event
occurs with fairly high frequency, long-running applications could
easily accumulate substantial leaks. `util::PointerState::drop` now
takes care of this.
- The `util` module has been split up into several sub-modules, as it
was getting rather lengthy. This accounts for a significant part of this
diff, unfortunately.
- Atoms are now cached. Xlib caches them too, so `XInternAtom` wouldn't
typically be a round-trip anyway, but the added complexity is
negligible.
- Switched from `std::sync::Mutex` to `parking_lot::Mutex` (within this
backend). There appears to be no downside to this, but if anyone finds
one, this would be easy to revert.
- The WM name and supported hints are now global to the application, and
are updated upon `ReparentNotify`, which should detect when the WM was
replaced (assuming a reparenting WM was involved, that is). Previously,
these values were per-window and would never update, meaning replacing
the WM could potentially lead to (admittedly very minor) problems.
- The result of `Window2::create_empty_cursor` will now only be used if
it actually succeeds.
- `Window2::load_cursor` no longer re-allocates the cursor name.
- `util::lookup_utf8` previously allocated a 16-byte buffer on the heap.
Now it allocates a 1024-byte buffer on the stack, and falls back to
dynamic allocation if the buffer is too small. This base buffer size is
admittedly gratuitous, but less so if you're using IME.
- `with_c_str` was finally removed.
- Added `util::Format` enum to help prevent goofs when dealing with
format arguments.
- `util::get_property`, something I added way back in my first winit PR,
only calculated offsets correctly for `util::Format::Char`. This was
concealed by the accomodating buffer size, as it would be very rare for
the offset to be needed; however, testing with a buffer size of 1,
`util::Format::Long` would read from the same offset multiple times, and
`util::Format::Short` would miss data. This function now works correctly
for all formats, relying on the simple fact that the offset increases by
the buffer size on each iteration. We also account for the extra byte
that `XGetWindowProperty` allocates at the end of the buffer, and copy
data from the buffer instead of moving it and taking ownership of the
pointer.
- Drag and drop now reliably works in release mode. This is presumably
related to the `util::get_property` changes.
- `util::change_property` now exists, which should make it easier to add
features in the future.
- The `EventsLoop` device map is no longer in a mutex.
- `XConnection` now implements `Debug`.
- Valgrind no longer complains about anything related to winit (with
either the system allocator or jemalloc, though "not having valgrind
complain about jemalloc" isn't something to strive for).
* X11: Add better diagnostics when initialization fails
* X11: Handle XIQueryDevice failure
* X11: Use correct types in error handler
2018-05-03 09:15:49 -04:00
|
|
|
unsafe extern "C" fn x_error_callback(
|
|
|
|
|
display: *mut x11::ffi::Display,
|
|
|
|
|
event: *mut x11::ffi::XErrorEvent,
|
|
|
|
|
) -> c_int {
|
2022-08-31 18:32:19 +02:00
|
|
|
let xconn_lock = X11_BACKEND.lock().unwrap();
|
2018-06-18 00:44:38 +00:00
|
|
|
if let Ok(ref xconn) = *xconn_lock {
|
2022-07-22 20:21:28 +03:00
|
|
|
// Call all the hooks.
|
|
|
|
|
let mut error_handled = false;
|
2023-09-30 21:43:41 +02:00
|
|
|
for hook in unsafe { XLIB_ERROR_HOOKS.lock() }.unwrap().iter() {
|
2022-07-22 20:21:28 +03:00
|
|
|
error_handled |= hook(display as *mut _, event as *mut _);
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-11 09:34:32 -07:00
|
|
|
// `assume_init` is safe here because the array consists of `MaybeUninit` values,
|
|
|
|
|
// which do not require initialization.
|
2023-09-30 21:43:41 +02:00
|
|
|
let mut buf: [MaybeUninit<c_char>; 1024] = unsafe { MaybeUninit::uninit().assume_init() };
|
|
|
|
|
unsafe {
|
|
|
|
|
(xconn.xlib.XGetErrorText)(
|
|
|
|
|
display,
|
|
|
|
|
(*event).error_code as c_int,
|
|
|
|
|
buf.as_mut_ptr() as *mut c_char,
|
|
|
|
|
buf.len() as c_int,
|
|
|
|
|
)
|
|
|
|
|
};
|
|
|
|
|
let description =
|
|
|
|
|
unsafe { CStr::from_ptr(buf.as_ptr() as *const c_char) }.to_string_lossy();
|
|
|
|
|
|
|
|
|
|
let error = unsafe {
|
|
|
|
|
XError {
|
|
|
|
|
description: description.into_owned(),
|
|
|
|
|
error_code: (*event).error_code,
|
|
|
|
|
request_code: (*event).request_code,
|
|
|
|
|
minor_code: (*event).minor_code,
|
|
|
|
|
}
|
2018-06-18 00:44:38 +00:00
|
|
|
};
|
|
|
|
|
|
2022-07-22 20:21:28 +03:00
|
|
|
// Don't log error.
|
|
|
|
|
if !error_handled {
|
2023-12-25 09:25:09 +01:00
|
|
|
log::error!("X11 error: {:#?}", error);
|
2023-01-18 05:58:09 +03:00
|
|
|
// XXX only update the error, if it wasn't handled by any of the hooks.
|
|
|
|
|
*xconn.latest_error.lock().unwrap() = Some(error);
|
2022-07-22 20:21:28 +03:00
|
|
|
}
|
2018-06-18 00:44:38 +00:00
|
|
|
}
|
X11: General cleanup (#491)
* X11: General cleanup
This is almost entirely internal changes, and as usual, doesn't actually
fix any problems people have complained about.
- `XSetInputFocus` can't be called before the window is visible. This
was previously handled by looping (with a sleep) and querying for the
window's state until it was visible. Now we use `XIfEvent`, which blocks
until we receive `VisibilityNotify`. Note that this can't be replaced
with an `XSync` (I tried).
- We now call `XSync` at the end of window creation and check for
errors, assuring that broken windows are never returned. When creating
invisible windows, this is the only time the output buffer is flushed
during the entire window creation process (AFAIK). For visible windows,
`XIfEvent` will generally flush, but window creation has overall been
reduced to the minimum number of flushes.
- `check_errors().expect()` has been a common pattern throughout the
backend, but it seems that people (myself included) didn't make a
distinction between using it after synchronous requests and asynchronous
requests. Now we only use it after async requests if we flush first,
though this still isn't correct (since the request likely hasn't been
processed yet). The only real solution (besides forcing a sync *every
time*) is to handle asynchronous errors *asynchronously*. For future
work, I plan on adding logging, though I don't plan on actually
*handling* those errors; that's more of something to hope for in the
hypothetical async/await XCB paradise.
- We now flush whenever it makes sense to. `util::Flusher` was added to
force contributors to be aware of the output buffer.
- `Window::get_position`, `Window::get_inner_position`,
`Window::get_inner_size`, and `Window::get_outer_size` previously all
required *several* round-trips. On my machine, it took an average of
around 80µs. They've now been reduced to one round-trip each, which
reduces my measurement to 16µs. This was accomplished simply by caching
the frame extents, which are expensive to calculate (due to various
queries and heuristics), but change infrequently and predictably. I
still recommend that application developers use these methods sparingly
and generally prefer storing the values from `Resized`/`Moved`, as
that's zero overhead.
- The above change enabled me to change the `Moved` event to supply
window positions, rather than client area positions. Additionally, we no
longer generate `Moved` for real (as in, not synthetic)
`ConfigureNotify` events. Real `ConfigureNotify` events contain
positions relative to the parent window, which are typically constant
and useless. Since that position would be completely different from the
root-relative positions supplied by synthetic `ConfigureNotify` events
(which are the vast majority of them), that meant real `ConfigureNotify`
events would *always* be detected as the position having changed, so the
resultant `Moved` was multiple levels of misleading. In practice, this
meant a garbage `Moved` would be sent every time the window was resized;
now a resize has to actually change the window's position to be
accompanied by `Moved`.
- Every time we processed an `XI_Enter` event, we would leak 4 bytes via
`util::query_pointer` (`XIQueryPointer`). `XIButtonState` contains a
dynamically-allocated mask field which we weren't freeing. As this event
occurs with fairly high frequency, long-running applications could
easily accumulate substantial leaks. `util::PointerState::drop` now
takes care of this.
- The `util` module has been split up into several sub-modules, as it
was getting rather lengthy. This accounts for a significant part of this
diff, unfortunately.
- Atoms are now cached. Xlib caches them too, so `XInternAtom` wouldn't
typically be a round-trip anyway, but the added complexity is
negligible.
- Switched from `std::sync::Mutex` to `parking_lot::Mutex` (within this
backend). There appears to be no downside to this, but if anyone finds
one, this would be easy to revert.
- The WM name and supported hints are now global to the application, and
are updated upon `ReparentNotify`, which should detect when the WM was
replaced (assuming a reparenting WM was involved, that is). Previously,
these values were per-window and would never update, meaning replacing
the WM could potentially lead to (admittedly very minor) problems.
- The result of `Window2::create_empty_cursor` will now only be used if
it actually succeeds.
- `Window2::load_cursor` no longer re-allocates the cursor name.
- `util::lookup_utf8` previously allocated a 16-byte buffer on the heap.
Now it allocates a 1024-byte buffer on the stack, and falls back to
dynamic allocation if the buffer is too small. This base buffer size is
admittedly gratuitous, but less so if you're using IME.
- `with_c_str` was finally removed.
- Added `util::Format` enum to help prevent goofs when dealing with
format arguments.
- `util::get_property`, something I added way back in my first winit PR,
only calculated offsets correctly for `util::Format::Char`. This was
concealed by the accomodating buffer size, as it would be very rare for
the offset to be needed; however, testing with a buffer size of 1,
`util::Format::Long` would read from the same offset multiple times, and
`util::Format::Short` would miss data. This function now works correctly
for all formats, relying on the simple fact that the offset increases by
the buffer size on each iteration. We also account for the extra byte
that `XGetWindowProperty` allocates at the end of the buffer, and copy
data from the buffer instead of moving it and taking ownership of the
pointer.
- Drag and drop now reliably works in release mode. This is presumably
related to the `util::get_property` changes.
- `util::change_property` now exists, which should make it easier to add
features in the future.
- The `EventsLoop` device map is no longer in a mutex.
- `XConnection` now implements `Debug`.
- Valgrind no longer complains about anything related to winit (with
either the system allocator or jemalloc, though "not having valgrind
complain about jemalloc" isn't something to strive for).
* X11: Add better diagnostics when initialization fails
* X11: Handle XIQueryDevice failure
* X11: Use correct types in error handler
2018-05-03 09:15:49 -04:00
|
|
|
// Fun fact: this return value is completely ignored.
|
2017-01-28 13:03:17 +01:00
|
|
|
0
|
|
|
|
|
}
|
2019-04-27 18:06:51 +02:00
|
|
|
|
2019-02-21 10:51:43 +01:00
|
|
|
pub enum EventLoop<T: 'static> {
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(wayland_platform)]
|
2022-07-29 14:39:41 +03:00
|
|
|
Wayland(Box<wayland::EventLoop<T>>),
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2019-06-21 11:33:15 -04:00
|
|
|
X(x11::EventLoop<T>),
|
2017-03-03 21:41:51 +01:00
|
|
|
}
|
|
|
|
|
|
2019-02-21 10:51:43 +01:00
|
|
|
pub enum EventLoopProxy<T: 'static> {
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2019-04-27 18:06:51 +02:00
|
|
|
X(x11::EventLoopProxy<T>),
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(wayland_platform)]
|
2019-02-21 10:51:43 +01:00
|
|
|
Wayland(wayland::EventLoopProxy<T>),
|
2017-05-25 23:19:13 +10:00
|
|
|
}
|
|
|
|
|
|
2019-08-06 05:51:42 +09:00
|
|
|
impl<T: 'static> Clone for EventLoopProxy<T> {
|
|
|
|
|
fn clone(&self) -> Self {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; EventLoopProxy(proxy) => proxy.clone(); as EventLoopProxy)
|
2019-08-06 05:51:42 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-21 11:33:15 -04:00
|
|
|
impl<T: 'static> EventLoop<T> {
|
2023-08-13 23:20:09 +04:00
|
|
|
pub(crate) fn new(
|
|
|
|
|
attributes: &PlatformSpecificEventLoopAttributes,
|
|
|
|
|
) -> Result<Self, EventLoopError> {
|
2022-02-16 22:09:03 +01:00
|
|
|
if !attributes.any_thread && !is_main_thread() {
|
|
|
|
|
panic!(
|
|
|
|
|
"Initializing the event loop outside of the main thread is a significant \
|
|
|
|
|
cross-platform compatibility hazard. If you absolutely need to create an \
|
|
|
|
|
EventLoop on a different thread, you can use the \
|
|
|
|
|
`EventLoopBuilderExtUnix::any_thread` function."
|
|
|
|
|
);
|
|
|
|
|
}
|
2019-10-18 11:51:06 -04:00
|
|
|
|
2023-10-19 17:03:15 +04:00
|
|
|
// NOTE: Wayland first because of X11 could be present under Wayland as well. Empty
|
|
|
|
|
// variables are also treated as not set.
|
2023-09-03 14:24:05 -07:00
|
|
|
let backend = match (
|
|
|
|
|
attributes.forced_backend,
|
2023-10-19 17:03:15 +04:00
|
|
|
env::var("WAYLAND_DISPLAY")
|
|
|
|
|
.map(|var| !var.is_empty())
|
|
|
|
|
.unwrap_or(false),
|
|
|
|
|
env::var("DISPLAY")
|
|
|
|
|
.map(|var| !var.is_empty())
|
|
|
|
|
.unwrap_or(false),
|
2023-09-03 14:24:05 -07:00
|
|
|
) {
|
|
|
|
|
// User is forcing a backend.
|
|
|
|
|
(Some(backend), _, _) => backend,
|
|
|
|
|
// Wayland is present.
|
|
|
|
|
#[cfg(wayland_platform)]
|
|
|
|
|
(None, true, _) => Backend::Wayland,
|
|
|
|
|
// X11 is present.
|
|
|
|
|
#[cfg(x11_platform)]
|
|
|
|
|
(None, _, true) => Backend::X,
|
|
|
|
|
// No backend is present.
|
|
|
|
|
_ => {
|
|
|
|
|
return Err(EventLoopError::Os(os_error!(OsError::Misc(
|
|
|
|
|
"neither WAYLAND_DISPLAY nor DISPLAY is set."
|
|
|
|
|
))));
|
|
|
|
|
}
|
|
|
|
|
};
|
2020-06-15 09:15:27 +02:00
|
|
|
|
2023-09-03 14:24:05 -07:00
|
|
|
// Create the display based on the backend.
|
|
|
|
|
match backend {
|
|
|
|
|
#[cfg(wayland_platform)]
|
|
|
|
|
Backend::Wayland => EventLoop::new_wayland_any_thread().map_err(Into::into),
|
|
|
|
|
#[cfg(x11_platform)]
|
2024-01-05 08:33:23 +04:00
|
|
|
Backend::X => EventLoop::new_x11_any_thread().map_err(Into::into),
|
2023-08-13 23:20:09 +04:00
|
|
|
}
|
2017-09-01 11:04:57 +02:00
|
|
|
}
|
|
|
|
|
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(wayland_platform)]
|
2023-08-13 23:20:09 +04:00
|
|
|
fn new_wayland_any_thread() -> Result<EventLoop<T>, EventLoopError> {
|
2022-07-29 14:39:41 +03:00
|
|
|
wayland::EventLoop::new().map(|evlp| EventLoop::Wayland(Box::new(evlp)))
|
2017-09-01 11:04:57 +02:00
|
|
|
}
|
|
|
|
|
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2024-01-05 08:33:23 +04:00
|
|
|
fn new_x11_any_thread() -> Result<EventLoop<T>, EventLoopError> {
|
2022-08-31 18:32:19 +02:00
|
|
|
let xconn = match X11_BACKEND.lock().unwrap().as_ref() {
|
2020-02-19 10:39:00 -07:00
|
|
|
Ok(xconn) => xconn.clone(),
|
2024-01-05 08:33:23 +04:00
|
|
|
Err(_) => return Err(EventLoopError::NotSupported(NotSupportedError::new())),
|
2020-02-19 10:39:00 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ok(EventLoop::X(x11::EventLoop::new(xconn)))
|
2017-09-01 11:04:57 +02:00
|
|
|
}
|
|
|
|
|
|
2019-02-21 10:51:43 +01:00
|
|
|
pub fn create_proxy(&self) -> EventLoopProxy<T> {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; EventLoop(evlp) => evlp.create_proxy(); as EventLoopProxy)
|
2017-05-25 23:19:13 +10:00
|
|
|
}
|
|
|
|
|
|
2023-08-13 23:20:09 +04:00
|
|
|
pub fn run<F>(mut self, callback: F) -> Result<(), EventLoopError>
|
2019-06-21 11:33:15 -04:00
|
|
|
where
|
2024-01-13 21:36:53 +01:00
|
|
|
F: FnMut(crate::event::Event<T>, &RootELW),
|
2017-03-03 21:41:51 +01:00
|
|
|
{
|
2023-10-03 23:24:42 +02:00
|
|
|
self.run_on_demand(callback)
|
2017-03-03 21:41:51 +01:00
|
|
|
}
|
2017-09-23 09:36:30 +02:00
|
|
|
|
2023-10-03 23:24:42 +02:00
|
|
|
pub fn run_on_demand<F>(&mut self, callback: F) -> Result<(), EventLoopError>
|
2023-06-18 12:40:03 +01:00
|
|
|
where
|
2024-01-13 21:36:53 +01:00
|
|
|
F: FnMut(crate::event::Event<T>, &RootELW),
|
2023-06-18 12:40:03 +01:00
|
|
|
{
|
2023-10-03 23:24:42 +02:00
|
|
|
x11_or_wayland!(match self; EventLoop(evlp) => evlp.run_on_demand(callback))
|
2023-06-18 12:40:03 +01:00
|
|
|
}
|
|
|
|
|
|
2023-07-24 00:37:51 +01:00
|
|
|
pub fn pump_events<F>(&mut self, timeout: Option<Duration>, callback: F) -> PumpStatus
|
2023-06-18 12:40:03 +01:00
|
|
|
where
|
2024-01-13 21:36:53 +01:00
|
|
|
F: FnMut(crate::event::Event<T>, &RootELW),
|
2023-06-18 12:40:03 +01:00
|
|
|
{
|
2023-07-24 00:37:51 +01:00
|
|
|
x11_or_wayland!(match self; EventLoop(evlp) => evlp.pump_events(timeout, callback))
|
2023-06-18 12:40:03 +01:00
|
|
|
}
|
|
|
|
|
|
2024-01-13 21:36:53 +01:00
|
|
|
pub fn window_target(&self) -> &crate::event_loop::EventLoopWindowTarget {
|
2022-06-07 23:17:45 +02:00
|
|
|
x11_or_wayland!(match self; EventLoop(evlp) => evlp.window_target())
|
2017-09-23 09:36:30 +02:00
|
|
|
}
|
2017-03-03 21:41:51 +01:00
|
|
|
}
|
2017-05-25 23:19:13 +10:00
|
|
|
|
2023-10-15 20:31:29 +04:00
|
|
|
impl<T> AsFd for EventLoop<T> {
|
|
|
|
|
fn as_fd(&self) -> BorrowedFd<'_> {
|
|
|
|
|
x11_or_wayland!(match self; EventLoop(evlp) => evlp.as_fd())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<T> AsRawFd for EventLoop<T> {
|
|
|
|
|
fn as_raw_fd(&self) -> RawFd {
|
|
|
|
|
x11_or_wayland!(match self; EventLoop(evlp) => evlp.as_raw_fd())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-21 10:51:43 +01:00
|
|
|
impl<T: 'static> EventLoopProxy<T> {
|
2019-12-07 18:22:03 +01:00
|
|
|
pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
|
2020-06-15 09:15:27 +02:00
|
|
|
x11_or_wayland!(match self; EventLoopProxy(proxy) => proxy.send_event(event))
|
2017-05-25 23:19:13 +10:00
|
|
|
}
|
|
|
|
|
}
|
2019-02-21 10:51:43 +01:00
|
|
|
|
2024-01-13 21:36:53 +01:00
|
|
|
pub enum EventLoopWindowTarget {
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(wayland_platform)]
|
2024-01-13 21:36:53 +01:00
|
|
|
Wayland(wayland::EventLoopWindowTarget),
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2024-01-13 21:36:53 +01:00
|
|
|
X(x11::EventLoopWindowTarget),
|
2019-02-21 10:51:43 +01:00
|
|
|
}
|
2019-04-27 18:06:51 +02:00
|
|
|
|
2024-01-13 21:36:53 +01:00
|
|
|
impl EventLoopWindowTarget {
|
2019-08-08 14:50:22 -07:00
|
|
|
#[inline]
|
|
|
|
|
pub fn is_wayland(&self) -> bool {
|
|
|
|
|
match *self {
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(wayland_platform)]
|
2019-08-08 14:50:22 -07:00
|
|
|
EventLoopWindowTarget::Wayland(_) => true,
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2020-06-15 09:15:27 +02:00
|
|
|
_ => false,
|
2019-08-08 14:50:22 -07:00
|
|
|
}
|
|
|
|
|
}
|
2020-07-04 15:46:41 -04:00
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn available_monitors(&self) -> VecDeque<MonitorHandle> {
|
|
|
|
|
match *self {
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(wayland_platform)]
|
2020-07-04 15:46:41 -04:00
|
|
|
EventLoopWindowTarget::Wayland(ref evlp) => evlp
|
|
|
|
|
.available_monitors()
|
|
|
|
|
.map(MonitorHandle::Wayland)
|
|
|
|
|
.collect(),
|
2022-12-25 09:57:27 +02:00
|
|
|
#[cfg(x11_platform)]
|
2023-09-01 23:14:16 +02:00
|
|
|
EventLoopWindowTarget::X(ref evlp) => {
|
|
|
|
|
evlp.available_monitors().map(MonitorHandle::X).collect()
|
|
|
|
|
}
|
2020-07-04 15:46:41 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2022-09-21 10:04:28 +02:00
|
|
|
pub fn primary_monitor(&self) -> Option<MonitorHandle> {
|
2023-09-01 23:14:16 +02:00
|
|
|
Some(
|
|
|
|
|
x11_or_wayland!(match self; EventLoopWindowTarget(evlp) => evlp.primary_monitor()?; as MonitorHandle),
|
|
|
|
|
)
|
2020-07-04 15:46:41 -04:00
|
|
|
}
|
2022-06-07 23:17:45 +02:00
|
|
|
|
|
|
|
|
#[inline]
|
2023-09-01 23:14:16 +02:00
|
|
|
pub fn listen_device_events(&self, allowed: DeviceEvents) {
|
|
|
|
|
x11_or_wayland!(match self; Self(evlp) => evlp.listen_device_events(allowed))
|
2022-06-07 23:17:45 +02:00
|
|
|
}
|
2022-07-21 22:22:36 +03:00
|
|
|
|
2023-10-14 19:07:39 -07:00
|
|
|
#[cfg(feature = "rwh_05")]
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle {
|
|
|
|
|
x11_or_wayland!(match self; Self(evlp) => evlp.raw_display_handle_rwh_05())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "rwh_06")]
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn raw_display_handle_rwh_06(
|
|
|
|
|
&self,
|
|
|
|
|
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
|
|
|
|
|
x11_or_wayland!(match self; Self(evlp) => evlp.raw_display_handle_rwh_06())
|
2022-07-21 22:22:36 +03:00
|
|
|
}
|
2019-08-08 14:50:22 -07:00
|
|
|
|
2023-09-07 08:25:04 +02:00
|
|
|
pub(crate) fn set_control_flow(&self, control_flow: ControlFlow) {
|
|
|
|
|
x11_or_wayland!(match self; Self(evlp) => evlp.set_control_flow(control_flow))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn control_flow(&self) -> ControlFlow {
|
|
|
|
|
x11_or_wayland!(match self; Self(evlp) => evlp.control_flow())
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-22 20:00:20 +04:00
|
|
|
pub(crate) fn clear_exit(&self) {
|
|
|
|
|
x11_or_wayland!(match self; Self(evlp) => evlp.clear_exit())
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-07 08:25:04 +02:00
|
|
|
pub(crate) fn exit(&self) {
|
|
|
|
|
x11_or_wayland!(match self; Self(evlp) => evlp.exit())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub(crate) fn exiting(&self) -> bool {
|
|
|
|
|
x11_or_wayland!(match self; Self(evlp) => evlp.exiting())
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-15 11:58:11 -08:00
|
|
|
pub(crate) fn owned_display_handle(&self) -> OwnedDisplayHandle {
|
|
|
|
|
match self {
|
|
|
|
|
#[cfg(x11_platform)]
|
|
|
|
|
Self::X(conn) => OwnedDisplayHandle::X(conn.x_connection().clone()),
|
|
|
|
|
#[cfg(wayland_platform)]
|
|
|
|
|
Self::Wayland(conn) => OwnedDisplayHandle::Wayland(conn.connection.clone()),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-07 08:25:04 +02:00
|
|
|
fn set_exit_code(&self, code: i32) {
|
|
|
|
|
x11_or_wayland!(match self; Self(evlp) => evlp.set_exit_code(code))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn exit_code(&self) -> Option<i32> {
|
|
|
|
|
x11_or_wayland!(match self; Self(evlp) => evlp.exit_code())
|
2022-01-11 01:23:20 +01:00
|
|
|
}
|
2019-05-29 21:29:54 -04:00
|
|
|
}
|
2019-10-18 11:51:06 -04:00
|
|
|
|
2024-01-15 11:58:11 -08:00
|
|
|
#[derive(Clone)]
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
pub(crate) enum OwnedDisplayHandle {
|
|
|
|
|
#[cfg(x11_platform)]
|
|
|
|
|
X(Arc<XConnection>),
|
|
|
|
|
#[cfg(wayland_platform)]
|
|
|
|
|
Wayland(wayland_client::Connection),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl OwnedDisplayHandle {
|
|
|
|
|
#[cfg(feature = "rwh_05")]
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn raw_display_handle_rwh_05(&self) -> rwh_05::RawDisplayHandle {
|
|
|
|
|
match self {
|
|
|
|
|
#[cfg(x11_platform)]
|
|
|
|
|
Self::X(xconn) => {
|
|
|
|
|
let mut xlib_handle = rwh_05::XlibDisplayHandle::empty();
|
|
|
|
|
xlib_handle.display = xconn.display.cast();
|
|
|
|
|
xlib_handle.screen = xconn.default_screen_index() as _;
|
|
|
|
|
xlib_handle.into()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(wayland_platform)]
|
|
|
|
|
Self::Wayland(conn) => {
|
|
|
|
|
use sctk::reexports::client::Proxy;
|
|
|
|
|
|
|
|
|
|
let mut wayland_handle = rwh_05::WaylandDisplayHandle::empty();
|
|
|
|
|
wayland_handle.display = conn.display().id().as_ptr() as *mut _;
|
|
|
|
|
wayland_handle.into()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(feature = "rwh_06")]
|
|
|
|
|
#[inline]
|
|
|
|
|
pub fn raw_display_handle_rwh_06(
|
|
|
|
|
&self,
|
|
|
|
|
) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
|
|
|
|
|
use std::ptr::NonNull;
|
|
|
|
|
|
|
|
|
|
match self {
|
|
|
|
|
#[cfg(x11_platform)]
|
|
|
|
|
Self::X(xconn) => Ok(rwh_06::XlibDisplayHandle::new(
|
|
|
|
|
NonNull::new(xconn.display.cast()),
|
|
|
|
|
xconn.default_screen_index() as _,
|
|
|
|
|
)
|
|
|
|
|
.into()),
|
|
|
|
|
|
|
|
|
|
#[cfg(wayland_platform)]
|
|
|
|
|
Self::Wayland(conn) => {
|
|
|
|
|
use sctk::reexports::client::Proxy;
|
|
|
|
|
|
|
|
|
|
Ok(rwh_06::WaylandDisplayHandle::new(
|
|
|
|
|
NonNull::new(conn.display().id().as_ptr().cast()).unwrap(),
|
|
|
|
|
)
|
|
|
|
|
.into())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-18 12:40:03 +01:00
|
|
|
/// Returns the minimum `Option<Duration>`, taking into account that `None`
|
|
|
|
|
/// equates to an infinite timeout, not a zero timeout (so can't just use
|
|
|
|
|
/// `Option::min`)
|
|
|
|
|
fn min_timeout(a: Option<Duration>, b: Option<Duration>) -> Option<Duration> {
|
|
|
|
|
a.map_or(b, |a_timeout| {
|
|
|
|
|
b.map_or(Some(a_timeout), |b_timeout| Some(a_timeout.min(b_timeout)))
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-18 11:51:06 -04:00
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
fn is_main_thread() -> bool {
|
2023-07-22 02:32:27 -07:00
|
|
|
rustix::thread::gettid() == rustix::process::getpid()
|
2019-10-18 11:51:06 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd"))]
|
|
|
|
|
fn is_main_thread() -> bool {
|
|
|
|
|
use libc::pthread_main_np;
|
|
|
|
|
|
|
|
|
|
unsafe { pthread_main_np() == 1 }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(target_os = "netbsd")]
|
|
|
|
|
fn is_main_thread() -> bool {
|
2020-08-20 18:12:01 +00:00
|
|
|
std::thread::current().name() == Some("main")
|
2019-10-18 11:51:06 -04:00
|
|
|
}
|