forked from AuroraMiddleware/gtk
password entry: Add a way to see the content
Add a ::show-peek-icon property and show a clickable icon when it is set. Clicking it toggles the visibility of the content. The same functionality is also accessible via a context menu item. This is a common feature of password entries.
This commit is contained in:
parent
d3cecd65a5
commit
a3b73a416e
@ -995,6 +995,8 @@ gtk_entry_get_type
|
||||
<TITLE>GtkPasswordEntry</TITLE>
|
||||
GtkPasswordEntry
|
||||
gtk_password_entry_new
|
||||
gtk_password_entry_set_show_peek_icon
|
||||
gtk_password_entry_get_show_peek_icon
|
||||
<SUBSECTION Private>
|
||||
gtk_password_entry_get_type
|
||||
</SECTION>
|
||||
|
@ -26,8 +26,10 @@
|
||||
#include "gtkbindings.h"
|
||||
#include "gtktextprivate.h"
|
||||
#include "gtkeditable.h"
|
||||
#include "gtkgesturemultipress.h"
|
||||
#include "gtkbox.h"
|
||||
#include "gtkimage.h"
|
||||
#include "gtkcheckmenuitem.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkmarshalers.h"
|
||||
@ -41,13 +43,14 @@
|
||||
* @Short_description: An entry for secrets
|
||||
* @Title: GtkPasswordEntry
|
||||
*
|
||||
* #GtkPasswordEntry is entry that has been tailored for
|
||||
* entering secrets. It does not show its contents in clear text,
|
||||
* does not allow to copy it to the clipboard, and it shows a
|
||||
* warning when Caps-Lock is engaged.
|
||||
* #GtkPasswordEntry is entry that has been tailored for entering secrets.
|
||||
* It does not show its contents in clear text, does not allow to copy it
|
||||
* to the clipboard, and it shows a warning when Caps Lock is engaged.
|
||||
*
|
||||
* GtkPasswordEntry provides no API of its own and should be used
|
||||
* with the #GtkEditable API.
|
||||
* Optionally, it can offer a way to reveal the contents in clear text.
|
||||
*
|
||||
* GtkPasswordEntry provides only minimal API and should be used with the
|
||||
* #GtkEditable API.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
@ -55,11 +58,13 @@ typedef struct {
|
||||
GtkWidget *entry;
|
||||
GtkWidget *icon;
|
||||
GdkKeymap *keymap;
|
||||
GtkWidget *peek_icon;
|
||||
} GtkPasswordEntryPrivate;
|
||||
|
||||
enum {
|
||||
PROP_PLACEHOLDER_TEXT = 1,
|
||||
PROP_ACTIVATES_DEFAULT,
|
||||
PROP_SHOW_PEEK_ICON,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
@ -96,6 +101,46 @@ focus_changed (GtkWidget *widget)
|
||||
keymap_state_changed (priv->keymap, widget);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_password_entry_toggle_peek (GtkPasswordEntry *entry)
|
||||
{
|
||||
GtkPasswordEntryPrivate *priv = gtk_password_entry_get_instance_private (entry);
|
||||
|
||||
if (gtk_text_get_visibility (GTK_TEXT (priv->entry)))
|
||||
{
|
||||
gtk_text_set_visibility (GTK_TEXT (priv->entry), FALSE);
|
||||
gtk_image_set_from_icon_name (GTK_IMAGE (priv->peek_icon), "eye-not-looking-symbolic");
|
||||
gtk_widget_set_tooltip_text (priv->peek_icon, _("Show text"));
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_text_set_visibility (GTK_TEXT (priv->entry), TRUE);
|
||||
gtk_image_set_from_icon_name (GTK_IMAGE (priv->peek_icon), "eye-open-negative-filled-symbolic");
|
||||
gtk_widget_set_tooltip_text (priv->peek_icon, _("Hide text"));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
populate_popup (GtkText *text,
|
||||
GtkWidget *popup,
|
||||
GtkPasswordEntry *entry)
|
||||
{
|
||||
GtkPasswordEntryPrivate *priv = gtk_password_entry_get_instance_private (entry);
|
||||
|
||||
if (priv->peek_icon != NULL)
|
||||
{
|
||||
GtkWidget *item;
|
||||
|
||||
item = gtk_check_menu_item_new_with_mnemonic (_("_Show text"));
|
||||
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
|
||||
gtk_text_get_visibility (text));
|
||||
g_signal_connect_swapped (item, "activate",
|
||||
G_CALLBACK (gtk_password_entry_toggle_peek), entry);
|
||||
gtk_widget_show (item);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (popup), item);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_password_entry_init (GtkPasswordEntry *entry)
|
||||
{
|
||||
@ -103,7 +148,7 @@ gtk_password_entry_init (GtkPasswordEntry *entry)
|
||||
|
||||
gtk_widget_set_has_surface (GTK_WIDGET (entry), FALSE);
|
||||
|
||||
priv->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
priv->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
|
||||
gtk_widget_set_hexpand (priv->box, FALSE);
|
||||
gtk_widget_set_vexpand (priv->box, FALSE);
|
||||
gtk_widget_set_parent (priv->box, GTK_WIDGET (entry));
|
||||
@ -115,6 +160,7 @@ gtk_password_entry_init (GtkPasswordEntry *entry)
|
||||
gtk_container_add (GTK_CONTAINER (priv->box), priv->entry);
|
||||
gtk_editable_init_delegate (GTK_EDITABLE (entry));
|
||||
g_signal_connect_swapped (priv->entry, "notify::has-focus", G_CALLBACK (focus_changed), entry);
|
||||
g_signal_connect (priv->entry, "populate-popup", G_CALLBACK (populate_popup), entry);
|
||||
|
||||
priv->icon = gtk_image_new_from_icon_name ("caps-lock-symbolic");
|
||||
gtk_widget_set_tooltip_text (priv->icon, _("Caps Lock is on"));
|
||||
@ -152,6 +198,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->box, gtk_widget_unparent);
|
||||
|
||||
G_OBJECT_CLASS (gtk_password_entry_parent_class)->dispose (object);
|
||||
@ -183,6 +230,9 @@ gtk_password_entry_set_property (GObject *object,
|
||||
|
||||
case PROP_ACTIVATES_DEFAULT:
|
||||
gtk_text_set_activates_default (GTK_TEXT (priv->entry), g_value_get_boolean (value));
|
||||
|
||||
case PROP_SHOW_PEEK_ICON:
|
||||
gtk_password_entry_set_show_peek_icon (entry, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -211,6 +261,9 @@ gtk_password_entry_get_property (GObject *object,
|
||||
|
||||
case PROP_ACTIVATES_DEFAULT:
|
||||
g_value_set_boolean (value, gtk_text_get_activates_default (GTK_TEXT (priv->entry)));
|
||||
|
||||
case PROP_SHOW_PEEK_ICON:
|
||||
g_value_set_boolean (value, gtk_password_entry_get_show_peek_icon (entry));
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -314,6 +367,13 @@ gtk_password_entry_class_init (GtkPasswordEntryClass *klass)
|
||||
FALSE,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
props[PROP_SHOW_PEEK_ICON] =
|
||||
g_param_spec_boolean ("show-peek-icon",
|
||||
P_("Show Peek Icon"),
|
||||
P_("Whether to show an icon for revealing the content"),
|
||||
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);
|
||||
|
||||
@ -348,3 +408,65 @@ gtk_password_entry_new (void)
|
||||
{
|
||||
return GTK_WIDGET (g_object_new (GTK_TYPE_PASSWORD_ENTRY, NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_password_entry_set_show_peek_icon:
|
||||
* @entry: a #GtkPasswordEntry
|
||||
* show_peek_icon: whether to show the peek icon
|
||||
*
|
||||
* Sets whether the entry should have a clickable icon
|
||||
* to show the contents of the entry in clear text.
|
||||
*
|
||||
* Setting this to %FALSE also hides the text again.
|
||||
*/
|
||||
void
|
||||
gtk_password_entry_set_show_peek_icon (GtkPasswordEntry *entry,
|
||||
gboolean show_peek_icon)
|
||||
{
|
||||
GtkPasswordEntryPrivate *priv = gtk_password_entry_get_instance_private (entry);
|
||||
|
||||
g_return_if_fail (GTK_IS_PASSWORD_ENTRY (entry));
|
||||
|
||||
if (show_peek_icon == (priv->peek_icon != NULL))
|
||||
return;
|
||||
|
||||
if (show_peek_icon)
|
||||
{
|
||||
GtkGesture *press;
|
||||
|
||||
priv->peek_icon = gtk_image_new_from_icon_name ("eye-not-looking-symbolic");
|
||||
gtk_widget_set_tooltip_text (priv->peek_icon, _("Show text"));
|
||||
gtk_container_add (GTK_CONTAINER (priv->box), priv->peek_icon);
|
||||
|
||||
press = gtk_gesture_multi_press_new ();
|
||||
g_signal_connect_swapped (press, "released",
|
||||
G_CALLBACK (gtk_password_entry_toggle_peek), entry);
|
||||
gtk_widget_add_controller (priv->peek_icon, GTK_EVENT_CONTROLLER (press));
|
||||
}
|
||||
else
|
||||
{
|
||||
g_clear_pointer (&priv->peek_icon, gtk_widget_unparent);
|
||||
gtk_text_set_visibility (GTK_TEXT (priv->entry), FALSE);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (entry), props[PROP_SHOW_PEEK_ICON]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_password_entry_get_show_peek_icon:
|
||||
* @entry: a #GtkPasswordEntry
|
||||
*
|
||||
* Returns whether the entry is showing a clickable icon
|
||||
* to reveal the contents of the entry in clear text.
|
||||
*
|
||||
* Returns: %TRUE if an icon is shown
|
||||
*/
|
||||
gboolean
|
||||
gtk_password_entry_get_show_peek_icon (GtkPasswordEntry *entry)
|
||||
{
|
||||
GtkPasswordEntryPrivate *priv = gtk_password_entry_get_instance_private (entry);
|
||||
|
||||
g_return_val_if_fail (GTK_IS_PASSWORD_ENTRY (entry), FALSE);
|
||||
|
||||
return priv->peek_icon != NULL;
|
||||
}
|
||||
|
@ -55,6 +55,12 @@ GType gtk_password_entry_get_type (void) G_GNUC_CONST;
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkWidget * gtk_password_entry_new (void);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_password_entry_set_show_peek_icon (GtkPasswordEntry *entry,
|
||||
gboolean show_peek_icon);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_password_entry_get_show_peek_icon (GtkPasswordEntry *entry);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_PASSWORD_ENTRY_H__ */
|
||||
|
BIN
gtk/icons/16x16/status/eye-not-looking-symbolic.symbolic.png
Normal file
BIN
gtk/icons/16x16/status/eye-not-looking-symbolic.symbolic.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 324 B |
Binary file not shown.
After Width: | Height: | Size: 295 B |
3
gtk/icons/scalable/status/eye-not-looking-symbolic.svg
Normal file
3
gtk/icons/scalable/status/eye-not-looking-symbolic.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
|
||||
<path d="M13.98 1.99a1 1 0 0 0-.687.303l-.984.984A8 8 0 0 0 8 2 8 8 0 0 0 .262 8.01a8 8 0 0 0 2.943 4.37l-.912.913a1 1 0 1 0 1.414 1.414l11-11a1 1 0 0 0-.727-1.717zM8 4a4 4 0 0 1 2.611.974l-1.42 1.42A2 2 0 0 0 8 6a2 2 0 0 0-2 2 2 2 0 0 0 .396 1.19l-1.42 1.42A4 4 0 0 1 4 8a4 4 0 0 1 4-4zm7.03 2.209l-3.344 3.343a4 4 0 0 1-2.127 2.127l-2.28 2.28a8 8 0 0 0 .721.04 8 8 0 0 0 7.738-6.01 8 8 0 0 0-.709-1.78zm-7.53.79a.5.5 0 0 1 .5.5.5.5 0 0 1-.5.5.5.5 0 0 1-.5-.5.5.5 0 0 1 .5-.5z" fill="#2e3436"/>
|
||||
</svg>
|
After Width: | Height: | Size: 570 B |
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" width="16" viewBox="0 0 16 16" version="1.1" id="svg7384" height="16">
|
||||
<metadata id="metadata90">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<dc:title>Gnome Symbolic Icon Theme</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<title id="title9167">Gnome Symbolic Icon Theme</title>
|
||||
<defs id="defs7386">
|
||||
<linearGradient osb:paint="solid" id="linearGradient7212">
|
||||
<stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop7214"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g transform="translate(-341.0002,-13.000323)" style="display:inline" id="layer9"/>
|
||||
<g transform="translate(-100,-380.00032)" id="layer1"/>
|
||||
<g transform="translate(-100,-380.00032)" style="display:inline" id="layer10">
|
||||
<path d="m 108,382 a 8,8 0 0 0 -7.73828,6.00977 A 8,8 0 0 0 108,394 8,8 0 0 0 115.73828,387.99023 8,8 0 0 0 108,382 Z m 0,2 a 4,4 0 0 1 4,4 4,4 0 0 1 -4,4 4,4 0 0 1 -4,-4 4,4 0 0 1 4,-4 z" id="path2314" style="opacity:1;vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"/>
|
||||
<path id="path2318" d="m 110,388.00003 a 2,2 0 0 1 -2,2 2,2 0 0 1 -2,-2 2,2 0 0 1 2,-2 2,2 0 0 1 2,2 z" style="vector-effect:none;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"/>
|
||||
</g>
|
||||
<g transform="translate(-100,-380.00032)" id="g6387"/>
|
||||
<g transform="translate(-100,-380.00032)" id="layer11"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
@ -242,6 +242,7 @@ main (int argc, char **argv)
|
||||
gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
|
||||
|
||||
entry = gtk_password_entry_new ();
|
||||
gtk_password_entry_set_show_peek_icon (GTK_PASSWORD_ENTRY (entry), TRUE);
|
||||
gtk_widget_set_hexpand (entry, TRUE);
|
||||
gtk_grid_attach (GTK_GRID (grid), entry, 1, 3, 1, 1);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user