Compare commits
16 Commits
3.9.5
...
wip/smartc
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d139adc25f | ||
![]() |
0d151f8d94 | ||
![]() |
e3fdc2858d | ||
![]() |
05dcd8575c | ||
![]() |
214440fde4 | ||
![]() |
e3621e13ac | ||
![]() |
df0aace025 | ||
![]() |
023f4b31d9 | ||
![]() |
16fba7bd5f | ||
![]() |
ebce362c05 | ||
![]() |
c4ca17d127 | ||
![]() |
3455dd1e76 | ||
![]() |
57abfab923 | ||
![]() |
3a13e7484a | ||
![]() |
a04895383a | ||
![]() |
43357a1b69 |
30
NEWS
30
NEWS
@@ -1,33 +1,3 @@
|
|||||||
3.9.5
|
|
||||||
=====
|
|
||||||
* Fix width changes of the calendar popup [Florian; #704200]
|
|
||||||
* Work towards aggregate status menu [Jasper; #702539, #704336, #704368,
|
|
||||||
#704670]
|
|
||||||
* Update design of lock screen notifications [Allan; #702305]
|
|
||||||
* Don't show empty backgroundMenu [Michael; #703868]
|
|
||||||
* Add option to limit app switcher to current workspace [Adel; #703538]
|
|
||||||
* Consolidate design of login screen and unlock dialog [Ray; #702308, #704795]
|
|
||||||
* Respect hasWorkspace property of session mode [Jasper; #698593]
|
|
||||||
* Fix fade of app menu icon in RTL locales [Jasper; #704583]
|
|
||||||
* Destroy notifications when the close button is clicked [Adel; #687016]
|
|
||||||
* Fix clicks on legacy tray icons in the message tray [Florian; #704095]
|
|
||||||
* authPrompt: Fade out message if users start to type [Ray; #704817]
|
|
||||||
* Export timestamps of global shortcuts on DBus [Bastien; #704859]
|
|
||||||
* Fix duplicate search provider results [Jasper; #700283]
|
|
||||||
* Misc bug fixes and cleanups [Lionel, Florian, Emilio, Ray, Jasper; #703859,
|
|
||||||
#703540, #704077, #703997, #704318, #704347, #704265, #704411, #704430,
|
|
||||||
#704347, #704453, #704471, #704542, #704707, #703905, #705037]
|
|
||||||
|
|
||||||
Contributors:
|
|
||||||
Allan Day, Adel Gadllah, Lionel Landwerlin, Florian Müllner, Bastien Nocera,
|
|
||||||
Emilio Pozuelo Monfort, Jasper St. Pierre, Ray Strode, Colin Walters,
|
|
||||||
Michael Wood
|
|
||||||
|
|
||||||
Translations:
|
|
||||||
eternalhui [zh_CN], Victor Ibragimov [tg], Dušan Kazik [sk],
|
|
||||||
Jiro Matsuzawa [ja], Kjartan Maraas [nb], Milo Casagrande [it],
|
|
||||||
Marek Černocký [cs], Daniel Mustieles [es], Benjamin Steinwender [de]
|
|
||||||
|
|
||||||
3.9.4
|
3.9.4
|
||||||
=====
|
=====
|
||||||
* Fix chat entries not being focused when expanded [Jasper; #698778]
|
* Fix chat entries not being focused when expanded [Jasper; #698778]
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
AC_PREREQ(2.63)
|
AC_PREREQ(2.63)
|
||||||
AC_INIT([gnome-shell],[3.9.5],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
AC_INIT([gnome-shell],[3.9.4],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||||
|
|
||||||
AC_CONFIG_HEADERS([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
AC_CONFIG_SRCDIR([src/shell-global.c])
|
AC_CONFIG_SRCDIR([src/shell-global.c])
|
||||||
@@ -63,7 +63,7 @@ AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
|||||||
CLUTTER_MIN_VERSION=1.13.4
|
CLUTTER_MIN_VERSION=1.13.4
|
||||||
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
|
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
|
||||||
GJS_MIN_VERSION=1.35.4
|
GJS_MIN_VERSION=1.35.4
|
||||||
MUTTER_MIN_VERSION=3.9.5
|
MUTTER_MIN_VERSION=3.9.4
|
||||||
GTK_MIN_VERSION=3.7.9
|
GTK_MIN_VERSION=3.7.9
|
||||||
GIO_MIN_VERSION=2.37.0
|
GIO_MIN_VERSION=2.37.0
|
||||||
LIBECAL_MIN_VERSION=3.5.3
|
LIBECAL_MIN_VERSION=3.5.3
|
||||||
|
@@ -34,7 +34,9 @@ nobase_dist_js_DATA = \
|
|||||||
misc/jsParse.js \
|
misc/jsParse.js \
|
||||||
misc/loginManager.js \
|
misc/loginManager.js \
|
||||||
misc/modemManager.js \
|
misc/modemManager.js \
|
||||||
|
misc/objectManager.js \
|
||||||
misc/params.js \
|
misc/params.js \
|
||||||
|
misc/smartcardManager.js \
|
||||||
misc/util.js \
|
misc/util.js \
|
||||||
perf/core.js \
|
perf/core.js \
|
||||||
ui/altTab.js \
|
ui/altTab.js \
|
||||||
|
@@ -24,11 +24,23 @@ const AuthPromptMode = {
|
|||||||
UNLOCK_OR_LOG_IN: 1
|
UNLOCK_OR_LOG_IN: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const AuthPromptStatus = {
|
||||||
|
NOT_VERIFYING: 0,
|
||||||
|
VERIFYING: 1,
|
||||||
|
VERIFICATION_FAILED: 2,
|
||||||
|
VERIFICATION_SUCCEEDED: 3
|
||||||
|
};
|
||||||
|
|
||||||
|
const BeginRequestType = {
|
||||||
|
PROVIDE_USERNAME: 0,
|
||||||
|
DONT_PROVIDE_USERNAME: 1
|
||||||
|
};
|
||||||
|
|
||||||
const AuthPrompt = new Lang.Class({
|
const AuthPrompt = new Lang.Class({
|
||||||
Name: 'AuthPrompt',
|
Name: 'AuthPrompt',
|
||||||
|
|
||||||
_init: function(gdmClient, mode) {
|
_init: function(gdmClient, mode) {
|
||||||
this.verifyingUser = false;
|
this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
|
||||||
|
|
||||||
this._gdmClient = gdmClient;
|
this._gdmClient = gdmClient;
|
||||||
this._mode = mode;
|
this._mode = mode;
|
||||||
@@ -48,6 +60,8 @@ const AuthPrompt = new Lang.Class({
|
|||||||
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
|
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
|
||||||
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._onShowLoginHint));
|
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._onShowLoginHint));
|
||||||
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._onHideLoginHint));
|
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._onHideLoginHint));
|
||||||
|
this._userVerifier.connect('smartcard-status-changed', Lang.bind(this, this._onSmartcardStatusChanged));
|
||||||
|
this.smartcardDetected = this._userVerifier.smartcardDetected;
|
||||||
|
|
||||||
this.connect('next', Lang.bind(this, function() {
|
this.connect('next', Lang.bind(this, function() {
|
||||||
this.updateSensitivity(false);
|
this.updateSensitivity(false);
|
||||||
@@ -123,6 +137,8 @@ const AuthPrompt = new Lang.Class({
|
|||||||
|
|
||||||
_onDestroy: function() {
|
_onDestroy: function() {
|
||||||
this._userVerifier.clear();
|
this._userVerifier.clear();
|
||||||
|
this._userVerifier.disconnectAll();
|
||||||
|
this._userVerifier = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
_initButtons: function() {
|
_initButtons: function() {
|
||||||
@@ -193,11 +209,6 @@ const AuthPrompt = new Lang.Class({
|
|||||||
this.setPasswordChar(passwordChar);
|
this.setPasswordChar(passwordChar);
|
||||||
this.setQuestion(question);
|
this.setQuestion(question);
|
||||||
|
|
||||||
if (this.verifyingUser)
|
|
||||||
this.cancelButton.show();
|
|
||||||
else
|
|
||||||
this.cancelButton.hide();
|
|
||||||
|
|
||||||
if (passwordChar) {
|
if (passwordChar) {
|
||||||
if (this._userVerifier.reauthenticating)
|
if (this._userVerifier.reauthenticating)
|
||||||
this.nextButton.label = _("Unlock");
|
this.nextButton.label = _("Unlock");
|
||||||
@@ -211,8 +222,23 @@ const AuthPrompt = new Lang.Class({
|
|||||||
this.emit('prompted');
|
this.emit('prompted');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onSmartcardStatusChanged: function() {
|
||||||
|
this.smartcardDetected = this._userVerifier.smartcardDetected;
|
||||||
|
|
||||||
|
// Don't reset on smartcard insertion if we're already verifying
|
||||||
|
// and the smartcard is the main service
|
||||||
|
if (this._userVerifier.serviceIsDefault(GdmUtil.SMARTCARD_SERVICE_NAME) &&
|
||||||
|
this.verificationStatus == AuthPromptStatus.VERIFYING &&
|
||||||
|
this.smartcardDetected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED)
|
||||||
|
this.reset();
|
||||||
|
},
|
||||||
|
|
||||||
_onShowMessage: function(userVerifier, message, styleClass) {
|
_onShowMessage: function(userVerifier, message, styleClass) {
|
||||||
this.setMessage(message, styleClass);
|
this.setMessage(message, styleClass);
|
||||||
|
this.emit('prompted');
|
||||||
},
|
},
|
||||||
|
|
||||||
_onVerificationFailed: function() {
|
_onVerificationFailed: function() {
|
||||||
@@ -220,16 +246,18 @@ const AuthPrompt = new Lang.Class({
|
|||||||
|
|
||||||
this.updateSensitivity(true);
|
this.updateSensitivity(true);
|
||||||
this.setActorInDefaultButtonWell(null);
|
this.setActorInDefaultButtonWell(null);
|
||||||
this.userVerified = false;
|
this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onVerificationComplete: function() {
|
_onVerificationComplete: function() {
|
||||||
this.userVerified = true;
|
this.verificationStatus = AuthPromptStatus.VERIFICATION_SUCCEEDED;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onReset: function() {
|
_onReset: function() {
|
||||||
if (!this.userVerified)
|
if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) {
|
||||||
|
this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
|
||||||
this.reset();
|
this.reset();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onShowLoginHint: function(verifier, message) {
|
_onShowLoginHint: function(verifier, message) {
|
||||||
@@ -401,8 +429,12 @@ const AuthPrompt = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
reset: function() {
|
reset: function() {
|
||||||
this.verifyingUser = false;
|
let oldStatus = this.verificationStatus;
|
||||||
this.userVerified = false;
|
this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
|
||||||
|
|
||||||
|
if (oldStatus == AuthPromptStatus.VERIFYING)
|
||||||
|
this._userVerifier.cancel();
|
||||||
|
|
||||||
this._queryingService = null;
|
this._queryingService = null;
|
||||||
this.clear();
|
this.clear();
|
||||||
this._message.opacity = 0;
|
this._message.opacity = 0;
|
||||||
@@ -410,7 +442,25 @@ const AuthPrompt = new Lang.Class({
|
|||||||
this.stopSpinning();
|
this.stopSpinning();
|
||||||
this.setHint(null);
|
this.setHint(null);
|
||||||
|
|
||||||
this.emit('reset');
|
if (oldStatus == AuthPromptStatus.VERIFICATION_FAILED)
|
||||||
|
this.emit('failed');
|
||||||
|
|
||||||
|
let beginRequestType;
|
||||||
|
|
||||||
|
if (this._mode == AuthPromptMode.UNLOCK_ONLY) {
|
||||||
|
// The user is constant at the unlock screen
|
||||||
|
beginRequestType = BeginRequestType.PROVIDE_USERNAME;
|
||||||
|
} else if (this.smartcardDetected &&
|
||||||
|
this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME)) {
|
||||||
|
// We don't need to know the username if the user preempted the login screen
|
||||||
|
// with a smartcard.
|
||||||
|
beginRequestType = BeginRequestType.DONT_PROVIDE_USERNAME;
|
||||||
|
} else {
|
||||||
|
// In all other cases, we should get the username up front.
|
||||||
|
beginRequestType = BeginRequestType.PROVIDE_USERNAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emit('reset', beginRequestType);
|
||||||
},
|
},
|
||||||
|
|
||||||
addCharacter: function(unichar) {
|
addCharacter: function(unichar) {
|
||||||
@@ -432,7 +482,7 @@ const AuthPrompt = new Lang.Class({
|
|||||||
hold = new Batch.Hold();
|
hold = new Batch.Hold();
|
||||||
|
|
||||||
this._userVerifier.begin(params.userName, hold);
|
this._userVerifier.begin(params.userName, hold);
|
||||||
this.verifyingUser = true;
|
this.verificationStatus = AuthPromptStatus.VERIFYING;
|
||||||
},
|
},
|
||||||
|
|
||||||
finish: function(onComplete) {
|
finish: function(onComplete) {
|
||||||
@@ -449,10 +499,8 @@ const AuthPrompt = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
cancel: function() {
|
cancel: function() {
|
||||||
if (this.verifyingUser)
|
|
||||||
this._userVerifier.cancel();
|
|
||||||
|
|
||||||
this.reset();
|
this.reset();
|
||||||
|
this.emit('cancelled');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(AuthPrompt.prototype);
|
Signals.addSignalMethods(AuthPrompt.prototype);
|
||||||
|
@@ -451,7 +451,7 @@ const LoginDialog = new Lang.Class({
|
|||||||
|
|
||||||
this._authPrompt = new AuthPrompt.AuthPrompt(gdmClient, AuthPrompt.AuthPromptMode.UNLOCK_OR_LOG_IN);
|
this._authPrompt = new AuthPrompt.AuthPrompt(gdmClient, AuthPrompt.AuthPromptMode.UNLOCK_OR_LOG_IN);
|
||||||
this._authPrompt.connect('prompted', Lang.bind(this, this._onPrompted));
|
this._authPrompt.connect('prompted', Lang.bind(this, this._onPrompted));
|
||||||
this._authPrompt.connect('reset', Lang.bind(this, this._reset));
|
this._authPrompt.connect('reset', Lang.bind(this, this._onReset));
|
||||||
this._authPrompt.hide();
|
this._authPrompt.hide();
|
||||||
|
|
||||||
this._authPrompt.actor.add_constraint(new Clutter.AlignConstraint({ source: this.actor,
|
this._authPrompt.actor.add_constraint(new Clutter.AlignConstraint({ source: this.actor,
|
||||||
@@ -475,7 +475,12 @@ const LoginDialog = new Lang.Class({
|
|||||||
x_align: St.Align.START,
|
x_align: St.Align.START,
|
||||||
x_fill: true });
|
x_fill: true });
|
||||||
|
|
||||||
this._notListedButton.connect('clicked', Lang.bind(this, this._hideUserListAndLogIn));
|
this._notListedButton.connect('clicked',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
this._authPrompt.cancelButton.show();
|
||||||
|
this._hideUserListAskForUsernameAndBeginVerification();
|
||||||
|
}));
|
||||||
|
|
||||||
this._notListedButton.hide();
|
this._notListedButton.hide();
|
||||||
|
|
||||||
this._userSelectionBox.add(this._notListedButton,
|
this._userSelectionBox.add(this._notListedButton,
|
||||||
@@ -529,8 +534,8 @@ const LoginDialog = new Lang.Class({
|
|||||||
if (disableUserList != this._disableUserList) {
|
if (disableUserList != this._disableUserList) {
|
||||||
this._disableUserList = disableUserList;
|
this._disableUserList = disableUserList;
|
||||||
|
|
||||||
if (!this._authPrompt.verifyingUser)
|
if (this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
|
||||||
this._reset();
|
this._authPrompt.reset();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -569,24 +574,25 @@ const LoginDialog = new Lang.Class({
|
|||||||
|
|
||||||
if (this._shouldShowSessionMenuButton())
|
if (this._shouldShowSessionMenuButton())
|
||||||
this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton.actor);
|
this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton.actor);
|
||||||
|
|
||||||
this._authPrompt.cancelButton.show();
|
|
||||||
|
|
||||||
this._showPrompt();
|
this._showPrompt();
|
||||||
},
|
},
|
||||||
|
|
||||||
_reset: function() {
|
_onReset: function(authPrompt, beginRequest) {
|
||||||
if (this._authPrompt.verifyingUser)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._sessionMenuButton.updateSensitivity(true);
|
this._sessionMenuButton.updateSensitivity(true);
|
||||||
|
|
||||||
this._user = null;
|
this._user = null;
|
||||||
|
|
||||||
if (this._disableUserList)
|
if (beginRequest == AuthPrompt.BeginRequestType.PROVIDE_USERNAME) {
|
||||||
this._hideUserListAndLogIn();
|
if (this._disableUserList) {
|
||||||
else
|
this._authPrompt.cancelButton.hide();
|
||||||
this._showUserList();
|
this._hideUserListAskForUsernameAndBeginVerification();
|
||||||
|
} else {
|
||||||
|
this._showUserList();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._authPrompt.cancelButton.hide();
|
||||||
|
this._hideUserListAndBeginVerification();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDefaultSessionChanged: function(client, sessionId) {
|
_onDefaultSessionChanged: function(client, sessionId) {
|
||||||
@@ -630,7 +636,7 @@ const LoginDialog = new Lang.Class({
|
|||||||
this._authPrompt.setHint(_("(e.g., user or %s)").format(hint));
|
this._authPrompt.setHint(_("(e.g., user or %s)").format(hint));
|
||||||
},
|
},
|
||||||
|
|
||||||
_askForUsernameAndLogIn: function() {
|
_askForUsernameAndBeginVerification: function() {
|
||||||
this._authPrompt.setPasswordChar('');
|
this._authPrompt.setPasswordChar('');
|
||||||
this._authPrompt.setQuestion(_("Username: "));
|
this._authPrompt.setQuestion(_("Username: "));
|
||||||
|
|
||||||
@@ -645,13 +651,13 @@ const LoginDialog = new Lang.Class({
|
|||||||
this._authPrompt.updateSensitivity(false);
|
this._authPrompt.updateSensitivity(false);
|
||||||
let answer = this._authPrompt.getAnswer();
|
let answer = this._authPrompt.getAnswer();
|
||||||
this._authPrompt.clear();
|
this._authPrompt.clear();
|
||||||
|
this._authPrompt.cancelButton.show();
|
||||||
this._authPrompt.startSpinning();
|
this._authPrompt.startSpinning();
|
||||||
this._authPrompt.begin({ userName: answer });
|
this._authPrompt.begin({ userName: answer });
|
||||||
|
|
||||||
realmManager.disconnect(realmSignalId)
|
realmManager.disconnect(realmSignalId)
|
||||||
realmManager.release();
|
realmManager.release();
|
||||||
}));
|
}));
|
||||||
this._authPrompt.cancelButton.hide();
|
|
||||||
this._showPrompt();
|
this._showPrompt();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -813,16 +819,26 @@ const LoginDialog = new Lang.Class({
|
|||||||
this._userSelectionBox.visible = expanded;
|
this._userSelectionBox.visible = expanded;
|
||||||
},
|
},
|
||||||
|
|
||||||
_hideUserListAndLogIn: function() {
|
_hideUserList: function() {
|
||||||
this._setUserListExpanded(false);
|
this._setUserListExpanded(false);
|
||||||
if (this._userSelectionBox.visible)
|
if (this._userSelectionBox.visible)
|
||||||
GdmUtil.cloneAndFadeOutActor(this._userSelectionBox);
|
GdmUtil.cloneAndFadeOutActor(this._userSelectionBox);
|
||||||
this._askForUsernameAndLogIn();
|
},
|
||||||
|
|
||||||
|
_hideUserListAskForUsernameAndBeginVerification: function() {
|
||||||
|
this._hideUserList();
|
||||||
|
this._askForUsernameAndBeginVerification();
|
||||||
|
},
|
||||||
|
|
||||||
|
_hideUserListAndBeginVerification: function() {
|
||||||
|
this._hideUserList();
|
||||||
|
this._authPrompt.begin();
|
||||||
},
|
},
|
||||||
|
|
||||||
_showUserList: function() {
|
_showUserList: function() {
|
||||||
this._authPrompt.hide();
|
this._authPrompt.hide();
|
||||||
this._sessionMenuButton.close();
|
this._sessionMenuButton.close();
|
||||||
|
this._authPrompt.cancelButton.show();
|
||||||
this._setUserListExpanded(true);
|
this._setUserListExpanded(true);
|
||||||
this._notListedButton.show();
|
this._notListedButton.show();
|
||||||
this._userList.actor.grab_key_focus();
|
this._userList.actor.grab_key_focus();
|
||||||
|
108
js/gdm/util.js
108
js/gdm/util.js
@@ -13,15 +13,19 @@ const Fprint = imports.gdm.fingerprint;
|
|||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const ShellEntry = imports.ui.shellEntry;
|
const ShellEntry = imports.ui.shellEntry;
|
||||||
|
const SmartcardManager = imports.misc.smartcardManager;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
const PASSWORD_SERVICE_NAME = 'gdm-password';
|
const PASSWORD_SERVICE_NAME = 'gdm-password';
|
||||||
const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
const FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
||||||
|
const SMARTCARD_SERVICE_NAME = 'gdm-smartcard';
|
||||||
const FADE_ANIMATION_TIME = 0.16;
|
const FADE_ANIMATION_TIME = 0.16;
|
||||||
const CLONE_FADE_ANIMATION_TIME = 0.25;
|
const CLONE_FADE_ANIMATION_TIME = 0.25;
|
||||||
|
|
||||||
const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
|
const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
|
||||||
|
const PASSWORD_AUTHENTICATION_KEY = 'enable-password-authentication';
|
||||||
const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
|
const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
|
||||||
|
const SMARTCARD_AUTHENTICATION_KEY = 'enable-smartcard-authentication';
|
||||||
const BANNER_MESSAGE_KEY = 'banner-message-enable';
|
const BANNER_MESSAGE_KEY = 'banner-message-enable';
|
||||||
const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text';
|
const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text';
|
||||||
const ALLOWED_FAILURES_KEY = 'allowed-failures';
|
const ALLOWED_FAILURES_KEY = 'allowed-failures';
|
||||||
@@ -116,8 +120,30 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
this._client = client;
|
this._client = client;
|
||||||
|
|
||||||
this._settings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA });
|
this._settings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA });
|
||||||
|
this._settings.connect('changed',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
this._updateDefaultService();
|
||||||
|
}));
|
||||||
|
this._updateDefaultService();
|
||||||
|
|
||||||
this._fprintManager = new Fprint.FprintManager();
|
this._fprintManager = new Fprint.FprintManager();
|
||||||
|
this._smartcardManager = SmartcardManager.getSmartcardManager();
|
||||||
|
|
||||||
|
// We check for smartcards right away, since an inserted smartcard
|
||||||
|
// at startup should result in immediately initiating authentication.
|
||||||
|
// This is different than fingeprint readers, where we only check them
|
||||||
|
// after a user has been picked.
|
||||||
|
this._checkForSmartcard();
|
||||||
|
|
||||||
|
this._smartcardManager.connect('smartcard-inserted',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
this._checkForSmartcard();
|
||||||
|
}));
|
||||||
|
this._smartcardManager.connect('smartcard-removed',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
this._checkForSmartcard();
|
||||||
|
}));
|
||||||
|
|
||||||
this._messageQueue = [];
|
this._messageQueue = [];
|
||||||
this._messageQueueTimeoutId = 0;
|
this._messageQueueTimeoutId = 0;
|
||||||
this.hasPendingMessages = false;
|
this.hasPendingMessages = false;
|
||||||
@@ -148,8 +174,10 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
if (this._cancellable)
|
if (this._cancellable)
|
||||||
this._cancellable.cancel();
|
this._cancellable.cancel();
|
||||||
|
|
||||||
if (this._userVerifier)
|
if (this._userVerifier) {
|
||||||
this._userVerifier.call_cancel_sync(null);
|
this._userVerifier.call_cancel_sync(null);
|
||||||
|
this.clear();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
clear: function() {
|
clear: function() {
|
||||||
@@ -244,6 +272,28 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_checkForSmartcard: function() {
|
||||||
|
let smartcardDetected;
|
||||||
|
|
||||||
|
if (!this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY))
|
||||||
|
smartcardDetected = false;
|
||||||
|
else if (this.reauthenticating)
|
||||||
|
smartcardDetected = this._smartcardManager.hasInsertedLoginToken();
|
||||||
|
else
|
||||||
|
smartcardDetected = this._smartcardManager.hasInsertedTokens();
|
||||||
|
|
||||||
|
if (smartcardDetected != this.smartcardDetected) {
|
||||||
|
this.smartcardDetected = smartcardDetected;
|
||||||
|
|
||||||
|
if (this.smartcardDetected)
|
||||||
|
this._preemptingService = SMARTCARD_SERVICE_NAME;
|
||||||
|
else if (this._preemptingService == SMARTCARD_SERVICE_NAME)
|
||||||
|
this._preemptingService = null;
|
||||||
|
|
||||||
|
this.emit('smartcard-status-changed');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_reportInitError: function(where, error) {
|
_reportInitError: function(where, error) {
|
||||||
logError(error, where);
|
logError(error, where);
|
||||||
this._hold.release();
|
this._hold.release();
|
||||||
@@ -300,11 +350,35 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
|
this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_getForegroundService: function() {
|
||||||
|
if (this._preemptingService)
|
||||||
|
return this._preemptingService;
|
||||||
|
|
||||||
|
return this._defaultService;
|
||||||
|
},
|
||||||
|
|
||||||
|
serviceIsForeground: function(serviceName) {
|
||||||
|
return serviceName == this._getForegroundService();
|
||||||
|
},
|
||||||
|
|
||||||
|
serviceIsDefault: function(serviceName) {
|
||||||
|
return serviceName == this._defaultService;
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateDefaultService: function() {
|
||||||
|
if (this._settings.get_boolean(PASSWORD_AUTHENTICATION_KEY))
|
||||||
|
this._defaultService = PASSWORD_SERVICE_NAME;
|
||||||
|
else if (this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY))
|
||||||
|
this._defaultService = SMARTCARD_SERVICE_NAME;
|
||||||
|
else if (this._settings.get_boolean(FINGERPRINT_AUTHENTICATION_KEY))
|
||||||
|
this._defaultService = FINGERPRINT_SERVICE_NAME;
|
||||||
|
},
|
||||||
|
|
||||||
_beginVerification: function() {
|
_beginVerification: function() {
|
||||||
this._hold.acquire();
|
this._hold.acquire();
|
||||||
|
|
||||||
if (this._userName) {
|
if (this._userName) {
|
||||||
this._userVerifier.call_begin_verification_for_user(PASSWORD_SERVICE_NAME,
|
this._userVerifier.call_begin_verification_for_user(this._getForegroundService(),
|
||||||
this._userName,
|
this._userName,
|
||||||
this._cancellable,
|
this._cancellable,
|
||||||
Lang.bind(this, function(obj, result) {
|
Lang.bind(this, function(obj, result) {
|
||||||
@@ -320,7 +394,7 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
this._hold.release();
|
this._hold.release();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (this._haveFingerprintReader) {
|
if (this._haveFingerprintReader && !this.serviceIsForeground(FINGERPRINT_SERVICE_NAME)) {
|
||||||
this._hold.acquire();
|
this._hold.acquire();
|
||||||
|
|
||||||
this._userVerifier.call_begin_verification_for_user(FINGERPRINT_SERVICE_NAME,
|
this._userVerifier.call_begin_verification_for_user(FINGERPRINT_SERVICE_NAME,
|
||||||
@@ -340,7 +414,7 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this._userVerifier.call_begin_verification(PASSWORD_SERVICE_NAME,
|
this._userVerifier.call_begin_verification(this._getForegroundService(),
|
||||||
this._cancellable,
|
this._cancellable,
|
||||||
Lang.bind(this, function(obj, result) {
|
Lang.bind(this, function(obj, result) {
|
||||||
try {
|
try {
|
||||||
@@ -358,39 +432,36 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onInfo: function(client, serviceName, info) {
|
_onInfo: function(client, serviceName, info) {
|
||||||
// We don't display fingerprint messages, because they
|
if (this.serviceIsForeground(serviceName)) {
|
||||||
// have words like UPEK in them. Instead we use the messages
|
this._queueMessage(info, 'login-dialog-message-info');
|
||||||
// as a cue to display our own message.
|
} else if (serviceName == FINGERPRINT_SERVICE_NAME &&
|
||||||
if (serviceName == FINGERPRINT_SERVICE_NAME &&
|
|
||||||
this._haveFingerprintReader) {
|
this._haveFingerprintReader) {
|
||||||
|
// We don't show fingeprint messages directly since it's
|
||||||
|
// not the main auth service. Instead we use the messages
|
||||||
|
// as a cue to display our own message.
|
||||||
|
|
||||||
// Translators: this message is shown below the password entry field
|
// Translators: this message is shown below the password entry field
|
||||||
// to indicate the user can swipe their finger instead
|
// to indicate the user can swipe their finger instead
|
||||||
this.emit('show-login-hint', _("(or swipe finger)"));
|
this.emit('show-login-hint', _("(or swipe finger)"));
|
||||||
} else if (serviceName == PASSWORD_SERVICE_NAME) {
|
|
||||||
this._queueMessage(info, 'login-dialog-message-info');
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onProblem: function(client, serviceName, problem) {
|
_onProblem: function(client, serviceName, problem) {
|
||||||
// we don't want to show auth failed messages to
|
if (!this.serviceIsForeground(serviceName))
|
||||||
// users who haven't enrolled their fingerprint.
|
|
||||||
if (serviceName != PASSWORD_SERVICE_NAME)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._queueMessage(problem, 'login-dialog-message-warning');
|
this._queueMessage(problem, 'login-dialog-message-warning');
|
||||||
},
|
},
|
||||||
|
|
||||||
_onInfoQuery: function(client, serviceName, question) {
|
_onInfoQuery: function(client, serviceName, question) {
|
||||||
// We only expect questions to come from the main auth service
|
if (!this.serviceIsForeground(serviceName))
|
||||||
if (serviceName != PASSWORD_SERVICE_NAME)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.emit('ask-question', serviceName, question, '');
|
this.emit('ask-question', serviceName, question, '');
|
||||||
},
|
},
|
||||||
|
|
||||||
_onSecretInfoQuery: function(client, serviceName, secretQuestion) {
|
_onSecretInfoQuery: function(client, serviceName, secretQuestion) {
|
||||||
// We only expect secret requests to come from the main auth service
|
if (!this.serviceIsForeground(serviceName))
|
||||||
if (serviceName != PASSWORD_SERVICE_NAME)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.emit('ask-question', serviceName, secretQuestion, '\u25cf');
|
this.emit('ask-question', serviceName, secretQuestion, '\u25cf');
|
||||||
@@ -399,6 +470,7 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
_onReset: function() {
|
_onReset: function() {
|
||||||
// Clear previous attempts to authenticate
|
// Clear previous attempts to authenticate
|
||||||
this._failCounter = 0;
|
this._failCounter = 0;
|
||||||
|
this._updateDefaultService();
|
||||||
|
|
||||||
this.emit('reset');
|
this.emit('reset');
|
||||||
},
|
},
|
||||||
@@ -455,7 +527,7 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
// if the password service fails, then cancel everything.
|
// if the password service fails, then cancel everything.
|
||||||
// But if, e.g., fingerprint fails, still give
|
// But if, e.g., fingerprint fails, still give
|
||||||
// password authentication a chance to succeed
|
// password authentication a chance to succeed
|
||||||
if (serviceName == PASSWORD_SERVICE_NAME) {
|
if (this.serviceIsForeground(serviceName)) {
|
||||||
this._verificationFailed(true);
|
this._verificationFailed(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
275
js/misc/objectManager.js
Normal file
275
js/misc/objectManager.js
Normal file
@@ -0,0 +1,275 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Params = imports.misc.params;
|
||||||
|
const Signals = imports.signals;
|
||||||
|
|
||||||
|
// Specified in the D-Bus specification here:
|
||||||
|
// http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager
|
||||||
|
const ObjectManagerIface = <interface name="org.freedesktop.DBus.ObjectManager">
|
||||||
|
<method name="GetManagedObjects">
|
||||||
|
<arg name="objects" type="a{oa{sa{sv}}}" direction="out"/>
|
||||||
|
</method>
|
||||||
|
<signal name="InterfacesAdded">
|
||||||
|
<arg name="objectPath" type="o"/>
|
||||||
|
<arg name="interfaces" type="a{sa{sv}}" />
|
||||||
|
</signal>
|
||||||
|
<signal name="InterfacesRemoved">
|
||||||
|
<arg name="objectPath" type="o"/>
|
||||||
|
<arg name="interfaces" type="as" />
|
||||||
|
</signal>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
const ObjectManagerInfo = Gio.DBusInterfaceInfo.new_for_xml(ObjectManagerIface);
|
||||||
|
|
||||||
|
const ObjectManager = new Lang.Class({
|
||||||
|
Name: 'ObjectManager',
|
||||||
|
_init: function(params) {
|
||||||
|
params = Params.parse(params, { connection: null,
|
||||||
|
name: null,
|
||||||
|
objectPath: null,
|
||||||
|
knownInterfaces: null,
|
||||||
|
cancellable: null,
|
||||||
|
onLoaded: null });
|
||||||
|
|
||||||
|
this._connection = params.connection;
|
||||||
|
this._serviceName = params.name;
|
||||||
|
this._managerPath = params.objectPath;
|
||||||
|
this._cancellable = params.cancellable;
|
||||||
|
|
||||||
|
this._managerProxy = new Gio.DBusProxy({ g_connection: this._connection,
|
||||||
|
g_interface_name: ObjectManagerInfo.name,
|
||||||
|
g_interface_info: ObjectManagerInfo,
|
||||||
|
g_name: this._serviceName,
|
||||||
|
g_object_path: this._managerPath,
|
||||||
|
g_flags: Gio.DBusProxyFlags.NONE });
|
||||||
|
|
||||||
|
this._interfaceInfos = {};
|
||||||
|
this._objects = {};
|
||||||
|
this._interfaces = {};
|
||||||
|
this._pendingProxies = [];
|
||||||
|
this._onLoaded = params.onLoaded;
|
||||||
|
|
||||||
|
if (params.knownInterfaces)
|
||||||
|
this._registerInterfaces(params.knownInterfaces);
|
||||||
|
|
||||||
|
this._managerProxy.init_async(GLib.PRIORITY_DEFAULT,
|
||||||
|
this._cancellable,
|
||||||
|
Lang.bind(this, this._onManagerProxyLoaded));
|
||||||
|
},
|
||||||
|
|
||||||
|
_addInterface: function(objectPath, interfaceName, onFinished) {
|
||||||
|
let info = this._interfaceInfos[interfaceName];
|
||||||
|
|
||||||
|
if (!info)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let proxy = new Gio.DBusProxy({ g_connection: this._connection,
|
||||||
|
g_name: this._serviceName,
|
||||||
|
g_object_path: objectPath,
|
||||||
|
g_interface_name: interfaceName,
|
||||||
|
g_interface_info: info,
|
||||||
|
g_flags: Gio.DBusProxyFlags.NONE });
|
||||||
|
|
||||||
|
this._pendingProxies.push(proxy);
|
||||||
|
|
||||||
|
proxy.init_async(GLib.PRIORITY_DEFAULT,
|
||||||
|
this._cancellable,
|
||||||
|
Lang.bind(this, function(initable, result) {
|
||||||
|
let index = this._pendingProxies.indexOf(proxy);
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
this._pendingProxies.splice(index, 1);
|
||||||
|
|
||||||
|
let error = null;
|
||||||
|
try {
|
||||||
|
initable.init_finish(result);
|
||||||
|
} catch(e) {
|
||||||
|
logError(e, 'could not initialize proxy for interface ' + interfaceName);
|
||||||
|
|
||||||
|
if (onFinished)
|
||||||
|
onFinished();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let isNewObject;
|
||||||
|
|
||||||
|
if (!this._objects[objectPath]) {
|
||||||
|
this._objects[objectPath] = {};
|
||||||
|
isNewObject = true;
|
||||||
|
} else {
|
||||||
|
isNewObject = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._objects[objectPath][interfaceName] = proxy;
|
||||||
|
|
||||||
|
if (!this._interfaces[interfaceName])
|
||||||
|
this._interfaces[interfaceName] = [];
|
||||||
|
|
||||||
|
this._interfaces[interfaceName].push(proxy);
|
||||||
|
|
||||||
|
if (isNewObject)
|
||||||
|
this.emit('object-added', objectPath);
|
||||||
|
|
||||||
|
this.emit('interface-added', interfaceName, proxy);
|
||||||
|
|
||||||
|
if (onFinished)
|
||||||
|
onFinished();
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_removeInterface: function(objectPath, interfaceName) {
|
||||||
|
if (!this._objects[objectPath])
|
||||||
|
return;
|
||||||
|
|
||||||
|
let proxy = this._objects[objectPath][interfaceName];
|
||||||
|
|
||||||
|
if (this._interfaces[interfaceName]) {
|
||||||
|
let index = this._interfaces[interfaceName].indexOf(proxy);
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
this._interfaces[interfaceName].splice(index, 1);
|
||||||
|
|
||||||
|
if (this._interfaces[interfaceName].length == 0)
|
||||||
|
delete this._interfaces[interfaceName];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emit('interface-removed', interfaceName, proxy);
|
||||||
|
|
||||||
|
this._objects[objectPath][interfaceName] = null;
|
||||||
|
|
||||||
|
if (Object.keys(this._objects[objectPath]).length == 0) {
|
||||||
|
delete this._objects[objectPath];
|
||||||
|
this.emit('object-removed', objectPath);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_onManagerProxyLoaded: function(initable, result) {
|
||||||
|
let error = null;
|
||||||
|
try {
|
||||||
|
initable.init_finish(result);
|
||||||
|
} catch(e) {
|
||||||
|
logError(e, 'could not initialize object manager for object ' + params.name);
|
||||||
|
|
||||||
|
if (this._onLoaded)
|
||||||
|
this._onLoaded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._managerProxy.connectSignal('InterfacesAdded',
|
||||||
|
Lang.bind(this, function(objectManager, sender, [objectPath, interfaces]) {
|
||||||
|
let interfaceNames = Object.keys(interfaces);
|
||||||
|
for (let i = 0; i < interfaceNames.length; i++)
|
||||||
|
this._addInterface(objectPath, interfaceNames[i]);
|
||||||
|
}));
|
||||||
|
this._managerProxy.connectSignal('InterfacesRemoved',
|
||||||
|
Lang.bind(this, function(objectManager, sender, [objectPath, interfaceNames]) {
|
||||||
|
for (let i = 0; i < interfaceNames.length; i++)
|
||||||
|
this._removeInterface(objectPath, interfaceNames[i]);
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
this._managerProxy.GetManagedObjectsRemote(Lang.bind(this, function(result, error) {
|
||||||
|
if (!result) {
|
||||||
|
if (error) {
|
||||||
|
logError(error, 'could not get remote objects for service ' + this._serviceName + ' path ' + this._managerPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._onLoaded)
|
||||||
|
this._onLoaded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let [objects] = result;
|
||||||
|
|
||||||
|
if (Object.keys(this._interfaceInfos).length == 0) {
|
||||||
|
if (this._onLoaded)
|
||||||
|
this._onLoaded();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let numLoadInhibitors = 0;
|
||||||
|
|
||||||
|
// First inhibitor is to prevent onLoaded from getting
|
||||||
|
// called until all interfaces have started being added.
|
||||||
|
// Subsequent inhibitors are to prevent onLoaded from getting
|
||||||
|
// called until all interfaces finish getting added.
|
||||||
|
numLoadInhibitors++;
|
||||||
|
let objectPaths = Object.keys(objects);
|
||||||
|
for (let i = 0; i < objectPaths.length; i++) {
|
||||||
|
let objectPath = objectPaths[i];
|
||||||
|
let object = objects[objectPath];
|
||||||
|
|
||||||
|
let interfaceNames = Object.keys(object);
|
||||||
|
for (let j = 0; j < interfaceNames.length; j++) {
|
||||||
|
let interfaceName = interfaceNames[j];
|
||||||
|
|
||||||
|
numLoadInhibitors++;
|
||||||
|
this._addInterface(objectPath,
|
||||||
|
interfaceName,
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
numLoadInhibitors--;
|
||||||
|
|
||||||
|
if (numLoadInhibitors == 0) {
|
||||||
|
if (this._onLoaded)
|
||||||
|
this._onLoaded();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
numLoadInhibitors--;
|
||||||
|
|
||||||
|
if (numLoadInhibitors == 0) {
|
||||||
|
if (this._onLoaded)
|
||||||
|
this._onLoaded();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_registerInterfaces: function(interfaces) {
|
||||||
|
for (let i = 0; i < interfaces.length; i++) {
|
||||||
|
let info = Gio.DBusInterfaceInfo.new_for_xml(interfaces[i]);
|
||||||
|
|
||||||
|
this._interfaceInfos[info.name] = info;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getProxy: function(objectPath, interfaceName) {
|
||||||
|
let object = this._objects[objectPath];
|
||||||
|
|
||||||
|
if (!object)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return object[interfaceName];
|
||||||
|
},
|
||||||
|
|
||||||
|
getProxiesForInterface: function(interfaceName) {
|
||||||
|
let proxyList = this._interfaces[interfaceName];
|
||||||
|
|
||||||
|
if (!proxyList)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
return proxyList;
|
||||||
|
},
|
||||||
|
|
||||||
|
getAllProxies: function() {
|
||||||
|
let proxies = [];
|
||||||
|
|
||||||
|
let objectPaths = Object.keys(this._objects);
|
||||||
|
for (let i = 0; i < objectPaths.length; i++) {
|
||||||
|
let object = this._objects[objectPaths];
|
||||||
|
|
||||||
|
let interfaceNames = Object.keys(object);
|
||||||
|
for (let j = 0; i < interfaceNames.length; i++) {
|
||||||
|
let interfaceName = interfaceNames[i];
|
||||||
|
if (object[interfaceName])
|
||||||
|
proxies.push(object(interfaceName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return proxies;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Signals.addSignalMethods(ObjectManager.prototype);
|
142
js/misc/smartcardManager.js
Normal file
142
js/misc/smartcardManager.js
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
|
const Signals = imports.signals;
|
||||||
|
|
||||||
|
const ObjectManager = imports.misc.objectManager;
|
||||||
|
|
||||||
|
const _SMARTCARD_SERVICE_DBUS_NAME = "org.gnome.SettingsDaemon.Smartcard";
|
||||||
|
|
||||||
|
const SmartcardManagerIface = <interface name="org.gnome.SettingsDaemon.Smartcard.Manager">
|
||||||
|
<method name="GetLoginToken">
|
||||||
|
<arg name="token" type="o" direction="out"/>
|
||||||
|
</method>
|
||||||
|
<method name="GetInsertedTokens">
|
||||||
|
<arg name="tokens" type="ao" direction="out"/>
|
||||||
|
</method>
|
||||||
|
</interface>;
|
||||||
|
|
||||||
|
const SmartcardTokenIface = <interface name="org.gnome.SettingsDaemon.Smartcard.Token">
|
||||||
|
<property name="Name" type="s" access="read"/>
|
||||||
|
<property name="Driver" type="o" access="read"/>
|
||||||
|
<property name="IsInserted" type="b" access="read"/>
|
||||||
|
<property name="UsedToLogin" type="b" access="read"/>
|
||||||
|
</interface>;
|
||||||
|
|
||||||
|
const SmartcardDriverIface = <interface name="org.gnome.SettingsDaemon.Smartcard.Driver">
|
||||||
|
<property name="Library" type="s" access="read"/>
|
||||||
|
<property name="Description" type="s" access="read"/>
|
||||||
|
</interface>;
|
||||||
|
|
||||||
|
let _smartcardManager = null;
|
||||||
|
|
||||||
|
function getSmartcardManager() {
|
||||||
|
if (_smartcardManager == null)
|
||||||
|
_smartcardManager = new SmartcardManager();
|
||||||
|
|
||||||
|
return _smartcardManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SmartcardManager = new Lang.Class({
|
||||||
|
Name: 'SmartcardManager',
|
||||||
|
_init: function() {
|
||||||
|
this._objectManager = new ObjectManager.ObjectManager({ connection: Gio.DBus.session,
|
||||||
|
name: _SMARTCARD_SERVICE_DBUS_NAME,
|
||||||
|
objectPath: '/org/gnome/SettingsDaemon/Smartcard',
|
||||||
|
knownInterfaces: [ SmartcardManagerIface,
|
||||||
|
SmartcardTokenIface,
|
||||||
|
SmartcardDriverIface ],
|
||||||
|
onLoaded: Lang.bind(this, this._onLoaded) });
|
||||||
|
this._insertedTokens = {};
|
||||||
|
this._removedTokens = {};
|
||||||
|
this._loginToken = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onLoaded: function() {
|
||||||
|
let tokens = this._objectManager.getProxiesForInterface('org.gnome.SettingsDaemon.Smartcard.Token');
|
||||||
|
|
||||||
|
for (let i = 0; i < tokens.length; i++)
|
||||||
|
this._addToken(tokens[i]);
|
||||||
|
|
||||||
|
this._objectManager.connect('interface-added', Lang.bind(this, function(objectManager, interfaceName, proxy) {
|
||||||
|
if (interfaceName == 'org.gnome.SettingsDaemon.Smartcard.Token')
|
||||||
|
this._addToken(proxy);
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._objectManager.connect('interface-removed', Lang.bind(this, function(objectManager, interfaceName, proxy) {
|
||||||
|
if (interfaceName == 'org.gnome.SettingsDaemon.Smartcard.Token')
|
||||||
|
this._removeToken(proxy);
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateToken: function(token) {
|
||||||
|
let objectPath = token.get_object_path();
|
||||||
|
|
||||||
|
delete this._insertedTokens[objectPath];
|
||||||
|
delete this._removedTokens[objectPath];
|
||||||
|
|
||||||
|
if (token.IsInserted)
|
||||||
|
this._insertedTokens[objectPath] = token;
|
||||||
|
else
|
||||||
|
this._removedTokens[objectPath] = token;
|
||||||
|
|
||||||
|
if (token.UsedToLogin)
|
||||||
|
this._loginToken = token;
|
||||||
|
},
|
||||||
|
|
||||||
|
_addToken: function(token) {
|
||||||
|
this._updateToken(token);
|
||||||
|
|
||||||
|
token.connect('g-properties-changed',
|
||||||
|
Lang.bind(this, function(proxy, properties) {
|
||||||
|
if ('IsInserted' in properties.deep_unpack()) {
|
||||||
|
this._updateToken(token);
|
||||||
|
|
||||||
|
if (token.IsInserted) {
|
||||||
|
this.emit('smartcard-inserted', token.Name);
|
||||||
|
} else {
|
||||||
|
this.emit('smartcard-removed', token.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Emit a smartcard-inserted at startup if it's already plugged in
|
||||||
|
if (token.IsInserted)
|
||||||
|
this.emit('smartcard-inserted', token.Name);
|
||||||
|
},
|
||||||
|
|
||||||
|
_removeToken: function(token) {
|
||||||
|
let objectPath = token.get_object_path();
|
||||||
|
|
||||||
|
if (objectPath) {
|
||||||
|
if (this._removedTokens[objectPath] == token) {
|
||||||
|
delete this._removedTokens[objectPath];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._insertedTokens[objectPath] == token) {
|
||||||
|
delete this._insertedTokens[objectPath];
|
||||||
|
this.emit('smartcard-removed', token.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
token.disconnectAll();
|
||||||
|
},
|
||||||
|
|
||||||
|
hasInsertedTokens: function() {
|
||||||
|
return Object.keys(this._insertedTokens).length > 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
hasInsertedLoginToken: function() {
|
||||||
|
if (!this._loginToken)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!this._loginToken.IsInserted)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
Signals.addSignalMethods(SmartcardManager.prototype);
|
@@ -23,6 +23,7 @@ const Main = imports.ui.main;
|
|||||||
const Overview = imports.ui.overview;
|
const Overview = imports.ui.overview;
|
||||||
const MessageTray = imports.ui.messageTray;
|
const MessageTray = imports.ui.messageTray;
|
||||||
const ShellDBus = imports.ui.shellDBus;
|
const ShellDBus = imports.ui.shellDBus;
|
||||||
|
const SmartcardManager = imports.misc.smartcardManager;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
const Util = imports.misc.util;
|
const Util = imports.misc.util;
|
||||||
|
|
||||||
@@ -516,6 +517,13 @@ const ScreenShield = new Lang.Class({
|
|||||||
|
|
||||||
this._screenSaverDBus = new ShellDBus.ScreenSaverDBus(this);
|
this._screenSaverDBus = new ShellDBus.ScreenSaverDBus(this);
|
||||||
|
|
||||||
|
this._smartcardManager = SmartcardManager.getSmartcardManager();
|
||||||
|
this._smartcardManager.connect('smartcard-inserted',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
if (this._isLocked)
|
||||||
|
this._liftShield(true, 0);
|
||||||
|
}));
|
||||||
|
|
||||||
this._inhibitor = null;
|
this._inhibitor = null;
|
||||||
this._aboutToSuspend = false;
|
this._aboutToSuspend = false;
|
||||||
this._loginManager = LoginManager.getLoginManager();
|
this._loginManager = LoginManager.getLoginManager();
|
||||||
|
@@ -49,8 +49,9 @@ const UnlockDialog = new Lang.Class({
|
|||||||
factor: 0.5 }));
|
factor: 0.5 }));
|
||||||
|
|
||||||
this._authPrompt = new AuthPrompt.AuthPrompt(new Gdm.Client(), AuthPrompt.AuthPromptMode.UNLOCK_ONLY);
|
this._authPrompt = new AuthPrompt.AuthPrompt(new Gdm.Client(), AuthPrompt.AuthPromptMode.UNLOCK_ONLY);
|
||||||
|
this._authPrompt.connect('failed', Lang.bind(this, this._fail));
|
||||||
|
this._authPrompt.connect('cancelled', Lang.bind(this, this._fail));
|
||||||
this._authPrompt.connect('reset', Lang.bind(this, this._onReset));
|
this._authPrompt.connect('reset', Lang.bind(this, this._onReset));
|
||||||
this._authPrompt.setUser(this._user);
|
|
||||||
this._authPrompt.setPasswordChar('\u25cf');
|
this._authPrompt.setPasswordChar('\u25cf');
|
||||||
this._authPrompt.nextButton.label = _("Unlock");
|
this._authPrompt.nextButton.label = _("Unlock");
|
||||||
|
|
||||||
@@ -74,7 +75,7 @@ const UnlockDialog = new Lang.Class({
|
|||||||
this._otherUserButton = null;
|
this._otherUserButton = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._authPrompt.begin({ userName: this._userName });
|
this._authPrompt.reset();
|
||||||
this._updateSensitivity(true);
|
this._updateSensitivity(true);
|
||||||
|
|
||||||
Main.ctrlAltTabManager.addGroup(this.actor, _("Unlock Window"), 'dialog-password-symbolic');
|
Main.ctrlAltTabManager.addGroup(this.actor, _("Unlock Window"), 'dialog-password-symbolic');
|
||||||
@@ -92,15 +93,25 @@ const UnlockDialog = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onReset: function() {
|
_fail: function() {
|
||||||
this.emit('failed');
|
this.emit('failed');
|
||||||
},
|
},
|
||||||
|
|
||||||
_escape: function() {
|
_onReset: function(authPrompt, beginRequest) {
|
||||||
if (this.allowCancel) {
|
let userName;
|
||||||
this._authPrompt.cancel();
|
if (beginRequest == AuthPrompt.BeginRequestType.PROVIDE_USERNAME) {
|
||||||
this.emit('failed');
|
this._authPrompt.setUser(this._user);
|
||||||
|
userName = this._userName;
|
||||||
|
} else {
|
||||||
|
userName = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._authPrompt.begin({ userName: userName });
|
||||||
|
},
|
||||||
|
|
||||||
|
_escape: function() {
|
||||||
|
if (this.allowCancel)
|
||||||
|
this._authPrompt.cancel();
|
||||||
},
|
},
|
||||||
|
|
||||||
_otherUserClicked: function(button, event) {
|
_otherUserClicked: function(button, event) {
|
||||||
|
120
po/cs.po
120
po/cs.po
@@ -12,8 +12,8 @@ msgstr ""
|
|||||||
"Project-Id-Version: gnome-shell\n"
|
"Project-Id-Version: gnome-shell\n"
|
||||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
|
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
|
||||||
"shell&keywords=I18N+L10N&component=general\n"
|
"shell&keywords=I18N+L10N&component=general\n"
|
||||||
"POT-Creation-Date: 2013-07-28 19:55+0000\n"
|
"POT-Creation-Date: 2013-07-26 08:43+0000\n"
|
||||||
"PO-Revision-Date: 2013-07-30 09:19+0200\n"
|
"PO-Revision-Date: 2013-07-28 13:09+0200\n"
|
||||||
"Last-Translator: Marek Černocký <marek@manet.cz>\n"
|
"Last-Translator: Marek Černocký <marek@manet.cz>\n"
|
||||||
"Language-Team: Czech <gnome-cs-list@gnome.org>\n"
|
"Language-Team: Czech <gnome-cs-list@gnome.org>\n"
|
||||||
"Language: cs\n"
|
"Language: cs\n"
|
||||||
@@ -366,8 +366,7 @@ msgstr ""
|
|||||||
#: ../js/gdm/authPrompt.js:132 ../js/ui/components/networkAgent.js:137
|
#: ../js/gdm/authPrompt.js:132 ../js/ui/components/networkAgent.js:137
|
||||||
#: ../js/ui/components/polkitAgent.js:161 ../js/ui/endSessionDialog.js:376
|
#: ../js/ui/components/polkitAgent.js:161 ../js/ui/endSessionDialog.js:376
|
||||||
#: ../js/ui/extensionDownloader.js:195 ../js/ui/shellMountOperation.js:399
|
#: ../js/ui/extensionDownloader.js:195 ../js/ui/shellMountOperation.js:399
|
||||||
#: ../js/ui/status/bluetooth.js:218 ../js/ui/status/network.js:635
|
#: ../js/ui/status/bluetooth.js:218 ../js/ui/status/system.js:305
|
||||||
#: ../js/ui/status/system.js:305
|
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr "Zrušit"
|
msgstr "Zrušit"
|
||||||
|
|
||||||
@@ -678,8 +677,7 @@ msgstr "Heslo:"
|
|||||||
msgid "Type again:"
|
msgid "Type again:"
|
||||||
msgstr "Napište znovu:"
|
msgstr "Napište znovu:"
|
||||||
|
|
||||||
#: ../js/ui/components/networkAgent.js:132 ../js/ui/status/network.js:112
|
#: ../js/ui/components/networkAgent.js:132
|
||||||
#: ../js/ui/status/network.js:268 ../js/ui/status/network.js:638
|
|
||||||
msgid "Connect"
|
msgid "Connect"
|
||||||
msgstr "Připojit"
|
msgstr "Připojit"
|
||||||
|
|
||||||
@@ -1414,16 +1412,16 @@ msgstr "Styl velkého textu"
|
|||||||
#: ../js/ui/status/bluetooth.js:21 ../js/ui/status/bluetooth.js:25
|
#: ../js/ui/status/bluetooth.js:21 ../js/ui/status/bluetooth.js:25
|
||||||
#: ../js/ui/status/bluetooth.js:59 ../js/ui/status/bluetooth.js:96
|
#: ../js/ui/status/bluetooth.js:59 ../js/ui/status/bluetooth.js:96
|
||||||
#: ../js/ui/status/bluetooth.js:124 ../js/ui/status/bluetooth.js:160
|
#: ../js/ui/status/bluetooth.js:124 ../js/ui/status/bluetooth.js:160
|
||||||
#: ../js/ui/status/bluetooth.js:191
|
#: ../js/ui/status/bluetooth.js:191 ../js/ui/status/network.js:713
|
||||||
msgid "Bluetooth"
|
msgid "Bluetooth"
|
||||||
msgstr "Bluetooth"
|
msgstr "Bluetooth"
|
||||||
|
|
||||||
#: ../js/ui/status/bluetooth.js:27 ../js/ui/status/network.js:112
|
#: ../js/ui/status/bluetooth.js:27
|
||||||
#: ../js/ui/status/network.js:978
|
|
||||||
msgid "Turn Off"
|
msgid "Turn Off"
|
||||||
msgstr "Vypnout"
|
msgstr "Vypnout"
|
||||||
|
|
||||||
#: ../js/ui/status/bluetooth.js:30
|
#: ../js/ui/status/bluetooth.js:30
|
||||||
|
#| msgid "Bluetooth"
|
||||||
msgid "Bluetooth Settings"
|
msgid "Bluetooth Settings"
|
||||||
msgstr "Nastavení Bluetooth"
|
msgstr "Nastavení Bluetooth"
|
||||||
|
|
||||||
@@ -1513,88 +1511,96 @@ msgstr "Zobrazit rozložení klávesnice"
|
|||||||
msgid "Volume, network, battery"
|
msgid "Volume, network, battery"
|
||||||
msgstr "Hlasitost, síť, baterie"
|
msgstr "Hlasitost, síť, baterie"
|
||||||
|
|
||||||
#: ../js/ui/status/network.js:72
|
#: ../js/ui/status/network.js:75
|
||||||
msgid "<unknown>"
|
msgid "<unknown>"
|
||||||
msgstr "<neznámé>"
|
msgstr "<neznámé>"
|
||||||
|
|
||||||
#: ../js/ui/status/network.js:196 ../js/ui/status/network.js:993
|
#: ../js/ui/status/network.js:125
|
||||||
msgid "Off"
|
msgid "Wi-Fi"
|
||||||
msgstr "Vypnuto"
|
msgstr "Wi-Fi"
|
||||||
|
|
||||||
#: ../js/ui/status/network.js:269 ../js/ui/status/network.js:899
|
#: ../js/ui/status/network.js:140
|
||||||
#| msgid "Power Settings"
|
msgid "hardware disabled"
|
||||||
msgid "Network Settings"
|
msgstr "zařízení zakázáno"
|
||||||
msgstr "Nastavení sítě"
|
|
||||||
|
#. Translators: this indicates that wireless or wwan is disabled by hardware killswitch
|
||||||
|
#: ../js/ui/status/network.js:162
|
||||||
|
msgid "disabled"
|
||||||
|
msgstr "zakázáno"
|
||||||
|
|
||||||
#. Translators: this is for network devices that are physically present but are not
|
#. Translators: this is for network devices that are physically present but are not
|
||||||
#. under NetworkManager's control (and thus cannot be used in the menu)
|
#. under NetworkManager's control (and thus cannot be used in the menu)
|
||||||
#: ../js/ui/status/network.js:357
|
#: ../js/ui/status/network.js:397
|
||||||
msgid "unmanaged"
|
msgid "unmanaged"
|
||||||
msgstr "nespravováno"
|
msgstr "nespravováno"
|
||||||
|
|
||||||
#: ../js/ui/status/network.js:359
|
#: ../js/ui/status/network.js:399
|
||||||
msgid "disconnecting..."
|
msgid "disconnecting..."
|
||||||
msgstr "odpojování…"
|
msgstr "odpojování…"
|
||||||
|
|
||||||
#: ../js/ui/status/network.js:365 ../js/ui/status/network.js:1044
|
#: ../js/ui/status/network.js:405 ../js/ui/status/network.js:1298
|
||||||
msgid "connecting..."
|
msgid "connecting..."
|
||||||
msgstr "připojování…"
|
msgstr "připojování…"
|
||||||
|
|
||||||
#. Translators: this is for network connections that require some kind of key or password
|
#. Translators: this is for network connections that require some kind of key or password
|
||||||
#: ../js/ui/status/network.js:368 ../js/ui/status/network.js:1047
|
#: ../js/ui/status/network.js:408 ../js/ui/status/network.js:1301
|
||||||
msgid "authentication required"
|
msgid "authentication required"
|
||||||
msgstr "je vyžadováno ověření"
|
msgstr "je vyžadováno ověření"
|
||||||
|
|
||||||
#. Translators: this is for devices that require some kind of firmware or kernel
|
#. Translators: this is for devices that require some kind of firmware or kernel
|
||||||
#. module, which is missing
|
#. module, which is missing
|
||||||
#: ../js/ui/status/network.js:376
|
#: ../js/ui/status/network.js:419
|
||||||
msgid "firmware missing"
|
msgid "firmware missing"
|
||||||
msgstr "nedostupný firmware"
|
msgstr "nedostupný firmware"
|
||||||
|
|
||||||
#. Translators: this is for a network device that cannot be activated (for example it
|
#. Translators: this is for a network device that cannot be activated (for example it
|
||||||
#. is disabled by rfkill, or it has no coverage
|
#. is disabled by rfkill, or it has no coverage
|
||||||
#: ../js/ui/status/network.js:380
|
#: ../js/ui/status/network.js:423
|
||||||
msgid "unavailable"
|
msgid "unavailable"
|
||||||
msgstr "nedostupné"
|
msgstr "nedostupné"
|
||||||
|
|
||||||
#: ../js/ui/status/network.js:382 ../js/ui/status/network.js:1049
|
#: ../js/ui/status/network.js:425 ../js/ui/status/network.js:1303
|
||||||
msgid "connection failed"
|
msgid "connection failed"
|
||||||
msgstr "připojení selhalo"
|
msgstr "připojení selhalo"
|
||||||
|
|
||||||
#: ../js/ui/status/network.js:615
|
#: ../js/ui/status/network.js:478 ../js/ui/status/network.js:1190
|
||||||
msgid "Wi-Fi Networks"
|
msgid "More…"
|
||||||
msgstr "Sítě WiFi"
|
msgstr "Další…"
|
||||||
|
|
||||||
#: ../js/ui/status/network.js:617
|
#. TRANSLATORS: this is the indication that a connection for another logged in user is active,
|
||||||
#| msgid "Enable networking"
|
#. and we cannot access its settings (including the name)
|
||||||
msgid "Select a network"
|
#: ../js/ui/status/network.js:506 ../js/ui/status/network.js:1142
|
||||||
msgstr "Vyberte síť"
|
msgid "Connected (private)"
|
||||||
|
msgstr "Připojení (soukromé)"
|
||||||
|
|
||||||
#: ../js/ui/status/network.js:893
|
#: ../js/ui/status/network.js:572
|
||||||
msgid "Select Network"
|
msgid "Wired"
|
||||||
msgstr "Vybrat síť"
|
msgstr "Drátová"
|
||||||
|
|
||||||
#: ../js/ui/status/network.js:978
|
#: ../js/ui/status/network.js:592
|
||||||
#| msgid "Turn Off"
|
msgid "Mobile broadband"
|
||||||
msgid "Turn On"
|
msgstr "Mobilní širokopásmová"
|
||||||
msgstr "Zapnout"
|
|
||||||
|
|
||||||
#: ../js/ui/status/network.js:1111
|
#: ../js/ui/status/network.js:1474
|
||||||
msgid "VPN"
|
msgid "Enable networking"
|
||||||
msgstr "VPN"
|
msgstr "Povolit síť"
|
||||||
|
|
||||||
#: ../js/ui/status/network.js:1250
|
#: ../js/ui/status/network.js:1537
|
||||||
msgid "Network Manager"
|
msgid "Network Manager"
|
||||||
msgstr "Network Manager"
|
msgstr "Network Manager"
|
||||||
|
|
||||||
#: ../js/ui/status/network.js:1292
|
#: ../js/ui/status/network.js:1621
|
||||||
msgid "Connection failed"
|
msgid "Connection failed"
|
||||||
msgstr "Připojení selhalo"
|
msgstr "Připojení selhalo"
|
||||||
|
|
||||||
#: ../js/ui/status/network.js:1293
|
#: ../js/ui/status/network.js:1622
|
||||||
msgid "Activation of network connection failed"
|
msgid "Activation of network connection failed"
|
||||||
msgstr "Aktivace síťového připojení selhala"
|
msgstr "Aktivace síťového připojení selhala"
|
||||||
|
|
||||||
|
#: ../js/ui/status/network.js:1936
|
||||||
|
msgid "Networking is disabled"
|
||||||
|
msgstr "Síť je zakázána"
|
||||||
|
|
||||||
#: ../js/ui/status/power.js:31 ../js/ui/status/power.js:44
|
#: ../js/ui/status/power.js:31 ../js/ui/status/power.js:44
|
||||||
msgid "Battery"
|
msgid "Battery"
|
||||||
msgstr "Baterie"
|
msgstr "Baterie"
|
||||||
@@ -1756,28 +1762,4 @@ msgstr "Heslo nemůže být prázdné."
|
|||||||
|
|
||||||
#: ../src/shell-polkit-authentication-agent.c:343
|
#: ../src/shell-polkit-authentication-agent.c:343
|
||||||
msgid "Authentication dialog was dismissed by the user"
|
msgid "Authentication dialog was dismissed by the user"
|
||||||
msgstr "Dialogové okno ověření bylo uživatelem zrušeno"
|
msgstr "Dialogové okno ověření bylo uživatelem zrušeno"
|
||||||
|
|
||||||
#~ msgid "Wi-Fi"
|
|
||||||
#~ msgstr "Wi-Fi"
|
|
||||||
|
|
||||||
#~ msgid "hardware disabled"
|
|
||||||
#~ msgstr "zařízení zakázáno"
|
|
||||||
|
|
||||||
#~ msgid "disabled"
|
|
||||||
#~ msgstr "zakázáno"
|
|
||||||
|
|
||||||
#~ msgid "More…"
|
|
||||||
#~ msgstr "Další…"
|
|
||||||
|
|
||||||
#~ msgid "Connected (private)"
|
|
||||||
#~ msgstr "Připojení (soukromé)"
|
|
||||||
|
|
||||||
#~ msgid "Wired"
|
|
||||||
#~ msgstr "Drátová"
|
|
||||||
|
|
||||||
#~ msgid "Mobile broadband"
|
|
||||||
#~ msgstr "Mobilní širokopásmová"
|
|
||||||
|
|
||||||
#~ msgid "Networking is disabled"
|
|
||||||
#~ msgstr "Síť je zakázána"
|
|
Reference in New Issue
Block a user