keyboard: Add common XKB options to the Typing shortcuts section
Both the compose key and the 3rd level chooser are common and useful enough to expose in the control center. Since these shortcuts are a small pre-defined set of only modifier keys we present them in combo cell renderers. https://bugzilla.gnome.org/show_bug.cgi?id=682069
This commit is contained in:
parent
4e0bc86e5b
commit
978ab40f3e
5 changed files with 736 additions and 62 deletions
|
@ -103,8 +103,8 @@ POLKIT_REQUIRED_VERSION=0.103
|
|||
GSD_REQUIRED_VERSION=3.5.2
|
||||
NETWORK_MANAGER_REQUIRED_VERSION=0.8.992
|
||||
LIBNOTIFY_REQUIRED_VERSION=0.7.3
|
||||
GNOME_DESKTOP_REQUIRED_VERSION=3.5.3
|
||||
SCHEMAS_REQUIRED_VERSION=3.5.3
|
||||
GNOME_DESKTOP_REQUIRED_VERSION=3.5.6
|
||||
SCHEMAS_REQUIRED_VERSION=3.5.5
|
||||
LIBWACOM_REQUIRED_VERSION=0.5
|
||||
CLUTTER_REQUIRED_VERSION=1.11.3
|
||||
GOA_REQUIRED_VERSION=3.5.90
|
||||
|
@ -130,7 +130,9 @@ PKG_CHECK_MODULES(DATETIME_PANEL, $COMMON_MODULES
|
|||
PKG_CHECK_MODULES(DISPLAY_PANEL, $COMMON_MODULES gnome-desktop-3.0 >= 3.1.0)
|
||||
PKG_CHECK_MODULES(INFO_PANEL, $COMMON_MODULES libgtop-2.0
|
||||
polkit-gobject-1 >= $POLKIT_REQUIRED_VERSION)
|
||||
PKG_CHECK_MODULES(KEYBOARD_PANEL, $COMMON_MODULES x11)
|
||||
PKG_CHECK_MODULES(KEYBOARD_PANEL, $COMMON_MODULES
|
||||
gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION
|
||||
x11)
|
||||
PKG_CHECK_MODULES(MEDIA_PANEL, $COMMON_MODULES)
|
||||
PKG_CHECK_MODULES(MOUSE_PANEL, $COMMON_MODULES xi >= 1.2
|
||||
gnome-settings-daemon >= $GSD_REQUIRED_VERSION x11)
|
||||
|
|
|
@ -10,6 +10,8 @@ libkeyboard_la_SOURCES = \
|
|||
cc-keyboard-panel.h \
|
||||
cc-keyboard-item.c \
|
||||
cc-keyboard-item.h \
|
||||
cc-keyboard-option.c \
|
||||
cc-keyboard-option.h \
|
||||
wm-common.c \
|
||||
wm-common.h \
|
||||
keyboard-general.c \
|
||||
|
|
449
panels/keyboard/cc-keyboard-option.c
Normal file
449
panels/keyboard/cc-keyboard-option.c
Normal file
|
@ -0,0 +1,449 @@
|
|||
/*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#define GNOME_DESKTOP_USE_UNSTABLE_API
|
||||
#include <libgnome-desktop/gnome-xkb-info.h>
|
||||
|
||||
#include "cc-keyboard-option.h"
|
||||
|
||||
#define CC_TYPE_KEYBOARD_OPTION (cc_keyboard_option_get_type ())
|
||||
#define CC_KEYBOARD_OPTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CC_TYPE_KEYBOARD_OPTION, CcKeyboardOption))
|
||||
#define CC_KEYBOARD_OPTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), CC_TYPE_KEYBOARD_OPTION, CcKeyboardOptionClass))
|
||||
#define CC_IS_KEYBOARD_OPTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CC_TYPE_KEYBOARD_OPTION))
|
||||
#define CC_IS_KEYBOARD_OPTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), CC_TYPE_KEYBOARD_OPTION))
|
||||
#define CC_KEYBOARD_OPTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), CC_TYPE_KEYBOARD_OPTION, CcKeyboardOptionClass))
|
||||
|
||||
#define INPUT_SOURCES_SCHEMA "org.gnome.desktop.input-sources"
|
||||
#define XKB_OPTIONS_KEY "xkb-options"
|
||||
|
||||
#define XKB_OPTION_GROUP_LVL3 "lv3"
|
||||
#define XKB_OPTION_GROUP_COMP "Compose key"
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_GROUP,
|
||||
PROP_DESCRIPTION
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CHANGED_SIGNAL,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
struct _CcKeyboardOption
|
||||
{
|
||||
GObject parent_object;
|
||||
|
||||
gchar *group;
|
||||
gchar *description;
|
||||
gchar *current_value;
|
||||
GtkListStore *store;
|
||||
|
||||
const gchar * const *whitelist;
|
||||
};
|
||||
|
||||
typedef struct _CcKeyboardOptionClass CcKeyboardOptionClass;
|
||||
struct _CcKeyboardOptionClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
static guint keyboard_option_signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static GnomeXkbInfo *xkb_info = NULL;
|
||||
static GSettings *input_sources_settings = NULL;
|
||||
static gchar **current_xkb_options = NULL;
|
||||
|
||||
static const gchar *xkb_option_lvl3_whitelist[] = {
|
||||
"lv3:switch",
|
||||
"lv3:menu_switch",
|
||||
"lv3:rwin_switch",
|
||||
"lv3:lalt_switch",
|
||||
"lv3:ralt_switch",
|
||||
"lv3:caps_switch",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const gchar *xkb_option_comp_whitelist[] = {
|
||||
"compose:ralt",
|
||||
"compose:rwin",
|
||||
"compose:menu",
|
||||
"compose:lctrl",
|
||||
"compose:rctrl",
|
||||
"compose:caps",
|
||||
NULL
|
||||
};
|
||||
|
||||
static GList *objects_list = NULL;
|
||||
|
||||
GType cc_keyboard_option_get_type (void);
|
||||
|
||||
G_DEFINE_TYPE (CcKeyboardOption, cc_keyboard_option, G_TYPE_OBJECT);
|
||||
|
||||
static gboolean
|
||||
strv_contains (const gchar * const *strv,
|
||||
const gchar *str)
|
||||
{
|
||||
const gchar * const *p = strv;
|
||||
for (p = strv; *p; p++)
|
||||
if (g_strcmp0 (*p, str) == 0)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
reload_setting (CcKeyboardOption *self)
|
||||
{
|
||||
gchar **iter;
|
||||
|
||||
for (iter = current_xkb_options; *iter; ++iter)
|
||||
if (strv_contains (self->whitelist, *iter))
|
||||
{
|
||||
if (g_strcmp0 (self->current_value, *iter) != 0)
|
||||
{
|
||||
g_free (self->current_value);
|
||||
self->current_value = g_strdup (*iter);
|
||||
g_signal_emit (self, keyboard_option_signals[CHANGED_SIGNAL], 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (*iter == NULL && self->current_value != NULL)
|
||||
{
|
||||
g_clear_pointer (&self->current_value, g_free);
|
||||
g_signal_emit (self, keyboard_option_signals[CHANGED_SIGNAL], 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
xkb_options_changed (GSettings *settings,
|
||||
gchar *key,
|
||||
gpointer data)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
g_strfreev (current_xkb_options);
|
||||
current_xkb_options = g_settings_get_strv (settings, key);
|
||||
|
||||
for (l = objects_list; l; l = l->next)
|
||||
reload_setting (CC_KEYBOARD_OPTION (l->data));
|
||||
}
|
||||
|
||||
static void
|
||||
cc_keyboard_option_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
CcKeyboardOption *self;
|
||||
|
||||
self = CC_KEYBOARD_OPTION (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_GROUP:
|
||||
g_value_set_string (value, self->group);
|
||||
break;
|
||||
case PROP_DESCRIPTION:
|
||||
g_value_set_string (value, self->description);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cc_keyboard_option_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
CcKeyboardOption *self;
|
||||
|
||||
self = CC_KEYBOARD_OPTION (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_GROUP:
|
||||
self->group = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_DESCRIPTION:
|
||||
self->description = g_value_dup_string (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cc_keyboard_option_init (CcKeyboardOption *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
cc_keyboard_option_finalize (GObject *object)
|
||||
{
|
||||
CcKeyboardOption *self = CC_KEYBOARD_OPTION (object);
|
||||
|
||||
g_clear_pointer (&self->group, g_free);
|
||||
g_clear_pointer (&self->description, g_free);
|
||||
g_clear_pointer (&self->current_value, g_free);
|
||||
g_clear_object (&self->store);
|
||||
|
||||
G_OBJECT_CLASS (cc_keyboard_option_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
cc_keyboard_option_constructed (GObject *object)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
GList *options, *l;
|
||||
gchar *option_id;
|
||||
CcKeyboardOption *self = CC_KEYBOARD_OPTION (object);
|
||||
|
||||
G_OBJECT_CLASS (cc_keyboard_option_parent_class)->constructed (object);
|
||||
|
||||
if (g_str_equal (self->group, XKB_OPTION_GROUP_LVL3))
|
||||
self->whitelist = xkb_option_lvl3_whitelist;
|
||||
else if (g_str_equal (self->group, XKB_OPTION_GROUP_COMP))
|
||||
self->whitelist = xkb_option_comp_whitelist;
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
|
||||
self->store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
|
||||
gtk_list_store_append (self->store, &iter);
|
||||
gtk_list_store_set (self->store, &iter,
|
||||
XKB_OPTION_DESCRIPTION_COLUMN, _("Disabled"),
|
||||
XKB_OPTION_ID_COLUMN, NULL,
|
||||
-1);
|
||||
options = gnome_xkb_info_get_options_for_group (xkb_info, self->group);
|
||||
for (l = options; l; l = l->next)
|
||||
{
|
||||
option_id = l->data;
|
||||
if (strv_contains (self->whitelist, option_id))
|
||||
{
|
||||
gtk_list_store_append (self->store, &iter);
|
||||
gtk_list_store_set (self->store, &iter,
|
||||
XKB_OPTION_DESCRIPTION_COLUMN,
|
||||
gnome_xkb_info_description_for_option (xkb_info, self->group, option_id),
|
||||
XKB_OPTION_ID_COLUMN,
|
||||
option_id,
|
||||
-1);
|
||||
}
|
||||
}
|
||||
g_list_free (options);
|
||||
|
||||
reload_setting (self);
|
||||
}
|
||||
|
||||
static void
|
||||
cc_keyboard_option_class_init (CcKeyboardOptionClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->get_property = cc_keyboard_option_get_property;
|
||||
gobject_class->set_property = cc_keyboard_option_set_property;
|
||||
gobject_class->finalize = cc_keyboard_option_finalize;
|
||||
gobject_class->constructed = cc_keyboard_option_constructed;
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_GROUP,
|
||||
g_param_spec_string ("group",
|
||||
"group",
|
||||
"xkb option group identifier",
|
||||
NULL,
|
||||
G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_DESCRIPTION,
|
||||
g_param_spec_string ("description",
|
||||
"description",
|
||||
"translated option description",
|
||||
NULL,
|
||||
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
|
||||
|
||||
keyboard_option_signals[CHANGED_SIGNAL] = g_signal_new ("changed",
|
||||
CC_TYPE_KEYBOARD_OPTION,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
}
|
||||
|
||||
GList *
|
||||
cc_keyboard_option_get_all (void)
|
||||
{
|
||||
if (objects_list)
|
||||
return objects_list;
|
||||
|
||||
xkb_info = gnome_xkb_info_new ();
|
||||
|
||||
input_sources_settings = g_settings_new (INPUT_SOURCES_SCHEMA);
|
||||
|
||||
g_signal_connect (input_sources_settings, "changed::" XKB_OPTIONS_KEY,
|
||||
G_CALLBACK (xkb_options_changed), NULL);
|
||||
|
||||
xkb_options_changed (input_sources_settings, XKB_OPTIONS_KEY, NULL);
|
||||
|
||||
objects_list = g_list_prepend (objects_list,
|
||||
g_object_new (CC_TYPE_KEYBOARD_OPTION,
|
||||
"group", XKB_OPTION_GROUP_LVL3,
|
||||
"description", _("Alternative Characters Key"),
|
||||
NULL));
|
||||
objects_list = g_list_prepend (objects_list,
|
||||
g_object_new (CC_TYPE_KEYBOARD_OPTION,
|
||||
"group", XKB_OPTION_GROUP_COMP,
|
||||
"description", _("Compose Key"),
|
||||
NULL));
|
||||
return objects_list;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
cc_keyboard_option_get_description (CcKeyboardOption *self)
|
||||
{
|
||||
g_return_val_if_fail (CC_IS_KEYBOARD_OPTION (self), NULL);
|
||||
|
||||
return self->description;
|
||||
}
|
||||
|
||||
GtkListStore *
|
||||
cc_keyboard_option_get_store (CcKeyboardOption *self)
|
||||
{
|
||||
g_return_val_if_fail (CC_IS_KEYBOARD_OPTION (self), NULL);
|
||||
|
||||
return self->store;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
cc_keyboard_option_get_current_value_description (CcKeyboardOption *self)
|
||||
{
|
||||
g_return_val_if_fail (CC_IS_KEYBOARD_OPTION (self), NULL);
|
||||
|
||||
if (!self->current_value)
|
||||
return _("Disabled");
|
||||
|
||||
return gnome_xkb_info_description_for_option (xkb_info, self->group, self->current_value);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_value (const gchar *value)
|
||||
{
|
||||
gchar **p;
|
||||
|
||||
for (p = current_xkb_options; *p; ++p)
|
||||
if (g_str_equal (*p, value))
|
||||
{
|
||||
g_free (*p);
|
||||
break;
|
||||
}
|
||||
|
||||
for (++p; *p; ++p)
|
||||
*(p - 1) = *p;
|
||||
|
||||
*(p - 1) = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
add_value (const gchar *value)
|
||||
{
|
||||
gchar **new_xkb_options;
|
||||
gchar **a, **b;
|
||||
|
||||
new_xkb_options = g_new0 (gchar *, g_strv_length (current_xkb_options) + 2);
|
||||
|
||||
a = new_xkb_options;
|
||||
for (b = current_xkb_options; *b; ++a, ++b)
|
||||
*a = g_strdup (*b);
|
||||
|
||||
*a = g_strdup (value);
|
||||
|
||||
g_strfreev (current_xkb_options);
|
||||
current_xkb_options = new_xkb_options;
|
||||
}
|
||||
|
||||
static void
|
||||
replace_value (const gchar *old,
|
||||
const gchar *new)
|
||||
{
|
||||
gchar **iter;
|
||||
|
||||
if (g_str_equal (old, new))
|
||||
return;
|
||||
|
||||
for (iter = current_xkb_options; *iter; ++iter)
|
||||
if (g_str_equal (*iter, old))
|
||||
{
|
||||
g_free (*iter);
|
||||
*iter = g_strdup (new);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cc_keyboard_option_set_selection (CcKeyboardOption *self,
|
||||
GtkTreeIter *iter)
|
||||
{
|
||||
gchar *new_value = NULL;
|
||||
|
||||
g_return_if_fail (CC_IS_KEYBOARD_OPTION (self));
|
||||
|
||||
gtk_tree_model_get (GTK_TREE_MODEL (self->store), iter,
|
||||
XKB_OPTION_ID_COLUMN, &new_value,
|
||||
-1);
|
||||
|
||||
if (!new_value)
|
||||
{
|
||||
if (self->current_value)
|
||||
remove_value (self->current_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (self->current_value)
|
||||
replace_value (self->current_value, new_value);
|
||||
else
|
||||
add_value (new_value);
|
||||
}
|
||||
|
||||
g_settings_set_strv (input_sources_settings, XKB_OPTIONS_KEY,
|
||||
(const gchar * const *) current_xkb_options);
|
||||
|
||||
g_free (new_value);
|
||||
}
|
||||
|
||||
void
|
||||
cc_keyboard_option_clear_all (void)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = objects_list; l; l = l->next)
|
||||
g_object_unref (l->data);
|
||||
|
||||
g_clear_pointer (&objects_list, g_list_free);
|
||||
g_clear_pointer (¤t_xkb_options, g_strfreev);
|
||||
g_clear_object (&input_sources_settings);
|
||||
g_clear_object (&xkb_info);
|
||||
}
|
48
panels/keyboard/cc-keyboard-option.h
Normal file
48
panels/keyboard/cc-keyboard-option.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __CC_KEYBOARD_OPTION_H__
|
||||
#define __CC_KEYBOARD_OPTION_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
enum
|
||||
{
|
||||
XKB_OPTION_DESCRIPTION_COLUMN,
|
||||
XKB_OPTION_ID_COLUMN,
|
||||
XKB_OPTION_N_COLUMNS
|
||||
};
|
||||
|
||||
typedef struct _CcKeyboardOption CcKeyboardOption;
|
||||
|
||||
GList * cc_keyboard_option_get_all (void);
|
||||
const gchar * cc_keyboard_option_get_description (CcKeyboardOption *self);
|
||||
GtkListStore * cc_keyboard_option_get_store (CcKeyboardOption *self);
|
||||
const gchar * cc_keyboard_option_get_current_value_description (CcKeyboardOption *self);
|
||||
void cc_keyboard_option_set_selection (CcKeyboardOption *self,
|
||||
GtkTreeIter *iter);
|
||||
void cc_keyboard_option_clear_all (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __CC_KEYBOARD_OPTION_H__ */
|
|
@ -22,8 +22,10 @@
|
|||
#include <config.h>
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "keyboard-shortcuts.h"
|
||||
#include "cc-keyboard-item.h"
|
||||
#include "cc-keyboard-option.h"
|
||||
#include "wm-common.h"
|
||||
|
||||
#define BINDINGS_SCHEMA "org.gnome.settings-daemon.plugins.media-keys"
|
||||
|
@ -53,10 +55,17 @@ typedef struct
|
|||
char *name; /* GSettings schema path, or GSettings key name depending on type */
|
||||
} KeyListEntry;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SHORTCUT_TYPE_KEY_ENTRY,
|
||||
SHORTCUT_TYPE_XKB_OPTION,
|
||||
} ShortcutType;
|
||||
|
||||
enum
|
||||
{
|
||||
DETAIL_DESCRIPTION_COLUMN,
|
||||
DETAIL_KEYENTRY_COLUMN,
|
||||
DETAIL_TYPE_COLUMN,
|
||||
DETAIL_N_COLUMNS
|
||||
};
|
||||
|
||||
|
@ -668,34 +677,53 @@ accel_set_func (GtkTreeViewColumn *tree_column,
|
|||
GtkTreeIter *iter,
|
||||
gpointer data)
|
||||
{
|
||||
CcKeyboardItem *item;
|
||||
gpointer entry;
|
||||
ShortcutType type;
|
||||
|
||||
gtk_tree_model_get (model, iter,
|
||||
DETAIL_KEYENTRY_COLUMN, &item,
|
||||
DETAIL_KEYENTRY_COLUMN, &entry,
|
||||
DETAIL_TYPE_COLUMN, &type,
|
||||
-1);
|
||||
|
||||
if (item == NULL)
|
||||
g_object_set (cell,
|
||||
"visible", FALSE,
|
||||
NULL);
|
||||
else if (! item->editable)
|
||||
g_object_set (cell,
|
||||
"visible", TRUE,
|
||||
"editable", FALSE,
|
||||
"accel-key", item->keyval,
|
||||
"accel-mods", item->mask,
|
||||
"keycode", item->keycode,
|
||||
"style", PANGO_STYLE_ITALIC,
|
||||
NULL);
|
||||
else
|
||||
g_object_set (cell,
|
||||
"visible", TRUE,
|
||||
"editable", TRUE,
|
||||
"accel-key", item->keyval,
|
||||
"accel-mods", item->mask,
|
||||
"keycode", item->keycode,
|
||||
"style", PANGO_STYLE_NORMAL,
|
||||
NULL);
|
||||
gtk_cell_renderer_set_visible (cell, FALSE);
|
||||
|
||||
if (type == SHORTCUT_TYPE_XKB_OPTION &&
|
||||
GTK_IS_CELL_RENDERER_COMBO (cell))
|
||||
{
|
||||
CcKeyboardOption *option = entry;
|
||||
|
||||
gtk_cell_renderer_set_visible (cell, TRUE);
|
||||
g_object_set (cell,
|
||||
"model", cc_keyboard_option_get_store (option),
|
||||
"text", cc_keyboard_option_get_current_value_description (option),
|
||||
NULL);
|
||||
}
|
||||
else if (type == SHORTCUT_TYPE_KEY_ENTRY &&
|
||||
GTK_IS_CELL_RENDERER_TEXT (cell) &&
|
||||
!GTK_IS_CELL_RENDERER_COMBO (cell) &&
|
||||
entry != NULL)
|
||||
{
|
||||
CcKeyboardItem *item = entry;
|
||||
|
||||
gtk_cell_renderer_set_visible (cell, TRUE);
|
||||
|
||||
if (item->editable)
|
||||
g_object_set (cell,
|
||||
"editable", TRUE,
|
||||
"accel-key", item->keyval,
|
||||
"accel-mods", item->mask,
|
||||
"keycode", item->keycode,
|
||||
"style", PANGO_STYLE_NORMAL,
|
||||
NULL);
|
||||
else
|
||||
g_object_set (cell,
|
||||
"editable", FALSE,
|
||||
"accel-key", item->keyval,
|
||||
"accel-mods", item->mask,
|
||||
"keycode", item->keycode,
|
||||
"style", PANGO_STYLE_ITALIC,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -705,21 +733,34 @@ description_set_func (GtkTreeViewColumn *tree_column,
|
|||
GtkTreeIter *iter,
|
||||
gpointer data)
|
||||
{
|
||||
gchar *description;
|
||||
CcKeyboardItem *item;
|
||||
ShortcutType type;
|
||||
|
||||
gtk_tree_model_get (model, iter,
|
||||
DETAIL_DESCRIPTION_COLUMN, &description,
|
||||
DETAIL_KEYENTRY_COLUMN, &item,
|
||||
DETAIL_TYPE_COLUMN, &type,
|
||||
-1);
|
||||
|
||||
if (item != NULL)
|
||||
g_object_set (cell,
|
||||
"editable", FALSE,
|
||||
"text", item->description != NULL ?
|
||||
item->description : _("<Unknown Action>"),
|
||||
NULL);
|
||||
if (type == SHORTCUT_TYPE_XKB_OPTION)
|
||||
{
|
||||
g_object_set (cell, "text", description, NULL);
|
||||
}
|
||||
else
|
||||
g_object_set (cell,
|
||||
"editable", FALSE, NULL);
|
||||
{
|
||||
if (item != NULL)
|
||||
g_object_set (cell,
|
||||
"editable", FALSE,
|
||||
"text", item->description != NULL ?
|
||||
item->description : _("<Unknown Action>"),
|
||||
NULL);
|
||||
else
|
||||
g_object_set (cell,
|
||||
"editable", FALSE, NULL);
|
||||
}
|
||||
|
||||
g_free (description);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -730,18 +771,42 @@ shortcut_selection_changed (GtkTreeSelection *selection, gpointer data)
|
|||
GtkTreeIter iter;
|
||||
CcKeyboardItem *item;
|
||||
gboolean can_remove;
|
||||
ShortcutType type;
|
||||
|
||||
can_remove = FALSE;
|
||||
if (gtk_tree_selection_get_selected (selection, &model, &iter))
|
||||
{
|
||||
gtk_tree_model_get (model, &iter, DETAIL_KEYENTRY_COLUMN, &item, -1);
|
||||
if (item && item->command != NULL && item->editable)
|
||||
gtk_tree_model_get (model, &iter,
|
||||
DETAIL_KEYENTRY_COLUMN, &item,
|
||||
DETAIL_TYPE_COLUMN, &type,
|
||||
-1);
|
||||
if (type == SHORTCUT_TYPE_KEY_ENTRY &&
|
||||
item && item->command != NULL && item->editable)
|
||||
can_remove = TRUE;
|
||||
}
|
||||
|
||||
gtk_widget_set_sensitive (button, can_remove);
|
||||
}
|
||||
|
||||
static void
|
||||
fill_xkb_options_shortcuts (GtkTreeModel *model)
|
||||
{
|
||||
GList *l;
|
||||
GtkTreeIter iter;
|
||||
|
||||
for (l = cc_keyboard_option_get_all (); l; l = l->next)
|
||||
{
|
||||
CcKeyboardOption *option = l->data;
|
||||
|
||||
gtk_list_store_append (GTK_LIST_STORE (model), &iter);
|
||||
gtk_list_store_set (GTK_LIST_STORE (model), &iter,
|
||||
DETAIL_DESCRIPTION_COLUMN, cc_keyboard_option_get_description (option),
|
||||
DETAIL_KEYENTRY_COLUMN, option,
|
||||
DETAIL_TYPE_COLUMN, SHORTCUT_TYPE_XKB_OPTION,
|
||||
-1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
section_selection_changed (GtkTreeSelection *selection, gpointer data)
|
||||
{
|
||||
|
@ -769,7 +834,6 @@ section_selection_changed (GtkTreeSelection *selection, gpointer data)
|
|||
g_free (description);
|
||||
return;
|
||||
}
|
||||
g_free (description);
|
||||
|
||||
gtk_widget_set_sensitive (WID (builder, "remove-toolbutton"), FALSE);
|
||||
|
||||
|
@ -787,8 +851,14 @@ section_selection_changed (GtkTreeSelection *selection, gpointer data)
|
|||
gtk_list_store_set (GTK_LIST_STORE (shortcut_model), &new_row,
|
||||
DETAIL_DESCRIPTION_COLUMN, item->description,
|
||||
DETAIL_KEYENTRY_COLUMN, item,
|
||||
DETAIL_TYPE_COLUMN, SHORTCUT_TYPE_KEY_ENTRY,
|
||||
-1);
|
||||
}
|
||||
|
||||
if (g_str_equal (description, _("Typing")))
|
||||
fill_xkb_options_shortcuts (shortcut_model);
|
||||
|
||||
g_free (description);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -907,6 +977,7 @@ start_editing_cb (GtkTreeView *tree_view,
|
|||
{
|
||||
GtkTreePath *path;
|
||||
GtkTreeViewColumn *column;
|
||||
GtkCellRenderer *cell = user_data;
|
||||
|
||||
if (event->window != gtk_tree_view_get_bin_window (tree_view))
|
||||
return FALSE;
|
||||
|
@ -920,32 +991,41 @@ start_editing_cb (GtkTreeView *tree_view,
|
|||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
CcKeyboardItem *item;
|
||||
ShortcutType type;
|
||||
|
||||
model = gtk_tree_view_get_model (tree_view);
|
||||
gtk_tree_model_get_iter (model, &iter, path);
|
||||
gtk_tree_model_get (model, &iter,
|
||||
DETAIL_KEYENTRY_COLUMN, &item,
|
||||
DETAIL_TYPE_COLUMN, &type,
|
||||
-1);
|
||||
|
||||
if (type == SHORTCUT_TYPE_XKB_OPTION)
|
||||
{
|
||||
gtk_tree_path_free (path);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* if only the accel can be edited on the selected row
|
||||
* always select the accel column */
|
||||
if (item->desc_editable &&
|
||||
column == gtk_tree_view_get_column (tree_view, 0))
|
||||
{
|
||||
gtk_widget_grab_focus (GTK_WIDGET (tree_view));
|
||||
gtk_tree_view_set_cursor (tree_view, path,
|
||||
gtk_tree_view_get_column (tree_view, 0),
|
||||
gtk_tree_view_set_cursor (tree_view,
|
||||
path,
|
||||
column,
|
||||
FALSE);
|
||||
update_custom_shortcut (model, &iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_grab_focus (GTK_WIDGET (tree_view));
|
||||
gtk_tree_view_set_cursor (tree_view,
|
||||
path,
|
||||
item->desc_editable ? column :
|
||||
gtk_tree_view_get_column (tree_view, 1),
|
||||
TRUE);
|
||||
gtk_tree_view_set_cursor_on_cell (tree_view,
|
||||
path,
|
||||
gtk_tree_view_get_column (tree_view, 1),
|
||||
cell,
|
||||
TRUE);
|
||||
}
|
||||
g_signal_stop_emission_by_name (tree_view, "button_press_event");
|
||||
gtk_tree_path_free (path);
|
||||
|
@ -954,39 +1034,47 @@ start_editing_cb (GtkTreeView *tree_view,
|
|||
}
|
||||
|
||||
static void
|
||||
start_editing_kb_cb (GtkTreeView *treeview,
|
||||
GtkTreePath *path,
|
||||
GtkTreeViewColumn *column,
|
||||
gpointer user_data)
|
||||
start_editing_kb_cb (GtkTreeView *treeview,
|
||||
GtkTreePath *path,
|
||||
GtkTreeViewColumn *column,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
CcKeyboardItem *item;
|
||||
ShortcutType type;
|
||||
GtkCellRenderer *cell = user_data;
|
||||
|
||||
model = gtk_tree_view_get_model (treeview);
|
||||
gtk_tree_model_get_iter (model, &iter, path);
|
||||
gtk_tree_model_get (model, &iter,
|
||||
DETAIL_KEYENTRY_COLUMN, &item,
|
||||
DETAIL_TYPE_COLUMN, &type,
|
||||
-1);
|
||||
|
||||
if (type == SHORTCUT_TYPE_XKB_OPTION)
|
||||
return;
|
||||
|
||||
/* if only the accel can be edited on the selected row
|
||||
* always select the accel column */
|
||||
if (item->desc_editable &&
|
||||
column == gtk_tree_view_get_column (treeview, 0))
|
||||
{
|
||||
gtk_widget_grab_focus (GTK_WIDGET (treeview));
|
||||
gtk_tree_view_set_cursor (treeview, path,
|
||||
gtk_tree_view_get_column (treeview, 0),
|
||||
gtk_tree_view_set_cursor (treeview,
|
||||
path,
|
||||
column,
|
||||
FALSE);
|
||||
update_custom_shortcut (model, &iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_grab_focus (GTK_WIDGET (treeview));
|
||||
gtk_tree_view_set_cursor (treeview,
|
||||
path,
|
||||
gtk_tree_view_get_column (treeview, 1),
|
||||
TRUE);
|
||||
gtk_tree_view_set_cursor_on_cell (treeview,
|
||||
path,
|
||||
gtk_tree_view_get_column (treeview, 1),
|
||||
cell,
|
||||
TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1465,6 +1553,74 @@ sections_separator_func (GtkTreeModel *model,
|
|||
return type == BINDING_GROUP_SEPARATOR;
|
||||
}
|
||||
|
||||
static void
|
||||
xkb_options_combo_changed (GtkCellRendererCombo *combo,
|
||||
gchar *model_path,
|
||||
GtkTreeIter *model_iter,
|
||||
gpointer data)
|
||||
{
|
||||
GtkTreeView *shortcut_treeview;
|
||||
GtkTreeModel *shortcut_model;
|
||||
GtkTreeIter shortcut_iter;
|
||||
GtkTreeSelection *selection;
|
||||
CcKeyboardOption *option;
|
||||
ShortcutType type;
|
||||
GtkBuilder *builder = data;
|
||||
|
||||
shortcut_treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder, "shortcut_treeview"));
|
||||
selection = gtk_tree_view_get_selection (shortcut_treeview);
|
||||
if (!gtk_tree_selection_get_selected (selection, &shortcut_model, &shortcut_iter))
|
||||
return;
|
||||
|
||||
gtk_tree_model_get (shortcut_model, &shortcut_iter,
|
||||
DETAIL_KEYENTRY_COLUMN, &option,
|
||||
DETAIL_TYPE_COLUMN, &type,
|
||||
-1);
|
||||
|
||||
if (type != SHORTCUT_TYPE_XKB_OPTION)
|
||||
return;
|
||||
|
||||
cc_keyboard_option_set_selection (option, model_iter);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
poke_xkb_option_row (GtkTreeModel *model,
|
||||
GtkTreePath *path,
|
||||
GtkTreeIter *iter,
|
||||
gpointer option)
|
||||
{
|
||||
gpointer item;
|
||||
|
||||
gtk_tree_model_get (model, iter,
|
||||
DETAIL_KEYENTRY_COLUMN, &item,
|
||||
-1);
|
||||
|
||||
if (item != option)
|
||||
return FALSE;
|
||||
|
||||
gtk_tree_model_row_changed (model, path, iter);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
xkb_option_changed (CcKeyboardOption *option,
|
||||
gpointer data)
|
||||
{
|
||||
GtkTreeModel *model = data;
|
||||
|
||||
gtk_tree_model_foreach (model, poke_xkb_option_row, option);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_keyboard_options (GtkListStore *store)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = cc_keyboard_option_get_all (); l; l = l->next)
|
||||
g_signal_connect (l->data, "changed",
|
||||
G_CALLBACK (xkb_option_changed), store);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_dialog (CcPanel *panel, GtkBuilder *builder)
|
||||
{
|
||||
|
@ -1529,11 +1685,6 @@ setup_dialog (CcPanel *panel, GtkBuilder *builder)
|
|||
|
||||
binding_settings = g_settings_new (BINDINGS_SCHEMA);
|
||||
|
||||
g_signal_connect (treeview, "button_press_event",
|
||||
G_CALLBACK (start_editing_cb), builder);
|
||||
g_signal_connect (treeview, "row-activated",
|
||||
G_CALLBACK (start_editing_kb_cb), NULL);
|
||||
|
||||
renderer = gtk_cell_renderer_text_new ();
|
||||
g_object_set (G_OBJECT (renderer), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
|
||||
|
||||
|
@ -1548,10 +1699,14 @@ setup_dialog (CcPanel *panel, GtkBuilder *builder)
|
|||
"accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_OTHER,
|
||||
NULL);
|
||||
|
||||
g_signal_connect (treeview, "button_press_event",
|
||||
G_CALLBACK (start_editing_cb), renderer);
|
||||
g_signal_connect (treeview, "row-activated",
|
||||
G_CALLBACK (start_editing_kb_cb), renderer);
|
||||
|
||||
g_signal_connect (renderer, "accel_edited",
|
||||
G_CALLBACK (accel_edited_callback),
|
||||
treeview);
|
||||
|
||||
g_signal_connect (renderer, "accel_cleared",
|
||||
G_CALLBACK (accel_cleared_callback),
|
||||
treeview);
|
||||
|
@ -1561,12 +1716,28 @@ setup_dialog (CcPanel *panel, GtkBuilder *builder)
|
|||
gtk_tree_view_column_set_resizable (column, FALSE);
|
||||
gtk_tree_view_column_set_expand (column, FALSE);
|
||||
|
||||
renderer = (GtkCellRenderer *) g_object_new (GTK_TYPE_CELL_RENDERER_COMBO,
|
||||
"has-entry", FALSE,
|
||||
"text-column", XKB_OPTION_DESCRIPTION_COLUMN,
|
||||
"editable", TRUE,
|
||||
"ellipsize", PANGO_ELLIPSIZE_END,
|
||||
"width-chars", 25,
|
||||
NULL);
|
||||
g_signal_connect (renderer, "changed",
|
||||
G_CALLBACK (xkb_options_combo_changed), builder);
|
||||
|
||||
gtk_tree_view_column_pack_end (column, renderer, FALSE);
|
||||
|
||||
gtk_tree_view_column_set_cell_data_func (column, renderer, accel_set_func, NULL, NULL);
|
||||
|
||||
gtk_tree_view_append_column (treeview, column);
|
||||
|
||||
model = gtk_list_store_new (DETAIL_N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER);
|
||||
model = gtk_list_store_new (DETAIL_N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_INT);
|
||||
gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (model));
|
||||
g_object_unref (model);
|
||||
|
||||
setup_keyboard_options (model);
|
||||
|
||||
widget = GTK_WIDGET (gtk_builder_get_object (builder, "actions_swindow"));
|
||||
context = gtk_widget_get_style_context (widget);
|
||||
gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
|
||||
|
@ -1639,4 +1810,6 @@ keyboard_shortcuts_dispose (CcPanel *panel)
|
|||
}
|
||||
|
||||
g_clear_object (&binding_settings);
|
||||
|
||||
cc_keyboard_option_clear_all ();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue