Compare commits

..

1 Commits

Author SHA1 Message Date
Benjamin Berg
b92afe6a63 util: Improve systemd start/stop API to permit waiting for job
In some cases it may be interesting to wait for the start/stop job to
complete. Improve the API to be asynchronous and add the appropriate
watches for systemd. Only return the task once the start or stop job has
been removed again on the systemd side.
2019-12-13 19:25:00 +01:00
63 changed files with 488 additions and 830 deletions

View File

@@ -20,8 +20,6 @@
<file>no-notifications.svg</file>
<file>noise-texture.png</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-drag-symbolic.svg">pointer-drag-symbolic.svg</file>
<file alias="icons/pointer-primary-click-symbolic.svg">pointer-primary-click-symbolic.svg</file>

View File

@@ -50,7 +50,7 @@
</description>
</key>
<key name="favorite-apps" type="as">
<default>[ 'org.gnome.Epiphany.desktop', 'org.gnome.Evolution.desktop', 'rhythmbox.desktop', 'org.gnome.Shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ]</default>
<default>[ 'epiphany.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'org.gnome.Shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ]</default>
<summary>List of desktop file IDs for favorite applications</summary>
<description>
The applications corresponding to these identifiers

View File

@@ -1,4 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 572 B

View File

@@ -1,27 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -97,11 +97,6 @@ StEntry {
warning-color: $warning_color;
padding: 0 4px;
}
StIcon.peek-password {
icon-size: 1.09em;
padding: 0 4px;
}
}
@@ -409,11 +404,6 @@ StScrollBar {
padding-bottom: 8px;
}
.prompt-dialog-caps-lock-warning {
@extend .prompt-dialog-error-label;
padding-left: 6.2em;
}
.prompt-dialog-info-label {
font-size: 10pt;
padding-bottom: 8px;

View File

@@ -66,11 +66,4 @@ its dependencies to build from tarballs.</description>
<gnome:userid>fmuellner</gnome:userid>
</foaf:Person>
</maintainer>
<maintainer>
<foaf:Person>
<foaf:name>Georges Basile Stavracas Neto</foaf:name>
<foaf:mbox rdf:resource="mailto:gbsneto@gnome.org" />
<gnome:userid>gbsneto</gnome:userid>
</foaf:Person>
</maintainer>
</Project>

View File

@@ -98,30 +98,18 @@ var AuthPrompt = GObject.registerClass({
});
this.add_child(this._label);
let entryParams = {
this._entry = new St.Entry({
style_class: 'login-dialog-prompt-entry',
can_focus: true,
x_expand: false,
y_expand: true,
};
});
ShellEntry.addContextMenu(this._entry, { isPassword: true, actionMode: Shell.ActionMode.NONE });
this._entry = null;
this._textEntry = new St.Entry(entryParams);
ShellEntry.addContextMenu(this._textEntry, { actionMode: Shell.ActionMode.NONE });
this._passwordEntry = new St.PasswordEntry(entryParams);
ShellEntry.addContextMenu(this._passwordEntry, { actionMode: Shell.ActionMode.NONE });
this._entry = this._passwordEntry;
this.add_child(this._entry);
this._entry.grab_key_focus();
this._capsLockWarningLabel = new ShellEntry.CapsLockWarning();
this.add_child(this._capsLockWarningLabel);
this._message = new St.Label({
opacity: 0,
styleClass: 'login-dialog-message',
@@ -207,18 +195,7 @@ var AuthPrompt = GObject.registerClass({
});
}
_updateEntry(secret) {
if (secret && (this._entry != this._passwordEntry)) {
this.replace_child(this._entry, this._passwordEntry);
this._entry = this._passwordEntry;
} else if (!secret && (this._entry != this._textEntry)) {
this.replace_child(this._entry, this._textEntry);
this._entry = this._textEntry;
}
this._capsLockWarningLabel.visible = secret;
}
_onAskQuestion(verifier, serviceName, question, secret) {
_onAskQuestion(verifier, serviceName, question, passwordChar) {
if (this._queryingService)
this.clear();
@@ -228,11 +205,10 @@ var AuthPrompt = GObject.registerClass({
this._preemptiveAnswer = null;
return;
}
this._updateEntry(secret);
this.setPasswordChar(passwordChar);
this.setQuestion(question);
if (secret) {
if (passwordChar) {
if (this._userVerifier.reauthenticating)
this.nextButton.label = _("Unlock");
else
@@ -382,6 +358,11 @@ var AuthPrompt = GObject.registerClass({
this.stopSpinning();
}
setPasswordChar(passwordChar) {
this._entry.clutter_text.set_password_char(passwordChar);
this._entry.menu.isPassword = passwordChar != '';
}
setQuestion(question) {
this._label.set_text(question);

View File

@@ -896,6 +896,7 @@ var LoginDialog = GObject.registerClass({
}
_askForUsernameAndBeginVerification() {
this._authPrompt.setPasswordChar('');
this._authPrompt.setQuestion(_("Username: "));
this._showRealmLoginHint(this._realmManager.loginFormat);

View File

@@ -485,7 +485,7 @@ var ShellUserVerifier = class {
if (!this.serviceIsForeground(serviceName))
return;
this.emit('ask-question', serviceName, question, false);
this.emit('ask-question', serviceName, question, '');
}
_onSecretInfoQuery(client, serviceName, secretQuestion) {
@@ -498,7 +498,7 @@ var ShellUserVerifier = class {
return;
}
this.emit('ask-question', serviceName, secretQuestion, true);
this.emit('ask-question', serviceName, secretQuestion, '\u25cf');
}
_onReset() {

View File

@@ -55,7 +55,6 @@ const RENAMED_DESKTOP_IDS = {
'org.gnome.taquin.desktop': 'org.gnome.Taquin.desktop',
'org.gnome.Weather.Application.desktop': 'org.gnome.Weather.desktop',
'polari.desktop': 'org.gnome.Polari.desktop',
'seahorse.desktop': 'org.gnome.seahorse.Application.desktop',
'shotwell.desktop': 'org.gnome.Shotwell.desktop',
'tali.desktop': 'org.gnome.Tali.desktop',
'totem.desktop': 'org.gnome.Totem.desktop',

View File

@@ -70,13 +70,12 @@ class KeyringDialog extends ModalDialog.ModalDialog {
y_align: Clutter.ActorAlign.CENTER });
label.set_text(_("Password:"));
label.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._passwordEntry = new St.PasswordEntry({
style_class: 'prompt-dialog-password-entry',
text: '',
can_focus: true,
x_expand: true,
});
ShellEntry.addContextMenu(this._passwordEntry);
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
text: '',
can_focus: true,
x_expand: true });
this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
this._passwordEntry.clutter_text.connect('activate', this._onPasswordActivate.bind(this));
this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, {
@@ -103,13 +102,12 @@ class KeyringDialog extends ModalDialog.ModalDialog {
x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.CENTER });
label.set_text(_("Type again:"));
this._confirmEntry = new St.PasswordEntry({
style_class: 'prompt-dialog-password-entry',
text: '',
can_focus: true,
x_expand: true,
});
ShellEntry.addContextMenu(this._confirmEntry);
this._confirmEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
text: '',
can_focus: true,
x_expand: true });
this._confirmEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
ShellEntry.addContextMenu(this._confirmEntry, { isPassword: true });
this._confirmEntry.clutter_text.connect('activate', this._onConfirmActivate.bind(this));
if (rtl) {
layout.attach(this._confirmEntry, 0, row, 1, 1);
@@ -126,12 +124,6 @@ class KeyringDialog extends ModalDialog.ModalDialog {
this.prompt.set_password_actor(this._passwordEntry ? this._passwordEntry.clutter_text : null);
this.prompt.set_confirm_actor(this._confirmEntry ? this._confirmEntry.clutter_text : null);
if (this._passwordEntry || this._confirmEntry) {
this._capsLockWarningLabel = new ShellEntry.CapsLockWarning();
layout.attach(this._capsLockWarningLabel, 1, row, 1, 1);
row++;
}
if (this.prompt.choice_visible) {
let choice = new CheckBox.CheckBox();
this.prompt.bind_property('choice-label', choice.getLabelActor(), 'text', GObject.BindingFlags.SYNC_CREATE);

View File

@@ -54,18 +54,12 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
let reactive = secret.key != null;
let entryParams = {
style_class: 'prompt-dialog-password-entry',
text: secret.value,
can_focus: reactive,
reactive,
x_expand: true,
};
if (secret.password)
secret.entry = new St.PasswordEntry(entryParams);
else
secret.entry = new St.Entry(entryParams);
ShellEntry.addContextMenu(secret.entry);
secret.entry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
text: secret.value, can_focus: reactive,
reactive,
x_expand: true });
ShellEntry.addContextMenu(secret.entry,
{ isPassword: secret.password });
if (secret.validate)
secret.valid = secret.validate(secret);
@@ -99,14 +93,9 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
layout.attach(secret.entry, 1, pos, 1, 1);
}
pos++;
}
if (this._content.secrets.some(s => s.password)) {
this._capsLockWarningLabel = new ShellEntry.CapsLockWarning();
if (rtl)
layout.attach(this._capsLockWarningLabel, 0, pos, 1, 1);
else
layout.attach(this._capsLockWarningLabel, 1, pos, 1, 1);
if (secret.password)
secret.entry.clutter_text.set_password_char('\u25cf');
}
contentBox.messageBox.add(secretTable);

View File

@@ -90,13 +90,13 @@ var AuthenticationDialog = GObject.registerClass({
y_align: Clutter.ActorAlign.CENTER,
});
this._passwordBox.add_child(this._passwordLabel);
this._passwordEntry = new St.PasswordEntry({
this._passwordEntry = new St.Entry({
style_class: 'prompt-dialog-password-entry',
text: "",
can_focus: true,
x_expand: true,
});
ShellEntry.addContextMenu(this._passwordEntry);
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
this._passwordEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this));
this._passwordEntry.bind_property('reactive',
this._passwordEntry.clutter_text, 'editable',
@@ -109,8 +109,6 @@ var AuthenticationDialog = GObject.registerClass({
this._passwordBox.add(this._workSpinner);
this._passwordBox.hide();
this._capsLockWarningLabel = new ShellEntry.CapsLockWarning({ 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.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
@@ -280,7 +278,10 @@ var AuthenticationDialog = GObject.registerClass({
else
this._passwordLabel.set_text(request);
this._passwordEntry.password_visible = echoOn;
if (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._passwordEntry.set_text('');

View File

@@ -194,15 +194,6 @@ var GrabHelper = class GrabHelper {
return true;
}
grabAsync(params) {
return new Promise((resolve, reject) => {
params.onUngrab = resolve;
if (!this.grab(params))
reject(new Error('Grab failed'));
});
}
_takeModalGrab() {
let firstGrab = this._modalCount == 0;
if (firstGrab) {

View File

@@ -51,7 +51,7 @@ class BaseIcon extends St.Bin {
this.set_child(this._box);
this.iconSize = ICON_SIZE;
this._iconBin = new St.Bin({ x_align: Clutter.ActorAlign.CENTER });
this._iconBin = new St.Bin();
this._box.add_actor(this._iconBin);

View File

@@ -564,14 +564,6 @@ var PadDiagram = GObject.registerClass({
this.add_actor(label);
}
updateLabels(getText) {
for (let i = 0; i < this._labels.length; i++) {
let [label, action, idx, dir] = this._labels[i];
let str = getText(action, idx, dir);
label.set_text(str);
}
}
_applyLabel(label, action, idx, dir, str) {
if (str != null) {
label.set_text(str);
@@ -784,29 +776,17 @@ var PadOsd = GObject.registerClass({
global.display.request_pad_osd(pad, editionMode);
}
_getActionText(type, number) {
let str = global.display.get_pad_action_label(this.padDevice, type, number);
return str ? str : _("None");
}
_createLabel(type, number, dir) {
let label = new St.Label({ text: this._getActionText(type, number) });
let str = global.display.get_pad_action_label(this.padDevice, type, number);
let label = new St.Label({ text: str ? str : _("None") });
this._padDiagram.addLabel(label, type, number, dir);
}
_updateActionLabels() {
this._padDiagram.updateLabels(this._getActionText.bind(this));
}
_onCapturedEvent(actor, event) {
let isModeSwitch =
(event.type() == Clutter.EventType.PAD_BUTTON_PRESS ||
event.type() == Clutter.EventType.PAD_BUTTON_RELEASE) &&
this.padDevice.get_mode_switch_button_group(event.get_button()) >= 0;
if (event.type() == Clutter.EventType.PAD_BUTTON_PRESS &&
event.get_source_device() == this.padDevice) {
this._padDiagram.activateButton(event.get_button());
let isModeSwitch = this.padDevice.get_mode_switch_button_group(event.get_button()) >= 0;
/* Buttons that switch between modes cannot be edited */
if (this._editionMode && !isModeSwitch)
@@ -815,11 +795,6 @@ var PadOsd = GObject.registerClass({
} else if (event.type() == Clutter.EventType.PAD_BUTTON_RELEASE &&
event.get_source_device() == this.padDevice) {
this._padDiagram.deactivateButton(event.get_button());
if (isModeSwitch) {
this._endActionEdition();
this._updateActionLabels();
}
return Clutter.EVENT_STOP;
} else if (event.type() == Clutter.EventType.KEY_PRESS &&
(!this._editionMode || event.get_key_symbol() === Clutter.KEY_Escape)) {

View File

@@ -962,7 +962,7 @@ class Panel extends St.Widget {
}
_toggleMenu(indicator) {
if (!indicator || !indicator.mapped)
if (!indicator || !indicator.container.visible)
return; // menu not supported by current session mode
let menu = indicator.menu;

View File

@@ -814,12 +814,7 @@ var PopupMenu = class extends PopupMenuBase {
if (this.sourceActor) {
this._keyPressId = this.sourceActor.connect('key-press-event',
this._onKeyPress.bind(this));
this._notifyMappedId = this.sourceActor.connect('notify::mapped',
() => {
if (!this.sourceActor.mapped)
this.close();
});
this._onKeyPress.bind(this));
}
this._systemModalOpenedId = 0;
@@ -933,9 +928,6 @@ var PopupMenu = class extends PopupMenuBase {
if (this._keyPressId)
this.sourceActor.disconnect(this._keyPressId);
if (this._notifyMappedId)
this.sourceActor.disconnect(this._notifyMappedId);
if (this._systemModalOpenedId)
Main.layoutManager.disconnect(this._systemModalOpenedId);
this._systemModalOpenedId = 0;

View File

@@ -227,19 +227,20 @@ var ScreenshotService = class {
});
}
async SelectAreaAsync(params, invocation) {
SelectAreaAsync(params, invocation) {
let selectArea = new SelectArea();
try {
let areaRectangle = await selectArea.selectAsync();
let retRectangle = this._unscaleArea(
areaRectangle.x, areaRectangle.y,
areaRectangle.width, areaRectangle.height);
invocation.return_value(GLib.Variant.new('(iiii)', retRectangle));
} catch (e) {
invocation.return_error_literal(
Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED,
'Operation was cancelled');
}
selectArea.show();
selectArea.connect('finished', (o, areaRectangle) => {
if (areaRectangle) {
let retRectangle = this._unscaleArea(areaRectangle.x, areaRectangle.y,
areaRectangle.width, areaRectangle.height);
let retval = GLib.Variant.new('(iiii)', retRectangle);
invocation.return_value(retval);
} else {
invocation.return_error_literal(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED,
"Operation was cancelled");
}
});
}
FlashAreaAsync(params, invocation) {
@@ -256,38 +257,38 @@ var ScreenshotService = class {
invocation.return_value(null);
}
async PickColorAsync(params, invocation) {
PickColorAsync(params, invocation) {
let pickPixel = new PickPixel();
try {
const coords = await pickPixel.pickAsync();
let screenshot = this._createScreenshot(invocation, false);
if (!screenshot)
return;
screenshot.pick_color(coords.x, coords.y, (_o, res) => {
let [success_, color] = screenshot.pick_color_finish(res);
let { red, green, blue } = color;
let retval = GLib.Variant.new('(a{sv})', [{
color: GLib.Variant.new('(ddd)', [
red / 255.0,
green / 255.0,
blue / 255.0,
]),
}]);
this._removeShooterForSender(invocation.get_sender());
invocation.return_value(retval);
});
} catch (e) {
invocation.return_error_literal(
Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED,
'Operation was cancelled');
}
pickPixel.show();
pickPixel.connect('finished', (obj, coords) => {
if (coords) {
let screenshot = this._createScreenshot(invocation, false);
if (!screenshot)
return;
screenshot.pick_color(coords.x, coords.y, (_o, res) => {
let [success_, color] = screenshot.pick_color_finish(res);
let { red, green, blue } = color;
let retval = GLib.Variant.new('(a{sv})', [{
color: GLib.Variant.new('(ddd)', [
red / 255.0,
green / 255.0,
blue / 255.0,
]),
}]);
this._removeShooterForSender(invocation.get_sender());
invocation.return_value(retval);
});
} else {
invocation.return_error_literal(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED,
"Operation was cancelled");
}
});
}
};
var SelectArea = GObject.registerClass(
class SelectArea extends St.Widget {
var SelectArea = GObject.registerClass({
Signals: { 'finished': { param_types: [Meta.Rectangle.$gtype] } },
}, class SelectArea extends St.Widget {
_init() {
this._startX = -1;
this._startY = -1;
@@ -316,21 +317,14 @@ class SelectArea extends St.Widget {
this.add_actor(this._rubberband);
}
async selectAsync() {
vfunc_show() {
if (!this._grabHelper.grab({ actor: this,
onUngrab: this._onUngrab.bind(this) }))
return;
global.display.set_cursor(Meta.Cursor.CROSSHAIR);
Main.uiGroup.set_child_above_sibling(this, null);
this.show();
await this._grabHelper.grabAsync({ actor: this });
global.display.set_cursor(Meta.Cursor.DEFAULT);
GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
this.destroy();
return GLib.SOURCE_REMOVE;
});
return this._result;
super.vfunc_show();
}
_getGeometry() {
@@ -377,10 +371,21 @@ class SelectArea extends St.Widget {
});
return Clutter.EVENT_PROPAGATE;
}
_onUngrab() {
global.display.set_cursor(Meta.Cursor.DEFAULT);
this.emit('finished', this._result);
GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
this.destroy();
return GLib.SOURCE_REMOVE;
});
}
});
var PickPixel = GObject.registerClass(
class PickPixel extends St.Widget {
var PickPixel = GObject.registerClass({
Signals: { 'finished': { param_types: [Graphene.Point.$gtype] } },
}, class PickPixel extends St.Widget {
_init() {
super._init({ visible: false, reactive: true });
@@ -395,21 +400,14 @@ class PickPixel extends St.Widget {
this.add_constraint(constraint);
}
async pickAsync() {
vfunc_show() {
if (!this._grabHelper.grab({ actor: this,
onUngrab: this._onUngrab.bind(this) }))
return;
global.display.set_cursor(Meta.Cursor.CROSSHAIR);
Main.uiGroup.set_child_above_sibling(this, null);
this.show();
await this._grabHelper.grabAsync({ actor: this });
global.display.set_cursor(Meta.Cursor.DEFAULT);
GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
this.destroy();
return GLib.SOURCE_REMOVE;
});
return this._result;
super.vfunc_show();
}
vfunc_button_release_event(buttonEvent) {
@@ -418,6 +416,16 @@ class PickPixel extends St.Widget {
this._grabHelper.ungrab();
return Clutter.EVENT_PROPAGATE;
}
_onUngrab() {
global.display.set_cursor(Meta.Cursor.DEFAULT);
this.emit('finished', this._result);
GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
this.destroy();
return GLib.SOURCE_REMOVE;
});
}
});
var FLASHSPOT_ANIMATION_OUT_TIME = 500; // milliseconds

View File

@@ -1,24 +1,17 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported addContextMenu CapsLockWarning */
/* exported addContextMenu */
const { Clutter, Gio, GObject, Pango, Shell, St } = imports.gi;
const { Clutter, Shell, St } = imports.gi;
const BoxPointer = imports.ui.boxpointer;
const Main = imports.ui.main;
const Params = imports.misc.params;
const PopupMenu = imports.ui.popupMenu;
const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
const DISABLE_SHOW_PASSWORD_KEY = 'disable-show-password';
var EntryMenu = class extends PopupMenu.PopupMenu {
constructor(entry) {
super(entry, 0, St.Side.TOP);
this._lockdownSettings = new Gio.Settings({ schema_id: LOCKDOWN_SCHEMA });
this._lockdownSettings.connect(`changed::${DISABLE_SHOW_PASSWORD_KEY}`,
this._applyLockdownSettings.bind(this));
this._entry = entry;
this._clipboard = St.Clipboard.get_default();
@@ -34,8 +27,7 @@ var EntryMenu = class extends PopupMenu.PopupMenu {
this.addMenuItem(item);
this._pasteItem = item;
if (entry instanceof St.PasswordEntry)
this._makePasswordItem();
this._passwordItem = null;
Main.uiGroup.add_actor(this.actor);
this.actor.hide();
@@ -46,20 +38,24 @@ var EntryMenu = class extends PopupMenu.PopupMenu {
item.connect('activate', this._onPasswordActivated.bind(this));
this.addMenuItem(item);
this._passwordItem = item;
this._applyLockdownSettings();
}
_applyLockdownSettings() {
if (!this._passwordItem)
get isPassword() {
return this._passwordItem != null;
}
set isPassword(v) {
if (v == this.isPassword)
return;
let passwordDisabled = this._lockdownSettings.get_boolean(DISABLE_SHOW_PASSWORD_KEY);
this._passwordItem.visible = !passwordDisabled;
this._entry.show_peek_icon = !passwordDisabled;
if (passwordDisabled)
this._entry.password_visible = false;
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) {
@@ -90,7 +86,8 @@ var EntryMenu = class extends PopupMenu.PopupMenu {
}
_updatePasswordItem() {
if (!this._entry.password_visible)
let textHidden = this._entry.clutter_text.password_char;
if (textHidden)
this._passwordItem.label.set_text(_("Show Text"));
else
this._passwordItem.label.set_text(_("Hide Text"));
@@ -113,7 +110,8 @@ var EntryMenu = class extends PopupMenu.PopupMenu {
}
_onPasswordActivated() {
this._entry.password_visible = !this._entry.password_visible;
let visible = !!this._entry.clutter_text.password_char;
this._entry.clutter_text.set_password_char(visible ? '' : '\u25cf');
}
};
@@ -147,9 +145,10 @@ function addContextMenu(entry, params) {
if (entry.menu)
return;
params = Params.parse(params, { actionMode: Shell.ActionMode.POPUP });
params = Params.parse(params, { isPassword: false, actionMode: Shell.ActionMode.POPUP });
entry.menu = new EntryMenu(entry);
entry.menu.isPassword = params.isPassword;
entry._menuManager = new PopupMenu.PopupMenuManager(entry,
{ actionMode: params.actionMode });
entry._menuManager.addMenu(entry.menu);
@@ -172,40 +171,3 @@ function addContextMenu(entry, params) {
entry._menuManager = null;
});
}
var CapsLockWarning = GObject.registerClass(
class CapsLockWarning extends St.Label {
_init(params) {
let defaultParams = { style_class: 'prompt-dialog-error-label' };
super._init(Object.assign(defaultParams, params));
this.text = _('Caps lock is on.');
this._keymap = Clutter.get_default_backend().get_keymap();
this.connect('notify::mapped', () => {
if (this.is_mapped()) {
this.stateChangedId = this._keymap.connect('state-changed',
this._updateCapsLockWarningOpacity.bind(this));
} else {
this._keymap.disconnect(this.stateChangedId);
this.stateChangedId = 0;
}
this._updateCapsLockWarningOpacity();
});
this.connect('destroy', () => {
if (this.stateChangedId > 0)
this._keymap.disconnect(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;
}
});

View File

@@ -326,13 +326,12 @@ var ShellMountPasswordDialog = GObject.registerClass({
this._pimLabel = new St.Label({ style_class: 'prompt-dialog-password-label',
text: _("PIM Number"),
y_align: Clutter.ActorAlign.CENTER });
this._pimEntry = new St.PasswordEntry({
style_class: 'prompt-dialog-password-entry',
can_focus: true,
x_expand: true,
});
this._pimEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
can_focus: true,
x_expand: true });
this._pimEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this));
ShellEntry.addContextMenu(this._pimEntry);
this._pimEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
ShellEntry.addContextMenu(this._pimEntry, { isPassword: true });
if (rtl) {
layout.attach(this._pimEntry, 0, 0, 1, 1);
@@ -356,28 +355,24 @@ var ShellMountPasswordDialog = GObject.registerClass({
this._passwordLabel = new St.Label({ style_class: 'prompt-dialog-password-label',
text: _("Password"),
y_align: Clutter.ActorAlign.CENTER });
this._passwordEntry = new St.PasswordEntry({
style_class: 'prompt-dialog-password-entry',
can_focus: true,
x_expand: true,
});
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
can_focus: true,
x_expand: true });
this._passwordEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this));
ShellEntry.addContextMenu(this._passwordEntry);
this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
this.setInitialKeyFocus(this._passwordEntry);
this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, {
animate: true,
});
this._passwordEntry.secondary_icon = this._workSpinner;
this._capsLockWarningLabel = new ShellEntry.CapsLockWarning();
if (rtl) {
layout.attach(this._passwordEntry, 0, 1, 1, 1);
layout.attach(this._passwordLabel, 1, 1, 1, 1);
layout.attach(this._capsLockWarningLabel, 0, 2, 1, 1);
} else {
layout.attach(this._passwordLabel, 0, 1, 1, 1);
layout.attach(this._passwordEntry, 1, 1, 1, 1);
layout.attach(this._capsLockWarningLabel, 1, 2, 1, 1);
}
content.messageBox.add(grid);

View File

@@ -41,6 +41,7 @@ var UnlockDialog = GObject.registerClass({
this._authPrompt.connect('failed', this._fail.bind(this));
this._authPrompt.connect('cancelled', this._fail.bind(this));
this._authPrompt.connect('reset', this._onReset.bind(this));
this._authPrompt.setPasswordChar('\u25cf');
this._authPrompt.nextButton.label = _("Unlock");
this._promptBox.add_child(this._authPrompt);

View File

@@ -1044,10 +1044,10 @@ var WindowManager = class {
global.display.connect('x11-display-opened', () => {
IBusManager.getIBusManager().restartDaemon(['--xim']);
Shell.util_start_systemd_unit('gnome-session-x11-services.target', 'fail');
Shell.util_start_systemd_unit('gnome-session-x11-services.target', 'fail', null, () => {});
});
global.display.connect('x11-display-closing', () => {
Shell.util_stop_systemd_unit('gnome-session-x11-services.target', 'fail');
Shell.util_stop_systemd_unit('gnome-session-x11-services.target', 'fail', null, () => {});
IBusManager.getIBusManager().restartDaemon();
});

View File

@@ -132,9 +132,20 @@ else
have_systemd = false
endif
if get_option('extensions_tool')
autoar_dep = dependency('gnome-autoar-0')
json_dep = dependency('json-glib-1.0')
endif
bash_completion = dependency('bash-completion', required: false)
if get_option('man')
xsltproc = find_program('xsltproc')
if get_option('extensions_tool')
a2x = find_program('a2x')
endif
subdir('man')
endif
@@ -243,16 +254,6 @@ libgvc = subproject('gvc',
)
libgvc_gir = libgvc.get_variable('libgvc_gir')
if get_option('extensions_tool')
subproject('extensions-tool',
default_options: [
'man=@0@'.format(get_option('man')),
'package_name=@0@'.format(meson.project_name()),
]
)
endif
po_dir = join_paths(meson.current_source_dir(), 'po')
subdir('js')

View File

@@ -72,6 +72,17 @@ js/ui/windowAttentionHandler.js
js/ui/windowManager.js
js/ui/windowMenu.js
src/calendar-server/evolution-calendar.desktop.in
src/extensions-tool/command-create.c
src/extensions-tool/command-disable.c
src/extensions-tool/command-enable.c
src/extensions-tool/command-info.c
src/extensions-tool/command-install.c
src/extensions-tool/command-list.c
src/extensions-tool/command-pack.c
src/extensions-tool/command-prefs.c
src/extensions-tool/command-reset.c
src/extensions-tool/command-uninstall.c
src/extensions-tool/main.c
src/main.c
src/shell-app.c
src/shell-app-system.c
@@ -79,16 +90,5 @@ src/shell-global.c
src/shell-keyring-prompt.c
src/shell-polkit-authentication-agent.c
src/shell-util.c
subprojects/extensions-tool/src/command-create.c
subprojects/extensions-tool/src/command-disable.c
subprojects/extensions-tool/src/command-enable.c
subprojects/extensions-tool/src/command-info.c
subprojects/extensions-tool/src/command-install.c
subprojects/extensions-tool/src/command-list.c
subprojects/extensions-tool/src/command-pack.c
subprojects/extensions-tool/src/command-prefs.c
subprojects/extensions-tool/src/command-reset.c
subprojects/extensions-tool/src/command-uninstall.c
subprojects/extensions-tool/src/main.c
# Please do not remove this file from POTFILES.in. Run "git submodule init && git submodule update" to get it.
subprojects/gvc/gvc-mixer-control.c

View File

@@ -118,14 +118,9 @@ launch_extension_source (GFile *dir, GError **error)
GList l;
main_source = g_file_get_child (dir, "extension.js");
handler = g_file_query_default_handler (main_source, NULL, NULL);
handler = g_file_query_default_handler (main_source, NULL, error);
if (handler == NULL)
{
/* Translators: a file path to an extension directory */
g_print (_("The new extension was successfully created in %s.\n"),
g_file_peek_path (dir));
return TRUE;
}
return FALSE;
l.data = main_source;
l.next = l.prev = NULL;

View File

@@ -0,0 +1,24 @@
sources = [
'commands.h',
'command-create.c',
'command-disable.c',
'command-enable.c',
'command-info.c',
'command-install.c',
'command-list.c',
'command-pack.c',
'command-prefs.c',
'common.h',
'main.c'
]
resources = gnome.compile_resources('resources',
'gnome-extensions-tool.gresource.xml',
source_dir: '.'
)
executable('gnome-extensions',
sources, resources,
dependencies: [gio_dep, gio_unix_dep, autoar_dep, json_dep],
install: true
)

View File

@@ -1,5 +1,5 @@
config_h = configuration_data()
config_h.set_quoted('GETTEXT_PACKAGE', package_name)
config_h.set_quoted('GETTEXT_PACKAGE', meson.project_name())
config_h.set_quoted('VERSION', meson.project_version())
config_h.set_quoted('LOCALEDIR', localedir)
config_h.set('HAVE_BIND_TEXTDOMAIN_CODESET', cc.has_function('bind_textdomain_codeset'))
@@ -32,3 +32,13 @@ executable('gnome-extensions',
dependencies: [gio_dep, gio_unix_dep, autoar_dep, json_dep],
install: true
)
if bash_completion.found()
install_data('completion/bash/gnome-extensions',
install_dir: bash_completion.get_pkgconfig_variable('completionsdir')
)
endif
if get_option('man')
subdir('man')
endif

View File

@@ -6,6 +6,10 @@ subdir('hotplug-sniffer')
subdir('st')
subdir('tray')
if get_option('extensions_tool')
subdir('extensions-tool')
endif
script_data = configuration_data()
script_data.set('bindir', bindir)
script_data.set('datadir', datadir)

View File

@@ -573,6 +573,53 @@ shell_util_check_cloexec_fds (void)
g_info ("Open fd CLOEXEC check complete");
}
typedef struct {
GDBusConnection *connection;
gchar *command;
GCancellable *cancellable;
gulong cancel_id;
guint job_watch;
gchar *job;
} SystemdCall;
static void
shell_util_systemd_call_data_free (SystemdCall *data)
{
if (data->job_watch)
{
g_dbus_connection_signal_unsubscribe (data->connection, data->job_watch);
data->job_watch = 0;
}
if (data->cancellable)
{
g_cancellable_disconnect (data->cancellable, data->cancel_id);
g_clear_object (&data->cancellable);
data->cancel_id = 0;
}
g_clear_object (&data->connection);
g_clear_pointer (&data->job, g_free);
g_clear_pointer (&data->command, g_free);
g_free (data);
}
static void
shell_util_systemd_call_cancelled_cb (GCancellable *cancellable,
GTask *task)
{
SystemdCall *data = g_task_get_task_data (task);
/* We are still in the DBus call; it will return the error. */
if (data->job == NULL)
return;
/* Return the cancellation error now. */
g_assert (g_task_return_error_if_cancelled (task));
}
static void
on_systemd_call_cb (GObject *source,
GAsyncResult *res,
@@ -580,26 +627,103 @@ on_systemd_call_cb (GObject *source,
{
g_autoptr (GVariant) reply = NULL;
g_autoptr (GError) error = NULL;
const gchar *command = user_data;
GTask *task = G_TASK (user_data);
SystemdCall *data;
reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source),
res, &error);
if (error)
g_warning ("Could not issue '%s' systemd call", command);
data = g_task_get_task_data (task);
if (error) {
g_warning ("Could not issue '%s' systemd call", data->command);
g_task_return_error (task, g_steal_pointer (&error));
g_object_unref (task);
return;
}
g_assert (data->job == NULL);
g_variant_get (reply, 0, "(o)", &data->job);
/* And we wait for the JobRemoved notification. */
}
static gboolean
shell_util_systemd_call (const char *command,
const char *unit,
const char *mode,
GError **error)
static void
on_systemd_job_removed_cb (GDBusConnection *connection,
const gchar *sender_name,
const gchar *object_path,
const gchar *interface_name,
const gchar *signal_name,
GVariant *parameters,
gpointer user_data)
{
GTask *task = G_TASK (user_data);
SystemdCall *data;
guint32 id;
const char *path, *unit, *result;
data = g_task_get_task_data (task);
/* No job information yet, ignore. */
if (data->job == NULL)
return;
g_variant_get (parameters, "(u&o&s&s)", &id, &path, &unit, &result);
/* Is it the job we are waiting for? */
if (g_strcmp0 (path, data->job) != 0)
return;
/* Task has completed; return the result of the job */
g_task_return_pointer (task, g_strdup (result), g_free);
g_object_unref (task);
}
static void
shell_util_systemd_call (const char *command,
const char *unit,
const char *mode,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_autoptr (GDBusConnection) connection = NULL;
g_autoptr (GTask) task = NULL;
GError *error = NULL;
SystemdCall *data;
connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, error);
task = g_task_new (NULL, cancellable, callback, user_data);
if (connection == NULL)
return FALSE;
connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
if (connection == NULL) {
g_task_return_error (task, error);
return;
}
data = g_new0 (SystemdCall, 1);
data->command = g_strdup (command);
data->connection = g_object_ref (connection);
data->job_watch = g_dbus_connection_signal_subscribe (connection,
"org.freedesktop.systemd1",
"org.freedesktop.systemd1.Manager",
"JobRemoved",
"/org/freedesktop/systemd1",
NULL,
G_DBUS_SIGNAL_FLAGS_NONE,
on_systemd_job_removed_cb,
g_object_ref (task),
g_object_unref);
g_task_set_task_data (task,
data,
(GDestroyNotify) shell_util_systemd_call_data_free);
if (cancellable)
data->cancel_id = g_cancellable_connect (cancellable,
G_CALLBACK (shell_util_systemd_call_cancelled_cb),
task,
NULL);
g_dbus_connection_call (connection,
"org.freedesktop.systemd1",
@@ -608,28 +732,49 @@ shell_util_systemd_call (const char *command,
command,
g_variant_new ("(ss)",
unit, mode),
NULL,
G_VARIANT_TYPE ("(o)"),
G_DBUS_CALL_FLAGS_NONE,
-1, NULL,
-1, cancellable,
on_systemd_call_cb,
(gpointer) command);
return TRUE;
g_steal_pointer (&task));
}
gboolean
shell_util_start_systemd_unit (const char *unit,
const char *mode,
GError **error)
void
shell_util_start_systemd_unit (const char *unit,
const char *mode,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
return shell_util_systemd_call ("StartUnit", unit, mode, error);
shell_util_systemd_call ("StartUnit", unit, mode,
cancellable, callback, user_data);
}
gboolean
shell_util_stop_systemd_unit (const char *unit,
const char *mode,
GError **error)
gchar*
shell_util_start_systemd_unit_finish (GObject *obj,
GAsyncResult *res,
GError **error)
{
return shell_util_systemd_call ("StopUnit", unit, mode, error);
return g_task_propagate_pointer (G_TASK (res), error);
}
void
shell_util_stop_systemd_unit (const char *unit,
const char *mode,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
shell_util_systemd_call ("StopUnit", unit, mode,
cancellable, callback, user_data);
}
gchar*
shell_util_stop_systemd_unit_finish (GObject *obj,
GAsyncResult *res,
GError **error)
{
return g_task_propagate_pointer (G_TASK (res), error);
}
void

View File

@@ -57,12 +57,23 @@ cairo_surface_t * shell_util_composite_capture_images (ClutterCapture *captures
void shell_util_check_cloexec_fds (void);
gboolean shell_util_start_systemd_unit (const char *unit,
const char *mode,
GError **error);
gboolean shell_util_stop_systemd_unit (const char *unit,
const char *mode,
GError **error);
void shell_util_start_systemd_unit (const char *unit,
const char *mode,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gchar* shell_util_start_systemd_unit_finish (GObject *obj,
GAsyncResult *res,
GError **error);
void shell_util_stop_systemd_unit (const char *unit,
const char *mode,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gchar* shell_util_stop_systemd_unit_finish (GObject *obj,
GAsyncResult *res,
GError **error);
void shell_util_sd_notify (void);

View File

@@ -15,7 +15,6 @@ st_headers = [
'st-icon-colors.h',
'st-image-content.h',
'st-label.h',
'st-password-entry.h',
'st-scrollable.h',
'st-scroll-bar.h',
'st-scroll-view.h',
@@ -126,7 +125,6 @@ st_sources = [
'st-icon-colors.c',
'st-image-content.c',
'st-label.c',
'st-password-entry.c',
'st-private.c',
'st-scrollable.c',
'st-scroll-bar.c',
@@ -155,15 +153,14 @@ st_gir_sources = st_sources + st_headers + st_enums
data_to_c = find_program(meson.source_root() + '/src/data-to-c.pl')
glsl_sources = custom_target('scroll-view-fade-glsl',
custom_target('scroll-view-fade-glsl',
input: ['st-scroll-view-fade.glsl'],
output: ['st-scroll-view-fade-generated.h'],
output: ['st-scroll-view-fade-generated.c'],
build_by_default: true,
capture: true,
command: [data_to_c, '@INPUT@', 'st_scroll_view_fade_glsl']
)
st_nogir_sources = [glsl_sources]
st_cflags = [
'-I@0@/src'.format(meson.source_root()),
'-I@0@'.format(meson.build_root()),
@@ -178,7 +175,7 @@ st_cflags = [
# Currently meson requires a shared library for building girs
libst = shared_library('st-1.0',
sources: st_gir_sources + st_nogir_sources + croco_sources,
sources: st_gir_sources + croco_sources,
c_args: st_cflags,
dependencies: [clutter_dep, gtk_dep, mutter_dep, libxml_dep, m_dep],
build_rpath: mutter_typelibdir,

View File

@@ -110,6 +110,7 @@ struct _StEntryPrivate
gfloat spacing;
gboolean capslock_warning_shown;
gboolean has_ibeam;
CoglPipeline *text_shadow_material;
@@ -215,14 +216,61 @@ 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
st_entry_dispose (GObject *object)
{
StEntry *entry = ST_ENTRY (object);
StEntryPrivate *priv = ST_ENTRY_PRIV (entry);
ClutterKeymap *keymap;
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);
}
@@ -520,9 +568,15 @@ clutter_text_focus_in_cb (ClutterText *text,
ClutterActor *actor)
{
StEntry *entry = ST_ENTRY (actor);
ClutterKeymap *keymap;
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");
clutter_text_set_cursor_visible (text, TRUE);
}
@@ -532,12 +586,29 @@ clutter_text_focus_out_cb (ClutterText *text,
ClutterActor *actor)
{
StEntry *entry = ST_ENTRY (actor);
ClutterKeymap *keymap;
st_widget_remove_style_pseudo_class (ST_WIDGET (actor), "focus");
st_entry_update_hint_visibility (entry);
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
@@ -983,6 +1054,9 @@ st_entry_init (StEntry *entry)
g_signal_connect (priv->entry, "key-focus-out",
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_CALLBACK (clutter_text_button_press_event), entry);

View File

@@ -1,290 +0,0 @@
/* -*- 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;
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);
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;
}

View File

@@ -1,46 +0,0 @@
/* -*- 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__ */

View File

@@ -32,7 +32,7 @@
#define DEFAULT_FADE_OFFSET 68.0f
#include "st-scroll-view-fade-generated.h"
#include "st-scroll-view-fade-generated.c"
struct _StScrollViewFade
{

View File

@@ -1,23 +0,0 @@
# gnome-extensions-tool
gnome-extensions-tool is a command line utility for managing
GNOME Shell extensions. It is usually built as part of gnome-shell,
but can be used as a stand-alone project as well (for example to
create an extension bundle as part of continuous integration).
Bugs should be reported to the GNOME [bug tracking system][bug-tracker].
## Building
Before the project can be built stand-alone, the po directory has
to be populated with translations (from gnome-shell).
To do that, simply run the included script:
```sh
$ ./generate-translations.sh
```
## License
gnome-extensions-tool is distributed under the terms of the GNU General Public
License, version 3 or later. See the [COPYING][license] file for details.
[bug-tracker]: https://gitlab.gnome.org/GNOME/gnome-shell/issues
[license]: COPYING

View File

@@ -1,19 +0,0 @@
#!/usr/bin/bash
cd $(dirname $0)
sed -e '/subprojects\/extensions-tool/!d' \
-e 's:subprojects/extensions-tool/::' ../../po/POTFILES.in > po/POTFILES.in
for l in $(<po/LINGUAS)
do
cp ../../po/$l.po po/$l.po
done
builddir=$(mktemp -d -p.)
meson -Dman=False $builddir
ninja -C $builddir gnome-extensions-tool-pot
ninja -C $builddir gnome-extensions-tool-update-po
rm -rf $builddir

View File

@@ -1,46 +0,0 @@
project('gnome-extensions-tool', 'c',
version: '3.35.1',
meson_version: '>= 0.47.0',
license: 'GPLv2+'
)
gio_req = '>= 2.56.0'
gnome = import('gnome')
i18n = import('i18n')
package_name = get_option('package_name')
prefix = get_option('prefix')
bindir = join_paths(prefix, get_option('bindir'))
datadir = join_paths(prefix, get_option('datadir'))
mandir = join_paths(prefix, get_option('mandir'))
localedir = join_paths(datadir, 'locale')
gio_dep = dependency('gio-2.0', version: gio_req)
gio_unix_dep = dependency('gio-unix-2.0', version: gio_req)
autoar_dep = dependency('gnome-autoar-0')
json_dep = dependency('json-glib-1.0')
cc = meson.get_compiler('c')
bash_completion = dependency('bash-completion', required: false)
subdir('src')
if bash_completion.found()
install_data('completion/bash/gnome-extensions',
install_dir: bash_completion.get_pkgconfig_variable('completionsdir')
)
endif
if get_option('man')
a2x = find_program('a2x')
subdir('man')
endif
if not meson.is_subproject()
subdir('po')
endif

View File

@@ -1,11 +0,0 @@
option('man',
type: 'boolean',
value: true,
description: 'Generate man pages'
)
option('package_name',
type: 'string',
value: 'gnome-extensions-tool',
description: 'The gettext domain name'
)

View File

@@ -1,3 +0,0 @@
*.po
*.pot
POTFILES.in

View File

@@ -1 +0,0 @@
../../../po/LINGUAS

View File

@@ -1 +0,0 @@
i18n.gettext(package_name, preset: 'glib')