summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2019-03-13 20:36:24 -0400
committerMatthias Clasen <mclasen@redhat.com>2019-03-14 20:44:06 -0400
commite0b5b95eff74a49f83ac964ead76a12305d3b6c2 (patch)
tree63ca2f89158b4a46b0d69528e0be120040d68edd
parent5822a35087c2930f9e9ebcf4d38904d99aa2ac1a (diff)
downloadgtk+-e0b5b95eff74a49f83ac964ead76a12305d3b6c2.tar.gz
password entry: Add a strength indicator
Use a levelbar to show password strength. The strength value itself is provided by the application via a signal.
-rw-r--r--gtk/gtkpasswordentry.c134
-rw-r--r--gtk/gtkpasswordentry.h6
2 files changed, 140 insertions, 0 deletions
diff --git a/gtk/gtkpasswordentry.c b/gtk/gtkpasswordentry.c
index 7dc6603a59..433eeb4c9f 100644
--- a/gtk/gtkpasswordentry.c
+++ b/gtk/gtkpasswordentry.c
@@ -30,6 +30,7 @@
#include "gtkbox.h"
#include "gtkimage.h"
#include "gtkcheckmenuitem.h"
+#include "gtklevelbar.h"
#include "gtkintl.h"
#include "gtkprivate.h"
#include "gtkmarshalers.h"
@@ -59,17 +60,26 @@ typedef struct {
GtkWidget *icon;
GdkKeymap *keymap;
GtkWidget *peek_icon;
+ GtkWidget *strength_widget;
} GtkPasswordEntryPrivate;
enum {
PROP_PLACEHOLDER_TEXT = 1,
PROP_ACTIVATES_DEFAULT,
PROP_SHOW_PEEK_ICON,
+ PROP_SHOW_STRENGTH,
NUM_PROPERTIES
};
static GParamSpec *props[NUM_PROPERTIES] = { NULL, };
+enum {
+ GET_STRENGTH,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
static void gtk_password_entry_editable_init (GtkEditableInterface *iface);
G_DEFINE_TYPE_WITH_CODE (GtkPasswordEntry, gtk_password_entry, GTK_TYPE_WIDGET,
@@ -199,6 +209,7 @@ gtk_password_entry_dispose (GObject *object)
g_clear_pointer (&priv->entry, gtk_widget_unparent);
g_clear_pointer (&priv->icon, gtk_widget_unparent);
g_clear_pointer (&priv->peek_icon, gtk_widget_unparent);
+ g_clear_pointer (&priv->strength_widget, gtk_widget_unparent);
g_clear_pointer (&priv->box, gtk_widget_unparent);
G_OBJECT_CLASS (gtk_password_entry_parent_class)->dispose (object);
@@ -235,6 +246,10 @@ gtk_password_entry_set_property (GObject *object,
gtk_password_entry_set_show_peek_icon (entry, g_value_get_boolean (value));
break;
+ case PROP_SHOW_STRENGTH:
+ gtk_password_entry_set_show_strength (entry, g_value_get_boolean (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -266,6 +281,10 @@ gtk_password_entry_get_property (GObject *object,
g_value_set_boolean (value, gtk_password_entry_get_show_peek_icon (entry));
break;
+ case PROP_SHOW_STRENGTH:
+ g_value_set_boolean (value, gtk_password_entry_get_show_strength (entry));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -287,6 +306,18 @@ gtk_password_entry_measure (GtkWidget *widget,
gtk_widget_measure (priv->box, orientation, for_size,
minimum, natural,
minimum_baseline, natural_baseline);
+
+ if (priv->strength_widget)
+ {
+ int s_minimum, s_natural;
+
+ gtk_widget_measure (priv->box, orientation, for_size,
+ &s_minimum, &s_natural,
+ NULL, NULL);
+
+ *minimum = MAX (*minimum, s_minimum);
+ *natural = MAX (*natural, s_natural);
+ }
}
static void
@@ -298,6 +329,25 @@ gtk_password_entry_size_allocate (GtkWidget *widget,
GtkPasswordEntry *entry = GTK_PASSWORD_ENTRY (widget);
GtkPasswordEntryPrivate *priv = gtk_password_entry_get_instance_private (entry);
+ if (priv->strength_widget)
+ {
+ GtkAllocation s_alloc;
+ int min, nat;
+
+ gtk_widget_measure (priv->strength_widget,
+ GTK_ORIENTATION_VERTICAL,
+ -1,
+ &min, &nat,
+ NULL, NULL);
+
+ s_alloc.x = 0;
+ s_alloc.y = height - nat;
+ s_alloc.width = width;
+ s_alloc.height = nat;
+
+ gtk_widget_size_allocate (priv->strength_widget, &s_alloc, -1);
+ }
+
gtk_widget_size_allocate (priv->box,
&(GtkAllocation) { 0, 0, width, height },
baseline);
@@ -336,6 +386,19 @@ gtk_password_entry_mnemonic_activate (GtkWidget *widget,
}
static void
+gtk_password_entry_snapshot (GtkWidget *widget,
+ GtkSnapshot *snapshot)
+{
+ GtkPasswordEntry *entry = GTK_PASSWORD_ENTRY (widget);
+ GtkPasswordEntryPrivate *priv = gtk_password_entry_get_instance_private (entry);
+
+ if (priv->strength_widget)
+ gtk_widget_snapshot_child (widget, priv->strength_widget, snapshot);
+
+ gtk_widget_snapshot_child (widget, priv->box, snapshot);
+}
+
+static void
gtk_password_entry_class_init (GtkPasswordEntryClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
@@ -349,6 +412,7 @@ gtk_password_entry_class_init (GtkPasswordEntryClass *klass)
widget_class->realize = gtk_password_entry_realize;
widget_class->measure = gtk_password_entry_measure;
widget_class->size_allocate = gtk_password_entry_size_allocate;
+ widget_class->snapshot = gtk_password_entry_snapshot;
widget_class->get_accessible = gtk_password_entry_get_accessible;
widget_class->grab_focus = gtk_password_entry_grab_focus;
widget_class->mnemonic_activate = gtk_password_entry_mnemonic_activate;
@@ -374,9 +438,25 @@ gtk_password_entry_class_init (GtkPasswordEntryClass *klass)
FALSE,
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+ props[PROP_SHOW_STRENGTH] =
+ g_param_spec_boolean ("show-strength",
+ P_("Show Strength"),
+ P_("Whether to show an indicator for password quality"),
+ FALSE,
+ GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+
g_object_class_install_properties (object_class, NUM_PROPERTIES, props);
gtk_editable_install_properties (object_class, NUM_PROPERTIES);
+ signals[GET_STRENGTH] =
+ g_signal_new (I_("get-strength"),
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ g_signal_accumulator_first_wins, NULL,
+ NULL,
+ G_TYPE_INT, 0);
+
gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_ENTRY_ACCESSIBLE);
gtk_widget_class_set_css_name (widget_class, I_("entry"));
}
@@ -470,3 +550,57 @@ gtk_password_entry_get_show_peek_icon (GtkPasswordEntry *entry)
return priv->peek_icon != NULL;
}
+
+static void
+update_strength (GObject *object,
+ GParamSpec *pspec,
+ GtkPasswordEntry *entry)
+{
+ GtkPasswordEntryPrivate *priv = gtk_password_entry_get_instance_private (entry);
+
+ int strength = 0;
+
+ g_signal_emit (entry, signals[GET_STRENGTH], 0, &strength);
+
+ gtk_level_bar_set_value (GTK_LEVEL_BAR (priv->strength_widget), strength);
+}
+
+void
+gtk_password_entry_set_show_strength (GtkPasswordEntry *entry,
+ gboolean show_strength)
+{
+ GtkPasswordEntryPrivate *priv = gtk_password_entry_get_instance_private (entry);
+
+ g_return_if_fail (GTK_IS_PASSWORD_ENTRY (entry));
+
+ if (show_strength == (priv->strength_widget != NULL))
+ return;
+
+ if (show_strength)
+ {
+ priv->strength_widget = gtk_level_bar_new_for_interval (0.0, 100.0);
+ gtk_level_bar_set_mode (GTK_LEVEL_BAR (priv->strength_widget), GTK_LEVEL_BAR_MODE_CONTINUOUS);
+ gtk_level_bar_add_offset_value (GTK_LEVEL_BAR (priv->strength_widget), GTK_LEVEL_BAR_OFFSET_LOW, 25);
+ gtk_level_bar_add_offset_value (GTK_LEVEL_BAR (priv->strength_widget), GTK_LEVEL_BAR_OFFSET_HIGH, 50);
+ gtk_level_bar_add_offset_value (GTK_LEVEL_BAR (priv->strength_widget), GTK_LEVEL_BAR_OFFSET_FULL, 100);
+ gtk_widget_set_parent (priv->strength_widget, GTK_WIDGET (entry));
+ g_signal_connect (priv->entry, "notify::text", G_CALLBACK (update_strength), entry);
+ }
+ else
+ {
+ g_signal_handlers_disconnect_by_func (priv->entry, update_strength, entry);
+ g_clear_pointer (&priv->strength_widget, gtk_widget_unparent);
+ }
+
+ g_object_notify_by_pspec (G_OBJECT (entry), props[PROP_SHOW_STRENGTH]);
+}
+
+gboolean
+gtk_password_entry_get_show_strength (GtkPasswordEntry *entry)
+{
+ GtkPasswordEntryPrivate *priv = gtk_password_entry_get_instance_private (entry);
+
+ g_return_val_if_fail (GTK_IS_PASSWORD_ENTRY (entry), FALSE);
+
+ return priv->strength_widget != NULL;
+}
diff --git a/gtk/gtkpasswordentry.h b/gtk/gtkpasswordentry.h
index 2527c58ca2..fe583437bd 100644
--- a/gtk/gtkpasswordentry.h
+++ b/gtk/gtkpasswordentry.h
@@ -61,6 +61,12 @@ void gtk_password_entry_set_show_peek_icon (GtkPasswordEntry *entry,
GDK_AVAILABLE_IN_ALL
gboolean gtk_password_entry_get_show_peek_icon (GtkPasswordEntry *entry);
+GDK_AVAILABLE_IN_ALL
+void gtk_password_entry_set_show_strength (GtkPasswordEntry *entry,
+ gboolean show_strength);
+GDK_AVAILABLE_IN_ALL
+gboolean gtk_password_entry_get_show_strength (GtkPasswordEntry *entry);
+
G_END_DECLS
#endif /* __GTK_PASSWORD_ENTRY_H__ */