Add experimental GtkDrawingArea based UI.
This commit is contained in:
		@ -78,6 +78,7 @@ EXTRA_HFILES=
 | 
				
			|||||||
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
 | 
					# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
 | 
				
			||||||
IGNORE_HFILES= eek-private.h \
 | 
					IGNORE_HFILES= eek-private.h \
 | 
				
			||||||
	eek-keysym.h \
 | 
						eek-keysym.h \
 | 
				
			||||||
 | 
						config.h \
 | 
				
			||||||
	$(NULL)
 | 
						$(NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Images to copy into HTML directory.
 | 
					# Images to copy into HTML directory.
 | 
				
			||||||
@ -101,6 +102,7 @@ expand_content_files=
 | 
				
			|||||||
GTKDOC_CFLAGS = $(GOBJECT2_CFLAGS)
 | 
					GTKDOC_CFLAGS = $(GOBJECT2_CFLAGS)
 | 
				
			||||||
GTKDOC_LIBS = $(top_srcdir)/eek/libeek.la \
 | 
					GTKDOC_LIBS = $(top_srcdir)/eek/libeek.la \
 | 
				
			||||||
	$(top_srcdir)/eek/libeek-clutter.la \
 | 
						$(top_srcdir)/eek/libeek-clutter.la \
 | 
				
			||||||
 | 
						$(top_srcdir)/eek/libeek-gtk.la \
 | 
				
			||||||
	$(top_srcdir)/eek/libeek-xkb.la \
 | 
						$(top_srcdir)/eek/libeek-xkb.la \
 | 
				
			||||||
	$(top_srcdir)/eek/libeek-xkl.la \
 | 
						$(top_srcdir)/eek/libeek-xkl.la \
 | 
				
			||||||
	$(GOBJECT2_LIBS) \
 | 
						$(GOBJECT2_LIBS) \
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,12 @@
 | 
				
			|||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
					# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
				
			||||||
# 02110-1301 USA
 | 
					# 02110-1301 USA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
lib_LTLIBRARIES = libeek.la libeek-clutter.la libeek-xkb.la libeek-xkl.la
 | 
					lib_LTLIBRARIES = \
 | 
				
			||||||
 | 
						libeek.la \
 | 
				
			||||||
 | 
						libeek-clutter.la \
 | 
				
			||||||
 | 
						libeek-gtk.la \
 | 
				
			||||||
 | 
						libeek-xkb.la \
 | 
				
			||||||
 | 
						libeek-xkl.la
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libeek_la_SOURCES = \
 | 
					libeek_la_SOURCES = \
 | 
				
			||||||
	eek-layout.c \
 | 
						eek-layout.c \
 | 
				
			||||||
@ -37,8 +42,7 @@ libeek_la_SOURCES = \
 | 
				
			|||||||
	eek-keysym.c \
 | 
						eek-keysym.c \
 | 
				
			||||||
	eek-special-keysym-labels.h \
 | 
						eek-special-keysym-labels.h \
 | 
				
			||||||
	eek-unicode-keysym-labels.h \
 | 
						eek-unicode-keysym-labels.h \
 | 
				
			||||||
	eek-keyname-keysym-labels.h \
 | 
						eek-keyname-keysym-labels.h
 | 
				
			||||||
	$(NULL)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
libeek_la_CFLAGS = $(GOBJECT2_CFLAGS) $(CAIRO_CFLAGS) $(PANGO_CFLAGS)
 | 
					libeek_la_CFLAGS = $(GOBJECT2_CFLAGS) $(CAIRO_CFLAGS) $(PANGO_CFLAGS)
 | 
				
			||||||
libeek_la_LIBADD = $(GOBJECT2_LIBS) $(CAIRO_LIBS) $(PANGO_LIBS)
 | 
					libeek_la_LIBADD = $(GOBJECT2_LIBS) $(CAIRO_LIBS) $(PANGO_LIBS)
 | 
				
			||||||
@ -52,24 +56,33 @@ libeek_clutter_la_SOURCES = \
 | 
				
			|||||||
	eek-clutter-key.h \
 | 
						eek-clutter-key.h \
 | 
				
			||||||
	eek-clutter-key-actor.c \
 | 
						eek-clutter-key-actor.c \
 | 
				
			||||||
	eek-clutter-key-actor.h \
 | 
						eek-clutter-key-actor.h \
 | 
				
			||||||
	eek-clutter.h \
 | 
						eek-drawing.h \
 | 
				
			||||||
	$(NULL)
 | 
						eek-drawing.c \
 | 
				
			||||||
 | 
						eek-clutter.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libeek_clutter_la_CFLAGS = $(CLUTTER_CFLAGS)
 | 
					libeek_clutter_la_CFLAGS = $(CLUTTER_CFLAGS)
 | 
				
			||||||
libeek_clutter_la_LIBADD = libeek.la $(CLUTTER_LIBS)
 | 
					libeek_clutter_la_LIBADD = libeek.la $(CLUTTER_LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					libeek_gtk_la_SOURCES = \
 | 
				
			||||||
 | 
						eek-gtk-keyboard.c \
 | 
				
			||||||
 | 
						eek-gtk-keyboard.h \
 | 
				
			||||||
 | 
						eek-drawing.h \
 | 
				
			||||||
 | 
						eek-drawing.c \
 | 
				
			||||||
 | 
						eek-gtk.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					libeek_gtk_la_CFLAGS = $(GTK2_CFLAGS)
 | 
				
			||||||
 | 
					libeek_gtk_la_LIBADD = libeek.la $(GTK2_LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libeek_xkb_la_SOURCES = \
 | 
					libeek_xkb_la_SOURCES = \
 | 
				
			||||||
	eek-xkb-layout.h \
 | 
						eek-xkb-layout.h \
 | 
				
			||||||
	eek-xkb-layout.c \
 | 
						eek-xkb-layout.c
 | 
				
			||||||
	$(NULL)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
libeek_xkb_la_CFLAGS = $(GTK2_CFLAGS) $(XKB_CFLAGS)
 | 
					libeek_xkb_la_CFLAGS = $(GTK2_CFLAGS) $(XKB_CFLAGS)
 | 
				
			||||||
libeek_xkb_la_LIBADD = libeek.la $(GTK2_LIBS) $(XKB_LIBS)
 | 
					libeek_xkb_la_LIBADD = libeek.la $(GTK2_LIBS) $(XKB_LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libeek_xkl_la_SOURCES = \
 | 
					libeek_xkl_la_SOURCES = \
 | 
				
			||||||
	eek-xkl-layout.h \
 | 
						eek-xkl-layout.h \
 | 
				
			||||||
	eek-xkl-layout.c \
 | 
						eek-xkl-layout.c
 | 
				
			||||||
	$(NULL)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
libeek_xkl_la_CFLAGS = $(GTK2_CFLAGS) $(LIBXKLAVIER_CFLAGS)
 | 
					libeek_xkl_la_CFLAGS = $(GTK2_CFLAGS) $(LIBXKLAVIER_CFLAGS)
 | 
				
			||||||
libeek_xkl_la_LIBADD = libeek-xkb.la $(GTK2_LIBS) $(LIBXKLAVIER_LIBS)
 | 
					libeek_xkl_la_LIBADD = libeek-xkb.la $(GTK2_LIBS) $(LIBXKLAVIER_LIBS)
 | 
				
			||||||
 | 
				
			|||||||
@ -26,13 +26,15 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <cogl/cogl.h>
 | 
					#include <cogl/cogl.h>
 | 
				
			||||||
#include <cogl/cogl-pango.h>
 | 
					#include <cogl/cogl-pango.h>
 | 
				
			||||||
#include <math.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef HAVE_CONFIG_H
 | 
					#ifdef HAVE_CONFIG_H
 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
#endif  /* HAVE_CONFIG_H */
 | 
					#endif  /* HAVE_CONFIG_H */
 | 
				
			||||||
#include "eek-clutter-key-actor.h"
 | 
					#include "eek-clutter-key-actor.h"
 | 
				
			||||||
#include "eek-keysym.h"
 | 
					#include "eek-keysym.h"
 | 
				
			||||||
 | 
					#include "eek-drawing.h"
 | 
				
			||||||
 | 
					#include "eek-section.h"
 | 
				
			||||||
 | 
					#include "eek-keyboard.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define noKBDRAW_DEBUG
 | 
					#define noKBDRAW_DEBUG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -54,6 +56,7 @@ struct _EekClutterKeyActorPrivate
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    EekKey *key;
 | 
					    EekKey *key;
 | 
				
			||||||
    ClutterActor *texture;
 | 
					    ClutterActor *texture;
 | 
				
			||||||
 | 
					    PangoFontDescription *font;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct {
 | 
					static struct {
 | 
				
			||||||
@ -61,20 +64,24 @@ static struct {
 | 
				
			|||||||
    GHashTable *outline_textures;
 | 
					    GHashTable *outline_textures;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* manually maintain the ref-count of outline_textures to set it
 | 
					    /* manually maintain the ref-count of outline_textures to set it
 | 
				
			||||||
       to NULL on destroy */
 | 
					       to NULL when all the EekClutterKeyActor are destroyed */
 | 
				
			||||||
    gint outline_textures_ref_count;
 | 
					    gint outline_textures_ref_count;
 | 
				
			||||||
} texture_cache;
 | 
					} texture_cache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct {
 | 
				
			||||||
 | 
					    /* keysym category -> PangoFontDescription * */
 | 
				
			||||||
 | 
					    PangoFontDescription *category_fonts[EEK_KEYSYM_CATEGORY_LAST];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* manually maintain the ref-count of category_fonts to set it to
 | 
				
			||||||
 | 
					       NULL when all the EekClutterKeyActor are destroyed */
 | 
				
			||||||
 | 
					    gint category_fonts_ref_count;
 | 
				
			||||||
 | 
					} font_cache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ClutterActor *get_texture          (EekClutterKeyActor *actor);
 | 
					static ClutterActor *get_texture          (EekClutterKeyActor *actor);
 | 
				
			||||||
static void          draw_key_on_layout   (EekKey             *key,
 | 
					static void          draw_key_on_layout   (EekClutterKeyActor *actor,
 | 
				
			||||||
                                           PangoLayout        *layout);
 | 
					                                           PangoLayout        *layout);
 | 
				
			||||||
static void          key_enlarge          (ClutterActor       *actor);
 | 
					static void          key_enlarge          (ClutterActor       *actor);
 | 
				
			||||||
static void          key_shrink           (ClutterActor       *actor);
 | 
					static void          key_shrink           (ClutterActor       *actor);
 | 
				
			||||||
static void          draw_rounded_polygon (cairo_t            *cr,
 | 
					 | 
				
			||||||
                                           gboolean            filled,
 | 
					 | 
				
			||||||
                                           gdouble             radius,
 | 
					 | 
				
			||||||
                                           EekPoint           *points,
 | 
					 | 
				
			||||||
                                           gint                num_points);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
eek_clutter_key_actor_real_paint (ClutterActor *self)
 | 
					eek_clutter_key_actor_real_paint (ClutterActor *self)
 | 
				
			||||||
@ -104,7 +111,7 @@ eek_clutter_key_actor_real_paint (ClutterActor *self)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /* Draw the label on the key. */
 | 
					    /* Draw the label on the key. */
 | 
				
			||||||
    layout = clutter_actor_create_pango_layout (self, NULL);
 | 
					    layout = clutter_actor_create_pango_layout (self, NULL);
 | 
				
			||||||
    draw_key_on_layout (priv->key, layout);
 | 
					    draw_key_on_layout (EEK_CLUTTER_KEY_ACTOR(self), layout);
 | 
				
			||||||
    pango_layout_get_extents (layout, NULL, &logical_rect);
 | 
					    pango_layout_get_extents (layout, NULL, &logical_rect);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* FIXME: Color should be configurable through a property. */
 | 
					    /* FIXME: Color should be configurable through a property. */
 | 
				
			||||||
@ -129,12 +136,11 @@ eek_clutter_key_actor_real_get_preferred_width (ClutterActor *self,
 | 
				
			|||||||
                                                gfloat       *min_width_p,
 | 
					                                                gfloat       *min_width_p,
 | 
				
			||||||
                                                gfloat       *natural_width_p)
 | 
					                                                gfloat       *natural_width_p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    EekClutterKeyActorPrivate *priv = EEK_CLUTTER_KEY_ACTOR_GET_PRIVATE (self);
 | 
					 | 
				
			||||||
    PangoLayout *layout;
 | 
					    PangoLayout *layout;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Draw the label on the key - just to validate the glyph cache. */
 | 
					    /* Draw the label on the key - just to validate the glyph cache. */
 | 
				
			||||||
    layout = clutter_actor_create_pango_layout (self, NULL);
 | 
					    layout = clutter_actor_create_pango_layout (self, NULL);
 | 
				
			||||||
    draw_key_on_layout (priv->key, layout);
 | 
					    draw_key_on_layout (EEK_CLUTTER_KEY_ACTOR(self), layout);
 | 
				
			||||||
    cogl_pango_ensure_glyph_cache_for_layout (layout);
 | 
					    cogl_pango_ensure_glyph_cache_for_layout (layout);
 | 
				
			||||||
    g_object_unref (layout);
 | 
					    g_object_unref (layout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -189,6 +195,18 @@ eek_clutter_key_actor_dispose (GObject *object)
 | 
				
			|||||||
            texture_cache.outline_textures = NULL;
 | 
					            texture_cache.outline_textures = NULL;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    if (priv->font) {
 | 
				
			||||||
 | 
					        /* no need to pango_font_description_free (priv->font) */
 | 
				
			||||||
 | 
					        priv->font = NULL;
 | 
				
			||||||
 | 
					        if (--font_cache.category_fonts_ref_count == 0) {
 | 
				
			||||||
 | 
					            gint i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (i = 0; i < EEK_KEYSYM_CATEGORY_LAST; i++) {
 | 
				
			||||||
 | 
					                pango_font_description_free (font_cache.category_fonts[i]);
 | 
				
			||||||
 | 
					                font_cache.category_fonts[i] = NULL;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    G_OBJECT_CLASS (eek_clutter_key_actor_parent_class)->dispose (object);
 | 
					    G_OBJECT_CLASS (eek_clutter_key_actor_parent_class)->dispose (object);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -268,6 +286,8 @@ eek_clutter_key_actor_init (EekClutterKeyActor *self)
 | 
				
			|||||||
    priv = self->priv = EEK_CLUTTER_KEY_ACTOR_GET_PRIVATE(self);
 | 
					    priv = self->priv = EEK_CLUTTER_KEY_ACTOR_GET_PRIVATE(self);
 | 
				
			||||||
    priv->key = NULL;
 | 
					    priv->key = NULL;
 | 
				
			||||||
    priv->texture = NULL;
 | 
					    priv->texture = NULL;
 | 
				
			||||||
 | 
					    priv->font = NULL;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    clutter_actor_set_reactive (CLUTTER_ACTOR(self), TRUE);
 | 
					    clutter_actor_set_reactive (CLUTTER_ACTOR(self), TRUE);
 | 
				
			||||||
    g_signal_connect (self, "button-press-event",
 | 
					    g_signal_connect (self, "button-press-event",
 | 
				
			||||||
                      G_CALLBACK (on_button_press_event), NULL);
 | 
					                      G_CALLBACK (on_button_press_event), NULL);
 | 
				
			||||||
@ -343,20 +363,20 @@ create_texture_for_key (EekKey *key)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    cairo_set_source (cr, pat);
 | 
					    cairo_set_source (cr, pat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    draw_rounded_polygon (cr,
 | 
					    eek_draw_rounded_polygon (cr,
 | 
				
			||||||
                          TRUE,
 | 
					                              TRUE,
 | 
				
			||||||
                          outline->corner_radius,
 | 
					                              outline->corner_radius,
 | 
				
			||||||
                          outline->points,
 | 
					                              outline->points,
 | 
				
			||||||
                          outline->num_points);
 | 
					                              outline->num_points);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cairo_pattern_destroy (pat);
 | 
					    cairo_pattern_destroy (pat);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cairo_set_source_rgba (cr, 0.3, 0.3, 0.3, 0.5);
 | 
					    cairo_set_source_rgba (cr, 0.3, 0.3, 0.3, 0.5);
 | 
				
			||||||
    draw_rounded_polygon (cr,
 | 
					    eek_draw_rounded_polygon (cr,
 | 
				
			||||||
                          FALSE,
 | 
					                              FALSE,
 | 
				
			||||||
                          outline->corner_radius,
 | 
					                              outline->corner_radius,
 | 
				
			||||||
                          outline->points,
 | 
					                              outline->points,
 | 
				
			||||||
                          outline->num_points);
 | 
					                              outline->num_points);
 | 
				
			||||||
    cairo_destroy (cr);
 | 
					    cairo_destroy (cr);
 | 
				
			||||||
    return texture;
 | 
					    return texture;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -382,272 +402,57 @@ get_texture (EekClutterKeyActor *actor)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
draw_text_on_layout (PangoLayout *layout,
 | 
					draw_key_on_layout (EekClutterKeyActor *self,
 | 
				
			||||||
                     const gchar *text,
 | 
					 | 
				
			||||||
                     gdouble      scale)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    PangoFontDescription *font_desc;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define FONT_SIZE (720 * 50)
 | 
					 | 
				
			||||||
    /* FIXME: Font should be configurable through a property. */
 | 
					 | 
				
			||||||
    font_desc = pango_font_description_from_string ("Sans");
 | 
					 | 
				
			||||||
    pango_font_description_set_size (font_desc, FONT_SIZE * scale);
 | 
					 | 
				
			||||||
    pango_layout_set_font_description (layout, font_desc);
 | 
					 | 
				
			||||||
    pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
 | 
					 | 
				
			||||||
    pango_layout_set_text (layout, text, -1);
 | 
					 | 
				
			||||||
    pango_font_description_free (font_desc);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
draw_key_on_layout (EekKey      *key,
 | 
					 | 
				
			||||||
                    PangoLayout *layout)
 | 
					                    PangoLayout *layout)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    PangoLayout *buffer;
 | 
					    EekClutterKeyActorPrivate *priv = EEK_CLUTTER_KEY_ACTOR_GET_PRIVATE (self);
 | 
				
			||||||
    PangoRectangle logical_rect = { 0, };
 | 
					 | 
				
			||||||
    EekBounds bounds;
 | 
					 | 
				
			||||||
    guint keysym;
 | 
					    guint keysym;
 | 
				
			||||||
    const gchar *label, *empty_label = "";
 | 
					    const gchar *label, *empty_label = "";
 | 
				
			||||||
    gdouble scale_x, scale_y;
 | 
					    EekKeysymCategory category;
 | 
				
			||||||
 | 
					    EekBounds bounds;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    eek_element_get_bounds (EEK_ELEMENT(key), &bounds);
 | 
					    if (font_cache.category_fonts_ref_count == 0) {
 | 
				
			||||||
    keysym = eek_key_get_keysym (key);
 | 
					        EekContainer *keyboard, *section;
 | 
				
			||||||
 | 
					        PangoFontDescription *font;
 | 
				
			||||||
 | 
					        PangoLayout *copy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        section = EEK_ELEMENT_GET_CLASS(priv->key)->
 | 
				
			||||||
 | 
					            get_parent (EEK_ELEMENT(priv->key));
 | 
				
			||||||
 | 
					        g_return_if_fail (EEK_IS_SECTION(section));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        keyboard = EEK_ELEMENT_GET_CLASS(section)->
 | 
				
			||||||
 | 
					            get_parent (EEK_ELEMENT(section));
 | 
				
			||||||
 | 
					        g_return_if_fail (EEK_IS_KEYBOARD(keyboard));
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        copy = pango_layout_copy (layout);
 | 
				
			||||||
 | 
					        font = pango_font_description_from_string ("Sans");
 | 
				
			||||||
 | 
					        pango_layout_set_font_description (copy, font);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        eek_get_fonts (EEK_KEYBOARD(keyboard), copy,
 | 
				
			||||||
 | 
					                       font_cache.category_fonts);
 | 
				
			||||||
 | 
					        g_object_unref (G_OBJECT(copy));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    keysym = eek_key_get_keysym (priv->key);
 | 
				
			||||||
    if (keysym == EEK_INVALID_KEYSYM)
 | 
					    if (keysym == EEK_INVALID_KEYSYM)
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
 | 
					    category = eek_keysym_get_category (keysym);
 | 
				
			||||||
 | 
					    if (category == EEK_KEYSYM_CATEGORY_UNKNOWN)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    if (!priv->font) {
 | 
				
			||||||
 | 
					        priv->font = font_cache.category_fonts[category];
 | 
				
			||||||
 | 
					        font_cache.category_fonts_ref_count++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pango_layout_set_font_description (layout, priv->font);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    eek_element_get_bounds (EEK_ELEMENT(priv->key), &bounds);
 | 
				
			||||||
 | 
					    pango_layout_set_width (layout, PANGO_SCALE * bounds.width);
 | 
				
			||||||
 | 
					    pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    label = eek_keysym_to_string (keysym);
 | 
					    label = eek_keysym_to_string (keysym);
 | 
				
			||||||
    if (!label)
 | 
					    if (!label)
 | 
				
			||||||
        label = empty_label;
 | 
					        label = empty_label;
 | 
				
			||||||
 | 
					    eek_draw_text_on_layout (layout, label);
 | 
				
			||||||
    /* Compute the layout extents. */
 | 
					 | 
				
			||||||
    buffer = pango_layout_copy (layout);
 | 
					 | 
				
			||||||
    draw_text_on_layout (buffer, label, 1.0);
 | 
					 | 
				
			||||||
    pango_layout_get_extents (buffer, NULL, &logical_rect);
 | 
					 | 
				
			||||||
    scale_x = scale_y = 1.0;
 | 
					 | 
				
			||||||
    if (PANGO_PIXELS(logical_rect.width) > bounds.width)
 | 
					 | 
				
			||||||
        scale_x = bounds.width / PANGO_PIXELS(logical_rect.width);
 | 
					 | 
				
			||||||
    if (PANGO_PIXELS(logical_rect.height) > bounds.height)
 | 
					 | 
				
			||||||
        scale_y = bounds.height / PANGO_PIXELS(logical_rect.height);
 | 
					 | 
				
			||||||
    g_object_unref (buffer);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Actually draw on the layout */
 | 
					 | 
				
			||||||
    draw_text_on_layout (layout,
 | 
					 | 
				
			||||||
                         label,
 | 
					 | 
				
			||||||
                         (scale_x < scale_y ? scale_x : scale_y) * 0.8);
 | 
					 | 
				
			||||||
    if (label != empty_label)
 | 
					    if (label != empty_label)
 | 
				
			||||||
        g_free ((gpointer)label);
 | 
					        g_free ((gpointer)label);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * The functions below are borrowed from
 | 
					 | 
				
			||||||
 * libgnomekbd/gkbd-keyboard-drawing.c.
 | 
					 | 
				
			||||||
 * Copyright (C) 2006 Sergey V. Udaltsov <svu@gnome.org>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * length(), point_line_distance(), normal_form(), inverse(), multiply(),
 | 
					 | 
				
			||||||
 * intersect(), rounded_corner(), draw_rounded_polygon()
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gdouble
 | 
					 | 
				
			||||||
length (gdouble x, gdouble y)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return sqrt (x * x + y * y);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static gdouble
 | 
					 | 
				
			||||||
point_line_distance (gdouble ax, gdouble ay, gdouble nx, gdouble ny)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return ax * nx + ay * ny;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
normal_form (gdouble ax, gdouble ay,
 | 
					 | 
				
			||||||
	     gdouble bx, gdouble by,
 | 
					 | 
				
			||||||
	     gdouble * nx, gdouble * ny, gdouble * d)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    gdouble l;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    *nx = by - ay;
 | 
					 | 
				
			||||||
    *ny = ax - bx;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    l = length (*nx, *ny);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    *nx /= l;
 | 
					 | 
				
			||||||
    *ny /= l;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    *d = point_line_distance (ax, ay, *nx, *ny);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
inverse (gdouble a, gdouble b, gdouble c, gdouble d,
 | 
					 | 
				
			||||||
	 gdouble * e, gdouble * f, gdouble * g, gdouble * h)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    gdouble det;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    det = a * d - b * c;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    *e = d / det;
 | 
					 | 
				
			||||||
    *f = -b / det;
 | 
					 | 
				
			||||||
    *g = -c / det;
 | 
					 | 
				
			||||||
    *h = a / det;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
multiply (gdouble a, gdouble b, gdouble c, gdouble d,
 | 
					 | 
				
			||||||
	  gdouble e, gdouble f, gdouble * x, gdouble * y)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    *x = a * e + b * f;
 | 
					 | 
				
			||||||
    *y = c * e + d * f;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
intersect (gdouble n1x, gdouble n1y, gdouble d1,
 | 
					 | 
				
			||||||
	   gdouble n2x, gdouble n2y, gdouble d2, gdouble * x, gdouble * y)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    gdouble e, f, g, h;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    inverse (n1x, n1y, n2x, n2y, &e, &f, &g, &h);
 | 
					 | 
				
			||||||
    multiply (e, f, g, h, d1, d2, x, y);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* draw an angle from the current point to b and then to c,
 | 
					 | 
				
			||||||
 * with a rounded corner of the given radius.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
rounded_corner (cairo_t * cr,
 | 
					 | 
				
			||||||
		gdouble bx, gdouble by,
 | 
					 | 
				
			||||||
		gdouble cx, gdouble cy, gdouble radius)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    gdouble ax, ay;
 | 
					 | 
				
			||||||
    gdouble n1x, n1y, d1;
 | 
					 | 
				
			||||||
    gdouble n2x, n2y, d2;
 | 
					 | 
				
			||||||
    gdouble pd1, pd2;
 | 
					 | 
				
			||||||
    gdouble ix, iy;
 | 
					 | 
				
			||||||
    gdouble dist1, dist2;
 | 
					 | 
				
			||||||
    gdouble nx, ny, d;
 | 
					 | 
				
			||||||
    gdouble a1x, a1y, c1x, c1y;
 | 
					 | 
				
			||||||
    gdouble phi1, phi2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    cairo_get_current_point (cr, &ax, &ay);
 | 
					 | 
				
			||||||
#ifdef KBDRAW_DEBUG
 | 
					 | 
				
			||||||
    printf ("        current point: (%f, %f), radius %f:\n", ax, ay,
 | 
					 | 
				
			||||||
            radius);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* make sure radius is not too large */
 | 
					 | 
				
			||||||
    dist1 = length (bx - ax, by - ay);
 | 
					 | 
				
			||||||
    dist2 = length (cx - bx, cy - by);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    radius = MIN (radius, MIN (dist1, dist2));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* construct normal forms of the lines */
 | 
					 | 
				
			||||||
    normal_form (ax, ay, bx, by, &n1x, &n1y, &d1);
 | 
					 | 
				
			||||||
    normal_form (bx, by, cx, cy, &n2x, &n2y, &d2);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* find which side of the line a,b the point c is on */
 | 
					 | 
				
			||||||
    if (point_line_distance (cx, cy, n1x, n1y) < d1)
 | 
					 | 
				
			||||||
        pd1 = d1 - radius;
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        pd1 = d1 + radius;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* find which side of the line b,c the point a is on */
 | 
					 | 
				
			||||||
    if (point_line_distance (ax, ay, n2x, n2y) < d2)
 | 
					 | 
				
			||||||
        pd2 = d2 - radius;
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        pd2 = d2 + radius;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* intersect the parallels to find the center of the arc */
 | 
					 | 
				
			||||||
    intersect (n1x, n1y, pd1, n2x, n2y, pd2, &ix, &iy);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    nx = (bx - ax) / dist1;
 | 
					 | 
				
			||||||
    ny = (by - ay) / dist1;
 | 
					 | 
				
			||||||
    d = point_line_distance (ix, iy, nx, ny);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* a1 is the point on the line a-b where the arc starts */
 | 
					 | 
				
			||||||
    intersect (n1x, n1y, d1, nx, ny, d, &a1x, &a1y);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    nx = (cx - bx) / dist2;
 | 
					 | 
				
			||||||
    ny = (cy - by) / dist2;
 | 
					 | 
				
			||||||
    d = point_line_distance (ix, iy, nx, ny);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* c1 is the point on the line b-c where the arc ends */
 | 
					 | 
				
			||||||
    intersect (n2x, n2y, d2, nx, ny, d, &c1x, &c1y);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* determine the first angle */
 | 
					 | 
				
			||||||
    if (a1x - ix == 0)
 | 
					 | 
				
			||||||
        phi1 = (a1y - iy > 0) ? M_PI_2 : 3 * M_PI_2;
 | 
					 | 
				
			||||||
    else if (a1x - ix > 0)
 | 
					 | 
				
			||||||
        phi1 = atan ((a1y - iy) / (a1x - ix));
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        phi1 = M_PI + atan ((a1y - iy) / (a1x - ix));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* determine the second angle */
 | 
					 | 
				
			||||||
    if (c1x - ix == 0)
 | 
					 | 
				
			||||||
        phi2 = (c1y - iy > 0) ? M_PI_2 : 3 * M_PI_2;
 | 
					 | 
				
			||||||
    else if (c1x - ix > 0)
 | 
					 | 
				
			||||||
        phi2 = atan ((c1y - iy) / (c1x - ix));
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        phi2 = M_PI + atan ((c1y - iy) / (c1x - ix));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* compute the difference between phi2 and phi1 mod 2pi */
 | 
					 | 
				
			||||||
    d = phi2 - phi1;
 | 
					 | 
				
			||||||
    while (d < 0)
 | 
					 | 
				
			||||||
        d += 2 * M_PI;
 | 
					 | 
				
			||||||
    while (d > 2 * M_PI)
 | 
					 | 
				
			||||||
        d -= 2 * M_PI;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef KBDRAW_DEBUG
 | 
					 | 
				
			||||||
    printf ("        line 1 to: (%f, %f):\n", a1x, a1y);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    if (!(isnan (a1x) || isnan (a1y)))
 | 
					 | 
				
			||||||
        cairo_line_to (cr, a1x, a1y);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* pick the short arc from phi1 to phi2 */
 | 
					 | 
				
			||||||
    if (d < M_PI)
 | 
					 | 
				
			||||||
        cairo_arc (cr, ix, iy, radius, phi1, phi2);
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        cairo_arc_negative (cr, ix, iy, radius, phi1, phi2);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef KBDRAW_DEBUG
 | 
					 | 
				
			||||||
    printf ("        line 2 to: (%f, %f):\n", cx, cy);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    cairo_line_to (cr, cx, cy);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
draw_rounded_polygon (cairo_t  *cr,
 | 
					 | 
				
			||||||
                      gboolean  filled,
 | 
					 | 
				
			||||||
                      gdouble   radius,
 | 
					 | 
				
			||||||
                      EekPoint *points,
 | 
					 | 
				
			||||||
                      gint      num_points)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    gint i, j;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    cairo_move_to (cr,
 | 
					 | 
				
			||||||
                   (gdouble) (points[num_points - 1].x +
 | 
					 | 
				
			||||||
                              points[0].x) / 2,
 | 
					 | 
				
			||||||
                   (gdouble) (points[num_points - 1].y +
 | 
					 | 
				
			||||||
                              points[0].y) / 2);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef KBDRAW_DEBUG
 | 
					 | 
				
			||||||
    printf ("    rounded polygon of radius %f:\n", radius);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    for (i = 0; i < num_points; i++) {
 | 
					 | 
				
			||||||
        j = (i + 1) % num_points;
 | 
					 | 
				
			||||||
        rounded_corner (cr, (gdouble) points[i].x,
 | 
					 | 
				
			||||||
                        (gdouble) points[i].y,
 | 
					 | 
				
			||||||
                        (gdouble) (points[i].x + points[j].x) / 2,
 | 
					 | 
				
			||||||
                        (gdouble) (points[i].y + points[j].y) / 2,
 | 
					 | 
				
			||||||
                        radius);
 | 
					 | 
				
			||||||
#ifdef KBDRAW_DEBUG
 | 
					 | 
				
			||||||
        printf ("      corner (%d, %d) -> (%d, %d):\n",
 | 
					 | 
				
			||||||
                points[i].x, points[i].y, points[j].x,
 | 
					 | 
				
			||||||
                points[j].y);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    cairo_close_path (cr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (filled)
 | 
					 | 
				
			||||||
        cairo_fill (cr);
 | 
					 | 
				
			||||||
    else
 | 
					 | 
				
			||||||
        cairo_stroke (cr);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -59,7 +59,9 @@ eek_container_real_add_child (EekContainer *self,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    g_return_if_fail (EEK_IS_ELEMENT(child));
 | 
					    g_return_if_fail (EEK_IS_ELEMENT(child));
 | 
				
			||||||
    g_object_ref_sink (child);
 | 
					    g_object_ref_sink (child);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    priv->children = g_slist_prepend (priv->children, child);
 | 
					    priv->children = g_slist_prepend (priv->children, child);
 | 
				
			||||||
 | 
					    EEK_ELEMENT_GET_CLASS(child)->set_parent (child, self);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
@ -74,6 +76,7 @@ eek_container_real_remove_child (EekContainer *self,
 | 
				
			|||||||
    g_return_if_fail (head);
 | 
					    g_return_if_fail (head);
 | 
				
			||||||
    g_object_unref (child);
 | 
					    g_object_unref (child);
 | 
				
			||||||
    priv->children = g_slist_remove_link (priv->children, head);
 | 
					    priv->children = g_slist_remove_link (priv->children, head);
 | 
				
			||||||
 | 
					    EEK_ELEMENT_GET_CLASS(child)->set_parent (child, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
@ -121,7 +124,6 @@ static void
 | 
				
			|||||||
eek_container_finalize (GObject *object)
 | 
					eek_container_finalize (GObject *object)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    EekContainerPrivate *priv = EEK_CONTAINER_GET_PRIVATE(object);
 | 
					    EekContainerPrivate *priv = EEK_CONTAINER_GET_PRIVATE(object);
 | 
				
			||||||
    GSList *head;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_slist_free (priv->children);
 | 
					    g_slist_free (priv->children);
 | 
				
			||||||
    G_OBJECT_CLASS(eek_container_parent_class)->finalize (object);
 | 
					    G_OBJECT_CLASS(eek_container_parent_class)->finalize (object);
 | 
				
			||||||
 | 
				
			|||||||
@ -31,7 +31,6 @@ G_BEGIN_DECLS
 | 
				
			|||||||
#define EEK_IS_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_CONTAINER))
 | 
					#define EEK_IS_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_CONTAINER))
 | 
				
			||||||
#define EEK_CONTAINER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_CONTAINER, EekContainerClass))
 | 
					#define EEK_CONTAINER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_CONTAINER, EekContainerClass))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct _EekContainer EekContainer;
 | 
					 | 
				
			||||||
typedef struct _EekContainerClass EekContainerClass;
 | 
					typedef struct _EekContainerClass EekContainerClass;
 | 
				
			||||||
typedef struct _EekContainerPrivate EekContainerPrivate;
 | 
					typedef struct _EekContainerPrivate EekContainerPrivate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										399
									
								
								eek/eek-drawing.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										399
									
								
								eek/eek-drawing.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,399 @@
 | 
				
			|||||||
 | 
					/* 
 | 
				
			||||||
 | 
					 * Copyright (C) 2006 Sergey V. Udaltsov <svu@gnome.org>
 | 
				
			||||||
 | 
					 * Copyright (C) 2010 Daiki Ueno <ueno@unixuser.org>
 | 
				
			||||||
 | 
					 * Copyright (C) 2010 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 <math.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_CONFIG_H
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					#endif  /* HAVE_CONFIG_H */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "eek-keyboard.h"
 | 
				
			||||||
 | 
					#include "eek-key.h"
 | 
				
			||||||
 | 
					#include "eek-drawing.h"
 | 
				
			||||||
 | 
					#include "eek-keysym.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					eek_draw_text_on_layout (PangoLayout *layout,
 | 
				
			||||||
 | 
					                         const gchar *text)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /* pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); */
 | 
				
			||||||
 | 
					    pango_layout_set_text (layout, text, -1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct _GetFontSizeCallbackData
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    PangoLayout *layout;
 | 
				
			||||||
 | 
					    EekKeysymCategory category;
 | 
				
			||||||
 | 
					    gint minimum_font_size;
 | 
				
			||||||
 | 
					    gint font_size;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					typedef struct _GetFontSizeCallbackData GetFontSizeCallbackData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static gint
 | 
				
			||||||
 | 
					get_font_size (const gchar *text,
 | 
				
			||||||
 | 
					               EekBounds   *bounds,
 | 
				
			||||||
 | 
					               PangoLayout *layout)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    gdouble scale_x, scale_y;
 | 
				
			||||||
 | 
					    const PangoFontDescription *base_font_desc;
 | 
				
			||||||
 | 
					    PangoFontDescription *font_desc;
 | 
				
			||||||
 | 
					    PangoRectangle logical_rect = { 0, };
 | 
				
			||||||
 | 
					    gint font_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    layout = pango_layout_copy (layout);
 | 
				
			||||||
 | 
					    base_font_desc = pango_layout_get_font_description (layout);
 | 
				
			||||||
 | 
					    font_desc = pango_font_description_copy (base_font_desc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    font_size = eek_bounds_long_side (bounds) * PANGO_SCALE;
 | 
				
			||||||
 | 
					    pango_font_description_set_size (font_desc, font_size);
 | 
				
			||||||
 | 
					    pango_layout_set_font_description (layout, font_desc);
 | 
				
			||||||
 | 
					    pango_font_description_free (font_desc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    eek_draw_text_on_layout (layout, text);
 | 
				
			||||||
 | 
					    pango_layout_get_extents (layout, NULL, &logical_rect);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    scale_x = scale_y = 1.0;
 | 
				
			||||||
 | 
					    if (logical_rect.width > bounds->width * PANGO_SCALE)
 | 
				
			||||||
 | 
					        scale_x = bounds->width * PANGO_SCALE / logical_rect.width;
 | 
				
			||||||
 | 
					    if (logical_rect.height > bounds->height * PANGO_SCALE)
 | 
				
			||||||
 | 
					        scale_y = bounds->height * PANGO_SCALE / logical_rect.height;
 | 
				
			||||||
 | 
					    g_object_unref (layout);
 | 
				
			||||||
 | 
					    return font_size * (scale_x < scale_y ? scale_x : scale_y);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					egf_key_callback (EekElement *element,
 | 
				
			||||||
 | 
					                  gpointer user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EekKey *key = EEK_KEY(element);
 | 
				
			||||||
 | 
					    GetFontSizeCallbackData *data = user_data;
 | 
				
			||||||
 | 
					    guint *keysyms;
 | 
				
			||||||
 | 
					    gint num_groups, num_levels, i;
 | 
				
			||||||
 | 
					    gdouble font_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    eek_key_get_keysyms (key, &keysyms, &num_groups, &num_levels);
 | 
				
			||||||
 | 
					    for (i = 0; i < num_groups * num_levels; i++) {
 | 
				
			||||||
 | 
					        guint keysym = keysyms[i];
 | 
				
			||||||
 | 
					        EekBounds bounds;
 | 
				
			||||||
 | 
					        const gchar *label;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (keysym == EEK_INVALID_KEYSYM ||
 | 
				
			||||||
 | 
					            eek_keysym_get_category (keysym) != data->category)
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        eek_element_get_bounds (EEK_ELEMENT(key), &bounds);
 | 
				
			||||||
 | 
					        label = eek_keysym_to_string (keysym);
 | 
				
			||||||
 | 
					        font_size = get_font_size (label, &bounds, data->layout);
 | 
				
			||||||
 | 
					        if (font_size < data->font_size && font_size >= data->minimum_font_size)
 | 
				
			||||||
 | 
					            data->font_size = font_size;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					egf_section_callback (EekElement *element,
 | 
				
			||||||
 | 
					                      gpointer    user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    eek_container_foreach_child (EEK_CONTAINER(element),
 | 
				
			||||||
 | 
					                                 egf_key_callback,
 | 
				
			||||||
 | 
					                                 user_data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static PangoFontDescription *
 | 
				
			||||||
 | 
					get_font_for_category (EekKeyboard      *keyboard,
 | 
				
			||||||
 | 
					                       EekKeysymCategory category,
 | 
				
			||||||
 | 
					                       PangoLayout      *layout,
 | 
				
			||||||
 | 
					                       gdouble           minimum_font_size,
 | 
				
			||||||
 | 
					                       gdouble           maximum_font_size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    GetFontSizeCallbackData data;
 | 
				
			||||||
 | 
					    PangoFontDescription *font_desc;
 | 
				
			||||||
 | 
					    const PangoFontDescription *base_font_desc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    data.layout = layout;
 | 
				
			||||||
 | 
					    data.category = category;
 | 
				
			||||||
 | 
					    data.minimum_font_size = minimum_font_size;
 | 
				
			||||||
 | 
					    data.font_size = maximum_font_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    eek_container_foreach_child (EEK_CONTAINER(keyboard),
 | 
				
			||||||
 | 
					                                 egf_section_callback,
 | 
				
			||||||
 | 
					                                 &data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    base_font_desc = pango_layout_get_font_description (layout);
 | 
				
			||||||
 | 
					    font_desc = pango_font_description_copy (base_font_desc);
 | 
				
			||||||
 | 
					    pango_font_description_set_size (font_desc, data.font_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return font_desc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					eek_get_fonts (EekKeyboard           *keyboard,
 | 
				
			||||||
 | 
					               PangoLayout           *layout,
 | 
				
			||||||
 | 
					               PangoFontDescription **fonts)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EekBounds bounds;
 | 
				
			||||||
 | 
					    PangoFontDescription *font_desc;
 | 
				
			||||||
 | 
					    gint font_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* font for EEK_KEYSYM_CATEGORY_LETTER */
 | 
				
			||||||
 | 
					    eek_element_get_bounds (EEK_ELEMENT(keyboard), &bounds);
 | 
				
			||||||
 | 
					    font_desc = get_font_for_category (keyboard,
 | 
				
			||||||
 | 
					                                       EEK_KEYSYM_CATEGORY_LETTER,
 | 
				
			||||||
 | 
					                                       layout,
 | 
				
			||||||
 | 
					                                       0,
 | 
				
			||||||
 | 
					                                       eek_bounds_long_side (&bounds) *
 | 
				
			||||||
 | 
					                                       PANGO_SCALE);
 | 
				
			||||||
 | 
					    font_size = pango_font_description_get_size (font_desc);
 | 
				
			||||||
 | 
					    fonts[EEK_KEYSYM_CATEGORY_LETTER] = font_desc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* font for EEK_KEYSYM_CATEGORY_FUNCTION */
 | 
				
			||||||
 | 
					    font_desc = get_font_for_category (keyboard,
 | 
				
			||||||
 | 
					                                       EEK_KEYSYM_CATEGORY_FUNCTION,
 | 
				
			||||||
 | 
					                                       layout,
 | 
				
			||||||
 | 
					                                       font_size * 0.3,
 | 
				
			||||||
 | 
					                                       font_size);
 | 
				
			||||||
 | 
					    fonts[EEK_KEYSYM_CATEGORY_FUNCTION] = font_desc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* font for EEK_KEYSYM_CATEGORY_KEYNAME */
 | 
				
			||||||
 | 
					    font_desc = get_font_for_category (keyboard,
 | 
				
			||||||
 | 
					                                       EEK_KEYSYM_CATEGORY_KEYNAME,
 | 
				
			||||||
 | 
					                                       layout,
 | 
				
			||||||
 | 
					                                       font_size * 0.3,
 | 
				
			||||||
 | 
					                                       font_size);
 | 
				
			||||||
 | 
					    fonts[EEK_KEYSYM_CATEGORY_KEYNAME] = font_desc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * The functions below are borrowed from
 | 
				
			||||||
 | 
					 * libgnomekbd/gkbd-keyboard-drawing.c.
 | 
				
			||||||
 | 
					 * Copyright (C) 2006 Sergey V. Udaltsov <svu@gnome.org>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * length(), point_line_distance(), normal_form(), inverse(), multiply(),
 | 
				
			||||||
 | 
					 * intersect(), rounded_corner(), draw_rounded_polygon()
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static gdouble
 | 
				
			||||||
 | 
					length (gdouble x, gdouble y)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return sqrt (x * x + y * y);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static gdouble
 | 
				
			||||||
 | 
					point_line_distance (gdouble ax, gdouble ay, gdouble nx, gdouble ny)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return ax * nx + ay * ny;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					normal_form (gdouble ax, gdouble ay,
 | 
				
			||||||
 | 
						     gdouble bx, gdouble by,
 | 
				
			||||||
 | 
						     gdouble * nx, gdouble * ny, gdouble * d)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    gdouble l;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *nx = by - ay;
 | 
				
			||||||
 | 
					    *ny = ax - bx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    l = length (*nx, *ny);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *nx /= l;
 | 
				
			||||||
 | 
					    *ny /= l;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *d = point_line_distance (ax, ay, *nx, *ny);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					inverse (gdouble a, gdouble b, gdouble c, gdouble d,
 | 
				
			||||||
 | 
						 gdouble * e, gdouble * f, gdouble * g, gdouble * h)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    gdouble det;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    det = a * d - b * c;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    *e = d / det;
 | 
				
			||||||
 | 
					    *f = -b / det;
 | 
				
			||||||
 | 
					    *g = -c / det;
 | 
				
			||||||
 | 
					    *h = a / det;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					multiply (gdouble a, gdouble b, gdouble c, gdouble d,
 | 
				
			||||||
 | 
						  gdouble e, gdouble f, gdouble * x, gdouble * y)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    *x = a * e + b * f;
 | 
				
			||||||
 | 
					    *y = c * e + d * f;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					intersect (gdouble n1x, gdouble n1y, gdouble d1,
 | 
				
			||||||
 | 
						   gdouble n2x, gdouble n2y, gdouble d2, gdouble * x, gdouble * y)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    gdouble e, f, g, h;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inverse (n1x, n1y, n2x, n2y, &e, &f, &g, &h);
 | 
				
			||||||
 | 
					    multiply (e, f, g, h, d1, d2, x, y);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* draw an angle from the current point to b and then to c,
 | 
				
			||||||
 | 
					 * with a rounded corner of the given radius.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					rounded_corner (cairo_t * cr,
 | 
				
			||||||
 | 
							gdouble bx, gdouble by,
 | 
				
			||||||
 | 
							gdouble cx, gdouble cy, gdouble radius)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    gdouble ax, ay;
 | 
				
			||||||
 | 
					    gdouble n1x, n1y, d1;
 | 
				
			||||||
 | 
					    gdouble n2x, n2y, d2;
 | 
				
			||||||
 | 
					    gdouble pd1, pd2;
 | 
				
			||||||
 | 
					    gdouble ix, iy;
 | 
				
			||||||
 | 
					    gdouble dist1, dist2;
 | 
				
			||||||
 | 
					    gdouble nx, ny, d;
 | 
				
			||||||
 | 
					    gdouble a1x, a1y, c1x, c1y;
 | 
				
			||||||
 | 
					    gdouble phi1, phi2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cairo_get_current_point (cr, &ax, &ay);
 | 
				
			||||||
 | 
					#ifdef KBDRAW_DEBUG
 | 
				
			||||||
 | 
					    printf ("        current point: (%f, %f), radius %f:\n", ax, ay,
 | 
				
			||||||
 | 
					            radius);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* make sure radius is not too large */
 | 
				
			||||||
 | 
					    dist1 = length (bx - ax, by - ay);
 | 
				
			||||||
 | 
					    dist2 = length (cx - bx, cy - by);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    radius = MIN (radius, MIN (dist1, dist2));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* construct normal forms of the lines */
 | 
				
			||||||
 | 
					    normal_form (ax, ay, bx, by, &n1x, &n1y, &d1);
 | 
				
			||||||
 | 
					    normal_form (bx, by, cx, cy, &n2x, &n2y, &d2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* find which side of the line a,b the point c is on */
 | 
				
			||||||
 | 
					    if (point_line_distance (cx, cy, n1x, n1y) < d1)
 | 
				
			||||||
 | 
					        pd1 = d1 - radius;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        pd1 = d1 + radius;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* find which side of the line b,c the point a is on */
 | 
				
			||||||
 | 
					    if (point_line_distance (ax, ay, n2x, n2y) < d2)
 | 
				
			||||||
 | 
					        pd2 = d2 - radius;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        pd2 = d2 + radius;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* intersect the parallels to find the center of the arc */
 | 
				
			||||||
 | 
					    intersect (n1x, n1y, pd1, n2x, n2y, pd2, &ix, &iy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nx = (bx - ax) / dist1;
 | 
				
			||||||
 | 
					    ny = (by - ay) / dist1;
 | 
				
			||||||
 | 
					    d = point_line_distance (ix, iy, nx, ny);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* a1 is the point on the line a-b where the arc starts */
 | 
				
			||||||
 | 
					    intersect (n1x, n1y, d1, nx, ny, d, &a1x, &a1y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nx = (cx - bx) / dist2;
 | 
				
			||||||
 | 
					    ny = (cy - by) / dist2;
 | 
				
			||||||
 | 
					    d = point_line_distance (ix, iy, nx, ny);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* c1 is the point on the line b-c where the arc ends */
 | 
				
			||||||
 | 
					    intersect (n2x, n2y, d2, nx, ny, d, &c1x, &c1y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* determine the first angle */
 | 
				
			||||||
 | 
					    if (a1x - ix == 0)
 | 
				
			||||||
 | 
					        phi1 = (a1y - iy > 0) ? M_PI_2 : 3 * M_PI_2;
 | 
				
			||||||
 | 
					    else if (a1x - ix > 0)
 | 
				
			||||||
 | 
					        phi1 = atan ((a1y - iy) / (a1x - ix));
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        phi1 = M_PI + atan ((a1y - iy) / (a1x - ix));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* determine the second angle */
 | 
				
			||||||
 | 
					    if (c1x - ix == 0)
 | 
				
			||||||
 | 
					        phi2 = (c1y - iy > 0) ? M_PI_2 : 3 * M_PI_2;
 | 
				
			||||||
 | 
					    else if (c1x - ix > 0)
 | 
				
			||||||
 | 
					        phi2 = atan ((c1y - iy) / (c1x - ix));
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        phi2 = M_PI + atan ((c1y - iy) / (c1x - ix));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* compute the difference between phi2 and phi1 mod 2pi */
 | 
				
			||||||
 | 
					    d = phi2 - phi1;
 | 
				
			||||||
 | 
					    while (d < 0)
 | 
				
			||||||
 | 
					        d += 2 * M_PI;
 | 
				
			||||||
 | 
					    while (d > 2 * M_PI)
 | 
				
			||||||
 | 
					        d -= 2 * M_PI;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef KBDRAW_DEBUG
 | 
				
			||||||
 | 
					    printf ("        line 1 to: (%f, %f):\n", a1x, a1y);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    if (!(isnan (a1x) || isnan (a1y)))
 | 
				
			||||||
 | 
					        cairo_line_to (cr, a1x, a1y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* pick the short arc from phi1 to phi2 */
 | 
				
			||||||
 | 
					    if (d < M_PI)
 | 
				
			||||||
 | 
					        cairo_arc (cr, ix, iy, radius, phi1, phi2);
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        cairo_arc_negative (cr, ix, iy, radius, phi1, phi2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef KBDRAW_DEBUG
 | 
				
			||||||
 | 
					    printf ("        line 2 to: (%f, %f):\n", cx, cy);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    cairo_line_to (cr, cx, cy);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					eek_draw_rounded_polygon (cairo_t  *cr,
 | 
				
			||||||
 | 
					                          gboolean  filled,
 | 
				
			||||||
 | 
					                          gdouble   radius,
 | 
				
			||||||
 | 
					                          EekPoint *points,
 | 
				
			||||||
 | 
					                          gint      num_points)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    gint i, j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cairo_move_to (cr,
 | 
				
			||||||
 | 
					                   (gdouble) (points[num_points - 1].x +
 | 
				
			||||||
 | 
					                              points[0].x) / 2,
 | 
				
			||||||
 | 
					                   (gdouble) (points[num_points - 1].y +
 | 
				
			||||||
 | 
					                              points[0].y) / 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef KBDRAW_DEBUG
 | 
				
			||||||
 | 
					    printf ("    rounded polygon of radius %f:\n", radius);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    for (i = 0; i < num_points; i++) {
 | 
				
			||||||
 | 
					        j = (i + 1) % num_points;
 | 
				
			||||||
 | 
					        rounded_corner (cr, (gdouble) points[i].x,
 | 
				
			||||||
 | 
					                        (gdouble) points[i].y,
 | 
				
			||||||
 | 
					                        (gdouble) (points[i].x + points[j].x) / 2,
 | 
				
			||||||
 | 
					                        (gdouble) (points[i].y + points[j].y) / 2,
 | 
				
			||||||
 | 
					                        radius);
 | 
				
			||||||
 | 
					#ifdef KBDRAW_DEBUG
 | 
				
			||||||
 | 
					        printf ("      corner (%d, %d) -> (%d, %d):\n",
 | 
				
			||||||
 | 
					                points[i].x, points[i].y, points[j].x,
 | 
				
			||||||
 | 
					                points[j].y);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    cairo_close_path (cr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (filled)
 | 
				
			||||||
 | 
					        cairo_fill (cr);
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        cairo_stroke (cr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										26
									
								
								eek/eek-drawing.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								eek/eek-drawing.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					#ifndef EEK_DRAWING_H
 | 
				
			||||||
 | 
					#define EEK_DRAWING_H 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <cairo/cairo.h>
 | 
				
			||||||
 | 
					#include <pango/pango.h>
 | 
				
			||||||
 | 
					#include "eek-keyboard.h"
 | 
				
			||||||
 | 
					#include "eek-keysym.h"
 | 
				
			||||||
 | 
					#include "eek-types.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					G_BEGIN_DECLS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void eek_draw_text_on_layout  (PangoLayout           *layout,
 | 
				
			||||||
 | 
					                               const gchar           *text);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void eek_get_fonts            (EekKeyboard           *keyboard,
 | 
				
			||||||
 | 
					                               PangoLayout           *layout,
 | 
				
			||||||
 | 
					                               PangoFontDescription **fonts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void eek_draw_rounded_polygon (cairo_t               *cr,
 | 
				
			||||||
 | 
					                               gboolean               filled,
 | 
				
			||||||
 | 
					                               gdouble                radius,
 | 
				
			||||||
 | 
					                               EekPoint              *points,
 | 
				
			||||||
 | 
					                               gint                   num_points);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					G_END_DECLS
 | 
				
			||||||
 | 
					#endif  /* EEK_DRAWING_H */
 | 
				
			||||||
@ -33,6 +33,7 @@
 | 
				
			|||||||
#endif  /* HAVE_CONFIG_H */
 | 
					#endif  /* HAVE_CONFIG_H */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "eek-element.h"
 | 
					#include "eek-element.h"
 | 
				
			||||||
 | 
					#include "eek-container.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
    PROP_0,
 | 
					    PROP_0,
 | 
				
			||||||
@ -51,14 +52,37 @@ struct _EekElementPrivate
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    gchar *name;
 | 
					    gchar *name;
 | 
				
			||||||
    EekBounds bounds;
 | 
					    EekBounds bounds;
 | 
				
			||||||
 | 
					    EekContainer *parent;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
eek_element_real_set_name (EekElement *self,
 | 
					eek_element_real_set_parent (EekElement *self,
 | 
				
			||||||
                                  const gchar *name)
 | 
					                             EekContainer *parent)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    EekElementPrivate *priv = EEK_ELEMENT_GET_PRIVATE(self);
 | 
					    EekElementPrivate *priv = EEK_ELEMENT_GET_PRIVATE(self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (parent) {
 | 
				
			||||||
 | 
					        g_return_if_fail (EEK_IS_CONTAINER(parent));
 | 
				
			||||||
 | 
					        g_object_ref_sink (G_OBJECT(parent));
 | 
				
			||||||
 | 
					    } else if (priv->parent)
 | 
				
			||||||
 | 
					        g_object_unref (G_OBJECT (priv->parent));
 | 
				
			||||||
 | 
					    priv->parent = parent;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static EekContainer *
 | 
				
			||||||
 | 
					eek_element_real_get_parent (EekElement *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EekElementPrivate *priv = EEK_ELEMENT_GET_PRIVATE(self);
 | 
				
			||||||
 | 
					    return priv->parent;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					eek_element_real_set_name (EekElement  *self,
 | 
				
			||||||
 | 
					                           const gchar *name)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EekElementPrivate *priv = EEK_ELEMENT_GET_PRIVATE(self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_free (priv->name);
 | 
				
			||||||
    priv->name = g_strdup (name);
 | 
					    priv->name = g_strdup (name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_object_notify (G_OBJECT(self), "name");
 | 
					    g_object_notify (G_OBJECT(self), "name");
 | 
				
			||||||
@ -93,6 +117,17 @@ eek_element_real_get_bounds (EekElement *self,
 | 
				
			|||||||
    g_object_notify (G_OBJECT(self), "bounds");
 | 
					    g_object_notify (G_OBJECT(self), "bounds");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					eek_element_dispose (GObject *object)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EekElementPrivate *priv = EEK_ELEMENT_GET_PRIVATE(object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (priv->parent) {
 | 
				
			||||||
 | 
					        g_object_unref (G_OBJECT(priv->parent));
 | 
				
			||||||
 | 
					        priv->parent = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
eek_element_finalize (GObject *object)
 | 
					eek_element_finalize (GObject *object)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -155,6 +190,8 @@ eek_element_class_init (EekElementClass *klass)
 | 
				
			|||||||
    g_type_class_add_private (gobject_class,
 | 
					    g_type_class_add_private (gobject_class,
 | 
				
			||||||
                              sizeof (EekElementPrivate));
 | 
					                              sizeof (EekElementPrivate));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    klass->set_parent = eek_element_real_set_parent;
 | 
				
			||||||
 | 
					    klass->get_parent = eek_element_real_get_parent;
 | 
				
			||||||
    klass->set_name = eek_element_real_set_name;
 | 
					    klass->set_name = eek_element_real_set_name;
 | 
				
			||||||
    klass->get_name = eek_element_real_get_name;
 | 
					    klass->get_name = eek_element_real_get_name;
 | 
				
			||||||
    klass->set_bounds = eek_element_real_set_bounds;
 | 
					    klass->set_bounds = eek_element_real_set_bounds;
 | 
				
			||||||
@ -163,6 +200,7 @@ eek_element_class_init (EekElementClass *klass)
 | 
				
			|||||||
    gobject_class->set_property = eek_element_set_property;
 | 
					    gobject_class->set_property = eek_element_set_property;
 | 
				
			||||||
    gobject_class->get_property = eek_element_get_property;
 | 
					    gobject_class->get_property = eek_element_get_property;
 | 
				
			||||||
    gobject_class->finalize     = eek_element_finalize;
 | 
					    gobject_class->finalize     = eek_element_finalize;
 | 
				
			||||||
 | 
					    gobject_class->dispose     = eek_element_dispose;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * EekElement:name:
 | 
					     * EekElement:name:
 | 
				
			||||||
 | 
				
			|||||||
@ -31,7 +31,6 @@ G_BEGIN_DECLS
 | 
				
			|||||||
#define EEK_IS_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_ELEMENT))
 | 
					#define EEK_IS_ELEMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_ELEMENT))
 | 
				
			||||||
#define EEK_ELEMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_ELEMENT, EekElementClass))
 | 
					#define EEK_ELEMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_ELEMENT, EekElementClass))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct _EekElement EekElement;
 | 
					 | 
				
			||||||
typedef struct _EekElementClass   EekElementClass;
 | 
					typedef struct _EekElementClass   EekElementClass;
 | 
				
			||||||
typedef struct _EekElementPrivate EekElementPrivate;
 | 
					typedef struct _EekElementPrivate EekElementPrivate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -48,16 +47,19 @@ struct _EekElementClass
 | 
				
			|||||||
    /*< private >*/
 | 
					    /*< private >*/
 | 
				
			||||||
    GInitiallyUnownedClass parent_class;
 | 
					    GInitiallyUnownedClass parent_class;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void                  (* set_name)   (EekElement  *element,
 | 
					    void                  (* set_parent) (EekElement   *self,
 | 
				
			||||||
                                          const gchar *name);
 | 
					                                          EekContainer *parent);
 | 
				
			||||||
 | 
					    EekContainer         *(* get_parent) (EekElement   *self);
 | 
				
			||||||
 | 
					    void                  (* set_name)   (EekElement   *self,
 | 
				
			||||||
 | 
					                                          const gchar  *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    G_CONST_RETURN gchar *(* get_name)   (EekElement  *element);
 | 
					    G_CONST_RETURN gchar *(* get_name)   (EekElement   *self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void                  (* set_bounds) (EekElement  *element,
 | 
					    void                  (* set_bounds) (EekElement   *self,
 | 
				
			||||||
                                          EekBounds   *bounds);
 | 
					                                          EekBounds    *bounds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void                  (* get_bounds) (EekElement  *element,
 | 
					    void                  (* get_bounds) (EekElement   *self,
 | 
				
			||||||
                                          EekBounds   *bounds);
 | 
					                                          EekBounds    *bounds);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GType                 eek_element_get_type   (void) G_GNUC_CONST;
 | 
					GType                 eek_element_get_type   (void) G_GNUC_CONST;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										259
									
								
								eek/eek-gtk-keyboard.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										259
									
								
								eek/eek-gtk-keyboard.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,259 @@
 | 
				
			|||||||
 | 
					/* 
 | 
				
			||||||
 | 
					 * Copyright (C) 2010 Daiki Ueno <ueno@unixuser.org>
 | 
				
			||||||
 | 
					 * Copyright (C) 2010 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
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * SECTION:eek-gtk-keyboard
 | 
				
			||||||
 | 
					 * @short_description: #EekKeyboard embedding a #GtkActor
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_CONFIG_H
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					#endif  /* HAVE_CONFIG_H */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "eek-gtk-keyboard.h"
 | 
				
			||||||
 | 
					#include "eek-drawing.h"
 | 
				
			||||||
 | 
					#include "eek-keyboard.h"
 | 
				
			||||||
 | 
					#include "eek-section.h"
 | 
				
			||||||
 | 
					#include "eek-key.h"
 | 
				
			||||||
 | 
					#include "eek-keysym.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					G_DEFINE_TYPE (EekGtkKeyboard, eek_gtk_keyboard, EEK_TYPE_KEYBOARD);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define EEK_GTK_KEYBOARD_GET_PRIVATE(obj)                                  \
 | 
				
			||||||
 | 
					    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_GTK_KEYBOARD, EekGtkKeyboardPrivate))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct _EekGtkKeyboardPrivate
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    GtkWidget *widget;          /* GtkDrawingArea */
 | 
				
			||||||
 | 
					    GdkPixmap *pixmap;
 | 
				
			||||||
 | 
					    GdkColor *dark_color;
 | 
				
			||||||
 | 
					    cairo_t *cr;
 | 
				
			||||||
 | 
					    PangoLayout *layout;
 | 
				
			||||||
 | 
					    PangoFontDescription *fonts[EEK_KEYSYM_CATEGORY_LAST];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					eek_gtk_keyboard_dispose (GObject *object)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (priv->widget) {
 | 
				
			||||||
 | 
					        g_object_unref (priv->widget);
 | 
				
			||||||
 | 
					        priv->widget = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    G_OBJECT_CLASS (eek_gtk_keyboard_parent_class)->dispose (object);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					eek_gtk_keyboard_finalize (GObject *object)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(object);
 | 
				
			||||||
 | 
					    gint i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (i = 0; i < EEK_KEYSYM_CATEGORY_LAST; i++)
 | 
				
			||||||
 | 
					        pango_font_description_free (priv->fonts[i]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					eek_gtk_keyboard_class_init (EekGtkKeyboardClass *klass)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_type_class_add_private (gobject_class,
 | 
				
			||||||
 | 
					                              sizeof (EekGtkKeyboardPrivate));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gobject_class->dispose = eek_gtk_keyboard_dispose;
 | 
				
			||||||
 | 
					    gobject_class->finalize = eek_gtk_keyboard_finalize;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					eek_gtk_keyboard_init (EekGtkKeyboard *self)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EekGtkKeyboardPrivate *priv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    priv = self->priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
 | 
				
			||||||
 | 
					    priv->widget = NULL;
 | 
				
			||||||
 | 
					    priv->pixmap = NULL;
 | 
				
			||||||
 | 
					    memset (priv->fonts, 0, sizeof priv->fonts);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * eek_gtk_keyboard_new:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Create a new #EekGtkKeyboard.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					EekKeyboard*
 | 
				
			||||||
 | 
					eek_gtk_keyboard_new (void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return g_object_new (EEK_TYPE_GTK_KEYBOARD, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					draw_key (EekElement *element, gpointer user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EekKeyboard *keyboard = user_data;
 | 
				
			||||||
 | 
					    EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard);
 | 
				
			||||||
 | 
					    EekKey *key = EEK_KEY(element);
 | 
				
			||||||
 | 
					    EekOutline *outline;
 | 
				
			||||||
 | 
					    EekBounds bounds;
 | 
				
			||||||
 | 
					    guint keysym;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gdk_cairo_set_source_color (priv->cr, priv->dark_color);
 | 
				
			||||||
 | 
					    cairo_set_line_width (priv->cr, 1);
 | 
				
			||||||
 | 
					    cairo_set_line_join (priv->cr, CAIRO_LINE_JOIN_ROUND);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    eek_element_get_bounds (EEK_ELEMENT(key), &bounds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cairo_save (priv->cr);
 | 
				
			||||||
 | 
					    cairo_translate (priv->cr, bounds.x, bounds.y);
 | 
				
			||||||
 | 
					    outline = eek_key_get_outline (key);
 | 
				
			||||||
 | 
					    eek_draw_rounded_polygon (priv->cr,
 | 
				
			||||||
 | 
					                              FALSE,
 | 
				
			||||||
 | 
					                              outline->corner_radius,
 | 
				
			||||||
 | 
					                              outline->points,
 | 
				
			||||||
 | 
					                              outline->num_points);
 | 
				
			||||||
 | 
					    cairo_stroke (priv->cr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    keysym = eek_key_get_keysym (key);
 | 
				
			||||||
 | 
					    if (keysym != EEK_INVALID_KEYSYM) {
 | 
				
			||||||
 | 
					        const gchar *label = eek_keysym_to_string (keysym);
 | 
				
			||||||
 | 
					        PangoRectangle logical_rect = { 0, };
 | 
				
			||||||
 | 
					        EekKeysymCategory category = eek_keysym_get_category (keysym);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (category != EEK_KEYSYM_CATEGORY_UNKNOWN && label) {
 | 
				
			||||||
 | 
					            pango_layout_set_font_description (priv->layout,
 | 
				
			||||||
 | 
					                                               priv->fonts[category]);
 | 
				
			||||||
 | 
					            pango_layout_set_text (priv->layout, label, -1);
 | 
				
			||||||
 | 
					            pango_layout_get_extents (priv->layout, NULL, &logical_rect);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            cairo_move_to
 | 
				
			||||||
 | 
					                (priv->cr,
 | 
				
			||||||
 | 
					                 (bounds.width - logical_rect.width / PANGO_SCALE) / 2,
 | 
				
			||||||
 | 
					                 (bounds.height - logical_rect.height / PANGO_SCALE) / 2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            pango_layout_set_width (priv->layout, PANGO_SCALE * bounds.width);
 | 
				
			||||||
 | 
					            pango_layout_set_ellipsize (priv->layout, PANGO_ELLIPSIZE_END);
 | 
				
			||||||
 | 
					            pango_cairo_show_layout (priv->cr, priv->layout);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    cairo_restore (priv->cr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					draw_section (EekElement *element, gpointer user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EekKeyboard *keyboard = user_data;
 | 
				
			||||||
 | 
					    EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard);
 | 
				
			||||||
 | 
					    EekBounds bounds;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gdk_cairo_set_source_color (priv->cr, priv->dark_color);
 | 
				
			||||||
 | 
					    eek_element_get_bounds (element, &bounds);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cairo_save (priv->cr);
 | 
				
			||||||
 | 
					    cairo_translate (priv->cr, bounds.x, bounds.y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					    cairo_rectangle (priv->cr, 0, 0, bounds.width, bounds.height);
 | 
				
			||||||
 | 
					    cairo_stroke (priv->cr);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    eek_container_foreach_child (EEK_CONTAINER(element), draw_key,
 | 
				
			||||||
 | 
					                                 keyboard);
 | 
				
			||||||
 | 
					    cairo_restore (priv->cr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static gboolean
 | 
				
			||||||
 | 
					on_gtk_expose_event (GtkWidget      *widget,
 | 
				
			||||||
 | 
					                     GdkEventExpose *event,
 | 
				
			||||||
 | 
					                     gpointer        user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EekGtkKeyboard *keyboard = user_data;
 | 
				
			||||||
 | 
					    EekGtkKeyboardPrivate *priv =
 | 
				
			||||||
 | 
					        EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard);
 | 
				
			||||||
 | 
					    GtkStateType state = gtk_widget_get_state (GTK_WIDGET (widget));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!priv->pixmap) {
 | 
				
			||||||
 | 
					        GtkStateType state = gtk_widget_get_state (GTK_WIDGET (priv->widget));
 | 
				
			||||||
 | 
					        GtkAllocation allocation;
 | 
				
			||||||
 | 
						PangoContext *context;
 | 
				
			||||||
 | 
					        PangoFontDescription *default_font_desc;
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        context = gtk_widget_get_pango_context (GTK_WIDGET (priv->widget));
 | 
				
			||||||
 | 
						priv->layout = pango_layout_new (context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* compute font sizes */
 | 
				
			||||||
 | 
					        default_font_desc =
 | 
				
			||||||
 | 
					            gtk_widget_get_style (GTK_WIDGET(priv->widget))->font_desc;
 | 
				
			||||||
 | 
					        pango_layout_set_font_description (priv->layout, default_font_desc);
 | 
				
			||||||
 | 
					        eek_get_fonts (EEK_KEYBOARD(keyboard), priv->layout, priv->fonts);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* create priv->pixmap */
 | 
				
			||||||
 | 
						gtk_widget_set_double_buffered (GTK_WIDGET (priv->widget), FALSE);
 | 
				
			||||||
 | 
					        gtk_widget_get_allocation (GTK_WIDGET (priv->widget), &allocation);
 | 
				
			||||||
 | 
					        priv->pixmap =
 | 
				
			||||||
 | 
					            gdk_pixmap_new (gtk_widget_get_window (GTK_WIDGET (priv->widget)),
 | 
				
			||||||
 | 
					                            allocation.width, allocation.height, -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* blank background */
 | 
				
			||||||
 | 
					        gdk_draw_rectangle
 | 
				
			||||||
 | 
					            (priv->pixmap,
 | 
				
			||||||
 | 
					             gtk_widget_get_style (GTK_WIDGET(priv->widget))->base_gc[state],
 | 
				
			||||||
 | 
					             TRUE,
 | 
				
			||||||
 | 
					             0, 0, allocation.width, allocation.height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* draw sections on the canvas */
 | 
				
			||||||
 | 
					        priv->cr = gdk_cairo_create (GDK_DRAWABLE (priv->pixmap));
 | 
				
			||||||
 | 
					        priv->dark_color =
 | 
				
			||||||
 | 
					            >k_widget_get_style (GTK_WIDGET (priv->widget))->dark[state];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        eek_container_foreach_child (EEK_CONTAINER(keyboard), draw_section,
 | 
				
			||||||
 | 
					                                     keyboard);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cairo_destroy (priv->cr);
 | 
				
			||||||
 | 
					        priv->cr = NULL;
 | 
				
			||||||
 | 
					        priv->dark_color = NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gdk_draw_drawable (gtk_widget_get_window (widget),
 | 
				
			||||||
 | 
					                       gtk_widget_get_style (widget)->fg_gc[state],
 | 
				
			||||||
 | 
					                       priv->pixmap,
 | 
				
			||||||
 | 
					                       event->area.x, event->area.y,
 | 
				
			||||||
 | 
					                       event->area.x, event->area.y,
 | 
				
			||||||
 | 
					                       event->area.width, event->area.height);
 | 
				
			||||||
 | 
					    return TRUE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GtkWidget *
 | 
				
			||||||
 | 
					eek_gtk_keyboard_get_widget (EekGtkKeyboard *keyboard)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EekGtkKeyboardPrivate *priv =
 | 
				
			||||||
 | 
					        EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!priv->widget) {
 | 
				
			||||||
 | 
					        priv->widget = gtk_drawing_area_new ();
 | 
				
			||||||
 | 
					        g_object_ref_sink (priv->widget);
 | 
				
			||||||
 | 
					        g_signal_connect (priv->widget, "expose_event",
 | 
				
			||||||
 | 
					                          G_CALLBACK (on_gtk_expose_event), keyboard);
 | 
				
			||||||
 | 
					        eek_keyboard_realize (EEK_KEYBOARD(keyboard));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return priv->widget;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										57
									
								
								eek/eek-gtk-keyboard.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								eek/eek-gtk-keyboard.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
				
			|||||||
 | 
					/* 
 | 
				
			||||||
 | 
					 * Copyright (C) 2010 Daiki Ueno <ueno@unixuser.org>
 | 
				
			||||||
 | 
					 * Copyright (C) 2010 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
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef EEK_GTK_KEYBOARD_H
 | 
				
			||||||
 | 
					#define EEK_GTK_KEYBOARD_H 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <gtk/gtk.h>
 | 
				
			||||||
 | 
					#include "eek-keyboard.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					G_BEGIN_DECLS
 | 
				
			||||||
 | 
					#define EEK_TYPE_GTK_KEYBOARD (eek_gtk_keyboard_get_type())
 | 
				
			||||||
 | 
					#define EEK_GTK_KEYBOARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EEK_TYPE_GTK_KEYBOARD, EekGtkKeyboard))
 | 
				
			||||||
 | 
					#define EEK_GTK_KEYBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EEK_TYPE_GTK_KEYBOARD, EekGtkKeyboardClass))
 | 
				
			||||||
 | 
					#define EEK_IS_GTK_KEYBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EEK_TYPE_GTK_KEYBOARD))
 | 
				
			||||||
 | 
					#define EEK_IS_GTK_KEYBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EEK_TYPE_GTK_KEYBOARD))
 | 
				
			||||||
 | 
					#define EEK_GTK_KEYBOARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EEK_TYPE_GTK_KEYBOARD, EekGtkKeyboardClass))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct _EekGtkKeyboard EekGtkKeyboard;
 | 
				
			||||||
 | 
					typedef struct _EekGtkKeyboardClass EekGtkKeyboardClass;
 | 
				
			||||||
 | 
					typedef struct _EekGtkKeyboardPrivate EekGtkKeyboardPrivate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct _EekGtkKeyboard
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /*< private >*/
 | 
				
			||||||
 | 
					    EekKeyboard parent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    EekGtkKeyboardPrivate *priv;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct _EekGtkKeyboardClass
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /*< private >*/
 | 
				
			||||||
 | 
					    EekKeyboardClass parent_class;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GType        eek_gtk_keyboard_get_type   (void) G_GNUC_CONST;
 | 
				
			||||||
 | 
					EekKeyboard *eek_gtk_keyboard_new        (void);
 | 
				
			||||||
 | 
					GtkWidget   *eek_gtk_keyboard_get_widget (EekGtkKeyboard *keyboard);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					G_END_DECLS
 | 
				
			||||||
 | 
					#endif  /* EEK_GTK_KEYBOARD_H */
 | 
				
			||||||
							
								
								
									
										26
									
								
								eek/eek-gtk.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								eek/eek-gtk.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					/* 
 | 
				
			||||||
 | 
					 * Copyright (C) 2010 Daiki Ueno <ueno@unixuser.org>
 | 
				
			||||||
 | 
					 * Copyright (C) 2010 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
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#ifndef EEK_GTK_H
 | 
				
			||||||
 | 
					#define EEK_GTK_H 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "eek.h"
 | 
				
			||||||
 | 
					#include "eek-gtk-keyboard.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif  /* EEK_GTK_H */
 | 
				
			||||||
@ -17,8 +17,8 @@
 | 
				
			|||||||
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
					 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
				
			||||||
 * 02110-1301 USA
 | 
					 * 02110-1301 USA
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#ifndef EEK_KEYSYMS_H
 | 
					#ifndef EEK_KEYSYM_H
 | 
				
			||||||
#define EEK_KEYSYMS_H 1
 | 
					#define EEK_KEYSYM_H 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define EEK_INVALID_KEYSYM ((guint)(-1))
 | 
					#define EEK_INVALID_KEYSYM ((guint)(-1))
 | 
				
			||||||
#define EEK_INVALID_KEYCODE ((guint)(-1))
 | 
					#define EEK_INVALID_KEYCODE ((guint)(-1))
 | 
				
			||||||
@ -27,10 +27,11 @@ typedef enum {
 | 
				
			|||||||
    EEK_KEYSYM_CATEGORY_LETTER,
 | 
					    EEK_KEYSYM_CATEGORY_LETTER,
 | 
				
			||||||
    EEK_KEYSYM_CATEGORY_FUNCTION,
 | 
					    EEK_KEYSYM_CATEGORY_FUNCTION,
 | 
				
			||||||
    EEK_KEYSYM_CATEGORY_KEYNAME,
 | 
					    EEK_KEYSYM_CATEGORY_KEYNAME,
 | 
				
			||||||
    EEK_KEYSYM_CATEGORY_UNKNOWN
 | 
					    EEK_KEYSYM_CATEGORY_UNKNOWN,
 | 
				
			||||||
 | 
					    EEK_KEYSYM_CATEGORY_LAST = EEK_KEYSYM_CATEGORY_UNKNOWN
 | 
				
			||||||
} EekKeysymCategory;
 | 
					} EekKeysymCategory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
G_CONST_RETURN gchar *eek_keysym_to_string (guint keysym);
 | 
					G_CONST_RETURN gchar *eek_keysym_to_string (guint keysym);
 | 
				
			||||||
EekKeysymCategory eek_keysym_get_category (guint keysym);
 | 
					EekKeysymCategory eek_keysym_get_category (guint keysym);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif  /* EEK_KEYSYMS_H */
 | 
					#endif  /* EEK_KEYSYM_H */
 | 
				
			||||||
 | 
				
			|||||||
@ -30,6 +30,8 @@ typedef enum {
 | 
				
			|||||||
    EEK_ORIENTATION_INVALID = -1
 | 
					    EEK_ORIENTATION_INVALID = -1
 | 
				
			||||||
} EekOrientation;
 | 
					} EekOrientation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct _EekElement EekElement;
 | 
				
			||||||
 | 
					typedef struct _EekContainer EekContainer;
 | 
				
			||||||
typedef struct _EekKey EekKey;
 | 
					typedef struct _EekKey EekKey;
 | 
				
			||||||
typedef struct _EekSection EekSection;
 | 
					typedef struct _EekSection EekSection;
 | 
				
			||||||
typedef struct _EekKeyboard EekKeyboard;
 | 
					typedef struct _EekKeyboard EekKeyboard;
 | 
				
			||||||
@ -91,6 +93,12 @@ typedef struct _EekBounds EekBounds;
 | 
				
			|||||||
#define EEK_TYPE_BOUNDS (eek_bounds_get_type ())
 | 
					#define EEK_TYPE_BOUNDS (eek_bounds_get_type ())
 | 
				
			||||||
GType eek_bounds_get_type (void) G_GNUC_CONST;
 | 
					GType eek_bounds_get_type (void) G_GNUC_CONST;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					G_INLINE_FUNC gdouble
 | 
				
			||||||
 | 
					eek_bounds_long_side (EekBounds *bounds)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return bounds->width > bounds->height ? bounds->width : bounds->height;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * EekOutline:
 | 
					 * EekOutline:
 | 
				
			||||||
 * @corner_radius: radius of corners of rounded polygon
 | 
					 * @corner_radius: radius of corners of rounded polygon
 | 
				
			||||||
 | 
				
			|||||||
@ -21,6 +21,8 @@
 | 
				
			|||||||
#define EEK_H 1
 | 
					#define EEK_H 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "eek-keyboard.h"
 | 
					#include "eek-keyboard.h"
 | 
				
			||||||
 | 
					#include "eek-section.h"
 | 
				
			||||||
 | 
					#include "eek-key.h"
 | 
				
			||||||
#include "eek-layout.h"
 | 
					#include "eek-layout.h"
 | 
				
			||||||
#include "eek-keysym.h"
 | 
					#include "eek-keysym.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -16,6 +16,9 @@
 | 
				
			|||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
					# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
				
			||||||
# 02110-1301 USA
 | 
					# 02110-1301 USA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bin_PROGRAMS = eekboard
 | 
					bin_PROGRAMS = eekboard eekboard-gtk
 | 
				
			||||||
eekboard_CFLAGS = -I$(top_srcdir) $(GOBJECT2_CFLAGS) $(CLUTTER_CFLAGS) $(CLUTTER_GTK_CFLAGS) $(GTK2_CFLAGS) $(XKB_CFLAGS) $(LIBXKLAVIER_CFLAGS) $(LIBFAKEKEY_CFLAGS)
 | 
					eekboard_CFLAGS = -I$(top_srcdir) $(GOBJECT2_CFLAGS) $(CLUTTER_CFLAGS) $(CLUTTER_GTK_CFLAGS) $(GTK2_CFLAGS) $(XKB_CFLAGS) $(LIBXKLAVIER_CFLAGS) $(LIBFAKEKEY_CFLAGS)
 | 
				
			||||||
eekboard_LDFLAGS = $(top_builddir)/eek/libeek.la $(top_builddir)/eek/libeek-xkl.la $(top_builddir)/eek/libeek-clutter.la $(GOBJECT2_LIBS) $(CLUTTER_LIBS) $(CLUTTER_GTK_LIBS) $(GTK2_CFLAGS) $(XKB_LIBS) $(LIBXKLAVIER_LIBS) $(LIBFAKEKEY_LIBS)
 | 
					eekboard_LDFLAGS = $(top_builddir)/eek/libeek.la $(top_builddir)/eek/libeek-xkl.la $(top_builddir)/eek/libeek-clutter.la $(GOBJECT2_LIBS) $(CLUTTER_LIBS) $(CLUTTER_GTK_LIBS) $(GTK2_CFLAGS) $(XKB_LIBS) $(LIBXKLAVIER_LIBS) $(LIBFAKEKEY_LIBS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					eekboard_gtk_CFLAGS = -I$(top_srcdir) $(GOBJECT2_CFLAGS) $(GTK2_CFLAGS) $(XKB_CFLAGS) $(LIBXKLAVIER_CFLAGS) $(LIBFAKEKEY_CFLAGS)
 | 
				
			||||||
 | 
					eekboard_gtk_LDFLAGS = $(top_builddir)/eek/libeek.la $(top_builddir)/eek/libeek-xkl.la $(top_builddir)/eek/libeek-gtk.la $(GOBJECT2_LIBS) $(GTK2_CFLAGS) $(XKB_LIBS) $(LIBXKLAVIER_LIBS) $(LIBFAKEKEY_LIBS)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										484
									
								
								src/eekboard-gtk.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										484
									
								
								src/eekboard-gtk.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,484 @@
 | 
				
			|||||||
 | 
					/* 
 | 
				
			||||||
 | 
					 * Copyright (C) 2010 Daiki Ueno <ueno@unixuser.org>
 | 
				
			||||||
 | 
					 * Copyright (C) 2010 Red Hat, Inc.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program 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 General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <fakekey/fakekey.h>
 | 
				
			||||||
 | 
					#include <glib/gi18n.h>
 | 
				
			||||||
 | 
					#include <gdk/gdkx.h>
 | 
				
			||||||
 | 
					#include <gtk/gtk.h>
 | 
				
			||||||
 | 
					#include <libxklavier/xklavier.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_CONFIG_H
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					#endif  /* HAVE_CONFIG_H */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "eek/eek-gtk.h"
 | 
				
			||||||
 | 
					#include "eek/eek-xkl.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CSW 640
 | 
				
			||||||
 | 
					#define CSH 480
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LICENSE \
 | 
				
			||||||
 | 
					    "This program is free software: you can redistribute it and/or modify " \
 | 
				
			||||||
 | 
					    "it under the terms of the GNU General Public License as published by " \
 | 
				
			||||||
 | 
					    "the Free Software Foundation, either version 3 of the License, or " \
 | 
				
			||||||
 | 
					    "(at your option) any later version." \
 | 
				
			||||||
 | 
					    "\n\n" \
 | 
				
			||||||
 | 
					    "This program 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 General Public License for more details." \
 | 
				
			||||||
 | 
					    "\n\n" \
 | 
				
			||||||
 | 
					    "You should have received a copy of the GNU General Public License " \
 | 
				
			||||||
 | 
					    "along with this program.  If not, see <http://www.gnu.org/licenses/>. " \
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct _EekBoard {
 | 
				
			||||||
 | 
					    EekKeyboard *keyboard;
 | 
				
			||||||
 | 
					    EekLayout *layout;          /* FIXME: eek_keyboard_get_layout() */
 | 
				
			||||||
 | 
					    Display *display;
 | 
				
			||||||
 | 
					    FakeKey *fakekey;
 | 
				
			||||||
 | 
					    guint modifiers;
 | 
				
			||||||
 | 
					    gfloat width, height;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					typedef struct _EekBoard EekBoard;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void on_about (GtkAction * action, GtkWidget *window);
 | 
				
			||||||
 | 
					static void on_monitor_key_event_toggled (GtkToggleAction *action,
 | 
				
			||||||
 | 
					                                          GtkWidget *window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char ui_description[] =
 | 
				
			||||||
 | 
					    "<ui>"
 | 
				
			||||||
 | 
					    "  <menubar name='MainMenu'>"
 | 
				
			||||||
 | 
					    "    <menu action='FileMenu'>"
 | 
				
			||||||
 | 
					    "      <menuitem action='Quit'/>"
 | 
				
			||||||
 | 
					    "    </menu>"
 | 
				
			||||||
 | 
					    "    <menu action='KeyboardMenu'>"
 | 
				
			||||||
 | 
					    "      <menuitem action='MonitorKeyEvent'/>"
 | 
				
			||||||
 | 
					    "      <menu action='SetLayout'>"
 | 
				
			||||||
 | 
					    "        <placeholder name='LayoutsPH'/>"
 | 
				
			||||||
 | 
					    "      </menu>"
 | 
				
			||||||
 | 
					    "    </menu>"
 | 
				
			||||||
 | 
					    "    <menu action='HelpMenu'>"
 | 
				
			||||||
 | 
					    "      <menuitem action='About'/>"
 | 
				
			||||||
 | 
					    "    </menu>"
 | 
				
			||||||
 | 
					    "  </menubar>"
 | 
				
			||||||
 | 
					    "</ui>";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SET_LAYOUT_UI_PATH "/MainMenu/KeyboardMenu/SetLayout/LayoutsPH"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct _ConfigCallbackData {
 | 
				
			||||||
 | 
					    EekBoard *eekboard;
 | 
				
			||||||
 | 
					    XklConfigRec *config;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					typedef struct _ConfigCallbackData ConfigCallbackData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct _LayoutCallbackData {
 | 
				
			||||||
 | 
					    EekBoard *eekboard;
 | 
				
			||||||
 | 
					    GtkUIManager *ui_manager;
 | 
				
			||||||
 | 
					    GtkActionGroup *action_group;
 | 
				
			||||||
 | 
					    guint merge_id;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					typedef struct _LayoutCallbackData LayoutCallbackData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const GtkActionEntry action_entry[] = {
 | 
				
			||||||
 | 
					    {"FileMenu", NULL, N_("_File")},
 | 
				
			||||||
 | 
					    {"KeyboardMenu", NULL, N_("_Keyboard")},
 | 
				
			||||||
 | 
					    {"HelpMenu", NULL, N_("_Help")},
 | 
				
			||||||
 | 
					    {"Quit", GTK_STOCK_QUIT, NULL, NULL, NULL, G_CALLBACK (gtk_main_quit)},
 | 
				
			||||||
 | 
					    {"SetLayout", NULL, N_("Set Layout"), NULL, NULL, NULL},
 | 
				
			||||||
 | 
					    {"About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK (on_about)}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const GtkToggleActionEntry toggle_action_entry[] = {
 | 
				
			||||||
 | 
					    {"MonitorKeyEvent", NULL, N_("Monitor Key Typing"), NULL, NULL,
 | 
				
			||||||
 | 
					     G_CALLBACK(on_monitor_key_event_toggled), FALSE}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					on_about (GtkAction * action, GtkWidget *window)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  const gchar *authors[] = { "Daiki Ueno", NULL };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  gtk_show_about_dialog (GTK_WINDOW (window),
 | 
				
			||||||
 | 
					                         "version", VERSION,
 | 
				
			||||||
 | 
					                         "copyright",
 | 
				
			||||||
 | 
					                         "Copyright \xc2\xa9 2010 Daiki Ueno\n"
 | 
				
			||||||
 | 
					                         "Copyright \xc2\xa9 2010 Red Hat, Inc.",
 | 
				
			||||||
 | 
					                         "license", LICENSE,
 | 
				
			||||||
 | 
					                         "comments",
 | 
				
			||||||
 | 
					                         _("A virtual keyboard for GNOME"),
 | 
				
			||||||
 | 
					                         "authors", authors,
 | 
				
			||||||
 | 
					                         "website",
 | 
				
			||||||
 | 
					                         "http://github.com/ueno/eek/",
 | 
				
			||||||
 | 
					                         "website-label", _("EekBoard web site"),
 | 
				
			||||||
 | 
					                         "wrap-license", TRUE, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					on_monitor_key_event_toggled (GtkToggleAction *action,
 | 
				
			||||||
 | 
					                              GtkWidget *window)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    g_warning ("not implemented");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					on_key_pressed (EekKeyboard *keyboard,
 | 
				
			||||||
 | 
					                EekKey      *key,
 | 
				
			||||||
 | 
					                gpointer user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EekBoard *eekboard = user_data;
 | 
				
			||||||
 | 
					    guint keysym;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    keysym = eek_key_get_keysym (key);
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					    g_debug ("%s %X", eek_keysym_to_string (keysym), eekboard->modifiers);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    fakekey_press_keysym (eekboard->fakekey, keysym, eekboard->modifiers);
 | 
				
			||||||
 | 
					    if (keysym == XK_Shift_L || keysym == XK_Shift_R) {
 | 
				
			||||||
 | 
					        gint group, level;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        eekboard->modifiers ^= ShiftMask;
 | 
				
			||||||
 | 
					        eek_keyboard_get_keysym_index (keyboard, &group, &level);
 | 
				
			||||||
 | 
					        eek_keyboard_set_keysym_index (keyboard, group,
 | 
				
			||||||
 | 
					                                       eekboard->modifiers & ShiftMask ? 1 : 0);
 | 
				
			||||||
 | 
					    } else if (keysym == XK_Control_L || keysym == XK_Control_R) {
 | 
				
			||||||
 | 
					        eekboard->modifiers ^= ControlMask;
 | 
				
			||||||
 | 
					    } else if (keysym == XK_Alt_L || keysym == XK_Alt_R) {
 | 
				
			||||||
 | 
					        eekboard->modifiers ^= Mod1Mask;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					on_key_released (EekKeyboard *keyboard,
 | 
				
			||||||
 | 
					                 EekKey      *key,
 | 
				
			||||||
 | 
					                 gpointer user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EekBoard *eekboard = user_data;
 | 
				
			||||||
 | 
					    fakekey_release (eekboard->fakekey);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					on_activate (GtkAction *action, gpointer user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ConfigCallbackData *data = user_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    eek_xkl_layout_set_config (EEK_XKL_LAYOUT(data->eekboard->layout),
 | 
				
			||||||
 | 
					                               data->config);
 | 
				
			||||||
 | 
					    g_object_unref (data->config);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					create_keyboard (EekBoard  *eekboard,
 | 
				
			||||||
 | 
					                 ClutterActor *stage,
 | 
				
			||||||
 | 
					                 EekLayout *layout,
 | 
				
			||||||
 | 
					                 gfloat     initial_width,
 | 
				
			||||||
 | 
					                 gfloat     initial_height)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ClutterActor *actor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    eekboard->keyboard = eek_clutter_keyboard_new (initial_width,
 | 
				
			||||||
 | 
					                                                   initial_height);
 | 
				
			||||||
 | 
					    g_signal_connect (eekboard->keyboard, "key-pressed",
 | 
				
			||||||
 | 
					                      G_CALLBACK(on_key_pressed), eekboard);
 | 
				
			||||||
 | 
					    g_signal_connect (eekboard->keyboard, "key-released",
 | 
				
			||||||
 | 
					                      G_CALLBACK(on_key_released), eekboard);
 | 
				
			||||||
 | 
					    eek_keyboard_set_layout (eekboard->keyboard, layout);
 | 
				
			||||||
 | 
					    actor = eek_clutter_keyboard_get_actor
 | 
				
			||||||
 | 
					        (EEK_CLUTTER_KEYBOARD(eekboard->keyboard));
 | 
				
			||||||
 | 
					    clutter_actor_get_size (actor,
 | 
				
			||||||
 | 
					                            &eekboard->width,
 | 
				
			||||||
 | 
					                            &eekboard->height);
 | 
				
			||||||
 | 
					    clutter_container_add_actor (CLUTTER_CONTAINER(stage), actor);
 | 
				
			||||||
 | 
					    clutter_actor_set_size (stage,
 | 
				
			||||||
 | 
					                            eekboard->width,
 | 
				
			||||||
 | 
					                            eekboard->height);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* FIXME: EekKeyboard should handle relayout by itself. */
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					on_changed (EekLayout *layout, gpointer user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EekBoard *eekboard = user_data;
 | 
				
			||||||
 | 
					    ClutterActor *stage, *actor;
 | 
				
			||||||
 | 
					    gfloat width, height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    actor = eek_clutter_keyboard_get_actor
 | 
				
			||||||
 | 
					        (EEK_CLUTTER_KEYBOARD(eekboard->keyboard));
 | 
				
			||||||
 | 
					    stage = clutter_actor_get_stage (actor);
 | 
				
			||||||
 | 
					    clutter_actor_get_size (stage, &width, &height);
 | 
				
			||||||
 | 
					    clutter_container_remove_actor (CLUTTER_CONTAINER(stage), actor);
 | 
				
			||||||
 | 
					    g_object_unref (eekboard->keyboard);
 | 
				
			||||||
 | 
					    create_keyboard (eekboard, stage, layout, width, height);
 | 
				
			||||||
 | 
					    clutter_actor_get_size (stage, &eekboard->width, &eekboard->height);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					variant_callback (XklConfigRegistry *registry,
 | 
				
			||||||
 | 
					                  const XklConfigItem *item,
 | 
				
			||||||
 | 
					                  gpointer user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    GSList **r_variants = user_data;
 | 
				
			||||||
 | 
					    XklConfigItem *_item;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _item = g_slice_dup (XklConfigItem, item);
 | 
				
			||||||
 | 
					    *r_variants = g_slist_prepend (*r_variants, _item);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					layout_callback (XklConfigRegistry *registry,
 | 
				
			||||||
 | 
					                 const XklConfigItem *item,
 | 
				
			||||||
 | 
					                 gpointer user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    LayoutCallbackData *data = user_data;
 | 
				
			||||||
 | 
					    GtkAction *action;
 | 
				
			||||||
 | 
					    GSList *variants = NULL;
 | 
				
			||||||
 | 
					    char layout_action_name[128], variant_action_name[128];
 | 
				
			||||||
 | 
					    ConfigCallbackData *config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_snprintf (layout_action_name, sizeof (layout_action_name),
 | 
				
			||||||
 | 
					                "SetLayout%s", item->name);
 | 
				
			||||||
 | 
					    action = gtk_action_new (layout_action_name, item->description, NULL, NULL);
 | 
				
			||||||
 | 
					    gtk_action_group_add_action (data->action_group, action);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    xkl_config_registry_foreach_layout_variant (registry,
 | 
				
			||||||
 | 
					                                                item->name,
 | 
				
			||||||
 | 
					                                                variant_callback,
 | 
				
			||||||
 | 
					                                                &variants);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!variants) {
 | 
				
			||||||
 | 
					        config = g_slice_new (ConfigCallbackData);
 | 
				
			||||||
 | 
					        config->eekboard = data->eekboard;
 | 
				
			||||||
 | 
					        config->config = xkl_config_rec_new ();
 | 
				
			||||||
 | 
					        config->config->layouts = g_new0 (char *, 2);
 | 
				
			||||||
 | 
					        config->config->layouts[0] = g_strdup (item->name);
 | 
				
			||||||
 | 
					        config->config->layouts[1] = NULL;
 | 
				
			||||||
 | 
					        config->config->variants = NULL;
 | 
				
			||||||
 | 
					        g_signal_connect (action, "activate", G_CALLBACK (on_activate),
 | 
				
			||||||
 | 
					                          config);
 | 
				
			||||||
 | 
					        g_object_unref (action);
 | 
				
			||||||
 | 
					        gtk_ui_manager_add_ui (data->ui_manager, data->merge_id,
 | 
				
			||||||
 | 
					                               SET_LAYOUT_UI_PATH,
 | 
				
			||||||
 | 
					                               layout_action_name, layout_action_name,
 | 
				
			||||||
 | 
					                               GTK_UI_MANAGER_MENUITEM, FALSE);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        char layout_path[128];
 | 
				
			||||||
 | 
					        GSList *head;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        g_object_unref (action);
 | 
				
			||||||
 | 
					        gtk_ui_manager_add_ui (data->ui_manager, data->merge_id,
 | 
				
			||||||
 | 
					                               SET_LAYOUT_UI_PATH,
 | 
				
			||||||
 | 
					                               layout_action_name, layout_action_name,
 | 
				
			||||||
 | 
					                               GTK_UI_MANAGER_MENU, FALSE);
 | 
				
			||||||
 | 
					        g_snprintf (layout_path, sizeof (layout_path),
 | 
				
			||||||
 | 
					                    SET_LAYOUT_UI_PATH "/%s", layout_action_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (head = variants; head; head = head->next) {
 | 
				
			||||||
 | 
					            XklConfigItem *_item = head->data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            g_snprintf (variant_action_name, sizeof (variant_action_name),
 | 
				
			||||||
 | 
					                        "SetVariant%s%s", item->name, _item->name);
 | 
				
			||||||
 | 
					            action = gtk_action_new (variant_action_name,
 | 
				
			||||||
 | 
					                                     _item->description,
 | 
				
			||||||
 | 
					                                     NULL,
 | 
				
			||||||
 | 
					                                     NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            config = g_slice_new (ConfigCallbackData);
 | 
				
			||||||
 | 
					            config->eekboard = data->eekboard;
 | 
				
			||||||
 | 
					            config->config = xkl_config_rec_new ();
 | 
				
			||||||
 | 
					            config->config->layouts = g_new0 (char *, 2);
 | 
				
			||||||
 | 
					            config->config->layouts[0] = g_strdup (item->name);
 | 
				
			||||||
 | 
					            config->config->layouts[1] = NULL;
 | 
				
			||||||
 | 
					            config->config->variants = g_new0 (char *, 2);
 | 
				
			||||||
 | 
					            config->config->variants[0] = g_strdup (_item->name);
 | 
				
			||||||
 | 
					            config->config->variants[1] = NULL;
 | 
				
			||||||
 | 
					            g_signal_connect (action, "activate", G_CALLBACK (on_activate),
 | 
				
			||||||
 | 
					                              config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            gtk_action_group_add_action (data->action_group, action);
 | 
				
			||||||
 | 
					            g_object_unref (action);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            gtk_ui_manager_add_ui (data->ui_manager, data->merge_id,
 | 
				
			||||||
 | 
					                                   layout_path,
 | 
				
			||||||
 | 
					                                   variant_action_name, variant_action_name,
 | 
				
			||||||
 | 
					                                   GTK_UI_MANAGER_MENUITEM, FALSE);
 | 
				
			||||||
 | 
					            g_slice_free (XklConfigItem, _item);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        g_slist_free (variants);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					create_layouts_menu (EekBoard *eekboard, GtkUIManager *ui_manager)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    XklEngine *engine;
 | 
				
			||||||
 | 
					    XklConfigRegistry *registry;
 | 
				
			||||||
 | 
					    LayoutCallbackData data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    data.eekboard = eekboard;
 | 
				
			||||||
 | 
					    data.ui_manager = ui_manager;
 | 
				
			||||||
 | 
					    data.action_group = gtk_action_group_new ("Layouts");
 | 
				
			||||||
 | 
					    gtk_ui_manager_insert_action_group (data.ui_manager, data.action_group, -1);
 | 
				
			||||||
 | 
					    data.merge_id = gtk_ui_manager_new_merge_id (ui_manager);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    engine = xkl_engine_get_instance (eekboard->display);
 | 
				
			||||||
 | 
					    registry = xkl_config_registry_get_instance (engine);
 | 
				
			||||||
 | 
					    xkl_config_registry_load (registry, FALSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    xkl_config_registry_foreach_layout (registry, layout_callback, &data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					create_menus (EekBoard      *eekboard,
 | 
				
			||||||
 | 
					              GtkWidget     *window,
 | 
				
			||||||
 | 
					              GtkUIManager * ui_manager)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    GtkActionGroup *action_group;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    action_group = gtk_action_group_new ("MenuActions");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gtk_action_group_add_actions (action_group, action_entry,
 | 
				
			||||||
 | 
					                                  G_N_ELEMENTS (action_entry), window);
 | 
				
			||||||
 | 
					    gtk_action_group_add_toggle_actions (action_group, toggle_action_entry,
 | 
				
			||||||
 | 
					                                         G_N_ELEMENTS (toggle_action_entry),
 | 
				
			||||||
 | 
					                                         window);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
 | 
				
			||||||
 | 
					    gtk_ui_manager_add_ui_from_string (ui_manager, ui_description, -1, NULL);
 | 
				
			||||||
 | 
					    create_layouts_menu (eekboard, ui_manager);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					static void
 | 
				
			||||||
 | 
					on_resize (GObject *object,
 | 
				
			||||||
 | 
						   GParamSpec *param_spec,
 | 
				
			||||||
 | 
						   gpointer user_data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EekBoard *eekboard = user_data;
 | 
				
			||||||
 | 
					    GValue value = {0};
 | 
				
			||||||
 | 
					    gfloat width, height, scale;
 | 
				
			||||||
 | 
					    ClutterActor *stage, *actor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    actor = eek_clutter_keyboard_get_actor
 | 
				
			||||||
 | 
					        (EEK_CLUTTER_KEYBOARD(eekboard->keyboard));
 | 
				
			||||||
 | 
					    stage = clutter_actor_get_stage (actor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_object_get (G_OBJECT(stage), "width", &width, NULL);
 | 
				
			||||||
 | 
					    g_object_get (G_OBJECT(stage), "height", &height, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_value_init (&value, G_TYPE_DOUBLE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    scale = width > height ? width / eekboard->width :
 | 
				
			||||||
 | 
					        width / eekboard->height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_value_set_double (&value, scale);
 | 
				
			||||||
 | 
					    g_object_set_property (G_OBJECT (stage),
 | 
				
			||||||
 | 
					                           "scale-x",
 | 
				
			||||||
 | 
					                           &value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_value_set_double (&value, scale);
 | 
				
			||||||
 | 
					    g_object_set_property (G_OBJECT (stage),
 | 
				
			||||||
 | 
					                           "scale-y",
 | 
				
			||||||
 | 
					                           &value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main (int argc, char *argv[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EekBoard eekboard;
 | 
				
			||||||
 | 
					    GtkWidget *menubar, *embed, *vbox, *window;
 | 
				
			||||||
 | 
					    GtkUIManager *ui_manager;
 | 
				
			||||||
 | 
					    EekBounds bounds;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!gtk_init_check (&argc, &argv)) {
 | 
				
			||||||
 | 
					        fprintf (stderr, "Can't init Clutter-Gtk\n");
 | 
				
			||||||
 | 
					        exit (1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset (&eekboard, 0, sizeof eekboard);
 | 
				
			||||||
 | 
					    eekboard.display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
 | 
				
			||||||
 | 
					    if (!eekboard.display) {
 | 
				
			||||||
 | 
					        fprintf (stderr, "Can't open display\n");
 | 
				
			||||||
 | 
					        exit (1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    eekboard.fakekey = fakekey_init (eekboard.display);
 | 
				
			||||||
 | 
					    if (!eekboard.fakekey) {
 | 
				
			||||||
 | 
					        fprintf (stderr, "Can't init fakekey\n");
 | 
				
			||||||
 | 
					        exit (1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    eekboard.layout = eek_xkl_layout_new ();
 | 
				
			||||||
 | 
					    if (!eekboard.layout) {
 | 
				
			||||||
 | 
					        fprintf (stderr, "Failed to create layout\n");
 | 
				
			||||||
 | 
					        exit (1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					    g_signal_connect (eekboard.layout,
 | 
				
			||||||
 | 
					                      "changed",
 | 
				
			||||||
 | 
					                      G_CALLBACK(on_changed),
 | 
				
			||||||
 | 
					                      &eekboard);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_signal_connect (stage, 
 | 
				
			||||||
 | 
					                      "notify::width",
 | 
				
			||||||
 | 
					                      G_CALLBACK (on_resize),
 | 
				
			||||||
 | 
					                      &eekboard);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_signal_connect (stage,
 | 
				
			||||||
 | 
					                      "notify::height",
 | 
				
			||||||
 | 
					                      G_CALLBACK (on_resize),
 | 
				
			||||||
 | 
					                      &eekboard);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 | 
				
			||||||
 | 
					    gtk_widget_set_can_focus (window, FALSE);
 | 
				
			||||||
 | 
					    g_object_set (G_OBJECT(window), "accept_focus", FALSE, NULL);
 | 
				
			||||||
 | 
					    gtk_window_set_title (GTK_WINDOW(window), "Keyboard");
 | 
				
			||||||
 | 
					    g_signal_connect (G_OBJECT (window), "destroy",
 | 
				
			||||||
 | 
					                      G_CALLBACK (gtk_main_quit), NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bounds.x = bounds.y = 0;
 | 
				
			||||||
 | 
					    bounds.width = CSW;
 | 
				
			||||||
 | 
					    bounds.height = CSH;
 | 
				
			||||||
 | 
					    eekboard.keyboard = eek_gtk_keyboard_new ();
 | 
				
			||||||
 | 
					    eek_element_set_bounds (eekboard.keyboard, &bounds);
 | 
				
			||||||
 | 
					    eek_keyboard_set_layout (eekboard.keyboard, eekboard.layout);
 | 
				
			||||||
 | 
					    embed = eek_gtk_keyboard_get_widget (EEK_GTK_KEYBOARD (eekboard.keyboard));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vbox = gtk_vbox_new (FALSE, 0);
 | 
				
			||||||
 | 
					    ui_manager = gtk_ui_manager_new ();
 | 
				
			||||||
 | 
					    create_menus (&eekboard, window, ui_manager);
 | 
				
			||||||
 | 
					    menubar = gtk_ui_manager_get_widget (ui_manager, "/MainMenu");
 | 
				
			||||||
 | 
					    gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0);
 | 
				
			||||||
 | 
					    gtk_container_add (GTK_CONTAINER(vbox), embed);
 | 
				
			||||||
 | 
					    gtk_container_add (GTK_CONTAINER(window), vbox);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gtk_widget_set_size_request (embed, CSW, CSH);
 | 
				
			||||||
 | 
					    gtk_widget_show_all (window);
 | 
				
			||||||
 | 
					    //gtk_widget_set_size_request (embed, -1, -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gtk_main ();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user