Break out symbol handling into Rust
This commit is contained in:
		@ -508,11 +508,3 @@ void eek_key_set_pressed(EekKey *key, gboolean value)
 | 
			
		||||
 | 
			
		||||
    priv->is_pressed = value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
eek_key_has_label(EekKey *key)
 | 
			
		||||
{
 | 
			
		||||
    EekSymbol *symbol = eek_key_get_symbol(key);
 | 
			
		||||
    return (eek_symbol_get_label(symbol) != NULL) ||
 | 
			
		||||
           (eek_symbol_get_icon_name(symbol) != NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -82,7 +82,5 @@ gboolean         eek_key_is_locked           (EekKey          *key);
 | 
			
		||||
void             eek_key_set_pressed         (EekKey          *key,
 | 
			
		||||
                                              gboolean         value);
 | 
			
		||||
 | 
			
		||||
gboolean         eek_key_has_label           (EekKey          *key);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
#endif  /* EEK_KEY_H */
 | 
			
		||||
 | 
			
		||||
@ -305,7 +305,7 @@ void eek_keyboard_press_key(EekKeyboard *keyboard, EekKey *key, guint32 timestam
 | 
			
		||||
    if (!symbol)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    EekModifierType modifier = eek_symbol_get_modifier_mask (symbol);
 | 
			
		||||
    EekModifierType modifier = squeek_symbol_get_modifier_mask (symbol);
 | 
			
		||||
    if (priv->modifier_behavior == EEK_MODIFIER_BEHAVIOR_NONE) {
 | 
			
		||||
        set_modifiers_with_key (keyboard, key, priv->modifiers | modifier);
 | 
			
		||||
        set_level_from_modifiers (keyboard, key);
 | 
			
		||||
@ -336,12 +336,10 @@ void eek_keyboard_release_key( EekKeyboard *keyboard,
 | 
			
		||||
    if (!symbol)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    EekModifierType modifier = eek_symbol_get_modifier_mask (symbol);
 | 
			
		||||
 | 
			
		||||
    if (!symbol)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    modifier = eek_symbol_get_modifier_mask (symbol);
 | 
			
		||||
    EekModifierType modifier = squeek_symbol_get_modifier_mask (symbol);
 | 
			
		||||
    switch (priv->modifier_behavior) {
 | 
			
		||||
    case EEK_MODIFIER_BEHAVIOR_NONE:
 | 
			
		||||
        set_modifiers_with_key (keyboard, key, priv->modifiers & ~modifier);
 | 
			
		||||
@ -810,11 +808,13 @@ eek_keyboard_get_keymap(EekKeyboard *keyboard)
 | 
			
		||||
 | 
			
		||||
        gchar *groups[2];
 | 
			
		||||
        for (i = 0, j = 0; i < 2; ++i, j += 2) {
 | 
			
		||||
            if (syms[j] && syms[j + 1])
 | 
			
		||||
                groups[i] = g_strjoin(", ", eek_symbol_get_name(syms[j]),
 | 
			
		||||
                                            eek_symbol_get_name(syms[j + 1]),
 | 
			
		||||
            if (syms[j] && syms[j + 1]) {
 | 
			
		||||
                char *tleft = squeek_symbol_get_name(syms[j]);
 | 
			
		||||
                char *tright = squeek_symbol_get_name(syms[j + 1]);
 | 
			
		||||
                groups[i] = g_strjoin(", ", tleft,
 | 
			
		||||
                                            tright,
 | 
			
		||||
                                            NULL);
 | 
			
		||||
            else
 | 
			
		||||
            } else
 | 
			
		||||
                groups[i] = "";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -228,6 +228,17 @@ eek_keysym_new (guint xkeysym)
 | 
			
		||||
    return eek_keysym_new_with_modifier (xkeysym, get_modifier_mask (xkeysym));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
guint32
 | 
			
		||||
eek_keysym_from_name (const gchar *name)
 | 
			
		||||
{
 | 
			
		||||
    for (uint i = 0; i < G_N_ELEMENTS(xkeysym_keysym_entries); i++) {
 | 
			
		||||
        if (g_strcmp0 (xkeysym_keysym_entries[i].name, name) == 0) {
 | 
			
		||||
            return xkeysym_keysym_entries[i].xkeysym;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * eek_keysym_new_from_name:
 | 
			
		||||
 * @name: an X keysym name
 | 
			
		||||
@ -237,9 +248,10 @@ eek_keysym_new (guint xkeysym)
 | 
			
		||||
EekSymbol*
 | 
			
		||||
eek_keysym_new_from_name (const gchar *name)
 | 
			
		||||
{
 | 
			
		||||
    for (uint i = 0; i < G_N_ELEMENTS(xkeysym_keysym_entries); i++)
 | 
			
		||||
        if (g_strcmp0 (xkeysym_keysym_entries[i].name, name) == 0)
 | 
			
		||||
            return eek_keysym_new (xkeysym_keysym_entries[i].xkeysym);
 | 
			
		||||
    guint32 xkeysym = eek_keysym_from_name(name);
 | 
			
		||||
    if (xkeysym != 0) {
 | 
			
		||||
        return eek_keysym_new(xkeysym);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    EekSymbol *ret = eek_symbol_new(name);
 | 
			
		||||
    eek_symbol_set_label(ret, name);
 | 
			
		||||
 | 
			
		||||
@ -40,6 +40,7 @@ G_BEGIN_DECLS
 | 
			
		||||
EekSymbol *eek_keysym_new               (guint           xkeysym);
 | 
			
		||||
guint      eek_keysym_get_xkeysym       (EekSymbol      *keysym);
 | 
			
		||||
 | 
			
		||||
guint32    eek_keysym_from_name         (const gchar    *name);
 | 
			
		||||
EekSymbol *eek_keysym_new_from_name     (const gchar    *name);
 | 
			
		||||
EekSymbol *eek_keysym_new_with_modifier (guint           xkeysym,
 | 
			
		||||
                                         EekModifierType modifier_mask);
 | 
			
		||||
 | 
			
		||||
@ -231,9 +231,6 @@ render_key (EekRenderer *self,
 | 
			
		||||
    PangoRectangle extents = { 0, };
 | 
			
		||||
    EekColor foreground;
 | 
			
		||||
 | 
			
		||||
    if (!eek_key_has_label(key))
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    oref = eek_key_get_oref (key);
 | 
			
		||||
    outline = eek_keyboard_get_outline (priv->keyboard, oref);
 | 
			
		||||
    if (outline == NULL)
 | 
			
		||||
@ -284,11 +281,11 @@ render_key (EekRenderer *self,
 | 
			
		||||
    if (!symbol)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (eek_symbol_get_icon_name (symbol)) {
 | 
			
		||||
    if (squeek_symbol_get_icon_name (symbol)) {
 | 
			
		||||
        gint scale = priv->scale_factor;
 | 
			
		||||
        cairo_surface_t *icon_surface =
 | 
			
		||||
            eek_renderer_get_icon_surface (self,
 | 
			
		||||
                                           eek_symbol_get_icon_name (symbol),
 | 
			
		||||
                                           squeek_symbol_get_icon_name (symbol),
 | 
			
		||||
                                           16 / priv->scale,
 | 
			
		||||
                                           scale);
 | 
			
		||||
        if (icon_surface) {
 | 
			
		||||
@ -397,7 +394,7 @@ eek_renderer_real_render_key_label (EekRenderer *self,
 | 
			
		||||
    if (!symbol)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    label = eek_symbol_get_label (symbol);
 | 
			
		||||
    label = squeek_symbol_get_label (symbol);
 | 
			
		||||
    if (!label)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -211,8 +211,6 @@ static void
 | 
			
		||||
eek_section_finalize (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
    EekSection        *self = EEK_SECTION (object);
 | 
			
		||||
    EekSectionPrivate *priv = (EekSectionPrivate*)eek_section_get_instance_private (self);
 | 
			
		||||
 | 
			
		||||
    G_OBJECT_CLASS (eek_section_parent_class)->finalize (object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -512,11 +510,6 @@ keycounter (EekElement *element, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    EekKey *key = EEK_KEY(element);
 | 
			
		||||
 | 
			
		||||
    /* Skip keys without labels for the current level. This causes those
 | 
			
		||||
       keys to be hidden in the visible layout. */
 | 
			
		||||
    if (!eek_key_has_label(key))
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    struct keys_info *data = user_data;
 | 
			
		||||
    data->count++;
 | 
			
		||||
    EekBounds key_bounds = {0};
 | 
			
		||||
@ -532,10 +525,6 @@ keyplacer(EekElement *element, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    EekKey *key = EEK_KEY(element);
 | 
			
		||||
 | 
			
		||||
    /* Skip keys without labels for the current level. */
 | 
			
		||||
    if (!eek_key_has_label(key))
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    double *current_offset = user_data;
 | 
			
		||||
    EekBounds key_bounds = {0};
 | 
			
		||||
    eek_element_get_bounds(element, &key_bounds);
 | 
			
		||||
 | 
			
		||||
@ -30,42 +30,15 @@
 | 
			
		||||
#include "eek-symbol.h"
 | 
			
		||||
#include "eek-enumtypes.h"
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
eek_symbol_destroy (EekSymbol *priv)
 | 
			
		||||
{
 | 
			
		||||
    g_free (priv->name);
 | 
			
		||||
    g_free (priv->label);
 | 
			
		||||
    g_free (priv->icon_name);
 | 
			
		||||
    g_free (priv->tooltip);
 | 
			
		||||
    g_free(priv->text);
 | 
			
		||||
    g_free(priv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
EekSymbol *
 | 
			
		||||
eek_symbol_new (const gchar *name)
 | 
			
		||||
{
 | 
			
		||||
    EekSymbol *self = g_new0(EekSymbol, 1);
 | 
			
		||||
    eek_symbol_set_name(self, name);
 | 
			
		||||
    self->name = g_strdup (name);
 | 
			
		||||
    self->category = EEK_SYMBOL_CATEGORY_UNKNOWN;
 | 
			
		||||
    return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
eek_symbol_set_name (EekSymbol   *symbol,
 | 
			
		||||
                     const gchar *name)
 | 
			
		||||
{
 | 
			
		||||
    g_free (symbol->name);
 | 
			
		||||
    symbol->name = g_strdup (name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const gchar *
 | 
			
		||||
eek_symbol_get_name (EekSymbol *symbol)
 | 
			
		||||
{
 | 
			
		||||
    if (symbol->name == NULL || *symbol->name == '\0')
 | 
			
		||||
        return NULL;
 | 
			
		||||
    return symbol->name;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * eek_symbol_set_label:
 | 
			
		||||
 * @symbol: an #EekSymbol
 | 
			
		||||
@ -81,20 +54,6 @@ eek_symbol_set_label (EekSymbol   *symbol,
 | 
			
		||||
    symbol->label = g_strdup (label);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * eek_symbol_get_label:
 | 
			
		||||
 * @symbol: an #EekSymbol
 | 
			
		||||
 *
 | 
			
		||||
 * Get the label text of @symbol.
 | 
			
		||||
 */
 | 
			
		||||
const gchar *
 | 
			
		||||
eek_symbol_get_label (EekSymbol *symbol)
 | 
			
		||||
{
 | 
			
		||||
    if (symbol->label == NULL || *symbol->label == '\0')
 | 
			
		||||
        return NULL;
 | 
			
		||||
    return symbol->label;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * eek_symbol_set_modifier_mask:
 | 
			
		||||
 * @symbol: an #EekSymbol
 | 
			
		||||
@ -118,15 +77,10 @@ eek_symbol_set_modifier_mask (EekSymbol      *symbol,
 | 
			
		||||
EekModifierType
 | 
			
		||||
eek_symbol_get_modifier_mask (EekSymbol *symbol)
 | 
			
		||||
{
 | 
			
		||||
    return 0;
 | 
			
		||||
    return symbol->modifier_mask;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
eek_symbol_is_modifier (EekSymbol *symbol)
 | 
			
		||||
{
 | 
			
		||||
    return eek_symbol_get_modifier_mask (symbol) != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
eek_symbol_set_icon_name (EekSymbol   *symbol,
 | 
			
		||||
                          const gchar *icon_name)
 | 
			
		||||
@ -138,9 +92,7 @@ eek_symbol_set_icon_name (EekSymbol   *symbol,
 | 
			
		||||
const gchar *
 | 
			
		||||
eek_symbol_get_icon_name (EekSymbol *symbol)
 | 
			
		||||
{
 | 
			
		||||
    if (symbol->icon_name == NULL || *symbol->icon_name == '\0')
 | 
			
		||||
        return NULL;
 | 
			
		||||
    return symbol->icon_name;
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@ -154,6 +106,7 @@ eek_symbol_set_tooltip (EekSymbol   *symbol,
 | 
			
		||||
const gchar *
 | 
			
		||||
eek_symbol_get_tooltip (EekSymbol *symbol)
 | 
			
		||||
{
 | 
			
		||||
    return NULL;
 | 
			
		||||
    if (symbol->tooltip == NULL || *symbol->tooltip == '\0')
 | 
			
		||||
        return NULL;
 | 
			
		||||
    return symbol->tooltip;
 | 
			
		||||
 | 
			
		||||
@ -26,6 +26,8 @@
 | 
			
		||||
#define EEK_SYMBOL_H 1
 | 
			
		||||
 | 
			
		||||
#include "eek-types.h"
 | 
			
		||||
#include "src/symbol.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
@ -91,7 +93,6 @@ EekSymbolCategory eek_symbol_get_category       (EekSymbol        *symbol);
 | 
			
		||||
EekModifierType   eek_symbol_get_modifier_mask  (EekSymbol        *symbol);
 | 
			
		||||
void              eek_symbol_set_modifier_mask  (EekSymbol        *symbol,
 | 
			
		||||
                                                 EekModifierType   mask);
 | 
			
		||||
gboolean          eek_symbol_is_modifier        (EekSymbol        *symbol);
 | 
			
		||||
void              eek_symbol_set_icon_name      (EekSymbol        *symbol,
 | 
			
		||||
                                                 const gchar      *icon_name);
 | 
			
		||||
const gchar      *eek_symbol_get_icon_name      (EekSymbol        *symbol);
 | 
			
		||||
 | 
			
		||||
@ -33,6 +33,7 @@
 | 
			
		||||
#include "eek-key.h"
 | 
			
		||||
#include "eek-keysym.h"
 | 
			
		||||
#include "eek-text.h"
 | 
			
		||||
#include "src/symbol.h"
 | 
			
		||||
 | 
			
		||||
#include "squeekboard-resources.h"
 | 
			
		||||
 | 
			
		||||
@ -732,38 +733,25 @@ symbols_end_element_callback (GMarkupParseContext *pcontext,
 | 
			
		||||
    if (g_strcmp0 (element_name, "symbol") == 0 ||
 | 
			
		||||
        g_strcmp0 (element_name, "keysym") == 0 ||
 | 
			
		||||
        g_strcmp0 (element_name, "text") == 0) {
 | 
			
		||||
        EekSymbol *symbol;
 | 
			
		||||
 | 
			
		||||
        if (g_strcmp0 (element_name, "keysym") == 0) {
 | 
			
		||||
            EekSymbol *keysym;
 | 
			
		||||
            if (data->keyval != EEK_INVALID_KEYSYM)
 | 
			
		||||
                keysym = eek_keysym_new (data->keyval);
 | 
			
		||||
            else
 | 
			
		||||
                keysym = eek_keysym_new_from_name (text);
 | 
			
		||||
            symbol = keysym;
 | 
			
		||||
        } else if (g_strcmp0 (element_name, "text") == 0) {
 | 
			
		||||
            symbol = eek_text_new (text);
 | 
			
		||||
        } else {
 | 
			
		||||
            symbol = eek_symbol_new (text);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (data->label) {
 | 
			
		||||
            eek_symbol_set_label (symbol, data->label);
 | 
			
		||||
            g_free (data->label);
 | 
			
		||||
            data->label = NULL;
 | 
			
		||||
        }
 | 
			
		||||
        if (data->icon) {
 | 
			
		||||
            eek_symbol_set_icon_name (symbol, data->icon);
 | 
			
		||||
            g_free (data->icon);
 | 
			
		||||
            data->icon = NULL;
 | 
			
		||||
        }
 | 
			
		||||
        if (data->tooltip) {
 | 
			
		||||
            eek_symbol_set_tooltip (symbol, data->tooltip);
 | 
			
		||||
            g_free (data->tooltip);
 | 
			
		||||
            data->tooltip = NULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        data->symbols = g_slist_prepend (data->symbols, symbol);
 | 
			
		||||
        data->symbols = g_slist_prepend (
 | 
			
		||||
            data->symbols,
 | 
			
		||||
            squeek_symbol_new(
 | 
			
		||||
                element_name,
 | 
			
		||||
                text,
 | 
			
		||||
                data->keyval,
 | 
			
		||||
                data->label,
 | 
			
		||||
                data->icon,
 | 
			
		||||
                data->tooltip
 | 
			
		||||
            )
 | 
			
		||||
        );
 | 
			
		||||
        data->keyval = 0;
 | 
			
		||||
        g_free(data->label);
 | 
			
		||||
        data->label = NULL;
 | 
			
		||||
        g_free(data->icon);
 | 
			
		||||
        data->icon = NULL;
 | 
			
		||||
        g_free(data->tooltip);
 | 
			
		||||
        data->tooltip = NULL;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -148,6 +148,10 @@ eekboard_context_service_real_create_keyboard (EekboardContextService *self,
 | 
			
		||||
 | 
			
		||||
    gchar *keymap_str = eek_keyboard_get_keymap(keyboard);
 | 
			
		||||
 | 
			
		||||
    int f = open("maprs.map", O_CREAT | O_WRONLY);
 | 
			
		||||
    write(f, keymap_str, strlen(keymap_str));
 | 
			
		||||
    close(f);
 | 
			
		||||
 | 
			
		||||
    struct xkb_keymap *keymap = xkb_keymap_new_from_string(context, keymap_str,
 | 
			
		||||
        XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2,3 +2,4 @@
 | 
			
		||||
mod bitflags;
 | 
			
		||||
 | 
			
		||||
mod imservice;
 | 
			
		||||
mod symbol;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										22
									
								
								src/symbol.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/symbol.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
			
		||||
#ifndef __SYMBOL_H
 | 
			
		||||
#define __SYMBOL_H
 | 
			
		||||
 | 
			
		||||
#include "stdbool.h"
 | 
			
		||||
#include "inttypes.h"
 | 
			
		||||
// Defined in Rust
 | 
			
		||||
 | 
			
		||||
struct squeek_symbol;
 | 
			
		||||
 | 
			
		||||
struct squeek_symbol* squeek_symbol_new(const char *element_name,
 | 
			
		||||
                                        const char *text, uint32_t keyval,
 | 
			
		||||
                                        const char *label, const char *icon,
 | 
			
		||||
                                        const char *tooltip);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
const char *squeek_symbol_get_name(struct squeek_symbol* symbol);
 | 
			
		||||
const char *squeek_symbol_get_label(struct squeek_symbol* symbol);
 | 
			
		||||
const char *squeek_symbol_get_icon_name(struct squeek_symbol* symbol);
 | 
			
		||||
uint32_t squeek_symbol_get_modifier_mask(struct squeek_symbol* symbol);
 | 
			
		||||
 | 
			
		||||
void squeek_symbol_print(struct squeek_symbol* symbol);
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										276
									
								
								src/symbol.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										276
									
								
								src/symbol.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,276 @@
 | 
			
		||||
use std::boxed::Box;
 | 
			
		||||
use std::ffi::CString;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// Gathers stuff defined in C or called by C
 | 
			
		||||
pub mod c {
 | 
			
		||||
    use super::*;
 | 
			
		||||
 | 
			
		||||
    use std::ffi::CStr;
 | 
			
		||||
    use std::os::raw::c_char;
 | 
			
		||||
    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
 | 
			
		||||
    
 | 
			
		||||
    #[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
 | 
			
		||||
    enum ModifierMask {
 | 
			
		||||
        Nothing = 0,
 | 
			
		||||
        Shift = 1,
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // 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_symbol_new(
 | 
			
		||||
        element: *const c_char,
 | 
			
		||||
        text_raw: *const c_char, keyval: u32,
 | 
			
		||||
        label: *const c_char, icon: *const c_char,
 | 
			
		||||
        tooltip: *const c_char,
 | 
			
		||||
    ) -> *mut Symbol {
 | 
			
		||||
        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
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        Box::<Symbol>::into_raw(Box::new(
 | 
			
		||||
            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),
 | 
			
		||||
            }
 | 
			
		||||
        ))
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_symbol_get_name(symbol: *const Symbol) -> *const c_char {
 | 
			
		||||
        let symbol = unsafe { &*symbol };
 | 
			
		||||
        match &symbol.action {
 | 
			
		||||
            Action::Submit { text: Some(text), .. } => text.as_ptr(),
 | 
			
		||||
            _ => ptr::null(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_symbol_get_label(symbol: *const Symbol) -> *const c_char {
 | 
			
		||||
        let symbol = unsafe { &*symbol };
 | 
			
		||||
        match &symbol.label {
 | 
			
		||||
            Label::Text(text) => text.as_ptr(),
 | 
			
		||||
            // returning static strings to C is a bit cumbersome
 | 
			
		||||
            Label::IconName(_) => unsafe {
 | 
			
		||||
                CStr::from_bytes_with_nul_unchecked(b"icon\0")
 | 
			
		||||
            }.as_ptr(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_symbol_get_icon_name(symbol: *const Symbol) -> *const c_char {
 | 
			
		||||
        let symbol = unsafe { &*symbol };
 | 
			
		||||
        match &symbol.label {
 | 
			
		||||
            Label::Text(_) => ptr::null(),
 | 
			
		||||
            Label::IconName(name) => name.as_ptr(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // Legacy; throw away
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_symbol_get_modifier_mask(symbol: *const Symbol) -> u32 {
 | 
			
		||||
        let symbol = unsafe { &*symbol };
 | 
			
		||||
        (match &symbol.action {
 | 
			
		||||
            Action::SetLevel(1) => ModifierMask::Shift,
 | 
			
		||||
            _ => ModifierMask::Nothing,
 | 
			
		||||
        }) as u32
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #[no_mangle]
 | 
			
		||||
    pub extern "C"
 | 
			
		||||
    fn squeek_symbol_print(symbol: *const Symbol) {
 | 
			
		||||
        let symbol = unsafe { &*symbol };
 | 
			
		||||
        println!("{:?}", symbol);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Just defines some int->identifier mappings for convenience
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
enum KeySym {
 | 
			
		||||
    Unknown = 0,
 | 
			
		||||
    Shift = 0xffe1,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl KeySym {
 | 
			
		||||
    fn from_u32(num: u32) -> KeySym {
 | 
			
		||||
        match num {
 | 
			
		||||
            0xffe1 => KeySym::Shift,
 | 
			
		||||
            _ => KeySym::Unknown,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct XKeySym(u32);
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum Label {
 | 
			
		||||
    /// Text used to display the symbol
 | 
			
		||||
    Text(CString),
 | 
			
		||||
    /// Icon name used to render the symbol
 | 
			
		||||
    IconName(CString),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Use to switch layouts
 | 
			
		||||
type Level = u8;
 | 
			
		||||
 | 
			
		||||
/// Use to send modified keypresses
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum Modifier {
 | 
			
		||||
    Control,
 | 
			
		||||
    Alt,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Action to perform on the keypress and, in reverse, on keyrelease
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum Action {
 | 
			
		||||
    /// Switch to this level TODO: reverse?
 | 
			
		||||
    SetLevel(Level),
 | 
			
		||||
    /// Set this modifier TODO: release?
 | 
			
		||||
    SetModifier(Modifier),
 | 
			
		||||
    /// Submit some text
 | 
			
		||||
    Submit {
 | 
			
		||||
        /// orig: Canonical name of the symbol
 | 
			
		||||
        text: Option<CString>,
 | 
			
		||||
        /// The key events this symbol submits when submitting text is not possible
 | 
			
		||||
        keys: Vec<XKeySym>,
 | 
			
		||||
    },
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Contains a static description of a particular key's actions
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct Symbol {
 | 
			
		||||
    /// The action that this key performs
 | 
			
		||||
    action: Action,
 | 
			
		||||
    /// Label to display to the user
 | 
			
		||||
    label: Label,
 | 
			
		||||
    // FIXME: is it used?
 | 
			
		||||
    tooltip: Option<CString>,
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user