gnome-keyring r1036 - in trunk: . ui



Author: nnielsen
Date: Wed Feb  6 04:02:53 2008
New Revision: 1036
URL: http://svn.gnome.org/viewvc/gnome-keyring?rev=1036&view=rev

Log:
	* ui/gkr-ask-entry.c: (added)
	* ui/gkr-ask-entry.h: (added)
	* ui/gkr-ask-tool.c: 
	* ui/Makefile.am:
	* ui/test-input.txt: (added)
	* configure.in: Don't lock the entire gnome-keyring-ask process into 
	memory. This allows it to work properly on systems where there is 
	limited lockable memory available.


Added:
   trunk/ui/gkr-ask-entry.c
   trunk/ui/gkr-ask-entry.h
   trunk/ui/test-input.txt
Modified:
   trunk/ChangeLog
   trunk/configure.in
   trunk/ui/Makefile.am
   trunk/ui/gkr-ask-tool.c

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Wed Feb  6 04:02:53 2008
@@ -188,7 +188,6 @@
 #
 
 AC_CHECK_FUNCS(mlock)
-AC_CHECK_FUNCS(mlockall)
 
 # --------------------------------------------------------------------
 # socket()

Modified: trunk/ui/Makefile.am
==============================================================================
--- trunk/ui/Makefile.am	(original)
+++ trunk/ui/Makefile.am	Wed Feb  6 04:02:53 2008
@@ -15,11 +15,13 @@
 	$(GTK_CFLAGS)
 	
 gnome_keyring_ask_SOURCES = \
+	gkr-ask-entry.c gkr-ask-entry.h \
 	gkr-ask-tool.c gkr-ask-tool.h \
 	gkr-ask-tool-widgets.c \
 	gkr-ask-request.h
 	
 gnome_keyring_ask_LDADD = \
+	$(top_builddir)/common/libgkr-module-common.la \
 	$(GTK_LIBS)
 
 noinst_LTLIBRARIES=libgkr-ui.la

Added: trunk/ui/gkr-ask-entry.c
==============================================================================
--- (empty file)
+++ trunk/ui/gkr-ask-entry.c	Wed Feb  6 04:02:53 2008
@@ -0,0 +1,2734 @@
+/* 
+ * GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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Ã
+ * <albrecht dress arcor de> Feb. 2004.
+ *
+ * (C) by Albrecht Dreà 2004 unter the terms of the GNU Lesser General
+ * Public License.
+ *
+ * The entry is invisible by default, uses secure memory methods to
+ * allocate the text memory, and all potentially dangerous methods
+ * (copy & paste, popup, etc.) have been removed.
+ */
+ 
+/* 
+ * Modified for inclusion into gnome-keyring by Stef Walter 
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "gkr-ask-entry.h"
+
+#include "common/gkr-secure-memory.h"
+
+#define MIN_ASK_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,
+    PROP_VISIBILITY
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/* GObject, GtkObject methods */
+static void gkr_ask_entry_class_init (GkrAskEntryClass *klass);
+static void gkr_ask_entry_editable_init (GtkEditableClass *iface);
+static void gkr_ask_entry_cell_editable_init (GtkCellEditableIface *iface);
+static void gkr_ask_entry_init (GkrAskEntry *entry);
+static void gkr_ask_entry_set_property (GObject *object, guint prop_id,
+                                                const GValue *value, GParamSpec *pspec);
+static void gkr_ask_entry_get_property (GObject *object, guint prop_id,
+                                                GValue *value, GParamSpec *pspec);
+static void gkr_ask_entry_finalize (GObject *object);
+
+/* GtkWidget methods */
+static void gkr_ask_entry_realize (GtkWidget *widget);
+static void gkr_ask_entry_unrealize (GtkWidget *widget);
+static void gkr_ask_entry_size_request (GtkWidget *widget, GtkRequisition *requisition);
+static void gkr_ask_entry_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
+static void gkr_ask_entry_draw_frame (GtkWidget *widget);
+static gint gkr_ask_entry_expose (GtkWidget *widget, GdkEventExpose *event);
+static gint gkr_ask_entry_button_press (GtkWidget *widget, GdkEventButton *event);
+static gint gkr_ask_entry_button_release (GtkWidget *widget, GdkEventButton *event);
+static gint gkr_ask_entry_motion_notify (GtkWidget *widget, GdkEventMotion *event);
+static gint gkr_ask_entry_key_press (GtkWidget *widget, GdkEventKey *event);
+static gint gkr_ask_entry_key_release (GtkWidget *widget, GdkEventKey *event);
+static gint gkr_ask_entry_focus_in (GtkWidget *widget, GdkEventFocus *event);
+static gint gkr_ask_entry_focus_out (GtkWidget *widget, GdkEventFocus *event);
+static void gkr_ask_entry_grab_focus (GtkWidget *widget);
+static void gkr_ask_entry_style_set (GtkWidget *widget, GtkStyle *previous_style);
+static void gkr_ask_entry_direction_changed (GtkWidget *widget, GtkTextDirection previous_dir);
+static void gkr_ask_entry_state_changed (GtkWidget *widget, GtkStateType previous_state);
+static void gkr_ask_entry_screen_changed (GtkWidget *widget, GdkScreen *old_screen);
+
+/* GtkEditable method implementations */
+static void gkr_ask_entry_insert_text (GtkEditable *editable, const gchar *new_text,
+                                               gint new_text_length, gint *position);
+static void gkr_ask_entry_delete_text (GtkEditable *editable, gint start_pos, gint end_pos);
+static void gkr_ask_entry_real_set_position (GtkEditable *editable, gint position);
+static gint gkr_ask_entry_get_position (GtkEditable *editable);
+static void gkr_ask_entry_set_selection_bounds (GtkEditable *editable, gint start, gint end);
+static gboolean gkr_ask_entry_get_selection_bounds (GtkEditable *editable, gint *start, gint *end);
+
+/* GtkCellEditable method implementations */
+static void gkr_ask_entry_start_editing (GtkCellEditable *cell_editable, GdkEvent *event);
+
+/* Default signal handlers */
+static void gkr_ask_entry_real_insert_text (GtkEditable *editable, const gchar *new_text,
+                                                    gint new_text_length, gint *position);
+static void gkr_ask_entry_real_delete_text (GtkEditable *editable, gint start_pos, gint end_pos);
+static void gkr_ask_entry_move_cursor (GkrAskEntry *entry, GtkMovementStep step,
+                                               gint count, gboolean extend_selection);
+static void gkr_ask_entry_insert_at_cursor (GkrAskEntry *entry, const gchar *str);
+static void gkr_ask_entry_delete_from_cursor (GkrAskEntry *entry, GtkDeleteType type, gint count);
+static void gkr_ask_entry_real_activate (GkrAskEntry *entry);
+static void gkr_ask_entry_keymap_direction_changed (GdkKeymap *keymap, GkrAskEntry *entry);
+
+/* IM Context Callbacks */
+static void gkr_ask_entry_commit_cb(GtkIMContext *context, const gchar *str, GkrAskEntry *entry);
+static void gkr_ask_entry_preedit_changed_cb (GtkIMContext * context, GkrAskEntry *entry);
+static gboolean gkr_ask_entry_retrieve_surrounding_cb (GtkIMContext *context, GkrAskEntry *entry);
+static gboolean gkr_ask_entry_delete_surrounding_cb (GtkIMContext *context, gint offset, 
+                                                             gint n_chars, GkrAskEntry *entry);
+
+/* Internal routines */
+static void gkr_ask_entry_enter_text (GkrAskEntry *entry, const gchar *str);
+static void gkr_ask_entry_set_positions (GkrAskEntry *entry, gint current_pos, gint selection_bound);
+static void gkr_ask_entry_draw_text (GkrAskEntry *entry);
+static void gkr_ask_entry_draw_cursor (GkrAskEntry *entry);
+static PangoLayout *gkr_ask_entry_ensure_layout(GkrAskEntry *entry, gboolean include_preedit);
+static void gkr_ask_entry_reset_layout (GkrAskEntry *entry);
+static void gkr_ask_entry_queue_draw (GkrAskEntry *entry);
+static void gkr_ask_entry_reset_im_context (GkrAskEntry *entry);
+static void gkr_ask_entry_recompute (GkrAskEntry *entry);
+static gint gkr_ask_entry_find_position (GkrAskEntry *entry, gint x);
+static void gkr_ask_entry_get_cursor_locations (GkrAskEntry *entry, gint *strong_x, gint *weak_x);
+static void gkr_ask_entry_adjust_scroll (GkrAskEntry *entry);
+static gint gkr_ask_entry_move_visually (GkrAskEntry *editable, gint start, gint count);
+static gint gkr_ask_entry_move_logically (GkrAskEntry *entry, gint start, gint count);
+static gboolean gkr_ask_entry_mnemonic_activate (GtkWidget *widget, gboolean group_cycling);
+static void gkr_ask_entry_state_changed (GtkWidget *widget, GtkStateType previous_state);
+static void gkr_ask_entry_check_cursor_blink (GkrAskEntry *entry);
+static void gkr_ask_entry_pend_cursor_blink (GkrAskEntry *entry);
+static void get_text_area_size (GkrAskEntry *entry, gint *x, gint *y, gint *width, gint *height);
+static void get_widget_window_size (GkrAskEntry *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;
+
+GType
+gkr_ask_entry_get_type(void)
+{
+    static GType entry_type = 0;
+
+    if (!entry_type) {
+        static const GTypeInfo entry_info = {
+            sizeof(GkrAskEntryClass),
+            NULL,       /* base_init */
+            NULL,       /* base_finalize */
+            (GClassInitFunc) gkr_ask_entry_class_init,
+            NULL,       /* class_finalize */
+            NULL,       /* class_data */
+            sizeof(GkrAskEntry),
+            0,          /* n_preallocs */
+            (GInstanceInitFunc) gkr_ask_entry_init,
+        };
+
+        static const GInterfaceInfo editable_info = {
+            (GInterfaceInitFunc) gkr_ask_entry_editable_init,    /* interface_init */
+            NULL,       /* interface_finalize */
+            NULL        /* interface_data */
+        };
+
+        static const GInterfaceInfo cell_editable_info = {
+            (GInterfaceInitFunc) gkr_ask_entry_cell_editable_init,   /* interface_init */
+            NULL,       /* interface_finalize */
+            NULL        /* interface_data */
+        };
+
+        entry_type = g_type_register_static(GTK_TYPE_WIDGET, "GkrAskEntry", &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
+gkr_ask_entry_class_init(GkrAskEntryClass *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 = gkr_ask_entry_finalize;
+    gobject_class->set_property = gkr_ask_entry_set_property;
+    gobject_class->get_property = gkr_ask_entry_get_property;
+
+    widget_class->realize = gkr_ask_entry_realize;
+    widget_class->unrealize = gkr_ask_entry_unrealize;
+    widget_class->size_request = gkr_ask_entry_size_request;
+    widget_class->size_allocate = gkr_ask_entry_size_allocate;
+    widget_class->expose_event = gkr_ask_entry_expose;
+    widget_class->button_press_event = gkr_ask_entry_button_press;
+    widget_class->button_release_event = gkr_ask_entry_button_release;
+    widget_class->motion_notify_event = gkr_ask_entry_motion_notify;
+    widget_class->key_press_event = gkr_ask_entry_key_press;
+    widget_class->key_release_event = gkr_ask_entry_key_release;
+    widget_class->focus_in_event = gkr_ask_entry_focus_in;
+    widget_class->focus_out_event = gkr_ask_entry_focus_out;
+    widget_class->grab_focus = gkr_ask_entry_grab_focus;
+    widget_class->style_set = gkr_ask_entry_style_set;
+    widget_class->direction_changed = gkr_ask_entry_direction_changed;
+    widget_class->state_changed = gkr_ask_entry_state_changed;
+    widget_class->screen_changed = gkr_ask_entry_screen_changed;
+    widget_class->mnemonic_activate = gkr_ask_entry_mnemonic_activate;
+
+    class->move_cursor = gkr_ask_entry_move_cursor;
+    class->insert_at_cursor = gkr_ask_entry_insert_at_cursor;
+    class->delete_from_cursor = gkr_ask_entry_delete_from_cursor;
+    class->activate = gkr_ask_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));
+                            
+    g_object_class_install_property (gobject_class, PROP_VISIBILITY,
+        g_param_spec_boolean ("visibility", "Visibility", "Whether contents are drawn using invisible character",
+                              FALSE, G_PARAM_READWRITE));
+
+    /* Action signals */
+
+    signals[ACTIVATE] =  g_signal_new ("activate", G_OBJECT_CLASS_TYPE (gobject_class),
+                                       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                                       G_STRUCT_OFFSET (GkrAskEntryClass, 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 (GkrAskEntryClass, 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 (GkrAskEntryClass, 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 (GkrAskEntryClass, 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
+gkr_ask_entry_editable_init (GtkEditableClass *iface)
+{
+    iface->do_insert_text = gkr_ask_entry_insert_text;
+    iface->do_delete_text = gkr_ask_entry_delete_text;
+    iface->insert_text = gkr_ask_entry_real_insert_text;
+    iface->delete_text = gkr_ask_entry_real_delete_text;
+    iface->set_selection_bounds = gkr_ask_entry_set_selection_bounds;
+    iface->get_selection_bounds = gkr_ask_entry_get_selection_bounds;
+    iface->set_position = gkr_ask_entry_real_set_position;
+    iface->get_position = gkr_ask_entry_get_position;
+}
+
+static void
+gkr_ask_entry_cell_editable_init (GtkCellEditableIface * iface)
+{
+    iface->start_editing = gkr_ask_entry_start_editing;
+}
+
+static void
+gkr_ask_entry_set_property (GObject *object, guint prop_id,
+                                    const GValue *value, GParamSpec *pspec)
+{
+    GkrAskEntry *entry = GKR_ASK_ENTRY(object);
+
+    switch (prop_id) {
+    case PROP_MAX_LENGTH:
+        gkr_ask_entry_set_max_length(entry, g_value_get_int(value));
+        break;
+
+    case PROP_HAS_FRAME:
+        gkr_ask_entry_set_has_frame(entry, g_value_get_boolean(value));
+        break;
+
+    case PROP_INVISIBLE_CHAR:
+        gkr_ask_entry_set_invisible_char(entry, g_value_get_uint(value));
+        break;
+
+    case PROP_ACTIVATES_DEFAULT:
+        gkr_ask_entry_set_activates_default(entry, g_value_get_boolean(value));
+        break;
+
+    case PROP_WIDTH_CHARS:
+        gkr_ask_entry_set_width_chars(entry, g_value_get_int(value));
+        break;
+
+    case PROP_TEXT:
+        gkr_ask_entry_set_text(entry, g_value_get_string(value));
+        break;
+    
+    case PROP_VISIBILITY:
+        gkr_ask_entry_set_visibility (entry, g_value_get_boolean (value));
+        break;
+
+    case PROP_SCROLL_OFFSET:
+    case PROP_CURSOR_POSITION:
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+gkr_ask_entry_get_property (GObject *object, guint prop_id,
+                                    GValue *value, GParamSpec *pspec)
+{
+    GkrAskEntry *entry = GKR_ASK_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, gkr_ask_entry_get_text(entry));
+        break;
+    case PROP_VISIBILITY:
+        g_value_set_boolean (value, gkr_ask_entry_get_visibility (entry));
+        break;
+    
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+gkr_ask_entry_init (GkrAskEntry *entry)
+{
+    GtkStyle *style;
+    GtkWidget *tempent;
+
+    GTK_WIDGET_SET_FLAGS (entry, GTK_CAN_FOCUS);
+
+    /* Get the RC style for a normal GtkEntry */
+    style = gtk_rc_get_style_by_paths (gtk_widget_get_settings (GTK_WIDGET (entry)), 
+                                       NULL, NULL, GTK_TYPE_ENTRY);
+    gtk_widget_set_style (GTK_WIDGET (entry), style); 
+
+    entry->text_size = MIN_SIZE;
+    entry->text = gkr_secure_alloc (entry->text_size + 1);
+    entry->text[0] = '\0';
+
+    entry->visibility = FALSE;
+    entry->width_chars = -1;
+    entry->is_cell_renderer = FALSE;
+    entry->editing_canceled = FALSE;
+    entry->has_frame = TRUE;
+
+    /* Use the invisible_char from GtkEntry */
+    tempent = gtk_entry_new ();
+    entry->invisible_char = gtk_entry_get_invisible_char (GTK_ENTRY (tempent));
+    g_object_ref_sink (tempent);
+    g_object_unref (tempent);
+
+    /* 
+     * 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 (gkr_ask_entry_commit_cb), entry);
+    g_signal_connect (entry->im_context, "preedit_changed",
+                      G_CALLBACK(gkr_ask_entry_preedit_changed_cb), entry);
+    g_signal_connect (entry->im_context, "retrieve_surrounding",
+                      G_CALLBACK(gkr_ask_entry_retrieve_surrounding_cb), entry);
+    g_signal_connect (entry->im_context, "delete_surrounding",
+                      G_CALLBACK(gkr_ask_entry_delete_surrounding_cb), entry);
+}
+
+static void
+gkr_ask_entry_finalize (GObject *object)
+{
+    GkrAskEntry *entry = GKR_ASK_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)
+    	gkr_secure_free (entry->text);
+    entry->text = NULL;
+
+    G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gkr_ask_entry_realize (GtkWidget *widget)
+{
+    GkrAskEntry *entry;
+    GtkEditable *editable;
+    GdkWindowAttr attributes;
+    gint attributes_mask;
+
+    GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+    entry = GKR_ASK_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;
+
+    widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), 
+                                     &attributes, attributes_mask);
+    gdk_window_set_user_data (widget->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 (widget->window, &attributes, attributes_mask);
+    gdk_window_set_user_data (entry->text_area, entry);
+
+    gdk_cursor_unref (attributes.cursor);
+
+    widget->style = gtk_style_attach (widget->style, widget->window);
+
+    gdk_window_set_background (widget->window, 
+                               &widget->style->base[GTK_WIDGET_STATE (widget)]);
+    gdk_window_set_background (entry->text_area, 
+                               &widget->style->base[GTK_WIDGET_STATE (widget)]);
+
+    gdk_window_show (entry->text_area);
+
+    gtk_im_context_set_client_window (entry->im_context, entry->text_area);
+
+    gkr_ask_entry_adjust_scroll (entry);
+}
+
+static void
+gkr_ask_entry_unrealize (GtkWidget *widget)
+{
+    GkrAskEntry *entry = GKR_ASK_ENTRY (widget);
+
+    gkr_ask_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 (GkrAskEntry *entry, gint *xborder, gint *yborder)
+{
+    GtkWidget *widget = GTK_WIDGET (entry);
+    gint focus_width;
+    gboolean interior_focus;
+
+    gtk_widget_style_get (widget, "interior-focus", &interior_focus,
+                          "focus-line-width", &focus_width, NULL);
+
+    if (entry->has_frame) {
+        *xborder = widget->style->xthickness;
+        *yborder = widget->style->ythickness;
+    } else {
+        *xborder = 0;
+        *yborder = 0;
+    }
+
+    if (!interior_focus) {
+        *xborder += focus_width;
+        *yborder += focus_width;
+    }
+}
+
+static void
+gkr_ask_entry_size_request (GtkWidget *widget, GtkRequisition *requisition)
+{
+    GkrAskEntry *entry = GKR_ASK_ENTRY (widget);
+    PangoFontMetrics *metrics;
+    gint xborder, yborder;
+    PangoContext *context;
+
+    context = gtk_widget_get_pango_context (widget);
+    metrics = pango_context_get_metrics (context, widget->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_ASK_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(GkrAskEntry *entry, gint *x, gint *y, gint *width, gint *height)
+{
+    gint xborder, yborder;
+    GtkRequisition requisition;
+    GtkWidget *widget = GTK_WIDGET (entry);
+
+    gtk_widget_get_child_requisition (widget, &requisition);
+
+    get_borders (entry, &xborder, &yborder);
+
+    if (x)
+        *x = xborder;
+
+    if (y)
+        *y = yborder;
+
+    if (width)
+        *width = GTK_WIDGET (entry)->allocation.width - xborder * 2;
+
+    if (height)
+        *height = requisition.height - yborder * 2;
+}
+
+static void
+get_widget_window_size (GkrAskEntry *entry, gint *x, gint *y, gint *width, gint *height)
+{
+    GtkRequisition requisition;
+    GtkWidget *widget = GTK_WIDGET (entry);
+
+    gtk_widget_get_child_requisition (widget, &requisition);
+
+    if (x)
+        *x = widget->allocation.x;
+
+    if (y) {
+        if (entry->is_cell_renderer)
+            *y = widget->allocation.y;
+        else
+            *y = widget->allocation.y + (widget->allocation.height -
+                                         requisition.height) / 2;
+    }
+
+    if (width)
+        *width = widget->allocation.width;
+
+    if (height) {
+        if (entry->is_cell_renderer)
+            *height = widget->allocation.height;
+        else
+            *height = requisition.height;
+    }
+}
+
+static void
+gkr_ask_entry_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
+{
+    GkrAskEntry *entry = GKR_ASK_ENTRY(widget);
+
+    widget->allocation = *allocation;
+
+    if (GTK_WIDGET_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 (widget->window, x, y, width, height);
+
+        get_text_area_size (entry, &x, &y, &width, &height);
+
+        gdk_window_move_resize (entry->text_area, x, y, width, height);
+
+        gkr_ask_entry_recompute (entry);
+    }
+}
+
+static void
+gkr_ask_entry_draw_frame (GtkWidget *widget)
+{
+    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);
+
+    gdk_drawable_get_size (widget->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;
+    }
+
+    gtk_paint_shadow (widget->style, widget->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(widget->style, widget->window, GTK_WIDGET_STATE (widget), 
+                        NULL, widget, "entry", 0, 0, width, height);
+    }
+}
+
+static gint
+gkr_ask_entry_expose(GtkWidget *widget, GdkEventExpose *event)
+{
+    GkrAskEntry *entry = GKR_ASK_ENTRY(widget);
+
+    if (widget->window == event->window)
+        gkr_ask_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);
+
+        gtk_paint_flat_box(widget->style, entry->text_area, GTK_WIDGET_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)
+            gkr_ask_entry_draw_cursor (GKR_ASK_ENTRY (widget));
+
+        gkr_ask_entry_draw_text (GKR_ASK_ENTRY (widget));
+    }
+
+    return FALSE;
+}
+
+static gint
+gkr_ask_entry_button_press(GtkWidget *widget, GdkEventButton *event)
+{
+    GkrAskEntry *entry = GKR_ASK_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 = gkr_ask_entry_find_position (entry, event->x + entry->scroll_offset);
+
+    if (event->button == 1) {
+        switch (event->type) {
+        case GDK_BUTTON_PRESS:
+            gkr_ask_entry_set_positions(entry, tmp_pos, tmp_pos);
+            break;
+        default:
+            break;
+        }
+
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+static gint
+gkr_ask_entry_button_release(GtkWidget *widget, GdkEventButton *event)
+{
+    GkrAskEntry *entry = GKR_ASK_ENTRY(widget);
+
+    if (event->window != entry->text_area || entry->button != event->button)
+        return FALSE;
+
+    entry->button = 0;
+    return TRUE;
+}
+
+static gint
+gkr_ask_entry_motion_notify(GtkWidget *widget, GdkEventMotion *event)
+{
+    GkrAskEntry *entry = GKR_ASK_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 = gkr_ask_entry_find_position (entry, 
+                                                event->x + entry->scroll_offset);
+
+        gkr_ask_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
+gkr_ask_entry_obscure_mouse_cursor (GkrAskEntry * entry)
+{
+    if (entry->mouse_cursor_obscured)
+        return;
+
+    set_invisible_cursor (entry->text_area);
+
+    entry->mouse_cursor_obscured = TRUE;
+}
+
+static gint
+gkr_ask_entry_key_press (GtkWidget *widget, GdkEventKey *event)
+{
+    GkrAskEntry *entry = GKR_ASK_ENTRY (widget);
+
+    gkr_ask_entry_pend_cursor_blink (entry);
+
+    if (gtk_im_context_filter_keypress (entry->im_context, event)) {
+        gkr_ask_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
+gkr_ask_entry_key_release (GtkWidget *widget, GdkEventKey *event)
+{
+    GkrAskEntry *entry = GKR_ASK_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
+gkr_ask_entry_focus_in (GtkWidget *widget, GdkEventFocus *event)
+{
+    GkrAskEntry *entry = GKR_ASK_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 (gkr_ask_entry_keymap_direction_changed), entry);
+
+    gkr_ask_entry_check_cursor_blink (entry);
+
+    return FALSE;
+}
+
+static gint
+gkr_ask_entry_focus_out (GtkWidget *widget, GdkEventFocus *event)
+{
+    GkrAskEntry *entry = GKR_ASK_ENTRY (widget);
+
+    gtk_widget_queue_draw (widget);
+
+    entry->need_im_reset = TRUE;
+    gtk_im_context_focus_out (entry->im_context);
+
+    gkr_ask_entry_check_cursor_blink (entry);
+
+    g_signal_handlers_disconnect_by_func (gdk_keymap_get_for_display (gtk_widget_get_display (widget)),
+                                          gkr_ask_entry_keymap_direction_changed, entry);
+
+    return FALSE;
+}
+
+static void
+gkr_ask_entry_grab_focus (GtkWidget *widget)
+{
+    GkrAskEntry *entry = GKR_ASK_ENTRY (widget);
+    GtkSettings *settings = gtk_widget_get_settings (widget);
+    gboolean select_on_focus = FALSE;
+
+    GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_DEFAULT);
+    GTK_WIDGET_CLASS (parent_class)->grab_focus(widget);
+
+    /* Some versions of GTK don't have this property */
+    if (g_object_class_find_property (G_OBJECT_CLASS (GTK_SETTINGS_GET_CLASS (settings)), 
+                                      "gtk-entry-select-on-focus"))
+        g_object_get (settings, "gtk-entry-select-on-focus", &select_on_focus, NULL);
+
+    if (select_on_focus && !entry->in_click)
+        gtk_editable_select_region (GTK_EDITABLE (widget), 0, -1);
+}
+
+static void
+gkr_ask_entry_direction_changed(GtkWidget *widget, GtkTextDirection previous_dir)
+{
+    GkrAskEntry *entry = GKR_ASK_ENTRY (widget);
+
+    gkr_ask_entry_recompute (entry);
+
+    GTK_WIDGET_CLASS (parent_class)->direction_changed (widget, previous_dir);
+}
+
+static void
+gkr_ask_entry_state_changed (GtkWidget *widget, GtkStateType previous_state)
+{
+    GkrAskEntry *entry = GKR_ASK_ENTRY (widget);
+
+    if (GTK_WIDGET_REALIZED (widget)) {
+        gdk_window_set_background (widget->window, 
+                                   &widget->style->base[GTK_WIDGET_STATE(widget)]);
+        gdk_window_set_background (entry->text_area, 
+                                   &widget->style->base[GTK_WIDGET_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
+gkr_ask_entry_screen_changed (GtkWidget *widget, GdkScreen *old_screen)
+{
+    gkr_ask_entry_recompute (GKR_ASK_ENTRY (widget));
+}
+
+/* GtkEditable method implementations */
+
+static void
+gkr_ask_entry_insert_text (GtkEditable *editable, const gchar *new_text,
+                                   gint new_text_length, gint * position)
+{
+    GkrAskEntry *entry = GKR_ASK_ENTRY(editable);
+    gchar *text;
+
+    if (*position < 0 || *position > entry->text_length)
+        *position = entry->text_length;
+
+    g_object_ref (editable);
+
+    text = gkr_secure_alloc (new_text_length + 1);
+
+    strncpy (text, new_text, new_text_length);
+    text[new_text_length] = '\0';
+
+    g_signal_emit_by_name (editable, "insert_text", text, 
+                           new_text_length, position);
+
+    gkr_secure_free (text);
+
+    g_object_unref (editable);
+}
+
+static void
+gkr_ask_entry_delete_text (GtkEditable* editable, gint start_pos, 
+                                   gint end_pos)
+{
+    GkrAskEntry *entry = GKR_ASK_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
+gkr_ask_entry_set_position_internal (GkrAskEntry *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)
+            gkr_ask_entry_reset_im_context (entry);
+        gkr_ask_entry_set_positions (entry, position, position);
+    }
+}
+
+static void
+gkr_ask_entry_real_set_position (GtkEditable *editable, gint position)
+{
+    gkr_ask_entry_set_position_internal (GKR_ASK_ENTRY (editable),
+                                                 position, TRUE);
+}
+
+static gint
+gkr_ask_entry_get_position (GtkEditable *editable)
+{
+    return GKR_ASK_ENTRY (editable)->current_pos;
+}
+
+static void
+gkr_ask_entry_set_selection_bounds (GtkEditable *editable,
+                                            gint start, gint end)
+{
+    GkrAskEntry *entry = GKR_ASK_ENTRY (editable);
+
+    if (start < 0)
+        start = entry->text_length;
+    if (end < 0)
+        end = entry->text_length;
+
+    gkr_ask_entry_reset_im_context (entry);
+
+    gkr_ask_entry_set_positions (entry, MIN (end, entry->text_length),
+                                         MIN (start, entry->text_length));
+}
+
+static gboolean
+gkr_ask_entry_get_selection_bounds (GtkEditable *editable, 
+                                            gint *start, gint *end)
+{
+    GkrAskEntry *entry = GKR_ASK_ENTRY (editable);
+
+    *start = entry->selection_bound;
+    *end = entry->current_pos;
+
+    return (entry->selection_bound != entry->current_pos);
+}
+
+static void
+gkr_ask_entry_style_set (GtkWidget *widget, GtkStyle *previous_style)
+{
+    GkrAskEntry *entry = GKR_ASK_ENTRY (widget);
+
+    gkr_ask_entry_recompute (entry);
+
+    if (previous_style && GTK_WIDGET_REALIZED (widget)) {
+        gdk_window_set_background (widget->window, 
+                                   &widget->style->base[GTK_WIDGET_STATE (widget)]);
+        gdk_window_set_background (entry->text_area,
+                                   &widget->style-> base[GTK_WIDGET_STATE (widget)]);
+    }
+}
+
+/* GtkCellEditable method implementations
+ */
+static void
+gtk_cell_editable_secure_entry_activated (GkrAskEntry *entry, gpointer data)
+{
+    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 (GkrAskEntry *entry, GdkEventKey *key_event, 
+                                   gpointer data)
+{
+    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
+gkr_ask_entry_start_editing (GtkCellEditable *cell_editable,
+                                     GdkEvent *event)
+{
+    GKR_ASK_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
+gkr_ask_entry_real_insert_text (GtkEditable *editable, const gchar *new_text,
+                                        gint new_text_length, gint *position)
+{
+    gint _index;
+    gint n_chars;
+
+    GkrAskEntry *entry = GKR_ASK_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;
+                }
+            }
+        }
+
+        entry->text = gkr_secure_realloc (entry->text, entry->text_size + 1);
+    }
+
+    _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;
+
+    gkr_ask_entry_recompute (entry);
+
+    entry->changed = TRUE;
+    g_signal_emit_by_name (editable, "changed");
+    g_object_notify (G_OBJECT (editable), "text");
+}
+
+static void
+gkr_ask_entry_real_delete_text (GtkEditable *editable, gint start_pos, 
+                                        gint end_pos)
+{
+    GkrAskEntry *entry = GKR_ASK_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;
+
+        gkr_ask_entry_set_positions(entry, current_pos, selection_bound);
+
+        gkr_ask_entry_recompute (entry);
+
+        entry->changed = TRUE;
+        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 (GkrAskEntry *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 = gkr_ask_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
+gkr_ask_entry_move_cursor (GkrAskEntry *entry, GtkMovementStep step,
+                                   gint count, gboolean extend_selection)
+{
+    gint new_pos = entry->current_pos;
+
+    gkr_ask_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 = gkr_ask_entry_move_logically (entry, new_pos, count);
+            break;
+        case GTK_MOVEMENT_VISUAL_POSITIONS:
+            new_pos = gkr_ask_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);
+
+    gkr_ask_entry_pend_cursor_blink (entry);
+}
+
+static void
+gkr_ask_entry_insert_at_cursor(GkrAskEntry *entry, const gchar *str)
+{
+    GtkEditable *editable = GTK_EDITABLE (entry);
+    gint pos = entry->current_pos;
+
+    gkr_ask_entry_reset_im_context (entry);
+
+    gtk_editable_insert_text (editable, str, -1, &pos);
+    gtk_editable_set_position (editable, pos);
+}
+
+static void
+gkr_ask_entry_delete_from_cursor (GkrAskEntry *entry, GtkDeleteType type, 
+                                          gint count)
+{
+    GtkEditable *editable = GTK_EDITABLE (entry);
+    gint start_pos = entry->current_pos;
+    gint end_pos = entry->current_pos;
+
+    gkr_ask_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 = gkr_ask_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;
+    }
+
+    gkr_ask_entry_pend_cursor_blink (entry);
+}
+
+static void
+gkr_ask_entry_real_activate (GkrAskEntry *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)) {
+        window = GTK_WINDOW(toplevel);
+
+        if (window && widget != window->default_widget &&
+            !(widget == window->focus_widget &&
+             (!window->default_widget || !GTK_WIDGET_SENSITIVE(window->default_widget))))
+            gtk_window_activate_default(window);
+        }
+    }
+}
+
+static void
+gkr_ask_entry_keymap_direction_changed (GdkKeymap *keymap, GkrAskEntry *entry)
+{
+    gkr_ask_entry_recompute (entry);
+}
+
+/* IM Context Callbacks */
+
+static void
+gkr_ask_entry_commit_cb (GtkIMContext *context, const gchar *str, 
+                                 GkrAskEntry *entry)
+{
+    gkr_ask_entry_enter_text (entry, str);
+}
+
+static void
+gkr_ask_entry_preedit_changed_cb (GtkIMContext *context, GkrAskEntry *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);
+
+    gkr_ask_entry_recompute (entry);
+}
+
+static gboolean
+gkr_ask_entry_retrieve_surrounding_cb (GtkIMContext *context, GkrAskEntry *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
+gkr_ask_entry_delete_surrounding_cb (GtkIMContext *slave, gint offset, gint n_chars,
+                                             GkrAskEntry *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
+gkr_ask_entry_enter_text (GkrAskEntry *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)
+            gkr_ask_entry_delete_from_cursor (entry, GTK_DELETE_CHARS, 1);
+    }
+
+    tmp_pos = entry->current_pos;
+    gtk_editable_insert_text (editable, str, strlen(str), &tmp_pos);
+    gkr_ask_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
+gkr_ask_entry_set_positions (GkrAskEntry *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)
+        gkr_ask_entry_recompute (entry);
+}
+
+static void
+gkr_ask_entry_reset_layout (GkrAskEntry *entry)
+{
+    if (entry->cached_layout) {
+        g_object_unref (entry->cached_layout);
+        entry->cached_layout = NULL;
+    }
+}
+
+static void
+update_im_cursor_location (GkrAskEntry *entry)
+{
+    GdkRectangle area;
+    gint strong_x;
+    gint strong_xoffset;
+    gint area_width, area_height;
+
+    gkr_ask_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)
+{
+    GkrAskEntry *entry;
+
+    GDK_THREADS_ENTER ();
+
+    entry = GKR_ASK_ENTRY (data);
+
+    entry->recompute_idle = 0;
+
+    if (gtk_widget_has_screen (GTK_WIDGET (entry))) {
+        gkr_ask_entry_adjust_scroll (entry);
+        gkr_ask_entry_queue_draw (entry);
+
+        update_im_cursor_location (entry);
+    }
+
+    GDK_THREADS_LEAVE ();
+
+    return FALSE;
+}
+
+static void
+gkr_ask_entry_recompute (GkrAskEntry *entry)
+{
+    gkr_ask_entry_reset_layout (entry);
+    gkr_ask_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 gunichar
+build_string (GkrAskEntry *entry, GString *str, gint extra)
+{
+    gint i, count, char_len;
+    gunichar invisible_char;
+    gchar buf[7];
+    
+    if (entry->visibility) {
+        g_string_append_len (str, entry->text, entry->n_bytes);
+        return 0;
+        
+    } else {
+        
+        if (entry->invisible_char != 0)
+            invisible_char = entry->invisible_char;
+        else
+            invisible_char = ' '; /* just pick a char */
+        
+        count = g_utf8_strlen (entry->text, entry->n_bytes) + extra;
+        
+        char_len = g_unichar_to_utf8 (entry->invisible_char, buf);
+        for (i = 0; i < count; i++)
+            g_string_append_len(str, buf, char_len);
+        
+        return invisible_char;
+    }
+}
+
+static PangoLayout *
+gkr_ask_entry_create_layout (GkrAskEntry * 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 preedit_len_chars;
+        gunichar invisible_char;
+
+        preedit_len_chars = g_utf8_strlen (preedit_string, -1);
+        invisible_char = build_string (entry, tmp_string, preedit_len_chars);
+    
+        /* 
+         * 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);
+            build_string (entry, str, 0);
+            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 *
+gkr_ask_entry_ensure_layout (GkrAskEntry *entry, gboolean include_preedit)
+{
+    if (entry->preedit_length > 0 && !include_preedit != !entry->cache_includes_preedit)
+        gkr_ask_entry_reset_layout (entry);
+
+    if (!entry->cached_layout) {
+        entry->cached_layout = gkr_ask_entry_create_layout (entry, include_preedit);
+        entry->cache_includes_preedit = include_preedit;
+    }
+
+    return entry->cached_layout;
+}
+
+static void
+get_layout_position (GkrAskEntry *entry, gint *x, gint *y)
+{
+    PangoLayout *layout;
+    PangoRectangle logical_rect;
+    gint area_width, area_height;
+    gint y_pos;
+    PangoLayoutLine *line;
+
+    layout = gkr_ask_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
+gkr_ask_entry_draw_text(GkrAskEntry *entry)
+{
+    GtkWidget *widget;
+    PangoLayoutLine *line;
+
+    if (entry->invisible_char == 0)
+        return;
+
+    if (GTK_WIDGET_DRAWABLE (entry)) {
+        PangoLayout *layout = gkr_ask_entry_ensure_layout (entry, TRUE);
+        gint x, y;
+        gint start_pos, end_pos;
+
+        widget = GTK_WIDGET(entry);
+
+        get_layout_position(entry, &x, &y);
+
+        gdk_draw_layout(entry->text_area, widget->style->text_gc[widget->state], 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;
+            GdkRegion *clip_region = gdk_region_new ();
+            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(entry)) {
+                selection_gc = widget->style->base_gc[GTK_STATE_SELECTED];
+                text_gc = widget->style->text_gc[GTK_STATE_SELECTED];
+            } else {
+                selection_gc = widget->style->base_gc[GTK_STATE_ACTIVE];
+                text_gc = widget->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);
+
+                gdk_region_union_with_rect(clip_region, &rect);
+            }
+
+            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);
+
+            gdk_region_destroy(clip_region);
+            g_free(ranges);
+        }
+    }
+}
+
+static void
+draw_insertion_cursor (GkrAskEntry *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
+gkr_ask_entry_draw_cursor (GkrAskEntry * entry)
+{
+    GdkKeymap *keymap = gdk_keymap_get_for_display (gtk_widget_get_display (GTK_WIDGET(entry)));
+    PangoDirection keymap_direction = gdk_keymap_get_direction (keymap);
+
+    if (GTK_WIDGET_DRAWABLE (entry)) {
+        GtkWidget *widget = GTK_WIDGET(entry);
+        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);
+
+        gkr_ask_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
+gkr_ask_entry_queue_draw (GkrAskEntry *entry)
+{
+    if (GTK_WIDGET_REALIZED (entry))
+        gdk_window_invalidate_rect (entry->text_area, NULL, FALSE);
+}
+
+static void
+gkr_ask_entry_reset_im_context (GkrAskEntry *entry)
+{
+    if (entry->need_im_reset) {
+        entry->need_im_reset = 0;
+        gtk_im_context_reset (entry->im_context);
+    }
+}
+
+static gint
+gkr_ask_entry_find_position (GkrAskEntry *entry, gint x)
+{
+    PangoLayout *layout;
+    PangoLayoutLine *line;
+    gint _index;
+    gint pos;
+    gboolean trailing;
+    const gchar *text;
+    gint cursor_index;
+
+    layout = gkr_ask_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
+gkr_ask_entry_get_cursor_locations (GkrAskEntry *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 = gkr_ask_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
+gkr_ask_entry_adjust_scroll (GkrAskEntry *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_REALIZED(entry))
+        return;
+
+    gdk_drawable_get_size (entry->text_area, &text_area_width, NULL);
+    text_area_width -= 2 * INNER_BORDER;
+
+    layout = gkr_ask_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.
+     */
+
+    gkr_ask_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
+gkr_ask_entry_move_visually (GkrAskEntry * entry,
+                                     gint start, gint count)
+{
+    gint _index;
+    PangoLayout *layout = gkr_ask_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
+gkr_ask_entry_move_logically (GkrAskEntry *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 *
+gkr_ask_entry_new (void)
+{
+    return g_object_new (GKR_TYPE_ASK_ENTRY, NULL);
+}
+
+void
+gkr_ask_entry_set_text (GkrAskEntry *entry, const gchar *text)
+{
+    gint tmp_pos;
+
+    g_return_if_fail (GKR_IS_ASK_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);
+}
+
+void 
+gkr_ask_entry_reset_changed (GkrAskEntry *entry)
+{
+    g_return_if_fail (GKR_IS_ASK_ENTRY (entry));
+    entry->changed = FALSE;
+}
+
+gboolean
+gkr_ask_entry_get_changed (GkrAskEntry *entry)
+{
+    g_return_val_if_fail (GKR_IS_ASK_ENTRY (entry), FALSE);
+    return entry->changed;
+}
+
+void
+gkr_ask_entry_set_visibility (GkrAskEntry *entry, gboolean setting)
+{
+    g_return_if_fail (GKR_IS_ASK_ENTRY (entry));
+
+    if (setting == entry->visibility)
+        return;
+
+    entry->visibility = setting;
+    g_object_notify (G_OBJECT (entry), "visibility");
+    gkr_ask_entry_recompute (entry);
+}
+
+gboolean
+gkr_ask_entry_get_visibility (GkrAskEntry *entry)
+{
+    g_return_val_if_fail (GKR_IS_ASK_ENTRY (entry), FALSE);
+    return entry->visibility;
+}
+
+
+/**
+ * gkr_ask_entry_set_invisible_char:
+ * @entry: a #GkrAskEntry
+ * @ch: a Unicode character
+ * 
+ * Sets the character to use in place of the actual text when
+ * gkr_ask_entry_set_visibility() has been called to set text 
+ * 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
+gkr_ask_entry_set_invisible_char (GkrAskEntry *entry, gunichar ch)
+{
+    g_return_if_fail (GKR_IS_ASK_ENTRY (entry));
+
+    if (ch == entry->invisible_char)
+        return;
+
+    entry->invisible_char = ch;
+    g_object_notify (G_OBJECT (entry), "invisible_char");
+    gkr_ask_entry_recompute (entry);
+}
+
+/**
+ * gkr_ask_entry_get_invisible_char:
+ * @entry: a #GkrAskEntry
+ *
+ * Retrieves the character displayed in place of the real characters
+ * for entries with visisbility set to false. See gkr_ask_entry_set_invisible_char().
+ *
+ * Return value: the current invisible char, or 0, if the entry does not
+ *               show invisible text at all. 
+ **/
+gunichar
+gkr_ask_entry_get_invisible_char (GkrAskEntry * entry)
+{
+    g_return_val_if_fail (GKR_IS_ASK_ENTRY (entry), 0);
+
+    return entry->invisible_char;
+}
+
+/**
+ * gkr_ask_entry_get_text:
+ * @entry: a #GkrAskEntry
+ *
+ * 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*
+gkr_ask_entry_get_text (GkrAskEntry *entry)
+{
+    g_return_val_if_fail (GKR_IS_ASK_ENTRY (entry), NULL);
+
+    return entry->text;
+}
+
+/**
+ * gkr_ask_entry_set_max_length:
+ * @entry: a #GkrAskEntry.
+ * @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
+gkr_ask_entry_set_max_length(GkrAskEntry *entry, gint max)
+{
+    g_return_if_fail (GKR_IS_ASK_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");
+}
+
+/**
+ * gkr_ask_entry_get_max_length:
+ * @entry: a #GkrAskEntry
+ *
+ * Retrieves the maximum allowed length of the text in
+ * @entry. See gkr_ask_entry_set_max_length().
+ *
+ * Return value: the maximum allowed number of characters
+ *               in #GkrAskEntry, or 0 if there is no maximum.
+ **/
+gint
+gkr_ask_entry_get_max_length (GkrAskEntry *entry)
+{
+    g_return_val_if_fail (GKR_IS_ASK_ENTRY (entry), 0);
+    return entry->text_max_length;
+}
+
+/**
+ * gkr_ask_entry_set_activates_default:
+ * @entry: a #GkrAskEntry
+ * @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
+gkr_ask_entry_set_activates_default (GkrAskEntry *entry,
+                                             gboolean setting)
+{
+    g_return_if_fail (GKR_IS_ASK_ENTRY (entry));
+    setting = setting != FALSE;
+
+    if (setting != entry->activates_default) {
+        entry->activates_default = setting;
+        g_object_notify (G_OBJECT (entry), "activates_default");
+    }
+}
+
+/**
+ * gkr_ask_entry_get_activates_default:
+ * @entry: a #GkrAskEntry
+ * 
+ * Retrieves the value set by gkr_ask_entry_set_activates_default().
+ * 
+ * Return value: %TRUE if the entry will activate the default widget
+ **/
+gboolean
+gkr_ask_entry_get_activates_default (GkrAskEntry *entry)
+{
+    g_return_val_if_fail (GKR_IS_ASK_ENTRY (entry), FALSE);
+    return entry->activates_default;
+}
+
+/**
+ * gkr_ask_entry_set_width_chars:
+ * @entry: a #GkrAskEntry
+ * @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
+ * <emphasis>request</emphasis>, 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
+gkr_ask_entry_set_width_chars (GkrAskEntry *entry, gint n_chars)    
+{
+    g_return_if_fail (GKR_IS_ASK_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));
+    }
+}
+
+/**
+ * gkr_ask_entry_get_width_chars:
+ * @entry: a #GkrAskEntry
+ * 
+ * Gets the value set by gkr_ask_entry_set_width_chars().
+ * 
+ * Return value: number of chars to request space for, or negative if unset
+ **/
+gint
+gkr_ask_entry_get_width_chars (GkrAskEntry *entry)
+{
+    g_return_val_if_fail (GKR_IS_ASK_ENTRY (entry), 0);
+    return entry->width_chars;
+}
+
+/**
+ * gkr_ask_entry_set_has_frame:
+ * @entry: a #GkrAskEntry
+ * @setting: new value
+ * 
+ * Sets whether the entry has a beveled frame around it.
+ **/
+void
+gkr_ask_entry_set_has_frame (GkrAskEntry *entry, gboolean setting)
+{
+    g_return_if_fail (GKR_IS_ASK_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");
+}
+
+/**
+ * gkr_ask_entry_get_has_frame:
+ * @entry: a #GkrAskEntry
+ * 
+ * Gets the value set by gkr_ask_entry_set_has_frame().
+ * 
+ * Return value: whether the entry has a beveled frame
+ **/
+gboolean
+gkr_ask_entry_get_has_frame (GkrAskEntry *entry)
+{
+    g_return_val_if_fail (GKR_IS_ASK_ENTRY (entry), FALSE);
+    return entry->has_frame;
+}
+
+static gboolean
+gkr_ask_entry_mnemonic_activate (GtkWidget *widget, gboolean group_cycling)
+{
+    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 (GkrAskEntry *entry)
+{
+    GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (entry));
+    gboolean blink;
+
+    if (GTK_WIDGET_HAS_FOCUS (entry) &&
+        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 (GkrAskEntry *entry)
+{
+    GtkSettings *settings = gtk_widget_get_settings (GTK_WIDGET (entry));
+    gint time;
+
+    g_object_get (settings, "gtk-cursor-blink-time", &time, NULL);
+
+    return time;
+}
+
+static void
+show_cursor (GkrAskEntry *entry)
+{
+    if (!entry->cursor_visible) {
+        entry->cursor_visible = TRUE;
+
+        if (GTK_WIDGET_HAS_FOCUS (entry) && 
+            entry->selection_bound == entry->current_pos)
+            gtk_widget_queue_draw (GTK_WIDGET (entry));
+    }
+}
+
+static void
+hide_cursor(GkrAskEntry * entry)
+{
+    if (entry->cursor_visible) {
+        entry->cursor_visible = FALSE;
+
+    if (GTK_WIDGET_HAS_FOCUS (entry) && 
+        entry->selection_bound == entry->current_pos)
+        gtk_widget_queue_draw (GTK_WIDGET (entry));
+    }
+}
+
+/*
+ * Blink!
+ */
+static gint
+blink_cb (gpointer data)
+{
+    GkrAskEntry *entry;
+
+    GDK_THREADS_ENTER ();
+
+    entry = GKR_ASK_ENTRY (data);
+
+    if (!GTK_WIDGET_HAS_FOCUS (entry)) {
+        g_warning ("GkrAskEntry - 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 (entry));
+    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
+gkr_ask_entry_check_cursor_blink (GkrAskEntry *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
+gkr_ask_entry_pend_cursor_blink (GkrAskEntry *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,
+                                    guint n_param_values, const GValue * param_values,
+                                    gpointer invocation_hint, 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,
+                            guint n_param_values, const GValue * param_values,
+                            gpointer invocation_hint, 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);
+}

Added: trunk/ui/gkr-ask-entry.h
==============================================================================
--- (empty file)
+++ trunk/ui/gkr-ask-entry.h	Wed Feb  6 04:02:53 2008
@@ -0,0 +1,187 @@
+/*
+ * GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * 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Ã
+ * <albrecht dress arcor de> Feb. 2004.
+ *
+ * (C) by Albrecht Dreà 2004 unter the terms of the GNU Lesser General
+ * Public License.
+ *
+ * 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.
+ */
+
+/* 
+ * Modified for inclusion into gnome-keyring by Stef Walter 
+ */
+
+#ifndef __GKR_ASK_ENTRY_H__
+#define __GKR_ASK_ENTRY_H__
+
+
+#include <gtk/gtk.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+    
+#define GKR_TYPE_ASK_ENTRY                  (gkr_ask_entry_get_type ())
+#define GKR_ASK_ENTRY(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKR_TYPE_ASK_ENTRY, GkrAskEntry))
+#define GKR_ASK_ENTRY_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GKR_TYPE_ASK_ENTRY, GkrAskEntryClass))
+#define GKR_IS_ASK_ENTRY(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKR_TYPE_ASK_ENTRY))
+#define GKR_IS_ASK_ENTRY_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GKR_TYPE_ASK_ENTRY))
+#define GKR_ASK_ENTRY_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GKR_TYPE_ASK_ENTRY, GkrAskEntryClass))
+    
+typedef struct _GkrAskEntry GkrAskEntry;
+typedef struct _GkrAskEntryClass GkrAskEntryClass;
+
+struct _GkrAskEntry {
+    GtkWidget widget;
+
+    gchar *text;
+
+    guint overwrite_mode : 1;
+
+    /* length in use, in chars */
+    guint16 text_length; 
+    guint16 text_max_length;
+
+    /*< private > */
+    GdkWindow *text_area;
+    GtkIMContext *im_context;
+
+    gint current_pos;
+    gint selection_bound;
+
+    PangoLayout *cached_layout;
+    guint cache_includes_preedit : 1;
+
+    guint need_im_reset : 1;
+
+    guint has_frame : 1;
+
+    guint activates_default : 1;
+
+    guint cursor_visible : 1;
+
+    /* Flag so we don't select all when clicking in entry to focus in */
+    guint in_click : 1;
+
+    /* Only used by GtkCellRendererText */
+    guint is_cell_renderer : 1;
+    guint editing_canceled : 1;    
+
+    guint mouse_cursor_obscured : 1;
+
+    /* PangoDirection */
+    guint resolved_dir : 4; 
+
+    guint button;
+    guint blink_timeout;
+    guint recompute_idle;
+    gint scroll_offset;
+    gint ascent;            /* font ascent, in pango units  */
+    gint descent;           /* font descent, in pango units  */
+
+    guint16 text_size;      /* allocated size, in bytes */
+    guint16 n_bytes;        /* length in use, in bytes */
+
+    guint16 preedit_length; /* length of preedit string, in bytes */
+    guint16 preedit_cursor; /* offset of cursor within preedit string, in chars */
+
+    gunichar invisible_char;
+    gint width_chars;
+    
+    gboolean visibility;
+    
+    /* Keeps track of whether changed between resets */
+    gboolean changed;
+};
+
+struct _GkrAskEntryClass {
+    GtkWidgetClass parent_class;
+
+    /* Action signals */
+    void (*activate) (GkrAskEntry *entry);
+    void (*move_cursor) (GkrAskEntry *entry, GtkMovementStep step,
+                         gint count, gboolean extend_selection);
+    void (*insert_at_cursor) (GkrAskEntry *entry, const gchar *str);
+    void (*delete_from_cursor) (GkrAskEntry *entry, GtkDeleteType type, gint count);
+
+    /* Padding for future expansion */
+    void (*_gtk_reserved1) (void);
+    void (*_gtk_reserved2) (void);
+    void (*_gtk_reserved3) (void);
+    void (*_gtk_reserved4) (void);
+};
+
+GType               gkr_ask_entry_get_type              (void) G_GNUC_CONST;
+
+GtkWidget*          gkr_ask_entry_new                   (void);
+
+void                gkr_ask_entry_reset_changed         (GkrAskEntry *entry);
+
+gboolean            gkr_ask_entry_get_changed           (GkrAskEntry *entry);
+
+void                gkr_ask_entry_set_visibility        (GkrAskEntry *entry, gboolean setting);
+
+gboolean            gkr_ask_entry_get_visibility        (GkrAskEntry *entry);
+
+void                gkr_ask_entry_set_invisible_char    (GkrAskEntry *entry, gunichar ch);
+
+gunichar            gkr_ask_entry_get_invisible_char    (GkrAskEntry *entry);
+
+void                gkr_ask_entry_set_has_frame         (GkrAskEntry *entry, gboolean setting);
+
+gboolean            gkr_ask_entry_get_has_frame         (GkrAskEntry *entry);
+
+/* text is truncated if needed */
+void                gkr_ask_entry_set_max_length        (GkrAskEntry *entry, gint max);
+
+gint                gkr_ask_entry_get_max_length        (GkrAskEntry *entry);
+
+void                gkr_ask_entry_set_activates_default (GkrAskEntry *entry, gboolean setting);
+
+gboolean            gkr_ask_entry_get_activates_default (GkrAskEntry *entry);
+
+void                gkr_ask_entry_set_width_chars       (GkrAskEntry *entry, gint n_chars);
+
+gint                gkr_ask_entry_get_width_chars       (GkrAskEntry *entry);
+
+/* Somewhat more convenient than the GtkEditable generic functions */
+void                gkr_ask_entry_set_text              (GkrAskEntry *entry, const gchar *text);
+
+/* returns a reference to the text */
+const gchar*        gkr_ask_entry_get_text              (GkrAskEntry *entry);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /*__GKR_ASK_ENTRY_H__ */

Modified: trunk/ui/gkr-ask-tool.c
==============================================================================
--- trunk/ui/gkr-ask-tool.c	(original)
+++ trunk/ui/gkr-ask-tool.c	Wed Feb  6 04:02:53 2008
@@ -22,9 +22,12 @@
 
 #include "config.h"
 
+#include "gkr-ask-entry.h"
 #include "gkr-ask-tool.h"
 #include "gkr-ask-request.h"
 
+#include "common/gkr-secure-memory.h"
+
 #include <gtk/gtk.h>
 #include <glib/gi18n.h>
 
@@ -40,6 +43,74 @@
 static GKeyFile *output_data = NULL;
 static gboolean grabbed = FALSE;
 
+/* -----------------------------------------------------------------------------
+ * MEMORY
+ */
+
+static gboolean do_warning = TRUE;
+#define WARNING  "couldn't allocate secure memory to keep passwords " \
+		 "and or keys from being written to the disk"
+		 
+#define ABORTMSG "The GNOME_KEYRING_PARANOID environment variable was set. " \
+                 "Exiting..."
+
+/* 
+ * These are called from gkr-secure-memory.c to provide appropriate
+ * locking for memory between threads
+ */ 
+
+void
+gkr_memory_lock (void)
+{
+	/* No threads used in ask tool, doesn't need locking */
+}
+
+void 
+gkr_memory_unlock (void)
+{
+	/* No threads used in ask tool, doesn't need locking */
+}
+
+void*
+gkr_memory_fallback (void *p, unsigned long sz)
+{
+	const gchar *env;
+	
+	/* We were asked to free memory */
+	if (!sz) {
+		g_free (p);
+		return NULL;
+	}
+	
+	/* We were asked to allocate */
+	if (!p) {
+		if (do_warning) {
+			g_message (WARNING);
+			do_warning = FALSE;
+		}
+		
+		env = g_getenv ("GNOME_KEYRING_PARANOID");
+		if (env && *env) 
+			g_error (ABORTMSG);
+			
+		return g_malloc0 (sz);
+	}
+	
+	/* 
+	 * Reallocation is a bit of a gray area, as we can be asked 
+	 * by external libraries (like libgcrypt) to reallocate a 
+	 * non-secure block into secure memory. We cannot satisfy 
+	 * this request (as we don't know the size of the original 
+	 * block) so we just try our best here.
+	 */
+			 
+	return g_realloc (p, sz);
+}
+
+/* -------------------------------------------------------------------------
+ * HELPERS 
+ */
+
 /* Because Solaris doesn't have err() :( */
 static void 
 fatal (const char *msg1, const char *msg2)
@@ -52,6 +123,28 @@
 	exit (1);
 }
 
+static void
+write_output (const gchar *data, gsize len)
+{
+	int res;
+	
+	while (len > 0) {
+		res = write (1, data, len);
+		if (res <= 0) {
+			if (errno == EAGAIN && errno == EINTR)
+				continue;
+			g_warning ("couldn't write dialog response to output: %s",
+			           g_strerror (errno));
+			exit (1);
+		} else  {
+			len -= res;
+			data += res;
+		}
+	}
+}
+
+/* ------------------------------------------------------------------------------ */
+
 static gchar*
 create_markup (const gchar *primary, const gchar *secondary)
 {
@@ -103,7 +196,7 @@
 	int upper, lower, digit, misc;
 	gdouble pwstrength;
 
-	password = gtk_entry_get_text (GTK_ENTRY (editable));
+	password = gkr_ask_entry_get_text (GKR_ASK_ENTRY (editable));
 
 	/*
 	 * This code is based on the Master Password dialog in Firefox
@@ -159,36 +252,6 @@
 	gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (user_data), pwstrength);
 }
 
-static void
-unlock_memory (void)
-{
-#ifdef HAVE_MLOCKALL
-	munlockall ();
-#endif
-}
-
-static void
-lock_memory (void)
-{
-	int r = 0;
-
-	/* 
-	 * TODO: This is a copout, due to the fact that GTK, and the entry 
-	 * control in particular are hard to lock into memory. 
-	 * 
-	 * Since this is short lived process, should work for now. In the future
-	 * we need to make this more fine grained.
-	 */
-#ifdef HAVE_MLOCKALL
-	r = mlockall (MCL_CURRENT);
-#endif
-
-	if (r < 0)
-		g_warning ("couldn't lock process in memory: %s", strerror (errno));
-	else
-		g_atexit (unlock_memory);
-}
-
 static gboolean
 grab_keyboard (GtkWidget *win, GdkEvent *event, gpointer data)
 {
@@ -351,8 +414,8 @@
 	if (include_original) {
 		gtk_table_resize (GTK_TABLE (ptable), ++row, 2);	
 		label = gtk_label_new_with_mnemonic (_("_Old password:"));
-		old = gtk_entry_new ();
-		gtk_entry_set_visibility (GTK_ENTRY (old), FALSE);
+		old = gkr_ask_entry_new ();
+		gkr_ask_entry_set_visibility (GKR_ASK_ENTRY (old), FALSE);
 		gtk_label_set_mnemonic_widget (GTK_LABEL (label), old);
 		g_signal_connect_swapped (old,
 					  "activate",
@@ -371,8 +434,8 @@
 	if (include_password) {
 		gtk_table_resize (GTK_TABLE (ptable), ++row, 2);	
 		label = gtk_label_new_with_mnemonic (_("_Password:"));
-		entry = gtk_entry_new ();
-		gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
+		entry = gkr_ask_entry_new ();
+		gkr_ask_entry_set_visibility (GKR_ASK_ENTRY (entry), FALSE);
 		gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
 		g_signal_connect_swapped (entry,
 					  "activate",
@@ -393,8 +456,8 @@
 	
 		gtk_table_resize (GTK_TABLE (ptable), ++row, 2);	
 		label = gtk_label_new_with_mnemonic (_("_Confirm password:"));
-		confirm = gtk_entry_new ();
-		gtk_entry_set_visibility (GTK_ENTRY (confirm), FALSE);
+		confirm = gkr_ask_entry_new ();
+		gkr_ask_entry_set_visibility (GKR_ASK_ENTRY (confirm), FALSE);
 		gtk_label_set_mnemonic_widget (GTK_LABEL (label), confirm);
 		g_signal_connect_swapped (confirm,
 					  "activate",
@@ -409,15 +472,13 @@
 					   1, 2, row - 1, row);
 
 		/* Strength bar: */
-		gtk_table_resize (GTK_TABLE (ptable), ++row, 2);
-		strength_bar = gtk_progress_bar_new ();
-		gtk_progress_bar_set_text (GTK_PROGRESS_BAR (strength_bar), _("New password strength"));
-		g_signal_connect ((gpointer) entry, "changed",
-				  G_CALLBACK (on_password_changed),
-				  strength_bar);
-		gtk_table_attach_defaults (GTK_TABLE (ptable), 
-					   strength_bar,
-					   1, 2, row - 1, row);
+		if (entry) {
+			gtk_table_resize (GTK_TABLE (ptable), ++row, 2);
+			strength_bar = gtk_progress_bar_new ();
+			gtk_progress_bar_set_text (GTK_PROGRESS_BAR (strength_bar), _("New password strength"));
+			g_signal_connect ((gpointer) entry, "changed", G_CALLBACK (on_password_changed), strength_bar);
+			gtk_table_attach_defaults (GTK_TABLE (ptable), strength_bar, 1, 2, row - 1, row);
+		}
 	}
 	
 	check = NULL;
@@ -454,12 +515,6 @@
 	gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
 	gtk_window_set_type_hint (GTK_WINDOW (dialog), GDK_WINDOW_TYPE_HINT_NORMAL);
 	
-	/*
-	 * We do this as late as possible, so all the memory the process needs is 
-	 * allocated in memory. This prevents mapping failures.
-	 */
-	lock_memory ();
-
  retry:
 	gtk_widget_show (dialog);
 	response = gtk_dialog_run (GTK_DIALOG (dialog));
@@ -468,16 +523,16 @@
 	
 	/* Get the original password */
 	if (include_original && old != NULL && response >= GKR_ASK_RESPONSE_ALLOW) {
-		original = gtk_entry_get_text (GTK_ENTRY (old));
-		*original_out = g_strdup (original);
+		original = gkr_ask_entry_get_text (GKR_ASK_ENTRY (old));
+		*original_out = gkr_secure_strdup (original);
 	}
 
 	/* Get the main password entry, and confirmation */
 	if (include_password && entry != NULL && response >= GKR_ASK_RESPONSE_ALLOW) {
-		password = gtk_entry_get_text (GTK_ENTRY (entry));
+		password = gkr_ask_entry_get_text (GKR_ASK_ENTRY (entry));
 		if (include_confirm && confirm != NULL) {
-			confirmation = gtk_entry_get_text (GTK_ENTRY (confirm));
-			if (strcmp(password, confirmation) != 0) {
+			confirmation = gkr_ask_entry_get_text (GKR_ASK_ENTRY (confirm));
+			if (strcmp (password, confirmation) != 0) {
 				notice_text = create_notice (_("Passwords do not match."));
 				gtk_label_set_markup (notice,  notice_text);
 				gtk_widget_show (GTK_WIDGET (notice));
@@ -485,7 +540,7 @@
 				goto retry;
 			}
 		}
-		*password_out = g_strdup (password);
+		*password_out = gkr_secure_strdup (password);
 	}
 	
 	/* When it's a new password and blank, double check */
@@ -589,26 +644,26 @@
 	}
 	
 	if (!password)
-		password = g_strdup ("");
+		password = gkr_secure_strdup ("");
 	if (!original)
-		original = g_strdup ("");
+		original = gkr_secure_strdup ("");
 
 	/* First two lines of the response are always the passwords */
 	if (response < GKR_ASK_RESPONSE_ALLOW || !(flags & GKR_ASK_REQUEST_PASSWORD))
 		password[0] = 0;
-	printf ("%s\n", password);
+	write_output (password, strlen (password));
+	write_output ("\n", 1);
 		
 	if (response < GKR_ASK_RESPONSE_ALLOW || !(flags & GKR_ASK_REQUEST_ORIGINAL_PASSWORD))
 		original[0] = 0;
-	printf ("%s\n", original);
-	
-	fflush (stdout);
+	write_output (original, strlen (original));
+	write_output ("\n", 1);
 	
 	/* Send back the response */
 	g_key_file_set_integer (output_data, "general", "response", response);
 	
-	g_free (password);
-	g_free (original);
+	gkr_secure_free (password);
+	gkr_secure_free (original);
 }
 
 static gchar*
@@ -635,26 +690,6 @@
 	return g_string_free (data, FALSE);
 }
 
-static void
-write_all_output (const gchar *data, gsize len)
-{
-	int res;
-	
-	while (len > 0) {
-		res = write (1, data, len);
-		if (res <= 0) {
-			if (errno == EAGAIN && errno == EINTR)
-				continue;
-			g_warning ("couldn't write dialog response to output: %s",
-			           g_strerror (errno));
-			exit (1);
-		} else  {
-			len -= res;
-			data += res;
-		}
-	}
-}
-
 int
 main (int argc, char *argv[])
 {
@@ -700,7 +735,7 @@
 	if (!data)
 		fatal ("couldn't format dialog response: %s", err ? err->message : ""); 
 	
-	write_all_output (data, length);
+	write_output (data, length);
 	g_free (data);
 	
 	return 0;

Added: trunk/ui/test-input.txt
==============================================================================
--- (empty file)
+++ trunk/ui/test-input.txt	Wed Feb  6 04:02:53 2008
@@ -0,0 +1,8 @@
+[general]
+flags=16641
+title=Test Ask Dialog
+primary=Primary prompt text.
+secondary=Some secondary prompt text is here.
+check-enable=true
+check-text=The check text
+



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]