diff options
author | Matthias Clasen <matthiasc@src.gnome.org> | 2005-09-11 05:43:19 +0000 |
---|---|---|
committer | Matthias Clasen <matthiasc@src.gnome.org> | 2005-09-11 05:43:19 +0000 |
commit | 247e2aa5d24eeb43e9ba92e6895d56bffe779b9e (patch) | |
tree | 26b90c19d0b450eb786d828949f8fc29bd7439be /gtk/gtkcellrendereraccel.c | |
parent | 1f700be359a10fd1a23fe75117461ac72bdcf058 (diff) | |
download | gtk+-247e2aa5d24eeb43e9ba92e6895d56bffe779b9e.tar.gz |
Forgotten files
Diffstat (limited to 'gtk/gtkcellrendereraccel.c')
-rw-r--r-- | gtk/gtkcellrendereraccel.c | 611 |
1 files changed, 611 insertions, 0 deletions
diff --git a/gtk/gtkcellrendereraccel.c b/gtk/gtkcellrendereraccel.c new file mode 100644 index 0000000000..38a16a6cfc --- /dev/null +++ b/gtk/gtkcellrendereraccel.c @@ -0,0 +1,611 @@ +/* gtkcellrendererkeys.h + * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "gtkintl.h" +#include "gtkaccelgroup.h" +#include "gtkmarshalers.h" +#include "gtkcellrendererkeys.h" +#include "gtklabel.h" +#include "gtkeventbox.h" +#include "gtkprivate.h" +#include "gdk/gdkkeysyms.h" +#include "gtkalias.h" + + +static void gtk_cell_renderer_keys_finalize (GObject *object); +static GtkCellEditable *gtk_cell_renderer_keys_start_editing (GtkCellRenderer *cell, + GdkEvent *event, + GtkWidget *widget, + const gchar *path, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GtkCellRendererState flags); + +static void gtk_cell_renderer_keys_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec); +static void gtk_cell_renderer_keys_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec); +static void gtk_cell_renderer_keys_get_size (GtkCellRenderer *cell, + GtkWidget *widget, + GdkRectangle *cell_area, + gint *x_offset, + gint *y_offset, + gint *width, + gint *height); + +enum { + ACCEL_EDITED, + ACCEL_CLEARED, + LAST_SIGNAL +}; + +enum { + PROP_0, + PROP_ACCEL_KEY, + PROP_ACCEL_MODS, + PROP_KEYCODE, + PROP_ACCEL_MODE +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE (GtkCellRendererKeys, gtk_cell_renderer_keys, GTK_TYPE_CELL_RENDERER_TEXT); + +static void +gtk_cell_renderer_keys_init (GtkCellRendererKeys *cell_keys) +{ +} + +static void +gtk_cell_renderer_keys_class_init (GtkCellRendererKeysClass *cell_keys_class) +{ + GObjectClass *object_class; + GtkCellRendererClass *cell_renderer_class; + + object_class = G_OBJECT_CLASS (cell_keys_class); + cell_renderer_class = GTK_CELL_RENDERER_CLASS (cell_keys_class); + + GTK_CELL_RENDERER_CLASS (cell_keys_class)->start_editing = gtk_cell_renderer_keys_start_editing; + + object_class->set_property = gtk_cell_renderer_keys_set_property; + object_class->get_property = gtk_cell_renderer_keys_get_property; + cell_renderer_class->get_size = gtk_cell_renderer_keys_get_size; + + object_class->finalize = gtk_cell_renderer_keys_finalize; + + /** + * GtkCellRendererKeys:accel-key: + * + * The keyval of the accelerator. + * + * Since: 2.10 + */ + g_object_class_install_property (object_class, + PROP_ACCEL_KEY, + g_param_spec_uint ("accel-key", + P_("Accelerator key"), + P_("The keyval of the accelerator"), + 0, + G_MAXINT, + 0, + GTK_PARAM_READWRITE)); + + /** + * GtkCellRendererKeys:accel-mods: + * + * The modifier mask of the accelerator. + * + * Since: 2.10 + */ + g_object_class_install_property (object_class, + PROP_ACCEL_MODS, + g_param_spec_flags ("accel-mods", + P_("Accelerator modifiers"), + P_("The modifier mask of the accelerator"), + GDK_TYPE_MODIFIER_TYPE, + 0, + GTK_PARAM_READWRITE)); + + /** + * GtkCellRendererKeys:keycode: + * + * The hardware keycode of the accelerator. Note that the hardware keycode is + * only relevant if the key does not have a keyval. Normally, the keyboard + * configuration should assign keyvals to all keys. + * + * Since: 2.10 + */ + g_object_class_install_property (object_class, + PROP_KEYCODE, + g_param_spec_uint ("keycode", + P_("Accelerator keycode"), + P_("The hardware keycode of the accelerator"), + 0, + G_MAXINT, + 0, + GTK_PARAM_READWRITE)); + + /** + * GtkCellRendererKeys:accel-mode: + * + * Determines if the edited accelerators are GTK+ accelerators. If + * they are, consumed modifiers are suppressed, only accelerators + * accepted by GTK+ are allowed, and the accelerators are rendered + * in the same way as they are in menus. + * + * Since: 2.10 + */ + g_object_class_install_property (object_class, + PROP_ACCEL_MODE, + g_param_spec_enum ("accel-mode", + P_("Accelerator Mode"), + P_("The type of accelerators"), + GTK_TYPE_CELL_RENDERER_KEYS_MODE, + GTK_CELL_RENDERER_KEYS_MODE_GTK, + GTK_PARAM_READWRITE)); + + /** + * GtkCellRendererKeys::accel-edited: + * @keys: the object reveiving the signal + * @path_string: the path identifying the row of the edited cell + * @accel_key: the new accelerator keyval + * @accel_mods: the new acclerator modifier mask + * @hardware_keycode: the keycode of the new accelerator + * + * Gets emitted when the user has selected a new accelerator. + * + * Since: 2.10 + */ + signals[ACCEL_EDITED] = g_signal_new (I_("accel-edited"), + GTK_TYPE_CELL_RENDERER_KEYS, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkCellRendererKeysClass, accel_edited), + NULL, NULL, + _gtk_marshal_VOID__STRING_UINT_FLAGS_UINT, + G_TYPE_NONE, 4, + G_TYPE_STRING, + G_TYPE_UINT, + GDK_TYPE_MODIFIER_TYPE, + G_TYPE_UINT); + + /** + * GtkCellRendererKeys::accel-cleared: + * @keys: the object reveiving the signal + * @path_string: the path identifying the row of the edited cell + * + * Gets emitted when the user has removed the accelerator. + * + * Since: 2.10 + */ + signals[ACCEL_CLEARED] = g_signal_new (I_("accel-cleared"), + GTK_TYPE_CELL_RENDERER_KEYS, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkCellRendererKeysClass, accel_cleared), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, + G_TYPE_STRING); +} + + +/** + * gtk_cell_renderer_keys_new: + * + * Creates a new #GtkCellRendererKeys. + * + * Returns: the new cell renderer + * + * Since: 2.10 + */ +GtkCellRenderer * +gtk_cell_renderer_keys_new (void) +{ + return GTK_CELL_RENDERER (g_object_new (GTK_TYPE_CELL_RENDERER_KEYS, NULL)); +} + +static void +gtk_cell_renderer_keys_finalize (GObject *object) +{ + + (* G_OBJECT_CLASS (gtk_cell_renderer_keys_parent_class)->finalize) (object); +} + +static gchar * +convert_keysym_state_to_string (GtkCellRendererKeys *keys, + guint keysym, + GdkModifierType mask, + guint keycode) +{ + if (keysym == 0 && keycode == 0) + /* This label is displayed in a treeview cell displaying + * a disabled accelerator key combination. Only include + * the text after the | in the translation. + */ + return g_strdup (Q_("Accelerator|Disabled")); + else + { + if (keys->accel_mode == GTK_CELL_RENDERER_KEYS_MODE_GTK) + return gtk_accelerator_get_label (keysym, mask); + else + { + gchar *name; + + name = gtk_accelerator_name (keysym, mask); + if (keysym == 0) + { + gchar *tmp; + + tmp = name; + name = g_strdup_printf ("%s0x%02x", tmp, keycode); + g_free (tmp); + } + + return name; + } + } +} + +static void +gtk_cell_renderer_keys_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GtkCellRendererKeys *keys; + + g_return_if_fail (GTK_IS_CELL_RENDERER_KEYS (object)); + + keys = GTK_CELL_RENDERER_KEYS (object); + + switch (param_id) + { + case PROP_ACCEL_KEY: + g_value_set_uint (value, keys->accel_key); + break; + + case PROP_ACCEL_MODS: + g_value_set_flags (value, keys->accel_mods); + break; + + case PROP_ACCEL_MODE: + g_value_set_enum (value, keys->accel_mode); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + } +} + +static void +gtk_cell_renderer_keys_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkCellRendererKeys *keys; + gboolean changed = FALSE; + + g_return_if_fail (GTK_IS_CELL_RENDERER_KEYS (object)); + + keys = GTK_CELL_RENDERER_KEYS (object); + + switch (param_id) + { + case PROP_ACCEL_KEY: + { + guint accel_key = g_value_get_uint (value); + + if (keys->accel_key != accel_key) + { + keys->accel_key = accel_key; + changed = TRUE; + } + } + break; + + case PROP_ACCEL_MODS: + { + guint accel_mods = g_value_get_flags (value); + + if (keys->accel_mods != accel_mods) + { + keys->accel_mods = accel_mods; + changed = TRUE; + } + } + break; + case PROP_KEYCODE: + { + guint keycode = g_value_get_uint (value); + + if (keys->keycode != keycode) + { + keys->keycode = keycode; + changed = TRUE; + } + } + break; + + case PROP_ACCEL_MODE: + keys->accel_mode = g_value_get_enum (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + } + + if (changed) + { + GtkCellRendererText *celltext; + gchar *text; + + celltext = GTK_CELL_RENDERER_TEXT (keys); + text = convert_keysym_state_to_string (keys, keys->accel_key, keys->accel_mods, keys->keycode); + g_object_set (keys, "text", text, NULL); + g_free (text); + } +} + +static void +gtk_cell_renderer_keys_get_size (GtkCellRenderer *cell, + GtkWidget *widget, + GdkRectangle *cell_area, + gint *x_offset, + gint *y_offset, + gint *width, + gint *height) + +{ + GtkCellRendererKeys *keys = (GtkCellRendererKeys *) cell; + GtkRequisition requisition; + + if (keys->sizing_label == NULL) + keys->sizing_label = gtk_label_new (_("New accelerator...")); + + gtk_widget_size_request (keys->sizing_label, &requisition); + (* GTK_CELL_RENDERER_CLASS (gtk_cell_renderer_keys_parent_class)->get_size) (cell, widget, cell_area, + x_offset, y_offset, width, height); + /* FIXME: need to take the cell_area et al. into account */ + if (width) + *width = MAX (*width, requisition.width); + if (height) + *height = MAX (*height, requisition.height); +} + +static gboolean +grab_key_callback (GtkWidget *widget, + GdkEventKey *event, + void *data) +{ + GdkModifierType accel_mods = 0; + guint accel_key; + GtkCellRendererKeys *keys; + char *path; + gboolean edited; + gboolean cleared; + GdkModifierType consumed_modifiers; + GdkDisplay *display; + + keys = GTK_CELL_RENDERER_KEYS (data); + + display = gtk_widget_get_display (widget); + + if (event->is_modifier) + return TRUE; + + edited = FALSE; + cleared = FALSE; + + gdk_keymap_translate_keyboard_state (gdk_keymap_get_for_display (display), + event->hardware_keycode, + event->state, + event->group, + NULL, NULL, NULL, &consumed_modifiers); + + accel_key = gdk_keyval_to_lower (event->keyval); + if (accel_key == GDK_ISO_Left_Tab) + accel_key = GDK_Tab; + + accel_mods = event->state & gtk_accelerator_get_default_mod_mask (); + + /* Filter consumed modifiers + */ + if (keys->accel_mode == GTK_CELL_RENDERER_KEYS_MODE_GTK) + accel_mods &= ~consumed_modifiers; + + /* Put shift back if it changed the case of the key, not otherwise. + */ + if (accel_key != event->keyval) + accel_mods |= GDK_SHIFT_MASK; + + if (accel_mods == 0) + { + switch (event->keyval) + { + case GDK_Escape: + goto out; /* cancel */ + case GDK_BackSpace: + /* clear the accelerator on Backspace */ + cleared = TRUE; + goto out; + default: + break; + } + } + + if (keys->accel_mode == GTK_CELL_RENDERER_KEYS_MODE_GTK) + { + if (!gtk_accelerator_valid (accel_key, accel_mods)) + { + gdk_display_beep (display); + + return TRUE; + } + } + + edited = TRUE; + + out: + gdk_keyboard_ungrab (event->time); + gdk_pointer_ungrab (event->time); + + path = g_strdup (g_object_get_data (G_OBJECT (keys->edit_widget), "gtk-cell-renderer-text")); + + gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (keys->edit_widget)); + gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (keys->edit_widget)); + keys->edit_widget = NULL; + keys->grab_widget = NULL; + + if (edited) + g_signal_emit (keys, signals[ACCEL_EDITED], 0, path, + accel_key, accel_mods, event->hardware_keycode); + else if (cleared) + g_signal_emit (keys, signals[ACCEL_CLEARED], 0, path); + + g_free (path); + + return TRUE; +} + +static void +ungrab_stuff (GtkWidget *widget, gpointer data) +{ + GtkCellRendererKeys *keys = GTK_CELL_RENDERER_KEYS (data); + + gdk_keyboard_ungrab (GDK_CURRENT_TIME); + gdk_pointer_ungrab (GDK_CURRENT_TIME); + + g_signal_handlers_disconnect_by_func (G_OBJECT (keys->grab_widget), + G_CALLBACK (grab_key_callback), data); +} + +static void +_gtk_cell_editable_event_box_start_editing (GtkCellEditable *cell_editable, + GdkEvent *event) +{ + /* do nothing, because we are pointless */ +} + +static void +_gtk_cell_editable_event_box_cell_editable_init (GtkCellEditableIface *iface) +{ + iface->start_editing = _gtk_cell_editable_event_box_start_editing; +} + +typedef GtkEventBox GtkCellEditableEventBox; +typedef GtkEventBoxClass GtkCellEditableEventBoxClass; + +G_DEFINE_TYPE_WITH_CODE (GtkCellEditableEventBox, _gtk_cell_editable_event_box, GTK_TYPE_EVENT_BOX, { \ + G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_EDITABLE, _gtk_cell_editable_event_box_cell_editable_init) \ + }); + + +static void +_gtk_cell_editable_event_box_class_init (GtkCellEditableEventBoxClass *class) +{ +} + +static void +_gtk_cell_editable_event_box_init (GtkCellEditableEventBox *box) +{ +} + +static GtkCellEditable * +gtk_cell_renderer_keys_start_editing (GtkCellRenderer *cell, + GdkEvent *event, + GtkWidget *widget, + const gchar *path, + GdkRectangle *background_area, + GdkRectangle *cell_area, + GtkCellRendererState flags) +{ + GtkCellRendererText *celltext; + GtkCellRendererKeys *keys; + GtkWidget *label; + GtkWidget *eventbox; + + celltext = GTK_CELL_RENDERER_TEXT (cell); + keys = GTK_CELL_RENDERER_KEYS (cell); + + /* If the cell isn't editable we return NULL. */ + if (celltext->editable == FALSE) + return NULL; + + g_return_val_if_fail (widget->window != NULL, NULL); + + if (gdk_keyboard_grab (widget->window, FALSE, + gdk_event_get_time (event)) != GDK_GRAB_SUCCESS) + return NULL; + + if (gdk_pointer_grab (widget->window, FALSE, + GDK_BUTTON_PRESS_MASK, + NULL, NULL, + gdk_event_get_time (event)) != GDK_GRAB_SUCCESS) + { + gdk_keyboard_ungrab (gdk_event_get_time (event)); + return NULL; + } + + keys->grab_widget = widget; + + g_signal_connect (G_OBJECT (widget), "key_press_event", + G_CALLBACK (grab_key_callback), + keys); + + eventbox = g_object_new (_gtk_cell_editable_event_box_get_type (), NULL); + keys->edit_widget = eventbox; + g_object_add_weak_pointer (G_OBJECT (keys->edit_widget), + (void**) &keys->edit_widget); + + label = gtk_label_new (NULL); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); + + gtk_widget_modify_bg (eventbox, GTK_STATE_NORMAL, + &widget->style->bg[GTK_STATE_SELECTED]); + + gtk_widget_modify_fg (label, GTK_STATE_NORMAL, + &widget->style->fg[GTK_STATE_SELECTED]); + + /* This label is displayed in a treeview cell displaying + * an accelerator when the cell is clicked to change the + * acelerator. + */ + gtk_label_set_text (GTK_LABEL (label), _("New accelerator...")); + + gtk_container_add (GTK_CONTAINER (eventbox), label); + + g_object_set_data_full (G_OBJECT (keys->edit_widget), "gtk-cell-renderer-text", + g_strdup (path), g_free); + + gtk_widget_show_all (keys->edit_widget); + + g_signal_connect (G_OBJECT (keys->edit_widget), "unrealize", + G_CALLBACK (ungrab_stuff), keys); + + return GTK_CELL_EDITABLE (keys->edit_widget); +} + + +#define __GTK_CELL_RENDERER_KEYS_C__ +#include "gtkaliasdef.c" |