eekkey: Moved state to KeyState
This commit is contained in:
		@ -31,6 +31,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "eek-section.h"
 | 
					#include "eek-section.h"
 | 
				
			||||||
#include "eek-keyboard.h"
 | 
					#include "eek-keyboard.h"
 | 
				
			||||||
 | 
					#include "src/keyboard.h"
 | 
				
			||||||
#include "src/symbol.h"
 | 
					#include "src/symbol.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "eek-key.h"
 | 
					#include "eek-key.h"
 | 
				
			||||||
@ -53,9 +54,8 @@ static guint signals[LAST_SIGNAL] = { 0, };
 | 
				
			|||||||
typedef struct _EekKeyPrivate
 | 
					typedef struct _EekKeyPrivate
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    guint keycode;
 | 
					    guint keycode;
 | 
				
			||||||
    struct squeek_symbols *symbols;
 | 
					 | 
				
			||||||
    gulong oref; // UI outline reference
 | 
					    gulong oref; // UI outline reference
 | 
				
			||||||
    gboolean is_pressed;
 | 
					    struct squeek_key *state;
 | 
				
			||||||
    gboolean is_locked;
 | 
					    gboolean is_locked;
 | 
				
			||||||
} EekKeyPrivate;
 | 
					} EekKeyPrivate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -89,7 +89,7 @@ eek_key_finalize (GObject *object)
 | 
				
			|||||||
    EekKey        *self = EEK_KEY (object);
 | 
					    EekKey        *self = EEK_KEY (object);
 | 
				
			||||||
    EekKeyPrivate *priv = eek_key_get_instance_private (self);
 | 
					    EekKeyPrivate *priv = eek_key_get_instance_private (self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    squeek_symbols_free (priv->symbols);
 | 
					    squeek_key_free (priv->state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    G_OBJECT_CLASS (eek_key_parent_class)->finalize (object);
 | 
					    G_OBJECT_CLASS (eek_key_parent_class)->finalize (object);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -211,7 +211,7 @@ static void
 | 
				
			|||||||
eek_key_init (EekKey *self)
 | 
					eek_key_init (EekKey *self)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    EekKeyPrivate *priv = eek_key_get_instance_private (self);
 | 
					    EekKeyPrivate *priv = eek_key_get_instance_private (self);
 | 
				
			||||||
    priv->symbols = squeek_symbols_new ();
 | 
					    priv->state = squeek_key_new (0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -253,23 +253,6 @@ eek_key_get_keycode (EekKey *key)
 | 
				
			|||||||
    return priv->keycode;
 | 
					    return priv->keycode;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * eek_key_get_symbol_matrix:
 | 
					 | 
				
			||||||
 * @key: an #EekKey
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Get the symbol matrix of @key.
 | 
					 | 
				
			||||||
 * Returns: (transfer none): #EekSymbolMatrix or %NULL
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
struct squeek_symbols *
 | 
					 | 
				
			||||||
eek_key_get_symbol_matrix (EekKey *key)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    g_return_val_if_fail (EEK_IS_KEY(key), NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    EekKeyPrivate *priv = eek_key_get_instance_private (key);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return priv->symbols;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * eek_key_get_symbol_at_index:
 | 
					 * eek_key_get_symbol_at_index:
 | 
				
			||||||
 * @key: an #EekKey
 | 
					 * @key: an #EekKey
 | 
				
			||||||
@ -286,8 +269,8 @@ eek_key_get_symbol_at_index (EekKey *key,
 | 
				
			|||||||
                             gint    group,
 | 
					                             gint    group,
 | 
				
			||||||
                             guint    level)
 | 
					                             guint    level)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    struct squeek_symbols *symbols = eek_key_get_symbol_matrix(key);
 | 
					    EekKeyPrivate *priv = eek_key_get_instance_private (key);
 | 
				
			||||||
    return squeek_symbols_get(symbols, level);
 | 
					    return squeek_key_get_symbol(priv->state, level);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -341,7 +324,7 @@ eek_key_is_pressed (EekKey *key)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    EekKeyPrivate *priv = eek_key_get_instance_private (key);
 | 
					    EekKeyPrivate *priv = eek_key_get_instance_private (key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return priv->is_pressed;
 | 
					    return (bool)squeek_key_is_pressed(priv->state);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -366,5 +349,10 @@ void eek_key_set_pressed(EekKey *key, gboolean value)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    EekKeyPrivate *priv = eek_key_get_instance_private (key);
 | 
					    EekKeyPrivate *priv = eek_key_get_instance_private (key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    priv->is_pressed = value;
 | 
					    squeek_key_set_pressed(priv->state, value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct squeek_key *eek_key_get_state(EekKey *key) {
 | 
				
			||||||
 | 
					    EekKeyPrivate *priv = eek_key_get_instance_private (key);
 | 
				
			||||||
 | 
					    return priv->state;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -58,8 +58,7 @@ GType            eek_key_get_type            (void) G_GNUC_CONST;
 | 
				
			|||||||
void             eek_key_set_keycode         (EekKey          *key,
 | 
					void             eek_key_set_keycode         (EekKey          *key,
 | 
				
			||||||
                                              guint            keycode);
 | 
					                                              guint            keycode);
 | 
				
			||||||
guint            eek_key_get_keycode         (EekKey          *key);
 | 
					guint            eek_key_get_keycode         (EekKey          *key);
 | 
				
			||||||
struct squeek_symbols *
 | 
					struct squeek_key *eek_key_get_state(EekKey *key);
 | 
				
			||||||
eek_key_get_symbol_matrix (EekKey *key);
 | 
					 | 
				
			||||||
struct squeek_symbol *eek_key_get_symbol_at_index (EekKey          *key,
 | 
					struct squeek_symbol *eek_key_get_symbol_at_index (EekKey          *key,
 | 
				
			||||||
                                              gint             group,
 | 
					                                              gint             group,
 | 
				
			||||||
                                              guint level);
 | 
					                                              guint level);
 | 
				
			||||||
 | 
				
			|||||||
@ -763,7 +763,7 @@ eek_keyboard_get_keymap(EekKeyboard *keyboard)
 | 
				
			|||||||
        // FIXME: free
 | 
					        // FIXME: free
 | 
				
			||||||
        const char *key_str = squeek_key_to_keymap_entry(
 | 
					        const char *key_str = squeek_key_to_keymap_entry(
 | 
				
			||||||
            (char*)key_name,
 | 
					            (char*)key_name,
 | 
				
			||||||
            eek_key_get_symbol_matrix(key)
 | 
					            eek_key_get_state(key)
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        current = symbols;
 | 
					        current = symbols;
 | 
				
			||||||
        symbols = g_strconcat(current, key_str, NULL);
 | 
					        symbols = g_strconcat(current, key_str, NULL);
 | 
				
			||||||
 | 
				
			|||||||
@ -86,10 +86,6 @@ static void render_key                         (EekRenderer *self,
 | 
				
			|||||||
                                                cairo_t     *cr,
 | 
					                                                cairo_t     *cr,
 | 
				
			||||||
                                                EekKey      *key, guint level,
 | 
					                                                EekKey      *key, guint level,
 | 
				
			||||||
                                                gboolean     active);
 | 
					                                                gboolean     active);
 | 
				
			||||||
static void on_symbol_index_changed            (EekKeyboard *keyboard,
 | 
					 | 
				
			||||||
                                                gint         group,
 | 
					 | 
				
			||||||
                                                gint         level,
 | 
					 | 
				
			||||||
                                                gpointer     user_data);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct _CreateKeyboardSurfaceCallbackData {
 | 
					struct _CreateKeyboardSurfaceCallbackData {
 | 
				
			||||||
    cairo_t *cr;
 | 
					    cairo_t *cr;
 | 
				
			||||||
@ -715,16 +711,6 @@ invalidate (EekRenderer *renderer)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
on_symbol_index_changed (EekKeyboard *keyboard,
 | 
					 | 
				
			||||||
                         gint         group,
 | 
					 | 
				
			||||||
                         gint         level,
 | 
					 | 
				
			||||||
                         gpointer     user_data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    EekRenderer *renderer = user_data;
 | 
					 | 
				
			||||||
    invalidate (renderer);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
EekRenderer *
 | 
					EekRenderer *
 | 
				
			||||||
eek_renderer_new (EekKeyboard  *keyboard,
 | 
					eek_renderer_new (EekKeyboard  *keyboard,
 | 
				
			||||||
                  PangoContext *pcontext,
 | 
					                  PangoContext *pcontext,
 | 
				
			||||||
 | 
				
			|||||||
@ -30,6 +30,7 @@
 | 
				
			|||||||
#include "eek-keyboard.h"
 | 
					#include "eek-keyboard.h"
 | 
				
			||||||
#include "eek-section.h"
 | 
					#include "eek-section.h"
 | 
				
			||||||
#include "eek-key.h"
 | 
					#include "eek-key.h"
 | 
				
			||||||
 | 
					#include "src/keyboard.h"
 | 
				
			||||||
#include "src/symbol.h"
 | 
					#include "src/symbol.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "squeekboard-resources.h"
 | 
					#include "squeekboard-resources.h"
 | 
				
			||||||
@ -748,8 +749,8 @@ symbols_end_element_callback (GMarkupParseContext *pcontext,
 | 
				
			|||||||
        g_strcmp0 (element_name, "keysym") == 0 ||
 | 
					        g_strcmp0 (element_name, "keysym") == 0 ||
 | 
				
			||||||
        g_strcmp0 (element_name, "text") == 0) {
 | 
					        g_strcmp0 (element_name, "text") == 0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        squeek_symbols_add(
 | 
					        squeek_key_add_symbol(
 | 
				
			||||||
            eek_key_get_symbol_matrix(data->key),
 | 
					            eek_key_get_state(data->key),
 | 
				
			||||||
            element_name,
 | 
					            element_name,
 | 
				
			||||||
            text,
 | 
					            text,
 | 
				
			||||||
            data->keyval,
 | 
					            data->keyval,
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										19
									
								
								src/keyboard.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/keyboard.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					#ifndef __KEYBOARD_H
 | 
				
			||||||
 | 
					#define __KYBOARD_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "stdbool.h"
 | 
				
			||||||
 | 
					#include "inttypes.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct squeek_key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct squeek_key *squeek_key_new(uint32_t keycode);
 | 
				
			||||||
 | 
					void squeek_key_free(struct squeek_key *key);
 | 
				
			||||||
 | 
					void squeek_key_add_symbol(struct squeek_key* key,
 | 
				
			||||||
 | 
					                           const char *element_name,
 | 
				
			||||||
 | 
					                           const char *text, uint32_t keyval,
 | 
				
			||||||
 | 
					                           const char *label, const char *icon,
 | 
				
			||||||
 | 
					                           const char *tooltip);
 | 
				
			||||||
 | 
					uint32_t squeek_key_is_pressed(struct squeek_key *key);
 | 
				
			||||||
 | 
					void squeek_key_set_pressed(struct squeek_key *key, uint32_t pressed);
 | 
				
			||||||
 | 
					struct squeek_symbol *squeek_key_get_symbol(struct squeek_key* key, uint32_t level);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										216
									
								
								src/keyboard.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								src/keyboard.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,216 @@
 | 
				
			|||||||
 | 
					use std::vec::Vec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use super::symbol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Gathers stuff defined in C or called by C
 | 
				
			||||||
 | 
					pub mod c {
 | 
				
			||||||
 | 
					    use super::*;
 | 
				
			||||||
 | 
					    use ::util::c::{ as_cstr, into_cstring };
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    use std::ffi::CString;
 | 
				
			||||||
 | 
					    use std::os::raw::c_char;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // The following defined in C
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    extern "C" {
 | 
				
			||||||
 | 
					        fn eek_keysym_from_name(name: *const c_char) -> u32;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // The following defined in Rust. TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // TODO: this will receive data from the filesystem,
 | 
				
			||||||
 | 
					    // 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(
 | 
				
			||||||
 | 
					            KeyState {
 | 
				
			||||||
 | 
					                pressed: false,
 | 
				
			||||||
 | 
					                keycode: keycode,
 | 
				
			||||||
 | 
					                symbols: Vec::new(),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        ))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    pub extern "C"
 | 
				
			||||||
 | 
					    fn squeek_key_free(key: *mut KeyState) {
 | 
				
			||||||
 | 
					        unsafe { Box::from_raw(key) }; // gets dropped
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    pub extern "C"
 | 
				
			||||||
 | 
					    fn squeek_key_is_pressed(key: *const KeyState) -> u32{
 | 
				
			||||||
 | 
					        let key = unsafe { &*key };
 | 
				
			||||||
 | 
					        return key.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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // TODO: this will receive data from the filesystem,
 | 
				
			||||||
 | 
					    // so it should handle garbled strings in the future
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    pub extern "C"
 | 
				
			||||||
 | 
					    fn squeek_key_add_symbol(
 | 
				
			||||||
 | 
					        key: *mut KeyState,
 | 
				
			||||||
 | 
					        element: *const c_char,
 | 
				
			||||||
 | 
					        text_raw: *const c_char, keyval: u32,
 | 
				
			||||||
 | 
					        label: *const c_char, icon: *const c_char,
 | 
				
			||||||
 | 
					        tooltip: *const c_char,
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        let element = as_cstr(&element)
 | 
				
			||||||
 | 
					            .expect("Missing element name");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let text = into_cstring(text_raw)
 | 
				
			||||||
 | 
					            .unwrap_or_else(|e| {
 | 
				
			||||||
 | 
					                eprintln!("Text unreadable: {}", e);
 | 
				
			||||||
 | 
					                None
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .and_then(|text| {
 | 
				
			||||||
 | 
					                if text.as_bytes() == b"" {
 | 
				
			||||||
 | 
					                    None
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    Some(text)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let icon = into_cstring(icon)
 | 
				
			||||||
 | 
					            .unwrap_or_else(|e| {
 | 
				
			||||||
 | 
					                eprintln!("Icon name unreadable: {}", e);
 | 
				
			||||||
 | 
					                None
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        use symbol::*;
 | 
				
			||||||
 | 
					        // Only read label if there's no icon
 | 
				
			||||||
 | 
					        let label = match icon {
 | 
				
			||||||
 | 
					            Some(icon) => Label::IconName(icon),
 | 
				
			||||||
 | 
					            None => Label::Text(
 | 
				
			||||||
 | 
					                into_cstring(label)
 | 
				
			||||||
 | 
					                    .unwrap_or_else(|e| {
 | 
				
			||||||
 | 
					                        eprintln!("Label unreadable: {}", e);
 | 
				
			||||||
 | 
					                        Some(CString::new(" ").unwrap())
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    .unwrap_or_else(|| {
 | 
				
			||||||
 | 
					                        eprintln!("Label missing");
 | 
				
			||||||
 | 
					                        CString::new(" ").unwrap()
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let tooltip = into_cstring(tooltip)
 | 
				
			||||||
 | 
					            .unwrap_or_else(|e| {
 | 
				
			||||||
 | 
					                eprintln!("Tooltip unreadable: {}", e);
 | 
				
			||||||
 | 
					                None
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        let symbol = match element.to_bytes() {
 | 
				
			||||||
 | 
					            b"symbol" => Symbol {
 | 
				
			||||||
 | 
					                action: Action::Submit {
 | 
				
			||||||
 | 
					                    text: text,
 | 
				
			||||||
 | 
					                    keys: Vec::new(),
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                label: label,
 | 
				
			||||||
 | 
					                tooltip: tooltip,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            b"keysym" => {
 | 
				
			||||||
 | 
					                let keysym = XKeySym(
 | 
				
			||||||
 | 
					                    if keyval == 0 {
 | 
				
			||||||
 | 
					                        unsafe { eek_keysym_from_name(text_raw) }
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        keyval
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                Symbol {
 | 
				
			||||||
 | 
					                    action: match KeySym::from_u32(keysym.0) {
 | 
				
			||||||
 | 
					                        KeySym::Shift => Action::SetLevel(1),
 | 
				
			||||||
 | 
					                        _ => Action::Submit {
 | 
				
			||||||
 | 
					                            text: text,
 | 
				
			||||||
 | 
					                            keys: vec![keysym],
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    label: label,
 | 
				
			||||||
 | 
					                    tooltip: tooltip,
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            _ => panic!("unsupported element type {:?}", element),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        let key = unsafe { &mut *key };
 | 
				
			||||||
 | 
					        key.symbols.push(symbol);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    pub extern "C"
 | 
				
			||||||
 | 
					    fn squeek_key_get_symbol(
 | 
				
			||||||
 | 
					        key: *const KeyState, index: u32
 | 
				
			||||||
 | 
					    ) -> *const symbol::Symbol {
 | 
				
			||||||
 | 
					        let key = unsafe { &*key };
 | 
				
			||||||
 | 
					        let index = index as usize;
 | 
				
			||||||
 | 
					        &key.symbols[
 | 
				
			||||||
 | 
					            if index < key.symbols.len() { index } else { 0 }
 | 
				
			||||||
 | 
					        ] as *const symbol::Symbol
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[no_mangle]
 | 
				
			||||||
 | 
					    pub extern "C"
 | 
				
			||||||
 | 
					    fn squeek_key_to_keymap_entry(
 | 
				
			||||||
 | 
					        key_name: *const c_char,
 | 
				
			||||||
 | 
					        key: *const KeyState,
 | 
				
			||||||
 | 
					    ) -> *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_names = key.symbols.iter()
 | 
				
			||||||
 | 
					            .map(|symbol| {
 | 
				
			||||||
 | 
					                match &symbol.action {
 | 
				
			||||||
 | 
					                    symbol::Action::Submit { text: Some(text), .. } => {
 | 
				
			||||||
 | 
					                        Some(
 | 
				
			||||||
 | 
					                            text.clone()
 | 
				
			||||||
 | 
					                                .into_string().expect("Bad symbol")
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                    _ => None
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .collect::<Vec<_>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let inner = match symbol_names.len() {
 | 
				
			||||||
 | 
					            1 => match &symbol_names[0] {
 | 
				
			||||||
 | 
					                Some(name) => format!("[ {} ]", name),
 | 
				
			||||||
 | 
					                _ => format!("[ ]"),
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            4 => {
 | 
				
			||||||
 | 
					                let first = match (&symbol_names[0], &symbol_names[1]) {
 | 
				
			||||||
 | 
					                    (Some(left), Some(right)) => format!("{}, {}", left, right),
 | 
				
			||||||
 | 
					                    _ => format!(""),
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                let second = match (&symbol_names[2], &symbol_names[3]) {
 | 
				
			||||||
 | 
					                    (Some(left), Some(right)) => format!("{}, {}", left, right),
 | 
				
			||||||
 | 
					                    _ => format!(""),
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                format!("[ {} ], [ {} ]", first, second)
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            _ => panic!("Unsupported number of symbols"),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        CString::new(format!("        key <{}> {{ {} }};\n", key_name, inner))
 | 
				
			||||||
 | 
					            .expect("Couldn't convert string")
 | 
				
			||||||
 | 
					            .into_raw()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					pub struct KeyState {
 | 
				
			||||||
 | 
					    pressed: bool,
 | 
				
			||||||
 | 
					    keycode: u32,
 | 
				
			||||||
 | 
					    symbols: Vec<symbol::Symbol>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -2,4 +2,6 @@
 | 
				
			|||||||
mod bitflags;
 | 
					mod bitflags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod imservice;
 | 
					mod imservice;
 | 
				
			||||||
 | 
					mod keyboard;
 | 
				
			||||||
mod symbol;
 | 
					mod symbol;
 | 
				
			||||||
 | 
					mod util;
 | 
				
			||||||
 | 
				
			|||||||
@ -22,9 +22,5 @@ uint32_t squeek_symbol_get_modifier_mask(struct squeek_symbol* symbol);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void squeek_symbol_print(struct squeek_symbol* symbol);
 | 
					void squeek_symbol_print(struct squeek_symbol* symbol);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct squeek_symbols* squeek_symbols_new();
 | 
					 | 
				
			||||||
void squeek_symbols_free(struct squeek_symbols*);
 | 
					 | 
				
			||||||
struct squeek_symbol *squeek_symbols_get(struct squeek_symbols*, uint32_t level);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const char* squeek_key_to_keymap_entry(const char *key_name, struct squeek_symbols *symbols);
 | 
					const char* squeek_key_to_keymap_entry(const char *key_name, struct squeek_symbols *symbols);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										226
									
								
								src/symbol.rs
									
									
									
									
									
								
							
							
						
						
									
										226
									
								
								src/symbol.rs
									
									
									
									
									
								
							@ -1,4 +1,3 @@
 | 
				
			|||||||
use std::boxed::Box;
 | 
					 | 
				
			||||||
use std::ffi::CString;
 | 
					use std::ffi::CString;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -9,59 +8,9 @@ pub mod c {
 | 
				
			|||||||
    use std::ffi::CStr;
 | 
					    use std::ffi::CStr;
 | 
				
			||||||
    use std::os::raw::c_char;
 | 
					    use std::os::raw::c_char;
 | 
				
			||||||
    use std::ptr;
 | 
					    use std::ptr;
 | 
				
			||||||
    use std::str::Utf8Error;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    fn as_str(s: &*const c_char) -> Result<Option<&str>, Utf8Error> {
 | 
					 | 
				
			||||||
        if s.is_null() {
 | 
					 | 
				
			||||||
            Ok(None)
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            unsafe {CStr::from_ptr(*s)}
 | 
					 | 
				
			||||||
                .to_str()
 | 
					 | 
				
			||||||
                .map(Some)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    fn as_cstr(s: &*const c_char) -> Option<&CStr> {
 | 
					 | 
				
			||||||
        if s.is_null() {
 | 
					 | 
				
			||||||
            None
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            Some(unsafe {CStr::from_ptr(*s)})
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn into_cstring(s: *const c_char) -> Result<Option<CString>, std::ffi::NulError> {
 | 
					 | 
				
			||||||
        if s.is_null() {
 | 
					 | 
				
			||||||
            Ok(None)
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            CString::new(
 | 
					 | 
				
			||||||
                unsafe {CStr::from_ptr(s)}.to_bytes()
 | 
					 | 
				
			||||||
            ).map(Some)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    #[cfg(test)]
 | 
					 | 
				
			||||||
    mod tests {
 | 
					 | 
				
			||||||
        use super::*;
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        #[test]
 | 
					 | 
				
			||||||
        fn test_null_cstring() {
 | 
					 | 
				
			||||||
            assert_eq!(into_cstring(ptr::null()), Ok(None))
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        #[test]
 | 
					 | 
				
			||||||
        fn test_null_str() {
 | 
					 | 
				
			||||||
            assert_eq!(as_str(&ptr::null()), Ok(None))
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    // The following defined in C
 | 
					    // The following defined in C
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    #[no_mangle]
 | 
					 | 
				
			||||||
    extern "C" {
 | 
					 | 
				
			||||||
        fn eek_keysym_from_name(name: *const c_char) -> u32;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Legacy; Will never be used in Rust as a bit field
 | 
					    // Legacy; Will never be used in Rust as a bit field
 | 
				
			||||||
    enum ModifierMask {
 | 
					    enum ModifierMask {
 | 
				
			||||||
        Nothing = 0,
 | 
					        Nothing = 0,
 | 
				
			||||||
@ -72,98 +21,6 @@ pub mod c {
 | 
				
			|||||||
    
 | 
					    
 | 
				
			||||||
    // TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
 | 
					    // TODO: wrap naked pointers to Rust data inside RefCells to prevent multiple writers
 | 
				
			||||||
    // Symbols are owned by Rust and will move towards no C manipulation, so it may make sense not to wrap them
 | 
					    // Symbols are owned by Rust and will move towards no C manipulation, so it may make sense not to wrap them
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    // TODO: this will receive data from the filesystem,
 | 
					 | 
				
			||||||
    // so it should handle garbled strings in the future
 | 
					 | 
				
			||||||
    #[no_mangle]
 | 
					 | 
				
			||||||
    pub extern "C"
 | 
					 | 
				
			||||||
    fn squeek_symbols_add(
 | 
					 | 
				
			||||||
        v: *mut Vec<Symbol>,
 | 
					 | 
				
			||||||
        element: *const c_char,
 | 
					 | 
				
			||||||
        text_raw: *const c_char, keyval: u32,
 | 
					 | 
				
			||||||
        label: *const c_char, icon: *const c_char,
 | 
					 | 
				
			||||||
        tooltip: *const c_char,
 | 
					 | 
				
			||||||
    ) {
 | 
					 | 
				
			||||||
        let element = as_cstr(&element)
 | 
					 | 
				
			||||||
            .expect("Missing element name");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let text = into_cstring(text_raw)
 | 
					 | 
				
			||||||
            .unwrap_or_else(|e| {
 | 
					 | 
				
			||||||
                eprintln!("Text unreadable: {}", e);
 | 
					 | 
				
			||||||
                None
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .and_then(|text| {
 | 
					 | 
				
			||||||
                if text.as_bytes() == b"" {
 | 
					 | 
				
			||||||
                    None
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    Some(text)
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let icon = into_cstring(icon)
 | 
					 | 
				
			||||||
            .unwrap_or_else(|e| {
 | 
					 | 
				
			||||||
                eprintln!("Icon name unreadable: {}", e);
 | 
					 | 
				
			||||||
                None
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Only read label if there's no icon
 | 
					 | 
				
			||||||
        let label = match icon {
 | 
					 | 
				
			||||||
            Some(icon) => Label::IconName(icon),
 | 
					 | 
				
			||||||
            None => Label::Text(
 | 
					 | 
				
			||||||
                into_cstring(label)
 | 
					 | 
				
			||||||
                    .unwrap_or_else(|e| {
 | 
					 | 
				
			||||||
                        eprintln!("Label unreadable: {}", e);
 | 
					 | 
				
			||||||
                        Some(CString::new(" ").unwrap())
 | 
					 | 
				
			||||||
                    })
 | 
					 | 
				
			||||||
                    .unwrap_or_else(|| {
 | 
					 | 
				
			||||||
                        eprintln!("Label missing");
 | 
					 | 
				
			||||||
                        CString::new(" ").unwrap()
 | 
					 | 
				
			||||||
                    })
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let tooltip = into_cstring(tooltip)
 | 
					 | 
				
			||||||
            .unwrap_or_else(|e| {
 | 
					 | 
				
			||||||
                eprintln!("Tooltip unreadable: {}", e);
 | 
					 | 
				
			||||||
                None
 | 
					 | 
				
			||||||
            });
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        let symbol = match element.to_bytes() {
 | 
					 | 
				
			||||||
            b"symbol" => Symbol {
 | 
					 | 
				
			||||||
                action: Action::Submit {
 | 
					 | 
				
			||||||
                    text: text,
 | 
					 | 
				
			||||||
                    keys: Vec::new(),
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                label: label,
 | 
					 | 
				
			||||||
                tooltip: tooltip,
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            b"keysym" => {
 | 
					 | 
				
			||||||
                let keysym = XKeySym(
 | 
					 | 
				
			||||||
                    if keyval == 0 {
 | 
					 | 
				
			||||||
                        unsafe { eek_keysym_from_name(text_raw) }
 | 
					 | 
				
			||||||
                    } else {
 | 
					 | 
				
			||||||
                        keyval
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
                Symbol {
 | 
					 | 
				
			||||||
                    action: match KeySym::from_u32(keysym.0) {
 | 
					 | 
				
			||||||
                        KeySym::Shift => Action::SetLevel(1),
 | 
					 | 
				
			||||||
                        _ => Action::Submit {
 | 
					 | 
				
			||||||
                            text: text,
 | 
					 | 
				
			||||||
                            keys: vec![keysym],
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                    label: label,
 | 
					 | 
				
			||||||
                    tooltip: tooltip,
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            _ => panic!("unsupported element type {:?}", element),
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        let v = unsafe { &mut *v };
 | 
					 | 
				
			||||||
        v.push(symbol);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    #[no_mangle]
 | 
					    #[no_mangle]
 | 
				
			||||||
    pub extern "C"
 | 
					    pub extern "C"
 | 
				
			||||||
    fn squeek_symbol_get_name(symbol: *const Symbol) -> *const c_char {
 | 
					    fn squeek_symbol_get_name(symbol: *const Symbol) -> *const c_char {
 | 
				
			||||||
@ -214,88 +71,17 @@ pub mod c {
 | 
				
			|||||||
        let symbol = unsafe { &*symbol };
 | 
					        let symbol = unsafe { &*symbol };
 | 
				
			||||||
        println!("{:?}", symbol);
 | 
					        println!("{:?}", symbol);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    #[no_mangle]
 | 
					 | 
				
			||||||
    pub extern "C"
 | 
					 | 
				
			||||||
    fn squeek_symbols_new() -> *const Vec<Symbol> {
 | 
					 | 
				
			||||||
        Box::into_raw(Box::new(Vec::new()))
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    #[no_mangle]
 | 
					 | 
				
			||||||
    pub extern "C"
 | 
					 | 
				
			||||||
    fn squeek_symbols_get(v: *mut Vec<Symbol>, index: u32) -> *const Symbol {
 | 
					 | 
				
			||||||
        let v = unsafe { &mut *v };
 | 
					 | 
				
			||||||
        let index = index as usize;
 | 
					 | 
				
			||||||
        &v[
 | 
					 | 
				
			||||||
            if index < v.len() { index } else { 0 }
 | 
					 | 
				
			||||||
        ] as *const Symbol
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    #[no_mangle]
 | 
					 | 
				
			||||||
    pub extern "C"
 | 
					 | 
				
			||||||
    fn squeek_symbols_free(symbols: *mut Vec<Symbol>) {
 | 
					 | 
				
			||||||
        unsafe { Box::from_raw(symbols) }; // Will just get dropped, together with the contents
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    #[no_mangle]
 | 
					 | 
				
			||||||
    pub extern "C"
 | 
					 | 
				
			||||||
    fn squeek_key_to_keymap_entry(
 | 
					 | 
				
			||||||
        key_name: *const c_char,
 | 
					 | 
				
			||||||
        symbols: *const Vec<Symbol>,
 | 
					 | 
				
			||||||
    ) -> *const c_char {
 | 
					 | 
				
			||||||
        let key_name = as_cstr(&key_name)
 | 
					 | 
				
			||||||
            .expect("Missing key name")
 | 
					 | 
				
			||||||
            .to_str()
 | 
					 | 
				
			||||||
            .expect("Bad key name");
 | 
					 | 
				
			||||||
        let symbols = unsafe { &*symbols };
 | 
					 | 
				
			||||||
        let symbol_names = symbols.iter()
 | 
					 | 
				
			||||||
            .map(|symbol| {
 | 
					 | 
				
			||||||
                match &symbol.action {
 | 
					 | 
				
			||||||
                    Action::Submit { text: Some(text), .. } => {
 | 
					 | 
				
			||||||
                        Some(
 | 
					 | 
				
			||||||
                            text.clone()
 | 
					 | 
				
			||||||
                                .into_string().expect("Bad symbol")
 | 
					 | 
				
			||||||
                        )
 | 
					 | 
				
			||||||
                    },
 | 
					 | 
				
			||||||
                    _ => None
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
            .collect::<Vec<_>>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        let inner = match symbol_names.len() {
 | 
					 | 
				
			||||||
            1 => match &symbol_names[0] {
 | 
					 | 
				
			||||||
                Some(name) => format!("[ {} ]", name),
 | 
					 | 
				
			||||||
                _ => format!("[ ]"),
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            4 => {
 | 
					 | 
				
			||||||
                let first = match (&symbol_names[0], &symbol_names[1]) {
 | 
					 | 
				
			||||||
                    (Some(left), Some(right)) => format!("{}, {}", left, right),
 | 
					 | 
				
			||||||
                    _ => format!(""),
 | 
					 | 
				
			||||||
                };
 | 
					 | 
				
			||||||
                let second = match (&symbol_names[2], &symbol_names[3]) {
 | 
					 | 
				
			||||||
                    (Some(left), Some(right)) => format!("{}, {}", left, right),
 | 
					 | 
				
			||||||
                    _ => format!(""),
 | 
					 | 
				
			||||||
                };
 | 
					 | 
				
			||||||
                format!("[ {} ], [ {} ]", first, second)
 | 
					 | 
				
			||||||
            },
 | 
					 | 
				
			||||||
            _ => panic!("Unsupported number of symbols"),
 | 
					 | 
				
			||||||
        };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        CString::new(format!("        key <{}> {{ {} }};\n", key_name, inner))
 | 
					 | 
				
			||||||
            .expect("Couldn't convert string")
 | 
					 | 
				
			||||||
            .into_raw()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Just defines some int->identifier mappings for convenience
 | 
					/// Just defines some int->identifier mappings for convenience
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
enum KeySym {
 | 
					pub enum KeySym {
 | 
				
			||||||
    Unknown = 0,
 | 
					    Unknown = 0,
 | 
				
			||||||
    Shift = 0xffe1,
 | 
					    Shift = 0xffe1,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl KeySym {
 | 
					impl KeySym {
 | 
				
			||||||
    fn from_u32(num: u32) -> KeySym {
 | 
					    pub fn from_u32(num: u32) -> KeySym {
 | 
				
			||||||
        match num {
 | 
					        match num {
 | 
				
			||||||
            0xffe1 => KeySym::Shift,
 | 
					            0xffe1 => KeySym::Shift,
 | 
				
			||||||
            _ => KeySym::Unknown,
 | 
					            _ => KeySym::Unknown,
 | 
				
			||||||
@ -304,7 +90,7 @@ impl KeySym {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct XKeySym(u32);
 | 
					pub struct XKeySym(pub u32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub enum Label {
 | 
					pub enum Label {
 | 
				
			||||||
@ -344,9 +130,9 @@ pub enum Action {
 | 
				
			|||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct Symbol {
 | 
					pub struct Symbol {
 | 
				
			||||||
    /// The action that this key performs
 | 
					    /// The action that this key performs
 | 
				
			||||||
    action: Action,
 | 
					    pub action: Action,
 | 
				
			||||||
    /// Label to display to the user
 | 
					    /// Label to display to the user
 | 
				
			||||||
    label: Label,
 | 
					    pub label: Label,
 | 
				
			||||||
    // FIXME: is it used?
 | 
					    // FIXME: is it used?
 | 
				
			||||||
    tooltip: Option<CString>,
 | 
					    pub tooltip: Option<CString>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										49
									
								
								src/util.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/util.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					pub mod c {
 | 
				
			||||||
 | 
					    use std::ffi::{ CStr, CString };
 | 
				
			||||||
 | 
					    use std::os::raw::c_char;
 | 
				
			||||||
 | 
					    use std::str::Utf8Error;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    pub fn as_str(s: &*const c_char) -> Result<Option<&str>, Utf8Error> {
 | 
				
			||||||
 | 
					        if s.is_null() {
 | 
				
			||||||
 | 
					            Ok(None)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            unsafe {CStr::from_ptr(*s)}
 | 
				
			||||||
 | 
					                .to_str()
 | 
				
			||||||
 | 
					                .map(Some)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    pub fn as_cstr(s: &*const c_char) -> Option<&CStr> {
 | 
				
			||||||
 | 
					        if s.is_null() {
 | 
				
			||||||
 | 
					            None
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            Some(unsafe {CStr::from_ptr(*s)})
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn into_cstring(s: *const c_char) -> Result<Option<CString>, std::ffi::NulError> {
 | 
				
			||||||
 | 
					        if s.is_null() {
 | 
				
			||||||
 | 
					            Ok(None)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            CString::new(
 | 
				
			||||||
 | 
					                unsafe {CStr::from_ptr(s)}.to_bytes()
 | 
				
			||||||
 | 
					            ).map(Some)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    #[cfg(test)]
 | 
				
			||||||
 | 
					    mod tests {
 | 
				
			||||||
 | 
					        use super::*;
 | 
				
			||||||
 | 
					        use std::ptr;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        #[test]
 | 
				
			||||||
 | 
					        fn test_null_cstring() {
 | 
				
			||||||
 | 
					            assert_eq!(into_cstring(ptr::null()), Ok(None))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        #[test]
 | 
				
			||||||
 | 
					        fn test_null_str() {
 | 
				
			||||||
 | 
					            assert_eq!(as_str(&ptr::null()), Ok(None))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user