Move X11 backend to winit-x11 (#4253)

This commit is contained in:
Mads Marquart 2025-05-25 17:24:00 +02:00 committed by GitHub
parent 1126e9ea2f
commit 256bbe949e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 232 additions and 227 deletions

3
.github/CODEOWNERS vendored
View file

@ -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

View file

@ -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 }}

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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();
}

View file

@ -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
View 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
View file

@ -0,0 +1 @@
../README.md

View file

@ -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.

View file

@ -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 {

View file

@ -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))))
}

View file

@ -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,
};

View file

@ -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>,

View file

@ -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)]

View file

@ -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) };

View file

@ -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(());

View file

@ -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))]

View file

@ -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
}

View file

@ -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;

View file

@ -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

View file

@ -1,7 +1,7 @@
use std::sync::Arc;
use super::*;
use crate::platform::x11::WindowType;
use crate::WindowType;
#[derive(Debug)]
#[allow(dead_code)]

View file

@ -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);

View file

@ -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 {

View file

@ -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
};

View file

@ -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(())

View file

@ -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.