Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

internal: Add libxcb and replace some Xlib functions #2614

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
strategy:
fail-fast: false
matrix:
rust_version: ['1.60.0', stable, nightly]
rust_version: ['1.61.0', stable, nightly]
platform:
# Note: Make sure that we test all the `docs.rs` targets defined in Cargo.toml!
- { target: x86_64-pc-windows-msvc, os: windows-latest, }
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ And please only add new entries to the top of this list, right below the `# Unre
- **Breaking:** On Android, switched to using [`android-activity`](https://github.com/rib/android-activity) crate as a glue layer instead of [`ndk-glue`](https://github.com/rust-windowing/android-ndk-rs/tree/master/ndk-glue). See [README.md#Android](https://github.com/rust-windowing/winit#Android) for more details. ([#2444](https://github.com/rust-windowing/winit/pull/2444))
- **Breaking:** Removed support for `raw-window-handle` version `0.4`
- On Wayland, `RedrawRequested` not emitted during resize.
- On X11, migrate from Xlib to libxcb.
- Add a `set_wait_timeout` function to `ControlFlow` to allow waiting for a `Duration`.
- **Breaking:** Remove the unstable `xlib_xconnection()` function from the private interface.
- Added Orbital support for Redox OS
Expand Down
9 changes: 6 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ rustdoc-args = ["--cfg", "docsrs"]

[features]
default = ["x11", "wayland", "wayland-dlopen", "wayland-csd-adwaita"]
x11 = ["x11-dl", "mio", "percent-encoding"]
x11 = ["bytemuck", "x11-dl", "x11rb", "mio", "percent-encoding", "xim"]
wayland = ["wayland-client", "wayland-protocols", "sctk", "wayland-commons"]
wayland-dlopen = ["sctk/dlopen", "wayland-client/dlopen"]
wayland-csd-adwaita = ["sctk-adwaita", "sctk-adwaita/ab_glyph"]
wayland-csd-adwaita-crossfont = ["sctk-adwaita", "sctk-adwaita/crossfont"]
wayland-csd-adwaita-notitle = ["sctk-adwaita"]
android-native-activity = [ "android-activity/native-activity" ]
android-game-activity = [ "android-activity/game-activity" ]
android-native-activity = ["android-activity/native-activity"]
android-game-activity = ["android-activity/game-activity"]

[build-dependencies]
cfg_aliases = "0.1.1"
Expand Down Expand Up @@ -104,6 +104,7 @@ features = [
]

[target.'cfg(all(unix, not(any(target_os = "redox", target_arch = "wasm32", target_os = "android", target_os = "ios", target_os = "macos"))))'.dependencies]
bytemuck = { version = "1.12.3", default-features = false, optional = true, features = ["derive", "extern_crate_alloc"] }
libc = "0.2.64"
mio = { version = "0.8", features = ["os-ext"], optional = true }
percent-encoding = { version = "2.0", optional = true }
Expand All @@ -113,6 +114,8 @@ wayland-client = { version = "0.29.5", default_features = false, features = ["u
wayland-protocols = { version = "0.29.5", features = [ "staging_protocols"], optional = true }
wayland-commons = { version = "0.29.5", optional = true }
x11-dl = { version = "2.18.5", optional = true }
x11rb = { version = "0.11.0", features = ["allow-unsafe-code", "dl-libxcb", "randr", "resource_manager", "xinput", "xkb"], optional = true }
xim = { git = "https://github.com/Riey/xim-rs.git", features = ["client", "x11rb-client", "x11rb-xcb"], optional = true }

[target.'cfg(target_os = "redox")'.dependencies]
orbclient = { version = "0.3.42", default-features = false }
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
// Doc feature labels can be tested locally by running RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![allow(clippy::missing_safety_doc)]
#![allow(clippy::uninlined_format_args)]

#[allow(unused_imports)]
#[macro_use]
Expand Down
37 changes: 30 additions & 7 deletions src/platform_impl/linux/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
#[cfg(x11_platform)]
pub use self::x11::XNotSupported;
#[cfg(x11_platform)]
use self::x11::{ffi::XVisualInfo, util::WindowType as XWindowType, XConnection, XError};
use self::x11::{
ffi::XVisualInfo, util::WindowType as XWindowType, PlatformError, XConnection, XError,
};
#[cfg(x11_platform)]
use crate::platform::x11::XlibErrorHook;
use crate::{
Expand Down Expand Up @@ -120,28 +122,49 @@ pub(crate) static X11_BACKEND: Lazy<Mutex<Result<Arc<XConnection>, XNotSupported
Lazy::new(|| Mutex::new(XConnection::new(Some(x_error_callback)).map(Arc::new)));

#[derive(Debug, Clone)]
pub enum OsError {
pub(crate) enum OsError {
#[cfg(x11_platform)]
XError(XError),
XError(Arc<PlatformError>),
#[cfg(x11_platform)]
XMisc(&'static str),
#[cfg(wayland_platform)]
WaylandMisc(&'static str),
}

impl fmt::Display for OsError {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
match *self {
#[cfg(x11_platform)]
OsError::XError(ref e) => _f.pad(&e.description),
OsError::XError(ref e) => fmt::Display::fmt(e, f),
#[cfg(x11_platform)]
OsError::XMisc(e) => _f.pad(e),
OsError::XMisc(e) => f.pad(e),
#[cfg(wayland_platform)]
OsError::WaylandMisc(e) => _f.pad(e),
OsError::WaylandMisc(e) => f.pad(e),
}
}
}

#[cfg(x11_platform)]
impl From<XError> for OsError {
fn from(value: XError) -> Self {
OsError::XError(Arc::new(value.into()))
}
}

#[cfg(x11_platform)]
impl From<PlatformError> for OsError {
fn from(value: PlatformError) -> Self {
OsError::XError(Arc::new(value))
}
}

#[cfg(x11_platform)]
impl From<x11rb::errors::ConnectionError> for OsError {
fn from(value: x11rb::errors::ConnectionError) -> Self {
OsError::XError(Arc::new(value.into()))
}
}

pub(crate) enum Window {
#[cfg(x11_platform)]
X(x11::Window),
Expand Down
160 changes: 160 additions & 0 deletions src/platform_impl/linux/x11/atoms.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
//! Atom management.

use x11rb::{
atom_manager, cookie,
errors::{ConnectionError, ReplyError},
protocol::xproto::{self, ConnectionExt as _},
xcb_ffi::XCBConnection,
};

// Note: text/uri-list is a special case and is handled separately.

macro_rules! make_atom_manager {
(
$($name: ident),*
) => {
/// The various atoms used within `Winit`.
#[allow(non_camel_case_types)]
pub(crate) enum AtomType {
TextUriList,
$(
$name,
)*
}

/// A collection of atoms used within `Winit`.
pub(crate) struct Atoms {
/// The textual atom list.
some_atoms: SomeAtoms,

/// `text/uri-list`.
text_uri_list: xproto::Atom,
}

/// The cookie for the `Atoms` structure.
pub(crate) struct AtomsCookie<'a> {
/// The textual atom list.
some_atoms: SomeAtomsCookie<'a, XCBConnection>,

/// `text/uri-list`.
text_uri_list: cookie::Cookie<'a, XCBConnection, xproto::InternAtomReply>,
}

impl Atoms {
/// Create a new `Atoms` structure.
pub(crate) fn request(conn: &XCBConnection) -> Result<AtomsCookie<'_>, ConnectionError> {
let some_atoms = SomeAtoms::new(conn)?;
let text_uri_list = conn.intern_atom(true, b"text/uri-list")?;
Ok(AtomsCookie {
some_atoms,
text_uri_list,
})
}
}

impl AtomsCookie<'_> {
/// Finish the creation of the `Atoms` structure.
pub(crate) fn reply(self) -> Result<Atoms, ReplyError> {
let some_atoms = self.some_atoms.reply()?;
let text_uri_list = self.text_uri_list.reply()?.atom;
Ok(Atoms {
some_atoms,
text_uri_list,
})
}
}

atom_manager! {
/// A collection of atoms used within `Winit`.
SomeAtoms : SomeAtomsCookie {
$(
$name,
)*
}
}

impl std::ops::Index<AtomType> for Atoms {
type Output = xproto::Atom;

fn index(&self, atom: AtomType) -> &Self::Output {
match atom {
AtomType::TextUriList => &self.text_uri_list,
$(
AtomType::$name => &self.some_atoms.$name,
)*
}
}
}
};
}

make_atom_manager! {
// Window type hints.
_NET_WM_WINDOW_TYPE,
_NET_WM_WINDOW_TYPE_DESKTOP,
_NET_WM_WINDOW_TYPE_DOCK,
_NET_WM_WINDOW_TYPE_TOOLBAR,
_NET_WM_WINDOW_TYPE_MENU,
_NET_WM_WINDOW_TYPE_UTILITY,
_NET_WM_WINDOW_TYPE_SPLASH,
_NET_WM_WINDOW_TYPE_DIALOG,
_NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
_NET_WM_WINDOW_TYPE_POPUP_MENU,
_NET_WM_WINDOW_TYPE_TOOLTIP,
_NET_WM_WINDOW_TYPE_NOTIFICATION,
_NET_WM_WINDOW_TYPE_COMBO,
_NET_WM_WINDOW_TYPE_DND,
_NET_WM_WINDOW_TYPE_NORMAL,

// Other _NET_WM hints
_NET_WM_MOVERESIZE,
_NET_WM_NAME,
_NET_WM_ICON,
_NET_WM_PID,
_NET_WM_PING,
_NET_WM_STATE,
_NET_WM_STATE_ABOVE,
_NET_WM_STATE_BELOW,
_NET_WM_STATE_FULLSCREEN,
_NET_WM_STATE_HIDDEN,
_NET_WM_STATE_MAXIMIZED_HORZ,
_NET_WM_STATE_MAXIMIZED_VERT,

// DND atoms.
XdndAware,
XdndEnter,
XdndLeave,
XdndDrop,
XdndPosition,
XdndStatus,
XdndActionPrivate,
XdndSelection,
XdndFinished,
XdndTypeList,

// _NET hints.
_NET_ACTIVE_WINDOW,
_NET_FRAME_EXTENTS,
_NET_CLIENT_LIST,
_NET_SUPPORTED,
_NET_SUPPORTING_WM_CHECK,

// Misc WM hints.
WM_CHANGE_STATE,
WM_CLIENT_MACHINE,
WM_DELETE_WINDOW,
WM_PROTOCOLS,
WM_STATE,

// Other misc atoms.
_MOTIF_WM_HINTS,
_GTK_THEME_VARIANT,
CARD32,
UTF8_STRING,
None
}

pub(crate) use AtomType::*;

/// Prevent the `None` atom from shadowing `Option::None`.
pub use std::option::Option::None;
Loading