WIP

WIP: keymap generation test passes

meta: Update features and version

WiP: cargo.lock

WIP: don't crash

WIP: no outlines

parsing: New tests

WIP: base level works

WIP: remove old keyboard

symbols correctly input

WIP: lodaing files

WIP: fallback works

Valid fallback
This commit is contained in:
Dorota Czaplejewicz
2019-09-01 11:38:05 +00:00
parent 3413021d30
commit b84c402c4a
41 changed files with 1319 additions and 2068 deletions

View File

@ -34,7 +34,6 @@
#include "eek-renderer.h"
#include "eek-keyboard.h"
#include "src/symbol.h"
#include "eek-gtk-keyboard.h"
@ -109,7 +108,7 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
eek_renderer_render_keyboard (priv->renderer, cr);
struct squeek_view *view = priv->keyboard->views[priv->keyboard->level];
struct squeek_view *view = squeek_layout_get_current_view(priv->keyboard->layout);
/* redraw pressed key */
const GList *list = priv->keyboard->pressed_buttons;

View File

@ -34,7 +34,6 @@
#include "eekboard/key-emitter.h"
#include "keymap.h"
#include "src/keyboard.h"
#include "src/symbol.h"
#include "eek-keyboard.h"
@ -58,20 +57,20 @@ set_key_states (LevelKeyboard *keyboard,
struct squeek_button *button,
guint new_level)
{
struct squeek_key *key = squeek_button_get_key(button);
// Keys locking rules hardcoded for the time being...
const gchar *name = squeek_symbol_get_name(squeek_key_get_symbol(key));
const gchar *name = squeek_button_get_name(button);
// Lock the shift whenever it's pressed on the baselevel
// TODO: need to lock shift on the destination level
if (g_strcmp0(name, "Shift_L") == 0 && keyboard->level == 0) {
if (g_strcmp0(name, "Shift_L") == 0 && squeek_layout_get_level(keyboard->layout) == 0) {
EekModifierKey *modifier_key = g_slice_new (EekModifierKey);
modifier_key->modifiers = 0;
modifier_key->button = button;
keyboard->locked_buttons =
g_list_prepend (keyboard->locked_buttons, modifier_key);
struct squeek_key *key = squeek_button_get_key(button);
squeek_key_set_locked(key, true);
}
if (keyboard->level == 1) {
if (squeek_layout_get_level(keyboard->layout) == 1) {
// Only shift is locked in this state, unlock on any key press
for (GList *head = keyboard->locked_buttons; head; ) {
EekModifierKey *modifier_key = head->data;
@ -92,10 +91,10 @@ static void
set_level_from_press (LevelKeyboard *keyboard, struct squeek_button *button)
{
/* The levels are: 0 Letters, 1 Upper case letters, 2 Numbers, 3 Symbols */
guint level = keyboard->level;
guint level = squeek_layout_get_level(keyboard->layout);
/* Handle non-emitting keys */
if (button) {
const gchar *name = squeek_symbol_get_name(squeek_key_get_symbol(squeek_button_get_key(button)));
const gchar *name = squeek_button_get_name(button);
if (g_strcmp0(name, "show_numbers") == 0) {
level = 2;
} else if (g_strcmp0(name, "show_letters") == 0) {
@ -107,9 +106,7 @@ set_level_from_press (LevelKeyboard *keyboard, struct squeek_button *button)
}
}
keyboard->level = set_key_states(keyboard, button, level);
eek_layout_update_layout(keyboard);
squeek_layout_set_level(keyboard->layout, set_key_states(keyboard, button, level));
}
void eek_keyboard_press_button(LevelKeyboard *keyboard, struct squeek_button *button, guint32 timestamp) {
@ -117,10 +114,6 @@ void eek_keyboard_press_button(LevelKeyboard *keyboard, struct squeek_button *bu
squeek_key_set_pressed(key, TRUE);
keyboard->pressed_buttons = g_list_prepend (keyboard->pressed_buttons, button);
struct squeek_symbol *symbol = squeek_key_get_symbol(key);
if (!symbol)
return;
// Only take action about setting level *after* the key has taken effect, i.e. on release
//set_level_from_press (keyboard, key);
@ -142,10 +135,6 @@ void eek_keyboard_release_button(LevelKeyboard *keyboard,
}
}
struct squeek_symbol *symbol = squeek_button_get_symbol(button);
if (!symbol)
return;
set_level_from_press (keyboard, button);
// "Borrowed" from eek-context-service; doesn't influence the state but forwards the event
@ -156,18 +145,7 @@ void eek_keyboard_release_button(LevelKeyboard *keyboard,
}
void level_keyboard_deinit(LevelKeyboard *self) {
g_hash_table_destroy (self->names);
for (guint i = 0; i < self->outline_array->len; i++) {
EekOutline *outline = &g_array_index (self->outline_array,
EekOutline,
i);
g_slice_free1 (sizeof (EekPoint) * outline->num_points,
outline->points);
}
g_array_free (self->outline_array, TRUE);
for (guint i = 0; i < 4; i++) {
// free self->view[i];
}
squeek_layout_free(self->layout);
}
void level_keyboard_free(LevelKeyboard *self) {
@ -175,115 +153,18 @@ void level_keyboard_free(LevelKeyboard *self) {
g_free(self);
}
void level_keyboard_init(LevelKeyboard *self) {
self->outline_array = g_array_new (FALSE, TRUE, sizeof (EekOutline));
void level_keyboard_init(LevelKeyboard *self, struct squeek_layout *layout) {
self->layout = layout;
}
LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek_view *views[4], GHashTable *name_button_hash) {
LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek_layout *layout) {
LevelKeyboard *keyboard = g_new0(LevelKeyboard, 1);
level_keyboard_init(keyboard);
for (uint i = 0; i < 4; i++) {
keyboard->views[i] = views[i];
}
level_keyboard_init(keyboard, layout);
keyboard->manager = manager;
keyboard->names = name_button_hash;
return keyboard;
}
/**
* eek_keyboard_find_key_by_name:
* @keyboard: an #EekKeyboard
* @name: a key name
*
* Find an #EekKey whose name is @name.
* Return value: (transfer none): #EekKey whose name is @name
*/
struct squeek_button*
eek_keyboard_find_button_by_name (LevelKeyboard *keyboard,
const gchar *name)
{
return g_hash_table_lookup (keyboard->names, name);
}
/**
* eek_keyboard_get_outline:
* @keyboard: an #EekKeyboard
* @oref: ID of the outline
*
* Get an outline associated with @oref in @keyboard.
* Returns: an #EekOutline, which should not be released
*/
EekOutline *
level_keyboard_get_outline (LevelKeyboard *keyboard,
guint oref)
{
if (oref > keyboard->outline_array->len)
return NULL;
return &g_array_index (keyboard->outline_array, EekOutline, oref);
}
/**
* eek_keyboard_get_keymap:
* @keyboard: an #EekKeyboard
*
* Get the keymap for the keyboard.
* Returns: a string containing the XKB keymap.
*/
gchar *
eek_keyboard_get_keymap(LevelKeyboard *keyboard)
{
/* Start the keycodes and symbols sections with their respective headers. */
gchar *keycodes = g_strdup(keymap_keycodes_header);
gchar *symbols = g_strdup(keymap_symbols_header);
/* Iterate over the keys in the name-to-key hash table. */
GHashTableIter iter;
gchar *button_name;
gpointer button_ptr;
g_hash_table_iter_init(&iter, keyboard->names);
while (g_hash_table_iter_next(&iter, (gpointer)&button_name, &button_ptr)) {
gchar *current, *line;
struct squeek_button *button = button_ptr;
struct squeek_key *key = squeek_button_get_key(button);
guint keycode = squeek_key_get_keycode(key);
/* Don't include invalid keycodes in the keymap. */
if (keycode == EEK_INVALID_KEYCODE)
continue;
/* Append a key name-to-keycode definition to the keycodes section. */
current = keycodes;
line = g_strdup_printf(" <%s> = %i;\n", (char *)button_name, keycode);
keycodes = g_strconcat(current, line, NULL);
g_free(line);
g_free(current);
// FIXME: free
const char *key_str = squeek_key_to_keymap_entry(
(char*)button_name,
key
);
current = symbols;
symbols = g_strconcat(current, key_str, NULL);
g_free(current);
}
/* Assemble the keymap file from the header, sections and footer. */
gchar *keymap = g_strconcat(keymap_header,
keycodes, " };\n\n",
symbols, " };\n\n",
keymap_footer, NULL);
g_free(keycodes);
g_free(symbols);
return keymap;
}
struct squeek_view *level_keyboard_current(LevelKeyboard *keyboard)
{
return keyboard->views[keyboard->level];
return squeek_layout_get_current_view(keyboard->layout);
}

View File

@ -42,37 +42,26 @@ typedef struct _EekModifierKey EekModifierKey;
/// Keyboard state holder
struct _LevelKeyboard {
struct squeek_view *views[4];
guint level;
struct squeek_layout *layout;
struct xkb_keymap *keymap;
int keymap_fd; // keymap formatted as XKB string
size_t keymap_len; // length of the data inside keymap_fd
GArray *outline_array;
GList *pressed_buttons; // struct squeek_button*
GList *locked_buttons; // struct squeek_button*
/* Map button names to button objects: */
GHashTable *names;
guint id; // as a key to layout choices
EekboardContextService *manager; // unowned reference
};
typedef struct _LevelKeyboard LevelKeyboard;
struct squeek_button *eek_keyboard_find_button_by_name(LevelKeyboard *keyboard,
const gchar *name);
/// Represents the path to the button within a view
struct button_place {
const struct squeek_row *row;
const struct squeek_button *button;
};
EekOutline *level_keyboard_get_outline
(LevelKeyboard *keyboard,
guint oref);
EekModifierKey *eek_modifier_key_copy
(EekModifierKey *modkey);
void eek_modifier_key_free
@ -81,11 +70,8 @@ void eek_modifier_key_free
void eek_keyboard_press_button(LevelKeyboard *keyboard, struct squeek_button *button, guint32 timestamp);
void eek_keyboard_release_button(LevelKeyboard *keyboard, struct squeek_button *button, guint32 timestamp);
gchar * eek_keyboard_get_keymap
(LevelKeyboard *keyboard);
struct squeek_view *level_keyboard_current(LevelKeyboard *keyboard);
LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek_view *views[], GHashTable *name_button_hash);
LevelKeyboard *level_keyboard_new(EekboardContextService *manager, struct squeek_layout *layout);
void level_keyboard_deinit(LevelKeyboard *self);
void level_keyboard_free(LevelKeyboard *self);

View File

@ -45,9 +45,3 @@ void
eek_layout_init (EekLayout *self)
{
}
void
eek_layout_update_layout(LevelKeyboard *keyboard)
{
squeek_view_place_contents(level_keyboard_current(keyboard), keyboard);
}

View File

@ -56,14 +56,5 @@ struct _EekLayoutClass
GType eek_layout_get_type (void) G_GNUC_CONST;
void eek_layout_place_rows(LevelKeyboard *keyboard, struct squeek_view *level);
void eek_layout_update_layout(LevelKeyboard *keyboard);
LevelKeyboard *
level_keyboard_from_layout (EekLayout *layout,
gdouble initial_width,
gdouble initial_height);
G_END_DECLS
#endif /* EEK_LAYOUT_H */

View File

@ -24,8 +24,6 @@
#include <string.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include "src/symbol.h"
#include "eek-renderer.h"
enum {
@ -188,13 +186,6 @@ render_button_outline (EekRenderer *renderer,
gboolean active)
{
EekRendererPrivate *priv = eek_renderer_get_instance_private (renderer);
EekOutline *outline;
guint oref = squeek_button_get_oref(button);
outline = level_keyboard_get_outline (priv->keyboard, oref);
if (outline == NULL)
return;
EekBounds bounds = squeek_button_get_bounds(button);
gtk_style_context_set_state(priv->key_context,
active ? GTK_STATE_FLAG_ACTIVE : GTK_STATE_FLAG_NORMAL);
@ -214,18 +205,12 @@ render_button (EekRenderer *self,
gboolean active)
{
EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
EekOutline *outline;
cairo_surface_t *outline_surface;
GHashTable *outline_surface_cache;
PangoLayout *layout;
PangoRectangle extents = { 0, };
EekColor foreground;
guint oref = squeek_button_get_oref (place->button);
outline = level_keyboard_get_outline (priv->keyboard, oref);
if (outline == NULL)
return;
/* render outline */
EekBounds bounds = squeek_button_get_bounds(place->button);
@ -234,7 +219,7 @@ render_button (EekRenderer *self,
else
outline_surface_cache = priv->outline_surface_cache;
outline_surface = g_hash_table_lookup (outline_surface_cache, outline);
outline_surface = g_hash_table_lookup (outline_surface_cache, place->button);
if (!outline_surface) {
cairo_t *cr;
@ -258,7 +243,7 @@ render_button (EekRenderer *self,
cairo_destroy (cr);
g_hash_table_insert (outline_surface_cache,
outline,
(gpointer)place->button,
outline_surface);
}
@ -267,16 +252,12 @@ render_button (EekRenderer *self,
eek_renderer_get_foreground_color (self, priv->key_context, &foreground);
/* render icon (if any) */
struct squeek_symbol *symbol = squeek_button_get_symbol(place->button);
if (!symbol)
return;
const char *icon_name = squeek_button_get_icon_name(place->button);
if (squeek_symbol_get_icon_name (symbol)) {
if (icon_name) {
gint scale = priv->scale_factor;
cairo_surface_t *icon_surface =
eek_renderer_get_icon_surface (self,
squeek_symbol_get_icon_name (symbol),
16 / priv->scale,
eek_renderer_get_icon_surface (self, icon_name, 16 / priv->scale,
scale);
if (icon_surface) {
gint width = cairo_image_surface_get_width (icon_surface);
@ -371,18 +352,16 @@ eek_renderer_real_render_button_label (EekRenderer *self,
{
EekRendererPrivate *priv = eek_renderer_get_instance_private (self);
const gchar *label;
const gchar *label = squeek_button_get_label(button);
if (!label) {
return;
}
PangoFontDescription *font;
PangoLayoutLine *line;
gdouble scale;
struct squeek_symbol *symbol = squeek_button_get_symbol(button);
if (!symbol)
return;
label = squeek_symbol_get_label (symbol);
if (!label)
return;
if (!priv->font) {
const PangoFontDescription *base_font;
@ -480,7 +459,7 @@ eek_renderer_real_render_keyboard (EekRenderer *self,
cairo_get_target (cr), 0, 0,
priv->allocation_width, priv->allocation_height);
render_keyboard_surface (self, priv->keyboard->views[priv->keyboard->level]);
render_keyboard_surface (self, squeek_layout_get_current_view(priv->keyboard->layout));
cairo_set_source_surface (cr, priv->keyboard_surface, 0.0, 0.0);
source = cairo_get_source (cr);

View File

@ -1,56 +0,0 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include "config.h"
#include "eek-section.h"
EekBounds eek_get_outline_size(LevelKeyboard *keyboard, uint32_t oref) {
EekOutline *outline = level_keyboard_get_outline (keyboard, oref);
if (outline && outline->num_points > 0) {
double minx = outline->points[0].x;
double maxx = minx;
double miny = outline->points[0].y;
double maxy = miny;
for (uint i = 1; i < outline->num_points; i++) {
EekPoint p = outline->points[i];
if (p.x < minx) {
minx = p.x;
} else if (p.x > maxx) {
maxx = p.x;
}
if (p.y < miny) {
miny = p.y;
} else if (p.y > maxy) {
maxy = p.y;
}
}
EekBounds key_bounds = {
.height = maxy - miny,
.width = maxx - minx,
.x = 0,
.y = 0,
};
return key_bounds;
}
EekBounds bounds = {0, 0, 0, 0};
return bounds;
}

View File

@ -1,34 +0,0 @@
/*
* Copyright (C) 2010-2011 Daiki Ueno <ueno@unixuser.org>
* Copyright (C) 2010-2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#if !defined(__EEK_H_INSIDE__) && !defined(EEK_COMPILATION)
#error "Only <eek/eek.h> can be included directly."
#endif
#ifndef EEK_SECTION_H
#define EEK_SECTION_H 1
/* Contains row-related functions that couldn't be done in Rust easily. */
#include <glib-object.h>
#include "eek-keyboard.h"
#include "src/layout.h"
#endif /* EEK_SECTION_H */

View File

@ -29,7 +29,6 @@
#include "eek-keyboard.h"
#include "src/keyboard.h"
#include "src/symbol.h"
#include "squeekboard-resources.h"
@ -62,21 +61,6 @@ G_DEFINE_BOXED_TYPE(EekXmlKeyboardDesc, eek_xml_keyboard_desc, eek_xml_keyboard_
static GList *parse_keyboards (const gchar *path,
GError **error);
static GList *parse_prerequisites
(const gchar *path,
GError **error);
static gboolean parse_geometry (const gchar *path,
struct squeek_view **views, GArray *outline_array, GHashTable *name_button_hash,
GError **error);
static gboolean parse_symbols_with_prerequisites
(const gchar *keyboards_dir,
const gchar *name,
LevelKeyboard *keyboard,
GList **loaded,
GError **error);
static gboolean parse_symbols (const gchar *path,
LevelKeyboard *keyboard,
GError **error);
static gboolean validate (const gchar **valid_path_list,
gsize valid_path_list_len,
@ -253,380 +237,6 @@ struct _GeometryParseData {
};
typedef struct _GeometryParseData GeometryParseData;
static GeometryParseData *
geometry_parse_data_new (struct squeek_view **views, GHashTable *name_button_hash, GArray *outline_array)
{
GeometryParseData *data = g_slice_new0 (GeometryParseData);
data->views = views;
data->outline_array = outline_array;
data->keyname_oref_hash =
g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
NULL);
data->outlineid_oref_hash =
g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
NULL);
data->name_button_hash = name_button_hash;
data->text = g_string_sized_new (BUFSIZE);
data->keycode = 8;
return data;
}
static void
geometry_parse_data_free (GeometryParseData *data)
{
g_hash_table_destroy (data->keyname_oref_hash);
g_hash_table_destroy (data->outlineid_oref_hash);
g_string_free (data->text, TRUE);
g_slice_free (GeometryParseData, data);
}
static const gchar *geometry_valid_path_list[] = {
"geometry",
"button/geometry",
"bounds/geometry",
"view/geometry",
"section/view/geometry",
"outline/geometry",
"point/outline/geometry",
};
static void
geometry_start_element_callback (GMarkupParseContext *pcontext,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error)
{
GeometryParseData *data = user_data;
const gchar *attribute;
if (!validate (geometry_valid_path_list,
G_N_ELEMENTS (geometry_valid_path_list),
element_name,
data->element_stack,
error)) {
return;
}
if (g_strcmp0 (element_name, "bounds") == 0) {
EekBounds bounds;
attribute = get_attribute (attribute_names, attribute_values, "x");
if (attribute == NULL) {
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_MISSING_ATTRIBUTE,
"no \"x\" attribute for \"bounds\"");
return;
}
bounds.x = g_strtod (attribute, NULL);
attribute = get_attribute (attribute_names, attribute_values,
"y");
if (attribute == NULL) {
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_MISSING_ATTRIBUTE,
"no \"y\" attribute for \"bounds\"");
return;
}
bounds.y = g_strtod (attribute, NULL);
attribute = get_attribute (attribute_names, attribute_values,
"width");
if (attribute == NULL) {
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_MISSING_ATTRIBUTE,
"no \"width\" attribute for \"bounds\"");
return;
}
bounds.width = g_strtod (attribute, NULL);
attribute = get_attribute (attribute_names, attribute_values,
"height");
if (attribute == NULL) {
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_MISSING_ATTRIBUTE,
"no \"height\" attribute for \"bounds\"");
return;
}
bounds.height = g_strtod (attribute, NULL);
data->bounds = bounds;
goto out;
}
if (g_strcmp0 (element_name, "view") == 0) {
/* Create an empty keyboard to which geometry and symbols
information are applied. */
struct squeek_view *view = squeek_view_new(data->bounds);
data->views[data->view_idx] = view;
}
if (g_strcmp0 (element_name, "section") == 0) {
gint angle = 0;
attribute = get_attribute (attribute_names, attribute_values,
"angle");
if (attribute != NULL) {
angle = strtol (attribute, NULL, 10);
}
data->row = squeek_view_create_row(data->views[data->view_idx], angle);
goto out;
}
if (g_strcmp0 (element_name, "button") == 0) {
const gchar *base_name = get_attribute (attribute_names, attribute_values,
"name");
if (base_name == NULL) {
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_MISSING_ATTRIBUTE,
"no \"name\" attribute for \"button\"");
return;
}
const gchar *oref_name = get_attribute (attribute_names, attribute_values,
"oref");
if (oref_name == NULL) {
oref_name = "default";
}
const gchar *keycode_name = get_attribute (attribute_names, attribute_values,
"keycode");
guint oref = GPOINTER_TO_UINT(g_hash_table_lookup(data->outlineid_oref_hash,
oref_name));
const gchar *name = base_name;
g_hash_table_insert (data->keyname_oref_hash,
g_strdup(name),
GUINT_TO_POINTER(oref));
struct squeek_button *button = g_hash_table_lookup(data->name_button_hash, name);
// never gets used! this section gets executed before any buttons get defined
if (button) {
if (keycode_name != NULL) {
// This sets the keycode for all buttons,
// since they share state
// TODO: get rid of this in the parser;
// this belongs after keymap is defined
struct squeek_key *key = squeek_button_get_key(button);
squeek_key_set_keycode(key, strtol (keycode_name, NULL, 10));
}
}
goto out;
}
if (g_strcmp0 (element_name, "outline") == 0) {
attribute = get_attribute (attribute_names, attribute_values, "id");
if (attribute == NULL) {
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_MISSING_ATTRIBUTE,
"no \"id\" attribute for \"outline\"");
return;
}
data->outline_id = g_strdup (attribute);
attribute = get_attribute (attribute_names, attribute_values,
"corner-radius");
if (attribute != NULL)
data->corner_radius = g_strtod (attribute, NULL);
goto out;
}
if (g_strcmp0 (element_name, "point") == 0) {
EekPoint *point;
gdouble x, y;
attribute = get_attribute (attribute_names, attribute_values, "x");
if (attribute == NULL) {
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_MISSING_ATTRIBUTE,
"no \"x\" attribute for \"bounds\"");
return;
}
x = g_strtod (attribute, NULL);
attribute = get_attribute (attribute_names, attribute_values, "y");
if (attribute == NULL) {
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_MISSING_ATTRIBUTE,
"no \"y\" attribute for \"bounds\"");
return;
}
y = g_strtod (attribute, NULL);
point = g_slice_new (EekPoint);
point->x = x;
point->y = y;
data->points = g_slist_prepend (data->points, point);
goto out;
}
out:
data->element_stack = g_slist_prepend (data->element_stack,
g_strdup (element_name));
data->text->len = 0;
}
/**
* eek_keyboard_add_outline:
* @keyboard: an #EekKeyboard
* @outline: an #EekOutline
*
* Register an outline of @keyboard.
* Returns: an unsigned integer ID of the registered outline, for
* later reference
*/
static guint
add_outline (GArray *outline_array,
EekOutline *outline)
{
EekOutline *_outline;
_outline = eek_outline_copy (outline);
g_array_append_val (outline_array, *_outline);
/* don't use eek_outline_free here, so as to keep _outline->points */
g_slice_free (EekOutline, _outline);
return outline_array->len - 1;
}
static void
geometry_end_element_callback (GMarkupParseContext *pcontext,
const gchar *element_name,
gpointer user_data,
GError **error)
{
GeometryParseData *data = user_data;
GSList *head = data->element_stack;
g_free (head->data);
data->element_stack = g_slist_next (data->element_stack);
g_slist_free1 (head);
const gchar *text = g_strndup (data->text->str, data->text->len);
if (g_strcmp0 (element_name, "view") == 0) {
data->view_idx++;
return;
}
if (g_strcmp0 (element_name, "section") == 0) {
// Split text on spaces and process each part
unsigned head = 0;
while (head < strlen(text)) {
// Skip to the first non-space character
for (; head < strlen(text); head++) {
if (text[head] != ' ') {
break;
}
}
unsigned start = head;
// Skip to the first space character
for (; head < strlen(text); head++) {
if (text[head] == ' ') {
break;
}
}
unsigned end = head;
/// Reached the end
if (start == end) {
break;
}
gchar *name = g_strndup (&text[start], end - start);
struct squeek_button *button = g_hash_table_lookup(data->name_button_hash, name);
if (!button) {
// Save button name together with its level,
// to account for buttons with the same name in multiple levels
guint keycode = data->keycode++;
guint oref = GPOINTER_TO_UINT(g_hash_table_lookup(data->keyname_oref_hash, name));
// default value gives idx 0, which is guaranteed to be occupied
button = squeek_row_create_button (data->row, keycode, oref);
g_hash_table_insert (data->name_button_hash,
g_strdup(name),
button);
} else {
struct squeek_button *new_button = squeek_row_create_button_with_state(data->row, button);
if (!new_button) {
g_set_error (error,
G_MARKUP_ERROR,
G_MARKUP_ERROR_MISSING_ATTRIBUTE,
"Couldn't create a shared button");
return;
}
}
}
data->row = NULL;
data->num_rows = 0;
return;
}
if (g_strcmp0 (element_name, "outline") == 0) {
EekOutline *outline = g_slice_new (EekOutline);
outline->corner_radius = data->corner_radius;
data->corner_radius = 0.0;
outline->num_points = g_slist_length (data->points);
outline->points = g_slice_alloc0 (sizeof (EekPoint) *
outline->num_points);
guint i;
for (i = 0, head = data->points = g_slist_reverse (data->points);
head && i < outline->num_points;
head = g_slist_next (head), i++) {
memcpy (&outline->points[i], head->data, sizeof (EekPoint));
g_slice_free1 (sizeof (EekPoint), head->data);
}
g_slist_free (data->points);
data->points = NULL;
guint oref = add_outline (data->outline_array, outline);
g_hash_table_insert (data->outlineid_oref_hash,
data->outline_id,
GUINT_TO_POINTER(oref));
return;
}
}
static void
geometry_text_callback (GMarkupParseContext *pcontext,
const gchar *text,
gsize text_len,
gpointer user_data,
GError **error)
{
GeometryParseData *data = user_data;
g_string_append_len (data->text, text, (gssize)text_len);
}
static const GMarkupParser geometry_parser = {
geometry_start_element_callback,
geometry_end_element_callback,
geometry_text_callback,
0,
0
};
struct _SymbolsParseData {
GSList *element_stack;
GString *text;
@ -641,139 +251,6 @@ struct _SymbolsParseData {
};
typedef struct _SymbolsParseData SymbolsParseData;
static SymbolsParseData *
symbols_parse_data_new (LevelKeyboard *keyboard)
{
SymbolsParseData *data = g_slice_new0 (SymbolsParseData);
data->keyboard = keyboard;
data->text = g_string_sized_new (BUFSIZE);
return data;
}
static void
symbols_parse_data_free (SymbolsParseData *data)
{
g_string_free (data->text, TRUE);
g_slice_free (SymbolsParseData, data);
}
static const gchar *symbols_valid_path_list[] = {
"symbols",
"symbol/symbols",
"include/symbols",
};
static void
symbols_start_element_callback (GMarkupParseContext *pcontext,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error)
{
SymbolsParseData *data = user_data;
const gchar *attribute;
if (!validate (symbols_valid_path_list,
G_N_ELEMENTS (symbols_valid_path_list),
element_name,
data->element_stack,
error))
return;
if (g_strcmp0 (element_name, "symbol") == 0) {
attribute = get_attribute (attribute_names, attribute_values,
"label");
if (attribute != NULL)
data->label = g_strdup (attribute);
attribute = get_attribute (attribute_names, attribute_values,
"icon");
if (attribute != NULL)
data->icon = g_strdup (attribute);
attribute = get_attribute (attribute_names, attribute_values,
"tooltip");
if (attribute != NULL)
data->tooltip = g_strdup (attribute);
}
data->element_stack = g_slist_prepend (data->element_stack,
g_strdup (element_name));
data->text->len = 0;
}
static void
symbols_end_element_callback (GMarkupParseContext *pcontext,
const gchar *element_name,
gpointer user_data,
GError **error)
{
SymbolsParseData *data = user_data;
GSList *head = data->element_stack;
gchar *text;
g_free (head->data);
data->element_stack = g_slist_next (data->element_stack);
g_slist_free1 (head);
// TODO: this could all be moved to text handler
text = g_strndup (data->text->str, data->text->len);
if (g_strcmp0 (element_name, "symbol") == 0) {
gchar *name = text;
struct squeek_button *button = eek_keyboard_find_button_by_name (data->keyboard,
name);
if (button) {
squeek_key_add_symbol(
squeek_button_get_key(button),
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;
}
if (g_strcmp0 (element_name, "invalid") == 0) {
goto out;
}
out:
g_free (text);
}
static void
symbols_text_callback (GMarkupParseContext *pcontext,
const gchar *text,
gsize text_len,
gpointer user_data,
GError **error)
{
SymbolsParseData *data = user_data;
g_string_append_len (data->text, text, text_len);
}
static const GMarkupParser symbols_parser = {
symbols_start_element_callback,
symbols_end_element_callback,
symbols_text_callback,
0,
0
};
struct _PrerequisitesParseData {
GSList *element_stack;
@ -783,157 +260,13 @@ struct _PrerequisitesParseData {
};
typedef struct _PrerequisitesParseData PrerequisitesParseData;
static PrerequisitesParseData *
prerequisites_parse_data_new (void)
{
PrerequisitesParseData *data = g_slice_new0 (PrerequisitesParseData);
data->text = g_string_sized_new (BUFSIZE);
return data;
}
static void
prerequisites_parse_data_free (PrerequisitesParseData *data)
{
g_list_free_full (data->prerequisites, g_free);
g_string_free (data->text, TRUE);
g_slice_free (PrerequisitesParseData, data);
}
static void
prerequisites_start_element_callback (GMarkupParseContext *pcontext,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer user_data,
GError **error)
{
PrerequisitesParseData *data = user_data;
if (!validate (symbols_valid_path_list,
G_N_ELEMENTS (symbols_valid_path_list),
element_name,
data->element_stack,
error))
return;
data->element_stack = g_slist_prepend (data->element_stack,
g_strdup (element_name));
data->text->len = 0;
}
static void
prerequisites_end_element_callback (GMarkupParseContext *pcontext,
const gchar *element_name,
gpointer user_data,
GError **error)
{
PrerequisitesParseData *data = user_data;
GSList *head = data->element_stack;
g_free (head->data);
data->element_stack = g_slist_next (data->element_stack);
g_slist_free1 (head);
if (g_strcmp0 (element_name, "include") == 0) {
data->prerequisites = g_list_append (data->prerequisites,
g_strndup (data->text->str,
data->text->len));
}
}
static void
prerequisites_text_callback (GMarkupParseContext *pcontext,
const gchar *text,
gsize text_len,
gpointer user_data,
GError **error)
{
PrerequisitesParseData *data = user_data;
g_string_append_len (data->text, text, text_len);
}
static const GMarkupParser prerequisites_parser = {
prerequisites_start_element_callback,
prerequisites_end_element_callback,
prerequisites_text_callback,
0,
0
};
LevelKeyboard *
eek_xml_layout_real_create_keyboard (EekLayout *self,
eek_xml_layout_real_create_keyboard (const char *keyboard_type,
EekboardContextService *manager)
{
EekXmlLayout *layout = EEK_XML_LAYOUT (self);
EekXmlLayoutPrivate *priv = eek_xml_layout_get_instance_private (layout);
gboolean retval;
/* Read geometry information. */
gchar *filename = g_strdup_printf ("%s.xml", priv->desc->geometry);
gchar *path = g_build_filename (priv->keyboards_dir, "geometry", filename, NULL);
g_free (filename);
GArray *outline_array = g_array_new (FALSE, TRUE, sizeof (EekOutline));
// char* -> struct squeek_button*
GHashTable *name_button_hash =
g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
NULL);
// One view for each level
struct squeek_view *views[4] = {0};
GError *error = NULL;
retval = parse_geometry (path, views, outline_array, name_button_hash, &error);
g_free (path);
if (!retval) {
for (uint i = 0; i < 4; i++) {
g_object_unref (views[i]);
}
g_warning ("can't parse geometry file %s: %s",
priv->desc->geometry,
error->message);
g_error_free (error);
return NULL;
}
LevelKeyboard *keyboard = level_keyboard_new(manager, views, name_button_hash);
keyboard->outline_array = outline_array;
// FIXME: are symbols shared betwen views?
/* Read symbols information. */
GList *loaded = NULL;
retval = parse_symbols_with_prerequisites (priv->keyboards_dir,
priv->desc->symbols,
keyboard,
&loaded,
&error);
g_list_free_full (loaded, g_free);
if (!retval) {
for (uint i = 0; i < 4; i++) {
if (views[i]) {
g_object_unref(views[i]);
views[i] = NULL;
}
}
//g_object_unref (view);
g_warning ("can't parse symbols file %s: %s",
priv->desc->symbols,
error->message);
g_error_free (error);
return NULL;
}
for (uint i = 0; i < 4; i++) {
if (views[i]) {
squeek_view_place_contents(views[i], keyboard);
}
}
return keyboard;
struct squeek_layout *layout = squeek_load_layout(keyboard_type);
squeek_layout_place_contents(layout);
return level_keyboard_new(manager, layout);
}
static void
@ -1116,190 +449,6 @@ eek_xml_keyboard_desc_free (EekXmlKeyboardDesc *desc)
g_slice_free (EekXmlKeyboardDesc, desc);
}
static gboolean
parse_geometry (const gchar *path, struct squeek_view **views, GArray *outline_array, GHashTable *name_button_hash, GError **error)
{
GeometryParseData *data;
GMarkupParseContext *pcontext;
GFile *file;
GFileInputStream *input;
gboolean retval;
file = g_str_has_prefix (path, "resource://")
? g_file_new_for_uri (path)
: g_file_new_for_path (path);
input = g_file_read (file, NULL, error);
g_object_unref (file);
if (input == NULL)
return FALSE;
data = geometry_parse_data_new (views, name_button_hash, outline_array);
pcontext = g_markup_parse_context_new (&geometry_parser,
0,
data,
NULL);
retval = parse (pcontext, G_INPUT_STREAM (input), error);
g_markup_parse_context_free (pcontext);
g_object_unref (input);
if (!retval) {
geometry_parse_data_free (data);
return FALSE;
}
/* Resolve outline references. */
/*
* GHashTable *oref_hash;
GHashTableIter iter;
gpointer k, v;
oref_hash = g_hash_table_new (g_str_hash, g_str_equal);
g_hash_table_iter_init (&iter, data->oref_outline_hash);
while (g_hash_table_iter_next (&iter, &k, &v)) {
EekOutline *outline = v;
gulong oref;
oref = add_outline (outline_array, outline);
g_hash_table_insert (oref_hash, k, GUINT_TO_POINTER(oref));
}*/
/*
g_hash_table_iter_init (&iter, data->key_oref_hash);
while (g_hash_table_iter_next (&iter, &k, &v)) {
gpointer oref;
if (g_hash_table_lookup_extended (oref_hash, v, NULL, &oref))
eek_key_set_oref (EEK_KEY(k), GPOINTER_TO_UINT(oref));
}*/
// g_hash_table_destroy (oref_hash);
geometry_parse_data_free (data);
return TRUE;
}
static gboolean
parse_symbols_with_prerequisites (const gchar *keyboards_dir,
const gchar *name,
LevelKeyboard *keyboard,
GList **loaded,
GError **error)
{
gchar *filename, *path;
GList *prerequisites, *p;
GError *prerequisites_error;
gboolean retval;
for (p = *loaded; p; p = p->next) {
if (g_strcmp0 (p->data, name) == 0) {
g_set_error (error,
EEK_ERROR,
EEK_ERROR_LAYOUT_ERROR,
"%s already loaded",
name);
return FALSE;
}
}
*loaded = g_list_prepend (*loaded, g_strdup (name));
filename = g_strdup_printf ("%s.xml", name);
path = g_build_filename (keyboards_dir, "symbols", filename, NULL);
g_free (filename);
prerequisites_error = NULL;
prerequisites = parse_prerequisites (path, &prerequisites_error);
if (prerequisites_error != NULL) {
g_propagate_error (error, prerequisites_error);
return FALSE;
}
for (p = prerequisites; p; p = p->next) {
retval = parse_symbols_with_prerequisites (keyboards_dir,
p->data,
keyboard,
loaded,
error);
if (!retval)
return FALSE;
}
g_list_free_full (prerequisites, (GDestroyNotify)g_free);
retval = parse_symbols (path, keyboard, error);
g_free (path);
return retval;
}
static gboolean
parse_symbols (const gchar *path, LevelKeyboard *keyboard, GError **error)
{
SymbolsParseData *data;
GMarkupParseContext *pcontext;
GFile *file;
GFileInputStream *input;
gboolean retval;
file = g_str_has_prefix (path, "resource://")
? g_file_new_for_uri (path)
: g_file_new_for_path (path);
input = g_file_read (file, NULL, error);
g_object_unref (file);
if (input == NULL)
return FALSE;
data = symbols_parse_data_new (keyboard);
pcontext = g_markup_parse_context_new (&symbols_parser,
0,
data,
NULL);
retval = parse (pcontext, G_INPUT_STREAM (input), error);
g_markup_parse_context_free (pcontext);
g_object_unref (input);
if (!retval) {
symbols_parse_data_free (data);
return FALSE;
}
symbols_parse_data_free (data);
return TRUE;
}
static GList *
parse_prerequisites (const gchar *path, GError **error)
{
PrerequisitesParseData *data;
GMarkupParseContext *pcontext;
GFile *file;
GFileInputStream *input;
GList *prerequisites;
gboolean retval;
file = g_str_has_prefix (path, "resource://")
? g_file_new_for_uri (path)
: g_file_new_for_path (path);
input = g_file_read (file, NULL, error);
g_object_unref (file);
if (input == NULL)
return FALSE;
data = prerequisites_parse_data_new ();
pcontext = g_markup_parse_context_new (&prerequisites_parser,
0,
data,
NULL);
retval = parse (pcontext, G_INPUT_STREAM (input), error);
g_markup_parse_context_free (pcontext);
g_object_unref (input);
if (!retval) {
prerequisites_parse_data_free (data);
return NULL;
}
prerequisites = data->prerequisites;
data->prerequisites = NULL;
prerequisites_parse_data_free (data);
return prerequisites;
}
static GList *
parse_keyboards (const gchar *path, GError **error)
{

View File

@ -63,7 +63,7 @@ EekXmlKeyboardDesc *eek_xml_keyboard_desc_copy (EekXmlKeyboardDesc *desc);
void eek_xml_keyboard_desc_free (EekXmlKeyboardDesc *desc);
LevelKeyboard *
eek_xml_layout_real_create_keyboard (EekLayout *self,
eek_xml_layout_real_create_keyboard (const char *keyboard_type,
EekboardContextService *manager);
G_END_DECLS
#endif /* EEK_XML_LAYOUT_H */

View File

@ -6,34 +6,3 @@ squeek_keymap_get_entries_for_keyval (struct xkb_keymap *xkb_keymap,
guint keyval,
GdkKeymapKey **keys,
guint *n_keys);
static const char *keymap_header = "xkb_keymap {\n\
\n";
static const char *keymap_keycodes_header = "\
xkb_keycodes \"squeekboard\" {\n\n\
minimum = 8;\n\
maximum = 255;\n\
\n";
static const char *keymap_symbols_header = "\
xkb_symbols \"squeekboard\" {\n\
\n\
name[Group1] = \"Letters\";\n\
name[Group2] = \"Numbers/Symbols\";\n\
\n";
static const char *keymap_footer = "\
xkb_types \"squeekboard\" {\n\
\n\
type \"TWO_LEVEL\" {\n\
modifiers = Shift;\n\
map[Shift] = Level2;\n\
level_name[Level1] = \"Base\";\n\
level_name[Level2] = \"Shift\";\n\
};\n\
};\n\
\n\
xkb_compatibility \"squeekboard\" {\n\
};\n\
};";