Commit b70afbe9 authored by Dorota Czaplejewicz's avatar Dorota Czaplejewicz
Browse files

keystate: Wrap in refconuter

parent 996f681e
......@@ -7,9 +7,16 @@ pub mod c {
use super::*;
use ::util::c::{ as_cstr, into_cstring };
use std::cell::RefCell;
use std::ffi::CString;
use std::os::raw::c_char;
use std::ptr;
use std::rc::Rc;
// traits
use std::borrow::ToOwned;
// The following defined in C
#[no_mangle]
......@@ -17,6 +24,33 @@ pub mod c {
fn eek_keysym_from_name(name: *const c_char) -> u32;
}
/// The wrapped structure for KeyState suitable for handling in C
/// Since C doesn't respect borrowing rules,
/// RefCell will enforce them dynamically (only 1 writer/many readers)
/// Rc is implied and will ensure timely dropping
pub struct CKeyState(*const RefCell<KeyState>);
impl CKeyState {
fn unwrap(self) -> Rc<RefCell<KeyState>> {
unsafe { Rc::from_raw(self.0) }
}
fn to_owned(self) -> KeyState {
let rc = self.unwrap();
let state = rc.borrow().to_owned();
Rc::into_raw(rc); // Prevent dropping
state
}
fn borrow_mut<F, T>(self, f: F) -> T where F: FnOnce(&mut KeyState) -> T {
let rc = self.unwrap();
let ret = {
let mut state = rc.borrow_mut();
f(&mut state)
};
Rc::into_raw(rc); // Prevent dropping
ret
}
}
// TODO: unwrapping
// The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
......@@ -24,63 +58,59 @@ pub mod c {
// so it should handle garbled strings in the future
#[no_mangle]
pub extern "C"
fn squeek_key_new(keycode: u32) -> *mut KeyState {
Box::into_raw(Box::new(
fn squeek_key_new(keycode: u32) -> CKeyState {
let state: Rc<RefCell<KeyState>> = Rc::new(RefCell::new(
KeyState {
pressed: false,
locked: false,
keycode: keycode,
symbol: None,
}
))
));
CKeyState(Rc::into_raw(state))
}
#[no_mangle]
pub extern "C"
fn squeek_key_free(key: *mut KeyState) {
unsafe { Box::from_raw(key) }; // gets dropped
fn squeek_key_free(key: CKeyState) {
key.unwrap(); // reference dropped
}
#[no_mangle]
pub extern "C"
fn squeek_key_is_pressed(key: *const KeyState) -> u32 {
let key = unsafe { &*key };
return key.pressed as u32;
fn squeek_key_is_pressed(key: CKeyState) -> u32 {
//let key = unsafe { Rc::from_raw(key.0) };
return key.to_owned().pressed as u32;
}
#[no_mangle]
pub extern "C"
fn squeek_key_set_pressed(key: *mut KeyState, pressed: u32) {
let key = unsafe { &mut *key };
key.pressed = pressed != 0;
fn squeek_key_set_pressed(key: CKeyState, pressed: u32) {
key.borrow_mut(|key| key.pressed = pressed != 0);
}
#[no_mangle]
pub extern "C"
fn squeek_key_is_locked(key: *const KeyState) -> u32 {
let key = unsafe { &*key };
return key.locked as u32;
fn squeek_key_is_locked(key: CKeyState) -> u32 {
return key.to_owned().locked as u32;
}
#[no_mangle]
pub extern "C"
fn squeek_key_set_locked(key: *mut KeyState, locked: u32) {
let key = unsafe { &mut *key };
key.locked = locked != 0;
fn squeek_key_set_locked(key: CKeyState, locked: u32) {
key.borrow_mut(|key| key.locked = locked != 0);
}
#[no_mangle]
pub extern "C"
fn squeek_key_get_keycode(key: *const KeyState) -> u32 {
let key = unsafe { &*key };
return key.keycode as u32;
fn squeek_key_get_keycode(key: CKeyState) -> u32 {
return key.to_owned().keycode as u32;
}
#[no_mangle]
pub extern "C"
fn squeek_key_set_keycode(key: *mut KeyState, code: u32) {
let key = unsafe { &mut *key };
key.keycode = code;
fn squeek_key_set_keycode(key: CKeyState, code: u32) {
key.borrow_mut(|key| key.keycode = code);
}
// TODO: this will receive data from the filesystem,
......@@ -88,7 +118,7 @@ pub mod c {
#[no_mangle]
pub extern "C"
fn squeek_key_add_symbol(
key: *mut KeyState,
key: CKeyState,
element: *const c_char,
text_raw: *const c_char, keyval: u32,
label: *const c_char, icon: *const c_char,
......@@ -110,14 +140,6 @@ pub mod c {
}
});
let key = unsafe { &mut *key };
if let Some(_) = key.symbol {
eprintln!("Key {:?} already has a symbol defined", text);
return;
}
let icon = into_cstring(icon)
.unwrap_or_else(|e| {
eprintln!("Icon name unreadable: {}", e);
......@@ -147,42 +169,52 @@ pub mod c {
None
});
key.symbol = Some(match element.to_bytes() {
b"symbol" => Symbol {
action: Action::Submit {
text: text,
keys: Vec::new(),
key.borrow_mut(|key| {
if let Some(_) = key.symbol {
eprintln!("Key {:?} already has a symbol defined", text);
return;
}
key.symbol = Some(match element.to_bytes() {
b"symbol" => Symbol {
action: Action::Submit {
text: text,
keys: Vec::new(),
},
label: label,
tooltip: tooltip,
},
label: label,
tooltip: tooltip,
},
_ => panic!("unsupported element type {:?}", element),
_ => panic!("unsupported element type {:?}", element),
});
});
}
#[no_mangle]
pub extern "C"
fn squeek_key_get_symbol(key: *const KeyState) -> *const symbol::Symbol {
let key = unsafe { &*key };
match key.symbol {
Some(ref symbol) => symbol as *const symbol::Symbol,
None => ptr::null(),
}
fn squeek_key_get_symbol(key: CKeyState) -> *const symbol::Symbol {
key.borrow_mut(|key| {
match key.symbol {
/// This pointer stays after the function exits,
/// so it must reference borrowed data and not any copy
Some(ref symbol) => symbol as *const symbol::Symbol,
None => ptr::null(),
}
})
}
#[no_mangle]
pub extern "C"
fn squeek_key_to_keymap_entry(
key_name: *const c_char,
key: *const KeyState,
key: CKeyState,
) -> *const c_char {
let key_name = as_cstr(&key_name)
.expect("Missing key name")
.to_str()
.expect("Bad key name");
let key = unsafe { &*key };
let symbol_name = match key.symbol {
let symbol_name = match key.to_owned().symbol {
Some(ref symbol) => match &symbol.action {
symbol::Action::Submit { text: Some(text), .. } => {
Some(
......@@ -209,7 +241,7 @@ pub mod c {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct KeyState {
pressed: bool,
locked: bool,
......
......@@ -74,7 +74,7 @@ pub mod c {
}
/// Just defines some int->identifier mappings for convenience
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum KeySym {
Unknown = 0,
Shift = 0xffe1,
......@@ -89,10 +89,10 @@ impl KeySym {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct XKeySym(pub u32);
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum Label {
/// Text used to display the symbol
Text(CString),
......@@ -104,14 +104,14 @@ pub enum Label {
type Level = u8;
/// Use to send modified keypresses
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum Modifier {
Control,
Alt,
}
/// Action to perform on the keypress and, in reverse, on keyrelease
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum Action {
/// Switch to this level TODO: reverse?
SetLevel(Level),
......@@ -127,7 +127,7 @@ pub enum Action {
}
/// Contains a static description of a particular key's actions
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Symbol {
/// The action that this key performs
pub action: Action,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment