[libgnomekbd] Introduced GkbdStatus for the notification area



commit 3584dc898c8212f154cd9ae22185c5d8aa7b4218
Author: Sergey V. Udaltsov <svu gnome org>
Date:   Mon Dec 14 13:23:07 2009 +0000

    Introduced GkbdStatus for the notification area
    
    Now it only works with flags

 ChangeLog                           |    6 +
 libgnomekbd/Makefile.am             |    1 +
 libgnomekbd/gkbd-indicator-config.c |   96 ++-----
 libgnomekbd/gkbd-indicator-config.h |   20 +-
 libgnomekbd/gkbd-indicator.c        |  104 ++++++-
 libgnomekbd/gkbd-status.c           |  596 +++++++++++++++++++++++++++++++++++
 libgnomekbd/gkbd-status.h           |   72 +++++
 test/.gitignore                     |    1 +
 test/Makefile.am                    |   44 ++--
 test/gkbd-status-test.c             |   55 ++++
 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;
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]