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);
362 text = convert_keysym_state_to_string (accel, accel->accel_key, accel->accel_mods, accel->keycode);
363 g_object_set (accel, "text", text, NULL);
369 gtk_cell_renderer_accel_get_size (GtkCellRenderer *cell,
371 GdkRectangle *cell_area,
378 GtkCellRendererAccel *accel = (GtkCellRendererAccel *) cell;
379 GtkRequisition requisition;
381 if (accel->sizing_label == NULL)
382 accel->sizing_label = gtk_label_new (_("New accelerator..."));
384 gtk_widget_size_request (accel->sizing_label, &requisition);
385 (* GTK_CELL_RENDERER_CLASS (gtk_cell_renderer_accel_parent_class)->get_size) (cell, widget, cell_area,
386 x_offset, y_offset, width, height);
387 /* FIXME: need to take the cell_area et al. into account */
389 *width = MAX (*width, requisition.width);
391 *height = MAX (*height, requisition.height);
395 grab_key_callback (GtkWidget *widget,
399 GdkModifierType accel_mods = 0;
401 GtkCellRendererAccel *accel;
405 GdkModifierType consumed_modifiers;
408 accel = GTK_CELL_RENDERER_ACCEL (data);
410 display = gtk_widget_get_display (widget);
412 if (event->is_modifier)
418 gdk_keymap_translate_keyboard_state (gdk_keymap_get_for_display (display),
419 event->hardware_keycode,
422 NULL, NULL, NULL, &consumed_modifiers);
424 accel_key = gdk_keyval_to_lower (event->keyval);
425 if (accel_key == GDK_ISO_Left_Tab)
428 accel_mods = event->state & gtk_accelerator_get_default_mod_mask ();
430 /* Filter consumed modifiers
432 if (accel->accel_mode == GTK_CELL_RENDERER_ACCEL_MODE_GTK)
433 accel_mods &= ~consumed_modifiers;
435 /* Put shift back if it changed the case of the key, not otherwise.
437 if (accel_key != event->keyval)
438 accel_mods |= GDK_SHIFT_MASK;
442 switch (event->keyval)
445 goto out; /* cancel */
447 /* clear the accelerator on Backspace */
455 if (accel->accel_mode == GTK_CELL_RENDERER_ACCEL_MODE_GTK)
457 if (!gtk_accelerator_valid (accel_key, accel_mods))
459 gtk_widget_error_bell (widget);
468 gdk_keyboard_ungrab (event->time);
469 gdk_pointer_ungrab (event->time);
471 path = g_strdup (g_object_get_data (G_OBJECT (accel->edit_widget), "gtk-cell-renderer-text"));
473 gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (accel->edit_widget));
474 gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (accel->edit_widget));
475 accel->edit_widget = NULL;
476 accel->grab_widget = NULL;
479 g_signal_emit (accel, signals[ACCEL_EDITED], 0, path,
480 accel_key, accel_mods, event->hardware_keycode);
482 g_signal_emit (accel, signals[ACCEL_CLEARED], 0, path);
490 ungrab_stuff (GtkWidget *widget,
493 GtkCellRendererAccel *accel = GTK_CELL_RENDERER_ACCEL (data);
495 gdk_keyboard_ungrab (GDK_CURRENT_TIME);
496 gdk_pointer_ungrab (GDK_CURRENT_TIME);
498 g_signal_handlers_disconnect_by_func (G_OBJECT (accel->grab_widget),
499 G_CALLBACK (grab_key_callback), data);
503 _gtk_cell_editable_event_box_start_editing (GtkCellEditable *cell_editable,
506 /* do nothing, because we are pointless */
510 _gtk_cell_editable_event_box_cell_editable_init (GtkCellEditableIface *iface)
512 iface->start_editing = _gtk_cell_editable_event_box_start_editing;
515 typedef GtkEventBox GtkCellEditableEventBox;
516 typedef GtkEventBoxClass GtkCellEditableEventBoxClass;
518 G_DEFINE_TYPE_WITH_CODE (GtkCellEditableEventBox, _gtk_cell_editable_event_box, GTK_TYPE_EVENT_BOX, { \
519 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_EDITABLE, _gtk_cell_editable_event_box_cell_editable_init) \
524 _gtk_cell_editable_event_box_class_init (GtkCellEditableEventBoxClass *class)
529 _gtk_cell_editable_event_box_init (GtkCellEditableEventBox *box)
533 static GtkCellEditable *
534 gtk_cell_renderer_accel_start_editing (GtkCellRenderer *cell,
538 GdkRectangle *background_area,
539 GdkRectangle *cell_area,
540 GtkCellRendererState flags)
542 GtkCellRendererText *celltext;
543 GtkCellRendererAccel *accel;
547 celltext = GTK_CELL_RENDERER_TEXT (cell);
548 accel = GTK_CELL_RENDERER_ACCEL (cell);
550 /* If the cell isn't editable we return NULL. */
551 if (celltext->editable == FALSE)
554 g_return_val_if_fail (widget->window != NULL, NULL);
556 if (gdk_keyboard_grab (widget->window, FALSE,
557 gdk_event_get_time (event)) != GDK_GRAB_SUCCESS)
560 if (gdk_pointer_grab (widget->window, FALSE,
561 GDK_BUTTON_PRESS_MASK,
563 gdk_event_get_time (event)) != GDK_GRAB_SUCCESS)
565 gdk_keyboard_ungrab (gdk_event_get_time (event));
569 accel->grab_widget = widget;
571 g_signal_connect (G_OBJECT (widget), "key_press_event",
572 G_CALLBACK (grab_key_callback),
575 eventbox = g_object_new (_gtk_cell_editable_event_box_get_type (), NULL);
576 accel->edit_widget = eventbox;
577 g_object_add_weak_pointer (G_OBJECT (accel->edit_widget),
578 (void**) &accel->edit_widget);
580 label = gtk_label_new (NULL);
581 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
583 gtk_widget_modify_bg (eventbox, GTK_STATE_NORMAL,
584 &widget->style->bg[GTK_STATE_SELECTED]);
586 gtk_widget_modify_fg (label, GTK_STATE_NORMAL,
587 &widget->style->fg[GTK_STATE_SELECTED]);
589 /* This label is displayed in a treeview cell displaying
590 * an accelerator when the cell is clicked to change the
593 gtk_label_set_text (GTK_LABEL (label), _("New accelerator..."));
595 gtk_container_add (GTK_CONTAINER (eventbox), label);
597 g_object_set_data_full (G_OBJECT (accel->edit_widget), "gtk-cell-renderer-text",
598 g_strdup (path), g_free);
600 gtk_widget_show_all (accel->edit_widget);
602 g_signal_connect (G_OBJECT (accel->edit_widget), "unrealize",
603 G_CALLBACK (ungrab_stuff), accel);
605 return GTK_CELL_EDITABLE (accel->edit_widget);
609 #define __GTK_CELL_RENDERER_ACCEL_C__
610 #include "gtkaliasdef.c"