Move X11 backend to winit-x11 (#4253)
This commit is contained in:
parent
1126e9ea2f
commit
256bbe949e
42 changed files with 232 additions and 227 deletions
3
.github/CODEOWNERS
vendored
3
.github/CODEOWNERS
vendored
|
|
@ -15,8 +15,7 @@
|
|||
/winit-wayland @kchibisov
|
||||
|
||||
# X11
|
||||
/src/platform/x11.rs @kchibisov @notgull
|
||||
/src/platform_impl/linux/x11 @kchibisov @notgull
|
||||
/winit-x11 @kchibisov @notgull
|
||||
|
||||
# Web
|
||||
/src/platform/web.rs @daxpedda
|
||||
|
|
|
|||
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
|
@ -210,6 +210,10 @@ jobs:
|
|||
if: contains(matrix.platform.target, 'windows')
|
||||
run: cargo $CMD test -p winit-win32 --target=${{ matrix.platform.target }}
|
||||
|
||||
- name: Test winit X11
|
||||
if: contains(matrix.platform.target, 'linux-gnu')
|
||||
run: cargo $CMD test -p winit-x11 --target=${{ matrix.platform.target }}
|
||||
|
||||
- name: Test winit Wayland
|
||||
if: contains(matrix.platform.target, 'linux-gnu')
|
||||
run: cargo $CMD test -p winit-wayland --target=${{ matrix.platform.target }}
|
||||
|
|
|
|||
21
Cargo.toml
21
Cargo.toml
|
|
@ -19,6 +19,7 @@ winit-orbital = { version = "0.0.0", path = "winit-orbital" }
|
|||
winit-uikit = { version = "0.0.0", path = "winit-uikit" }
|
||||
winit-wayland = { version = "0.0.0", path = "winit-wayland", default-features = false }
|
||||
winit-win32 = { version = "0.0.0", path = "winit-win32" }
|
||||
winit-x11 = { version = "0.0.0", path = "winit-x11" }
|
||||
|
||||
# Core dependencies.
|
||||
bitflags = "2"
|
||||
|
|
@ -173,7 +174,7 @@ wayland-csd-adwaita = ["winit-wayland/csd-adwaita"]
|
|||
wayland-csd-adwaita-crossfont = ["winit-wayland/csd-adwaita-crossfont"]
|
||||
wayland-csd-adwaita-notitle = ["winit-wayland/csd-adwaita-notitle"]
|
||||
wayland-dlopen = ["winit-wayland/dlopen"]
|
||||
x11 = ["x11-dl", "bytemuck", "percent-encoding", "xkbcommon-dl/x11", "x11rb", "winit-common/x11"]
|
||||
x11 = ["dep:winit-x11"]
|
||||
|
||||
[build-dependencies]
|
||||
cfg_aliases.workspace = true
|
||||
|
|
@ -298,25 +299,11 @@ winit-win32.workspace = true
|
|||
|
||||
# Linux
|
||||
[target.'cfg(all(unix, not(any(target_os = "redox", target_family = "wasm", target_os = "android", target_vendor = "apple"))))'.dependencies]
|
||||
bytemuck = { workspace = true, optional = true }
|
||||
calloop.workspace = true
|
||||
libc.workspace = true
|
||||
percent-encoding = { workspace = true, optional = true }
|
||||
rustix = { workspace = true, features = ["std", "system", "thread", "process"] }
|
||||
rustix = { workspace = true, features = ["std", "thread"] }
|
||||
winit-common = { workspace = true, features = ["xkb"] }
|
||||
winit-wayland = { workspace = true, optional = true, default-features = false }
|
||||
x11-dl = { workspace = true, optional = true }
|
||||
x11rb = { workspace = true, optional = true, features = [
|
||||
"allow-unsafe-code",
|
||||
"cursor",
|
||||
"dl-libxcb",
|
||||
"randr",
|
||||
"resource_manager",
|
||||
"sync",
|
||||
"xinput",
|
||||
"xkb",
|
||||
] }
|
||||
xkbcommon-dl.workspace = true
|
||||
winit-x11 = { workspace = true, optional = true }
|
||||
|
||||
[target.'cfg(target_os = "redox")'.dependencies]
|
||||
winit-orbital.workspace = true
|
||||
|
|
|
|||
|
|
@ -395,6 +395,29 @@ impl winit_win32::EventLoopBuilderExtWindows for EventLoopBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(x11_platform)]
|
||||
impl winit_x11::EventLoopExtX11 for EventLoop {
|
||||
#[inline]
|
||||
fn is_x11(&self) -> bool {
|
||||
!self.event_loop.is_wayland()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(x11_platform)]
|
||||
impl winit_x11::EventLoopBuilderExtX11 for EventLoopBuilder {
|
||||
#[inline]
|
||||
fn with_x11(&mut self) -> &mut Self {
|
||||
self.platform_specific.forced_backend = Some(crate::platform_impl::Backend::X);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
|
||||
self.platform_specific.any_thread = any_thread;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// ```compile_error
|
||||
/// use winit::event_loop::run_on_demand::EventLoopExtRunOnDemand;
|
||||
/// use winit::event_loop::EventLoop;
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ pub mod web;
|
|||
#[cfg(windows_platform)]
|
||||
pub use winit_win32 as windows;
|
||||
#[cfg(x11_platform)]
|
||||
pub mod x11;
|
||||
pub use winit_x11 as x11;
|
||||
|
||||
#[cfg(any(windows_platform, macos_platform, x11_platform, wayland_platform, docsrs))]
|
||||
pub mod scancode;
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ impl WindowExtStartupNotify for dyn Window + '_ {
|
|||
}
|
||||
|
||||
#[cfg(x11_platform)]
|
||||
if let Some(window) = self.cast_ref::<crate::platform_impl::x11::window::Window>() {
|
||||
if let Some(window) = self.cast_ref::<crate::platform_impl::x11::Window>() {
|
||||
return window.request_activation_token();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,21 +7,15 @@ use std::env;
|
|||
use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
||||
use std::time::Duration;
|
||||
|
||||
#[cfg(x11_platform)]
|
||||
use dpi::Size;
|
||||
pub(crate) use winit_common::xkb::{physicalkey_to_scancode, scancode_to_physicalkey};
|
||||
use winit_core::application::ApplicationHandler;
|
||||
use winit_core::error::{EventLoopError, NotSupportedError};
|
||||
use winit_core::event_loop::pump_events::PumpStatus;
|
||||
use winit_core::event_loop::ActiveEventLoop;
|
||||
use winit_core::window::ActivationToken;
|
||||
#[cfg(wayland_platform)]
|
||||
pub(crate) use winit_wayland as wayland;
|
||||
|
||||
#[cfg(x11_platform)]
|
||||
use crate::platform::x11::WindowType as XWindowType;
|
||||
#[cfg(x11_platform)]
|
||||
pub(crate) mod x11;
|
||||
pub(crate) use winit_x11 as x11;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub(crate) enum Backend {
|
||||
|
|
@ -37,59 +31,6 @@ pub(crate) struct PlatformSpecificEventLoopAttributes {
|
|||
pub(crate) any_thread: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ApplicationName {
|
||||
pub general: String,
|
||||
pub instance: String,
|
||||
}
|
||||
|
||||
impl ApplicationName {
|
||||
#[allow(dead_code)]
|
||||
pub fn new(general: String, instance: String) -> Self {
|
||||
Self { general, instance }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct PlatformSpecificWindowAttributes {
|
||||
pub name: Option<ApplicationName>,
|
||||
pub activation_token: Option<ActivationToken>,
|
||||
#[cfg(x11_platform)]
|
||||
pub x11: X11WindowAttributes,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[cfg(x11_platform)]
|
||||
pub struct X11WindowAttributes {
|
||||
pub visual_id: Option<x11rb::protocol::xproto::Visualid>,
|
||||
pub screen_id: Option<i32>,
|
||||
pub base_size: Option<Size>,
|
||||
pub override_redirect: bool,
|
||||
pub x11_window_types: Vec<XWindowType>,
|
||||
|
||||
/// The parent window to embed this window into.
|
||||
pub embed_window: Option<x11rb::protocol::xproto::Window>,
|
||||
}
|
||||
|
||||
#[cfg_attr(not(x11_platform), allow(clippy::derivable_impls))]
|
||||
impl Default for PlatformSpecificWindowAttributes {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
name: None,
|
||||
activation_token: None,
|
||||
#[cfg(x11_platform)]
|
||||
x11: X11WindowAttributes {
|
||||
visual_id: None,
|
||||
screen_id: None,
|
||||
base_size: None,
|
||||
override_redirect: false,
|
||||
x11_window_types: vec![XWindowType::Normal],
|
||||
embed_window: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `x11_or_wayland!(match expr; Enum(foo) => foo.something())`
|
||||
/// expands to the equivalent of
|
||||
/// ```ignore
|
||||
|
|
@ -242,14 +183,6 @@ impl AsRawFd for EventLoop {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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`)
|
||||
#[allow(dead_code)]
|
||||
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))))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn is_main_thread() -> bool {
|
||||
rustix::thread::gettid() == rustix::process::getpid()
|
||||
|
|
|
|||
48
winit-x11/Cargo.toml
Normal file
48
winit-x11/Cargo.toml
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
[package]
|
||||
description = "Winit's X11 backend"
|
||||
documentation = "https://docs.rs/winit-x11"
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
name = "winit-x11"
|
||||
repository.workspace = true
|
||||
rust-version.workspace = true
|
||||
version = "0.0.0"
|
||||
|
||||
[features]
|
||||
serde = ["dep:serde", "bitflags/serde", "smol_str/serde", "dpi/serde"]
|
||||
|
||||
[dependencies]
|
||||
bitflags.workspace = true
|
||||
cursor-icon.workspace = true
|
||||
dpi.workspace = true
|
||||
rwh_06.workspace = true
|
||||
serde = { workspace = true, optional = true }
|
||||
smol_str.workspace = true
|
||||
tracing.workspace = true
|
||||
winit-core.workspace = true
|
||||
|
||||
# Platform-specific
|
||||
bytemuck.workspace = true
|
||||
calloop.workspace = true
|
||||
libc.workspace = true
|
||||
percent-encoding.workspace = true
|
||||
rustix = { workspace = true, features = ["std", "system", "thread", "process"] }
|
||||
winit-common = { workspace = true, features = ["xkb", "x11"] }
|
||||
x11-dl.workspace = true
|
||||
x11rb = { workspace = true, features = [
|
||||
"allow-unsafe-code",
|
||||
"cursor",
|
||||
"dl-libxcb",
|
||||
"randr",
|
||||
"resource_manager",
|
||||
"sync",
|
||||
"xinput",
|
||||
"xkb",
|
||||
] }
|
||||
xkbcommon-dl = { workspace = true, features = ["x11"] }
|
||||
|
||||
[dev-dependencies]
|
||||
winit.workspace = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
1
winit-x11/README.md
Symbolic link
1
winit-x11/README.md
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../README.md
|
||||
|
|
@ -10,8 +10,9 @@ use std::fmt::Write;
|
|||
|
||||
use x11rb::protocol::xproto::{self, ConnectionExt as _};
|
||||
|
||||
use super::atoms::*;
|
||||
use super::{VoidCookie, X11Error, XConnection};
|
||||
use crate::atoms::*;
|
||||
use crate::event_loop::{VoidCookie, X11Error};
|
||||
use crate::xdisplay::XConnection;
|
||||
|
||||
impl XConnection {
|
||||
/// "Request" a new activation token from the server.
|
||||
|
|
@ -8,9 +8,11 @@ use dpi::PhysicalPosition;
|
|||
use percent_encoding::percent_decode;
|
||||
use x11rb::protocol::xproto::{self, ConnectionExt};
|
||||
|
||||
use super::atoms::AtomName::None as DndNone;
|
||||
use super::atoms::*;
|
||||
use super::{util, CookieResultExt, X11Error, XConnection};
|
||||
use crate::atoms::AtomName::None as DndNone;
|
||||
use crate::atoms::*;
|
||||
use crate::event_loop::{CookieResultExt, X11Error};
|
||||
use crate::util;
|
||||
use crate::xdisplay::XConnection;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum DndState {
|
||||
|
|
@ -35,50 +35,31 @@ use x11rb::protocol::{xkb, xproto};
|
|||
use x11rb::x11_utils::X11Error as LogicalError;
|
||||
use x11rb::xcb_ffi::ReplyOrIdError;
|
||||
|
||||
use crate::platform::x11::XlibErrorHook;
|
||||
use crate::platform_impl::platform::min_timeout;
|
||||
use crate::platform_impl::x11::window::Window;
|
||||
|
||||
mod activation;
|
||||
mod atoms;
|
||||
mod dnd;
|
||||
mod event_processor;
|
||||
pub mod ffi;
|
||||
mod ime;
|
||||
mod monitor;
|
||||
mod util;
|
||||
pub(crate) mod window;
|
||||
mod xdisplay;
|
||||
mod xsettings;
|
||||
|
||||
use atoms::*;
|
||||
use dnd::{Dnd, DndState};
|
||||
use event_processor::{EventProcessor, MAX_MOD_REPLAY_LEN};
|
||||
use ime::{Ime, ImeCreationError, ImeReceiver, ImeRequest, ImeSender};
|
||||
pub(crate) use monitor::{MonitorHandle, VideoModeHandle};
|
||||
pub use util::CustomCursor;
|
||||
use window::UnownedWindow;
|
||||
pub(crate) use xdisplay::{XConnection, XError, XNotSupported};
|
||||
use crate::atoms::*;
|
||||
use crate::dnd::Dnd;
|
||||
use crate::event_processor::{EventProcessor, MAX_MOD_REPLAY_LEN};
|
||||
use crate::ime::{self, Ime, ImeCreationError, ImeSender};
|
||||
use crate::util::{self, CustomCursor};
|
||||
use crate::window::{UnownedWindow, Window};
|
||||
use crate::xdisplay::{XConnection, XError, XNotSupported};
|
||||
use crate::{ffi, xsettings, XlibErrorHook};
|
||||
|
||||
// Xinput constants not defined in x11rb
|
||||
const ALL_DEVICES: u16 = 0;
|
||||
const ALL_MASTER_DEVICES: u16 = 1;
|
||||
const ICONIC_STATE: u32 = 3;
|
||||
pub(crate) const ALL_DEVICES: u16 = 0;
|
||||
pub(crate) const ALL_MASTER_DEVICES: u16 = 1;
|
||||
pub(crate) const ICONIC_STATE: u32 = 3;
|
||||
|
||||
/// The underlying x11rb connection that we are using.
|
||||
type X11rbConnection = x11rb::xcb_ffi::XCBConnection;
|
||||
|
||||
type X11Source = Generic<BorrowedFd<'static>>;
|
||||
|
||||
#[cfg(x11_platform)]
|
||||
pub(crate) static X11_BACKEND: LazyLock<Mutex<Result<Arc<XConnection>, XNotSupported>>> =
|
||||
LazyLock::new(|| Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new)));
|
||||
|
||||
/// Hooks for X11 errors.
|
||||
#[cfg(x11_platform)]
|
||||
pub(crate) static XLIB_ERROR_HOOKS: Mutex<Vec<XlibErrorHook>> = Mutex::new(Vec::new());
|
||||
|
||||
#[cfg(x11_platform)]
|
||||
unsafe extern "C" fn x_error_callback(
|
||||
display: *mut ffi::Display,
|
||||
event: *mut ffi::XErrorEvent,
|
||||
|
|
@ -126,7 +107,7 @@ unsafe extern "C" fn x_error_callback(
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct WakeSender<T> {
|
||||
pub(crate) struct WakeSender<T> {
|
||||
sender: Sender<T>,
|
||||
waker: Ping,
|
||||
}
|
||||
|
|
@ -185,18 +166,18 @@ impl<T> PeekableReceiver<T> {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct ActiveEventLoop {
|
||||
xconn: Arc<XConnection>,
|
||||
wm_delete_window: xproto::Atom,
|
||||
net_wm_ping: xproto::Atom,
|
||||
net_wm_sync_request: xproto::Atom,
|
||||
ime_sender: ImeSender,
|
||||
pub(crate) xconn: Arc<XConnection>,
|
||||
pub(crate) wm_delete_window: xproto::Atom,
|
||||
pub(crate) net_wm_ping: xproto::Atom,
|
||||
pub(crate) net_wm_sync_request: xproto::Atom,
|
||||
pub(crate) ime_sender: ImeSender,
|
||||
control_flow: Cell<ControlFlow>,
|
||||
exit: Cell<Option<i32>>,
|
||||
root: xproto::Window,
|
||||
ime: Option<RefCell<Ime>>,
|
||||
windows: RefCell<HashMap<WindowId, Weak<UnownedWindow>>>,
|
||||
redraw_sender: WakeSender<WindowId>,
|
||||
activation_sender: WakeSender<ActivationToken>,
|
||||
pub(crate) root: xproto::Window,
|
||||
pub(crate) ime: Option<RefCell<Ime>>,
|
||||
pub(crate) windows: RefCell<HashMap<WindowId, Weak<UnownedWindow>>>,
|
||||
pub(crate) redraw_sender: WakeSender<WindowId>,
|
||||
pub(crate) activation_sender: WakeSender<ActivationItem>,
|
||||
event_loop_proxy: CoreEventLoopProxy,
|
||||
device_events: Cell<DeviceEvents>,
|
||||
}
|
||||
|
|
@ -207,13 +188,13 @@ pub struct EventLoop {
|
|||
event_loop: Loop<'static, EventLoopState>,
|
||||
event_processor: EventProcessor,
|
||||
redraw_receiver: PeekableReceiver<WindowId>,
|
||||
activation_receiver: PeekableReceiver<ActivationToken>,
|
||||
activation_receiver: PeekableReceiver<ActivationItem>,
|
||||
|
||||
/// The current state of the event loop.
|
||||
state: EventLoopState,
|
||||
}
|
||||
|
||||
type ActivationToken = (WindowId, winit_core::event_loop::AsyncRequestSerial);
|
||||
pub(crate) type ActivationItem = (WindowId, winit_core::event_loop::AsyncRequestSerial);
|
||||
|
||||
#[derive(Debug)]
|
||||
struct EventLoopState {
|
||||
|
|
@ -225,7 +206,7 @@ struct EventLoopState {
|
|||
}
|
||||
|
||||
impl EventLoop {
|
||||
pub(crate) fn new() -> Result<EventLoop, EventLoopError> {
|
||||
pub fn new() -> Result<EventLoop, EventLoopError> {
|
||||
let xconn = match X11_BACKEND.lock().unwrap_or_else(|e| e.into_inner()).as_ref() {
|
||||
Ok(xconn) => xconn.clone(),
|
||||
Err(err) => return Err(os_error!(err.clone()).into()),
|
||||
|
|
@ -435,7 +416,7 @@ impl EventLoop {
|
|||
Ok(event_loop)
|
||||
}
|
||||
|
||||
pub(crate) fn window_target(&self) -> &dyn RootActiveEventLoop {
|
||||
pub fn window_target(&self) -> &dyn RootActiveEventLoop {
|
||||
&self.event_processor.target
|
||||
}
|
||||
|
||||
|
|
@ -783,14 +764,14 @@ impl rwh_06::HasDisplayHandle for ActiveEventLoop {
|
|||
}
|
||||
}
|
||||
|
||||
struct DeviceInfo<'a> {
|
||||
pub(crate) struct DeviceInfo<'a> {
|
||||
xconn: &'a XConnection,
|
||||
info: *const ffi::XIDeviceInfo,
|
||||
count: usize,
|
||||
}
|
||||
|
||||
impl<'a> DeviceInfo<'a> {
|
||||
fn get(xconn: &'a XConnection, device: c_int) -> Option<Self> {
|
||||
pub(crate) fn get(xconn: &'a XConnection, device: c_int) -> Option<Self> {
|
||||
unsafe {
|
||||
let mut count = 0;
|
||||
let info = (xconn.xinput2.XIQueryDevice)(xconn.display, device, &mut count);
|
||||
|
|
@ -989,10 +970,10 @@ impl From<util::GetPropertyError> for X11Error {
|
|||
}
|
||||
|
||||
/// Type alias for a void cookie.
|
||||
type VoidCookie<'a> = x11rb::cookie::VoidCookie<'a, X11rbConnection>;
|
||||
pub(crate) type VoidCookie<'a> = x11rb::cookie::VoidCookie<'a, X11rbConnection>;
|
||||
|
||||
/// Extension trait for `Result<VoidCookie, E>`.
|
||||
trait CookieResultExt {
|
||||
pub(crate) trait CookieResultExt {
|
||||
/// Unwrap the send error and ignore the result.
|
||||
fn expect_then_ignore_error(self, msg: &str);
|
||||
}
|
||||
|
|
@ -1003,37 +984,38 @@ impl<E: fmt::Debug> CookieResultExt for Result<VoidCookie<'_>, E> {
|
|||
}
|
||||
}
|
||||
|
||||
fn mkwid(w: xproto::Window) -> winit_core::window::WindowId {
|
||||
pub(crate) fn mkwid(w: xproto::Window) -> winit_core::window::WindowId {
|
||||
winit_core::window::WindowId::from_raw(w as _)
|
||||
}
|
||||
fn mkdid(w: xinput::DeviceId) -> DeviceId {
|
||||
|
||||
pub(crate) fn mkdid(w: xinput::DeviceId) -> DeviceId {
|
||||
DeviceId::from_raw(w as i64)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Device {
|
||||
_name: String,
|
||||
scroll_axes: Vec<(i32, ScrollAxis)>,
|
||||
pub(crate) scroll_axes: Vec<(i32, ScrollAxis)>,
|
||||
// For master devices, this is the paired device (pointer <-> keyboard).
|
||||
// For slave devices, this is the master.
|
||||
attachment: c_int,
|
||||
pub(crate) attachment: c_int,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct ScrollAxis {
|
||||
increment: f64,
|
||||
orientation: ScrollOrientation,
|
||||
position: f64,
|
||||
pub(crate) struct ScrollAxis {
|
||||
pub(crate) increment: f64,
|
||||
pub(crate) orientation: ScrollOrientation,
|
||||
pub(crate) position: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
enum ScrollOrientation {
|
||||
pub(crate) enum ScrollOrientation {
|
||||
Vertical,
|
||||
Horizontal,
|
||||
}
|
||||
|
||||
impl Device {
|
||||
fn new(info: &ffi::XIDeviceInfo) -> Self {
|
||||
pub(crate) fn new(info: &ffi::XIDeviceInfo) -> Self {
|
||||
let name = unsafe { CStr::from_ptr(info.name).to_string_lossy() };
|
||||
let mut scroll_axes = Vec::new();
|
||||
|
||||
|
|
@ -1062,7 +1044,7 @@ impl Device {
|
|||
device
|
||||
}
|
||||
|
||||
fn reset_scroll_position(&mut self, info: &ffi::XIDeviceInfo) {
|
||||
pub(crate) fn reset_scroll_position(&mut self, info: &ffi::XIDeviceInfo) {
|
||||
if Device::physical_device(info) {
|
||||
for &class_ptr in Device::classes(info) {
|
||||
let ty = unsafe { (*class_ptr)._type };
|
||||
|
|
@ -1098,6 +1080,13 @@ impl Device {
|
|||
|
||||
/// Convert the raw X11 representation for a 32-bit floating point to a double.
|
||||
#[inline]
|
||||
fn xinput_fp1616_to_float(fp: xinput::Fp1616) -> f64 {
|
||||
pub(crate) fn xinput_fp1616_to_float(fp: xinput::Fp1616) -> f64 {
|
||||
(fp as f64) / ((1 << 16) as f64)
|
||||
}
|
||||
|
||||
/// 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))))
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ use winit_core::event::{
|
|||
WindowEvent,
|
||||
};
|
||||
use winit_core::keyboard::ModifiersState;
|
||||
use winit_core::window::WindowId;
|
||||
use x11_dl::xinput2::{
|
||||
self, XIDeviceEvent, XIEnterEvent, XIFocusInEvent, XIFocusOutEvent, XIHierarchyEvent,
|
||||
XILeaveEvent, XIModifierState, XIRawEvent,
|
||||
|
|
@ -29,14 +30,16 @@ use x11rb::protocol::xproto::{self, ConnectionExt as _, ModMask};
|
|||
use x11rb::x11_utils::{ExtensionInformation, Serialize};
|
||||
use xkbcommon_dl::xkb_mod_mask_t;
|
||||
|
||||
use crate::platform_impl::platform::x11::ime::{ImeEvent, ImeEventReceiver, ImeRequest};
|
||||
use crate::platform_impl::platform::x11::ActiveEventLoop;
|
||||
use crate::platform_impl::x11::atoms::*;
|
||||
use crate::platform_impl::x11::util::cookie::GenericEventCookie;
|
||||
use crate::platform_impl::x11::{
|
||||
mkdid, mkwid, util, CookieResultExt, Device, DeviceInfo, Dnd, DndState, ImeReceiver,
|
||||
ScrollOrientation, UnownedWindow, WindowId,
|
||||
use crate::atoms::*;
|
||||
use crate::dnd::{Dnd, DndState};
|
||||
use crate::event_loop::{
|
||||
mkdid, mkwid, ActiveEventLoop, CookieResultExt, Device, DeviceInfo, ScrollOrientation,
|
||||
ALL_DEVICES,
|
||||
};
|
||||
use crate::ime::{ImeEvent, ImeEventReceiver, ImeReceiver, ImeRequest};
|
||||
use crate::util;
|
||||
use crate::util::cookie::GenericEventCookie;
|
||||
use crate::window::UnownedWindow;
|
||||
|
||||
/// The maximum amount of X modifiers to replay.
|
||||
pub const MAX_MOD_REPLAY_LEN: usize = 32;
|
||||
|
|
@ -1124,7 +1127,7 @@ impl EventProcessor {
|
|||
let window_id = mkwid(window);
|
||||
let device_id = mkdid(event.deviceid as xinput::DeviceId);
|
||||
|
||||
if let Some(all_info) = DeviceInfo::get(&self.target.xconn, super::ALL_DEVICES.into()) {
|
||||
if let Some(all_info) = DeviceInfo::get(&self.target.xconn, ALL_DEVICES.into()) {
|
||||
let mut devices = self.devices.borrow_mut();
|
||||
for device_info in all_info.iter() {
|
||||
// The second expression is need for resetting to work correctly on i3, and
|
||||
|
|
@ -1465,7 +1468,7 @@ impl EventProcessor {
|
|||
self.xkb_context.set_keymap_from_x11(xcb);
|
||||
self.xmodmap.reload_from_x_connection(&self.target.xconn);
|
||||
|
||||
let window_id = match self.active_window.map(super::mkwid) {
|
||||
let window_id = match self.active_window.map(mkwid) {
|
||||
Some(window_id) => window_id,
|
||||
None => return,
|
||||
};
|
||||
|
|
@ -1480,7 +1483,7 @@ impl EventProcessor {
|
|||
let xcb = self.target.xconn.xcb_connection().get_raw_xcb_connection();
|
||||
self.xkb_context.set_keymap_from_x11(xcb);
|
||||
self.xmodmap.reload_from_x_connection(&self.target.xconn);
|
||||
let window_id = match self.active_window.map(super::mkwid) {
|
||||
let window_id = match self.active_window.map(mkwid) {
|
||||
Some(window_id) => window_id,
|
||||
None => return,
|
||||
};
|
||||
|
|
@ -1506,7 +1509,7 @@ impl EventProcessor {
|
|||
xev.locked_group as u32,
|
||||
);
|
||||
|
||||
let window_id = match self.active_window.map(super::mkwid) {
|
||||
let window_id = match self.active_window.map(mkwid) {
|
||||
Some(window_id) => window_id,
|
||||
None => return,
|
||||
};
|
||||
|
|
@ -1538,7 +1541,7 @@ impl EventProcessor {
|
|||
|
||||
// NOTE: we use active window since generally sub windows don't have keyboard input,
|
||||
// and winit assumes that unfocused window doesn't have modifiers.
|
||||
let window_id = match self.active_window.map(super::mkwid) {
|
||||
let window_id = match self.active_window.map(mkwid) {
|
||||
Some(window_id) => window_id,
|
||||
None => return,
|
||||
};
|
||||
|
|
@ -4,9 +4,10 @@ use std::ptr;
|
|||
use std::sync::Arc;
|
||||
|
||||
use super::context::{ImeContext, ImeContextCreationError};
|
||||
use super::ffi;
|
||||
use super::inner::{close_im, ImeInner};
|
||||
use super::input_method::PotentialInputMethods;
|
||||
use super::{ffi, XConnection, XError};
|
||||
use crate::xdisplay::{XConnection, XError};
|
||||
|
||||
pub(crate) unsafe fn xim_set_callback(
|
||||
xconn: &Arc<XConnection>,
|
||||
|
|
@ -5,9 +5,9 @@ use std::{fmt, mem, ptr};
|
|||
|
||||
use x11_dl::xlib::{XIMCallback, XIMPreeditCaretCallbackStruct, XIMPreeditDrawCallbackStruct};
|
||||
|
||||
use super::{ffi, util, XConnection, XError};
|
||||
use crate::platform_impl::platform::x11::ime::input_method::{InputMethod, Style, XIMStyle};
|
||||
use crate::platform_impl::platform::x11::ime::{ImeEvent, ImeEventSender};
|
||||
use super::input_method::{InputMethod, Style, XIMStyle};
|
||||
use super::{ffi, util, ImeEvent, ImeEventSender};
|
||||
use crate::xdisplay::{XConnection, XError};
|
||||
|
||||
/// IME creation error.
|
||||
#[derive(Debug)]
|
||||
|
|
@ -4,8 +4,8 @@ use std::sync::Arc;
|
|||
|
||||
use super::context::ImeContext;
|
||||
use super::input_method::{InputMethod, PotentialInputMethods};
|
||||
use super::{ffi, XConnection, XError};
|
||||
use crate::platform_impl::platform::x11::ime::ImeEventSender;
|
||||
use super::{ffi, ImeEventSender};
|
||||
use crate::xdisplay::{XConnection, XError};
|
||||
|
||||
pub(crate) unsafe fn close_im(xconn: &Arc<XConnection>, im: ffi::XIM) -> Result<(), XError> {
|
||||
unsafe { (xconn.xlib.XCloseIM)(im) };
|
||||
|
|
@ -6,7 +6,8 @@ use std::{env, fmt, ptr};
|
|||
use x11rb::protocol::xproto;
|
||||
|
||||
use super::super::atoms::*;
|
||||
use super::{ffi, util, XConnection, XError};
|
||||
use super::{ffi, util};
|
||||
use crate::xdisplay::{XConnection, XError};
|
||||
|
||||
static GLOBAL_LOCK: Mutex<()> = Mutex::new(());
|
||||
|
||||
|
|
@ -17,7 +17,8 @@ use self::context::ImeContext;
|
|||
pub use self::context::ImeContextCreationError;
|
||||
use self::inner::{close_im, ImeInner};
|
||||
use self::input_method::PotentialInputMethods;
|
||||
use super::{ffi, util, XConnection, XError};
|
||||
use crate::xdisplay::{XConnection, XError};
|
||||
use crate::{ffi, util};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
|
|
@ -1,11 +1,32 @@
|
|||
//! # X11
|
||||
|
||||
use dpi::Size;
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
use winit_core::event_loop::ActiveEventLoop as CoreActiveEventLoop;
|
||||
use winit_core::window::{ActivationToken, PlatformWindowAttributes, Window as CoreWindow};
|
||||
|
||||
use crate::dpi::Size;
|
||||
use crate::event_loop::{ActiveEventLoop, EventLoop, EventLoopBuilder};
|
||||
use crate::platform_impl::ApplicationName;
|
||||
pub use crate::event_loop::{ActiveEventLoop, EventLoop};
|
||||
pub use crate::window::Window;
|
||||
|
||||
macro_rules! os_error {
|
||||
($error:expr) => {{
|
||||
winit_core::error::OsError::new(line!(), file!(), $error)
|
||||
}};
|
||||
}
|
||||
|
||||
mod activation;
|
||||
mod atoms;
|
||||
mod dnd;
|
||||
mod event_loop;
|
||||
mod event_processor;
|
||||
pub mod ffi;
|
||||
mod ime;
|
||||
mod monitor;
|
||||
mod util;
|
||||
mod window;
|
||||
mod xdisplay;
|
||||
mod xsettings;
|
||||
|
||||
/// X window type. Maps directly to
|
||||
/// [`_NET_WM_WINDOW_TYPE`](https://specifications.freedesktop.org/wm-spec/wm-spec-1.5.html).
|
||||
|
|
@ -80,19 +101,21 @@ pub type XWindow = u32;
|
|||
#[inline]
|
||||
pub fn register_xlib_error_hook(hook: XlibErrorHook) {
|
||||
// Append new hook.
|
||||
crate::platform_impl::x11::XLIB_ERROR_HOOKS.lock().unwrap().push(hook);
|
||||
crate::event_loop::XLIB_ERROR_HOOKS.lock().unwrap().push(hook);
|
||||
}
|
||||
|
||||
/// Additional methods on [`ActiveEventLoop`] that are specific to X11.
|
||||
///
|
||||
/// [`ActiveEventLoop`]: winit_core::event_loop::ActiveEventLoop
|
||||
pub trait ActiveEventLoopExtX11 {
|
||||
/// True if the [`ActiveEventLoop`] uses X11.
|
||||
/// True if the event loop uses X11.
|
||||
fn is_x11(&self) -> bool;
|
||||
}
|
||||
|
||||
impl ActiveEventLoopExtX11 for dyn ActiveEventLoop + '_ {
|
||||
impl ActiveEventLoopExtX11 for dyn CoreActiveEventLoop + '_ {
|
||||
#[inline]
|
||||
fn is_x11(&self) -> bool {
|
||||
self.cast_ref::<crate::platform_impl::x11::ActiveEventLoop>().is_some()
|
||||
self.cast_ref::<ActiveEventLoop>().is_some()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -102,13 +125,6 @@ pub trait EventLoopExtX11 {
|
|||
fn is_x11(&self) -> bool;
|
||||
}
|
||||
|
||||
impl EventLoopExtX11 for EventLoop {
|
||||
#[inline]
|
||||
fn is_x11(&self) -> bool {
|
||||
!self.event_loop.is_wayland()
|
||||
}
|
||||
}
|
||||
|
||||
/// Additional methods on [`EventLoopBuilder`] that are specific to X11.
|
||||
pub trait EventLoopBuilderExtX11 {
|
||||
/// Force using X11.
|
||||
|
|
@ -121,20 +137,6 @@ pub trait EventLoopBuilderExtX11 {
|
|||
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self;
|
||||
}
|
||||
|
||||
impl EventLoopBuilderExtX11 for EventLoopBuilder {
|
||||
#[inline]
|
||||
fn with_x11(&mut self) -> &mut Self {
|
||||
self.platform_specific.forced_backend = Some(crate::platform_impl::Backend::X);
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn with_any_thread(&mut self, any_thread: bool) -> &mut Self {
|
||||
self.platform_specific.any_thread = any_thread;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Additional methods on [`Window`] that are specific to X11.
|
||||
///
|
||||
/// [`Window`]: crate::window::Window
|
||||
|
|
@ -142,6 +144,12 @@ pub trait WindowExtX11 {}
|
|||
|
||||
impl WindowExtX11 for dyn CoreWindow {}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub(crate) struct ApplicationName {
|
||||
pub(crate) general: String,
|
||||
pub(crate) instance: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct WindowAttributesX11 {
|
||||
pub(crate) name: Option<ApplicationName>,
|
||||
|
|
@ -192,8 +200,7 @@ impl WindowAttributesX11 {
|
|||
/// For details about application ID conventions, see the
|
||||
/// [Desktop Entry Spec](https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#desktop-file-id)
|
||||
pub fn with_name(mut self, general: impl Into<String>, instance: impl Into<String>) -> Self {
|
||||
self.name =
|
||||
Some(crate::platform_impl::ApplicationName::new(general.into(), instance.into()));
|
||||
self.name = Some(ApplicationName { general: general.into(), instance: instance.into() });
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -6,7 +6,9 @@ use x11rb::connection::RequestConnection;
|
|||
use x11rb::protocol::randr::{self, ConnectionExt as _};
|
||||
use x11rb::protocol::xproto;
|
||||
|
||||
use super::{util, X11Error, XConnection};
|
||||
use crate::event_loop::X11Error;
|
||||
use crate::util;
|
||||
use crate::xdisplay::XConnection;
|
||||
|
||||
// Used for testing. This should always be committed as false.
|
||||
const DISABLE_MONITOR_LIST_CACHING: bool = false;
|
||||
|
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
|||
|
||||
use x11_dl::xlib::{self, XEvent, XGenericEventCookie};
|
||||
|
||||
use crate::platform_impl::x11::XConnection;
|
||||
use crate::xdisplay::XConnection;
|
||||
|
||||
/// 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
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use super::*;
|
||||
use crate::platform::x11::WindowType;
|
||||
use crate::WindowType;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
|
|
@ -32,7 +32,9 @@ pub use self::window_property::*;
|
|||
pub use self::wm::*;
|
||||
pub use self::xmodmap::ModifierKeymap;
|
||||
use super::atoms::*;
|
||||
use super::{ffi, VoidCookie, X11Error, XConnection, XError};
|
||||
use super::ffi;
|
||||
use crate::event_loop::{VoidCookie, X11Error};
|
||||
use crate::xdisplay::{XConnection, XError};
|
||||
|
||||
pub fn maybe_change<T: PartialEq>(field: &mut Option<T>, value: T) -> bool {
|
||||
let wrapped = Some(value);
|
||||
|
|
@ -8,7 +8,7 @@ use winit_core::monitor::VideoMode;
|
|||
use x11rb::protocol::randr::{self, ConnectionExt as _};
|
||||
|
||||
use super::*;
|
||||
use crate::platform_impl::platform::x11::{monitor, VideoModeHandle};
|
||||
use crate::monitor::{self, VideoModeHandle};
|
||||
|
||||
/// Represents values of `WINIT_HIDPI_FACTOR`.
|
||||
pub enum EnvVarDPI {
|
||||
|
|
@ -31,20 +31,19 @@ use x11rb::protocol::xfixes::{ConnectionExt, RegionWrapper};
|
|||
use x11rb::protocol::xproto::{self, ConnectionExt as _, Rectangle};
|
||||
use x11rb::protocol::{randr, xinput};
|
||||
|
||||
use super::util::{self, SelectedCursor};
|
||||
use super::{
|
||||
ffi, ActiveEventLoop, CookieResultExt, CustomCursor, ImeRequest, ImeSender, VoidCookie,
|
||||
XConnection,
|
||||
};
|
||||
use crate::platform::x11::{WindowAttributesX11, WindowType};
|
||||
use crate::platform_impl::x11::atoms::*;
|
||||
use crate::platform_impl::x11::util::rgba_to_cardinals;
|
||||
use crate::platform_impl::x11::{
|
||||
xinput_fp1616_to_float, MonitorHandle as X11MonitorHandle, WakeSender, X11Error,
|
||||
use crate::atoms::*;
|
||||
use crate::event_loop::{
|
||||
xinput_fp1616_to_float, ActivationItem, ActiveEventLoop, CookieResultExt, VoidCookie,
|
||||
WakeSender, X11Error, ALL_MASTER_DEVICES, ICONIC_STATE,
|
||||
};
|
||||
use crate::ime::{ImeRequest, ImeSender};
|
||||
use crate::monitor::MonitorHandle as X11MonitorHandle;
|
||||
use crate::util::{self, rgba_to_cardinals, CustomCursor, SelectedCursor};
|
||||
use crate::xdisplay::XConnection;
|
||||
use crate::{ffi, WindowAttributesX11, WindowType};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Window(Arc<UnownedWindow>);
|
||||
pub struct Window(Arc<UnownedWindow>);
|
||||
|
||||
impl Deref for Window {
|
||||
type Target = UnownedWindow;
|
||||
|
|
@ -430,7 +429,7 @@ pub struct UnownedWindow {
|
|||
ime_sender: Mutex<ImeSender>,
|
||||
pub shared_state: Mutex<SharedState>,
|
||||
redraw_sender: WakeSender<WindowId>,
|
||||
activation_sender: WakeSender<super::ActivationToken>,
|
||||
activation_sender: WakeSender<ActivationItem>,
|
||||
}
|
||||
macro_rules! leap {
|
||||
($e:expr) => {
|
||||
|
|
@ -827,7 +826,7 @@ impl UnownedWindow {
|
|||
| xinput::XIEventMask::TOUCH_BEGIN
|
||||
| xinput::XIEventMask::TOUCH_UPDATE
|
||||
| xinput::XIEventMask::TOUCH_END;
|
||||
leap!(xconn.select_xinput_events(window.xwindow, super::ALL_MASTER_DEVICES, mask))
|
||||
leap!(xconn.select_xinput_events(window.xwindow, ALL_MASTER_DEVICES, mask))
|
||||
.ignore_error();
|
||||
|
||||
// Set visibility (map window)
|
||||
|
|
@ -2092,7 +2091,7 @@ impl UnownedWindow {
|
|||
let is_minimized = if let Ok(state) =
|
||||
self.xconn.get_property::<u32>(self.xwindow, state_atom, state_type_atom)
|
||||
{
|
||||
state.contains(&super::ICONIC_STATE)
|
||||
state.contains(&ICONIC_STATE)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
|
@ -17,6 +17,7 @@ use x11rb::xcb_ffi::XCBConnection;
|
|||
use super::atoms::Atoms;
|
||||
use super::ffi;
|
||||
use super::monitor::MonitorHandle;
|
||||
use crate::event_loop::X11Error;
|
||||
|
||||
/// A connection to an X server.
|
||||
pub struct XConnection {
|
||||
|
|
@ -235,7 +236,7 @@ impl XConnection {
|
|||
|
||||
/// Reload the resource database.
|
||||
#[inline]
|
||||
pub fn reload_database(&self) -> Result<(), super::X11Error> {
|
||||
pub fn reload_database(&self) -> Result<(), X11Error> {
|
||||
let database = resource_manager::new_from_default(self.xcb_connection())?;
|
||||
*self.database.write().unwrap_or_else(|e| e.into_inner()) = database;
|
||||
Ok(())
|
||||
|
|
@ -10,7 +10,8 @@ use std::num::NonZeroUsize;
|
|||
use x11rb::protocol::xproto::{self, ConnectionExt};
|
||||
|
||||
use super::atoms::*;
|
||||
use super::XConnection;
|
||||
use crate::event_loop::X11Error;
|
||||
use crate::xdisplay::XConnection;
|
||||
|
||||
type Result<T> = core::result::Result<T, ParserError>;
|
||||
|
||||
|
|
@ -24,7 +25,7 @@ impl XConnection {
|
|||
pub(crate) fn xsettings_dpi(
|
||||
&self,
|
||||
xsettings_screen: xproto::Atom,
|
||||
) -> core::result::Result<Option<f64>, super::X11Error> {
|
||||
) -> core::result::Result<Option<f64>, X11Error> {
|
||||
let atoms = self.atoms();
|
||||
|
||||
// Get the current owner of the screen's settings.
|
||||
Loading…
Add table
Add a link
Reference in a new issue