1
/* GTK - The GIMP Toolkit
2
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3
* Copyright (C) 2004 Albrecht Dre�
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the
17
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
* Boston, MA 02111-1307, USA.
22
* Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23
* file for a list of people on the GTK+ Team. See the ChangeLog
24
* files for a list of changes. These files are distributed with
25
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
29
* Heavily stripped down for use in pinentry-gtk-2 by Albrecht Dre�
30
* <albrecht.dress@arcor.de> Feb. 2004:
32
* The entry is now always invisible, uses secure memory methods to
33
* allocate the text memory, and all potentially dangerous methods
34
* (copy & paste, popup, etc.) have been removed.
39
#include <gdk/gdkkeysyms.h>
42
#include "gtksecentry.h"
47
# define _(x) gettext(x)
50
#define MIN_SECURE_ENTRY_WIDTH 150
51
#define DRAW_TIMEOUT 20
52
#define INNER_BORDER 2
54
/* Initial size of buffer, in bytes */
57
/* Maximum size of text buffer, in bytes */
58
#define MAX_SIZE G_MAXUSHORT
75
PROP_ACTIVATES_DEFAULT,
81
static guint signals[LAST_SIGNAL] = { 0 };
83
/* GObject, GtkObject methods
85
static void gtk_secure_entry_class_init(GtkSecureEntryClass * klass);
86
static void gtk_secure_entry_editable_init(GtkEditableClass * iface);
87
static void gtk_secure_entry_cell_editable_init(GtkCellEditableIface *
89
static void gtk_secure_entry_init(GtkSecureEntry * entry);
90
static void gtk_secure_entry_set_property(GObject * object,
94
static void gtk_secure_entry_get_property(GObject * object,
98
static void gtk_secure_entry_finalize(GObject * object);
102
static void gtk_secure_entry_realize(GtkWidget * widget);
103
static void gtk_secure_entry_unrealize(GtkWidget * widget);
104
static void gtk_secure_entry_size_request(GtkWidget * widget,
105
GtkRequisition * requisition);
106
static void gtk_secure_entry_size_allocate(GtkWidget * widget,
107
GtkAllocation * allocation);
108
static void gtk_secure_entry_draw_frame(GtkWidget * widget);
109
static gint gtk_secure_entry_expose(GtkWidget * widget,
110
GdkEventExpose * event);
111
static gint gtk_secure_entry_button_press(GtkWidget * widget,
112
GdkEventButton * event);
113
static gint gtk_secure_entry_button_release(GtkWidget * widget,
114
GdkEventButton * event);
115
static gint gtk_secure_entry_motion_notify(GtkWidget * widget,
116
GdkEventMotion * event);
117
static gint gtk_secure_entry_key_press(GtkWidget * widget,
118
GdkEventKey * event);
119
static gint gtk_secure_entry_key_release(GtkWidget * widget,
120
GdkEventKey * event);
121
static gint gtk_secure_entry_focus_in(GtkWidget * widget,
122
GdkEventFocus * event);
123
static gint gtk_secure_entry_focus_out(GtkWidget * widget,
124
GdkEventFocus * event);
125
static void gtk_secure_entry_grab_focus(GtkWidget * widget);
126
static void gtk_secure_entry_style_set(GtkWidget * widget,
127
GtkStyle * previous_style);
128
static void gtk_secure_entry_direction_changed(GtkWidget * widget,
131
static void gtk_secure_entry_state_changed(GtkWidget * widget,
132
GtkStateType previous_state);
133
static void gtk_secure_entry_screen_changed(GtkWidget * widget,
134
GdkScreen * old_screen);
136
/* GtkEditable method implementations
138
static void gtk_secure_entry_insert_text(GtkEditable * editable,
139
const gchar * new_text,
140
gint new_text_length,
142
static void gtk_secure_entry_delete_text(GtkEditable * editable,
143
gint start_pos, gint end_pos);
144
static void gtk_secure_entry_real_set_position(GtkEditable * editable,
146
static gint gtk_secure_entry_get_position(GtkEditable * editable);
147
static void gtk_secure_entry_set_selection_bounds(GtkEditable * editable,
148
gint start, gint end);
149
static gboolean gtk_secure_entry_get_selection_bounds(GtkEditable *
154
/* GtkCellEditable method implementations
156
static void gtk_secure_entry_start_editing(GtkCellEditable * cell_editable,
159
/* Default signal handlers
161
static void gtk_secure_entry_real_insert_text(GtkEditable * editable,
162
const gchar * new_text,
163
gint new_text_length,
165
static void gtk_secure_entry_real_delete_text(GtkEditable * editable,
168
static void gtk_secure_entry_move_cursor(GtkSecureEntry * entry,
169
GtkMovementStep step,
171
gboolean extend_selection);
172
static void gtk_secure_entry_insert_at_cursor(GtkSecureEntry * entry,
174
static void gtk_secure_entry_delete_from_cursor(GtkSecureEntry * entry,
177
static void gtk_secure_entry_real_activate(GtkSecureEntry * entry);
179
static void gtk_secure_entry_keymap_direction_changed(GdkKeymap * keymap,
182
/* IM Context Callbacks
184
static void gtk_secure_entry_commit_cb(GtkIMContext * context,
186
GtkSecureEntry * entry);
187
static void gtk_secure_entry_preedit_changed_cb(GtkIMContext * context,
188
GtkSecureEntry * entry);
189
static gboolean gtk_secure_entry_retrieve_surrounding_cb(GtkIMContext *
193
static gboolean gtk_secure_entry_delete_surrounding_cb(GtkIMContext *
202
static void gtk_secure_entry_enter_text(GtkSecureEntry * entry,
204
static void gtk_secure_entry_set_positions(GtkSecureEntry * entry,
206
gint selection_bound);
207
static void gtk_secure_entry_draw_text(GtkSecureEntry * entry);
208
static void gtk_secure_entry_draw_cursor(GtkSecureEntry * entry);
209
static PangoLayout *gtk_secure_entry_ensure_layout(GtkSecureEntry * entry,
212
static void gtk_secure_entry_reset_layout(GtkSecureEntry * entry);
213
static void gtk_secure_entry_queue_draw(GtkSecureEntry * entry);
214
static void gtk_secure_entry_reset_im_context(GtkSecureEntry * entry);
215
static void gtk_secure_entry_recompute(GtkSecureEntry * entry);
216
static gint gtk_secure_entry_find_position(GtkSecureEntry * entry, gint x);
217
static void gtk_secure_entry_get_cursor_locations(GtkSecureEntry * entry,
220
static void gtk_secure_entry_adjust_scroll(GtkSecureEntry * entry);
221
static gint gtk_secure_entry_move_visually(GtkSecureEntry * editable,
222
gint start, gint count);
223
static gint gtk_secure_entry_move_logically(GtkSecureEntry * entry,
224
gint start, gint count);
225
static gboolean gtk_secure_entry_mnemonic_activate(GtkWidget * widget,
226
gboolean group_cycling);
227
static void gtk_secure_entry_state_changed(GtkWidget * widget,
228
GtkStateType previous_state);
229
static void gtk_secure_entry_check_cursor_blink(GtkSecureEntry * entry);
230
static void gtk_secure_entry_pend_cursor_blink(GtkSecureEntry * entry);
231
static void get_text_area_size(GtkSecureEntry * entry,
233
gint * y, gint * width, gint * height);
234
static void get_widget_window_size(GtkSecureEntry * entry,
236
gint * y, gint * width, gint * height);
240
#define _gtk_marshal_VOID__VOID g_cclosure_marshal_VOID__VOID
241
#define _gtk_marshal_VOID__STRING g_cclosure_marshal_VOID__STRING
242
static void _gtk_marshal_VOID__ENUM_INT_BOOLEAN(GClosure * closure,
243
GValue * return_value,
244
guint n_param_values,
247
gpointer invocation_hint,
248
gpointer marshal_data);
249
static void _gtk_marshal_VOID__ENUM_INT(GClosure * closure,
250
GValue * return_value,
251
guint n_param_values,
252
const GValue * param_values,
253
gpointer invocation_hint,
254
gpointer marshal_data);
257
static GtkWidgetClass *parent_class = NULL;
259
gboolean g_use_secure_mem = FALSE;
261
# define g_sec_new(type, count) \
262
((type *) g_sec_malloc ((unsigned) sizeof (type) * (count)))
264
#define WITH_SECURE_MEM(EXP) do { \
265
gboolean tmp = g_use_secure_mem; \
266
g_use_secure_mem = TRUE; \
268
g_use_secure_mem = tmp; \
273
g_malloc(gulong size)
280
if (g_use_secure_mem)
281
p = (gpointer) secmem_malloc(size);
283
p = (gpointer) malloc(size);
285
g_error("could not allocate %ld bytes", size);
291
g_malloc0(gulong size)
298
if (g_use_secure_mem) {
299
p = (gpointer) secmem_malloc(size);
303
p = (gpointer) calloc(size, 1);
305
g_error("could not allocate %ld bytes", size);
311
g_realloc(gpointer mem, gulong size)
322
if (g_use_secure_mem)
323
p = (gpointer) secmem_malloc(size);
325
p = (gpointer) malloc(size);
327
if (g_use_secure_mem) {
328
g_assert(m_is_secure(mem));
329
p = (gpointer) secmem_realloc(mem, size);
331
p = (gpointer) realloc(mem, size);
335
g_error("could not reallocate %lu bytes", (gulong) size);
344
if (m_is_secure(mem))
352
gtk_secure_entry_get_type(void)
354
static GType entry_type = 0;
357
static const GTypeInfo entry_info = {
358
sizeof(GtkSecureEntryClass),
359
NULL, /* base_init */
360
NULL, /* base_finalize */
361
(GClassInitFunc) gtk_secure_entry_class_init,
362
NULL, /* class_finalize */
363
NULL, /* class_data */
364
sizeof(GtkSecureEntry),
366
(GInstanceInitFunc) gtk_secure_entry_init,
369
static const GInterfaceInfo editable_info = {
370
(GInterfaceInitFunc) gtk_secure_entry_editable_init, /* interface_init */
371
NULL, /* interface_finalize */
372
NULL /* interface_data */
375
static const GInterfaceInfo cell_editable_info = {
376
(GInterfaceInitFunc) gtk_secure_entry_cell_editable_init, /* interface_init */
377
NULL, /* interface_finalize */
378
NULL /* interface_data */
382
g_type_register_static(GTK_TYPE_WIDGET, "GtkSecureEntry",
385
g_type_add_interface_static(entry_type,
386
GTK_TYPE_EDITABLE, &editable_info);
387
g_type_add_interface_static(entry_type,
388
GTK_TYPE_CELL_EDITABLE,
389
&cell_editable_info);
396
add_move_binding(GtkBindingSet * binding_set,
398
guint modmask, GtkMovementStep step, gint count)
400
g_return_if_fail((modmask & GDK_SHIFT_MASK) == 0);
402
gtk_binding_entry_add_signal(binding_set, keyval, modmask,
405
G_TYPE_INT, count, G_TYPE_BOOLEAN, FALSE);
407
/* Selection-extending version */
408
gtk_binding_entry_add_signal(binding_set, keyval,
409
modmask | GDK_SHIFT_MASK, "move_cursor",
410
3, G_TYPE_ENUM, step, G_TYPE_INT, count,
411
G_TYPE_BOOLEAN, TRUE);
415
gtk_secure_entry_class_init(GtkSecureEntryClass * class)
417
GObjectClass *gobject_class = G_OBJECT_CLASS(class);
418
GtkWidgetClass *widget_class;
419
GtkBindingSet *binding_set;
421
widget_class = (GtkWidgetClass *) class;
422
parent_class = g_type_class_peek_parent(class);
424
gobject_class->finalize = gtk_secure_entry_finalize;
425
gobject_class->set_property = gtk_secure_entry_set_property;
426
gobject_class->get_property = gtk_secure_entry_get_property;
428
widget_class->realize = gtk_secure_entry_realize;
429
widget_class->unrealize = gtk_secure_entry_unrealize;
430
widget_class->size_request = gtk_secure_entry_size_request;
431
widget_class->size_allocate = gtk_secure_entry_size_allocate;
432
widget_class->expose_event = gtk_secure_entry_expose;
433
widget_class->button_press_event = gtk_secure_entry_button_press;
434
widget_class->button_release_event = gtk_secure_entry_button_release;
435
widget_class->motion_notify_event = gtk_secure_entry_motion_notify;
436
widget_class->key_press_event = gtk_secure_entry_key_press;
437
widget_class->key_release_event = gtk_secure_entry_key_release;
438
widget_class->focus_in_event = gtk_secure_entry_focus_in;
439
widget_class->focus_out_event = gtk_secure_entry_focus_out;
440
widget_class->grab_focus = gtk_secure_entry_grab_focus;
441
widget_class->style_set = gtk_secure_entry_style_set;
442
widget_class->direction_changed = gtk_secure_entry_direction_changed;
443
widget_class->state_changed = gtk_secure_entry_state_changed;
444
widget_class->screen_changed = gtk_secure_entry_screen_changed;
445
widget_class->mnemonic_activate = gtk_secure_entry_mnemonic_activate;
447
class->move_cursor = gtk_secure_entry_move_cursor;
448
class->insert_at_cursor = gtk_secure_entry_insert_at_cursor;
449
class->delete_from_cursor = gtk_secure_entry_delete_from_cursor;
450
class->activate = gtk_secure_entry_real_activate;
452
g_object_class_install_property(gobject_class,
453
PROP_CURSOR_POSITION,
454
g_param_spec_int("cursor_position",
455
_("Cursor Position"),
457
("The current position of the insertion cursor in chars"),
461
g_object_class_install_property(gobject_class,
462
PROP_SELECTION_BOUND,
463
g_param_spec_int("selection_bound",
464
_("Selection Bound"),
466
("The position of the opposite end of the selection from the cursor in chars"),
470
g_object_class_install_property(gobject_class,
472
g_param_spec_int("max_length",
475
("Maximum number of characters for this entry. Zero if no maximum"),
480
g_object_class_install_property(gobject_class,
482
g_param_spec_boolean("has_frame",
485
("FALSE removes outside bevel from entry"),
490
g_object_class_install_property(gobject_class,
492
g_param_spec_unichar("invisible_char",
494
("Invisible character"),
496
("The character to use when masking entry contents (in \"password mode\")"),
501
g_object_class_install_property(gobject_class,
502
PROP_ACTIVATES_DEFAULT,
504
("activates_default",
505
_("Activates default"),
507
("Whether to activate the default widget (such as the default button in a dialog) when Enter is pressed"),
509
G_PARAM_READABLE | G_PARAM_WRITABLE));
510
g_object_class_install_property(gobject_class, PROP_WIDTH_CHARS,
511
g_param_spec_int("width_chars",
514
("Number of characters to leave space for in the entry"),
519
g_object_class_install_property(gobject_class,
521
g_param_spec_int("scroll_offset",
524
("Number of pixels of the entry scrolled off the screen to the left"),
528
g_object_class_install_property(gobject_class,
530
g_param_spec_string("text",
533
("The contents of the entry"),
541
g_signal_new("activate",
542
G_OBJECT_CLASS_TYPE(gobject_class),
543
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
544
G_STRUCT_OFFSET(GtkSecureEntryClass, activate),
545
NULL, NULL, _gtk_marshal_VOID__VOID, G_TYPE_NONE, 0);
546
widget_class->activate_signal = signals[ACTIVATE];
548
signals[MOVE_CURSOR] =
549
g_signal_new("move_cursor",
550
G_OBJECT_CLASS_TYPE(gobject_class),
551
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
552
G_STRUCT_OFFSET(GtkSecureEntryClass, move_cursor),
554
_gtk_marshal_VOID__ENUM_INT_BOOLEAN,
556
GTK_TYPE_MOVEMENT_STEP, G_TYPE_INT, G_TYPE_BOOLEAN);
558
signals[INSERT_AT_CURSOR] =
559
g_signal_new("insert_at_cursor",
560
G_OBJECT_CLASS_TYPE(gobject_class),
561
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
562
G_STRUCT_OFFSET(GtkSecureEntryClass,
563
insert_at_cursor), NULL, NULL,
564
_gtk_marshal_VOID__STRING, G_TYPE_NONE, 1,
567
signals[DELETE_FROM_CURSOR] =
568
g_signal_new("delete_from_cursor",
569
G_OBJECT_CLASS_TYPE(gobject_class),
570
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
571
G_STRUCT_OFFSET(GtkSecureEntryClass,
572
delete_from_cursor), NULL, NULL,
573
_gtk_marshal_VOID__ENUM_INT, G_TYPE_NONE, 2,
574
GTK_TYPE_DELETE_TYPE, G_TYPE_INT);
580
binding_set = gtk_binding_set_by_class(class);
582
/* Moving the insertion point */
583
add_move_binding(binding_set, GDK_Right, 0,
584
GTK_MOVEMENT_VISUAL_POSITIONS, 1);
586
add_move_binding(binding_set, GDK_Left, 0,
587
GTK_MOVEMENT_VISUAL_POSITIONS, -1);
589
add_move_binding(binding_set, GDK_KP_Right, 0,
590
GTK_MOVEMENT_VISUAL_POSITIONS, 1);
592
add_move_binding(binding_set, GDK_KP_Left, 0,
593
GTK_MOVEMENT_VISUAL_POSITIONS, -1);
595
add_move_binding(binding_set, GDK_Right, GDK_CONTROL_MASK,
596
GTK_MOVEMENT_WORDS, 1);
598
add_move_binding(binding_set, GDK_Left, GDK_CONTROL_MASK,
599
GTK_MOVEMENT_WORDS, -1);
601
add_move_binding(binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
602
GTK_MOVEMENT_WORDS, 1);
604
add_move_binding(binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
605
GTK_MOVEMENT_WORDS, -1);
607
add_move_binding(binding_set, GDK_Home, 0,
608
GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
610
add_move_binding(binding_set, GDK_End, 0,
611
GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
613
add_move_binding(binding_set, GDK_KP_Home, 0,
614
GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1);
616
add_move_binding(binding_set, GDK_KP_End, 0,
617
GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1);
619
add_move_binding(binding_set, GDK_Home, GDK_CONTROL_MASK,
620
GTK_MOVEMENT_BUFFER_ENDS, -1);
622
add_move_binding(binding_set, GDK_End, GDK_CONTROL_MASK,
623
GTK_MOVEMENT_BUFFER_ENDS, 1);
625
add_move_binding(binding_set, GDK_KP_Home, GDK_CONTROL_MASK,
626
GTK_MOVEMENT_BUFFER_ENDS, -1);
628
add_move_binding(binding_set, GDK_KP_End, GDK_CONTROL_MASK,
629
GTK_MOVEMENT_BUFFER_ENDS, 1);
633
gtk_binding_entry_add_signal(binding_set, GDK_a, GDK_CONTROL_MASK,
635
GTK_TYPE_MOVEMENT_STEP,
636
GTK_MOVEMENT_BUFFER_ENDS, G_TYPE_INT, -1,
637
G_TYPE_BOOLEAN, FALSE);
638
gtk_binding_entry_add_signal(binding_set, GDK_a, GDK_CONTROL_MASK,
639
"move_cursor", 3, GTK_TYPE_MOVEMENT_STEP,
640
GTK_MOVEMENT_BUFFER_ENDS, G_TYPE_INT, 1,
641
G_TYPE_BOOLEAN, TRUE);
646
gtk_binding_entry_add_signal(binding_set, GDK_Return, 0,
648
gtk_binding_entry_add_signal(binding_set, GDK_KP_Enter, 0,
652
gtk_binding_entry_add_signal(binding_set, GDK_Delete, 0,
653
"delete_from_cursor", 2,
654
G_TYPE_ENUM, GTK_DELETE_CHARS,
657
gtk_binding_entry_add_signal(binding_set, GDK_KP_Delete, 0,
658
"delete_from_cursor", 2,
659
G_TYPE_ENUM, GTK_DELETE_CHARS,
662
gtk_binding_entry_add_signal(binding_set, GDK_BackSpace, 0,
663
"delete_from_cursor", 2,
664
G_TYPE_ENUM, GTK_DELETE_CHARS,
667
/* Make this do the same as Backspace, to help with mis-typing */
668
gtk_binding_entry_add_signal(binding_set, GDK_BackSpace,
669
GDK_SHIFT_MASK, "delete_from_cursor", 2,
670
G_TYPE_ENUM, GTK_DELETE_CHARS, G_TYPE_INT,
673
gtk_binding_entry_add_signal(binding_set, GDK_Delete, GDK_CONTROL_MASK,
674
"delete_from_cursor", 2,
675
G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
678
gtk_binding_entry_add_signal(binding_set, GDK_KP_Delete,
679
GDK_CONTROL_MASK, "delete_from_cursor", 2,
680
G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
683
gtk_binding_entry_add_signal(binding_set, GDK_BackSpace,
684
GDK_CONTROL_MASK, "delete_from_cursor", 2,
685
G_TYPE_ENUM, GTK_DELETE_WORD_ENDS,
688
gtk_settings_install_property(g_param_spec_boolean
689
("gtk-entry-select-on-focus",
690
_("Select on focus"),
692
("Whether to select the contents of an entry when it is focused"),
693
TRUE, G_PARAM_READWRITE));
697
gtk_secure_entry_editable_init(GtkEditableClass * iface)
699
iface->do_insert_text = gtk_secure_entry_insert_text;
700
iface->do_delete_text = gtk_secure_entry_delete_text;
701
iface->insert_text = gtk_secure_entry_real_insert_text;
702
iface->delete_text = gtk_secure_entry_real_delete_text;
703
iface->set_selection_bounds = gtk_secure_entry_set_selection_bounds;
704
iface->get_selection_bounds = gtk_secure_entry_get_selection_bounds;
705
iface->set_position = gtk_secure_entry_real_set_position;
706
iface->get_position = gtk_secure_entry_get_position;
710
gtk_secure_entry_cell_editable_init(GtkCellEditableIface * iface)
712
iface->start_editing = gtk_secure_entry_start_editing;
716
gtk_secure_entry_set_property(GObject * object,
718
const GValue * value, GParamSpec * pspec)
720
GtkSecureEntry *entry = GTK_SECURE_ENTRY(object);
723
case PROP_MAX_LENGTH:
724
gtk_secure_entry_set_max_length(entry, g_value_get_int(value));
728
gtk_secure_entry_set_has_frame(entry, g_value_get_boolean(value));
731
case PROP_INVISIBLE_CHAR:
732
gtk_secure_entry_set_invisible_char(entry,
733
g_value_get_uint(value));
736
case PROP_ACTIVATES_DEFAULT:
737
gtk_secure_entry_set_activates_default(entry,
738
g_value_get_boolean(value));
741
case PROP_WIDTH_CHARS:
742
gtk_secure_entry_set_width_chars(entry, g_value_get_int(value));
746
gtk_secure_entry_set_text(entry, g_value_get_string(value));
749
case PROP_SCROLL_OFFSET:
750
case PROP_CURSOR_POSITION:
752
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
758
gtk_secure_entry_get_property(GObject * object,
760
GValue * value, GParamSpec * pspec)
762
GtkSecureEntry *entry = GTK_SECURE_ENTRY(object);
765
case PROP_CURSOR_POSITION:
766
g_value_set_int(value, entry->current_pos);
768
case PROP_SELECTION_BOUND:
769
g_value_set_int(value, entry->selection_bound);
771
case PROP_MAX_LENGTH:
772
g_value_set_int(value, entry->text_max_length);
775
g_value_set_boolean(value, entry->has_frame);
777
case PROP_INVISIBLE_CHAR:
778
g_value_set_uint(value, entry->invisible_char);
780
case PROP_ACTIVATES_DEFAULT:
781
g_value_set_boolean(value, entry->activates_default);
783
case PROP_WIDTH_CHARS:
784
g_value_set_int(value, entry->width_chars);
786
case PROP_SCROLL_OFFSET:
787
g_value_set_int(value, entry->scroll_offset);
790
g_value_set_string(value, gtk_secure_entry_get_text(entry));
794
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
800
gtk_secure_entry_init(GtkSecureEntry * entry)
802
GTK_WIDGET_SET_FLAGS(entry, GTK_CAN_FOCUS);
804
entry->text_size = MIN_SIZE;
805
WITH_SECURE_MEM(entry->text = g_malloc(entry->text_size));
806
entry->text[0] = '\0';
808
entry->invisible_char = '*';
809
entry->width_chars = -1;
810
entry->is_cell_renderer = FALSE;
811
entry->editing_canceled = FALSE;
812
entry->has_frame = TRUE;
814
/* This object is completely private. No external entity can gain a reference
815
* to it; so we create it here and destroy it in finalize().
817
entry->im_context = gtk_im_multicontext_new();
819
g_signal_connect(entry->im_context, "commit",
820
G_CALLBACK(gtk_secure_entry_commit_cb), entry);
821
g_signal_connect(entry->im_context, "preedit_changed",
822
G_CALLBACK(gtk_secure_entry_preedit_changed_cb),
824
g_signal_connect(entry->im_context, "retrieve_surrounding",
825
G_CALLBACK(gtk_secure_entry_retrieve_surrounding_cb),
827
g_signal_connect(entry->im_context, "delete_surrounding",
828
G_CALLBACK(gtk_secure_entry_delete_surrounding_cb),
833
gtk_secure_entry_finalize(GObject * object)
835
GtkSecureEntry *entry = GTK_SECURE_ENTRY(object);
837
if (entry->cached_layout)
838
g_object_unref(entry->cached_layout);
840
g_object_unref(entry->im_context);
842
if (entry->blink_timeout)
843
g_source_remove(entry->blink_timeout);
845
if (entry->recompute_idle)
846
g_source_remove(entry->recompute_idle);
848
entry->text_size = 0;
851
WITH_SECURE_MEM(g_free(entry->text));
854
G_OBJECT_CLASS(parent_class)->finalize(object);
858
gtk_secure_entry_realize(GtkWidget * widget)
860
GtkSecureEntry *entry;
861
GtkEditable *editable;
862
GdkWindowAttr attributes;
863
gint attributes_mask;
865
GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
866
entry = GTK_SECURE_ENTRY(widget);
867
editable = GTK_EDITABLE(widget);
869
attributes.window_type = GDK_WINDOW_CHILD;
871
get_widget_window_size(entry, &attributes.x, &attributes.y,
872
&attributes.width, &attributes.height);
874
attributes.wclass = GDK_INPUT_OUTPUT;
875
attributes.visual = gtk_widget_get_visual(widget);
876
attributes.colormap = gtk_widget_get_colormap(widget);
877
attributes.event_mask = gtk_widget_get_events(widget);
878
attributes.event_mask |= (GDK_EXPOSURE_MASK |
879
GDK_BUTTON_PRESS_MASK |
880
GDK_BUTTON_RELEASE_MASK |
881
GDK_BUTTON1_MOTION_MASK |
882
GDK_BUTTON3_MOTION_MASK |
883
GDK_POINTER_MOTION_HINT_MASK |
884
GDK_POINTER_MOTION_MASK |
885
GDK_ENTER_NOTIFY_MASK |
886
GDK_LEAVE_NOTIFY_MASK);
888
GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
891
gdk_window_new(gtk_widget_get_parent_window(widget), &attributes,
893
gdk_window_set_user_data(widget->window, entry);
895
get_text_area_size(entry, &attributes.x, &attributes.y,
896
&attributes.width, &attributes.height);
899
gdk_cursor_new_for_display(gtk_widget_get_display(widget),
901
attributes_mask |= GDK_WA_CURSOR;
904
gdk_window_new(widget->window, &attributes, attributes_mask);
905
gdk_window_set_user_data(entry->text_area, entry);
907
gdk_cursor_unref(attributes.cursor);
909
widget->style = gtk_style_attach(widget->style, widget->window);
911
gdk_window_set_background(widget->window,
913
base[GTK_WIDGET_STATE(widget)]);
914
gdk_window_set_background(entry->text_area,
916
base[GTK_WIDGET_STATE(widget)]);
918
gdk_window_show(entry->text_area);
920
gtk_im_context_set_client_window(entry->im_context, entry->text_area);
922
gtk_secure_entry_adjust_scroll(entry);
926
gtk_secure_entry_unrealize(GtkWidget * widget)
928
GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget);
930
gtk_secure_entry_reset_layout(entry);
932
gtk_im_context_set_client_window(entry->im_context, NULL);
934
if (entry->text_area) {
935
gdk_window_set_user_data(entry->text_area, NULL);
936
gdk_window_destroy(entry->text_area);
937
entry->text_area = NULL;
940
if (GTK_WIDGET_CLASS(parent_class)->unrealize)
941
(*GTK_WIDGET_CLASS(parent_class)->unrealize) (widget);
945
get_borders(GtkSecureEntry * entry, gint * xborder, gint * yborder)
947
GtkWidget *widget = GTK_WIDGET(entry);
949
gboolean interior_focus;
951
gtk_widget_style_get(widget,
952
"interior-focus", &interior_focus,
953
"focus-line-width", &focus_width, NULL);
955
if (entry->has_frame) {
956
*xborder = widget->style->xthickness;
957
*yborder = widget->style->ythickness;
963
if (!interior_focus) {
964
*xborder += focus_width;
965
*yborder += focus_width;
970
gtk_secure_entry_size_request(GtkWidget * widget,
971
GtkRequisition * requisition)
973
GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget);
974
PangoFontMetrics *metrics;
975
gint xborder, yborder;
976
PangoContext *context;
978
context = gtk_widget_get_pango_context(widget);
979
metrics = pango_context_get_metrics(context,
980
widget->style->font_desc,
981
pango_context_get_language
984
entry->ascent = pango_font_metrics_get_ascent(metrics);
985
entry->descent = pango_font_metrics_get_descent(metrics);
987
get_borders(entry, &xborder, &yborder);
989
xborder += INNER_BORDER;
990
yborder += INNER_BORDER;
992
if (entry->width_chars < 0)
993
requisition->width = MIN_SECURE_ENTRY_WIDTH + xborder * 2;
996
pango_font_metrics_get_approximate_char_width(metrics);
998
pango_font_metrics_get_approximate_digit_width(metrics);
1000
(MAX(char_width, digit_width) + PANGO_SCALE - 1) / PANGO_SCALE;
1002
requisition->width =
1003
char_pixels * entry->width_chars + xborder * 2;
1006
requisition->height =
1007
PANGO_PIXELS(entry->ascent + entry->descent) + yborder * 2;
1009
pango_font_metrics_unref(metrics);
1013
get_text_area_size(GtkSecureEntry * entry,
1014
gint * x, gint * y, gint * width, gint * height)
1016
gint xborder, yborder;
1017
GtkRequisition requisition;
1018
GtkWidget *widget = GTK_WIDGET(entry);
1020
gtk_widget_get_child_requisition(widget, &requisition);
1022
get_borders(entry, &xborder, &yborder);
1031
*width = GTK_WIDGET(entry)->allocation.width - xborder * 2;
1034
*height = requisition.height - yborder * 2;
1038
get_widget_window_size(GtkSecureEntry * entry,
1039
gint * x, gint * y, gint * width, gint * height)
1041
GtkRequisition requisition;
1042
GtkWidget *widget = GTK_WIDGET(entry);
1044
gtk_widget_get_child_requisition(widget, &requisition);
1047
*x = widget->allocation.x;
1050
if (entry->is_cell_renderer)
1051
*y = widget->allocation.y;
1053
*y = widget->allocation.y + (widget->allocation.height -
1054
requisition.height) / 2;
1058
*width = widget->allocation.width;
1061
if (entry->is_cell_renderer)
1062
*height = widget->allocation.height;
1064
*height = requisition.height;
1069
gtk_secure_entry_size_allocate(GtkWidget * widget,
1070
GtkAllocation * allocation)
1072
GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget);
1074
widget->allocation = *allocation;
1076
if (GTK_WIDGET_REALIZED(widget)) {
1077
/* We call gtk_widget_get_child_requisition, since we want (for
1078
* backwards compatibility reasons) the realization here to
1079
* be affected by the usize of the entry, if set
1081
gint x, y, width, height;
1083
get_widget_window_size(entry, &x, &y, &width, &height);
1085
gdk_window_move_resize(widget->window, x, y, width, height);
1087
get_text_area_size(entry, &x, &y, &width, &height);
1089
gdk_window_move_resize(entry->text_area, x, y, width, height);
1091
gtk_secure_entry_recompute(entry);
1096
gtk_secure_entry_draw_frame(GtkWidget * widget)
1100
gboolean interior_focus;
1103
gtk_widget_style_get(widget,
1104
"interior-focus", &interior_focus,
1105
"focus-line-width", &focus_width, NULL);
1107
gdk_drawable_get_size(widget->window, &width, &height);
1109
if (GTK_WIDGET_HAS_FOCUS(widget) && !interior_focus) {
1112
width -= 2 * focus_width;
1113
height -= 2 * focus_width;
1116
gtk_paint_shadow(widget->style, widget->window,
1117
GTK_STATE_NORMAL, GTK_SHADOW_IN,
1118
NULL, widget, "entry", x, y, width, height);
1120
if (GTK_WIDGET_HAS_FOCUS(widget) && !interior_focus) {
1123
width += 2 * focus_width;
1124
height += 2 * focus_width;
1126
gtk_paint_focus(widget->style, widget->window,
1127
GTK_WIDGET_STATE(widget), NULL, widget, "entry", 0,
1133
gtk_secure_entry_expose(GtkWidget * widget, GdkEventExpose * event)
1135
GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget);
1137
if (widget->window == event->window)
1138
gtk_secure_entry_draw_frame(widget);
1139
else if (entry->text_area == event->window) {
1140
gint area_width, area_height;
1142
get_text_area_size(entry, NULL, NULL, &area_width, &area_height);
1144
gtk_paint_flat_box(widget->style, entry->text_area,
1145
GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE,
1146
NULL, widget, "entry_bg",
1147
0, 0, area_width, area_height);
1149
if ((entry->invisible_char != 0) &&
1150
GTK_WIDGET_HAS_FOCUS(widget) &&
1151
entry->selection_bound == entry->current_pos
1152
&& entry->cursor_visible)
1153
gtk_secure_entry_draw_cursor(GTK_SECURE_ENTRY(widget));
1155
gtk_secure_entry_draw_text(GTK_SECURE_ENTRY(widget));
1162
gtk_secure_entry_button_press(GtkWidget * widget, GdkEventButton * event)
1164
GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget);
1167
if (event->window != entry->text_area ||
1168
(entry->button && event->button != entry->button))
1171
entry->button = event->button;
1173
if (!GTK_WIDGET_HAS_FOCUS(widget)) {
1174
entry->in_click = TRUE;
1175
gtk_widget_grab_focus(widget);
1176
entry->in_click = FALSE;
1180
gtk_secure_entry_find_position(entry,
1181
event->x + entry->scroll_offset);
1183
if (event->button == 1) {
1184
switch (event->type) {
1185
case GDK_BUTTON_PRESS:
1186
gtk_secure_entry_set_positions(entry, tmp_pos, tmp_pos);
1200
gtk_secure_entry_button_release(GtkWidget * widget, GdkEventButton * event)
1202
GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget);
1204
if (event->window != entry->text_area
1205
|| entry->button != event->button)
1214
gtk_secure_entry_motion_notify(GtkWidget * widget, GdkEventMotion * event)
1216
GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget);
1219
if (entry->mouse_cursor_obscured) {
1223
gdk_cursor_new_for_display(gtk_widget_get_display(widget),
1225
gdk_window_set_cursor(entry->text_area, cursor);
1226
gdk_cursor_unref(cursor);
1227
entry->mouse_cursor_obscured = FALSE;
1230
if (event->window != entry->text_area || entry->button != 1)
1233
if (event->is_hint || (entry->text_area != event->window))
1234
gdk_window_get_pointer(entry->text_area, NULL, NULL, NULL);
1238
gdk_drawable_get_size(entry->text_area, NULL, &height);
1242
else if (event->y >= height)
1243
tmp_pos = entry->text_length;
1246
gtk_secure_entry_find_position(entry,
1248
entry->scroll_offset);
1250
gtk_secure_entry_set_positions(entry, tmp_pos, -1);
1257
set_invisible_cursor(GdkWindow * window)
1259
GdkBitmap *empty_bitmap;
1262
char invisible_cursor_bits[] = { 0x0 };
1264
useless.red = useless.green = useless.blue = 0;
1267
empty_bitmap = gdk_bitmap_create_from_data(window,
1268
invisible_cursor_bits, 1,
1271
cursor = gdk_cursor_new_from_pixmap(empty_bitmap,
1273
&useless, &useless, 0, 0);
1275
gdk_window_set_cursor(window, cursor);
1277
gdk_cursor_unref(cursor);
1279
g_object_unref(empty_bitmap);
1283
gtk_secure_entry_obscure_mouse_cursor(GtkSecureEntry * entry)
1285
if (entry->mouse_cursor_obscured)
1288
set_invisible_cursor(entry->text_area);
1290
entry->mouse_cursor_obscured = TRUE;
1294
gtk_secure_entry_key_press(GtkWidget * widget, GdkEventKey * event)
1296
GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget);
1298
gtk_secure_entry_pend_cursor_blink(entry);
1300
if (gtk_im_context_filter_keypress(entry->im_context, event)) {
1301
gtk_secure_entry_obscure_mouse_cursor(entry);
1302
entry->need_im_reset = TRUE;
1306
if (GTK_WIDGET_CLASS(parent_class)->key_press_event(widget, event))
1307
/* Activate key bindings
1315
gtk_secure_entry_key_release(GtkWidget * widget, GdkEventKey * event)
1317
GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget);
1319
if (gtk_im_context_filter_keypress(entry->im_context, event)) {
1320
entry->need_im_reset = TRUE;
1324
return GTK_WIDGET_CLASS(parent_class)->key_release_event(widget,
1329
gtk_secure_entry_focus_in(GtkWidget * widget, GdkEventFocus * event)
1331
GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget);
1333
gtk_widget_queue_draw(widget);
1335
entry->need_im_reset = TRUE;
1336
gtk_im_context_focus_in(entry->im_context);
1338
g_signal_connect(gdk_keymap_get_for_display
1339
(gtk_widget_get_display(widget)), "direction_changed",
1340
G_CALLBACK(gtk_secure_entry_keymap_direction_changed),
1343
gtk_secure_entry_check_cursor_blink(entry);
1349
gtk_secure_entry_focus_out(GtkWidget * widget, GdkEventFocus * event)
1351
GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget);
1353
gtk_widget_queue_draw(widget);
1355
entry->need_im_reset = TRUE;
1356
gtk_im_context_focus_out(entry->im_context);
1358
gtk_secure_entry_check_cursor_blink(entry);
1360
g_signal_handlers_disconnect_by_func(gdk_keymap_get_for_display
1361
(gtk_widget_get_display(widget)),
1362
gtk_secure_entry_keymap_direction_changed,
1369
gtk_secure_entry_grab_focus(GtkWidget * widget)
1371
GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget);
1372
gboolean select_on_focus;
1374
GTK_WIDGET_SET_FLAGS(widget, GTK_CAN_DEFAULT);
1375
GTK_WIDGET_CLASS(parent_class)->grab_focus(widget);
1377
g_object_get(gtk_widget_get_settings(widget),
1378
"gtk-entry-select-on-focus", &select_on_focus, NULL);
1380
if (select_on_focus && !entry->in_click)
1381
gtk_editable_select_region(GTK_EDITABLE(widget), 0, -1);
1385
gtk_secure_entry_direction_changed(GtkWidget * widget,
1386
GtkTextDirection previous_dir)
1388
GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget);
1390
gtk_secure_entry_recompute(entry);
1392
GTK_WIDGET_CLASS(parent_class)->direction_changed(widget,
1397
gtk_secure_entry_state_changed(GtkWidget * widget,
1398
GtkStateType previous_state)
1400
GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget);
1402
if (GTK_WIDGET_REALIZED(widget)) {
1403
gdk_window_set_background(widget->window,
1405
base[GTK_WIDGET_STATE(widget)]);
1406
gdk_window_set_background(entry->text_area,
1408
base[GTK_WIDGET_STATE(widget)]);
1411
if (!GTK_WIDGET_IS_SENSITIVE(widget)) {
1412
/* Clear any selection */
1413
gtk_editable_select_region(GTK_EDITABLE(entry), entry->current_pos,
1414
entry->current_pos);
1417
gtk_widget_queue_draw(widget);
1421
gtk_secure_entry_screen_changed(GtkWidget * widget, GdkScreen * old_screen)
1423
gtk_secure_entry_recompute(GTK_SECURE_ENTRY(widget));
1426
/* GtkEditable method implementations
1429
gtk_secure_entry_insert_text(GtkEditable * editable,
1430
const gchar * new_text,
1431
gint new_text_length, gint * position)
1433
GtkSecureEntry *entry = GTK_SECURE_ENTRY(editable);
1436
if (*position < 0 || *position > entry->text_length)
1437
*position = entry->text_length;
1439
g_object_ref(editable);
1441
WITH_SECURE_MEM(text = g_new(gchar, new_text_length + 1));
1443
text[new_text_length] = '\0';
1444
strncpy(text, new_text, new_text_length);
1446
g_signal_emit_by_name(editable, "insert_text", text, new_text_length,
1449
WITH_SECURE_MEM(g_free(text));
1451
g_object_unref(editable);
1455
gtk_secure_entry_delete_text(GtkEditable * editable,
1456
gint start_pos, gint end_pos)
1458
GtkSecureEntry *entry = GTK_SECURE_ENTRY(editable);
1460
if (end_pos < 0 || end_pos > entry->text_length)
1461
end_pos = entry->text_length;
1464
if (start_pos > end_pos)
1465
start_pos = end_pos;
1467
g_object_ref(editable);
1469
g_signal_emit_by_name(editable, "delete_text", start_pos, end_pos);
1471
g_object_unref(editable);
1475
gtk_secure_entry_set_position_internal(GtkSecureEntry * entry,
1476
gint position, gboolean reset_im)
1478
if (position < 0 || position > entry->text_length)
1479
position = entry->text_length;
1481
if (position != entry->current_pos ||
1482
position != entry->selection_bound) {
1484
gtk_secure_entry_reset_im_context(entry);
1485
gtk_secure_entry_set_positions(entry, position, position);
1490
gtk_secure_entry_real_set_position(GtkEditable * editable, gint position)
1492
gtk_secure_entry_set_position_internal(GTK_SECURE_ENTRY(editable),
1497
gtk_secure_entry_get_position(GtkEditable * editable)
1499
return GTK_SECURE_ENTRY(editable)->current_pos;
1503
gtk_secure_entry_set_selection_bounds(GtkEditable * editable,
1504
gint start, gint end)
1506
GtkSecureEntry *entry = GTK_SECURE_ENTRY(editable);
1509
start = entry->text_length;
1511
end = entry->text_length;
1513
gtk_secure_entry_reset_im_context(entry);
1515
gtk_secure_entry_set_positions(entry,
1516
MIN(end, entry->text_length),
1517
MIN(start, entry->text_length));
1521
gtk_secure_entry_get_selection_bounds(GtkEditable * editable,
1522
gint * start, gint * end)
1524
GtkSecureEntry *entry = GTK_SECURE_ENTRY(editable);
1526
*start = entry->selection_bound;
1527
*end = entry->current_pos;
1529
return (entry->selection_bound != entry->current_pos);
1533
gtk_secure_entry_style_set(GtkWidget * widget, GtkStyle * previous_style)
1535
GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget);
1537
gtk_secure_entry_recompute(entry);
1539
if (previous_style && GTK_WIDGET_REALIZED(widget)) {
1540
gdk_window_set_background(widget->window,
1542
base[GTK_WIDGET_STATE(widget)]);
1543
gdk_window_set_background(entry->text_area,
1545
base[GTK_WIDGET_STATE(widget)]);
1549
/* GtkCellEditable method implementations
1552
gtk_cell_editable_secure_entry_activated(GtkSecureEntry * entry, gpointer data)
1554
gtk_cell_editable_editing_done(GTK_CELL_EDITABLE(entry));
1555
gtk_cell_editable_remove_widget(GTK_CELL_EDITABLE(entry));
1559
gtk_cell_editable_key_press_event(GtkSecureEntry * entry,
1560
GdkEventKey * key_event, gpointer data)
1562
if (key_event->keyval == GDK_Escape) {
1563
entry->editing_canceled = TRUE;
1564
gtk_cell_editable_editing_done(GTK_CELL_EDITABLE(entry));
1565
gtk_cell_editable_remove_widget(GTK_CELL_EDITABLE(entry));
1570
/* override focus */
1571
if (key_event->keyval == GDK_Up || key_event->keyval == GDK_Down) {
1572
gtk_cell_editable_editing_done(GTK_CELL_EDITABLE(entry));
1573
gtk_cell_editable_remove_widget(GTK_CELL_EDITABLE(entry));
1582
gtk_secure_entry_start_editing(GtkCellEditable * cell_editable,
1585
GTK_SECURE_ENTRY(cell_editable)->is_cell_renderer = TRUE;
1587
g_signal_connect(cell_editable, "activate",
1588
G_CALLBACK(gtk_cell_editable_secure_entry_activated), NULL);
1589
g_signal_connect(cell_editable, "key_press_event",
1590
G_CALLBACK(gtk_cell_editable_key_press_event), NULL);
1593
/* Default signal handlers
1596
gtk_secure_entry_real_insert_text(GtkEditable * editable,
1597
const gchar * new_text,
1598
gint new_text_length, gint * position)
1603
GtkSecureEntry *entry = GTK_SECURE_ENTRY(editable);
1605
if (new_text_length < 0)
1606
new_text_length = strlen(new_text);
1608
n_chars = g_utf8_strlen(new_text, new_text_length);
1609
if (entry->text_max_length > 0
1610
&& n_chars + entry->text_length > entry->text_max_length) {
1611
gdk_display_beep(gtk_widget_get_display(GTK_WIDGET(entry)));
1612
n_chars = entry->text_max_length - entry->text_length;
1614
g_utf8_offset_to_pointer(new_text, n_chars) - new_text;
1617
if (new_text_length + entry->n_bytes + 1 > entry->text_size) {
1618
while (new_text_length + entry->n_bytes + 1 > entry->text_size) {
1619
if (entry->text_size == 0)
1620
entry->text_size = MIN_SIZE;
1622
if (2 * (guint) entry->text_size < MAX_SIZE &&
1623
2 * (guint) entry->text_size > entry->text_size)
1624
entry->text_size *= 2;
1626
entry->text_size = MAX_SIZE;
1627
if (new_text_length >
1628
(gint) entry->text_size - (gint) entry->n_bytes -
1631
(gint) entry->text_size -
1632
(gint) entry->n_bytes - 1;
1634
g_utf8_find_prev_char(new_text,
1636
new_text_length + 1) -
1638
n_chars = g_utf8_strlen(new_text, new_text_length);
1645
WITH_SECURE_MEM(entry->text =
1646
g_realloc(entry->text, entry->text_size));
1649
_index = g_utf8_offset_to_pointer(entry->text, *position) - entry->text;
1651
g_memmove(entry->text + _index + new_text_length, entry->text + _index,
1652
entry->n_bytes - _index);
1653
memcpy(entry->text + _index, new_text, new_text_length);
1655
entry->n_bytes += new_text_length;
1656
entry->text_length += n_chars;
1658
/* NUL terminate for safety and convenience */
1659
entry->text[entry->n_bytes] = '\0';
1661
if (entry->current_pos > *position)
1662
entry->current_pos += n_chars;
1664
if (entry->selection_bound > *position)
1665
entry->selection_bound += n_chars;
1667
*position += n_chars;
1669
gtk_secure_entry_recompute(entry);
1671
g_signal_emit_by_name(editable, "changed");
1672
g_object_notify(G_OBJECT(editable), "text");
1676
gtk_secure_entry_real_delete_text(GtkEditable * editable,
1677
gint start_pos, gint end_pos)
1679
GtkSecureEntry *entry = GTK_SECURE_ENTRY(editable);
1683
if (end_pos < 0 || end_pos > entry->text_length)
1684
end_pos = entry->text_length;
1686
if (start_pos < end_pos) {
1688
g_utf8_offset_to_pointer(entry->text, start_pos) - entry->text;
1690
g_utf8_offset_to_pointer(entry->text, end_pos) - entry->text;
1692
gint selection_bound;
1694
g_memmove(entry->text + start_index, entry->text + end_index,
1695
entry->n_bytes + 1 - end_index);
1696
entry->text_length -= (end_pos - start_pos);
1697
entry->n_bytes -= (end_index - start_index);
1699
current_pos = entry->current_pos;
1700
if (current_pos > start_pos)
1701
current_pos -= MIN(current_pos, end_pos) - start_pos;
1703
selection_bound = entry->selection_bound;
1704
if (selection_bound > start_pos)
1705
selection_bound -= MIN(selection_bound, end_pos) - start_pos;
1707
gtk_secure_entry_set_positions(entry, current_pos,
1710
gtk_secure_entry_recompute(entry);
1712
g_signal_emit_by_name(editable, "changed");
1713
g_object_notify(G_OBJECT(editable), "text");
1717
/* Compute the X position for an offset that corresponds to the "more important
1718
* cursor position for that offset. We use this when trying to guess to which
1719
* end of the selection we should go to when the user hits the left or
1723
get_better_cursor_x(GtkSecureEntry * entry, gint offset)
1726
gdk_keymap_get_for_display(gtk_widget_get_display
1727
(GTK_WIDGET(entry)));
1728
PangoDirection keymap_direction = gdk_keymap_get_direction(keymap);
1729
gboolean split_cursor;
1731
PangoLayout *layout = gtk_secure_entry_ensure_layout(entry, TRUE);
1732
const gchar *text = pango_layout_get_text(layout);
1733
gint _index = g_utf8_offset_to_pointer(text, offset) - text;
1735
PangoRectangle strong_pos, weak_pos;
1737
g_object_get(gtk_widget_get_settings(GTK_WIDGET(entry)),
1738
"gtk-split-cursor", &split_cursor, NULL);
1740
pango_layout_get_cursor_pos(layout, _index, &strong_pos, &weak_pos);
1743
return strong_pos.x / PANGO_SCALE;
1745
return (keymap_direction ==
1746
entry->resolved_dir) ? strong_pos.x /
1747
PANGO_SCALE : weak_pos.x / PANGO_SCALE;
1751
gtk_secure_entry_move_cursor(GtkSecureEntry * entry,
1752
GtkMovementStep step,
1753
gint count, gboolean extend_selection)
1755
gint new_pos = entry->current_pos;
1757
gtk_secure_entry_reset_im_context(entry);
1759
if (entry->current_pos != entry->selection_bound && !extend_selection) {
1760
/* If we have a current selection and aren't extending it, move to the
1761
* start/or end of the selection as appropriate
1764
case GTK_MOVEMENT_VISUAL_POSITIONS:
1767
get_better_cursor_x(entry, entry->current_pos);
1769
get_better_cursor_x(entry, entry->selection_bound);
1774
bound_x ? entry->current_pos : entry->
1779
bound_x ? entry->current_pos : entry->
1784
case GTK_MOVEMENT_LOGICAL_POSITIONS:
1785
case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
1786
case GTK_MOVEMENT_PARAGRAPH_ENDS:
1787
case GTK_MOVEMENT_BUFFER_ENDS:
1788
new_pos = count < 0 ? 0 : entry->text_length;
1790
case GTK_MOVEMENT_WORDS:
1791
case GTK_MOVEMENT_DISPLAY_LINES:
1792
case GTK_MOVEMENT_PARAGRAPHS:
1793
case GTK_MOVEMENT_PAGES:
1794
case GTK_MOVEMENT_HORIZONTAL_PAGES:
1799
case GTK_MOVEMENT_LOGICAL_POSITIONS:
1801
gtk_secure_entry_move_logically(entry, new_pos, count);
1803
case GTK_MOVEMENT_VISUAL_POSITIONS:
1805
gtk_secure_entry_move_visually(entry, new_pos, count);
1807
case GTK_MOVEMENT_DISPLAY_LINE_ENDS:
1808
case GTK_MOVEMENT_PARAGRAPH_ENDS:
1809
case GTK_MOVEMENT_BUFFER_ENDS:
1810
new_pos = count < 0 ? 0 : entry->text_length;
1812
case GTK_MOVEMENT_WORDS:
1813
case GTK_MOVEMENT_DISPLAY_LINES:
1814
case GTK_MOVEMENT_PARAGRAPHS:
1815
case GTK_MOVEMENT_PAGES:
1816
case GTK_MOVEMENT_HORIZONTAL_PAGES:
1821
if (extend_selection)
1822
gtk_editable_select_region(GTK_EDITABLE(entry),
1823
entry->selection_bound, new_pos);
1825
gtk_editable_set_position(GTK_EDITABLE(entry), new_pos);
1827
gtk_secure_entry_pend_cursor_blink(entry);
1831
gtk_secure_entry_insert_at_cursor(GtkSecureEntry * entry,
1834
GtkEditable *editable = GTK_EDITABLE(entry);
1835
gint pos = entry->current_pos;
1837
gtk_secure_entry_reset_im_context(entry);
1839
gtk_editable_insert_text(editable, str, -1, &pos);
1840
gtk_editable_set_position(editable, pos);
1844
gtk_secure_entry_delete_from_cursor(GtkSecureEntry * entry,
1845
GtkDeleteType type, gint count)
1847
GtkEditable *editable = GTK_EDITABLE(entry);
1848
gint start_pos = entry->current_pos;
1849
gint end_pos = entry->current_pos;
1851
gtk_secure_entry_reset_im_context(entry);
1853
if (entry->selection_bound != entry->current_pos) {
1854
gtk_editable_delete_selection(editable);
1859
case GTK_DELETE_CHARS:
1861
gtk_secure_entry_move_logically(entry, entry->current_pos,
1863
gtk_editable_delete_text(editable, MIN(start_pos, end_pos),
1864
MAX(start_pos, end_pos));
1866
case GTK_DELETE_DISPLAY_LINE_ENDS:
1867
case GTK_DELETE_PARAGRAPH_ENDS:
1869
gtk_editable_delete_text(editable, 0, entry->current_pos);
1871
gtk_editable_delete_text(editable, entry->current_pos, -1);
1873
case GTK_DELETE_DISPLAY_LINES:
1874
case GTK_DELETE_PARAGRAPHS:
1875
gtk_editable_delete_text(editable, 0, -1);
1881
gtk_secure_entry_pend_cursor_blink(entry);
1885
gtk_secure_entry_delete_cb(GtkSecureEntry * entry)
1887
GtkEditable *editable = GTK_EDITABLE(entry);
1890
if (gtk_editable_get_selection_bounds(editable, &start, &end))
1891
gtk_editable_delete_text(editable, start, end);
1895
gtk_secure_entry_toggle_overwrite(GtkSecureEntry * entry)
1897
entry->overwrite_mode = !entry->overwrite_mode;
1901
gtk_secure_entry_real_activate(GtkSecureEntry * entry)
1904
GtkWidget *toplevel;
1907
widget = GTK_WIDGET(entry);
1909
if (entry->activates_default) {
1910
toplevel = gtk_widget_get_toplevel(widget);
1911
if (GTK_IS_WINDOW(toplevel)) {
1912
window = GTK_WINDOW(toplevel);
1915
widget != window->default_widget &&
1916
!(widget == window->focus_widget &&
1917
(!window->default_widget
1918
|| !GTK_WIDGET_SENSITIVE(window->default_widget))))
1919
gtk_window_activate_default(window);
1925
gtk_secure_entry_keymap_direction_changed(GdkKeymap * keymap,
1926
GtkSecureEntry * entry)
1928
gtk_secure_entry_recompute(entry);
1931
/* IM Context Callbacks
1935
gtk_secure_entry_commit_cb(GtkIMContext * context,
1936
const gchar * str, GtkSecureEntry * entry)
1938
gtk_secure_entry_enter_text(entry, str);
1942
gtk_secure_entry_preedit_changed_cb(GtkIMContext * context,
1943
GtkSecureEntry * entry)
1945
gchar *preedit_string;
1948
gtk_im_context_get_preedit_string(entry->im_context,
1949
&preedit_string, NULL, &cursor_pos);
1950
entry->preedit_length = strlen(preedit_string);
1951
cursor_pos = CLAMP(cursor_pos, 0, g_utf8_strlen(preedit_string, -1));
1952
entry->preedit_cursor = cursor_pos;
1953
g_free(preedit_string);
1955
gtk_secure_entry_recompute(entry);
1959
gtk_secure_entry_retrieve_surrounding_cb(GtkIMContext * context,
1960
GtkSecureEntry * entry)
1962
gtk_im_context_set_surrounding(context,
1965
g_utf8_offset_to_pointer(entry->text,
1974
gtk_secure_entry_delete_surrounding_cb(GtkIMContext * slave,
1977
GtkSecureEntry * entry)
1979
gtk_editable_delete_text(GTK_EDITABLE(entry),
1980
entry->current_pos + offset,
1981
entry->current_pos + offset + n_chars);
1986
/* Internal functions
1989
/* Used for im_commit_cb and inserting Unicode chars */
1991
gtk_secure_entry_enter_text(GtkSecureEntry * entry, const gchar * str)
1993
GtkEditable *editable = GTK_EDITABLE(entry);
1996
if (gtk_editable_get_selection_bounds(editable, NULL, NULL))
1997
gtk_editable_delete_selection(editable);
1999
if (entry->overwrite_mode)
2000
gtk_secure_entry_delete_from_cursor(entry, GTK_DELETE_CHARS,
2004
tmp_pos = entry->current_pos;
2005
gtk_editable_insert_text(editable, str, strlen(str), &tmp_pos);
2006
gtk_secure_entry_set_position_internal(entry, tmp_pos, FALSE);
2009
/* All changes to entry->current_pos and entry->selection_bound
2010
* should go through this function.
2013
gtk_secure_entry_set_positions(GtkSecureEntry * entry,
2014
gint current_pos, gint selection_bound)
2016
gboolean changed = FALSE;
2018
g_object_freeze_notify(G_OBJECT(entry));
2020
if (current_pos != -1 && entry->current_pos != current_pos) {
2021
entry->current_pos = current_pos;
2024
g_object_notify(G_OBJECT(entry), "cursor_position");
2027
if (selection_bound != -1 && entry->selection_bound != selection_bound) {
2028
entry->selection_bound = selection_bound;
2031
g_object_notify(G_OBJECT(entry), "selection_bound");
2034
g_object_thaw_notify(G_OBJECT(entry));
2037
gtk_secure_entry_recompute(entry);
2041
gtk_secure_entry_reset_layout(GtkSecureEntry * entry)
2043
if (entry->cached_layout) {
2044
g_object_unref(entry->cached_layout);
2045
entry->cached_layout = NULL;
2050
update_im_cursor_location(GtkSecureEntry * entry)
2054
gint strong_xoffset;
2055
gint area_width, area_height;
2057
gtk_secure_entry_get_cursor_locations(entry, &strong_x, NULL);
2058
get_text_area_size(entry, NULL, NULL, &area_width, &area_height);
2060
strong_xoffset = strong_x - entry->scroll_offset;
2061
if (strong_xoffset < 0) {
2063
} else if (strong_xoffset > area_width) {
2064
strong_xoffset = area_width;
2066
area.x = strong_xoffset;
2069
area.height = area_height;
2071
gtk_im_context_set_cursor_location(entry->im_context, &area);
2075
recompute_idle_func(gpointer data)
2077
GtkSecureEntry *entry;
2079
GDK_THREADS_ENTER();
2081
entry = GTK_SECURE_ENTRY(data);
2083
entry->recompute_idle = 0;
2085
if (gtk_widget_has_screen(GTK_WIDGET(entry))) {
2086
gtk_secure_entry_adjust_scroll(entry);
2087
gtk_secure_entry_queue_draw(entry);
2089
update_im_cursor_location(entry);
2092
GDK_THREADS_LEAVE();
2098
gtk_secure_entry_recompute(GtkSecureEntry * entry)
2100
gtk_secure_entry_reset_layout(entry);
2101
gtk_secure_entry_check_cursor_blink(entry);
2103
if (!entry->recompute_idle) {
2104
entry->recompute_idle = g_idle_add_full(G_PRIORITY_HIGH_IDLE + 15, /* between resize and redraw */
2105
recompute_idle_func, entry,
2111
append_char(GString * str, gunichar ch, gint count)
2117
char_len = g_unichar_to_utf8(ch, buf);
2121
g_string_append_len(str, buf, char_len);
2126
static PangoLayout *
2127
gtk_secure_entry_create_layout(GtkSecureEntry * entry,
2128
gboolean include_preedit)
2130
GtkWidget *widget = GTK_WIDGET(entry);
2131
PangoLayout *layout = gtk_widget_create_pango_layout(widget, NULL);
2132
PangoAttrList *tmp_attrs = pango_attr_list_new();
2134
gchar *preedit_string = NULL;
2135
gint preedit_length = 0;
2136
PangoAttrList *preedit_attrs = NULL;
2138
pango_layout_set_single_paragraph_mode(layout, TRUE);
2140
if (include_preedit) {
2141
gtk_im_context_get_preedit_string(entry->im_context,
2142
&preedit_string, &preedit_attrs,
2144
preedit_length = entry->preedit_length;
2147
if (preedit_length) {
2148
GString *tmp_string = g_string_new(NULL);
2150
gint cursor_index = g_utf8_offset_to_pointer(entry->text,
2151
entry->current_pos) -
2155
gint preedit_len_chars;
2156
gunichar invisible_char;
2158
ch_len = g_utf8_strlen(entry->text, entry->n_bytes);
2159
preedit_len_chars = g_utf8_strlen(preedit_string, -1);
2160
ch_len += preedit_len_chars;
2162
if (entry->invisible_char != 0)
2163
invisible_char = entry->invisible_char;
2165
invisible_char = ' '; /* just pick a char */
2167
append_char(tmp_string, invisible_char, ch_len);
2169
/* Fix cursor index to point to invisible char corresponding
2170
* to the preedit, fix preedit_length to be the length of
2171
* the invisible chars representing the preedit
2174
g_utf8_offset_to_pointer(tmp_string->str,
2175
entry->current_pos) -
2178
preedit_len_chars * g_unichar_to_utf8(invisible_char,
2181
pango_layout_set_text(layout, tmp_string->str, tmp_string->len);
2183
pango_attr_list_splice(tmp_attrs, preedit_attrs,
2184
cursor_index, preedit_length);
2186
g_string_free(tmp_string, TRUE);
2188
PangoDirection pango_dir;
2190
pango_dir = pango_find_base_dir(entry->text, entry->n_bytes);
2191
if (pango_dir == PANGO_DIRECTION_NEUTRAL) {
2192
if (GTK_WIDGET_HAS_FOCUS(widget)) {
2193
GdkDisplay *display = gtk_widget_get_display(widget);
2194
GdkKeymap *keymap = gdk_keymap_get_for_display(display);
2195
pango_dir = gdk_keymap_get_direction(keymap);
2197
if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_LTR)
2198
pango_dir = PANGO_DIRECTION_LTR;
2200
pango_dir = PANGO_DIRECTION_RTL;
2204
pango_context_set_base_dir(gtk_widget_get_pango_context(widget),
2207
pango_layout_set_alignment(layout, pango_dir);
2209
entry->resolved_dir = pango_dir;
2212
GString *str = g_string_new(NULL);
2213
gunichar invisible_char;
2215
if (entry->invisible_char != 0)
2216
invisible_char = entry->invisible_char;
2218
invisible_char = ' '; /* just pick a char */
2220
append_char(str, invisible_char, entry->text_length);
2221
pango_layout_set_text(layout, str->str, str->len);
2222
g_string_free(str, TRUE);
2226
pango_layout_set_attributes(layout, tmp_attrs);
2229
g_free(preedit_string);
2231
pango_attr_list_unref(preedit_attrs);
2233
pango_attr_list_unref(tmp_attrs);
2238
static PangoLayout *
2239
gtk_secure_entry_ensure_layout(GtkSecureEntry * entry,
2240
gboolean include_preedit)
2242
if (entry->preedit_length > 0 &&
2243
!include_preedit != !entry->cache_includes_preedit)
2244
gtk_secure_entry_reset_layout(entry);
2246
if (!entry->cached_layout) {
2247
entry->cached_layout =
2248
gtk_secure_entry_create_layout(entry, include_preedit);
2249
entry->cache_includes_preedit = include_preedit;
2252
return entry->cached_layout;
2256
get_layout_position(GtkSecureEntry * entry, gint * x, gint * y)
2258
PangoLayout *layout;
2259
PangoRectangle logical_rect;
2260
gint area_width, area_height;
2262
PangoLayoutLine *line;
2264
layout = gtk_secure_entry_ensure_layout(entry, TRUE);
2266
get_text_area_size(entry, NULL, NULL, &area_width, &area_height);
2268
area_height = PANGO_SCALE * (area_height - 2 * INNER_BORDER);
2270
line = pango_layout_get_lines(layout)->data;
2271
pango_layout_line_get_extents(line, NULL, &logical_rect);
2273
/* Align primarily for locale's ascent/descent */
2274
y_pos = ((area_height - entry->ascent - entry->descent) / 2 +
2275
entry->ascent + logical_rect.y);
2277
/* Now see if we need to adjust to fit in actual drawn string */
2278
if (logical_rect.height > area_height)
2279
y_pos = (area_height - logical_rect.height) / 2;
2282
else if (y_pos + logical_rect.height > area_height)
2283
y_pos = area_height - logical_rect.height;
2285
y_pos = INNER_BORDER + y_pos / PANGO_SCALE;
2288
*x = INNER_BORDER - entry->scroll_offset;
2295
gtk_secure_entry_draw_text(GtkSecureEntry * entry)
2298
PangoLayoutLine *line;
2300
if (entry->invisible_char == 0)
2303
if (GTK_WIDGET_DRAWABLE(entry)) {
2304
PangoLayout *layout = gtk_secure_entry_ensure_layout(entry, TRUE);
2306
gint start_pos, end_pos;
2308
widget = GTK_WIDGET(entry);
2310
get_layout_position(entry, &x, &y);
2312
gdk_draw_layout(entry->text_area,
2313
widget->style->text_gc[widget->state], x, y,
2316
if (gtk_editable_get_selection_bounds
2317
(GTK_EDITABLE(entry), &start_pos, &end_pos)) {
2320
PangoRectangle logical_rect;
2321
const gchar *text = pango_layout_get_text(layout);
2323
g_utf8_offset_to_pointer(text, start_pos) - text;
2325
g_utf8_offset_to_pointer(text, end_pos) - text;
2326
GdkRegion *clip_region = gdk_region_new();
2328
GdkGC *selection_gc;
2330
line = pango_layout_get_lines(layout)->data;
2332
pango_layout_line_get_x_ranges(line, start_index, end_index,
2333
&ranges, &n_ranges);
2335
pango_layout_get_extents(layout, NULL, &logical_rect);
2337
if (GTK_WIDGET_HAS_FOCUS(entry)) {
2338
selection_gc = widget->style->base_gc[GTK_STATE_SELECTED];
2339
text_gc = widget->style->text_gc[GTK_STATE_SELECTED];
2341
selection_gc = widget->style->base_gc[GTK_STATE_ACTIVE];
2342
text_gc = widget->style->text_gc[GTK_STATE_ACTIVE];
2345
for (i = 0; i < n_ranges; i++) {
2349
INNER_BORDER - entry->scroll_offset +
2350
ranges[2 * i] / PANGO_SCALE;
2353
(ranges[2 * i + 1] - ranges[2 * i]) / PANGO_SCALE;
2354
rect.height = logical_rect.height / PANGO_SCALE;
2356
gdk_draw_rectangle(entry->text_area, selection_gc, TRUE,
2357
rect.x, rect.y, rect.width,
2360
gdk_region_union_with_rect(clip_region, &rect);
2363
gdk_gc_set_clip_region(text_gc, clip_region);
2364
gdk_draw_layout(entry->text_area, text_gc, x, y, layout);
2365
gdk_gc_set_clip_region(text_gc, NULL);
2367
gdk_region_destroy(clip_region);
2374
draw_insertion_cursor(GtkSecureEntry * entry,
2375
GdkRectangle * cursor_location,
2376
gboolean is_primary,
2377
PangoDirection direction, gboolean draw_arrow)
2379
GtkWidget *widget = GTK_WIDGET(entry);
2380
GtkTextDirection text_dir;
2382
if (direction == PANGO_DIRECTION_LTR)
2383
text_dir = GTK_TEXT_DIR_LTR;
2385
text_dir = GTK_TEXT_DIR_RTL;
2387
gtk_draw_insertion_cursor(widget, entry->text_area, NULL,
2389
is_primary, text_dir, draw_arrow);
2393
gtk_secure_entry_draw_cursor(GtkSecureEntry * entry)
2396
gdk_keymap_get_for_display(gtk_widget_get_display
2397
(GTK_WIDGET(entry)));
2398
PangoDirection keymap_direction = gdk_keymap_get_direction(keymap);
2400
if (GTK_WIDGET_DRAWABLE(entry)) {
2401
GtkWidget *widget = GTK_WIDGET(entry);
2402
GdkRectangle cursor_location;
2403
gboolean split_cursor;
2405
gint xoffset = INNER_BORDER - entry->scroll_offset;
2406
gint strong_x, weak_x;
2407
gint text_area_height;
2408
PangoDirection dir1 = PANGO_DIRECTION_NEUTRAL;
2409
PangoDirection dir2 = PANGO_DIRECTION_NEUTRAL;
2413
gdk_drawable_get_size(entry->text_area, NULL, &text_area_height);
2415
gtk_secure_entry_get_cursor_locations(entry, &strong_x, &weak_x);
2417
g_object_get(gtk_widget_get_settings(widget),
2418
"gtk-split-cursor", &split_cursor, NULL);
2420
dir1 = entry->resolved_dir;
2425
if (weak_x != strong_x) {
2427
(entry->resolved_dir ==
2428
PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL :
2429
PANGO_DIRECTION_LTR;
2433
if (keymap_direction == entry->resolved_dir)
2439
cursor_location.x = xoffset + x1;
2440
cursor_location.y = INNER_BORDER;
2441
cursor_location.width = 0;
2442
cursor_location.height = text_area_height - 2 * INNER_BORDER;
2444
draw_insertion_cursor(entry,
2445
&cursor_location, TRUE, dir1,
2446
dir2 != PANGO_DIRECTION_NEUTRAL);
2448
if (dir2 != PANGO_DIRECTION_NEUTRAL) {
2449
cursor_location.x = xoffset + x2;
2450
draw_insertion_cursor(entry,
2451
&cursor_location, FALSE, dir2, TRUE);
2457
gtk_secure_entry_queue_draw(GtkSecureEntry * entry)
2459
if (GTK_WIDGET_REALIZED(entry))
2460
gdk_window_invalidate_rect(entry->text_area, NULL, FALSE);
2464
gtk_secure_entry_reset_im_context(GtkSecureEntry * entry)
2466
if (entry->need_im_reset) {
2467
entry->need_im_reset = 0;
2468
gtk_im_context_reset(entry->im_context);
2473
gtk_secure_entry_find_position(GtkSecureEntry * entry, gint x)
2475
PangoLayout *layout;
2476
PangoLayoutLine *line;
2483
layout = gtk_secure_entry_ensure_layout(entry, TRUE);
2484
text = pango_layout_get_text(layout);
2486
g_utf8_offset_to_pointer(text, entry->current_pos) - text;
2488
line = pango_layout_get_lines(layout)->data;
2489
pango_layout_line_x_to_index(line, x * PANGO_SCALE, &_index, &trailing);
2491
if (_index >= cursor_index && entry->preedit_length) {
2492
if (_index >= cursor_index + entry->preedit_length)
2493
_index -= entry->preedit_length;
2495
_index = cursor_index;
2500
pos = g_utf8_pointer_to_offset(text, text + _index);
2507
gtk_secure_entry_get_cursor_locations(GtkSecureEntry * entry,
2508
gint * strong_x, gint * weak_x)
2510
if (!entry->invisible_char) {
2517
PangoLayout *layout = gtk_secure_entry_ensure_layout(entry, TRUE);
2518
const gchar *text = pango_layout_get_text(layout);
2519
PangoRectangle strong_pos, weak_pos;
2523
g_utf8_offset_to_pointer(text,
2524
entry->current_pos +
2525
entry->preedit_cursor) - text;
2527
pango_layout_get_cursor_pos(layout, _index, &strong_pos, &weak_pos);
2530
*strong_x = strong_pos.x / PANGO_SCALE;
2533
*weak_x = weak_pos.x / PANGO_SCALE;
2538
gtk_secure_entry_adjust_scroll(GtkSecureEntry * entry)
2540
gint min_offset, max_offset;
2541
gint text_area_width, text_width;
2542
gint strong_x, weak_x;
2543
gint strong_xoffset, weak_xoffset;
2544
PangoLayout *layout;
2545
PangoLayoutLine *line;
2546
PangoRectangle logical_rect;
2548
if (!GTK_WIDGET_REALIZED(entry))
2551
gdk_drawable_get_size(entry->text_area, &text_area_width, NULL);
2552
text_area_width -= 2 * INNER_BORDER;
2554
layout = gtk_secure_entry_ensure_layout(entry, TRUE);
2555
line = pango_layout_get_lines(layout)->data;
2557
pango_layout_line_get_extents(line, NULL, &logical_rect);
2559
/* Display as much text as we can */
2561
text_width = PANGO_PIXELS(logical_rect.width);
2563
if (text_width > text_area_width) {
2565
max_offset = text_width - text_area_width;
2568
max_offset = min_offset;
2571
entry->scroll_offset =
2572
CLAMP(entry->scroll_offset, min_offset, max_offset);
2574
/* And make sure cursors are on screen. Note that the cursor is
2575
* actually drawn one pixel into the INNER_BORDER space on
2576
* the right, when the scroll is at the utmost right. This
2577
* looks better to to me than confining the cursor inside the
2578
* border entirely, though it means that the cursor gets one
2579
* pixel closer to the the edge of the widget on the right than
2580
* on the left. This might need changing if one changed
2581
* INNER_BORDER from 2 to 1, as one would do on a
2582
* small-screen-real-estate display.
2584
* We always make sure that the strong cursor is on screen, and
2585
* put the weak cursor on screen if possible.
2588
gtk_secure_entry_get_cursor_locations(entry, &strong_x, &weak_x);
2590
strong_xoffset = strong_x - entry->scroll_offset;
2592
if (strong_xoffset < 0) {
2593
entry->scroll_offset += strong_xoffset;
2595
} else if (strong_xoffset > text_area_width) {
2596
entry->scroll_offset += strong_xoffset - text_area_width;
2597
strong_xoffset = text_area_width;
2600
weak_xoffset = weak_x - entry->scroll_offset;
2602
if (weak_xoffset < 0
2603
&& strong_xoffset - weak_xoffset <= text_area_width) {
2604
entry->scroll_offset += weak_xoffset;
2605
} else if (weak_xoffset > text_area_width &&
2606
strong_xoffset - (weak_xoffset - text_area_width) >= 0) {
2607
entry->scroll_offset += weak_xoffset - text_area_width;
2610
g_object_notify(G_OBJECT(entry), "scroll_offset");
2614
gtk_secure_entry_move_visually(GtkSecureEntry * entry,
2615
gint start, gint count)
2618
PangoLayout *layout = gtk_secure_entry_ensure_layout(entry, FALSE);
2621
text = pango_layout_get_text(layout);
2623
_index = g_utf8_offset_to_pointer(text, start) - text;
2625
while (count != 0) {
2626
int new_index, new_trailing;
2627
gboolean split_cursor;
2630
g_object_get(gtk_widget_get_settings(GTK_WIDGET(entry)),
2631
"gtk-split-cursor", &split_cursor, NULL);
2637
gdk_keymap_get_for_display(gtk_widget_get_display
2638
(GTK_WIDGET(entry)));
2639
PangoDirection keymap_direction =
2640
gdk_keymap_get_direction(keymap);
2642
strong = keymap_direction == entry->resolved_dir;
2646
pango_layout_move_cursor_visually(layout, strong, _index, 0, 1,
2647
&new_index, &new_trailing);
2650
pango_layout_move_cursor_visually(layout, strong, _index, 0, -1,
2651
&new_index, &new_trailing);
2655
if (new_index < 0 || new_index == G_MAXINT)
2660
while (new_trailing--)
2661
_index = g_utf8_next_char(text + new_index) - text;
2664
return g_utf8_pointer_to_offset(text, text + _index);
2668
gtk_secure_entry_move_logically(GtkSecureEntry * entry,
2669
gint start, gint count)
2671
gint new_pos = start;
2673
/* Prevent any leak of information */
2674
new_pos = CLAMP(start + count, 0, entry->text_length);
2683
gtk_secure_entry_new(void)
2685
return g_object_new(GTK_TYPE_SECURE_ENTRY, NULL);
2689
* gtk_secure_entry_new_with_max_length:
2690
* @max: the maximum length of the entry, or 0 for no maximum.
2691
* (other than the maximum length of entries.) The value passed in will
2692
* be clamped to the range 0-65536.
2694
* Creates a new #GtkSecureEntry widget with the given maximum length.
2696
* Note: the existence of this function is inconsistent
2697
* with the rest of the GTK+ API. The normal setup would
2698
* be to just require the user to make an extra call
2699
* to gtk_secure_entry_set_max_length() instead. It is not
2700
* expected that this function will be removed, but
2701
* it would be better practice not to use it.
2703
* Return value: a new #GtkSecureEntry.
2706
gtk_secure_entry_new_with_max_length(gint max)
2708
GtkSecureEntry *entry;
2710
max = CLAMP(max, 0, MAX_SIZE);
2712
entry = g_object_new(GTK_TYPE_SECURE_ENTRY, NULL);
2713
entry->text_max_length = max;
2715
return GTK_WIDGET(entry);
2719
gtk_secure_entry_set_text(GtkSecureEntry * entry, const gchar * text)
2723
g_return_if_fail(GTK_IS_SECURE_ENTRY(entry));
2724
g_return_if_fail(text != NULL);
2726
/* Actually setting the text will affect the cursor and selection;
2727
* if the contents don't actually change, this will look odd to the user.
2729
if (strcmp(entry->text, text) == 0)
2732
gtk_editable_delete_text(GTK_EDITABLE(entry), 0, -1);
2735
gtk_editable_insert_text(GTK_EDITABLE(entry), text, strlen(text),
2740
gtk_secure_entry_append_text(GtkSecureEntry * entry, const gchar * text)
2744
g_return_if_fail(GTK_IS_SECURE_ENTRY(entry));
2745
g_return_if_fail(text != NULL);
2747
tmp_pos = entry->text_length;
2748
gtk_editable_insert_text(GTK_EDITABLE(entry), text, -1, &tmp_pos);
2752
gtk_secure_entry_prepend_text(GtkSecureEntry * entry, const gchar * text)
2756
g_return_if_fail(GTK_IS_SECURE_ENTRY(entry));
2757
g_return_if_fail(text != NULL);
2760
gtk_editable_insert_text(GTK_EDITABLE(entry), text, -1, &tmp_pos);
2764
gtk_secure_entry_set_position(GtkSecureEntry * entry, gint position)
2766
g_return_if_fail(GTK_IS_SECURE_ENTRY(entry));
2768
gtk_editable_set_position(GTK_EDITABLE(entry), position);
2772
* gtk_secure_entry_set_invisible_char:
2773
* @entry: a #GtkSecureEntry
2774
* @ch: a Unicode character
2776
* Sets the character to use in place of the actual text when
2777
* gtk_secure_entry_set_visibility() has been called to set text visibility
2778
* to %FALSE. i.e. this is the character used in "password mode" to
2779
* show the user how many characters have been typed. The default
2780
* invisible char is an asterisk ('*'). If you set the invisible char
2781
* to 0, then the user will get no feedback at all; there will be
2782
* no text on the screen as they type.
2786
gtk_secure_entry_set_invisible_char(GtkSecureEntry * entry, gunichar ch)
2788
g_return_if_fail(GTK_IS_SECURE_ENTRY(entry));
2790
if (ch == entry->invisible_char)
2793
entry->invisible_char = ch;
2794
g_object_notify(G_OBJECT(entry), "invisible_char");
2795
gtk_secure_entry_recompute(entry);
2799
* gtk_secure_entry_get_invisible_char:
2800
* @entry: a #GtkSecureEntry
2802
* Retrieves the character displayed in place of the real characters
2803
* for entries with visisbility set to false. See gtk_secure_entry_set_invisible_char().
2805
* Return value: the current invisible char, or 0, if the entry does not
2806
* show invisible text at all.
2809
gtk_secure_entry_get_invisible_char(GtkSecureEntry * entry)
2811
g_return_val_if_fail(GTK_IS_SECURE_ENTRY(entry), 0);
2813
return entry->invisible_char;
2817
* gtk_secure_entry_get_text:
2818
* @entry: a #GtkSecureEntry
2820
* Retrieves the contents of the entry widget.
2821
* See also gtk_editable_get_chars().
2823
* Return value: a pointer to the contents of the widget as a
2824
* string. This string points to internally allocated
2825
* storage in the widget and must not be freed, modified or
2828
G_CONST_RETURN gchar *
2829
gtk_secure_entry_get_text(GtkSecureEntry * entry)
2831
g_return_val_if_fail(GTK_IS_SECURE_ENTRY(entry), NULL);
2837
gtk_secure_entry_select_region(GtkSecureEntry * entry,
2838
gint start, gint end)
2840
gtk_editable_select_region(GTK_EDITABLE(entry), start, end);
2844
* gtk_secure_entry_set_max_length:
2845
* @entry: a #GtkSecureEntry.
2846
* @max: the maximum length of the entry, or 0 for no maximum.
2847
* (other than the maximum length of entries.) The value passed in will
2848
* be clamped to the range 0-65536.
2850
* Sets the maximum allowed length of the contents of the widget. If
2851
* the current contents are longer than the given length, then they
2852
* will be truncated to fit.
2855
gtk_secure_entry_set_max_length(GtkSecureEntry * entry, gint max)
2857
g_return_if_fail(GTK_IS_SECURE_ENTRY(entry));
2859
max = CLAMP(max, 0, MAX_SIZE);
2861
if (max > 0 && entry->text_length > max)
2862
gtk_editable_delete_text(GTK_EDITABLE(entry), max, -1);
2864
entry->text_max_length = max;
2865
g_object_notify(G_OBJECT(entry), "max_length");
2869
* gtk_secure_entry_get_max_length:
2870
* @entry: a #GtkSecureEntry
2872
* Retrieves the maximum allowed length of the text in
2873
* @entry. See gtk_secure_entry_set_max_length().
2875
* Return value: the maximum allowed number of characters
2876
* in #GtkSecureEntry, or 0 if there is no maximum.
2879
gtk_secure_entry_get_max_length(GtkSecureEntry * entry)
2881
g_return_val_if_fail(GTK_IS_SECURE_ENTRY(entry), 0);
2883
return entry->text_max_length;
2887
* gtk_secure_entry_set_activates_default:
2888
* @entry: a #GtkSecureEntry
2889
* @setting: %TRUE to activate window's default widget on Enter keypress
2891
* If @setting is %TRUE, pressing Enter in the @entry will activate the default
2892
* widget for the window containing the entry. This usually means that
2893
* the dialog box containing the entry will be closed, since the default
2894
* widget is usually one of the dialog buttons.
2896
* (For experts: if @setting is %TRUE, the entry calls
2897
* gtk_window_activate_default() on the window containing the entry, in
2898
* the default handler for the "activate" signal.)
2902
gtk_secure_entry_set_activates_default(GtkSecureEntry * entry,
2905
g_return_if_fail(GTK_IS_SECURE_ENTRY(entry));
2906
setting = setting != FALSE;
2908
if (setting != entry->activates_default) {
2909
entry->activates_default = setting;
2910
g_object_notify(G_OBJECT(entry), "activates_default");
2915
* gtk_secure_entry_get_activates_default:
2916
* @entry: a #GtkSecureEntry
2918
* Retrieves the value set by gtk_secure_entry_set_activates_default().
2920
* Return value: %TRUE if the entry will activate the default widget
2923
gtk_secure_entry_get_activates_default(GtkSecureEntry * entry)
2925
g_return_val_if_fail(GTK_IS_SECURE_ENTRY(entry), FALSE);
2927
return entry->activates_default;
2931
* gtk_secure_entry_set_width_chars:
2932
* @entry: a #GtkSecureEntry
2933
* @n_chars: width in chars
2935
* Changes the size request of the entry to be about the right size
2936
* for @n_chars characters. Note that it changes the size
2937
* <emphasis>request</emphasis>, the size can still be affected by
2938
* how you pack the widget into containers. If @n_chars is -1, the
2939
* size reverts to the default entry size.
2943
gtk_secure_entry_set_width_chars(GtkSecureEntry * entry, gint n_chars)
2945
g_return_if_fail(GTK_IS_SECURE_ENTRY(entry));
2947
if (entry->width_chars != n_chars) {
2948
entry->width_chars = n_chars;
2949
g_object_notify(G_OBJECT(entry), "width_chars");
2950
gtk_widget_queue_resize(GTK_WIDGET(entry));
2955
* gtk_secure_entry_get_width_chars:
2956
* @entry: a #GtkSecureEntry
2958
* Gets the value set by gtk_secure_entry_set_width_chars().
2960
* Return value: number of chars to request space for, or negative if unset
2963
gtk_secure_entry_get_width_chars(GtkSecureEntry * entry)
2965
g_return_val_if_fail(GTK_IS_SECURE_ENTRY(entry), 0);
2967
return entry->width_chars;
2971
* gtk_secure_entry_set_has_frame:
2972
* @entry: a #GtkSecureEntry
2973
* @setting: new value
2975
* Sets whether the entry has a beveled frame around it.
2978
gtk_secure_entry_set_has_frame(GtkSecureEntry * entry, gboolean setting)
2980
g_return_if_fail(GTK_IS_SECURE_ENTRY(entry));
2982
setting = (setting != FALSE);
2984
if (entry->has_frame == setting)
2987
gtk_widget_queue_resize(GTK_WIDGET(entry));
2988
entry->has_frame = setting;
2989
g_object_notify(G_OBJECT(entry), "has_frame");
2993
* gtk_secure_entry_get_has_frame:
2994
* @entry: a #GtkSecureEntry
2996
* Gets the value set by gtk_secure_entry_set_has_frame().
2998
* Return value: whether the entry has a beveled frame
3001
gtk_secure_entry_get_has_frame(GtkSecureEntry * entry)
3003
g_return_val_if_fail(GTK_IS_SECURE_ENTRY(entry), FALSE);
3005
return entry->has_frame;
3010
* gtk_secure_entry_get_layout:
3011
* @entry: a #GtkSecureEntry
3013
* Gets the #PangoLayout used to display the entry.
3014
* The layout is useful to e.g. convert text positions to
3015
* pixel positions, in combination with gtk_secure_entry_get_layout_offsets().
3016
* The returned layout is owned by the entry so need not be
3017
* freed by the caller.
3019
* Keep in mind that the layout text may contain a preedit string, so
3020
* gtk_secure_entry_layout_index_to_text_index() and
3021
* gtk_secure_entry_text_index_to_layout_index() are needed to convert byte
3022
* indices in the layout to byte indices in the entry contents.
3024
* Return value: the #PangoLayout for this entry
3027
gtk_secure_entry_get_layout(GtkSecureEntry * entry)
3029
PangoLayout *layout;
3031
g_return_val_if_fail(GTK_IS_SECURE_ENTRY(entry), NULL);
3033
layout = gtk_secure_entry_ensure_layout(entry, TRUE);
3040
* gtk_secure_entry_layout_index_to_text_index:
3041
* @entry: a #GtkSecureEntry
3042
* @layout_index: byte index into the entry layout text
3044
* Converts from a position in the entry contents (returned
3045
* by gtk_secure_entry_get_text()) to a position in the
3046
* entry's #PangoLayout (returned by gtk_secure_entry_get_layout(),
3047
* with text retrieved via pango_layout_get_text()).
3049
* Return value: byte index into the entry contents
3052
gtk_secure_entry_layout_index_to_text_index(GtkSecureEntry * entry,
3055
PangoLayout *layout;
3059
g_return_val_if_fail(GTK_IS_SECURE_ENTRY(entry), 0);
3061
layout = gtk_secure_entry_ensure_layout(entry, TRUE);
3062
text = pango_layout_get_text(layout);
3064
g_utf8_offset_to_pointer(text, entry->current_pos) - text;
3066
if (layout_index >= cursor_index && entry->preedit_length) {
3067
if (layout_index >= cursor_index + entry->preedit_length)
3068
layout_index -= entry->preedit_length;
3070
layout_index = cursor_index;
3073
return layout_index;
3077
* gtk_secure_entry_text_index_to_layout_index:
3078
* @entry: a #GtkSecureEntry
3079
* @text_index: byte index into the entry contents
3081
* Converts from a position in the entry's #PangoLayout(returned by
3082
* gtk_secure_entry_get_layout()) to a position in the entry contents
3083
* (returned by gtk_secure_entry_get_text()).
3085
* Return value: byte index into the entry layout text
3088
gtk_secure_entry_text_index_to_layout_index(GtkSecureEntry * entry,
3091
PangoLayout *layout;
3094
g_return_val_if_fail(GTK_IS_SECURE_ENTRY(entry), 0);
3096
layout = gtk_secure_entry_ensure_layout(entry, TRUE);
3097
text = pango_layout_get_text(layout);
3099
g_utf8_offset_to_pointer(text, entry->current_pos) - text;
3101
if (text_index > cursor_index)
3102
text_index += entry->preedit_length;
3108
* gtk_secure_entry_get_layout_offsets:
3109
* @entry: a #GtkSecureEntry
3110
* @x: location to store X offset of layout, or %NULL
3111
* @y: location to store Y offset of layout, or %NULL
3114
* Obtains the position of the #PangoLayout used to render text
3115
* in the entry, in widget coordinates. Useful if you want to line
3116
* up the text in an entry with some other text, e.g. when using the
3117
* entry to implement editable cells in a sheet widget.
3119
* Also useful to convert mouse events into coordinates inside the
3120
* #PangoLayout, e.g. to take some action if some part of the entry text
3123
* Note that as the user scrolls around in the entry the offsets will
3124
* change; you'll need to connect to the "notify::scroll_offset"
3125
* signal to track this. Remember when using the #PangoLayout
3126
* functions you need to convert to and from pixels using
3127
* PANGO_PIXELS() or #PANGO_SCALE.
3129
* Keep in mind that the layout text may contain a preedit string, so
3130
* gtk_secure_entry_layout_index_to_text_index() and
3131
* gtk_secure_entry_text_index_to_layout_index() are needed to convert byte
3132
* indices in the layout to byte indices in the entry contents.
3136
gtk_secure_entry_get_layout_offsets(GtkSecureEntry * entry,
3139
gint text_area_x, text_area_y;
3141
g_return_if_fail(GTK_IS_SECURE_ENTRY(entry));
3143
/* this gets coords relative to text area */
3144
get_layout_position(entry, x, y);
3146
/* convert to widget coords */
3147
get_text_area_size(entry, &text_area_x, &text_area_y, NULL, NULL);
3157
/* Quick hack of a popup menu
3160
activate_cb(GtkWidget * menuitem, GtkSecureEntry * entry)
3162
const gchar *signal =
3163
g_object_get_data(G_OBJECT(menuitem), "gtk-signal");
3164
g_signal_emit_by_name(entry, signal);
3169
gtk_secure_entry_mnemonic_activate(GtkWidget * widget,
3170
gboolean group_cycling)
3172
gtk_widget_grab_focus(widget);
3178
unichar_chosen_func(const char *text, gpointer data)
3180
GtkSecureEntry *entry = GTK_SECURE_ENTRY(data);
3182
gtk_secure_entry_enter_text(entry, text);
3185
/* We display the cursor when
3187
* - the selection is empty, AND
3188
* - the widget has focus
3191
#define CURSOR_ON_MULTIPLIER 0.66
3192
#define CURSOR_OFF_MULTIPLIER 0.34
3193
#define CURSOR_PEND_MULTIPLIER 1.0
3196
cursor_blinks(GtkSecureEntry * entry)
3198
GtkSettings *settings = gtk_widget_get_settings(GTK_WIDGET(entry));
3201
if (GTK_WIDGET_HAS_FOCUS(entry) &&
3202
entry->selection_bound == entry->current_pos) {
3203
g_object_get(settings, "gtk-cursor-blink", &blink, NULL);
3210
get_cursor_time(GtkSecureEntry * entry)
3212
GtkSettings *settings = gtk_widget_get_settings(GTK_WIDGET(entry));
3215
g_object_get(settings, "gtk-cursor-blink-time", &time, NULL);
3221
show_cursor(GtkSecureEntry * entry)
3223
if (!entry->cursor_visible) {
3224
entry->cursor_visible = TRUE;
3226
if (GTK_WIDGET_HAS_FOCUS(entry)
3227
&& entry->selection_bound == entry->current_pos)
3228
gtk_widget_queue_draw(GTK_WIDGET(entry));
3233
hide_cursor(GtkSecureEntry * entry)
3235
if (entry->cursor_visible) {
3236
entry->cursor_visible = FALSE;
3238
if (GTK_WIDGET_HAS_FOCUS(entry)
3239
&& entry->selection_bound == entry->current_pos)
3240
gtk_widget_queue_draw(GTK_WIDGET(entry));
3248
blink_cb(gpointer data)
3250
GtkSecureEntry *entry;
3252
GDK_THREADS_ENTER();
3254
entry = GTK_SECURE_ENTRY(data);
3256
if (!GTK_WIDGET_HAS_FOCUS(entry)) {
3258
("GtkSecureEntry - did not receive focus-out-event. If you\n"
3259
"connect a handler to this signal, it must return\n"
3260
"FALSE so the entry gets the event as well");
3263
g_assert(GTK_WIDGET_HAS_FOCUS(entry));
3264
g_assert(entry->selection_bound == entry->current_pos);
3266
if (entry->cursor_visible) {
3268
entry->blink_timeout =
3269
g_timeout_add(get_cursor_time(entry) * CURSOR_OFF_MULTIPLIER,
3273
entry->blink_timeout =
3274
g_timeout_add(get_cursor_time(entry) * CURSOR_ON_MULTIPLIER,
3278
GDK_THREADS_LEAVE();
3280
/* Remove ourselves */
3285
gtk_secure_entry_check_cursor_blink(GtkSecureEntry * entry)
3287
if (cursor_blinks(entry)) {
3288
if (!entry->blink_timeout) {
3289
entry->blink_timeout =
3290
g_timeout_add(get_cursor_time(entry) *
3291
CURSOR_ON_MULTIPLIER, blink_cb, entry);
3295
if (entry->blink_timeout) {
3296
g_source_remove(entry->blink_timeout);
3297
entry->blink_timeout = 0;
3300
entry->cursor_visible = TRUE;
3306
gtk_secure_entry_pend_cursor_blink(GtkSecureEntry * entry)
3308
if (cursor_blinks(entry)) {
3309
if (entry->blink_timeout != 0)
3310
g_source_remove(entry->blink_timeout);
3312
entry->blink_timeout =
3313
g_timeout_add(get_cursor_time(entry) * CURSOR_PEND_MULTIPLIER,
3319
static inline gboolean
3320
keyval_is_cursor_move(guint keyval)
3322
if (keyval == GDK_Up || keyval == GDK_KP_Up)
3325
if (keyval == GDK_Down || keyval == GDK_KP_Down)
3328
if (keyval == GDK_Page_Up)
3331
if (keyval == GDK_Page_Down)
3337
/* stolen from gtkmarshalers.c */
3339
#define g_marshal_value_peek_enum(v) (v)->data[0].v_int
3340
#define g_marshal_value_peek_int(v) (v)->data[0].v_int
3341
#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
3343
/* VOID:ENUM,INT,BOOLEAN (gtkmarshalers.list:64) */
3345
_gtk_marshal_VOID__ENUM_INT_BOOLEAN(GClosure * closure,
3346
GValue * return_value,
3347
guint n_param_values,
3348
const GValue * param_values,
3349
gpointer invocation_hint,
3350
gpointer marshal_data)
3352
typedef void (*GMarshalFunc_VOID__ENUM_INT_BOOLEAN) (gpointer data1,
3357
register GMarshalFunc_VOID__ENUM_INT_BOOLEAN callback;
3358
register GCClosure *cc = (GCClosure *) closure;
3359
register gpointer data1, data2;
3361
g_return_if_fail(n_param_values == 4);
3363
if (G_CCLOSURE_SWAP_DATA(closure)) {
3364
data1 = closure->data;
3365
data2 = g_value_peek_pointer(param_values + 0);
3367
data1 = g_value_peek_pointer(param_values + 0);
3368
data2 = closure->data;
3371
(GMarshalFunc_VOID__ENUM_INT_BOOLEAN) (marshal_data ? marshal_data
3375
g_marshal_value_peek_enum(param_values + 1),
3376
g_marshal_value_peek_int(param_values + 2),
3377
g_marshal_value_peek_boolean(param_values + 3), data2);
3381
_gtk_marshal_VOID__ENUM_INT(GClosure * closure,
3382
GValue * return_value,
3383
guint n_param_values,
3384
const GValue * param_values,
3385
gpointer invocation_hint,
3386
gpointer marshal_data)
3388
typedef void (*GMarshalFunc_VOID__ENUM_INT) (gpointer data1,
3392
register GMarshalFunc_VOID__ENUM_INT callback;
3393
register GCClosure *cc = (GCClosure *) closure;
3394
register gpointer data1, data2;
3396
g_return_if_fail(n_param_values == 3);
3398
if (G_CCLOSURE_SWAP_DATA(closure)) {
3399
data1 = closure->data;
3400
data2 = g_value_peek_pointer(param_values + 0);
3402
data1 = g_value_peek_pointer(param_values + 0);
3403
data2 = closure->data;
3406
(GMarshalFunc_VOID__ENUM_INT) (marshal_data ? marshal_data : cc->
3410
g_marshal_value_peek_enum(param_values + 1),
3411
g_marshal_value_peek_int(param_values + 2), data2);