Skip to content

Commit

Permalink
Start working on a safe X11 module (#55)
Browse files Browse the repository at this point in the history
I had this idea when trying `slice::from_raw_parts` for debugging this part of
the code the other day. If I could encapsulate all of the unsafe code in this
`x` module, then rwm proper could use only safe code. One day this could even be
a separate crate for other window managers to use.
  • Loading branch information
ntBre authored Feb 24, 2025
1 parent 232c264 commit 008b52b
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 10 deletions.
13 changes: 3 additions & 10 deletions src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::xembed::{
XEMBED_WINDOW_DEACTIVATE,
};
use crate::{
drw, handlers, Arg, Client, Layout, Monitor, Pertag, State, Systray,
drw, handlers, x, Arg, Client, Layout, Monitor, Pertag, State, Systray,
Window, ICONIC_STATE, NORMAL_STATE, WITHDRAWN_STATE,
};
use libc::{c_long, c_uchar, pid_t, sigaction};
Expand Down Expand Up @@ -512,22 +512,15 @@ pub fn sendevent(
d4: c_long,
) -> c_int {
log::trace!("sendevent");
let mut n = 0;
let mut protocols = std::ptr::null_mut();
let mt;
let mut exists = 0;
unsafe {
if proto == state.wmatom[WM::TakeFocus as usize]
|| proto == state.wmatom[WM::Delete as usize]
{
mt = state.wmatom[WM::Protocols as usize];
if xlib::XGetWMProtocols(state.dpy, w, &mut protocols, &mut n) != 0
{
while exists == 0 && n > 0 {
n -= 1;
exists = (*protocols.offset(n as isize) == proto) as c_int;
}
XFree(protocols.cast());
if let Ok(protocols) = x::get_wm_protocols(state.dpy, w) {
exists = protocols.iter().rev().any(|p| *p == proto) as c_int;
}
} else {
exists = 1;
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub mod handlers;
pub mod key_handlers;
pub mod layouts;
pub mod util;
pub mod x;
pub mod xembed;

pub use core::*;
Expand Down
52 changes: 52 additions & 0 deletions src/x.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//! Safe bindings to X11 functions
use std::os::raw::c_int;

use x11::xlib::{self, Atom, Display, XFree};

use crate::Window;

pub struct WmProtocols<'a> {
atoms: *mut Atom,
slice: &'a [Atom],
}

impl WmProtocols<'_> {
pub fn iter(&self) -> impl DoubleEndedIterator<Item = &Atom> {
self.slice.iter()
}
}

impl Drop for WmProtocols<'_> {
fn drop(&mut self) {
unsafe {
XFree(self.atoms.cast());
}
}
}

/// Return the list of atoms stored in the `WM_PROTOCOLS` property on `w`.
///
/// See `XGetWMProtocols(3)` for more details.
pub fn get_wm_protocols<'a>(
display: *mut Display,
w: Window,
) -> Result<WmProtocols<'a>, c_int> {
let mut protocols = std::ptr::null_mut();
let mut n = 0;
unsafe {
let status = xlib::XGetWMProtocols(display, w, &mut protocols, &mut n);

if status == 0 {
return Err(status);
}

Ok(WmProtocols {
atoms: protocols,
slice: std::slice::from_raw_parts(
protocols,
usize::try_from(n).unwrap(),
),
})
}
}

0 comments on commit 008b52b

Please sign in to comment.