5
#include <gdk/gdkkeysyms.h>
6
#include "eggcellrendererkeys.h"
7
#include "eggaccelerators.h"
9
#ifndef EGG_COMPILATION
11
#define _(x) dgettext (GETTEXT_PACKAGE, x)
19
#define EGG_CELL_RENDERER_TEXT_PATH "egg-cell-renderer-text"
21
#define TOOLTIP_TEXT _("New accelerator...")
23
static void egg_cell_renderer_keys_finalize (GObject *object);
24
static void egg_cell_renderer_keys_init (EggCellRendererKeys *cell_keys);
25
static void egg_cell_renderer_keys_class_init (EggCellRendererKeysClass *cell_keys_class);
26
static GtkCellEditable *egg_cell_renderer_keys_start_editing (GtkCellRenderer *cell,
30
GdkRectangle *background_area,
31
GdkRectangle *cell_area,
32
GtkCellRendererState flags);
35
static void egg_cell_renderer_keys_get_property (GObject *object,
39
static void egg_cell_renderer_keys_set_property (GObject *object,
43
static void egg_cell_renderer_keys_get_size (GtkCellRenderer *cell,
45
GdkRectangle *cell_area,
61
static GtkCellRendererTextClass *parent_class = NULL;
64
egg_cell_renderer_keys_get_type (void)
66
static GType cell_keys_type = 0;
70
static const GTypeInfo cell_keys_info =
72
sizeof (EggCellRendererKeysClass),
74
NULL, /* base_finalize */
75
(GClassInitFunc)egg_cell_renderer_keys_class_init,
76
NULL, /* class_finalize */
77
NULL, /* class_data */
78
sizeof (EggCellRendererKeys),
80
(GInstanceInitFunc) egg_cell_renderer_keys_init
83
cell_keys_type = g_type_register_static (GTK_TYPE_CELL_RENDERER_TEXT, "EggCellRendererKeys", &cell_keys_info, 0);
86
return cell_keys_type;
90
egg_cell_renderer_keys_init (EggCellRendererKeys *cell_keys)
92
cell_keys->accel_mode = EGG_CELL_RENDERER_KEYS_MODE_GTK;
95
/* FIXME setup stuff to generate this */
96
/* VOID:STRING,UINT,FLAGS,UINT */
98
marshal_VOID__STRING_UINT_FLAGS_UINT (GClosure *closure,
100
guint n_param_values,
101
const GValue *param_values,
102
gpointer invocation_hint,
103
gpointer marshal_data)
105
typedef void (*GMarshalFunc_VOID__STRING_UINT_FLAGS_UINT) (gpointer data1,
111
register GMarshalFunc_VOID__STRING_UINT_FLAGS_UINT callback;
112
register GCClosure *cc = (GCClosure*) closure;
113
register gpointer data1, data2;
115
g_return_if_fail (n_param_values == 5);
117
if (G_CCLOSURE_SWAP_DATA (closure))
119
data1 = closure->data;
120
data2 = g_value_peek_pointer (param_values + 0);
124
data1 = g_value_peek_pointer (param_values + 0);
125
data2 = closure->data;
128
callback = (GMarshalFunc_VOID__STRING_UINT_FLAGS_UINT) (marshal_data ? marshal_data : cc->callback);
131
g_value_get_string (param_values + 1),
132
g_value_get_uint (param_values + 2),
133
g_value_get_flags (param_values + 3),
134
g_value_get_uint (param_values + 4),
139
egg_cell_renderer_keys_class_init (EggCellRendererKeysClass *cell_keys_class)
141
GObjectClass *object_class;
142
GtkCellRendererClass *cell_renderer_class;
144
object_class = G_OBJECT_CLASS (cell_keys_class);
145
cell_renderer_class = GTK_CELL_RENDERER_CLASS (cell_keys_class);
146
parent_class = g_type_class_peek_parent (object_class);
148
GTK_CELL_RENDERER_CLASS (cell_keys_class)->start_editing = egg_cell_renderer_keys_start_editing;
150
object_class->set_property = egg_cell_renderer_keys_set_property;
151
object_class->get_property = egg_cell_renderer_keys_get_property;
152
cell_renderer_class->get_size = egg_cell_renderer_keys_get_size;
154
object_class->finalize = egg_cell_renderer_keys_finalize;
156
/* FIXME if this gets moved to a real library, rename the properties
157
* to match whatever the GTK convention is
160
g_object_class_install_property (object_class,
162
g_param_spec_uint ("accel_key",
163
_("Accelerator key"),
164
_("Accelerator key"),
168
G_PARAM_READABLE | G_PARAM_WRITABLE));
170
g_object_class_install_property (object_class,
172
g_param_spec_flags ("accel_mask",
173
_("Accelerator modifiers"),
174
_("Accelerator modifiers"),
175
GDK_TYPE_MODIFIER_TYPE,
177
G_PARAM_READABLE | G_PARAM_WRITABLE));
179
g_object_class_install_property (object_class,
181
g_param_spec_uint ("keycode",
182
_("Accelerator keycode"),
183
_("Accelerator keycode"),
187
G_PARAM_READABLE | G_PARAM_WRITABLE));
189
/* FIXME: Register the enum when moving to GTK+ */
190
g_object_class_install_property (object_class,
192
g_param_spec_int ("accel_mode",
194
_("The type of accelerator."),
198
G_PARAM_READABLE | G_PARAM_WRITABLE));
200
g_signal_new ("accel_edited",
201
EGG_TYPE_CELL_RENDERER_KEYS,
203
G_STRUCT_OFFSET (EggCellRendererKeysClass, accel_edited),
205
marshal_VOID__STRING_UINT_FLAGS_UINT,
209
GDK_TYPE_MODIFIER_TYPE,
212
g_signal_new ("accel_cleared",
213
EGG_TYPE_CELL_RENDERER_KEYS,
215
G_STRUCT_OFFSET (EggCellRendererKeysClass, accel_cleared),
217
gtk_marshal_VOID__STRING,
224
egg_cell_renderer_keys_new (void)
226
return GTK_CELL_RENDERER (g_object_new (EGG_TYPE_CELL_RENDERER_KEYS, NULL));
230
egg_cell_renderer_keys_finalize (GObject *object)
233
(* G_OBJECT_CLASS (parent_class)->finalize) (object);
237
convert_keysym_state_to_string (guint keysym,
239
EggVirtualModifierType mask)
241
if (keysym == 0 && keycode == 0)
242
return g_strdup (_("Disabled"));
244
return egg_virtual_accelerator_label (keysym, keycode, mask);
248
egg_cell_renderer_keys_get_property (GObject *object,
253
EggCellRendererKeys *keys;
255
g_return_if_fail (EGG_IS_CELL_RENDERER_KEYS (object));
257
keys = EGG_CELL_RENDERER_KEYS (object);
262
g_value_set_uint (value, keys->accel_key);
265
case PROP_ACCEL_MASK:
266
g_value_set_flags (value, keys->accel_mask);
269
case PROP_ACCEL_MODE:
270
g_value_set_int (value, keys->accel_mode);
274
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
279
egg_cell_renderer_keys_set_property (GObject *object,
284
EggCellRendererKeys *keys;
286
g_return_if_fail (EGG_IS_CELL_RENDERER_KEYS (object));
288
keys = EGG_CELL_RENDERER_KEYS (object);
293
egg_cell_renderer_keys_set_accelerator (keys,
294
g_value_get_uint (value),
299
case PROP_ACCEL_MASK:
300
egg_cell_renderer_keys_set_accelerator (keys,
303
g_value_get_flags (value));
306
egg_cell_renderer_keys_set_accelerator (keys,
308
g_value_get_uint (value),
312
case PROP_ACCEL_MODE:
313
egg_cell_renderer_keys_set_accel_mode (keys, g_value_get_int (value));
317
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
322
is_modifier (guint keycode)
326
XModifierKeymap *mod_keymap;
327
gboolean retval = FALSE;
329
mod_keymap = XGetModifierMapping (gdk_display);
331
map_size = 8 * mod_keymap->max_keypermod;
335
if (keycode == mod_keymap->modifiermap[i])
343
XFreeModifiermap (mod_keymap);
349
egg_cell_renderer_keys_get_size (GtkCellRenderer *cell,
351
GdkRectangle *cell_area,
358
EggCellRendererKeys *keys = (EggCellRendererKeys *) cell;
359
GtkRequisition requisition;
361
if (keys->sizing_label == NULL)
362
keys->sizing_label = gtk_label_new (TOOLTIP_TEXT);
364
gtk_widget_size_request (keys->sizing_label, &requisition);
365
(* GTK_CELL_RENDERER_CLASS (parent_class)->get_size) (cell, widget, cell_area, x_offset, y_offset, width, height);
366
/* FIXME: need to take the cell_area et al. into account */
368
*width = MAX (*width, requisition.width);
370
*height = MAX (*height, requisition.height);
373
/* FIXME: Currently we don't differentiate between a 'bogus' key (like tab in
374
* GTK mode) and a removed key.
378
grab_key_callback (GtkWidget *widget,
382
GdkModifierType accel_mods = 0;
384
EggCellRendererKeys *keys;
388
GdkModifierType consumed_modifiers;
390
GdkModifierType ignored_modifiers;
392
keys = EGG_CELL_RENDERER_KEYS (data);
394
if (is_modifier (event->hardware_keycode))
400
consumed_modifiers = 0;
401
gdk_keymap_translate_keyboard_state (gdk_keymap_get_default (),
402
event->hardware_keycode,
405
NULL, NULL, NULL, &consumed_modifiers);
407
upper = event->keyval;
408
accel_keyval = gdk_keyval_to_lower (upper);
409
if (accel_keyval == GDK_ISO_Left_Tab)
410
accel_keyval = GDK_Tab;
414
/* Put shift back if it changed the case of the key, not otherwise.
416
if (upper != accel_keyval &&
417
(consumed_modifiers & GDK_SHIFT_MASK))
419
consumed_modifiers &= ~(GDK_SHIFT_MASK);
422
egg_keymap_resolve_virtual_modifiers (gdk_keymap_get_default (),
423
EGG_VIRTUAL_NUM_LOCK_MASK |
424
EGG_VIRTUAL_SCROLL_LOCK_MASK |
425
EGG_VIRTUAL_LOCK_MASK,
428
/* http://bugzilla.gnome.org/show_bug.cgi?id=139605
429
* mouse keys should effect keybindings */
430
ignored_modifiers |= GDK_BUTTON1_MASK |
436
/* filter consumed/ignored modifiers */
438
if (keys->accel_mode == EGG_CELL_RENDERER_KEYS_MODE_GTK)
439
accel_mods = event->state & GDK_MODIFIER_MASK & ~(consumed_modifiers | ignored_modifiers);
440
else if (keys->accel_mode == EGG_CELL_RENDERER_KEYS_MODE_X)
441
accel_mods = event->state & GDK_MODIFIER_MASK & ~(ignored_modifiers);
443
g_assert_not_reached ();
445
if (accel_mods == 0 && accel_keyval == GDK_Escape)
446
goto out; /* cancel */
448
/* clear the accelerator on Backspace */
449
if (accel_mods == 0 && accel_keyval == GDK_BackSpace)
455
if (keys->accel_mode == EGG_CELL_RENDERER_KEYS_MODE_GTK)
457
if (!gtk_accelerator_valid (accel_keyval, accel_mods))
466
gdk_keyboard_ungrab (event->time);
467
gdk_pointer_ungrab (event->time);
469
path = g_strdup (g_object_get_data (G_OBJECT (keys->edit_widget), EGG_CELL_RENDERER_TEXT_PATH));
471
gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (keys->edit_widget));
472
gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (keys->edit_widget));
473
keys->edit_widget = NULL;
474
keys->grab_widget = NULL;
478
g_signal_emit_by_name (G_OBJECT (keys), "accel_edited", path,
479
accel_keyval, accel_mods, event->hardware_keycode);
483
g_signal_emit_by_name (G_OBJECT (keys), "accel_cleared", path);
491
ungrab_stuff (GtkWidget *widget, gpointer data)
493
EggCellRendererKeys *keys = EGG_CELL_RENDERER_KEYS (data);
495
gdk_keyboard_ungrab (GDK_CURRENT_TIME);
496
gdk_pointer_ungrab (GDK_CURRENT_TIME);
498
g_signal_handlers_disconnect_by_func (G_OBJECT (keys->grab_widget),
499
G_CALLBACK (grab_key_callback), data);
503
pointless_eventbox_start_editing (GtkCellEditable *cell_editable,
506
/* do nothing, because we are pointless */
510
pointless_eventbox_cell_editable_init (GtkCellEditableIface *iface)
512
iface->start_editing = pointless_eventbox_start_editing;
516
pointless_eventbox_subclass_get_type (void)
518
static GType eventbox_type = 0;
522
static const GTypeInfo eventbox_info =
524
sizeof (GtkEventBoxClass),
525
NULL, /* base_init */
526
NULL, /* base_finalize */
528
NULL, /* class_finalize */
529
NULL, /* class_data */
530
sizeof (GtkEventBox),
532
(GInstanceInitFunc) NULL,
535
static const GInterfaceInfo cell_editable_info = {
536
(GInterfaceInitFunc) pointless_eventbox_cell_editable_init,
539
eventbox_type = g_type_register_static (GTK_TYPE_EVENT_BOX, "EggCellEditableEventBox", &eventbox_info, 0);
541
g_type_add_interface_static (eventbox_type,
542
GTK_TYPE_CELL_EDITABLE,
543
&cell_editable_info);
546
return eventbox_type;
549
static GtkCellEditable *
550
egg_cell_renderer_keys_start_editing (GtkCellRenderer *cell,
554
GdkRectangle *background_area,
555
GdkRectangle *cell_area,
556
GtkCellRendererState flags)
558
GtkCellRendererText *celltext;
559
EggCellRendererKeys *keys;
563
celltext = GTK_CELL_RENDERER_TEXT (cell);
564
keys = EGG_CELL_RENDERER_KEYS (cell);
566
/* If the cell isn't editable we return NULL. */
567
if (celltext->editable == FALSE)
570
g_return_val_if_fail (widget->window != NULL, NULL);
572
if (gdk_keyboard_grab (widget->window, FALSE,
573
gdk_event_get_time (event)) != GDK_GRAB_SUCCESS)
576
if (gdk_pointer_grab (widget->window, FALSE,
577
GDK_BUTTON_PRESS_MASK,
579
gdk_event_get_time (event)) != GDK_GRAB_SUCCESS)
581
gdk_keyboard_ungrab (gdk_event_get_time (event));
585
keys->grab_widget = widget;
587
g_signal_connect (G_OBJECT (widget), "key_press_event",
588
G_CALLBACK (grab_key_callback),
591
eventbox = g_object_new (pointless_eventbox_subclass_get_type (),
593
keys->edit_widget = eventbox;
594
g_object_add_weak_pointer (G_OBJECT (keys->edit_widget),
595
(void**) &keys->edit_widget);
597
label = gtk_label_new (NULL);
598
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
600
gtk_widget_modify_bg (eventbox, GTK_STATE_NORMAL,
601
&widget->style->bg[GTK_STATE_SELECTED]);
603
gtk_widget_modify_fg (label, GTK_STATE_NORMAL,
604
&widget->style->fg[GTK_STATE_SELECTED]);
606
gtk_label_set_text (GTK_LABEL (label),
609
gtk_container_add (GTK_CONTAINER (eventbox), label);
611
g_object_set_data_full (G_OBJECT (keys->edit_widget), EGG_CELL_RENDERER_TEXT_PATH,
612
g_strdup (path), g_free);
614
gtk_widget_show_all (keys->edit_widget);
616
g_signal_connect (G_OBJECT (keys->edit_widget), "unrealize",
617
G_CALLBACK (ungrab_stuff), keys);
619
keys->edit_key = keys->accel_key;
621
return GTK_CELL_EDITABLE (keys->edit_widget);
625
egg_cell_renderer_keys_set_accelerator (EggCellRendererKeys *keys,
628
EggVirtualModifierType mask)
633
g_return_if_fail (EGG_IS_CELL_RENDERER_KEYS (keys));
635
g_object_freeze_notify (G_OBJECT (keys));
639
if (keyval != keys->accel_key)
641
keys->accel_key = keyval;
642
g_object_notify (G_OBJECT (keys), "accel_key");
646
if (mask != keys->accel_mask)
648
keys->accel_mask = mask;
650
g_object_notify (G_OBJECT (keys), "accel_mask");
654
if (keycode != keys->keycode)
656
keys->keycode = keycode;
658
g_object_notify (G_OBJECT (keys), "keycode");
661
g_object_thaw_notify (G_OBJECT (keys));
665
/* sync string to the key values */
666
text = convert_keysym_state_to_string (keys->accel_key, keys->keycode, keys->accel_mask);
667
g_object_set (keys, "text", text, NULL);
673
egg_cell_renderer_keys_get_accelerator (EggCellRendererKeys *keys,
675
EggVirtualModifierType *mask)
677
g_return_if_fail (EGG_IS_CELL_RENDERER_KEYS (keys));
680
*keyval = keys->accel_key;
683
*mask = keys->accel_mask;
687
egg_cell_renderer_keys_set_accel_mode (EggCellRendererKeys *keys,
688
EggCellRendererKeysMode accel_mode)
690
g_return_if_fail (EGG_IS_CELL_RENDERER_KEYS (keys));
691
keys->accel_mode = accel_mode;
692
g_object_notify (G_OBJECT (keys), "accel_mode");