1
#include "gtkentryaccel.h"
2
#include <glib/gi18n.h>
4
#define GTK_ENTRY_ACCEL_MODIFIER_MASK (GDK_MODIFIER_MASK & \
12
#define GTK_TYPE_ENTRY_ACCEL_POST_ACTION (gtk_entry_accel_post_action_get_type ())
13
#define GTK_ENTRY_ACCEL_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ENTRY_ACCEL, GtkEntryAccelPrivate))
15
struct _GtkEntryAccelPrivate
26
gboolean left_shift : 1;
27
gboolean right_shift : 1;
28
gboolean left_control : 1;
29
gboolean right_control : 1;
30
gboolean left_alt : 1;
31
gboolean right_alt : 1;
32
gboolean left_super : 1;
33
gboolean right_super : 1;
36
G_DEFINE_TYPE (GtkEntryAccel, gtk_entry_accel, GTK_TYPE_ENTRY);
45
static GParamSpec *properties[N_PROPERTIES] = { NULL };
53
static guint signals[N_SIGNALS] = { 0 };
56
gtk_entry_accel_post_action_get_type (void)
58
static GType type = 0;
60
if (G_UNLIKELY (type == 0))
62
static const GEnumValue values[] = {
63
{ GTK_ENTRY_ACCEL_UPDATE, "GTK_ENTRY_ACCEL_UPDATE", "update" },
64
{ GTK_ENTRY_ACCEL_CANCEL, "GTK_ENTRY_ACCEL_CANCEL", "cancel" },
65
{ GTK_ENTRY_ACCEL_IGNORE, "GTK_ENTRY_ACCEL_IGNORE", "ignore" },
66
{ GTK_ENTRY_ACCEL_PASS_THROUGH, "GTK_ENTRY_ACCEL_PASS_THROUGH", "pass-through" },
70
type = g_enum_register_static (g_intern_static_string ("GtkEntryAccelPostAction"), values);
77
gtk_entry_accel_reset_modifier_states (GtkEntryAccel *entry)
79
g_return_if_fail (GTK_IS_ENTRY_ACCEL (entry));
81
entry->priv->left_shift = FALSE;
82
entry->priv->right_shift = FALSE;
83
entry->priv->left_control = FALSE;
84
entry->priv->right_control = FALSE;
85
entry->priv->left_alt = FALSE;
86
entry->priv->right_alt = FALSE;
87
entry->priv->left_super = FALSE;
88
entry->priv->right_super = FALSE;
92
gtk_entry_accel_get_modifier_state (GtkEntryAccel *entry,
95
g_return_val_if_fail (GTK_IS_ENTRY_ACCEL (entry), FALSE);
100
return entry->priv->left_shift;
101
case GDK_KEY_Shift_R:
102
return entry->priv->right_shift;
103
case GDK_KEY_Control_L:
104
return entry->priv->left_control;
105
case GDK_KEY_Control_R:
106
return entry->priv->right_control;
109
return entry->priv->left_alt;
112
return entry->priv->right_alt;
113
case GDK_KEY_Super_L:
114
return entry->priv->left_super;
115
case GDK_KEY_Super_R:
116
return entry->priv->right_super;
123
gtk_entry_accel_set_modifier_state (GtkEntryAccel *entry,
127
g_return_if_fail (GTK_IS_ENTRY_ACCEL (entry));
131
case GDK_KEY_Shift_L:
132
entry->priv->left_shift = state;
134
case GDK_KEY_Shift_R:
135
entry->priv->right_shift = state;
137
case GDK_KEY_Control_L:
138
entry->priv->left_control = state;
140
case GDK_KEY_Control_R:
141
entry->priv->right_control = state;
145
entry->priv->left_alt = state;
149
entry->priv->right_alt = state;
151
case GDK_KEY_Super_L:
152
entry->priv->left_super = state;
154
case GDK_KEY_Super_R:
155
entry->priv->right_super = state;
161
gtk_entry_accel_update_text (GtkEntryAccel *entry)
163
if (entry->priv->keyboard == NULL || entry->priv->pointer == NULL)
165
if (entry->priv->key != 0 || entry->priv->code != 0 || entry->priv->mask != 0)
167
gchar *label = gtk_accelerator_get_label_with_keycode (NULL,
172
gtk_entry_set_text (GTK_ENTRY (entry), label);
177
gtk_entry_set_text (GTK_ENTRY (entry), "");
180
gtk_entry_set_text (GTK_ENTRY (entry), _("New acceleratorā¦"));
184
gtk_entry_accel_set_key (GtkEntryAccel *entry,
187
GdkModifierType mask)
189
if (key != entry->priv->key || code != entry->priv->code || mask != entry->priv->mask)
191
entry->priv->key = key;
192
entry->priv->code = code;
193
entry->priv->mask = mask;
195
g_free (entry->priv->accel);
197
if (key != 0 || code != 0 || mask != 0)
198
entry->priv->accel = gtk_accelerator_name_with_keycode (NULL, key, code, mask);
200
entry->priv->accel = NULL;
202
g_object_notify_by_pspec (G_OBJECT (entry), properties[PROP_ACCEL]);
205
gtk_entry_accel_update_text (entry);
209
gtk_entry_accel_ungrab_input (GtkEntryAccel *entry,
212
guint32 time = gdk_event_get_time (event);
214
if (entry->priv->keyboard != NULL && entry->priv->pointer != NULL)
215
gtk_grab_remove (GTK_WIDGET (entry));
217
if (entry->priv->keyboard != NULL)
219
gdk_device_ungrab (entry->priv->keyboard, time);
220
g_clear_object (&entry->priv->keyboard);
223
if (entry->priv->pointer != NULL)
225
gdk_device_ungrab (entry->priv->pointer, time);
226
g_clear_object (&entry->priv->pointer);
229
gtk_entry_accel_reset_modifier_states (entry);
230
gtk_entry_accel_update_text (entry);
234
gtk_entry_accel_grab_input (GtkEntryAccel *entry,
237
GdkWindow *window = NULL;
238
GdkDevice *device = NULL;
239
GdkDevice *keyboard = NULL;
240
GdkDevice *pointer = NULL;
243
if (entry->priv->keyboard != NULL && entry->priv->pointer != NULL)
246
gtk_entry_accel_ungrab_input (entry, event);
249
device = gdk_event_get_device (event);
252
device = gtk_get_current_event_device ();
257
if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
260
pointer = gdk_device_get_associated_device (device);
265
keyboard = gdk_device_get_associated_device (device);
268
if (gdk_device_get_source (keyboard) != GDK_SOURCE_KEYBOARD)
271
window = gtk_widget_get_window (GTK_WIDGET (entry));
272
time = gdk_event_get_time (event);
274
if (gdk_device_grab (keyboard,
276
GDK_OWNERSHIP_WINDOW,
278
GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
280
time) != GDK_GRAB_SUCCESS)
283
if (gdk_device_grab (pointer,
285
GDK_OWNERSHIP_WINDOW,
287
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK,
289
time) != GDK_GRAB_SUCCESS)
291
gdk_device_ungrab (keyboard, time);
296
gtk_grab_add (GTK_WIDGET (entry));
298
entry->priv->keyboard = g_object_ref (keyboard);
299
entry->priv->pointer = g_object_ref (pointer);
303
gtk_entry_accel_dispose (GObject *object)
305
GtkEntryAccel *entry = GTK_ENTRY_ACCEL (object);
307
gtk_entry_accel_ungrab_input (entry, NULL);
309
G_OBJECT_CLASS (gtk_entry_accel_parent_class)->dispose (object);
313
gtk_entry_accel_finalize (GObject *object)
315
GtkEntryAccel *entry = GTK_ENTRY_ACCEL (object);
317
g_free (entry->priv->accel);
319
G_OBJECT_CLASS (gtk_entry_accel_parent_class)->finalize (object);
323
gtk_entry_accel_get_property (GObject *object,
328
GtkEntryAccel *entry = GTK_ENTRY_ACCEL (object);
334
accel = gtk_entry_accel_get_accel (entry);
335
g_value_set_string (value, accel != NULL ? accel : "");
339
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
345
gtk_entry_accel_set_property (GObject *object,
350
GtkEntryAccel *entry = GTK_ENTRY_ACCEL (object);
355
gtk_entry_accel_set_accel (entry, g_value_get_string (value));
359
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
365
gtk_entry_accel_button_press_event (GtkWidget *widget,
366
GdkEventButton *event)
368
if (event->button == 1)
370
GtkEntryAccel *entry = GTK_ENTRY_ACCEL (widget);
372
if (entry->priv->keyboard != NULL && entry->priv->pointer != NULL)
373
gtk_entry_accel_ungrab_input (entry, (GdkEvent *) event);
375
gtk_entry_accel_grab_input (entry, (GdkEvent *) event);
377
gtk_entry_accel_update_text (entry);
384
gtk_entry_accel_post_action_accumulator (GSignalInvocationHint *ihint,
386
const GValue *handler_return,
389
GtkEntryAccelPostAction action = g_value_get_enum (return_accu);
390
GtkEntryAccelPostAction current_action = g_value_get_enum (handler_return);
392
if (action == GTK_ENTRY_ACCEL_UPDATE)
393
action = current_action;
395
g_value_set_enum (return_accu, action);
397
return action == GTK_ENTRY_ACCEL_UPDATE;
400
static GtkEntryAccelPostAction
401
gtk_entry_accel_real_key_pressed (GtkEntryAccel *entry,
404
GdkModifierType *mask)
406
return GTK_ENTRY_ACCEL_UPDATE;
409
static GtkEntryAccelPostAction
410
gtk_entry_accel_key_pressed (GtkEntryAccel *entry,
413
GdkModifierType *mask)
415
GtkEntryAccelPostAction action;
417
g_signal_emit (entry,
418
signals[SIGNAL_KEY_PRESSED],
429
gtk_entry_accel_key_press_event (GtkWidget *widget,
432
GtkEntryAccel *entry = GTK_ENTRY_ACCEL (widget);
433
guint key = event->keyval;
434
guint mask = event->state & GTK_ENTRY_ACCEL_MODIFIER_MASK;
435
gboolean grabbed = entry->priv->keyboard != NULL && entry->priv->pointer != NULL;
437
gtk_entry_accel_set_modifier_state (entry, key, TRUE);
439
return ((grabbed ? mask : (mask & ~GDK_SHIFT_MASK)) != 0 ||
440
(key != GDK_KEY_Tab &&
441
key != GDK_KEY_KP_Tab &&
442
key != GDK_KEY_ISO_Left_Tab &&
443
key != GDK_KEY_3270_BackTab) ||
444
GTK_WIDGET_CLASS (gtk_entry_accel_parent_class)->key_press_event (widget, event));
448
gtk_entry_accel_get_mask_for_key (guint key)
452
case GDK_KEY_Shift_L:
453
case GDK_KEY_Shift_R:
454
return GDK_SHIFT_MASK;
455
case GDK_KEY_Control_L:
456
case GDK_KEY_Control_R:
457
return GDK_CONTROL_MASK;
458
case GDK_KEY_Caps_Lock:
459
case GDK_KEY_Shift_Lock:
460
return GDK_LOCK_MASK;
463
return GDK_META_MASK;
466
return GDK_MOD1_MASK;
467
case GDK_KEY_Super_L:
468
case GDK_KEY_Super_R:
469
return GDK_SUPER_MASK;
470
case GDK_KEY_Hyper_L:
471
case GDK_KEY_Hyper_R:
472
return GDK_HYPER_MASK;
479
gtk_entry_accel_get_mirrored_key (guint key)
483
case GDK_KEY_Shift_L:
484
return GDK_KEY_Shift_R;
485
case GDK_KEY_Shift_R:
486
return GDK_KEY_Shift_L;
487
case GDK_KEY_Control_L:
488
return GDK_KEY_Control_R;
489
case GDK_KEY_Control_R:
490
return GDK_KEY_Control_L;
492
return GDK_KEY_Meta_R;
494
return GDK_KEY_Meta_L;
496
return GDK_KEY_Alt_R;
498
return GDK_KEY_Alt_L;
499
case GDK_KEY_Super_L:
500
return GDK_KEY_Super_R;
501
case GDK_KEY_Super_R:
502
return GDK_KEY_Super_L;
503
case GDK_KEY_Hyper_L:
504
return GDK_KEY_Hyper_R;
511
gtk_entry_accel_key_release_event (GtkWidget *widget,
514
GtkEntryAccel *entry = GTK_ENTRY_ACCEL (widget);
515
guint key = event->keyval;
516
guint code = event->hardware_keycode;
517
guint mask = event->state & GTK_ENTRY_ACCEL_MODIFIER_MASK;
519
if (entry->priv->keyboard != NULL && entry->priv->pointer != NULL)
532
if (event->is_modifier && !gtk_entry_accel_get_modifier_state (entry, gtk_entry_accel_get_mirrored_key (key)))
533
mask &= ~gtk_entry_accel_get_mask_for_key (key);
535
gtk_entry_accel_ungrab_input (entry, (GdkEvent *) event);
537
switch (gtk_entry_accel_key_pressed (entry, &key, &code, &mask))
539
case GTK_ENTRY_ACCEL_UPDATE:
540
gtk_entry_accel_set_key (entry, key, code, mask);
541
case GTK_ENTRY_ACCEL_CANCEL:
542
gtk_entry_accel_ungrab_input (entry, (GdkEvent *) event);
543
case GTK_ENTRY_ACCEL_IGNORE:
548
event->hardware_keycode = code;
551
gtk_entry_accel_ungrab_input (entry, (GdkEvent *) event);
553
return GTK_WIDGET_CLASS (gtk_entry_accel_parent_class)->key_release_event (widget, event);
557
(key == GDK_KEY_Return ||
558
key == GDK_KEY_KP_Enter ||
559
key == GDK_KEY_ISO_Enter ||
560
key == GDK_KEY_3270_Enter))
562
gtk_entry_accel_grab_input (entry, (GdkEvent *) event);
563
gtk_entry_accel_update_text (entry);
568
return ((mask & ~GDK_SHIFT_MASK) != 0 ||
569
(key != GDK_KEY_Tab &&
570
key != GDK_KEY_KP_Tab &&
571
key != GDK_KEY_ISO_Left_Tab &&
572
key != GDK_KEY_3270_BackTab) ||
573
GTK_WIDGET_CLASS (gtk_entry_accel_parent_class)->key_release_event (widget, event));
577
gtk_entry_accel_class_init (GtkEntryAccelClass *klass)
579
GObjectClass *object_class = G_OBJECT_CLASS (klass);
580
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
582
object_class->dispose = gtk_entry_accel_dispose;
583
object_class->finalize = gtk_entry_accel_finalize;
584
object_class->get_property = gtk_entry_accel_get_property;
585
object_class->set_property = gtk_entry_accel_set_property;
586
widget_class->button_press_event = gtk_entry_accel_button_press_event;
587
widget_class->key_press_event = gtk_entry_accel_key_press_event;
588
widget_class->key_release_event = gtk_entry_accel_key_release_event;
589
klass->key_pressed = gtk_entry_accel_real_key_pressed;
591
properties[PROP_ACCEL] = g_param_spec_string ("accel",
593
"Current accelerator",
597
g_object_class_install_property (object_class,
599
properties[PROP_ACCEL]);
601
signals[SIGNAL_KEY_PRESSED] = g_signal_new ("key-pressed",
602
G_OBJECT_CLASS_TYPE (klass),
604
G_STRUCT_OFFSET (GtkEntryAccelClass, key_pressed),
605
gtk_entry_accel_post_action_accumulator,
608
GTK_TYPE_ENTRY_ACCEL_POST_ACTION,
614
g_type_class_add_private (klass, sizeof (GtkEntryAccelPrivate));
618
gtk_entry_accel_init (GtkEntryAccel *self)
620
self->priv = GTK_ENTRY_ACCEL_GET_PRIVATE (self);
624
gtk_entry_accel_new (void)
626
return g_object_new (GTK_TYPE_ENTRY_ACCEL, NULL);
630
gtk_entry_accel_get_accel (GtkEntryAccel *entry)
632
g_return_val_if_fail (GTK_IS_ENTRY_ACCEL (entry), NULL);
634
return entry->priv->accel;
638
gtk_entry_accel_set_accel (GtkEntryAccel *entry,
643
GdkModifierType mask = 0;
645
g_return_if_fail (GTK_IS_ENTRY_ACCEL (entry));
648
gtk_accelerator_parse_with_keycode (accel, &key, &codes, &mask);
650
gtk_entry_accel_set_key (entry, key, codes != NULL ? codes[0] : 0, mask);