X11: util design improvements (#534)

This commit is contained in:
Francesca Frangipane 2018-05-27 08:49:35 -04:00 committed by GitHub
parent 282770f11a
commit 30f798b246
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 992 additions and 1073 deletions

View file

@ -1,44 +1,12 @@
use std::str;
use super::*;
use events::ModifiersState;
pub unsafe fn select_xinput_events(
xconn: &Arc<XConnection>,
window: c_ulong,
device_id: c_int,
mask: i32,
) -> Flusher {
let mut event_mask = ffi::XIEventMask {
deviceid: device_id,
mask: &mask as *const _ as *mut c_uchar,
mask_len: mem::size_of_val(&mask) as c_int,
};
(xconn.xinput2.XISelectEvents)(
xconn.display,
window,
&mut event_mask as *mut ffi::XIEventMask,
1, // number of masks to read from pointer above
);
Flusher::new(xconn)
}
#[allow(dead_code)]
pub unsafe fn select_xkb_events(
xconn: &Arc<XConnection>,
device_id: c_uint,
mask: c_ulong,
) -> Option<Flusher> {
let status = (xconn.xlib.XkbSelectEvents)(
xconn.display,
device_id,
mask,
mask,
);
if status == ffi::True {
Some(Flusher::new(xconn))
} else {
None
}
}
// A base buffer size of 1kB uses a negligible amount of RAM while preventing us from having to
// re-allocate (and make another round-trip) in the *vast* majority of cases.
// To test if `lookup_utf8` works correctly, set this to 1.
const TEXT_BUFFER_SIZE: usize = 1024;
impl From<ffi::XIModifierState> for ModifiersState {
fn from(mods: ffi::XIModifierState) -> Self {
@ -53,17 +21,17 @@ impl From<ffi::XIModifierState> for ModifiersState {
}
pub struct PointerState<'a> {
xconn: &'a Arc<XConnection>,
_root: ffi::Window,
_child: ffi::Window,
_root_x: c_double,
_root_y: c_double,
_win_x: c_double,
_win_y: c_double,
_buttons: ffi::XIButtonState,
xconn: &'a XConnection,
root: ffi::Window,
child: ffi::Window,
root_x: c_double,
root_y: c_double,
win_x: c_double,
win_y: c_double,
buttons: ffi::XIButtonState,
modifiers: ffi::XIModifierState,
_group: ffi::XIGroupState,
_relative_to_window: bool,
group: ffi::XIGroupState,
relative_to_window: bool,
}
impl<'a> PointerState<'a> {
@ -74,114 +42,115 @@ impl<'a> PointerState<'a> {
impl<'a> Drop for PointerState<'a> {
fn drop(&mut self) {
unsafe {
// This is why you need to read the docs carefully...
(self.xconn.xlib.XFree)(self._buttons.mask as _);
if !self.buttons.mask.is_null() {
unsafe {
// This is why you need to read the docs carefully...
(self.xconn.xlib.XFree)(self.buttons.mask as _);
}
}
}
}
pub unsafe fn query_pointer(
xconn: &Arc<XConnection>,
window: ffi::Window,
device_id: c_int,
) -> Result<PointerState, XError> {
let mut root_return = mem::uninitialized();
let mut child_return = mem::uninitialized();
let mut root_x_return = mem::uninitialized();
let mut root_y_return = mem::uninitialized();
let mut win_x_return = mem::uninitialized();
let mut win_y_return = mem::uninitialized();
let mut buttons_return = mem::uninitialized();
let mut modifiers_return = mem::uninitialized();
let mut group_return = mem::uninitialized();
impl XConnection {
pub fn select_xinput_events(&self, window: c_ulong, device_id: c_int, mask: i32) -> Flusher {
let mut event_mask = ffi::XIEventMask {
deviceid: device_id,
mask: &mask as *const _ as *mut c_uchar,
mask_len: mem::size_of_val(&mask) as c_int,
};
unsafe {
(self.xinput2.XISelectEvents)(
self.display,
window,
&mut event_mask as *mut ffi::XIEventMask,
1, // number of masks to read from pointer above
);
}
Flusher::new(self)
}
let relative_to_window = (xconn.xinput2.XIQueryPointer)(
xconn.display,
device_id,
window,
&mut root_return,
&mut child_return,
&mut root_x_return,
&mut root_y_return,
&mut win_x_return,
&mut win_y_return,
&mut buttons_return,
&mut modifiers_return,
&mut group_return,
) == ffi::True;
#[allow(dead_code)]
pub fn select_xkb_events(&self, device_id: c_uint, mask: c_ulong) -> Option<Flusher> {
let status = unsafe {
(self.xlib.XkbSelectEvents)(
self.display,
device_id,
mask,
mask,
)
};
if status == ffi::True {
Some(Flusher::new(self))
} else {
None
}
}
xconn.check_errors()?;
pub fn query_pointer(&self, window: ffi::Window, device_id: c_int) -> Result<PointerState, XError> {
unsafe {
let mut pointer_state: PointerState = mem::uninitialized();
pointer_state.xconn = self;
pointer_state.relative_to_window = (self.xinput2.XIQueryPointer)(
self.display,
device_id,
window,
&mut pointer_state.root,
&mut pointer_state.child,
&mut pointer_state.root_x,
&mut pointer_state.root_y,
&mut pointer_state.win_x,
&mut pointer_state.win_y,
&mut pointer_state.buttons,
&mut pointer_state.modifiers,
&mut pointer_state.group,
) == ffi::True;
if let Err(err) = self.check_errors() {
// Running the destrutor would be bad news for us...
mem::forget(pointer_state);
Err(err)
} else {
Ok(pointer_state)
}
}
}
Ok(PointerState {
xconn,
_root: root_return,
_child: child_return,
_root_x: root_x_return,
_root_y: root_y_return,
_win_x: win_x_return,
_win_y: win_y_return,
_buttons: buttons_return,
modifiers: modifiers_return,
_group: group_return,
_relative_to_window: relative_to_window,
})
}
fn lookup_utf8_inner(
&self,
ic: ffi::XIC,
key_event: &mut ffi::XKeyEvent,
buffer: &mut [u8],
) -> (ffi::KeySym, ffi::Status, c_int) {
let mut keysym: ffi::KeySym = 0;
let mut status: ffi::Status = 0;
let count = unsafe {
(self.xlib.Xutf8LookupString)(
ic,
key_event,
buffer.as_mut_ptr() as *mut c_char,
buffer.len() as c_int,
&mut keysym,
&mut status,
)
};
(keysym, status, count)
}
unsafe fn lookup_utf8_inner(
xconn: &Arc<XConnection>,
ic: ffi::XIC,
key_event: &mut ffi::XKeyEvent,
buffer: &mut [u8],
) -> (ffi::KeySym, ffi::Status, c_int) {
let mut keysym: ffi::KeySym = 0;
let mut status: ffi::Status = 0;
let count = (xconn.xlib.Xutf8LookupString)(
ic,
key_event,
buffer.as_mut_ptr() as *mut c_char,
buffer.len() as c_int,
&mut keysym,
&mut status,
);
(keysym, status, count)
}
// A base buffer size of 1kB uses a negligible amount of RAM while preventing us from having to
// re-allocate (and make another round-trip) in the *vast* majority of cases.
// To test if lookup_utf8 works correctly, set this to 1.
const TEXT_BUFFER_SIZE: usize = 1024;
pub unsafe fn lookup_utf8(
xconn: &Arc<XConnection>,
ic: ffi::XIC,
key_event: &mut ffi::XKeyEvent,
) -> String {
let mut buffer: [u8; TEXT_BUFFER_SIZE] = mem::uninitialized();
let (_, status, count) = lookup_utf8_inner(
xconn,
ic,
key_event,
&mut buffer,
);
// The buffer overflowed, so we'll make a new one on the heap.
if status == ffi::XBufferOverflow {
let mut buffer = Vec::with_capacity(count as usize);
buffer.set_len(count as usize);
let (_, _, new_count) = lookup_utf8_inner(
xconn,
ic,
key_event,
&mut buffer,
);
debug_assert_eq!(count, new_count);
str::from_utf8(&buffer[..count as usize])
.unwrap_or("")
.to_string()
} else {
str::from_utf8(&buffer[..count as usize])
.unwrap_or("")
.to_string()
pub fn lookup_utf8(&self, ic: ffi::XIC, key_event: &mut ffi::XKeyEvent) -> String {
let mut buffer: [u8; TEXT_BUFFER_SIZE] = unsafe { mem::uninitialized() };
let (_, status, count) = self.lookup_utf8_inner(ic, key_event, &mut buffer);
// The buffer overflowed, so we'll make a new one on the heap.
if status == ffi::XBufferOverflow {
let mut buffer = Vec::with_capacity(count as usize);
unsafe { buffer.set_len(count as usize) };
let (_, _, new_count) = self.lookup_utf8_inner(ic, key_event, &mut buffer);
debug_assert_eq!(count, new_count);
str::from_utf8(&buffer[..count as usize])
.unwrap_or("")
.to_string()
} else {
str::from_utf8(&buffer[..count as usize])
.unwrap_or("")
.to_string()
}
}
}