1
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
3
const Cairo = imports.cairo;
4
const Clutter = imports.gi.Clutter;
5
const Gio = imports.gi.Gio;
6
const GLib = imports.gi.GLib;
7
const GnomeDesktop = imports.gi.GnomeDesktop;
8
const Lang = imports.lang;
9
const Mainloop = imports.mainloop;
10
const Meta = imports.gi.Meta;
11
const Signals = imports.signals;
12
const St = imports.gi.St;
13
const TweenerEquations = imports.tweener.equations;
15
const GnomeSession = imports.misc.gnomeSession;
16
const Layout = imports.ui.layout;
17
const LoginManager = imports.misc.loginManager;
18
const Lightbox = imports.ui.lightbox;
19
const Main = imports.ui.main;
20
const Overview = imports.ui.overview;
21
const MessageTray = imports.ui.messageTray;
22
const ShellDBus = imports.ui.shellDBus;
23
const Tweener = imports.ui.tweener;
25
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
26
const LOCK_ENABLED_KEY = 'lock-enabled';
28
const CURTAIN_SLIDE_TIME = 0.5;
29
// fraction of screen height the arrow must reach before completing
30
// the slide up automatically
31
const ARROW_DRAG_THRESHOLD = 0.1;
33
// Parameters for the arrow animation
35
const ARROW_ANIMATION_TIME = 0.6;
36
const ARROW_ANIMATION_PEAK_OPACITY = 0.4;
38
// The distance in px that the lock screen will move to when pressing
39
// a key that has no effect in the lock screen (bumping it)
41
const BUMP_TIME = 0.3;
43
const SUMMARY_ICON_SIZE = 48;
45
// Lightbox fading times
46
// STANDARD_FADE_TIME is used when the session goes idle, while
47
// SHORT_FADE_TIME is used when requesting lock explicitly from the user menu
48
const STANDARD_FADE_TIME = 10;
49
const SHORT_FADE_TIME = 0.8;
51
const Clock = new Lang.Class({
52
Name: 'ScreenShieldClock',
54
CLOCK_FORMAT_KEY: 'clock-format',
55
CLOCK_SHOW_SECONDS_KEY: 'clock-show-seconds',
58
this.actor = new St.BoxLayout({ style_class: 'screen-shield-clock',
61
this._time = new St.Label({ style_class: 'screen-shield-clock-time' });
62
this._date = new St.Label({ style_class: 'screen-shield-clock-date' });
64
this.actor.add(this._time, { x_align: St.Align.MIDDLE });
65
this.actor.add(this._date, { x_align: St.Align.MIDDLE });
67
this._wallClock = new GnomeDesktop.WallClock({ time_only: true });
68
this._wallClock.connect('notify::clock', Lang.bind(this, this._updateClock));
73
_updateClock: function() {
74
this._time.text = this._wallClock.clock;
76
let date = new Date();
77
/* Translators: This is a time format for a date in
79
this._date.text = date.toLocaleFormat(_("%A, %B %d"));
84
this._wallClock.run_dispose();
88
const NotificationsBox = new Lang.Class({
89
Name: 'NotificationsBox',
92
this.actor = new St.BoxLayout({ vertical: true,
93
name: 'screenShieldNotifications',
94
style_class: 'screen-shield-notifications-box' });
96
this._residentNotificationBox = new St.BoxLayout({ vertical: true,
97
style_class: 'screen-shield-notifications-box' });
98
let scrollView = new St.ScrollView({ x_fill: false, x_align: St.Align.MIDDLE });
99
this._persistentNotificationBox = new St.BoxLayout({ vertical: true,
100
style_class: 'screen-shield-notifications-box' });
101
scrollView.add_actor(this._persistentNotificationBox);
103
this.actor.add(this._residentNotificationBox, { x_fill: true });
104
this.actor.add(scrollView, { x_fill: true, x_align: St.Align.MIDDLE });
107
Main.messageTray.getSummaryItems().forEach(Lang.bind(this, function(item) {
108
this._summaryItemAdded(Main.messageTray, item, true);
110
this._updateVisibility();
112
this._summaryAddedId = Main.messageTray.connect('summary-item-added', Lang.bind(this, this._summaryItemAdded));
115
destroy: function() {
116
if (this._summaryAddedId) {
117
Main.messageTray.disconnect(this._summaryAddedId);
118
this._summaryAddedId = 0;
121
for (let i = 0; i < this._items.length; i++)
122
this._removeItem(this._items[i]);
125
this.actor.destroy();
128
_updateVisibility: function() {
129
if (this._residentNotificationBox.get_n_children() > 0) {
134
let children = this._persistentNotificationBox.get_children();
135
this.actor.visible = children.some(function(a) { return a.visible; });
138
_sourceIsResident: function(source) {
139
return source.hasResidentNotification() && !source.isChat;
142
_makeNotificationCountText: function(count, isChat) {
144
return ngettext("%d new message", "%d new messages", count).format(count);
146
return ngettext("%d new notification", "%d new notifications", count).format(count);
149
_makeNotificationSource: function(source) {
150
let box = new St.BoxLayout({ style_class: 'screen-shield-notification-source' });
152
let sourceActor = new MessageTray.SourceActor(source, SUMMARY_ICON_SIZE);
153
box.add(sourceActor.actor, { y_fill: true });
155
let textBox = new St.BoxLayout({ vertical: true });
158
let label = new St.Label({ text: source.title,
159
style_class: 'screen-shield-notification-label' });
162
let count = source.unseenCount;
163
let countLabel = new St.Label({ text: this._makeNotificationCountText(count, source.isChat),
164
style_class: 'screen-shield-notification-count-text' });
165
textBox.add(countLabel);
167
box.visible = count != 0;
168
return [box, countLabel];
171
_summaryItemAdded: function(tray, item, dontUpdateVisibility) {
172
// Ignore transient sources, or sources explicitly marked not to show
173
// in the lock screen
174
if (item.source.isTransient || !item.source.showInLockScreen)
180
resident: this._sourceIsResident(item.source),
188
this._residentNotificationBox.add(item.notificationStackWidget);
189
item.closeButtonVisible = false;
190
item.prepareNotificationStackForShowing();
192
[obj.sourceBox, obj.countLabel] = this._makeNotificationSource(item.source);
193
this._persistentNotificationBox.add(obj.sourceBox, { x_fill: false, x_align: St.Align.MIDDLE });
196
obj.contentUpdatedId = item.connect('content-updated', Lang.bind(this, this._onItemContentUpdated));
197
obj.sourceCountChangedId = item.source.connect('count-updated', Lang.bind(this, this._onSourceChanged));
198
obj.sourceTitleChangedId = item.source.connect('title-changed', Lang.bind(this, this._onSourceChanged));
199
obj.sourceDestroyId = item.source.connect('destroy', Lang.bind(this, this._onSourceDestroy));
200
this._items.push(obj);
202
if (!dontUpdateVisibility)
203
this._updateVisibility();
206
_findSource: function(source) {
207
for (let i = 0; i < this._items.length; i++) {
208
if (this._items[i].source == source)
215
_onItemContentUpdated: function(item) {
216
let obj = this._items[this._findSource(item.source)];
217
this._updateItem(obj);
220
_onSourceChanged: function(source) {
221
let obj = this._items[this._findSource(source)];
222
this._updateItem(obj);
225
_updateItem: function(obj) {
226
let itemShouldBeResident = this._sourceIsResident(obj.source);
228
if (itemShouldBeResident && obj.resident) {
229
// Nothing to do here, the actor is already updated
233
if (obj.resident && !itemShouldBeResident) {
234
// make into a regular item
235
obj.item.doneShowingNotificationStack();
236
this._residentNotificationBox.remove_actor(obj.item.notificationStackWidget);
238
[obj.sourceBox, obj.countLabel] = this._makeNotificationSource(obj.source);
239
this._persistentNotificationBox.add(obj.sourceBox);
240
} else if (itemShouldBeResident && !obj.resident) {
241
// make into a resident item
242
obj.sourceBox.destroy();
243
obj.sourceBox = obj.countLabel = null;
246
this._residentNotificationBox.add(obj.item.notificationStackWidget);
247
obj.item.closeButtonVisible = false;
248
obj.item.prepareNotificationStackForShowing();
250
// just update the counter
251
let count = obj.source.unseenCount;
252
obj.countLabel.text = this._makeNotificationCountText(count, obj.source.isChat);
253
obj.sourceBox.visible = count != 0;
256
this._updateVisibility();
259
_onSourceDestroy: function(source) {
260
let idx = this._findSource(source);
262
this._removeItem(this._items[idx]);
263
this._items.splice(idx, 1);
265
this._updateVisibility();
268
_removeItem: function(obj) {
270
obj.item.doneShowingNotificationStack();
271
this._residentNotificationBox.remove_actor(obj.item.notificationStackWidget);
273
obj.sourceBox.destroy();
276
obj.item.disconnect(obj.contentUpdatedId);
277
obj.source.disconnect(obj.sourceDestroyId);
278
obj.source.disconnect(obj.sourceCountChangedId);
282
const Arrow = new Lang.Class({
286
_init: function(params) {
288
this.x_fill = this.y_fill = true;
289
this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
291
this._drawingArea = new St.DrawingArea();
292
this._drawingArea.connect('repaint', Lang.bind(this, this._drawArrow));
293
this.child = this._drawingArea;
295
this._shadowHelper = null;
296
this._shadowWidth = this._shadowHeight = 0;
299
_drawArrow: function(arrow) {
300
let cr = arrow.get_context();
301
let [w, h] = arrow.get_surface_size();
302
let node = this.get_theme_node();
303
let thickness = node.get_length('-arrow-thickness');
305
Clutter.cairo_set_source_color(cr, node.get_foreground_color());
307
cr.setLineCap(Cairo.LineCap.ROUND);
308
cr.setLineWidth(thickness);
310
cr.moveTo(thickness / 2, h - thickness / 2);
311
cr.lineTo(w/2, thickness);
312
cr.lineTo(w - thickness / 2, h - thickness / 2);
316
vfunc_style_changed: function() {
317
let node = this.get_theme_node();
318
this._shadow = node.get_shadow('-arrow-shadow');
320
this._shadowHelper = St.ShadowHelper.new(this._shadow);
322
this._shadowHelper = null;
325
vfunc_paint: function() {
326
if (this._shadowHelper) {
327
this._shadowHelper.update(this._drawingArea);
329
let allocation = this._drawingArea.get_allocation_box();
330
let paintOpacity = this._drawingArea.get_paint_opacity();
331
this._shadowHelper.paint(allocation, paintOpacity);
334
this._drawingArea.paint();
339
* To test screen shield, make sure to kill gnome-screensaver.
341
* If you are setting org.gnome.desktop.session.idle-delay directly in dconf,
342
* rather than through System Settings, you also need to set
343
* org.gnome.settings-daemon.plugins.power.sleep-display-ac and
344
* org.gnome.settings-daemon.plugins.power.sleep-display-battery to the same value.
345
* This will ensure that the screen blanks at the right time when it fades out.
346
* https://bugzilla.gnome.org/show_bug.cgi?id=668703 explains the dependance.
348
const ScreenShield = new Lang.Class({
349
Name: 'ScreenShield',
352
this.actor = Main.layoutManager.screenShieldGroup;
354
this._lockScreenState = MessageTray.State.HIDDEN;
355
this._lockScreenGroup = new St.Widget({ x_expand: true,
359
name: 'lockScreenGroup',
361
this._lockScreenGroup.connect('key-release-event',
362
Lang.bind(this, this._onLockScreenKeyRelease));
363
this._lockScreenGroup.connect('scroll-event',
364
Lang.bind(this, this._onLockScreenScroll));
366
this._lockScreenContents = new St.Widget({ layout_manager: new Clutter.BinLayout(),
367
name: 'lockScreenContents' });
368
this._lockScreenContents.add_constraint(new Layout.MonitorConstraint({ primary: true }));
370
this._background = new St.Bin({ style_class: 'screen-shield-background',
371
child: Meta.BackgroundActor.new_for_screen(global.screen) });
372
this._lockScreenGroup.add_actor(this._background);
373
this._lockScreenGroup.add_actor(this._lockScreenContents);
375
this._arrowContainer = new St.BoxLayout({ style_class: 'screen-shield-arrows',
377
x_align: Clutter.ActorAlign.CENTER,
378
y_align: Clutter.ActorAlign.END,
379
// HACK: without these, ClutterBinLayout
380
// ignores alignment properties on the actor
384
for (let i = 0; i < N_ARROWS; i++) {
385
let arrow = new Arrow({ opacity: 0 });
386
this._arrowContainer.add_actor(arrow);
388
this._lockScreenContents.add_actor(this._arrowContainer);
390
let dragArea = new Clutter.Rect({ origin: new Clutter.Point({ x: 0, y: -global.screen_height, }),
391
size: new Clutter.Size({ width: global.screen_width,
392
height: global.screen_height }) });
393
let action = new Clutter.DragAction({ drag_axis: Clutter.DragAxis.Y_AXIS,
394
drag_area: dragArea });
395
action.connect('drag-begin', Lang.bind(this, this._onDragBegin));
396
action.connect('drag-end', Lang.bind(this, this._onDragEnd));
397
this._lockScreenGroup.add_action(action);
399
this._lockDialogGroup = new St.Widget({ x_expand: true,
401
pivot_point: new Clutter.Point({ x: 0.5, y: 0.5 }),
402
name: 'lockDialogGroup' });
404
this.actor.add_actor(this._lockDialogGroup);
405
this.actor.add_actor(this._lockScreenGroup);
407
this._presence = new GnomeSession.Presence(Lang.bind(this, function(proxy, error) {
409
logError(error, 'Error while reading gnome-session presence');
413
this._onStatusChanged(proxy.status);
415
this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
416
this._onStatusChanged(status);
419
this._screenSaverDBus = new ShellDBus.ScreenSaverDBus(this);
421
this._loginManager = LoginManager.getLoginManager();
422
this._loginSession = this._loginManager.getCurrentSessionProxy();
423
this._loginSession.connectSignal('Lock', Lang.bind(this, function() { this.lock(false); }));
424
this._loginSession.connectSignal('Unlock', Lang.bind(this, function() { this.unlock(); }));
426
this._settings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA });
428
this._isModal = false;
429
this._hasLockScreen = false;
430
this._isGreeter = false;
431
this._isActive = false;
432
this._inUnlockAnimation = false;
434
this._lightbox = new Lightbox.Lightbox(Main.uiGroup,
435
{ inhibitEvents: true,
436
fadeInTime: STANDARD_FADE_TIME,
440
_onLockScreenKeyRelease: function(actor, event) {
441
let symbol = event.get_key_symbol();
443
if (symbol == Clutter.KEY_Escape ||
444
symbol == Clutter.KEY_Return ||
445
symbol == Clutter.KEY_KP_Enter) {
446
this._ensureUnlockDialog();
447
this._hideLockScreen(true);
451
// Don't bump if the lock screen is not showing or is
452
// animating, as the bump overrides the animation and would
453
// remove any onComplete handler
454
if (this._lockScreenState == MessageTray.State.SHOWN)
455
this._bumpLockScreen();
459
_onLockScreenScroll: function(actor, event) {
460
if (this._lockScreenState != MessageTray.State.SHOWN)
464
if (event.get_scroll_direction() == Clutter.ScrollDirection.UP)
466
else if (event.get_scroll_direction() == Clutter.ScrollDirection.SMOOTH)
467
delta = Math.max(0, event.get_scroll_delta()[0]);
469
this._lockScreenScrollCounter += delta;
471
// 7 standard scrolls to lift up
472
if (this._lockScreenScrollCounter > 35) {
473
this._ensureUnlockDialog();
474
this._hideLockScreen(true);
480
_animateArrows: function() {
481
let arrows = this._arrowContainer.get_children();
482
let unitaryDelay = ARROW_ANIMATION_TIME / (arrows.length + 1);
483
let maxOpacity = 255 * ARROW_ANIMATION_PEAK_OPACITY;
484
for (let i = 0; i < arrows.length; i++) {
486
Tweener.addTween(arrows[i],
488
delay: unitaryDelay * (N_ARROWS - (i + 1)),
489
time: ARROW_ANIMATION_TIME,
490
transition: function(t, b, c, d) {
492
return TweenerEquations.easeOutQuad(t, 0, maxOpacity, d/2);
494
return TweenerEquations.easeInQuad(t - d/2, maxOpacity, -maxOpacity, d/2);
502
_onDragBegin: function() {
503
Tweener.removeTweens(this._lockScreenGroup);
504
this._lockScreenState = MessageTray.State.HIDING;
505
this._ensureUnlockDialog();
508
_onDragEnd: function(action, actor, eventX, eventY, modifiers) {
509
if (this._lockScreenGroup.y < -(ARROW_DRAG_THRESHOLD * global.stage.height)) {
510
// Complete motion automatically
511
this._hideLockScreen(true);
513
// restore the lock screen to its original place
514
// try to use the same speed as the normal animation
515
let h = global.stage.height;
516
let time = CURTAIN_SLIDE_TIME * (-this._lockScreenGroup.y) / h;
517
Tweener.removeTweens(this._lockScreenGroup);
518
Tweener.addTween(this._lockScreenGroup,
521
transition: 'linear',
522
onComplete: function() {
523
this._lockScreenGroup.fixed_position_set = false;
524
this._lockScreenState = MessageTray.State.SHOWN;
526
onCompleteScope: this,
529
// If we have a unlock dialog, cancel it
531
this._dialog.cancel();
532
if (!this._isGreeter) {
539
_onStatusChanged: function(status) {
540
if (status == GnomeSession.PresenceStatus.IDLE) {
542
this._dialog.cancel();
543
if (!this._isGreeter) {
548
if (!this._isModal) {
549
Main.pushModal(this.actor);
550
this._isModal = true;
554
this._lightbox.show();
556
let lightboxWasShown = this._lightbox.shown;
557
this._lightbox.hide();
559
let shouldLock = lightboxWasShown && this._settings.get_boolean(LOCK_ENABLED_KEY);
560
if (shouldLock || this._isActive) {
562
} else if (this._isModal) {
568
showDialog: function() {
569
// Ensure that the stage window is mapped, before taking a grab
570
// otherwise X errors out
571
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
572
if (!this._isModal) {
573
Main.pushModal(this.actor);
574
this._isModal = true;
581
this._isGreeter = Main.sessionMode.isGreeter;
582
this._ensureUnlockDialog();
583
this._hideLockScreen(false);
586
_bumpLockScreen: function() {
587
Tweener.removeTweens(this._lockScreenGroup);
588
Tweener.addTween(this._lockScreenGroup,
591
transition: 'easeOutQuad',
592
onComplete: function() {
593
Tweener.addTween(this,
596
transition: 'easeInQuad' });
601
_hideLockScreen: function(animate) {
602
this._lockScreenState = MessageTray.State.HIDING;
605
// Tween the lock screen out of screen
606
// try to use the same speed regardless of original position
607
let h = global.stage.height;
608
let time = CURTAIN_SLIDE_TIME * (h + this._lockScreenGroup.y) / h;
609
Tweener.removeTweens(this._lockScreenGroup);
610
Tweener.addTween(this._lockScreenGroup,
613
transition: 'linear',
614
onComplete: function() {
615
this._lockScreenState = MessageTray.State.HIDDEN;
616
this._lockScreenGroup.hide();
618
onCompleteScope: this,
621
this._lockScreenState = MessageTray.State.HIDDEN;
622
this._lockScreenGroup.hide();
625
if (Main.sessionMode.currentMode == 'lock-screen')
626
Main.sessionMode.popMode('lock-screen');
629
_ensureUnlockDialog: function() {
631
let constructor = Main.sessionMode.unlockDialog;
632
this._dialog = new constructor(this._lockDialogGroup);
634
// This session mode has no locking capabilities
639
this._dialog.connect('loaded', Lang.bind(this, function() {
640
if (!this._dialog.open()) {
641
log('Could not open login dialog: failed to acquire grab');
646
this._dialog.connect('failed', Lang.bind(this, this._onUnlockFailed));
647
this._dialog.connect('unlocked', Lang.bind(this, this._onUnlockSucceded));
651
_onUnlockFailed: function() {
652
this._resetLockScreen(true, false);
655
_onUnlockSucceded: function() {
656
this._tweenUnlocked();
659
_resetLockScreen: function(animateLockScreen, animateLockDialog) {
660
this._ensureLockScreen();
661
this._lockDialogGroup.scale_x = 1;
662
this._lockDialogGroup.scale_y = 1;
664
this._lockScreenGroup.show();
665
this._lockScreenState = MessageTray.State.SHOWING;
667
if (animateLockScreen) {
668
this._lockScreenGroup.y = -global.screen_height;
669
Tweener.removeTweens(this._lockScreenGroup);
670
Tweener.addTween(this._lockScreenGroup,
672
time: SHORT_FADE_TIME,
673
transition: 'linear',
674
onComplete: function() {
675
this._lockScreenShown();
677
onCompleteScope: this
680
this._lockScreenGroup.fixed_position_set = false;
681
this._lockScreenShown();
684
if (animateLockDialog) {
685
this._lockDialogGroup.opacity = 0;
686
Tweener.removeTweens(this._lockDialogGroup);
687
Tweener.addTween(this._lockDialogGroup,
689
time: SHORT_FADE_TIME,
690
transition: 'easeOutQuad' });
692
this._lockDialogGroup.opacity = 255;
695
this._lockScreenGroup.grab_key_focus();
697
if (Main.sessionMode.currentMode != 'lock-screen')
698
Main.sessionMode.pushMode('lock-screen');
701
_lockScreenShown: function() {
702
if (this._dialog && !this._isGreeter) {
703
this._dialog.destroy();
707
if (this._arrowAnimationId)
708
Mainloop.source_remove(this._arrowAnimationId);
709
this._arrowAnimationId = Mainloop.timeout_add(6000, Lang.bind(this, this._animateArrows));
710
this._animateArrows();
712
this._lockScreenState = MessageTray.State.SHOWN;
713
this._lockScreenGroup.fixed_position_set = false;
714
this._lockScreenScrollCounter = 0;
716
this.emit('lock-screen-shown');
719
// Some of the actors in the lock screen are heavy in
720
// resources, so we only create them when needed
721
_ensureLockScreen: function() {
722
if (this._hasLockScreen)
725
this._lockScreenContentsBox = new St.BoxLayout({ x_align: Clutter.ActorAlign.CENTER,
726
y_align: Clutter.ActorAlign.CENTER,
730
this._clock = new Clock();
731
this._lockScreenContentsBox.add(this._clock.actor, { x_fill: true,
734
this._lockScreenContents.add_actor(this._lockScreenContentsBox);
736
if (this._settings.get_boolean('show-notifications')) {
737
this._notificationsBox = new NotificationsBox();
738
this._lockScreenContentsBox.add(this._notificationsBox.actor, { x_fill: true,
743
this._hasLockScreen = true;
746
_clearLockScreen: function() {
747
this._clock.destroy();
750
if (this._notificationsBox) {
751
this._notificationsBox.destroy();
752
this._notificationsBox = null;
755
this._lockScreenContentsBox.destroy();
757
if (this._arrowAnimationId) {
758
Mainloop.source_remove(this._arrowAnimationId);
759
this._arrowAnimationId = 0;
762
this._hasLockScreen = false;
766
return this._isActive;
769
_tweenUnlocked: function() {
770
this._inUnlockAnimation = true;
772
Tweener.addTween(this._lockDialogGroup, {
775
time: Overview.ANIMATION_TIME,
776
transition: 'easeOutQuad',
777
onComplete: function() {
779
this._dialog.destroy();
783
this._inUnlockAnimation = false;
785
onCompleteScope: this
790
if (this._hasLockScreen)
791
this._clearLockScreen();
793
if (this._dialog && !this._isGreeter) {
794
this._dialog.destroy();
798
this._lightbox.hide();
801
Main.popModal(this.actor);
802
this._isModal = false;
805
if (!this._inUnlockAnimation)
808
if (Main.sessionMode.currentMode == 'lock-screen')
809
Main.sessionMode.popMode('lock-screen');
810
if (Main.sessionMode.currentMode == 'unlock-dialog')
811
Main.sessionMode.popMode('unlock-dialog');
813
this._isActive = false;
814
this.emit('lock-status-changed');
817
lock: function(animate) {
818
if (!this._isModal) {
819
Main.pushModal(this.actor);
820
this._isModal = true;
825
if (Main.sessionMode.currentMode != 'unlock-dialog' &&
826
Main.sessionMode.currentMode != 'lock-screen') {
827
this._isGreeter = Main.sessionMode.isGreeter;
828
if (!this._isGreeter)
829
Main.sessionMode.pushMode('unlock-dialog');
832
this._resetLockScreen(animate, animate);
834
this._isActive = true;
835
this.emit('lock-status-changed');
838
Signals.addSignalMethods(ScreenShield.prototype);
840
/* Fallback code to handle session locking using gnome-screensaver,
841
in case the required GDM dependency is not there
843
const ScreenShieldFallback = new Lang.Class({
844
Name: 'ScreenShieldFallback',
847
this._proxy = new Gio.DBusProxy({ g_connection: Gio.DBus.session,
848
g_name: 'org.gnome.ScreenSaver',
849
g_object_path: '/org/gnome/ScreenSaver',
850
g_interface_name: 'org.gnome.ScreenSaver',
851
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
852
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES),
854
this._proxy.init(null);
856
this._proxy.connect('g-signal', Lang.bind(this, this._onSignal));
857
this._proxy.connect('notify::g-name-owner', Lang.bind(this, this._onNameOwnerChanged));
860
_onNameOwnerChanged: function(object, pspec) {
861
if (this._proxy.g_name_owner)
862
[this._locked] = this._proxy.call_sync('GetActive', null,
863
Gio.DBusCallFlags.NONE, -1, null).deep_unpack();
865
this._locked = false;
867
this.emit('lock-status-changed', this._locked);
870
_onSignal: function(proxy, senderName, signalName, params) {
871
if (signalName == 'ActiveChanged') {
872
[this._locked] = params.deep_unpack();
873
this.emit('lock-status-changed', this._locked);
882
this._proxy.call('Lock', null, Gio.DBusCallFlags.NONE, -1, null,
883
Lang.bind(this, function(proxy, result) {
884
proxy.call_finish(result);
886
this.emit('lock-screen-shown');
891
this._proxy.call('SetActive', GLib.Variant.new('(b)', false),
892
Gio.DBusCallFlags.NONE, -1, null, null);
895
Signals.addSignalMethods(ScreenShieldFallback.prototype);