1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-22 21:01:36 +03:00

window: deps: upgrade to xcb 1.1

Was a bit fiddly.

Eliminated the xcb_util crate

refs: https://github.com/wez/wezterm/issues/1952
This commit is contained in:
Wez Furlong 2022-05-07 14:18:26 -07:00
parent b25d4d22ee
commit abc42f7bcb
12 changed files with 947 additions and 842 deletions

42
Cargo.lock generated
View File

@ -3089,6 +3089,15 @@ version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b45c49fc4f91f35bae654f85ebb3a44d60ac64f11b3166ffa609def390c732d8"
[[package]]
name = "quick-xml"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8533f14c8382aaad0d592c812ac3b826162128b65662331e1127b45c3d18536b"
dependencies = [
"memchr",
]
[[package]]
name = "quote"
version = "1.0.18"
@ -5043,9 +5052,8 @@ dependencies = [
"windows",
"winreg",
"x11",
"xcb 0.9.0",
"xcb 1.1.1",
"xcb-imdkit",
"xcb-util",
"xkbcommon",
]
@ -5151,36 +5159,26 @@ dependencies = [
[[package]]
name = "xcb"
version = "0.9.0"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62056f63138b39116f82a540c983cc11f1c90cd70b3d492a70c25eaa50bd22a6"
checksum = "b127bf5bfe9dbb39118d6567e3773d4bbc795411a8e1ef7b7e056bccac0011a9"
dependencies = [
"bitflags",
"libc",
"log",
"quick-xml",
"x11",
]
[[package]]
name = "xcb-imdkit"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677422b629e6ad41bcf5493f246001be38dc00ea9f8068506fdc991e062f6981"
version = "0.2.0"
source = "git+https://github.com/wez/xcb-imdkit-rs.git?rev=7498cce1085ec23535f1b8d6729407485bf66c00#7498cce1085ec23535f1b8d6729407485bf66c00"
dependencies = [
"bitflags",
"cc",
"lazy_static",
"pkg-config",
"xcb 0.9.0",
]
[[package]]
name = "xcb-util"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43893e47f27bf7d81d489feef3a0e34a457e90bc314b7e74ad9bb3980e4c1c48"
dependencies = [
"libc",
"xcb 0.9.0",
"xcb 1.1.1",
]
[[package]]
@ -5194,12 +5192,12 @@ dependencies = [
[[package]]
name = "xkbcommon"
version = "0.5.0"
source = "git+https://github.com/wez/xkbcommon-rs.git?rev=5cc8f233ac2b8bfa0d7a26fd981b77e68c3f2219#5cc8f233ac2b8bfa0d7a26fd981b77e68c3f2219"
version = "0.6.0"
source = "git+https://github.com/wez/xkbcommon-rs.git?rev=69a29877e99369b4ec74703d3193b6dd694145e9#69a29877e99369b4ec74703d3193b6dd694145e9"
dependencies = [
"libc",
"memmap",
"xcb 0.9.0",
"xcb 1.1.1",
]
[[package]]

View File

@ -67,18 +67,16 @@ winreg = "0.10"
dirs-next = "2.0"
filedescriptor = { version="0.8", path = "../filedescriptor" }
x11 = {version ="2.18", features = ["xlib_xcb"]}
xcb = {version="0.9", features=["render", "randr", "xkb", "xlib_xcb"]}
xcb-util = { features = [ "cursor", "image", "icccm", "ewmh", "keysyms"], version = "0.3" }
xkbcommon = { version = "0.5", features = ["x11", "wayland"], git="https://github.com/wez/xkbcommon-rs.git", rev="5cc8f233ac2b8bfa0d7a26fd981b77e68c3f2219"}
#xkbcommon = { version = "0.5", features = ["x11", "wayland"], path="../../xkbcommon-rs" }
xcb = {version="1.1", features=["render", "randr", "xkb", "xlib_xcb"]}
xkbcommon = { version = "0.6", features = ["x11", "wayland"], git="https://github.com/wez/xkbcommon-rs.git", rev="69a29877e99369b4ec74703d3193b6dd694145e9"}
#xkbcommon = { version = "0.6", features = ["x11", "wayland"], path="../../xkbcommon-rs" }
mio = {version="0.8", features=["os-ext"]}
libc = "0.2"
smithay-client-toolkit = {version = "0.15", default-features=false, optional=true}
wayland-protocols = {version="0.29", optional=true}
wayland-client = {version="0.29", optional=true}
wayland-egl = {version="0.29", optional=true}
xcb-imdkit = "0.1"
#xcb-imdkit = { path = "../../github/xcb-imdkit-rs" }
xcb-imdkit = { version="0.2", git="https://github.com/wez/xcb-imdkit-rs.git", rev="7498cce1085ec23535f1b8d6729407485bf66c00"}
[target.'cfg(target_os="macos")'.dependencies]
cocoa = "0.20"

View File

@ -14,37 +14,41 @@ use std::collections::HashMap;
use std::os::unix::io::AsRawFd;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use xcb_util::ffi::keysyms::{xcb_key_symbols_alloc, xcb_key_symbols_free, xcb_key_symbols_t};
use xcb::x::Atom;
pub struct XConnection {
pub conn: xcb_util::ewmh::Connection,
pub conn: xcb::Connection,
default_dpi: RefCell<f64>,
pub(crate) xsettings: RefCell<XSettingsMap>,
pub screen_num: i32,
pub root: xcb::xproto::Window,
pub root: xcb::x::Window,
pub keyboard: Keyboard,
pub kbd_ev: u8,
pub atom_protocols: xcb::Atom,
pub cursor_font_id: xcb::ffi::xcb_font_t,
pub atom_delete: xcb::Atom,
pub atom_utf8_string: xcb::Atom,
pub atom_xsel_data: xcb::Atom,
pub atom_targets: xcb::Atom,
pub atom_clipboard: xcb::Atom,
pub atom_gtk_edge_constraints: xcb::Atom,
pub atom_xsettings_selection: xcb::Atom,
pub atom_xsettings_settings: xcb::Atom,
pub atom_manager: xcb::Atom,
pub atom_state_maximized_vert: xcb::Atom,
pub atom_state_maximized_horz: xcb::Atom,
pub atom_state_hidden: xcb::Atom,
pub atom_state_fullscreen: xcb::Atom,
pub atom_net_wm_state: xcb::Atom,
keysyms: *mut xcb_key_symbols_t,
pub atom_protocols: Atom,
pub cursor_font_id: xcb::x::Font,
pub atom_delete: Atom,
pub atom_utf8_string: Atom,
pub atom_xsel_data: Atom,
pub atom_targets: Atom,
pub atom_clipboard: Atom,
pub atom_gtk_edge_constraints: Atom,
pub atom_xsettings_selection: Atom,
pub atom_xsettings_settings: Atom,
pub atom_manager: Atom,
pub atom_state_maximized_vert: Atom,
pub atom_state_maximized_horz: Atom,
pub atom_state_hidden: Atom,
pub atom_state_fullscreen: Atom,
pub atom_net_wm_state: Atom,
pub atom_motif_wm_hints: Atom,
pub atom_net_wm_pid: Atom,
pub atom_net_wm_name: Atom,
pub atom_net_wm_icon: Atom,
pub atom_net_move_resize_window: Atom,
pub(crate) xrm: RefCell<HashMap<String, String>>,
pub(crate) windows: RefCell<HashMap<xcb::xproto::Window, Arc<Mutex<XWindowInner>>>>,
pub(crate) windows: RefCell<HashMap<xcb::x::Window, Arc<Mutex<XWindowInner>>>>,
should_terminate: RefCell<bool>,
pub(crate) visual: xcb::xproto::Visualtype,
pub(crate) visual: xcb::x::Visualtype,
pub(crate) depth: u8,
pub(crate) gl_connection: RefCell<Option<Rc<crate::egl::GlConnection>>>,
pub(crate) ime: RefCell<std::pin::Pin<Box<xcb_imdkit::ImeClient>>>,
@ -84,80 +88,28 @@ impl Source for XConnection {
}
}
fn window_id_from_event(event: &xcb::GenericEvent) -> Option<xcb::xproto::Window> {
match event.response_type() & 0x7f {
xcb::EXPOSE => {
let expose: &xcb::ExposeEvent = unsafe { xcb::cast_event(event) };
Some(expose.window())
}
xcb::CONFIGURE_NOTIFY => {
let cfg: &xcb::ConfigureNotifyEvent = unsafe { xcb::cast_event(event) };
Some(cfg.window())
}
xcb::KEY_PRESS | xcb::KEY_RELEASE => {
let key_press: &xcb::KeyPressEvent = unsafe { xcb::cast_event(event) };
Some(key_press.event())
}
xcb::MOTION_NOTIFY => {
let motion: &xcb::MotionNotifyEvent = unsafe { xcb::cast_event(event) };
Some(motion.event())
}
xcb::BUTTON_PRESS | xcb::BUTTON_RELEASE => {
let button_press: &xcb::ButtonPressEvent = unsafe { xcb::cast_event(event) };
Some(button_press.event())
}
xcb::CLIENT_MESSAGE => {
let msg: &xcb::ClientMessageEvent = unsafe { xcb::cast_event(event) };
Some(msg.window())
}
xcb::DESTROY_NOTIFY => {
let msg: &xcb::DestroyNotifyEvent = unsafe { xcb::cast_event(event) };
Some(msg.window())
}
xcb::SELECTION_CLEAR => {
let msg: &xcb::SelectionClearEvent = unsafe { xcb::cast_event(event) };
Some(msg.owner())
}
xcb::PROPERTY_NOTIFY => {
let msg: &xcb::PropertyNotifyEvent = unsafe { xcb::cast_event(event) };
Some(msg.window())
}
xcb::SELECTION_NOTIFY => {
let msg: &xcb::SelectionNotifyEvent = unsafe { xcb::cast_event(event) };
Some(msg.requestor())
}
xcb::SELECTION_REQUEST => {
let msg: &xcb::SelectionRequestEvent = unsafe { xcb::cast_event(event) };
Some(msg.owner())
}
xcb::FOCUS_IN => {
let msg: &xcb::FocusInEvent = unsafe { xcb::cast_event(event) };
Some(msg.event())
}
xcb::FOCUS_OUT => {
let msg: &xcb::FocusOutEvent = unsafe { xcb::cast_event(event) };
Some(msg.event())
}
xcb::LEAVE_NOTIFY => {
let msg: &xcb::LeaveNotifyEvent = unsafe { xcb::cast_event(event) };
Some(msg.event())
}
fn window_id_from_event(event: &xcb::Event) -> Option<xcb::x::Window> {
match event {
xcb::Event::X(xcb::x::Event::Expose(e)) => Some(e.window()),
xcb::Event::X(xcb::x::Event::ConfigureNotify(e)) => Some(e.window()),
xcb::Event::X(xcb::x::Event::KeyPress(e)) => Some(e.event()),
xcb::Event::X(xcb::x::Event::KeyRelease(e)) => Some(e.event()),
xcb::Event::X(xcb::x::Event::MotionNotify(e)) => Some(e.event()),
xcb::Event::X(xcb::x::Event::ButtonPress(e)) => Some(e.event()),
xcb::Event::X(xcb::x::Event::ButtonRelease(e)) => Some(e.event()),
xcb::Event::X(xcb::x::Event::ClientMessage(e)) => Some(e.window()),
xcb::Event::X(xcb::x::Event::DestroyNotify(e)) => Some(e.window()),
xcb::Event::X(xcb::x::Event::SelectionClear(e)) => Some(e.owner()),
xcb::Event::X(xcb::x::Event::SelectionNotify(e)) => Some(e.requestor()),
xcb::Event::X(xcb::x::Event::SelectionRequest(e)) => Some(e.owner()),
xcb::Event::X(xcb::x::Event::PropertyNotify(e)) => Some(e.window()),
xcb::Event::X(xcb::x::Event::FocusIn(e)) => Some(e.event()),
xcb::Event::X(xcb::x::Event::FocusOut(e)) => Some(e.event()),
xcb::Event::X(xcb::x::Event::LeaveNotify(e)) => Some(e.event()),
_ => None,
}
}
fn connect_with_xlib_display() -> anyhow::Result<(xcb::Connection, i32)> {
let display = unsafe { x11::xlib::XOpenDisplay(std::ptr::null()) };
anyhow::ensure!(!display.is_null(), "failed to open X11 display");
let default_screen = unsafe { x11::xlib::XDefaultScreen(display) };
// Note: we don't use xcb::Connection::connect_with_xlib_display because it
// asserts rather than reports an error if it cannot connect to the server!
let conn = unsafe { xcb::Connection::new_from_xlib_display(display) };
conn.set_event_queue_owner(xcb::EventQueueOwner::Xcb);
Ok((conn, default_screen))
}
impl ConnectionOps for XConnection {
fn terminate_message_loop(&self) {
*self.should_terminate.borrow_mut() = true;
@ -189,7 +141,7 @@ impl ConnectionOps for XConnection {
}
fn run_message_loop(&self) -> anyhow::Result<()> {
self.conn.flush();
self.conn.flush()?;
const TOK_XCB: usize = 0xffff_fffc;
const TOK_SPAWN: usize = 0xffff_fffd;
@ -240,7 +192,7 @@ impl ConnectionOps for XConnection {
}
fn beep(&self) {
xcb::xproto::bell(&self.conn, 0);
self.conn.send_request(&xcb::x::Bell { percent: 0 });
}
}
@ -284,34 +236,30 @@ impl XConnection {
}
fn process_queued_xcb(&self) -> anyhow::Result<()> {
match self.conn.poll_for_event() {
None => match self.conn.has_error() {
Ok(_) => (),
Err(err) => {
bail!("X11 connection is broken: {:?} {}", err, err.to_string());
}
},
Some(event) => {
if let Err(err) = self.process_xcb_event_ime(&event) {
return Err(err);
}
if let Some(event) = self
.conn
.poll_for_event()
.context("X11 connection is broken")?
{
if let Err(err) = self.process_xcb_event_ime(&event) {
return Err(err);
}
}
self.conn.flush();
self.conn.flush()?;
loop {
match self.conn.poll_for_queued_event() {
match self.conn.poll_for_queued_event()? {
None => {
self.conn.flush();
self.conn.flush()?;
return Ok(());
}
Some(event) => self.process_xcb_event_ime(&event)?,
}
self.conn.flush();
self.conn.flush()?;
}
}
fn process_xcb_event_ime(&self, event: &xcb::GenericEvent) -> anyhow::Result<()> {
fn process_xcb_event_ime(&self, event: &xcb::Event) -> anyhow::Result<()> {
// check for previous errors produced by the IME forward_event callback
self.ime_process_event_result.replace(Ok(()))?;
@ -322,25 +270,22 @@ impl XConnection {
}
}
fn process_xcb_event(&self, event: &xcb::GenericEvent) -> anyhow::Result<()> {
fn process_xcb_event(&self, event: &xcb::Event) -> anyhow::Result<()> {
if let Some(window_id) = window_id_from_event(event) {
self.process_window_event(window_id, event)?;
} else {
let r = event.response_type() & 0x7f;
if r == self.kbd_ev {
// key press/release are not processed here.
// xkbcommon depends on those events in order to:
// - update modifiers state
// - update keymap/state on keyboard changes
self.keyboard.process_xkb_event(&self.conn, event)?;
}
} else if matches!(event, xcb::Event::Xkb(_)) {
// key press/release are not processed here.
// xkbcommon depends on those events in order to:
// - update modifiers state
// - update keymap/state on keyboard changes
self.keyboard.process_xkb_event(&self.conn, event)?;
}
Ok(())
}
pub(crate) fn window_by_id(
&self,
window_id: xcb::xproto::Window,
window_id: xcb::x::Window,
) -> Option<Arc<Mutex<XWindowInner>>> {
self.windows.borrow().get(&window_id).map(Arc::clone)
}
@ -356,8 +301,8 @@ impl XConnection {
fn process_window_event(
&self,
window_id: xcb::xproto::Window,
event: &xcb::GenericEvent,
window_id: xcb::x::Window,
event: &xcb::Event,
) -> anyhow::Result<()> {
if let Some(window) = self.window_by_id(window_id) {
let mut inner = window.lock().unwrap();
@ -366,66 +311,48 @@ impl XConnection {
Ok(())
}
fn intern_atom(conn: &xcb::Connection, name: &str) -> anyhow::Result<Atom> {
let cookie = conn.send_request(&xcb::x::InternAtom {
only_if_exists: false,
name: name.as_bytes(),
});
let reply = conn.wait_for_reply(cookie)?;
Ok(reply.atom())
}
pub(crate) fn create_new() -> anyhow::Result<Rc<XConnection>> {
let (conn, screen_num) = connect_with_xlib_display()?;
let conn = xcb_util::ewmh::Connection::connect(conn)
.map_err(|_| anyhow!("failed to init ewmh"))?;
let (conn, screen_num) = xcb::Connection::connect_with_xlib_display_and_extensions(
&[xcb::Extension::Xkb],
&[
xcb::Extension::RandR,
xcb::Extension::Render,
xcb::Extension::Xkb,
],
)?;
let atom_protocols = xcb::intern_atom(&conn, false, "WM_PROTOCOLS")
.get_reply()?
.atom();
let atom_delete = xcb::intern_atom(&conn, false, "WM_DELETE_WINDOW")
.get_reply()?
.atom();
let atom_utf8_string = xcb::intern_atom(&conn, false, "UTF8_STRING")
.get_reply()?
.atom();
let atom_xsel_data = xcb::intern_atom(&conn, false, "XSEL_DATA")
.get_reply()?
.atom();
let atom_targets = xcb::intern_atom(&conn, false, "TARGETS")
.get_reply()?
.atom();
let atom_clipboard = xcb::intern_atom(&conn, false, "CLIPBOARD")
.get_reply()?
.atom();
let atom_gtk_edge_constraints = xcb::intern_atom(&conn, false, "_GTK_EDGE_CONSTRAINTS")
.get_reply()?
.atom();
let atom_protocols = Self::intern_atom(&conn, "WM_PROTOCOLS")?;
let atom_delete = Self::intern_atom(&conn, "WM_DELETE_WINDOW")?;
let atom_utf8_string = Self::intern_atom(&conn, "UTF8_STRING")?;
let atom_xsel_data = Self::intern_atom(&conn, "XSEL_DATA")?;
let atom_targets = Self::intern_atom(&conn, "TARGETS")?;
let atom_clipboard = Self::intern_atom(&conn, "CLIPBOARD")?;
let atom_gtk_edge_constraints = Self::intern_atom(&conn, "_GTK_EDGE_CONSTRAINTS")?;
let atom_xsettings_selection =
xcb::intern_atom(&conn, false, &format!("_XSETTINGS_S{}", screen_num))
.get_reply()?
.atom();
let atom_xsettings_settings = xcb::intern_atom(&conn, false, "_XSETTINGS_SETTINGS")
.get_reply()?
.atom();
let atom_manager = xcb::intern_atom(&conn, false, "MANAGER")
.get_reply()?
.atom();
let atom_state_maximized_vert =
xcb::intern_atom(&conn, false, "_NET_WM_STATE_MAXIMIZED_VERT")
.get_reply()?
.atom();
let atom_state_maximized_horz =
xcb::intern_atom(&conn, false, "_NET_WM_STATE_MAXIMIZED_HORZ")
.get_reply()?
.atom();
let atom_state_hidden = xcb::intern_atom(&conn, false, "_NET_WM_STATE_HIDDEN")
.get_reply()?
.atom();
let atom_state_fullscreen = xcb::intern_atom(&conn, false, "_NET_WM_STATE_FULLSCREEN")
.get_reply()?
.atom();
let atom_net_wm_state = xcb::intern_atom(&conn, false, "_NET_WM_STATE")
.get_reply()?
.atom();
Self::intern_atom(&conn, &format!("_XSETTINGS_S{}", screen_num))?;
let atom_xsettings_settings = Self::intern_atom(&conn, "_XSETTINGS_SETTINGS")?;
let atom_manager = Self::intern_atom(&conn, "MANAGER")?;
let atom_state_maximized_vert = Self::intern_atom(&conn, "_NET_WM_STATE_MAXIMIZED_VERT")?;
let atom_state_maximized_horz = Self::intern_atom(&conn, "_NET_WM_STATE_MAXIMIZED_HORZ")?;
let atom_state_hidden = Self::intern_atom(&conn, "_NET_WM_STATE_HIDDEN")?;
let atom_state_fullscreen = Self::intern_atom(&conn, "_NET_WM_STATE_FULLSCREEN")?;
let atom_net_wm_state = Self::intern_atom(&conn, "_NET_WM_STATE")?;
let atom_motif_wm_hints = Self::intern_atom(&conn, "_MOTIF_WM_HINTS")?;
let atom_net_wm_pid = Self::intern_atom(&conn, "_NET_WM_PID")?;
let atom_net_wm_name = Self::intern_atom(&conn, "_NET_WM_NAME")?;
let atom_net_wm_icon = Self::intern_atom(&conn, "_NET_WM_ICON")?;
let atom_net_move_resize_window = Self::intern_atom(&conn, "_NET_MOVERESIZE_WINDOW")?;
let has_randr = conn
.get_extension_data(xcb::randr::id())
.map(|info| info.present())
.unwrap_or(false);
let keysyms = unsafe { xcb_key_symbols_alloc((*conn).get_raw_conn()) };
let has_randr = conn.active_extensions().any(|e| e == xcb::Extension::RandR);
let screen = conn
.get_setup()
@ -438,7 +365,7 @@ impl XConnection {
let depth_bpp = depth.depth();
if depth_bpp == 24 || depth_bpp == 32 {
for vis in depth.visuals() {
if vis.class() == xcb::xproto::VISUAL_CLASS_TRUE_COLOR as u8
if vis.class() == xcb::x::VisualClass::TrueColor
&& vis.bits_per_rgb_value() >= 8
{
visuals.push((depth_bpp, vis));
@ -451,9 +378,10 @@ impl XConnection {
}
visuals.sort_by(|(a_depth, _), (b_depth, _)| b_depth.cmp(&a_depth));
let (depth, visual) = visuals[0];
let visual = *visual;
log::trace!(
"picked depth {} visual id:0x{:x}, class:{}, bits_per_rgb_value:{}, \
"picked depth {} visual id:0x{:x}, class:{:?}, bits_per_rgb_value:{}, \
colormap entries:{}, masks: r=0x{:x},g=0x{:x},b=0x{:x}",
depth,
visual.visual_id(),
@ -468,9 +396,11 @@ impl XConnection {
let cursor_font_id = conn.generate_id();
let cursor_font_name = "cursor";
xcb::open_font_checked(&conn, cursor_font_id, cursor_font_name)
.request_check()
.context("xcb::open_font_checked")?;
conn.check_request(conn.send_request_checked(&xcb::x::OpenFont {
fid: cursor_font_id,
name: cursor_font_name.as_bytes(),
}))
.context("OpenFont")?;
let root = screen.root();
@ -517,7 +447,11 @@ impl XConnection {
atom_state_hidden,
atom_state_fullscreen,
atom_net_wm_state,
keysyms,
atom_motif_wm_hints,
atom_net_wm_pid,
atom_net_wm_name,
atom_net_move_resize_window,
atom_net_wm_icon,
keyboard,
kbd_ev,
atom_utf8_string,
@ -590,19 +524,15 @@ impl XConnection {
Ok(conn)
}
pub fn ewmh_conn(&self) -> &xcb_util::ewmh::Connection {
&self.conn
}
pub fn conn(&self) -> &xcb::Connection {
&*self.conn
&self.conn
}
pub fn screen_num(&self) -> i32 {
self.screen_num
}
pub fn atom_delete(&self) -> xcb::Atom {
pub fn atom_delete(&self) -> Atom {
self.atom_delete
}
@ -610,7 +540,7 @@ impl XConnection {
R,
F: FnOnce(&mut XWindowInner) -> anyhow::Result<R> + Send + 'static,
>(
window: xcb::xproto::Window,
window: xcb::x::Window,
f: F,
) -> promise::Future<R>
where
@ -630,11 +560,3 @@ impl XConnection {
future
}
}
impl Drop for XConnection {
fn drop(&mut self) {
unsafe {
xcb_key_symbols_free(self.keysyms);
}
}
}

View File

@ -1,3 +1,4 @@
use crate::os::x11::xcb_util::*;
use crate::x11::XConnection;
use crate::MouseCursor;
use anyhow::{ensure, Context};
@ -9,17 +10,26 @@ use std::io::prelude::*;
use std::io::SeekFrom;
use std::path::PathBuf;
use std::rc::{Rc, Weak};
use xcb::ffi::xcb_cursor_t;
use xcb::x::Cursor;
use xcb::Xid;
// X11 classic Cursor glyphs
pub const HAND1: u16 = 58;
pub const SB_H_DOUBLE_ARROW: u16 = 108;
pub const SB_V_DOUBLE_ARROW: u16 = 116;
pub const TOP_LEFT_ARROW: u16 = 132;
pub const TOP_LEFT_CORNER: u16 = 134;
pub const XTERM: u16 = 152;
pub struct XcbCursor {
pub id: xcb_cursor_t,
pub id: Cursor,
pub conn: Weak<XConnection>,
}
impl Drop for XcbCursor {
fn drop(&mut self) {
if let Some(conn) = self.conn.upgrade() {
xcb::free_cursor(&conn.conn, self.id);
conn.send_request(&xcb::x::FreeCursor { cursor: self.id });
}
}
}
@ -126,18 +136,14 @@ impl CursorInfo {
let mut pict_format_id = None;
// If we know the theme to use, then we need the render extension
// if we are to be able to load the cursor
let has_render = unsafe {
conn.get_extension_data(&mut xcb::ffi::render::xcb_render_id)
.map_or(false, |ext| ext.present())
};
let has_render = conn
.active_extensions()
.any(|e| e == xcb::Extension::Render);
if has_render {
if let Ok(vers) = xcb::render::query_version(
conn.conn(),
xcb::ffi::render::XCB_RENDER_MAJOR_VERSION,
xcb::ffi::render::XCB_RENDER_MINOR_VERSION,
)
.get_reply()
{
if let Ok(vers) = conn.wait_for_reply(conn.send_request(&xcb::render::QueryVersion {
client_major_version: xcb::render::MAJOR_VERSION,
client_minor_version: xcb::render::MINOR_VERSION,
})) {
// 0.5 and later have the required support
if (vers.major_version(), vers.minor_version()) >= (0, 5) {
size.replace(cursor_size(&config.xcursor_size, &*conn.xrm.borrow()));
@ -148,14 +154,16 @@ impl CursorInfo {
.or_else(|| conn.xrm.borrow().get("Xcursor.theme").cloned());
// Locate the Pictformat corresponding to ARGB32
if let Ok(formats) = xcb::render::query_pict_formats(conn.conn()).get_reply() {
if let Ok(formats) =
conn.wait_for_reply(conn.send_request(&xcb::render::QueryPictFormats {}))
{
for fmt in formats.formats() {
if fmt.depth() == 32 {
let direct = fmt.direct();
if direct.alpha_shift() == 24
&& direct.red_shift() == 16
&& direct.green_shift() == 8
&& direct.blue_shift() == 0
if direct.alpha_shift == 24
&& direct.red_shift == 16
&& direct.green_shift == 8
&& direct.blue_shift == 0
{
pict_format_id.replace(fmt.id());
break;
@ -186,7 +194,7 @@ impl CursorInfo {
pub fn set_cursor(
&mut self,
window_id: xcb::xproto::Window,
window_id: xcb::x::Window,
cursor: Option<MouseCursor>,
) -> anyhow::Result<()> {
if cursor == self.cursor {
@ -203,79 +211,81 @@ impl CursorInfo {
},
};
xcb::change_window_attributes(&conn, window_id, &[(xcb::ffi::XCB_CW_CURSOR, cursor_id)]);
conn.send_request(&xcb::x::ChangeWindowAttributes {
window: window_id,
value_list: &[xcb::x::Cw::Cursor(cursor_id)],
});
self.cursor = cursor;
Ok(())
}
fn create_blank(&mut self, conn: &Rc<XConnection>) -> anyhow::Result<u32> {
fn create_blank(&mut self, conn: &Rc<XConnection>) -> anyhow::Result<Cursor> {
let mut pixels = [0u8; 4];
let image = unsafe {
xcb_util::ffi::image::xcb_image_create_native(
conn.conn().get_raw_conn(),
1,
1,
xcb::xproto::IMAGE_FORMAT_Z_PIXMAP,
32,
std::ptr::null_mut(),
pixels.len() as u32,
pixels.as_mut_ptr(),
)
};
ensure!(!image.is_null(), "failed to create native image");
let image = XcbImage::create_native(
conn,
1,
1,
xcb::x::ImageFormat::ZPixmap as u32,
32,
std::ptr::null_mut(),
pixels.len() as u32,
pixels.as_mut_ptr(),
)?;
let pixmap = conn.generate_id();
xcb::xproto::create_pixmap_checked(conn, 32, pixmap, conn.root, 1, 1)
.request_check()
.context("create_pixmap")?;
conn.check_request(conn.send_request_checked(&xcb::x::CreatePixmap {
depth: 32,
pid: pixmap,
drawable: xcb::x::Drawable::Window(conn.root),
width: 1,
height: 1,
}))
.context("CreatePixmap")?;
let gc = conn.generate_id();
xcb::create_gc(conn.conn(), gc, pixmap, &[]);
conn.send_request(&xcb::x::CreateGc {
cid: gc,
drawable: xcb::x::Drawable::Pixmap(pixmap),
value_list: &[],
});
unsafe {
xcb_util::ffi::image::xcb_image_put(
conn.conn().get_raw_conn(),
pixmap,
gc,
image,
0,
0,
0,
)
};
image.put(conn, pixmap.resource_id(), gc.resource_id(), 0, 0, 0);
xcb::free_gc(conn.conn(), gc);
conn.send_request(&xcb::x::FreeGc { gc });
let pic = conn.generate_id();
xcb::render::create_picture_checked(
conn.conn(),
pic,
pixmap,
self.pict_format_id.unwrap(),
&[],
)
.request_check()
conn.check_request(conn.send_request_checked(&xcb::render::CreatePicture {
pid: pic,
drawable: xcb::x::Drawable::Pixmap(pixmap),
format: self.pict_format_id.unwrap(),
value_list: &[],
}))
.context("create_picture")?;
xcb::xproto::free_pixmap(conn.conn(), pixmap);
conn.send_request(&xcb::x::FreePixmap { pixmap });
let cursor_id: xcb::ffi::xcb_cursor_t = conn.generate_id();
xcb::render::create_cursor_checked(conn.conn(), cursor_id, pic, 0, 0)
.request_check()
.context("create_cursor")?;
let cursor_id: Cursor = conn.generate_id();
conn.check_request(conn.send_request_checked(&xcb::render::CreateCursor {
cid: cursor_id,
source: pic,
x: 0,
y: 0,
}))
.context("create_cursor")?;
xcb::render::free_picture(conn.conn(), pic);
unsafe {
xcb_util::ffi::image::xcb_image_destroy(image);
}
conn.send_request(&xcb::render::FreePicture { picture: pic });
Ok(cursor_id)
}
fn load_themed(&mut self, conn: &Rc<XConnection>, cursor: Option<MouseCursor>) -> Option<u32> {
fn load_themed(
&mut self,
conn: &Rc<XConnection>,
cursor: Option<MouseCursor>,
) -> Option<Cursor> {
if cursor.is_none() {
match self.create_blank(conn) {
Ok(cursor_id) => {
@ -334,33 +344,32 @@ impl CursorInfo {
None
}
fn load_basic(&mut self, conn: &Rc<XConnection>, cursor: Option<MouseCursor>) -> u32 {
fn load_basic(&mut self, conn: &Rc<XConnection>, cursor: Option<MouseCursor>) -> Cursor {
let id_no = match cursor.unwrap_or(MouseCursor::Arrow) {
// `/usr/include/X11/cursorfont.h`
// <https://docs.rs/xcb-util/0.3.0/src/xcb_util/cursor.rs.html>
MouseCursor::Arrow => xcb_util::cursor::TOP_LEFT_ARROW,
MouseCursor::Hand => xcb_util::cursor::HAND1,
MouseCursor::Text => xcb_util::cursor::XTERM,
MouseCursor::SizeUpDown => xcb_util::cursor::SB_V_DOUBLE_ARROW,
MouseCursor::SizeLeftRight => xcb_util::cursor::SB_H_DOUBLE_ARROW,
MouseCursor::Arrow => TOP_LEFT_ARROW,
MouseCursor::Hand => HAND1,
MouseCursor::Text => XTERM,
MouseCursor::SizeUpDown => SB_V_DOUBLE_ARROW,
MouseCursor::SizeLeftRight => SB_H_DOUBLE_ARROW,
};
log::trace!("loading X11 basic cursor {} for {:?}", id_no, cursor);
let cursor_id: xcb::ffi::xcb_cursor_t = conn.generate_id();
xcb::create_glyph_cursor(
&conn,
cursor_id,
conn.cursor_font_id,
conn.cursor_font_id,
id_no,
id_no + 1,
0xffff,
0xffff,
0xffff,
0,
0,
0,
);
let cursor_id: Cursor = conn.generate_id();
conn.send_request(&xcb::x::CreateGlyphCursor {
cid: cursor_id,
source_font: conn.cursor_font_id,
mask_font: conn.cursor_font_id,
source_char: id_no,
mask_char: id_no + 1,
fore_red: 0xffff,
fore_green: 0xffff,
fore_blue: 0xffff,
back_red: 0,
back_green: 0,
back_blue: 0,
});
self.cursors.insert(
cursor,
@ -377,7 +386,7 @@ impl CursorInfo {
&self,
conn: &Rc<XConnection>,
mut file: std::fs::File,
) -> anyhow::Result<u32> {
) -> anyhow::Result<Cursor> {
/* See: <https://cgit.freedesktop.org/xcb/util-cursor/tree/cursor/load_cursor.c>
*
* Cursor files start with a header. The header
@ -529,77 +538,59 @@ impl CursorInfo {
chunk.copy_from_slice(&data);
}
let image = unsafe {
xcb_util::ffi::image::xcb_image_create_native(
conn.conn().get_raw_conn(),
width.try_into()?,
height.try_into()?,
xcb::xproto::IMAGE_FORMAT_Z_PIXMAP,
32,
std::ptr::null_mut(),
pixels.len() as u32,
pixels.as_mut_ptr(),
)
};
ensure!(!image.is_null(), "failed to create native image");
let image = XcbImage::create_native(
conn,
width.try_into()?,
height.try_into()?,
xcb::x::ImageFormat::ZPixmap as u32,
32,
std::ptr::null_mut(),
pixels.len() as u32,
pixels.as_mut_ptr(),
)?;
let pixmap = conn.generate_id();
xcb::xproto::create_pixmap_checked(
conn,
32,
pixmap,
conn.root,
width as u16,
height as u16,
)
.request_check()
conn.check_request(conn.send_request_checked(&xcb::x::CreatePixmap {
depth: 32,
pid: pixmap,
drawable: xcb::x::Drawable::Window(conn.root),
width: width as u16,
height: height as u16,
}))
.context("create_pixmap")?;
let gc = conn.generate_id();
xcb::create_gc(conn.conn(), gc, pixmap, &[]);
conn.send_request(&xcb::x::CreateGc {
cid: gc,
drawable: xcb::x::Drawable::Pixmap(pixmap),
value_list: &[],
});
unsafe {
xcb_util::ffi::image::xcb_image_put(
conn.conn().get_raw_conn(),
pixmap,
gc,
image,
0,
0,
0,
)
};
image.put(conn, pixmap.resource_id(), gc.resource_id(), 0, 0, 0);
xcb::free_gc(conn.conn(), gc);
conn.send_request(&xcb::x::FreeGc { gc });
let pic = conn.generate_id();
xcb::render::create_picture_checked(
conn.conn(),
pic,
pixmap,
self.pict_format_id.unwrap(),
&[],
)
.request_check()
conn.check_request(conn.send_request_checked(&xcb::render::CreatePicture {
pid: pic,
drawable: xcb::x::Drawable::Pixmap(pixmap),
format: self.pict_format_id.unwrap(),
value_list: &[],
}))
.context("create_picture")?;
xcb::xproto::free_pixmap(conn.conn(), pixmap);
conn.send_request(&xcb::x::FreePixmap { pixmap });
let cursor_id: xcb::ffi::xcb_cursor_t = conn.generate_id();
xcb::render::create_cursor_checked(
conn.conn(),
cursor_id,
pic,
xhot.try_into()?,
yhot.try_into()?,
)
.request_check()
let cursor_id: Cursor = conn.generate_id();
conn.check_request(conn.send_request_checked(&xcb::render::CreateCursor {
cid: cursor_id,
source: pic,
x: xhot.try_into()?,
y: yhot.try_into()?,
}))
.context("create_cursor")?;
xcb::render::free_picture(conn.conn(), pic);
unsafe {
xcb_util::ffi::image::xcb_image_destroy(image);
}
conn.send_request(&xcb::render::FreePicture { picture: pic });
Ok(cursor_id)
}

View File

@ -165,28 +165,9 @@ impl Keyboard {
}
pub fn new(connection: &xcb::Connection) -> anyhow::Result<(Keyboard, u8)> {
connection.prefetch_extension_data(xcb::xkb::id());
let first_ev = connection
.get_extension_data(xcb::xkb::id())
.map(|r| r.first_event())
.ok_or_else(|| anyhow!("could not get xkb extension data"))?;
{
let cookie = xcb::xkb::use_extension(
&connection,
xkb::x11::MIN_MAJOR_XKB_VERSION,
xkb::x11::MIN_MINOR_XKB_VERSION,
);
let r = cookie.get_reply()?;
ensure!(
r.supported(),
"required xcb-xkb-{}-{} is not supported",
xkb::x11::MIN_MAJOR_XKB_VERSION,
xkb::x11::MIN_MINOR_XKB_VERSION
);
}
let first_ev = xcb::xkb::get_extension_data(connection)
.ok_or_else(|| anyhow!("could not get xkb extension data"))?
.first_event;
let context = xkb::Context::new(xkb::CONTEXT_NO_FLAGS);
let device_id = xkb::x11::get_core_keyboard_device_id(&connection);
@ -212,31 +193,28 @@ impl Keyboard {
let compose_state = xkb::compose::State::new(&table, xkb::compose::STATE_NO_FLAGS);
{
let map_parts = xcb::xkb::MAP_PART_KEY_TYPES
| xcb::xkb::MAP_PART_KEY_SYMS
| xcb::xkb::MAP_PART_MODIFIER_MAP
| xcb::xkb::MAP_PART_EXPLICIT_COMPONENTS
| xcb::xkb::MAP_PART_KEY_ACTIONS
| xcb::xkb::MAP_PART_KEY_BEHAVIORS
| xcb::xkb::MAP_PART_VIRTUAL_MODS
| xcb::xkb::MAP_PART_VIRTUAL_MOD_MAP;
let map_parts = xcb::xkb::MapPart::KEY_TYPES
| xcb::xkb::MapPart::KEY_SYMS
| xcb::xkb::MapPart::MODIFIER_MAP
| xcb::xkb::MapPart::EXPLICIT_COMPONENTS
| xcb::xkb::MapPart::KEY_ACTIONS
| xcb::xkb::MapPart::KEY_BEHAVIORS
| xcb::xkb::MapPart::VIRTUAL_MODS
| xcb::xkb::MapPart::VIRTUAL_MOD_MAP;
let events = xcb::xkb::EVENT_TYPE_NEW_KEYBOARD_NOTIFY
| xcb::xkb::EVENT_TYPE_MAP_NOTIFY
| xcb::xkb::EVENT_TYPE_STATE_NOTIFY;
let events = xcb::xkb::EventType::NEW_KEYBOARD_NOTIFY
| xcb::xkb::EventType::MAP_NOTIFY
| xcb::xkb::EventType::STATE_NOTIFY;
let cookie = xcb::xkb::select_events_checked(
&connection,
device_id as u16,
events as u16,
0,
events as u16,
map_parts as u16,
map_parts as u16,
None,
);
cookie.request_check()?;
connection.check_request(connection.send_request_checked(&xcb::xkb::SelectEvents {
device_spec: device_id as u16,
affect_which: events,
clear: xcb::xkb::EventType::empty(),
select_all: events,
affect_map: map_parts,
map: map_parts,
details: &[],
}))?;
}
let phys_code_map = build_physkeycode_map(&keymap);
@ -269,11 +247,22 @@ impl Keyboard {
self.process_key_event_impl(code + 8, pressed, events, want_repeat)
}
pub fn process_key_event(&self, xcb_ev: &xcb::KeyPressEvent, events: &mut WindowEventSender) {
let pressed = (xcb_ev.response_type() & !0x80) == xcb::KEY_PRESS;
pub fn process_key_press_event(
&self,
xcb_ev: &xcb::x::KeyPressEvent,
events: &mut WindowEventSender,
) {
let xcode = xkb::Keycode::from(xcb_ev.detail());
self.process_key_event_impl(xcode, pressed, events, false);
self.process_key_event_impl(xcode, true, events, false);
}
pub fn process_key_release_event(
&self,
xcb_ev: &xcb::x::KeyReleaseEvent,
events: &mut WindowEventSender,
) {
let xcode = xkb::Keycode::from(xcb_ev.detail());
self.process_key_event_impl(xcode, false, events, false);
}
fn process_key_event_impl(
@ -427,20 +416,18 @@ impl Keyboard {
pub fn process_xkb_event(
&self,
connection: &xcb::Connection,
event: &xcb::GenericEvent,
event: &xcb::Event,
) -> anyhow::Result<()> {
let xkb_ev: &XkbGenericEvent = unsafe { xcb::cast_event(&event) };
if xkb_ev.device_id() == self.get_device_id() as u8 {
match xkb_ev.xkb_type() {
xcb::xkb::STATE_NOTIFY => {
self.update_state(unsafe { xcb::cast_event(&event) });
}
xcb::xkb::MAP_NOTIFY | xcb::xkb::NEW_KEYBOARD_NOTIFY => {
self.update_keymap(connection)?;
}
_ => {}
match event {
xcb::Event::Xkb(xcb::xkb::Event::StateNotify(e)) => {
self.update_state(e);
}
xcb::Event::Xkb(
xcb::xkb::Event::MapNotify(_) | xcb::xkb::Event::NewKeyboardNotify(_),
) => {
self.update_keymap(connection)?;
}
_ => {}
}
Ok(())
}
@ -464,12 +451,12 @@ impl Keyboard {
pub fn update_state(&self, ev: &xcb::xkb::StateNotifyEvent) {
self.state.borrow_mut().update_mask(
xkb::ModMask::from(ev.base_mods()),
xkb::ModMask::from(ev.latched_mods()),
xkb::ModMask::from(ev.locked_mods()),
xkb::ModMask::from(ev.base_mods().bits()),
xkb::ModMask::from(ev.latched_mods().bits()),
xkb::ModMask::from(ev.locked_mods().bits()),
ev.base_group() as xkb::LayoutIndex,
ev.latched_group() as xkb::LayoutIndex,
xkb::LayoutIndex::from(ev.locked_group()),
xkb::LayoutIndex::from(ev.locked_group() as u32),
);
}
@ -506,31 +493,6 @@ fn query_lc_ctype() -> anyhow::Result<&'static CStr> {
unsafe { Ok(CStr::from_ptr(ptr)) }
}
/// struct that has fields common to the 3 different xkb events
/// (StateNotify, NewKeyboardNotify, MapNotify)
#[repr(C)]
struct xcb_xkb_generic_event_t {
response_type: u8,
xkb_type: u8,
sequence: u16,
time: xcb::Timestamp,
device_id: u8,
}
struct XkbGenericEvent {
base: xcb::Event<xcb_xkb_generic_event_t>,
}
impl XkbGenericEvent {
pub fn xkb_type(&self) -> u8 {
unsafe { (*self.base.ptr).xkb_type }
}
pub fn device_id(&self) -> u8 {
unsafe { (*self.base.ptr).device_id }
}
}
fn build_physkeycode_map(keymap: &xkb::Keymap) -> HashMap<xkb::Keycode, PhysKeyCode> {
let mut map = HashMap::new();

View File

@ -3,6 +3,7 @@ pub mod connection;
pub mod cursor;
pub mod keyboard;
pub mod window;
pub mod xcb_util;
pub mod xrm;
pub mod xsettings;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,136 @@
#![allow(non_camel_case_types)]
use libc::c_void;
use xcb::ffi::*;
pub type xcb_image_format_t = u32;
pub type xcb_drawable_t = u32;
pub type xcb_gcontext_t = u32;
pub type xcb_void_cookie_t = u64;
pub type xcb_image_t = ();
pub struct XcbImage(*mut xcb_image_t);
impl Drop for XcbImage {
fn drop(&mut self) {
unsafe {
xcb_image_destroy(self.0);
}
}
}
impl XcbImage {
pub fn create_native(
c: &xcb::Connection,
width: u16,
height: u16,
format: xcb_image_format_t,
depth: u8,
base: *mut c_void,
bytes: u32,
data: *mut u8,
) -> anyhow::Result<Self> {
let image = unsafe {
xcb_image_create_native(
c.get_raw_conn(),
width,
height,
format,
depth,
base,
bytes,
data,
)
};
if image.is_null() {
anyhow::bail!("failed to create native image");
} else {
Ok(Self(image))
}
}
pub fn put(
&self,
conn: &xcb::Connection,
draw: xcb_drawable_t,
gc: xcb_gcontext_t,
x: i16,
y: i16,
left_pad: u8,
) -> xcb_void_cookie_t {
unsafe { xcb_image_put(conn.get_raw_conn(), draw, gc, self.0, x, y, left_pad) }
}
}
#[link(name = "xcb-image")]
extern "C" {
pub fn xcb_image_create_native(
c: *mut xcb_connection_t,
width: u16,
height: u16,
format: xcb_image_format_t,
depth: u8,
base: *mut c_void,
bytes: u32,
data: *mut u8,
) -> *mut xcb_image_t;
pub fn xcb_image_destroy(image: *mut xcb_image_t);
pub fn xcb_image_put(
conn: *mut xcb_connection_t,
draw: xcb_drawable_t,
gc: xcb_gcontext_t,
image: *const xcb_image_t,
x: i16,
y: i16,
left_pad: u8,
) -> xcb_void_cookie_t;
}
pub const XCB_ICCCM_SIZE_HINT_US_SIZE: u32 = 1 << 1;
pub const XCB_ICCCM_SIZE_HINT_P_POSITION: u32 = 1 << 2;
pub const XCB_ICCCM_SIZE_HINT_P_SIZE: u32 = 1 << 3;
pub const XCB_ICCCM_SIZE_HINT_P_MIN_SIZE: u32 = 1 << 4;
pub const XCB_ICCCM_SIZE_HINT_P_MAX_SIZE: u32 = 1 << 5;
pub const XCB_ICCCM_SIZE_HINT_P_RESIZE_INC: u32 = 1 << 6;
pub const XCB_ICCCM_SIZE_HINT_P_ASPECT: u32 = 1 << 7;
pub const XCB_ICCCM_SIZE_HINT_BASE_SIZE: u32 = 1 << 8;
pub const XCB_ICCCM_SIZE_HINT_P_WIN_GRAVITY: u32 = 1 << 9;
#[repr(C)]
pub struct xcb_size_hints_t {
pub flags: u32,
pub x: i32,
pub y: i32,
pub width: i32,
pub height: i32,
pub min_width: i32,
pub min_height: i32,
pub max_width: i32,
pub max_height: i32,
pub width_inc: i32,
pub height_inc: i32,
pub min_aspect_num: i32,
pub min_aspect_den: i32,
pub max_aspect_num: i32,
pub max_aspect_den: i32,
pub base_width: i32,
pub base_height: i32,
pub win_gravity: u32,
}
pub const MOVE_RESIZE_WINDOW_X: u32 = 1 << 8;
pub const MOVE_RESIZE_WINDOW_Y: u32 = 1 << 9;
pub const MOVE_RESIZE_WINDOW_WIDTH: u32 = 1 << 10;
pub const MOVE_RESIZE_WINDOW_HEIGHT: u32 = 1 << 11;
pub const MOVE_RESIZE_SIZE_TOPLEFT: u32 = 0;
pub const MOVE_RESIZE_SIZE_TOP: u32 = 1;
pub const MOVE_RESIZE_SIZE_TOPRIGHT: u32 = 2;
pub const MOVE_RESIZE_SIZE_RIGHT: u32 = 3;
pub const MOVE_RESIZE_SIZE_BOTTOMRIGHT: u32 = 4;
pub const MOVE_RESIZE_SIZE_BOTTOM: u32 = 5;
pub const MOVE_RESIZE_SIZE_BOTTOMLEFT: u32 = 6;
pub const MOVE_RESIZE_SIZE_LEFT: u32 = 7;
pub const MOVE_RESIZE_MOVE: u32 = 8;
pub const MOVE_RESIZE_SIZE_KEYBOARD: u32 = 9;
pub const MOVE_RESIZE_MOVE_KEYBOARD: u32 = 10;
pub const MOVE_RESIZE_CANCEL: u32 = 11;

View File

@ -1,3 +1,4 @@
use anyhow::Context;
use std::collections::HashMap;
/// Parses:
@ -5,18 +6,18 @@ use std::collections::HashMap;
/// RESOURCE_MANAGER(STRING) = "Xft.dpi:\t96\nXft.hinting:\t1\nXft.hintstyle:\thintslight\nXft.antialias:\t1\nXft.rgba:\tnone\nXcursor.size:\t24\nXcursor.theme:\tAdwaita\n"
pub fn parse_root_resource_manager(
conn: &xcb::Connection,
root: xcb::xproto::Window,
root: xcb::x::Window,
) -> anyhow::Result<HashMap<String, String>> {
let reply = xcb::xproto::get_property(
conn,
false,
root,
xcb::ffi::XCB_ATOM_RESOURCE_MANAGER,
xcb::xproto::ATOM_STRING,
0,
1024 * 1024,
)
.get_reply()?;
let reply = conn
.wait_for_reply(conn.send_request(&xcb::x::GetProperty {
delete: false,
window: root,
property: xcb::x::ATOM_RESOURCE_MANAGER,
r#type: xcb::x::ATOM_STRING,
long_offset: 0,
long_length: 1024 * 1024,
}))
.context("GetProperty ATOM_RESOURCE_MANAGER")?;
let text = String::from_utf8_lossy(reply.value::<u8>());
let mut map = HashMap::new();

View File

@ -7,6 +7,7 @@ use anyhow::Context;
/// but otherwise it seems to parse the data from my 2021 gnome window environment.
use bytes::Buf;
use std::collections::BTreeMap;
use xcb::x::Atom;
pub type XSettingsMap = BTreeMap<String, XSetting>;
@ -19,41 +20,38 @@ pub enum XSetting {
fn read_xsettings_grabbed(
conn: &xcb::Connection,
atom_xsettings_selection: xcb::Atom,
atom_xsettings_settings: xcb::Atom,
atom_xsettings_selection: Atom,
atom_xsettings_settings: Atom,
) -> anyhow::Result<XSettingsMap> {
let manager = xcb::get_selection_owner(&conn, atom_xsettings_selection)
.get_reply()?
let manager = conn
.wait_for_reply(conn.send_request(&xcb::x::GetSelectionOwner {
selection: atom_xsettings_selection,
}))?
.owner();
let reply = xcb::xproto::get_property(
&conn,
false,
manager,
atom_xsettings_settings,
atom_xsettings_settings,
0,
u32::max_value(),
)
.get_reply()
.context("get_property")?;
anyhow::ensure!(reply.format() == 8);
let reply = conn
.wait_for_reply(conn.send_request(&xcb::x::GetProperty {
delete: false,
window: manager,
property: atom_xsettings_settings,
r#type: atom_xsettings_settings,
long_offset: 0,
long_length: u32::max_value(),
}))
.context("get_property")?;
parse_xsettings(reply.value::<u8>())
}
pub fn read_xsettings(
conn: &xcb::Connection,
atom_xsettings_selection: xcb::Atom,
atom_xsettings_settings: xcb::Atom,
atom_xsettings_selection: Atom,
atom_xsettings_settings: Atom,
) -> anyhow::Result<XSettingsMap> {
xcb::xproto::grab_server(conn)
.request_check()
conn.check_request(conn.send_request_checked(&xcb::x::GrabServer {}))
.context("grab_server")?;
let res = read_xsettings_grabbed(conn, atom_xsettings_selection, atom_xsettings_settings);
xcb::xproto::ungrab_server(conn)
.request_check()
conn.check_request(conn.send_request_checked(&xcb::x::UngrabServer {}))
.context("ungrab_server")?;
res
}

View File

@ -316,8 +316,10 @@ impl WindowOps for Window {
}
fn set_text_cursor_position(&self, cursor: Rect) {
if let Self::X11(x) = self {
x.set_text_cursor_position(cursor);
match self {
Self::X11(x) => x.set_text_cursor_position(cursor),
#[cfg(feature = "wayland")]
Self::Wayland(_) => {}
}
}

View File

@ -2,22 +2,19 @@
use crate::{KeyCode, Modifiers};
pub fn modifiers_from_state(state: u16) -> Modifiers {
use xcb::xproto::*;
pub fn modifiers_from_state(state: u32) -> Modifiers {
let mut mods = Modifiers::default();
let state = u32::from(state);
if state & MOD_MASK_SHIFT != 0 {
if (state & xcb::x::ModMask::SHIFT.bits()) != 0 {
mods |= Modifiers::SHIFT;
}
if state & MOD_MASK_CONTROL != 0 {
if (state & xcb::x::ModMask::CONTROL.bits()) != 0 {
mods |= Modifiers::CTRL;
}
if state & MOD_MASK_1 != 0 {
if (state & xcb::x::ModMask::N1.bits()) != 0 {
mods |= Modifiers::ALT;
}
if state & MOD_MASK_4 != 0 {
if (state & xcb::x::ModMask::N4.bits()) != 0 {
mods |= Modifiers::SUPER;
}