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_finalize (GObject *object);
33 static GtkCellEditable *gtk_cell_renderer_accel_start_editing (GtkCellRenderer *cell,
37 GdkRectangle *background_area,
38 GdkRectangle *cell_area,
39 GtkCellRendererState flags);
41 static void gtk_cell_renderer_accel_get_property (GObject *object,
45 static void gtk_cell_renderer_accel_set_property (GObject *object,
49 static void gtk_cell_renderer_accel_get_size (GtkCellRenderer *cell,
51 GdkRectangle *cell_area,
71 static guint signals[LAST_SIGNAL] = { 0 };
73 G_DEFINE_TYPE (GtkCellRendererAccel, gtk_cell_renderer_accel, GTK_TYPE_CELL_RENDERER_TEXT)
76 gtk_cell_renderer_accel_init (GtkCellRendererAccel *cell_accel)
81 gtk_cell_renderer_accel_class_init (GtkCellRendererAccelClass *cell_accel_class)
83 GObjectClass *object_class;
84 GtkCellRendererClass *cell_renderer_class;
86 object_class = G_OBJECT_CLASS (cell_accel_class);
87 cell_renderer_class = GTK_CELL_RENDERER_CLASS (cell_accel_class);
89 GTK_CELL_RENDERER_CLASS (cell_accel_class)->start_editing = gtk_cell_renderer_accel_start_editing;
91 object_class->set_property = gtk_cell_renderer_accel_set_property;
92 object_class->get_property = gtk_cell_renderer_accel_get_property;
93 cell_renderer_class->get_size = gtk_cell_renderer_accel_get_size;
95 object_class->finalize = gtk_cell_renderer_accel_finalize;
98 * GtkCellRendererAccel:accel-key:
100 * The keyval of the accelerator.
104 g_object_class_install_property (object_class,
106 g_param_spec_uint ("accel-key",
107 P_("Accelerator key"),
108 P_("The keyval of the accelerator"),
112 GTK_PARAM_READWRITE));
115 * GtkCellRendererAccel:accel-mods:
117 * The modifier mask of the accelerator.
121 g_object_class_install_property (object_class,
123 g_param_spec_flags ("accel-mods",
124 P_("Accelerator modifiers"),
125 P_("The modifier mask of the accelerator"),
126 GDK_TYPE_MODIFIER_TYPE,
128 GTK_PARAM_READWRITE));
131 * GtkCellRendererAccel:keycode:
133 * The hardware keycode of the accelerator. Note that the hardware keycode is
134 * only relevant if the key does not have a keyval. Normally, the keyboard
135 * configuration should assign keyvals to all keys.
139 g_object_class_install_property (object_class,
141 g_param_spec_uint ("keycode",
142 P_("Accelerator keycode"),
143 P_("The hardware keycode of the accelerator"),
147 GTK_PARAM_READWRITE));
150 * GtkCellRendererAccel:accel-mode:
152 * Determines if the edited accelerators are GTK+ accelerators. If
153 * they are, consumed modifiers are suppressed, only accelerators
154 * accepted by GTK+ are allowed, and the accelerators are rendered
155 * in the same way as they are in menus.
159 g_object_class_install_property (object_class,
161 g_param_spec_enum ("accel-mode",
162 P_("Accelerator Mode"),
163 P_("The type of accelerators"),
164 GTK_TYPE_CELL_RENDERER_ACCEL_MODE,
165 GTK_CELL_RENDERER_ACCEL_MODE_GTK,
166 GTK_PARAM_READWRITE));
169 * GtkCellRendererAccel::accel-edited:
170 * @accel: the object reveiving the signal
171 * @path_string: the path identifying the row of the edited cell
172 * @accel_key: the new accelerator keyval
173 * @accel_mods: the new acclerator modifier mask
174 * @hardware_keycode: the keycode of the new accelerator
176 * Gets emitted when the user has selected a new accelerator.
180 signals[ACCEL_EDITED] = g_signal_new (I_("accel-edited"),
181 GTK_TYPE_CELL_RENDERER_ACCEL,
183 G_STRUCT_OFFSET (GtkCellRendererAccelClass, accel_edited),
185 _gtk_marshal_VOID__STRING_UINT_FLAGS_UINT,
189 GDK_TYPE_MODIFIER_TYPE,
193 * GtkCellRendererAccel::accel-cleared:
194 * @accel: the object reveiving the signal
195 * @path_string: the path identifying the row of the edited cell
197 * Gets emitted when the user has removed the accelerator.
201 signals[ACCEL_CLEARED] = g_signal_new (I_("accel-cleared"),
202 GTK_TYPE_CELL_RENDERER_ACCEL,
204 G_STRUCT_OFFSET (GtkCellRendererAccelClass, accel_cleared),
206 g_cclosure_marshal_VOID__STRING,
213 * gtk_cell_renderer_accel_new:
215 * Creates a new #GtkCellRendererAccel.
217 * Returns: the new cell renderer
222 gtk_cell_renderer_accel_new (void)
224 return GTK_CELL_RENDERER (g_object_new (GTK_TYPE_CELL_RENDERER_ACCEL, NULL));
228 gtk_cell_renderer_accel_finalize (GObject *object)
231 (* G_OBJECT_CLASS (gtk_cell_renderer_accel_parent_class)->finalize) (object);
235 convert_keysym_state_to_string (GtkCellRendererAccel *accel,
237 GdkModifierType mask,
240 if (keysym == 0 && keycode == 0)
241 /* This label is displayed in a treeview cell displaying
242 * a disabled accelerator key combination. Only include
243 * the text after the | in the translation.
245 return g_strdup (Q_("Accelerator|Disabled"));
248 if (accel->accel_mode == GTK_CELL_RENDERER_ACCEL_MODE_GTK)
249 return gtk_accelerator_get_label (keysym, mask);
254 name = gtk_accelerator_name (keysym, mask);
260 name = g_strdup_printf ("%s0x%02x", tmp, keycode);
270 gtk_cell_renderer_accel_get_property (GObject *object,
275 GtkCellRendererAccel *accel;
277 g_return_if_fail (GTK_IS_CELL_RENDERER_ACCEL (object));
279 accel = GTK_CELL_RENDERER_ACCEL (object);
284 g_value_set_uint (value, accel->accel_key);
287 case PROP_ACCEL_MODS:
288 g_value_set_flags (value, accel->accel_mods);
291 case PROP_ACCEL_MODE:
292 g_value_set_enum (value, accel->accel_mode);
296 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
301 gtk_cell_renderer_accel_set_property (GObject *object,
306 GtkCellRendererAccel *accel;
307 gboolean changed = FALSE;
309 g_return_if_fail (GTK_IS_CELL_RENDERER_ACCEL (object));
311 accel = GTK_CELL_RENDERER_ACCEL (object);
317 guint accel_key = g_value_get_uint (value);
319 if (accel->accel_key != accel_key)
321 accel->accel_key = accel_key;
327 case PROP_ACCEL_MODS:
329 guint accel_mods = g_value_get_flags (value);
331 if (accel->accel_mods != accel_mods)
333 accel->accel_mods = accel_mods;
340 guint keycode = g_value_get_uint (value);
342 if (accel->keycode != keycode)
344 accel->keycode = keycode;
350 case PROP_ACCEL_MODE:
351 accel->accel_mode = g_value_get_enum (value);
355 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
360 GtkCellRendererText *celltext;
363 celltext = GTK_CELL_RENDERER_TEXT (accel);
364 text = convert_keysym_state_to_string (accel, accel->accel_key, accel->accel_mods, accel->keycode);
365 g_object_set (accel, "text", text, NULL);
371 gtk_cell_renderer_accel_get_size (GtkCellRenderer *cell,
373 GdkRectangle *cell_area,
380 GtkCellRendererAccel *accel = (GtkCellRendererAccel *) cell;
381 GtkRequisition requisition;
383 if (accel->sizing_label == NULL)
384 accel->sizing_label = gtk_label_new (_("New accelerator..."));
386 gtk_widget_size_request (accel->sizing_label, &requisition);
387 (* GTK_CELL_RENDERER_CLASS (gtk_cell_renderer_accel_parent_class)->get_size) (cell, widget, cell_area,
388 x_offset, y_offset, width, height);
389 /* FIXME: need to take the cell_area et al. into account */
391 *width = MAX (*width, requisition.width);
393 *height = MAX (*height, requisition.height);
397 grab_key_callback (GtkWidget *widget,
401 GdkModifierType accel_mods = 0;
403 GtkCellRendererAccel *accel;
407 GdkModifierType consumed_modifiers;
410 accel = GTK_CELL_RENDERER_ACCEL (data);
412 display = gtk_widget_get_display (widget);
414 if (event->is_modifier)
420 gdk_keymap_translate_keyboard_state (gdk_keymap_get_for_display (display),
421 event->hardware_keycode,
424 NULL, NULL, NULL, &consumed_modifiers);
426 accel_key = gdk_keyval_to_lower (event->keyval);
427 if (accel_key == GDK_ISO_Left_Tab)
430 accel_mods = event->state & gtk_accelerator_get_default_mod_mask ();
432 /* Filter consumed modifiers
434 if (accel->accel_mode == GTK_CELL_RENDERER_ACCEL_MODE_GTK)
435 accel_mods &= ~consumed_modifiers;
437 /* Put shift back if it changed the case of the key, not otherwise.
439 if (accel_key != event->keyval)
440 accel_mods |= GDK_SHIFT_MASK;
444 switch (event->keyval)
447 goto out; /* cancel */
449 /* clear the accelerator on Backspace */
457 if (accel->accel_mode == GTK_CELL_RENDERER_ACCEL_MODE_GTK)
459 if (!gtk_accelerator_valid (accel_key, accel_mods))
461 gdk_display_beep (display);
470 gdk_keyboard_ungrab (event->time);
471 gdk_pointer_ungrab (event->time);
473 path = g_strdup (g_object_get_data (G_OBJECT (accel->edit_widget), "gtk-cell-renderer-text"));
475 gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (accel->edit_widget));
476 gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (accel->edit_widget));
477 accel->edit_widget = NULL;
478 accel->grab_widget = NULL;
481 g_signal_emit (accel, signals[ACCEL_EDITED], 0, path,
482 accel_key, accel_mods, event->hardware_keycode);
484 g_signal_emit (accel, signals[ACCEL_CLEARED], 0, path);
492 ungrab_stuff (GtkWidget *widget,
495 GtkCellRendererAccel *accel = GTK_CELL_RENDERER_ACCEL (data);
497 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
498 gdk_pointer_ungrab (GDK_CURRENT_TIME);
500 g_signal_handlers_disconnect_by_func (G_OBJECT (accel->grab_widget),
501 G_CALLBACK (grab_key_callback), data);
505 _gtk_cell_editable_event_box_start_editing (GtkCellEditable *cell_editable,
508 /* do nothing, because we are pointless */
512 _gtk_cell_editable_event_box_cell_editable_init (GtkCellEditableIface *iface)
514 iface->start_editing = _gtk_cell_editable_event_box_start_editing;
517 typedef GtkEventBox GtkCellEditableEventBox;
518 typedef GtkEventBoxClass GtkCellEditableEventBoxClass;
520 G_DEFINE_TYPE_WITH_CODE (GtkCellEditableEventBox, _gtk_cell_editable_event_box, GTK_TYPE_EVENT_BOX, { \
521 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_EDITABLE, _gtk_cell_editable_event_box_cell_editable_init) \
526 _gtk_cell_editable_event_box_class_init (GtkCellEditableEventBoxClass *class)
531 _gtk_cell_editable_event_box_init (GtkCellEditableEventBox *box)
535 static GtkCellEditable *
536 gtk_cell_renderer_accel_start_editing (GtkCellRenderer *cell,
540 GdkRectangle *background_area,
541 GdkRectangle *cell_area,
542 GtkCellRendererState flags)
544 GtkCellRendererText *celltext;
545 GtkCellRendererAccel *accel;
549 celltext = GTK_CELL_RENDERER_TEXT (cell);
550 accel = GTK_CELL_RENDERER_ACCEL (cell);
552 /* If the cell isn't editable we return NULL. */
553 if (celltext->editable == FALSE)
556 g_return_val_if_fail (widget->window != NULL, NULL);
558 if (gdk_keyboard_grab (widget->window, FALSE,
559 gdk_event_get_time (event)) != GDK_GRAB_SUCCESS)
562 if (gdk_pointer_grab (widget->window, FALSE,
563 GDK_BUTTON_PRESS_MASK,
565 gdk_event_get_time (event)) != GDK_GRAB_SUCCESS)
567 gdk_keyboard_ungrab (gdk_event_get_time (event));
571 accel->grab_widget = widget;
573 g_signal_connect (G_OBJECT (widget), "key_press_event",
574 G_CALLBACK (grab_key_callback),
577 eventbox = g_object_new (_gtk_cell_editable_event_box_get_type (), NULL);
578 accel->edit_widget = eventbox;
579 g_object_add_weak_pointer (G_OBJECT (accel->edit_widget),
580 (void**) &accel->edit_widget);
582 label = gtk_label_new (NULL);
583 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
585 gtk_widget_modify_bg (eventbox, GTK_STATE_NORMAL,
586 &widget->style->bg[GTK_STATE_SELECTED]);
588 gtk_widget_modify_fg (label, GTK_STATE_NORMAL,
589 &widget->style->fg[GTK_STATE_SELECTED]);
591 /* This label is displayed in a treeview cell displaying
592 * an accelerator when the cell is clicked to change the
595 gtk_label_set_text (GTK_LABEL (label), _("New accelerator..."));
597 gtk_container_add (GTK_CONTAINER (eventbox), label);
599 g_object_set_data_full (G_OBJECT (accel->edit_widget), "gtk-cell-renderer-text",
600 g_strdup (path), g_free);
602 gtk_widget_show_all (accel->edit_widget);
604 g_signal_connect (G_OBJECT (accel->edit_widget), "unrealize",
605 G_CALLBACK (ungrab_stuff), accel);
607 return GTK_CELL_EDITABLE (accel->edit_widget);
611 #define __GTK_CELL_RENDERER_ACCEL_C__
612 #include "gtkaliasdef.c"