Compare commits

...

40 Commits

Author SHA1 Message Date
Umang Jain
05bed41dd1 gnome-shell-sass: Add top padding to unlock-dialog-clock-time
The (imaginary)center line for clock time of unlock dialog and the user
avatar should be the same. Since the clock font is 64pt, we need
32pt padding (or 42px).
2019-12-17 15:27:31 +05:30
Umang Jain
e56f81b29c fixup! userWidget: Pack vertically and align in the center
Username font-size should match with date's font-size which is
16pt.
2019-12-17 15:00:45 +05:30
Umang Jain
01c2313c16 gdm: Do not display "Password:" Label for gdm-password service
The mockups do not mention the "Password:" above the password
entry. Although preserve the label place-holder for question
prompt other than PASSWORD_SERVICE_NAME.
2019-12-17 11:24:08 +05:30
Umang Jain
92b57ee992 authPrompt: Add "Enter Password…" as hint-text 2019-12-17 11:24:08 +05:30
Umang Jain
468fde932a authPrompt: Iconize the cancel button
Replace the "Cancel" label in the cancel button
by an arrow icon, and adjust the theme to make
it circular.
2019-12-17 11:24:08 +05:30
Umang Jain
05719ce674 authPrompt: Move cancel button and cog to a single row 2019-12-17 11:24:08 +05:30
Umang Jain
d7befc5875 authPrompt: Remove Next button and its references 2019-12-17 11:24:08 +05:30
Umang Jain
ca046cd29b userWidget: Pack vertically and align in the center 2019-12-17 11:24:08 +05:30
Georges Basile Stavracas Neto
4c288bd122 screenShield: Cleanup _ensureUnlockDialog
Just like on ScreenShield.activate(), we can just ensure the
unlock screen on ScreenShield.showDialog().

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:13 -03:00
Georges Basile Stavracas Neto
24d36e13ec screenShield: Rework key focus management
Instead of always grabbing key focus for the screen lock
group, do that for the unlock dialog itself.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:13 -03:00
Georges Basile Stavracas Neto
3387c8787c unlockDialog: Create auth prompt on demand
AuthPrompt is the set of actors that contain the user avatar,
the username, and the password entry. With the removal of the
screen shield, the unlock dialog (be it UnlockDialog or the
LoginDialog) is always created, and in the case of UnlockDialog,
so is the auth prompt.

This is problematic, though, since for passwordless accounts,
the simple act of creating AuthPrompt authenticates the user,
and lifts the lock screen.

Create the AuthPrompt on deman in UnlockDialog.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:13 -03:00
Georges Basile Stavracas Neto
47d3203622 theme: Adjust style of lock screen notifications
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:13 -03:00
Georges Basile Stavracas Neto
852cefb6fc unlockDialog: Make notification labels vertical
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:13 -03:00
Georges Basile Stavracas Neto
cfce9550a4 unlockDialog: Use just the counter to format notifications
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:13 -03:00
Georges Basile Stavracas Neto
15692b618a unlockDialog: Add user name label below clock
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:13 -03:00
Georges Basile Stavracas Neto
ce1b4b9f43 unlockDialog: Show clock when canceling or failing auth
There is still a problem of focus not going to the entry after the
first cancel, but it seems to work fine otherwise.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:13 -03:00
Georges Basile Stavracas Neto
cb89b7c0c4 unlockDialog: Toggle between clock and auth prompt
Toggle between them when (1) tapping anythere on the screen, and
(2) pressing any key.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:13 -03:00
Georges Basile Stavracas Neto
cb914b8095 unlockDialog: Move auth prompt and clock to a ShellStack
We will toggle between each other in the next commit, so add
both to a ShellStack.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:13 -03:00
Georges Basile Stavracas Neto
806d3b37cd screenShield: Remove key press event handler
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:13 -03:00
Georges Basile Stavracas Neto
803a6dcfb0 unlockDialog: Introduce UnlockDialogLayout
This is the layout manager responsible for ensuring
that the clock is always at the third of the screen
height, and the notifications can push it to above.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:10 -03:00
Georges Basile Stavracas Neto
d2111d1bb3 screenShield: Cleanup lock screen position state
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:10 -03:00
Georges Basile Stavracas Neto
4a62c072d2 theme: Adjust lock screen clock fonts
These values were decided during the GNOME Shell Hackfest, but
they're still subject to changes.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:10 -03:00
Georges Basile Stavracas Neto
8395f8bad5 sessionMode: Remove lock-screen mode
Now that the screen shield is gone (at least, as it used to
be), the corresponding session mode is not necessary anymore
as well.

Remove the 'lock-screen' session mode, and the corresponding
CSS.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:10 -03:00
Georges Basile Stavracas Neto
37c41af1b7 screenShield: Move lock shield below dialog
Pretty much what the commit title says.

This gives the lock shield actor another role: instead of
being the interactive screen shield, make it the invisible
actor that prevents interacting with windows while the
unlock dialog is sliding down.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:10 -03:00
Georges Basile Stavracas Neto
262b600490 screenShield: Only animate the unlock dialog
Remove the slide-up-down animation from the lock shield.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:10 -03:00
Georges Basile Stavracas Neto
c937103071 screenShield: Lift the unlock dialog
Instead of scaling it, lift the unlock dialog when unlocking,
and vice-versa.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:10 -03:00
Georges Basile Stavracas Neto
a3a00434b1 screenShield: Remove scrolling
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:10 -03:00
Georges Basile Stavracas Neto
28f85a3308 screenShield: Cleanup unused method arguments
The 'velocity' argument is not used anymore, since the only
caller passing a different value than 0 was the drag motion
callback.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:10 -03:00
Georges Basile Stavracas Neto
2a1ea497c0 screenShield: Remove the drag action from the shield
This is start of the end of the screen shield; start by
removing the dragging action from it.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:10 -03:00
Georges Basile Stavracas Neto
e64c12dd27 unlockDialog: Don't destroy on cancel
Otherwise there will be no way to recover it in the future. Also
remove an else condition that assumed the dialog would destroy
itself on cancel.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:10 -03:00
Georges Basile Stavracas Neto
a6897c5f90 screenShield: Always show session's unlock dialog
Instead of destroying the dialog when the screen shield is
visible, and creating it when lifting the shield, always show
the session's unlock dialog.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:10 -03:00
Georges Basile Stavracas Neto
e3f87bac23 screenShield: Remove _lockScreenContents and family
It is not used anymore, and together with it, we don't need the
_ensureLockScreen() / _clearLockScreen() pair anymore too.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:10 -03:00
Georges Basile Stavracas Neto
57cff9a48b screenShield: Move background to Unlock Dialog
In addition to that, remove the ClutterBoxLayout that is set as
the layout manager of the Unlock Dialog, and apply the primary
monitor constraint to the child St.BoxLayout instead.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:10 -03:00
Georges Basile Stavracas Neto
7274ed52dd screenShield: Remove unused 'onPrimary' argument
The 'onPrimary' argument was being passed to dialog.open(). Turns out,
neither UnlockDialog nor LoginDialog use this parameter.

Remove the unnecessary 'onPrimary' parameter, and cleanup the related
code.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:10 -03:00
Georges Basile Stavracas Neto
5e8943340d screenShield: Move notifications to Unlock Dialog
Also adjust the CSS style classes names to match the new owner.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:43:07 -03:00
Georges Basile Stavracas Neto
044ef27c7e unlockDialog, loginDialog: Add a 'wake-up-screen' signal
The signal is currently present in the notifications box, but next
commits will move the notifications box to the unlock dialog.

Add a 'wake-up-screen' signal to the dialogs.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:35:51 -03:00
Georges Basile Stavracas Neto
ef716a7eb5 screenShield: Move clock to Unlock Dialog
Move the Screen Shield clock to Unlock Dialog. Also adjust
the CSS style classes names to match the new owner.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:35:51 -03:00
Georges Basile Stavracas Neto
0cead8c074 screenShield: Remove arrows
They are not present anywhere in the new mockups.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/872
2019-12-16 14:35:51 -03:00
Georges Basile Stavracas Neto
b41ae733a9 screenShield: Animate shield using translation_y
Instead of using the 'y', which queues a full relayout and
thus forces effects to be reapplied, use the 'translation_y'
property, that doesn't force relayouts and allows the blur
effect to actually use the cached framebuffers a lot more.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/864
2019-12-16 13:01:33 -03:00
Georges Basile Stavracas Neto
768193ab20 screenShield: Blur background
This is a moderately fast two-pass gaussian blur implementation.
It downscales the framebuffer dynamically before applying the
gaussian shader, which cuts down rendering time quite considerably.

The blur shader takes 2 uniforms as input: the blur radius; and
whether to blur vertically or horizontally.

The blur radius is treated as an integer in C land to simplify
calculations. The vertical parameter is treated as an integer by
the shader simply due to Cogl not having proper boolean support
in snippets.

At last, brightness is also added to avoid needing to use an extra
effect to achieve that. Brightness is applied in a different pipeline
than blur, so we can control it more tightly.

ShellBlurEffect also implements a "below" mode, where the contents
beneath the actor are blurred, but not the actor itself. This mode
is performance-heavy.

Related: https://gitlab.gnome.org/GNOME/gnome-shell/issues/1848

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/864
2019-12-16 13:01:33 -03:00
11 changed files with 1851 additions and 924 deletions

View File

@ -826,8 +826,7 @@ StScrollBar {
font-feature-settings: "tnum"; font-feature-settings: "tnum";
&.unlock-screen, &.unlock-screen,
&.login-screen, &.login-screen {
&.lock-screen {
background-color: transparent; background-color: transparent;
} }
@ -845,7 +844,7 @@ StScrollBar {
-panel-corner-border-color: lighten($selected_bg_color,5%); -panel-corner-border-color: lighten($selected_bg_color,5%);
} }
&.lock-screen, &.login-screen, &.unlock-screen { &.login-screen, &.unlock-screen {
-panel-corner-radius: 0; -panel-corner-radius: 0;
-panel-corner-background-color: transparent; -panel-corner-background-color: transparent;
-panel-corner-border-color: transparent; -panel-corner-border-color: transparent;
@ -879,8 +878,7 @@ StScrollBar {
.system-status-icon { icon-size: 1.09em; padding: 0 5px; } .system-status-icon { icon-size: 1.09em; padding: 0 5px; }
.unlock-screen &, .unlock-screen &,
.login-screen &, .login-screen & {
.lock-screen & {
color: lighten($fg_color, 10%); color: lighten($fg_color, 10%);
&:focus, &:hover, &:active { color: lighten($fg_color, 10%); } &:focus, &:hover, &:active { color: lighten($fg_color, 10%); }
} }
@ -1886,6 +1884,7 @@ StScrollBar {
.user-icon { .user-icon {
background-size: contain; background-size: contain;
color: $osd_fg_color; color: $osd_fg_color;
text-align: center;
border-radius: 99px; border-radius: 99px;
&:hover { &:hover {
color: lighten($osd_fg_color,30%); color: lighten($osd_fg_color,30%);
@ -1966,6 +1965,16 @@ StScrollBar {
} }
} }
} }
.cancel-button {
padding: 0;
border-radius: 16px;
width: 32px;
height: 32px;
border-color: transparentize($bg_color,0.7);
background-color: transparentize($bg_color,0.7);
StIcon { icon-size: 16px; }
}
} }
.login-dialog-logo-bin { padding: 24px 0px; } .login-dialog-logo-bin { padding: 24px 0px; }
@ -2012,15 +2021,10 @@ StScrollBar {
.login-dialog-username, .login-dialog-username,
.user-widget-label { .user-widget-label {
color: $osd_fg_color; color: $osd_fg_color;
font-size: 120%; font-size: 16pt;
font-weight: bold; text-align: center;
text-align: left; padding-top: 24px;
padding-left: 15px;
} }
.user-widget-label {
&:ltr { padding-left: 14px; }
&:rtl { padding-right: 14px; }
}
.login-dialog-prompt-layout { .login-dialog-prompt-layout {
padding-top: 24px; padding-top: 24px;
@ -2047,69 +2051,58 @@ StScrollBar {
//SCREEN SHIELD //SCREEN SHIELD
$_screenshield_shadow: 0px 0px 6px rgba(0, 0, 0, 0.726); $_unlockdialog_shadow: 0px 0px 6px rgba(0, 0, 0, 0.726);
.screen-shield-arrows { .unlock-dialog-clock {
padding-bottom: 3em;
}
.screen-shield-arrows Gjs_Arrow {
color: white;
width: 80px;
height: 48px;
-arrow-thickness: 12px;
-arrow-shadow: $_screenshield_shadow;
}
.screen-shield-clock {
color: white; color: white;
text-shadow: $_screenshield_shadow; font-weight: 300;
font-weight: bold;
text-align: center; text-align: center;
padding-bottom: 1.5em; padding-bottom: 2.5em;
} }
.screen-shield-clock-time { .unlock-dialog-clock-time {
font-size: 72pt; font-size: 64pt;
text-shadow: $_screenshield_shadow; padding-bottom: 24px;
padding-top: 42px;
font-feature-settings: "tnum"; font-feature-settings: "tnum";
} }
.screen-shield-clock-date { .unlock-dialog-clock-date {
font-size: 28pt; font-size: 16pt;
font-weight: normal;
} }
.screen-shield-notifications-container { .unlock-dialog-user-name {
padding: 12px 0px;
}
.unlock-dialog-notifications-container {
margin: 12px 0;
spacing: 6px; spacing: 6px;
width: 30em;
background-color: transparent; background-color: transparent;
max-height: 500px;
.summary-notification-stack-scrollview { .summary-notification-stack-scrollview {
padding-top: 0; padding-top: 0;
padding-bottom: 0; padding-bottom: 0;
} }
.notification, .notification,
.screen-shield-notification-source { .unlock-dialog-notification-source {
padding: 12px 6px; padding: 12px 6px;
border: 1px solid $osd_outer_borders_color; border: 1px solid $osd_outer_borders_color;
background-color: transparentize($osd_bg_color,0.5); background-color: transparentize($osd_bg_color,0.5);
color: $osd_fg_color; color: $osd_fg_color;
border-radius: 4px; border-radius: 4px;
} }
.notification { margin-right: 15px; } //compensate for space allocated to the scrollbar
} }
.screen-shield-notification-label { .unlock-dialog-notification-label {
font-weight: bold;
padding: 0px 0px 0px 12px; padding: 0px 0px 0px 12px;
} }
.screen-shield-notification-count-text { padding: 0px 0px 0px 12px; } .unlock-dialog-notification-count-text {
weight: bold;
#panel.lock-screen { background-color: transparentize($osd_bg_color, 0.5); } padding: 0px 12px 0px 12px;
}
.screen-shield-background { //just the shadow, really .screen-shield-background { //just the shadow, really
background: black; background: black;
@ -2121,7 +2114,7 @@ $_screenshield_shadow: 0px 0px 6px rgba(0, 0, 0, 0.726);
background-repeat: repeat; background-repeat: repeat;
} }
#screenShieldNotifications { #unlockDialogNotifications {
StButton#vhandle, StButton#hhandle { StButton#vhandle, StButton#hhandle {
background-color: transparentize($bg_color,0.7); background-color: transparentize($bg_color,0.7);
&:hover, &:focus { background-color: transparentize($bg_color,0.5); } &:hover, &:focus { background-color: transparentize($bg_color,0.5); }

View File

@ -98,17 +98,8 @@ var AuthPrompt = GObject.registerClass({
}); });
this.add_child(this._label); this.add_child(this._label);
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.add_child(this._entry); this._initEntryRow();
this._entry.grab_key_focus();
this._message = new St.Label({ this._message = new St.Label({
opacity: 0, opacity: 0,
@ -120,26 +111,6 @@ var AuthPrompt = GObject.registerClass({
this._message.clutter_text.line_wrap = true; this._message.clutter_text.line_wrap = true;
this._message.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; this._message.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this.add_child(this._message); this.add_child(this._message);
this._buttonBox = new St.BoxLayout({
style_class: 'login-dialog-button-box',
vertical: false,
y_align: Clutter.ActorAlign.END,
});
this.add_child(this._buttonBox);
this._defaultButtonWell = new St.Widget({
layout_manager: new Clutter.BinLayout(),
x_align: Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.CENTER,
});
this._initButtons();
this._spinner = new Animation.Spinner(DEFAULT_BUTTON_WELL_ICON_SIZE);
this._spinner.opacity = 0;
this._spinner.show();
this._defaultButtonWell.add_child(this._spinner);
} }
_onDestroy() { _onDestroy() {
@ -153,46 +124,55 @@ var AuthPrompt = GObject.registerClass({
return Clutter.EVENT_PROPAGATE; return Clutter.EVENT_PROPAGATE;
} }
_initButtons() { _initEntryRow() {
let mainBox = new St.BoxLayout({
style_class: 'login-dialog-button-box',
vertical: false,
});
this.add_child(mainBox);
this.cancelButton = new St.Button({ this.cancelButton = new St.Button({
style_class: 'modal-dialog-button button', style_class: 'modal-dialog-button button cancel-button',
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
reactive: true, reactive: true,
can_focus: true, can_focus: true,
label: _("Cancel"),
x_expand: true, x_expand: true,
x_align: Clutter.ActorAlign.START, x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.END, y_align: Clutter.ActorAlign.END,
child: new St.Icon({ icon_name: 'go-previous-symbolic' }),
}); });
this.cancelButton.connect('clicked', () => this.cancel()); this.cancelButton.connect('clicked', () => this.cancel());
this._buttonBox.add_child(this.cancelButton); mainBox.add_child(this.cancelButton);
this._buttonBox.add_child(this._defaultButtonWell); this._entry = new St.Entry({
this.nextButton = new St.Button({ style_class: 'login-dialog-prompt-entry',
style_class: 'modal-dialog-button button',
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
reactive: true,
can_focus: true, can_focus: true,
label: _("Next"), x_expand: false,
x_align: Clutter.ActorAlign.END, y_expand: true,
y_align: Clutter.ActorAlign.END, hint_text: "Enter Password…",
}); });
this.nextButton.connect('clicked', () => this.emit('next')); ShellEntry.addContextMenu(this._entry, { isPassword: true, actionMode: Shell.ActionMode.NONE });
this.nextButton.add_style_pseudo_class('default');
this._buttonBox.add_child(this.nextButton);
this._updateNextButtonSensitivity(this._entry.text.length > 0); mainBox.add_child(this._entry);
this._entry.grab_key_focus();
this._entry.clutter_text.connect('activate', () => this.emit('next'));
this._entry.clutter_text.connect('text-changed', () => { this._entry.clutter_text.connect('text-changed', () => {
if (!this._userVerifier.hasPendingMessages) if (!this._userVerifier.hasPendingMessages)
this._fadeOutMessage(); this._fadeOutMessage();
});
this._updateNextButtonSensitivity(this._entry.text.length > 0 || this.verificationStatus == AuthPromptStatus.VERIFYING); this._defaultButtonWell = new St.Widget({
}); layout_manager: new Clutter.BinLayout(),
this._entry.clutter_text.connect('activate', () => { x_align: Clutter.ActorAlign.END,
if (this.nextButton.reactive) y_align: Clutter.ActorAlign.CENTER,
this.emit('next');
}); });
mainBox.add_child(this._defaultButtonWell);
this._spinner = new Animation.Spinner(DEFAULT_BUTTON_WELL_ICON_SIZE);
this._spinner.opacity = 0;
this._spinner.show();
this._defaultButtonWell.add_child(this._spinner);
} }
_onAskQuestion(verifier, serviceName, question, passwordChar) { _onAskQuestion(verifier, serviceName, question, passwordChar) {
@ -208,15 +188,6 @@ var AuthPrompt = GObject.registerClass({
this.setPasswordChar(passwordChar); this.setPasswordChar(passwordChar);
this.setQuestion(question); this.setQuestion(question);
if (passwordChar) {
if (this._userVerifier.reauthenticating)
this.nextButton.label = _("Unlock");
else
this.nextButton.label = C_("button", "Sign In");
} else {
this.nextButton.label = _("Next");
}
this.updateSensitivity(true); this.updateSensitivity(true);
this.emit('prompted'); this.emit('prompted');
} }
@ -416,13 +387,7 @@ var AuthPrompt = GObject.registerClass({
} }
} }
_updateNextButtonSensitivity(sensitive) {
this.nextButton.reactive = sensitive;
this.nextButton.can_focus = sensitive;
}
updateSensitivity(sensitive) { updateSensitivity(sensitive) {
this._updateNextButtonSensitivity(sensitive && (this._entry.text.length > 0 || this.verificationStatus == AuthPromptStatus.VERIFYING));
this._entry.reactive = sensitive; this._entry.reactive = sensitive;
this._entry.clutter_text.editable = sensitive; this._entry.clutter_text.editable = sensitive;
} }
@ -445,7 +410,7 @@ var AuthPrompt = GObject.registerClass({
if (user) { if (user) {
let userWidget = new UserWidget.UserWidget(user); let userWidget = new UserWidget.UserWidget(user);
userWidget.x_align = Clutter.ActorAlign.START; userWidget.x_align = Clutter.ActorAlign.CENTER;
this._userWell.set_child(userWidget); this._userWell.set_child(userWidget);
} }
} }
@ -454,7 +419,6 @@ var AuthPrompt = GObject.registerClass({
let oldStatus = this.verificationStatus; let oldStatus = this.verificationStatus;
this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
this.cancelButton.reactive = true; this.cancelButton.reactive = true;
this.nextButton.label = _("Next");
this._preemptiveAnswer = null; this._preemptiveAnswer = null;
if (this._userVerifier) if (this._userVerifier)

View File

@ -409,7 +409,10 @@ var SessionMenuButton = GObject.registerClass({
}); });
var LoginDialog = GObject.registerClass({ var LoginDialog = GObject.registerClass({
Signals: { 'failed': {} }, Signals: {
'failed': {},
'wake-up-screen': {},
},
}, class LoginDialog extends St.Widget { }, class LoginDialog extends St.Widget {
_init(parentActor) { _init(parentActor) {
super._init({ style_class: 'login-dialog', visible: false }); super._init({ style_class: 'login-dialog', visible: false });

View File

@ -496,6 +496,8 @@ var ShellUserVerifier = class {
// The only question asked by this service is "Token?" // The only question asked by this service is "Token?"
this.answerQuery(serviceName, this._oVirtCredentialsManager.getToken()); this.answerQuery(serviceName, this._oVirtCredentialsManager.getToken());
return; return;
} else if (serviceName == PASSWORD_SERVICE_NAME) {
secretQuestion = '';
} }
this.emit('ask-question', serviceName, secretQuestion, '\u25cf'); this.emit('ask-question', serviceName, secretQuestion, '\u25cf');

View File

@ -1,21 +1,16 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const { AccountsService, Clutter, Gio, GLib, const { AccountsService, Clutter, Gio,
GnomeDesktop, GObject, Graphene, Meta, Shell, St } = imports.gi; GLib, Graphene, Meta, Shell, St } = imports.gi;
const Cairo = imports.cairo;
const Signals = imports.signals; const Signals = imports.signals;
const Background = imports.ui.background;
const GnomeSession = imports.misc.gnomeSession; const GnomeSession = imports.misc.gnomeSession;
const Layout = imports.ui.layout;
const OVirt = imports.gdm.oVirt;
const LoginManager = imports.misc.loginManager; const LoginManager = imports.misc.loginManager;
const Lightbox = imports.ui.lightbox; const Lightbox = imports.ui.lightbox;
const Main = imports.ui.main; 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 { adjustAnimationTime } = imports.ui.environment; const { adjustAnimationTime } = imports.ui.environment;
@ -27,17 +22,6 @@ const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
const DISABLE_LOCK_KEY = 'disable-lock-screen'; const DISABLE_LOCK_KEY = 'disable-lock-screen';
const LOCKED_STATE_STR = 'screenShield.locked'; const LOCKED_STATE_STR = 'screenShield.locked';
// fraction of screen height the arrow must reach before completing
// the slide up automatically
var ARROW_DRAG_THRESHOLD = 0.1;
// Parameters for the arrow animation
var N_ARROWS = 3;
var ARROW_ANIMATION_TIME = 600;
var ARROW_ANIMATION_PEAK_OPACITY = 0.4;
var ARROW_IDLE_TIME = 30000; // ms
var SUMMARY_ICON_SIZE = 48;
// ScreenShield animation time // ScreenShield animation time
// - STANDARD_FADE_TIME is used when the session goes idle // - STANDARD_FADE_TIME is used when the session goes idle
@ -48,384 +32,6 @@ var STANDARD_FADE_TIME = 10000;
var MANUAL_FADE_TIME = 300; var MANUAL_FADE_TIME = 300;
var CURTAIN_SLIDE_TIME = 300; var CURTAIN_SLIDE_TIME = 300;
var Clock = GObject.registerClass(
class ScreenShieldClock extends St.BoxLayout {
_init() {
super._init({ style_class: 'screen-shield-clock', vertical: true });
this._time = new St.Label({
style_class: 'screen-shield-clock-time',
x_align: Clutter.ActorAlign.CENTER,
});
this._date = new St.Label({
style_class: 'screen-shield-clock-date',
x_align: Clutter.ActorAlign.CENTER,
});
this.add_child(this._time);
this.add_child(this._date);
this._wallClock = new GnomeDesktop.WallClock({ time_only: true });
this._wallClock.connect('notify::clock', this._updateClock.bind(this));
this._updateClock();
this.connect('destroy', this._onDestroy.bind(this));
}
_updateClock() {
this._time.text = this._wallClock.clock;
let date = new Date();
/* Translators: This is a time format for a date in
long format */
let dateFormat = Shell.util_translate_time_string(N_("%A, %B %d"));
this._date.text = date.toLocaleFormat(dateFormat);
}
_onDestroy() {
this._wallClock.run_dispose();
}
});
var NotificationsBox = GObject.registerClass({
Signals: { 'wake-up-screen': {} },
}, class NotificationsBox extends St.BoxLayout {
_init() {
super._init({
vertical: true,
name: 'screenShieldNotifications',
style_class: 'screen-shield-notifications-container',
});
this._scrollView = new St.ScrollView({ hscrollbar_policy: St.PolicyType.NEVER });
this._notificationBox = new St.BoxLayout({ vertical: true,
style_class: 'screen-shield-notifications-container' });
this._scrollView.add_actor(this._notificationBox);
this.add_child(this._scrollView);
this._sources = new Map();
Main.messageTray.getSources().forEach(source => {
this._sourceAdded(Main.messageTray, source, true);
});
this._updateVisibility();
this._sourceAddedId = Main.messageTray.connect('source-added', this._sourceAdded.bind(this));
this.connect('destroy', this._onDestroy.bind(this));
}
_onDestroy() {
if (this._sourceAddedId) {
Main.messageTray.disconnect(this._sourceAddedId);
this._sourceAddedId = 0;
}
let items = this._sources.entries();
for (let [source, obj] of items)
this._removeSource(source, obj);
}
_updateVisibility() {
this._notificationBox.visible =
this._notificationBox.get_children().some(a => a.visible);
this.visible = this._notificationBox.visible;
}
_makeNotificationCountText(count, isChat) {
if (isChat)
return ngettext("%d new message", "%d new messages", count).format(count);
else
return ngettext("%d new notification", "%d new notifications", count).format(count);
}
_makeNotificationSource(source, box) {
let sourceActor = new MessageTray.SourceActor(source, SUMMARY_ICON_SIZE);
box.add_child(sourceActor);
let textBox = new St.BoxLayout({ vertical: true });
box.add_child(textBox);
let title = new St.Label({ text: source.title,
style_class: 'screen-shield-notification-label' });
textBox.add(title);
let count = source.unseenCount;
let countLabel = new St.Label({ text: this._makeNotificationCountText(count, source.isChat),
style_class: 'screen-shield-notification-count-text' });
textBox.add(countLabel);
box.visible = count != 0;
return [title, countLabel];
}
_makeNotificationDetailedSource(source, box) {
let sourceActor = new MessageTray.SourceActor(source, SUMMARY_ICON_SIZE);
let sourceBin = new St.Bin({ child: sourceActor });
box.add(sourceBin);
let textBox = new St.BoxLayout({ vertical: true });
box.add_child(textBox);
let title = new St.Label({ text: source.title,
style_class: 'screen-shield-notification-label' });
textBox.add(title);
let visible = false;
for (let i = 0; i < source.notifications.length; i++) {
let n = source.notifications[i];
if (n.acknowledged)
continue;
let body = '';
if (n.bannerBodyText) {
body = n.bannerBodyMarkup
? n.bannerBodyText
: GLib.markup_escape_text(n.bannerBodyText, -1);
}
let label = new St.Label({ style_class: 'screen-shield-notification-count-text' });
label.clutter_text.set_markup(`<b>${n.title}</b> ${body}`);
textBox.add(label);
visible = true;
}
box.visible = visible;
return [title, null];
}
_shouldShowDetails(source) {
return source.policy.detailsInLockScreen ||
source.narrowestPrivacyScope == MessageTray.PrivacyScope.SYSTEM;
}
_showSource(source, obj, box) {
if (obj.detailed)
[obj.titleLabel, obj.countLabel] = this._makeNotificationDetailedSource(source, box);
else
[obj.titleLabel, obj.countLabel] = this._makeNotificationSource(source, box);
box.visible = obj.visible && (source.unseenCount > 0);
}
_sourceAdded(tray, source, initial) {
let obj = {
visible: source.policy.showInLockScreen,
detailed: this._shouldShowDetails(source),
sourceDestroyId: 0,
sourceCountChangedId: 0,
sourceTitleChangedId: 0,
sourceUpdatedId: 0,
sourceBox: null,
titleLabel: null,
countLabel: null,
};
obj.sourceBox = new St.BoxLayout({ style_class: 'screen-shield-notification-source',
x_expand: true });
this._showSource(source, obj, obj.sourceBox);
this._notificationBox.add_child(obj.sourceBox);
obj.sourceCountChangedId = source.connect('notify::count', () => {
this._countChanged(source, obj);
});
obj.sourceTitleChangedId = source.connect('notify::title', () => {
this._titleChanged(source, obj);
});
obj.policyChangedId = source.policy.connect('notify', (policy, pspec) => {
if (pspec.name == 'show-in-lock-screen')
this._visibleChanged(source, obj);
else
this._detailedChanged(source, obj);
});
obj.sourceDestroyId = source.connect('destroy', () => {
this._onSourceDestroy(source, obj);
});
this._sources.set(source, obj);
if (!initial) {
// block scrollbars while animating, if they're not needed now
let boxHeight = this._notificationBox.height;
if (this._scrollView.height >= boxHeight)
this._scrollView.vscrollbar_policy = St.PolicyType.NEVER;
let widget = obj.sourceBox;
let [, natHeight] = widget.get_preferred_height(-1);
widget.height = 0;
widget.ease({
height: natHeight,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: 250,
onComplete: () => {
this._scrollView.vscrollbar_policy = St.PolicyType.AUTOMATIC;
widget.set_height(-1);
},
});
this._updateVisibility();
if (obj.sourceBox.visible)
this.emit('wake-up-screen');
}
}
_titleChanged(source, obj) {
obj.titleLabel.text = source.title;
}
_countChanged(source, obj) {
// A change in the number of notifications may change whether we show
// details.
let newDetailed = this._shouldShowDetails(source);
let oldDetailed = obj.detailed;
obj.detailed = newDetailed;
if (obj.detailed || oldDetailed != newDetailed) {
// A new notification was pushed, or a previous notification was destroyed.
// Give up, and build the list again.
obj.sourceBox.destroy_all_children();
obj.titleLabel = obj.countLabel = null;
this._showSource(source, obj, obj.sourceBox);
} else {
let count = source.unseenCount;
obj.countLabel.text = this._makeNotificationCountText(count, source.isChat);
}
obj.sourceBox.visible = obj.visible && (source.unseenCount > 0);
this._updateVisibility();
if (obj.sourceBox.visible)
this.emit('wake-up-screen');
}
_visibleChanged(source, obj) {
if (obj.visible == source.policy.showInLockScreen)
return;
obj.visible = source.policy.showInLockScreen;
obj.sourceBox.visible = obj.visible && source.unseenCount > 0;
this._updateVisibility();
if (obj.sourceBox.visible)
this.emit('wake-up-screen');
}
_detailedChanged(source, obj) {
let newDetailed = this._shouldShowDetails(source);
if (obj.detailed == newDetailed)
return;
obj.detailed = newDetailed;
obj.sourceBox.destroy_all_children();
obj.titleLabel = obj.countLabel = null;
this._showSource(source, obj, obj.sourceBox);
}
_onSourceDestroy(source, obj) {
this._removeSource(source, obj);
this._updateVisibility();
}
_removeSource(source, obj) {
obj.sourceBox.destroy();
obj.sourceBox = obj.titleLabel = obj.countLabel = null;
source.disconnect(obj.sourceDestroyId);
source.disconnect(obj.sourceCountChangedId);
source.disconnect(obj.sourceTitleChangedId);
source.policy.disconnect(obj.policyChangedId);
this._sources.delete(source);
}
});
var Arrow = GObject.registerClass(
class ScreenShieldArrow extends St.Bin {
_init(params) {
super._init(params);
this._drawingArea = new St.DrawingArea({
x_expand: true,
y_expand: true,
});
this._drawingArea.connect('repaint', this._drawArrow.bind(this));
this.child = this._drawingArea;
this._shadowHelper = null;
this._shadowWidth = this._shadowHeight = 0;
}
_drawArrow(arrow) {
let cr = arrow.get_context();
let [w, h] = arrow.get_surface_size();
let node = this.get_theme_node();
let thickness = node.get_length('-arrow-thickness');
Clutter.cairo_set_source_color(cr, node.get_foreground_color());
cr.setLineCap(Cairo.LineCap.ROUND);
cr.setLineWidth(thickness);
cr.moveTo(thickness / 2, h - thickness / 2);
cr.lineTo(w / 2, thickness);
cr.lineTo(w - thickness / 2, h - thickness / 2);
cr.stroke();
cr.$dispose();
}
vfunc_get_paint_volume(volume) {
if (!super.vfunc_get_paint_volume(volume))
return false;
if (!this._shadow)
return true;
let shadowBox = new Clutter.ActorBox();
this._shadow.get_box(this._drawingArea.get_allocation_box(), shadowBox);
volume.set_width(Math.max(shadowBox.x2 - shadowBox.x1, volume.get_width()));
volume.set_height(Math.max(shadowBox.y2 - shadowBox.y1, volume.get_height()));
return true;
}
vfunc_style_changed() {
let node = this.get_theme_node();
this._shadow = node.get_shadow('-arrow-shadow');
if (this._shadow)
this._shadowHelper = St.ShadowHelper.new(this._shadow);
else
this._shadowHelper = null;
super.vfunc_style_changed();
}
vfunc_paint(paintContext) {
if (this._shadowHelper) {
this._shadowHelper.update(this._drawingArea);
let allocation = this._drawingArea.get_allocation_box();
let paintOpacity = this._drawingArea.get_paint_opacity();
let framebuffer = paintContext.get_framebuffer();
this._shadowHelper.paint(framebuffer, allocation, paintOpacity);
}
this._drawingArea.paint(paintContext);
}
});
function clamp(value, min, max) {
return Math.max(min, Math.min(max, value));
}
/** /**
* If you are setting org.gnome.desktop.session.idle-delay directly in dconf, * If you are setting org.gnome.desktop.session.idle-delay directly in dconf,
* rather than through System Settings, you also need to set * rather than through System Settings, you also need to set
@ -447,59 +53,19 @@ var ScreenShield = class {
name: 'lockScreenGroup', name: 'lockScreenGroup',
visible: false, visible: false,
}); });
this._lockScreenGroup.connect('key-press-event',
this._onLockScreenKeyPress.bind(this));
this._lockScreenGroup.connect('scroll-event',
this._onLockScreenScroll.bind(this));
Main.ctrlAltTabManager.addGroup(this._lockScreenGroup, _("Lock"), 'changes-prevent-symbolic'); Main.ctrlAltTabManager.addGroup(this._lockScreenGroup, _("Lock"), 'changes-prevent-symbolic');
this._lockScreenContents = new St.Widget({ layout_manager: new Clutter.BinLayout(), this._lockDialogGroup = new St.Widget({
name: 'lockScreenContents' }); x_expand: true,
this._lockScreenContents.add_constraint(new Layout.MonitorConstraint({ primary: true })); y_expand: true,
reactive: true,
can_focus: true,
pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }),
name: 'lockDialogGroup',
});
this._lockScreenGroup.add_actor(this._lockScreenContents);
this._backgroundGroup = new Clutter.Actor();
this._lockScreenGroup.add_actor(this._backgroundGroup);
this._lockScreenGroup.set_child_below_sibling(this._backgroundGroup, null);
this._bgManagers = [];
this._updateBackgrounds();
Main.layoutManager.connect('monitors-changed', this._updateBackgrounds.bind(this));
this._arrowAnimationId = 0;
this._arrowWatchId = 0;
this._arrowActiveWatchId = 0;
this._arrowContainer = new St.BoxLayout({ style_class: 'screen-shield-arrows',
vertical: true,
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.END,
// HACK: without these, ClutterBinLayout
// ignores alignment properties on the actor
x_expand: true,
y_expand: true });
for (let i = 0; i < N_ARROWS; i++) {
let arrow = new Arrow({ opacity: 0 });
this._arrowContainer.add_actor(arrow);
}
this._lockScreenContents.add_actor(this._arrowContainer);
this._dragAction = new Clutter.GestureAction();
this._dragAction.connect('gesture-begin', this._onDragBegin.bind(this));
this._dragAction.connect('gesture-progress', this._onDragMotion.bind(this));
this._dragAction.connect('gesture-end', this._onDragEnd.bind(this));
this._lockScreenGroup.add_action(this._dragAction);
this._lockDialogGroup = new St.Widget({ x_expand: true,
y_expand: true,
reactive: true,
pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }),
name: 'lockDialogGroup' });
this.actor.add_actor(this._lockDialogGroup);
this.actor.add_actor(this._lockScreenGroup); this.actor.add_actor(this._lockScreenGroup);
this.actor.add_actor(this._lockDialogGroup);
this._presence = new GnomeSession.Presence((proxy, error) => { this._presence = new GnomeSession.Presence((proxy, error) => {
if (error) { if (error) {
@ -515,20 +81,6 @@ var ScreenShield = class {
this._screenSaverDBus = new ShellDBus.ScreenSaverDBus(this); this._screenSaverDBus = new ShellDBus.ScreenSaverDBus(this);
this._smartcardManager = SmartcardManager.getSmartcardManager();
this._smartcardManager.connect('smartcard-inserted',
(manager, token) => {
if (this._isLocked && token.UsedToLogin)
this._liftShield(true, 0);
});
this._oVirtCredentialsManager = OVirt.getOVirtCredentialsManager();
this._oVirtCredentialsManager.connect('user-authenticated',
() => {
if (this._isLocked)
this._liftShield(true, 0);
});
this._loginManager = LoginManager.getLoginManager(); this._loginManager = LoginManager.getLoginManager();
this._loginManager.connect('prepare-for-sleep', this._loginManager.connect('prepare-for-sleep',
this._prepareForSleep.bind(this)); this._prepareForSleep.bind(this));
@ -551,7 +103,6 @@ var ScreenShield = class {
this._lockSettings.connect(`changed::${DISABLE_LOCK_KEY}`, this._syncInhibitor.bind(this)); this._lockSettings.connect(`changed::${DISABLE_LOCK_KEY}`, this._syncInhibitor.bind(this));
this._isModal = false; this._isModal = false;
this._hasLockScreen = false;
this._isGreeter = false; this._isGreeter = false;
this._isActive = false; this._isActive = false;
this._isLocked = false; this._isLocked = false;
@ -591,44 +142,6 @@ var ScreenShield = class {
this._syncInhibitor(); this._syncInhibitor();
} }
_createBackground(monitorIndex) {
let monitor = Main.layoutManager.monitors[monitorIndex];
let widget = new St.Widget({ style_class: 'screen-shield-background',
x: monitor.x,
y: monitor.y,
width: monitor.width,
height: monitor.height });
let bgManager = new Background.BackgroundManager({ container: widget,
monitorIndex,
controlPosition: false,
settingsSchema: SCREENSAVER_SCHEMA });
this._bgManagers.push(bgManager);
this._backgroundGroup.add_child(widget);
}
_updateBackgrounds() {
for (let i = 0; i < this._bgManagers.length; i++)
this._bgManagers[i].destroy();
this._bgManagers = [];
this._backgroundGroup.destroy_all_children();
for (let i = 0; i < Main.layoutManager.monitors.length; i++)
this._createBackground(i);
}
_liftShield(onPrimary, velocity) {
if (this._isLocked) {
if (this._ensureUnlockDialog(onPrimary, true /* allowCancel */))
this._hideLockScreen(true /* animate */, velocity);
} else {
this.deactivate(true /* animate */);
}
}
_maybeCancelDialog() { _maybeCancelDialog() {
if (!this._dialog) if (!this._dialog)
return; return;
@ -638,9 +151,7 @@ var ScreenShield = class {
// LoginDialog.cancel() will grab the key focus // LoginDialog.cancel() will grab the key focus
// on its own, so ensure it stays on lock screen // on its own, so ensure it stays on lock screen
// instead // instead
this._lockScreenGroup.grab_key_focus(); this._dialog.grab_key_focus();
} else {
this._dialog = null;
} }
} }
@ -659,55 +170,6 @@ var ScreenShield = class {
return this._isModal; return this._isModal;
} }
_onLockScreenKeyPress(actor, event) {
let symbol = event.get_key_symbol();
let unichar = event.get_key_unicode();
// Do nothing if the lock screen is not fully shown.
// This avoids reusing the previous (and stale) unlock
// dialog if esc is pressed while the curtain is going
// down after cancel.
if (this._lockScreenState != MessageTray.State.SHOWN)
return Clutter.EVENT_PROPAGATE;
let isEnter = symbol == Clutter.KEY_Return ||
symbol == Clutter.KEY_KP_Enter ||
symbol == Clutter.KEY_ISO_Enter;
let isEscape = symbol == Clutter.KEY_Escape;
let isLiftChar = GLib.unichar_isprint(unichar) &&
(this._isLocked || !GLib.unichar_isgraph(unichar));
if (!isEnter && !isEscape && !isLiftChar)
return Clutter.EVENT_PROPAGATE;
if (this._isLocked &&
this._ensureUnlockDialog(true, true) &&
GLib.unichar_isgraph(unichar))
this._dialog.addCharacter(unichar);
this._liftShield(true, 0);
return Clutter.EVENT_STOP;
}
_onLockScreenScroll(actor, event) {
if (this._lockScreenState != MessageTray.State.SHOWN)
return Clutter.EVENT_PROPAGATE;
let delta = 0;
if (event.get_scroll_direction() == Clutter.ScrollDirection.SMOOTH)
delta = Math.abs(event.get_scroll_delta()[0]);
else
delta = 5;
this._lockScreenScrollCounter += delta;
// 7 standard scrolls to lift up
if (this._lockScreenScrollCounter > 35)
this._liftShield(true, 0);
return Clutter.EVENT_STOP;
}
_syncInhibitor() { _syncInhibitor() {
let lockEnabled = this._settings.get_boolean(LOCK_ENABLED_KEY); let lockEnabled = this._settings.get_boolean(LOCK_ENABLED_KEY);
let lockLocked = this._lockSettings.get_boolean(DISABLE_LOCK_KEY); let lockLocked = this._lockSettings.get_boolean(DISABLE_LOCK_KEY);
@ -736,79 +198,6 @@ var ScreenShield = class {
} }
} }
_animateArrows() {
let arrows = this._arrowContainer.get_children();
let unitaryDelay = ARROW_ANIMATION_TIME / (arrows.length + 1);
let maxOpacity = 255 * ARROW_ANIMATION_PEAK_OPACITY;
for (let i = 0; i < arrows.length; i++) {
arrows[i].opacity = 0;
arrows[i].ease({
opacity: maxOpacity,
delay: unitaryDelay * (N_ARROWS - (i + 1)),
duration: ARROW_ANIMATION_TIME / 2,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
arrows[i].ease({
opacity: 0,
duration: ARROW_ANIMATION_TIME / 2,
mode: Clutter.AnimationMode.EASE_IN_QUAD,
});
},
});
}
return GLib.SOURCE_CONTINUE;
}
_onDragBegin() {
this._lockScreenGroup.remove_all_transitions();
this._lockScreenState = MessageTray.State.HIDING;
if (this._isLocked)
this._ensureUnlockDialog(false, false);
return true;
}
_onDragMotion() {
let [, origY] = this._dragAction.get_press_coords(0);
let [, currentY] = this._dragAction.get_motion_coords(0);
let newY = currentY - origY;
newY = clamp(newY, -global.stage.height, 0);
this._lockScreenGroup.y = newY;
return true;
}
_onDragEnd(_action, _actor, _eventX, _eventY, _modifiers) {
if (this._lockScreenState != MessageTray.State.HIDING)
return;
if (this._lockScreenGroup.y < -(ARROW_DRAG_THRESHOLD * global.stage.height)) {
// Complete motion automatically
let [velocity_, velocityX_, velocityY] = this._dragAction.get_velocity(0);
this._liftShield(true, -velocityY);
} else {
// restore the lock screen to its original place
// try to use the same speed as the normal animation
let h = global.stage.height;
let duration = MANUAL_FADE_TIME * -this._lockScreenGroup.y / h;
this._lockScreenGroup.remove_all_transitions();
this._lockScreenGroup.ease({
y: 0,
duration,
mode: Clutter.AnimationMode.EASE_IN_QUAD,
onComplete: () => {
this._lockScreenGroup.fixed_position_set = false;
this._lockScreenState = MessageTray.State.SHOWN;
},
});
this._maybeCancelDialog();
}
}
_onStatusChanged(status) { _onStatusChanged(status) {
if (status != GnomeSession.PresenceStatus.IDLE) if (status != GnomeSession.PresenceStatus.IDLE)
return; return;
@ -914,14 +303,10 @@ var ScreenShield = class {
this.actor.show(); this.actor.show();
this._isGreeter = Main.sessionMode.isGreeter; this._isGreeter = Main.sessionMode.isGreeter;
this._isLocked = true; this._isLocked = true;
if (this._ensureUnlockDialog(true, true)) this._ensureUnlockDialog(true);
this._hideLockScreen(false, 0);
} }
_hideLockScreenComplete() { _hideLockScreenComplete() {
if (Main.sessionMode.currentMode == 'lock-screen')
Main.sessionMode.popMode('lock-screen');
this._lockScreenState = MessageTray.State.HIDDEN; this._lockScreenState = MessageTray.State.HIDDEN;
this._lockScreenGroup.hide(); this._lockScreenGroup.hide();
@ -931,13 +316,13 @@ var ScreenShield = class {
} }
} }
_hideLockScreen(animate, velocity) { _hideLockScreen(animate) {
if (this._lockScreenState == MessageTray.State.HIDDEN) if (this._lockScreenState == MessageTray.State.HIDDEN)
return; return;
this._lockScreenState = MessageTray.State.HIDING; this._lockScreenState = MessageTray.State.HIDING;
this._lockScreenGroup.remove_all_transitions(); this._lockDialogGroup.remove_all_transitions();
if (animate) { if (animate) {
// Tween the lock screen out of screen // Tween the lock screen out of screen
@ -945,16 +330,14 @@ var ScreenShield = class {
// use the same speed regardless of original position // use the same speed regardless of original position
// if velocity is specified, it's in pixels per milliseconds // if velocity is specified, it's in pixels per milliseconds
let h = global.stage.height; let h = global.stage.height;
let delta = h + this._lockScreenGroup.y; let delta = h + this._lockDialogGroup.translation_y;
let minVelocity = global.stage.height / CURTAIN_SLIDE_TIME; let velocity = global.stage.height / CURTAIN_SLIDE_TIME;
velocity = Math.max(minVelocity, velocity);
let duration = delta / velocity; let duration = delta / velocity;
this._lockScreenGroup.ease({ this._lockDialogGroup.ease({
y: -h, translation_y: -h,
duration, duration,
mode: Clutter.AnimationMode.EASE_IN_QUAD, mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => this._hideLockScreenComplete(), onComplete: () => this._hideLockScreenComplete(),
}); });
} else { } else {
@ -964,7 +347,7 @@ var ScreenShield = class {
this._cursorTracker.set_pointer_visible(true); this._cursorTracker.set_pointer_visible(true);
} }
_ensureUnlockDialog(onPrimary, allowCancel) { _ensureUnlockDialog(allowCancel) {
if (!this._dialog) { if (!this._dialog) {
let constructor = Main.sessionMode.unlockDialog; let constructor = Main.sessionMode.unlockDialog;
if (!constructor) { if (!constructor) {
@ -976,7 +359,7 @@ var ScreenShield = class {
this._dialog = new constructor(this._lockDialogGroup); this._dialog = new constructor(this._lockDialogGroup);
let time = global.get_current_time(); let time = global.get_current_time();
if (!this._dialog.open(time, onPrimary)) { if (!this._dialog.open(time)) {
// This is kind of an impossible error: we're already modal // This is kind of an impossible error: we're already modal
// by the time we reach this... // by the time we reach this...
log('Could not open login dialog: failed to acquire grab'); log('Could not open login dialog: failed to acquire grab');
@ -985,6 +368,8 @@ var ScreenShield = class {
} }
this._dialog.connect('failed', this._onUnlockFailed.bind(this)); this._dialog.connect('failed', this._onUnlockFailed.bind(this));
this._wakeUpScreenId = this._dialog.connect(
'wake-up-screen', this._wakeUpScreen.bind(this));
} }
this._dialog.allowCancel = allowCancel; this._dialog.allowCancel = allowCancel;
@ -1004,94 +389,30 @@ var ScreenShield = class {
if (this._lockScreenState != MessageTray.State.HIDDEN) if (this._lockScreenState != MessageTray.State.HIDDEN)
return; return;
this._ensureLockScreen();
this._lockDialogGroup.scale_x = 1;
this._lockDialogGroup.scale_y = 1;
this._lockScreenGroup.show(); this._lockScreenGroup.show();
this._lockScreenState = MessageTray.State.SHOWING; this._lockScreenState = MessageTray.State.SHOWING;
let fadeToBlack = params.fadeToBlack; let fadeToBlack = params.fadeToBlack;
if (params.animateLockScreen) { if (params.animateLockScreen) {
this._lockScreenGroup.y = -global.screen_height; this._lockDialogGroup.translation_y = -global.screen_height;
this._lockScreenGroup.remove_all_transitions(); this._lockDialogGroup.remove_all_transitions();
this._lockScreenGroup.ease({ this._lockDialogGroup.ease({
y: 0, translation_y: 0,
duration: MANUAL_FADE_TIME, duration: Overview.ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => { onComplete: () => {
this._lockScreenShown({ fadeToBlack, animateFade: true }); this._lockScreenShown({ fadeToBlack, animateFade: true });
}, },
}); });
} else { } else {
this._lockScreenGroup.fixed_position_set = false;
this._lockScreenShown({ fadeToBlack, animateFade: false }); this._lockScreenShown({ fadeToBlack, animateFade: false });
} }
this._lockScreenGroup.grab_key_focus(); this._dialog.grab_key_focus();
if (Main.sessionMode.currentMode != 'lock-screen')
Main.sessionMode.pushMode('lock-screen');
}
_startArrowAnimation() {
this._arrowActiveWatchId = 0;
if (!this._arrowAnimationId) {
this._arrowAnimationId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 6000, this._animateArrows.bind(this));
GLib.Source.set_name_by_id(this._arrowAnimationId, '[gnome-shell] this._animateArrows');
this._animateArrows();
}
if (!this._arrowWatchId) {
this._arrowWatchId = this.idleMonitor.add_idle_watch(ARROW_IDLE_TIME,
this._pauseArrowAnimation.bind(this));
}
}
_pauseArrowAnimation() {
if (this._arrowAnimationId) {
GLib.source_remove(this._arrowAnimationId);
this._arrowAnimationId = 0;
}
if (!this._arrowActiveWatchId)
this._arrowActiveWatchId = this.idleMonitor.add_user_active_watch(this._startArrowAnimation.bind(this));
}
_stopArrowAnimation() {
if (this._arrowAnimationId) {
GLib.source_remove(this._arrowAnimationId);
this._arrowAnimationId = 0;
}
if (this._arrowActiveWatchId) {
this.idleMonitor.remove_watch(this._arrowActiveWatchId);
this._arrowActiveWatchId = 0;
}
if (this._arrowWatchId) {
this.idleMonitor.remove_watch(this._arrowWatchId);
this._arrowWatchId = 0;
}
}
_checkArrowAnimation() {
let idleTime = this.idleMonitor.get_idletime();
if (idleTime < ARROW_IDLE_TIME)
this._startArrowAnimation();
else
this._pauseArrowAnimation();
} }
_lockScreenShown(params) { _lockScreenShown(params) {
if (this._dialog && !this._isGreeter) {
this._dialog.destroy();
this._dialog = null;
}
this._checkArrowAnimation();
let motionId = global.stage.connect('captured-event', (stage, event) => { let motionId = global.stage.connect('captured-event', (stage, event) => {
if (event.type() == Clutter.EventType.MOTION) { if (event.type() == Clutter.EventType.MOTION) {
this._cursorTracker.set_pointer_visible(true); this._cursorTracker.set_pointer_visible(true);
@ -1103,8 +424,6 @@ var ScreenShield = class {
this._cursorTracker.set_pointer_visible(false); this._cursorTracker.set_pointer_visible(false);
this._lockScreenState = MessageTray.State.SHOWN; this._lockScreenState = MessageTray.State.SHOWN;
this._lockScreenGroup.fixed_position_set = false;
this._lockScreenScrollCounter = 0;
if (params.fadeToBlack && params.animateFade) { if (params.fadeToBlack && params.animateFade) {
// Take a beat // Take a beat
@ -1127,52 +446,11 @@ var ScreenShield = class {
this.emit('lock-screen-shown'); this.emit('lock-screen-shown');
} }
// Some of the actors in the lock screen are heavy in
// resources, so we only create them when needed
_ensureLockScreen() {
if (this._hasLockScreen)
return;
this._lockScreenContentsBox = new St.BoxLayout({ x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER,
x_expand: true,
y_expand: true,
vertical: true,
style_class: 'screen-shield-contents-box' });
this._clock = new Clock();
this._lockScreenContentsBox.add_child(this._clock);
this._lockScreenContents.add_actor(this._lockScreenContentsBox);
this._notificationsBox = new NotificationsBox();
this._wakeUpScreenId = this._notificationsBox.connect('wake-up-screen', this._wakeUpScreen.bind(this));
this._lockScreenContentsBox.add_child(this._notificationsBox);
this._hasLockScreen = true;
}
_wakeUpScreen() { _wakeUpScreen() {
this._onUserBecameActive(); this._onUserBecameActive();
this.emit('wake-up-screen'); this.emit('wake-up-screen');
} }
_clearLockScreen() {
this._clock.destroy();
this._clock = null;
if (this._notificationsBox) {
this._notificationsBox.disconnect(this._wakeUpScreenId);
this._notificationsBox.destroy();
this._notificationsBox = null;
}
this._stopArrowAnimation();
this._lockScreenContentsBox.destroy();
this._hasLockScreen = false;
}
get locked() { get locked() {
return this._isLocked; return this._isLocked;
} }
@ -1193,13 +471,8 @@ var ScreenShield = class {
} }
_continueDeactivate(animate) { _continueDeactivate(animate) {
this._hideLockScreen(animate, 0); this._hideLockScreen(animate);
if (this._hasLockScreen)
this._clearLockScreen();
if (Main.sessionMode.currentMode == 'lock-screen')
Main.sessionMode.popMode('lock-screen');
if (Main.sessionMode.currentMode == 'unlock-dialog') if (Main.sessionMode.currentMode == 'unlock-dialog')
Main.sessionMode.popMode('unlock-dialog'); Main.sessionMode.popMode('unlock-dialog');
@ -1225,9 +498,8 @@ var ScreenShield = class {
} }
this._lockDialogGroup.ease({ this._lockDialogGroup.ease({
scale_x: 0, translation_y: -global.screen_height,
scale_y: 0, duration: Overview.ANIMATION_TIME,
duration: animate ? Overview.ANIMATION_TIME : 0,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => this._completeDeactivate(), onComplete: () => this._completeDeactivate(),
}); });
@ -1264,10 +536,11 @@ var ScreenShield = class {
if (this._activationTime == 0) if (this._activationTime == 0)
this._activationTime = GLib.get_monotonic_time(); this._activationTime = GLib.get_monotonic_time();
this._ensureUnlockDialog(true);
this.actor.show(); this.actor.show();
if (Main.sessionMode.currentMode != 'unlock-dialog' && if (Main.sessionMode.currentMode != 'unlock-dialog') {
Main.sessionMode.currentMode != 'lock-screen') {
this._isGreeter = Main.sessionMode.isGreeter; this._isGreeter = Main.sessionMode.isGreeter;
if (!this._isGreeter) if (!this._isGreeter)
Main.sessionMode.pushMode('unlock-dialog'); Main.sessionMode.pushMode('unlock-dialog');

View File

@ -53,19 +53,6 @@ const _modes = {
panelStyle: 'login-screen', panelStyle: 'login-screen',
}, },
'lock-screen': {
isLocked: true,
isGreeter: undefined,
unlockDialog: undefined,
components: ['polkitAgent', 'telepathyClient'],
panel: {
left: [],
center: [],
right: ['aggregateMenu'],
},
panelStyle: 'lock-screen',
},
'unlock-dialog': { 'unlock-dialog': {
isLocked: true, isLocked: true,
unlockDialog: undefined, unlockDialog: undefined,

View File

@ -1,61 +1,558 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported UnlockDialog */ /* exported UnlockDialog */
const { AccountsService, Atk, Clutter, const { AccountsService, Atk, Clutter, Gdm, Gio,
Gdm, Gio, GLib, GObject, Meta, Shell, St } = imports.gi; GnomeDesktop, GLib, GObject, Meta, Shell, St } = imports.gi;
const Background = imports.ui.background;
const Layout = imports.ui.layout; const Layout = imports.ui.layout;
const Main = imports.ui.main; const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const AuthPrompt = imports.gdm.authPrompt; const AuthPrompt = imports.gdm.authPrompt;
// The timeout before going back automatically to the lock screen (in seconds) // The timeout before going back automatically to the lock screen (in seconds)
const IDLE_TIMEOUT = 2 * 60; const IDLE_TIMEOUT = 2 * 60;
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
const BLUR_BRIGHTNESS = 0.55;
const BLUR_RADIUS = 200;
const SUMMARY_ICON_SIZE = 32;
var NotificationsBox = GObject.registerClass({
Signals: { 'wake-up-screen': {} },
}, class NotificationsBox extends St.BoxLayout {
_init() {
super._init({
vertical: true,
name: 'unlockDialogNotifications',
style_class: 'unlock-dialog-notifications-container',
});
this._scrollView = new St.ScrollView({ hscrollbar_policy: St.PolicyType.NEVER });
this._notificationBox = new St.BoxLayout({ vertical: true,
style_class: 'unlock-dialog-notifications-container' });
this._scrollView.add_actor(this._notificationBox);
this.add_child(this._scrollView);
this._sources = new Map();
Main.messageTray.getSources().forEach(source => {
this._sourceAdded(Main.messageTray, source, true);
});
this._updateVisibility();
this._sourceAddedId = Main.messageTray.connect('source-added', this._sourceAdded.bind(this));
this.connect('destroy', this._onDestroy.bind(this));
}
_onDestroy() {
if (this._sourceAddedId) {
Main.messageTray.disconnect(this._sourceAddedId);
this._sourceAddedId = 0;
}
let items = this._sources.entries();
for (let [source, obj] of items)
this._removeSource(source, obj);
}
_updateVisibility() {
this._notificationBox.visible =
this._notificationBox.get_children().some(a => a.visible);
this.visible = this._notificationBox.visible;
}
_makeNotificationCountText(count) {
return "%d".format(count);
}
_makeNotificationSource(source, box) {
let sourceActor = new MessageTray.SourceActor(source, SUMMARY_ICON_SIZE);
box.add_child(sourceActor);
let textBox = new St.BoxLayout({
x_expand: true,
y_expand: true,
y_align: Clutter.ActorAlign.CENTER,
});
box.add_child(textBox);
let title = new St.Label({
text: source.title,
style_class: 'unlock-dialog-notification-label',
x_expand: true,
x_align: Clutter.ActorAlign.START,
});
textBox.add(title);
let count = source.unseenCount;
let countLabel = new St.Label({
text: this._makeNotificationCountText(count),
style_class: 'unlock-dialog-notification-count-text',
});
textBox.add(countLabel);
box.visible = count != 0;
return [title, countLabel];
}
_makeNotificationDetailedSource(source, box) {
let sourceActor = new MessageTray.SourceActor(source, SUMMARY_ICON_SIZE);
let sourceBin = new St.Bin({ child: sourceActor });
box.add(sourceBin);
let textBox = new St.BoxLayout({ vertical: true });
box.add_child(textBox);
let title = new St.Label({ text: source.title,
style_class: 'unlock-dialog-notification-label' });
textBox.add(title);
let visible = false;
for (let i = 0; i < source.notifications.length; i++) {
let n = source.notifications[i];
if (n.acknowledged)
continue;
let body = '';
if (n.bannerBodyText) {
body = n.bannerBodyMarkup
? n.bannerBodyText
: GLib.markup_escape_text(n.bannerBodyText, -1);
}
let label = new St.Label({ style_class: 'unlock-dialog-notification-count-text' });
label.clutter_text.set_markup(`<b>${n.title}</b> ${body}`);
textBox.add(label);
visible = true;
}
box.visible = visible;
return [title, null];
}
_shouldShowDetails(source) {
return source.policy.detailsInLockScreen ||
source.narrowestPrivacyScope == MessageTray.PrivacyScope.SYSTEM;
}
_showSource(source, obj, box) {
if (obj.detailed)
[obj.titleLabel, obj.countLabel] = this._makeNotificationDetailedSource(source, box);
else
[obj.titleLabel, obj.countLabel] = this._makeNotificationSource(source, box);
box.visible = obj.visible && (source.unseenCount > 0);
}
_sourceAdded(tray, source, initial) {
let obj = {
visible: source.policy.showInLockScreen,
detailed: this._shouldShowDetails(source),
sourceDestroyId: 0,
sourceCountChangedId: 0,
sourceTitleChangedId: 0,
sourceUpdatedId: 0,
sourceBox: null,
titleLabel: null,
countLabel: null,
};
obj.sourceBox = new St.BoxLayout({ style_class: 'unlock-dialog-notification-source',
x_expand: true });
this._showSource(source, obj, obj.sourceBox);
this._notificationBox.add_child(obj.sourceBox);
obj.sourceCountChangedId = source.connect('notify::count', () => {
this._countChanged(source, obj);
});
obj.sourceTitleChangedId = source.connect('notify::title', () => {
this._titleChanged(source, obj);
});
obj.policyChangedId = source.policy.connect('notify', (policy, pspec) => {
if (pspec.name == 'show-in-lock-screen')
this._visibleChanged(source, obj);
else
this._detailedChanged(source, obj);
});
obj.sourceDestroyId = source.connect('destroy', () => {
this._onSourceDestroy(source, obj);
});
this._sources.set(source, obj);
if (!initial) {
// block scrollbars while animating, if they're not needed now
let boxHeight = this._notificationBox.height;
if (this._scrollView.height >= boxHeight)
this._scrollView.vscrollbar_policy = St.PolicyType.NEVER;
let widget = obj.sourceBox;
let [, natHeight] = widget.get_preferred_height(-1);
widget.height = 0;
widget.ease({
height: natHeight,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: 250,
onComplete: () => {
this._scrollView.vscrollbar_policy = St.PolicyType.AUTOMATIC;
widget.set_height(-1);
},
});
this._updateVisibility();
if (obj.sourceBox.visible)
this.emit('wake-up-screen');
}
}
_titleChanged(source, obj) {
obj.titleLabel.text = source.title;
}
_countChanged(source, obj) {
// A change in the number of notifications may change whether we show
// details.
let newDetailed = this._shouldShowDetails(source);
let oldDetailed = obj.detailed;
obj.detailed = newDetailed;
if (obj.detailed || oldDetailed != newDetailed) {
// A new notification was pushed, or a previous notification was destroyed.
// Give up, and build the list again.
obj.sourceBox.destroy_all_children();
obj.titleLabel = obj.countLabel = null;
this._showSource(source, obj, obj.sourceBox);
} else {
let count = source.unseenCount;
obj.countLabel.text = this._makeNotificationCountText(count);
}
obj.sourceBox.visible = obj.visible && (source.unseenCount > 0);
this._updateVisibility();
if (obj.sourceBox.visible)
this.emit('wake-up-screen');
}
_visibleChanged(source, obj) {
if (obj.visible == source.policy.showInLockScreen)
return;
obj.visible = source.policy.showInLockScreen;
obj.sourceBox.visible = obj.visible && source.unseenCount > 0;
this._updateVisibility();
if (obj.sourceBox.visible)
this.emit('wake-up-screen');
}
_detailedChanged(source, obj) {
let newDetailed = this._shouldShowDetails(source);
if (obj.detailed == newDetailed)
return;
obj.detailed = newDetailed;
obj.sourceBox.destroy_all_children();
obj.titleLabel = obj.countLabel = null;
this._showSource(source, obj, obj.sourceBox);
}
_onSourceDestroy(source, obj) {
this._removeSource(source, obj);
this._updateVisibility();
}
_removeSource(source, obj) {
obj.sourceBox.destroy();
obj.sourceBox = obj.titleLabel = obj.countLabel = null;
source.disconnect(obj.sourceDestroyId);
source.disconnect(obj.sourceCountChangedId);
source.disconnect(obj.sourceTitleChangedId);
source.policy.disconnect(obj.policyChangedId);
this._sources.delete(source);
}
});
var Clock = GObject.registerClass(
class UnlockDialogClock extends St.BoxLayout {
_init() {
super._init({ style_class: 'unlock-dialog-clock', vertical: true });
this._time = new St.Label({
style_class: 'unlock-dialog-clock-time',
x_align: Clutter.ActorAlign.CENTER,
});
this._date = new St.Label({
style_class: 'unlock-dialog-clock-date',
x_align: Clutter.ActorAlign.CENTER,
});
this.add_child(this._time);
this.add_child(this._date);
this._wallClock = new GnomeDesktop.WallClock({ time_only: true });
this._wallClock.connect('notify::clock', this._updateClock.bind(this));
this._updateClock();
this.connect('destroy', this._onDestroy.bind(this));
}
_updateClock() {
this._time.text = this._wallClock.clock;
let date = new Date();
/* Translators: This is a time format for a date in
long format */
let dateFormat = Shell.util_translate_time_string(N_("%A, %B %d"));
this._date.text = date.toLocaleFormat(dateFormat);
}
_onDestroy() {
this._wallClock.run_dispose();
}
});
var UnlockDialogLayout = GObject.registerClass(
class UnlockDialogLayout extends Clutter.LayoutManager {
_init(stack, notifications) {
super._init();
this._stack = stack;
this._notifications = notifications;
}
vfunc_get_preferred_width(container, forHeight) {
return this._stack.get_preferred_width(forHeight);
}
vfunc_get_preferred_height(container, forWidth) {
return this._stack.get_preferred_height(forWidth);
}
vfunc_allocate(container, box, flags) {
let [width, height] = box.get_size();
let tenthOfHeight = height / 10.0;
let thirdOfHeight = height / 3.0;
let [, , stackWidth, stackHeight] =
this._stack.get_preferred_size();
let [, , notificationsWidth, notificationsHeight] =
this._notifications.get_preferred_size();
let columnWidth = Math.max(stackWidth, notificationsWidth);
let columnX1 = Math.floor(width / 2.0 - columnWidth / 2.0);
let actorBox = new Clutter.ActorBox();
// Notifications
let maxNotificationsHeight = Math.min(
notificationsHeight,
height - tenthOfHeight - stackHeight);
actorBox.x1 = columnX1;
actorBox.y1 = height - maxNotificationsHeight;
actorBox.x2 = columnX1 + columnWidth;
actorBox.y2 = actorBox.y1 + maxNotificationsHeight;
this._notifications.allocate(actorBox, flags);
// Authentication Box
let stackY = Math.min(
thirdOfHeight,
height - stackHeight - maxNotificationsHeight);
actorBox.x1 = columnX1;
actorBox.y1 = stackY;
actorBox.x2 = columnX1 + columnWidth;
actorBox.y2 = stackY + stackHeight;
this._stack.allocate(actorBox, flags);
}
});
var UnlockDialog = GObject.registerClass({ var UnlockDialog = GObject.registerClass({
Signals: { 'failed': {} }, Signals: {
'failed': {},
'wake-up-screen': {},
},
}, class UnlockDialog extends St.Widget { }, class UnlockDialog extends St.Widget {
_init(parentActor) { _init(parentActor) {
super._init({ super._init({
accessible_role: Atk.Role.WINDOW, accessible_role: Atk.Role.WINDOW,
style_class: 'login-dialog', style_class: 'login-dialog',
layout_manager: new Clutter.BoxLayout(),
visible: false, visible: false,
can_focus: true,
reactive: true,
}); });
this.add_constraint(new Layout.MonitorConstraint({ primary: true }));
parentActor.add_child(this); parentActor.add_child(this);
this._activePage = null;
let tapAction = new Clutter.TapAction();
tapAction.connect('tap', this._showPrompt.bind(this));
this.add_action(tapAction);
// Background
this._backgroundGroup = new Clutter.Actor();
this.add_child(this._backgroundGroup);
this.set_child_below_sibling(this._backgroundGroup, null);
this._bgManagers = [];
this._updateBackgrounds();
Main.layoutManager.connect('monitors-changed', this._updateBackgrounds.bind(this));
this._userManager = AccountsService.UserManager.get_default(); this._userManager = AccountsService.UserManager.get_default();
this._userName = GLib.get_user_name(); this._userName = GLib.get_user_name();
this._user = this._userManager.get_user(this._userName); this._user = this._userManager.get_user(this._userName);
this._promptBox = new St.BoxLayout({ vertical: true, // Authentication & Clock stack
x_align: Clutter.ActorAlign.CENTER, let stack = new Shell.Stack();
y_align: Clutter.ActorAlign.CENTER,
x_expand: true, this._promptBox = new St.BoxLayout({ vertical: true });
y_expand: true }); stack.add_child(this._promptBox);
this.add_child(this._promptBox);
// Clock
this._clock = new St.BoxLayout({ vertical: true });
let clock = new Clock();
this._clock.add_child(clock);
let nameLabel = new St.Label({
style_class: 'unlock-dialog-user-name',
text: this._user.get_real_name(),
x_expand: true,
x_align: Clutter.ActorAlign.CENTER,
});
this._clock.add_child(nameLabel);
stack.add_child(this._clock);
this._showClock();
this.allowCancel = false;
Main.ctrlAltTabManager.addGroup(this, _("Unlock Window"), 'dialog-password-symbolic');
// Notifications
this._notificationsBox = new NotificationsBox();
this._wakeUpScreenId = this._notificationsBox.connect('wake-up-screen', () => {
this.emit('wake-up-screen');
});
// Main Box
let mainBox = new Clutter.Actor();
mainBox.add_constraint(new Layout.MonitorConstraint({ primary: true }));
mainBox.add_child(stack);
mainBox.add_child(this._notificationsBox);
mainBox.layout_manager = new UnlockDialogLayout(
stack,
this._notificationsBox);
this.add_child(mainBox);
this._idleMonitor = Meta.IdleMonitor.get_core();
this._idleWatchId = this._idleMonitor.add_idle_watch(IDLE_TIMEOUT * 1000, this._escape.bind(this));
this.connect('destroy', this._onDestroy.bind(this));
}
vfunc_key_press_event(keyEvent) {
if (this._activePage == this._promptBox)
return Clutter.EVENT_PROPAGATE;
let symbol = keyEvent.keyval;
let unichar = keyEvent.unicode_value;
let isLiftChar = GLib.unichar_isprint(unichar);
let isEnter = symbol == Clutter.KEY_Return ||
symbol == Clutter.KEY_KP_Enter ||
symbol == Clutter.KEY_ISO_Enter;
if (!isEnter && !isLiftChar)
return Clutter.EVENT_PROPAGATE;
this._showPrompt();
if (GLib.unichar_isgraph(unichar))
this.addCharacter(unichar);
return Clutter.EVENT_PROPAGATE;
}
_createBackground(monitorIndex) {
let monitor = Main.layoutManager.monitors[monitorIndex];
let widget = new St.Widget({ style_class: 'screen-shield-background',
x: monitor.x,
y: monitor.y,
width: monitor.width,
height: monitor.height });
let bgManager = new Background.BackgroundManager({ container: widget,
monitorIndex,
controlPosition: false,
settingsSchema: SCREENSAVER_SCHEMA });
this._bgManagers.push(bgManager);
this._backgroundGroup.add_child(widget);
widget.add_effect(new Shell.BlurEffect({
brightness: BLUR_BRIGHTNESS,
blur_radius: BLUR_RADIUS,
}));
}
_updateBackgrounds() {
for (let i = 0; i < this._bgManagers.length; i++)
this._bgManagers[i].destroy();
this._bgManagers = [];
this._backgroundGroup.destroy_all_children();
for (let i = 0; i < Main.layoutManager.monitors.length; i++)
this._createBackground(i);
}
_ensureAuthPrompt() {
if (this._authPrompt)
return;
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', this._fail.bind(this)); this._authPrompt.connect('failed', this._fail.bind(this));
this._authPrompt.connect('cancelled', this._fail.bind(this)); this._authPrompt.connect('cancelled', this._fail.bind(this));
this._authPrompt.connect('reset', this._onReset.bind(this)); this._authPrompt.connect('reset', this._onReset.bind(this));
this._authPrompt.setPasswordChar('\u25cf'); this._authPrompt.setPasswordChar('\u25cf');
this._authPrompt.nextButton.label = _("Unlock");
this._promptBox.add_child(this._authPrompt); this._promptBox.add_child(this._authPrompt);
this.allowCancel = false;
let screenSaverSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.screensaver' }); let screenSaverSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.screensaver' });
if (screenSaverSettings.get_boolean('user-switch-enabled')) { if (screenSaverSettings.get_boolean('user-switch-enabled')) {
let otherUserLabel = new St.Label({ text: _("Log in as another user"), let otherUserLabel = new St.Label({
style_class: 'login-dialog-not-listed-label' }); text: _("Log in as another user"),
this._otherUserButton = new St.Button({ style_class: 'login-dialog-not-listed-button', style_class: 'login-dialog-not-listed-label',
can_focus: true, });
child: otherUserLabel, this._otherUserButton = new St.Button({
reactive: true }); style_class: 'login-dialog-not-listed-button',
can_focus: true,
child: otherUserLabel,
reactive: true,
});
this._otherUserButton.connect('clicked', this._otherUserClicked.bind(this)); this._otherUserButton.connect('clicked', this._otherUserClicked.bind(this));
this._promptBox.add_child(this._otherUserButton); this._promptBox.add_child(this._otherUserButton);
} else { } else {
@ -64,13 +561,18 @@ var UnlockDialog = GObject.registerClass({
this._authPrompt.reset(); this._authPrompt.reset();
this._updateSensitivity(true); this._updateSensitivity(true);
}
Main.ctrlAltTabManager.addGroup(this, _("Unlock Window"), 'dialog-password-symbolic'); _maybeDestroyAuthPrompt() {
this.grab_key_focus();
this._idleMonitor = Meta.IdleMonitor.get_core(); if (this._authPrompt) {
this._idleWatchId = this._idleMonitor.add_idle_watch(IDLE_TIMEOUT * 1000, this._escape.bind(this)); this._authPrompt.destroy();
this._authPrompt = null;
this.connect('destroy', this._onDestroy.bind(this)); this._otherUserButton.destroy();
this._otherUserButton = null;
}
} }
_updateSensitivity(sensitive) { _updateSensitivity(sensitive) {
@ -82,7 +584,55 @@ var UnlockDialog = GObject.registerClass({
} }
} }
_showClock() {
if (this._activePage == this._clock)
return;
this._activePage = this._clock;
this._clock.show();
this._promptBox.ease({
opacity: 0,
duration: 300,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
this._promptBox.hide();
this._maybeDestroyAuthPrompt();
},
});
this._clock.ease({
opacity: 255,
duration: 300,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
});
}
_showPrompt() {
this._ensureAuthPrompt();
if (this._activePage == this._promptBox)
return;
this._activePage = this._promptBox;
this._promptBox.show();
this._clock.ease({
opacity: 0,
duration: 300,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => this._clock.hide(),
});
this._promptBox.ease({
opacity: 255,
duration: 300,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
});
}
_fail() { _fail() {
this._showClock();
this.emit('failed'); this.emit('failed');
} }
@ -110,6 +660,17 @@ var UnlockDialog = GObject.registerClass({
} }
_onDestroy() { _onDestroy() {
if (this._clock) {
this._clock.destroy();
this._clock = null;
}
if (this._notificationsBox) {
this._notificationsBox.disconnect(this._wakeUpScreenId);
this._notificationsBox.destroy();
this._notificationsBox = null;
}
this.popModal(); this.popModal();
if (this._idleWatchId) { if (this._idleWatchId) {
@ -119,16 +680,17 @@ var UnlockDialog = GObject.registerClass({
} }
cancel() { cancel() {
this._ensureAuthPrompt();
this._authPrompt.cancel(); this._authPrompt.cancel();
this.destroy();
} }
addCharacter(unichar) { addCharacter(unichar) {
this._showPrompt();
this._authPrompt.addCharacter(unichar); this._authPrompt.addCharacter(unichar);
} }
finish(onComplete) { finish(onComplete) {
this._ensureAuthPrompt();
this._authPrompt.finish(onComplete); this._authPrompt.finish(onComplete);
} }

View File

@ -7,7 +7,7 @@ const { Clutter, GLib, GObject, St } = imports.gi;
const Params = imports.misc.params; const Params = imports.misc.params;
var AVATAR_ICON_SIZE = 64; var AVATAR_ICON_SIZE = 128;
// Adapted from gdm/gui/user-switch-applet/applet.c // Adapted from gdm/gui/user-switch-applet/applet.c
// //
@ -20,7 +20,8 @@ class Avatar extends St.Bin {
let themeContext = St.ThemeContext.get_for_stage(global.stage); let themeContext = St.ThemeContext.get_for_stage(global.stage);
params = Params.parse(params, { reactive: false, params = Params.parse(params, { reactive: false,
iconSize: AVATAR_ICON_SIZE, iconSize: AVATAR_ICON_SIZE,
styleClass: 'user-icon' }); styleClass: 'user-icon',
x_align: St.Align.MIDDLE, });
super._init({ super._init({
style_class: params.styleClass, style_class: params.styleClass,
@ -73,7 +74,9 @@ class Avatar extends St.Bin {
} else { } else {
this.style = null; this.style = null;
this.child = new St.Icon({ icon_name: 'avatar-default-symbolic', this.child = new St.Icon({ icon_name: 'avatar-default-symbolic',
icon_size: this._iconSize }); icon_size: this._iconSize,
x_expand: true,
x_align: Clutter.ActorAlign.CENTER });
} }
} }
}); });
@ -86,11 +89,13 @@ class UserWidgetLabel extends St.Widget {
this._user = user; this._user = user;
this._realNameLabel = new St.Label({ style_class: 'user-widget-label', this._realNameLabel = new St.Label({ style_class: 'user-widget-label',
y_align: Clutter.ActorAlign.CENTER }); x_expand: true,
x_align: Clutter.ActorAlign.CENTER });
this.add_child(this._realNameLabel); this.add_child(this._realNameLabel);
this._userNameLabel = new St.Label({ style_class: 'user-widget-label', this._userNameLabel = new St.Label({ style_class: 'user-widget-label',
y_align: Clutter.ActorAlign.CENTER }); x_expand: true,
x_align: Clutter.ActorAlign.CENTER });
this.add_child(this._userNameLabel); this.add_child(this._userNameLabel);
this._currentLabel = null; this._currentLabel = null;
@ -160,7 +165,7 @@ class UserWidgetLabel extends St.Widget {
var UserWidget = GObject.registerClass( var UserWidget = GObject.registerClass(
class UserWidget extends St.BoxLayout { class UserWidget extends St.BoxLayout {
_init(user) { _init(user) {
super._init({ style_class: 'user-widget', vertical: false }); super._init({ style_class: 'user-widget', vertical: true });
this._user = user; this._user = user;

View File

@ -95,6 +95,7 @@ libshell_public_headers = [
'shell-app.h', 'shell-app.h',
'shell-app-system.h', 'shell-app-system.h',
'shell-app-usage.h', 'shell-app-usage.h',
'shell-blur-effect.h',
'shell-embedded-window.h', 'shell-embedded-window.h',
'shell-glsl-effect.h', 'shell-glsl-effect.h',
'shell-gtk-embed.h', 'shell-gtk-embed.h',
@ -129,6 +130,7 @@ libshell_sources = [
'shell-app.c', 'shell-app.c',
'shell-app-system.c', 'shell-app-system.c',
'shell-app-usage.c', 'shell-app-usage.c',
'shell-blur-effect.c',
'shell-embedded-window.c', 'shell-embedded-window.c',
'shell-embedded-window-private.h', 'shell-embedded-window-private.h',
'shell-global.c', 'shell-global.c',

1079
src/shell-blur-effect.c Normal file

File diff suppressed because it is too large Load Diff

57
src/shell-blur-effect.h Normal file
View File

@ -0,0 +1,57 @@
/* shell-blur-effect.h
*
* Copyright 2019 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
#include <clutter/clutter.h>
G_BEGIN_DECLS
/**
* ShellBlurMode:
* @SHELL_BLUR_MODE_ACTOR: blur the actor contents, and its children
* @SHELL_BLUR_MODE_BELOW: blur what's beneath the actor
*
* The mode of blurring of the effect.
*/
typedef enum
{
SHELL_BLUR_MODE_ACTOR,
SHELL_BLUR_MODE_BELOW,
} ShellBlurMode;
#define SHELL_TYPE_BLUR_EFFECT (shell_blur_effect_get_type())
G_DECLARE_FINAL_TYPE (ShellBlurEffect, shell_blur_effect, SHELL, BLUR_EFFECT, ClutterEffect)
ShellBlurEffect *shell_blur_effect_new (void);
int shell_blur_effect_get_blur_radius (ShellBlurEffect *self);
void shell_blur_effect_set_blur_radius (ShellBlurEffect *self,
int radius);
float shell_blur_effect_get_brightness (ShellBlurEffect *self);
void shell_blur_effect_set_brightness (ShellBlurEffect *self,
float brightness);
ShellBlurMode shell_blur_effect_get_mode (ShellBlurEffect *self);
void shell_blur_effect_set_mode (ShellBlurEffect *self,
ShellBlurMode mode);
G_END_DECLS