diff --git a/data/gnome-shell-theme.gresource.xml b/data/gnome-shell-theme.gresource.xml index 21191f0ce..cc9caef0a 100644 --- a/data/gnome-shell-theme.gresource.xml +++ b/data/gnome-shell-theme.gresource.xml @@ -20,6 +20,8 @@ no-notifications.svg noise-texture.png pad-osd.css + eye-open-negative-filled-symbolic.svg + eye-not-looking-symbolic.svg pointer-double-click-symbolic.svg pointer-drag-symbolic.svg pointer-primary-click-symbolic.svg diff --git a/data/theme/eye-not-looking-symbolic.svg b/data/theme/eye-not-looking-symbolic.svg new file mode 100644 index 000000000..a168c87d8 --- /dev/null +++ b/data/theme/eye-not-looking-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/data/theme/eye-open-negative-filled-symbolic.svg b/data/theme/eye-open-negative-filled-symbolic.svg new file mode 100644 index 000000000..1e5351c99 --- /dev/null +++ b/data/theme/eye-open-negative-filled-symbolic.svg @@ -0,0 +1,27 @@ + + + + + + image/svg+xml + + Gnome Symbolic Icon Theme + + + + Gnome Symbolic Icon Theme + + + + + + + + + + + + + + + diff --git a/data/theme/gnome-shell-sass/_common.scss b/data/theme/gnome-shell-sass/_common.scss index 8d203ada7..d4148306f 100644 --- a/data/theme/gnome-shell-sass/_common.scss +++ b/data/theme/gnome-shell-sass/_common.scss @@ -97,6 +97,11 @@ StEntry { warning-color: $warning_color; padding: 0 4px; } + + StIcon.peek-password { + icon-size: 1.09em; + padding: 0 4px; + } } diff --git a/src/st/st-password-entry.c b/src/st/st-password-entry.c index be8c92612..79793d28b 100644 --- a/src/st/st-password-entry.c +++ b/src/st/st-password-entry.c @@ -19,6 +19,7 @@ #include "st-private.h" #include "st-password-entry.h" +#include "st-icon.h" #define BLACK_CIRCLE 9679 @@ -34,7 +35,9 @@ struct _StPasswordEntry struct _StPasswordEntryPrivate { + ClutterActor *peek_password_icon; gboolean password_visible; + gboolean show_peek_icon; }; enum @@ -42,6 +45,7 @@ enum PROP_0, PROP_PASSWORD_VISIBLE, + PROP_SHOW_PEEK_ICON, N_PROPS }; @@ -50,6 +54,15 @@ static GParamSpec *props[N_PROPS] = { NULL, }; G_DEFINE_TYPE_WITH_PRIVATE (StPasswordEntry, st_password_entry, ST_TYPE_ENTRY); +static void +st_password_entry_secondary_icon_clicked (StEntry *entry) +{ + StPasswordEntry *password_entry = ST_PASSWORD_ENTRY (entry); + StPasswordEntryPrivate *priv = ST_PASSWORD_ENTRY_PRIV (password_entry); + + st_password_entry_set_password_visible (password_entry, !priv->password_visible); +} + static void st_password_entry_get_property (GObject *gobject, guint prop_id, @@ -63,7 +76,9 @@ st_password_entry_get_property (GObject *gobject, case PROP_PASSWORD_VISIBLE: g_value_set_boolean (value, priv->password_visible); break; - + case PROP_SHOW_PEEK_ICON: + g_value_set_boolean (value, priv->show_peek_icon); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; @@ -83,7 +98,9 @@ st_password_entry_set_property (GObject *gobject, case PROP_PASSWORD_VISIBLE: st_password_entry_set_password_visible (entry, g_value_get_boolean (value)); break; - + case PROP_SHOW_PEEK_ICON: + st_password_entry_set_show_peek_icon (entry, g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; @@ -94,16 +111,25 @@ static void st_password_entry_class_init (StPasswordEntryClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + StEntryClass *st_entry_class = ST_ENTRY_CLASS (klass); gobject_class->get_property = st_password_entry_get_property; gobject_class->set_property = st_password_entry_set_property; + st_entry_class->secondary_icon_clicked = st_password_entry_secondary_icon_clicked; + props[PROP_PASSWORD_VISIBLE] = g_param_spec_boolean ("password-visible", "Password visible", "Whether to text in the entry is masked or not", FALSE, ST_PARAM_READWRITE); + props[PROP_SHOW_PEEK_ICON] = g_param_spec_boolean ("show-peek-icon", + "Show peek icon", + "Whether to show the password peek icon", + TRUE, + ST_PARAM_READWRITE); + g_object_class_install_properties (gobject_class, N_PROPS, props); } @@ -125,10 +151,17 @@ clutter_text_password_char_cb (GObject *object, static void st_password_entry_init (StPasswordEntry *entry) { + StPasswordEntryPrivate *priv = ST_PASSWORD_ENTRY_PRIV (entry); ClutterActor *clutter_text; st_entry_set_text (ST_ENTRY (entry), ""); + priv->peek_password_icon = g_object_new (ST_TYPE_ICON, + "style-class", "peek-password", + "icon-name", "eye-not-looking-symbolic", + NULL); + st_entry_set_secondary_icon (ST_ENTRY (entry), priv->peek_password_icon); + clutter_text = st_entry_get_clutter_text (ST_ENTRY (entry)); clutter_text_set_password_char (CLUTTER_TEXT (clutter_text), BLACK_CIRCLE); @@ -151,6 +184,50 @@ st_password_entry_new (void) return ST_ENTRY (g_object_new (ST_TYPE_PASSWORD_ENTRY, NULL)); } +/** + * st_password_entry_set_show_peek_icon: + * @entry: a #StPasswordEntry + * @value: #TRUE to show the peek-icon in the entry, #FALSE otherwise + * + * Sets whether to show or hide the peek-icon in the password entry. + */ +void +st_password_entry_set_show_peek_icon (StPasswordEntry *entry, gboolean value) +{ + StPasswordEntryPrivate *priv; + + g_return_if_fail (ST_IS_PASSWORD_ENTRY (entry)); + + priv = ST_PASSWORD_ENTRY_PRIV (entry); + if (priv->show_peek_icon == value) + return; + + priv->show_peek_icon = value; + if (priv->show_peek_icon) + st_entry_set_secondary_icon (ST_ENTRY (entry), priv->peek_password_icon); + else + st_entry_set_secondary_icon (ST_ENTRY (entry), NULL); + + g_object_notify_by_pspec (G_OBJECT (entry), props[PROP_SHOW_PEEK_ICON]); +} + +/** + * st_password_entry_get_show_peek_icon: + * @entry: a #StPasswordEntry + * + * Gets whether peek-icon is shown or hidden in the password entry. + */ +gboolean +st_password_entry_get_show_peek_icon (StPasswordEntry *entry) +{ + StPasswordEntryPrivate *priv; + + g_return_val_if_fail (ST_IS_PASSWORD_ENTRY (entry), TRUE); + + priv = ST_PASSWORD_ENTRY_PRIV (entry); + return priv->show_peek_icon; +} + /** * st_password_entry_set_password_visible: * @entry: a #StPasswordEntry @@ -174,9 +251,15 @@ st_password_entry_set_password_visible (StPasswordEntry *entry, gboolean value) clutter_text = st_entry_get_clutter_text (ST_ENTRY (entry)); if (priv->password_visible) - clutter_text_set_password_char (CLUTTER_TEXT (clutter_text), 0); + { + clutter_text_set_password_char (CLUTTER_TEXT (clutter_text), 0); + st_icon_set_icon_name (ST_ICON (priv->peek_password_icon), "eye-open-negative-filled-symbolic"); + } else - clutter_text_set_password_char (CLUTTER_TEXT (clutter_text), BLACK_CIRCLE); + { + clutter_text_set_password_char (CLUTTER_TEXT (clutter_text), BLACK_CIRCLE); + st_icon_set_icon_name (ST_ICON (priv->peek_password_icon), "eye-not-looking-symbolic"); + } g_object_notify_by_pspec (G_OBJECT (entry), props[PROP_PASSWORD_VISIBLE]); } diff --git a/src/st/st-password-entry.h b/src/st/st-password-entry.h index 44dd0b193..399806808 100644 --- a/src/st/st-password-entry.h +++ b/src/st/st-password-entry.h @@ -36,6 +36,9 @@ StEntry *st_password_entry_new (void); gboolean st_password_entry_get_password_visible (StPasswordEntry *entry); void st_password_entry_set_password_visible (StPasswordEntry *entry, gboolean value); +gboolean st_password_entry_get_show_peek_icon (StPasswordEntry *entry); +void st_password_entry_set_show_peek_icon (StPasswordEntry *entry, + gboolean value); G_END_DECLS