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:
parent
b25d4d22ee
commit
abc42f7bcb
42
Cargo.lock
generated
42
Cargo.lock
generated
@ -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]]
|
||||
|
@ -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"
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
136
window/src/os/x11/xcb_util.rs
Normal file
136
window/src/os/x11/xcb_util.rs
Normal 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;
|
@ -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();
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user