1
/* GTK - The GIMP Toolkit
2
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4
* This library is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Library General Public
6
* License as published by the Free Software Foundation; either
7
* version 2 of the License, or (at your option) any later version.
9
* This library is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Library General Public License for more details.
14
* You should have received a copy of the GNU Library General Public
15
* License along with this library; if not, write to the
16
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17
* Boston, MA 02111-1307, USA.
21
* Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
22
* file for a list of people on the GTK+ Team. See the ChangeLog
23
* files for a list of changes. These files are distributed with
24
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
28
* Further modified by robbe to form GtkSecureEntry
32
* text_length: unclassified, can be seen on the screen (should that change??)
33
* char_offsets: unclassified, because it only gives the stars' offsets
34
* (which makes it pretty pointless, anyway)
35
* text_mb: classified (essentially the same as text)
41
#include <gdk/gdkkeysyms.h>
42
#include <gdk/gdki18n.h>
43
#include <gtk/gtkmain.h>
44
#include <gtk/gtkselection.h>
45
#include <gtk/gtksignal.h>
46
#include <gtk/gtkstyle.h>
47
#include "gtksecentry.h"
50
#define MIN_SECURE_ENTRY_WIDTH 150
51
#define DRAW_TIMEOUT 20
52
#define INNER_BORDER 2
61
static void gtk_secure_entry_class_init (GtkSecureEntryClass *klass);
62
static void gtk_secure_entry_init (GtkSecureEntry *entry);
63
static void gtk_secure_entry_set_arg (GtkObject *object,
66
static void gtk_secure_entry_get_arg (GtkObject *object,
69
static void gtk_secure_entry_finalize (GtkObject *object);
70
static void gtk_secure_entry_realize (GtkWidget *widget);
71
static void gtk_secure_entry_unrealize (GtkWidget *widget);
72
static void gtk_secure_entry_draw_focus (GtkWidget *widget);
73
static void gtk_secure_entry_size_request (GtkWidget *widget,
74
GtkRequisition *requisition);
75
static void gtk_secure_entry_size_allocate (GtkWidget *widget,
76
GtkAllocation *allocation);
77
static void gtk_secure_entry_make_backing_pixmap (GtkSecureEntry *entry,
78
gint width, gint height);
79
static void gtk_secure_entry_draw (GtkWidget *widget,
81
static gint gtk_secure_entry_expose (GtkWidget *widget,
82
GdkEventExpose *event);
83
static gint gtk_secure_entry_button_press (GtkWidget *widget,
84
GdkEventButton *event);
85
static gint gtk_secure_entry_button_release (GtkWidget *widget,
86
GdkEventButton *event);
87
static gint gtk_secure_entry_motion_notify (GtkWidget *widget,
88
GdkEventMotion *event);
89
static gint gtk_secure_entry_key_press (GtkWidget *widget,
91
static gint gtk_secure_entry_focus_in (GtkWidget *widget,
92
GdkEventFocus *event);
93
static gint gtk_secure_entry_focus_out (GtkWidget *widget,
94
GdkEventFocus *event);
95
static void gtk_secure_entry_draw_text (GtkSecureEntry *entry);
96
static void gtk_secure_entry_draw_cursor (GtkSecureEntry *entry);
97
static void gtk_secure_entry_draw_cursor_on_drawable
98
(GtkSecureEntry *entry,
99
GdkDrawable *drawable);
100
static void gtk_secure_entry_style_set (GtkWidget *widget,
101
GtkStyle *previous_style);
102
static void gtk_secure_entry_state_changed (GtkWidget *widget,
103
GtkStateType previous_state);
105
static void gtk_secure_entry_update_ic_attr (GtkWidget *widget);
107
static void gtk_secure_entry_queue_draw (GtkSecureEntry *entry);
108
static gint gtk_secure_entry_timer (gpointer data);
109
static gint gtk_secure_entry_position (GtkSecureEntry *entry,
111
static void entry_adjust_scroll (GtkSecureEntry *entry);
112
static void gtk_secure_entry_grow_text (GtkSecureEntry *entry);
113
static void gtk_secure_entry_insert_text (GtkEditable *editable,
114
const gchar *new_text,
115
gint new_text_length,
117
static void gtk_secure_entry_delete_text (GtkEditable *editable,
120
static void gtk_secure_entry_update_text (GtkEditable *editable,
123
static gchar *gtk_secure_entry_get_chars (GtkEditable *editable,
127
/* Binding actions */
128
static void gtk_secure_entry_move_cursor (GtkEditable *editable,
131
static void gtk_secure_entry_move_word (GtkEditable *editable,
133
static void gtk_secure_entry_move_to_column (GtkEditable *editable,
135
static void gtk_secure_entry_kill_char (GtkEditable *editable,
137
static void gtk_secure_entry_kill_word (GtkEditable *editable,
139
static void gtk_secure_entry_kill_line (GtkEditable *editable,
143
static void gtk_move_forward_character (GtkSecureEntry *entry);
144
static void gtk_move_backward_character (GtkSecureEntry *entry);
145
static void gtk_move_forward_word (GtkSecureEntry *entry);
146
static void gtk_move_backward_word (GtkSecureEntry *entry);
147
static void gtk_move_beginning_of_line (GtkSecureEntry *entry);
148
static void gtk_move_end_of_line (GtkSecureEntry *entry);
149
static void gtk_delete_forward_character (GtkSecureEntry *entry);
150
static void gtk_delete_backward_character (GtkSecureEntry *entry);
151
static void gtk_delete_forward_word (GtkSecureEntry *entry);
152
static void gtk_delete_backward_word (GtkSecureEntry *entry);
153
static void gtk_delete_line (GtkSecureEntry *entry);
154
static void gtk_delete_to_line_end (GtkSecureEntry *entry);
155
static void gtk_select_word (GtkSecureEntry *entry,
157
static void gtk_select_line (GtkSecureEntry *entry,
161
static void gtk_secure_entry_set_selection (GtkEditable *editable,
165
static void gtk_secure_entry_recompute_offsets (GtkSecureEntry *entry);
166
static gint gtk_secure_entry_find_position (GtkSecureEntry *entry,
168
static void gtk_secure_entry_set_position_from_editable (GtkEditable *editable,
171
static GtkWidgetClass *parent_class = NULL;
172
static GdkAtom ctext_atom = GDK_NONE;
174
static const GtkTextFunction control_keys[26] =
176
(GtkTextFunction)gtk_move_beginning_of_line, /* a */
177
(GtkTextFunction)gtk_move_backward_character, /* b */
178
(GtkTextFunction)gtk_editable_copy_clipboard, /* c */
179
(GtkTextFunction)gtk_delete_forward_character, /* d */
180
(GtkTextFunction)gtk_move_end_of_line, /* e */
181
(GtkTextFunction)gtk_move_forward_character, /* f */
183
(GtkTextFunction)gtk_delete_backward_character, /* h */
186
(GtkTextFunction)gtk_delete_to_line_end, /* k */
196
(GtkTextFunction)gtk_delete_line, /* u */
197
(GtkTextFunction)gtk_editable_paste_clipboard, /* v */
198
(GtkTextFunction)gtk_delete_backward_word, /* w */
199
(GtkTextFunction)gtk_editable_cut_clipboard, /* x */
204
static const GtkTextFunction alt_keys[26] =
207
(GtkTextFunction)gtk_move_backward_word, /* b */
209
(GtkTextFunction)gtk_delete_forward_word, /* d */
211
(GtkTextFunction)gtk_move_forward_word, /* f */
234
gboolean g_use_secure_mem = FALSE;
236
# define g_sec_new(type, count) \
237
((type *) g_sec_malloc ((unsigned) sizeof (type) * (count)))
239
#define WITH_SECURE_MEM(EXP) do { \
240
gboolean tmp = g_use_secure_mem; \
241
g_use_secure_mem = TRUE; \
243
g_use_secure_mem = tmp; \
247
g_malloc (gulong size)
254
if (g_use_secure_mem)
255
p = (gpointer) secmem_malloc(size);
257
p = (gpointer) malloc (size);
259
g_error ("could not allocate %ld bytes", size);
265
g_malloc0 (gulong size)
272
if (g_use_secure_mem) {
273
p = (gpointer) secmem_malloc(size);
277
p = (gpointer) calloc (size, 1);
279
g_error ("could not allocate %ld bytes", size);
285
g_realloc (gpointer mem,
299
if (g_use_secure_mem)
300
p = (gpointer) secmem_malloc (size);
302
p = (gpointer) malloc (size);
306
if (g_use_secure_mem) {
307
g_assert(m_is_secure(mem));
308
p = (gpointer) secmem_realloc (mem, size);
310
p = (gpointer) realloc (mem, size);
314
g_error ("could not reallocate %lu bytes", (gulong) size);
320
g_free (gpointer mem)
324
if (m_is_secure(mem))
332
gtk_secure_entry_get_type (void)
334
static GtkType entry_type = 0;
338
static const GtkTypeInfo entry_info =
341
sizeof (GtkSecureEntry),
342
sizeof (GtkSecureEntryClass),
343
(GtkClassInitFunc) gtk_secure_entry_class_init,
344
(GtkObjectInitFunc) gtk_secure_entry_init,
345
/* reserved_1 */ NULL,
346
/* reserved_2 */ NULL,
347
(GtkClassInitFunc) NULL,
350
entry_type = gtk_type_unique (GTK_TYPE_EDITABLE, &entry_info);
357
gtk_secure_entry_class_init (GtkSecureEntryClass *class)
359
GtkObjectClass *object_class;
360
GtkWidgetClass *widget_class;
361
GtkEditableClass *editable_class;
363
object_class = (GtkObjectClass*) class;
364
widget_class = (GtkWidgetClass*) class;
365
editable_class = (GtkEditableClass*) class;
366
parent_class = gtk_type_class (GTK_TYPE_EDITABLE);
368
gtk_object_add_arg_type ("GtkSecureEntry::max_length", GTK_TYPE_UINT, GTK_ARG_READWRITE, ARG_MAX_LENGTH);
369
gtk_object_add_arg_type ("GtkSecureEntry::visibility", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_VISIBILITY);
371
object_class->set_arg = gtk_secure_entry_set_arg;
372
object_class->get_arg = gtk_secure_entry_get_arg;
373
object_class->finalize = gtk_secure_entry_finalize;
375
widget_class->realize = gtk_secure_entry_realize;
376
widget_class->unrealize = gtk_secure_entry_unrealize;
377
widget_class->draw_focus = gtk_secure_entry_draw_focus;
378
widget_class->size_request = gtk_secure_entry_size_request;
379
widget_class->size_allocate = gtk_secure_entry_size_allocate;
380
widget_class->draw = gtk_secure_entry_draw;
381
widget_class->expose_event = gtk_secure_entry_expose;
382
widget_class->button_press_event = gtk_secure_entry_button_press;
383
widget_class->button_release_event = gtk_secure_entry_button_release;
384
widget_class->motion_notify_event = gtk_secure_entry_motion_notify;
385
widget_class->key_press_event = gtk_secure_entry_key_press;
386
widget_class->focus_in_event = gtk_secure_entry_focus_in;
387
widget_class->focus_out_event = gtk_secure_entry_focus_out;
388
widget_class->style_set = gtk_secure_entry_style_set;
389
widget_class->state_changed = gtk_secure_entry_state_changed;
391
editable_class->insert_text = gtk_secure_entry_insert_text;
392
editable_class->delete_text = gtk_secure_entry_delete_text;
393
editable_class->changed = (void (*)(GtkEditable *)) entry_adjust_scroll;
395
editable_class->move_cursor = gtk_secure_entry_move_cursor;
396
editable_class->move_word = gtk_secure_entry_move_word;
397
editable_class->move_to_column = gtk_secure_entry_move_to_column;
399
editable_class->kill_char = gtk_secure_entry_kill_char;
400
editable_class->kill_word = gtk_secure_entry_kill_word;
401
editable_class->kill_line = gtk_secure_entry_kill_line;
403
editable_class->update_text = gtk_secure_entry_update_text;
404
editable_class->get_chars = gtk_secure_entry_get_chars;
405
editable_class->set_selection = gtk_secure_entry_set_selection;
406
editable_class->set_position = gtk_secure_entry_set_position_from_editable;
410
gtk_secure_entry_set_arg (GtkObject *object,
414
GtkSecureEntry *entry;
416
entry = GTK_SECURE_ENTRY (object);
421
gtk_secure_entry_set_max_length (entry, GTK_VALUE_UINT (*arg));
424
gtk_secure_entry_set_visibility (entry, GTK_VALUE_BOOL (*arg));
432
gtk_secure_entry_get_arg (GtkObject *object,
436
GtkSecureEntry *entry;
438
entry = GTK_SECURE_ENTRY (object);
443
GTK_VALUE_UINT (*arg) = entry->text_max_length;
446
GTK_VALUE_BOOL (*arg) = GTK_EDITABLE (entry)->visible;
449
arg->type = GTK_TYPE_INVALID;
455
gtk_secure_entry_init (GtkSecureEntry *entry)
457
GTK_WIDGET_SET_FLAGS (entry, GTK_CAN_FOCUS);
459
entry->text_area = NULL;
460
entry->backing_pixmap = NULL;
462
entry->text_size = 0;
463
entry->text_length = 0;
464
entry->text_max_length = 0;
465
entry->scroll_offset = 0;
470
entry->char_offset = NULL;
471
entry->text_mb = NULL;
472
entry->text_mb_dirty = TRUE;
473
entry->use_wchar = FALSE;
475
gtk_secure_entry_grow_text (entry);
479
gtk_secure_entry_new (void)
481
return GTK_WIDGET (gtk_type_new (GTK_TYPE_SECURE_ENTRY));
485
gtk_secure_entry_new_with_max_length (guint16 max)
487
GtkSecureEntry *entry;
489
entry = gtk_type_new (GTK_TYPE_SECURE_ENTRY);
490
entry->text_max_length = max;
492
return GTK_WIDGET (entry);
496
gtk_secure_entry_set_text (GtkSecureEntry *entry,
501
GtkEditable *editable;
503
g_return_if_fail (entry != NULL);
504
g_return_if_fail (GTK_IS_SECURE_ENTRY (entry));
505
g_return_if_fail (text != NULL);
507
editable = GTK_EDITABLE (entry);
509
gtk_secure_entry_delete_text (GTK_EDITABLE(entry), 0, entry->text_length);
512
gtk_secure_entry_insert_text (editable, text, strlen (text), &tmp_pos);
513
editable->current_pos = tmp_pos;
515
editable->selection_start_pos = 0;
516
editable->selection_end_pos = 0;
518
if (GTK_WIDGET_DRAWABLE (entry))
519
gtk_secure_entry_draw_text (entry);
523
gtk_secure_entry_append_text (GtkSecureEntry *entry,
528
g_return_if_fail (entry != NULL);
529
g_return_if_fail (GTK_IS_SECURE_ENTRY (entry));
530
g_return_if_fail (text != NULL);
532
tmp_pos = entry->text_length;
533
gtk_secure_entry_insert_text (GTK_EDITABLE(entry), text, strlen (text), &tmp_pos);
534
GTK_EDITABLE(entry)->current_pos = tmp_pos;
538
gtk_secure_entry_prepend_text (GtkSecureEntry *entry,
543
g_return_if_fail (entry != NULL);
544
g_return_if_fail (GTK_IS_SECURE_ENTRY (entry));
545
g_return_if_fail (text != NULL);
548
gtk_secure_entry_insert_text (GTK_EDITABLE(entry), text, strlen (text), &tmp_pos);
549
GTK_EDITABLE(entry)->current_pos = tmp_pos;
553
gtk_secure_entry_set_position (GtkSecureEntry *entry,
556
g_return_if_fail (entry != NULL);
557
g_return_if_fail (GTK_IS_SECURE_ENTRY (entry));
559
if ((position == -1) || (position > entry->text_length))
560
GTK_EDITABLE(entry)->current_pos = entry->text_length;
562
GTK_EDITABLE(entry)->current_pos = position;
563
entry_adjust_scroll (entry);
567
gtk_secure_entry_set_position_from_editable (GtkEditable *editable,
570
gtk_secure_entry_set_position (GTK_SECURE_ENTRY (editable), position);
574
gtk_secure_entry_set_visibility (GtkSecureEntry *entry,
577
g_return_if_fail (entry != NULL);
578
g_return_if_fail (GTK_IS_SECURE_ENTRY (entry));
580
entry->visible = visible ? TRUE : FALSE;
581
GTK_EDITABLE (entry)->visible = visible ? TRUE : FALSE;
582
gtk_secure_entry_recompute_offsets (entry);
583
gtk_widget_queue_draw (GTK_WIDGET (entry));
587
gtk_secure_entry_set_editable(GtkSecureEntry *entry,
590
g_return_if_fail (entry != NULL);
591
g_return_if_fail (GTK_IS_SECURE_ENTRY (entry));
593
gtk_editable_set_editable (GTK_EDITABLE (entry), editable);
597
gtk_secure_entry_get_text (GtkSecureEntry *entry)
599
g_return_val_if_fail (entry != NULL, NULL);
600
g_return_val_if_fail (GTK_IS_SECURE_ENTRY (entry), NULL);
602
if (!entry->text_mb_dirty)
603
return entry->text_mb;
606
WITH_SECURE_MEM(g_free(entry->text_mb));
610
WITH_SECURE_MEM(entry->text_mb = g_new(gchar, 1));
611
entry->text_mb[0] = 0;
615
entry->text_mb = gtk_secure_entry_get_chars(GTK_EDITABLE(entry), 0, -1);
617
entry->text_mb_dirty = 0;
619
return entry->text_mb;
623
gtk_secure_entry_finalize (GtkObject *object)
625
GtkSecureEntry *entry;
627
g_return_if_fail (object != NULL);
628
g_return_if_fail (GTK_IS_SECURE_ENTRY (object));
630
entry = GTK_SECURE_ENTRY (object);
633
gtk_timeout_remove (entry->timer);
635
entry->text_size = 0;
638
WITH_SECURE_MEM(g_free (entry->text));
639
if (entry->char_offset)
640
g_free (entry->char_offset);
644
WITH_SECURE_MEM(g_free (entry->text_mb));
645
entry->text_mb = NULL;
647
if (entry->backing_pixmap)
648
gdk_pixmap_unref (entry->backing_pixmap);
650
(* GTK_OBJECT_CLASS (parent_class)->finalize) (object);
654
gtk_secure_entry_realize (GtkWidget *widget)
656
GtkSecureEntry *entry;
657
GtkEditable *editable;
658
GtkRequisition requisition;
659
GdkWindowAttr attributes;
660
gint attributes_mask;
662
g_return_if_fail (widget != NULL);
663
g_return_if_fail (GTK_IS_SECURE_ENTRY (widget));
665
GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
666
entry = GTK_SECURE_ENTRY (widget);
667
editable = GTK_EDITABLE (widget);
669
gtk_widget_get_child_requisition (widget, &requisition);
671
attributes.window_type = GDK_WINDOW_CHILD;
672
attributes.x = widget->allocation.x;
673
attributes.y = widget->allocation.y + (widget->allocation.height -
674
requisition.height) / 2;
675
attributes.width = widget->allocation.width;
676
attributes.height = requisition.height;
677
attributes.wclass = GDK_INPUT_OUTPUT;
678
attributes.visual = gtk_widget_get_visual (widget);
679
attributes.colormap = gtk_widget_get_colormap (widget);
680
attributes.event_mask = gtk_widget_get_events (widget);
681
attributes.event_mask |= (GDK_EXPOSURE_MASK |
682
GDK_BUTTON_PRESS_MASK |
683
GDK_BUTTON_RELEASE_MASK |
684
GDK_BUTTON1_MOTION_MASK |
685
GDK_BUTTON3_MOTION_MASK |
686
GDK_POINTER_MOTION_HINT_MASK |
687
GDK_ENTER_NOTIFY_MASK |
688
GDK_LEAVE_NOTIFY_MASK |
690
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
692
widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
693
gdk_window_set_user_data (widget->window, entry);
695
attributes.x = widget->style->klass->xthickness;
696
attributes.y = widget->style->klass->ythickness;
697
attributes.width = widget->allocation.width - attributes.x * 2;
698
attributes.height = requisition.height - attributes.y * 2;
699
attributes.cursor = entry->cursor = gdk_cursor_new (GDK_XTERM);
700
attributes_mask |= GDK_WA_CURSOR;
702
entry->text_area = gdk_window_new (widget->window, &attributes, attributes_mask);
703
gdk_window_set_user_data (entry->text_area, entry);
705
widget->style = gtk_style_attach (widget->style, widget->window);
707
gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
708
gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
711
if (gdk_im_ready () && (editable->ic_attr = gdk_ic_attr_new ()) != NULL)
715
GdkColormap *colormap;
716
GdkICAttr *attr = editable->ic_attr;
717
GdkICAttributesType attrmask = GDK_IC_ALL_REQ;
719
GdkIMStyle supported_style = GDK_IM_PREEDIT_NONE |
720
GDK_IM_PREEDIT_NOTHING |
721
GDK_IM_PREEDIT_POSITION |
723
GDK_IM_STATUS_NOTHING;
725
if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
726
supported_style &= ~GDK_IM_PREEDIT_POSITION;
728
attr->style = style = gdk_im_decide_style (supported_style);
729
attr->client_window = entry->text_area;
731
if ((colormap = gtk_widget_get_colormap (widget)) !=
732
gtk_widget_get_default_colormap ())
734
attrmask |= GDK_IC_PREEDIT_COLORMAP;
735
attr->preedit_colormap = colormap;
737
attrmask |= GDK_IC_PREEDIT_FOREGROUND;
738
attrmask |= GDK_IC_PREEDIT_BACKGROUND;
739
attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
740
attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
742
switch (style & GDK_IM_PREEDIT_MASK)
744
case GDK_IM_PREEDIT_POSITION:
745
if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
747
g_warning ("over-the-spot style requires fontset");
751
gdk_window_get_size (entry->text_area, &width, &height);
753
attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
754
attr->spot_location.x = 0;
755
attr->spot_location.y = height;
756
attr->preedit_area.x = 0;
757
attr->preedit_area.y = 0;
758
attr->preedit_area.width = width;
759
attr->preedit_area.height = height;
760
attr->preedit_fontset = widget->style->font;
764
editable->ic = gdk_ic_new (attr, attrmask);
766
if (editable->ic == NULL)
767
g_warning ("Can't create input context.");
770
mask = gdk_window_get_events (entry->text_area);
771
mask |= gdk_ic_get_events (editable->ic);
772
gdk_window_set_events (entry->text_area, mask);
774
if (GTK_WIDGET_HAS_FOCUS(widget))
775
gdk_im_begin (editable->ic, entry->text_area);
780
gdk_window_show (entry->text_area);
782
if (editable->selection_start_pos != editable->selection_end_pos)
783
gtk_editable_claim_selection (editable, TRUE, GDK_CURRENT_TIME);
785
gtk_secure_entry_recompute_offsets (entry);
789
gtk_secure_entry_unrealize (GtkWidget *widget)
791
GtkSecureEntry *entry;
793
g_return_if_fail (widget != NULL);
794
g_return_if_fail (GTK_IS_SECURE_ENTRY (widget));
796
entry = GTK_SECURE_ENTRY (widget);
799
if (GTK_EDITABLE (widget)->ic)
801
gdk_ic_destroy (GTK_EDITABLE (widget)->ic);
802
GTK_EDITABLE (widget)->ic = NULL;
804
if (GTK_EDITABLE (widget)->ic_attr)
806
gdk_ic_attr_destroy (GTK_EDITABLE (widget)->ic_attr);
807
GTK_EDITABLE (widget)->ic_attr = NULL;
811
if (entry->text_area)
813
gdk_window_set_user_data (entry->text_area, NULL);
814
gdk_window_destroy (entry->text_area);
815
entry->text_area = NULL;
816
gdk_cursor_destroy (entry->cursor);
817
entry->cursor = NULL;
820
if (GTK_WIDGET_CLASS (parent_class)->unrealize)
821
(* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
825
gtk_secure_entry_draw_focus (GtkWidget *widget)
830
g_return_if_fail (widget != NULL);
831
g_return_if_fail (GTK_IS_SECURE_ENTRY (widget));
833
if (GTK_WIDGET_DRAWABLE (widget))
837
gdk_window_get_size (widget->window, &width, &height);
839
if (GTK_WIDGET_HAS_FOCUS (widget))
847
gtk_paint_shadow (widget->style, widget->window,
848
GTK_STATE_NORMAL, GTK_SHADOW_IN,
849
NULL, widget, "entry",
850
x, y, width, height);
852
if (GTK_WIDGET_HAS_FOCUS (widget))
854
gdk_window_get_size (widget->window, &width, &height);
855
gtk_paint_focus (widget->style, widget->window,
856
NULL, widget, "entry",
857
0, 0, width - 1, height - 1);
860
if (GTK_EDITABLE (widget)->editable)
861
gtk_secure_entry_draw_cursor (GTK_SECURE_ENTRY (widget));
866
gtk_secure_entry_size_request (GtkWidget *widget,
867
GtkRequisition *requisition)
869
g_return_if_fail (widget != NULL);
870
g_return_if_fail (GTK_IS_SECURE_ENTRY (widget));
871
g_return_if_fail (requisition != NULL);
873
requisition->width = MIN_SECURE_ENTRY_WIDTH + (widget->style->klass->xthickness + INNER_BORDER) * 2;
874
requisition->height = (widget->style->font->ascent +
875
widget->style->font->descent +
876
(widget->style->klass->ythickness + INNER_BORDER) * 2);
880
gtk_secure_entry_size_allocate (GtkWidget *widget,
881
GtkAllocation *allocation)
883
GtkSecureEntry *entry;
884
GtkEditable *editable;
886
g_return_if_fail (widget != NULL);
887
g_return_if_fail (GTK_IS_SECURE_ENTRY (widget));
888
g_return_if_fail (allocation != NULL);
890
widget->allocation = *allocation;
891
entry = GTK_SECURE_ENTRY (widget);
892
editable = GTK_EDITABLE (widget);
894
if (GTK_WIDGET_REALIZED (widget))
896
/* We call gtk_widget_get_child_requisition, since we want (for
897
* backwards compatibility reasons) the realization here to
898
* be affected by the usize of the entry, if set
900
GtkRequisition requisition;
901
gtk_widget_get_child_requisition (widget, &requisition);
903
gdk_window_move_resize (widget->window,
905
allocation->y + (allocation->height - requisition.height) / 2,
906
allocation->width, requisition.height);
907
gdk_window_move_resize (entry->text_area,
908
widget->style->klass->xthickness,
909
widget->style->klass->ythickness,
910
allocation->width - widget->style->klass->xthickness * 2,
911
requisition.height - widget->style->klass->ythickness * 2);
913
/* And make sure the cursor is on screen */
914
entry_adjust_scroll (entry);
918
(gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION))
922
gdk_window_get_size (entry->text_area, &width, &height);
923
editable->ic_attr->preedit_area.width = width;
924
editable->ic_attr->preedit_area.height = height;
925
gdk_ic_set_attr (editable->ic, editable->ic_attr,
926
GDK_IC_PREEDIT_AREA);
933
gtk_secure_entry_draw (GtkWidget *widget,
936
g_return_if_fail (widget != NULL);
937
g_return_if_fail (GTK_IS_SECURE_ENTRY (widget));
938
g_return_if_fail (area != NULL);
940
if (GTK_WIDGET_DRAWABLE (widget))
942
gtk_widget_draw_focus (widget);
943
gtk_secure_entry_draw_text (GTK_SECURE_ENTRY (widget));
948
gtk_secure_entry_expose (GtkWidget *widget,
949
GdkEventExpose *event)
951
GtkSecureEntry *entry;
953
g_return_val_if_fail (widget != NULL, FALSE);
954
g_return_val_if_fail (GTK_IS_SECURE_ENTRY (widget), FALSE);
955
g_return_val_if_fail (event != NULL, FALSE);
957
entry = GTK_SECURE_ENTRY (widget);
959
if (widget->window == event->window)
960
gtk_widget_draw_focus (widget);
961
else if (entry->text_area == event->window)
962
gtk_secure_entry_draw_text (GTK_SECURE_ENTRY (widget));
968
gtk_secure_entry_button_press (GtkWidget *widget,
969
GdkEventButton *event)
971
GtkSecureEntry *entry;
972
GtkEditable *editable;
975
g_return_val_if_fail (widget != NULL, FALSE);
976
g_return_val_if_fail (GTK_IS_SECURE_ENTRY (widget), FALSE);
977
g_return_val_if_fail (event != NULL, FALSE);
979
if (ctext_atom == GDK_NONE)
980
ctext_atom = gdk_atom_intern ("COMPOUND_TEXT", FALSE);
982
entry = GTK_SECURE_ENTRY (widget);
983
editable = GTK_EDITABLE (widget);
985
if (entry->button && (event->button != entry->button))
988
entry->button = event->button;
990
if (!GTK_WIDGET_HAS_FOCUS (widget))
991
gtk_widget_grab_focus (widget);
993
if (event->button == 1)
997
case GDK_BUTTON_PRESS:
998
gtk_grab_add (widget);
1000
tmp_pos = gtk_secure_entry_position (entry, event->x + entry->scroll_offset);
1001
/* Set it now, so we display things right. We'll unset it
1002
* later if things don't work out */
1003
editable->has_selection = TRUE;
1004
gtk_secure_entry_set_selection (editable, tmp_pos, tmp_pos);
1005
editable->current_pos = editable->selection_start_pos;
1008
case GDK_2BUTTON_PRESS:
1009
gtk_select_word (entry, event->time);
1012
case GDK_3BUTTON_PRESS:
1013
gtk_select_line (entry, event->time);
1020
else if (event->type == GDK_BUTTON_PRESS)
1022
if ((event->button == 2) && editable->editable)
1024
if (editable->selection_start_pos == editable->selection_end_pos ||
1025
editable->has_selection)
1026
editable->current_pos = gtk_secure_entry_position (entry, event->x + entry->scroll_offset);
1027
gtk_selection_convert (widget, GDK_SELECTION_PRIMARY,
1028
ctext_atom, event->time);
1032
gtk_grab_add (widget);
1034
tmp_pos = gtk_secure_entry_position (entry, event->x + entry->scroll_offset);
1035
gtk_secure_entry_set_selection (editable, tmp_pos, tmp_pos);
1036
editable->has_selection = FALSE;
1037
editable->current_pos = editable->selection_start_pos;
1039
if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
1040
gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time);
1048
gtk_secure_entry_button_release (GtkWidget *widget,
1049
GdkEventButton *event)
1051
GtkSecureEntry *entry;
1052
GtkEditable *editable;
1054
g_return_val_if_fail (widget != NULL, FALSE);
1055
g_return_val_if_fail (GTK_IS_SECURE_ENTRY (widget), FALSE);
1056
g_return_val_if_fail (event != NULL, FALSE);
1058
entry = GTK_SECURE_ENTRY (widget);
1059
editable = GTK_EDITABLE (widget);
1061
if (entry->button != event->button)
1066
if (event->button == 1)
1068
gtk_grab_remove (widget);
1070
editable->has_selection = FALSE;
1071
if (editable->selection_start_pos != editable->selection_end_pos)
1073
if (gtk_selection_owner_set (widget,
1074
GDK_SELECTION_PRIMARY,
1076
editable->has_selection = TRUE;
1078
gtk_secure_entry_queue_draw (entry);
1082
if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
1083
gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY, event->time);
1086
else if (event->button == 3)
1088
gtk_grab_remove (widget);
1095
gtk_secure_entry_motion_notify (GtkWidget *widget,
1096
GdkEventMotion *event)
1098
GtkSecureEntry *entry;
1101
g_return_val_if_fail (widget != NULL, FALSE);
1102
g_return_val_if_fail (GTK_IS_SECURE_ENTRY (widget), FALSE);
1103
g_return_val_if_fail (event != NULL, FALSE);
1105
entry = GTK_SECURE_ENTRY (widget);
1107
if (entry->button == 0)
1111
if (event->is_hint || (entry->text_area != event->window))
1112
gdk_window_get_pointer (entry->text_area, &x, NULL, NULL);
1114
GTK_EDITABLE(entry)->selection_end_pos = gtk_secure_entry_position (entry, x + entry->scroll_offset);
1115
GTK_EDITABLE(entry)->current_pos = GTK_EDITABLE(entry)->selection_end_pos;
1116
entry_adjust_scroll (entry);
1117
gtk_secure_entry_queue_draw (entry);
1123
gtk_secure_entry_key_press (GtkWidget *widget,
1126
GtkSecureEntry *entry;
1127
GtkEditable *editable;
1132
gint extend_selection;
1135
g_return_val_if_fail (widget != NULL, FALSE);
1136
g_return_val_if_fail (GTK_IS_SECURE_ENTRY (widget), FALSE);
1137
g_return_val_if_fail (event != NULL, FALSE);
1139
entry = GTK_SECURE_ENTRY (widget);
1140
editable = GTK_EDITABLE (widget);
1143
if(editable->editable == FALSE)
1146
initial_pos = editable->current_pos;
1148
extend_selection = event->state & GDK_SHIFT_MASK;
1149
extend_start = FALSE;
1151
if (extend_selection)
1153
if (editable->selection_start_pos == editable->selection_end_pos)
1155
editable->selection_start_pos = editable->current_pos;
1156
editable->selection_end_pos = editable->current_pos;
1159
extend_start = (editable->current_pos == editable->selection_start_pos);
1162
switch (event->keyval)
1166
if (event->state & GDK_CONTROL_MASK)
1167
gtk_delete_backward_word (entry);
1169
gtk_delete_backward_character (entry);
1173
gtk_delete_line (entry);
1177
if (event->state & GDK_SHIFT_MASK)
1179
extend_selection = FALSE;
1180
gtk_editable_paste_clipboard (editable);
1182
else if (event->state & GDK_CONTROL_MASK)
1184
gtk_editable_copy_clipboard (editable);
1188
/* gtk_toggle_insert(entry) -- IMPLEMENT */
1193
if (event->state & GDK_CONTROL_MASK)
1194
gtk_delete_forward_word (entry);
1195
else if (event->state & GDK_SHIFT_MASK)
1197
extend_selection = FALSE;
1198
gtk_editable_cut_clipboard (editable);
1201
gtk_delete_forward_character (entry);
1205
gtk_move_beginning_of_line (entry);
1209
gtk_move_end_of_line (entry);
1213
if (event->state & GDK_CONTROL_MASK)
1214
gtk_move_backward_word (entry);
1216
gtk_move_backward_character (entry);
1220
if (event->state & GDK_CONTROL_MASK)
1221
gtk_move_forward_word (entry);
1223
gtk_move_forward_character (entry);
1228
gtk_widget_activate (widget);
1230
/* The next two keys should not be inserted literally. Any others ??? */
1235
if ((event->keyval >= 0x20) && (event->keyval <= 0xFF))
1237
key = event->keyval;
1239
if (event->state & GDK_CONTROL_MASK)
1241
if ((key >= 'A') && (key <= 'Z'))
1244
if ((key >= 'a') && (key <= 'z') && control_keys[key - 'a'])
1246
(* control_keys[key - 'a']) (editable, event->time);
1251
else if (event->state & GDK_MOD1_MASK)
1253
if ((key >= 'A') && (key <= 'Z'))
1256
if ((key >= 'a') && (key <= 'z') && alt_keys[key - 'a'])
1258
(* alt_keys[key - 'a']) (editable, event->time);
1264
if (event->length > 0)
1268
extend_selection = FALSE;
1269
gtk_editable_delete_selection (editable);
1271
tmp_pos = editable->current_pos;
1272
gtk_secure_entry_insert_text (editable, event->string, event->length, &tmp_pos);
1273
editable->current_pos = tmp_pos;
1280
/* since we emit signals from within the above code,
1281
* the widget might already be destroyed or at least
1284
if (GTK_WIDGET_REALIZED (editable) &&
1285
return_val && (editable->current_pos != initial_pos))
1287
if (extend_selection)
1289
if (editable->current_pos < editable->selection_start_pos)
1290
editable->selection_start_pos = editable->current_pos;
1291
else if (editable->current_pos > editable->selection_end_pos)
1292
editable->selection_end_pos = editable->current_pos;
1296
editable->selection_start_pos = editable->current_pos;
1298
editable->selection_end_pos = editable->current_pos;
1303
editable->selection_start_pos = 0;
1304
editable->selection_end_pos = 0;
1307
gtk_editable_claim_selection (editable,
1308
editable->selection_start_pos != editable->selection_end_pos,
1311
entry_adjust_scroll (entry);
1312
gtk_secure_entry_queue_draw (entry);
1319
gtk_secure_entry_focus_in (GtkWidget *widget,
1320
GdkEventFocus *event)
1322
g_return_val_if_fail (widget != NULL, FALSE);
1323
g_return_val_if_fail (GTK_IS_SECURE_ENTRY (widget), FALSE);
1324
g_return_val_if_fail (event != NULL, FALSE);
1326
GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
1327
gtk_widget_draw_focus (widget);
1330
if (GTK_EDITABLE(widget)->ic)
1331
gdk_im_begin (GTK_EDITABLE(widget)->ic, GTK_SECURE_ENTRY(widget)->text_area);
1338
gtk_secure_entry_focus_out (GtkWidget *widget,
1339
GdkEventFocus *event)
1341
g_return_val_if_fail (widget != NULL, FALSE);
1342
g_return_val_if_fail (GTK_IS_SECURE_ENTRY (widget), FALSE);
1343
g_return_val_if_fail (event != NULL, FALSE);
1345
GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
1346
gtk_widget_draw_focus (widget);
1356
gtk_secure_entry_make_backing_pixmap (GtkSecureEntry *entry, gint width, gint height)
1358
gint pixmap_width, pixmap_height;
1360
if (!entry->backing_pixmap)
1363
entry->backing_pixmap = gdk_pixmap_new (entry->text_area,
1369
/* reallocate if sizes don't match */
1370
gdk_window_get_size (entry->backing_pixmap,
1371
&pixmap_width, &pixmap_height);
1372
if ((pixmap_width != width) || (pixmap_height != height))
1374
gdk_pixmap_unref (entry->backing_pixmap);
1375
entry->backing_pixmap = gdk_pixmap_new (entry->text_area,
1383
gtk_secure_entry_draw_text (GtkSecureEntry *entry)
1386
GtkEditable *editable;
1387
GtkStateType selected_state;
1391
gint selection_start_pos;
1392
gint selection_end_pos;
1393
gint selection_start_xoffset;
1394
gint selection_end_xoffset;
1397
GdkDrawable *drawable;
1398
gint use_backing_pixmap;
1402
g_return_if_fail (entry != NULL);
1403
g_return_if_fail (GTK_IS_SECURE_ENTRY (entry));
1407
gtk_timeout_remove (entry->timer);
1411
if (GTK_WIDGET_DRAWABLE (entry))
1413
widget = GTK_WIDGET (entry);
1414
editable = GTK_EDITABLE (entry);
1418
gtk_paint_flat_box (widget->style, entry->text_area,
1419
GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE,
1420
NULL, widget, "entry_bg",
1423
if (editable->editable)
1424
gtk_secure_entry_draw_cursor (entry);
1428
gdk_window_get_size (entry->text_area, &width, &height);
1431
If the widget has focus, draw on a backing pixmap to avoid flickering
1432
and copy it to the text_area.
1433
Otherwise draw to text_area directly for better speed.
1435
use_backing_pixmap = GTK_WIDGET_HAS_FOCUS (widget) && (entry->text != NULL);
1436
if (use_backing_pixmap)
1438
gtk_secure_entry_make_backing_pixmap (entry, width, height);
1439
drawable = entry->backing_pixmap;
1443
drawable = entry->text_area;
1445
gtk_paint_flat_box (widget->style, drawable,
1446
GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE,
1447
NULL, widget, "entry_bg",
1448
0, 0, width, height);
1450
y = (height - (widget->style->font->ascent + widget->style->font->descent)) / 2;
1451
y += widget->style->font->ascent;
1453
start_pos = gtk_secure_entry_find_position (entry, entry->scroll_offset);
1454
start_xoffset = entry->char_offset[start_pos] - entry->scroll_offset;
1456
end_pos = gtk_secure_entry_find_position (entry, entry->scroll_offset + width);
1457
if (end_pos < entry->text_length)
1460
selected_state = GTK_STATE_SELECTED;
1461
if (!editable->has_selection)
1462
selected_state = GTK_STATE_ACTIVE;
1464
selection_start_pos = MIN (editable->selection_start_pos, editable->selection_end_pos);
1465
selection_end_pos = MAX (editable->selection_start_pos, editable->selection_end_pos);
1467
selection_start_pos = CLAMP (selection_start_pos, start_pos, end_pos);
1468
selection_end_pos = CLAMP (selection_end_pos, start_pos, end_pos);
1470
selection_start_xoffset =
1471
entry->char_offset[selection_start_pos] - entry->scroll_offset;
1472
selection_end_xoffset =
1473
entry->char_offset[selection_end_pos] -entry->scroll_offset;
1475
/* if editable->visible, print a bunch of stars. If not, print the standard text. */
1476
if (editable->visible)
1478
toprint = entry->text + start_pos;
1484
stars = g_new (GdkWChar, end_pos - start_pos);
1485
for (i = 0; i < end_pos - start_pos; i++)
1490
if (selection_start_pos > start_pos)
1491
gdk_draw_text_wc (drawable, widget->style->font,
1492
widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
1493
INNER_BORDER + start_xoffset, y,
1495
selection_start_pos - start_pos);
1497
if ((selection_end_pos >= start_pos) &&
1498
(selection_start_pos < end_pos) &&
1499
(selection_start_pos != selection_end_pos))
1501
gtk_paint_flat_box (widget->style, drawable,
1502
selected_state, GTK_SHADOW_NONE,
1503
NULL, widget, "text",
1504
INNER_BORDER + selection_start_xoffset,
1506
selection_end_xoffset - selection_start_xoffset,
1507
height - 2*INNER_BORDER);
1508
gdk_draw_text_wc (drawable, widget->style->font,
1509
widget->style->fg_gc[selected_state],
1510
INNER_BORDER + selection_start_xoffset, y,
1511
toprint + selection_start_pos - start_pos,
1512
selection_end_pos - selection_start_pos);
1515
if (selection_end_pos < end_pos)
1516
gdk_draw_text_wc (drawable, widget->style->font,
1517
widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
1518
INNER_BORDER + selection_end_xoffset, y,
1519
toprint + selection_end_pos - start_pos,
1520
end_pos - selection_end_pos);
1521
/* free the space allocated for the stars if it's neccessary. */
1522
if (!editable->visible)
1525
if (editable->editable)
1526
gtk_secure_entry_draw_cursor_on_drawable (entry, drawable);
1528
if (use_backing_pixmap)
1529
gdk_draw_pixmap(entry->text_area,
1530
widget->style->fg_gc[GTK_STATE_NORMAL],
1531
entry->backing_pixmap,
1532
0, 0, 0, 0, width, height);
1537
gtk_secure_entry_draw_cursor (GtkSecureEntry *entry)
1539
g_return_if_fail (entry != NULL);
1540
g_return_if_fail (GTK_IS_SECURE_ENTRY (entry));
1542
gtk_secure_entry_draw_cursor_on_drawable (entry, entry->text_area);
1546
gtk_secure_entry_draw_cursor_on_drawable (GtkSecureEntry *entry, GdkDrawable *drawable)
1549
GtkEditable *editable;
1551
gint text_area_height;
1553
g_return_if_fail (entry != NULL);
1554
g_return_if_fail (GTK_IS_SECURE_ENTRY (entry));
1556
if (GTK_WIDGET_DRAWABLE (entry))
1558
widget = GTK_WIDGET (entry);
1559
editable = GTK_EDITABLE (entry);
1561
xoffset = INNER_BORDER + entry->char_offset[editable->current_pos];
1562
xoffset -= entry->scroll_offset;
1564
gdk_window_get_size (entry->text_area, NULL, &text_area_height);
1566
if (GTK_WIDGET_HAS_FOCUS (widget) &&
1567
(editable->selection_start_pos == editable->selection_end_pos))
1569
gdk_draw_line (drawable, widget->style->fg_gc[GTK_STATE_NORMAL],
1570
xoffset, INNER_BORDER,
1571
xoffset, text_area_height - INNER_BORDER);
1577
(widget->style->font->ascent + widget->style->font->descent)) / 2
1578
+ widget->style->font->ascent;
1580
gtk_paint_flat_box (widget->style, drawable,
1581
GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE,
1582
NULL, widget, "entry_bg",
1583
xoffset, INNER_BORDER,
1584
1, text_area_height - INNER_BORDER);
1586
/* Draw the character under the cursor again
1588
if ((editable->current_pos < entry->text_length) &&
1589
(editable->selection_start_pos == editable->selection_end_pos))
1591
GdkWChar c = editable->visible ?
1592
*(entry->text + editable->current_pos) :
1595
gdk_draw_text_wc (drawable, widget->style->font,
1596
widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
1597
xoffset, yoffset, &c, 1);
1603
if (GTK_WIDGET_HAS_FOCUS(widget) && gdk_im_ready() && editable->ic &&
1604
(gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION))
1606
editable->ic_attr->spot_location.x = xoffset;
1607
editable->ic_attr->spot_location.y =
1608
(text_area_height + (widget->style->font->ascent
1609
- widget->style->font->descent) + 1) / 2;
1611
gdk_ic_set_attr (editable->ic,
1612
editable->ic_attr, GDK_IC_SPOT_LOCATION);
1619
gtk_secure_entry_queue_draw (GtkSecureEntry *entry)
1621
g_return_if_fail (entry != NULL);
1622
g_return_if_fail (GTK_IS_SECURE_ENTRY (entry));
1625
entry->timer = gtk_timeout_add (DRAW_TIMEOUT, gtk_secure_entry_timer, entry);
1629
gtk_secure_entry_timer (gpointer data)
1631
GtkSecureEntry *entry;
1633
GDK_THREADS_ENTER ();
1635
entry = GTK_SECURE_ENTRY (data);
1637
gtk_secure_entry_draw_text (entry);
1639
GDK_THREADS_LEAVE ();
1645
gtk_secure_entry_find_position (GtkSecureEntry *entry,
1649
gint end = entry->text_length;
1654
if (x >= entry->char_offset[end])
1657
/* invariant - char_offset[start] <= x < char_offset[end] */
1659
while (start != end)
1661
half = (start+end)/2;
1664
else if (entry->char_offset[half] <= x)
1674
gtk_secure_entry_position (GtkSecureEntry *entry,
1677
return gtk_secure_entry_find_position(entry, x);
1681
entry_adjust_scroll (GtkSecureEntry *entry)
1683
gint xoffset, max_offset;
1684
gint text_area_width;
1686
g_return_if_fail (entry != NULL);
1687
g_return_if_fail (GTK_IS_SECURE_ENTRY (entry));
1689
if (!entry->text_area)
1692
gdk_window_get_size (entry->text_area, &text_area_width, NULL);
1694
/* Display as much text as we can */
1695
max_offset = MAX(0, entry->char_offset[entry->text_length] - text_area_width);
1697
if (entry->scroll_offset > max_offset)
1698
entry->scroll_offset = max_offset;
1700
/* And make sure cursor is on screen */
1701
xoffset = entry->char_offset[GTK_EDITABLE(entry)->current_pos];
1702
xoffset -= entry->scroll_offset;
1705
entry->scroll_offset += xoffset;
1706
else if (xoffset > text_area_width)
1707
entry->scroll_offset += xoffset - text_area_width + 1;
1709
gtk_widget_queue_draw (GTK_WIDGET (entry));
1713
gtk_secure_entry_grow_text (GtkSecureEntry *entry)
1718
g_return_if_fail (entry != NULL);
1719
g_return_if_fail (GTK_IS_SECURE_ENTRY (entry));
1721
previous_size = entry->text_size;
1722
if (!entry->text_size)
1723
entry->text_size = 128;
1725
entry->text_size *= 2;
1726
WITH_SECURE_MEM(entry->text = g_realloc (entry->text,
1727
entry->text_size * sizeof(GdkWChar)));
1728
entry->char_offset = g_realloc (entry->char_offset,
1729
entry->text_size * sizeof(guint));
1731
if (entry->text_length == 0) /* initial allocation */
1733
entry->char_offset[0] = 0;
1736
for (i = previous_size; i < entry->text_size; i++)
1737
entry->text[i] = '\0';
1741
gtk_secure_entry_insert_text (GtkEditable *editable,
1742
const gchar *new_text,
1743
gint new_text_length,
1753
guchar *new_text_nt;
1754
gint insertion_length;
1755
GdkWChar *insertion_text;
1757
GtkSecureEntry *entry;
1760
g_return_if_fail (editable != NULL);
1761
g_return_if_fail (GTK_IS_SECURE_ENTRY (editable));
1763
entry = GTK_SECURE_ENTRY (editable);
1764
widget = GTK_WIDGET (editable);
1766
if ((entry->text_length == 0) && (entry->use_wchar == FALSE))
1768
if (!GTK_WIDGET_REALIZED (widget))
1769
gtk_widget_ensure_style (widget);
1770
if ((widget->style) && (widget->style->font->type == GDK_FONT_FONTSET))
1771
entry->use_wchar = TRUE;
1774
if (new_text_length < 0)
1776
new_text_nt = (gchar *)new_text;
1777
new_text_length = strlen (new_text);
1778
if (new_text_length <= 0) return;
1780
else if (new_text_length == 0)
1786
/* make a null-terminated copy of new_text */
1787
WITH_SECURE_MEM(new_text_nt = g_new (gchar, new_text_length + 1));
1788
memcpy (new_text_nt, new_text, new_text_length);
1789
new_text_nt[new_text_length] = 0;
1792
/* The algorithms here will work as long as, the text size (a
1793
* multiple of 2), fits into a guint16 but we specify a shorter
1794
* maximum length so that if the user pastes a very long text, there
1795
* is not a long hang from the slow X_LOCALE functions. */
1797
if (entry->text_max_length == 0)
1800
max_length = MIN (2047, entry->text_max_length);
1802
/* Convert to wide characters */
1803
WITH_SECURE_MEM(insertion_text = g_new (GdkWChar, new_text_length));
1804
if (entry->use_wchar)
1805
insertion_length = gdk_mbstowcs (insertion_text, new_text_nt,
1808
for (insertion_length=0; new_text_nt[insertion_length]; insertion_length++)
1809
insertion_text[insertion_length] = new_text_nt[insertion_length];
1810
if (new_text_nt != (guchar *)new_text)
1811
WITH_SECURE_MEM(g_free (new_text_nt));
1813
/* Make sure we do not exceed the maximum size of the entry. */
1814
if (insertion_length + entry->text_length > max_length)
1815
insertion_length = max_length - entry->text_length;
1817
/* Don't insert anything, if there was nothing to insert. */
1818
if (insertion_length <= 0)
1820
WITH_SECURE_MEM(g_free(insertion_text));
1824
/* Make sure we are inserting at integral character position */
1825
start_pos = *position;
1828
else if (start_pos > entry->text_length)
1829
start_pos = entry->text_length;
1831
end_pos = start_pos + insertion_length;
1832
last_pos = insertion_length + entry->text_length;
1834
if (editable->selection_start_pos >= *position)
1835
editable->selection_start_pos += insertion_length;
1836
if (editable->selection_end_pos >= *position)
1837
editable->selection_end_pos += insertion_length;
1839
while (last_pos >= entry->text_size)
1840
gtk_secure_entry_grow_text (entry);
1843
for (i = last_pos - 1; i >= end_pos; i--)
1844
text[i] = text[i- (end_pos - start_pos)];
1845
for (i = start_pos; i < end_pos; i++)
1846
text[i] = insertion_text[i - start_pos];
1847
WITH_SECURE_MEM(g_free (insertion_text));
1849
/* Fix up the the character offsets */
1851
if (GTK_WIDGET_REALIZED (entry))
1855
for (i = last_pos; i >= end_pos; i--)
1856
entry->char_offset[i]
1857
= entry->char_offset[i - insertion_length];
1859
for (i=start_pos; i<end_pos; i++)
1861
entry->char_offset[i] = entry->char_offset[start_pos] + offset;
1862
if (editable->visible)
1864
offset += gdk_char_width_wc (GTK_WIDGET (entry)->style->font,
1869
offset += gdk_char_width (GTK_WIDGET (entry)->style->font, '*');
1872
for (i = end_pos; i <= last_pos; i++)
1873
entry->char_offset[i] += offset;
1876
entry->text_length += insertion_length;
1877
*position = end_pos;
1879
entry->text_mb_dirty = 1;
1880
gtk_secure_entry_queue_draw (entry);
1883
/* Recompute the x offsets of all characters in the buffer */
1885
gtk_secure_entry_recompute_offsets (GtkSecureEntry *entry)
1890
for (i=0; i<entry->text_length; i++)
1892
entry->char_offset[i] = offset;
1893
if (GTK_EDITABLE (entry)->visible)
1895
offset += gdk_char_width_wc (GTK_WIDGET (entry)->style->font,
1900
offset += gdk_char_width (GTK_WIDGET (entry)->style->font, '*');
1904
entry->char_offset[i] = offset;
1908
gtk_secure_entry_delete_text (GtkEditable *editable,
1913
gint deletion_length;
1916
GtkSecureEntry *entry;
1918
g_return_if_fail (editable != NULL);
1919
g_return_if_fail (GTK_IS_SECURE_ENTRY (editable));
1921
entry = GTK_SECURE_ENTRY (editable);
1924
end_pos = entry->text_length;
1926
if (editable->selection_start_pos > start_pos)
1927
editable->selection_start_pos -= MIN(end_pos, editable->selection_start_pos) - start_pos;
1928
if (editable->selection_end_pos > start_pos)
1929
editable->selection_end_pos -= MIN(end_pos, editable->selection_end_pos) - start_pos;
1931
if ((start_pos < end_pos) &&
1933
(end_pos <= entry->text_length))
1936
deletion_length = end_pos - start_pos;
1938
/* Fix up the character offsets */
1939
if (GTK_WIDGET_REALIZED (entry))
1941
gint deletion_width =
1942
entry->char_offset[end_pos] - entry->char_offset[start_pos];
1944
for (i = 0 ; i <= entry->text_length - end_pos; i++)
1945
entry->char_offset[start_pos+i] = entry->char_offset[end_pos+i] - deletion_width;
1948
for (i = end_pos; i < entry->text_length; i++)
1949
text[i - deletion_length] = text[i];
1951
for (i = entry->text_length - deletion_length; i < entry->text_length; i++)
1954
entry->text_length -= deletion_length;
1955
editable->current_pos = start_pos;
1958
entry->text_mb_dirty = 1;
1959
gtk_secure_entry_queue_draw (entry);
1963
gtk_secure_entry_update_text (GtkEditable *editable,
1967
gtk_secure_entry_queue_draw (GTK_SECURE_ENTRY(editable));
1971
gtk_secure_entry_get_chars (GtkEditable *editable,
1975
GtkSecureEntry *entry;
1977
g_return_val_if_fail (editable != NULL, NULL);
1978
g_return_val_if_fail (GTK_IS_SECURE_ENTRY (editable), NULL);
1980
entry = GTK_SECURE_ENTRY (editable);
1983
end_pos = entry->text_length;
1985
start_pos = MIN(entry->text_length, start_pos);
1986
end_pos = MIN(entry->text_length, end_pos);
1988
if (start_pos <= end_pos)
1991
if (entry->use_wchar)
1994
if (end_pos >= entry->text_size)
1995
gtk_secure_entry_grow_text(entry);
1996
ch = entry->text[end_pos];
1997
entry->text[end_pos] = 0;
1998
WITH_SECURE_MEM(mbstr = gdk_wcstombs (entry->text + start_pos));
1999
entry->text[end_pos] = ch;
2000
return (gchar *)mbstr;
2005
WITH_SECURE_MEM(mbstr = g_new (gchar, end_pos - start_pos + 1));
2006
for (i=0; i<end_pos-start_pos; i++)
2007
mbstr[i] = entry->text[start_pos + i];
2009
return (gchar *)mbstr;
2017
gtk_secure_entry_move_cursor (GtkEditable *editable,
2021
GtkSecureEntry *entry;
2022
entry = GTK_SECURE_ENTRY (editable);
2024
/* Horizontal motion */
2025
if ((gint)editable->current_pos < -x)
2026
editable->current_pos = 0;
2027
else if (editable->current_pos + x > entry->text_length)
2028
editable->current_pos = entry->text_length;
2030
editable->current_pos += x;
2032
/* Ignore vertical motion */
2036
gtk_move_forward_character (GtkSecureEntry *entry)
2038
gtk_secure_entry_move_cursor (GTK_EDITABLE (entry), 1, 0);
2042
gtk_move_backward_character (GtkSecureEntry *entry)
2044
gtk_secure_entry_move_cursor (GTK_EDITABLE (entry), -1, 0);
2048
gtk_secure_entry_move_word (GtkEditable *editable,
2052
gtk_move_forward_word (GTK_SECURE_ENTRY (editable));
2054
gtk_move_backward_word (GTK_SECURE_ENTRY (editable));
2058
gtk_move_forward_word (GtkSecureEntry *entry)
2060
GtkEditable *editable;
2064
editable = GTK_EDITABLE (entry);
2066
if (entry->text && (editable->current_pos < entry->text_length))
2069
i = editable->current_pos;
2071
if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
2072
for (; i < entry->text_length; i++)
2074
if ((entry->use_wchar) ? gdk_iswalnum (text[i]) : isalnum (text[i]))
2078
for (; i < entry->text_length; i++)
2080
if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
2084
editable->current_pos = i;
2089
gtk_move_backward_word (GtkSecureEntry *entry)
2091
GtkEditable *editable;
2095
editable = GTK_EDITABLE (entry);
2097
if (entry->text && editable->current_pos > 0)
2100
i = editable->current_pos - 1;
2101
if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
2104
if ((entry->use_wchar) ? gdk_iswalnum (text[i]) : isalnum (text[i]))
2109
if ((entry->use_wchar) ? (!gdk_iswalnum (text[i])) : (!isalnum (text[i])))
2119
editable->current_pos = i;
2124
gtk_secure_entry_move_to_column (GtkEditable *editable, gint column)
2126
GtkSecureEntry *entry;
2128
entry = GTK_SECURE_ENTRY (editable);
2130
if (column < 0 || column > entry->text_length)
2131
editable->current_pos = entry->text_length;
2133
editable->current_pos = column;
2137
gtk_move_beginning_of_line (GtkSecureEntry *entry)
2139
gtk_secure_entry_move_to_column (GTK_EDITABLE (entry), 0);
2143
gtk_move_end_of_line (GtkSecureEntry *entry)
2145
gtk_secure_entry_move_to_column (GTK_EDITABLE (entry), -1);
2149
gtk_secure_entry_kill_char (GtkEditable *editable,
2152
if (editable->selection_start_pos != editable->selection_end_pos)
2153
gtk_editable_delete_selection (editable);
2156
gint old_pos = editable->current_pos;
2159
gtk_secure_entry_move_cursor (editable, 1, 0);
2160
gtk_editable_delete_text (editable, old_pos, editable->current_pos);
2164
gtk_secure_entry_move_cursor (editable, -1, 0);
2165
gtk_editable_delete_text (editable, editable->current_pos, old_pos);
2171
gtk_delete_forward_character (GtkSecureEntry *entry)
2173
gtk_secure_entry_kill_char (GTK_EDITABLE (entry), 1);
2177
gtk_delete_backward_character (GtkSecureEntry *entry)
2179
gtk_secure_entry_kill_char (GTK_EDITABLE (entry), -1);
2183
gtk_secure_entry_kill_word (GtkEditable *editable,
2186
if (editable->selection_start_pos != editable->selection_end_pos)
2187
gtk_editable_delete_selection (editable);
2190
gint old_pos = editable->current_pos;
2193
gtk_secure_entry_move_word (editable, 1);
2194
gtk_editable_delete_text (editable, old_pos, editable->current_pos);
2198
gtk_secure_entry_move_word (editable, -1);
2199
gtk_editable_delete_text (editable, editable->current_pos, old_pos);
2205
gtk_delete_forward_word (GtkSecureEntry *entry)
2207
gtk_secure_entry_kill_word (GTK_EDITABLE (entry), 1);
2211
gtk_delete_backward_word (GtkSecureEntry *entry)
2213
gtk_secure_entry_kill_word (GTK_EDITABLE (entry), -1);
2217
gtk_secure_entry_kill_line (GtkEditable *editable,
2220
gint old_pos = editable->current_pos;
2223
gtk_secure_entry_move_to_column (editable, -1);
2224
gtk_editable_delete_text (editable, old_pos, editable->current_pos);
2228
gtk_secure_entry_move_to_column (editable, 0);
2229
gtk_editable_delete_text (editable, editable->current_pos, old_pos);
2234
gtk_delete_line (GtkSecureEntry *entry)
2236
gtk_secure_entry_move_to_column (GTK_EDITABLE (entry), 0);
2237
gtk_secure_entry_kill_line (GTK_EDITABLE (entry), 1);
2241
gtk_delete_to_line_end (GtkSecureEntry *entry)
2243
gtk_editable_delete_text (GTK_EDITABLE(entry), GTK_EDITABLE(entry)->current_pos, entry->text_length);
2247
gtk_select_word (GtkSecureEntry *entry,
2250
GtkEditable *editable;
2254
editable = GTK_EDITABLE (entry);
2256
gtk_move_backward_word (entry);
2257
start_pos = editable->current_pos;
2259
gtk_move_forward_word (entry);
2260
end_pos = editable->current_pos;
2262
editable->has_selection = TRUE;
2263
gtk_secure_entry_set_selection (editable, start_pos, end_pos);
2264
gtk_editable_claim_selection (editable, start_pos != end_pos, time);
2268
gtk_select_line (GtkSecureEntry *entry,
2271
GtkEditable *editable;
2273
editable = GTK_EDITABLE (entry);
2275
editable->has_selection = TRUE;
2276
gtk_secure_entry_set_selection (editable, 0, entry->text_length);
2277
gtk_editable_claim_selection (editable, entry->text_length != 0, time);
2279
editable->current_pos = editable->selection_end_pos;
2283
gtk_secure_entry_set_selection (GtkEditable *editable,
2287
g_return_if_fail (editable != NULL);
2288
g_return_if_fail (GTK_IS_SECURE_ENTRY (editable));
2291
end = GTK_SECURE_ENTRY (editable)->text_length;
2293
editable->selection_start_pos = start;
2294
editable->selection_end_pos = end;
2296
gtk_secure_entry_queue_draw (GTK_SECURE_ENTRY (editable));
2300
gtk_secure_entry_select_region (GtkSecureEntry *entry,
2304
gtk_editable_select_region (GTK_EDITABLE (entry), start, end);
2308
gtk_secure_entry_set_max_length (GtkSecureEntry *entry,
2311
g_return_if_fail (entry != NULL);
2312
g_return_if_fail (GTK_IS_SECURE_ENTRY (entry));
2314
if (max && entry->text_length > max)
2315
gtk_editable_delete_text(GTK_EDITABLE(entry), max, -1);
2316
entry->text_max_length = max;
2321
gtk_secure_entry_update_ic_attr (GtkWidget *widget)
2323
GtkEditable *editable = (GtkEditable *) widget;
2324
GdkICAttributesType mask = 0;
2326
if (editable->ic == NULL)
2329
gdk_ic_get_attr (editable->ic, editable->ic_attr,
2330
GDK_IC_PREEDIT_FOREGROUND |
2331
GDK_IC_PREEDIT_BACKGROUND |
2332
GDK_IC_PREEDIT_FONTSET);
2334
if (editable->ic_attr->preedit_foreground.pixel !=
2335
widget->style->fg[GTK_STATE_NORMAL].pixel)
2337
mask |= GDK_IC_PREEDIT_FOREGROUND;
2338
editable->ic_attr->preedit_foreground
2339
= widget->style->fg[GTK_STATE_NORMAL];
2341
if (editable->ic_attr->preedit_background.pixel !=
2342
widget->style->base[GTK_STATE_NORMAL].pixel)
2344
mask |= GDK_IC_PREEDIT_BACKGROUND;
2345
editable->ic_attr->preedit_background
2346
= widget->style->base[GTK_STATE_NORMAL];
2348
if ((gdk_ic_get_style (editable->ic) & GDK_IM_PREEDIT_POSITION) &&
2349
widget->style->font != NULL &&
2350
widget->style->font->type == GDK_FONT_FONTSET &&
2351
!gdk_font_equal (editable->ic_attr->preedit_fontset,
2352
widget->style->font))
2354
mask |= GDK_IC_PREEDIT_FONTSET;
2355
editable->ic_attr->preedit_fontset = widget->style->font;
2359
gdk_ic_set_attr (editable->ic, editable->ic_attr, mask);
2361
#endif /* USE_XIM */
2364
gtk_secure_entry_style_set (GtkWidget *widget,
2365
GtkStyle *previous_style)
2367
GtkSecureEntry *entry;
2370
g_return_if_fail (widget != NULL);
2371
g_return_if_fail (GTK_IS_SECURE_ENTRY (widget));
2373
if (previous_style && GTK_WIDGET_REALIZED (widget))
2375
entry = GTK_SECURE_ENTRY (widget);
2377
scroll_char = gtk_secure_entry_find_position (entry, entry->scroll_offset);
2378
gtk_secure_entry_recompute_offsets (GTK_SECURE_ENTRY (widget));
2379
entry->scroll_offset = entry->char_offset[scroll_char];
2380
entry_adjust_scroll (entry);
2382
gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2383
gdk_window_set_background (entry->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2386
gtk_secure_entry_update_ic_attr (widget);
2392
gtk_secure_entry_state_changed (GtkWidget *widget,
2393
GtkStateType previous_state)
2395
g_return_if_fail (widget != NULL);
2396
g_return_if_fail (GTK_IS_SECURE_ENTRY (widget));
2398
if (GTK_WIDGET_REALIZED (widget))
2400
gdk_window_set_background (widget->window, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2401
gdk_window_set_background (GTK_SECURE_ENTRY (widget)->text_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
2404
gtk_secure_entry_update_ic_attr (widget);
2408
if (GTK_WIDGET_DRAWABLE (widget))
2409
gtk_widget_queue_clear(widget);