From c646d52761bf59f014b9c385d15309880cc5309c Mon Sep 17 00:00:00 2001 From: Guido Günther Date: Mon, 14 Feb 2011 21:00:53 +0100 Subject: New upstream version 2.91.6 --- gtksecentry/gtksecentry.c | 3364 --------------------------------------------- 1 file changed, 3364 deletions(-) delete mode 100644 gtksecentry/gtksecentry.c (limited to 'gtksecentry/gtksecentry.c') diff --git a/gtksecentry/gtksecentry.c b/gtksecentry/gtksecentry.c deleted file mode 100644 index f68f094..0000000 --- a/gtksecentry/gtksecentry.c +++ /dev/null @@ -1,3364 +0,0 @@ -/* GTK - The GIMP Toolkit - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * Copyright (C) 2004 Albrecht Dreß - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS - * file for a list of people on the GTK+ Team. See the ChangeLog - * files for a list of changes. These files are distributed with - * GTK+ at ftp://ftp.gtk.org/pub/gtk/. - */ - -/* - * Heavily stripped down for use in pinentry-gtk-2 by Albrecht Dreß - * Feb. 2004: - * - * The entry is now always invisible, uses secure memory methods to - * allocate the text memory, and all potentially dangerous methods - * (copy & paste, popup, etc.) have been removed. - */ - -#include -#include -#include -#include - -#include "gtksecentry.h" -#include "memory.h" - -#define MIN_SECURE_ENTRY_WIDTH 150 -#define DRAW_TIMEOUT 20 -#define INNER_BORDER 2 - -/* Initial size of buffer, in bytes */ -#define MIN_SIZE 16 - -/* Maximum size of text buffer, in bytes */ -#define MAX_SIZE G_MAXUSHORT - -enum { - ACTIVATE, - MOVE_CURSOR, - INSERT_AT_CURSOR, - DELETE_FROM_CURSOR, - LAST_SIGNAL -}; - -enum { - PROP_0, - PROP_CURSOR_POSITION, - PROP_SELECTION_BOUND, - PROP_MAX_LENGTH, - PROP_HAS_FRAME, - PROP_INVISIBLE_CHAR, - PROP_ACTIVATES_DEFAULT, - PROP_WIDTH_CHARS, - PROP_SCROLL_OFFSET, - PROP_TEXT -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -/* GObject, GtkObject methods - */ -static void gtk_secure_entry_class_init(GtkSecureEntryClass * klass); -static void gtk_secure_entry_editable_init(GtkEditableClass * iface); -static void gtk_secure_entry_cell_editable_init(GtkCellEditableIface * - iface); -static void gtk_secure_entry_init(GtkSecureEntry * entry); -static void gtk_secure_entry_set_property(GObject * object, - guint prop_id, - const GValue * value, - GParamSpec * pspec); -static void gtk_secure_entry_get_property(GObject * object, - guint prop_id, - GValue * value, - GParamSpec * pspec); -static void gtk_secure_entry_finalize(GObject * object); - -/* GtkWidget methods - */ -static void gtk_secure_entry_realize(GtkWidget * widget); -static void gtk_secure_entry_unrealize(GtkWidget * widget); -static void gtk_secure_entry_size_request(GtkWidget * widget, - GtkRequisition * requisition); -static void gtk_secure_entry_size_allocate(GtkWidget * widget, - GtkAllocation * allocation); -static void gtk_secure_entry_draw_frame(GtkWidget * widget); -static gint gtk_secure_entry_expose(GtkWidget * widget, - GdkEventExpose * event); -static gint gtk_secure_entry_button_press(GtkWidget * widget, - GdkEventButton * event); -static gint gtk_secure_entry_button_release(GtkWidget * widget, - GdkEventButton * event); -static gint gtk_secure_entry_motion_notify(GtkWidget * widget, - GdkEventMotion * event); -static gint gtk_secure_entry_key_press(GtkWidget * widget, - GdkEventKey * event); -static gint gtk_secure_entry_key_release(GtkWidget * widget, - GdkEventKey * event); -static gint gtk_secure_entry_focus_in(GtkWidget * widget, - GdkEventFocus * event); -static gint gtk_secure_entry_focus_out(GtkWidget * widget, - GdkEventFocus * event); -static void gtk_secure_entry_grab_focus(GtkWidget * widget); -static void gtk_secure_entry_style_set(GtkWidget * widget, - GtkStyle * previous_style); -static void gtk_secure_entry_direction_changed(GtkWidget * widget, - GtkTextDirection - previous_dir); -static void gtk_secure_entry_state_changed(GtkWidget * widget, - GtkStateType previous_state); -static void gtk_secure_entry_screen_changed(GtkWidget * widget, - GdkScreen * old_screen); - -/* GtkEditable method implementations - */ -static void gtk_secure_entry_insert_text(GtkEditable * editable, - const gchar * new_text, - gint new_text_length, - gint * position); -static void gtk_secure_entry_delete_text(GtkEditable * editable, - gint start_pos, gint end_pos); -static void gtk_secure_entry_real_set_position(GtkEditable * editable, - gint position); -static gint gtk_secure_entry_get_position(GtkEditable * editable); -static void gtk_secure_entry_set_selection_bounds(GtkEditable * editable, - gint start, gint end); -static gboolean gtk_secure_entry_get_selection_bounds(GtkEditable * - editable, - gint * start, - gint * end); - -/* GtkCellEditable method implementations - */ -static void gtk_secure_entry_start_editing(GtkCellEditable * cell_editable, - GdkEvent * event); - -/* Default signal handlers - */ -static void gtk_secure_entry_real_insert_text(GtkEditable * editable, - const gchar * new_text, - gint new_text_length, - gint * position); -static void gtk_secure_entry_real_delete_text(GtkEditable * editable, - gint start_pos, - gint end_pos); -static void gtk_secure_entry_move_cursor(GtkSecureEntry * entry, - GtkMovementStep step, - gint count, - gboolean extend_selection); -static void gtk_secure_entry_insert_at_cursor(GtkSecureEntry * entry, - const gchar * str); -static void gtk_secure_entry_delete_from_cursor(GtkSecureEntry * entry, - GtkDeleteType type, - gint count); -static void gtk_secure_entry_real_activate(GtkSecureEntry * entry); - -static void gtk_secure_entry_keymap_direction_changed(GdkKeymap * keymap, - GtkSecureEntry * - entry); -/* IM Context Callbacks - */ -static void gtk_secure_entry_commit_cb(GtkIMContext * context, - const gchar * str, - GtkSecureEntry * entry); -static void gtk_secure_entry_preedit_changed_cb(GtkIMContext * context, - GtkSecureEntry * entry); -static gboolean gtk_secure_entry_retrieve_surrounding_cb(GtkIMContext * - context, - GtkSecureEntry * - entry); -static gboolean gtk_secure_entry_delete_surrounding_cb(GtkIMContext * - context, - gint offset, - gint n_chars, - GtkSecureEntry * - entry); - -/* Internal routines - */ -static void gtk_secure_entry_enter_text(GtkSecureEntry * entry, - const gchar * str); -static void gtk_secure_entry_set_positions(GtkSecureEntry * entry, - gint current_pos, - gint selection_bound); -static void gtk_secure_entry_draw_text(GtkSecureEntry * entry); -static void gtk_secure_entry_draw_cursor(GtkSecureEntry * entry); -static PangoLayout *gtk_secure_entry_ensure_layout(GtkSecureEntry * entry, - gboolean - include_preedit); -static void gtk_secure_entry_reset_layout(GtkSecureEntry * entry); -static void gtk_secure_entry_queue_draw(GtkSecureEntry * entry); -static void gtk_secure_entry_reset_im_context(GtkSecureEntry * entry); -static void gtk_secure_entry_recompute(GtkSecureEntry * entry); -static gint gtk_secure_entry_find_position(GtkSecureEntry * entry, gint x); -static void gtk_secure_entry_get_cursor_locations(GtkSecureEntry * entry, - gint * strong_x, - gint * weak_x); -static void gtk_secure_entry_adjust_scroll(GtkSecureEntry * entry); -static gint gtk_secure_entry_move_visually(GtkSecureEntry * editable, - gint start, gint count); -static gint gtk_secure_entry_move_logically(GtkSecureEntry * entry, - gint start, gint count); -static gboolean gtk_secure_entry_mnemonic_activate(GtkWidget * widget, - gboolean group_cycling); -static void gtk_secure_entry_check_cursor_blink(GtkSecureEntry * entry); -static void gtk_secure_entry_pend_cursor_blink(GtkSecureEntry * entry); -static void get_text_area_size(GtkSecureEntry * entry, - gint * x, - gint * y, gint * width, gint * height); -static void get_widget_window_size(GtkSecureEntry * entry, - gint * x, - gint * y, gint * width, gint * height); - - - -#define _gtk_marshal_VOID__VOID g_cclosure_marshal_VOID__VOID -#define _gtk_marshal_VOID__STRING g_cclosure_marshal_VOID__STRING -static void _gtk_marshal_VOID__ENUM_INT_BOOLEAN(GClosure * closure, - GValue * return_value, - guint n_param_values, - const GValue * - param_values, - gpointer invocation_hint, - gpointer marshal_data); -static void _gtk_marshal_VOID__ENUM_INT(GClosure * closure, - GValue * return_value, - guint n_param_values, - const GValue * param_values, - gpointer invocation_hint, - gpointer marshal_data); - - -static GtkWidgetClass *parent_class = NULL; - -gboolean g_use_secure_mem = FALSE; - -# define g_sec_new(type, count) \ - ((type *) g_sec_malloc ((unsigned) sizeof (type) * (count))) - -#define WITH_SECURE_MEM(EXP) do { \ - gboolean tmp = g_use_secure_mem; \ - g_use_secure_mem = TRUE; \ - EXP; \ - g_use_secure_mem = tmp; \ - } while(0) - - -gpointer -g_malloc(gsize size) -{ - gpointer p; - - if (size == 0) - return NULL; - - if (g_use_secure_mem) - p = (gpointer) secmem_malloc(size); - else - p = (gpointer) malloc(size); - if (!p) - g_error("could not allocate %"G_GSIZE_FORMAT" bytes", size); - - return p; -} - -gpointer -g_malloc0(gsize size) -{ - gpointer p; - - if (size == 0) - return NULL; - - if (g_use_secure_mem) { - p = (gpointer) secmem_malloc(size); - if (p) - memset(p, 0, size); - } else - p = (gpointer) calloc(size, 1); - if (!p) - g_error("could not allocate %"G_GSIZE_FORMAT" bytes", size); - - return p; -} - -gpointer -g_realloc(gpointer mem, gsize size) -{ - gpointer p; - - if (size == 0) { - g_free(mem); - - return NULL; - } - - if (!mem) { - if (g_use_secure_mem) - p = (gpointer) secmem_malloc(size); - else - p = (gpointer) malloc(size); - } else { - if (g_use_secure_mem) { - g_assert(m_is_secure(mem)); - p = (gpointer) secmem_realloc(mem, size); - } else - p = (gpointer) realloc(mem, size); - } - - if (!p) - g_error("could not reallocate %lu bytes", (gulong) size); - - return p; -} - -void -g_free(gpointer mem) -{ - if (mem) { - if (m_is_secure(mem)) - secmem_free(mem); - else - free(mem); - } -} - -GType -gtk_secure_entry_get_type(void) -{ - static GType entry_type = 0; - - if (!entry_type) { - static const GTypeInfo entry_info = { - sizeof(GtkSecureEntryClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) gtk_secure_entry_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof(GtkSecureEntry), - 0, /* n_preallocs */ - (GInstanceInitFunc) gtk_secure_entry_init, - NULL, - }; - - static const GInterfaceInfo editable_info = { - (GInterfaceInitFunc) gtk_secure_entry_editable_init, /* interface_init */ - NULL, /* interface_finalize */ - NULL /* interface_data */ - }; - - static const GInterfaceInfo cell_editable_info = { - (GInterfaceInitFunc) gtk_secure_entry_cell_editable_init, /* interface_init */ - NULL, /* interface_finalize */ - NULL /* interface_data */ - }; - - entry_type = - g_type_register_static(GTK_TYPE_WIDGET, "GtkSecureEntry", - &entry_info, 0); - - g_type_add_interface_static(entry_type, - GTK_TYPE_EDITABLE, &editable_info); - g_type_add_interface_static(entry_type, - GTK_TYPE_CELL_EDITABLE, - &cell_editable_info); - } - - return entry_type; -} - -static void -add_move_binding(GtkBindingSet * binding_set, - guint keyval, - guint modmask, GtkMovementStep step, gint count) -{ - g_return_if_fail((modmask & GDK_SHIFT_MASK) == 0); - - gtk_binding_entry_add_signal(binding_set, keyval, modmask, - "move_cursor", 3, - G_TYPE_ENUM, step, - G_TYPE_INT, count, G_TYPE_BOOLEAN, FALSE); - - /* Selection-extending version */ - gtk_binding_entry_add_signal(binding_set, keyval, - modmask | GDK_SHIFT_MASK, "move_cursor", - 3, G_TYPE_ENUM, step, G_TYPE_INT, count, - G_TYPE_BOOLEAN, TRUE); -} - -static void -gtk_secure_entry_class_init(GtkSecureEntryClass * class) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS(class); - GtkWidgetClass *widget_class; - GtkBindingSet *binding_set; - - widget_class = (GtkWidgetClass *) class; - parent_class = g_type_class_peek_parent(class); - - gobject_class->finalize = gtk_secure_entry_finalize; - gobject_class->set_property = gtk_secure_entry_set_property; - gobject_class->get_property = gtk_secure_entry_get_property; - - widget_class->realize = gtk_secure_entry_realize; - widget_class->unrealize = gtk_secure_entry_unrealize; - widget_class->size_request = gtk_secure_entry_size_request; - widget_class->size_allocate = gtk_secure_entry_size_allocate; - widget_class->expose_event = gtk_secure_entry_expose; - widget_class->button_press_event = gtk_secure_entry_button_press; - widget_class->button_release_event = gtk_secure_entry_button_release; - widget_class->motion_notify_event = gtk_secure_entry_motion_notify; - widget_class->key_press_event = gtk_secure_entry_key_press; - widget_class->key_release_event = gtk_secure_entry_key_release; - widget_class->focus_in_event = gtk_secure_entry_focus_in; - widget_class->focus_out_event = gtk_secure_entry_focus_out; - widget_class->grab_focus = gtk_secure_entry_grab_focus; - widget_class->style_set = gtk_secure_entry_style_set; - widget_class->direction_changed = gtk_secure_entry_direction_changed; - widget_class->state_changed = gtk_secure_entry_state_changed; - widget_class->screen_changed = gtk_secure_entry_screen_changed; - widget_class->mnemonic_activate = gtk_secure_entry_mnemonic_activate; - - class->move_cursor = gtk_secure_entry_move_cursor; - class->insert_at_cursor = gtk_secure_entry_insert_at_cursor; - class->delete_from_cursor = gtk_secure_entry_delete_from_cursor; - class->activate = gtk_secure_entry_real_activate; - - g_object_class_install_property(gobject_class, - PROP_CURSOR_POSITION, - g_param_spec_int("cursor_position", - "Cursor Position", - "The current position of the insertion cursor in chars", - 0, MAX_SIZE, 0, - G_PARAM_READABLE)); - - g_object_class_install_property(gobject_class, - PROP_SELECTION_BOUND, - g_param_spec_int("selection_bound", - "Selection Bound", - "The position of the opposite end of the selection from the cursor in chars", - 0, MAX_SIZE, 0, - G_PARAM_READABLE)); - - g_object_class_install_property(gobject_class, - PROP_MAX_LENGTH, - g_param_spec_int("max_length", - "Maximum length", - "Maximum number of characters for this entry. Zero if no maximum", - 0, MAX_SIZE, 0, - G_PARAM_READABLE | - G_PARAM_WRITABLE)); - - g_object_class_install_property(gobject_class, - PROP_HAS_FRAME, - g_param_spec_boolean("has_frame", - "Has Frame", - "FALSE removes outside bevel from entry", - TRUE, - G_PARAM_READABLE | - G_PARAM_WRITABLE)); - - g_object_class_install_property(gobject_class, - PROP_INVISIBLE_CHAR, - g_param_spec_unichar("invisible_char", - "Invisible character", - "The character to use when masking entry contents (in \"password mode\")", - '*', - G_PARAM_READABLE | - G_PARAM_WRITABLE)); - - g_object_class_install_property(gobject_class, - PROP_ACTIVATES_DEFAULT, - g_param_spec_boolean - ("activates_default", - "Activates default", - "Whether to activate the default widget (such as the default button in a dialog) when Enter is pressed", - FALSE, - G_PARAM_READABLE | G_PARAM_WRITABLE)); - g_object_class_install_property(gobject_class, PROP_WIDTH_CHARS, - g_param_spec_int("width_chars", - "Width in chars", - "Number of characters to leave space for in the entry", - -1, G_MAXINT, -1, - G_PARAM_READABLE | - G_PARAM_WRITABLE)); - - g_object_class_install_property(gobject_class, - PROP_SCROLL_OFFSET, - g_param_spec_int("scroll_offset", - "Scroll offset", - "Number of pixels of the entry scrolled off the screen to the left", - 0, G_MAXINT, 0, - G_PARAM_READABLE)); - - g_object_class_install_property(gobject_class, - PROP_TEXT, - g_param_spec_string("text", - "Text", - "The contents of the entry", - "", - G_PARAM_READABLE | - G_PARAM_WRITABLE)); - - /* Action signals */ - - signals[ACTIVATE] = - g_signal_new("activate", - G_OBJECT_CLASS_TYPE(gobject_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET(GtkSecureEntryClass, activate), - NULL, NULL, _gtk_marshal_VOID__VOID, G_TYPE_NONE, 0); - widget_class->activate_signal = signals[ACTIVATE]; - - signals[MOVE_CURSOR] = - g_signal_new("move_cursor", - G_OBJECT_CLASS_TYPE(gobject_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET(GtkSecureEntryClass, move_cursor), - NULL, NULL, - _gtk_marshal_VOID__ENUM_INT_BOOLEAN, - G_TYPE_NONE, 3, - GTK_TYPE_MOVEMENT_STEP, G_TYPE_INT, G_TYPE_BOOLEAN); - - signals[INSERT_AT_CURSOR] = - g_signal_new("insert_at_cursor", - G_OBJECT_CLASS_TYPE(gobject_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET(GtkSecureEntryClass, - insert_at_cursor), NULL, NULL, - _gtk_marshal_VOID__STRING, G_TYPE_NONE, 1, - G_TYPE_STRING); - - signals[DELETE_FROM_CURSOR] = - g_signal_new("delete_from_cursor", - G_OBJECT_CLASS_TYPE(gobject_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET(GtkSecureEntryClass, - delete_from_cursor), NULL, NULL, - _gtk_marshal_VOID__ENUM_INT, G_TYPE_NONE, 2, - GTK_TYPE_DELETE_TYPE, G_TYPE_INT); - - /* - * Key bindings - */ - - binding_set = gtk_binding_set_by_class(class); - - /* Moving the insertion point */ - add_move_binding(binding_set, GDK_Right, 0, - GTK_MOVEMENT_VISUAL_POSITIONS, 1); - - add_move_binding(binding_set, GDK_Left, 0, - GTK_MOVEMENT_VISUAL_POSITIONS, -1); - - add_move_binding(binding_set, GDK_KP_Right, 0, - GTK_MOVEMENT_VISUAL_POSITIONS, 1); - - add_move_binding(binding_set, GDK_KP_Left, 0, - GTK_MOVEMENT_VISUAL_POSITIONS, -1); - - add_move_binding(binding_set, GDK_Right, GDK_CONTROL_MASK, - GTK_MOVEMENT_WORDS, 1); - - add_move_binding(binding_set, GDK_Left, GDK_CONTROL_MASK, - GTK_MOVEMENT_WORDS, -1); - - add_move_binding(binding_set, GDK_KP_Right, GDK_CONTROL_MASK, - GTK_MOVEMENT_WORDS, 1); - - add_move_binding(binding_set, GDK_KP_Left, GDK_CONTROL_MASK, - GTK_MOVEMENT_WORDS, -1); - - add_move_binding(binding_set, GDK_Home, 0, - GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1); - - add_move_binding(binding_set, GDK_End, 0, - GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1); - - add_move_binding(binding_set, GDK_KP_Home, 0, - GTK_MOVEMENT_DISPLAY_LINE_ENDS, -1); - - add_move_binding(binding_set, GDK_KP_End, 0, - GTK_MOVEMENT_DISPLAY_LINE_ENDS, 1); - - add_move_binding(binding_set, GDK_Home, GDK_CONTROL_MASK, - GTK_MOVEMENT_BUFFER_ENDS, -1); - - add_move_binding(binding_set, GDK_End, GDK_CONTROL_MASK, - GTK_MOVEMENT_BUFFER_ENDS, 1); - - add_move_binding(binding_set, GDK_KP_Home, GDK_CONTROL_MASK, - GTK_MOVEMENT_BUFFER_ENDS, -1); - - add_move_binding(binding_set, GDK_KP_End, GDK_CONTROL_MASK, - GTK_MOVEMENT_BUFFER_ENDS, 1); - - /* Select all - */ - gtk_binding_entry_add_signal(binding_set, GDK_a, GDK_CONTROL_MASK, - "move_cursor", 3, - GTK_TYPE_MOVEMENT_STEP, - GTK_MOVEMENT_BUFFER_ENDS, G_TYPE_INT, -1, - G_TYPE_BOOLEAN, FALSE); - gtk_binding_entry_add_signal(binding_set, GDK_a, GDK_CONTROL_MASK, - "move_cursor", 3, GTK_TYPE_MOVEMENT_STEP, - GTK_MOVEMENT_BUFFER_ENDS, G_TYPE_INT, 1, - G_TYPE_BOOLEAN, TRUE); - - - /* Activate - */ - gtk_binding_entry_add_signal(binding_set, GDK_Return, 0, - "activate", 0); - gtk_binding_entry_add_signal(binding_set, GDK_KP_Enter, 0, - "activate", 0); - - /* Deleting text */ - gtk_binding_entry_add_signal(binding_set, GDK_Delete, 0, - "delete_from_cursor", 2, - G_TYPE_ENUM, GTK_DELETE_CHARS, - G_TYPE_INT, 1); - - gtk_binding_entry_add_signal(binding_set, GDK_KP_Delete, 0, - "delete_from_cursor", 2, - G_TYPE_ENUM, GTK_DELETE_CHARS, - G_TYPE_INT, 1); - - gtk_binding_entry_add_signal(binding_set, GDK_BackSpace, 0, - "delete_from_cursor", 2, - G_TYPE_ENUM, GTK_DELETE_CHARS, - G_TYPE_INT, -1); - - /* Make this do the same as Backspace, to help with mis-typing */ - gtk_binding_entry_add_signal(binding_set, GDK_BackSpace, - GDK_SHIFT_MASK, "delete_from_cursor", 2, - G_TYPE_ENUM, GTK_DELETE_CHARS, G_TYPE_INT, - -1); - - gtk_binding_entry_add_signal(binding_set, GDK_Delete, GDK_CONTROL_MASK, - "delete_from_cursor", 2, - G_TYPE_ENUM, GTK_DELETE_WORD_ENDS, - G_TYPE_INT, 1); - - gtk_binding_entry_add_signal(binding_set, GDK_KP_Delete, - GDK_CONTROL_MASK, "delete_from_cursor", 2, - G_TYPE_ENUM, GTK_DELETE_WORD_ENDS, - G_TYPE_INT, 1); - - gtk_binding_entry_add_signal(binding_set, GDK_BackSpace, - GDK_CONTROL_MASK, "delete_from_cursor", 2, - G_TYPE_ENUM, GTK_DELETE_WORD_ENDS, - G_TYPE_INT, -1); -} - -static void -gtk_secure_entry_editable_init(GtkEditableClass * iface) -{ - iface->do_insert_text = gtk_secure_entry_insert_text; - iface->do_delete_text = gtk_secure_entry_delete_text; - iface->insert_text = gtk_secure_entry_real_insert_text; - iface->delete_text = gtk_secure_entry_real_delete_text; - iface->set_selection_bounds = gtk_secure_entry_set_selection_bounds; - iface->get_selection_bounds = gtk_secure_entry_get_selection_bounds; - iface->set_position = gtk_secure_entry_real_set_position; - iface->get_position = gtk_secure_entry_get_position; -} - -static void -gtk_secure_entry_cell_editable_init(GtkCellEditableIface * iface) -{ - iface->start_editing = gtk_secure_entry_start_editing; -} - -static void -gtk_secure_entry_set_property(GObject * object, - guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(object); - - switch (prop_id) { - case PROP_MAX_LENGTH: - gtk_secure_entry_set_max_length(entry, g_value_get_int(value)); - break; - - case PROP_HAS_FRAME: - gtk_secure_entry_set_has_frame(entry, g_value_get_boolean(value)); - break; - - case PROP_INVISIBLE_CHAR: - gtk_secure_entry_set_invisible_char(entry, - g_value_get_uint(value)); - break; - - case PROP_ACTIVATES_DEFAULT: - gtk_secure_entry_set_activates_default(entry, - g_value_get_boolean(value)); - break; - - case PROP_WIDTH_CHARS: - gtk_secure_entry_set_width_chars(entry, g_value_get_int(value)); - break; - - case PROP_TEXT: - gtk_secure_entry_set_text(entry, g_value_get_string(value)); - break; - - case PROP_SCROLL_OFFSET: - case PROP_CURSOR_POSITION: - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -gtk_secure_entry_get_property(GObject * object, - guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(object); - - switch (prop_id) { - case PROP_CURSOR_POSITION: - g_value_set_int(value, entry->current_pos); - break; - case PROP_SELECTION_BOUND: - g_value_set_int(value, entry->selection_bound); - break; - case PROP_MAX_LENGTH: - g_value_set_int(value, entry->text_max_length); - break; - case PROP_HAS_FRAME: - g_value_set_boolean(value, entry->has_frame); - break; - case PROP_INVISIBLE_CHAR: - g_value_set_uint(value, entry->invisible_char); - break; - case PROP_ACTIVATES_DEFAULT: - g_value_set_boolean(value, entry->activates_default); - break; - case PROP_WIDTH_CHARS: - g_value_set_int(value, entry->width_chars); - break; - case PROP_SCROLL_OFFSET: - g_value_set_int(value, entry->scroll_offset); - break; - case PROP_TEXT: - g_value_set_string(value, gtk_secure_entry_get_text(entry)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -gtk_secure_entry_init(GtkSecureEntry * entry) -{ - gtk_widget_set_can_focus (GTK_WIDGET(entry), TRUE); - - entry->text_size = MIN_SIZE; - WITH_SECURE_MEM(entry->text = g_malloc(entry->text_size)); - entry->text[0] = '\0'; - - entry->invisible_char = '*'; - entry->width_chars = -1; - entry->is_cell_renderer = FALSE; - entry->editing_canceled = FALSE; - entry->has_frame = TRUE; - - /* This object is completely private. No external entity can gain a reference - * to it; so we create it here and destroy it in finalize(). - */ - entry->im_context = gtk_im_multicontext_new(); - - g_signal_connect(entry->im_context, "commit", - G_CALLBACK(gtk_secure_entry_commit_cb), entry); - g_signal_connect(entry->im_context, "preedit_changed", - G_CALLBACK(gtk_secure_entry_preedit_changed_cb), - entry); - g_signal_connect(entry->im_context, "retrieve_surrounding", - G_CALLBACK(gtk_secure_entry_retrieve_surrounding_cb), - entry); - g_signal_connect(entry->im_context, "delete_surrounding", - G_CALLBACK(gtk_secure_entry_delete_surrounding_cb), - entry); -} - -static void -gtk_secure_entry_finalize(GObject * object) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(object); - - if (entry->cached_layout) - g_object_unref(entry->cached_layout); - - g_object_unref(entry->im_context); - - if (entry->blink_timeout) - g_source_remove(entry->blink_timeout); - - if (entry->recompute_idle) - g_source_remove(entry->recompute_idle); - - entry->text_size = 0; - - if (entry->text) - WITH_SECURE_MEM(g_free(entry->text)); - entry->text = NULL; - - G_OBJECT_CLASS(parent_class)->finalize(object); -} - -static void -gtk_secure_entry_realize(GtkWidget * widget) -{ - GtkSecureEntry *entry; - GtkEditable *editable; - GdkWindow *window; - GtkStyle *style; - GdkWindowAttr attributes; - gint attributes_mask; - - gtk_widget_set_realized (widget, TRUE); - - entry = GTK_SECURE_ENTRY(widget); - editable = GTK_EDITABLE(widget); - - attributes.window_type = GDK_WINDOW_CHILD; - - get_widget_window_size(entry, &attributes.x, &attributes.y, - &attributes.width, &attributes.height); - - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.visual = gtk_widget_get_visual(widget); - attributes.colormap = gtk_widget_get_colormap(widget); - attributes.event_mask = gtk_widget_get_events(widget); - attributes.event_mask |= (GDK_EXPOSURE_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_BUTTON1_MOTION_MASK | - GDK_BUTTON3_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK | - GDK_POINTER_MOTION_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK); - attributes_mask = - GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - - window = gdk_window_new(gtk_widget_get_parent_window(widget), - &attributes, attributes_mask); - gtk_widget_set_window (widget, window); - gdk_window_set_user_data(window, entry); - - get_text_area_size(entry, &attributes.x, &attributes.y, - &attributes.width, &attributes.height); - - attributes.cursor = - gdk_cursor_new_for_display(gtk_widget_get_display(widget), - GDK_XTERM); - attributes_mask |= GDK_WA_CURSOR; - - entry->text_area = - gdk_window_new(window, &attributes, attributes_mask); - gdk_window_set_user_data(entry->text_area, entry); - - gdk_cursor_unref(attributes.cursor); - - style = gtk_widget_get_style (widget); - style = gtk_style_attach(style, window); - gtk_widget_set_style (widget, style); - - gdk_window_set_background(window, - &style->base[gtk_widget_get_state (widget)]); - gdk_window_set_background(entry->text_area, - &style->base[gtk_widget_get_state (widget)]); - - gdk_window_show(entry->text_area); - - gtk_im_context_set_client_window(entry->im_context, entry->text_area); - - gtk_secure_entry_adjust_scroll(entry); -} - -static void -gtk_secure_entry_unrealize(GtkWidget * widget) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget); - - gtk_secure_entry_reset_layout(entry); - - gtk_im_context_set_client_window(entry->im_context, NULL); - - if (entry->text_area) { - gdk_window_set_user_data(entry->text_area, NULL); - gdk_window_destroy(entry->text_area); - entry->text_area = NULL; - } - - if (GTK_WIDGET_CLASS(parent_class)->unrealize) - (*GTK_WIDGET_CLASS(parent_class)->unrealize) (widget); -} - -static void -get_borders(GtkSecureEntry * entry, gint * xborder, gint * yborder) -{ - GtkWidget *widget = GTK_WIDGET(entry); - GtkStyle *style; - gint focus_width; - gboolean interior_focus; - - gtk_widget_style_get(widget, - "interior-focus", &interior_focus, - "focus-line-width", &focus_width, NULL); - - style = gtk_widget_get_style (widget); - if (entry->has_frame) { - *xborder = style->xthickness; - *yborder = style->ythickness; - } else { - *xborder = 0; - *yborder = 0; - } - - if (!interior_focus) { - *xborder += focus_width; - *yborder += focus_width; - } -} - -static void -gtk_secure_entry_size_request(GtkWidget * widget, - GtkRequisition * requisition) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget); - GtkStyle *style; - PangoFontMetrics *metrics; - gint xborder, yborder; - PangoContext *context; - - style = gtk_widget_get_style (widget); - context = gtk_widget_get_pango_context(widget); - metrics = pango_context_get_metrics(context, - style->font_desc, - pango_context_get_language - (context)); - - entry->ascent = pango_font_metrics_get_ascent(metrics); - entry->descent = pango_font_metrics_get_descent(metrics); - - get_borders(entry, &xborder, &yborder); - - xborder += INNER_BORDER; - yborder += INNER_BORDER; - - if (entry->width_chars < 0) - requisition->width = MIN_SECURE_ENTRY_WIDTH + xborder * 2; - else { - gint char_width = - pango_font_metrics_get_approximate_char_width(metrics); - gint digit_width = - pango_font_metrics_get_approximate_digit_width(metrics); - gint char_pixels = - (MAX(char_width, digit_width) + PANGO_SCALE - 1) / PANGO_SCALE; - - requisition->width = - char_pixels * entry->width_chars + xborder * 2; - } - - requisition->height = - PANGO_PIXELS(entry->ascent + entry->descent) + yborder * 2; - - pango_font_metrics_unref(metrics); -} - -static void -get_text_area_size(GtkSecureEntry * entry, - gint * x, gint * y, gint * width, gint * height) -{ - gint xborder, yborder; - GtkRequisition requisition; - GtkWidget *widget = GTK_WIDGET(entry); - GtkAllocation allocation; - - gtk_widget_get_child_requisition(widget, &requisition); - gtk_widget_get_allocation (GTK_WIDGET(entry), &allocation); - - get_borders(entry, &xborder, &yborder); - - if (x) - *x = xborder; - - if (y) - *y = yborder; - - if (width) - *width = allocation.width - xborder * 2; - - if (height) - *height = requisition.height - yborder * 2; -} - -static void -get_widget_window_size(GtkSecureEntry * entry, - gint * x, gint * y, gint * width, gint * height) -{ - GtkRequisition requisition; - GtkWidget *widget = GTK_WIDGET(entry); - GtkAllocation allocation; - - gtk_widget_get_child_requisition(widget, &requisition); - gtk_widget_get_allocation (GTK_WIDGET(entry), &allocation); - - if (x) - *x = allocation.x; - - if (y) { - if (entry->is_cell_renderer) - *y = allocation.y; - else - *y = allocation.y + (allocation.height - - requisition.height) / 2; - } - - if (width) - *width = allocation.width; - - if (height) { - if (entry->is_cell_renderer) - *height = allocation.height; - else - *height = requisition.height; - } -} - -static void -gtk_secure_entry_size_allocate(GtkWidget * widget, - GtkAllocation * allocation) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget); - - gtk_widget_set_allocation (widget, allocation); - - if (gtk_widget_get_realized (widget)) { - /* We call gtk_widget_get_child_requisition, since we want (for - * backwards compatibility reasons) the realization here to - * be affected by the usize of the entry, if set - */ - gint x, y, width, height; - - get_widget_window_size(entry, &x, &y, &width, &height); - - gdk_window_move_resize(gtk_widget_get_window (widget), - x, y, width, height); - - get_text_area_size(entry, &x, &y, &width, &height); - - gdk_window_move_resize(entry->text_area, x, y, width, height); - - gtk_secure_entry_recompute(entry); - } -} - -static void -gtk_secure_entry_draw_frame(GtkWidget * widget) -{ - GtkStyle *style; - GdkWindow *window; - gint x = 0, y = 0; - gint width, height; - gboolean interior_focus; - gint focus_width; - - gtk_widget_style_get(widget, - "interior-focus", &interior_focus, - "focus-line-width", &focus_width, NULL); - - window = gtk_widget_get_window (widget); - gdk_drawable_get_size(window, &width, &height); - - if (gtk_widget_has_focus (widget) && !interior_focus) { - x += focus_width; - y += focus_width; - width -= 2 * focus_width; - height -= 2 * focus_width; - } - - style = gtk_widget_get_style (widget); - gtk_paint_shadow(style, window, - GTK_STATE_NORMAL, GTK_SHADOW_IN, - NULL, widget, "entry", x, y, width, height); - - if (gtk_widget_has_focus (widget) && !interior_focus) { - x -= focus_width; - y -= focus_width; - width += 2 * focus_width; - height += 2 * focus_width; - - gtk_paint_focus(style, window, - gtk_widget_get_state (widget), NULL, widget, "entry", 0, - 0, width, height); - } -} - -static gint -gtk_secure_entry_expose(GtkWidget * widget, GdkEventExpose * event) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget); - GtkStyle *style; - - if (gtk_widget_get_window (widget) == event->window) - gtk_secure_entry_draw_frame(widget); - else if (entry->text_area == event->window) { - gint area_width, area_height; - - get_text_area_size(entry, NULL, NULL, &area_width, &area_height); - - - style = gtk_widget_get_style (widget); - gtk_paint_flat_box(style, entry->text_area, - gtk_widget_get_state (widget), GTK_SHADOW_NONE, - NULL, widget, "entry_bg", - 0, 0, area_width, area_height); - - if ((entry->invisible_char != 0) && - gtk_widget_has_focus (widget) && - entry->selection_bound == entry->current_pos - && entry->cursor_visible) - gtk_secure_entry_draw_cursor(GTK_SECURE_ENTRY(widget)); - - gtk_secure_entry_draw_text(GTK_SECURE_ENTRY(widget)); - } - - return FALSE; -} - -static gint -gtk_secure_entry_button_press(GtkWidget * widget, GdkEventButton * event) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget); - gint tmp_pos; - - if (event->window != entry->text_area || - (entry->button && event->button != entry->button)) - return FALSE; - - entry->button = event->button; - - if (!gtk_widget_has_focus (widget)) { - entry->in_click = TRUE; - gtk_widget_grab_focus(widget); - entry->in_click = FALSE; - } - - tmp_pos = - gtk_secure_entry_find_position(entry, - event->x + entry->scroll_offset); - - if (event->button == 1) { - switch (event->type) { - case GDK_BUTTON_PRESS: - gtk_secure_entry_set_positions(entry, tmp_pos, tmp_pos); - break; - - default: - break; - } - - return TRUE; - } - - return FALSE; -} - -static gint -gtk_secure_entry_button_release(GtkWidget * widget, GdkEventButton * event) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget); - - if (event->window != entry->text_area - || entry->button != event->button) - return FALSE; - - entry->button = 0; - - return TRUE; -} - -static gint -gtk_secure_entry_motion_notify(GtkWidget * widget, GdkEventMotion * event) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget); - gint tmp_pos; - - if (entry->mouse_cursor_obscured) { - GdkCursor *cursor; - - cursor = - gdk_cursor_new_for_display(gtk_widget_get_display(widget), - GDK_XTERM); - gdk_window_set_cursor(entry->text_area, cursor); - gdk_cursor_unref(cursor); - entry->mouse_cursor_obscured = FALSE; - } - - if (event->window != entry->text_area || entry->button != 1) - return FALSE; - - if (event->is_hint || (entry->text_area != event->window)) - gdk_window_get_pointer(entry->text_area, NULL, NULL, NULL); - - { - gint height; - gdk_drawable_get_size(entry->text_area, NULL, &height); - - if (event->y < 0) - tmp_pos = 0; - else if (event->y >= height) - tmp_pos = entry->text_length; - else - tmp_pos = - gtk_secure_entry_find_position(entry, - event->x + - entry->scroll_offset); - - gtk_secure_entry_set_positions(entry, tmp_pos, -1); - } - - return TRUE; -} - -static void -set_invisible_cursor(GdkWindow * window) -{ - GdkBitmap *empty_bitmap; - GdkCursor *cursor; - GdkColor useless; - char invisible_cursor_bits[] = { 0x0 }; - - useless.red = useless.green = useless.blue = 0; - useless.pixel = 0; - - empty_bitmap = gdk_bitmap_create_from_data(window, - invisible_cursor_bits, 1, - 1); - - cursor = gdk_cursor_new_from_pixmap(empty_bitmap, - empty_bitmap, - &useless, &useless, 0, 0); - - gdk_window_set_cursor(window, cursor); - - gdk_cursor_unref(cursor); - - g_object_unref(empty_bitmap); -} - -static void -gtk_secure_entry_obscure_mouse_cursor(GtkSecureEntry * entry) -{ - if (entry->mouse_cursor_obscured) - return; - - set_invisible_cursor(entry->text_area); - - entry->mouse_cursor_obscured = TRUE; -} - -static gint -gtk_secure_entry_key_press(GtkWidget * widget, GdkEventKey * event) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget); - - gtk_secure_entry_pend_cursor_blink(entry); - - if (gtk_im_context_filter_keypress(entry->im_context, event)) { - gtk_secure_entry_obscure_mouse_cursor(entry); - entry->need_im_reset = TRUE; - return TRUE; - } - - if (GTK_WIDGET_CLASS(parent_class)->key_press_event(widget, event)) - /* Activate key bindings - */ - return TRUE; - - return FALSE; -} - -static gint -gtk_secure_entry_key_release(GtkWidget * widget, GdkEventKey * event) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget); - - if (gtk_im_context_filter_keypress(entry->im_context, event)) { - entry->need_im_reset = TRUE; - return TRUE; - } - - return GTK_WIDGET_CLASS(parent_class)->key_release_event(widget, - event); -} - -static gint -gtk_secure_entry_focus_in(GtkWidget * widget, - GdkEventFocus * event G_GNUC_UNUSED) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget); - - gtk_widget_queue_draw(widget); - - entry->need_im_reset = TRUE; - gtk_im_context_focus_in(entry->im_context); - - g_signal_connect(gdk_keymap_get_for_display - (gtk_widget_get_display(widget)), "direction_changed", - G_CALLBACK(gtk_secure_entry_keymap_direction_changed), - entry); - - gtk_secure_entry_check_cursor_blink(entry); - - return FALSE; -} - -static gint -gtk_secure_entry_focus_out(GtkWidget * widget, - GdkEventFocus * event G_GNUC_UNUSED) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget); - - gtk_widget_queue_draw(widget); - - entry->need_im_reset = TRUE; - gtk_im_context_focus_out(entry->im_context); - - gtk_secure_entry_check_cursor_blink(entry); - - g_signal_handlers_disconnect_by_func(gdk_keymap_get_for_display - (gtk_widget_get_display(widget)), - gtk_secure_entry_keymap_direction_changed, - entry); - - return FALSE; -} - -static void -gtk_secure_entry_grab_focus(GtkWidget * widget) -{ - GtkWidget *tmp; - GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget); - gboolean select_on_focus; - - gtk_widget_set_can_default (widget, TRUE); - GTK_WIDGET_CLASS(parent_class)->grab_focus(widget); - - /* read current select on focus setting from GtkEntry */ - tmp = gtk_entry_new (); - g_object_get(gtk_widget_get_settings(tmp), - "gtk-entry-select-on-focus", &select_on_focus, NULL); - gtk_widget_destroy (tmp); - - if (select_on_focus && !entry->in_click) - gtk_editable_select_region(GTK_EDITABLE(widget), 0, -1); -} - -static void -gtk_secure_entry_direction_changed(GtkWidget * widget, - GtkTextDirection previous_dir) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget); - - gtk_secure_entry_recompute(entry); - - GTK_WIDGET_CLASS(parent_class)->direction_changed(widget, - previous_dir); -} - -static void -gtk_secure_entry_state_changed(GtkWidget * widget, - GtkStateType previous_state G_GNUC_UNUSED) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget); - GtkStyle *style; - - style = gtk_widget_get_style (widget); - if (gtk_widget_get_realized (widget)) { - gdk_window_set_background(gtk_widget_get_window(widget), - &style->base[gtk_widget_get_state (widget)]); - gdk_window_set_background(entry->text_area, - &style->base[gtk_widget_get_state (widget)]); - } - - if (!gtk_widget_is_sensitive (widget)) { - /* Clear any selection */ - gtk_editable_select_region(GTK_EDITABLE(entry), entry->current_pos, - entry->current_pos); - } - - gtk_widget_queue_draw(widget); -} - -static void -gtk_secure_entry_screen_changed(GtkWidget * widget, - GdkScreen * old_screen G_GNUC_UNUSED) -{ - gtk_secure_entry_recompute(GTK_SECURE_ENTRY(widget)); -} - -/* GtkEditable method implementations - */ -static void -gtk_secure_entry_insert_text(GtkEditable * editable, - const gchar * new_text, - gint new_text_length, gint * position) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(editable); - gchar *text; - - if (*position < 0 || *position > entry->text_length) - *position = entry->text_length; - - g_object_ref(editable); - - WITH_SECURE_MEM(text = g_new(gchar, new_text_length + 1)); - - text[new_text_length] = '\0'; - strncpy(text, new_text, new_text_length); - - g_signal_emit_by_name(editable, "insert_text", text, new_text_length, - position); - - WITH_SECURE_MEM(g_free(text)); - - g_object_unref(editable); -} - -static void -gtk_secure_entry_delete_text(GtkEditable * editable, - gint start_pos, gint end_pos) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(editable); - - if (end_pos < 0 || end_pos > entry->text_length) - end_pos = entry->text_length; - if (start_pos < 0) - start_pos = 0; - if (start_pos > end_pos) - start_pos = end_pos; - - g_object_ref(editable); - - g_signal_emit_by_name(editable, "delete_text", start_pos, end_pos); - - g_object_unref(editable); -} - -static void -gtk_secure_entry_set_position_internal(GtkSecureEntry * entry, - gint position, gboolean reset_im) -{ - if (position < 0 || position > entry->text_length) - position = entry->text_length; - - if (position != entry->current_pos || - position != entry->selection_bound) { - if (reset_im) - gtk_secure_entry_reset_im_context(entry); - gtk_secure_entry_set_positions(entry, position, position); - } -} - -static void -gtk_secure_entry_real_set_position(GtkEditable * editable, gint position) -{ - gtk_secure_entry_set_position_internal(GTK_SECURE_ENTRY(editable), - position, TRUE); -} - -static gint -gtk_secure_entry_get_position(GtkEditable * editable) -{ - return GTK_SECURE_ENTRY(editable)->current_pos; -} - -static void -gtk_secure_entry_set_selection_bounds(GtkEditable * editable, - gint start, gint end) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(editable); - - if (start < 0) - start = entry->text_length; - if (end < 0) - end = entry->text_length; - - gtk_secure_entry_reset_im_context(entry); - - gtk_secure_entry_set_positions(entry, - MIN(end, entry->text_length), - MIN(start, entry->text_length)); -} - -static gboolean -gtk_secure_entry_get_selection_bounds(GtkEditable * editable, - gint * start, gint * end) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(editable); - - *start = entry->selection_bound; - *end = entry->current_pos; - - return (entry->selection_bound != entry->current_pos); -} - -static void -gtk_secure_entry_style_set(GtkWidget * widget, GtkStyle * previous_style) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(widget); - GtkStyle *style; - - gtk_secure_entry_recompute(entry); - - style = gtk_widget_get_style (widget); - if (previous_style && gtk_widget_get_realized (widget)) { - gdk_window_set_background(gtk_widget_get_window (widget), - &style->base[gtk_widget_get_state (widget)]); - gdk_window_set_background(entry->text_area, - &style->base[gtk_widget_get_state (widget)]); - } -} - -/* GtkCellEditable method implementations - */ -static void -gtk_cell_editable_secure_entry_activated(GtkSecureEntry * entry, - gpointer data G_GNUC_UNUSED) -{ - gtk_cell_editable_editing_done(GTK_CELL_EDITABLE(entry)); - gtk_cell_editable_remove_widget(GTK_CELL_EDITABLE(entry)); -} - -static gboolean -gtk_cell_editable_key_press_event(GtkSecureEntry * entry, - GdkEventKey * key_event, - gpointer data G_GNUC_UNUSED) -{ - if (key_event->keyval == GDK_Escape) { - entry->editing_canceled = TRUE; - gtk_cell_editable_editing_done(GTK_CELL_EDITABLE(entry)); - gtk_cell_editable_remove_widget(GTK_CELL_EDITABLE(entry)); - - return TRUE; - } - - /* override focus */ - if (key_event->keyval == GDK_Up || key_event->keyval == GDK_Down) { - gtk_cell_editable_editing_done(GTK_CELL_EDITABLE(entry)); - gtk_cell_editable_remove_widget(GTK_CELL_EDITABLE(entry)); - - return TRUE; - } - - return FALSE; -} - -static void -gtk_secure_entry_start_editing(GtkCellEditable * cell_editable, - GdkEvent * event G_GNUC_UNUSED) -{ - GTK_SECURE_ENTRY(cell_editable)->is_cell_renderer = TRUE; - - g_signal_connect(cell_editable, "activate", - G_CALLBACK(gtk_cell_editable_secure_entry_activated), NULL); - g_signal_connect(cell_editable, "key_press_event", - G_CALLBACK(gtk_cell_editable_key_press_event), NULL); -} - -/* Default signal handlers - */ -static void -gtk_secure_entry_real_insert_text(GtkEditable * editable, - const gchar * new_text, - gint new_text_length, gint * position) -{ - gint _index; - gint n_chars; - - GtkSecureEntry *entry = GTK_SECURE_ENTRY(editable); - - if (new_text_length < 0) - new_text_length = strlen(new_text); - - n_chars = g_utf8_strlen(new_text, new_text_length); - if (entry->text_max_length > 0 - && n_chars + entry->text_length > entry->text_max_length) { - gdk_display_beep(gtk_widget_get_display(GTK_WIDGET(entry))); - n_chars = entry->text_max_length - entry->text_length; - new_text_length = - g_utf8_offset_to_pointer(new_text, n_chars) - new_text; - } - - if (new_text_length + entry->n_bytes + 1 > entry->text_size) { - while (new_text_length + entry->n_bytes + 1 > entry->text_size) { - if (entry->text_size == 0) - entry->text_size = MIN_SIZE; - else { - if (2 * (guint) entry->text_size < MAX_SIZE && - 2 * (guint) entry->text_size > entry->text_size) - entry->text_size *= 2; - else { - entry->text_size = MAX_SIZE; - if (new_text_length > - (gint) entry->text_size - (gint) entry->n_bytes - - 1) { - new_text_length = - (gint) entry->text_size - - (gint) entry->n_bytes - 1; - new_text_length = - g_utf8_find_prev_char(new_text, - new_text + - new_text_length + 1) - - new_text; - n_chars = g_utf8_strlen(new_text, new_text_length); - } - break; - } - } - } - - WITH_SECURE_MEM(entry->text = - g_realloc(entry->text, entry->text_size)); - } - - _index = g_utf8_offset_to_pointer(entry->text, *position) - entry->text; - - g_memmove(entry->text + _index + new_text_length, entry->text + _index, - entry->n_bytes - _index); - memcpy(entry->text + _index, new_text, new_text_length); - - entry->n_bytes += new_text_length; - entry->text_length += n_chars; - - /* NUL terminate for safety and convenience */ - entry->text[entry->n_bytes] = '\0'; - - if (entry->current_pos > *position) - entry->current_pos += n_chars; - - if (entry->selection_bound > *position) - entry->selection_bound += n_chars; - - *position += n_chars; - - gtk_secure_entry_recompute(entry); - - g_signal_emit_by_name(editable, "changed"); - g_object_notify(G_OBJECT(editable), "text"); -} - -static void -gtk_secure_entry_real_delete_text(GtkEditable * editable, - gint start_pos, gint end_pos) -{ - GtkSecureEntry *entry = GTK_SECURE_ENTRY(editable); - - if (start_pos < 0) - start_pos = 0; - if (end_pos < 0 || end_pos > entry->text_length) - end_pos = entry->text_length; - - if (start_pos < end_pos) { - gint start_index = - g_utf8_offset_to_pointer(entry->text, start_pos) - entry->text; - gint end_index = - g_utf8_offset_to_pointer(entry->text, end_pos) - entry->text; - gint current_pos; - gint selection_bound; - - g_memmove(entry->text + start_index, entry->text + end_index, - entry->n_bytes + 1 - end_index); - entry->text_length -= (end_pos - start_pos); - entry->n_bytes -= (end_index - start_index); - - current_pos = entry->current_pos; - if (current_pos > start_pos) - current_pos -= MIN(current_pos, end_pos) - start_pos; - - selection_bound = entry->selection_bound; - if (selection_bound > start_pos) - selection_bound -= MIN(selection_bound, end_pos) - start_pos; - - gtk_secure_entry_set_positions(entry, current_pos, - selection_bound); - - gtk_secure_entry_recompute(entry); - - g_signal_emit_by_name(editable, "changed"); - g_object_notify(G_OBJECT(editable), "text"); - } -} - -/* Compute the X position for an offset that corresponds to the "more important - * cursor position for that offset. We use this when trying to guess to which - * end of the selection we should go to when the user hits the left or - * right arrow key. - */ -static gint -get_better_cursor_x(GtkSecureEntry * entry, gint offset) -{ - GdkKeymap *keymap = - gdk_keymap_get_for_display(gtk_widget_get_display - (GTK_WIDGET(entry))); - PangoDirection keymap_direction = gdk_keymap_get_direction(keymap); - gboolean split_cursor; - - PangoLayout *layout = gtk_secure_entry_ensure_layout(entry, TRUE); - const gchar *text = pango_layout_get_text(layout); - gint _index = g_utf8_offset_to_pointer(text, offset) - text; - - PangoRectangle strong_pos, weak_pos; - - g_object_get(gtk_widget_get_settings(GTK_WIDGET(entry)), - "gtk-split-cursor", &split_cursor, NULL); - - pango_layout_get_cursor_pos(layout, _index, &strong_pos, &weak_pos); - - if (split_cursor) - return strong_pos.x / PANGO_SCALE; - else - return (keymap_direction == - entry->resolved_dir) ? strong_pos.x / - PANGO_SCALE : weak_pos.x / PANGO_SCALE; -} - -static void -gtk_secure_entry_move_cursor(GtkSecureEntry * entry, - GtkMovementStep step, - gint count, gboolean extend_selection) -{ - gint new_pos = entry->current_pos; - - gtk_secure_entry_reset_im_context(entry); - - if (entry->current_pos != entry->selection_bound && !extend_selection) { - /* If we have a current selection and aren't extending it, move to the - * start/or end of the selection as appropriate - */ - switch (step) { - case GTK_MOVEMENT_VISUAL_POSITIONS: - { - gint current_x = - get_better_cursor_x(entry, entry->current_pos); - gint bound_x = - get_better_cursor_x(entry, entry->selection_bound); - - if (count < 0) - new_pos = - current_x < - bound_x ? entry->current_pos : entry-> - selection_bound; - else - new_pos = - current_x > - bound_x ? entry->current_pos : entry-> - selection_bound; - - break; - } - case GTK_MOVEMENT_LOGICAL_POSITIONS: - case GTK_MOVEMENT_DISPLAY_LINE_ENDS: - case GTK_MOVEMENT_PARAGRAPH_ENDS: - case GTK_MOVEMENT_BUFFER_ENDS: - new_pos = count < 0 ? 0 : entry->text_length; - break; - case GTK_MOVEMENT_WORDS: - case GTK_MOVEMENT_DISPLAY_LINES: - case GTK_MOVEMENT_PARAGRAPHS: - case GTK_MOVEMENT_PAGES: - case GTK_MOVEMENT_HORIZONTAL_PAGES: - break; - } - } else { - switch (step) { - case GTK_MOVEMENT_LOGICAL_POSITIONS: - new_pos = - gtk_secure_entry_move_logically(entry, new_pos, count); - break; - case GTK_MOVEMENT_VISUAL_POSITIONS: - new_pos = - gtk_secure_entry_move_visually(entry, new_pos, count); - break; - case GTK_MOVEMENT_DISPLAY_LINE_ENDS: - case GTK_MOVEMENT_PARAGRAPH_ENDS: - case GTK_MOVEMENT_BUFFER_ENDS: - new_pos = count < 0 ? 0 : entry->text_length; - break; - case GTK_MOVEMENT_WORDS: - case GTK_MOVEMENT_DISPLAY_LINES: - case GTK_MOVEMENT_PARAGRAPHS: - case GTK_MOVEMENT_PAGES: - case GTK_MOVEMENT_HORIZONTAL_PAGES: - break; - } - } - - if (extend_selection) - gtk_editable_select_region(GTK_EDITABLE(entry), - entry->selection_bound, new_pos); - else - gtk_editable_set_position(GTK_EDITABLE(entry), new_pos); - - gtk_secure_entry_pend_cursor_blink(entry); -} - -static void -gtk_secure_entry_insert_at_cursor(GtkSecureEntry * entry, - const gchar * str) -{ - GtkEditable *editable = GTK_EDITABLE(entry); - gint pos = entry->current_pos; - - gtk_secure_entry_reset_im_context(entry); - - gtk_editable_insert_text(editable, str, -1, &pos); - gtk_editable_set_position(editable, pos); -} - -static void -gtk_secure_entry_delete_from_cursor(GtkSecureEntry * entry, - GtkDeleteType type, gint count) -{ - GtkEditable *editable = GTK_EDITABLE(entry); - gint start_pos = entry->current_pos; - gint end_pos = entry->current_pos; - - gtk_secure_entry_reset_im_context(entry); - - if (entry->selection_bound != entry->current_pos) { - gtk_editable_delete_selection(editable); - return; - } - - switch (type) { - case GTK_DELETE_CHARS: - end_pos = - gtk_secure_entry_move_logically(entry, entry->current_pos, - count); - gtk_editable_delete_text(editable, MIN(start_pos, end_pos), - MAX(start_pos, end_pos)); - break; - case GTK_DELETE_DISPLAY_LINE_ENDS: - case GTK_DELETE_PARAGRAPH_ENDS: - if (count < 0) - gtk_editable_delete_text(editable, 0, entry->current_pos); - else - gtk_editable_delete_text(editable, entry->current_pos, -1); - break; - case GTK_DELETE_DISPLAY_LINES: - case GTK_DELETE_PARAGRAPHS: - gtk_editable_delete_text(editable, 0, -1); - break; - default: - break; - } - - gtk_secure_entry_pend_cursor_blink(entry); -} - -static void -gtk_secure_entry_real_activate(GtkSecureEntry * entry) -{ - GtkWindow *window; - GtkWidget *toplevel; - GtkWidget *widget; - - widget = GTK_WIDGET(entry); - - if (entry->activates_default) { - toplevel = gtk_widget_get_toplevel(widget); - if (GTK_IS_WINDOW(toplevel)) { - GtkWidget *default_widget; - - window = GTK_WINDOW(toplevel); - if (window) - default_widget = gtk_window_get_default_widget (window); - else - return; - - if (widget != default_widget && - !(widget == gtk_window_get_focus (window) && - (!default_widget - || !gtk_widget_get_sensitive (default_widget)))) - gtk_window_activate_default(window); - } - } -} - -static void -gtk_secure_entry_keymap_direction_changed(GdkKeymap * keymap G_GNUC_UNUSED, - GtkSecureEntry * entry) -{ - gtk_secure_entry_recompute(entry); -} - -/* IM Context Callbacks - */ - -static void -gtk_secure_entry_commit_cb(GtkIMContext * context G_GNUC_UNUSED, - const gchar * str, GtkSecureEntry * entry) -{ - gtk_secure_entry_enter_text(entry, str); -} - -static void -gtk_secure_entry_preedit_changed_cb(GtkIMContext * context G_GNUC_UNUSED, - GtkSecureEntry * entry) -{ - gchar *preedit_string; - gint cursor_pos; - - gtk_im_context_get_preedit_string(entry->im_context, - &preedit_string, NULL, &cursor_pos); - entry->preedit_length = strlen(preedit_string); - cursor_pos = CLAMP(cursor_pos, 0, g_utf8_strlen(preedit_string, -1)); - entry->preedit_cursor = cursor_pos; - g_free(preedit_string); - - gtk_secure_entry_recompute(entry); -} - -static gboolean -gtk_secure_entry_retrieve_surrounding_cb(GtkIMContext * context, - GtkSecureEntry * entry) -{ - gtk_im_context_set_surrounding(context, - entry->text, - entry->n_bytes, - g_utf8_offset_to_pointer(entry->text, - entry-> - current_pos) - - entry->text); - - return TRUE; -} - -static gboolean -gtk_secure_entry_delete_surrounding_cb(GtkIMContext * slave G_GNUC_UNUSED, - gint offset, - gint n_chars, - GtkSecureEntry * entry) -{ - gtk_editable_delete_text(GTK_EDITABLE(entry), - entry->current_pos + offset, - entry->current_pos + offset + n_chars); - - return TRUE; -} - -/* Internal functions - */ - -/* Used for im_commit_cb and inserting Unicode chars */ -static void -gtk_secure_entry_enter_text(GtkSecureEntry * entry, const gchar * str) -{ - GtkEditable *editable = GTK_EDITABLE(entry); - gint tmp_pos; - - if (gtk_editable_get_selection_bounds(editable, NULL, NULL)) - gtk_editable_delete_selection(editable); - else { - if (entry->overwrite_mode) - gtk_secure_entry_delete_from_cursor(entry, GTK_DELETE_CHARS, - 1); - } - - tmp_pos = entry->current_pos; - gtk_editable_insert_text(editable, str, strlen(str), &tmp_pos); - gtk_secure_entry_set_position_internal(entry, tmp_pos, FALSE); -} - -/* All changes to entry->current_pos and entry->selection_bound - * should go through this function. - */ -static void -gtk_secure_entry_set_positions(GtkSecureEntry * entry, - gint current_pos, gint selection_bound) -{ - gboolean changed = FALSE; - - g_object_freeze_notify(G_OBJECT(entry)); - - if (current_pos != -1 && entry->current_pos != current_pos) { - entry->current_pos = current_pos; - changed = TRUE; - - g_object_notify(G_OBJECT(entry), "cursor_position"); - } - - if (selection_bound != -1 && entry->selection_bound != selection_bound) { - entry->selection_bound = selection_bound; - changed = TRUE; - - g_object_notify(G_OBJECT(entry), "selection_bound"); - } - - g_object_thaw_notify(G_OBJECT(entry)); - - if (changed) - gtk_secure_entry_recompute(entry); -} - -static void -gtk_secure_entry_reset_layout(GtkSecureEntry * entry) -{ - if (entry->cached_layout) { - g_object_unref(entry->cached_layout); - entry->cached_layout = NULL; - } -} - -static void -update_im_cursor_location(GtkSecureEntry * entry) -{ - GdkRectangle area; - gint strong_x; - gint strong_xoffset; - gint area_width, area_height; - - gtk_secure_entry_get_cursor_locations(entry, &strong_x, NULL); - get_text_area_size(entry, NULL, NULL, &area_width, &area_height); - - strong_xoffset = strong_x - entry->scroll_offset; - if (strong_xoffset < 0) { - strong_xoffset = 0; - } else if (strong_xoffset > area_width) { - strong_xoffset = area_width; - } - area.x = strong_xoffset; - area.y = 0; - area.width = 0; - area.height = area_height; - - gtk_im_context_set_cursor_location(entry->im_context, &area); -} - -static gboolean -recompute_idle_func(gpointer data) -{ - GtkSecureEntry *entry; - - GDK_THREADS_ENTER(); - - entry = GTK_SECURE_ENTRY(data); - - entry->recompute_idle = 0; - - if (gtk_widget_has_screen(GTK_WIDGET(entry))) { - gtk_secure_entry_adjust_scroll(entry); - gtk_secure_entry_queue_draw(entry); - - update_im_cursor_location(entry); - } - - GDK_THREADS_LEAVE(); - - return FALSE; -} - -static void -gtk_secure_entry_recompute(GtkSecureEntry * entry) -{ - gtk_secure_entry_reset_layout(entry); - gtk_secure_entry_check_cursor_blink(entry); - - if (!entry->recompute_idle) { - entry->recompute_idle = g_idle_add_full(G_PRIORITY_HIGH_IDLE + 15, /* between resize and redraw */ - recompute_idle_func, entry, - NULL); - } -} - -static void -append_char(GString * str, gunichar ch, gint count) -{ - gint i; - gint char_len; - gchar buf[7]; - - char_len = g_unichar_to_utf8(ch, buf); - - i = 0; - while (i < count) { - g_string_append_len(str, buf, char_len); - ++i; - } -} - -static PangoLayout * -gtk_secure_entry_create_layout(GtkSecureEntry * entry, - gboolean include_preedit) -{ - GtkWidget *widget = GTK_WIDGET(entry); - PangoLayout *layout = gtk_widget_create_pango_layout(widget, NULL); - PangoAttrList *tmp_attrs = pango_attr_list_new(); - - gchar *preedit_string = NULL; - gint preedit_length = 0; - PangoAttrList *preedit_attrs = NULL; - - pango_layout_set_single_paragraph_mode(layout, TRUE); - - if (include_preedit) { - gtk_im_context_get_preedit_string(entry->im_context, - &preedit_string, &preedit_attrs, - NULL); - preedit_length = entry->preedit_length; - } - - if (preedit_length) { - GString *tmp_string = g_string_new(NULL); - - gint cursor_index = g_utf8_offset_to_pointer(entry->text, - entry->current_pos) - - entry->text; - - gint ch_len; - gint preedit_len_chars; - gunichar invisible_char; - - ch_len = g_utf8_strlen(entry->text, entry->n_bytes); - preedit_len_chars = g_utf8_strlen(preedit_string, -1); - ch_len += preedit_len_chars; - - if (entry->invisible_char != 0) - invisible_char = entry->invisible_char; - else - invisible_char = ' '; /* just pick a char */ - - append_char(tmp_string, invisible_char, ch_len); - - /* Fix cursor index to point to invisible char corresponding - * to the preedit, fix preedit_length to be the length of - * the invisible chars representing the preedit - */ - cursor_index = - g_utf8_offset_to_pointer(tmp_string->str, - entry->current_pos) - - tmp_string->str; - preedit_length = - preedit_len_chars * g_unichar_to_utf8(invisible_char, - NULL); - - pango_layout_set_text(layout, tmp_string->str, tmp_string->len); - - pango_attr_list_splice(tmp_attrs, preedit_attrs, - cursor_index, preedit_length); - - g_string_free(tmp_string, TRUE); - } else { - PangoDirection pango_dir; - - pango_dir = pango_find_base_dir(entry->text, entry->n_bytes); - if (pango_dir == PANGO_DIRECTION_NEUTRAL) { - if (gtk_widget_has_focus (widget)) { - GdkDisplay *display = gtk_widget_get_display(widget); - GdkKeymap *keymap = gdk_keymap_get_for_display(display); - pango_dir = gdk_keymap_get_direction(keymap); - } else { - if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_LTR) - pango_dir = PANGO_DIRECTION_LTR; - else - pango_dir = PANGO_DIRECTION_RTL; - } - } - - pango_context_set_base_dir(gtk_widget_get_pango_context(widget), - pango_dir); - - pango_layout_set_alignment(layout, pango_dir); - - entry->resolved_dir = pango_dir; - - { - GString *str = g_string_new(NULL); - gunichar invisible_char; - - if (entry->invisible_char != 0) - invisible_char = entry->invisible_char; - else - invisible_char = ' '; /* just pick a char */ - - append_char(str, invisible_char, entry->text_length); - pango_layout_set_text(layout, str->str, str->len); - g_string_free(str, TRUE); - } - } - - pango_layout_set_attributes(layout, tmp_attrs); - - if (preedit_string) - g_free(preedit_string); - if (preedit_attrs) - pango_attr_list_unref(preedit_attrs); - - pango_attr_list_unref(tmp_attrs); - - return layout; -} - -static PangoLayout * -gtk_secure_entry_ensure_layout(GtkSecureEntry * entry, - gboolean include_preedit) -{ - if (entry->preedit_length > 0 && - !include_preedit != !entry->cache_includes_preedit) - gtk_secure_entry_reset_layout(entry); - - if (!entry->cached_layout) { - entry->cached_layout = - gtk_secure_entry_create_layout(entry, include_preedit); - entry->cache_includes_preedit = include_preedit; - } - - return entry->cached_layout; -} - -static void -get_layout_position(GtkSecureEntry * entry, gint * x, gint * y) -{ - PangoLayout *layout; - PangoRectangle logical_rect; - gint area_width, area_height; - gint y_pos; - PangoLayoutLine *line; - - layout = gtk_secure_entry_ensure_layout(entry, TRUE); - - get_text_area_size(entry, NULL, NULL, &area_width, &area_height); - - area_height = PANGO_SCALE * (area_height - 2 * INNER_BORDER); - - line = pango_layout_get_lines(layout)->data; - pango_layout_line_get_extents(line, NULL, &logical_rect); - - /* Align primarily for locale's ascent/descent */ - y_pos = ((area_height - entry->ascent - entry->descent) / 2 + - entry->ascent + logical_rect.y); - - /* Now see if we need to adjust to fit in actual drawn string */ - if (logical_rect.height > area_height) - y_pos = (area_height - logical_rect.height) / 2; - else if (y_pos < 0) - y_pos = 0; - else if (y_pos + logical_rect.height > area_height) - y_pos = area_height - logical_rect.height; - - y_pos = INNER_BORDER + y_pos / PANGO_SCALE; - - if (x) - *x = INNER_BORDER - entry->scroll_offset; - - if (y) - *y = y_pos; -} - -static void -gtk_secure_entry_draw_text(GtkSecureEntry * entry) -{ - GtkWidget *widget = GTK_WIDGET(entry); - PangoLayoutLine *line; - GtkStyle *style; - - if (entry->invisible_char == 0) - return; - - if (gtk_widget_is_drawable (widget)) { - PangoLayout *layout = gtk_secure_entry_ensure_layout(entry, TRUE); - gint x, y; - gint start_pos, end_pos; - - get_layout_position(entry, &x, &y); - - style = gtk_widget_get_style (widget); - gdk_draw_layout(entry->text_area, - style->text_gc[gtk_widget_get_state (widget)], - x, y, layout); - - if (gtk_editable_get_selection_bounds - (GTK_EDITABLE(entry), &start_pos, &end_pos)) { - gint *ranges; - gint n_ranges, i; - PangoRectangle logical_rect; - const gchar *text = pango_layout_get_text(layout); - gint start_index = - g_utf8_offset_to_pointer(text, start_pos) - text; - gint end_index = - g_utf8_offset_to_pointer(text, end_pos) - text; -#if GTK_CHECK_VERSION(2, 90, 5) - cairo_region_t *clip_region = cairo_region_create(); -#else - GdkRegion *clip_region = gdk_region_new(); -#endif - GdkGC *text_gc; - GdkGC *selection_gc; - - line = pango_layout_get_lines(layout)->data; - - pango_layout_line_get_x_ranges(line, start_index, end_index, - &ranges, &n_ranges); - - pango_layout_get_extents(layout, NULL, &logical_rect); - - if (gtk_widget_has_focus (widget)) { - selection_gc = style->base_gc[GTK_STATE_SELECTED]; - text_gc = style->text_gc[GTK_STATE_SELECTED]; - } else { - selection_gc = style->base_gc[GTK_STATE_ACTIVE]; - text_gc = style->text_gc[GTK_STATE_ACTIVE]; - } - - for (i = 0; i < n_ranges; i++) { - GdkRectangle rect; - - rect.x = - INNER_BORDER - entry->scroll_offset + - ranges[2 * i] / PANGO_SCALE; - rect.y = y; - rect.width = - (ranges[2 * i + 1] - ranges[2 * i]) / PANGO_SCALE; - rect.height = logical_rect.height / PANGO_SCALE; - - gdk_draw_rectangle(entry->text_area, selection_gc, TRUE, - rect.x, rect.y, rect.width, - rect.height); -#if GTK_CHECK_VERSION(2, 90, 5) - cairo_region_union_rectangle (clip_region, &rect); -#else - gdk_region_union_with_rect(clip_region, &rect); -#endif - } - - gdk_gc_set_clip_region(text_gc, clip_region); - gdk_draw_layout(entry->text_area, text_gc, x, y, layout); - gdk_gc_set_clip_region(text_gc, NULL); - -#if GTK_CHECK_VERSION(2, 90, 5) - cairo_region_destroy(clip_region); -#else - gdk_region_destroy(clip_region); -#endif - g_free(ranges); - } - } -} - -static void -draw_insertion_cursor(GtkSecureEntry * entry, - GdkRectangle * cursor_location, - gboolean is_primary, - PangoDirection direction, gboolean draw_arrow) -{ - GtkWidget *widget = GTK_WIDGET(entry); - GtkTextDirection text_dir; - - if (direction == PANGO_DIRECTION_LTR) - text_dir = GTK_TEXT_DIR_LTR; - else - text_dir = GTK_TEXT_DIR_RTL; - - gtk_draw_insertion_cursor(widget, entry->text_area, NULL, - cursor_location, - is_primary, text_dir, draw_arrow); -} - -static void -gtk_secure_entry_draw_cursor(GtkSecureEntry * entry) -{ - GtkWidget *widget = GTK_WIDGET(entry); - GdkKeymap *keymap = - gdk_keymap_get_for_display(gtk_widget_get_display - (widget)); - PangoDirection keymap_direction = gdk_keymap_get_direction(keymap); - - if (gtk_widget_is_drawable (widget)) { - GdkRectangle cursor_location; - gboolean split_cursor; - - gint xoffset = INNER_BORDER - entry->scroll_offset; - gint strong_x, weak_x; - gint text_area_height; - PangoDirection dir1 = PANGO_DIRECTION_NEUTRAL; - PangoDirection dir2 = PANGO_DIRECTION_NEUTRAL; - gint x1 = 0; - gint x2 = 0; - - gdk_drawable_get_size(entry->text_area, NULL, &text_area_height); - - gtk_secure_entry_get_cursor_locations(entry, &strong_x, &weak_x); - - g_object_get(gtk_widget_get_settings(widget), - "gtk-split-cursor", &split_cursor, NULL); - - dir1 = entry->resolved_dir; - - if (split_cursor) { - x1 = strong_x; - - if (weak_x != strong_x) { - dir2 = - (entry->resolved_dir == - PANGO_DIRECTION_LTR) ? PANGO_DIRECTION_RTL : - PANGO_DIRECTION_LTR; - x2 = weak_x; - } - } else { - if (keymap_direction == entry->resolved_dir) - x1 = strong_x; - else - x1 = weak_x; - } - - cursor_location.x = xoffset + x1; - cursor_location.y = INNER_BORDER; - cursor_location.width = 0; - cursor_location.height = text_area_height - 2 * INNER_BORDER; - - draw_insertion_cursor(entry, - &cursor_location, TRUE, dir1, - dir2 != PANGO_DIRECTION_NEUTRAL); - - if (dir2 != PANGO_DIRECTION_NEUTRAL) { - cursor_location.x = xoffset + x2; - draw_insertion_cursor(entry, - &cursor_location, FALSE, dir2, TRUE); - } - } -} - -static void -gtk_secure_entry_queue_draw(GtkSecureEntry * entry) -{ - if (gtk_widget_get_realized (GTK_WIDGET(entry))) - gdk_window_invalidate_rect(entry->text_area, NULL, FALSE); -} - -static void -gtk_secure_entry_reset_im_context(GtkSecureEntry * entry) -{ - if (entry->need_im_reset) { - entry->need_im_reset = 0; - gtk_im_context_reset(entry->im_context); - } -} - -static gint -gtk_secure_entry_find_position(GtkSecureEntry * entry, gint x) -{ - PangoLayout *layout; - PangoLayoutLine *line; - gint _index; - gint pos; - gboolean trailing; - const gchar *text; - gint cursor_index; - - layout = gtk_secure_entry_ensure_layout(entry, TRUE); - text = pango_layout_get_text(layout); - cursor_index = - g_utf8_offset_to_pointer(text, entry->current_pos) - text; - - line = pango_layout_get_lines(layout)->data; - pango_layout_line_x_to_index(line, x * PANGO_SCALE, &_index, &trailing); - - if (_index >= cursor_index && entry->preedit_length) { - if (_index >= cursor_index + entry->preedit_length) - _index -= entry->preedit_length; - else { - _index = cursor_index; - trailing = 0; - } - } - - pos = g_utf8_pointer_to_offset(text, text + _index); - pos += trailing; - - return pos; -} - -static void -gtk_secure_entry_get_cursor_locations(GtkSecureEntry * entry, - gint * strong_x, gint * weak_x) -{ - if (!entry->invisible_char) { - if (strong_x) - *strong_x = 0; - - if (weak_x) - *weak_x = 0; - } else { - PangoLayout *layout = gtk_secure_entry_ensure_layout(entry, TRUE); - const gchar *text = pango_layout_get_text(layout); - PangoRectangle strong_pos, weak_pos; - gint _index; - - _index = - g_utf8_offset_to_pointer(text, - entry->current_pos + - entry->preedit_cursor) - text; - - pango_layout_get_cursor_pos(layout, _index, &strong_pos, &weak_pos); - - if (strong_x) - *strong_x = strong_pos.x / PANGO_SCALE; - - if (weak_x) - *weak_x = weak_pos.x / PANGO_SCALE; - } -} - -static void -gtk_secure_entry_adjust_scroll(GtkSecureEntry * entry) -{ - gint min_offset, max_offset; - gint text_area_width, text_width; - gint strong_x, weak_x; - gint strong_xoffset, weak_xoffset; - PangoLayout *layout; - PangoLayoutLine *line; - PangoRectangle logical_rect; - - if (!gtk_widget_get_realized (GTK_WIDGET(entry))) - return; - - gdk_drawable_get_size(entry->text_area, &text_area_width, NULL); - text_area_width -= 2 * INNER_BORDER; - - layout = gtk_secure_entry_ensure_layout(entry, TRUE); - line = pango_layout_get_lines(layout)->data; - - pango_layout_line_get_extents(line, NULL, &logical_rect); - - /* Display as much text as we can */ - - text_width = PANGO_PIXELS(logical_rect.width); - - if (text_width > text_area_width) { - min_offset = 0; - max_offset = text_width - text_area_width; - } else { - min_offset = 0; - max_offset = min_offset; - } - - entry->scroll_offset = - CLAMP(entry->scroll_offset, min_offset, max_offset); - - /* And make sure cursors are on screen. Note that the cursor is - * actually drawn one pixel into the INNER_BORDER space on - * the right, when the scroll is at the utmost right. This - * looks better to to me than confining the cursor inside the - * border entirely, though it means that the cursor gets one - * pixel closer to the the edge of the widget on the right than - * on the left. This might need changing if one changed - * INNER_BORDER from 2 to 1, as one would do on a - * small-screen-real-estate display. - * - * We always make sure that the strong cursor is on screen, and - * put the weak cursor on screen if possible. - */ - - gtk_secure_entry_get_cursor_locations(entry, &strong_x, &weak_x); - - strong_xoffset = strong_x - entry->scroll_offset; - - if (strong_xoffset < 0) { - entry->scroll_offset += strong_xoffset; - strong_xoffset = 0; - } else if (strong_xoffset > text_area_width) { - entry->scroll_offset += strong_xoffset - text_area_width; - strong_xoffset = text_area_width; - } - - weak_xoffset = weak_x - entry->scroll_offset; - - if (weak_xoffset < 0 - && strong_xoffset - weak_xoffset <= text_area_width) { - entry->scroll_offset += weak_xoffset; - } else if (weak_xoffset > text_area_width && - strong_xoffset - (weak_xoffset - text_area_width) >= 0) { - entry->scroll_offset += weak_xoffset - text_area_width; - } - - g_object_notify(G_OBJECT(entry), "scroll_offset"); -} - -static gint -gtk_secure_entry_move_visually(GtkSecureEntry * entry, - gint start, gint count) -{ - gint _index; - PangoLayout *layout = gtk_secure_entry_ensure_layout(entry, FALSE); - const gchar *text; - - text = pango_layout_get_text(layout); - - _index = g_utf8_offset_to_pointer(text, start) - text; - - while (count != 0) { - int new_index, new_trailing; - gboolean split_cursor; - gboolean strong; - - g_object_get(gtk_widget_get_settings(GTK_WIDGET(entry)), - "gtk-split-cursor", &split_cursor, NULL); - - if (split_cursor) - strong = TRUE; - else { - GdkKeymap *keymap = - gdk_keymap_get_for_display(gtk_widget_get_display - (GTK_WIDGET(entry))); - PangoDirection keymap_direction = - gdk_keymap_get_direction(keymap); - - strong = keymap_direction == entry->resolved_dir; - } - - if (count > 0) { - pango_layout_move_cursor_visually(layout, strong, _index, 0, 1, - &new_index, &new_trailing); - count--; - } else { - pango_layout_move_cursor_visually(layout, strong, _index, 0, -1, - &new_index, &new_trailing); - count++; - } - - if (new_index < 0 || new_index == G_MAXINT) - break; - - _index = new_index; - - while (new_trailing--) - _index = g_utf8_next_char(text + new_index) - text; - } - - return g_utf8_pointer_to_offset(text, text + _index); -} - -static gint -gtk_secure_entry_move_logically(GtkSecureEntry * entry, - gint start, gint count) -{ - gint new_pos = start; - - /* Prevent any leak of information */ - new_pos = CLAMP(start + count, 0, entry->text_length); - - return new_pos; -} - -/* Public API - */ - -GtkWidget * -gtk_secure_entry_new(void) -{ - return g_object_new(GTK_TYPE_SECURE_ENTRY, NULL); -} - -/** - * gtk_secure_entry_new_with_max_length: - * @max: the maximum length of the entry, or 0 for no maximum. - * (other than the maximum length of entries.) The value passed in will - * be clamped to the range 0-65536. - * - * Creates a new #GtkSecureEntry widget with the given maximum length. - * - * Note: the existence of this function is inconsistent - * with the rest of the GTK+ API. The normal setup would - * be to just require the user to make an extra call - * to gtk_secure_entry_set_max_length() instead. It is not - * expected that this function will be removed, but - * it would be better practice not to use it. - * - * Return value: a new #GtkSecureEntry. - **/ -GtkWidget * -gtk_secure_entry_new_with_max_length(gint max) -{ - GtkSecureEntry *entry; - - max = CLAMP(max, 0, MAX_SIZE); - - entry = g_object_new(GTK_TYPE_SECURE_ENTRY, NULL); - entry->text_max_length = max; - - return GTK_WIDGET(entry); -} - -void -gtk_secure_entry_set_text(GtkSecureEntry * entry, const gchar * text) -{ - gint tmp_pos; - - g_return_if_fail(GTK_IS_SECURE_ENTRY(entry)); - g_return_if_fail(text != NULL); - - /* Actually setting the text will affect the cursor and selection; - * if the contents don't actually change, this will look odd to the user. - */ - if (strcmp(entry->text, text) == 0) - return; - - gtk_editable_delete_text(GTK_EDITABLE(entry), 0, -1); - - tmp_pos = 0; - gtk_editable_insert_text(GTK_EDITABLE(entry), text, strlen(text), - &tmp_pos); -} - -/** - * gtk_secure_entry_set_invisible_char: - * @entry: a #GtkSecureEntry - * @ch: a Unicode character - * - * Sets the character to use in place of the actual text when - * gtk_secure_entry_set_visibility() has been called to set text visibility - * to %FALSE. i.e. this is the character used in "password mode" to - * show the user how many characters have been typed. The default - * invisible char is an asterisk ('*'). If you set the invisible char - * to 0, then the user will get no feedback at all; there will be - * no text on the screen as they type. - * - **/ -void -gtk_secure_entry_set_invisible_char(GtkSecureEntry * entry, gunichar ch) -{ - g_return_if_fail(GTK_IS_SECURE_ENTRY(entry)); - - if (ch == entry->invisible_char) - return; - - entry->invisible_char = ch; - g_object_notify(G_OBJECT(entry), "invisible_char"); - gtk_secure_entry_recompute(entry); -} - -/** - * gtk_secure_entry_get_invisible_char: - * @entry: a #GtkSecureEntry - * - * Retrieves the character displayed in place of the real characters - * for entries with visisbility set to false. See gtk_secure_entry_set_invisible_char(). - * - * Return value: the current invisible char, or 0, if the entry does not - * show invisible text at all. - **/ -gunichar -gtk_secure_entry_get_invisible_char(GtkSecureEntry * entry) -{ - g_return_val_if_fail(GTK_IS_SECURE_ENTRY(entry), 0); - - return entry->invisible_char; -} - -/** - * gtk_secure_entry_get_text: - * @entry: a #GtkSecureEntry - * - * Retrieves the contents of the entry widget. - * See also gtk_editable_get_chars(). - * - * Return value: a pointer to the contents of the widget as a - * string. This string points to internally allocated - * storage in the widget and must not be freed, modified or - * stored. - **/ -G_CONST_RETURN gchar * -gtk_secure_entry_get_text(GtkSecureEntry * entry) -{ - g_return_val_if_fail(GTK_IS_SECURE_ENTRY(entry), NULL); - - return entry->text; -} - -/** - * gtk_secure_entry_set_max_length: - * @entry: a #GtkSecureEntry. - * @max: the maximum length of the entry, or 0 for no maximum. - * (other than the maximum length of entries.) The value passed in will - * be clamped to the range 0-65536. - * - * Sets the maximum allowed length of the contents of the widget. If - * the current contents are longer than the given length, then they - * will be truncated to fit. - **/ -void -gtk_secure_entry_set_max_length(GtkSecureEntry * entry, gint max) -{ - g_return_if_fail(GTK_IS_SECURE_ENTRY(entry)); - - max = CLAMP(max, 0, MAX_SIZE); - - if (max > 0 && entry->text_length > max) - gtk_editable_delete_text(GTK_EDITABLE(entry), max, -1); - - entry->text_max_length = max; - g_object_notify(G_OBJECT(entry), "max_length"); -} - -/** - * gtk_secure_entry_get_max_length: - * @entry: a #GtkSecureEntry - * - * Retrieves the maximum allowed length of the text in - * @entry. See gtk_secure_entry_set_max_length(). - * - * Return value: the maximum allowed number of characters - * in #GtkSecureEntry, or 0 if there is no maximum. - **/ -gint -gtk_secure_entry_get_max_length(GtkSecureEntry * entry) -{ - g_return_val_if_fail(GTK_IS_SECURE_ENTRY(entry), 0); - - return entry->text_max_length; -} - -/** - * gtk_secure_entry_set_activates_default: - * @entry: a #GtkSecureEntry - * @setting: %TRUE to activate window's default widget on Enter keypress - * - * If @setting is %TRUE, pressing Enter in the @entry will activate the default - * widget for the window containing the entry. This usually means that - * the dialog box containing the entry will be closed, since the default - * widget is usually one of the dialog buttons. - * - * (For experts: if @setting is %TRUE, the entry calls - * gtk_window_activate_default() on the window containing the entry, in - * the default handler for the "activate" signal.) - * - **/ -void -gtk_secure_entry_set_activates_default(GtkSecureEntry * entry, - gboolean setting) -{ - g_return_if_fail(GTK_IS_SECURE_ENTRY(entry)); - setting = setting != FALSE; - - if (setting != entry->activates_default) { - entry->activates_default = setting; - g_object_notify(G_OBJECT(entry), "activates_default"); - } -} - -/** - * gtk_secure_entry_get_activates_default: - * @entry: a #GtkSecureEntry - * - * Retrieves the value set by gtk_secure_entry_set_activates_default(). - * - * Return value: %TRUE if the entry will activate the default widget - **/ -gboolean -gtk_secure_entry_get_activates_default(GtkSecureEntry * entry) -{ - g_return_val_if_fail(GTK_IS_SECURE_ENTRY(entry), FALSE); - - return entry->activates_default; -} - -/** - * gtk_secure_entry_set_width_chars: - * @entry: a #GtkSecureEntry - * @n_chars: width in chars - * - * Changes the size request of the entry to be about the right size - * for @n_chars characters. Note that it changes the size - * request, the size can still be affected by - * how you pack the widget into containers. If @n_chars is -1, the - * size reverts to the default entry size. - * - **/ -void -gtk_secure_entry_set_width_chars(GtkSecureEntry * entry, gint n_chars) -{ - g_return_if_fail(GTK_IS_SECURE_ENTRY(entry)); - - if (entry->width_chars != n_chars) { - entry->width_chars = n_chars; - g_object_notify(G_OBJECT(entry), "width_chars"); - gtk_widget_queue_resize(GTK_WIDGET(entry)); - } -} - -/** - * gtk_secure_entry_get_width_chars: - * @entry: a #GtkSecureEntry - * - * Gets the value set by gtk_secure_entry_set_width_chars(). - * - * Return value: number of chars to request space for, or negative if unset - **/ -gint -gtk_secure_entry_get_width_chars(GtkSecureEntry * entry) -{ - g_return_val_if_fail(GTK_IS_SECURE_ENTRY(entry), 0); - - return entry->width_chars; -} - -/** - * gtk_secure_entry_set_has_frame: - * @entry: a #GtkSecureEntry - * @setting: new value - * - * Sets whether the entry has a beveled frame around it. - **/ -void -gtk_secure_entry_set_has_frame(GtkSecureEntry * entry, gboolean setting) -{ - g_return_if_fail(GTK_IS_SECURE_ENTRY(entry)); - - setting = (setting != FALSE); - - if (entry->has_frame == setting) - return; - - gtk_widget_queue_resize(GTK_WIDGET(entry)); - entry->has_frame = setting; - g_object_notify(G_OBJECT(entry), "has_frame"); -} - -/** - * gtk_secure_entry_get_has_frame: - * @entry: a #GtkSecureEntry - * - * Gets the value set by gtk_secure_entry_set_has_frame(). - * - * Return value: whether the entry has a beveled frame - **/ -gboolean -gtk_secure_entry_get_has_frame(GtkSecureEntry * entry) -{ - g_return_val_if_fail(GTK_IS_SECURE_ENTRY(entry), FALSE); - - return entry->has_frame; -} - - -/** - * gtk_secure_entry_get_layout: - * @entry: a #GtkSecureEntry - * - * Gets the #PangoLayout used to display the entry. - * The layout is useful to e.g. convert text positions to - * pixel positions, in combination with gtk_secure_entry_get_layout_offsets(). - * The returned layout is owned by the entry so need not be - * freed by the caller. - * - * Keep in mind that the layout text may contain a preedit string, so - * gtk_secure_entry_layout_index_to_text_index() and - * gtk_secure_entry_text_index_to_layout_index() are needed to convert byte - * indices in the layout to byte indices in the entry contents. - * - * Return value: the #PangoLayout for this entry - **/ -PangoLayout * -gtk_secure_entry_get_layout(GtkSecureEntry * entry) -{ - PangoLayout *layout; - - g_return_val_if_fail(GTK_IS_SECURE_ENTRY(entry), NULL); - - layout = gtk_secure_entry_ensure_layout(entry, TRUE); - - return layout; -} - - -/** - * gtk_secure_entry_layout_index_to_text_index: - * @entry: a #GtkSecureEntry - * @layout_index: byte index into the entry layout text - * - * Converts from a position in the entry contents (returned - * by gtk_secure_entry_get_text()) to a position in the - * entry's #PangoLayout (returned by gtk_secure_entry_get_layout(), - * with text retrieved via pango_layout_get_text()). - * - * Return value: byte index into the entry contents - **/ -gint -gtk_secure_entry_layout_index_to_text_index(GtkSecureEntry * entry, - gint layout_index) -{ - PangoLayout *layout; - const gchar *text; - gint cursor_index; - - g_return_val_if_fail(GTK_IS_SECURE_ENTRY(entry), 0); - - layout = gtk_secure_entry_ensure_layout(entry, TRUE); - text = pango_layout_get_text(layout); - cursor_index = - g_utf8_offset_to_pointer(text, entry->current_pos) - text; - - if (layout_index >= cursor_index && entry->preedit_length) { - if (layout_index >= cursor_index + entry->preedit_length) - layout_index -= entry->preedit_length; - else - layout_index = cursor_index; - } - - return layout_index; -} - -/** - * gtk_secure_entry_text_index_to_layout_index: - * @entry: a #GtkSecureEntry - * @text_index: byte index into the entry contents - * - * Converts from a position in the entry's #PangoLayout(returned by - * gtk_secure_entry_get_layout()) to a position in the entry contents - * (returned by gtk_secure_entry_get_text()). - * - * Return value: byte index into the entry layout text - **/ -gint -gtk_secure_entry_text_index_to_layout_index(GtkSecureEntry * entry, - gint text_index) -{ - PangoLayout *layout; - const gchar *text; - gint cursor_index; - g_return_val_if_fail(GTK_IS_SECURE_ENTRY(entry), 0); - - layout = gtk_secure_entry_ensure_layout(entry, TRUE); - text = pango_layout_get_text(layout); - cursor_index = - g_utf8_offset_to_pointer(text, entry->current_pos) - text; - - if (text_index > cursor_index) - text_index += entry->preedit_length; - - return text_index; -} - -/** - * gtk_secure_entry_get_layout_offsets: - * @entry: a #GtkSecureEntry - * @x: location to store X offset of layout, or %NULL - * @y: location to store Y offset of layout, or %NULL - * - * - * Obtains the position of the #PangoLayout used to render text - * in the entry, in widget coordinates. Useful if you want to line - * up the text in an entry with some other text, e.g. when using the - * entry to implement editable cells in a sheet widget. - * - * Also useful to convert mouse events into coordinates inside the - * #PangoLayout, e.g. to take some action if some part of the entry text - * is clicked. - * - * Note that as the user scrolls around in the entry the offsets will - * change; you'll need to connect to the "notify::scroll_offset" - * signal to track this. Remember when using the #PangoLayout - * functions you need to convert to and from pixels using - * PANGO_PIXELS() or #PANGO_SCALE. - * - * Keep in mind that the layout text may contain a preedit string, so - * gtk_secure_entry_layout_index_to_text_index() and - * gtk_secure_entry_text_index_to_layout_index() are needed to convert byte - * indices in the layout to byte indices in the entry contents. - * - **/ -void -gtk_secure_entry_get_layout_offsets(GtkSecureEntry * entry, - gint * x, gint * y) -{ - gint text_area_x, text_area_y; - - g_return_if_fail(GTK_IS_SECURE_ENTRY(entry)); - - /* this gets coords relative to text area */ - get_layout_position(entry, x, y); - - /* convert to widget coords */ - get_text_area_size(entry, &text_area_x, &text_area_y, NULL, NULL); - - if (x) - *x += text_area_x; - - if (y) - *y += text_area_y; -} - -static gboolean -gtk_secure_entry_mnemonic_activate(GtkWidget * widget, - gboolean group_cycling G_GNUC_UNUSED) -{ - gtk_widget_grab_focus(widget); - return TRUE; -} - -/* We display the cursor when - * - * - the selection is empty, AND - * - the widget has focus - */ - -#define CURSOR_ON_MULTIPLIER 0.66 -#define CURSOR_OFF_MULTIPLIER 0.34 -#define CURSOR_PEND_MULTIPLIER 1.0 - -static gboolean -cursor_blinks(GtkSecureEntry * entry) -{ - GtkWidget *widget = GTK_WIDGET(entry); - GtkSettings *settings = gtk_widget_get_settings(widget); - gboolean blink; - - if (gtk_widget_has_focus (widget) && - entry->selection_bound == entry->current_pos) { - g_object_get(settings, "gtk-cursor-blink", &blink, NULL); - return blink; - } else - return FALSE; -} - -static gint -get_cursor_time(GtkSecureEntry * entry) -{ - GtkSettings *settings = gtk_widget_get_settings(GTK_WIDGET(entry)); - gint blinktime; - - g_object_get(settings, "gtk-cursor-blink-time", &blinktime, NULL); - - return blinktime; -} - -static void -show_cursor(GtkSecureEntry * entry) -{ - GtkWidget *widget = GTK_WIDGET(entry); - - if (!entry->cursor_visible) { - entry->cursor_visible = TRUE; - - if (gtk_widget_has_focus (widget) - && entry->selection_bound == entry->current_pos) - gtk_widget_queue_draw(widget); - } -} - -static void -hide_cursor(GtkSecureEntry * entry) -{ - GtkWidget *widget = GTK_WIDGET(entry); - - if (entry->cursor_visible) { - entry->cursor_visible = FALSE; - - if (gtk_widget_has_focus (widget) - && entry->selection_bound == entry->current_pos) - gtk_widget_queue_draw(widget); - } -} - -/* - * Blink! - */ -static gint -blink_cb(gpointer data) -{ - GtkSecureEntry *entry; - GtkWidget *widget; - - GDK_THREADS_ENTER(); - - entry = GTK_SECURE_ENTRY(data); - widget = GTK_WIDGET (entry); - - if (!gtk_widget_has_focus (widget)) { - g_warning - ("GtkSecureEntry - did not receive focus-out-event. If you\n" - "connect a handler to this signal, it must return\n" - "FALSE so the entry gets the event as well"); - } - - g_assert(gtk_widget_has_focus (widget)); - g_assert(entry->selection_bound == entry->current_pos); - - if (entry->cursor_visible) { - hide_cursor(entry); - entry->blink_timeout = - g_timeout_add(get_cursor_time(entry) * CURSOR_OFF_MULTIPLIER, - blink_cb, entry); - } else { - show_cursor(entry); - entry->blink_timeout = - g_timeout_add(get_cursor_time(entry) * CURSOR_ON_MULTIPLIER, - blink_cb, entry); - } - - GDK_THREADS_LEAVE(); - - /* Remove ourselves */ - return FALSE; -} - -static void -gtk_secure_entry_check_cursor_blink(GtkSecureEntry * entry) -{ - if (cursor_blinks(entry)) { - if (!entry->blink_timeout) { - entry->blink_timeout = - g_timeout_add(get_cursor_time(entry) * - CURSOR_ON_MULTIPLIER, blink_cb, entry); - show_cursor(entry); - } - } else { - if (entry->blink_timeout) { - g_source_remove(entry->blink_timeout); - entry->blink_timeout = 0; - } - - entry->cursor_visible = TRUE; - } - -} - -static void -gtk_secure_entry_pend_cursor_blink(GtkSecureEntry * entry) -{ - if (cursor_blinks(entry)) { - if (entry->blink_timeout != 0) - g_source_remove(entry->blink_timeout); - - entry->blink_timeout = - g_timeout_add(get_cursor_time(entry) * CURSOR_PEND_MULTIPLIER, - blink_cb, entry); - show_cursor(entry); - } -} - -static inline gboolean -keyval_is_cursor_move(guint keyval) -{ - if (keyval == GDK_Up || keyval == GDK_KP_Up) - return TRUE; - - if (keyval == GDK_Down || keyval == GDK_KP_Down) - return TRUE; - - if (keyval == GDK_Page_Up) - return TRUE; - - if (keyval == GDK_Page_Down) - return TRUE; - - return FALSE; -} - -/* stolen from gtkmarshalers.c */ - -#define g_marshal_value_peek_enum(v) (v)->data[0].v_int -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int - -/* VOID:ENUM,INT,BOOLEAN (gtkmarshalers.list:64) */ -static void -_gtk_marshal_VOID__ENUM_INT_BOOLEAN(GClosure * closure, - GValue * return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue * param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef void (*GMarshalFunc_VOID__ENUM_INT_BOOLEAN) (gpointer data1, - gint arg_1, - gint arg_2, - gboolean arg_3, - gpointer data2); - register GMarshalFunc_VOID__ENUM_INT_BOOLEAN callback; - register GCClosure *cc = (GCClosure *) closure; - register gpointer data1, data2; - - g_return_if_fail(n_param_values == 4); - - if (G_CCLOSURE_SWAP_DATA(closure)) { - data1 = closure->data; - data2 = g_value_peek_pointer(param_values + 0); - } else { - data1 = g_value_peek_pointer(param_values + 0); - data2 = closure->data; - } - callback = - (GMarshalFunc_VOID__ENUM_INT_BOOLEAN) (marshal_data ? marshal_data - : cc->callback); - - callback(data1, - g_marshal_value_peek_enum(param_values + 1), - g_marshal_value_peek_int(param_values + 2), - g_marshal_value_peek_boolean(param_values + 3), data2); -} - -static void -_gtk_marshal_VOID__ENUM_INT(GClosure * closure, - GValue * return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue * param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef void (*GMarshalFunc_VOID__ENUM_INT) (gpointer data1, - gint arg_1, - gint arg_2, - gpointer data2); - register GMarshalFunc_VOID__ENUM_INT callback; - register GCClosure *cc = (GCClosure *) closure; - register gpointer data1, data2; - - g_return_if_fail(n_param_values == 3); - - if (G_CCLOSURE_SWAP_DATA(closure)) { - data1 = closure->data; - data2 = g_value_peek_pointer(param_values + 0); - } else { - data1 = g_value_peek_pointer(param_values + 0); - data2 = closure->data; - } - callback = - (GMarshalFunc_VOID__ENUM_INT) (marshal_data ? marshal_data : cc-> - callback); - - callback(data1, - g_marshal_value_peek_enum(param_values + 1), - g_marshal_value_peek_int(param_values + 2), data2); -} -- cgit