diff --git a/libgnomekbd/Makefile.am b/libgnomekbd/Makefile.am index 45f2376..8189f20 100644 --- a/libgnomekbd/Makefile.am +++ b/libgnomekbd/Makefile.am @@ -42,6 +42,7 @@ libgnomekbd_la_SOURCES = \ gkbd-util.c libgnomekbdui_la_SOURCES = \ + gkbd-configuration.c \ gkbd-indicator-config.c \ gkbd-indicator.c \ gkbd-status.c \ @@ -59,6 +60,7 @@ CLEANFILES = $(BUILT_SOURCES) $(schema_DATA) gnomekbdincdir = $(includedir)/libgnomekbd gnomekbdinc_HEADERS = \ + gkbd-configuration.h \ gkbd-desktop-config.h \ gkbd-keyboard-config.h \ gkbd-indicator.h \ diff --git a/libgnomekbd/gkbd-configuration.c b/libgnomekbd/gkbd-configuration.c new file mode 100644 index 0000000..af95ca7 --- /dev/null +++ b/libgnomekbd/gkbd-configuration.c @@ -0,0 +1,357 @@ +/* + * Copyright (C) 2010 Jan Arne Petersen + * + * Based on gkbd-status.c by Sergey V. Udaltsov + * + * 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 + +#include +#include +#include + +#include + +#include +#include + +struct _GkbdConfigurationPrivate { + XklEngine *engine; + XklConfigRegistry *registry; + + GkbdDesktopConfig cfg; + GkbdIndicatorConfig ind_cfg; + GkbdKeyboardConfig kbd_cfg; + + gchar **full_group_names; + gchar **short_group_names; + + gulong state_changed_handler; + gulong config_changed_handler; +}; + +enum { + SIGNAL_CHANGED, + SIGNAL_GROUP_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0, }; + +#define GKBD_CONFIGURATION_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), GKBD_TYPE_CONFIGURATION, GkbdConfigurationPrivate)) + +G_DEFINE_TYPE (GkbdConfiguration, gkbd_configuration, G_TYPE_OBJECT) + +/* Should be called once for all widgets */ +static void +gkbd_configuration_cfg_changed (GConfClient * client, + guint cnxn_id, GConfEntry * entry, + GkbdConfiguration * configuration) +{ + GkbdConfigurationPrivate *priv = configuration->priv; + + xkl_debug (100, + "General configuration changed in GConf - reiniting...\n"); + gkbd_desktop_config_load_from_gconf (&priv->cfg); + gkbd_desktop_config_activate (&priv->cfg); + + g_signal_emit (configuration, + signals[SIGNAL_CHANGED], 0); +} + +/* Should be called once for all widgets */ +static void +gkbd_configuration_ind_cfg_changed (GConfClient * client, + guint cnxn_id, GConfEntry * entry, + GkbdConfiguration * configuration) +{ + GkbdConfigurationPrivate *priv = configuration->priv; + xkl_debug (100, + "Applet configuration changed in GConf - reiniting...\n"); + gkbd_indicator_config_load_from_gconf (&priv->ind_cfg); + + gkbd_indicator_config_free_image_filenames (&priv->ind_cfg); + gkbd_indicator_config_load_image_filenames (&priv->ind_cfg, + &priv->kbd_cfg); + + gkbd_indicator_config_activate (&priv->ind_cfg); + + g_signal_emit (configuration, + signals[SIGNAL_CHANGED], 0); +} + +static void +gkbd_configuration_load_group_names (GkbdConfiguration * configuration, + XklConfigRec * xklrec) +{ + GkbdConfigurationPrivate *priv = configuration->priv; + + if (!gkbd_desktop_config_load_group_descriptions (&priv->cfg, + priv->registry, + (const char **) xklrec->layouts, + (const char **) xklrec->variants, + &priv->short_group_names, + &priv->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 (priv->engine); + xkl_debug (150, "group descriptions loaded: %d!\n", + total_groups); + priv->full_group_names = + g_new0 (char *, total_groups + 1); + + if (xkl_engine_get_features (priv->engine) & + XKLF_MULTIPLE_LAYOUTS_SUPPORTED) { + GSList *lst = priv->kbd_cfg.layouts_variants; + for (i = 0; lst; lst = lst->next, i++) { + priv->full_group_names[i] = + g_strdup ((char *) lst->data); + } + } else { + for (i = total_groups; --i >= 0;) { + priv->full_group_names[i] = + g_strdup_printf ("Group %d", i); + } + } + } +} + +/* Should be called once for all widgets */ +static void +gkbd_configuration_kbd_cfg_callback (XklEngine *engine, + GkbdConfiguration *configuration) +{ + GkbdConfigurationPrivate *priv = configuration->priv; + XklConfigRec *xklrec = xkl_config_rec_new (); + xkl_debug (100, + "XKB configuration changed on X Server - reiniting...\n"); + + gkbd_keyboard_config_load_from_x_current (&priv->kbd_cfg, + xklrec); + + gkbd_indicator_config_free_image_filenames (&priv->ind_cfg); + gkbd_indicator_config_load_image_filenames (&priv->ind_cfg, + &priv->kbd_cfg); + + g_strfreev (priv->full_group_names); + priv->full_group_names = NULL; + + g_strfreev (priv->short_group_names); + priv->short_group_names = NULL; + + gkbd_configuration_load_group_names (configuration, + xklrec); + + g_signal_emit (configuration, + signals[SIGNAL_CHANGED], + 0); + + g_object_unref (G_OBJECT (xklrec)); +} + +/* Should be called once for all applets */ +static void +gkbd_configuration_state_callback (XklEngine * engine, + XklEngineStateChange changeType, + gint group, gboolean restore, + GkbdConfiguration * configuration) +{ + xkl_debug (150, "group is now %d, restore: %d\n", group, restore); + + if (changeType == GROUP_CHANGED) { + g_signal_emit (configuration, + signals[SIGNAL_GROUP_CHANGED], 0, + group); + } +} + +static void +gkbd_configuration_init (GkbdConfiguration *configuration) +{ + GkbdConfigurationPrivate *priv; + GConfClient *gconf_client; + XklConfigRec *xklrec = xkl_config_rec_new (); + + priv = GKBD_CONFIGURATION_GET_PRIVATE (configuration); + configuration->priv = priv; + + priv->engine = xkl_engine_get_instance (GDK_DISPLAY ()); + if (priv->engine == NULL) { + xkl_debug (0, "Libxklavier initialization error"); + return; + } + + gconf_client = gconf_client_get_default (); + + priv->state_changed_handler = + g_signal_connect (priv->engine, "X-state-changed", + G_CALLBACK (gkbd_configuration_state_callback), + configuration); + priv->config_changed_handler = + g_signal_connect (priv->engine, "X-config-changed", + G_CALLBACK (gkbd_configuration_kbd_cfg_callback), + configuration); + + gkbd_desktop_config_init (&priv->cfg, gconf_client, + priv->engine); + gkbd_keyboard_config_init (&priv->kbd_cfg, gconf_client, + priv->engine); + gkbd_indicator_config_init (&priv->ind_cfg, gconf_client, + priv->engine); + + g_object_unref (gconf_client); + + gkbd_desktop_config_load_from_gconf (&priv->cfg); + gkbd_desktop_config_activate (&priv->cfg); + + priv->registry = xkl_config_registry_get_instance (priv->engine); + xkl_config_registry_load (priv->registry, + priv->cfg.load_extra_items); + + gkbd_keyboard_config_load_from_x_current (&priv->kbd_cfg, + xklrec); + + gkbd_indicator_config_load_from_gconf (&priv->ind_cfg); + + gkbd_indicator_config_load_image_filenames (&priv->ind_cfg, + &priv->kbd_cfg); + + gkbd_indicator_config_activate (&priv->ind_cfg); + + gkbd_configuration_load_group_names (configuration, + xklrec); + g_object_unref (G_OBJECT (xklrec)); + + gkbd_desktop_config_start_listen (&priv->cfg, + (GConfClientNotifyFunc) gkbd_configuration_cfg_changed, + configuration); + gkbd_indicator_config_start_listen (&priv->ind_cfg, + (GConfClientNotifyFunc) gkbd_configuration_ind_cfg_changed, + configuration); + xkl_engine_start_listen (priv->engine, + XKLL_TRACK_KEYBOARD_STATE); + + xkl_debug (100, "Initiating the widget startup process for %p\n", + configuration); +} + +static void +gkbd_configuration_finalize (GObject * obj) +{ + GkbdConfiguration *configuration = GKBD_CONFIGURATION (obj); + GkbdConfigurationPrivate *priv = configuration->priv; + + xkl_debug (100, + "Starting the gnome-kbd-configuration widget shutdown process for %p\n", + configuration); + + xkl_engine_stop_listen (priv->engine, + XKLL_TRACK_KEYBOARD_STATE); + + gkbd_desktop_config_stop_listen (&priv->cfg); + gkbd_indicator_config_stop_listen (&priv->ind_cfg); + + gkbd_indicator_config_term (&priv->ind_cfg); + gkbd_keyboard_config_term (&priv->kbd_cfg); + gkbd_desktop_config_term (&priv->cfg); + + if (g_signal_handler_is_connected (priv->engine, + priv->state_changed_handler)) { + g_signal_handler_disconnect (priv->engine, + priv->state_changed_handler); + priv->state_changed_handler = 0; + } + if (g_signal_handler_is_connected (priv->engine, + priv->config_changed_handler)) { + g_signal_handler_disconnect (priv->engine, + priv->config_changed_handler); + priv->config_changed_handler = 0; + } + + g_object_unref (priv->registry); + priv->registry = NULL; + g_object_unref (priv->engine); + priv->engine = NULL; + + G_OBJECT_CLASS (gkbd_configuration_parent_class)->finalize (obj); +} + +static void +gkbd_configuration_class_init (GkbdConfigurationClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + /* Initing vtable */ + object_class->finalize = gkbd_configuration_finalize; + + /* Signals */ + signals[SIGNAL_CHANGED] = g_signal_new ("changed", + GKBD_TYPE_CONFIGURATION, + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + signals[SIGNAL_GROUP_CHANGED] = g_signal_new ("group-changed", + GKBD_TYPE_CONFIGURATION, + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, + 1, + G_TYPE_INT); + + g_type_class_add_private (klass, sizeof (GkbdConfigurationPrivate)); +} + +GkbdConfiguration * +gkbd_configuration_get (void) +{ + static gpointer instance = NULL; + + if (!instance) { + instance = g_object_new (GKBD_TYPE_CONFIGURATION, NULL); + g_object_add_weak_pointer (instance, &instance); + } else { + g_object_ref (instance); + } + + return instance; +} + +XklEngine * +gkbd_configuration_get_xkl_engine (GkbdConfiguration *configuration) +{ + return configuration->priv->engine; +} + +const char * const * +gkbd_configuration_get_group_names (GkbdConfiguration *configuration) +{ + return configuration->priv->full_group_names; +} + +const char * const * +gkbd_configuration_get_short_group_names (GkbdConfiguration *configuration) +{ + return configuration->priv->short_group_names; +} diff --git a/libgnomekbd/gkbd-configuration.h b/libgnomekbd/gkbd-configuration.h new file mode 100644 index 0000000..96ff211 --- /dev/null +++ b/libgnomekbd/gkbd-configuration.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2010 Jan Arne Petersen + * + * Based on gkbd-status.h by Sergey V. Udaltsov + * + * 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_CONFIGURATION_H__ +#define __GKBD_CONFIGURATION_H__ + +#include + +#include + +G_BEGIN_DECLS + +typedef struct _GkbdConfiguration GkbdConfiguration; +typedef struct _GkbdConfigurationPrivate GkbdConfigurationPrivate; +typedef struct _GkbdConfigurationClass GkbdConfigurationClass; + +#define GKBD_TYPE_CONFIGURATION (gkbd_configuration_get_type ()) +#define GKBD_CONFIGURATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKBD_TYPE_CONFIGURATION, GkbdConfiguration)) +#define GKBD_INDCATOR_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), GKBD_TYPE_CONFIGURATION, GkbdConfigurationClass)) +#define GKBD_IS_CONFIGURATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKBD_TYPE_CONFIGURATION)) +#define GKBD_IS_CONFIGURATION_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), GKBD_TYPE_CONFIGURATION)) +#define GKBD_CONFIGURATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GKBD_TYPE_CONFIGURATION, GkbdConfigurationClass)) + +struct _GkbdConfiguration { + GObject parent; + + GkbdConfigurationPrivate *priv; +}; + +struct _GkbdConfigurationClass { + GObjectClass parent_class; +}; + +extern GType gkbd_configuration_get_type (void); + +extern GkbdConfiguration *gkbd_configuration_get (void); + +extern XklEngine *gkbd_configuration_get_xkl_engine (GkbdConfiguration *configuration); + +extern const char * const *gkbd_configuration_get_group_names (GkbdConfiguration *configuration); +extern const char * const *gkbd_configuration_get_short_group_names (GkbdConfiguration *configuration); + +G_END_DECLS + +#endif