2011-09-28 09:16:26 -04:00
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
2009-11-10 12:13:58 -05:00
2011-05-10 10:13:05 -04:00
const AccountsService = imports . gi . AccountsService ;
2011-03-21 08:51:46 -04:00
const Gio = imports . gi . Gio ;
2009-11-10 12:13:58 -05:00
const GLib = imports . gi . GLib ;
const Lang = imports . lang ;
2011-08-23 13:15:31 -04:00
const Pango = imports . gi . Pango ;
2009-11-10 12:13:58 -05:00
const Shell = imports . gi . Shell ;
const St = imports . gi . St ;
2011-02-28 11:03:35 -05:00
const Tp = imports . gi . TelepathyGLib ;
2011-02-04 18:37:54 -05:00
const UPowerGlib = imports . gi . UPowerGlib ;
2012-02-27 11:31:10 -05:00
const Atk = imports . gi . Atk ;
2009-11-10 12:13:58 -05:00
2010-04-29 13:13:20 -04:00
const GnomeSession = imports . misc . gnomeSession ;
2010-06-03 19:21:08 -04:00
const Main = imports . ui . main ;
2010-06-22 17:02:26 -04:00
const PanelMenu = imports . ui . panelMenu ;
2010-05-20 11:18:46 -04:00
const PopupMenu = imports . ui . popupMenu ;
2011-07-12 11:42:33 -04:00
const ScreenSaver = imports . misc . screenSaver ;
2010-11-17 11:43:08 -05:00
const Util = imports . misc . util ;
2009-11-10 12:13:58 -05:00
2011-03-21 08:51:46 -04:00
const LOCKDOWN _SCHEMA = 'org.gnome.desktop.lockdown' ;
const DISABLE _USER _SWITCH _KEY = 'disable-user-switching' ;
const DISABLE _LOCK _SCREEN _KEY = 'disable-lock-screen' ;
const DISABLE _LOG _OUT _KEY = 'disable-log-out' ;
2011-07-28 10:59:03 -04:00
const DIALOG _ICON _SIZE = 64 ;
const IMStatus = {
AVAILABLE : 0 ,
BUSY : 1 ,
HIDDEN : 2 ,
AWAY : 3 ,
IDLE : 4 ,
OFFLINE : 5 ,
LAST : 6
} ;
2009-11-10 12:13:58 -05:00
// Adapted from gdm/gui/user-switch-applet/applet.c
//
// Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
// Copyright (C) 2008,2009 Red Hat, Inc.
2011-07-28 10:59:03 -04:00
2011-11-20 08:10:48 -05:00
const IMStatusItem = new Lang . Class ( {
Name : 'IMStatusItem' ,
Extends : PopupMenu . PopupBaseMenuItem ,
2011-07-28 10:59:03 -04:00
_init : function ( label , iconName ) {
2011-11-20 08:10:48 -05:00
this . parent ( ) ;
2011-07-28 10:59:03 -04:00
this . actor . add _style _class _name ( 'status-chooser-status-item' ) ;
this . _icon = new St . Icon ( { style _class : 'popup-menu-icon' } ) ;
this . addActor ( this . _icon ) ;
if ( iconName )
this . _icon . icon _name = iconName ;
this . label = new St . Label ( { text : label } ) ;
2012-03-15 14:04:54 -04:00
this . actor . label _actor = this . label ;
2011-07-28 10:59:03 -04:00
this . addActor ( this . label ) ;
}
2011-11-20 08:10:48 -05:00
} ) ;
2011-07-28 10:59:03 -04:00
2011-11-20 08:10:48 -05:00
const IMUserNameItem = new Lang . Class ( {
Name : 'IMUserNameItem' ,
Extends : PopupMenu . PopupBaseMenuItem ,
2011-07-28 10:59:03 -04:00
_init : function ( ) {
2011-11-20 08:10:48 -05:00
this . parent ( { reactive : false ,
style _class : 'status-chooser-user-name' } ) ;
2011-07-28 10:59:03 -04:00
this . _wrapper = new Shell . GenericContainer ( ) ;
this . _wrapper . connect ( 'get-preferred-width' ,
Lang . bind ( this , this . _wrapperGetPreferredWidth ) ) ;
this . _wrapper . connect ( 'get-preferred-height' ,
Lang . bind ( this , this . _wrapperGetPreferredHeight ) ) ;
this . _wrapper . connect ( 'allocate' ,
Lang . bind ( this , this . _wrapperAllocate ) ) ;
this . addActor ( this . _wrapper , { expand : true , span : - 1 } ) ;
this . label = new St . Label ( ) ;
this . label . clutter _text . set _line _wrap ( true ) ;
2011-08-23 13:15:31 -04:00
this . label . clutter _text . set _ellipsize ( Pango . EllipsizeMode . NONE ) ;
2011-07-28 10:59:03 -04:00
this . _wrapper . add _actor ( this . label ) ;
} ,
_wrapperGetPreferredWidth : function ( actor , forHeight , alloc ) {
2011-08-23 13:15:31 -04:00
alloc . min _size = 1 ;
alloc . natural _size = 1 ;
2011-07-28 10:59:03 -04:00
} ,
_wrapperGetPreferredHeight : function ( actor , forWidth , alloc ) {
[ alloc . min _size , alloc . natural _size ] = this . label . get _preferred _height ( forWidth ) ;
} ,
_wrapperAllocate : function ( actor , box , flags ) {
this . label . allocate ( box , flags ) ;
}
2011-11-20 08:10:48 -05:00
} ) ;
2011-07-28 10:59:03 -04:00
2011-11-20 08:10:48 -05:00
const IMStatusChooserItem = new Lang . Class ( {
Name : 'IMStatusChooserItem' ,
Extends : PopupMenu . PopupBaseMenuItem ,
2011-07-28 10:59:03 -04:00
_init : function ( ) {
2011-11-20 08:10:48 -05:00
this . parent ( { reactive : false ,
style _class : 'status-chooser' } ) ;
2011-07-28 10:59:03 -04:00
this . _iconBin = new St . Button ( { style _class : 'status-chooser-user-icon' } ) ;
this . addActor ( this . _iconBin ) ;
this . _iconBin . connect ( 'clicked' , Lang . bind ( this ,
function ( ) {
this . activate ( ) ;
} ) ) ;
this . _section = new PopupMenu . PopupMenuSection ( ) ;
this . addActor ( this . _section . actor ) ;
this . _name = new IMUserNameItem ( ) ;
this . _section . addMenuItem ( this . _name ) ;
this . _combo = new PopupMenu . PopupComboBoxMenuItem ( { style _class : 'status-chooser-combo' } ) ;
this . _section . addMenuItem ( this . _combo ) ;
let item ;
item = new IMStatusItem ( _ ( "Available" ) , 'user-available' ) ;
this . _combo . addMenuItem ( item , IMStatus . AVAILABLE ) ;
item = new IMStatusItem ( _ ( "Busy" ) , 'user-busy' ) ;
this . _combo . addMenuItem ( item , IMStatus . BUSY ) ;
item = new IMStatusItem ( _ ( "Hidden" ) , 'user-invisible' ) ;
this . _combo . addMenuItem ( item , IMStatus . HIDDEN ) ;
item = new IMStatusItem ( _ ( "Away" ) , 'user-away' ) ;
this . _combo . addMenuItem ( item , IMStatus . AWAY ) ;
item = new IMStatusItem ( _ ( "Idle" ) , 'user-idle' ) ;
this . _combo . addMenuItem ( item , IMStatus . IDLE ) ;
item = new IMStatusItem ( _ ( "Unavailable" ) , 'user-offline' ) ;
this . _combo . addMenuItem ( item , IMStatus . OFFLINE ) ;
this . _combo . connect ( 'active-item-changed' ,
Lang . bind ( this , this . _changeIMStatus ) ) ;
this . _presence = new GnomeSession . Presence ( ) ;
2011-08-16 08:24:39 -04:00
this . _presence . connectSignal ( 'StatusChanged' , Lang . bind ( this , function ( proxy , senderName , [ status ] ) {
2011-11-11 16:41:47 -05:00
this . _sessionStatusChanged ( status ) ;
2011-08-16 08:24:39 -04:00
} ) ) ;
2011-07-28 10:59:03 -04:00
2011-10-05 20:47:18 -04:00
this . _sessionPresenceRestored = false ;
this . _imPresenceRestored = false ;
2011-09-02 08:15:31 -04:00
this . _currentPresence = undefined ;
2011-07-28 10:59:03 -04:00
2011-10-20 16:54:41 -04:00
this . _accountMgr = Tp . AccountManager . dup ( ) ;
2011-07-28 10:59:03 -04:00
this . _accountMgr . connect ( 'most-available-presence-changed' ,
Lang . bind ( this , this . _IMStatusChanged ) ) ;
2011-10-26 15:16:08 -04:00
this . _accountMgr . connect ( 'account-enabled' ,
Lang . bind ( this , this . _IMAccountsChanged ) ) ;
this . _accountMgr . connect ( 'account-disabled' ,
Lang . bind ( this , this . _IMAccountsChanged ) ) ;
this . _accountMgr . connect ( 'account-removed' ,
Lang . bind ( this , this . _IMAccountsChanged ) ) ;
2012-03-16 17:47:42 -04:00
this . _accountMgr . connect ( 'account-validity-changed' ,
Lang . bind ( this , this . _IMAccountsChanged ) ) ;
2011-07-28 10:59:03 -04:00
this . _accountMgr . prepare _async ( null , Lang . bind ( this ,
function ( mgr ) {
2011-09-30 12:54:45 -04:00
let [ presence , status , msg ] = mgr . get _most _available _presence ( ) ;
let savedPresence = global . settings . get _int ( 'saved-im-presence' ) ;
2011-10-26 15:16:08 -04:00
this . _IMAccountsChanged ( mgr ) ;
2011-09-30 12:54:45 -04:00
if ( savedPresence == presence ) {
this . _IMStatusChanged ( mgr , presence , status , msg ) ;
} else {
this . _setComboboxPresence ( savedPresence ) ;
status = this . _statusForPresence ( savedPresence ) ;
msg = msg ? msg : '' ;
mgr . set _all _requested _presences ( savedPresence , status , msg ) ;
}
2011-07-28 10:59:03 -04:00
} ) ) ;
2011-05-10 10:13:05 -04:00
this . _userManager = AccountsService . UserManager . get _default ( ) ;
2011-07-28 10:59:03 -04:00
2011-05-10 10:13:05 -04:00
this . _user = this . _userManager . get _user ( GLib . get _user _name ( ) ) ;
2011-07-28 10:59:03 -04:00
this . _userLoadedId = this . _user . connect ( 'notify::is-loaded' ,
Lang . bind ( this ,
this . _updateUser ) ) ;
this . _userChangedId = this . _user . connect ( 'changed' ,
Lang . bind ( this ,
this . _updateUser ) ) ;
2011-09-08 17:11:45 -04:00
this . actor . connect ( 'notify::mapped' , Lang . bind ( this , function ( ) {
if ( this . actor . mapped )
this . _updateUser ( ) ;
} ) ) ;
2011-07-28 10:59:03 -04:00
} ,
2011-10-17 09:18:25 -04:00
destroy : function ( ) {
// clean up signal handlers
if ( this . _userLoadedId != 0 ) {
this . _user . disconnect ( this . _userLoadedId ) ;
this . _userLoadedId = 0 ;
}
if ( this . _userChangedId != 0 ) {
this . _user . disconnect ( this . _userChangedId ) ;
this . _userChangedId = 0 ;
}
2011-11-20 08:10:48 -05:00
this . parent ( ) ;
2011-10-17 09:18:25 -04:00
} ,
2011-07-28 10:59:03 -04:00
// Override getColumnWidths()/setColumnWidths() to make the item
// independent from the overall column layout of the menu
getColumnWidths : function ( ) {
return [ ] ;
} ,
setColumnWidths : function ( widths ) {
} ,
_updateUser : function ( ) {
let iconFile = null ;
if ( this . _user . is _loaded ) {
this . _name . label . set _text ( this . _user . get _real _name ( ) ) ;
iconFile = this . _user . get _icon _file ( ) ;
if ( ! GLib . file _test ( iconFile , GLib . FileTest . EXISTS ) )
iconFile = null ;
} else {
this . _name . label . set _text ( "" ) ;
}
if ( iconFile )
this . _setIconFromFile ( iconFile ) ;
else
this . _setIconFromName ( 'avatar-default' ) ;
} ,
_setIconFromFile : function ( iconFile ) {
2012-01-09 19:48:14 -05:00
this . _iconBin . set _style ( 'background-image: url("' + iconFile + '");' +
'background-size: contain;' ) ;
2011-08-29 17:41:10 -04:00
this . _iconBin . child = null ;
2011-07-28 10:59:03 -04:00
} ,
_setIconFromName : function ( iconName ) {
this . _iconBin . set _style ( null ) ;
if ( iconName != null ) {
let textureCache = St . TextureCache . get _default ( ) ;
let icon = textureCache . load _icon _name ( this . _iconBin . get _theme _node ( ) ,
iconName ,
St . IconType . SYMBOLIC ,
DIALOG _ICON _SIZE ) ;
this . _iconBin . child = icon ;
this . _iconBin . show ( ) ;
} else {
this . _iconBin . child = null ;
this . _iconBin . hide ( ) ;
}
} ,
_statusForPresence : function ( presence ) {
switch ( presence ) {
case Tp . ConnectionPresenceType . AVAILABLE :
2011-08-30 08:35:20 -04:00
return 'available' ;
2011-07-28 10:59:03 -04:00
case Tp . ConnectionPresenceType . BUSY :
2011-08-30 08:35:20 -04:00
return 'busy' ;
2011-07-28 10:59:03 -04:00
case Tp . ConnectionPresenceType . OFFLINE :
2011-08-30 08:35:20 -04:00
return 'offline' ;
2011-07-28 10:59:03 -04:00
case Tp . ConnectionPresenceType . HIDDEN :
2011-08-30 08:35:20 -04:00
return 'hidden' ;
2011-07-28 10:59:03 -04:00
case Tp . ConnectionPresenceType . AWAY :
2011-08-30 08:35:20 -04:00
return 'away' ;
2011-07-28 10:59:03 -04:00
case Tp . ConnectionPresenceType . EXTENDED _AWAY :
2011-08-30 08:35:20 -04:00
return 'xa' ;
2011-07-28 10:59:03 -04:00
default :
2011-08-30 08:35:20 -04:00
return 'unknown' ;
2011-07-28 10:59:03 -04:00
}
} ,
2011-10-26 15:16:08 -04:00
_IMAccountsChanged : function ( mgr ) {
let accounts = mgr . get _valid _accounts ( ) . filter ( function ( account ) {
return account . enabled ;
} ) ;
this . _combo . setSensitive ( accounts . length > 0 ) ;
} ,
2011-07-28 10:59:03 -04:00
_IMStatusChanged : function ( accountMgr , presence , status , message ) {
2011-10-05 20:47:18 -04:00
if ( ! this . _imPresenceRestored )
this . _imPresenceRestored = true ;
2011-09-02 08:15:31 -04:00
if ( presence == this . _currentPresence )
return ;
this . _currentPresence = presence ;
2011-09-30 12:54:45 -04:00
this . _setComboboxPresence ( presence ) ;
2011-09-02 08:15:31 -04:00
2011-10-05 20:47:18 -04:00
if ( ! this . _sessionPresenceRestored ) {
2011-11-11 16:41:47 -05:00
this . _sessionStatusChanged ( this . _presence . status ) ;
2011-10-05 20:47:18 -04:00
return ;
}
2011-07-28 10:59:03 -04:00
if ( presence == Tp . ConnectionPresenceType . AVAILABLE )
2011-11-11 16:41:47 -05:00
this . _presence . status = GnomeSession . PresenceStatus . AVAILABLE ;
2011-07-28 10:59:03 -04:00
2011-10-11 15:53:29 -04:00
// We ignore the actual value of _expectedPresence and never safe
// the first presence change after an "automatic" change, assuming
// that it is the response to our request; this is to account for
// mission control falling back to "similar" presences if an account
// type does not implement the requested presence.
if ( ! this . _expectedPresence )
2011-09-30 12:54:45 -04:00
global . settings . set _int ( 'saved-im-presence' , presence ) ;
2011-07-28 10:59:03 -04:00
else
this . _expectedPresence = undefined ;
2011-09-30 12:54:45 -04:00
} ,
2011-07-28 10:59:03 -04:00
2011-09-30 12:54:45 -04:00
_setComboboxPresence : function ( presence ) {
2011-07-28 10:59:03 -04:00
let activatedItem ;
if ( presence == Tp . ConnectionPresenceType . AVAILABLE )
activatedItem = IMStatus . AVAILABLE ;
else if ( presence == Tp . ConnectionPresenceType . BUSY )
activatedItem = IMStatus . BUSY ;
else if ( presence == Tp . ConnectionPresenceType . HIDDEN )
activatedItem = IMStatus . HIDDEN ;
else if ( presence == Tp . ConnectionPresenceType . AWAY )
activatedItem = IMStatus . AWAY ;
else if ( presence == Tp . ConnectionPresenceType . EXTENDED _AWAY )
activatedItem = IMStatus . IDLE ;
else
activatedItem = IMStatus . OFFLINE ;
this . _combo . setActiveItem ( activatedItem ) ;
for ( let i = 0 ; i < IMStatus . LAST ; i ++ ) {
if ( i == IMStatus . AVAILABLE || i == IMStatus . OFFLINE )
continue ; // always visible
this . _combo . setItemVisible ( i , i == activatedItem ) ;
}
} ,
_changeIMStatus : function ( menuItem , id ) {
let [ presence , s , msg ] = this . _accountMgr . get _most _available _presence ( ) ;
let newPresence , status ;
if ( id == IMStatus . AVAILABLE ) {
newPresence = Tp . ConnectionPresenceType . AVAILABLE ;
} else if ( id == IMStatus . OFFLINE ) {
newPresence = Tp . ConnectionPresenceType . OFFLINE ;
} else
return ;
status = this . _statusForPresence ( newPresence ) ;
2011-09-30 17:30:47 -04:00
msg = msg ? msg : '' ;
2011-07-28 10:59:03 -04:00
this . _accountMgr . set _all _requested _presences ( newPresence , status , msg ) ;
} ,
2011-09-09 12:49:04 -04:00
getIMPresenceForSessionStatus : function ( sessionStatus ) {
2011-09-30 12:54:45 -04:00
// Restore the last user-set presence when coming back from
// BUSY/IDLE (otherwise the last user-set presence matches
// the current one)
2011-09-09 12:49:04 -04:00
if ( sessionStatus == GnomeSession . PresenceStatus . AVAILABLE )
2011-09-30 12:54:45 -04:00
return global . settings . get _int ( 'saved-im-presence' ) ;
2011-07-28 10:59:03 -04:00
2011-09-09 12:49:04 -04:00
if ( sessionStatus == GnomeSession . PresenceStatus . BUSY ) {
2011-07-28 10:59:03 -04:00
// Only change presence if the current one is "more present" than
// busy, or if coming back from idle
2011-09-09 12:49:04 -04:00
if ( this . _currentPresence == Tp . ConnectionPresenceType . AVAILABLE ||
this . _currentPresence == Tp . ConnectionPresenceType . EXTENDED _AWAY )
return Tp . ConnectionPresenceType . BUSY ;
}
if ( sessionStatus == GnomeSession . PresenceStatus . IDLE ) {
2011-07-28 10:59:03 -04:00
// Only change presence if the current one is "more present" than
// idle
2011-10-19 09:15:14 -04:00
if ( this . _currentPresence != Tp . ConnectionPresenceType . OFFLINE &&
this . _currentPresence != Tp . ConnectionPresenceType . HIDDEN )
2011-09-09 12:49:04 -04:00
return Tp . ConnectionPresenceType . EXTENDED _AWAY ;
2011-07-28 10:59:03 -04:00
}
2011-09-09 12:49:04 -04:00
return this . _currentPresence ;
} ,
2011-08-16 08:24:39 -04:00
_sessionStatusChanged : function ( sessionStatus ) {
2011-10-05 20:47:18 -04:00
if ( ! this . _imPresenceRestored )
return ;
2012-01-19 13:04:56 -05:00
let savedStatus = global . settings . get _int ( 'saved-session-presence' ) ;
2011-10-05 20:47:18 -04:00
if ( ! this . _sessionPresenceRestored ) {
2012-03-03 02:35:03 -05:00
// We should never save/restore a status other than AVAILABLE
// or BUSY
if ( savedStatus != GnomeSession . PresenceStatus . AVAILABLE &&
savedStatus != GnomeSession . PresenceStatus . BUSY )
savedStatus = GnomeSession . PresenceStatus . AVAILABLE ;
2011-10-05 20:47:18 -04:00
if ( sessionStatus != savedStatus ) {
2011-08-16 08:24:39 -04:00
this . _presence . status = savedStatus ;
2011-10-05 20:47:18 -04:00
return ;
}
this . _sessionPresenceRestored = true ;
}
2012-01-19 13:04:56 -05:00
if ( ( sessionStatus == GnomeSession . PresenceStatus . AVAILABLE ||
sessionStatus == GnomeSession . PresenceStatus . BUSY ) &&
savedStatus != sessionStatus )
2012-03-03 02:35:03 -05:00
global . settings . set _int ( 'saved-session-presence' , sessionStatus ) ;
2011-10-05 20:47:18 -04:00
2011-09-09 12:49:04 -04:00
let [ presence , s , msg ] = this . _accountMgr . get _most _available _presence ( ) ;
let newPresence , status ;
let newPresence = this . getIMPresenceForSessionStatus ( sessionStatus ) ;
if ( ! newPresence || newPresence == presence )
2011-07-28 10:59:03 -04:00
return ;
status = this . _statusForPresence ( newPresence ) ;
2011-09-30 17:30:47 -04:00
msg = msg ? msg : '' ;
2011-07-28 10:59:03 -04:00
this . _expectedPresence = newPresence ;
this . _accountMgr . set _all _requested _presences ( newPresence , status , msg ) ;
}
2011-11-20 08:10:48 -05:00
} ) ;
2011-07-28 10:59:03 -04:00
2011-11-20 09:38:48 -05:00
const UserMenuButton = new Lang . Class ( {
Name : 'UserMenuButton' ,
Extends : PanelMenu . Button ,
2010-05-10 09:46:54 -04:00
2009-11-10 12:13:58 -05:00
_init : function ( ) {
2011-11-20 09:38:48 -05:00
this . parent ( 0.0 ) ;
2012-02-27 11:31:10 -05:00
this . actor . accessible _role = Atk . Role . MENU ;
2011-09-07 12:23:27 -04:00
let box = new St . BoxLayout ( { name : 'panelUserMenu' } ) ;
2011-06-09 11:50:24 -04:00
this . actor . add _actor ( box ) ;
2010-05-10 09:46:54 -04:00
2011-03-21 08:51:46 -04:00
this . _lockdownSettings = new Gio . Settings ( { schema : LOCKDOWN _SCHEMA } ) ;
2011-05-10 10:13:05 -04:00
this . _userManager = AccountsService . UserManager . get _default ( ) ;
2010-10-07 18:22:20 -04:00
2011-05-10 10:13:05 -04:00
this . _user = this . _userManager . get _user ( GLib . get _user _name ( ) ) ;
2010-04-29 13:13:20 -04:00
this . _presence = new GnomeSession . Presence ( ) ;
2011-03-12 15:34:01 -05:00
this . _session = new GnomeSession . SessionManager ( ) ;
2011-06-03 18:10:55 -04:00
this . _haveShutdown = true ;
2009-11-10 12:13:58 -05:00
2011-10-20 16:54:41 -04:00
this . _accountMgr = Tp . AccountManager . dup ( ) ;
2011-02-28 11:03:35 -05:00
2011-02-04 18:37:54 -05:00
this . _upClient = new UPowerGlib . Client ( ) ;
2011-07-12 11:42:33 -04:00
this . _screenSaverProxy = new ScreenSaver . ScreenSaverProxy ( ) ;
2009-11-10 12:13:58 -05:00
this . actor . connect ( 'destroy' , Lang . bind ( this , this . _onDestroy ) ) ;
2009-11-10 16:34:13 -05:00
this . _iconBox = new St . Bin ( ) ;
2010-05-10 09:46:54 -04:00
box . add ( this . _iconBox , { y _align : St . Align . MIDDLE , y _fill : false } ) ;
2009-11-10 16:34:13 -05:00
2010-02-09 12:42:07 -05:00
let textureCache = St . TextureCache . get _default ( ) ;
2011-07-28 10:59:03 -04:00
this . _offlineIcon = new St . Icon ( { icon _name : 'user-offline' ,
style _class : 'popup-menu-icon' } ) ;
this . _availableIcon = new St . Icon ( { icon _name : 'user-available' ,
style _class : 'popup-menu-icon' } ) ;
this . _busyIcon = new St . Icon ( { icon _name : 'user-busy' ,
style _class : 'popup-menu-icon' } ) ;
this . _invisibleIcon = new St . Icon ( { icon _name : 'user-invisible' ,
style _class : 'popup-menu-icon' } ) ;
this . _awayIcon = new St . Icon ( { icon _name : 'user-away' ,
style _class : 'popup-menu-icon' } ) ;
this . _idleIcon = new St . Icon ( { icon _name : 'user-idle' ,
style _class : 'popup-menu-icon' } ) ;
2011-10-20 16:44:09 -04:00
this . _accountMgr . connect ( 'most-available-presence-changed' ,
2011-07-28 10:59:03 -04:00
Lang . bind ( this , this . _updatePresenceIcon ) ) ;
2011-10-20 16:44:09 -04:00
this . _accountMgr . prepare _async ( null , Lang . bind ( this ,
2011-07-28 10:59:03 -04:00
function ( mgr ) {
let [ presence , s , msg ] = mgr . get _most _available _presence ( ) ;
this . _updatePresenceIcon ( mgr , presence , s , msg ) ;
} ) ) ;
2009-11-10 16:34:13 -05:00
2010-10-07 18:22:20 -04:00
this . _name = new St . Label ( ) ;
2012-01-05 13:00:06 -05:00
this . actor . label _actor = this . _name ;
2010-05-10 09:46:54 -04:00
box . add ( this . _name , { y _align : St . Align . MIDDLE , y _fill : false } ) ;
2010-10-07 18:22:20 -04:00
this . _userLoadedId = this . _user . connect ( 'notify::is-loaded' , Lang . bind ( this , this . _updateUserName ) ) ;
this . _userChangedId = this . _user . connect ( 'changed' , Lang . bind ( this , this . _updateUserName ) ) ;
2011-09-08 17:11:45 -04:00
this . _updateUserName ( ) ;
2009-11-10 12:13:58 -05:00
this . _createSubMenu ( ) ;
2011-11-11 16:41:47 -05:00
this . _updateSwitch ( this . _presence . status ) ;
this . _presence . connectSignal ( 'StatusChanged' , Lang . bind ( this , function ( proxy , senderName , [ status ] ) {
this . _updateSwitch ( status ) ;
} ) ) ;
2011-05-10 10:13:05 -04:00
this . _userManager . connect ( 'notify::is-loaded' ,
Lang . bind ( this , this . _updateSwitchUser ) ) ;
2011-10-18 14:57:24 -04:00
this . _userManager . connect ( 'notify::has-multiple-users' ,
Lang . bind ( this , this . _updateSwitchUser ) ) ;
2011-05-10 10:13:05 -04:00
this . _userManager . connect ( 'user-added' ,
Lang . bind ( this , this . _updateSwitchUser ) ) ;
this . _userManager . connect ( 'user-removed' ,
Lang . bind ( this , this . _updateSwitchUser ) ) ;
2011-03-21 08:51:46 -04:00
this . _lockdownSettings . connect ( 'changed::' + DISABLE _USER _SWITCH _KEY ,
Lang . bind ( this , this . _updateSwitchUser ) ) ;
this . _lockdownSettings . connect ( 'changed::' + DISABLE _LOG _OUT _KEY ,
Lang . bind ( this , this . _updateLogout ) ) ;
2011-06-03 18:10:55 -04:00
2011-03-21 08:51:46 -04:00
this . _lockdownSettings . connect ( 'changed::' + DISABLE _LOCK _SCREEN _KEY ,
Lang . bind ( this , this . _updateLockScreen ) ) ;
this . _updateSwitchUser ( ) ;
this . _updateLogout ( ) ;
this . _updateLockScreen ( ) ;
2011-02-04 18:37:54 -05:00
2011-06-03 18:10:55 -04:00
// Whether shutdown is available or not depends on both lockdown
// settings (disable-log-out) and Polkit policy - the latter doesn't
// notify, so we update the menu item each time the menu opens or
// the lockdown setting changes, which should be close enough.
this . menu . connect ( 'open-state-changed' , Lang . bind ( this ,
function ( menu , open ) {
if ( open )
this . _updateHaveShutdown ( ) ;
} ) ) ;
this . _lockdownSettings . connect ( 'changed::' + DISABLE _LOG _OUT _KEY ,
Lang . bind ( this , this . _updateHaveShutdown ) ) ;
2011-02-04 18:37:54 -05:00
this . _upClient . connect ( 'notify::can-suspend' , Lang . bind ( this , this . _updateSuspendOrPowerOff ) ) ;
2009-11-10 12:13:58 -05:00
} ,
_onDestroy : function ( ) {
2010-10-07 18:22:20 -04:00
this . _user . disconnect ( this . _userLoadedId ) ;
this . _user . disconnect ( this . _userChangedId ) ;
2009-11-10 12:13:58 -05:00
} ,
_updateUserName : function ( ) {
2010-10-07 18:22:20 -04:00
if ( this . _user . is _loaded )
2011-07-28 10:59:03 -04:00
this . _name . set _text ( this . _user . get _real _name ( ) ) ;
2010-10-07 18:22:20 -04:00
else
2011-07-28 10:59:03 -04:00
this . _name . set _text ( "" ) ;
2009-11-10 12:13:58 -05:00
} ,
_updateSwitchUser : function ( ) {
2011-03-21 08:51:46 -04:00
let allowSwitch = ! this . _lockdownSettings . get _boolean ( DISABLE _USER _SWITCH _KEY ) ;
2011-10-18 14:57:24 -04:00
if ( allowSwitch &&
this . _userManager . can _switch ( ) &&
this . _userManager . has _multiple _users )
2010-05-10 09:46:54 -04:00
this . _loginScreenItem . actor . show ( ) ;
2009-11-10 12:13:58 -05:00
else
2010-05-10 09:46:54 -04:00
this . _loginScreenItem . actor . hide ( ) ;
2011-03-21 08:51:46 -04:00
} ,
_updateLogout : function ( ) {
let allowLogout = ! this . _lockdownSettings . get _boolean ( DISABLE _LOG _OUT _KEY ) ;
if ( allowLogout )
this . _logoutItem . actor . show ( ) ;
else
this . _logoutItem . actor . hide ( ) ;
} ,
_updateLockScreen : function ( ) {
let allowLockScreen = ! this . _lockdownSettings . get _boolean ( DISABLE _LOCK _SCREEN _KEY ) ;
if ( allowLockScreen )
this . _lockScreenItem . actor . show ( ) ;
else
this . _lockScreenItem . actor . hide ( ) ;
2009-11-10 12:13:58 -05:00
} ,
2011-06-03 18:10:55 -04:00
_updateHaveShutdown : function ( ) {
this . _session . CanShutdownRemote ( Lang . bind ( this ,
function ( result , error ) {
if ( ! error ) {
this . _haveShutdown = result ;
this . _updateSuspendOrPowerOff ( ) ;
}
} ) ) ;
} ,
2011-02-04 18:37:54 -05:00
_updateSuspendOrPowerOff : function ( ) {
this . _haveSuspend = this . _upClient . get _can _suspend ( ) ;
if ( ! this . _suspendOrPowerOffItem )
return ;
2011-06-03 18:10:55 -04:00
if ( ! this . _haveShutdown && ! this . _haveSuspend )
this . _suspendOrPowerOffItem . actor . hide ( ) ;
else
this . _suspendOrPowerOffItem . actor . show ( ) ;
2011-02-04 18:37:54 -05:00
// If we can't suspend show Power Off... instead
// and disable the alt key
if ( ! this . _haveSuspend ) {
this . _suspendOrPowerOffItem . updateText ( _ ( "Power Off..." ) , null ) ;
2011-06-03 18:10:55 -04:00
} else if ( ! this . _haveShutdown ) {
this . _suspendOrPowerOffItem . updateText ( _ ( "Suspend" ) , null ) ;
2011-02-04 18:37:54 -05:00
} else {
2011-03-24 14:11:20 -04:00
this . _suspendOrPowerOffItem . updateText ( _ ( "Suspend" ) , _ ( "Power Off..." ) ) ;
2011-02-04 18:37:54 -05:00
}
} ,
2011-08-16 08:24:39 -04:00
_updateSwitch : function ( status ) {
2011-09-04 12:39:37 -04:00
let active = status == GnomeSession . PresenceStatus . AVAILABLE ;
this . _notificationsSwitch . setToggleState ( active ) ;
2011-07-28 10:59:03 -04:00
} ,
_updatePresenceIcon : function ( accountMgr , presence , status , message ) {
if ( presence == Tp . ConnectionPresenceType . AVAILABLE )
2009-11-10 16:34:13 -05:00
this . _iconBox . child = this . _availableIcon ;
2011-07-28 10:59:03 -04:00
else if ( presence == Tp . ConnectionPresenceType . BUSY )
2009-11-10 16:34:13 -05:00
this . _iconBox . child = this . _busyIcon ;
2011-07-28 10:59:03 -04:00
else if ( presence == Tp . ConnectionPresenceType . HIDDEN )
2009-11-10 16:34:13 -05:00
this . _iconBox . child = this . _invisibleIcon ;
2011-07-28 10:59:03 -04:00
else if ( presence == Tp . ConnectionPresenceType . AWAY )
this . _iconBox . child = this . _awayIcon ;
else if ( presence == Tp . ConnectionPresenceType . EXTENDED _AWAY )
2009-11-10 16:34:13 -05:00
this . _iconBox . child = this . _idleIcon ;
2011-07-28 10:59:03 -04:00
else
this . _iconBox . child = this . _offlineIcon ;
2009-11-10 16:34:13 -05:00
} ,
2009-11-10 12:13:58 -05:00
_createSubMenu : function ( ) {
let item ;
2011-07-28 10:59:03 -04:00
item = new IMStatusChooserItem ( ) ;
item . connect ( 'activate' , Lang . bind ( this , this . _onMyAccountActivate ) ) ;
2010-05-10 09:46:54 -04:00
this . menu . addMenuItem ( item ) ;
2011-09-09 12:49:04 -04:00
this . _statusChooser = item ;
2009-11-10 16:34:13 -05:00
2011-09-04 12:39:37 -04:00
item = new PopupMenu . PopupSwitchMenuItem ( _ ( "Notifications" ) ) ;
2011-11-21 08:16:51 -05:00
item . connect ( 'toggled' , Lang . bind ( this , this . _updatePresenceStatus ) ) ;
2010-05-10 09:46:54 -04:00
this . menu . addMenuItem ( item ) ;
2011-09-04 12:39:37 -04:00
this . _notificationsSwitch = item ;
2009-11-10 16:34:13 -05:00
2010-05-20 11:18:46 -04:00
item = new PopupMenu . PopupSeparatorMenuItem ( ) ;
2010-05-10 09:46:54 -04:00
this . menu . addMenuItem ( item ) ;
2009-11-10 16:34:13 -05:00
2011-07-28 10:59:03 -04:00
item = new PopupMenu . PopupMenuItem ( _ ( "Online Accounts" ) ) ;
item . connect ( 'activate' , Lang . bind ( this , this . _onOnlineAccountsActivate ) ) ;
2010-05-10 09:46:54 -04:00
this . menu . addMenuItem ( item ) ;
2009-11-10 12:13:58 -05:00
2010-11-22 15:19:37 -05:00
item = new PopupMenu . PopupMenuItem ( _ ( "System Settings" ) ) ;
2009-11-10 12:13:58 -05:00
item . connect ( 'activate' , Lang . bind ( this , this . _onPreferencesActivate ) ) ;
2010-05-10 09:46:54 -04:00
this . menu . addMenuItem ( item ) ;
2009-11-10 12:13:58 -05:00
2010-05-20 11:18:46 -04:00
item = new PopupMenu . PopupSeparatorMenuItem ( ) ;
2010-05-10 09:46:54 -04:00
this . menu . addMenuItem ( item ) ;
2009-11-10 12:13:58 -05:00
2010-10-19 11:59:23 -04:00
item = new PopupMenu . PopupMenuItem ( _ ( "Lock Screen" ) ) ;
2009-11-10 12:13:58 -05:00
item . connect ( 'activate' , Lang . bind ( this , this . _onLockScreenActivate ) ) ;
2010-05-10 09:46:54 -04:00
this . menu . addMenuItem ( item ) ;
2011-03-21 08:51:46 -04:00
this . _lockScreenItem = item ;
2009-11-10 12:13:58 -05:00
2010-10-19 11:59:23 -04:00
item = new PopupMenu . PopupMenuItem ( _ ( "Switch User" ) ) ;
2009-11-10 12:13:58 -05:00
item . connect ( 'activate' , Lang . bind ( this , this . _onLoginScreenActivate ) ) ;
2010-05-10 09:46:54 -04:00
this . menu . addMenuItem ( item ) ;
2009-11-10 12:13:58 -05:00
this . _loginScreenItem = item ;
2010-10-19 11:59:23 -04:00
item = new PopupMenu . PopupMenuItem ( _ ( "Log Out..." ) ) ;
2009-11-10 12:13:58 -05:00
item . connect ( 'activate' , Lang . bind ( this , this . _onQuitSessionActivate ) ) ;
2010-05-10 09:46:54 -04:00
this . menu . addMenuItem ( item ) ;
2011-03-21 08:51:46 -04:00
this . _logoutItem = item ;
2009-11-10 12:13:58 -05:00
2010-10-19 12:04:58 -04:00
item = new PopupMenu . PopupSeparatorMenuItem ( ) ;
this . menu . addMenuItem ( item ) ;
2011-02-04 18:37:54 -05:00
item = new PopupMenu . PopupAlternatingMenuItem ( _ ( "Suspend" ) ,
_ ( "Power Off..." ) ) ;
2010-05-10 09:46:54 -04:00
this . menu . addMenuItem ( item ) ;
2011-02-04 18:37:54 -05:00
this . _suspendOrPowerOffItem = item ;
item . connect ( 'activate' , Lang . bind ( this , this . _onSuspendOrPowerOffActivate ) ) ;
this . _updateSuspendOrPowerOff ( ) ;
2009-11-10 12:13:58 -05:00
} ,
2011-07-28 10:59:03 -04:00
_updatePresenceStatus : function ( item , event ) {
2011-09-09 12:49:04 -04:00
let status ;
if ( item . state ) {
status = GnomeSession . PresenceStatus . AVAILABLE ;
} else {
status = GnomeSession . PresenceStatus . BUSY ;
2011-10-20 16:44:09 -04:00
let [ presence , s , msg ] = this . _accountMgr . get _most _available _presence ( ) ;
2011-09-09 12:49:04 -04:00
let newPresence = this . _statusChooser . getIMPresenceForSessionStatus ( status ) ;
if ( newPresence != presence &&
newPresence == Tp . ConnectionPresenceType . BUSY )
Main . notify ( _ ( "Your chat status will be set to busy" ) ,
_ ( "Notifications are now disabled, including chat messages. Your online status has been adjusted to let others know that you might not see their messages." ) ) ;
}
2011-11-11 16:41:47 -05:00
this . _presence . status = status ;
2009-11-10 16:34:13 -05:00
} ,
2010-10-19 12:04:58 -04:00
_onMyAccountActivate : function ( ) {
2010-06-03 19:21:08 -04:00
Main . overview . hide ( ) ;
Kill off ShellAppInfo, move into ShellApp
This dramatically thins down and sanitizes the application code.
The ShellAppSystem changes in a number of ways:
* Preferences are special cased more explicitly; they aren't apps,
they're shortcuts for an app), and we don't have many of them, so
don't need e.g. the optimizations in ShellAppSystem for searching.
* get_app() changes to lookup_app() and returns null if an app isn't
found. The semantics where it tried to find the .desktop file
if we didn't know about it were just broken; I am pretty sure no
caller needs this, and if they do we'll fix them.
* ShellAppSystem maintains two indexes on apps (by desktop file id
and by GMenuTreeEntry), but is no longer in the business of
dealing with GMenuTree as far as hierarchy and categories go. That
is moved up into js/ui/appDisplay.js. Actually, it flattens both
apps and settings.
Also, ShellWindowTracker is now the sole reference-owner for
window-backed apps. We still do the weird "window:0x1234beef" id
for these apps, but a reference is not stored in ShellAppSystem.
The js/ui/appDisplay.js code is rewritten, and sucks a lot less.
Variable names are clearer:
_apps -> _appIcons
_filterApp -> _visibleApps
_filters -> _categoryBox
Similarly for function names. We no longer call (for every app) a
recursive lookup in GMenuTree to see if it's in a particular section
on every category switch; it's all cached.
NOTE - this intentionally reverts the incremental loading code from
commit 7813c5b93f6bcde8c4beae286e82bfc472b2b656. It's fast enough
here without that.
https://bugzilla.gnome.org/show_bug.cgi?id=648149
2011-04-21 13:35:01 -04:00
let app = Shell . AppSystem . get _default ( ) . lookup _setting ( 'gnome-user-accounts-panel.desktop' ) ;
2011-08-11 05:35:23 -04:00
app . activate ( ) ;
2009-11-10 12:13:58 -05:00
} ,
2011-07-28 10:59:03 -04:00
_onOnlineAccountsActivate : function ( ) {
Main . overview . hide ( ) ;
let app = Shell . AppSystem . get _default ( ) . lookup _setting ( 'gnome-online-accounts-panel.desktop' ) ;
app . activate ( - 1 ) ;
} ,
2009-11-10 12:13:58 -05:00
_onPreferencesActivate : function ( ) {
2010-06-03 19:21:08 -04:00
Main . overview . hide ( ) ;
Kill off ShellAppInfo, move into ShellApp
This dramatically thins down and sanitizes the application code.
The ShellAppSystem changes in a number of ways:
* Preferences are special cased more explicitly; they aren't apps,
they're shortcuts for an app), and we don't have many of them, so
don't need e.g. the optimizations in ShellAppSystem for searching.
* get_app() changes to lookup_app() and returns null if an app isn't
found. The semantics where it tried to find the .desktop file
if we didn't know about it were just broken; I am pretty sure no
caller needs this, and if they do we'll fix them.
* ShellAppSystem maintains two indexes on apps (by desktop file id
and by GMenuTreeEntry), but is no longer in the business of
dealing with GMenuTree as far as hierarchy and categories go. That
is moved up into js/ui/appDisplay.js. Actually, it flattens both
apps and settings.
Also, ShellWindowTracker is now the sole reference-owner for
window-backed apps. We still do the weird "window:0x1234beef" id
for these apps, but a reference is not stored in ShellAppSystem.
The js/ui/appDisplay.js code is rewritten, and sucks a lot less.
Variable names are clearer:
_apps -> _appIcons
_filterApp -> _visibleApps
_filters -> _categoryBox
Similarly for function names. We no longer call (for every app) a
recursive lookup in GMenuTree to see if it's in a particular section
on every category switch; it's all cached.
NOTE - this intentionally reverts the incremental loading code from
commit 7813c5b93f6bcde8c4beae286e82bfc472b2b656. It's fast enough
here without that.
https://bugzilla.gnome.org/show_bug.cgi?id=648149
2011-04-21 13:35:01 -04:00
let app = Shell . AppSystem . get _default ( ) . lookup _app ( 'gnome-control-center.desktop' ) ;
2011-08-11 05:35:23 -04:00
app . activate ( ) ;
2009-11-10 12:13:58 -05:00
} ,
_onLockScreenActivate : function ( ) {
2010-06-03 19:21:08 -04:00
Main . overview . hide ( ) ;
2011-03-09 15:59:26 -05:00
this . _screenSaverProxy . LockRemote ( ) ;
2009-11-10 12:13:58 -05:00
} ,
_onLoginScreenActivate : function ( ) {
2010-06-03 19:21:08 -04:00
Main . overview . hide ( ) ;
2011-07-05 09:29:05 -04:00
// Ensure we only move to GDM after the screensaver has activated; in some
// OS configurations, the X server may block event processing on VT switch
2011-07-13 17:43:23 -04:00
this . _screenSaverProxy . SetActiveRemote ( true , Lang . bind ( this , function ( ) {
2011-05-10 10:13:05 -04:00
this . _userManager . goto _login _session ( ) ;
2011-07-05 09:29:05 -04:00
} ) ) ;
2009-11-10 12:13:58 -05:00
} ,
_onQuitSessionActivate : function ( ) {
2010-06-03 19:21:08 -04:00
Main . overview . hide ( ) ;
2011-03-12 15:34:01 -05:00
this . _session . LogoutRemote ( 0 ) ;
2009-11-10 12:13:58 -05:00
} ,
2011-02-04 18:37:54 -05:00
_onSuspendOrPowerOffActivate : function ( ) {
2010-06-03 19:21:08 -04:00
Main . overview . hide ( ) ;
2011-02-04 18:37:54 -05:00
if ( this . _haveSuspend &&
this . _suspendOrPowerOffItem . state == PopupMenu . PopupAlternatingMenuItemState . DEFAULT ) {
2012-02-26 15:23:01 -05:00
// Ensure we only suspend after locking the screen
2012-02-28 10:41:34 -05:00
this . _screenSaverProxy . LockRemote ( Lang . bind ( this , function ( ) {
2011-03-09 15:59:50 -05:00
this . _upClient . suspend _sync ( null ) ;
} ) ) ;
2011-02-04 18:37:54 -05:00
} else {
2011-03-12 15:34:01 -05:00
this . _session . ShutdownRemote ( ) ;
2011-02-04 18:37:54 -05:00
}
2009-11-10 12:13:58 -05:00
}
2011-11-20 09:38:48 -05:00
} ) ;