Commit 37c25792 authored by Daiki Ueno's avatar Daiki Ueno
Browse files

Merge theme handling code (WIP).

parent 23ab2a34
eekboard is written by Daiki Ueno <ueno@unixuser.org>
eekboard is written by Daiki Ueno <ueno@unixuser.org>. The following
files contain code derived from other free software packages:
Cairo keyboard drawing functions are borrowed from the libgnomekbd
library by Sergey V. Udaltsov <svu@gnome.org>. See the comments in
eek/eek-drawing.c for detail.
eek/eek-keyboard-drawing.h
eek/eek-keyboard-drawing.c
These files contain code derived from the libgnomekbd library.
Copyright (C) 2006 Sergey V. Udaltsov <svu@gnome.org>
eek/eek-theme-node.h
eek/eek-theme-node.c
eek/eek-theme.h
eek/eek-theme.c
These files contain code derived from gnome-shell.
Copyright 2008-2010 Red Hat, Inc.
Copyright 2009 Steve Frécinaux
Copyright 2009, 2010 Florian Müllner
Copyright 2010 Adel Gadllah
Copyright 2010 Giovanni Campagna
Copyright 2003-2004 Dodji Seketeli
data/icons/8x8/Makefile.am
data/icons/16x16/Makefile.am
data/icons/22x22/Makefile.am
data/icons/24x24/Makefile.am
data/icons/32x32/Makefile.am
data/icons/48x48/Makefile.am
data/icons/scalable/Makefile.am
These files contain code derived from im-chooser.
Copyright (C) 2006-2008 Red Hat, Inc. All rights reserved.
......@@ -7,7 +7,7 @@ tools to implement desktop virtual keyboards.
** Dependencies
REQUIRED: GLib2, GTK, GConf2, PangoCairo, libxklavier
REQUIRED: GLib2, GTK, GConf2, PangoCairo, libxklavier, libcroco
OPTIONAL: fakekey, CSPI, Clutter, Clutter-Gtk, Vala, gobject-introspection
** Build from git repo
......
......@@ -101,6 +101,8 @@ PKG_CHECK_MODULES([XKB], [x11], ,
[AC_MSG_ERROR([XKB support not found])])
PKG_CHECK_MODULES([LIBXKLAVIER], [libxklavier x11], ,
[AC_MSG_ERROR([Libxklavier not found])])
PKG_CHECK_MODULES([LIBCROCO], [libcroco-0.6], ,
[AC_MSG_ERROR([libcroco not found])])
dnl use libfakekey to generate key events
AC_MSG_CHECKING([whether you enable fakekey])
......
......@@ -39,6 +39,7 @@ libeek_public_headers = \
$(srcdir)/eek-xml.h \
$(srcdir)/eek-xml-layout.h \
$(srcdir)/eek-serializable.h \
$(srcdir)/eek-theme.h \
$(srcdir)/eek.h
libeek_private_headers = \
......@@ -46,7 +47,8 @@ libeek_private_headers = \
$(srcdir)/eek-special-keysym-entries.h \
$(srcdir)/eek-unicode-keysym-entries.h \
$(srcdir)/eek-xkeysym-keysym-entries.h \
$(srcdir)/eek-marshalers.h
$(srcdir)/eek-marshalers.h \
$(srcdir)/eek-theme-node.h
libeek_sources = \
$(srcdir)/eek-layout.c \
......@@ -62,7 +64,9 @@ libeek_sources = \
$(srcdir)/eek-xml.c \
$(srcdir)/eek-xml-layout.c \
$(srcdir)/eek-renderer.c \
$(srcdir)/eek-keyboard-drawing.c
$(srcdir)/eek-keyboard-drawing.c \
$(srcdir)/eek-theme.c \
$(srcdir)/eek-theme-node.c
libeek_keysym_sources = \
$(srcdir)/eek-special-keysym-entries.h \
......@@ -85,8 +89,8 @@ libeek_la_SOURCES = \
$(libeek_sources) \
$(srcdir)/eek-marshalers.c
libeek_la_CFLAGS = $(GIO2_CFLAGS) $(PANGOCAIRO_CFLAGS)
libeek_la_LIBADD = $(GIO2_LIBS) $(PANGOCAIRO_LIBS) -lm
libeek_la_CFLAGS = $(GIO2_CFLAGS) $(PANGOCAIRO_CFLAGS) $(LIBCROCO_CFLAGS)
libeek_la_LIBADD = $(GIO2_LIBS) $(PANGOCAIRO_LIBS) $(LIBCROCO_LIBS) -lm
if ENABLE_CLUTTER
libeek_clutter_public_headers = \
......
......@@ -50,6 +50,7 @@ struct _EekClutterKeyboardPrivate
{
EekKeyboard *keyboard;
EekClutterRenderer *renderer;
EekTheme *theme;
};
struct _CreateSectionCallbackData {
......@@ -78,6 +79,9 @@ eek_clutter_keyboard_real_realize (ClutterActor *self)
priv = EEK_CLUTTER_KEYBOARD_GET_PRIVATE(self);
if (priv->theme)
eek_renderer_set_theme (EEK_RENDERER(priv->renderer), priv->theme);
scale = eek_renderer_get_scale (EEK_RENDERER(priv->renderer));
clutter_actor_set_position (CLUTTER_ACTOR(self),
bounds.x * scale,
......@@ -126,7 +130,6 @@ eek_clutter_keyboard_real_allocate (ClutterActor *self,
{
EekClutterKeyboardPrivate *priv = EEK_CLUTTER_KEYBOARD_GET_PRIVATE(self);
g_assert (priv->renderer);
eek_renderer_set_allocation_size (EEK_RENDERER(priv->renderer),
box->x2 - box->x1,
box->y2 - box->y1);
......@@ -193,6 +196,11 @@ eek_clutter_keyboard_dispose (GObject *object)
priv->keyboard = NULL;
}
if (priv->theme) {
g_object_unref (priv->theme);
priv->keyboard = NULL;
}
G_OBJECT_CLASS (eek_clutter_keyboard_parent_class)->dispose (object);
}
......@@ -249,3 +257,16 @@ eek_clutter_keyboard_new (EekKeyboard *keyboard)
{
return g_object_new (EEK_TYPE_CLUTTER_KEYBOARD, "keyboard", keyboard, NULL);
}
void
eek_clutter_keyboard_set_theme (EekClutterKeyboard *keyboard,
EekTheme *theme)
{
EekClutterKeyboardPrivate *priv;
g_return_if_fail (EEK_IS_CLUTTER_KEYBOARD(keyboard));
g_return_if_fail (EEK_IS_THEME(theme));
priv = EEK_CLUTTER_KEYBOARD_GET_PRIVATE(keyboard);
priv->theme = g_object_ref (theme);
}
......@@ -54,7 +54,9 @@ struct _EekClutterKeyboardClass
};
GType eek_clutter_keyboard_get_type (void) G_GNUC_CONST;
ClutterActor *eek_clutter_keyboard_new (EekKeyboard *keyboard);
ClutterActor *eek_clutter_keyboard_new (EekKeyboard *keyboard);
void eek_clutter_keyboard_set_theme (EekClutterKeyboard *keyboard,
EekTheme *theme);
G_END_DECLS
#endif /* EEK_CLUTTER_KEYBOARD_H */
......@@ -119,7 +119,8 @@ eek_clutter_renderer_render_key (EekClutterRenderer *renderer,
CoglHandle *outline_texture;
PangoLayout *layout;
PangoRectangle extents = { 0, };
CoglColor color = { 0x00, 0x00, 0x00, 0xFF };
const EekColor *foreground;
CoglColor color;
ClutterGeometry geom;
gulong oref;
EekKeyboard *keyboard;
......@@ -200,6 +201,17 @@ eek_clutter_renderer_render_key (EekClutterRenderer *renderer,
layout = eek_renderer_create_pango_layout (EEK_RENDERER(renderer));
eek_renderer_render_key_label (EEK_RENDERER(renderer), layout, key);
pango_layout_get_extents (layout, NULL, &extents);
foreground = eek_renderer_get_foreground_color (EEK_RENDERER(renderer),
EEK_ELEMENT(key));
cogl_color_set_from_4f (&color,
foreground->red,
foreground->green,
foreground->blue,
foreground->alpha);
eek_color_free (foreground);
cogl_pango_render_layout (layout,
(geom.width - extents.width / PANGO_SCALE) / 2,
(geom.height - extents.height / PANGO_SCALE) / 2,
......
......@@ -61,6 +61,7 @@ struct _EekGtkKeyboardPrivate
gulong key_pressed_handler;
gulong key_released_handler;
gulong symbol_index_changed_handler;
EekTheme *theme;
};
static EekColor * color_from_gdk_color (GdkColor *gdk_color);
......@@ -108,6 +109,8 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
pcontext = gtk_widget_get_pango_context (self);
priv->renderer = eek_gtk_renderer_new (priv->keyboard, pcontext, self);
if (priv->theme)
eek_renderer_set_theme (priv->renderer, priv->theme);
eek_renderer_set_allocation_size (priv->renderer,
allocation.width,
......@@ -117,11 +120,11 @@ eek_gtk_keyboard_real_draw (GtkWidget *self,
state = gtk_widget_get_state (self);
color = color_from_gdk_color (&style->fg[state]);
eek_renderer_set_foreground (priv->renderer, color);
eek_renderer_set_default_foreground_color (priv->renderer, color);
eek_color_free (color);
color = color_from_gdk_color (&style->bg[state]);
eek_renderer_set_background (priv->renderer, color);
eek_renderer_set_default_background_color (priv->renderer, color);
eek_color_free (color);
}
......@@ -273,7 +276,12 @@ eek_gtk_keyboard_dispose (GObject *object)
g_object_unref (priv->keyboard);
priv->keyboard = NULL;
}
if (priv->theme) {
g_object_unref (priv->theme);
priv->theme = NULL;
}
G_OBJECT_CLASS (eek_gtk_keyboard_parent_class)->dispose (object);
}
......@@ -428,3 +436,16 @@ on_symbol_index_changed (EekKeyboard *keyboard,
gtk_widget_queue_draw (widget);
}
void
eek_gtk_keyboard_set_theme (EekGtkKeyboard *keyboard,
EekTheme *theme)
{
EekGtkKeyboardPrivate *priv;
g_return_if_fail (EEK_IS_GTK_KEYBOARD(keyboard));
g_return_if_fail (EEK_IS_THEME(theme));
priv = EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard);
priv->theme = g_object_ref (theme);
}
......@@ -55,8 +55,10 @@ struct _EekGtkKeyboardClass
gpointer pdummy[24];
};
GType eek_gtk_keyboard_get_type (void) G_GNUC_CONST;
GtkWidget *eek_gtk_keyboard_new (EekKeyboard *keyboard);
GType eek_gtk_keyboard_get_type (void) G_GNUC_CONST;
GtkWidget *eek_gtk_keyboard_new (EekKeyboard *keyboard);
void eek_gtk_keyboard_set_theme (EekGtkKeyboard *keyboard,
EekTheme *theme);
G_END_DECLS
#endif /* EEK_GTK_KEYBOARD_H */
......@@ -45,8 +45,8 @@ struct _EekRendererPrivate
EekKeyboard *keyboard;
PangoContext *pcontext;
EekColor *foreground;
EekColor *background;
EekColor *default_foreground;
EekColor *default_background;
gdouble border_width;
gdouble allocation_width;
......@@ -57,6 +57,10 @@ struct _EekRendererPrivate
GHashTable *outline_surface_cache;
cairo_surface_t *keyboard_surface;
gulong symbol_index_changed_handler;
EekTheme *theme;
/* a mapping from EekElement to EekThemeNode */
GHashTable *theme_node_hash;
};
struct {
......@@ -147,6 +151,14 @@ create_keyboard_surface (EekRenderer *renderer)
EekBounds bounds;
cairo_surface_t *keyboard_surface;
CreateKeyboardSurfaceCallbackData data;
EekColor *foreground, *background;
foreground =
eek_renderer_get_foreground_color (renderer,
EEK_ELEMENT(priv->keyboard));
background =
eek_renderer_get_background_color (renderer,
EEK_ELEMENT(priv->keyboard));
eek_element_get_bounds (EEK_ELEMENT(priv->keyboard), &bounds);
keyboard_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
......@@ -159,10 +171,10 @@ create_keyboard_surface (EekRenderer *renderer)
/* blank background */
cairo_set_source_rgba (data.cr,
priv->background->red,
priv->background->green,
priv->background->blue,
priv->background->alpha);
background->red,
background->green,
background->blue,
background->alpha);
cairo_rectangle (data.cr,
0.0,
0.0,
......@@ -170,11 +182,21 @@ create_keyboard_surface (EekRenderer *renderer)
cairo_image_surface_get_height (keyboard_surface));
cairo_fill (data.cr);
cairo_set_source_rgba (data.cr,
foreground->red,
foreground->green,
foreground->blue,
foreground->alpha);
/* draw sections */
eek_container_foreach_child (EEK_CONTAINER(priv->keyboard),
create_keyboard_surface_section_callback,
&data);
cairo_destroy (data.cr);
eek_color_free (foreground);
eek_color_free (background);
return keyboard_surface;
}
......@@ -190,6 +212,8 @@ render_key_outline (EekRenderer *renderer,
gdouble scale;
gint i;
gulong oref;
EekColor *foreground, *background;
EekGradient *gradient;
/* need to rescale so that the border fit inside the clipping
region */
......@@ -212,25 +236,60 @@ render_key_outline (EekRenderer *renderer,
priv->border_width / 2 * priv->scale,
priv->border_width / 2 * priv->scale);
/* paint the background with gradient */
pat = cairo_pattern_create_linear (0.0,
0.0,
0.0,
bounds.height * priv->scale * 5.0);
cairo_pattern_add_color_stop_rgba (pat,
1,
priv->background->red * 0.5,
priv->background->green * 0.5,
priv->background->blue * 0.5,
priv->background->alpha);
cairo_pattern_add_color_stop_rgba (pat,
0,
priv->background->red,
priv->background->green,
priv->background->blue,
priv->background->alpha);
cairo_set_source (cr, pat);
foreground = eek_renderer_get_foreground_color (renderer, EEK_ELEMENT(key));
background = eek_renderer_get_background_color (renderer, EEK_ELEMENT(key));
gradient = eek_renderer_get_background_gradient (renderer,
EEK_ELEMENT(key));
if (gradient) {
switch (gradient->type) {
case EEK_GRADIENT_VERTICAL:
pat = cairo_pattern_create_linear (bounds.width / 2 * priv->scale,
0.0,
bounds.width / 2 * priv->scale,
bounds.height * priv->scale);
break;
case EEK_GRADIENT_HORIZONTAL:
pat = cairo_pattern_create_linear (0.0,
bounds.height / 2 * priv->scale,
bounds.width * priv->scale,
bounds.height / 2 * priv->scale);
break;
case EEK_GRADIENT_RADIAL:
pat = cairo_pattern_create_radial (0.0,
0.0,
0,
0.0,
0.0,
MIN(bounds.width, bounds.height) * priv->scale);
break;
default:
g_assert_not_reached ();
break;
}
cairo_pattern_add_color_stop_rgba (pat,
1,
gradient->start->red * 0.5,
gradient->start->green * 0.5,
gradient->start->blue * 0.5,
gradient->start->alpha);
cairo_pattern_add_color_stop_rgba (pat,
0,
gradient->stop->red,
gradient->stop->green,
gradient->stop->blue,
gradient->stop->alpha);
cairo_set_source (cr, pat);
} else {
cairo_set_source_rgba (cr,
background->red,
background->green,
background->blue,
background->alpha);
}
_eek_rounded_polygon (cr,
outline->corner_radius,
outline->points,
......@@ -239,16 +298,16 @@ render_key_outline (EekRenderer *renderer,
cairo_pattern_destroy (pat);
/* paint the border */
/* paint the border - FIXME: should be configured through theme */
cairo_set_line_width (cr, priv->border_width);
cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
cairo_set_source_rgba
(cr,
ABS(priv->background->red - priv->foreground->red) * 0.7,
ABS(priv->background->green - priv->foreground->green) * 0.7,
ABS(priv->background->blue - priv->foreground->blue) * 0.7,
priv->foreground->alpha);
ABS(background->red - foreground->red) * 0.7,
ABS(background->green - foreground->green) * 0.7,
ABS(background->blue - foreground->blue) * 0.7,
foreground->alpha);
_eek_rounded_polygon (cr,
outline->corner_radius,
......@@ -257,6 +316,12 @@ render_key_outline (EekRenderer *renderer,
cairo_stroke (cr);
eek_outline_free (outline);
eek_color_free (foreground);
eek_color_free (background);
if (gradient)
eek_gradient_free (gradient);
}
struct _CalculateFontSizeCallbackData {
......@@ -400,6 +465,7 @@ render_key (EekRenderer *self,
} else {
PangoLayout *layout;
PangoRectangle extents = { 0, };
EekColor *foreground;
layout = pango_cairo_create_layout (cr);
eek_renderer_render_key_label (self, layout, key);
......@@ -410,11 +476,14 @@ render_key (EekRenderer *self,
(cr,
(bounds.width * priv->scale - extents.width / PANGO_SCALE) / 2,
(bounds.height * priv->scale - extents.height / PANGO_SCALE) / 2);
foreground = eek_renderer_get_foreground_color (self, EEK_ELEMENT(key));
cairo_set_source_rgba (cr,
priv->foreground->red,
priv->foreground->green,
priv->foreground->blue,
priv->foreground->alpha);
foreground->red,
foreground->green,
foreground->blue,
foreground->alpha);
eek_color_free (foreground);
pango_cairo_show_layout (cr, layout);
cairo_restore (cr);
......@@ -535,6 +604,7 @@ eek_renderer_real_render_keyboard (EekRenderer *self,
cairo_t *cr)
{
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(self);
EekColor *background;
g_return_if_fail (priv->keyboard);
g_return_if_fail (priv->allocation_width > 0.0);
......@@ -544,11 +614,15 @@ eek_renderer_real_render_keyboard (EekRenderer *self,
priv->keyboard_surface = create_keyboard_surface (self);
/* blank background */
background = eek_renderer_get_background_color (self,
EEK_ELEMENT(priv->keyboard));
cairo_set_source_rgba (cr,
priv->background->red,
priv->background->green,
priv->background->blue,
priv->background->alpha);
background->red,
background->green,
background->blue,
background->alpha);
eek_color_free (background);
cairo_rectangle (cr,
0.0,
0.0,
......@@ -639,9 +713,10 @@ eek_renderer_finalize (GObject *object)
{
EekRendererPrivate *priv = EEK_RENDERER_GET_PRIVATE(object);
g_hash_table_destroy (priv->outline_surface_cache);
eek_color_free (priv->foreground);
eek_color_free (priv->background);
eek_color_free (priv->default_foreground);
eek_color_free (priv->default_background);
pango_font_description_free (priv->font);
g_hash_table_destroy (priv->theme_node_hash);
G_OBJECT_CLASS (eek_renderer_parent_class)->finalize (object);
}
......@@ -691,8 +766,8 @@ eek_renderer_init (EekRenderer *self)
priv = self->priv = EEK_RENDERER_GET_PRIVATE(self);
priv->keyboard = NULL;
priv->pcontext = NULL;
priv->foreground = eek_color_new (0.3, 0.3, 0.3, 1.0);
priv->background = eek_color_new (1.0, 1.0, 1.0, 1.0);
priv->default_foreground = eek_color_new (0.3, 0.3, 0.3, 1.0);
priv->default_background = eek_color_new (1.0, 1.0, 1.0, 1.0);
priv->border_width = 1.0;
priv->allocation_width = 0.0;
priv->allocation_height = 0.0;
......@@ -705,6 +780,11 @@ eek_renderer_init (EekRenderer *self)
(GDestroyNotify)cairo_surface_destroy);
priv->keyboard_surface = NULL;
priv->symbol_index_changed_handler = 0;
priv->theme_node_hash =
g_hash_table_new_full (g_direct_hash,
g_direct_equal,
NULL,
(GDestroyNotify)g_object_unref);
}
static void
......@@ -956,8 +1036,8 @@ eek_renderer_render_keyboard (EekRenderer *renderer,
}
void
eek_renderer_set_foreground (EekRenderer *renderer,
EekColor *foreground)
eek_renderer_set_default_foreground_color (EekRenderer *renderer,
EekColor *foreground)
{
EekRendererPrivate *priv;
......@@ -965,14 +1045,14 @@ eek_renderer_set_foreground (EekRenderer *renderer,
g_return_if_fail (foreground);
priv = EEK_RENDERER_GET_PRIVATE(renderer);
if (priv->foreground)
eek_color_free (priv->foreground);
priv->foreground = eek_color_copy (foreground);
if (priv->default_foreground)
eek_color_free (priv->default_foreground);
priv->default_foreground = eek_color_copy (foreground);
}
void
eek_renderer_set_background (EekRenderer *renderer,
EekColor *background)
eek_renderer_set_default_background_color (EekRenderer *renderer,
EekColor *background)
{
EekRendererPrivate *priv;
......@@ -980,35 +1060,66 @@ eek_renderer_set_background (EekRenderer *renderer,
g_return_if_fail (background);
priv = EEK_RENDERER_GET_PRIVATE(renderer);
if (priv->background)
eek_color_free (priv->background);
priv->background = eek_color_copy (background);
if (priv->default_background)
eek_color_free (priv->default_background);
priv->default_background = eek_color_copy (background);
}
void
eek_renderer_get_foreground (EekRenderer *renderer,
EekColor *foreground)
EekColor *
eek_renderer_get_foreground_color (EekRenderer *renderer, EekElement *element)
{
EekRendererPrivate *priv;
EekThemeNode *theme_node;
g_return_if_fail (EEK_IS_RENDERER(renderer));
g_return_if_fail (foreground);
g_assert (EEK_IS_RENDERER(renderer));
priv = EEK_RENDERER_GET_PRIVATE(renderer);
*foreground = *priv->foreground;
theme_node = g_hash_table_lookup (priv->theme_node_hash, element);
if (theme_node) {
EekColor *color = eek_theme_node_get_foreground_color (theme_node);
if (color)
return color;
}
return eek_color_copy (priv->default_foreground);
}
void
eek_renderer_get_background (EekRenderer *renderer,
EekColor *background)
EekColor *
eek_renderer_get_background_color (EekRenderer *renderer, EekElement *element)
{
EekRendererPrivate *priv;
EekThemeNode *theme_node;
g_return_if_fail (EEK_IS_RENDERER(renderer));
g_return_if_fail (background);
g_assert (EEK_IS_RENDERER(renderer));