1 /* gtkcellrendereraccel.h
2 * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
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.
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.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #include "gtkaccelgroup.h"
23 #include "gtkmarshalers.h"
24 #include "gtkcellrendereraccel.h"
26 #include "gtkeventbox.h"
27 #include "gtkprivate.h"
28 #include "gdk/gdkkeysyms.h"
32 static void gtk_cell_renderer_accel_get_property (GObject *object,
36 static void gtk_cell_renderer_accel_set_property (GObject *object,
40 static void gtk_cell_renderer_accel_get_size (GtkCellRenderer *cell,
42 GdkRectangle *cell_area,
47 static GtkCellEditable *
48 gtk_cell_renderer_accel_start_editing (GtkCellRenderer *cell,
52 GdkRectangle *background_area,
53 GdkRectangle *cell_area,
54 GtkCellRendererState flags);
70 static guint signals[LAST_SIGNAL] = { 0 };
72 G_DEFINE_TYPE (GtkCellRendererAccel, gtk_cell_renderer_accel, GTK_TYPE_CELL_RENDERER_TEXT)
75 gtk_cell_renderer_accel_init (GtkCellRendererAccel *cell_accel)
80 gtk_cell_renderer_accel_class_init (GtkCellRendererAccelClass *cell_accel_class)
82 GObjectClass *object_class;
83 GtkCellRendererClass *cell_renderer_class;
85 object_class = G_OBJECT_CLASS (cell_accel_class);
86 cell_renderer_class = GTK_CELL_RENDERER_CLASS (cell_accel_class);
88 object_class->set_property = gtk_cell_renderer_accel_set_property;
89 object_class->get_property = gtk_cell_renderer_accel_get_property;
91 cell_renderer_class->get_size = gtk_cell_renderer_accel_get_size;
92 cell_renderer_class->start_editing = gtk_cell_renderer_accel_start_editing;
95 * GtkCellRendererAccel:accel-key:
97 * The keyval of the accelerator.
101 g_object_class_install_property (object_class,
103 g_param_spec_uint ("accel-key",
104 P_("Accelerator key"),
105 P_("The keyval of the accelerator"),
109 GTK_PARAM_READWRITE));
112 * GtkCellRendererAccel:accel-mods:
114 * The modifier mask of the accelerator.
118 g_object_class_install_property (object_class,
120 g_param_spec_flags ("accel-mods",
121 P_("Accelerator modifiers"),
122 P_("The modifier mask of the accelerator"),
123 GDK_TYPE_MODIFIER_TYPE,
125 GTK_PARAM_READWRITE));
128 * GtkCellRendererAccel:keycode:
130 * The hardware keycode of the accelerator. Note that the hardware keycode is
131 * only relevant if the key does not have a keyval. Normally, the keyboard
132 * configuration should assign keyvals to all keys.
136 g_object_class_install_property (object_class,
138 g_param_spec_uint ("keycode",
139 P_("Accelerator keycode"),
140 P_("The hardware keycode of the accelerator"),
144 GTK_PARAM_READWRITE));
147 * GtkCellRendererAccel:accel-mode:
149 * Determines if the edited accelerators are GTK+ accelerators. If
150 * they are, consumed modifiers are suppressed, only accelerators
151 * accepted by GTK+ are allowed, and the accelerators are rendered
152 * in the same way as they are in menus.
156 g_object_class_install_property (object_class,
158 g_param_spec_enum ("accel-mode",
159 P_("Accelerator Mode"),
160 P_("The type of accelerators"),
161 GTK_TYPE_CELL_RENDERER_ACCEL_MODE,
162 GTK_CELL_RENDERER_ACCEL_MODE_GTK,
163 GTK_PARAM_READWRITE));
166 * GtkCellRendererAccel::accel-edited:
167 * @accel: the object reveiving the signal
168 * @path_string: the path identifying the row of the edited cell
169 * @accel_key: the new accelerator keyval
170 * @accel_mods: the new acclerator modifier mask
171 * @hardware_keycode: the keycode of the new accelerator
173 * Gets emitted when the user has selected a new accelerator.
177 signals[ACCEL_EDITED] = g_signal_new (I_("accel-edited"),
178 GTK_TYPE_CELL_RENDERER_ACCEL,
180 G_STRUCT_OFFSET (GtkCellRendererAccelClass, accel_edited),
182 _gtk_marshal_VOID__STRING_UINT_FLAGS_UINT,
186 GDK_TYPE_MODIFIER_TYPE,
190 * GtkCellRendererAccel::accel-cleared:
191 * @accel: the object reveiving the signal
192 * @path_string: the path identifying the row of the edited cell
194 * Gets emitted when the user has removed the accelerator.
198 signals[ACCEL_CLEARED] = g_signal_new (I_("accel-cleared"),
199 GTK_TYPE_CELL_RENDERER_ACCEL,
201 G_STRUCT_OFFSET (GtkCellRendererAccelClass, accel_cleared),
203 g_cclosure_marshal_VOID__STRING,
210 * gtk_cell_renderer_accel_new:
212 * Creates a new #GtkCellRendererAccel.
214 * Returns: the new cell renderer
219 gtk_cell_renderer_accel_new (void)
221 return g_object_new (GTK_TYPE_CELL_RENDERER_ACCEL, NULL);
225 convert_keysym_state_to_string (GtkCellRendererAccel *accel,
227 GdkModifierType mask,
230 if (keysym == 0 && keycode == 0)
231 /* This label is displayed in a treeview cell displaying
232 * a disabled accelerator key combination. Only include
233 * the text after the | in the translation.
235 return g_strdup (Q_("Accelerator|Disabled"));
238 if (accel->accel_mode == GTK_CELL_RENDERER_ACCEL_MODE_GTK)
239 return gtk_accelerator_get_label (keysym, mask);
244 name = gtk_accelerator_name (keysym, mask);
250 name = g_strdup_printf ("%s0x%02x", tmp, keycode);
260 gtk_cell_renderer_accel_get_property (GObject *object,
265 GtkCellRendererAccel *accel = GTK_CELL_RENDERER_ACCEL (object);
270 g_value_set_uint (value, accel->accel_key);
273 case PROP_ACCEL_MODS:
274 g_value_set_flags (value, accel->accel_mods);
278 g_value_set_uint (value, accel->keycode);
281 case PROP_ACCEL_MODE:
282 g_value_set_enum (value, accel->accel_mode);
286 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
291 gtk_cell_renderer_accel_set_property (GObject *object,
296 GtkCellRendererAccel *accel = GTK_CELL_RENDERER_ACCEL (object);
297 gboolean changed = FALSE;
303 guint accel_key = g_value_get_uint (value);
305 if (accel->accel_key != accel_key)
307 accel->accel_key = accel_key;
313 case PROP_ACCEL_MODS:
315 guint accel_mods = g_value_get_flags (value);
317 if (accel->accel_mods != accel_mods)
319 accel->accel_mods = accel_mods;
326 guint keycode = g_value_get_uint (value);
328 if (accel->keycode != keycode)
330 accel->keycode = keycode;
336 case PROP_ACCEL_MODE:
337 accel->accel_mode = g_value_get_enum (value);
341 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
348 text = convert_keysym_state_to_string (accel, accel->accel_key, accel->accel_mods, accel->keycode);
349 g_object_set (accel, "text", text, NULL);
355 gtk_cell_renderer_accel_get_size (GtkCellRenderer *cell,
357 GdkRectangle *cell_area,
364 GtkCellRendererAccel *accel = (GtkCellRendererAccel *) cell;
365 GtkRequisition requisition;
367 if (accel->sizing_label == NULL)
368 accel->sizing_label = gtk_label_new (_("New accelerator..."));
370 gtk_widget_size_request (accel->sizing_label, &requisition);
372 GTK_CELL_RENDERER_CLASS (gtk_cell_renderer_accel_parent_class)->get_size (cell, widget, cell_area,
373 x_offset, y_offset, width, height);
375 /* FIXME: need to take the cell_area et al. into account */
377 *width = MAX (*width, requisition.width);
379 *height = MAX (*height, requisition.height);
383 grab_key_callback (GtkWidget *widget,
385 GtkCellRendererAccel *accel)
387 GdkModifierType accel_mods = 0;
392 GdkModifierType consumed_modifiers;
395 display = gtk_widget_get_display (widget);
397 if (event->is_modifier)
403 gdk_keymap_translate_keyboard_state (gdk_keymap_get_for_display (display),
404 event->hardware_keycode,
407 NULL, NULL, NULL, &consumed_modifiers);
409 accel_key = gdk_keyval_to_lower (event->keyval);
410 if (accel_key == GDK_ISO_Left_Tab)
413 accel_mods = event->state & gtk_accelerator_get_default_mod_mask ();
415 /* Filter consumed modifiers
417 if (accel->accel_mode == GTK_CELL_RENDERER_ACCEL_MODE_GTK)
418 accel_mods &= ~consumed_modifiers;
420 /* Put shift back if it changed the case of the key, not otherwise.
422 if (accel_key != event->keyval)
423 accel_mods |= GDK_SHIFT_MASK;
427 switch (event->keyval)
430 goto out; /* cancel */
432 /* clear the accelerator on Backspace */
440 if (accel->accel_mode == GTK_CELL_RENDERER_ACCEL_MODE_GTK)
442 if (!gtk_accelerator_valid (accel_key, accel_mods))
444 gtk_widget_error_bell (widget);
453 gdk_display_keyboard_ungrab (display, event->time);
454 gdk_display_pointer_ungrab (display, event->time);
456 path = g_strdup (g_object_get_data (G_OBJECT (accel->edit_widget), "gtk-cell-renderer-text"));
458 gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (accel->edit_widget));
459 gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (accel->edit_widget));
460 accel->edit_widget = NULL;
461 accel->grab_widget = NULL;
464 g_signal_emit (accel, signals[ACCEL_EDITED], 0, path,
465 accel_key, accel_mods, event->hardware_keycode);
467 g_signal_emit (accel, signals[ACCEL_CLEARED], 0, path);
475 ungrab_stuff (GtkWidget *widget,
476 GtkCellRendererAccel *accel)
478 GdkDisplay *display = gtk_widget_get_display (widget);
480 gdk_display_keyboard_ungrab (display, GDK_CURRENT_TIME);
481 gdk_display_pointer_ungrab (display, GDK_CURRENT_TIME);
483 g_signal_handlers_disconnect_by_func (G_OBJECT (accel->grab_widget),
484 G_CALLBACK (grab_key_callback),
489 _gtk_cell_editable_event_box_start_editing (GtkCellEditable *cell_editable,
492 /* do nothing, because we are pointless */
496 _gtk_cell_editable_event_box_cell_editable_init (GtkCellEditableIface *iface)
498 iface->start_editing = _gtk_cell_editable_event_box_start_editing;
501 typedef GtkEventBox GtkCellEditableEventBox;
502 typedef GtkEventBoxClass GtkCellEditableEventBoxClass;
504 G_DEFINE_TYPE_WITH_CODE (GtkCellEditableEventBox, _gtk_cell_editable_event_box, GTK_TYPE_EVENT_BOX, { \
505 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_EDITABLE, _gtk_cell_editable_event_box_cell_editable_init) \
510 _gtk_cell_editable_event_box_class_init (GtkCellEditableEventBoxClass *class)
515 _gtk_cell_editable_event_box_init (GtkCellEditableEventBox *box)
519 static GtkCellEditable *
520 gtk_cell_renderer_accel_start_editing (GtkCellRenderer *cell,
524 GdkRectangle *background_area,
525 GdkRectangle *cell_area,
526 GtkCellRendererState flags)
528 GtkCellRendererText *celltext;
529 GtkCellRendererAccel *accel;
533 celltext = GTK_CELL_RENDERER_TEXT (cell);
534 accel = GTK_CELL_RENDERER_ACCEL (cell);
536 /* If the cell isn't editable we return NULL. */
537 if (celltext->editable == FALSE)
540 g_return_val_if_fail (widget->window != NULL, NULL);
542 if (gdk_keyboard_grab (widget->window, FALSE,
543 gdk_event_get_time (event)) != GDK_GRAB_SUCCESS)
546 if (gdk_pointer_grab (widget->window, FALSE,
547 GDK_BUTTON_PRESS_MASK,
549 gdk_event_get_time (event)) != GDK_GRAB_SUCCESS)
551 gdk_display_keyboard_ungrab (gtk_widget_get_display (widget),
552 gdk_event_get_time (event));
556 accel->grab_widget = widget;
558 g_signal_connect (G_OBJECT (widget), "key_press_event",
559 G_CALLBACK (grab_key_callback),
562 eventbox = g_object_new (_gtk_cell_editable_event_box_get_type (), NULL);
563 accel->edit_widget = eventbox;
564 g_object_add_weak_pointer (G_OBJECT (accel->edit_widget),
565 (gpointer) &accel->edit_widget);
567 label = gtk_label_new (NULL);
568 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
570 gtk_widget_modify_bg (eventbox, GTK_STATE_NORMAL,
571 &widget->style->bg[GTK_STATE_SELECTED]);
573 gtk_widget_modify_fg (label, GTK_STATE_NORMAL,
574 &widget->style->fg[GTK_STATE_SELECTED]);
576 /* This label is displayed in a treeview cell displaying
577 * an accelerator when the cell is clicked to change the
580 gtk_label_set_text (GTK_LABEL (label), _("New accelerator..."));
582 gtk_container_add (GTK_CONTAINER (eventbox), label);
584 g_object_set_data_full (G_OBJECT (accel->edit_widget), "gtk-cell-renderer-text",
585 g_strdup (path), g_free);
587 gtk_widget_show_all (accel->edit_widget);
589 g_signal_connect (G_OBJECT (accel->edit_widget), "unrealize",
590 G_CALLBACK (ungrab_stuff), accel);
592 return GTK_CELL_EDITABLE (accel->edit_widget);
596 #define __GTK_CELL_RENDERER_ACCEL_C__
597 #include "gtkaliasdef.c"