~ubuntu-branches/debian/jessie/gnome-shell/jessie

« back to all changes in this revision

Viewing changes to .pc/22-remove-online-accounts-from-user-menu.patch/js/ui/userMenu.js

  • Committer: Package Import Robot
  • Author(s): Michael Biebl
  • Date: 2012-05-30 13:19:38 UTC
  • mfrom: (18.1.24 experimental)
  • Revision ID: package-import@ubuntu.com-20120530131938-i3trc1g1p3is2u6x
Tags: 3.4.1-3
Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
 
2
 
 
3
const AccountsService = imports.gi.AccountsService;
 
4
const Gio = imports.gi.Gio;
 
5
const GLib = imports.gi.GLib;
 
6
const Lang = imports.lang;
 
7
const Pango = imports.gi.Pango;
 
8
const Shell = imports.gi.Shell;
 
9
const St = imports.gi.St;
 
10
const Tp = imports.gi.TelepathyGLib;
 
11
const UPowerGlib = imports.gi.UPowerGlib;
 
12
const Atk = imports.gi.Atk;
 
13
 
 
14
const GnomeSession = imports.misc.gnomeSession;
 
15
const Main = imports.ui.main;
 
16
const PanelMenu = imports.ui.panelMenu;
 
17
const PopupMenu = imports.ui.popupMenu;
 
18
const ScreenSaver = imports.misc.screenSaver;
 
19
const Util = imports.misc.util;
 
20
 
 
21
const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
 
22
const DISABLE_USER_SWITCH_KEY = 'disable-user-switching';
 
23
const DISABLE_LOCK_SCREEN_KEY = 'disable-lock-screen';
 
24
const DISABLE_LOG_OUT_KEY = 'disable-log-out';
 
25
 
 
26
const DIALOG_ICON_SIZE = 64;
 
27
 
 
28
const IMStatus = {
 
29
    AVAILABLE: 0,
 
30
    BUSY: 1,
 
31
    HIDDEN: 2,
 
32
    AWAY: 3,
 
33
    IDLE: 4,
 
34
    OFFLINE: 5,
 
35
    LAST: 6
 
36
};
 
37
 
 
38
// Adapted from gdm/gui/user-switch-applet/applet.c
 
39
//
 
40
// Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
 
41
// Copyright (C) 2008,2009 Red Hat, Inc.
 
42
 
 
43
 
 
44
const IMStatusItem = new Lang.Class({
 
45
    Name: 'IMStatusItem',
 
46
    Extends: PopupMenu.PopupBaseMenuItem,
 
47
 
 
48
    _init: function(label, iconName) {
 
49
        this.parent();
 
50
 
 
51
        this.actor.add_style_class_name('status-chooser-status-item');
 
52
 
 
53
        this._icon = new St.Icon({ style_class: 'popup-menu-icon' });
 
54
        this.addActor(this._icon);
 
55
 
 
56
        if (iconName)
 
57
            this._icon.icon_name = iconName;
 
58
 
 
59
        this.label = new St.Label({ text: label });
 
60
        this.actor.label_actor = this.label;
 
61
        this.addActor(this.label);
 
62
    }
 
63
});
 
64
 
 
65
const IMUserNameItem = new Lang.Class({
 
66
    Name: 'IMUserNameItem',
 
67
    Extends: PopupMenu.PopupBaseMenuItem,
 
68
 
 
69
    _init: function() {
 
70
        this.parent({ reactive: false,
 
71
                      style_class: 'status-chooser-user-name' });
 
72
 
 
73
        this._wrapper = new Shell.GenericContainer();
 
74
        this._wrapper.connect('get-preferred-width',
 
75
                              Lang.bind(this, this._wrapperGetPreferredWidth));
 
76
        this._wrapper.connect('get-preferred-height',
 
77
                              Lang.bind(this, this._wrapperGetPreferredHeight));
 
78
        this._wrapper.connect('allocate',
 
79
                              Lang.bind(this, this._wrapperAllocate));
 
80
        this.addActor(this._wrapper, { expand: true, span: -1 });
 
81
 
 
82
        this.label = new St.Label();
 
83
        this.label.clutter_text.set_line_wrap(true);
 
84
        this.label.clutter_text.set_ellipsize(Pango.EllipsizeMode.NONE);
 
85
        this._wrapper.add_actor(this.label);
 
86
    },
 
87
 
 
88
    _wrapperGetPreferredWidth: function(actor, forHeight, alloc) {
 
89
        alloc.min_size = 1;
 
90
        alloc.natural_size = 1;
 
91
    },
 
92
 
 
93
    _wrapperGetPreferredHeight: function(actor, forWidth, alloc) {
 
94
        [alloc.min_size, alloc.natural_size] = this.label.get_preferred_height(forWidth);
 
95
    },
 
96
 
 
97
    _wrapperAllocate: function(actor, box, flags) {
 
98
        this.label.allocate(box, flags);
 
99
    }
 
100
});
 
101
 
 
102
const IMStatusChooserItem = new Lang.Class({
 
103
    Name: 'IMStatusChooserItem',
 
104
    Extends: PopupMenu.PopupBaseMenuItem,
 
105
 
 
106
    _init: function() {
 
107
        this.parent({ reactive: false,
 
108
                      style_class: 'status-chooser' });
 
109
 
 
110
        this._iconBin = new St.Button({ style_class: 'status-chooser-user-icon' });
 
111
        this.addActor(this._iconBin);
 
112
 
 
113
        this._iconBin.connect('clicked', Lang.bind(this,
 
114
            function() {
 
115
                this.activate();
 
116
            }));
 
117
 
 
118
        this._section = new PopupMenu.PopupMenuSection();
 
119
        this.addActor(this._section.actor);
 
120
 
 
121
        this._name = new IMUserNameItem();
 
122
        this._section.addMenuItem(this._name);
 
123
 
 
124
        this._combo = new PopupMenu.PopupComboBoxMenuItem({ style_class: 'status-chooser-combo' });
 
125
        this._section.addMenuItem(this._combo);
 
126
 
 
127
        let item;
 
128
 
 
129
        item = new IMStatusItem(_("Available"), 'user-available');
 
130
        this._combo.addMenuItem(item, IMStatus.AVAILABLE);
 
131
 
 
132
        item = new IMStatusItem(_("Busy"), 'user-busy');
 
133
        this._combo.addMenuItem(item, IMStatus.BUSY);
 
134
 
 
135
        item = new IMStatusItem(_("Hidden"), 'user-invisible');
 
136
        this._combo.addMenuItem(item, IMStatus.HIDDEN);
 
137
 
 
138
        item = new IMStatusItem(_("Away"), 'user-away');
 
139
        this._combo.addMenuItem(item, IMStatus.AWAY);
 
140
 
 
141
        item = new IMStatusItem(_("Idle"), 'user-idle');
 
142
        this._combo.addMenuItem(item, IMStatus.IDLE);
 
143
 
 
144
        item = new IMStatusItem(_("Unavailable"), 'user-offline');
 
145
        this._combo.addMenuItem(item, IMStatus.OFFLINE);
 
146
 
 
147
        this._combo.connect('active-item-changed',
 
148
                            Lang.bind(this, this._changeIMStatus));
 
149
 
 
150
        this._presence = new GnomeSession.Presence();
 
151
        this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
 
152
            this._sessionStatusChanged(status);
 
153
        }));
 
154
 
 
155
        this._sessionPresenceRestored = false;
 
156
        this._imPresenceRestored = false;
 
157
        this._currentPresence = undefined;
 
158
 
 
159
        this._accountMgr = Tp.AccountManager.dup();
 
160
        this._accountMgr.connect('most-available-presence-changed',
 
161
                                 Lang.bind(this, this._IMStatusChanged));
 
162
        this._accountMgr.connect('account-enabled',
 
163
                                 Lang.bind(this, this._IMAccountsChanged));
 
164
        this._accountMgr.connect('account-disabled',
 
165
                                 Lang.bind(this, this._IMAccountsChanged));
 
166
        this._accountMgr.connect('account-removed',
 
167
                                 Lang.bind(this, this._IMAccountsChanged));
 
168
        this._accountMgr.connect('account-validity-changed',
 
169
                                 Lang.bind(this, this._IMAccountsChanged));
 
170
        this._accountMgr.prepare_async(null, Lang.bind(this,
 
171
            function(mgr) {
 
172
                let [presence, status, msg] = mgr.get_most_available_presence();
 
173
 
 
174
                let savedPresence = global.settings.get_int('saved-im-presence');
 
175
 
 
176
                this._IMAccountsChanged(mgr);
 
177
 
 
178
                if (savedPresence == presence) {
 
179
                    this._IMStatusChanged(mgr, presence, status, msg);
 
180
                } else {
 
181
                    this._setComboboxPresence(savedPresence);
 
182
                    status = this._statusForPresence(savedPresence);
 
183
                    msg = msg ? msg : '';
 
184
                    mgr.set_all_requested_presences(savedPresence, status, msg);
 
185
                }
 
186
            }));
 
187
 
 
188
        this._userManager = AccountsService.UserManager.get_default();
 
189
 
 
190
        this._user = this._userManager.get_user(GLib.get_user_name());
 
191
 
 
192
        this._userLoadedId = this._user.connect('notify::is-loaded',
 
193
                                                Lang.bind(this,
 
194
                                                          this._updateUser));
 
195
        this._userChangedId = this._user.connect('changed',
 
196
                                                 Lang.bind(this,
 
197
                                                           this._updateUser));
 
198
        this.actor.connect('notify::mapped', Lang.bind(this, function() {
 
199
            if (this.actor.mapped)
 
200
                this._updateUser();
 
201
        }));
 
202
    },
 
203
 
 
204
    destroy: function() {
 
205
        // clean up signal handlers
 
206
        if (this._userLoadedId != 0) {
 
207
            this._user.disconnect(this._userLoadedId);
 
208
            this._userLoadedId = 0;
 
209
        }
 
210
 
 
211
        if (this._userChangedId != 0) {
 
212
            this._user.disconnect(this._userChangedId);
 
213
            this._userChangedId = 0;
 
214
        }
 
215
 
 
216
        this.parent();
 
217
    },
 
218
 
 
219
    // Override getColumnWidths()/setColumnWidths() to make the item
 
220
    // independent from the overall column layout of the menu
 
221
    getColumnWidths: function() {
 
222
        return [];
 
223
    },
 
224
 
 
225
    setColumnWidths: function(widths) {
 
226
    },
 
227
 
 
228
    _updateUser: function() {
 
229
        let iconFile = null;
 
230
        if (this._user.is_loaded) {
 
231
            this._name.label.set_text(this._user.get_real_name());
 
232
            iconFile = this._user.get_icon_file();
 
233
            if (!GLib.file_test(iconFile, GLib.FileTest.EXISTS))
 
234
                iconFile = null;
 
235
        } else {
 
236
            this._name.label.set_text("");
 
237
        }
 
238
 
 
239
        if (iconFile)
 
240
            this._setIconFromFile(iconFile);
 
241
        else
 
242
            this._setIconFromName('avatar-default');
 
243
    },
 
244
 
 
245
    _setIconFromFile: function(iconFile) {
 
246
        this._iconBin.set_style('background-image: url("' + iconFile + '");' +
 
247
                                'background-size: contain;');
 
248
        this._iconBin.child = null;
 
249
    },
 
250
 
 
251
    _setIconFromName: function(iconName) {
 
252
        this._iconBin.set_style(null);
 
253
 
 
254
        if (iconName != null) {
 
255
            let textureCache = St.TextureCache.get_default();
 
256
            let icon = textureCache.load_icon_name(this._iconBin.get_theme_node(),
 
257
                                                   iconName,
 
258
                                                   St.IconType.SYMBOLIC,
 
259
                                                   DIALOG_ICON_SIZE);
 
260
 
 
261
            this._iconBin.child = icon;
 
262
            this._iconBin.show();
 
263
        } else {
 
264
            this._iconBin.child = null;
 
265
            this._iconBin.hide();
 
266
        }
 
267
    },
 
268
 
 
269
    _statusForPresence: function(presence) {
 
270
        switch(presence) {
 
271
            case Tp.ConnectionPresenceType.AVAILABLE:
 
272
                return 'available';
 
273
            case Tp.ConnectionPresenceType.BUSY:
 
274
                return 'busy';
 
275
            case Tp.ConnectionPresenceType.OFFLINE:
 
276
                return 'offline';
 
277
            case Tp.ConnectionPresenceType.HIDDEN:
 
278
                return 'hidden';
 
279
            case Tp.ConnectionPresenceType.AWAY:
 
280
                return 'away';
 
281
            case Tp.ConnectionPresenceType.EXTENDED_AWAY:
 
282
                return 'xa';
 
283
            default:
 
284
                return 'unknown';
 
285
        }
 
286
    },
 
287
 
 
288
    _IMAccountsChanged: function(mgr) {
 
289
        let accounts = mgr.get_valid_accounts().filter(function(account) {
 
290
            return account.enabled;
 
291
        });
 
292
        this._combo.setSensitive(accounts.length > 0);
 
293
    },
 
294
 
 
295
    _IMStatusChanged: function(accountMgr, presence, status, message) {
 
296
        if (!this._imPresenceRestored)
 
297
            this._imPresenceRestored = true;
 
298
 
 
299
        if (presence == this._currentPresence)
 
300
            return;
 
301
 
 
302
        this._currentPresence = presence;
 
303
        this._setComboboxPresence(presence);
 
304
 
 
305
        if (!this._sessionPresenceRestored) {
 
306
            this._sessionStatusChanged(this._presence.status);
 
307
            return;
 
308
        }
 
309
 
 
310
        if (presence == Tp.ConnectionPresenceType.AVAILABLE)
 
311
            this._presence.status = GnomeSession.PresenceStatus.AVAILABLE;
 
312
 
 
313
        // We ignore the actual value of _expectedPresence and never safe
 
314
        // the first presence change after an "automatic" change, assuming
 
315
        // that it is the response to our request; this is to account for
 
316
        // mission control falling back to "similar" presences if an account
 
317
        // type does not implement the requested presence.
 
318
        if (!this._expectedPresence)
 
319
            global.settings.set_int('saved-im-presence', presence);
 
320
        else
 
321
            this._expectedPresence = undefined;
 
322
    },
 
323
 
 
324
    _setComboboxPresence: function(presence) {
 
325
        let activatedItem;
 
326
 
 
327
        if (presence == Tp.ConnectionPresenceType.AVAILABLE)
 
328
            activatedItem = IMStatus.AVAILABLE;
 
329
        else if (presence == Tp.ConnectionPresenceType.BUSY)
 
330
            activatedItem = IMStatus.BUSY;
 
331
        else if (presence == Tp.ConnectionPresenceType.HIDDEN)
 
332
            activatedItem = IMStatus.HIDDEN;
 
333
        else if (presence == Tp.ConnectionPresenceType.AWAY)
 
334
            activatedItem = IMStatus.AWAY;
 
335
        else if (presence == Tp.ConnectionPresenceType.EXTENDED_AWAY)
 
336
            activatedItem = IMStatus.IDLE;
 
337
        else
 
338
            activatedItem = IMStatus.OFFLINE;
 
339
 
 
340
        this._combo.setActiveItem(activatedItem);
 
341
        for (let i = 0; i < IMStatus.LAST; i++) {
 
342
            if (i == IMStatus.AVAILABLE || i == IMStatus.OFFLINE)
 
343
                continue;   // always visible
 
344
 
 
345
            this._combo.setItemVisible(i, i == activatedItem);
 
346
        }
 
347
    },
 
348
 
 
349
    _changeIMStatus: function(menuItem, id) {
 
350
        let [presence, s, msg] = this._accountMgr.get_most_available_presence();
 
351
        let newPresence, status;
 
352
 
 
353
        if (id == IMStatus.AVAILABLE) {
 
354
            newPresence = Tp.ConnectionPresenceType.AVAILABLE;
 
355
        } else if (id == IMStatus.OFFLINE) {
 
356
            newPresence = Tp.ConnectionPresenceType.OFFLINE;
 
357
        } else
 
358
            return;
 
359
 
 
360
        status = this._statusForPresence(newPresence);
 
361
        msg = msg ? msg : '';
 
362
        this._accountMgr.set_all_requested_presences(newPresence, status, msg);
 
363
    },
 
364
 
 
365
    getIMPresenceForSessionStatus: function(sessionStatus) {
 
366
        // Restore the last user-set presence when coming back from
 
367
        // BUSY/IDLE (otherwise the last user-set presence matches
 
368
        // the current one)
 
369
        if (sessionStatus == GnomeSession.PresenceStatus.AVAILABLE)
 
370
            return global.settings.get_int('saved-im-presence');
 
371
 
 
372
        if (sessionStatus == GnomeSession.PresenceStatus.BUSY) {
 
373
            // Only change presence if the current one is "more present" than
 
374
            // busy, or if coming back from idle
 
375
            if (this._currentPresence == Tp.ConnectionPresenceType.AVAILABLE ||
 
376
                this._currentPresence == Tp.ConnectionPresenceType.EXTENDED_AWAY)
 
377
                return Tp.ConnectionPresenceType.BUSY;
 
378
        }
 
379
 
 
380
        if (sessionStatus == GnomeSession.PresenceStatus.IDLE) {
 
381
            // Only change presence if the current one is "more present" than
 
382
            // idle
 
383
            if (this._currentPresence != Tp.ConnectionPresenceType.OFFLINE &&
 
384
                this._currentPresence != Tp.ConnectionPresenceType.HIDDEN)
 
385
                return Tp.ConnectionPresenceType.EXTENDED_AWAY;
 
386
        }
 
387
 
 
388
        return this._currentPresence;
 
389
    },
 
390
 
 
391
    _sessionStatusChanged: function(sessionStatus) {
 
392
        if (!this._imPresenceRestored)
 
393
            return;
 
394
 
 
395
        let savedStatus = global.settings.get_int('saved-session-presence');
 
396
        if (!this._sessionPresenceRestored) {
 
397
 
 
398
            // We should never save/restore a status other than AVAILABLE
 
399
            // or BUSY
 
400
            if (savedStatus != GnomeSession.PresenceStatus.AVAILABLE &&
 
401
                savedStatus != GnomeSession.PresenceStatus.BUSY)
 
402
                savedStatus = GnomeSession.PresenceStatus.AVAILABLE;
 
403
 
 
404
            if (sessionStatus != savedStatus) {
 
405
                this._presence.status = savedStatus;
 
406
                return;
 
407
            }
 
408
            this._sessionPresenceRestored = true;
 
409
        }
 
410
 
 
411
        if ((sessionStatus == GnomeSession.PresenceStatus.AVAILABLE ||
 
412
             sessionStatus == GnomeSession.PresenceStatus.BUSY) &&
 
413
            savedStatus != sessionStatus)
 
414
            global.settings.set_int('saved-session-presence', sessionStatus);
 
415
 
 
416
        let [presence, s, msg] = this._accountMgr.get_most_available_presence();
 
417
        let newPresence, status;
 
418
 
 
419
        let newPresence = this.getIMPresenceForSessionStatus(sessionStatus);
 
420
 
 
421
        if (!newPresence || newPresence == presence)
 
422
            return;
 
423
 
 
424
        status = this._statusForPresence(newPresence);
 
425
        msg = msg ? msg : '';
 
426
 
 
427
        this._expectedPresence = newPresence;
 
428
        this._accountMgr.set_all_requested_presences(newPresence, status, msg);
 
429
    }
 
430
});
 
431
 
 
432
 
 
433
const UserMenuButton = new Lang.Class({
 
434
    Name: 'UserMenuButton',
 
435
    Extends: PanelMenu.Button,
 
436
 
 
437
    _init: function() {
 
438
        this.parent(0.0);
 
439
 
 
440
        this.actor.accessible_role = Atk.Role.MENU;
 
441
 
 
442
        let box = new St.BoxLayout({ name: 'panelUserMenu' });
 
443
        this.actor.add_actor(box);
 
444
 
 
445
        this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA });
 
446
 
 
447
        this._userManager = AccountsService.UserManager.get_default();
 
448
 
 
449
        this._user = this._userManager.get_user(GLib.get_user_name());
 
450
        this._presence = new GnomeSession.Presence();
 
451
        this._session = new GnomeSession.SessionManager();
 
452
        this._haveShutdown = true;
 
453
 
 
454
        this._accountMgr = Tp.AccountManager.dup();
 
455
 
 
456
        this._upClient = new UPowerGlib.Client();
 
457
        this._screenSaverProxy = new ScreenSaver.ScreenSaverProxy();
 
458
        this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
 
459
 
 
460
        this._iconBox = new St.Bin();
 
461
        box.add(this._iconBox, { y_align: St.Align.MIDDLE, y_fill: false });
 
462
 
 
463
        let textureCache = St.TextureCache.get_default();
 
464
        this._offlineIcon = new St.Icon({ icon_name: 'user-offline',
 
465
                                          style_class: 'popup-menu-icon' });
 
466
        this._availableIcon = new St.Icon({ icon_name: 'user-available',
 
467
                                            style_class: 'popup-menu-icon' });
 
468
        this._busyIcon = new St.Icon({ icon_name: 'user-busy',
 
469
                                       style_class: 'popup-menu-icon' });
 
470
        this._invisibleIcon = new St.Icon({ icon_name: 'user-invisible',
 
471
                                            style_class: 'popup-menu-icon' });
 
472
        this._awayIcon = new St.Icon({ icon_name: 'user-away',
 
473
                                       style_class: 'popup-menu-icon' });
 
474
        this._idleIcon = new St.Icon({ icon_name: 'user-idle',
 
475
                                       style_class: 'popup-menu-icon' });
 
476
 
 
477
        this._accountMgr.connect('most-available-presence-changed',
 
478
                                  Lang.bind(this, this._updatePresenceIcon));
 
479
        this._accountMgr.prepare_async(null, Lang.bind(this,
 
480
            function(mgr) {
 
481
                let [presence, s, msg] = mgr.get_most_available_presence();
 
482
                this._updatePresenceIcon(mgr, presence, s, msg);
 
483
            }));
 
484
 
 
485
        this._name = new St.Label();
 
486
        this.actor.label_actor = this._name;
 
487
        box.add(this._name, { y_align: St.Align.MIDDLE, y_fill: false });
 
488
        this._userLoadedId = this._user.connect('notify::is-loaded', Lang.bind(this, this._updateUserName));
 
489
        this._userChangedId = this._user.connect('changed', Lang.bind(this, this._updateUserName));
 
490
        this._updateUserName();
 
491
 
 
492
        this._createSubMenu();
 
493
 
 
494
        this._updateSwitch(this._presence.status);
 
495
        this._presence.connectSignal('StatusChanged', Lang.bind(this, function (proxy, senderName, [status]) {
 
496
            this._updateSwitch(status);
 
497
        }));
 
498
 
 
499
        this._userManager.connect('notify::is-loaded',
 
500
                                  Lang.bind(this, this._updateSwitchUser));
 
501
        this._userManager.connect('notify::has-multiple-users',
 
502
                                  Lang.bind(this, this._updateSwitchUser));
 
503
        this._userManager.connect('user-added',
 
504
                                  Lang.bind(this, this._updateSwitchUser));
 
505
        this._userManager.connect('user-removed',
 
506
                                  Lang.bind(this, this._updateSwitchUser));
 
507
        this._lockdownSettings.connect('changed::' + DISABLE_USER_SWITCH_KEY,
 
508
                                       Lang.bind(this, this._updateSwitchUser));
 
509
        this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
 
510
                                       Lang.bind(this, this._updateLogout));
 
511
 
 
512
        this._lockdownSettings.connect('changed::' + DISABLE_LOCK_SCREEN_KEY,
 
513
                                       Lang.bind(this, this._updateLockScreen));
 
514
        this._updateSwitchUser();
 
515
        this._updateLogout();
 
516
        this._updateLockScreen();
 
517
 
 
518
        // Whether shutdown is available or not depends on both lockdown
 
519
        // settings (disable-log-out) and Polkit policy - the latter doesn't
 
520
        // notify, so we update the menu item each time the menu opens or
 
521
        // the lockdown setting changes, which should be close enough.
 
522
        this.menu.connect('open-state-changed', Lang.bind(this,
 
523
            function(menu, open) {
 
524
                if (open)
 
525
                    this._updateHaveShutdown();
 
526
            }));
 
527
        this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
 
528
                                       Lang.bind(this, this._updateHaveShutdown));
 
529
 
 
530
        this._upClient.connect('notify::can-suspend', Lang.bind(this, this._updateSuspendOrPowerOff));
 
531
    },
 
532
 
 
533
    _onDestroy: function() {
 
534
        this._user.disconnect(this._userLoadedId);
 
535
        this._user.disconnect(this._userChangedId);
 
536
    },
 
537
 
 
538
    _updateUserName: function() {
 
539
        if (this._user.is_loaded)
 
540
            this._name.set_text(this._user.get_real_name());
 
541
        else
 
542
            this._name.set_text("");
 
543
    },
 
544
 
 
545
    _updateSwitchUser: function() {
 
546
        let allowSwitch = !this._lockdownSettings.get_boolean(DISABLE_USER_SWITCH_KEY);
 
547
        if (allowSwitch &&
 
548
            this._userManager.can_switch() &&
 
549
            this._userManager.has_multiple_users)
 
550
            this._loginScreenItem.actor.show();
 
551
        else
 
552
            this._loginScreenItem.actor.hide();
 
553
    },
 
554
 
 
555
    _updateLogout: function() {
 
556
        let allowLogout = !this._lockdownSettings.get_boolean(DISABLE_LOG_OUT_KEY);
 
557
        if (allowLogout)
 
558
            this._logoutItem.actor.show();
 
559
        else
 
560
            this._logoutItem.actor.hide();
 
561
    },
 
562
 
 
563
    _updateLockScreen: function() {
 
564
        let allowLockScreen = !this._lockdownSettings.get_boolean(DISABLE_LOCK_SCREEN_KEY);
 
565
        if (allowLockScreen)
 
566
            this._lockScreenItem.actor.show();
 
567
        else
 
568
            this._lockScreenItem.actor.hide();
 
569
    },
 
570
 
 
571
    _updateHaveShutdown: function() {
 
572
        this._session.CanShutdownRemote(Lang.bind(this,
 
573
            function(result, error) {
 
574
                if (!error) {
 
575
                    this._haveShutdown = result;
 
576
                    this._updateSuspendOrPowerOff();
 
577
                }
 
578
            }));
 
579
    },
 
580
 
 
581
    _updateSuspendOrPowerOff: function() {
 
582
        this._haveSuspend = this._upClient.get_can_suspend();
 
583
 
 
584
        if (!this._suspendOrPowerOffItem)
 
585
            return;
 
586
 
 
587
        if (!this._haveShutdown && !this._haveSuspend)
 
588
            this._suspendOrPowerOffItem.actor.hide();
 
589
        else
 
590
            this._suspendOrPowerOffItem.actor.show();
 
591
 
 
592
        // If we can't suspend show Power Off... instead
 
593
        // and disable the alt key
 
594
        if (!this._haveSuspend) {
 
595
            this._suspendOrPowerOffItem.updateText(_("Power Off..."), null);
 
596
        } else if (!this._haveShutdown) {
 
597
            this._suspendOrPowerOffItem.updateText(_("Suspend"), null);
 
598
        } else {
 
599
            this._suspendOrPowerOffItem.updateText(_("Suspend"), _("Power Off..."));
 
600
        }
 
601
    },
 
602
 
 
603
    _updateSwitch: function(status) {
 
604
        let active = status == GnomeSession.PresenceStatus.AVAILABLE;
 
605
        this._notificationsSwitch.setToggleState(active);
 
606
    },
 
607
 
 
608
    _updatePresenceIcon: function(accountMgr, presence, status, message) {
 
609
        if (presence == Tp.ConnectionPresenceType.AVAILABLE)
 
610
            this._iconBox.child = this._availableIcon;
 
611
        else if (presence == Tp.ConnectionPresenceType.BUSY)
 
612
            this._iconBox.child = this._busyIcon;
 
613
        else if (presence == Tp.ConnectionPresenceType.HIDDEN)
 
614
            this._iconBox.child = this._invisibleIcon;
 
615
        else if (presence == Tp.ConnectionPresenceType.AWAY)
 
616
            this._iconBox.child = this._awayIcon;
 
617
        else if (presence == Tp.ConnectionPresenceType.EXTENDED_AWAY)
 
618
            this._iconBox.child = this._idleIcon;
 
619
        else
 
620
            this._iconBox.child = this._offlineIcon;
 
621
    },
 
622
 
 
623
    _createSubMenu: function() {
 
624
        let item;
 
625
 
 
626
        item = new IMStatusChooserItem();
 
627
        item.connect('activate', Lang.bind(this, this._onMyAccountActivate));
 
628
        this.menu.addMenuItem(item);
 
629
        this._statusChooser = item;
 
630
 
 
631
        item = new PopupMenu.PopupSwitchMenuItem(_("Notifications"));
 
632
        item.connect('toggled', Lang.bind(this, this._updatePresenceStatus));
 
633
        this.menu.addMenuItem(item);
 
634
        this._notificationsSwitch = item;
 
635
 
 
636
        item = new PopupMenu.PopupSeparatorMenuItem();
 
637
        this.menu.addMenuItem(item);
 
638
 
 
639
        item = new PopupMenu.PopupMenuItem(_("Online Accounts"));
 
640
        item.connect('activate', Lang.bind(this, this._onOnlineAccountsActivate));
 
641
        this.menu.addMenuItem(item);
 
642
 
 
643
        item = new PopupMenu.PopupMenuItem(_("System Settings"));
 
644
        item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
 
645
        this.menu.addMenuItem(item);
 
646
 
 
647
        item = new PopupMenu.PopupSeparatorMenuItem();
 
648
        this.menu.addMenuItem(item);
 
649
 
 
650
        item = new PopupMenu.PopupMenuItem(_("Lock Screen"));
 
651
        item.connect('activate', Lang.bind(this, this._onLockScreenActivate));
 
652
        this.menu.addMenuItem(item);
 
653
        this._lockScreenItem = item;
 
654
 
 
655
        item = new PopupMenu.PopupMenuItem(_("Switch User"));
 
656
        item.connect('activate', Lang.bind(this, this._onLoginScreenActivate));
 
657
        this.menu.addMenuItem(item);
 
658
        this._loginScreenItem = item;
 
659
 
 
660
        item = new PopupMenu.PopupMenuItem(_("Log Out..."));
 
661
        item.connect('activate', Lang.bind(this, this._onQuitSessionActivate));
 
662
        this.menu.addMenuItem(item);
 
663
        this._logoutItem = item;
 
664
 
 
665
        item = new PopupMenu.PopupSeparatorMenuItem();
 
666
        this.menu.addMenuItem(item);
 
667
 
 
668
        item = new PopupMenu.PopupAlternatingMenuItem(_("Suspend"),
 
669
                                                      _("Power Off..."));
 
670
        this.menu.addMenuItem(item);
 
671
        this._suspendOrPowerOffItem = item;
 
672
        item.connect('activate', Lang.bind(this, this._onSuspendOrPowerOffActivate));
 
673
        this._updateSuspendOrPowerOff();
 
674
    },
 
675
 
 
676
    _updatePresenceStatus: function(item, event) {
 
677
        let status;
 
678
 
 
679
        if (item.state) {
 
680
            status = GnomeSession.PresenceStatus.AVAILABLE;
 
681
        } else {
 
682
            status = GnomeSession.PresenceStatus.BUSY;
 
683
 
 
684
            let [presence, s, msg] = this._accountMgr.get_most_available_presence();
 
685
            let newPresence = this._statusChooser.getIMPresenceForSessionStatus(status);
 
686
            if (newPresence != presence &&
 
687
                newPresence == Tp.ConnectionPresenceType.BUSY)
 
688
                Main.notify(_("Your chat status will be set to busy"),
 
689
                            _("Notifications are now disabled, including chat messages. Your online status has been adjusted to let others know that you might not see their messages."));
 
690
        }
 
691
 
 
692
        this._presence.status = status;
 
693
    },
 
694
 
 
695
    _onMyAccountActivate: function() {
 
696
        Main.overview.hide();
 
697
        let app = Shell.AppSystem.get_default().lookup_setting('gnome-user-accounts-panel.desktop');
 
698
        app.activate();
 
699
    },
 
700
 
 
701
    _onOnlineAccountsActivate: function() {
 
702
        Main.overview.hide();
 
703
        let app = Shell.AppSystem.get_default().lookup_setting('gnome-online-accounts-panel.desktop');
 
704
        app.activate(-1);
 
705
    },
 
706
 
 
707
    _onPreferencesActivate: function() {
 
708
        Main.overview.hide();
 
709
        let app = Shell.AppSystem.get_default().lookup_app('gnome-control-center.desktop');
 
710
        app.activate();
 
711
    },
 
712
 
 
713
    _onLockScreenActivate: function() {
 
714
        Main.overview.hide();
 
715
        this._screenSaverProxy.LockRemote();
 
716
    },
 
717
 
 
718
    _onLoginScreenActivate: function() {
 
719
        Main.overview.hide();
 
720
        // Ensure we only move to GDM after the screensaver has activated; in some
 
721
        // OS configurations, the X server may block event processing on VT switch
 
722
        this._screenSaverProxy.SetActiveRemote(true, Lang.bind(this, function() {
 
723
            this._userManager.goto_login_session();
 
724
        }));
 
725
    },
 
726
 
 
727
    _onQuitSessionActivate: function() {
 
728
        Main.overview.hide();
 
729
        this._session.LogoutRemote(0);
 
730
    },
 
731
 
 
732
    _onSuspendOrPowerOffActivate: function() {
 
733
        Main.overview.hide();
 
734
 
 
735
        if (this._haveSuspend &&
 
736
            this._suspendOrPowerOffItem.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
 
737
            // Ensure we only suspend after locking the screen
 
738
            this._screenSaverProxy.LockRemote(Lang.bind(this, function() {
 
739
                this._upClient.suspend_sync(null);
 
740
            }));
 
741
        } else {
 
742
            this._session.ShutdownRemote();
 
743
        }
 
744
    }
 
745
});