[gtk+/wip/matthiasc/password-indicator: 2/2] entry: Add a password indicator
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/matthiasc/password-indicator: 2/2] entry: Add a password indicator
- Date: Fri, 18 Dec 2015 19:23:31 +0000 (UTC)
commit 2313f5ac5c6c654c137bb0bab53981424d528b28
Author: Matthias Clasen <mclasen redhat com>
Date: Fri Dec 18 14:21:10 2015 -0500
entry: Add a password indicator
This adds a password-indicator property to GtkEntry. When set
on a password entry, the entry shows an icon indicating it is
in password mode, which can be clicked to reveal the text.
We are careful to not interfere with the Caps Lock warning,
which uses the same icon position.
gtk/gtkentry.c | 134 +++++++++++++++++++++++--
gtk/icons/16x16/status/password-invisible.png | Bin 0 -> 284 bytes
gtk/icons/16x16/status/password-visible.png | Bin 0 -> 312 bytes
tests/testentryicons.c | 3 +
4 files changed, 129 insertions(+), 8 deletions(-)
---
diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c
index 6318af7..ad83f6b 100644
--- a/gtk/gtkentry.c
+++ b/gtk/gtkentry.c
@@ -243,6 +243,8 @@ struct _GtkEntryPrivate
guint cache_includes_preedit : 1;
guint caps_lock_warning : 1;
guint caps_lock_warning_shown : 1;
+ guint password_indicator : 1;
+ guint password_indicator_connected : 1;
guint change_count : 8;
guint cursor_visible : 1;
guint editing_canceled : 1; /* Only used by GtkCellRendererText */
@@ -333,6 +335,7 @@ enum {
PROP_TEXT_LENGTH,
PROP_INVISIBLE_CHAR_SET,
PROP_CAPS_LOCK_WARNING,
+ PROP_PASSWORD_INDICATOR,
PROP_PROGRESS_FRACTION,
PROP_PROGRESS_PULSE_STEP,
PROP_PIXBUF_PRIMARY,
@@ -649,6 +652,7 @@ static void get_frame_size (GtkEntry *entry,
static void gtk_entry_move_adjustments (GtkEntry *entry);
static void gtk_entry_update_cached_style_values(GtkEntry *entry);
static gboolean get_middle_click_paste (GtkEntry *entry);
+static void update_password_indicator (GtkEntry *entry);
/* GtkTextHandle handlers */
static void gtk_entry_handle_drag_started (GtkTextHandle *handle,
@@ -1031,7 +1035,7 @@ gtk_entry_class_init (GtkEntryClass *class)
/**
* GtkEntry:caps-lock-warning:
*
- * Whether password entries will show a warning when Caps Lock is on.
+ * Whether the entry will show a warning when Caps Lock is on in password mode.
*
* Note that the warning is shown using a secondary icon, and thus
* does not work if you are using the secondary icon position for some
@@ -1042,11 +1046,29 @@ gtk_entry_class_init (GtkEntryClass *class)
entry_props[PROP_CAPS_LOCK_WARNING] =
g_param_spec_boolean ("caps-lock-warning",
P_("Caps Lock warning"),
- P_("Whether password entries will show a warning when Caps Lock is on"),
+ P_("Whether the entry shows a warning when Caps Lock is on in password mode"),
TRUE,
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
/**
+ * GtkEntry:password-indicator:
+ *
+ * Whether the entry shows an icon to toggle password mode on and off.
+ *
+ * Note that the icon is shown using a secondary icon, and thus
+ * does not work if you are using the secondary icon position for some
+ * other purpose.
+ *
+ * Since: 3.20
+ */
+ entry_props[PROP_PASSWORD_INDICATOR] =
+ g_param_spec_boolean ("password-indicator",
+ P_("Password indicator"),
+ P_("Whether the entry shows an icon to toggle password mode"),
+ FALSE,
+ GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+
+ /**
* GtkEntry:progress-fraction:
*
* The current fraction of the task that's been completed.
@@ -2226,6 +2248,15 @@ gtk_entry_set_property (GObject *object,
}
break;
+ case PROP_PASSWORD_INDICATOR:
+ if (priv->password_indicator != g_value_get_boolean (value))
+ {
+ priv->password_indicator = g_value_get_boolean (value);
+ update_password_indicator (entry);
+ g_object_notify_by_pspec (object, pspec);
+ }
+ break;
+
case PROP_PROGRESS_FRACTION:
gtk_entry_set_progress_fraction (entry, g_value_get_double (value));
break;
@@ -2489,6 +2520,10 @@ gtk_entry_get_property (GObject *object,
g_value_set_boolean (value, priv->caps_lock_warning);
break;
+ case PROP_PASSWORD_INDICATOR:
+ g_value_set_boolean (value, priv->password_indicator);
+ break;
+
case PROP_PROGRESS_FRACTION:
g_value_set_double (value, priv->progress_fraction);
break;
@@ -2711,6 +2746,8 @@ gtk_entry_init (GtkEntry *entry)
priv->xalign = 0.0;
priv->caps_lock_warning = TRUE;
priv->caps_lock_warning_shown = FALSE;
+ priv->password_indicator = FALSE;
+ priv->password_indicator_connected = FALSE;
priv->progress_fraction = 0.0;
priv->progress_pulse_fraction = 0.1;
@@ -3144,7 +3181,7 @@ realize_icon_info (GtkWidget *widget,
GDK_BUTTON3_MOTION_MASK |
GDK_POINTER_MOTION_MASK |
GDK_ENTER_NOTIFY_MASK |
- GDK_LEAVE_NOTIFY_MASK);
+ GDK_LEAVE_NOTIFY_MASK);
attributes_mask = GDK_WA_X | GDK_WA_Y;
icon_info->window = gdk_window_new (gtk_widget_get_window (widget),
@@ -3402,6 +3439,7 @@ gtk_entry_realize (GtkWidget *widget)
gtk_entry_adjust_scroll (entry);
gtk_entry_update_primary_selection (entry);
+ update_password_indicator (entry);
/* If the icon positions are already setup, create their windows.
* Otherwise if they don't exist yet, then construct_icon_info()
@@ -4325,6 +4363,8 @@ gtk_entry_event (GtkWidget *widget,
}
}
+g_print ("entry event: %s, icon_info %p\n", (event->type == GDK_BUTTON_PRESS ? "press" : (event->type ==
GDK_BUTTON_RELEASE ? "release" : (event->type == GDK_MOTION_NOTIFY ? "motion" : "other"))), icon_info);
+
if (!icon_info)
return GDK_EVENT_PROPAGATE;
@@ -4346,6 +4386,7 @@ gtk_entry_event (GtkWidget *widget,
case GDK_BUTTON_PRESS:
case GDK_2BUTTON_PRESS:
case GDK_3BUTTON_PRESS:
+g_print ("button press\n");
if (should_prelight (GTK_ENTRY (widget), i))
{
icon_info->prelight = FALSE;
@@ -4359,8 +4400,10 @@ gtk_entry_event (GtkWidget *widget,
icon_info->device = device;
if (!icon_info->nonactivatable)
+{
+g_print ("::icon-press %d\n", i);
g_signal_emit (widget, signals[ICON_PRESS], 0, i, event);
-
+}
break;
case GDK_TOUCH_UPDATE:
if (icon_info->device != device ||
@@ -4394,6 +4437,7 @@ gtk_entry_event (GtkWidget *widget,
icon_info->current_sequence = NULL;
/* Fall through */
case GDK_BUTTON_RELEASE:
+g_print ("button release\n");
icon_info->pressed = FALSE;
icon_info->device = NULL;
@@ -4408,8 +4452,10 @@ gtk_entry_event (GtkWidget *widget,
}
if (!icon_info->nonactivatable)
+{
+g_print ("::icon-release %d\n", i);
g_signal_emit (widget, signals[ICON_RELEASE], 0, i, event);
-
+}
break;
default:
return GDK_EVENT_PROPAGATE;
@@ -7814,6 +7860,7 @@ gtk_entry_set_visibility (GtkEntry *entry,
{
priv->visible = visible;
+ update_password_indicator (entry);
g_object_notify_by_pspec (G_OBJECT (entry), entry_props[PROP_VISIBILITY]);
gtk_entry_recompute (entry);
}
@@ -10988,7 +11035,77 @@ gtk_entry_get_placeholder_text (GtkEntry *entry)
return priv->placeholder_text;
}
-/* Caps Lock warning for password entries */
+/* Caps Lock warning and password indicator */
+
+static void
+password_indicator_show (GtkEntry *entry,
+ GtkEntryIconPosition pos,
+ GdkEvent *event,
+ gpointer data)
+{
+ GtkEntryPrivate *priv = entry->priv;
+
+ if (pos == GTK_ENTRY_ICON_SECONDARY && priv->password_indicator)
+ gtk_entry_set_visibility (entry, TRUE);
+}
+
+static void
+password_indicator_hide (GtkEntry *entry,
+ GtkEntryIconPosition pos,
+ GdkEvent *event,
+ gpointer data)
+{
+ GtkEntryPrivate *priv = entry->priv;
+
+ if (pos == GTK_ENTRY_ICON_SECONDARY && priv->password_indicator)
+ gtk_entry_set_visibility (entry, FALSE);
+}
+
+static void
+update_password_indicator (GtkEntry *entry)
+{
+ GtkEntryPrivate *priv = entry->priv;
+
+ if (priv->caps_lock_warning_shown)
+ return;
+
+ if (priv->password_indicator)
+ {
+ if (!priv->password_indicator_connected)
+ {
+ g_signal_connect (entry, "icon-press", G_CALLBACK (password_indicator_show), NULL);
+ g_signal_connect (entry, "icon-release", G_CALLBACK (password_indicator_hide), NULL);
+ priv->password_indicator_connected = TRUE;
+ }
+
+ gtk_entry_set_icon_activatable (entry, GTK_ENTRY_ICON_SECONDARY, TRUE);
+
+ if (gtk_entry_get_display_mode (entry) != DISPLAY_NORMAL)
+ {
+ gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, "password-invisible");
+ gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY, _("Show text"));
+ }
+ else
+ {
+ gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, "password-visible");
+ gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY, _("Hide text"));
+ }
+
+ }
+ else
+ {
+ if (priv->password_indicator_connected)
+ {
+ g_signal_handlers_disconnect_by_func (entry, password_indicator_show, NULL);
+ g_signal_handlers_disconnect_by_func (entry, password_indicator_hide, NULL);
+ priv->password_indicator_connected = FALSE;
+ }
+
+ gtk_entry_set_icon_activatable (entry, GTK_ENTRY_ICON_SECONDARY, FALSE);
+ gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, NULL);
+ gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY, NULL);
+ }
+}
static void
show_capslock_feedback (GtkEntry *entry,
@@ -10996,7 +11113,8 @@ show_capslock_feedback (GtkEntry *entry,
{
GtkEntryPrivate *priv = entry->priv;
- if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_SECONDARY) == GTK_IMAGE_EMPTY)
+ if (gtk_entry_get_icon_storage_type (entry, GTK_ENTRY_ICON_SECONDARY) == GTK_IMAGE_EMPTY ||
+ priv->password_indicator)
{
gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, "dialog-warning-symbolic");
gtk_entry_set_icon_activatable (entry, GTK_ENTRY_ICON_SECONDARY, FALSE);
@@ -11016,8 +11134,8 @@ remove_capslock_feedback (GtkEntry *entry)
if (priv->caps_lock_warning_shown)
{
- gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, NULL);
priv->caps_lock_warning_shown = FALSE;
+ update_password_indicator (entry);
}
}
diff --git a/gtk/icons/16x16/status/password-invisible.png b/gtk/icons/16x16/status/password-invisible.png
new file mode 100644
index 0000000..54eeba9
Binary files /dev/null and b/gtk/icons/16x16/status/password-invisible.png differ
diff --git a/gtk/icons/16x16/status/password-visible.png b/gtk/icons/16x16/status/password-visible.png
new file mode 100644
index 0000000..fee7fbd
Binary files /dev/null and b/gtk/icons/16x16/status/password-visible.png differ
diff --git a/tests/testentryicons.c b/tests/testentryicons.c
index df1d02b..f0a3c49 100644
--- a/tests/testentryicons.c
+++ b/tests/testentryicons.c
@@ -165,6 +165,8 @@ main (int argc, char **argv)
gtk_grid_attach (GTK_GRID (grid), entry, 1, 3, 1, 1);
gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
+ g_object_set (entry, "password-indicator", TRUE, NULL);
+#if 0
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry),
GTK_ENTRY_ICON_PRIMARY,
"dialog-password-symbolic");
@@ -172,6 +174,7 @@ main (int argc, char **argv)
gtk_entry_set_icon_activatable (GTK_ENTRY (entry),
GTK_ENTRY_ICON_PRIMARY,
FALSE);
+#endif
/* Name - Does not set any icons. */
label = gtk_label_new ("Name:");
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]