diff --git a/capplets/keyboard/Makefile.am b/capplets/keyboard/Makefile.am index 2e3f7c54f..2ed09909a 100644 --- a/capplets/keyboard/Makefile.am +++ b/capplets/keyboard/Makefile.am @@ -3,6 +3,7 @@ bin_PROGRAMS = gnome-keyboard-properties gnome_keyboard_properties_SOURCES = gnome-keyboard-properties.c \ gnome-keyboard-properties-xkb.c \ gnome-keyboard-properties-xkblt.c \ + gnome-keyboard-properties-xkbot.c \ gnome-keyboard-properties-xkb.h gnome_keyboard_properties_LDADD = \ ../accessibility/keyboard/libaccessibility-keyboard.a \ diff --git a/capplets/keyboard/gnome-keyboard-properties-xkb.c b/capplets/keyboard/gnome-keyboard-properties-xkb.c index c4a151b9b..04a911c4f 100644 --- a/capplets/keyboard/gnome-keyboard-properties-xkb.c +++ b/capplets/keyboard/gnome-keyboard-properties-xkb.c @@ -116,7 +116,7 @@ model_to_widget (GConfPropertyEditor * peditor, GConfValue * value) } static void -cleanup_xkb_tabs (GtkWidget * widget, GladeXML * dialog) +cleanup_xkb_tabs (GladeXML * dialog) { XklConfigFreeRegistry (); XklConfigTerm (); @@ -178,11 +178,19 @@ setup_xkb_tabs (GladeXML * dialog, GConfChangeSet * changeset) "conv-from-widget-cb", model_from_widget, NULL); fill_available_layouts_tree (dialog); + fill_available_options_tree (dialog); prepare_selected_layouts_tree (dialog); + prepare_selected_options_tree (dialog); fill_selected_layouts_tree (dialog); - register_layouts_buttons_handlers (dialog); - register_layouts_gconf_listener (dialog); + fill_selected_options_tree (dialog); - g_signal_connect (G_OBJECT (WID ("keyboard_dialog")), "destroy", - (GCallback) cleanup_xkb_tabs, NULL); + register_layouts_buttons_handlers (dialog); + register_options_buttons_handlers (dialog); + + register_layouts_gconf_listener (dialog); + register_options_gconf_listener (dialog); + + g_signal_connect (G_OBJECT (WID ("keyboard_dialog")), + "destroy", G_CALLBACK (cleanup_xkb_tabs), + dialog); } diff --git a/capplets/keyboard/gnome-keyboard-properties-xkb.h b/capplets/keyboard/gnome-keyboard-properties-xkb.h index 224234a68..8d41a2758 100644 --- a/capplets/keyboard/gnome-keyboard-properties-xkb.h +++ b/capplets/keyboard/gnome-keyboard-properties-xkb.h @@ -27,20 +27,34 @@ #include G_BEGIN_DECLS - extern void setup_xkb_tabs (GladeXML * dialog, - GConfChangeSet * changeset); + +extern void setup_xkb_tabs (GladeXML * dialog, + GConfChangeSet * changeset); extern void fill_available_layouts_tree (GladeXML * dialog); -extern void prepare_selected_layouts_tree (GladeXML * dialog); +extern void fill_available_options_tree (GladeXML * dialog); extern void fill_selected_layouts_tree (GladeXML * dialog); -extern char *xci_desc_to_utf8 (XklConfigItem * ci); +extern void fill_selected_options_tree (GladeXML * dialog); extern void register_layouts_buttons_handlers (GladeXML * dialog); +extern void register_options_buttons_handlers (GladeXML * dialog); + extern void register_layouts_gconf_listener (GladeXML * dialog); +extern void register_options_gconf_listener (GladeXML * dialog); + +extern void prepare_selected_layouts_tree (GladeXML * dialog); + +extern void prepare_selected_options_tree (GladeXML * dialog); + +extern void clear_xkb_elements_list (GSList * list); + +extern char *xci_desc_to_utf8 (XklConfigItem * ci); + G_END_DECLS + #endif /* __GNOME_KEYBOARD_PROPERTY_XKB_H */ diff --git a/capplets/keyboard/gnome-keyboard-properties-xkblt.c b/capplets/keyboard/gnome-keyboard-properties-xkblt.c index 2b7847e36..d7f8c4126 100644 --- a/capplets/keyboard/gnome-keyboard-properties-xkblt.c +++ b/capplets/keyboard/gnome-keyboard-properties-xkblt.c @@ -44,8 +44,8 @@ static const char *current1stLevelId; static int idx2Select = -1; static int maxSelectedLayouts = -1; -static void -clear_list (GSList * list) +void +clear_xkb_elements_list (GSList * list) { while (list != NULL) { GSList *p = list; @@ -55,22 +55,15 @@ clear_list (GSList * list) } } -static GSList * -get_selected_layouts_list () -{ - return gconf_client_get_list (gconf_client_get_default (), - GSWITCHIT_CONFIG_XKB_KEY_LAYOUTS, - GCONF_VALUE_STRING, NULL); +#define get_selected_layouts_list() \ + gconf_client_get_list (gconf_client_get_default (), \ + GSWITCHIT_CONFIG_XKB_KEY_LAYOUTS, \ + GCONF_VALUE_STRING, NULL) -} - -static void -set_selected_layouts_list (GSList * list) -{ - gconf_client_set_list (gconf_client_get_default (), - GSWITCHIT_CONFIG_XKB_KEY_LAYOUTS, - GCONF_VALUE_STRING, list, NULL); -} +#define set_selected_layouts_list(list) \ + gconf_client_set_list (gconf_client_get_default (), \ + GSWITCHIT_CONFIG_XKB_KEY_LAYOUTS, \ + GCONF_VALUE_STRING, (list), NULL) static void add_variant_to_available_layouts_tree (const XklConfigItemPtr @@ -116,7 +109,7 @@ add_layout_to_available_layouts_tree (const XklConfigItemPtr } static void -enable_disable_layout_buttons (GladeXML * dialog) +enable_disable_layouts_buttons (GladeXML * dialog) { GtkWidget *addLayoutBtn = WID ("xkb_layouts_add"); GtkWidget *delLayoutBtn = WID ("xkb_layouts_remove"); @@ -152,7 +145,7 @@ enable_disable_layout_buttons (GladeXML * dialog) nSelectedSelectedLayouts > 0); if (gtk_tree_selection_get_selected - (sSelection, &selectedLayoutsModel, &iter)) { + (sSelection, NULL, &iter)) { GtkTreePath *path = gtk_tree_model_get_path (selectedLayoutsModel, &iter); @@ -189,7 +182,8 @@ prepare_selected_layouts_tree (GladeXML * dialog) gtk_tree_view_append_column (GTK_TREE_VIEW (treeView), column); g_signal_connect_swapped (G_OBJECT (selection), "changed", G_CALLBACK - (enable_disable_layout_buttons), dialog); + (enable_disable_layouts_buttons), + dialog); maxSelectedLayouts = XklMultipleLayoutsSupported ()? XkbNumKbdGroups : 1; } @@ -212,14 +206,14 @@ fill_selected_layouts_tree (GladeXML * dialog) const char *visible = (char *) curLayout->data; gtk_list_store_append (listStore, &iter); if (GSwitchItConfigGetDescriptions - (curLayout->data, &sl, &l, &sv, &v)) + (visible, &sl, &l, &sv, &v)) visible = GSwitchItConfigFormatFullLayout (l, v); gtk_list_store_set (listStore, &iter, 0, visible, 1, curLayout->data, -1); } - clear_list (layouts); - enable_disable_layout_buttons (dialog); + clear_xkb_elements_list (layouts); + enable_disable_layouts_buttons (dialog); if (idx2Select != -1) { GtkTreeSelection *selection = gtk_tree_view_get_selection ((GTK_TREE_VIEW @@ -260,7 +254,8 @@ fill_available_layouts_tree (GladeXML * dialog) g_signal_connect_swapped (G_OBJECT (selection), "changed", G_CALLBACK - (enable_disable_layout_buttons), dialog); + (enable_disable_layouts_buttons), + dialog); } static void @@ -278,7 +273,7 @@ add_selected_layout (GtkWidget * button, GladeXML * dialog) gtk_tree_model_get (model, &selectedIter, 1, &id, -1); layoutsList = g_slist_append (layoutsList, id); set_selected_layouts_list (layoutsList); - clear_list (layoutsList); + clear_xkb_elements_list (layoutsList); } } @@ -319,7 +314,7 @@ move_selected_layout (GladeXML * dialog, int offset) set_selected_layouts_list (layoutsList); gtk_tree_path_free (path); } - clear_list (layoutsList); + clear_xkb_elements_list (layoutsList); } } diff --git a/capplets/keyboard/gnome-keyboard-properties-xkbot.c b/capplets/keyboard/gnome-keyboard-properties-xkbot.c new file mode 100644 index 000000000..91245c5e4 --- /dev/null +++ b/capplets/keyboard/gnome-keyboard-properties-xkbot.c @@ -0,0 +1,388 @@ +/* -*- mode: c; style: linux -*- */ + +/* gnome-keyboard-properties-xkbot.c + * Copyright (C) 2003 Sergey V. Oudaltsov + * + * Written by: Sergey V. Oudaltsov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "libgswitchit/gswitchit_xkb_config.h" + +#include "capplet-util.h" +#include "gconf-property-editor.h" +#include "activate-settings-daemon.h" +#include "capplet-stock-icons.h" +#include <../accessibility/keyboard/accessibility-keyboard.h> + +#include "gnome-keyboard-properties-xkb.h" + +static GtkTreeIter current1stLevelIter; +static const char *current1stLevelId; + +#define get_selected_options_list() \ + gconf_client_get_list (gconf_client_get_default (), \ + GSWITCHIT_CONFIG_XKB_KEY_OPTIONS, \ + GCONF_VALUE_STRING, NULL) + +#define set_selected_options_list(list) \ + gconf_client_set_list (gconf_client_get_default (), \ + GSWITCHIT_CONFIG_XKB_KEY_OPTIONS, \ + GCONF_VALUE_STRING, (list), NULL) + +static gboolean +can_add_option (GladeXML * dialog) +{ + GtkWidget *availableOptionsTree = WID ("xkb_options_available"); + GtkWidget *selectedOptionsTree = WID ("xkb_options_selected"); + GtkTreeSelection *aSelection = + gtk_tree_view_get_selection (GTK_TREE_VIEW + (availableOptionsTree)); + GtkTreeIter aiter, siter, groupIter; + GtkTreeModel *availableOptionsModel, *selectedOptionsModel; + GtkTreePath *path, *groupPath; + char *selectedOptionId = NULL, *selectedGroupId = + NULL, *selectedFullOptionId = NULL; + gboolean retval = FALSE, multipleAllowed = TRUE; + int depth; + + if (!gtk_tree_selection_get_selected + (aSelection, &availableOptionsModel, &aiter)) + return FALSE; + + path = gtk_tree_model_get_path (availableOptionsModel, &aiter); + if (path == NULL) + return FALSE; + + depth = gtk_tree_path_get_depth (path); + + if (depth != 2) { + gtk_tree_path_free (path); + return FALSE; + } + + if (!gtk_tree_model_iter_parent + (availableOptionsModel, &groupIter, &aiter)) { + gtk_tree_path_free (path); + return FALSE; + } + groupPath = + gtk_tree_model_get_path (availableOptionsModel, &groupIter); + if (groupPath == NULL) { + gtk_tree_path_free (path); + return FALSE; + } + + gtk_tree_model_get (availableOptionsModel, &groupIter, 2, + &multipleAllowed, -1); + + gtk_tree_model_get (availableOptionsModel, &aiter, 1, + &selectedFullOptionId, -1); + + if (!GSwitchItConfigSplitItems + (selectedFullOptionId, &selectedGroupId, &selectedOptionId)) { + gtk_tree_path_free (groupPath); + gtk_tree_path_free (path); + return FALSE; + } + selectedGroupId = g_strdup (selectedGroupId); + selectedOptionId = g_strdup (selectedOptionId); + + selectedOptionsModel = + gtk_tree_view_get_model (GTK_TREE_VIEW (selectedOptionsTree)); + + retval = TRUE; + + if (gtk_tree_model_get_iter_first (selectedOptionsModel, &siter)) { + do { + char *sid = NULL; + gtk_tree_model_get (selectedOptionsModel, + &siter, 1, &sid, -1); + if (multipleAllowed) { + // look for the _same_ option - and do not allow it twice + if (!g_strcasecmp + (sid, selectedFullOptionId)) { + retval = FALSE; + } + } else { + // look for options within same group + char *sgid = NULL, *soid = NULL; + gtk_tree_model_get (selectedOptionsModel, + &siter, 1, &sid, -1); + if (GSwitchItConfigSplitItems + (sid, &sgid, &soid) + && !g_strcasecmp (sgid, + selectedGroupId)) { + retval = FALSE; + } + } + g_free (sid); + } while (retval && gtk_tree_model_iter_next + (selectedOptionsModel, &siter)); + } + + g_free (selectedFullOptionId); + g_free (selectedGroupId); + g_free (selectedOptionId); + + gtk_tree_path_free (groupPath); + gtk_tree_path_free (path); + return retval; +} + +static void +enable_disable_options_buttons (GladeXML * dialog) +{ + GtkWidget *addOptionBtn = WID ("xkb_options_add"); + GtkWidget *delOptionBtn = WID ("xkb_options_remove"); + GtkWidget *selectedOptionsTree = WID ("xkb_options_selected"); + + GtkTreeSelection *sSelection = + gtk_tree_view_get_selection (GTK_TREE_VIEW + (selectedOptionsTree)); + const int nSelectedSelectedOptions = + gtk_tree_selection_count_selected_rows (sSelection); + + gtk_widget_set_sensitive (addOptionBtn, can_add_option (dialog)); + gtk_widget_set_sensitive (delOptionBtn, + nSelectedSelectedOptions > 0); +} + +void +prepare_selected_options_tree (GladeXML * dialog) +{ + GtkListStore *listStore = + gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_STRING); + GtkWidget *treeView = WID ("xkb_options_selected"); + GtkCellRenderer *renderer = + GTK_CELL_RENDERER (gtk_cell_renderer_text_new ()); + GtkTreeViewColumn *column = + gtk_tree_view_column_new_with_attributes (NULL, + renderer, + "text", + 0, + NULL); + GtkTreeSelection *selection = + gtk_tree_view_get_selection (GTK_TREE_VIEW (treeView)); + gtk_tree_view_set_model (GTK_TREE_VIEW (treeView), + GTK_TREE_MODEL (listStore)); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeView), column); + g_signal_connect_swapped (G_OBJECT (selection), "changed", + G_CALLBACK + (enable_disable_options_buttons), + dialog); +} + +static void +add_selected_option (GtkWidget * button, GladeXML * dialog) +{ + GtkTreeSelection *selection = + gtk_tree_view_get_selection (GTK_TREE_VIEW + (WID ("xkb_options_available"))); + GtkTreeIter selectedIter; + GtkTreeModel *model; + if (gtk_tree_selection_get_selected + (selection, &model, &selectedIter)) { + gchar *id; + GSList *optionsList = get_selected_options_list (); + gtk_tree_model_get (model, &selectedIter, 1, &id, -1); + optionsList = g_slist_append (optionsList, id); + set_selected_options_list (optionsList); + clear_xkb_elements_list (optionsList); + } +} + +static void +remove_selected_option (GtkWidget * button, GladeXML * dialog) +{ + GtkTreeSelection *selection = + gtk_tree_view_get_selection (GTK_TREE_VIEW + (WID ("xkb_options_selected"))); + GtkTreeIter selectedIter; + GtkTreeModel *model; + if (gtk_tree_selection_get_selected + (selection, &model, &selectedIter)) { + GSList *optionsList = get_selected_options_list (); + GtkTreePath *path = gtk_tree_model_get_path (model, + &selectedIter); + if (path != NULL) { + int *indices = gtk_tree_path_get_indices (path); + char *id = NULL; + GSList *node2Remove = + g_slist_nth (optionsList, indices[0]); + + optionsList = + g_slist_remove_link (optionsList, node2Remove); + + id = (char *) node2Remove->data; + g_slist_free_1 (node2Remove); + + g_free (id); + + set_selected_options_list (optionsList); + gtk_tree_path_free (path); + } + clear_xkb_elements_list (optionsList); + } +} + +static void +add_option_to_available_options_tree (const XklConfigItemPtr + configItem, GladeXML * dialog) +{ + GtkWidget *optionsTree = WID ("xkb_options_available"); + GtkTreeIter iter; + GtkTreeStore *treeStore = + GTK_TREE_STORE (gtk_tree_view_get_model + (GTK_TREE_VIEW (optionsTree))); + const gchar *fullOptionName = + GSwitchItConfigMergeItems (current1stLevelId, + configItem->name); + char *utfOptionName = xci_desc_to_utf8 (configItem); + + gtk_tree_store_append (treeStore, &iter, ¤t1stLevelIter); + gtk_tree_store_set (treeStore, &iter, 0, utfOptionName, 1, + fullOptionName, -1); + g_free (utfOptionName); +} + +static void +add_group_to_available_options_tree (const XklConfigItemPtr + configItem, + Bool allowMultipleSelection, + GladeXML * dialog) +{ + GtkWidget *optionsTree = WID ("xkb_options_available"); + GtkTreeStore *treeStore = + GTK_TREE_STORE (gtk_tree_view_get_model + (GTK_TREE_VIEW (optionsTree))); + char *utfGroupName = xci_desc_to_utf8 (configItem); + + gtk_tree_store_append (treeStore, ¤t1stLevelIter, NULL); + gtk_tree_store_set (treeStore, ¤t1stLevelIter, 0, + utfGroupName, 1, configItem->name, 2, + (gboolean) allowMultipleSelection, -1); + g_free (utfGroupName); + + current1stLevelId = configItem->name; + + XklConfigEnumOptions (configItem->name, (ConfigItemProcessFunc) + add_option_to_available_options_tree, + dialog); +} + +void +fill_available_options_tree (GladeXML * dialog) +{ + GtkTreeStore *treeStore = + gtk_tree_store_new (3, G_TYPE_STRING, G_TYPE_STRING, + G_TYPE_BOOLEAN); + GtkWidget *treeView = WID ("xkb_options_available"); + GtkCellRenderer *renderer = + GTK_CELL_RENDERER (gtk_cell_renderer_text_new ()); + GtkTreeViewColumn *column = + gtk_tree_view_column_new_with_attributes (NULL, + renderer, + "text", + 0, + NULL); + GtkTreeSelection *selection = + gtk_tree_view_get_selection (GTK_TREE_VIEW (treeView)); + + gtk_tree_view_set_model (GTK_TREE_VIEW (treeView), + GTK_TREE_MODEL (treeStore)); + gtk_tree_view_append_column (GTK_TREE_VIEW (treeView), column); + + XklConfigEnumOptionGroups ((GroupProcessFunc) + add_group_to_available_options_tree, + dialog); + + g_signal_connect_swapped (G_OBJECT (selection), "changed", + G_CALLBACK + (enable_disable_options_buttons), + dialog); +} + +void +fill_selected_options_tree (GladeXML * dialog) +{ + GSList *options = get_selected_options_list (); + GSList *curOption; + GtkListStore *listStore = + GTK_LIST_STORE (gtk_tree_view_get_model + (GTK_TREE_VIEW + (WID ("xkb_options_selected")))); + gtk_list_store_clear (listStore); + + for (curOption = options; curOption != NULL; + curOption = curOption->next) { + GtkTreeIter iter; + char *groupName, *optionName; + const char *visible = (char *) curOption->data; + + if (GSwitchItConfigSplitItems + (visible, &groupName, &optionName)) { + XklConfigItem citem; + g_snprintf (citem.name, sizeof (citem.name), "%s", + optionName); + if (XklConfigFindOption (groupName, &citem)) { + visible = citem.description; + } + gtk_list_store_append (listStore, &iter); + gtk_list_store_set (listStore, &iter, + 0, visible, 1, curOption->data, + -1); + } + + } + + clear_xkb_elements_list (options); + enable_disable_options_buttons (dialog); +} + +void +register_options_buttons_handlers (GladeXML * dialog) +{ + g_signal_connect (G_OBJECT (WID ("xkb_options_add")), "clicked", + G_CALLBACK (add_selected_option), dialog); + g_signal_connect (G_OBJECT (WID ("xkb_options_remove")), "clicked", + G_CALLBACK (remove_selected_option), dialog); +} +static void +update_options_list (GConfClient * client, + guint cnxn_id, GConfEntry * entry, GladeXML * dialog) +{ + fill_selected_options_tree (dialog); +} + +void +register_options_gconf_listener (GladeXML * dialog) +{ + gconf_client_notify_add (gconf_client_get_default (), + GSWITCHIT_CONFIG_XKB_KEY_OPTIONS, + (GConfClientNotifyFunc) + update_options_list, dialog, NULL, NULL); +} diff --git a/capplets/keyboard/gnome-keyboard-properties.glade b/capplets/keyboard/gnome-keyboard-properties.glade index 9c8827136..80d27a56f 100644 --- a/capplets/keyboard/gnome-keyboard-properties.glade +++ b/capplets/keyboard/gnome-keyboard-properties.glade @@ -1448,7 +1448,7 @@ GTK_CORNER_TOP_LEFT - + True True False @@ -1473,7 +1473,7 @@ 12 - + True True gtk-add @@ -1488,7 +1488,7 @@ - + True True gtk-remove @@ -1523,7 +1523,7 @@ GTK_CORNER_TOP_LEFT - + True True False