1/* gtkcellrendereraccel.h
2 * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "config.h"
19
20#include "gtkcellrendereraccel.h"
21
22#include "gtkintl.h"
23#include "gtkaccelgroup.h"
24#include "gtkmarshalers.h"
25#include "gtklabel.h"
26#include "gtkmain.h"
27#include "gtksizerequest.h"
28#include "gtktypebuiltins.h"
29#include "gtkprivate.h"
30#include "gtkeventcontrollerkey.h"
31#include "gtknative.h"
32#include "gtkbinlayout.h"
33
34
35/**
36 * GtkCellRendererAccel:
37 *
38 * Renders a keyboard accelerator in a cell
39 *
40 * `GtkCellRendererAccel` displays a keyboard accelerator (i.e. a key
41 * combination like `Control + a`). If the cell renderer is editable,
42 * the accelerator can be changed by simply typing the new combination.
43 */
44
45
46static void gtk_cell_renderer_accel_get_property (GObject *object,
47 guint param_id,
48 GValue *value,
49 GParamSpec *pspec);
50static void gtk_cell_renderer_accel_set_property (GObject *object,
51 guint param_id,
52 const GValue *value,
53 GParamSpec *pspec);
54static void gtk_cell_renderer_accel_get_preferred_width
55 (GtkCellRenderer *cell,
56 GtkWidget *widget,
57 int *minimum_size,
58 int *natural_size);
59static GtkCellEditable *
60 gtk_cell_renderer_accel_start_editing (GtkCellRenderer *cell,
61 GdkEvent *event,
62 GtkWidget *widget,
63 const char *path,
64 const GdkRectangle *background_area,
65 const GdkRectangle *cell_area,
66 GtkCellRendererState flags);
67static char *convert_keysym_state_to_string (GtkCellRendererAccel *accel,
68 guint keysym,
69 GdkModifierType mask,
70 guint keycode);
71static GtkWidget *gtk_cell_editable_widget_new (GtkCellRenderer *cell,
72 GtkCellRendererAccelMode mode,
73 const char *path);
74
75enum {
76 ACCEL_EDITED,
77 ACCEL_CLEARED,
78 LAST_SIGNAL
79};
80
81enum {
82 PROP_ACCEL_KEY = 1,
83 PROP_ACCEL_MODS,
84 PROP_KEYCODE,
85 PROP_ACCEL_MODE
86};
87
88static guint signals[LAST_SIGNAL] = { 0 };
89
90typedef struct _GtkCellRendererAccelPrivate GtkCellRendererAccelPrivate;
91typedef struct _GtkCellRendererAccelClass GtkCellRendererAccelClass;
92
93struct _GtkCellRendererAccel
94{
95 GtkCellRendererText parent;
96};
97
98struct _GtkCellRendererAccelClass
99{
100 GtkCellRendererTextClass parent_class;
101
102 void (* accel_edited) (GtkCellRendererAccel *accel,
103 const char *path_string,
104 guint accel_key,
105 GdkModifierType accel_mods,
106 guint hardware_keycode);
107
108 void (* accel_cleared) (GtkCellRendererAccel *accel,
109 const char *path_string);
110
111 /* Padding for future expansion */
112 void (*_gtk_reserved0) (void);
113 void (*_gtk_reserved1) (void);
114 void (*_gtk_reserved2) (void);
115 void (*_gtk_reserved3) (void);
116 void (*_gtk_reserved4) (void);
117};
118
119struct _GtkCellRendererAccelPrivate
120{
121 GtkWidget *sizing_label;
122
123 GtkCellRendererAccelMode accel_mode;
124 GdkModifierType accel_mods;
125 guint accel_key;
126 guint keycode;
127};
128
129G_DEFINE_TYPE_WITH_PRIVATE (GtkCellRendererAccel, gtk_cell_renderer_accel, GTK_TYPE_CELL_RENDERER_TEXT)
130
131static void
132gtk_cell_renderer_accel_init (GtkCellRendererAccel *cell_accel)
133{
134 char *text;
135
136 text = convert_keysym_state_to_string (accel: cell_accel, keysym: 0, mask: 0, keycode: 0);
137 g_object_set (object: cell_accel, first_property_name: "text", text, NULL);
138 g_free (mem: text);
139}
140
141static void
142gtk_cell_renderer_accel_dispose (GObject *object)
143{
144 GtkCellRendererAccelPrivate *priv = gtk_cell_renderer_accel_get_instance_private (GTK_CELL_RENDERER_ACCEL (object));
145
146 g_clear_object (&priv->sizing_label);
147
148 G_OBJECT_CLASS (gtk_cell_renderer_accel_parent_class)->dispose (object);
149}
150
151static void
152gtk_cell_renderer_accel_class_init (GtkCellRendererAccelClass *cell_accel_class)
153{
154 GObjectClass *object_class;
155 GtkCellRendererClass *cell_renderer_class;
156
157 object_class = G_OBJECT_CLASS (cell_accel_class);
158 cell_renderer_class = GTK_CELL_RENDERER_CLASS (cell_accel_class);
159
160 object_class->set_property = gtk_cell_renderer_accel_set_property;
161 object_class->get_property = gtk_cell_renderer_accel_get_property;
162 object_class->dispose = gtk_cell_renderer_accel_dispose;
163
164 cell_renderer_class->get_preferred_width = gtk_cell_renderer_accel_get_preferred_width;
165 cell_renderer_class->start_editing = gtk_cell_renderer_accel_start_editing;
166
167 /**
168 * GtkCellRendererAccel:accel-key:
169 *
170 * The keyval of the accelerator.
171 */
172 g_object_class_install_property (oclass: object_class,
173 property_id: PROP_ACCEL_KEY,
174 pspec: g_param_spec_uint (name: "accel-key",
175 P_("Accelerator key"),
176 P_("The keyval of the accelerator"),
177 minimum: 0,
178 G_MAXINT,
179 default_value: 0,
180 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
181
182 /**
183 * GtkCellRendererAccel:accel-mods:
184 *
185 * The modifier mask of the accelerator.
186 */
187 g_object_class_install_property (oclass: object_class,
188 property_id: PROP_ACCEL_MODS,
189 pspec: g_param_spec_flags (name: "accel-mods",
190 P_("Accelerator modifiers"),
191 P_("The modifier mask of the accelerator"),
192 flags_type: GDK_TYPE_MODIFIER_TYPE,
193 default_value: 0,
194 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
195
196 /**
197 * GtkCellRendererAccel:keycode:
198 *
199 * The hardware keycode of the accelerator. Note that the hardware keycode is
200 * only relevant if the key does not have a keyval. Normally, the keyboard
201 * configuration should assign keyvals to all keys.
202 */
203 g_object_class_install_property (oclass: object_class,
204 property_id: PROP_KEYCODE,
205 pspec: g_param_spec_uint (name: "keycode",
206 P_("Accelerator keycode"),
207 P_("The hardware keycode of the accelerator"),
208 minimum: 0,
209 G_MAXINT,
210 default_value: 0,
211 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
212
213 /**
214 * GtkCellRendererAccel:accel-mode:
215 *
216 * Determines if the edited accelerators are GTK accelerators. If
217 * they are, consumed modifiers are suppressed, only accelerators
218 * accepted by GTK are allowed, and the accelerators are rendered
219 * in the same way as they are in menus.
220 */
221 g_object_class_install_property (oclass: object_class,
222 property_id: PROP_ACCEL_MODE,
223 pspec: g_param_spec_enum (name: "accel-mode",
224 P_("Accelerator Mode"),
225 P_("The type of accelerators"),
226 enum_type: GTK_TYPE_CELL_RENDERER_ACCEL_MODE,
227 default_value: GTK_CELL_RENDERER_ACCEL_MODE_GTK,
228 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
229
230 /**
231 * GtkCellRendererAccel::accel-edited:
232 * @accel: the object reveiving the signal
233 * @path_string: the path identifying the row of the edited cell
234 * @accel_key: the new accelerator keyval
235 * @accel_mods: the new acclerator modifier mask
236 * @hardware_keycode: the keycode of the new accelerator
237 *
238 * Gets emitted when the user has selected a new accelerator.
239 */
240 signals[ACCEL_EDITED] = g_signal_new (I_("accel-edited"),
241 GTK_TYPE_CELL_RENDERER_ACCEL,
242 signal_flags: G_SIGNAL_RUN_LAST,
243 G_STRUCT_OFFSET (GtkCellRendererAccelClass, accel_edited),
244 NULL, NULL,
245 c_marshaller: _gtk_marshal_VOID__STRING_UINT_FLAGS_UINT,
246 G_TYPE_NONE, n_params: 4,
247 G_TYPE_STRING,
248 G_TYPE_UINT,
249 GDK_TYPE_MODIFIER_TYPE,
250 G_TYPE_UINT);
251
252 /**
253 * GtkCellRendererAccel::accel-cleared:
254 * @accel: the object reveiving the signal
255 * @path_string: the path identifying the row of the edited cell
256 *
257 * Gets emitted when the user has removed the accelerator.
258 */
259 signals[ACCEL_CLEARED] = g_signal_new (I_("accel-cleared"),
260 GTK_TYPE_CELL_RENDERER_ACCEL,
261 signal_flags: G_SIGNAL_RUN_LAST,
262 G_STRUCT_OFFSET (GtkCellRendererAccelClass, accel_cleared),
263 NULL, NULL,
264 NULL,
265 G_TYPE_NONE, n_params: 1,
266 G_TYPE_STRING);
267}
268
269
270/**
271 * gtk_cell_renderer_accel_new:
272 *
273 * Creates a new `GtkCellRendererAccel`.
274 *
275 * Returns: the new cell renderer
276 */
277GtkCellRenderer *
278gtk_cell_renderer_accel_new (void)
279{
280 return g_object_new (GTK_TYPE_CELL_RENDERER_ACCEL, NULL);
281}
282
283static char *
284convert_keysym_state_to_string (GtkCellRendererAccel *accel,
285 guint keysym,
286 GdkModifierType mask,
287 guint keycode)
288{
289 GtkCellRendererAccelPrivate *priv = gtk_cell_renderer_accel_get_instance_private (self: accel);
290
291 if (keysym == 0 && keycode == 0)
292 /* This label is displayed in a treeview cell displaying
293 * a disabled accelerator key combination.
294 */
295 return g_strdup (C_("Accelerator", "Disabled"));
296 else
297 {
298 if (priv->accel_mode == GTK_CELL_RENDERER_ACCEL_MODE_GTK)
299 {
300 if (!gtk_accelerator_valid (keyval: keysym, modifiers: mask))
301 /* This label is displayed in a treeview cell displaying
302 * an accelerator key combination that is not valid according
303 * to gtk_accelerator_valid().
304 */
305 return g_strdup (C_("Accelerator", "Invalid"));
306
307 return gtk_accelerator_get_label (accelerator_key: keysym, accelerator_mods: mask);
308 }
309 else
310 {
311 char *name;
312
313 name = gtk_accelerator_get_label_with_keycode (NULL, accelerator_key: keysym, keycode, accelerator_mods: mask);
314 if (name == NULL)
315 name = gtk_accelerator_name_with_keycode (NULL, accelerator_key: keysym, keycode, accelerator_mods: mask);
316
317 return name;
318 }
319 }
320}
321
322static void
323gtk_cell_renderer_accel_get_property (GObject *object,
324 guint param_id,
325 GValue *value,
326 GParamSpec *pspec)
327{
328 GtkCellRendererAccelPrivate *priv = gtk_cell_renderer_accel_get_instance_private (GTK_CELL_RENDERER_ACCEL (object));
329
330 switch (param_id)
331 {
332 case PROP_ACCEL_KEY:
333 g_value_set_uint (value, v_uint: priv->accel_key);
334 break;
335
336 case PROP_ACCEL_MODS:
337 g_value_set_flags (value, v_flags: priv->accel_mods);
338 break;
339
340 case PROP_KEYCODE:
341 g_value_set_uint (value, v_uint: priv->keycode);
342 break;
343
344 case PROP_ACCEL_MODE:
345 g_value_set_enum (value, v_enum: priv->accel_mode);
346 break;
347
348 default:
349 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
350 }
351}
352
353static void
354gtk_cell_renderer_accel_set_property (GObject *object,
355 guint param_id,
356 const GValue *value,
357 GParamSpec *pspec)
358{
359 GtkCellRendererAccel *accel = GTK_CELL_RENDERER_ACCEL (object);
360 GtkCellRendererAccelPrivate *priv = gtk_cell_renderer_accel_get_instance_private (GTK_CELL_RENDERER_ACCEL (object));
361 gboolean changed = FALSE;
362
363 switch (param_id)
364 {
365 case PROP_ACCEL_KEY:
366 {
367 guint accel_key = g_value_get_uint (value);
368
369 if (priv->accel_key != accel_key)
370 {
371 priv->accel_key = accel_key;
372 changed = TRUE;
373 g_object_notify (object, property_name: "accel-key");
374 }
375 }
376 break;
377
378 case PROP_ACCEL_MODS:
379 {
380 guint accel_mods = g_value_get_flags (value);
381
382 if (priv->accel_mods != accel_mods)
383 {
384 priv->accel_mods = accel_mods;
385 changed = TRUE;
386 g_object_notify (object, property_name: "accel-mods");
387 }
388 }
389 break;
390 case PROP_KEYCODE:
391 {
392 guint keycode = g_value_get_uint (value);
393
394 if (priv->keycode != keycode)
395 {
396 priv->keycode = keycode;
397 changed = TRUE;
398 g_object_notify (object, property_name: "keycode");
399 }
400 }
401 break;
402
403 case PROP_ACCEL_MODE:
404 if (priv->accel_mode != g_value_get_enum (value))
405 {
406 priv->accel_mode = g_value_get_enum (value);
407 g_object_notify (object, property_name: "accel-mode");
408 }
409 break;
410
411 default:
412 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
413 }
414
415 if (changed)
416 {
417 char *text;
418
419 text = convert_keysym_state_to_string (accel, keysym: priv->accel_key, mask: priv->accel_mods, keycode: priv->keycode);
420 g_object_set (object: accel, first_property_name: "text", text, NULL);
421 g_free (mem: text);
422 }
423}
424
425static void
426gtk_cell_renderer_accel_get_preferred_width (GtkCellRenderer *cell,
427 GtkWidget *widget,
428 int *minimum_size,
429 int *natural_size)
430
431{
432 GtkCellRendererAccelPrivate *priv = gtk_cell_renderer_accel_get_instance_private (GTK_CELL_RENDERER_ACCEL (cell));
433 GtkRequisition min_req, nat_req;
434
435 if (priv->sizing_label == NULL)
436 {
437 priv->sizing_label = gtk_label_new (_("New accelerator…"));
438 g_object_ref_sink (priv->sizing_label);
439 }
440
441 gtk_widget_get_preferred_size (widget: priv->sizing_label, minimum_size: &min_req, natural_size: &nat_req);
442
443 GTK_CELL_RENDERER_CLASS (gtk_cell_renderer_accel_parent_class)->get_preferred_width (cell, widget,
444 minimum_size, natural_size);
445
446 /* FIXME: need to take the cell_area et al. into account */
447 if (minimum_size)
448 *minimum_size = MAX (*minimum_size, min_req.width);
449 if (natural_size)
450 *natural_size = MAX (*natural_size, nat_req.width);
451}
452
453static GtkCellEditable *
454gtk_cell_renderer_accel_start_editing (GtkCellRenderer *cell,
455 GdkEvent *event,
456 GtkWidget *widget,
457 const char *path,
458 const GdkRectangle *background_area,
459 const GdkRectangle *cell_area,
460 GtkCellRendererState flags)
461{
462 GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (cell);
463 GtkCellRendererAccel *accel = GTK_CELL_RENDERER_ACCEL (cell);
464 GtkCellRendererAccelPrivate *priv = gtk_cell_renderer_accel_get_instance_private (self: accel);
465 GtkWidget *editable;
466 gboolean is_editable;
467
468 /* If the cell isn't editable we return NULL. */
469 g_object_get (object: celltext, first_property_name: "editable", &is_editable, NULL);
470 if (!is_editable)
471 return NULL;
472
473 editable = gtk_cell_editable_widget_new (cell, mode: priv->accel_mode, path);
474
475 return GTK_CELL_EDITABLE (editable);
476}
477
478/* --------------------------------- */
479
480typedef struct _GtkCellEditableWidget GtkCellEditableWidget;
481typedef GtkWidgetClass GtkCellEditableWidgetClass;
482
483struct _GtkCellEditableWidget
484{
485 GtkWidget parent;
486
487 gboolean editing_canceled;
488 GtkCellRendererAccelMode accel_mode;
489 char *path;
490 GtkCellRenderer *cell;
491 GtkWidget *label;
492};
493
494enum {
495 PROP_EDITING_CANCELED = 1,
496 PROP_MODE,
497 PROP_PATH
498};
499
500GType gtk_cell_editable_widget_get_type (void);
501static void gtk_cell_editable_widget_cell_editable_init (GtkCellEditableIface *iface);
502
503G_DEFINE_TYPE_WITH_CODE (GtkCellEditableWidget, gtk_cell_editable_widget, GTK_TYPE_WIDGET,
504 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_EDITABLE, gtk_cell_editable_widget_cell_editable_init))
505
506static void
507gtk_cell_editable_widget_start_editing (GtkCellEditable *cell_editable,
508 GdkEvent *event)
509{
510 /* do nothing, because we are pointless */
511}
512
513static void
514gtk_cell_editable_widget_cell_editable_init (GtkCellEditableIface *iface)
515{
516 iface->start_editing = gtk_cell_editable_widget_start_editing;
517}
518
519static gboolean
520key_controller_modifiers (GtkEventControllerKey *key,
521 GdkModifierType state,
522 GtkWidget *widget)
523{
524 /* Ignore modifiers */
525 return TRUE;
526}
527
528static gboolean
529key_controller_key_pressed (GtkEventControllerKey *key,
530 guint keyval,
531 guint keycode,
532 GdkModifierType state,
533 GtkWidget *widget)
534{
535 GtkCellEditableWidget *box = (GtkCellEditableWidget*)widget;
536 gboolean edited = FALSE;
537 gboolean cleared = FALSE;
538 GdkModifierType accel_mods = 0;
539 guint accel_key;
540 GdkEvent *event;
541
542 event = gtk_event_controller_get_current_event (GTK_EVENT_CONTROLLER (key));
543 if (!gdk_key_event_get_match (event, keyval: &accel_key, modifiers: &accel_mods))
544 return FALSE;
545
546 if (accel_mods == 0)
547 {
548 switch (keyval)
549 {
550 case GDK_KEY_BackSpace:
551 cleared = TRUE;
552 G_GNUC_FALLTHROUGH;
553 case GDK_KEY_Escape:
554 goto out;
555 default:
556 break;
557 }
558 }
559
560 if (box->accel_mode == GTK_CELL_RENDERER_ACCEL_MODE_GTK &&
561 !gtk_accelerator_valid (keyval: accel_key, modifiers: accel_mods))
562 {
563 gtk_widget_error_bell (widget);
564 return TRUE;
565 }
566
567 edited = TRUE;
568
569 out:
570 gtk_grab_remove (widget);
571 gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (widget));
572 gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (widget));
573
574 if (edited)
575 g_signal_emit (instance: box->cell, signal_id: signals[ACCEL_EDITED], detail: 0, box->path,
576 accel_key, accel_mods, keycode);
577 else if (cleared)
578 g_signal_emit (instance: box->cell, signal_id: signals[ACCEL_CLEARED], detail: 0, box->path);
579
580 return TRUE;
581}
582
583static void
584gtk_cell_editable_widget_unrealize (GtkWidget *widget)
585{
586 gtk_grab_remove (widget);
587
588 GTK_WIDGET_CLASS (gtk_cell_editable_widget_parent_class)->unrealize (widget);
589}
590
591static void
592gtk_cell_editable_widget_set_property (GObject *object,
593 guint prop_id,
594 const GValue *value,
595 GParamSpec *pspec)
596{
597 GtkCellEditableWidget *box = (GtkCellEditableWidget*)object;
598
599 switch (prop_id)
600 {
601 case PROP_EDITING_CANCELED:
602 box->editing_canceled = g_value_get_boolean (value);
603 break;
604 case PROP_MODE:
605 box->accel_mode = g_value_get_enum (value);
606 break;
607 case PROP_PATH:
608 box->path = g_value_dup_string (value);
609 break;
610 default:
611 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
612 break;
613 }
614}
615
616static void
617gtk_cell_editable_widget_get_property (GObject *object,
618 guint prop_id,
619 GValue *value,
620 GParamSpec *pspec)
621{
622 GtkCellEditableWidget *box = (GtkCellEditableWidget*)object;
623
624 switch (prop_id)
625 {
626 case PROP_EDITING_CANCELED:
627 g_value_set_boolean (value, v_boolean: box->editing_canceled);
628 break;
629 case PROP_MODE:
630 g_value_set_enum (value, v_enum: box->accel_mode);
631 break;
632 case PROP_PATH:
633 g_value_set_string (value, v_string: box->path);
634 break;
635 default:
636 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
637 break;
638 }
639}
640
641static void
642gtk_cell_editable_widget_dispose (GObject *object)
643{
644 GtkCellEditableWidget *box = (GtkCellEditableWidget*)object;
645
646 g_clear_pointer (&box->label, gtk_widget_unparent);
647
648 G_OBJECT_CLASS (gtk_cell_editable_widget_parent_class)->dispose (object);
649}
650
651static void
652gtk_cell_editable_widget_finalize (GObject *object)
653{
654 GtkCellEditableWidget *box = (GtkCellEditableWidget*)object;
655
656 g_free (mem: box->path);
657
658 G_OBJECT_CLASS (gtk_cell_editable_widget_parent_class)->finalize (object);
659}
660
661static void
662gtk_cell_editable_widget_class_init (GtkCellEditableWidgetClass *class)
663{
664 GObjectClass *object_class = G_OBJECT_CLASS (class);
665 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
666
667 object_class->finalize = gtk_cell_editable_widget_finalize;
668 object_class->dispose = gtk_cell_editable_widget_dispose;
669 object_class->set_property = gtk_cell_editable_widget_set_property;
670 object_class->get_property = gtk_cell_editable_widget_get_property;
671
672 widget_class->unrealize = gtk_cell_editable_widget_unrealize;
673
674 g_object_class_override_property (oclass: object_class,
675 property_id: PROP_EDITING_CANCELED,
676 name: "editing-canceled");
677
678 g_object_class_install_property (oclass: object_class, property_id: PROP_MODE,
679 pspec: g_param_spec_enum (name: "accel-mode", NULL, NULL,
680 enum_type: GTK_TYPE_CELL_RENDERER_ACCEL_MODE,
681 default_value: GTK_CELL_RENDERER_ACCEL_MODE_GTK,
682 GTK_PARAM_READWRITE));
683
684 g_object_class_install_property (oclass: object_class, property_id: PROP_PATH,
685 pspec: g_param_spec_string (name: "path", NULL, NULL,
686 NULL, GTK_PARAM_READWRITE));
687
688 gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
689 gtk_widget_class_set_css_name (widget_class, I_("acceleditor"));
690}
691
692static void
693gtk_cell_editable_widget_init (GtkCellEditableWidget *box)
694{
695 GtkWidget *widget = GTK_WIDGET (box);
696 GtkEventController *controller;
697
698 gtk_widget_set_focusable (widget, TRUE);
699
700 controller = gtk_event_controller_key_new ();
701 g_signal_connect (controller, "key-pressed",
702 G_CALLBACK (key_controller_key_pressed), box);
703 g_signal_connect (controller, "modifiers",
704 G_CALLBACK (key_controller_modifiers), box);
705 gtk_widget_add_controller (widget, controller);
706}
707
708static GtkWidget *
709gtk_cell_editable_widget_new (GtkCellRenderer *cell,
710 GtkCellRendererAccelMode mode,
711 const char *path)
712{
713 GtkCellEditableWidget *box;
714
715 box = g_object_new (object_type: gtk_cell_editable_widget_get_type (),
716 first_property_name: "accel-mode", mode,
717 "path", path,
718 NULL);
719 box->cell = cell;
720
721 box->label = gtk_label_new (NULL);
722 gtk_widget_set_halign (widget: box->label, align: GTK_ALIGN_START);
723 gtk_widget_set_valign (widget: box->label, align: GTK_ALIGN_CENTER);
724
725 gtk_widget_set_state_flags (widget: box->label, flags: GTK_STATE_FLAG_SELECTED, TRUE);
726
727 /* This label is displayed in a treeview cell displaying an accelerator
728 * when the cell is clicked to change the acelerator.
729 */
730 gtk_label_set_text (GTK_LABEL (box->label), _("New accelerator…"));
731
732 gtk_widget_set_parent (widget: box->label, GTK_WIDGET (box));
733
734 gtk_grab_add (GTK_WIDGET (box));
735
736 return GTK_WIDGET (box);
737}
738

source code of gtk/gtk/gtkcellrendereraccel.c