Compare commits

...

15 Commits

Author SHA1 Message Date
Rui Matos
d47beb4561 region: Get the available XKB layouts from the XKB rules file
Instead of having just a handful of harcoded ones. The IBus input
sources that we claim to support are still hardcoded for now.
2012-05-15 02:17:01 +02:00
Rui Matos
ad2a238420 keyboard: Add shortcuts to switch among input sources 2012-05-15 02:17:01 +02:00
Rui Matos
776cf56a7e region: Use a hand-crafted input sources list
Instead of asking IBus, we want to use an hand-crafted list of input
sources that we are sure that a) is intelligible for the user and b)
lists both an XKB layout and an IBus engine that work together.

For now we just hard-code this list but we might want to move it into
its own file and maybe even to some other module.

This also removes the dependency on IBus.
2012-05-15 02:17:01 +02:00
Rui Matos
ce92413af2 region: Fix a couple of memory leaks 2012-05-15 02:17:01 +02:00
Rui Matos
816a551cae region: Improved keynav and selection handling on the input chooser 2012-05-15 02:17:01 +02:00
Rui Matos
e21d9313ea region: Remove the input source switch keybindings handling for now
We want to do the keybinding capturing in gnome-shell so that it also
works in the Activities Overview. IBus wouldn't use our input source
settings anyway so remove this for now.
2012-05-15 02:17:01 +02:00
Rui Matos
1d6f62e026 region: Remove the last remnants of libgnomekbd
There's no need to be linking to libgnomekbd and libxklavier just to
show keyboard previews, we can just spawn gkbd-keyboard-display. This
isn't ideal but we can polish it better later on.
2012-05-15 02:17:01 +02:00
Matthias Clasen
2c09c8e0ff Group tool buttons
Also add an (unfunctional for now) 'Input Source Settings' button.
Unfortunately, the preferences-system-symbolic icon is broken,
so it comes out black.

http://mclasen.fedorapeople.org/blackeye.png
2012-05-15 02:17:01 +02:00
Matthias Clasen
5e7dc53d9b Region: Add a 'Shortcuts' link to the input sources tab
Now we just need to make the shortcuts page actually provide
previous/next input source shortcuts.
2012-05-15 02:17:01 +02:00
Matthias Clasen
3e7c33f2e1 Keyboard: Make it possible to jump to shortcuts tab
To make this work, we need to move the setting up of priv->builder
to the instance init, so that it is available when construct properties
are set; the other setup needs to remain in the constructor, since
it relies on construct properties.
2012-05-15 02:17:01 +02:00
Matthias Clasen
67302794ae Initial removal of the Layouts tab
Still to do: system-wide settings for input sources
2012-05-15 02:17:01 +02:00
Matthias Clasen
ff8d5e9660 Use ibus_init
This ensures that all required IBus types are registered, avoiding
problems with deserialization.
2012-05-15 02:17:00 +02:00
Matthias Clasen
38ea325a36 More complete IBus support
Things that work now:
- Adding and removing sources works
- Input soures can be rearranged
- Changes are written back to IBus configuration
- We show the actual shortcuts
- Keyboard layouts can be previewed
2012-05-15 02:17:00 +02:00
Matthias Clasen
d894c6d3dd Some initial ibus code
Populate the list of active input sources, and wire up
some of the buttons.
2012-05-15 02:17:00 +02:00
Matthias Clasen
2b953a694c Add an initial input sources tab
This is just the scaffolding according to
https://live.gnome.org/Design/SystemSettings/RegionAndLanguage
No code behind it yet, and the XKB tab has not been removed yet.
2012-05-15 02:17:00 +02:00
21 changed files with 1885 additions and 2496 deletions

View File

@@ -112,9 +112,9 @@ PKG_CHECK_MODULES(POWER_PANEL, $COMMON_MODULES upower-glib >= 0.9.1
PKG_CHECK_MODULES(COLOR_PANEL, $COMMON_MODULES colord >= 0.1.8)
PKG_CHECK_MODULES(PRINTERS_PANEL, $COMMON_MODULES
polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION)
PKG_CHECK_MODULES(REGION_PANEL, $COMMON_MODULES libgnomekbd >= 2.91.91
PKG_CHECK_MODULES(REGION_PANEL, $COMMON_MODULES
polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION
libxklavier >= 5.1 libgnomekbdui >= 2.91.91)
xkbfile)
PKG_CHECK_MODULES(SCREEN_PANEL, $COMMON_MODULES)
PKG_CHECK_MODULES(SOUND_PANEL, $COMMON_MODULES libxml-2.0
libcanberra-gtk3 >= $CANBERRA_REQUIRED_VERSION
@@ -135,6 +135,13 @@ PKG_CHECK_MODULES(WACOM_PANEL, $COMMON_MODULES
GDESKTOP_PREFIX=`$PKG_CONFIG --variable prefix gsettings-desktop-schemas`
AC_SUBST(GDESKTOP_PREFIX)
AC_ARG_WITH(xkb-config-root,
AS_HELP_STRING([--with-xkb-config-root=<paths>],
[Set default XKB config root (default: ${datadir}/X11/xkb)]),
[XKBCONFIGROOT="$withval"],
[XKBCONFIGROOT=${datadir}/X11/xkb])
AC_SUBST([XKBCONFIGROOT])
# Check for NetworkManager ~0.9
PKG_CHECK_MODULES(NETWORK_MANAGER, NetworkManager >= $NETWORK_MANAGER_REQUIRED_VERSION
libnm-glib >= $NETWORK_MANAGER_REQUIRED_VERSION

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
<KeyListEntries group="system"
schema="org.gnome.desktop.input-sources.keybindings"
_name="Input Sources">
<KeyListEntry name="switch-previous"
_description="Switch to previous source"/>
<KeyListEntry name="switch-next"
_description="Switch to next source"/>
</KeyListEntries>

View File

@@ -33,7 +33,13 @@ desktop_DATA = $(Desktop_in_files:.desktop.in=.desktop)
@INTLTOOL_XML_NOMERGE_RULE@
xmldir = $(pkgdatadir)/keybindings
xml_in_files = 00-multimedia.xml.in 01-launchers.xml.in 01-screenshot.xml.in 01-system.xml.in 50-accessibility.xml.in
xml_in_files = \
00-multimedia.xml.in \
01-input-sources.xml.in \
01-launchers.xml.in \
01-screenshot.xml.in \
01-system.xml.in \
50-accessibility.xml.in
xml_DATA = $(xml_in_files:.xml.in=.xml)
pkgconfigdir = $(datadir)/pkgconfig

View File

@@ -47,19 +47,85 @@ cc_keyboard_panel_get_property (GObject *object,
}
}
enum {
PROP_0,
PROP_ARGV
};
enum {
TYPING_PAGE,
SHORTCUTS_PAGE
};
static void
cc_keyboard_panel_set_page (CcKeyboardPanel *panel,
const gchar *page)
{
GtkWidget *notebook;
gint page_num;
if (g_strcmp0 (page, "typing") == 0)
page_num = TYPING_PAGE;
else
page_num = SHORTCUTS_PAGE;
notebook = GTK_WIDGET (gtk_builder_get_object (panel->priv->builder, "keyboard_notebook"));
gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), page_num);
}
static void
cc_keyboard_panel_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
CcKeyboardPanel *panel = CC_KEYBOARD_PANEL (object);
switch (property_id)
{
case PROP_ARGV: {
gchar **args;
args = g_value_get_boxed (value);
if (args && args[0]) {
cc_keyboard_panel_set_page (panel, args[0]);
}
break;
}
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
static GObject *
cc_keyboard_panel_constructor (GType gtype,
guint n_properties,
GObjectConstructParam *properties)
{
GObject *obj;
CcKeyboardPanel *self;
CcKeyboardPanelPrivate *priv;
GtkWidget *widget;
obj = G_OBJECT_CLASS (cc_keyboard_panel_parent_class)->constructor (gtype, n_properties, properties);
self = CC_KEYBOARD_PANEL (obj);
priv = self->priv;
keyboard_general_init (CC_PANEL (self), priv->builder);
keyboard_shortcuts_init (CC_PANEL (self), priv->builder);
widget = (GtkWidget *) gtk_builder_get_object (priv->builder,
"keyboard_notebook");
gtk_widget_reparent (widget, (GtkWidget *) self);
return obj;
}
static void
cc_keyboard_panel_dispose (GObject *object)
{
@@ -72,49 +138,14 @@ cc_keyboard_panel_dispose (GObject *object)
static void
cc_keyboard_panel_finalize (GObject *object)
{
CcKeyboardPanel *panel = CC_KEYBOARD_PANEL (object);
if (panel->priv->builder)
g_object_unref (panel->priv->builder);
G_OBJECT_CLASS (cc_keyboard_panel_parent_class)->finalize (object);
}
static GObject *
cc_keyboard_panel_constructor (GType gtype,
guint n_properties,
GObjectConstructParam *properties)
{
GObject *obj;
CcKeyboardPanel *self;
CcKeyboardPanelPrivate *priv;
GError *error = NULL;
GtkWidget *widget;
const gchar *uifile = GNOMECC_UI_DIR "/gnome-keyboard-panel.ui";
obj = G_OBJECT_CLASS (cc_keyboard_panel_parent_class)->constructor (gtype, n_properties, properties);
self = CC_KEYBOARD_PANEL (obj);
priv = self->priv = KEYBOARD_PANEL_PRIVATE (self);
priv->builder = gtk_builder_new ();
if (gtk_builder_add_from_file (priv->builder, uifile, &error) == 0)
{
g_warning ("Could not load UI: %s", error->message);
g_clear_error (&error);
g_object_unref (priv->builder);
priv->builder = NULL;
return obj;
}
keyboard_general_init (CC_PANEL (self), priv->builder);
keyboard_shortcuts_init (CC_PANEL (self), priv->builder);
widget = (GtkWidget *) gtk_builder_get_object (priv->builder,
"keyboard_notebook");
gtk_widget_reparent (widget, (GtkWidget *) self);
return obj;
}
static void
cc_keyboard_panel_class_init (CcKeyboardPanelClass *klass)
{
@@ -127,6 +158,8 @@ cc_keyboard_panel_class_init (CcKeyboardPanelClass *klass)
object_class->set_property = cc_keyboard_panel_set_property;
object_class->dispose = cc_keyboard_panel_dispose;
object_class->finalize = cc_keyboard_panel_finalize;
g_object_class_override_property (object_class, PROP_ARGV, "argv");
}
static void
@@ -137,6 +170,21 @@ cc_keyboard_panel_class_finalize (CcKeyboardPanelClass *klass)
static void
cc_keyboard_panel_init (CcKeyboardPanel *self)
{
const gchar *uifile = GNOMECC_UI_DIR "/gnome-keyboard-panel.ui";
CcKeyboardPanelPrivate *priv;
GError *error = NULL;
priv = self->priv = KEYBOARD_PANEL_PRIVATE (self);
priv->builder = gtk_builder_new ();
if (gtk_builder_add_from_file (priv->builder, uifile, &error) == 0)
{
g_warning ("Could not load UI: %s", error->message);
g_clear_error (&error);
g_object_unref (priv->builder);
priv->builder = NULL;
}
}
void

View File

@@ -1,12 +1,15 @@
# This is used in PANEL_CFLAGS
cappletname = region
XKBCONFIGROOT=@XKBCONFIGROOT@
INCLUDES = \
$(PANEL_CFLAGS) \
$(REGION_PANEL_CFLAGS) \
-DGNOMELOCALEDIR="\"$(datadir)/locale\"" \
-DGNOMECC_DATA_DIR="\"$(pkgdatadir)\"" \
-DGNOMECC_UI_DIR="\"$(uidir)\"" \
-DDFLT_XKB_CONFIG_ROOT=\"$(XKBCONFIGROOT)\" \
-I$(srcdir)/../common/ \
$(NULL)
@@ -23,12 +26,10 @@ libregion_la_SOURCES = \
gnome-region-panel-lang.h \
gnome-region-panel-system.c \
gnome-region-panel-system.h \
gnome-region-panel-xkb.c \
gnome-region-panel-xkblt.c \
gnome-region-panel-xkbltadd.c \
gnome-region-panel-xkbot.c \
gnome-region-panel-xkbpv.c \
gnome-region-panel-xkb.h
gnome-region-panel-input.c \
gnome-region-panel-input.h \
xkb-rules-db.c \
xkb-rules-db.h
libregion_la_LIBADD = $(PANEL_LIBS) $(REGION_PANEL_LIBS) $(builddir)/../common/liblanguage.la
@@ -39,8 +40,7 @@ libregion_la_LDFLAGS = $(PANEL_LDFLAGS)
uidir = $(pkgdatadir)/ui
ui_DATA = \
gnome-region-panel.ui \
gnome-region-panel-layout-chooser.ui \
gnome-region-panel-options-dialog.ui
gnome-region-panel-input-chooser.ui
desktopdir = $(datadir)/applications
Desktop_in_files = gnome-region-panel.desktop.in

View File

@@ -22,7 +22,7 @@
#include "cc-region-panel.h"
#include <gtk/gtk.h>
#include "gnome-region-panel-xkb.h"
#include "gnome-region-panel-input.h"
#include "gnome-region-panel-lang.h"
#include "gnome-region-panel-formats.h"
#include "gnome-region-panel-system.h"
@@ -151,7 +151,7 @@ cc_region_panel_init (CcRegionPanel * self)
gtk_widget_reparent (prefs_widget, GTK_WIDGET (self));
setup_xkb_tabs (priv->builder);
setup_input_tabs (priv->builder, self);
setup_language (priv->builder);
setup_formats (priv->builder);
setup_system (priv->builder);

View File

@@ -1,28 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.16"/>
<object class="GtkListStore" id="layout_list_model">
<object class="GtkListStore" id="input_source_model">
<columns>
<!-- column-name sort_order -->
<column type="gchararray"/>
<!-- column-name visible -->
<column type="gchararray"/>
<!-- column-name xkb_id -->
<column type="gchararray"/>
<!-- column-name country_desc -->
<column type="gchararray"/>
<!-- column-name language_desc -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkTreeModelFilter" id="filtered_layout_list_model">
<property name="child_model">layout_list_model</property>
<object class="GtkTreeModelFilter" id="filtered_input_source_model">
<property name="child_model">input_source_model</property>
</object>
<object class="GtkDialog" id="xkb_layout_chooser">
<object class="GtkDialog" id="input_source_chooser">
<property name="visible">False</property>
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Choose a Layout</property>
<property name="title" translatable="yes">Choose an input source</property>
<property name="modal">True</property>
<property name="window_position">center-on-parent</property>
<property name="type_hint">dialog</property>
@@ -38,22 +31,7 @@
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="btnPreview">
<property name="label" translatable="yes">Preview</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
<property name="secondary">True</property>
</packing>
</child>
<child>
<object class="GtkButton" id="btnCancel">
<object class="GtkButton" id="cancel-button">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
@@ -70,7 +48,7 @@
</packing>
</child>
<child>
<object class="GtkButton" id="btnOk">
<object class="GtkButton" id="ok-button">
<property name="label">gtk-add</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
@@ -121,15 +99,12 @@
<property name="min_content_width">450</property>
<property name="min_content_height">250</property>
<child>
<object class="GtkTreeView" id="xkb_filtered_layouts_list">
<object class="GtkTreeView" id="filtered_input_source_list">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">filtered_layout_list_model</property>
<property name="model">filtered_input_source_model</property>
<property name="headers_visible">False</property>
<property name="search_column">0</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection1"/>
</child>
</object>
</child>
</object>
@@ -147,7 +122,7 @@
</packing>
</child>
<child>
<object class="GtkEntry" id="xkb_layout_filter">
<object class="GtkEntry" id="input_source_filter">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
@@ -172,9 +147,8 @@
</object>
</child>
<action-widgets>
<action-widget response="1">btnPreview</action-widget>
<action-widget response="-5">btnOk</action-widget>
<action-widget response="-6">btnCancel</action-widget>
<action-widget response="-5">ok-button</action-widget>
<action-widget response="-6">cancel-button</action-widget>
</action-widgets>
</object>
</interface>

View File

@@ -0,0 +1,764 @@
/*
* Copyright (C) 2011 Red Hat, Inc.
*
* Written by: Matthias Clasen <mclasen@redhat.com>
*
* 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.
*/
#include <config.h>
#include <string.h>
#include <glib.h>
#include <glib/gi18n.h>
#include "xkb-rules-db.h"
#include "gnome-region-panel-input.h"
#define WID(s) GTK_WIDGET(gtk_builder_get_object (builder, s))
/* TODO
*
* - There is a large overlap between xkb and m17n:kbd -
* we need to somehow decide and filter out
* cases to consider:
* Amharic: xkb:layout:et vs m17n:am:sera - probably keep both
* Arabic: xkb:layout:ara vs m17n:ar:kbd - probably not
*
* - Straighten out the naming. It needs to be either
* "Language" or "Language (Method)" when the same
* language occurs more than once. Need to decide what
* to do about xkb and m17n
*
* - Implement system-wide settings
*
* - Debug hotkeys, they don't act right
*
* - Allow changing shortcuts ?
*/
typedef struct _InputSource InputSource;
struct _InputSource
{
const gchar *name;
const gchar *short_name;
const gchar *xkb_layout;
const gchar *xkb_variant;
const gchar *ibus_engine;
};
static const InputSource ibus_sources[] = {
{ "Chinese (Bopomofo)", "", "us", "", "bopomofo" },
{ "Chinese (Pinyin)", "", "us", "", "pinyin" },
{ "Japanese (Anthy)", "", "jp", "", "anthy" },
{ "Korean (Hangul)", "", "us", "", "hangul" },
};
#define GNOME_DESKTOP_INPUT_SOURCES_DIR "org.gnome.desktop.input-sources"
#define KEY_CURRENT_IS "current"
#define KEY_INPUT_SOURCES "sources"
static GSettings *is_settings = NULL;
static GtkWidget *input_chooser_new (GtkBuilder *builder);
static gboolean input_chooser_get_selected (GtkWidget *chooser,
GtkTreeModel **model,
GtkTreeIter *iter);
static gboolean
add_source_to_table (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
gpointer data)
{
GHashTable *hash = data;
gchar *name;
gtk_tree_model_get (model, iter, 0, &name, -1);
g_hash_table_add (hash, name);
return FALSE;
}
static void
populate_model (GtkListStore *store,
GtkListStore *active_sources)
{
GHashTable *active_sources_table;
GtkTreeIter iter;
GSList *all_sources, *tmp;
gint i;
active_sources_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
gtk_tree_model_foreach (GTK_TREE_MODEL (active_sources),
add_source_to_table,
active_sources_table);
all_sources = xkb_rules_db_get_all_layout_names ();
for (i = 0; i < G_N_ELEMENTS (ibus_sources); ++i)
all_sources = g_slist_prepend (all_sources, (gpointer)ibus_sources[i].name);
for (tmp = all_sources; tmp; tmp = tmp->next)
{
if (g_hash_table_contains (active_sources_table, tmp->data))
continue;
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
0, tmp->data,
-1);
}
g_slist_free (all_sources);
g_hash_table_destroy (active_sources_table);
}
static void
populate_with_active_sources (GtkListStore *store)
{
GVariant *sources;
GVariantIter iter;
const gchar *name;
GtkTreeIter tree_iter;
sources = g_settings_get_value (is_settings, KEY_INPUT_SOURCES);
g_variant_iter_init (&iter, sources);
while (g_variant_iter_next (&iter, "(&s&s&s&s&s)", &name, NULL, NULL, NULL, NULL))
{
gtk_list_store_append (store, &tree_iter);
gtk_list_store_set (store, &tree_iter,
0, name,
-1);
}
g_variant_unref (sources);
}
static void
update_configuration (GtkTreeModel *model)
{
GtkTreeIter iter;
gchar *name;
const gchar *short_name = "";
const gchar *xkb_layout = "";
const gchar *xkb_variant = "";
const gchar *ibus_engine = "";
GVariantBuilder builder;
gint i;
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sssss)"));
gtk_tree_model_get_iter_first (model, &iter);
do {
gtk_tree_model_get (model, &iter,
0, &name,
-1);
if (xkb_rules_db_get_layout_info (name, &short_name, &xkb_layout, &xkb_variant))
ibus_engine = "";
else
for (i = 0; i < G_N_ELEMENTS (ibus_sources); ++i)
if (strcmp (name, ibus_sources[i].name) == 0)
{
short_name = ibus_sources[i].short_name;
xkb_layout = ibus_sources[i].xkb_layout;
xkb_variant = ibus_sources[i].xkb_variant;
ibus_engine = ibus_sources[i].ibus_engine;
break;
}
g_variant_builder_add (&builder, "(sssss)", name, short_name, xkb_layout, xkb_variant, ibus_engine);
g_free (name);
} while (gtk_tree_model_iter_next (model, &iter));
g_settings_set_value (is_settings, KEY_INPUT_SOURCES, g_variant_builder_end (&builder));
}
/* List handling {{{1 */
static gboolean
get_selected_iter (GtkBuilder *builder,
GtkTreeModel **model,
GtkTreeIter *iter)
{
GtkTreeSelection *selection;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("active_input_sources")));
return gtk_tree_selection_get_selected (selection, model, iter);
}
static gint
find_selected_layout_idx (GtkBuilder *builder)
{
GtkTreeIter iter;
GtkTreeModel *model;
GtkTreePath *path;
gint idx;
if (!get_selected_iter (builder, &model, &iter))
return -1;
path = gtk_tree_model_get_path (model, &iter);
if (path == NULL)
return -1;
idx = gtk_tree_path_get_indices (path)[0];
gtk_tree_path_free (path);
return idx;
}
static void
update_button_sensitivity (GtkBuilder *builder)
{
GtkWidget *remove_button;
GtkWidget *up_button;
GtkWidget *down_button;
GtkWidget *show_button;
GtkTreeView *tv;
gint n_active;
gint index;
remove_button = WID("input_source_remove");
show_button = WID("input_source_show");
up_button = WID("input_source_move_up");
down_button = WID("input_source_move_down");
tv = GTK_TREE_VIEW (WID ("active_input_sources"));
n_active = gtk_tree_model_iter_n_children (gtk_tree_view_get_model (tv), NULL);
index = find_selected_layout_idx (builder);
gtk_widget_set_sensitive (remove_button, index >= 0 && n_active > 1);
gtk_widget_set_sensitive (show_button, index >= 0);
gtk_widget_set_sensitive (up_button, index > 0);
gtk_widget_set_sensitive (down_button, index >= 0 && index < n_active - 1);
}
static void
set_selected_path (GtkBuilder *builder,
GtkTreePath *path)
{
GtkTreeSelection *selection;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("active_input_sources")));
gtk_tree_selection_select_path (selection, path);
}
static void
chooser_response (GtkWidget *chooser, gint response_id, gpointer data)
{
GtkBuilder *builder = data;
if (response_id == GTK_RESPONSE_OK)
{
GtkTreeModel *model;
GtkTreeIter iter;
if (input_chooser_get_selected (chooser, &model, &iter))
{
GtkTreeView *my_tv;
GtkListStore *my_model;
GtkTreeIter my_iter;
gchar *name;
gtk_tree_model_get (model, &iter,
0, &name,
-1);
my_tv = GTK_TREE_VIEW (WID ("active_input_sources"));
my_model = GTK_LIST_STORE (gtk_tree_view_get_model (my_tv));
gtk_list_store_append (my_model, &my_iter);
gtk_list_store_set (my_model, &my_iter,
0, name,
-1);
g_free (name);
gtk_tree_selection_select_iter (gtk_tree_view_get_selection (my_tv), &my_iter);
update_button_sensitivity (builder);
update_configuration (GTK_TREE_MODEL (my_model));
}
else
{
g_debug ("nothing selected, nothing added");
}
}
gtk_widget_destroy (GTK_WIDGET (chooser));
}
static void
add_input (GtkButton *button, gpointer data)
{
GtkBuilder *builder = data;
GtkWidget *chooser;
g_debug ("add an input source");
chooser = input_chooser_new (builder);
g_signal_connect (chooser, "response",
G_CALLBACK (chooser_response), builder);
}
static void
remove_selected_input (GtkButton *button, gpointer data)
{
GtkBuilder *builder = data;
GtkTreeModel *model;
GtkTreeIter iter;
GtkTreePath *path;
g_debug ("remove selected input source");
if (get_selected_iter (builder, &model, &iter) == FALSE)
return;
path = gtk_tree_model_get_path (model, &iter);
gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
if (!gtk_tree_model_get_iter (model, &iter, path))
gtk_tree_path_prev (path);
set_selected_path (builder, path);
gtk_tree_path_free (path);
update_button_sensitivity (builder);
update_configuration (model);
}
static void
move_selected_input_up (GtkButton *button, gpointer data)
{
GtkBuilder *builder = data;
GtkTreeModel *model;
GtkTreeIter iter, prev;
GtkTreePath *path;
g_debug ("move selected input source up");
if (!get_selected_iter (builder, &model, &iter))
return;
prev = iter;
if (!gtk_tree_model_iter_previous (model, &prev))
return;
path = gtk_tree_model_get_path (model, &prev);
gtk_list_store_swap (GTK_LIST_STORE (model), &iter, &prev);
set_selected_path (builder, path);
gtk_tree_path_free (path);
update_button_sensitivity (builder);
update_configuration (model);
}
static void
move_selected_input_down (GtkButton *button, gpointer data)
{
GtkBuilder *builder = data;
GtkTreeModel *model;
GtkTreeIter iter, next;
GtkTreePath *path;
g_debug ("move selected input source down");
if (!get_selected_iter (builder, &model, &iter))
return;
next = iter;
if (!gtk_tree_model_iter_next (model, &next))
return;
path = gtk_tree_model_get_path (model, &next);
gtk_list_store_swap (GTK_LIST_STORE (model), &iter, &next);
set_selected_path (builder, path);
gtk_tree_path_free (path);
update_button_sensitivity (builder);
update_configuration (model);
}
static void
show_selected_layout (GtkButton *button, gpointer data)
{
GtkBuilder *builder = data;
GtkTreeModel *model;
GtkTreeIter iter;
gchar *name;
gchar *kbd_viewer_args;
const gchar *xkb_layout = "";
const gchar *xkb_variant = "";
gint i;
g_debug ("show selected layout");
if (!get_selected_iter (builder, &model, &iter))
return;
gtk_tree_model_get (model, &iter,
0, &name,
-1);
if (!xkb_rules_db_get_layout_info (name, NULL, &xkb_layout, &xkb_variant))
for (i = 0; i < G_N_ELEMENTS (ibus_sources); ++i)
if (strcmp (name, ibus_sources[i].name) == 0)
{
xkb_layout = ibus_sources[i].xkb_layout;
xkb_variant = ibus_sources[i].xkb_variant;
break;
}
if (xkb_variant[0])
kbd_viewer_args = g_strdup_printf ("gkbd-keyboard-display -l \"%s\t%s\"",
xkb_layout, xkb_variant);
else
kbd_viewer_args = g_strdup_printf ("gkbd-keyboard-display -l %s",
xkb_layout);
g_spawn_command_line_async (kbd_viewer_args, NULL);
g_free (kbd_viewer_args);
g_free (name);
}
/* Main setup {{{1 */
static gboolean
go_to_shortcuts (GtkLinkButton *button,
CcRegionPanel *panel)
{
CcShell *shell;
const gchar *argv[] = { "shortcuts", NULL };
GError *error = NULL;
shell = cc_panel_get_shell (CC_PANEL (panel));
if (!cc_shell_set_active_panel_from_id (shell, "keyboard", argv, &error))
{
g_warning ("Failed to activate Keyboard panel: %s", error->message);
g_error_free (error);
}
return TRUE;
}
void
setup_input_tabs (GtkBuilder *builder,
CcRegionPanel *panel)
{
GtkWidget *treeview;
GtkTreeViewColumn *column;
GtkCellRenderer *cell;
GtkListStore *store;
GtkTreeSelection *selection;
gchar *previous = NULL;
gchar *next = NULL;
GtkWidget *label;
is_settings = g_settings_new (GNOME_DESKTOP_INPUT_SOURCES_DIR);
/* set up the list of active inputs */
treeview = WID("active_input_sources");
column = gtk_tree_view_column_new ();
cell = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, cell, TRUE);
gtk_tree_view_column_add_attribute (column, cell, "text", 0);
gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
store = gtk_list_store_new (1, G_TYPE_STRING);
populate_with_active_sources (store);
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
g_signal_connect_swapped (selection, "changed",
G_CALLBACK (update_button_sensitivity), builder);
gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store));
/* set up the buttons */
g_signal_connect (WID("input_source_add"), "clicked",
G_CALLBACK (add_input), builder);
g_signal_connect (WID("input_source_remove"), "clicked",
G_CALLBACK (remove_selected_input), builder);
g_signal_connect (WID("input_source_move_up"), "clicked",
G_CALLBACK (move_selected_input_up), builder);
g_signal_connect (WID("input_source_move_down"), "clicked",
G_CALLBACK (move_selected_input_down), builder);
g_signal_connect (WID("input_source_show"), "clicked",
G_CALLBACK (show_selected_layout), builder);
/* use an em dash is no shortcut */
if (!previous)
previous = g_strdup ("\342\200\224");
if (!next)
next = g_strdup ("\342\200\224");
label = WID("prev-source-shortcut-label");
gtk_label_set_label (GTK_LABEL (label), previous);
label = WID("next-source-shortcut-label");
gtk_label_set_label (GTK_LABEL (label), next);
g_free (previous);
g_free (next);
g_signal_connect (WID("jump-to-shortcuts"), "activate-link",
G_CALLBACK (go_to_shortcuts), panel);
}
/* Chooser dialog {{{1 */
static void
filter_clear (GtkEntry *entry,
GtkEntryIconPosition icon_pos,
GdkEvent *event,
gpointer user_data)
{
gtk_entry_set_text (entry, "");
}
static gchar **search_pattern_list;
static void
filter_changed (GtkBuilder *builder)
{
GtkTreeModelFilter *filtered_model;
GtkTreeView *tree_view;
GtkTreeSelection *selection;
GtkTreeIter selected_iter;
GtkWidget *filter_entry;
const gchar *pattern;
gchar *upattern;
filter_entry = WID ("input_source_filter");
pattern = gtk_entry_get_text (GTK_ENTRY (filter_entry));
upattern = g_utf8_strup (pattern, -1);
if (!g_strcmp0 (pattern, ""))
g_object_set (G_OBJECT (filter_entry),
"secondary-icon-name", "edit-find-symbolic",
"secondary-icon-activatable", FALSE,
"secondary-icon-sensitive", FALSE,
NULL);
else
g_object_set (G_OBJECT (filter_entry),
"secondary-icon-name", "edit-clear-symbolic",
"secondary-icon-activatable", TRUE,
"secondary-icon-sensitive", TRUE,
NULL);
if (search_pattern_list != NULL)
g_strfreev (search_pattern_list);
search_pattern_list = g_strsplit (upattern, " ", -1);
g_free (upattern);
filtered_model =
GTK_TREE_MODEL_FILTER (gtk_builder_get_object (builder, "filtered_input_source_model"));
gtk_tree_model_filter_refilter (filtered_model);
tree_view = GTK_TREE_VIEW (WID ("filtered_input_source_list"));
selection = gtk_tree_view_get_selection (tree_view);
if (gtk_tree_selection_get_selected (selection, NULL, &selected_iter))
{
GtkTreePath *path = gtk_tree_model_get_path (GTK_TREE_MODEL (filtered_model),
&selected_iter);
gtk_tree_view_scroll_to_cell (tree_view, path, NULL, TRUE, 0.5, 0.5);
gtk_tree_path_free (path);
}
else
{
GtkTreeIter iter;
if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (filtered_model), &iter))
gtk_tree_selection_select_iter (selection, &iter);
}
}
static void
selection_changed (GtkTreeSelection *selection,
GtkBuilder *builder)
{
gtk_widget_set_sensitive (WID ("ok-button"),
gtk_tree_selection_get_selected (selection, NULL, NULL));
}
static void
row_activated (GtkTreeView *tree_view,
GtkTreePath *path,
GtkTreeViewColumn *column,
GtkBuilder *builder)
{
GtkWidget *add_button;
GtkWidget *dialog;
add_button = WID ("ok-button");
dialog = WID ("input_source_chooser");
if (gtk_widget_is_sensitive (add_button))
gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
}
static void
entry_activated (GtkBuilder *builder,
gpointer data)
{
row_activated (NULL, NULL, NULL, builder);
}
static gboolean
filter_func (GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{
gchar *name = NULL;
gchar **pattern;
gboolean rv = TRUE;
if (search_pattern_list == NULL || search_pattern_list[0] == NULL)
return TRUE;
gtk_tree_model_get (model, iter,
0, &name,
-1);
pattern = search_pattern_list;
do {
gboolean is_pattern_found = FALSE;
gchar *udesc = g_utf8_strup (name, -1);
if (udesc != NULL && g_strstr_len (udesc, -1, *pattern))
{
is_pattern_found = TRUE;
}
g_free (udesc);
if (!is_pattern_found)
{
rv = FALSE;
break;
}
} while (*++pattern != NULL);
g_free (name);
return rv;
}
static GtkWidget *
input_chooser_new (GtkBuilder *main_builder)
{
GtkBuilder *builder;
GtkWidget *chooser;
GtkWidget *filtered_list;
GtkWidget *filter_entry;
GtkTreeViewColumn *visible_column;
GtkTreeSelection *selection;
GtkListStore *model;
GtkTreeModelFilter *filtered_model;
GtkTreeIter iter;
builder = gtk_builder_new ();
gtk_builder_add_from_file (builder,
GNOMECC_UI_DIR "/gnome-region-panel-input-chooser.ui",
NULL);
chooser = WID ("input_source_chooser");
g_object_set_data_full (G_OBJECT (chooser), "builder", builder, g_object_unref);
filtered_list = WID ("filtered_input_source_list");
filter_entry = WID ("input_source_filter");
g_object_set_data (G_OBJECT (chooser),
"filtered_input_source_list", filtered_list);
visible_column =
gtk_tree_view_column_new_with_attributes ("Input Sources",
gtk_cell_renderer_text_new (),
"text", 0,
NULL);
gtk_window_set_transient_for (GTK_WINDOW (chooser),
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (gtk_builder_get_object (main_builder, "region_notebook")))));
gtk_tree_view_append_column (GTK_TREE_VIEW (filtered_list),
visible_column);
/* We handle searching ourselves, thank you. */
gtk_tree_view_set_enable_search (GTK_TREE_VIEW (filtered_list), FALSE);
gtk_tree_view_set_search_column (GTK_TREE_VIEW (filtered_list), -1);
g_signal_connect_swapped (G_OBJECT (filter_entry), "activate",
G_CALLBACK (entry_activated), builder);
g_signal_connect_swapped (G_OBJECT (filter_entry), "notify::text",
G_CALLBACK (filter_changed), builder);
g_signal_connect (G_OBJECT (filter_entry), "icon-release",
G_CALLBACK (filter_clear), NULL);
filtered_model =
GTK_TREE_MODEL_FILTER (gtk_builder_get_object (builder, "filtered_input_source_model"));
model =
GTK_LIST_STORE (gtk_builder_get_object (builder, "input_source_model"));
populate_model (model,
GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (gtk_builder_get_object (main_builder,
"active_input_sources")))));
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
0, GTK_SORT_ASCENDING);
gtk_tree_model_filter_set_visible_func (filtered_model,
filter_func,
NULL, NULL);
selection =
gtk_tree_view_get_selection (GTK_TREE_VIEW (filtered_list));
g_signal_connect (G_OBJECT (selection), "changed",
G_CALLBACK (selection_changed), builder);
if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (filtered_model), &iter))
gtk_tree_selection_select_iter (selection, &iter);
g_signal_connect (G_OBJECT (filtered_list), "row-activated",
G_CALLBACK (row_activated), builder);
gtk_widget_grab_focus (filter_entry);
gtk_widget_show (chooser);
return chooser;
}
static gboolean
input_chooser_get_selected (GtkWidget *dialog,
GtkTreeModel **model,
GtkTreeIter *iter)
{
GtkWidget *tv;
GtkTreeSelection *selection;
tv = g_object_get_data (G_OBJECT (dialog), "filtered_input_source_list");
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv));
return gtk_tree_selection_get_selected (selection, model, iter);
}
/* Epilogue {{{1 */
/* vim: set foldmethod=marker: */

View File

@@ -0,0 +1,36 @@
/* gnome-region-panel-input.h
* Copyright (C) 2011 Red Hat, Inc.
*
* Written by Matthias Clasen
*
* 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.
*/
#ifndef __GNOME_KEYBOARD_PROPERTY_INPUT_H
#define __GNOME_KEYBOARD_PROPERTY_INPUT_H
#include <gtk/gtk.h>
#include "cc-region-panel.h"
G_BEGIN_DECLS
void setup_input_tabs (GtkBuilder *builder,
CcRegionPanel *self);
G_END_DECLS
#endif /* __GNOME_KEYBOARD_PROPERTY_INPUT_H */

View File

@@ -1,79 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.16"/>
<object class="GtkDialog" id="xkb_options_dialog">
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">Keyboard Layout Options</property>
<property name="window_position">center-on-parent</property>
<property name="default_width">550</property>
<property name="default_height">400</property>
<property name="type_hint">dialog</property>
<child internal-child="vbox">
<object class="GtkBox" id="dialog_vbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child>
<object class="GtkScrolledWindow" id="options_scroll">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="border_width">5</property>
<property name="shadow_type">out</property>
<child>
<object class="GtkViewport" id="viewport1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkVBox" id="options_vbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog-action_area4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkButton" id="button2">
<property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-7">button2</action-widget>
</action-widgets>
</object>
</interface>

View File

@@ -29,13 +29,13 @@
#include <glib/gi18n.h>
#include <libgnomekbd/gkbd-keyboard-config.h>
#include "cc-common-language.h"
#include "gdm-languages.h"
#include "gnome-region-panel-system.h"
#include "gnome-region-panel-xkb.h"
static GSettings *locale_settings, *xkb_settings;
#define WID(s) GTK_WIDGET(gtk_builder_get_object (dialog, s))
static GSettings *locale_settings;
static GDBusProxy *localed_proxy;
static GPermission *localed_permission;
@@ -130,64 +130,6 @@ system_update_language (GtkBuilder *dialog, const gchar *language)
update_copy_button (dialog);
}
static void
xkb_settings_changed (GSettings *settings,
const gchar *key,
GtkBuilder *dialog)
{
guint i;
GString *disp, *list, *variants;
GtkWidget *label;
gchar **layouts;
layouts = g_settings_get_strv (settings, "layouts");
if (layouts == NULL)
return;
label = WID ("user_input_source");
disp = g_string_new ("");
list = g_string_new ("");
variants = g_string_new ("");
for (i = 0; layouts[i]; i++) {
gchar *utf_visible;
char **split;
gchar *layout, *variant;
utf_visible = xkb_layout_description_utf8 (layouts[i]);
if (disp->str[0] != '\0')
g_string_append (disp, ", ");
g_string_append (disp, utf_visible ? utf_visible : layouts[i]);
g_free (utf_visible);
split = g_strsplit_set (layouts[i], " \t", 2);
if (split == NULL || split[0] == NULL)
continue;
layout = split[0];
variant = split[1];
if (list->str[0] != '\0')
g_string_append (list, ",");
g_string_append (list, layout);
if (variants->str[0] != '\0')
g_string_append (variants, ",");
g_string_append (variants, variant ? variant : "");
g_strfreev (split);
}
g_strfreev (layouts);
g_object_set_data_full (G_OBJECT (label), "input_source", g_string_free (list, FALSE), g_free);
g_object_set_data_full (G_OBJECT (label), "input_variants", g_string_free (variants, FALSE), g_free);
gtk_label_set_text (GTK_LABEL (label), disp->str);
g_string_free (disp, TRUE);
update_copy_button (dialog);
}
static void
update_property (GDBusProxy *proxy,
const char *property)
@@ -287,6 +229,7 @@ on_localed_properties_changed (GDBusProxy *proxy,
g_variant_unref (v);
}
#if 0
label = WID ("system_input_source");
v = g_dbus_proxy_get_cached_property (proxy, "X11Layout");
if (v) {
@@ -313,6 +256,7 @@ on_localed_properties_changed (GDBusProxy *proxy,
g_string_free (disp, TRUE);
g_variant_unref (v);
#endif
update_copy_button (dialog);
}
@@ -468,11 +412,6 @@ setup_system (GtkBuilder *dialog)
G_CALLBACK (locale_settings_changed), dialog);
g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify) g_object_unref, locale_settings);
xkb_settings = g_settings_new (GKBD_KEYBOARD_SCHEMA);
g_signal_connect (xkb_settings, "changed::layouts",
G_CALLBACK (xkb_settings_changed), dialog);
g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify) g_object_unref, xkb_settings);
/* Display user settings */
language = cc_common_language_get_current_language ();
system_update_language (dialog, language);
@@ -480,8 +419,6 @@ setup_system (GtkBuilder *dialog)
locale_settings_changed (locale_settings, "region", dialog);
xkb_settings_changed (xkb_settings, "layouts", dialog);
bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
g_dbus_proxy_new (bus,
G_DBUS_PROXY_FLAGS_NONE,

View File

@@ -1,190 +0,0 @@
/* gnome-region-panel-xkb.c
* Copyright (C) 2003-2007 Sergey V. Udaltsov
*
* Written by: Sergey V. Udaltsov <svu@gnome.org>
*
* 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 <config.h>
#endif
#include <string.h>
#include <gdk/gdkx.h>
#include <glib/gi18n.h>
#include "gnome-region-panel-xkb.h"
#include <libgnomekbd/gkbd-desktop-config.h>
XklEngine *engine;
XklConfigRegistry *config_registry;
GkbdKeyboardConfig initial_config;
GkbdDesktopConfig desktop_config;
GSettings *xkb_keyboard_settings;
GSettings *xkb_desktop_settings;
char *
xci_desc_to_utf8 (const XklConfigItem * ci)
{
gchar *dd = g_strdup (ci->description);
gchar *sd = g_strstrip (dd);
gchar *rv = g_strdup (sd[0] == 0 ? ci->name : sd);
g_free (dd);
return rv;
}
static void
cleanup_xkb_tabs (GtkBuilder * dialog,
GObject *where_the_object_wa)
{
gkbd_desktop_config_term (&desktop_config);
gkbd_keyboard_config_term (&initial_config);
g_object_unref (G_OBJECT (config_registry));
config_registry = NULL;
/* Don't unref it here, or we'll crash if open the panel again */
engine = NULL;
g_object_unref (G_OBJECT (xkb_keyboard_settings));
g_object_unref (G_OBJECT (xkb_desktop_settings));
xkb_keyboard_settings = NULL;
xkb_desktop_settings = NULL;
}
static void
reset_to_defaults (GtkWidget * button, GtkBuilder * dialog)
{
GkbdKeyboardConfig empty_kbd_config;
gkbd_keyboard_config_init (&empty_kbd_config, engine);
gkbd_keyboard_config_save (&empty_kbd_config);
gkbd_keyboard_config_term (&empty_kbd_config);
g_settings_reset (xkb_desktop_settings,
GKBD_DESKTOP_CONFIG_KEY_DEFAULT_GROUP);
/* all the rest is g-s-d's business */
}
static void
chk_new_windows_inherit_layout_toggled (GtkWidget *
chk_new_windows_inherit_layout,
GtkBuilder * dialog)
{
xkb_save_default_group (gtk_toggle_button_get_active
(GTK_TOGGLE_BUTTON
(chk_new_windows_inherit_layout)) ? -1 :
0);
}
void
setup_xkb_tabs (GtkBuilder * dialog)
{
GtkWidget *widget;
GtkStyleContext *context;
GtkWidget *chk_new_windows_inherit_layout;
chk_new_windows_inherit_layout = WID ("chk_new_windows_inherit_layout");
xkb_desktop_settings = g_settings_new (GKBD_DESKTOP_SCHEMA);
xkb_keyboard_settings = g_settings_new (GKBD_KEYBOARD_SCHEMA);
engine =
xkl_engine_get_instance (GDK_DISPLAY_XDISPLAY
(gdk_display_get_default ()));
config_registry = xkl_config_registry_get_instance (engine);
gkbd_desktop_config_init (&desktop_config, engine);
gkbd_desktop_config_load (&desktop_config);
xkl_config_registry_load (config_registry,
desktop_config.load_extra_items);
gkbd_keyboard_config_init (&initial_config, engine);
gkbd_keyboard_config_load_from_x_initial (&initial_config, NULL);
/* Set initial state */
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (WID ("chk_separate_group_per_window")),
g_settings_get_boolean (xkb_desktop_settings,
GKBD_DESKTOP_CONFIG_KEY_GROUP_PER_WINDOW));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (chk_new_windows_inherit_layout),
xkb_get_default_group () < 0);
g_settings_bind (xkb_desktop_settings,
GKBD_DESKTOP_CONFIG_KEY_GROUP_PER_WINDOW,
WID ("chk_separate_group_per_window"), "active",
G_SETTINGS_BIND_DEFAULT);
g_settings_bind (xkb_desktop_settings,
GKBD_DESKTOP_CONFIG_KEY_GROUP_PER_WINDOW,
WID ("chk_new_windows_inherit_layout"), "sensitive",
G_SETTINGS_BIND_DEFAULT);
g_settings_bind (xkb_desktop_settings,
GKBD_DESKTOP_CONFIG_KEY_GROUP_PER_WINDOW,
WID ("chk_new_windows_default_layout"), "sensitive",
G_SETTINGS_BIND_DEFAULT);
xkb_layouts_prepare_selected_tree (dialog);
xkb_layouts_fill_selected_tree (dialog);
xkb_layouts_register_buttons_handlers (dialog);
g_signal_connect (G_OBJECT (WID ("xkb_reset_to_defaults")),
"clicked", G_CALLBACK (reset_to_defaults),
dialog);
g_signal_connect (G_OBJECT (chk_new_windows_inherit_layout),
"toggled",
G_CALLBACK
(chk_new_windows_inherit_layout_toggled),
dialog);
g_signal_connect_swapped (G_OBJECT (WID ("xkb_layout_options")),
"clicked",
G_CALLBACK (xkb_options_popup_dialog),
dialog);
xkb_layouts_register_conf_listener (dialog);
xkb_options_register_conf_listener (dialog);
g_object_weak_ref (G_OBJECT (WID ("region_notebook")),
(GWeakNotify) cleanup_xkb_tabs, dialog);
enable_disable_restoring (dialog);
/* Setup junction between toolbar and treeview */
widget = WID ("xkb_layouts_swindow");
context = gtk_widget_get_style_context (widget);
gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
widget = WID ("layouts-toolbar");
context = gtk_widget_get_style_context (widget);
gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
}
void
enable_disable_restoring (GtkBuilder * dialog)
{
GkbdKeyboardConfig gswic;
gboolean enable;
gkbd_keyboard_config_init (&gswic, engine);
gkbd_keyboard_config_load (&gswic, NULL);
enable = !gkbd_keyboard_config_equals (&gswic, &initial_config);
gkbd_keyboard_config_term (&gswic);
gtk_widget_set_sensitive (WID ("xkb_reset_to_defaults"), enable);
}

View File

@@ -1,96 +0,0 @@
/* gnome-region-panel-xkb.h
* Copyright (C) 2003-2007 Sergey V Udaltsov
*
* Written by Sergey V. Udaltsov <svu@gnome.org>
*
* 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.
*/
#ifndef __GNOME_KEYBOARD_PROPERTY_XKB_H
#define __GNOME_KEYBOARD_PROPERTY_XKB_H
#include <gtk/gtk.h>
#include "libgnomekbd/gkbd-keyboard-config.h"
#include "libgnomekbd/gkbd-util.h"
G_BEGIN_DECLS
#define CWID(s) GTK_WIDGET (gtk_builder_get_object (chooser_dialog, s))
#define WID(s) GTK_WIDGET (gtk_builder_get_object (dialog, s))
extern XklEngine *engine;
extern XklConfigRegistry *config_registry;
extern GSettings *xkb_keyboard_settings;
extern GSettings *xkb_desktop_settings;
extern GkbdKeyboardConfig initial_config;
extern void setup_xkb_tabs (GtkBuilder * dialog);
extern void xkb_layouts_fill_selected_tree (GtkBuilder * dialog);
extern void xkb_layouts_register_buttons_handlers (GtkBuilder * dialog);
extern void xkb_layouts_register_conf_listener (GtkBuilder * dialog);
extern void xkb_options_register_conf_listener (GtkBuilder * dialog);
extern void xkb_layouts_prepare_selected_tree (GtkBuilder * dialog);
extern void xkb_options_load_options (GtkBuilder * dialog);
extern void xkb_options_popup_dialog (GtkBuilder * dialog);
extern char *xci_desc_to_utf8 (const XklConfigItem * ci);
extern gchar *xkb_layout_description_utf8 (const gchar * visible);
extern void enable_disable_restoring (GtkBuilder * dialog);
extern void preview_toggled (GtkBuilder * dialog, GtkWidget * button);
extern GtkWidget *xkb_layout_choose (GtkBuilder * dialog);
extern void xkb_layout_chooser_response (GtkDialog *dialog, gint response_id);
extern gchar **xkb_layouts_get_selected_list (void);
extern gchar **xkb_options_get_selected_list (void);
#define xkb_layouts_set_selected_list(list) \
g_settings_set_strv (xkb_keyboard_settings, \
GKBD_KEYBOARD_CONFIG_KEY_LAYOUTS, \
(const gchar *const*)(list))
#define xkb_options_set_selected_list(list) \
g_settings_set_strv (xkb_keyboard_settings, \
GKBD_KEYBOARD_CONFIG_KEY_OPTIONS, \
(const gchar *const*)(list))
extern GtkWidget *xkb_layout_preview_create_widget (GtkBuilder *
chooser_dialog);
extern void xkb_layout_preview_update (GtkBuilder * chooser_dialog);
extern void xkb_layout_preview_set_drawing_layout (GtkWidget * kbdraw,
const gchar * id);
extern gchar *xkb_layout_chooser_get_selected_id (GtkDialog *dialog);
extern void xkb_save_default_group (gint group_no);
extern gint xkb_get_default_group (void);
G_END_DECLS
#endif /* __GNOME_KEYBOARD_PROPERTY_XKB_H */

View File

@@ -1,470 +0,0 @@
/* gnome-region-panel-xkblt.c
* Copyright (C) 2003-2007 Sergey V. Udaltsov
*
* Written by: Sergey V. Udaltsov <svu@gnome.org>
*
* 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 <config.h>
#endif
#include <gdk/gdkx.h>
#include <glib/gi18n.h>
#include <libgnomekbd/gkbd-desktop-config.h>
#include <libgnomekbd/gkbd-keyboard-drawing.h>
#include "gnome-region-panel-xkb.h"
enum {
SEL_LAYOUT_TREE_COL_DESCRIPTION,
SEL_LAYOUT_TREE_COL_ID,
SEL_LAYOUT_TREE_COL_ENABLED,
SEL_LAYOUT_N_COLS
};
static int idx2select = -1;
static int max_selected_layouts = -1;
static GtkCellRenderer *text_renderer;
static gboolean disable_buttons_sensibility_update = FALSE;
static gboolean
get_selected_iter (GtkBuilder *dialog,
GtkTreeModel **model,
GtkTreeIter *iter)
{
GtkTreeSelection *selection;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("xkb_layouts_selected")));
return gtk_tree_selection_get_selected (selection, model, iter);
}
static void
set_selected_path (GtkBuilder *dialog,
GtkTreePath *path)
{
GtkTreeSelection *selection;
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (WID ("xkb_layouts_selected")));
gtk_tree_selection_select_path (selection, path);
}
static gint
find_selected_layout_idx (GtkBuilder *dialog)
{
GtkTreeIter selected_iter;
GtkTreeModel *model;
GtkTreePath *path;
gint *indices;
gint rv;
if (!get_selected_iter (dialog, &model, &selected_iter))
return -1;
path = gtk_tree_model_get_path (model, &selected_iter);
if (path == NULL)
return -1;
indices = gtk_tree_path_get_indices (path);
rv = indices[0];
gtk_tree_path_free (path);
return rv;
}
gchar **
xkb_layouts_get_selected_list (void)
{
gchar **retval;
retval = g_settings_get_strv (xkb_keyboard_settings,
GKBD_KEYBOARD_CONFIG_KEY_LAYOUTS);
if (retval == NULL || retval[0] == NULL) {
g_strfreev (retval);
retval = g_strdupv (initial_config.layouts_variants);
}
return retval;
}
gint
xkb_get_default_group ()
{
return g_settings_get_int (xkb_desktop_settings,
GKBD_DESKTOP_CONFIG_KEY_DEFAULT_GROUP);
}
void
xkb_save_default_group (gint default_group)
{
g_settings_set_int (xkb_desktop_settings,
GKBD_DESKTOP_CONFIG_KEY_DEFAULT_GROUP,
default_group);
}
static void
xkb_layouts_enable_disable_buttons (GtkBuilder * dialog)
{
GtkWidget *add_layout_btn = WID ("xkb_layouts_add");
GtkWidget *show_layout_btn = WID ("xkb_layouts_show");
GtkWidget *del_layout_btn = WID ("xkb_layouts_remove");
GtkWidget *selected_layouts_tree = WID ("xkb_layouts_selected");
GtkWidget *move_up_layout_btn = WID ("xkb_layouts_move_up");
GtkWidget *move_down_layout_btn = WID ("xkb_layouts_move_down");
GtkTreeSelection *s_selection =
gtk_tree_view_get_selection (GTK_TREE_VIEW
(selected_layouts_tree));
const int n_selected_selected_layouts =
gtk_tree_selection_count_selected_rows (s_selection);
GtkTreeModel *selected_layouts_model = gtk_tree_view_get_model
(GTK_TREE_VIEW (selected_layouts_tree));
const int n_selected_layouts =
gtk_tree_model_iter_n_children (selected_layouts_model,
NULL);
gint sidx = find_selected_layout_idx (dialog);
if (disable_buttons_sensibility_update)
return;
gtk_widget_set_sensitive (add_layout_btn,
(n_selected_layouts <
max_selected_layouts
|| max_selected_layouts == 0));
gtk_widget_set_sensitive (del_layout_btn, (n_selected_layouts > 1)
&& (n_selected_selected_layouts > 0));
gtk_widget_set_sensitive (show_layout_btn,
(n_selected_selected_layouts > 0));
gtk_widget_set_sensitive (move_up_layout_btn, sidx > 0);
gtk_widget_set_sensitive (move_down_layout_btn, sidx >= 0
&& sidx < (n_selected_layouts - 1));
}
static void
update_layouts_list (GtkTreeModel *model,
GtkBuilder *dialog)
{
gboolean cont;
GtkTreeIter iter;
GPtrArray *array;
array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
cont = gtk_tree_model_get_iter_first (model, &iter);
while (cont) {
char *id;
gtk_tree_model_get (model, &iter,
SEL_LAYOUT_TREE_COL_ID, &id,
-1);
g_ptr_array_add (array, id);
cont = gtk_tree_model_iter_next (model, &iter);
}
g_ptr_array_add (array, NULL);
xkb_layouts_set_selected_list (array->pdata);
g_ptr_array_free (array, TRUE);
xkb_layouts_enable_disable_buttons (dialog);
}
static void
xkb_layouts_drag_end (GtkWidget *widget,
GdkDragContext *drag_context,
gpointer user_data)
{
update_layouts_list (gtk_tree_view_get_model (GTK_TREE_VIEW (widget)),
GTK_BUILDER (user_data));
}
void
xkb_layouts_prepare_selected_tree (GtkBuilder * dialog)
{
GtkListStore *list_store;
GtkWidget *tree_view = WID ("xkb_layouts_selected");
GtkTreeSelection *selection;
GtkTreeViewColumn *desc_column;
list_store = gtk_list_store_new (SEL_LAYOUT_N_COLS,
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
text_renderer = GTK_CELL_RENDERER (gtk_cell_renderer_text_new ());
desc_column =
gtk_tree_view_column_new_with_attributes (_("Layout"),
text_renderer,
"text",
SEL_LAYOUT_TREE_COL_DESCRIPTION,
"sensitive",
SEL_LAYOUT_TREE_COL_ENABLED,
NULL);
selection =
gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view),
GTK_TREE_MODEL (list_store));
gtk_tree_view_column_set_sizing (desc_column,
GTK_TREE_VIEW_COLUMN_AUTOSIZE);
gtk_tree_view_column_set_resizable (desc_column, TRUE);
gtk_tree_view_column_set_expand (desc_column, TRUE);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
desc_column);
g_signal_connect_swapped (G_OBJECT (selection), "changed",
G_CALLBACK
(xkb_layouts_enable_disable_buttons),
dialog);
max_selected_layouts = xkl_engine_get_max_num_groups (engine);
/* Setting up DnD */
gtk_tree_view_set_reorderable (GTK_TREE_VIEW (tree_view), TRUE);
g_signal_connect (G_OBJECT (tree_view), "drag-end",
G_CALLBACK (xkb_layouts_drag_end), dialog);
}
gchar *
xkb_layout_description_utf8 (const gchar * visible)
{
char *l, *sl, *v, *sv;
if (gkbd_keyboard_config_get_descriptions
(config_registry, visible, &sl, &l, &sv, &v))
visible =
gkbd_keyboard_config_format_full_description (l, v);
return g_strstrip (g_strdup (visible));
}
void
xkb_layouts_fill_selected_tree (GtkBuilder * dialog)
{
gchar **layouts = xkb_layouts_get_selected_list ();
guint i;
GtkListStore *list_store =
GTK_LIST_STORE (gtk_tree_view_get_model
(GTK_TREE_VIEW
(WID ("xkb_layouts_selected"))));
/* temporarily disable the buttons' status update */
disable_buttons_sensibility_update = TRUE;
gtk_list_store_clear (list_store);
for (i = 0; layouts != NULL && layouts[i] != NULL; i++) {
char *cur_layout = layouts[i];
gchar *utf_visible =
xkb_layout_description_utf8 (cur_layout);
gtk_list_store_insert_with_values (list_store, NULL, G_MAXINT,
SEL_LAYOUT_TREE_COL_DESCRIPTION,
utf_visible,
SEL_LAYOUT_TREE_COL_ID,
cur_layout,
SEL_LAYOUT_TREE_COL_ENABLED,
i < max_selected_layouts, -1);
g_free (utf_visible);
}
g_strfreev (layouts);
/* enable the buttons' status update */
disable_buttons_sensibility_update = FALSE;
if (idx2select != -1) {
GtkTreeSelection *selection =
gtk_tree_view_get_selection ((GTK_TREE_VIEW
(WID
("xkb_layouts_selected"))));
GtkTreePath *path =
gtk_tree_path_new_from_indices (idx2select, -1);
gtk_tree_selection_select_path (selection, path);
gtk_tree_path_free (path);
idx2select = -1;
} else {
/* if there is nothing to select - just enable/disable the buttons,
otherwise it would be done by the selection change */
xkb_layouts_enable_disable_buttons (dialog);
}
}
static void
add_default_switcher_if_necessary ()
{
gchar **layouts_list = xkb_layouts_get_selected_list();
gchar **options_list = xkb_options_get_selected_list ();
gboolean was_appended;
options_list =
gkbd_keyboard_config_add_default_switch_option_if_necessary
(layouts_list, options_list, &was_appended);
if (was_appended)
xkb_options_set_selected_list (options_list);
g_strfreev (options_list);
}
static void
chooser_response (GtkDialog *chooser,
int response_id,
GtkBuilder *dialog)
{
if (response_id == GTK_RESPONSE_OK) {
char *id, *name;
GtkListStore *list_store;
list_store = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (WID ("xkb_layouts_selected"))));
id = xkb_layout_chooser_get_selected_id (chooser);
name = xkb_layout_description_utf8 (id);
gtk_list_store_insert_with_values (list_store, NULL, G_MAXINT,
SEL_LAYOUT_TREE_COL_DESCRIPTION, name,
SEL_LAYOUT_TREE_COL_ID, id,
SEL_LAYOUT_TREE_COL_ENABLED, TRUE,
-1);
g_free (name);
add_default_switcher_if_necessary ();
update_layouts_list (GTK_TREE_MODEL (list_store), dialog);
}
xkb_layout_chooser_response (chooser, response_id);
}
static void
add_selected_layout (GtkWidget * button, GtkBuilder * dialog)
{
GtkWidget *chooser;
chooser = xkb_layout_choose (dialog);
g_signal_connect (G_OBJECT (chooser), "response",
G_CALLBACK (chooser_response), dialog);
}
static void
show_selected_layout (GtkWidget * button, GtkBuilder * dialog)
{
gint idx = find_selected_layout_idx (dialog);
if (idx != -1) {
GtkWidget *parent = WID ("region_notebook");
GtkWidget *popup = gkbd_keyboard_drawing_dialog_new ();
gkbd_keyboard_drawing_dialog_set_group (popup,
config_registry,
idx);
gtk_window_set_transient_for (GTK_WINDOW (popup),
GTK_WINDOW
(gtk_widget_get_toplevel
(parent)));
gtk_widget_show_all (popup);
}
}
static void
remove_selected_layout (GtkWidget * button, GtkBuilder * dialog)
{
GtkTreeModel *model;
GtkTreeIter iter;
if (get_selected_iter (dialog, &model, &iter) == FALSE)
return;
gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
update_layouts_list (model, dialog);
}
static void
move_up_selected_layout (GtkWidget * button, GtkBuilder * dialog)
{
GtkTreeModel *model;
GtkTreeIter iter, prev;
GtkTreePath *path;
if (get_selected_iter (dialog, &model, &iter) == FALSE)
return;
prev = iter;
if (!gtk_tree_model_iter_previous (model, &prev))
return;
path = gtk_tree_model_get_path (model, &prev);
gtk_list_store_swap (GTK_LIST_STORE (model), &iter, &prev);
update_layouts_list (model, dialog);
set_selected_path (dialog, path);
gtk_tree_path_free (path);
}
static void
move_down_selected_layout (GtkWidget * button, GtkBuilder * dialog)
{
GtkTreeModel *model;
GtkTreeIter iter, next;
GtkTreePath *path;
if (get_selected_iter (dialog, &model, &iter) == FALSE)
return;
next = iter;
if (!gtk_tree_model_iter_next (model, &next))
return;
path = gtk_tree_model_get_path (model, &next);
gtk_list_store_swap (GTK_LIST_STORE (model), &iter, &next);
update_layouts_list (model, dialog);
set_selected_path (dialog, path);
gtk_tree_path_free (path);
}
void
xkb_layouts_register_buttons_handlers (GtkBuilder * dialog)
{
g_signal_connect (G_OBJECT (WID ("xkb_layouts_add")), "clicked",
G_CALLBACK (add_selected_layout), dialog);
g_signal_connect (G_OBJECT (WID ("xkb_layouts_show")), "clicked",
G_CALLBACK (show_selected_layout), dialog);
g_signal_connect (G_OBJECT (WID ("xkb_layouts_remove")), "clicked",
G_CALLBACK (remove_selected_layout), dialog);
g_signal_connect (G_OBJECT (WID ("xkb_layouts_move_up")),
"clicked", G_CALLBACK (move_up_selected_layout),
dialog);
g_signal_connect (G_OBJECT (WID ("xkb_layouts_move_down")),
"clicked",
G_CALLBACK (move_down_selected_layout), dialog);
}
static void
xkb_layouts_update_list (GSettings * settings,
gchar * key, GtkBuilder * dialog)
{
if (strcmp (key, GKBD_KEYBOARD_CONFIG_KEY_LAYOUTS) == 0) {
xkb_layouts_fill_selected_tree (dialog);
enable_disable_restoring (dialog);
}
}
void
xkb_layouts_register_conf_listener (GtkBuilder * dialog)
{
g_signal_connect (xkb_keyboard_settings, "changed",
G_CALLBACK (xkb_layouts_update_list), dialog);
}

View File

@@ -1,495 +0,0 @@
/* gnome-region-panel-xkbltadd.c
* Copyright (C) 2007 Sergey V. Udaltsov
*
* Written by: Sergey V. Udaltsov <svu@gnome.org>
*
* 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 <config.h>
#endif
#include <string.h>
#include <libgnomekbd/gkbd-keyboard-drawing.h>
#include <libgnomekbd/gkbd-util.h>
#include "gnome-region-panel-xkb.h"
enum {
COMBO_BOX_MODEL_COL_SORT,
COMBO_BOX_MODEL_COL_VISIBLE,
COMBO_BOX_MODEL_COL_XKB_ID,
COMBO_BOX_MODEL_COL_COUNTRY_DESC,
COMBO_BOX_MODEL_COL_LANGUAGE_DESC
};
static gchar **search_pattern_list = NULL;
static GtkWidget *preview_dialog = NULL;
static GRegex *left_bracket_regex = NULL;
#define RESPONSE_PREVIEW 1
static void
xkb_preview_destroy_callback (GtkWidget * widget)
{
preview_dialog = NULL;
}
static gboolean
xkb_layout_chooser_selection_dupe (GtkDialog * dialog)
{
gchar *selected_id =
(gchar *) xkb_layout_chooser_get_selected_id (dialog);
gchar **layouts_list, **pl;
gboolean rv = FALSE;
if (selected_id == NULL)
return rv;
layouts_list = pl = xkb_layouts_get_selected_list ();
while (pl && *pl) {
if (!g_ascii_strcasecmp (*pl++, selected_id)) {
rv = TRUE;
break;
}
}
g_strfreev (layouts_list);
return rv;
}
void
xkb_layout_chooser_response (GtkDialog * dialog, gint response)
{
switch (response)
case GTK_RESPONSE_OK:{
/* Handled by the main code */
break;
case RESPONSE_PREVIEW:{
gchar *selected_id = (gchar *)
xkb_layout_chooser_get_selected_id
(dialog);
if (selected_id != NULL) {
if (preview_dialog == NULL) {
preview_dialog =
gkbd_keyboard_drawing_dialog_new
();
g_signal_connect (G_OBJECT
(preview_dialog),
"destroy",
G_CALLBACK
(xkb_preview_destroy_callback),
NULL);
/* Put into the separate group to avoid conflict
with modal parent */
gtk_window_group_add_window
(gtk_window_group_new
(),
GTK_WINDOW
(preview_dialog));
};
gkbd_keyboard_drawing_dialog_set_layout
(preview_dialog,
config_registry, selected_id);
gtk_widget_show_all
(preview_dialog);
}
}
return;
}
if (preview_dialog != NULL) {
gtk_widget_destroy (preview_dialog);
}
if (search_pattern_list != NULL) {
g_strfreev (search_pattern_list);
search_pattern_list = NULL;
}
gtk_widget_destroy (GTK_WIDGET (dialog));
}
static gchar *
xkl_create_description_from_list (const XklConfigItem * item,
const XklConfigItem * subitem,
const gchar * prop_name,
const gchar *
(*desc_getter) (const gchar * code))
{
gchar *rv = NULL, *code = NULL;
gchar **list = NULL;
const gchar *desc;
if (subitem != NULL)
list =
(gchar
**) (g_object_get_data (G_OBJECT (subitem),
prop_name));
if (list == NULL || *list == 0)
list =
(gchar
**) (g_object_get_data (G_OBJECT (item), prop_name));
/* First try the parent id as such */
desc = desc_getter (item->name);
if (desc != NULL) {
rv = g_utf8_strup (desc, -1);
} else {
code = g_utf8_strup (item->name, -1);
desc = desc_getter (code);
if (desc != NULL) {
rv = g_utf8_strup (desc, -1);
}
g_free (code);
}
if (list == NULL || *list == 0)
return rv;
while (*list != 0) {
code = *list++;
desc = desc_getter (code);
if (desc != NULL) {
gchar *udesc = g_utf8_strup (desc, -1);
if (rv == NULL) {
rv = udesc;
} else {
gchar *orv = rv;
rv = g_strdup_printf ("%s %s", rv, udesc);
g_free (orv);
g_free (udesc);
}
}
}
return rv;
}
static void
xkl_layout_add_to_list (XklConfigRegistry * config,
const XklConfigItem * item,
const XklConfigItem * subitem,
GtkBuilder * chooser_dialog)
{
GtkListStore *list_store =
GTK_LIST_STORE (gtk_builder_get_object (chooser_dialog,
"layout_list_model"));
GtkTreeIter iter;
gchar *utf_variant_name =
subitem ?
xkb_layout_description_utf8 (gkbd_keyboard_config_merge_items
(item->name,
subitem->name)) :
xci_desc_to_utf8 (item);
const gchar *xkb_id =
subitem ? gkbd_keyboard_config_merge_items (item->name,
subitem->name) :
item->name;
gchar *country_desc =
xkl_create_description_from_list (item, subitem,
XCI_PROP_COUNTRY_LIST,
xkl_get_country_name);
gchar *language_desc =
xkl_create_description_from_list (item, subitem,
XCI_PROP_LANGUAGE_LIST,
xkl_get_language_name);
gchar *tmp = utf_variant_name;
utf_variant_name =
g_regex_replace_literal (left_bracket_regex, tmp, -1, 0,
"&lt;", 0, NULL);
g_free (tmp);
if (subitem
&& g_object_get_data (G_OBJECT (subitem),
XCI_PROP_EXTRA_ITEM)) {
gchar *buf =
g_strdup_printf ("<i>%s</i>", utf_variant_name);
gtk_list_store_insert_with_values (list_store, &iter, -1,
COMBO_BOX_MODEL_COL_SORT,
utf_variant_name,
COMBO_BOX_MODEL_COL_VISIBLE,
buf,
COMBO_BOX_MODEL_COL_XKB_ID,
xkb_id,
COMBO_BOX_MODEL_COL_COUNTRY_DESC,
country_desc,
COMBO_BOX_MODEL_COL_LANGUAGE_DESC,
language_desc, -1);
g_free (buf);
} else
gtk_list_store_insert_with_values (list_store, &iter,
-1,
COMBO_BOX_MODEL_COL_SORT,
utf_variant_name,
COMBO_BOX_MODEL_COL_VISIBLE,
utf_variant_name,
COMBO_BOX_MODEL_COL_XKB_ID,
xkb_id,
COMBO_BOX_MODEL_COL_COUNTRY_DESC,
country_desc,
COMBO_BOX_MODEL_COL_LANGUAGE_DESC,
language_desc, -1);
g_free (utf_variant_name);
g_free (country_desc);
g_free (language_desc);
}
static void
xkb_layout_filter_clear (GtkEntry * entry,
GtkEntryIconPosition icon_pos,
GdkEvent * event, gpointer user_data)
{
gtk_entry_set_text (entry, "");
}
static void
xkb_layout_filter_changed (GtkBuilder * chooser_dialog)
{
GtkTreeModelFilter *filtered_model =
GTK_TREE_MODEL_FILTER (gtk_builder_get_object (chooser_dialog,
"filtered_layout_list_model"));
GtkWidget *xkb_layout_filter = CWID ("xkb_layout_filter");
const gchar *pattern =
gtk_entry_get_text (GTK_ENTRY (xkb_layout_filter));
gchar *upattern = g_utf8_strup (pattern, -1);
if (!g_strcmp0 (pattern, "")) {
g_object_set (G_OBJECT (xkb_layout_filter),
"secondary-icon-name", "edit-find-symbolic",
"secondary-icon-activatable", FALSE,
"secondary-icon-sensitive", FALSE, NULL);
} else {
g_object_set (G_OBJECT (xkb_layout_filter),
"secondary-icon-name", "edit-clear-symbolic",
"secondary-icon-activatable", TRUE,
"secondary-icon-sensitive", TRUE, NULL);
}
if (search_pattern_list != NULL)
g_strfreev (search_pattern_list);
search_pattern_list = g_strsplit (upattern, " ", -1);
g_free (upattern);
gtk_tree_model_filter_refilter (filtered_model);
}
static void
xkb_layout_chooser_selection_changed (GtkTreeSelection * selection,
GtkBuilder * chooser_dialog)
{
GList *selected_layouts =
gtk_tree_selection_get_selected_rows (selection, NULL);
GtkWidget *add_button = CWID ("btnOk");
GtkWidget *preview_button = CWID ("btnPreview");
gboolean anything_selected = g_list_length (selected_layouts) == 1;
gboolean dupe =
xkb_layout_chooser_selection_dupe (GTK_DIALOG
(CWID
("xkb_layout_chooser")));
gtk_widget_set_sensitive (add_button, anything_selected && !dupe);
gtk_widget_set_sensitive (preview_button, anything_selected);
}
static void
xkb_layout_chooser_row_activated (GtkTreeView * tree_view,
GtkTreePath * path,
GtkTreeViewColumn * column,
GtkBuilder * chooser_dialog)
{
GtkWidget *add_button = CWID ("btnOk");
GtkWidget *dialog = CWID ("xkb_layout_chooser");
if (gtk_widget_is_sensitive (add_button))
gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
}
static gboolean
xkb_filter_layouts (GtkTreeModel * model,
GtkTreeIter * iter, gpointer data)
{
gchar *desc = NULL, *country_desc = NULL, *language_desc =
NULL, **pattern;
gboolean rv = TRUE;
if (search_pattern_list == NULL || search_pattern_list[0] == NULL)
return TRUE;
gtk_tree_model_get (model, iter,
COMBO_BOX_MODEL_COL_SORT, &desc,
COMBO_BOX_MODEL_COL_COUNTRY_DESC,
&country_desc,
COMBO_BOX_MODEL_COL_LANGUAGE_DESC,
&language_desc, -1);
pattern = search_pattern_list;
do {
gboolean is_pattern_found = FALSE;
gchar *udesc = g_utf8_strup (desc, -1);
if (udesc != NULL && g_strstr_len (udesc, -1, *pattern)) {
is_pattern_found = TRUE;
} else if (country_desc != NULL
&& g_strstr_len (country_desc, -1, *pattern)) {
is_pattern_found = TRUE;
} else if (language_desc != NULL
&& g_strstr_len (language_desc, -1, *pattern)) {
is_pattern_found = TRUE;
}
g_free (udesc);
if (!is_pattern_found) {
rv = FALSE;
break;
}
} while (*++pattern != NULL);
g_free (desc);
g_free (country_desc);
g_free (language_desc);
return rv;
}
GtkWidget *
xkb_layout_choose (GtkBuilder * dialog)
{
GtkBuilder *chooser_dialog = gtk_builder_new ();
GtkWidget *chooser, *xkb_filtered_layouts_list, *xkb_layout_filter;
GtkTreeViewColumn *visible_column;
GtkTreeSelection *selection;
GtkListStore *model;
GtkTreeModelFilter *filtered_model;
gtk_builder_add_from_file (chooser_dialog, GNOMECC_UI_DIR
"/gnome-region-panel-layout-chooser.ui",
NULL);
chooser = CWID ("xkb_layout_chooser");
xkb_filtered_layouts_list = CWID ("xkb_filtered_layouts_list");
xkb_layout_filter = CWID ("xkb_layout_filter");
g_object_set_data (G_OBJECT (chooser), "xkb_filtered_layouts_list",
xkb_filtered_layouts_list);
visible_column =
gtk_tree_view_column_new_with_attributes ("Layout",
gtk_cell_renderer_text_new
(), "markup",
COMBO_BOX_MODEL_COL_VISIBLE,
NULL);
gtk_window_set_transient_for (GTK_WINDOW (chooser),
GTK_WINDOW
(gtk_widget_get_toplevel
(WID ("region_notebook"))));
gtk_tree_view_append_column (GTK_TREE_VIEW
(xkb_filtered_layouts_list),
visible_column);
g_signal_connect_swapped (G_OBJECT (xkb_layout_filter),
"notify::text",
G_CALLBACK
(xkb_layout_filter_changed),
chooser_dialog);
g_signal_connect (G_OBJECT (xkb_layout_filter), "icon-release",
G_CALLBACK (xkb_layout_filter_clear), NULL);
selection =
gtk_tree_view_get_selection (GTK_TREE_VIEW
(xkb_filtered_layouts_list));
g_signal_connect (G_OBJECT (selection),
"changed",
G_CALLBACK
(xkb_layout_chooser_selection_changed),
chooser_dialog);
xkb_layout_chooser_selection_changed (selection, chooser_dialog);
g_signal_connect (G_OBJECT (xkb_filtered_layouts_list),
"row-activated",
G_CALLBACK (xkb_layout_chooser_row_activated),
chooser_dialog);
filtered_model =
GTK_TREE_MODEL_FILTER (gtk_builder_get_object
(chooser_dialog,
"filtered_layout_list_model"));
model =
GTK_LIST_STORE (gtk_builder_get_object
(chooser_dialog, "layout_list_model"));
left_bracket_regex = g_regex_new ("<", 0, 0, NULL);
xkl_config_registry_search_by_pattern (config_registry,
NULL,
(TwoConfigItemsProcessFunc)
(xkl_layout_add_to_list),
chooser_dialog);
g_regex_unref (left_bracket_regex);
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
COMBO_BOX_MODEL_COL_SORT,
GTK_SORT_ASCENDING);
gtk_tree_model_filter_set_visible_func (filtered_model,
xkb_filter_layouts,
NULL, NULL);
gtk_widget_grab_focus (xkb_layout_filter);
gtk_widget_show (chooser);
return chooser;
}
gchar *
xkb_layout_chooser_get_selected_id (GtkDialog * dialog)
{
GtkTreeModel *filtered_list_model;
GtkWidget *xkb_filtered_layouts_list =
g_object_get_data (G_OBJECT (dialog),
"xkb_filtered_layouts_list");
GtkTreeIter viter;
gchar *v_id;
GtkTreeSelection *selection =
gtk_tree_view_get_selection (GTK_TREE_VIEW
(xkb_filtered_layouts_list));
GList *selected_layouts =
gtk_tree_selection_get_selected_rows (selection,
&filtered_list_model);
if (g_list_length (selected_layouts) != 1)
return NULL;
gtk_tree_model_get_iter (filtered_list_model,
&viter,
(GtkTreePath *) (selected_layouts->data));
g_list_foreach (selected_layouts,
(GFunc) gtk_tree_path_free, NULL);
g_list_free (selected_layouts);
gtk_tree_model_get (filtered_list_model, &viter,
COMBO_BOX_MODEL_COL_XKB_ID, &v_id, -1);
return v_id;
}

View File

@@ -1,515 +0,0 @@
/* gnome-region-panel-xkbot.c
* Copyright (C) 2003-2007 Sergey V. Udaltsov
*
* Written by: Sergey V. Udaltsov <svu@gnome.org>
* John Spray <spray_john@users.sourceforge.net>
*
* 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 <config.h>
#endif
#include <glib/gi18n.h>
#include <string.h>
#include "gnome-region-panel-xkb.h"
static GtkBuilder *chooser_dialog = NULL;
static const char *current1st_level_id = NULL;
static GSList *option_checks_list = NULL;
static GtkWidget *current_none_radio = NULL;
static GtkWidget *current_expander = NULL;
static gboolean current_multi_select = FALSE;
static GSList *current_radio_group = NULL;
#define OPTION_ID_PROP "optionID"
#define SELCOUNTER_PROP "selectionCounter"
#define GCONFSTATE_PROP "gconfState"
#define EXPANDERS_PROP "expandersList"
gchar **
xkb_options_get_selected_list (void)
{
gchar **retval;
retval =
g_settings_get_strv (xkb_keyboard_settings,
GKBD_KEYBOARD_CONFIG_KEY_OPTIONS);
if (retval == NULL) {
retval = g_strdupv (initial_config.options);
}
return retval;
}
/* Returns the selection counter of the expander (static current_expander) */
static int
xkb_options_expander_selcounter_get (void)
{
return
GPOINTER_TO_INT (g_object_get_data
(G_OBJECT (current_expander),
SELCOUNTER_PROP));
}
/* Increments the selection counter in the expander (static current_expander)
using the value (can be 0)*/
static void
xkb_options_expander_selcounter_add (int value)
{
g_object_set_data (G_OBJECT (current_expander), SELCOUNTER_PROP,
GINT_TO_POINTER
(xkb_options_expander_selcounter_get ()
+ value));
}
/* Resets the seletion counter in the expander (static current_expander) */
static void
xkb_options_expander_selcounter_reset (void)
{
g_object_set_data (G_OBJECT (current_expander), SELCOUNTER_PROP,
GINT_TO_POINTER (0));
}
/* Formats the expander (static current_expander), based on the selection counter */
static void
xkb_options_expander_highlight (void)
{
char *utf_group_name =
g_object_get_data (G_OBJECT (current_expander),
"utfGroupName");
int counter = xkb_options_expander_selcounter_get ();
if (utf_group_name != NULL) {
gchar *titlemarkup =
g_strconcat (counter >
0 ? "<span weight=\"bold\">" : "<span>",
utf_group_name, "</span>", NULL);
gtk_expander_set_label (GTK_EXPANDER (current_expander),
titlemarkup);
g_free (titlemarkup);
}
}
/* Add optionname from the backend's selection list if it's not
already in there. */
static void
xkb_options_select (gchar * optionname)
{
gboolean already_selected = FALSE;
gchar **options_list;
guint i;
options_list = xkb_options_get_selected_list ();
for (i = 0; options_list != NULL && options_list[i] != NULL; i++) {
gchar *option = options_list[i];
if (!strcmp (option, optionname)) {
already_selected = TRUE;
break;
}
}
if (!already_selected) {
options_list =
gkbd_strv_append (options_list, g_strdup (optionname));
xkb_options_set_selected_list (options_list);
}
g_strfreev (options_list);
}
/* Remove all occurences of optionname from the backend's selection list */
static void
xkb_options_deselect (gchar * optionname)
{
gchar **options_list = xkb_options_get_selected_list ();
if (options_list != NULL) {
gchar **option = options_list;
while (*option != NULL) {
gchar *id = *option;
if (!strcmp (id, optionname)) {
gkbd_strv_behead (option);
} else
option++;
}
xkb_options_set_selected_list (options_list);
}
g_strfreev (options_list);
}
/* Return true if optionname describes a string already in the backend's
list of selected options */
static gboolean
xkb_options_is_selected (gchar * optionname)
{
gboolean retval = FALSE;
gchar **options_list = xkb_options_get_selected_list ();
if (options_list != NULL) {
gchar **option = options_list;
while (*option != NULL) {
if (!strcmp (*option, optionname)) {
retval = TRUE;
break;
}
option++;
}
}
g_strfreev (options_list);
return retval;
}
/* Make sure selected options stay visible when navigating with the keyboard */
static gboolean
option_focused_cb (GtkWidget * widget, GdkEventFocus * event,
gpointer data)
{
GtkScrolledWindow *win = GTK_SCROLLED_WINDOW (data);
GtkAllocation alloc;
GtkAdjustment *adj;
gtk_widget_get_allocation (widget, &alloc);
adj = gtk_scrolled_window_get_vadjustment (win);
gtk_adjustment_clamp_page (adj, alloc.y, alloc.y + alloc.height);
return FALSE;
}
/* Update xkb backend to reflect the new UI state */
static void
option_toggled_cb (GtkWidget * checkbutton, gpointer data)
{
gpointer optionID =
g_object_get_data (G_OBJECT (checkbutton), OPTION_ID_PROP);
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbutton)))
xkb_options_select (optionID);
else
xkb_options_deselect (optionID);
}
/* Add a check_button or radio_button to control a particular option
This function makes particular use of the current... variables at
the top of this file. */
static void
xkb_options_add_option (XklConfigRegistry * config_registry,
XklConfigItem * config_item, GtkBuilder * dialog)
{
GtkWidget *option_check;
gchar *utf_option_name = xci_desc_to_utf8 (config_item);
/* Copy this out because we'll load it into the widget with set_data */
gchar *full_option_name =
g_strdup (gkbd_keyboard_config_merge_items
(current1st_level_id, config_item->name));
gboolean initial_state;
if (current_multi_select)
option_check =
gtk_check_button_new_with_label (utf_option_name);
else {
if (current_radio_group == NULL) {
/* The first radio in a group is to be "Default", meaning none of
the below options are to be included in the selected list.
This is a HIG-compliant alternative to allowing no
selection in the group. */
option_check =
gtk_radio_button_new_with_label
(current_radio_group, _("Default"));
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
(option_check),
TRUE);
/* Make option name underscore -
to enforce its first position in the list */
g_object_set_data_full (G_OBJECT (option_check),
"utfOptionName",
g_strdup (" "), g_free);
option_checks_list =
g_slist_append (option_checks_list,
option_check);
current_radio_group =
gtk_radio_button_get_group (GTK_RADIO_BUTTON
(option_check));
current_none_radio = option_check;
g_signal_connect (option_check, "focus-in-event",
G_CALLBACK (option_focused_cb),
WID ("options_scroll"));
}
option_check =
gtk_radio_button_new_with_label (current_radio_group,
utf_option_name);
current_radio_group =
gtk_radio_button_get_group (GTK_RADIO_BUTTON
(option_check));
g_object_set_data (G_OBJECT (option_check), "NoneRadio",
current_none_radio);
}
initial_state = xkb_options_is_selected (full_option_name);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (option_check),
initial_state);
g_object_set_data_full (G_OBJECT (option_check), OPTION_ID_PROP,
full_option_name, g_free);
g_object_set_data_full (G_OBJECT (option_check), "utfOptionName",
utf_option_name, g_free);
g_signal_connect (option_check, "toggled",
G_CALLBACK (option_toggled_cb), NULL);
option_checks_list =
g_slist_append (option_checks_list, option_check);
g_signal_connect (option_check, "focus-in-event",
G_CALLBACK (option_focused_cb),
WID ("options_scroll"));
xkb_options_expander_selcounter_add (initial_state);
g_object_set_data (G_OBJECT (option_check), GCONFSTATE_PROP,
GINT_TO_POINTER (initial_state));
}
static gint
xkb_option_checks_compare (GtkWidget * chk1, GtkWidget * chk2)
{
const gchar *t1 =
g_object_get_data (G_OBJECT (chk1), "utfOptionName");
const gchar *t2 =
g_object_get_data (G_OBJECT (chk2), "utfOptionName");
return g_utf8_collate (t1, t2);
}
/* Add a group of options: create title and layout widgets and then
add widgets for all the options in the group. */
static void
xkb_options_add_group (XklConfigRegistry * config_registry,
XklConfigItem * config_item, GtkBuilder * dialog)
{
GtkWidget *align, *vbox, *option_check;
gboolean allow_multiple_selection =
GPOINTER_TO_INT (g_object_get_data (G_OBJECT (config_item),
XCI_PROP_ALLOW_MULTIPLE_SELECTION));
GSList *expanders_list =
g_object_get_data (G_OBJECT (dialog), EXPANDERS_PROP);
gchar *utf_group_name = xci_desc_to_utf8 (config_item);
gchar *titlemarkup =
g_strconcat ("<span>", utf_group_name, "</span>", NULL);
current_expander = gtk_expander_new (titlemarkup);
gtk_expander_set_use_markup (GTK_EXPANDER (current_expander),
TRUE);
g_object_set_data_full (G_OBJECT (current_expander),
"utfGroupName", utf_group_name, g_free);
g_object_set_data_full (G_OBJECT (current_expander), "groupId",
g_strdup (config_item->name), g_free);
g_free (titlemarkup);
align = gtk_alignment_new (0, 0, 1, 1);
gtk_alignment_set_padding (GTK_ALIGNMENT (align), 6, 12, 12, 0);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_box_set_homogeneous (GTK_BOX (vbox), TRUE);
gtk_container_add (GTK_CONTAINER (align), vbox);
gtk_container_add (GTK_CONTAINER (current_expander), align);
current_multi_select = (gboolean) allow_multiple_selection;
current_radio_group = NULL;
current1st_level_id = config_item->name;
option_checks_list = NULL;
xkl_config_registry_foreach_option (config_registry,
config_item->name,
(ConfigItemProcessFunc)
xkb_options_add_option,
dialog);
/* sort it */
option_checks_list =
g_slist_sort (option_checks_list,
(GCompareFunc) xkb_option_checks_compare);
while (option_checks_list) {
option_check = GTK_WIDGET (option_checks_list->data);
gtk_box_pack_start (GTK_BOX (vbox), option_check, TRUE,
TRUE, 0);
option_checks_list = option_checks_list->next;
}
/* free it */
g_slist_free (option_checks_list);
option_checks_list = NULL;
xkb_options_expander_highlight ();
expanders_list = g_slist_append (expanders_list, current_expander);
g_object_set_data (G_OBJECT (dialog), EXPANDERS_PROP,
expanders_list);
g_signal_connect (current_expander, "focus-in-event",
G_CALLBACK (option_focused_cb),
WID ("options_scroll"));
}
static gint
xkb_options_expanders_compare (GtkWidget * expander1,
GtkWidget * expander2)
{
const gchar *t1 =
g_object_get_data (G_OBJECT (expander1), "utfGroupName");
const gchar *t2 =
g_object_get_data (G_OBJECT (expander2), "utfGroupName");
return g_utf8_collate (t1, t2);
}
/* Create widgets to represent the options made available by the backend */
void
xkb_options_load_options (GtkBuilder * dialog)
{
GtkWidget *opts_vbox = WID ("options_vbox");
GtkWidget *dialog_vbox = WID ("dialog_vbox");
GtkWidget *options_scroll = WID ("options_scroll");
GtkWidget *expander;
GSList *expanders_list;
current1st_level_id = NULL;
current_none_radio = NULL;
current_multi_select = FALSE;
current_radio_group = NULL;
/* fill the list */
xkl_config_registry_foreach_option_group (config_registry,
(ConfigItemProcessFunc)
xkb_options_add_group,
dialog);
/* sort it */
expanders_list =
g_object_get_data (G_OBJECT (dialog), EXPANDERS_PROP);
expanders_list =
g_slist_sort (expanders_list,
(GCompareFunc) xkb_options_expanders_compare);
g_object_set_data (G_OBJECT (dialog), EXPANDERS_PROP,
expanders_list);
while (expanders_list) {
expander = GTK_WIDGET (expanders_list->data);
gtk_box_pack_start (GTK_BOX (opts_vbox), expander, FALSE,
FALSE, 0);
expanders_list = expanders_list->next;
}
/* Somewhere in gtk3 the top vbox in dialog is made non-expandable */
gtk_box_set_child_packing (GTK_BOX (dialog_vbox), options_scroll,
TRUE, TRUE, 0, GTK_PACK_START);
gtk_widget_show_all (dialog_vbox);
}
static void
chooser_response_cb (GtkDialog * dialog, gint response, gpointer data)
{
switch (response) {
case GTK_RESPONSE_DELETE_EVENT:
case GTK_RESPONSE_CLOSE: {
/* just cleanup */
GSList *expanders_list =
g_object_get_data (G_OBJECT (dialog),
EXPANDERS_PROP);
g_object_set_data (G_OBJECT (dialog),
EXPANDERS_PROP, NULL);
g_slist_free (expanders_list);
gtk_widget_destroy (GTK_WIDGET (dialog));
chooser_dialog = NULL;
}
break;
}
}
/* Create popup dialog */
void
xkb_options_popup_dialog (GtkBuilder * dialog)
{
GtkWidget *chooser;
chooser_dialog = gtk_builder_new ();
gtk_builder_add_from_file (chooser_dialog, GNOMECC_UI_DIR
"/gnome-region-panel-options-dialog.ui",
NULL);
chooser = CWID ("xkb_options_dialog");
gtk_window_set_transient_for (GTK_WINDOW (chooser),
GTK_WINDOW (gtk_widget_get_toplevel (WID ("region_notebook"))));
gtk_window_set_modal (GTK_WINDOW (chooser), TRUE);
xkb_options_load_options (chooser_dialog);
g_signal_connect (chooser, "response",
G_CALLBACK (chooser_response_cb), dialog);
gtk_widget_show (chooser);
}
/* Update selected option counters for a group-bound expander */
static void
xkb_options_update_option_counters (XklConfigRegistry * config_registry,
XklConfigItem * config_item)
{
gchar *full_option_name =
g_strdup (gkbd_keyboard_config_merge_items
(current1st_level_id, config_item->name));
gboolean current_state =
xkb_options_is_selected (full_option_name);
g_free (full_option_name);
xkb_options_expander_selcounter_add (current_state);
}
/* Respond to a change in the xkb gconf settings */
static void
xkb_options_update (GSettings * settings, gchar * key, GtkBuilder * dialog)
{
if (!strcmp (key, GKBD_KEYBOARD_CONFIG_KEY_OPTIONS)) {
/* Updating options is handled by gconf notifies for each widget
This is here to avoid calling it N_OPTIONS times for each gconf
change. */
enable_disable_restoring (dialog);
if (chooser_dialog != NULL) {
GSList *expanders_list =
g_object_get_data (G_OBJECT (chooser_dialog),
EXPANDERS_PROP);
while (expanders_list) {
current_expander =
GTK_WIDGET (expanders_list->data);
gchar *group_id =
g_object_get_data (G_OBJECT
(current_expander),
"groupId");
current1st_level_id = group_id;
xkb_options_expander_selcounter_reset ();
xkl_config_registry_foreach_option
(config_registry, group_id,
(ConfigItemProcessFunc)
xkb_options_update_option_counters,
current_expander);
xkb_options_expander_highlight ();
expanders_list = expanders_list->next;
}
}
}
}
void
xkb_options_register_conf_listener (GtkBuilder * dialog)
{
g_signal_connect (xkb_keyboard_settings, "changed",
G_CALLBACK (xkb_options_update), dialog);
}

View File

@@ -1,120 +0,0 @@
/* gnome-region-panel-xkbpv.c
* Copyright (C) 2003-2007 Sergey V. Udaltsov
*
* Written by: Sergey V. Udaltsov <svu@gnome.org>
*
* 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 <config.h>
#endif
#include <libgnomekbd/gkbd-keyboard-drawing.h>
#include "gnome-region-panel-xkb.h"
#ifdef HAVE_X11_EXTENSIONS_XKB_H
#include "X11/XKBlib.h"
/**
* BAD STYLE: Taken from xklavier_private_xkb.h
* Any ideas on architectural improvements are WELCOME
*/
extern gboolean xkl_xkb_config_native_prepare (XklEngine * engine,
const XklConfigRec * data,
XkbComponentNamesPtr
component_names);
extern void xkl_xkb_config_native_cleanup (XklEngine * engine,
XkbComponentNamesPtr
component_names);
/* */
#endif
static GkbdKeyboardDrawingGroupLevel groupsLevels[] =
{ {0, 1}, {0, 3}, {0, 0}, {0, 2} };
static GkbdKeyboardDrawingGroupLevel *pGroupsLevels[] = {
groupsLevels, groupsLevels + 1, groupsLevels + 2, groupsLevels + 3
};
GtkWidget *
xkb_layout_preview_create_widget (GtkBuilder * chooserDialog)
{
GtkWidget *kbdraw = gkbd_keyboard_drawing_new ();
gkbd_keyboard_drawing_set_groups_levels (GKBD_KEYBOARD_DRAWING
(kbdraw), pGroupsLevels);
return kbdraw;
}
void
xkb_layout_preview_set_drawing_layout (GtkWidget * kbdraw,
const gchar * id)
{
#ifdef HAVE_X11_EXTENSIONS_XKB_H
if (kbdraw != NULL) {
if (id != NULL) {
XklConfigRec *data;
char **p, *layout, *variant;
XkbComponentNamesRec component_names;
data = xkl_config_rec_new ();
if (xkl_config_rec_get_from_server (data, engine)) {
if ((p = data->layouts) != NULL)
g_strfreev (data->layouts);
if ((p = data->variants) != NULL)
g_strfreev (data->variants);
data->layouts = g_new0 (char *, 2);
data->variants = g_new0 (char *, 2);
if (gkbd_keyboard_config_split_items
(id, &layout, &variant)
&& variant != NULL) {
data->layouts[0] =
(layout ==
NULL) ? NULL :
g_strdup (layout);
data->variants[0] =
(variant ==
NULL) ? NULL :
g_strdup (variant);
} else {
data->layouts[0] =
(id ==
NULL) ? NULL : g_strdup (id);
data->variants[0] = NULL;
}
if (xkl_xkb_config_native_prepare
(engine, data, &component_names)) {
gkbd_keyboard_drawing_set_keyboard
(GKBD_KEYBOARD_DRAWING
(kbdraw), &component_names);
xkl_xkb_config_native_cleanup
(engine, &component_names);
}
}
g_object_unref (G_OBJECT (data));
} else
gkbd_keyboard_drawing_set_keyboard
(GKBD_KEYBOARD_DRAWING (kbdraw), NULL);
}
#endif
}

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="2.22"/>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkAdjustment" id="adjustment1">
<property name="lower">100</property>
<property name="upper">2000</property>
@@ -152,6 +152,55 @@
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkToolbar" id="language-toolbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="toolbar_style">icons</property>
<property name="show_arrow">False</property>
<property name="icon_size">1</property>
<style>
<class name="inline-toolbar"/>
</style>
<style>
<class name="inline-toolbar"/>
</style>
<child>
<object class="GtkToolButton" id="language_add">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="label" translatable="yes">Add Language</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="icon_name">list-add-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="language_remove">
<property name="use_action_appearance">False</property>
<property name="label" translatable="yes">Remove Language</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="icon_name">list-remove-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkVBox" id="vbox3">
<property name="can_focus">False</property>
@@ -159,6 +208,8 @@
<object class="GtkLabel" id="label23">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="label" translatable="yes">Add Language</property>
</object>
<packing>
<property name="expand">True</property>
@@ -173,9 +224,6 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="has_tooltip">True</property>
<property name="use_action_appearance">False</property>
<property name="relief">none</property>
<property name="uri">http://glade.gnome.org</property>
</object>
<packing>
<property name="expand">False</property>
@@ -190,52 +238,6 @@
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkToolbar" id="language-toolbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="toolbar_style">icons</property>
<property name="show_arrow">False</property>
<property name="icon_size">1</property>
<style>
<class name="inline-toolbar"/>
</style>
<child>
<object class="GtkToolButton" id="language_add">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
<property name="icon_name">list-add-symbolic</property>
<property name="label" translatable="yes">Add Language</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="language_remove">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
<property name="icon_name">list-remove-symbolic</property>
<property name="label" translatable="yes">Remove Language</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
@@ -259,12 +261,12 @@
<object class="GtkGrid" id="table1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="column_spacing">12</property>
<property name="row_spacing">6</property>
<property name="margin_top">12</property>
<property name="margin_bottom">12</property>
<property name="margin_left">12</property>
<property name="margin_right">12</property>
<property name="margin_top">12</property>
<property name="margin_bottom">12</property>
<property name="row_spacing">6</property>
<property name="column_spacing">12</property>
<child>
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
@@ -273,92 +275,92 @@
<property name="label" translatable="yes">Select a region (change will be applied the next time you log in)</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">2</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="region-box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkScrolledWindow" id="region-swindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<property name="halign">fill</property>
<property name="valign">fill</property>
<property name="vexpand">True</property>
<child>
<object class="GtkTreeView" id="region_selector">
<object class="GtkScrolledWindow" id="region-swindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">False</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="region-treeview-selection"/>
<property name="vexpand">True</property>
<property name="hscrollbar_policy">never</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="region_selector">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">False</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="region-treeview-selection"/>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkToolbar" id="region-toolbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="toolbar_style">icons</property>
<property name="show_arrow">False</property>
<property name="icon_size">1</property>
<style>
<class name="inline-toolbar"/>
</style>
<child>
<object class="GtkToolButton" id="region_add">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
<property name="icon_name">list-add-symbolic</property>
<property name="label" translatable="yes">Add Region</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="region_remove">
<object class="GtkToolbar" id="region-toolbar">
<property name="toolbar_style">icons</property>
<property name="show_arrow">False</property>
<property name="icon_size">1</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
<property name="icon_name">list-remove-symbolic</property>
<property name="label" translatable="yes">Remove Region</property>
<style>
<class name="inline-toolbar"/>
</style>
<child>
<object class="GtkToolButton" id="region_add">
<property name="use_action_appearance">False</property>
<property name="label" translatable="yes">Add Region</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="icon_name">list-add-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="region_remove">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="label" translatable="yes">Remove Region</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="icon_name">list-remove-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
@@ -616,8 +618,16 @@
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="position">1</property>
@@ -635,36 +645,43 @@
</packing>
</child>
<child>
<object class="GtkVBox" id="vbox1">
<object class="GtkVBox" id="vbox5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">10</property>
<property name="spacing">12</property>
<child>
<placeholder/>
<object class="GtkLabel" id="label24">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Select keyboards or other input sources</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkHBox" id="hbox2">
<object class="GtkHBox" id="hbox3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">12</property>
<child>
<object class="GtkVBox" id="vbox7">
<object class="GtkVBox" id="vbox6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkScrolledWindow" id="xkb_layouts_swindow">
<object class="GtkScrolledWindow" id="input_sources_swindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="xkb_layouts_selected">
<object class="GtkTreeView" id="active_input_sources">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="headers_visible">False</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection1"/>
</child>
</object>
</child>
</object>
@@ -675,7 +692,7 @@
</packing>
</child>
<child>
<object class="GtkToolbar" id="layouts-toolbar">
<object class="GtkToolbar" id="input-toolbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="toolbar_style">icons</property>
@@ -685,75 +702,166 @@
<class name="inline-toolbar"/>
</style>
<child>
<object class="GtkToolButton" id="xkb_layouts_add">
<object class="GtkToolItem" id="i_s_ar_item">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
<property name="icon_name">list-add-symbolic</property>
<property name="label" translatable="yes">Add Layout</property>
<child>
<object class="GtkBox" id="i_s_ar_box">
<property name="visible">True</property>
<child>
<object class="GtkButton" id="input_source_add">
<property name="visible">True</property>
<child internal-child="accessible">
<object class="AtkObject" id="i_s_a_a11y">
<property name="accessible-name" translatable="yes">Add Input Source</property>
</object>
</child>
<child>
<object class="GtkImage" id="i_s_a_image">
<property name="visible">True</property>
<property name="icon-name">list-add-symbolic</property>
<property name="icon-size">1</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton" id="input_source_remove">
<property name="visible">True</property>
<child internal-child="accessible">
<object class="AtkObject" id="i_s_r_a11y">
<property name="accessible-name" translatable="yes">Remove Input Source</property>
</object>
</child>
<child>
<object class="GtkImage" id="i_s_r_image">
<property name="visible">True</property>
<property name="icon-name">list-remove-symbolic</property>
<property name="icon-size">1</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="xkb_layouts_remove">
<object class="GtkSeparatorToolItem" id="sep1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
<property name="icon_name">list-remove-symbolic</property>
<property name="label" translatable="yes">Remove Layout</property>
<property name="draw">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
<property name="expand">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="xkb_layouts_move_up">
<object class="GtkToolItem" id="i_s_ud_item">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
<property name="icon_name">go-up-symbolic</property>
<property name="label" translatable="yes">Move Up</property>
<child>
<object class="GtkBox" id="i_s_ud_box">
<property name="visible">True</property>
<child>
<object class="GtkButton" id="input_source_move_up">
<property name="visible">True</property>
<child internal-child="accessible">
<object class="AtkObject" id="i_s_u_a11y">
<property name="accessible-name" translatable="yes">Move Input Source Up</property>
</object>
</child>
<child>
<object class="GtkImage" id="i_s_u_image">
<property name="visible">True</property>
<property name="icon-name">go-up-symbolic</property>
<property name="icon-size">1</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton" id="input_source_move_down">
<property name="visible">True</property>
<child internal-child="accessible">
<object class="AtkObject" id="i_s_d_a11y">
<property name="accessible-name" translatable="yes">Move Input Source Down</property>
</object>
</child>
<child>
<object class="GtkImage" id="i_s_d_image">
<property name="visible">True</property>
<property name="icon-name">go-down-symbolic</property>
<property name="icon-size">1</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="xkb_layouts_move_down">
<object class="GtkSeparatorToolItem" id="sep2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
<property name="icon_name">go-down-symbolic</property>
<property name="label" translatable="yes">Move Down</property>
<property name="draw">False</property>
<property name="hexpand">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
<property name="expand">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="xkb_layouts_show">
<object class="GtkToolItem" id="i_s_sp_item">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
<property name="icon_name">input-keyboard-symbolic</property>
<property name="label" translatable="yes">Preview Layout</property>
<child>
<object class="GtkBox" id="i_s_sp_box">
<property name="visible">True</property>
<child>
<object class="GtkButton" id="input_source_settings">
<property name="visible">True</property>
<child internal-child="accessible">
<object class="AtkObject" id="i_s_s_a11y">
<property name="accessible-name" translatable="yes">Input Source Settings</property>
</object>
</child>
<child>
<object class="GtkImage" id="i_s_s_image">
<property name="visible">True</property>
<property name="icon_name">preferences-system-symbolic</property>
<property name="icon_size">1</property>
<property name="pixel_size">16</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton" id="input_source_show">
<property name="visible">True</property>
<child internal-child="accessible">
<object class="AtkObject" id="i_s_p_a11y">
<property name="accessible-name" translatable="yes">Show Keyboard Layout</property>
</object>
</child>
<child>
<object class="GtkImage" id="i_s_p_image">
<property name="visible">True</property>
<property name="icon_name">input-keyboard-symbolic</property>
<property name="icon-size">1</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
@@ -769,174 +877,111 @@
</packing>
</child>
<child>
<object class="GtkVBox" id="vbox33">
<object class="GtkFrame" id="frame4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">12</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkVBox" id="vbox34">
<object class="GtkAlignment" id="alignment3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<property name="left_padding">12</property>
<child>
<object class="GtkRadioButton" id="chk_same_group">
<property name="label" translatable="yes">Use the same layout for all windows</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="chk_separate_group_per_window">
<property name="label" translatable="yes">Allow different layouts for individual windows</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">chk_same_group</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkAlignment" id="alignment1">
<object class="GtkGrid" id="shortcuts-grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="left_padding">12</property>
<property name="margin_top">6</property>
<property name="row_spacing">6</property>
<property name="column_spacing">6</property>
<child>
<object class="GtkVBox" id="vbox4">
<object class="GtkLabel" id="prev-source-label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkRadioButton" id="chk_new_windows_default_layout">
<property name="label" translatable="yes">New windows use the default layout</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="chk_new_windows_inherit_layout">
<property name="label" translatable="yes">New windows use the previous window's layout</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">chk_new_windows_default_layout</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<property name="xalign">0</property>
<property name="label" translatable="yes">Switch to previous source</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="prev-source-shortcut-label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">Ctrl+Alt+Space</property>
<style><class name="dim-label"/></style>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="next-source-label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Switch to next source</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="next-source-shortcut-label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">Ctrl+Alt+Shift+Space</property>
<style><class name="dim-label"/></style>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
<child>
<object class="GtkLinkButton" id="jump-to-shortcuts">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">Shortcut Settings</property>
<property name="halign">end</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
<property name="width">1</property>
<property name="height">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label2">
<child type="label">
<object class="GtkLabel" id="shortcuts-frame-label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Shortcuts</property>
<property name="use_markup">True</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkHButtonBox" id="hbuttonbox2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="xkb_layout_options">
<property name="label" translatable="yes">_Options...</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="has_tooltip">True</property>
<property name="tooltip_markup" translatable="yes">View and edit keyboard layout options</property>
<property name="tooltip_text" translatable="yes">View and edit keyboard layout options</property>
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="xkb_reset_to_defaults">
<property name="label" translatable="yes">Reset to De_faults</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="has_tooltip">True</property>
<property name="tooltip_markup" translatable="yes">Replace the current keyboard layout settings with the
default settings</property>
<property name="tooltip_text" translatable="yes">Replace the current keyboard layout settings with the
default settings</property>
<property name="use_action_appearance">False</property>
<property name="use_underline">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
<property name="position">1</property>
<property name="secondary">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
@@ -954,17 +999,17 @@ default settings</property>
</child>
</object>
<packing>
<property name="position">2</property>
<property name="position">3</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel" id="label46">
<object class="GtkLabel" id="label13">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Layouts</property>
<property name="label" translatable="yes">Input Sources</property>
</object>
<packing>
<property name="position">2</property>
<property name="position">3</property>
<property name="tab_fill">False</property>
</packing>
</child>
@@ -985,7 +1030,7 @@ default settings</property>
<property name="ypad">6</property>
<property name="label" translatable="yes">The login screen, system accounts and new user accounts use the system-wide Region and Language settings. You may change the system settings to match yours.</property>
<property name="wrap">True</property>
<property name="width-chars">60</property>
<property name="width_chars">60</property>
</object>
<packing>
<property name="right_attach">2</property>
@@ -1003,10 +1048,10 @@ default settings</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkTable" id="table4">
<property name="margin_top">12</property>
<property name="margin_left">12</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">12</property>
<property name="margin_top">12</property>
<property name="n_rows">3</property>
<property name="n_columns">2</property>
<property name="column_spacing">3</property>
@@ -1130,10 +1175,10 @@ default settings</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkTable" id="table5">
<property name="margin_left">12</property>
<property name="margin_top">12</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">12</property>
<property name="margin_top">12</property>
<property name="n_rows">3</property>
<property name="n_columns">2</property>
<property name="column_spacing">3</property>
@@ -1254,10 +1299,10 @@ default settings</property>
<child>
<object class="GtkButton" id="copy_settings_button">
<property name="label" translatable="yes">Copy Settings...</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
</object>
<packing>
<property name="left_attach">1</property>
@@ -1275,7 +1320,7 @@ default settings</property>
</child>
</object>
<packing>
<property name="position">3</property>
<property name="position">4</property>
</packing>
</child>
<child type="tab">
@@ -1285,7 +1330,7 @@ default settings</property>
<property name="label" translatable="yes">System</property>
</object>
<packing>
<property name="position">3</property>
<property name="position">4</property>
<property name="tab_fill">False</property>
</packing>
</child>

View File

@@ -1,42 +0,0 @@
Preface
This document describes the scenarios which have to be checked every time someone makes changes in the gnome keyboard handling modules, namely:
- libxklavier (project in freedesktop.org CVS)
- libgswitchit (virtual module in gnome.org CVS)
- gnome-settings-daemon (module in gnome-control-center, gnome.org CVS)
- gnome-keyboard-properties (module in gnome-control-center, gnome.org CVS)
- gnome-keyboard-indicator (module in gnome-applets, gnome.org CVS)
Changes in configuration
The tests should be performed under different configurations, controlled by several variables:
- "group per window" mode (GPW: on/off): visible in UI
- "default group" (DG: switchited off - or some group selected): only in GConf
- "keep indicators with the group" (IPW: on/off): only in GConf
- "hidden groups" (HG: some list of groups, can be empty): only in GConf
Taking that parameters DG and IPW only make sense when GPW is on, there are 5 combinations possible for the first 3 parameters. Taking that DG and IPW do not interfere, it is reasonable to test 3 combinations:
- GPW: off
- GPW: on, DG: off, IPW: off
- GPW: on, DG: {some value}, IPW: on
It is necessary to perform each test with the empty and non-empty HG. If HG is not empty, every test should be performed with both "enabled" and "hidden" groups.
Test cases
1. Open a terminal window. Type in some characters. Change the group using some chosen keyboard combination (default LAlt-RAlt or any other from the list of available ones). Type in some characters - ensure the group was changed.
2. Same as #1 - but change the group by clicking on the indicator applet
3. Same as #1 - but choose the group from the applet's menu
4. Set the US group in one terminal window. Create new terminal window. Ensure the group matches the DG setting.
5. Switch between two terminal windows using Alt-Tab. Ensure the behaviour matches the GPW setting and IPW setting.
6. Same as #5, but switch using the panel WindowList applet.
7. Change the settings in g-k-p, ensure the applet picks the changes.

View File

@@ -0,0 +1,529 @@
/*
* Copyright (C) 2012 Red Hat, Inc.
*
* Written by: Rui Matos <rmatos@redhat.com>
*
* 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.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/XKBlib.h>
#include <X11/extensions/XKBrules.h>
#include <gdk/gdkx.h>
#include "xkb-rules-db.h"
#ifndef DFLT_XKB_CONFIG_ROOT
#define DFLT_XKB_CONFIG_ROOT "/usr/share/X11/xkb"
#endif
#ifndef DFLT_XKB_RULES_FILE
#define DFLT_XKB_RULES_FILE "base"
#endif
#ifndef DFLT_XKB_LAYOUT
#define DFLT_XKB_LAYOUT "us"
#endif
#ifndef DFLT_XKB_MODEL
#define DFLT_XKB_MODEL "pc105"
#endif
typedef struct _Layout Layout;
struct _Layout
{
gchar *id;
gchar *xkb_name;
gchar *short_id;
gboolean is_variant;
const Layout *main_layout;
};
static GHashTable *layouts_by_short_id = NULL;
static GHashTable *layouts_by_iso639 = NULL;
static GHashTable *layouts_table = NULL;
static Layout *current_parser_layout = NULL;
static Layout *current_parser_variant = NULL;
static gchar **current_parser_text = NULL;
static gchar *current_parser_iso639Id = NULL;
static void
free_layout (gpointer data)
{
Layout *layout = data;
g_free (layout->id);
g_free (layout->xkb_name);
g_free (layout->short_id);
g_free (layout);
}
static void
get_xkb_values (gchar **rules,
XkbRF_VarDefsRec *var_defs)
{
Display *display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
*rules = NULL;
/* Get it from the X property or fallback on defaults */
if (!XkbRF_GetNamesProp (display, rules, var_defs) || !*rules) {
*rules = strdup (DFLT_XKB_RULES_FILE);
var_defs->model = strdup (DFLT_XKB_MODEL);
var_defs->layout = strdup (DFLT_XKB_LAYOUT);
var_defs->variant = NULL;
var_defs->options = NULL;
}
}
static void
free_xkb_var_defs (XkbRF_VarDefsRec *p)
{
if (p->model)
free (p->model);
if (p->layout)
free (p->layout);
if (p->variant)
free (p->variant);
if (p->options)
free (p->options);
free (p);
}
static gchar *
get_rules_file_path (void)
{
XkbRF_VarDefsRec *xkb_var_defs;
gchar *rules_file;
gchar *rules_path;
xkb_var_defs = calloc (1, sizeof (XkbRF_VarDefsRec));
get_xkb_values (&rules_file, xkb_var_defs);
if (rules_file[0] == '/')
rules_path = g_strdup_printf ("%s.xml", rules_file);
else
rules_path = g_strdup_printf ("%s/rules/%s.xml",
DFLT_XKB_CONFIG_ROOT,
rules_file);
free_xkb_var_defs (xkb_var_defs);
free (rules_file);
return rules_path;
}
static void
parse_start_element (GMarkupParseContext *context,
const gchar *element_name,
const gchar **attribute_names,
const gchar **attribute_values,
gpointer data,
GError **error)
{
if (current_parser_text)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"Expected character data but got element '%s'", element_name);
return;
}
if (strcmp (element_name, "name") == 0)
{
if (current_parser_variant)
current_parser_text = &current_parser_variant->xkb_name;
else if (current_parser_layout)
current_parser_text = &current_parser_layout->xkb_name;
}
else if (strcmp (element_name, "description") == 0)
{
if (current_parser_variant)
current_parser_text = &current_parser_variant->id;
else if (current_parser_layout)
current_parser_text = &current_parser_layout->id;
}
else if (strcmp (element_name, "shortDescription") == 0)
{
if (current_parser_variant)
current_parser_text = &current_parser_variant->short_id;
else if (current_parser_layout)
current_parser_text = &current_parser_layout->short_id;
}
else if (strcmp (element_name, "iso639Id") == 0)
{
current_parser_text = &current_parser_iso639Id;
}
else if (strcmp (element_name, "layout") == 0)
{
if (current_parser_layout)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"'layout' elements can't be nested");
return;
}
current_parser_layout = g_new0 (Layout, 1);
}
else if (strcmp (element_name, "variant") == 0)
{
if (current_parser_variant)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"'variant' elements can't be nested");
return;
}
if (!current_parser_layout)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"'variant' elements must be inside 'layout' elements");
return;
}
current_parser_variant = g_new0 (Layout, 1);
current_parser_variant->is_variant = TRUE;
current_parser_variant->main_layout = current_parser_layout;
}
}
static void
maybe_replace (GHashTable *table,
gchar *key,
Layout *new_layout)
{
Layout *layout;
gboolean exists;
gboolean replace = TRUE;
exists = g_hash_table_lookup_extended (table, key, NULL, (gpointer *)&layout);
if (exists)
replace = strlen (new_layout->id) < strlen (layout->id);
if (replace)
g_hash_table_replace (table, key, new_layout);
}
static void
parse_end_element (GMarkupParseContext *context,
const gchar *element_name,
gpointer data,
GError **error)
{
if (strcmp (element_name, "layout") == 0)
{
if (!current_parser_layout->id || !current_parser_layout->xkb_name)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"'layout' elements must enclose 'description' and 'name' elements");
return;
}
if (current_parser_layout->short_id)
maybe_replace (layouts_by_short_id,
current_parser_layout->short_id, current_parser_layout);
g_hash_table_replace (layouts_table,
current_parser_layout->id,
current_parser_layout);
current_parser_layout = NULL;
}
else if (strcmp (element_name, "variant") == 0)
{
if (!current_parser_variant->id || !current_parser_variant->xkb_name)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"'variant' elements must enclose 'description' and 'name' elements");
return;
}
if (current_parser_variant->short_id)
maybe_replace (layouts_by_short_id,
current_parser_variant->short_id, current_parser_variant);
g_hash_table_replace (layouts_table,
current_parser_variant->id,
current_parser_variant);
current_parser_variant = NULL;
}
else if (strcmp (element_name, "iso639Id") == 0)
{
if (!current_parser_iso639Id)
{
g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
"'iso639Id' elements must enclose text");
return;
}
if (current_parser_layout)
maybe_replace (layouts_by_iso639,
current_parser_iso639Id, current_parser_layout);
else if (current_parser_variant)
maybe_replace (layouts_by_iso639,
current_parser_iso639Id, current_parser_variant);
else
g_free (current_parser_iso639Id);
current_parser_iso639Id = NULL;
}
}
static void
parse_text (GMarkupParseContext *context,
const gchar *text,
gsize text_len,
gpointer data,
GError **error)
{
if (current_parser_text)
{
*current_parser_text = g_strndup (text, text_len);
current_parser_text = NULL;
}
}
static void
parse_error (GMarkupParseContext *context,
GError *error,
gpointer data)
{
free_layout (current_parser_layout);
free_layout (current_parser_variant);
g_free (current_parser_iso639Id);
}
static const GMarkupParser markup_parser = {
parse_start_element,
parse_end_element,
parse_text,
NULL,
parse_error
};
static void
parse_rules_file (void)
{
gchar *buffer;
gsize length;
GMarkupParseContext *context;
GError *error = NULL;
gchar *full_path = get_rules_file_path ();
g_file_get_contents (full_path, &buffer, &length, &error);
g_free (full_path);
if (error)
{
g_warning ("Failed to read XKB rules file: %s", error->message);
g_error_free (error);
return;
}
layouts_by_short_id = g_hash_table_new (g_str_hash, g_str_equal);
layouts_by_iso639 = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
/* This is the "master" table so it assumes memory "ownership". */
layouts_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, free_layout);
context = g_markup_parse_context_new (&markup_parser, 0, NULL, NULL);
g_markup_parse_context_parse (context, buffer, length, &error);
g_markup_parse_context_free (context);
g_free (buffer);
if (error)
{
g_warning ("Failed to parse XKB rules file: %s", error->message);
g_error_free (error);
g_hash_table_destroy (layouts_by_short_id);
g_hash_table_destroy (layouts_by_iso639);
g_hash_table_destroy (layouts_table);
layouts_table = NULL;
return;
}
}
static gboolean
ensure_rules_are_parsed (void)
{
if (!layouts_table)
parse_rules_file ();
return !!layouts_table;
}
static void
add_name_to_list (gpointer key,
gpointer value,
gpointer data)
{
GSList **list = data;
*list = g_slist_prepend (*list, key);
}
/**
* xkb_rules_db_get_all_layout_names:
*
* Returns a list of all layout names we know about.
*
* Return value: (transfer container): the list of layout names. The
* caller takes ownership of the #GSList but not of the strings
* themselves, those are internally allocated and must not be
* modified.
*/
GSList *
xkb_rules_db_get_all_layout_names (void)
{
GSList *layout_names = NULL;
if (!ensure_rules_are_parsed ())
return NULL;
g_hash_table_foreach (layouts_table, add_name_to_list, &layout_names);
return layout_names;
}
/**
* xkb_rules_db_get_layout_info:
* @name: layout's name about which to retrieve the info
* @short_name: (out) (allow-none) (transfer none): location to store
* the layout's short name, or %NULL
* @xkb_layout: (out) (allow-none) (transfer none): location to store
* the layout's XKB name, or %NULL
* @xkb_variant: (out) (allow-none) (transfer none): location to store
* the layout's XKB variant, or %NULL
*
* Retrieves information about a layout. Some layouts don't provide a
* short name (2 or 3 letters) or don't specify a XKB variant, in
* those cases @short_name or @xkb_variant are empty strings, i.e. "".
*
* If the given layout doesn't exist the return value is %FALSE and
* all the (out) parameters are set to %NULL.
*
* Return value: %TRUE if the layout exists or %FALSE otherwise.
*/
gboolean
xkb_rules_db_get_layout_info (const gchar *name,
const gchar **short_name,
const gchar **xkb_layout,
const gchar **xkb_variant)
{
const Layout *layout;
if (short_name)
*short_name = NULL;
if (xkb_layout)
*xkb_layout = NULL;
if (xkb_variant)
*xkb_variant = NULL;
if (!ensure_rules_are_parsed ())
return FALSE;
if (!g_hash_table_lookup_extended (layouts_table, name, NULL, (gpointer *)&layout))
return FALSE;
if (!layout->is_variant)
{
if (short_name)
*short_name = layout->short_id ? layout->short_id : "";
if (xkb_layout)
*xkb_layout = layout->xkb_name;
if (xkb_variant)
*xkb_variant = "";
}
else
{
if (short_name)
*short_name = layout->short_id ? layout->short_id :
layout->main_layout->short_id ? layout->main_layout->short_id : "";
if (xkb_layout)
*xkb_layout = layout->main_layout->xkb_name;
if (xkb_variant)
*xkb_variant = layout->xkb_name;
}
return TRUE;
}
/**
* xkb_rules_db_get_layout_info_for_language:
* @language: an ISO 639 code
* @name: (out) (allow-none) (transfer none): location to store the
* layout's name, or %NULL
* @short_name: (out) (allow-none) (transfer none): location to store
* the layout's short name, or %NULL
* @xkb_layout: (out) (allow-none) (transfer none): location to store
* the layout's XKB name, or %NULL
* @xkb_variant: (out) (allow-none) (transfer none): location to store
* the layout's XKB variant, or %NULL
*
* Retrieves the layout that better fits @language. It also fetches
* information about that layout like xkb_rules_db_get_layout_info().
*
* If the a layout can't be found the return value is %FALSE and all
* the (out) parameters are set to %NULL.
*
* Return value: %TRUE if a layout exists or %FALSE otherwise.
*/
gboolean
xkb_rules_db_get_layout_info_for_language (const gchar *language,
const gchar **name,
const gchar **short_name,
const gchar **xkb_layout,
const gchar **xkb_variant)
{
const Layout *layout;
if (name)
*name = NULL;
if (short_name)
*short_name = NULL;
if (xkb_layout)
*xkb_layout = NULL;
if (xkb_variant)
*xkb_variant = NULL;
if (!ensure_rules_are_parsed ())
return FALSE;
if (!g_hash_table_lookup_extended (layouts_by_iso639, language, NULL, (gpointer *)&layout))
if (!g_hash_table_lookup_extended (layouts_by_short_id, language, NULL, (gpointer *)&layout))
return FALSE;
if (name)
*name = layout->id;
if (!layout->is_variant)
{
if (short_name)
*short_name = layout->short_id ? layout->short_id : "";
if (xkb_layout)
*xkb_layout = layout->xkb_name;
if (xkb_variant)
*xkb_variant = "";
}
else
{
if (short_name)
*short_name = layout->short_id ? layout->short_id :
layout->main_layout->short_id ? layout->main_layout->short_id : "";
if (xkb_layout)
*xkb_layout = layout->main_layout->xkb_name;
if (xkb_variant)
*xkb_variant = layout->xkb_name;
}
return TRUE;
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (C) 2012 Red Hat, Inc.
*
* Written by: Rui Matos <rmatos@redhat.com>
*
* 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.
*/
#ifndef __XKB_RULES_DB_H__
#define __XKB_RULES_DB_H__
#include <glib.h>
GSList *xkb_rules_db_get_all_layout_names (void);
gboolean xkb_rules_db_get_layout_info (const gchar *name,
const gchar **short_name,
const gchar **xkb_layout,
const gchar **xkb_variant);
gboolean xkb_rules_db_get_layout_info_for_language (const gchar *language,
const gchar **name,
const gchar **short_name,
const gchar **xkb_layout,
const gchar **xkb_variant);
#endif /* __XKB_RULES_DB_H__ */