summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey V. Udaltsov <svu@gnome.org>2009-12-14 13:23:07 +0000
committerSergey V. Udaltsov <svu@gnome.org>2009-12-14 13:23:07 +0000
commit3584dc898c8212f154cd9ae22185c5d8aa7b4218 (patch)
treec8b93a515b0c3025e8218b17300ff337989d430c
parentd9ade98d2374648e237c4351c6b23445f3c7d8ef (diff)
downloadlibgnomekbd-3584dc898c8212f154cd9ae22185c5d8aa7b4218.tar.gz
Introduced GkbdStatus for the notification area
Now it only works with flags
-rw-r--r--ChangeLog6
-rw-r--r--libgnomekbd/Makefile.am1
-rw-r--r--libgnomekbd/gkbd-indicator-config.c96
-rw-r--r--libgnomekbd/gkbd-indicator-config.h20
-rw-r--r--libgnomekbd/gkbd-indicator.c104
-rw-r--r--libgnomekbd/gkbd-status.c596
-rw-r--r--libgnomekbd/gkbd-status.h72
-rw-r--r--test/.gitignore1
-rw-r--r--test/Makefile.am44
-rw-r--r--test/gkbd-status-test.c55
10 files changed, 872 insertions, 123 deletions
diff --git a/ChangeLog b/ChangeLog
index b22925f..434aeab 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,12 @@
2009-12-14 svu
* configure.in, NEWS: release 2.28.2
+ * libgnomekbd/Makefile.am, libgnomekbd/gkbd-indicator-config.c,
+ libgnomekbd/gkbd-indicator-config.h, libgnomekbd/gkbd-indicator.c,
+ libgnomekbd/gkbd-status.c, libgnomekbd/gkbd-status.h, test/.gitignore,
+ test/Makefile.am, test/gkbd-status-test.c: introduced the status icon
+ widget (functions only with flags so far)
+
2009-12-09 svu
diff --git a/libgnomekbd/Makefile.am b/libgnomekbd/Makefile.am
index fd848bd..17b67d3 100644
--- a/libgnomekbd/Makefile.am
+++ b/libgnomekbd/Makefile.am
@@ -44,6 +44,7 @@ libgnomekbd_la_SOURCES = \
libgnomekbdui_la_SOURCES = \
gkbd-indicator-config.c \
gkbd-indicator.c \
+ gkbd-status.c \
gkbd-indicator-marshal.c \
gkbd-indicator-plugin-manager.c \
gkbd-keyboard-drawing-marshal.c \
diff --git a/libgnomekbd/gkbd-indicator-config.c b/libgnomekbd/gkbd-indicator-config.c
index fdc7867..45d1d8f 100644
--- a/libgnomekbd/gkbd-indicator-config.c
+++ b/libgnomekbd/gkbd-indicator-config.c
@@ -66,26 +66,6 @@ gkbd_indicator_config_free_enabled_plugins (GkbdIndicatorConfig *
}
}
-/**
- * extern applet kbdConfig functions
- */
-void
-gkbd_indicator_config_free_images (GkbdIndicatorConfig * ind_config)
-{
- GdkPixbuf *pi;
- GSList *img_node;
- while ((img_node = ind_config->images) != NULL) {
- pi = GDK_PIXBUF (img_node->data);
- /* It can be NULL - some images may be missing */
- if (pi != NULL) {
- g_object_unref (pi);
- }
- ind_config->images =
- g_slist_remove_link (ind_config->images, img_node);
- g_slist_free_1 (img_node);
- }
-}
-
char *
gkbd_indicator_config_get_images_file (GkbdIndicatorConfig *
ind_config,
@@ -100,9 +80,8 @@ gkbd_indicator_config_get_images_file (GkbdIndicatorConfig *
if ((kbd_config->layouts_variants != NULL) &&
(g_slist_length (kbd_config->layouts_variants) > group)) {
- char *full_layout_name =
- (char *) g_slist_nth_data (kbd_config->
- layouts_variants, group);
+ char *full_layout_name = (char *)
+ g_slist_nth_data (kbd_config->layouts_variants, group);
if (full_layout_name != NULL) {
char *l, *v;
@@ -130,59 +109,39 @@ gkbd_indicator_config_get_images_file (GkbdIndicatorConfig *
}
void
-gkbd_indicator_config_load_images (GkbdIndicatorConfig * ind_config,
- GkbdKeyboardConfig * kbd_config)
+gkbd_indicator_config_load_image_filenames (GkbdIndicatorConfig *
+ ind_config,
+ GkbdKeyboardConfig *
+ kbd_config)
{
int i;
- ind_config->images = NULL;
+ ind_config->image_filenames = NULL;
if (!ind_config->show_flags)
return;
for (i = xkl_engine_get_max_num_groups (ind_config->engine);
--i >= 0;) {
- GdkPixbuf *image = NULL;
char *image_file =
gkbd_indicator_config_get_images_file (ind_config,
kbd_config,
i);
+ ind_config->image_filenames =
+ g_slist_prepend (ind_config->image_filenames,
+ image_file);
+ }
+}
- if (image_file != NULL) {
- GError *gerror = NULL;
- image =
- gdk_pixbuf_new_from_file (image_file, &gerror);
- if (image == NULL) {
- GtkWidget *dialog =
- gtk_message_dialog_new (NULL,
- GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_OK,
- _
- ("There was an error loading an image: %s"),
- gerror->
- message);
- g_signal_connect (G_OBJECT (dialog),
- "response",
- G_CALLBACK
- (gtk_widget_destroy),
- NULL);
-
- gtk_window_set_resizable (GTK_WINDOW
- (dialog), FALSE);
-
- gtk_widget_show (dialog);
- g_error_free (gerror);
- }
- xkl_debug (150,
- "Image %d[%s] loaded -> %p[%dx%d]\n",
- i, image_file, image,
- gdk_pixbuf_get_width (image),
- gdk_pixbuf_get_height (image));
- g_free (image_file);
- }
- /* We append the image anyway - even if it is NULL! */
- ind_config->images =
- g_slist_prepend (ind_config->images, image);
+void
+gkbd_indicator_config_free_image_filenames (GkbdIndicatorConfig *
+ ind_config)
+{
+ while (ind_config->image_filenames) {
+ if (ind_config->image_filenames->data)
+ g_free (ind_config->image_filenames->data);
+ ind_config->image_filenames =
+ g_slist_delete_link (ind_config->image_filenames,
+ ind_config->image_filenames);
}
}
@@ -239,7 +198,7 @@ gkbd_indicator_config_term (GkbdIndicatorConfig * ind_config)
#endif
ind_config->icon_theme = NULL;
- gkbd_indicator_config_free_images (ind_config);
+ gkbd_indicator_config_free_image_filenames (ind_config);
gkbd_indicator_config_free_enabled_plugins (ind_config);
g_object_unref (ind_config->conf_client);
@@ -247,15 +206,6 @@ gkbd_indicator_config_term (GkbdIndicatorConfig * ind_config)
}
void
-gkbd_indicator_config_update_images (GkbdIndicatorConfig *
- ind_config,
- GkbdKeyboardConfig * kbd_config)
-{
- gkbd_indicator_config_free_images (ind_config);
- gkbd_indicator_config_load_images (ind_config, kbd_config);
-}
-
-void
gkbd_indicator_config_load_from_gconf (GkbdIndicatorConfig * ind_config)
{
GError *gerror = NULL;
diff --git a/libgnomekbd/gkbd-indicator-config.h b/libgnomekbd/gkbd-indicator-config.h
index 556b911..38173bf 100644
--- a/libgnomekbd/gkbd-indicator-config.h
+++ b/libgnomekbd/gkbd-indicator-config.h
@@ -35,7 +35,7 @@ typedef struct _GkbdIndicatorConfig {
/* private, transient */
GConfClient *conf_client;
- GSList *images;
+ GSList *image_filenames;
GtkIconTheme *icon_theme;
int config_listener_id;
XklEngine *engine;
@@ -64,18 +64,12 @@ extern gchar
GkbdKeyboardConfig *
kbd_config, int group);
-extern void gkbd_indicator_config_load_images (GkbdIndicatorConfig *
- applet_config,
- GkbdKeyboardConfig *
- kbd_config);
-extern void gkbd_indicator_config_free_images (GkbdIndicatorConfig *
- applet_config);
-
-/* Should be updated on Indicator/GConf and Kbd/GConf configuration change */
-extern void gkbd_indicator_config_update_images (GkbdIndicatorConfig *
- applet_config,
- GkbdKeyboardConfig *
- kbd_config);
+extern void gkbd_indicator_config_load_image_filenames (GkbdIndicatorConfig
+ * applet_config,
+ GkbdKeyboardConfig
+ * kbd_config);
+extern void gkbd_indicator_config_free_image_filenames (GkbdIndicatorConfig
+ * applet_config);
/* Should be updated on Indicator/GConf configuration change */
extern void gkbd_indicator_config_activate (GkbdIndicatorConfig *
diff --git a/libgnomekbd/gkbd-indicator.c b/libgnomekbd/gkbd-indicator.c
index be573be..2ddd1f9 100644
--- a/libgnomekbd/gkbd-indicator.c
+++ b/libgnomekbd/gkbd-indicator.c
@@ -46,6 +46,7 @@ typedef struct _gki_globals {
gchar **full_group_names;
gchar **short_group_names;
GSList *widget_instances;
+ GSList *images;
} gki_globals;
struct _GkbdIndicatorPrivate {
@@ -85,6 +86,89 @@ static void
gkbd_indicator_set_tooltips (GkbdIndicator * gki, const char *str);
void
+gkbd_indicator_load_images ()
+{
+ int i;
+ GSList *image_filename;
+
+ globals.images = NULL;
+ gkbd_indicator_config_load_image_filenames (&globals.ind_cfg,
+ &globals.kbd_cfg);
+
+ if (!globals.ind_cfg.show_flags)
+ return;
+
+ image_filename = globals.ind_cfg.image_filenames;
+
+ for (i = xkl_engine_get_max_num_groups (globals.engine);
+ --i >= 0; image_filename = image_filename->next) {
+ GdkPixbuf *image = NULL;
+ char *image_file = (char *) image_filename->data;
+
+ if (image_file != NULL) {
+ GError *gerror = NULL;
+ image =
+ gdk_pixbuf_new_from_file (image_file, &gerror);
+ if (image == NULL) {
+ GtkWidget *dialog =
+ gtk_message_dialog_new (NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _
+ ("There was an error loading an image: %s"),
+ gerror->message);
+ g_signal_connect (G_OBJECT (dialog),
+ "response",
+ G_CALLBACK
+ (gtk_widget_destroy),
+ NULL);
+
+ gtk_window_set_resizable (GTK_WINDOW
+ (dialog), FALSE);
+
+ gtk_widget_show (dialog);
+ g_error_free (gerror);
+ }
+ xkl_debug (150,
+ "Image %d[%s] loaded -> %p[%dx%d]\n",
+ i, image_file, image,
+ gdk_pixbuf_get_width (image),
+ gdk_pixbuf_get_height (image));
+ }
+ /* We append the image anyway - even if it is NULL! */
+ globals.images = g_slist_append (globals.images, image);
+ }
+}
+
+static void
+gkbd_indicator_free_images ()
+{
+ GdkPixbuf *pi;
+ GSList *img_node;
+
+ gkbd_indicator_config_free_image_filenames (&globals.ind_cfg);
+
+ while ((img_node = globals.images) != NULL) {
+ pi = GDK_PIXBUF (img_node->data);
+ /* It can be NULL - some images may be missing */
+ if (pi != NULL) {
+ g_object_unref (pi);
+ }
+ globals.images =
+ g_slist_remove_link (globals.images, img_node);
+ g_slist_free_1 (img_node);
+ }
+}
+
+static void
+gkbd_indicator_update_images (void)
+{
+ gkbd_indicator_free_images ();
+ gkbd_indicator_load_images ();
+}
+
+void
gkbd_indicator_set_tooltips (GkbdIndicator * gki, const char *str)
{
g_assert (str == NULL || g_utf8_validate (str, -1, NULL));
@@ -226,7 +310,7 @@ gkbd_indicator_prepare_drawing (GkbdIndicator * gki, int group)
GdkPixbuf *image;
GtkWidget *ebox;
- pimage = g_slist_nth_data (globals.ind_cfg.images, group);
+ pimage = g_slist_nth_data (globals.images, group);
ebox = gtk_event_box_new ();
gtk_event_box_set_visible_window (GTK_EVENT_BOX (ebox), FALSE);
if (globals.ind_cfg.show_flags) {
@@ -264,8 +348,8 @@ gkbd_indicator_prepare_drawing (GkbdIndicator * gki, int group)
if (xkl_engine_get_features (globals.engine) &
XKLF_MULTIPLE_LAYOUTS_SUPPORTED) {
char *full_layout_name = (char *)
- g_slist_nth_data (globals.kbd_cfg.
- layouts_variants,
+ g_slist_nth_data (globals.
+ kbd_cfg.layouts_variants,
group);
char *variant_name;
if (!gkbd_keyboard_config_split_items
@@ -408,8 +492,7 @@ gkbd_indicator_ind_cfg_changed (GConfClient * client,
xkl_debug (100,
"Applet configuration changed in GConf - reiniting...\n");
gkbd_indicator_config_load_from_gconf (&globals.ind_cfg);
- gkbd_indicator_config_update_images (&globals.ind_cfg,
- &globals.kbd_cfg);
+ gkbd_indicator_update_images ();
gkbd_indicator_config_activate (&globals.ind_cfg);
gkbd_indicator_plugin_manager_toggle_plugins
@@ -461,8 +544,7 @@ gkbd_indicator_kbd_cfg_callback (GkbdIndicator * gki)
gkbd_keyboard_config_load_from_x_current (&globals.kbd_cfg,
xklrec);
- gkbd_indicator_config_update_images (&globals.ind_cfg,
- &globals.kbd_cfg);
+ gkbd_indicator_update_images ();
g_strfreev (globals.full_group_names);
globals.full_group_names = NULL;
@@ -511,8 +593,7 @@ gkbd_indicator_set_current_page (GkbdIndicator * gki)
cur_state = xkl_engine_get_current_state (globals.engine);
if (cur_state->group >= 0)
gkbd_indicator_set_current_page_for_group (gki,
- cur_state->
- group);
+ cur_state->group);
}
void
@@ -761,8 +842,7 @@ gkbd_indicator_global_init (void)
xklrec);
gkbd_indicator_config_load_from_gconf (&globals.ind_cfg);
- gkbd_indicator_config_update_images (&globals.ind_cfg,
- &globals.kbd_cfg);
+ gkbd_indicator_update_images ();
gkbd_indicator_config_activate (&globals.ind_cfg);
gkbd_indicator_load_group_names ((const gchar **) xklrec->layouts,
@@ -836,7 +916,7 @@ gdouble
gkbd_indicator_get_max_width_height_ratio (void)
{
gdouble rv = 0.0;
- GSList *ip = globals.ind_cfg.images;
+ GSList *ip = globals.images;
if (!globals.ind_cfg.show_flags)
return 0;
while (ip != NULL) {
diff --git a/libgnomekbd/gkbd-status.c b/libgnomekbd/gkbd-status.c
new file mode 100644
index 0000000..7e70088
--- /dev/null
+++ b/libgnomekbd/gkbd-status.c
@@ -0,0 +1,596 @@
+/*
+ * Copyright (C) 2006 Sergey V. Udaltsov <svu@gnome.org>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <memory.h>
+
+#include <cairo.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdkx.h>
+#include <glib/gi18n.h>
+
+#include <gkbd-status.h>
+
+#include <gkbd-desktop-config.h>
+#include <gkbd-indicator-config.h>
+
+typedef struct _gki_globals {
+ XklEngine *engine;
+ XklConfigRegistry *registry;
+
+ GkbdDesktopConfig cfg;
+ GkbdIndicatorConfig ind_cfg;
+ GkbdKeyboardConfig kbd_cfg;
+
+ const gchar *tooltips_format;
+ gchar **full_group_names;
+ gchar **short_group_names;
+
+ gint current_size;
+ GSList *icons; /* list of GdkPixbuf */
+ GSList *widget_instances; /* list of GkbdStatus */
+} gki_globals;
+
+struct _GkbdStatusPrivate {
+ gdouble angle;
+};
+
+/* one instance for ALL widgets */
+static gki_globals globals;
+
+#define ForAllIndicators() \
+ { \
+ GSList* cur; \
+ for (cur = globals.widget_instances; cur != NULL; cur = cur->next) { \
+ GkbdStatus * gki = (GkbdStatus*)cur->data;
+#define NextIndicator() \
+ } \
+ }
+
+G_DEFINE_TYPE (GkbdStatus, gkbd_status, GTK_TYPE_STATUS_ICON)
+
+static void
+gkbd_status_global_init (void);
+static void
+gkbd_status_global_term (void);
+static GdkPixbuf *
+gkbd_status_prepare_drawing (GkbdStatus * gki, int group);
+static void
+gkbd_status_set_current_page_for_group (GkbdStatus * gki, int group);
+static void
+gkbd_status_set_current_page (GkbdStatus * gki);
+static void
+gkbd_status_cleanup (GkbdStatus * gki);
+static void
+gkbd_status_fill (GkbdStatus * gki);
+static void
+gkbd_status_set_tooltips (GkbdStatus * gki, const char *str);
+
+void
+gkbd_status_set_tooltips (GkbdStatus * gki, const char *str)
+{
+ g_assert (str == NULL || g_utf8_validate (str, -1, NULL));
+
+ gtk_status_icon_set_tooltip_text (GTK_STATUS_ICON (gki), str);
+}
+
+void
+gkbd_status_cleanup (GkbdStatus * gki)
+{
+ while (globals.icons) {
+ if (globals.icons->data)
+ g_object_unref (G_OBJECT (globals.icons->data));
+ globals.icons =
+ g_slist_delete_link (globals.icons, globals.icons);
+ }
+}
+
+void
+gkbd_status_fill (GkbdStatus * gki)
+{
+ int grp;
+ int total_groups = xkl_engine_get_num_groups (globals.engine);
+
+ for (grp = 0; grp < total_groups; grp++) {
+ GdkPixbuf *page = gkbd_status_prepare_drawing (gki, grp);
+ globals.icons = g_slist_append (globals.icons, page);
+ }
+}
+
+static void
+gkbd_status_activate (GkbdStatus * gki)
+{
+ xkl_debug (150, "Mouse button pressed on applet\n");
+ gkbd_desktop_config_lock_next_group (&globals.cfg);
+}
+
+static GdkPixbuf *
+gkbd_status_prepare_drawing (GkbdStatus * gki, int group)
+{
+ GError *gerror = NULL;
+ char *image_filename;
+ GdkPixbuf *image;
+
+ if (globals.current_size == 0)
+ return NULL;
+
+ image_filename = (char *) g_slist_nth_data (globals.ind_cfg.image_filenames,
+ group);
+
+ image = gdk_pixbuf_new_from_file_at_size (image_filename,
+ globals.current_size,
+ globals.current_size,
+ &gerror);
+
+ if (image == NULL) {
+ GtkWidget *dialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _
+ ("There was an error loading an image: %s"),
+ gerror ==
+ NULL ?
+ "Unknown" :
+ gerror->
+ message);
+ g_signal_connect (G_OBJECT (dialog), "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+
+ gtk_widget_show (dialog);
+ g_error_free (gerror);
+
+ return NULL;
+ }
+ xkl_debug (150,
+ "Image %d[%s] loaded -> %p[%dx%d]\n",
+ group, image_filename, image,
+ gdk_pixbuf_get_width (image),
+ gdk_pixbuf_get_height (image));
+
+ return image;
+}
+
+static void
+gkbd_status_update_tooltips (GkbdStatus * gki)
+{
+ XklState *state = xkl_engine_get_current_state (globals.engine);
+ gchar *buf;
+ if (state == NULL || state->group < 0
+ || state->group >= g_strv_length (globals.full_group_names))
+ return;
+
+ buf = g_strdup_printf (globals.tooltips_format,
+ globals.full_group_names[state->group]);
+
+ gkbd_status_set_tooltips (gki, buf);
+ g_free (buf);
+}
+
+void
+gkbd_status_reinit_ui (GkbdStatus * gki)
+{
+ gkbd_status_cleanup (gki);
+ gkbd_status_fill (gki);
+
+ gkbd_status_set_current_page (gki);
+}
+
+/* Should be called once for all widgets */
+static void
+gkbd_status_cfg_changed (GConfClient * client,
+ guint cnxn_id, GConfEntry * entry)
+{
+ xkl_debug (100,
+ "General configuration changed in GConf - reiniting...\n");
+ gkbd_desktop_config_load_from_gconf (&globals.cfg);
+ gkbd_desktop_config_activate (&globals.cfg);
+ ForAllIndicators () {
+ gkbd_status_reinit_ui (gki);
+ } NextIndicator ();
+}
+
+/* Should be called once for all widgets */
+static void
+gkbd_status_ind_cfg_changed (GConfClient * client,
+ guint cnxn_id, GConfEntry * entry)
+{
+ xkl_debug (100,
+ "Applet configuration changed in GConf - reiniting...\n");
+ gkbd_indicator_config_load_from_gconf (&globals.ind_cfg);
+
+ gkbd_indicator_config_free_image_filenames (&globals.ind_cfg);
+ gkbd_indicator_config_load_image_filenames (&globals.ind_cfg,
+ &globals.kbd_cfg);
+
+ gkbd_indicator_config_activate (&globals.ind_cfg);
+
+ ForAllIndicators () {
+ gkbd_status_reinit_ui (gki);
+ } NextIndicator ();
+}
+
+static void
+gkbd_status_load_group_names (const gchar ** layout_ids,
+ const gchar ** variant_ids)
+{
+ if (!gkbd_desktop_config_load_group_descriptions
+ (&globals.cfg, globals.registry, layout_ids, variant_ids,
+ &globals.short_group_names, &globals.full_group_names)) {
+ /* We just populate no short names (remain NULL) -
+ * full names are going to be used anyway */
+ gint i, total_groups =
+ xkl_engine_get_num_groups (globals.engine);
+ globals.full_group_names =
+ g_new0 (char *, total_groups + 1);
+
+ if (xkl_engine_get_features (globals.engine) &
+ XKLF_MULTIPLE_LAYOUTS_SUPPORTED) {
+ GSList *lst = globals.kbd_cfg.layouts_variants;
+ for (i = 0; lst; lst = lst->next, i++) {
+ globals.full_group_names[i] =
+ g_strdup ((char *) lst->data);
+ }
+ } else {
+ for (i = total_groups; --i >= 0;) {
+ globals.full_group_names[i] =
+ g_strdup_printf ("Group %d", i);
+ }
+ }
+ }
+}
+
+/* Should be called once for all widgets */
+static void
+gkbd_status_kbd_cfg_callback (GkbdStatus * gki)
+{
+ XklConfigRec *xklrec = xkl_config_rec_new ();
+ xkl_debug (100,
+ "XKB configuration changed on X Server - reiniting...\n");
+
+ gkbd_keyboard_config_load_from_x_current (&globals.kbd_cfg,
+ xklrec);
+
+ gkbd_indicator_config_free_image_filenames (&globals.ind_cfg);
+ gkbd_indicator_config_load_image_filenames (&globals.ind_cfg,
+ &globals.kbd_cfg);
+
+ g_strfreev (globals.full_group_names);
+ globals.full_group_names = NULL;
+
+ if (globals.short_group_names != NULL) {
+ g_strfreev (globals.short_group_names);
+ globals.short_group_names = NULL;
+ }
+
+ gkbd_status_load_group_names ((const gchar **) xklrec->layouts,
+ (const gchar **)
+ xklrec->variants);
+
+ ForAllIndicators () {
+ gkbd_status_reinit_ui (gki);
+ } NextIndicator ();
+ g_object_unref (G_OBJECT (xklrec));
+}
+
+/* Should be called once for all applets */
+static void
+gkbd_status_state_callback (XklEngine * engine,
+ XklEngineStateChange changeType,
+ gint group, gboolean restore)
+{
+ xkl_debug (150, "group is now %d, restore: %d\n", group, restore);
+
+ if (changeType == GROUP_CHANGED) {
+ ForAllIndicators () {
+ xkl_debug (200, "do repaint\n");
+ gkbd_status_set_current_page_for_group
+ (gki, group);
+ }
+ NextIndicator ();
+ }
+}
+
+
+void
+gkbd_status_set_current_page (GkbdStatus * gki)
+{
+ XklState *cur_state;
+ cur_state = xkl_engine_get_current_state (globals.engine);
+ if (cur_state->group >= 0)
+ gkbd_status_set_current_page_for_group (gki,
+ cur_state->group);
+}
+
+void
+gkbd_status_set_current_page_for_group (GkbdStatus * gki, int group)
+{
+ xkl_debug (200, "Revalidating for group %d\n", group);
+
+ gtk_status_icon_set_from_pixbuf (GTK_STATUS_ICON (gki),
+ GDK_PIXBUF (g_slist_nth_data
+ (globals.icons,
+ group)));
+
+ gkbd_status_update_tooltips (gki);
+}
+
+/* Should be called once for all widgets */
+static GdkFilterReturn
+gkbd_status_filter_x_evt (GdkXEvent * xev, GdkEvent * event)
+{
+ XEvent *xevent = (XEvent *) xev;
+
+ xkl_engine_filter_events (globals.engine, xevent);
+ switch (xevent->type) {
+ case ReparentNotify:
+ {
+ XReparentEvent *rne = (XReparentEvent *) xev;
+
+ ForAllIndicators () {
+ guint32 xid =
+ gtk_status_icon_get_x11_window_id
+ (GTK_STATUS_ICON (gki));
+
+ /* compare the indicator's parent window with the even window */
+ if (xid == rne->window) {
+ /* if so - make it transparent... */
+ xkl_engine_set_window_transparent
+ (globals.engine, rne->window,
+ TRUE);
+ }
+ }
+ NextIndicator ()
+ }
+ break;
+ }
+ return GDK_FILTER_CONTINUE;
+}
+
+
+/* Should be called once for all widgets */
+static void
+gkbd_status_start_listen (void)
+{
+ gdk_window_add_filter (NULL, (GdkFilterFunc)
+ gkbd_status_filter_x_evt, NULL);
+ gdk_window_add_filter (gdk_get_default_root_window (),
+ (GdkFilterFunc)
+ gkbd_status_filter_x_evt, NULL);
+
+ xkl_engine_start_listen (globals.engine,
+ XKLL_TRACK_KEYBOARD_STATE);
+}
+
+/* Should be called once for all widgets */
+static void
+gkbd_status_stop_listen (void)
+{
+ xkl_engine_stop_listen (globals.engine);
+
+ gdk_window_remove_filter (NULL, (GdkFilterFunc)
+ gkbd_status_filter_x_evt, NULL);
+ gdk_window_remove_filter
+ (gdk_get_default_root_window (),
+ (GdkFilterFunc) gkbd_status_filter_x_evt, NULL);
+}
+
+static void
+gkbd_status_size_changed (GkbdStatus * gki, gint size)
+{
+ if (globals.current_size != size) {
+ globals.current_size = size;
+ gkbd_status_reinit_ui (gki);
+ }
+}
+
+static void
+gkbd_status_init (GkbdStatus * gki)
+{
+ if (!g_slist_length (globals.widget_instances))
+ gkbd_status_global_init ();
+
+ gki->priv = g_new0 (GkbdStatusPrivate, 1);
+
+ xkl_debug (100, "Initiating the widget startup process for %p\n",
+ gki);
+
+ if (globals.engine == NULL) {
+ gkbd_status_set_tooltips (gki,
+ _("XKB initialization error"));
+ return;
+ }
+
+ gkbd_status_set_tooltips (gki, NULL);
+
+ gkbd_status_fill (gki);
+ gkbd_status_set_current_page (gki);
+
+ /* append AFTER all initialization work is finished */
+ globals.widget_instances =
+ g_slist_append (globals.widget_instances, gki);
+
+ g_signal_connect (gki, "size-changed",
+ G_CALLBACK (gkbd_status_size_changed), NULL);
+ g_signal_connect (gki, "activate",
+ G_CALLBACK (gkbd_status_activate), NULL);
+}
+
+static void
+gkbd_status_finalize (GObject * obj)
+{
+ GkbdStatus *gki = GKBD_STATUS (obj);
+ xkl_debug (100,
+ "Starting the gnome-kbd-indicator widget shutdown process for %p\n",
+ gki);
+
+ /* remove BEFORE all termination work is finished */
+ globals.widget_instances =
+ g_slist_remove (globals.widget_instances, gki);
+
+ gkbd_status_cleanup (gki);
+
+ xkl_debug (100,
+ "The instance of gnome-kbd-indicator successfully finalized\n");
+
+ g_free (gki->priv);
+
+ G_OBJECT_CLASS (gkbd_status_parent_class)->finalize (obj);
+
+ if (!g_slist_length (globals.widget_instances))
+ gkbd_status_global_term ();
+}
+
+static void
+gkbd_status_global_term (void)
+{
+ xkl_debug (100, "*** Last GkbdStatus instance *** \n");
+ gkbd_status_stop_listen ();
+
+ gkbd_desktop_config_stop_listen (&globals.cfg);
+ gkbd_indicator_config_stop_listen (&globals.ind_cfg);
+
+ gkbd_indicator_config_term (&globals.ind_cfg);
+ gkbd_keyboard_config_term (&globals.kbd_cfg);
+ gkbd_desktop_config_term (&globals.cfg);
+
+ g_object_unref (G_OBJECT (globals.registry));
+ globals.registry = NULL;
+ g_object_unref (G_OBJECT (globals.engine));
+ globals.engine = NULL;
+ xkl_debug (100, "*** Terminated globals *** \n");
+}
+
+static void
+gkbd_status_class_init (GkbdStatusClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ xkl_debug (100, "*** First GkbdStatus instance *** \n");
+
+ memset (&globals, 0, sizeof (globals));
+
+ /* Initing some global vars */
+ globals.tooltips_format = "%s";
+
+ /* Initing vtable */
+ object_class->finalize = gkbd_status_finalize;
+
+ /* Signals */
+}
+
+static void
+gkbd_status_global_init (void)
+{
+ GConfClient *gconf_client;
+ XklConfigRec *xklrec = xkl_config_rec_new ();
+
+ globals.engine = xkl_engine_get_instance (GDK_DISPLAY ());
+ if (globals.engine == NULL) {
+ xkl_debug (0, "Libxklavier initialization error");
+ return;
+ }
+
+ gconf_client = gconf_client_get_default ();
+
+ g_signal_connect (globals.engine, "X-state-changed",
+ G_CALLBACK (gkbd_status_state_callback), NULL);
+ g_signal_connect (globals.engine, "X-config-changed",
+ G_CALLBACK (gkbd_status_kbd_cfg_callback), NULL);
+
+ gkbd_desktop_config_init (&globals.cfg, gconf_client,
+ globals.engine);
+ gkbd_keyboard_config_init (&globals.kbd_cfg, gconf_client,
+ globals.engine);
+ gkbd_indicator_config_init (&globals.ind_cfg, gconf_client,
+ globals.engine);
+
+ g_object_unref (gconf_client);
+
+ gkbd_desktop_config_load_from_gconf (&globals.cfg);
+ gkbd_desktop_config_activate (&globals.cfg);
+
+ globals.registry =
+ xkl_config_registry_get_instance (globals.engine);
+ xkl_config_registry_load (globals.registry,
+ globals.cfg.load_extra_items);
+
+ gkbd_keyboard_config_load_from_x_current (&globals.kbd_cfg,
+ xklrec);
+
+ gkbd_indicator_config_load_from_gconf (&globals.ind_cfg);
+
+ gkbd_indicator_config_load_image_filenames (&globals.ind_cfg,
+ &globals.kbd_cfg);
+
+ gkbd_indicator_config_activate (&globals.ind_cfg);
+
+ gkbd_status_load_group_names ((const gchar **) xklrec->layouts,
+ (const gchar **)
+ xklrec->variants);
+ g_object_unref (G_OBJECT (xklrec));
+
+ gkbd_desktop_config_start_listen (&globals.cfg,
+ (GConfClientNotifyFunc)
+ gkbd_status_cfg_changed, NULL);
+ gkbd_indicator_config_start_listen (&globals.ind_cfg,
+ (GConfClientNotifyFunc)
+ gkbd_status_ind_cfg_changed,
+ NULL);
+ gkbd_status_start_listen ();
+
+ xkl_debug (100, "*** Inited globals *** \n");
+}
+
+GtkStatusIcon *
+gkbd_status_new (void)
+{
+ return
+ GTK_STATUS_ICON (g_object_new (gkbd_status_get_type (), NULL));
+}
+
+XklEngine *
+gkbd_status_get_xkl_engine ()
+{
+ return globals.engine;
+}
+
+gchar **
+gkbd_status_get_group_names ()
+{
+ return globals.full_group_names;
+}
+
+gchar *
+gkbd_status_get_image_filename (guint group)
+{
+ if (!globals.ind_cfg.show_flags)
+ return NULL;
+ return gkbd_indicator_config_get_images_file (&globals.ind_cfg,
+ &globals.kbd_cfg,
+ group);
+}
+
+void
+gkbd_status_set_angle (GkbdStatus * gki, gdouble angle)
+{
+ gki->priv->angle = angle;
+}
diff --git a/libgnomekbd/gkbd-status.h b/libgnomekbd/gkbd-status.h
new file mode 100644
index 0000000..5c99ea2
--- /dev/null
+++ b/libgnomekbd/gkbd-status.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2009 Sergey V. Udaltsov <svu@gnome.org>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GKBD_STATUS_H__
+#define __GKBD_STATUS_H__
+
+#include <gtk/gtk.h>
+
+#include <libxklavier/xklavier.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ typedef struct _GkbdStatus GkbdStatus;
+ typedef struct _GkbdStatusPrivate GkbdStatusPrivate;
+ typedef struct _GkbdStatusClass GkbdStatusClass;
+
+#define GKBD_TYPE_STATUS (gkbd_status_get_type ())
+#define GKBD_STATUS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKBD_TYPE_STATUS, GkbdStatus))
+#define GKBD_INDCATOR_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), GKBD_TYPE_STATUS, GkbdStatusClass))
+#define GKBD_IS_STATUS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKBD_TYPE_STATUS))
+#define GKBD_IS_STATUS_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), GKBD_TYPE_STATUS))
+#define GKBD_STATUS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GKBD_TYPE_STATUS, GkbdStatusClass))
+
+ struct _GkbdStatus {
+ GtkStatusIcon parent;
+ GkbdStatusPrivate *priv;
+ };
+
+ struct _GkbdStatusClass {
+ GtkNotebookClass parent_class;
+ };
+
+ extern GType gkbd_status_get_type (void);
+
+ extern GtkStatusIcon *gkbd_status_new (void);
+
+ extern void gkbd_status_reinit_ui (GkbdStatus * gki);
+
+ extern void gkbd_status_set_angle (GkbdStatus * gki,
+ gdouble angle);
+
+ extern XklEngine *gkbd_status_get_xkl_engine (void);
+
+ extern gchar **gkbd_status_get_group_names (void);
+
+ extern gchar *gkbd_status_get_image_filename (guint group);
+
+ extern void
+ gkbd_status_set_tooltips_format (const gchar str[]);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/test/.gitignore b/test/.gitignore
index 5ede48f..8a1b08b 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -1,4 +1,5 @@
.deps
+gkbd-status-test
gkbd-indicator-test
gkbd-keyboard-drawing-test
.libs
diff --git a/test/Makefile.am b/test/Makefile.am
index 896b851..81ccbb5 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1,31 +1,25 @@
noinst_PROGRAMS = gkbd-indicator-test \
- gkbd-keyboard-drawing-test
+ gkbd-keyboard-drawing-test \
+ gkbd-status-test
-gkbd_indicator_test_CFLAGS= \
- $(WARN_CFLAGS) -I$(top_srcdir) -Wall \
- $(GTK_CFLAGS) \
- $(LIBGLADE_CFLAGS) \
- $(LIBXKLAVIER_CFLAGS) \
- -I$(top_srcdir)/intl \
- -DSYS_PLUGIN_DIR=\"$(libdir)/gnomekbd/\" \
- -DG_LOG_DOMAIN=\"GnomeKbdIndicatorTest\" \
- -DGNOMELOCALEDIR="\"$(datadir)/locale\"" \
- -DDATADIR=\"$(datadir)\"
-
-gkbd_indicator_test_LDFLAGS= \
- $(GTK_LIBS) \
- $(LIBGLADE_LIBS) \
- $(LIBXKLAVIER_LIBS) \
+common_CFLAGS = $(WARN_CFLAGS) -I$(top_srcdir) -Wall \
+ $(GTK_CFLAGS) \
+ $(LIBXKLAVIER_CFLAGS) \
+ -DGNOMELOCALEDIR="\"$(datadir)/locale\""
+
+common_LDFLAGS = $(GTK_LIBS) \
+ $(LIBXKLAVIER_LIBS) \
$(top_builddir)/libgnomekbd/libgnomekbd.la \
$(top_builddir)/libgnomekbd/libgnomekbdui.la
-gkbd_keyboard_drawing_test_CFLAGS= \
- $(WARN_CFLAGS) -I$(top_srcdir) \
- $(GTK_CFLAGS) $(GLIB_CFLAGS)
+gkbd_indicator_test_CFLAGS=$(common_CFLAGS)
-gkbd_keyboard_drawing_test_LDFLAGS= \
- $(GLIB_LIBS) \
- $(GTK_LIBS) \
- $(LIBXKLAVIER_LIBS) \
- $(top_builddir)/libgnomekbd/libgnomekbd.la \
- $(top_builddir)/libgnomekbd/libgnomekbdui.la
+gkbd_indicator_test_LDFLAGS=$(common_LDFLAGS)
+
+gkbd_keyboard_drawing_test_CFLAGS=$(common_CFLAGS)
+
+gkbd_keyboard_drawing_test_LDFLAGS=$(common_LDFLAGS)
+
+gkbd_status_test_CFLAGS=$(common_CFLAGS)
+
+gkbd_status_test_LDFLAGS=$(common_LDFLAGS)
diff --git a/test/gkbd-status-test.c b/test/gkbd-status-test.c
new file mode 100644
index 0000000..3b2c365
--- /dev/null
+++ b/test/gkbd-status-test.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2006 Sergey V. Udaltsov <svu@gnome.org>
+ *
+ * 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., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "libxklavier/xklavier.h"
+#include "libgnomekbd/gkbd-status.h"
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "X11/XKBlib.h"
+
+int
+main (int argc, char **argv)
+{
+ GtkStatusIcon *icon;
+
+ bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ gtk_init (&argc, &argv);
+
+ icon = gkbd_status_new ();
+
+ gtk_main ();
+
+ return 0;
+}