1 #include <config.h>
2 #include <glib.h>
3 #include <glib/gi18n.h>
4 #include <gtk/gtk.h>
5 #include <gdk/gdkx.h>
6 #include <gdk/gdkkeysyms.h>
7 #include "eggcellrendererkeys.h"
8 #include "eggaccelerators.h"
9
10 #define EGG_CELL_RENDERER_TEXT_PATH "egg-cell-renderer-text"
11
12 #define TOOLTIP_TEXT _("New shortcut...")
13
14 static void egg_cell_renderer_keys_finalize (GObject *object);
15 static void egg_cell_renderer_keys_init (EggCellRendererKeys *cell_keys);
16 static void egg_cell_renderer_keys_class_init (EggCellRendererKeysClass *cell_keys_class);
17 static GtkCellEditable *egg_cell_renderer_keys_start_editing (GtkCellRenderer *cell,
18 GdkEvent *event,
19 GtkWidget *widget,
20 const gchar *path,
21 const GdkRectangle *background_area,
22 const GdkRectangle *cell_area,
23 GtkCellRendererState flags);
24
25
26 static void egg_cell_renderer_keys_get_property (GObject *object,
27 guint param_id,
28 GValue *value,
29 GParamSpec *pspec);
30 static void egg_cell_renderer_keys_set_property (GObject *object,
31 guint param_id,
32 const GValue *value,
33 GParamSpec *pspec);
34 static void egg_cell_renderer_keys_get_size (GtkCellRenderer *cell,
35 GtkWidget *widget,
36 const GdkRectangle *cell_area,
37 gint *x_offset,
38 gint *y_offset,
39 gint *width,
40 gint *height);
41
42
43 enum {
44 PROP_0,
45
46 PROP_ACCEL_KEY,
47 PROP_ACCEL_MASK,
48 PROP_KEYCODE,
49 PROP_ACCEL_MODE
50 };
51
52 static GtkCellRendererTextClass* parent_class = NULL;
53
egg_cell_renderer_keys_get_type(void)54 GType egg_cell_renderer_keys_get_type(void)
55 {
56 static GType cell_keys_type = 0;
57
58 if (!cell_keys_type)
59 {
60 static const GTypeInfo cell_keys_info = {
61 sizeof (EggCellRendererKeysClass),
62 NULL, /* base_init */
63 NULL, /* base_finalize */
64 (GClassInitFunc)egg_cell_renderer_keys_class_init,
65 NULL, /* class_finalize */
66 NULL, /* class_data */
67 sizeof (EggCellRendererKeys),
68 0, /* n_preallocs */
69 (GInstanceInitFunc) egg_cell_renderer_keys_init
70 };
71
72 cell_keys_type = g_type_register_static (GTK_TYPE_CELL_RENDERER_TEXT, "EggCellRendererKeys", &cell_keys_info, 0);
73 }
74
75 return cell_keys_type;
76 }
77
egg_cell_renderer_keys_init(EggCellRendererKeys * cell_keys)78 static void egg_cell_renderer_keys_init(EggCellRendererKeys* cell_keys)
79 {
80 cell_keys->accel_mode = EGG_CELL_RENDERER_KEYS_MODE_GTK;
81 }
82
83 /* FIXME setup stuff to generate this */
84 /* VOID:STRING,UINT,FLAGS,UINT */
marshal_VOID__STRING_UINT_FLAGS_UINT(GClosure * closure,GValue * return_value,guint n_param_values,const GValue * param_values,gpointer invocation_hint,gpointer marshal_data)85 static void marshal_VOID__STRING_UINT_FLAGS_UINT(GClosure* closure, GValue* return_value, guint n_param_values, const GValue* param_values, gpointer invocation_hint, gpointer marshal_data)
86 {
87 /* typedef inside a function? wow */
88 typedef void (*GMarshalFunc_VOID__STRING_UINT_FLAGS_UINT) (
89 gpointer data1,
90 const char* arg_1,
91 guint arg_2,
92 int arg_3,
93 guint arg_4,
94 gpointer data2);
95
96 register GMarshalFunc_VOID__STRING_UINT_FLAGS_UINT callback;
97 register GCClosure* cc = (GCClosure*) closure;
98 register gpointer data1, data2;
99
100 g_return_if_fail (n_param_values == 5);
101
102 if (G_CCLOSURE_SWAP_DATA(closure))
103 {
104 data1 = closure->data;
105 data2 = g_value_peek_pointer(param_values + 0);
106 }
107 else
108 {
109 data1 = g_value_peek_pointer(param_values + 0);
110 data2 = closure->data;
111 }
112
113 callback = (GMarshalFunc_VOID__STRING_UINT_FLAGS_UINT) (marshal_data ? marshal_data : cc->callback);
114
115 callback(data1,
116 g_value_get_string(param_values + 1),
117 g_value_get_uint(param_values + 2),
118 g_value_get_flags(param_values + 3),
119 g_value_get_uint(param_values + 4),
120 data2);
121 }
122
123 static void
egg_cell_renderer_keys_class_init(EggCellRendererKeysClass * cell_keys_class)124 egg_cell_renderer_keys_class_init (EggCellRendererKeysClass *cell_keys_class)
125 {
126 GObjectClass *object_class;
127 GtkCellRendererClass *cell_renderer_class;
128
129 object_class = G_OBJECT_CLASS (cell_keys_class);
130 cell_renderer_class = GTK_CELL_RENDERER_CLASS (cell_keys_class);
131 parent_class = g_type_class_peek_parent (object_class);
132
133 GTK_CELL_RENDERER_CLASS (cell_keys_class)->start_editing = egg_cell_renderer_keys_start_editing;
134
135 object_class->set_property = egg_cell_renderer_keys_set_property;
136 object_class->get_property = egg_cell_renderer_keys_get_property;
137 cell_renderer_class->get_size = egg_cell_renderer_keys_get_size;
138
139 object_class->finalize = egg_cell_renderer_keys_finalize;
140
141 /* FIXME if this gets moved to a real library, rename the properties
142 * to match whatever the GTK convention is
143 */
144
145 g_object_class_install_property (object_class,
146 PROP_ACCEL_KEY,
147 g_param_spec_uint ("accel_key",
148 _("Accelerator key"),
149 _("Accelerator key"),
150 0,
151 G_MAXINT,
152 0,
153 G_PARAM_READABLE | G_PARAM_WRITABLE));
154
155 g_object_class_install_property (object_class,
156 PROP_ACCEL_MASK,
157 g_param_spec_flags ("accel_mask",
158 _("Accelerator modifiers"),
159 _("Accelerator modifiers"),
160 GDK_TYPE_MODIFIER_TYPE,
161 0,
162 G_PARAM_READABLE | G_PARAM_WRITABLE));
163
164 g_object_class_install_property (object_class,
165 PROP_KEYCODE,
166 g_param_spec_uint ("keycode",
167 _("Accelerator keycode"),
168 _("Accelerator keycode"),
169 0,
170 G_MAXINT,
171 0,
172 G_PARAM_READABLE | G_PARAM_WRITABLE));
173
174 /* FIXME: Register the enum when moving to GTK+ */
175 g_object_class_install_property (object_class,
176 PROP_ACCEL_MODE,
177 g_param_spec_int ("accel_mode",
178 _("Accel Mode"),
179 _("The type of accelerator."),
180 0,
181 2,
182 0,
183 G_PARAM_READABLE | G_PARAM_WRITABLE));
184
185 g_signal_new ("accel_edited",
186 EGG_TYPE_CELL_RENDERER_KEYS,
187 G_SIGNAL_RUN_LAST,
188 G_STRUCT_OFFSET (EggCellRendererKeysClass, accel_edited),
189 NULL, NULL,
190 marshal_VOID__STRING_UINT_FLAGS_UINT,
191 G_TYPE_NONE, 4,
192 G_TYPE_STRING,
193 G_TYPE_UINT,
194 GDK_TYPE_MODIFIER_TYPE,
195 G_TYPE_UINT);
196
197 g_signal_new ("accel_cleared",
198 EGG_TYPE_CELL_RENDERER_KEYS,
199 G_SIGNAL_RUN_LAST,
200 G_STRUCT_OFFSET (EggCellRendererKeysClass, accel_cleared),
201 NULL, NULL,
202 g_cclosure_marshal_VOID__STRING,
203 G_TYPE_NONE, 1,
204 G_TYPE_STRING);
205 }
206
207
egg_cell_renderer_keys_new(void)208 GtkCellRenderer* egg_cell_renderer_keys_new(void)
209 {
210 return GTK_CELL_RENDERER(g_object_new(EGG_TYPE_CELL_RENDERER_KEYS, NULL));
211 }
212
egg_cell_renderer_keys_finalize(GObject * object)213 static void egg_cell_renderer_keys_finalize(GObject* object)
214 {
215 (*G_OBJECT_CLASS(parent_class)->finalize)(object);
216 }
217
convert_keysym_state_to_string(guint keysym,guint keycode,EggVirtualModifierType mask)218 static gchar* convert_keysym_state_to_string(guint keysym, guint keycode, EggVirtualModifierType mask)
219 {
220 if (keysym == 0 && keycode == 0)
221 {
222 return g_strdup (_("Disabled"));
223 }
224 else
225 {
226 return egg_virtual_accelerator_label(keysym, keycode, mask);
227 }
228 }
229
230 static void
egg_cell_renderer_keys_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)231 egg_cell_renderer_keys_get_property (GObject *object,
232 guint param_id,
233 GValue *value,
234 GParamSpec *pspec)
235 {
236 EggCellRendererKeys *keys;
237
238 g_return_if_fail (EGG_IS_CELL_RENDERER_KEYS (object));
239
240 keys = EGG_CELL_RENDERER_KEYS (object);
241
242 switch (param_id)
243 {
244 case PROP_ACCEL_KEY:
245 g_value_set_uint (value, keys->accel_key);
246 break;
247
248 case PROP_ACCEL_MASK:
249 g_value_set_flags (value, keys->accel_mask);
250 break;
251
252 case PROP_ACCEL_MODE:
253 g_value_set_int (value, keys->accel_mode);
254 break;
255
256 default:
257 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
258 }
259 }
260
261 static void
egg_cell_renderer_keys_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)262 egg_cell_renderer_keys_set_property (GObject *object,
263 guint param_id,
264 const GValue *value,
265 GParamSpec *pspec)
266 {
267 EggCellRendererKeys *keys;
268
269 g_return_if_fail (EGG_IS_CELL_RENDERER_KEYS (object));
270
271 keys = EGG_CELL_RENDERER_KEYS (object);
272
273 switch (param_id)
274 {
275 case PROP_ACCEL_KEY:
276 egg_cell_renderer_keys_set_accelerator (keys,
277 g_value_get_uint (value),
278 keys->keycode,
279 keys->accel_mask);
280 break;
281
282 case PROP_ACCEL_MASK:
283 egg_cell_renderer_keys_set_accelerator (keys,
284 keys->accel_key,
285 keys->keycode,
286 g_value_get_flags (value));
287 break;
288 case PROP_KEYCODE:
289 egg_cell_renderer_keys_set_accelerator (keys,
290 keys->accel_key,
291 g_value_get_uint (value),
292 keys->accel_mask);
293 break;
294
295 case PROP_ACCEL_MODE:
296 egg_cell_renderer_keys_set_accel_mode (keys, g_value_get_int (value));
297 break;
298
299 default:
300 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
301 }
302 }
303
is_modifier(guint keycode)304 static gboolean is_modifier(guint keycode)
305 {
306 gint i;
307 gint map_size;
308 XModifierKeymap* mod_keymap;
309 gboolean retval = FALSE;
310
311 mod_keymap = XGetModifierMapping(gdk_x11_display_get_xdisplay(gdk_display_get_default()));
312
313 map_size = 8 * mod_keymap->max_keypermod;
314 i = 0;
315
316 while (i < map_size)
317 {
318 if (keycode == mod_keymap->modifiermap[i])
319 {
320 retval = TRUE;
321 break;
322 }
323
324 ++i;
325 }
326
327 XFreeModifiermap(mod_keymap);
328
329 return retval;
330 }
331
332 static void
egg_cell_renderer_keys_get_size(GtkCellRenderer * cell,GtkWidget * widget,const GdkRectangle * cell_area,gint * x_offset,gint * y_offset,gint * width,gint * height)333 egg_cell_renderer_keys_get_size(GtkCellRenderer *cell,
334 GtkWidget *widget,
335 const GdkRectangle *cell_area,
336 gint *x_offset,
337 gint *y_offset,
338 gint *width,
339 gint *height)
340 {
341 EggCellRendererKeys *keys = (EggCellRendererKeys *) cell;
342 GtkRequisition requisition;
343
344 if (keys->sizing_label == NULL)
345 keys->sizing_label = gtk_label_new (TOOLTIP_TEXT);
346
347 gtk_widget_get_preferred_size (keys->sizing_label, &requisition, NULL);
348 (* GTK_CELL_RENDERER_CLASS (parent_class)->get_size) (cell, widget, cell_area, x_offset, y_offset, width, height);
349 /* FIXME: need to take the cell_area et al. into account */
350 if (width)
351 *width = MAX (*width, requisition.width);
352 if (height)
353 *height = MAX (*height, requisition.height);
354 }
355
356 /* FIXME: Currently we don't differentiate between a 'bogus' key (like tab in
357 * GTK mode) and a removed key.
358 */
359
grab_key_callback(GtkWidget * widget,GdkEventKey * event,void * data)360 static gboolean grab_key_callback(GtkWidget* widget, GdkEventKey* event, void* data)
361 {
362 GdkModifierType accel_mods = 0;
363 guint accel_keyval;
364 EggCellRendererKeys *keys;
365 char *path;
366 gboolean edited;
367 gboolean cleared;
368 GdkModifierType consumed_modifiers;
369 guint upper;
370 GdkModifierType ignored_modifiers;
371 GdkDisplay *display;
372 GdkSeat *seat;
373
374 keys = EGG_CELL_RENDERER_KEYS(data);
375
376 if (is_modifier(event->hardware_keycode))
377 {
378 return TRUE;
379 }
380
381 edited = FALSE;
382 cleared = FALSE;
383
384 consumed_modifiers = 0;
385 gdk_keymap_translate_keyboard_state (gdk_keymap_get_for_display (gdk_display_get_default ()),
386 event->hardware_keycode,
387 event->state,
388 event->group,
389 NULL, NULL, NULL, &consumed_modifiers);
390
391 upper = event->keyval;
392 accel_keyval = gdk_keyval_to_lower(upper);
393
394 if (accel_keyval == GDK_KEY_ISO_Left_Tab)
395 {
396 accel_keyval = GDK_KEY_Tab;
397 }
398
399 /* Put shift back if it changed the case of the key, not otherwise. */
400 if (upper != accel_keyval && (consumed_modifiers & GDK_SHIFT_MASK))
401 {
402 consumed_modifiers &= ~(GDK_SHIFT_MASK);
403 }
404
405 egg_keymap_resolve_virtual_modifiers (gdk_keymap_get_for_display (gdk_display_get_default ()),
406 EGG_VIRTUAL_NUM_LOCK_MASK |
407 EGG_VIRTUAL_SCROLL_LOCK_MASK |
408 EGG_VIRTUAL_LOCK_MASK,
409 &ignored_modifiers);
410
411 /* http://bugzilla.gnome.org/show_bug.cgi?id=139605
412 * mouse keys should effect keybindings */
413 ignored_modifiers |= GDK_BUTTON1_MASK |
414 GDK_BUTTON2_MASK |
415 GDK_BUTTON3_MASK |
416 GDK_BUTTON4_MASK |
417 GDK_BUTTON5_MASK;
418
419 /* filter consumed/ignored modifiers */
420 if (keys->accel_mode == EGG_CELL_RENDERER_KEYS_MODE_GTK)
421 {
422 accel_mods = event->state & GDK_MODIFIER_MASK & ~(consumed_modifiers | ignored_modifiers);
423 }
424 else if (keys->accel_mode == EGG_CELL_RENDERER_KEYS_MODE_X)
425 {
426 accel_mods = event->state & GDK_MODIFIER_MASK & ~(ignored_modifiers);
427 }
428 else
429 {
430 g_assert_not_reached();
431 }
432
433 if (accel_mods == 0 && accel_keyval == GDK_KEY_Escape)
434 {
435 goto out; /* cancel */
436 }
437
438 /* clear the accelerator on Backspace */
439 if (accel_mods == 0 && accel_keyval == GDK_KEY_BackSpace)
440 {
441 cleared = TRUE;
442 goto out;
443 }
444
445 if (keys->accel_mode == EGG_CELL_RENDERER_KEYS_MODE_GTK)
446 {
447 if (!gtk_accelerator_valid (accel_keyval, accel_mods))
448 {
449 accel_keyval = 0;
450 accel_mods = 0;
451 }
452 }
453
454 edited = TRUE;
455
456 out:
457
458 display = gtk_widget_get_display (widget);
459 seat = gdk_display_get_default_seat (display);
460
461 gdk_seat_ungrab (seat);
462
463 path = g_strdup(g_object_get_data(G_OBJECT(keys->edit_widget), EGG_CELL_RENDERER_TEXT_PATH));
464
465 gtk_cell_editable_editing_done(GTK_CELL_EDITABLE(keys->edit_widget));
466 gtk_cell_editable_remove_widget(GTK_CELL_EDITABLE(keys->edit_widget));
467 keys->edit_widget = NULL;
468 keys->grab_widget = NULL;
469
470 if (edited)
471 {
472 g_signal_emit_by_name(G_OBJECT(keys), "accel_edited", path, accel_keyval, accel_mods, event->hardware_keycode);
473 }
474 else if (cleared)
475 {
476 g_signal_emit_by_name(G_OBJECT(keys), "accel_cleared", path);
477 }
478
479 g_free (path);
480 return TRUE;
481 }
482
ungrab_stuff(GtkWidget * widget,gpointer data)483 static void ungrab_stuff(GtkWidget* widget, gpointer data)
484 {
485 EggCellRendererKeys* keys = EGG_CELL_RENDERER_KEYS(data);
486 GdkDisplay *display;
487 GdkSeat *seat;
488
489 display = gtk_widget_get_display (widget);
490 seat = gdk_display_get_default_seat (display);
491
492 gdk_seat_ungrab (seat);
493
494 g_signal_handlers_disconnect_by_func(G_OBJECT(keys->grab_widget), G_CALLBACK(grab_key_callback), data);
495 }
496
pointless_eventbox_start_editing(GtkCellEditable * cell_editable,GdkEvent * event)497 static void pointless_eventbox_start_editing(GtkCellEditable* cell_editable, GdkEvent* event)
498 {
499 /* do nothing, because we are pointless */
500 }
501
pointless_eventbox_cell_editable_init(GtkCellEditableIface * iface)502 static void pointless_eventbox_cell_editable_init(GtkCellEditableIface* iface)
503 {
504 iface->start_editing = pointless_eventbox_start_editing;
505 }
506
507 static GType
pointless_eventbox_subclass_get_type(void)508 pointless_eventbox_subclass_get_type (void)
509 {
510 static GType eventbox_type = 0;
511
512 if (!eventbox_type)
513 {
514 static const GTypeInfo eventbox_info =
515 {
516 sizeof (GtkEventBoxClass),
517 NULL, /* base_init */
518 NULL, /* base_finalize */
519 NULL,
520 NULL, /* class_finalize */
521 NULL, /* class_data */
522 sizeof (GtkEventBox),
523 0, /* n_preallocs */
524 (GInstanceInitFunc) NULL,
525 };
526
527 static const GInterfaceInfo cell_editable_info = {
528 (GInterfaceInitFunc) pointless_eventbox_cell_editable_init,
529 NULL, NULL };
530
531 eventbox_type = g_type_register_static (GTK_TYPE_EVENT_BOX, "EggCellEditableEventBox", &eventbox_info, 0);
532
533 g_type_add_interface_static (eventbox_type,
534 GTK_TYPE_CELL_EDITABLE,
535 &cell_editable_info);
536 }
537
538 return eventbox_type;
539 }
540
541 static void
override_background_color(GtkWidget * widget,GdkRGBA * rgba)542 override_background_color (GtkWidget *widget,
543 GdkRGBA *rgba)
544 {
545 gchar *css;
546 GtkCssProvider *provider;
547
548 provider = gtk_css_provider_new ();
549
550 css = g_strdup_printf ("* { background-color: %s;}",
551 gdk_rgba_to_string (rgba));
552 gtk_css_provider_load_from_data (provider, css, -1, NULL);
553 g_free (css);
554
555 gtk_style_context_add_provider (gtk_widget_get_style_context (widget),
556 GTK_STYLE_PROVIDER (provider),
557 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
558 g_object_unref (provider);
559 }
560
561 static void
override_color(GtkWidget * widget,GdkRGBA * rgba)562 override_color (GtkWidget *widget,
563 GdkRGBA *rgba)
564 {
565 gchar *css;
566 GtkCssProvider *provider;
567
568 provider = gtk_css_provider_new ();
569
570 css = g_strdup_printf ("* { color: %s;}",
571 gdk_rgba_to_string (rgba));
572 gtk_css_provider_load_from_data (provider, css, -1, NULL);
573 g_free (css);
574
575 gtk_style_context_add_provider (gtk_widget_get_style_context (widget),
576 GTK_STYLE_PROVIDER (provider),
577 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
578 g_object_unref (provider);
579 }
580
581 static GtkCellEditable *
egg_cell_renderer_keys_start_editing(GtkCellRenderer * cell,GdkEvent * event,GtkWidget * widget,const gchar * path,const GdkRectangle * background_area,const GdkRectangle * cell_area,GtkCellRendererState flags)582 egg_cell_renderer_keys_start_editing (GtkCellRenderer *cell,
583 GdkEvent *event,
584 GtkWidget *widget,
585 const gchar *path,
586 const GdkRectangle *background_area,
587 const GdkRectangle *cell_area,
588 GtkCellRendererState flags)
589 {
590 GtkCellRendererText *celltext;
591 EggCellRendererKeys *keys;
592 GdkDisplay *display;
593 GdkSeat *seat;
594 GtkWidget *label;
595 GtkWidget *eventbox;
596 GValue celltext_editable = {0};
597 GdkRGBA box_color;
598 GdkRGBA label_color;
599 GdkRGBA *c;
600
601 celltext = GTK_CELL_RENDERER_TEXT (cell);
602 keys = EGG_CELL_RENDERER_KEYS (cell);
603
604 /* If the cell isn't editable we return NULL. */
605 g_value_init (&celltext_editable, G_TYPE_BOOLEAN);
606 g_object_get_property (G_OBJECT (celltext), "editable", &celltext_editable);
607 if (g_value_get_boolean (&celltext_editable) == FALSE)
608 return NULL;
609 g_return_val_if_fail (gtk_widget_get_window (widget) != NULL, NULL);
610
611 display = gtk_widget_get_display (widget);
612 seat = gdk_display_get_default_seat (display);
613
614 if (gdk_seat_grab (seat,
615 gtk_widget_get_window (widget),
616 GDK_SEAT_CAPABILITY_ALL,
617 FALSE,
618 NULL,
619 event,
620 NULL,
621 NULL) != GDK_GRAB_SUCCESS)
622 return NULL;
623
624 keys->grab_widget = widget;
625
626 g_signal_connect (G_OBJECT (widget), "key_press_event",
627 G_CALLBACK (grab_key_callback),
628 keys);
629
630 eventbox = g_object_new (pointless_eventbox_subclass_get_type (),
631 NULL);
632 keys->edit_widget = eventbox;
633 g_object_add_weak_pointer (G_OBJECT (keys->edit_widget),
634 (void**) &keys->edit_widget);
635
636 label = gtk_label_new (NULL);
637 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
638
639 gtk_style_context_get (gtk_widget_get_style_context (widget), GTK_STATE_INSENSITIVE,
640 GTK_STYLE_PROPERTY_BACKGROUND_COLOR,
641 &c, NULL);
642 box_color = *c;
643 gdk_rgba_free (c);
644
645 override_background_color (eventbox, &box_color);
646
647 gtk_style_context_get_color (gtk_widget_get_style_context (widget),
648 GTK_STATE_INSENSITIVE,
649 &label_color);
650
651 override_color (label, &label_color);
652
653 gtk_label_set_text (GTK_LABEL (label),
654 TOOLTIP_TEXT);
655
656 gtk_container_add (GTK_CONTAINER (eventbox), label);
657
658 g_object_set_data_full (G_OBJECT (keys->edit_widget), EGG_CELL_RENDERER_TEXT_PATH,
659 g_strdup (path), g_free);
660
661 gtk_widget_show_all (keys->edit_widget);
662
663 g_signal_connect (G_OBJECT (keys->edit_widget), "unrealize",
664 G_CALLBACK (ungrab_stuff), keys);
665
666 keys->edit_key = keys->accel_key;
667
668 return GTK_CELL_EDITABLE (keys->edit_widget);
669 }
670
egg_cell_renderer_keys_set_accelerator(EggCellRendererKeys * keys,guint keyval,guint keycode,EggVirtualModifierType mask)671 void egg_cell_renderer_keys_set_accelerator(EggCellRendererKeys* keys, guint keyval, guint keycode, EggVirtualModifierType mask)
672 {
673 char *text;
674 gboolean changed;
675
676 g_return_if_fail (EGG_IS_CELL_RENDERER_KEYS (keys));
677
678 g_object_freeze_notify (G_OBJECT (keys));
679
680 changed = FALSE;
681
682 if (keyval != keys->accel_key)
683 {
684 keys->accel_key = keyval;
685 g_object_notify (G_OBJECT (keys), "accel_key");
686 changed = TRUE;
687 }
688
689 if (mask != keys->accel_mask)
690 {
691 keys->accel_mask = mask;
692
693 g_object_notify (G_OBJECT (keys), "accel_mask");
694 changed = TRUE;
695 }
696
697 if (keycode != keys->keycode)
698 {
699 keys->keycode = keycode;
700
701 g_object_notify (G_OBJECT (keys), "keycode");
702 changed = TRUE;
703 }
704
705 g_object_thaw_notify (G_OBJECT (keys));
706
707 if (changed)
708 {
709 /* sync string to the key values */
710 text = convert_keysym_state_to_string (keys->accel_key, keys->keycode, keys->accel_mask);
711 g_object_set (keys, "text", text, NULL);
712 g_free (text);
713 }
714 }
715
egg_cell_renderer_keys_get_accelerator(EggCellRendererKeys * keys,guint * keyval,EggVirtualModifierType * mask)716 void egg_cell_renderer_keys_get_accelerator(EggCellRendererKeys* keys, guint* keyval, EggVirtualModifierType* mask)
717 {
718 g_return_if_fail(EGG_IS_CELL_RENDERER_KEYS(keys));
719
720 if (keyval)
721 {
722 *keyval = keys->accel_key;
723 }
724
725 if (mask)
726 {
727 *mask = keys->accel_mask;
728 }
729 }
730
egg_cell_renderer_keys_set_accel_mode(EggCellRendererKeys * keys,EggCellRendererKeysMode accel_mode)731 void egg_cell_renderer_keys_set_accel_mode (EggCellRendererKeys* keys, EggCellRendererKeysMode accel_mode)
732 {
733 g_return_if_fail(EGG_IS_CELL_RENDERER_KEYS(keys));
734 keys->accel_mode = accel_mode;
735 g_object_notify(G_OBJECT(keys), "accel_mode");
736 }
737