Patch from Bastien Nocera to to handle keycodes as well as keysyms.

Tue Nov 18 12:23:26 2003  Jonathan Blandford  <jrb@redhat.com>

	* eggcellrendererkeys.[ch]: Patch from Bastien Nocera to to handle
	keycodes as well as keysyms.

	* eggaccelerators.[ch]: handle keycodes.

	* gnome-keybinding-properties.c: handle keycodes.
This commit is contained in:
Jonathan Blandford 2003-11-18 17:23:06 +00:00 committed by Jonathan Blandford
parent ec488e37c0
commit 5f2e3042d9
6 changed files with 207 additions and 38 deletions

View file

@ -1,3 +1,12 @@
Tue Nov 18 12:23:26 2003 Jonathan Blandford <jrb@redhat.com>
* eggcellrendererkeys.[ch]: Patch from Bastien Nocera to to handle
keycodes as well as keysyms.
* eggaccelerators.[ch]: handle keycodes.
* gnome-keybinding-properties.c: handle keycodes.
2003-10-28 Jody Goldberg <jody@gnome.org>
* Release 2.5.0

View file

@ -20,6 +20,7 @@
#include "eggaccelerators.h"
#include <stdlib.h>
#include <string.h>
#include <gdk/gdkx.h>
#include <gdk/gdkkeysyms.h>
@ -175,6 +176,13 @@ is_hyper (const gchar *string)
(string[6] == '>'));
}
static inline gboolean
is_keycode (const gchar *string)
{
return ((string[0] == '0') &&
(string[1] == 'x'));
}
/**
* egg_accelerator_parse_virtual:
* @accelerator: string representing an accelerator
@ -203,6 +211,7 @@ is_hyper (const gchar *string)
gboolean
egg_accelerator_parse_virtual (const gchar *accelerator,
guint *accelerator_key,
guint *keycode,
EggVirtualModifierType *accelerator_mods)
{
guint keyval;
@ -214,6 +223,8 @@ egg_accelerator_parse_virtual (const gchar *accelerator,
*accelerator_key = 0;
if (accelerator_mods)
*accelerator_mods = 0;
if (keycode)
*keycode = 0;
g_return_val_if_fail (accelerator != NULL, FALSE);
@ -314,12 +325,37 @@ egg_accelerator_parse_virtual (const gchar *accelerator,
else
{
keyval = gdk_keyval_from_name (accelerator);
if (keyval == 0)
bad_keyval = TRUE;
{
/* If keyval is 0, than maybe it's a keycode. Check for 0x## */
if (len >= 4 && is_keycode (accelerator))
{
char keystring[5];
gchar *endptr;
gint tmp_keycode;
memcpy (keystring, accelerator, 4);
keystring [4] = '\000';
tmp_keycode = strtol (keystring, &endptr, 16);
if (endptr == NULL || *endptr != '\000')
{
bad_keyval = TRUE;
}
else
{
*keycode = tmp_keycode;
/* 0x00 is an invalid keycode too. */
if (*keycode == 0)
bad_keyval = TRUE;
}
}
}
accelerator += len;
len -= len;
len -= len;
}
}
@ -347,6 +383,7 @@ egg_accelerator_parse_virtual (const gchar *accelerator,
*/
gchar*
egg_virtual_accelerator_name (guint accelerator_key,
guint keycode,
EggVirtualModifierType accelerator_mods)
{
static const gchar text_release[] = "<Release>";
@ -366,9 +403,16 @@ egg_virtual_accelerator_name (guint accelerator_key,
accelerator_mods &= EGG_VIRTUAL_MODIFIER_MASK;
keyval_name = gdk_keyval_name (gdk_keyval_to_lower (accelerator_key));
if (!keyval_name)
keyval_name = "";
if (!accelerator_key)
{
keyval_name = g_strdup_printf ("0x%02x", keycode);
}
else
{
keyval_name = gdk_keyval_name (gdk_keyval_to_lower (accelerator_key));
if (!keyval_name)
keyval_name = "";
}
l = 0;
if (accelerator_mods & EGG_VIRTUAL_RELEASE_MASK)

View file

@ -70,6 +70,7 @@ typedef enum
gboolean egg_accelerator_parse_virtual (const gchar *accelerator,
guint *accelerator_key,
guint *keycode,
EggVirtualModifierType *accelerator_mods);
void egg_keymap_resolve_virtual_modifiers (GdkKeymap *keymap,
EggVirtualModifierType virtual_mods,
@ -79,6 +80,7 @@ void egg_keymap_virtualize_modifiers (GdkKeymap *keymap,
EggVirtualModifierType *virtual_mods);
gchar* egg_virtual_accelerator_name (guint accelerator_key,
guint keycode,
EggVirtualModifierType accelerator_mods);
G_END_DECLS

View file

@ -52,6 +52,7 @@ enum {
PROP_ACCEL_KEY,
PROP_ACCEL_MASK,
PROP_KEYCODE,
PROP_ACCEL_MODE
};
@ -172,6 +173,16 @@ egg_cell_renderer_keys_class_init (EggCellRendererKeysClass *cell_keys_class)
GDK_TYPE_MODIFIER_TYPE,
0,
G_PARAM_READABLE | G_PARAM_WRITABLE));
g_object_class_install_property (object_class,
PROP_KEYCODE,
g_param_spec_uint ("keycode",
_("Accelerator keycode"),
_("Accelerator keycode"),
0,
G_MAXINT,
0,
G_PARAM_READABLE | G_PARAM_WRITABLE));
/* FIXME: Register the enum when moving to GTK+ */
g_object_class_install_property (object_class,
@ -184,10 +195,10 @@ egg_cell_renderer_keys_class_init (EggCellRendererKeysClass *cell_keys_class)
0,
G_PARAM_READABLE | G_PARAM_WRITABLE));
g_signal_new ("keys_edited",
g_signal_new ("accel_edited",
EGG_TYPE_CELL_RENDERER_KEYS,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EggCellRendererKeysClass, keys_edited),
G_STRUCT_OFFSET (EggCellRendererKeysClass, accel_edited),
NULL, NULL,
marshal_VOID__STRING_UINT_FLAGS_UINT,
G_TYPE_NONE, 4,
@ -195,6 +206,15 @@ egg_cell_renderer_keys_class_init (EggCellRendererKeysClass *cell_keys_class)
G_TYPE_UINT,
GDK_TYPE_MODIFIER_TYPE,
G_TYPE_UINT);
g_signal_new ("accel_cleared",
EGG_TYPE_CELL_RENDERER_KEYS,
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (EggCellRendererKeysClass, accel_cleared),
NULL, NULL,
gtk_marshal_VOID__STRING,
G_TYPE_NONE, 1,
G_TYPE_STRING);
}
@ -213,12 +233,13 @@ egg_cell_renderer_keys_finalize (GObject *object)
static gchar *
convert_keysym_state_to_string (guint keysym,
guint keycode,
EggVirtualModifierType mask)
{
if (keysym == 0)
if (keysym == 0 && keycode == 0)
return g_strdup (_("Disabled"));
else
return egg_virtual_accelerator_name (keysym, mask);
return egg_virtual_accelerator_name (keysym, keycode, mask);
}
static void
@ -269,14 +290,22 @@ egg_cell_renderer_keys_set_property (GObject *object,
case PROP_ACCEL_KEY:
egg_cell_renderer_keys_set_accelerator (keys,
g_value_get_uint (value),
keys->keycode,
keys->accel_mask);
break;
case PROP_ACCEL_MASK:
egg_cell_renderer_keys_set_accelerator (keys,
keys->accel_key,
keys->keycode,
g_value_get_flags (value));
break;
case PROP_KEYCODE:
egg_cell_renderer_keys_set_accelerator (keys,
keys->accel_key,
g_value_get_uint (value),
keys->accel_mask);
break;
case PROP_ACCEL_MODE:
egg_cell_renderer_keys_set_accel_mode (keys, g_value_get_int (value));
@ -352,6 +381,7 @@ grab_key_callback (GtkWidget *widget,
EggCellRendererKeys *keys;
char *path;
gboolean edited;
gboolean cleared;
GdkModifierType consumed_modifiers;
guint upper;
GdkModifierType ignored_modifiers;
@ -362,6 +392,7 @@ grab_key_callback (GtkWidget *widget,
return TRUE;
edited = FALSE;
cleared = FALSE;
consumed_modifiers = 0;
gdk_keymap_translate_keyboard_state (gdk_keymap_get_default (),
@ -403,10 +434,11 @@ grab_key_callback (GtkWidget *widget,
goto out; /* cancel */
/* clear the accelerator on Backspace */
if (keys->edit_key != 0 &&
accel_mods == 0 &&
accel_keyval == GDK_BackSpace)
accel_keyval = 0;
if (accel_mods == 0 && accel_keyval == GDK_BackSpace)
{
cleared = TRUE;
goto out;
}
if (keys->accel_mode == EGG_CELL_RENDERER_KEYS_MODE_GTK)
{
@ -422,23 +454,27 @@ grab_key_callback (GtkWidget *widget,
edited = TRUE;
out:
path = g_strdup (g_object_get_data (G_OBJECT (keys->edit_widget),
EGG_CELL_RENDERER_TEXT_PATH));
gdk_keyboard_ungrab (event->time);
gdk_pointer_ungrab (event->time);
path = g_strdup (g_object_get_data (G_OBJECT (keys->edit_widget), EGG_CELL_RENDERER_TEXT_PATH));
gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (keys->edit_widget));
gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (keys->edit_widget));
keys->edit_widget = NULL;
keys->grab_widget = NULL;
if (edited)
g_signal_emit_by_name (G_OBJECT (keys), "keys_edited", path,
accel_keyval, accel_mods, event->hardware_keycode);
{
g_signal_emit_by_name (G_OBJECT (keys), "accel_edited", path,
accel_keyval, accel_mods, event->hardware_keycode);
}
else if (cleared)
{
g_signal_emit_by_name (G_OBJECT (keys), "accel_cleared", path);
}
g_free (path);
return TRUE;
}
@ -583,6 +619,7 @@ egg_cell_renderer_keys_start_editing (GtkCellRenderer *cell,
void
egg_cell_renderer_keys_set_accelerator (EggCellRendererKeys *keys,
guint keyval,
guint keycode,
GdkModifierType mask)
{
char *text;
@ -609,13 +646,21 @@ egg_cell_renderer_keys_set_accelerator (EggCellRendererKeys *keys,
g_object_notify (G_OBJECT (keys), "accel_mask");
changed = TRUE;
}
if (keycode != keys->keycode)
{
keys->keycode = keycode;
g_object_notify (G_OBJECT (keys), "keycode");
changed = TRUE;
}
g_object_thaw_notify (G_OBJECT (keys));
if (changed)
{
/* sync string to the key values */
celltext = GTK_CELL_RENDERER_TEXT (keys);
text = convert_keysym_state_to_string (keys->accel_key, keys->accel_mask);
text = convert_keysym_state_to_string (keys->accel_key, keys->keycode, keys->accel_mask);
g_object_set (keys, "text", text, NULL);
g_free (text);
}

View file

@ -46,6 +46,7 @@ struct _EggCellRendererKeys
{
GtkCellRendererText parent;
guint accel_key;
guint keycode;
EggVirtualModifierType accel_mask;
GtkWidget *edit_widget;
GtkWidget *grab_widget;
@ -58,11 +59,14 @@ struct _EggCellRendererKeysClass
{
GtkCellRendererTextClass parent_class;
void (* keys_edited) (EggCellRendererKeys *keys,
const char *path_string,
guint keyval,
EggVirtualModifierType mask,
guint hardware_keycode);
void (* accel_edited) (EggCellRendererKeys *keys,
const char *path_string,
guint keyval,
EggVirtualModifierType mask,
guint hardware_keycode);
void (* accel_cleared) (EggCellRendererKeys *keys,
const char *path_string);
};
GType egg_cell_renderer_keys_get_type (void);
@ -70,6 +74,7 @@ GtkCellRenderer *egg_cell_renderer_keys_new (void);
void egg_cell_renderer_keys_set_accelerator (EggCellRendererKeys *keys,
guint keyval,
guint keycode,
EggVirtualModifierType mask);
void egg_cell_renderer_keys_get_accelerator (EggCellRendererKeys *keys,
guint *keyval,

View file

@ -112,6 +112,7 @@ typedef struct
{
char *gconf_key;
guint keyval;
guint keycode;
EggVirtualModifierType mask;
gboolean editable;
GtkTreeModel *model;
@ -122,6 +123,7 @@ typedef struct
static void reload_key_entries (gpointer wm_name,
GladeXML *dialog);
static char* binding_name (guint keyval,
guint keycode,
EggVirtualModifierType mask,
gboolean translate);
@ -195,11 +197,12 @@ create_dialog (void)
static char*
binding_name (guint keyval,
guint keycode,
EggVirtualModifierType mask,
gboolean translate)
{
if (keyval != 0)
return egg_virtual_accelerator_name (keyval, mask);
if (keyval != 0 || keycode != 0)
return egg_virtual_accelerator_name (keyval, keycode, mask);
else
return translate ? g_strdup (_("Disabled")) : g_strdup ("disabled");
}
@ -207,6 +210,7 @@ binding_name (guint keyval,
static gboolean
binding_from_string (const char *str,
guint *accelerator_key,
guint *keycode,
EggVirtualModifierType *accelerator_mods)
{
g_return_val_if_fail (accelerator_key != NULL, FALSE);
@ -214,11 +218,12 @@ binding_from_string (const char *str,
if (str == NULL || (str && strcmp (str, "disabled") == 0))
{
*accelerator_key = 0;
*keycode = 0;
*accelerator_mods = 0;
return TRUE;
}
egg_accelerator_parse_virtual (str, accelerator_key, accelerator_mods);
egg_accelerator_parse_virtual (str, accelerator_key, keycode, accelerator_mods);
if (*accelerator_key == 0)
return FALSE;
@ -249,6 +254,7 @@ accel_set_func (GtkTreeViewColumn *tree_column,
"editable", FALSE,
"accel_key", key_entry->keyval,
"accel_mask", key_entry->mask,
"keycode", key_entry->keycode,
"style", PANGO_STYLE_ITALIC,
NULL);
else
@ -257,6 +263,7 @@ accel_set_func (GtkTreeViewColumn *tree_column,
"editable", TRUE,
"accel_key", key_entry->keyval,
"accel_mask", key_entry->mask,
"keycode", key_entry->keycode,
"style", PANGO_STYLE_NORMAL,
NULL);
}
@ -295,7 +302,7 @@ keybinding_key_changed (GConfClient *client,
key_entry = (KeyEntry *)user_data;
key_value = gconf_value_get_string (entry->value);
binding_from_string (key_value, &key_entry->keyval, &key_entry->mask);
binding_from_string (key_value, &key_entry->keyval, &key_entry->keycode, &key_entry->mask);
key_entry->editable = gconf_entry_get_is_writable (entry);
/* update the model */
@ -329,6 +336,7 @@ keyentry_sort_func (GtkTreeModel *model,
if (key_entry_a != NULL)
name_a = binding_name (key_entry_a->keyval,
key_entry_a->keycode,
key_entry_a->mask,
TRUE);
else
@ -336,6 +344,7 @@ keyentry_sort_func (GtkTreeModel *model,
if (key_entry_b != NULL)
name_b = binding_name (key_entry_b->keyval,
key_entry_b->keycode,
key_entry_b->mask,
TRUE);
else
@ -514,7 +523,7 @@ append_keys_to_tree (GladeXML *dialog,
key_string,
(GConfClientNotifyFunc) &keybinding_key_changed,
key_entry, NULL, NULL);
binding_from_string (key_value, &key_entry->keyval, &key_entry->mask);
binding_from_string (key_value, &key_entry->keyval, &key_entry->keycode, &key_entry->mask);
g_free (key_value);
key_entry->description = g_strdup (gconf_schema_get_short_desc (schema));
@ -632,6 +641,7 @@ cb_check_for_uniqueness (GtkTreeModel *model,
if (tmp_key_entry != NULL &&
key_entry->keyval == tmp_key_entry->keyval &&
key_entry->mask == tmp_key_entry->mask &&
key_entry->keycode == tmp_key_entry->keycode &&
/* be sure we don't claim a key is a dup of itself */
strcmp (key_entry->gconf_key, tmp_key_entry->gconf_key) != 0)
{
@ -648,7 +658,7 @@ accel_edited_callback (GtkCellRendererText *cell,
const char *path_string,
guint keyval,
EggVirtualModifierType mask,
guint keycode,
guint keycode,
gpointer data)
{
GtkTreeView *view = (GtkTreeView *)data;
@ -674,12 +684,13 @@ accel_edited_callback (GtkCellRendererText *cell,
tmp_key.model = model;
tmp_key.keyval = keyval;
tmp_key.keycode = keycode;
tmp_key.mask = mask;
tmp_key.gconf_key = key_entry->gconf_key;
tmp_key.description = NULL;
tmp_key.editable = TRUE; /* kludge to stuff in a return flag */
if (keyval != 0) /* any number of keys can be disabled */
if (keyval != 0 || keycode != 0) /* any number of keys can be disabled */
gtk_tree_model_foreach (model, cb_check_for_uniqueness, &tmp_key);
/* flag to see if the new accelerator was in use by something */
@ -688,7 +699,7 @@ accel_edited_callback (GtkCellRendererText *cell,
GtkWidget *dialog;
char *name;
name = egg_virtual_accelerator_name (keyval, mask);
name = egg_virtual_accelerator_name (keyval, keycode, mask);
dialog =
gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
@ -705,12 +716,12 @@ accel_edited_callback (GtkCellRendererText *cell,
/* set it back to its previous value. */
egg_cell_renderer_keys_set_accelerator (EGG_CELL_RENDERER_KEYS (cell),
key_entry->keyval, key_entry->mask);
key_entry->keyval, key_entry->keycode, key_entry->mask);
gtk_tree_path_free (path);
return;
}
str = binding_name (keyval, mask, FALSE);
str = binding_name (keyval, keycode, mask, FALSE);
gconf_client_set_string (gconf_client_get_default(),
key_entry->gconf_key,
@ -738,6 +749,54 @@ accel_edited_callback (GtkCellRendererText *cell,
gtk_tree_path_free (path);
}
static void
accel_cleared_callback (GtkCellRendererText *cell,
const char *path_string,
gpointer data)
{
GtkTreeView *view = (GtkTreeView *) data;
GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
KeyEntry *key_entry;
GtkTreeIter iter;
GError *err = NULL;
GtkTreeModel *model;
model = get_real_model (view);
gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_model_get (model, &iter,
KEYENTRY_COLUMN, &key_entry,
-1);
/* sanity check */
if (key_entry == NULL)
{
gtk_tree_path_free (path);
return;
}
/* Unset the key */
gconf_client_set_string (gconf_client_get_default(),
key_entry->gconf_key,
"disabled",
&err);
if (err != NULL)
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
GTK_MESSAGE_WARNING,
GTK_BUTTONS_OK,
_("Error unsetting accelerator in configuration database: %s\n"),
err->message);
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
g_error_free (err);
key_entry->editable = FALSE;
}
}
static void
theme_changed_func (gpointer uri,
@ -914,10 +973,15 @@ setup_dialog (GladeXML *dialog)
NULL);
g_signal_connect (G_OBJECT (renderer),
"keys_edited",
"accel_edited",
G_CALLBACK (accel_edited_callback),
WID ("shortcut_treeview"));
g_signal_connect (G_OBJECT (renderer),
"accel_cleared",
G_CALLBACK (accel_cleared_callback),
WID ("shortcut_treeview"));
column = gtk_tree_view_column_new_with_attributes (_("Shortcut"), renderer, NULL);
gtk_tree_view_column_set_cell_data_func (column, renderer, accel_set_func, NULL, NULL);
gtk_tree_view_column_set_resizable (column, FALSE);