Add XML layout engine (WIP).
This commit is contained in:
		
							
								
								
									
										343
									
								
								eek/eek-xml-layout.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										343
									
								
								eek/eek-xml-layout.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,343 @@
 | 
			
		||||
/**
 | 
			
		||||
 * SECTION:eek-xml-layout
 | 
			
		||||
 * @short_description: Layout engine which loads layout information from XML
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#endif  /* HAVE_CONFIG_H */
 | 
			
		||||
 | 
			
		||||
#include "eek-xml-layout.h"
 | 
			
		||||
#include "eek-keyboard.h"
 | 
			
		||||
#include "eek-section.h"
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    PROP_0,
 | 
			
		||||
    PROP_SOURCE,
 | 
			
		||||
    PROP_LAST
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE (EekXmlLayout, eek_xml_layout, EEK_TYPE_LAYOUT);
 | 
			
		||||
 | 
			
		||||
#define EEK_XML_LAYOUT_GET_PRIVATE(obj)                                  \
 | 
			
		||||
    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_XML_LAYOUT, EekXmlLayoutPrivate))
 | 
			
		||||
 | 
			
		||||
struct _EekXmlLayoutPrivate
 | 
			
		||||
{
 | 
			
		||||
    GInputStream *source;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define BUFSIZE	8192
 | 
			
		||||
 | 
			
		||||
struct _ParseCallbackData {
 | 
			
		||||
    GSList *element_stack;
 | 
			
		||||
    GString *text;
 | 
			
		||||
    EekLayout *layout;
 | 
			
		||||
    EekKeyboard *keyboard;
 | 
			
		||||
    EekSection *section;
 | 
			
		||||
    EekKey *key;
 | 
			
		||||
};
 | 
			
		||||
typedef struct _ParseCallbackData ParseCallbackData;
 | 
			
		||||
 | 
			
		||||
static const gchar *valid_path_list[] = {
 | 
			
		||||
    "keyboard",
 | 
			
		||||
    "keyboard/bounds",
 | 
			
		||||
    "keyboard/section",
 | 
			
		||||
    "keyboard/outline",
 | 
			
		||||
    "section/bounds",
 | 
			
		||||
    "section/angle",
 | 
			
		||||
    "section/key",
 | 
			
		||||
    "bounds/key",
 | 
			
		||||
    "outline/key",
 | 
			
		||||
    "keysyms/key",
 | 
			
		||||
    "keycode/key",
 | 
			
		||||
    "index/key",
 | 
			
		||||
    "groups/keysyms",
 | 
			
		||||
    "levels/keysyms",
 | 
			
		||||
    "keysym/keysyms",
 | 
			
		||||
    "point/outline/keyboard"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static gchar *
 | 
			
		||||
join_element_names (GSList *element_names)
 | 
			
		||||
{
 | 
			
		||||
    GString *string = g_string_sized_new (64);
 | 
			
		||||
 | 
			
		||||
    if (element_names == NULL)
 | 
			
		||||
        return g_strdup ("");
 | 
			
		||||
    else
 | 
			
		||||
        for (; element_names; element_names = g_slist_next (element_names)) {
 | 
			
		||||
            g_string_append (string, element_names->data);
 | 
			
		||||
            if (g_slist_next (element_names))
 | 
			
		||||
                g_string_append (string, "/");
 | 
			
		||||
        }
 | 
			
		||||
    return g_string_free (string, FALSE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
validate (const gchar  *element_name,
 | 
			
		||||
          GSList       *element_stack,
 | 
			
		||||
          GError      **error)
 | 
			
		||||
{
 | 
			
		||||
    gint i;
 | 
			
		||||
    gchar *element_path;
 | 
			
		||||
 | 
			
		||||
    element_stack = g_slist_prepend (element_stack, element_name);
 | 
			
		||||
    element_path = join_element_names (element_stack);
 | 
			
		||||
    for (i = 0; i < G_N_ELEMENTS(valid_path_list); i++) {
 | 
			
		||||
        if (*valid_path_list[i] == '@')
 | 
			
		||||
            continue;
 | 
			
		||||
        if (g_strcmp0 (element_path, valid_path_list[i]) == 0)
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (i == G_N_ELEMENTS(valid_path_list)) {
 | 
			
		||||
        g_set_error (error,
 | 
			
		||||
                     G_MARKUP_ERROR,
 | 
			
		||||
                     G_MARKUP_ERROR_UNKNOWN_ELEMENT,
 | 
			
		||||
                     "%s cannot appear under %s",
 | 
			
		||||
                     element_name,
 | 
			
		||||
                     element_path);
 | 
			
		||||
        g_free (element_path);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    g_free (element_path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
start_element_callback (GMarkupParseContext *pcontext,
 | 
			
		||||
                        const gchar         *element_name,
 | 
			
		||||
                        const gchar        **attribute_names,
 | 
			
		||||
                        const gchar        **attribute_values,
 | 
			
		||||
                        gpointer             user_data,
 | 
			
		||||
                        GError             **error)
 | 
			
		||||
{
 | 
			
		||||
    ParseCallbackData *data = user_data;
 | 
			
		||||
    const gchar **names = attribute_names;
 | 
			
		||||
    const gchar **values = attribute_values;
 | 
			
		||||
    gint column = -1, row = -1;
 | 
			
		||||
    gchar *name = NULL;
 | 
			
		||||
 | 
			
		||||
    validate (element_name, data->element_stack, error);
 | 
			
		||||
    if (error && *error)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    while (*names && *values) {
 | 
			
		||||
        if (g_strcmp0 (*names, "column") == 0)
 | 
			
		||||
            column = strtol (*values, NULL, 10);
 | 
			
		||||
        else if (g_strcmp0 (*names, "row") == 0)
 | 
			
		||||
            row = strtol (*values, NULL, 10);
 | 
			
		||||
        else if (g_strcmp0 (*names, "name") == 0)
 | 
			
		||||
            name = g_strdup (*values);
 | 
			
		||||
        names++;
 | 
			
		||||
        values++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (g_strcmp0 (element_name, "keyboard") == 0) {
 | 
			
		||||
        data->keyboard = g_object_new (EEK_TYPE_KEYBOARD,
 | 
			
		||||
                                       "layout", data->layout,
 | 
			
		||||
                                       NULL);
 | 
			
		||||
        if (name)
 | 
			
		||||
            eek_element_set_name (EEK_ELEMENT(data->keyboard), name);
 | 
			
		||||
    } else if (g_strcmp0 (element_name, "section") == 0) {
 | 
			
		||||
        data->section = eek_keyboard_create_section (data->keyboard);
 | 
			
		||||
        if (name)
 | 
			
		||||
            eek_element_set_name (EEK_ELEMENT(data->section), name);
 | 
			
		||||
    } else if (g_strcmp0 (element_name, "key") == 0) {
 | 
			
		||||
        data->key = eek_section_create_key (data->section, column, row);
 | 
			
		||||
        if (name)
 | 
			
		||||
            eek_element_set_name (EEK_ELEMENT(data->key), name);
 | 
			
		||||
    }
 | 
			
		||||
    g_free (name);
 | 
			
		||||
 | 
			
		||||
    data->element_stack = g_slist_prepend (data->element_stack,
 | 
			
		||||
                                           g_strdup (element_name));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
end_element_callback (GMarkupParseContext *pcontext,
 | 
			
		||||
                      const gchar         *element_name,
 | 
			
		||||
                      gpointer             user_data,
 | 
			
		||||
                      GError             **error)
 | 
			
		||||
{
 | 
			
		||||
    ParseCallbackData *data = user_data;
 | 
			
		||||
 | 
			
		||||
    g_free (data->element_stack->data);
 | 
			
		||||
    data->element_stack = g_slist_remove_link (data->element_stack,
 | 
			
		||||
                                               data->element_stack);
 | 
			
		||||
    g_slist_free1 (data->element_stack);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
text_callback (GMarkupParseContext *pcontext,
 | 
			
		||||
               const gchar         *text,
 | 
			
		||||
               gsize                text_len,  
 | 
			
		||||
               gpointer             user_data,
 | 
			
		||||
               GError             **error)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const GMarkupParser parser = {
 | 
			
		||||
    start_element_callback,
 | 
			
		||||
    end_element_callback,
 | 
			
		||||
    text_callback,
 | 
			
		||||
    0,
 | 
			
		||||
    0
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static EekKeyboard *
 | 
			
		||||
eek_xml_layout_real_create_keyboard (EekLayout *self,
 | 
			
		||||
                                     gdouble    initial_width,
 | 
			
		||||
                                     gdouble    initial_height)
 | 
			
		||||
{
 | 
			
		||||
    EekXmlLayoutPrivate *priv = EEK_XML_LAYOUT_GET_PRIVATE (self);
 | 
			
		||||
    GMarkupParseContext *pcontext;
 | 
			
		||||
    GError *error;
 | 
			
		||||
    gchar buffer[BUFSIZE];
 | 
			
		||||
    ParseCallbackData data;
 | 
			
		||||
 | 
			
		||||
    g_return_val_if_fail (priv->source, NULL);
 | 
			
		||||
 | 
			
		||||
    data.element_stack = NULL;
 | 
			
		||||
    data.text = g_string_sized_new (BUFSIZE);
 | 
			
		||||
    data.keyboard = NULL;
 | 
			
		||||
    pcontext = g_markup_parse_context_new (&parser, 0, &data, NULL);
 | 
			
		||||
    while (1) {
 | 
			
		||||
        gssize nread;
 | 
			
		||||
                
 | 
			
		||||
        error = NULL;
 | 
			
		||||
        nread = g_input_stream_read (G_INPUT_STREAM(priv->source),
 | 
			
		||||
                                     buffer, sizeof buffer, NULL,
 | 
			
		||||
                                     &error);
 | 
			
		||||
        if (nread <= 0)
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        error = NULL;
 | 
			
		||||
        if (!g_markup_parse_context_parse (pcontext, buffer, nread, &error))
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    error = NULL;
 | 
			
		||||
    g_markup_parse_context_end_parse (pcontext, &error);
 | 
			
		||||
    g_markup_parse_context_free (pcontext);
 | 
			
		||||
    g_string_free (data.text, TRUE);
 | 
			
		||||
 | 
			
		||||
    return data.keyboard;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_xml_layout_set_property (GObject      *object,
 | 
			
		||||
                             guint         prop_id,
 | 
			
		||||
                             const GValue *value,
 | 
			
		||||
                             GParamSpec   *pspec)
 | 
			
		||||
{
 | 
			
		||||
    switch (prop_id) {
 | 
			
		||||
    case PROP_SOURCE:
 | 
			
		||||
        eek_xml_layout_set_source (EEK_XML_LAYOUT(object),
 | 
			
		||||
                                   g_value_get_object (value));
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        g_object_set_property (object,
 | 
			
		||||
                               g_param_spec_get_name (pspec),
 | 
			
		||||
                               value);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_xml_layout_get_property (GObject    *object,
 | 
			
		||||
                             guint       prop_id,
 | 
			
		||||
                             GValue     *value,
 | 
			
		||||
                             GParamSpec *pspec)
 | 
			
		||||
{
 | 
			
		||||
    switch (prop_id) {
 | 
			
		||||
    case PROP_SOURCE:
 | 
			
		||||
        g_value_set_object (value,
 | 
			
		||||
                            eek_xml_layout_get_source (EEK_XML_LAYOUT(object)));
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        g_object_get_property (object,
 | 
			
		||||
                               g_param_spec_get_name (pspec),
 | 
			
		||||
                               value);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_xml_layout_dispose (GObject *object)
 | 
			
		||||
{
 | 
			
		||||
    EekXmlLayoutPrivate *priv = EEK_XML_LAYOUT_GET_PRIVATE (object);
 | 
			
		||||
 | 
			
		||||
    if (priv->source) {
 | 
			
		||||
        g_object_unref (priv->source);
 | 
			
		||||
        priv->source = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_xml_layout_class_init (EekXmlLayoutClass *klass)
 | 
			
		||||
{
 | 
			
		||||
    EekLayoutClass *layout_class = EEK_LAYOUT_CLASS (klass);
 | 
			
		||||
    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 | 
			
		||||
    GParamSpec *pspec;
 | 
			
		||||
 | 
			
		||||
    g_type_class_add_private (gobject_class, sizeof (EekXmlLayoutPrivate));
 | 
			
		||||
 | 
			
		||||
    layout_class->create_keyboard = eek_xml_layout_real_create_keyboard;
 | 
			
		||||
 | 
			
		||||
    gobject_class->set_property = eek_xml_layout_set_property;
 | 
			
		||||
    gobject_class->get_property = eek_xml_layout_get_property;
 | 
			
		||||
    gobject_class->dispose = eek_xml_layout_dispose;
 | 
			
		||||
 | 
			
		||||
    pspec = g_param_spec_object ("source",
 | 
			
		||||
				 "Source",
 | 
			
		||||
				 "XML source input stram",
 | 
			
		||||
				 G_TYPE_INPUT_STREAM,
 | 
			
		||||
				 G_PARAM_READWRITE);
 | 
			
		||||
    g_object_class_install_property (gobject_class, PROP_SOURCE, pspec);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_xml_layout_init (EekXmlLayout *self)
 | 
			
		||||
{
 | 
			
		||||
    EekXmlLayoutPrivate *priv;
 | 
			
		||||
 | 
			
		||||
    priv = self->priv = EEK_XML_LAYOUT_GET_PRIVATE (self);
 | 
			
		||||
    priv->source = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
EekLayout *
 | 
			
		||||
eek_xml_layout_new (GInputStream *source)
 | 
			
		||||
{
 | 
			
		||||
    return g_object_new (EEK_TYPE_XML_LAYOUT, "source", source, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
eek_xml_layout_set_source (EekXmlLayout *layout,
 | 
			
		||||
                           GInputStream *source)
 | 
			
		||||
{
 | 
			
		||||
    EekXmlLayoutPrivate *priv;
 | 
			
		||||
 | 
			
		||||
    g_return_if_fail (EEK_IS_XML_LAYOUT(layout));
 | 
			
		||||
    g_return_if_fail (G_IS_INPUT_STREAM(source));
 | 
			
		||||
 | 
			
		||||
    priv = EEK_XML_LAYOUT_GET_PRIVATE(layout);
 | 
			
		||||
    if (priv->source)
 | 
			
		||||
        g_object_unref (priv->source);
 | 
			
		||||
    priv->source = g_object_ref (source);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GInputStream *
 | 
			
		||||
eek_xml_layout_get_source (EekXmlLayout *layout)
 | 
			
		||||
{
 | 
			
		||||
    EekXmlLayoutPrivate *priv;
 | 
			
		||||
 | 
			
		||||
    g_assert (EEK_IS_XML_LAYOUT(layout));
 | 
			
		||||
    priv = EEK_XML_LAYOUT_GET_PRIVATE(layout);
 | 
			
		||||
    return priv->source;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										47
									
								
								eek/eek-xml-layout.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								eek/eek-xml-layout.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
			
		||||
#ifndef EEK_XML_LAYOUT_H
 | 
			
		||||
#define EEK_XML_LAYOUT_H 1
 | 
			
		||||
 | 
			
		||||
#include <gio/gio.h>
 | 
			
		||||
#include "eek-layout.h"
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#define EEK_TYPE_XML_LAYOUT (eek_xml_layout_get_type())
 | 
			
		||||
#define EEK_XML_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEK_TYPE_XML_LAYOUT, EekXmlLayout))
 | 
			
		||||
#define EEK_XML_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEK_TYPE_XML_LAYOUT, EekXmlLayoutClass))
 | 
			
		||||
#define EEK_IS_XML_LAYOUT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEK_TYPE_XML_LAYOUT))
 | 
			
		||||
#define EEK_IS_XML_LAYOUT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_XML_LAYOUT))
 | 
			
		||||
#define EEK_XML_LAYOUT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_XML_LAYOUT, EekXmlLayoutClass))
 | 
			
		||||
 | 
			
		||||
typedef struct _EekXmlLayout        EekXmlLayout;
 | 
			
		||||
typedef struct _EekXmlLayoutClass   EekXmlLayoutClass;
 | 
			
		||||
typedef struct _EekXmlLayoutPrivate EekXmlLayoutPrivate;
 | 
			
		||||
 | 
			
		||||
struct _EekXmlLayout
 | 
			
		||||
{
 | 
			
		||||
    /*< private >*/
 | 
			
		||||
    EekLayout parent;
 | 
			
		||||
 | 
			
		||||
    EekXmlLayoutPrivate *priv;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _EekXmlLayoutClass
 | 
			
		||||
{
 | 
			
		||||
    /*< private >*/
 | 
			
		||||
    EekLayoutClass parent_class;
 | 
			
		||||
 | 
			
		||||
    /* padding */
 | 
			
		||||
    gpointer pdummy[24];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
GType          eek_xml_layout_get_type   (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
EekLayout     *eek_xml_layout_new        (GInputStream *source);
 | 
			
		||||
 | 
			
		||||
void           eek_xml_layout_set_source (EekXmlLayout *layout,
 | 
			
		||||
                                          GInputStream *source);
 | 
			
		||||
 | 
			
		||||
GInputStream * eek_xml_layout_get_source (EekXmlLayout *layout);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
#endif  /* EEK_XML_LAYOUT_H */
 | 
			
		||||
							
								
								
									
										207
									
								
								eek/eek-xml.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								eek/eek-xml.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,207 @@
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
#include <glib/gprintf.h>
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#endif  /* HAVE_CONFIG_H */
 | 
			
		||||
 | 
			
		||||
#include "eek-section.h"
 | 
			
		||||
#include "eek-key.h"
 | 
			
		||||
#include "eek-xml.h"
 | 
			
		||||
 | 
			
		||||
#define g_string_append_indent(string, indent)  \
 | 
			
		||||
    {                                           \
 | 
			
		||||
        gint i;                                 \
 | 
			
		||||
        for (i = 0; i < (indent); i++) {        \
 | 
			
		||||
            g_string_append (string, "    ");   \
 | 
			
		||||
        }                                       \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
G_INLINE_FUNC void
 | 
			
		||||
g_string_markup_printf (GString *output, const gchar *format, ...)
 | 
			
		||||
{
 | 
			
		||||
    gchar *escaped_text;
 | 
			
		||||
    va_list ap;
 | 
			
		||||
 | 
			
		||||
    va_start (ap, format);
 | 
			
		||||
    escaped_text = g_markup_vprintf_escaped (format, ap);
 | 
			
		||||
    va_end (ap);
 | 
			
		||||
 | 
			
		||||
    g_string_append (output, escaped_text);
 | 
			
		||||
    g_free (escaped_text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct _OutputCallbackData {
 | 
			
		||||
    GString *output;
 | 
			
		||||
    gint indent;
 | 
			
		||||
    GArray *outline_array;
 | 
			
		||||
};
 | 
			
		||||
typedef struct _OutputCallbackData OutputCallbackData;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
output_bounds (GString *output, EekBounds *bounds)
 | 
			
		||||
{
 | 
			
		||||
    g_string_markup_printf (output,
 | 
			
		||||
                            "<bounds>%lf,%lf,%lf,%lf</bounds>\n",
 | 
			
		||||
                            bounds->x,
 | 
			
		||||
                            bounds->y,
 | 
			
		||||
                            bounds->width,
 | 
			
		||||
                            bounds->height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
output_key_callback (EekElement *element, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    OutputCallbackData *data = user_data;
 | 
			
		||||
    EekBounds bounds;
 | 
			
		||||
    EekOutline *outline;
 | 
			
		||||
    gint i, num_groups, num_levels;
 | 
			
		||||
    guint *keysyms;
 | 
			
		||||
    gint column, row;
 | 
			
		||||
 | 
			
		||||
    eek_key_get_index (EEK_KEY(element), &column, &row);
 | 
			
		||||
    g_string_append_indent (data->output, data->indent);
 | 
			
		||||
    if (eek_element_get_name (element))
 | 
			
		||||
        g_string_markup_printf (data->output,
 | 
			
		||||
                                "<key column=\"%d\" row=\"%d\" name=\"%s\">\n",
 | 
			
		||||
                                column, row, eek_element_get_name (element));
 | 
			
		||||
    else
 | 
			
		||||
        g_string_markup_printf (data->output,
 | 
			
		||||
                                "<key column=\"%d\" row=\"%d\">\n",
 | 
			
		||||
                                column, row);
 | 
			
		||||
 | 
			
		||||
    eek_element_get_bounds (element, &bounds);
 | 
			
		||||
    g_string_append_indent (data->output, data->indent + 1);
 | 
			
		||||
    output_bounds (data->output, &bounds);
 | 
			
		||||
 | 
			
		||||
    outline = eek_key_get_outline (EEK_KEY(element));
 | 
			
		||||
    if (outline) {
 | 
			
		||||
        for (i = 0;
 | 
			
		||||
             i < data->outline_array->len &&
 | 
			
		||||
                 g_array_index (data->outline_array, gpointer, i) == outline;
 | 
			
		||||
             i++)
 | 
			
		||||
            ;
 | 
			
		||||
        if (i == data->outline_array->len)
 | 
			
		||||
            g_array_append_val (data->outline_array, outline);
 | 
			
		||||
        g_string_append_indent (data->output, data->indent + 1);
 | 
			
		||||
        g_string_markup_printf (data->output,
 | 
			
		||||
                                "<outline>outline%d</outline>\n",
 | 
			
		||||
                                i);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g_string_append_indent (data->output, data->indent + 1);
 | 
			
		||||
    g_string_markup_printf (data->output, "<keycode>%u</keycode>\n",
 | 
			
		||||
                            eek_key_get_keycode (EEK_KEY(element)));
 | 
			
		||||
 | 
			
		||||
    keysyms = NULL;
 | 
			
		||||
    eek_key_get_keysyms (EEK_KEY(element), &keysyms, &num_groups, &num_levels);
 | 
			
		||||
    if (keysyms) {
 | 
			
		||||
        g_string_append_indent (data->output, data->indent + 1);
 | 
			
		||||
        g_string_markup_printf (data->output,
 | 
			
		||||
                                "<keysyms groups=\"%d\" levels=\"%d\">\n",
 | 
			
		||||
                                num_groups, num_levels);
 | 
			
		||||
 | 
			
		||||
        for (i = 0; i < num_groups * num_levels; i++) {
 | 
			
		||||
            g_string_append_indent (data->output, data->indent + 2);
 | 
			
		||||
            if (keysyms[i] != EEK_INVALID_KEYSYM) {
 | 
			
		||||
                gchar *name = eek_keysym_to_string (keysyms[i]);
 | 
			
		||||
 | 
			
		||||
                g_string_markup_printf (data->output,
 | 
			
		||||
                                        "<keysym name=\"%s\">%u</keysym>\n",
 | 
			
		||||
                                        name, keysyms[i]);
 | 
			
		||||
                g_free (name);
 | 
			
		||||
            } else
 | 
			
		||||
                g_string_markup_printf (data->output,
 | 
			
		||||
                                        "<keysym>%u</keysym>\n",
 | 
			
		||||
                                        keysyms[i]);
 | 
			
		||||
        }
 | 
			
		||||
        g_string_append_indent (data->output, data->indent + 1);
 | 
			
		||||
        g_string_markup_printf (data->output, "</keysyms>\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g_string_append_indent (data->output, data->indent);
 | 
			
		||||
    g_string_markup_printf (data->output, "</key>\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
output_section_callback (EekElement *element, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    OutputCallbackData *data = user_data;
 | 
			
		||||
    EekBounds bounds;
 | 
			
		||||
    gint angle;
 | 
			
		||||
 | 
			
		||||
    g_string_append_indent (data->output, data->indent);
 | 
			
		||||
    if (eek_element_get_name (element))
 | 
			
		||||
        g_string_markup_printf (data->output, "<section name=\"%s\">\n",
 | 
			
		||||
                                eek_element_get_name (element));
 | 
			
		||||
    else
 | 
			
		||||
        g_string_markup_printf (data->output, "<section>\n");
 | 
			
		||||
 | 
			
		||||
    eek_element_get_bounds (element, &bounds);
 | 
			
		||||
    g_string_append_indent (data->output, data->indent + 1);
 | 
			
		||||
    output_bounds (data->output, &bounds);
 | 
			
		||||
 | 
			
		||||
    angle = eek_section_get_angle (EEK_SECTION(element));
 | 
			
		||||
    g_string_append_indent (data->output, data->indent + 1);
 | 
			
		||||
    g_string_markup_printf (data->output, "<angle>%d</angle>\n", angle);
 | 
			
		||||
    
 | 
			
		||||
    data->indent++;
 | 
			
		||||
    eek_container_foreach_child (EEK_CONTAINER(element),
 | 
			
		||||
                                 output_key_callback,
 | 
			
		||||
                                 data);
 | 
			
		||||
    data->indent--;
 | 
			
		||||
 | 
			
		||||
    g_string_append_indent (data->output, data->indent);
 | 
			
		||||
    g_string_markup_printf (data->output, "</section>\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
eek_keyboard_output (EekKeyboard *keyboard, GString *output, gint indent)
 | 
			
		||||
{
 | 
			
		||||
    OutputCallbackData data;
 | 
			
		||||
    EekBounds bounds;
 | 
			
		||||
    gint i;
 | 
			
		||||
 | 
			
		||||
    g_assert (EEK_IS_KEYBOARD(keyboard));
 | 
			
		||||
 
 | 
			
		||||
    g_string_append_indent (output, indent);
 | 
			
		||||
    g_string_markup_printf (output, "<?xml version=\"1.0\"?>\n<keyboard>\n");
 | 
			
		||||
 | 
			
		||||
    eek_element_get_bounds (EEK_ELEMENT(keyboard), &bounds);
 | 
			
		||||
    g_string_append_indent (output, indent + 1);
 | 
			
		||||
    output_bounds (output, &bounds);
 | 
			
		||||
 | 
			
		||||
    data.output = output;
 | 
			
		||||
    data.indent = indent;
 | 
			
		||||
    data.outline_array = g_array_new (FALSE, FALSE, sizeof (gpointer));
 | 
			
		||||
 | 
			
		||||
    data.indent++;
 | 
			
		||||
    eek_container_foreach_child (EEK_CONTAINER(keyboard),
 | 
			
		||||
                                 output_section_callback,
 | 
			
		||||
                                 &data);
 | 
			
		||||
    data.indent--;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < data.outline_array->len; i++) {
 | 
			
		||||
        EekOutline *outline;
 | 
			
		||||
        gint j;
 | 
			
		||||
 | 
			
		||||
        g_string_append_indent (output, indent + 1);
 | 
			
		||||
        g_string_markup_printf (output, "<outline id=\"outline%d\">\n", i);
 | 
			
		||||
 | 
			
		||||
        outline = g_array_index (data.outline_array, gpointer, i);
 | 
			
		||||
        for (j = 0; j < outline->num_points; j++) {
 | 
			
		||||
            g_string_append_indent (output, indent + 2);
 | 
			
		||||
            g_string_markup_printf (output, "<point>%lf,%lf</point>\n",
 | 
			
		||||
                                    outline->points[j].x,
 | 
			
		||||
                                    outline->points[j].y);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        g_string_append_indent (output, indent + 1);
 | 
			
		||||
        g_string_markup_printf (output, "</outline>\n");
 | 
			
		||||
    }
 | 
			
		||||
    g_array_free (data.outline_array, FALSE);
 | 
			
		||||
 | 
			
		||||
    g_string_append_indent (output, indent);
 | 
			
		||||
    g_string_markup_printf (output, "</keyboard>\n");
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								eek/eek-xml.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								eek/eek-xml.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
#ifndef EEK_XML_H
 | 
			
		||||
#define EEK_XML_H 1
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
#include "eek-keyboard.h"
 | 
			
		||||
#include "eek-xml-layout.h"
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
void eek_keyboard_print (EekKeyboard *keyboard, gint indent);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
#endif  /* EEK_XML_H */
 | 
			
		||||
		Reference in New Issue
	
	Block a user