Compare commits
8 Commits
citadel
...
uajain/st-
Author | SHA1 | Date | |
---|---|---|---|
|
e55dd716e2 | ||
|
35171aed37 | ||
|
b4f1fc2305 | ||
|
10da0e9d8f | ||
|
5adbfdb590 | ||
|
b0b8ab6c73 | ||
|
97b81a2319 | ||
|
f61a1f3180 |
@ -20,6 +20,8 @@
|
|||||||
<file>no-notifications.svg</file>
|
<file>no-notifications.svg</file>
|
||||||
<file>noise-texture.png</file>
|
<file>noise-texture.png</file>
|
||||||
<file>pad-osd.css</file>
|
<file>pad-osd.css</file>
|
||||||
|
<file alias="icons/eye-open-negative-filled-symbolic.svg">eye-open-negative-filled-symbolic.svg</file>
|
||||||
|
<file alias="icons/eye-not-looking-symbolic.svg">eye-not-looking-symbolic.svg</file>
|
||||||
<file alias="icons/pointer-double-click-symbolic.svg">pointer-double-click-symbolic.svg</file>
|
<file alias="icons/pointer-double-click-symbolic.svg">pointer-double-click-symbolic.svg</file>
|
||||||
<file alias="icons/pointer-drag-symbolic.svg">pointer-drag-symbolic.svg</file>
|
<file alias="icons/pointer-drag-symbolic.svg">pointer-drag-symbolic.svg</file>
|
||||||
<file alias="icons/pointer-primary-click-symbolic.svg">pointer-primary-click-symbolic.svg</file>
|
<file alias="icons/pointer-primary-click-symbolic.svg">pointer-primary-click-symbolic.svg</file>
|
||||||
|
4
data/theme/eye-not-looking-symbolic.svg
Normal file
4
data/theme/eye-not-looking-symbolic.svg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<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: 572 B |
27
data/theme/eye-open-negative-filled-symbolic.svg
Normal file
27
data/theme/eye-open-negative-filled-symbolic.svg
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?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 |
@ -97,6 +97,11 @@ StEntry {
|
|||||||
warning-color: $warning_color;
|
warning-color: $warning_color;
|
||||||
padding: 0 4px;
|
padding: 0 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StIcon.peek-password {
|
||||||
|
icon-size: 1.09em;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -404,6 +409,11 @@ StScrollBar {
|
|||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.prompt-dialog-caps-lock-warning {
|
||||||
|
@extend .prompt-dialog-error-label;
|
||||||
|
padding-left: 6.2em;
|
||||||
|
}
|
||||||
|
|
||||||
.prompt-dialog-info-label {
|
.prompt-dialog-info-label {
|
||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
|
@ -98,18 +98,31 @@ var AuthPrompt = GObject.registerClass({
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.add_child(this._label);
|
this.add_child(this._label);
|
||||||
this._entry = new St.Entry({
|
this._entry = null;
|
||||||
|
|
||||||
|
this._textEntry = new St.Entry({
|
||||||
|
style_class: 'login-dialog-prompt-entry',
|
||||||
|
can_focus: true,
|
||||||
|
x_expand: false,
|
||||||
|
y_expand: true,
|
||||||
|
});
|
||||||
|
ShellEntry.addContextMenu(this._textEntry, { actionMode: Shell.ActionMode.NONE });
|
||||||
|
this._passwordEntry = new St.PasswordEntry({
|
||||||
style_class: 'login-dialog-prompt-entry',
|
style_class: 'login-dialog-prompt-entry',
|
||||||
can_focus: true,
|
can_focus: true,
|
||||||
x_expand: false,
|
x_expand: false,
|
||||||
y_expand: true,
|
y_expand: true,
|
||||||
});
|
});
|
||||||
ShellEntry.addContextMenu(this._entry, { isPassword: true, actionMode: Shell.ActionMode.NONE });
|
|
||||||
|
|
||||||
|
ShellEntry.addContextMenu(this._passwordEntry, { actionMode: Shell.ActionMode.NONE });
|
||||||
|
this._entry = this._passwordEntry;
|
||||||
this.add_child(this._entry);
|
this.add_child(this._entry);
|
||||||
|
|
||||||
this._entry.grab_key_focus();
|
this._entry.grab_key_focus();
|
||||||
|
|
||||||
|
this._capsLockWarningLabel = new ShellEntry.CapsLockWarning(this._entry);
|
||||||
|
this.add_child(this._capsLockWarningLabel);
|
||||||
|
|
||||||
this._message = new St.Label({
|
this._message = new St.Label({
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
styleClass: 'login-dialog-message',
|
styleClass: 'login-dialog-message',
|
||||||
@ -195,7 +208,19 @@ var AuthPrompt = GObject.registerClass({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_onAskQuestion(verifier, serviceName, question, passwordChar) {
|
_updateEntry(secret) {
|
||||||
|
if (secret && (this._entry != this._passwordEntry)) {
|
||||||
|
this.replace_child(this._entry, this._passwordEntry);
|
||||||
|
this._entry = this._passwordEntry;
|
||||||
|
this.insert_child_below(this._capsLockWarningLabel, this._entry);
|
||||||
|
} else if (!secret && (this._entry != this._textEntry)) {
|
||||||
|
this.replace_child(this._entry, this._textEntry);
|
||||||
|
this._entry = this._textEntry;
|
||||||
|
this.remove_child(this._capsLockWarningLabel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onAskQuestion(verifier, serviceName, question, secret) {
|
||||||
if (this._queryingService)
|
if (this._queryingService)
|
||||||
this.clear();
|
this.clear();
|
||||||
|
|
||||||
@ -205,10 +230,11 @@ var AuthPrompt = GObject.registerClass({
|
|||||||
this._preemptiveAnswer = null;
|
this._preemptiveAnswer = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.setPasswordChar(passwordChar);
|
|
||||||
|
this._updateEntry(secret);
|
||||||
this.setQuestion(question);
|
this.setQuestion(question);
|
||||||
|
|
||||||
if (passwordChar) {
|
if (secret) {
|
||||||
if (this._userVerifier.reauthenticating)
|
if (this._userVerifier.reauthenticating)
|
||||||
this.nextButton.label = _("Unlock");
|
this.nextButton.label = _("Unlock");
|
||||||
else
|
else
|
||||||
@ -358,11 +384,6 @@ var AuthPrompt = GObject.registerClass({
|
|||||||
this.stopSpinning();
|
this.stopSpinning();
|
||||||
}
|
}
|
||||||
|
|
||||||
setPasswordChar(passwordChar) {
|
|
||||||
this._entry.clutter_text.set_password_char(passwordChar);
|
|
||||||
this._entry.menu.isPassword = passwordChar != '';
|
|
||||||
}
|
|
||||||
|
|
||||||
setQuestion(question) {
|
setQuestion(question) {
|
||||||
this._label.set_text(question);
|
this._label.set_text(question);
|
||||||
|
|
||||||
|
@ -485,7 +485,7 @@ var ShellUserVerifier = class {
|
|||||||
if (!this.serviceIsForeground(serviceName))
|
if (!this.serviceIsForeground(serviceName))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.emit('ask-question', serviceName, question, '');
|
this.emit('ask-question', serviceName, question, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onSecretInfoQuery(client, serviceName, secretQuestion) {
|
_onSecretInfoQuery(client, serviceName, secretQuestion) {
|
||||||
@ -498,7 +498,7 @@ var ShellUserVerifier = class {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit('ask-question', serviceName, secretQuestion, '\u25cf');
|
this.emit('ask-question', serviceName, secretQuestion, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onReset() {
|
_onReset() {
|
||||||
|
@ -70,12 +70,13 @@ class KeyringDialog extends ModalDialog.ModalDialog {
|
|||||||
y_align: Clutter.ActorAlign.CENTER });
|
y_align: Clutter.ActorAlign.CENTER });
|
||||||
label.set_text(_("Password:"));
|
label.set_text(_("Password:"));
|
||||||
label.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
label.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
this._passwordEntry = new St.PasswordEntry({
|
||||||
text: '',
|
style_class: 'prompt-dialog-password-entry',
|
||||||
can_focus: true,
|
text: '',
|
||||||
x_expand: true });
|
can_focus: true,
|
||||||
this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
x_expand: true,
|
||||||
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
|
});
|
||||||
|
ShellEntry.addContextMenu(this._passwordEntry);
|
||||||
this._passwordEntry.clutter_text.connect('activate', this._onPasswordActivate.bind(this));
|
this._passwordEntry.clutter_text.connect('activate', this._onPasswordActivate.bind(this));
|
||||||
|
|
||||||
this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, {
|
this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, {
|
||||||
@ -102,12 +103,13 @@ class KeyringDialog extends ModalDialog.ModalDialog {
|
|||||||
x_align: Clutter.ActorAlign.START,
|
x_align: Clutter.ActorAlign.START,
|
||||||
y_align: Clutter.ActorAlign.CENTER });
|
y_align: Clutter.ActorAlign.CENTER });
|
||||||
label.set_text(_("Type again:"));
|
label.set_text(_("Type again:"));
|
||||||
this._confirmEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
this._confirmEntry = new St.PasswordEntry({
|
||||||
text: '',
|
style_class: 'prompt-dialog-password-entry',
|
||||||
can_focus: true,
|
text: '',
|
||||||
x_expand: true });
|
can_focus: true,
|
||||||
this._confirmEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
x_expand: true,
|
||||||
ShellEntry.addContextMenu(this._confirmEntry, { isPassword: true });
|
});
|
||||||
|
ShellEntry.addContextMenu(this._confirmEntry);
|
||||||
this._confirmEntry.clutter_text.connect('activate', this._onConfirmActivate.bind(this));
|
this._confirmEntry.clutter_text.connect('activate', this._onConfirmActivate.bind(this));
|
||||||
if (rtl) {
|
if (rtl) {
|
||||||
layout.attach(this._confirmEntry, 0, row, 1, 1);
|
layout.attach(this._confirmEntry, 0, row, 1, 1);
|
||||||
@ -124,6 +126,13 @@ class KeyringDialog extends ModalDialog.ModalDialog {
|
|||||||
this.prompt.set_password_actor(this._passwordEntry ? this._passwordEntry.clutter_text : null);
|
this.prompt.set_password_actor(this._passwordEntry ? this._passwordEntry.clutter_text : null);
|
||||||
this.prompt.set_confirm_actor(this._confirmEntry ? this._confirmEntry.clutter_text : null);
|
this.prompt.set_confirm_actor(this._confirmEntry ? this._confirmEntry.clutter_text : null);
|
||||||
|
|
||||||
|
if (this._passwordEntry || this._confirmEntry) {
|
||||||
|
let entry = this._passwordEntry ? this._passwordEntry : this._confirmEntry;
|
||||||
|
this._capsLockWarningLabel = new ShellEntry.CapsLockWarning(entry);
|
||||||
|
layout.attach(this._capsLockWarningLabel, 1, row, 1, 1);
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.prompt.choice_visible) {
|
if (this.prompt.choice_visible) {
|
||||||
let choice = new CheckBox.CheckBox();
|
let choice = new CheckBox.CheckBox();
|
||||||
this.prompt.bind_property('choice-label', choice.getLabelActor(), 'text', GObject.BindingFlags.SYNC_CREATE);
|
this.prompt.bind_property('choice-label', choice.getLabelActor(), 'text', GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
@ -44,6 +44,7 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
|
|||||||
let rtl = secretTable.get_text_direction() == Clutter.TextDirection.RTL;
|
let rtl = secretTable.get_text_direction() == Clutter.TextDirection.RTL;
|
||||||
let initialFocusSet = false;
|
let initialFocusSet = false;
|
||||||
let pos = 0;
|
let pos = 0;
|
||||||
|
let lastPasswordEntry = 0;
|
||||||
for (let i = 0; i < this._content.secrets.length; i++) {
|
for (let i = 0; i < this._content.secrets.length; i++) {
|
||||||
let secret = this._content.secrets[i];
|
let secret = this._content.secrets[i];
|
||||||
let label = new St.Label({ style_class: 'prompt-dialog-password-label',
|
let label = new St.Label({ style_class: 'prompt-dialog-password-label',
|
||||||
@ -54,12 +55,20 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
|
|||||||
|
|
||||||
let reactive = secret.key != null;
|
let reactive = secret.key != null;
|
||||||
|
|
||||||
secret.entry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
let entryParams = {
|
||||||
text: secret.value, can_focus: reactive,
|
style_class: 'prompt-dialog-password-entry',
|
||||||
reactive,
|
text: secret.value,
|
||||||
x_expand: true });
|
can_focus: reactive,
|
||||||
ShellEntry.addContextMenu(secret.entry,
|
reactive,
|
||||||
{ isPassword: secret.password });
|
x_expand: true,
|
||||||
|
};
|
||||||
|
if (secret.password) {
|
||||||
|
secret.entry = new St.PasswordEntry(entryParams);
|
||||||
|
lastPasswordEntry = i;
|
||||||
|
} else {
|
||||||
|
secret.entry = new St.Entry(entryParams);
|
||||||
|
}
|
||||||
|
ShellEntry.addContextMenu(secret.entry);
|
||||||
|
|
||||||
if (secret.validate)
|
if (secret.validate)
|
||||||
secret.valid = secret.validate(secret);
|
secret.valid = secret.validate(secret);
|
||||||
@ -93,9 +102,14 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
|
|||||||
layout.attach(secret.entry, 1, pos, 1, 1);
|
layout.attach(secret.entry, 1, pos, 1, 1);
|
||||||
}
|
}
|
||||||
pos++;
|
pos++;
|
||||||
|
}
|
||||||
if (secret.password)
|
// Bind the caps-lock warning to the last password-entry and pack below it.
|
||||||
secret.entry.clutter_text.set_password_char('\u25cf');
|
if (this._content.secrets[lastPasswordEntry].password) {
|
||||||
|
this._capsLockWarningLabel = new ShellEntry.CapsLockWarning(this._content.secrets[lastPasswordEntry].entry);
|
||||||
|
if (rtl)
|
||||||
|
layout.attach(this._capsLockWarningLabel, 0, ++pos, 1, 1);
|
||||||
|
else
|
||||||
|
layout.attach(this._capsLockWarningLabel, 1, ++pos, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
contentBox.messageBox.add(secretTable);
|
contentBox.messageBox.add(secretTable);
|
||||||
|
@ -90,13 +90,13 @@ var AuthenticationDialog = GObject.registerClass({
|
|||||||
y_align: Clutter.ActorAlign.CENTER,
|
y_align: Clutter.ActorAlign.CENTER,
|
||||||
});
|
});
|
||||||
this._passwordBox.add_child(this._passwordLabel);
|
this._passwordBox.add_child(this._passwordLabel);
|
||||||
this._passwordEntry = new St.Entry({
|
this._passwordEntry = new St.PasswordEntry({
|
||||||
style_class: 'prompt-dialog-password-entry',
|
style_class: 'prompt-dialog-password-entry',
|
||||||
text: "",
|
text: "",
|
||||||
can_focus: true,
|
can_focus: true,
|
||||||
x_expand: true,
|
x_expand: true,
|
||||||
});
|
});
|
||||||
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
|
ShellEntry.addContextMenu(this._passwordEntry);
|
||||||
this._passwordEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this));
|
this._passwordEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this));
|
||||||
this._passwordEntry.bind_property('reactive',
|
this._passwordEntry.bind_property('reactive',
|
||||||
this._passwordEntry.clutter_text, 'editable',
|
this._passwordEntry.clutter_text, 'editable',
|
||||||
@ -109,6 +109,10 @@ var AuthenticationDialog = GObject.registerClass({
|
|||||||
this._passwordBox.add(this._workSpinner);
|
this._passwordBox.add(this._workSpinner);
|
||||||
|
|
||||||
this._passwordBox.hide();
|
this._passwordBox.hide();
|
||||||
|
this._capsLockWarningLabel = new ShellEntry.CapsLockWarning(this._passwordEntry, {
|
||||||
|
style_class: 'prompt-dialog-caps-lock-warning',
|
||||||
|
});
|
||||||
|
content.messageBox.add(this._capsLockWarningLabel);
|
||||||
|
|
||||||
this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label' });
|
this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label' });
|
||||||
this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
@ -278,10 +282,7 @@ var AuthenticationDialog = GObject.registerClass({
|
|||||||
else
|
else
|
||||||
this._passwordLabel.set_text(request);
|
this._passwordLabel.set_text(request);
|
||||||
|
|
||||||
if (echoOn)
|
this._passwordEntry.password_visible = echoOn;
|
||||||
this._passwordEntry.clutter_text.set_password_char('');
|
|
||||||
else
|
|
||||||
this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
|
||||||
|
|
||||||
this._passwordBox.show();
|
this._passwordBox.show();
|
||||||
this._passwordEntry.set_text('');
|
this._passwordEntry.set_text('');
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
/* exported addContextMenu */
|
/* exported addContextMenu CapsLockWarning */
|
||||||
|
|
||||||
const { Clutter, Shell, St } = imports.gi;
|
const { Clutter, GObject, Pango, Shell, St } = imports.gi;
|
||||||
|
|
||||||
const BoxPointer = imports.ui.boxpointer;
|
const BoxPointer = imports.ui.boxpointer;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
@ -27,7 +27,8 @@ var EntryMenu = class extends PopupMenu.PopupMenu {
|
|||||||
this.addMenuItem(item);
|
this.addMenuItem(item);
|
||||||
this._pasteItem = item;
|
this._pasteItem = item;
|
||||||
|
|
||||||
this._passwordItem = null;
|
if (entry instanceof St.PasswordEntry)
|
||||||
|
this._makePasswordItem();
|
||||||
|
|
||||||
Main.uiGroup.add_actor(this.actor);
|
Main.uiGroup.add_actor(this.actor);
|
||||||
this.actor.hide();
|
this.actor.hide();
|
||||||
@ -40,24 +41,6 @@ var EntryMenu = class extends PopupMenu.PopupMenu {
|
|||||||
this._passwordItem = item;
|
this._passwordItem = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isPassword() {
|
|
||||||
return this._passwordItem != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
set isPassword(v) {
|
|
||||||
if (v == this.isPassword)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (v) {
|
|
||||||
this._makePasswordItem();
|
|
||||||
this._entry.input_purpose = Clutter.InputContentPurpose.PASSWORD;
|
|
||||||
} else {
|
|
||||||
this._passwordItem.destroy();
|
|
||||||
this._passwordItem = null;
|
|
||||||
this._entry.input_purpose = Clutter.InputContentPurpose.NORMAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open(animate) {
|
open(animate) {
|
||||||
this._updatePasteItem();
|
this._updatePasteItem();
|
||||||
this._updateCopyItem();
|
this._updateCopyItem();
|
||||||
@ -86,8 +69,7 @@ var EntryMenu = class extends PopupMenu.PopupMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_updatePasswordItem() {
|
_updatePasswordItem() {
|
||||||
let textHidden = this._entry.clutter_text.password_char;
|
if (!this._entry.password_visible)
|
||||||
if (textHidden)
|
|
||||||
this._passwordItem.label.set_text(_("Show Text"));
|
this._passwordItem.label.set_text(_("Show Text"));
|
||||||
else
|
else
|
||||||
this._passwordItem.label.set_text(_("Hide Text"));
|
this._passwordItem.label.set_text(_("Hide Text"));
|
||||||
@ -110,8 +92,7 @@ var EntryMenu = class extends PopupMenu.PopupMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_onPasswordActivated() {
|
_onPasswordActivated() {
|
||||||
let visible = !!this._entry.clutter_text.password_char;
|
this._entry.password_visible = !this._entry.password_visible;
|
||||||
this._entry.clutter_text.set_password_char(visible ? '' : '\u25cf');
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -145,10 +126,9 @@ function addContextMenu(entry, params) {
|
|||||||
if (entry.menu)
|
if (entry.menu)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
params = Params.parse(params, { isPassword: false, actionMode: Shell.ActionMode.POPUP });
|
params = Params.parse(params, { actionMode: Shell.ActionMode.POPUP });
|
||||||
|
|
||||||
entry.menu = new EntryMenu(entry);
|
entry.menu = new EntryMenu(entry);
|
||||||
entry.menu.isPassword = params.isPassword;
|
|
||||||
entry._menuManager = new PopupMenu.PopupMenuManager(entry,
|
entry._menuManager = new PopupMenu.PopupMenuManager(entry,
|
||||||
{ actionMode: params.actionMode });
|
{ actionMode: params.actionMode });
|
||||||
entry._menuManager.addMenu(entry.menu);
|
entry._menuManager.addMenu(entry.menu);
|
||||||
@ -171,3 +151,39 @@ function addContextMenu(entry, params) {
|
|||||||
entry._menuManager = null;
|
entry._menuManager = null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var CapsLockWarning = GObject.registerClass(
|
||||||
|
class CapsLockWarning extends St.Label {
|
||||||
|
_init(passwordEntry, params) {
|
||||||
|
super._init({
|
||||||
|
text: _('Caps lock is on.'),
|
||||||
|
});
|
||||||
|
|
||||||
|
params = Params.parse(params, {
|
||||||
|
style_class: 'prompt-dialog-error-label',
|
||||||
|
x_align: St.Align.START,
|
||||||
|
});
|
||||||
|
this.set(params);
|
||||||
|
|
||||||
|
this.keymap = Clutter.get_default_backend().get_keymap();
|
||||||
|
this._updateCapsLockWarningOpacity();
|
||||||
|
|
||||||
|
this._passwordEntry = passwordEntry;
|
||||||
|
this._passwordEntry.connect('notify::mapped', () => {
|
||||||
|
if (this._passwordEntry.is_mapped()) {
|
||||||
|
this.stateChangedId = this.keymap.connect('state-changed',
|
||||||
|
this._updateCapsLockWarningOpacity.bind(this));
|
||||||
|
} else {
|
||||||
|
this.keymap.disonnect(this.stateChangedId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
|
this.clutter_text.line_wrap = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateCapsLockWarningOpacity() {
|
||||||
|
let capsLockOn = this.keymap.get_caps_lock_state();
|
||||||
|
this.opacity = capsLockOn ? 255 : 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
@ -326,12 +326,13 @@ var ShellMountPasswordDialog = GObject.registerClass({
|
|||||||
this._pimLabel = new St.Label({ style_class: 'prompt-dialog-password-label',
|
this._pimLabel = new St.Label({ style_class: 'prompt-dialog-password-label',
|
||||||
text: _("PIM Number"),
|
text: _("PIM Number"),
|
||||||
y_align: Clutter.ActorAlign.CENTER });
|
y_align: Clutter.ActorAlign.CENTER });
|
||||||
this._pimEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
this._pimEntry = new St.PasswordEntry({
|
||||||
can_focus: true,
|
style_class: 'prompt-dialog-password-entry',
|
||||||
x_expand: true });
|
can_focus: true,
|
||||||
|
x_expand: true,
|
||||||
|
});
|
||||||
this._pimEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this));
|
this._pimEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this));
|
||||||
this._pimEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
ShellEntry.addContextMenu(this._pimEntry);
|
||||||
ShellEntry.addContextMenu(this._pimEntry, { isPassword: true });
|
|
||||||
|
|
||||||
if (rtl) {
|
if (rtl) {
|
||||||
layout.attach(this._pimEntry, 0, 0, 1, 1);
|
layout.attach(this._pimEntry, 0, 0, 1, 1);
|
||||||
@ -355,24 +356,28 @@ var ShellMountPasswordDialog = GObject.registerClass({
|
|||||||
this._passwordLabel = new St.Label({ style_class: 'prompt-dialog-password-label',
|
this._passwordLabel = new St.Label({ style_class: 'prompt-dialog-password-label',
|
||||||
text: _("Password"),
|
text: _("Password"),
|
||||||
y_align: Clutter.ActorAlign.CENTER });
|
y_align: Clutter.ActorAlign.CENTER });
|
||||||
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
this._passwordEntry = new St.PasswordEntry({
|
||||||
can_focus: true,
|
style_class: 'prompt-dialog-password-entry',
|
||||||
x_expand: true });
|
can_focus: true,
|
||||||
|
x_expand: true,
|
||||||
|
});
|
||||||
this._passwordEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this));
|
this._passwordEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this));
|
||||||
this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
ShellEntry.addContextMenu(this._passwordEntry);
|
||||||
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
|
|
||||||
this.setInitialKeyFocus(this._passwordEntry);
|
this.setInitialKeyFocus(this._passwordEntry);
|
||||||
this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, {
|
this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, {
|
||||||
animate: true,
|
animate: true,
|
||||||
});
|
});
|
||||||
this._passwordEntry.secondary_icon = this._workSpinner;
|
this._passwordEntry.secondary_icon = this._workSpinner;
|
||||||
|
this._capsLockWarningLabel = new ShellEntry.CapsLockWarning(this._passwordEntry);
|
||||||
|
|
||||||
if (rtl) {
|
if (rtl) {
|
||||||
layout.attach(this._passwordEntry, 0, 1, 1, 1);
|
layout.attach(this._passwordEntry, 0, 1, 1, 1);
|
||||||
layout.attach(this._passwordLabel, 1, 1, 1, 1);
|
layout.attach(this._passwordLabel, 1, 1, 1, 1);
|
||||||
|
layout.attach(this._capsLockWarningLabel, 0, 2, 1, 1);
|
||||||
} else {
|
} else {
|
||||||
layout.attach(this._passwordLabel, 0, 1, 1, 1);
|
layout.attach(this._passwordLabel, 0, 1, 1, 1);
|
||||||
layout.attach(this._passwordEntry, 1, 1, 1, 1);
|
layout.attach(this._passwordEntry, 1, 1, 1, 1);
|
||||||
|
layout.attach(this._capsLockWarningLabel, 1, 2, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
content.messageBox.add(grid);
|
content.messageBox.add(grid);
|
||||||
|
@ -15,6 +15,7 @@ st_headers = [
|
|||||||
'st-icon-colors.h',
|
'st-icon-colors.h',
|
||||||
'st-image-content.h',
|
'st-image-content.h',
|
||||||
'st-label.h',
|
'st-label.h',
|
||||||
|
'st-password-entry.h',
|
||||||
'st-scrollable.h',
|
'st-scrollable.h',
|
||||||
'st-scroll-bar.h',
|
'st-scroll-bar.h',
|
||||||
'st-scroll-view.h',
|
'st-scroll-view.h',
|
||||||
@ -125,6 +126,7 @@ st_sources = [
|
|||||||
'st-icon-colors.c',
|
'st-icon-colors.c',
|
||||||
'st-image-content.c',
|
'st-image-content.c',
|
||||||
'st-label.c',
|
'st-label.c',
|
||||||
|
'st-password-entry.c',
|
||||||
'st-private.c',
|
'st-private.c',
|
||||||
'st-scrollable.c',
|
'st-scrollable.c',
|
||||||
'st-scroll-bar.c',
|
'st-scroll-bar.c',
|
||||||
|
@ -110,7 +110,6 @@ struct _StEntryPrivate
|
|||||||
|
|
||||||
gfloat spacing;
|
gfloat spacing;
|
||||||
|
|
||||||
gboolean capslock_warning_shown;
|
|
||||||
gboolean has_ibeam;
|
gboolean has_ibeam;
|
||||||
|
|
||||||
CoglPipeline *text_shadow_material;
|
CoglPipeline *text_shadow_material;
|
||||||
@ -216,61 +215,14 @@ st_entry_get_property (GObject *gobject,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
show_capslock_feedback (StEntry *entry)
|
|
||||||
{
|
|
||||||
StEntryPrivate *priv = ST_ENTRY_PRIV (entry);
|
|
||||||
if (priv->secondary_icon == NULL)
|
|
||||||
{
|
|
||||||
ClutterActor *icon = g_object_new (ST_TYPE_ICON,
|
|
||||||
"style-class", "capslock-warning",
|
|
||||||
"icon-name", "dialog-warning-symbolic",
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
st_entry_set_secondary_icon (entry, icon);
|
|
||||||
priv->capslock_warning_shown = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
remove_capslock_feedback (StEntry *entry)
|
|
||||||
{
|
|
||||||
StEntryPrivate *priv = ST_ENTRY_PRIV (entry);
|
|
||||||
if (priv->capslock_warning_shown)
|
|
||||||
{
|
|
||||||
st_entry_set_secondary_icon (entry, NULL);
|
|
||||||
priv->capslock_warning_shown = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
keymap_state_changed (ClutterKeymap *keymap,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
StEntry *entry = ST_ENTRY (user_data);
|
|
||||||
StEntryPrivate *priv = ST_ENTRY_PRIV (entry);
|
|
||||||
|
|
||||||
if (clutter_text_get_password_char (CLUTTER_TEXT (priv->entry)) != 0)
|
|
||||||
{
|
|
||||||
if (clutter_keymap_get_caps_lock_state (keymap))
|
|
||||||
show_capslock_feedback (entry);
|
|
||||||
else
|
|
||||||
remove_capslock_feedback (entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
st_entry_dispose (GObject *object)
|
st_entry_dispose (GObject *object)
|
||||||
{
|
{
|
||||||
StEntry *entry = ST_ENTRY (object);
|
StEntry *entry = ST_ENTRY (object);
|
||||||
StEntryPrivate *priv = ST_ENTRY_PRIV (entry);
|
StEntryPrivate *priv = ST_ENTRY_PRIV (entry);
|
||||||
ClutterKeymap *keymap;
|
|
||||||
|
|
||||||
cogl_clear_object (&priv->text_shadow_material);
|
cogl_clear_object (&priv->text_shadow_material);
|
||||||
|
|
||||||
keymap = clutter_backend_get_keymap (clutter_get_default_backend ());
|
|
||||||
g_signal_handlers_disconnect_by_func (keymap, keymap_state_changed, entry);
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (st_entry_parent_class)->dispose (object);
|
G_OBJECT_CLASS (st_entry_parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -568,15 +520,9 @@ clutter_text_focus_in_cb (ClutterText *text,
|
|||||||
ClutterActor *actor)
|
ClutterActor *actor)
|
||||||
{
|
{
|
||||||
StEntry *entry = ST_ENTRY (actor);
|
StEntry *entry = ST_ENTRY (actor);
|
||||||
ClutterKeymap *keymap;
|
|
||||||
|
|
||||||
st_entry_update_hint_visibility (entry);
|
st_entry_update_hint_visibility (entry);
|
||||||
|
|
||||||
keymap = clutter_backend_get_keymap (clutter_get_default_backend ());
|
|
||||||
keymap_state_changed (keymap, entry);
|
|
||||||
g_signal_connect (keymap, "state-changed",
|
|
||||||
G_CALLBACK (keymap_state_changed), entry);
|
|
||||||
|
|
||||||
st_widget_add_style_pseudo_class (ST_WIDGET (actor), "focus");
|
st_widget_add_style_pseudo_class (ST_WIDGET (actor), "focus");
|
||||||
clutter_text_set_cursor_visible (text, TRUE);
|
clutter_text_set_cursor_visible (text, TRUE);
|
||||||
}
|
}
|
||||||
@ -586,29 +532,12 @@ clutter_text_focus_out_cb (ClutterText *text,
|
|||||||
ClutterActor *actor)
|
ClutterActor *actor)
|
||||||
{
|
{
|
||||||
StEntry *entry = ST_ENTRY (actor);
|
StEntry *entry = ST_ENTRY (actor);
|
||||||
ClutterKeymap *keymap;
|
|
||||||
|
|
||||||
st_widget_remove_style_pseudo_class (ST_WIDGET (actor), "focus");
|
st_widget_remove_style_pseudo_class (ST_WIDGET (actor), "focus");
|
||||||
|
|
||||||
st_entry_update_hint_visibility (entry);
|
st_entry_update_hint_visibility (entry);
|
||||||
|
|
||||||
clutter_text_set_cursor_visible (text, FALSE);
|
clutter_text_set_cursor_visible (text, FALSE);
|
||||||
remove_capslock_feedback (entry);
|
|
||||||
|
|
||||||
keymap = clutter_backend_get_keymap (clutter_get_default_backend ());
|
|
||||||
g_signal_handlers_disconnect_by_func (keymap, keymap_state_changed, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
clutter_text_password_char_cb (GObject *object,
|
|
||||||
GParamSpec *pspec,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
StEntry *entry = ST_ENTRY (user_data);
|
|
||||||
StEntryPrivate *priv = ST_ENTRY_PRIV (entry);
|
|
||||||
|
|
||||||
if (clutter_text_get_password_char (CLUTTER_TEXT (priv->entry)) == 0)
|
|
||||||
remove_capslock_feedback (entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1054,9 +983,6 @@ st_entry_init (StEntry *entry)
|
|||||||
g_signal_connect (priv->entry, "key-focus-out",
|
g_signal_connect (priv->entry, "key-focus-out",
|
||||||
G_CALLBACK (clutter_text_focus_out_cb), entry);
|
G_CALLBACK (clutter_text_focus_out_cb), entry);
|
||||||
|
|
||||||
g_signal_connect (priv->entry, "notify::password-char",
|
|
||||||
G_CALLBACK (clutter_text_password_char_cb), entry);
|
|
||||||
|
|
||||||
g_signal_connect (priv->entry, "button-press-event",
|
g_signal_connect (priv->entry, "button-press-event",
|
||||||
G_CALLBACK (clutter_text_button_press_event), entry);
|
G_CALLBACK (clutter_text_button_press_event), entry);
|
||||||
|
|
||||||
|
282
src/st/st-password-entry.c
Normal file
282
src/st/st-password-entry.c
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||||
|
/*
|
||||||
|
* st-password-entry.c: Password entry actor based on st-entry
|
||||||
|
*
|
||||||
|
* Copyright 2019 Endless Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU Lesser General Public License,
|
||||||
|
* version 2.1, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "st-private.h"
|
||||||
|
#include "st-password-entry.h"
|
||||||
|
#include "st-icon.h"
|
||||||
|
|
||||||
|
#define BLACK_CIRCLE 9679
|
||||||
|
|
||||||
|
#define ST_PASSWORD_ENTRY_PRIV(x) st_password_entry_get_instance_private ((StPasswordEntry *) x)
|
||||||
|
|
||||||
|
typedef struct _StPasswordEntryPrivate StPasswordEntryPrivate;
|
||||||
|
|
||||||
|
struct _StPasswordEntry
|
||||||
|
{
|
||||||
|
/*< private >*/
|
||||||
|
StEntry parent_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _StPasswordEntryPrivate
|
||||||
|
{
|
||||||
|
ClutterActor *peek_password_icon;
|
||||||
|
gboolean password_visible;
|
||||||
|
gboolean show_peek_icon;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PROP_0,
|
||||||
|
|
||||||
|
PROP_PASSWORD_VISIBLE,
|
||||||
|
PROP_SHOW_PEEK_ICON,
|
||||||
|
|
||||||
|
N_PROPS
|
||||||
|
};
|
||||||
|
|
||||||
|
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,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
StPasswordEntryPrivate *priv = ST_PASSWORD_ENTRY_PRIV (gobject);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
st_password_entry_set_property (GObject *gobject,
|
||||||
|
guint prop_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
StPasswordEntry *entry = ST_PASSWORD_ENTRY (gobject);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clutter_text_password_char_cb (GObject *object,
|
||||||
|
GParamSpec *pspec,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
StPasswordEntry *entry = ST_PASSWORD_ENTRY (user_data);
|
||||||
|
ClutterActor *clutter_text;
|
||||||
|
|
||||||
|
clutter_text = st_entry_get_clutter_text (ST_ENTRY (entry));
|
||||||
|
if (clutter_text_get_password_char (CLUTTER_TEXT (clutter_text)) == 0)
|
||||||
|
st_password_entry_set_password_visible (entry, TRUE);
|
||||||
|
else
|
||||||
|
st_password_entry_set_password_visible (entry, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
st_entry_set_input_purpose (ST_ENTRY (entry), CLUTTER_INPUT_CONTENT_PURPOSE_PASSWORD);
|
||||||
|
|
||||||
|
g_signal_connect (clutter_text, "notify::password-char",
|
||||||
|
G_CALLBACK (clutter_text_password_char_cb), entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* st_password_entry_new:
|
||||||
|
*
|
||||||
|
* Create a new #StPasswordEntry.
|
||||||
|
*
|
||||||
|
* Returns: a new #StEntry
|
||||||
|
*/
|
||||||
|
StEntry*
|
||||||
|
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
|
||||||
|
* @value: #TRUE to show the password in the entry, #FALSE otherwise
|
||||||
|
*
|
||||||
|
* Sets whether to show or hide text in the password entry.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
st_password_entry_set_password_visible (StPasswordEntry *entry, gboolean value)
|
||||||
|
{
|
||||||
|
StPasswordEntryPrivate *priv;
|
||||||
|
ClutterActor *clutter_text;
|
||||||
|
|
||||||
|
g_return_if_fail (ST_IS_PASSWORD_ENTRY (entry));
|
||||||
|
|
||||||
|
priv = ST_PASSWORD_ENTRY_PRIV (entry);
|
||||||
|
if (priv->password_visible == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
priv->password_visible = 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);
|
||||||
|
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);
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* st_password_entry_get_password_visible:
|
||||||
|
* @entry: a #StPasswordEntry
|
||||||
|
*
|
||||||
|
* Gets whether the text is masked in the password entry.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
st_password_entry_get_password_visible (StPasswordEntry *entry)
|
||||||
|
{
|
||||||
|
StPasswordEntryPrivate *priv;
|
||||||
|
|
||||||
|
g_return_val_if_fail (ST_IS_PASSWORD_ENTRY (entry), FALSE);
|
||||||
|
|
||||||
|
priv = ST_PASSWORD_ENTRY_PRIV (entry);
|
||||||
|
return priv->password_visible;
|
||||||
|
}
|
46
src/st/st-password-entry.h
Normal file
46
src/st/st-password-entry.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||||
|
/*
|
||||||
|
* st-password-entry.h: Password entry actor based on st-entry
|
||||||
|
*
|
||||||
|
* Copyright 2019 Endless Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU Lesser General Public License,
|
||||||
|
* version 2.1, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
|
||||||
|
#error "Only <st/st.h> can be included directly.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __ST_PASSWORD_ENTRY_H__
|
||||||
|
#define __ST_PASSWORD_ENTRY_H__
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#include <st/st-entry.h>
|
||||||
|
|
||||||
|
#define ST_TYPE_PASSWORD_ENTRY (st_password_entry_get_type ())
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (StPasswordEntry, st_password_entry, ST, PASSWORD_ENTRY, StEntry)
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
#endif /* __ST_PASSWORD_ENTRY_H__ */
|
||||||
|
|
Loading…
Reference in New Issue
Block a user