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