2011-09-28 09:16:26 -04:00
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
2019-01-31 09:07:06 -05:00
/* exported init, EndSessionDialog */
2011-09-28 09:16:26 -04:00
/ *
2016-03-15 13:46:40 -04:00
* Copyright 2010 - 2016 Red Hat , Inc
2011-01-06 10:30:15 -05:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2014-01-07 16:32:37 -05:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2011-01-06 10:30:15 -05:00
* /
2019-02-08 22:21:36 -05:00
const { AccountsService , Clutter , Gio ,
2019-05-23 16:45:44 -04:00
GLib , GObject , Pango , Polkit , Shell , St } = imports . gi ;
2011-01-06 10:30:15 -05:00
2014-02-19 13:58:50 -05:00
const CheckBox = imports . ui . checkBox ;
2011-08-16 08:24:39 -04:00
const GnomeSession = imports . misc . gnomeSession ;
2013-08-22 14:35:28 -04:00
const LoginManager = imports . misc . loginManager ;
2011-01-06 10:30:15 -05:00
const ModalDialog = imports . ui . modalDialog ;
2013-04-23 22:31:08 -04:00
const UserWidget = imports . ui . userWidget ;
2011-01-06 10:30:15 -05:00
2018-09-05 20:55:20 -04:00
const { loadInterfaceXML } = imports . misc . fileUtils ;
2011-01-06 10:30:15 -05:00
const _ITEM _ICON _SIZE = 48 ;
2014-02-18 15:41:30 -05:00
const _DIALOG _ICON _SIZE = 48 ;
2011-01-06 10:30:15 -05:00
2018-09-05 20:55:20 -04:00
const EndSessionDialogIface = loadInterfaceXML ( 'org.gnome.SessionManager.EndSessionDialog' ) ;
2011-01-06 10:30:15 -05:00
const logoutDialogContent = {
2011-10-21 16:29:13 -04:00
subjectWithUser : C _ ( "title" , "Log Out %s" ) ,
subject : C _ ( "title" , "Log Out" ) ,
2017-10-30 20:03:21 -04:00
descriptionWithUser ( user , seconds ) {
2011-09-07 07:34:48 -04:00
return ngettext ( "%s will be logged out automatically in %d second." ,
"%s will be logged out automatically in %d seconds." ,
seconds ) . format ( user , seconds ) ;
} ,
2017-10-30 20:03:21 -04:00
description ( seconds ) {
2011-09-07 07:34:48 -04:00
return ngettext ( "You will be logged out automatically in %d second." ,
"You will be logged out automatically in %d seconds." ,
seconds ) . format ( seconds ) ;
} ,
2014-02-19 13:59:47 -05:00
showBatteryWarning : false ,
2011-03-21 16:12:30 -04:00
confirmButtons : [ { signal : 'ConfirmedLogout' ,
2019-01-28 20:27:05 -05:00
label : C _ ( "button" , "Log Out" ) } ] ,
2013-08-30 07:40:40 -04:00
iconStyleClass : 'end-session-dialog-logout-icon' ,
showOtherSessions : false ,
2011-01-06 10:30:15 -05:00
} ;
const shutdownDialogContent = {
2011-10-21 16:29:13 -04:00
subject : C _ ( "title" , "Power Off" ) ,
2014-02-19 13:58:50 -05:00
subjectWithUpdates : C _ ( "title" , "Install Updates & Power Off" ) ,
2017-10-30 20:03:21 -04:00
description ( seconds ) {
2011-09-07 07:34:48 -04:00
return ngettext ( "The system will power off automatically in %d second." ,
"The system will power off automatically in %d seconds." ,
seconds ) . format ( seconds ) ;
} ,
2014-02-19 13:58:50 -05:00
checkBoxText : C _ ( "checkbox" , "Install pending software updates" ) ,
2014-02-19 13:59:47 -05:00
showBatteryWarning : true ,
2011-03-21 16:12:30 -04:00
confirmButtons : [ { signal : 'ConfirmedReboot' ,
2019-01-28 20:27:05 -05:00
label : C _ ( "button" , "Restart" ) } ,
2011-03-21 16:12:30 -04:00
{ signal : 'ConfirmedShutdown' ,
2019-01-28 20:27:05 -05:00
label : C _ ( "button" , "Power Off" ) } ] ,
2012-05-30 09:58:37 -04:00
iconName : 'system-shutdown-symbolic' ,
2013-08-30 07:40:40 -04:00
iconStyleClass : 'end-session-dialog-shutdown-icon' ,
showOtherSessions : true ,
2011-01-06 10:30:15 -05:00
} ;
const restartDialogContent = {
2011-10-21 16:29:13 -04:00
subject : C _ ( "title" , "Restart" ) ,
2017-10-30 20:03:21 -04:00
description ( seconds ) {
2011-09-07 07:34:48 -04:00
return ngettext ( "The system will restart automatically in %d second." ,
"The system will restart automatically in %d seconds." ,
seconds ) . format ( seconds ) ;
} ,
2014-02-19 13:59:47 -05:00
showBatteryWarning : false ,
2011-03-21 16:12:30 -04:00
confirmButtons : [ { signal : 'ConfirmedReboot' ,
2019-01-28 20:27:05 -05:00
label : C _ ( "button" , "Restart" ) } ] ,
2012-11-01 12:18:32 -04:00
iconName : 'view-refresh-symbolic' ,
2013-08-30 07:40:40 -04:00
iconStyleClass : 'end-session-dialog-shutdown-icon' ,
showOtherSessions : true ,
2011-01-06 10:30:15 -05:00
} ;
2016-03-14 18:52:14 -04:00
const restartUpdateDialogContent = {
2013-08-26 00:52:41 -04:00
subject : C _ ( "title" , "Restart & Install Updates" ) ,
2017-10-30 20:03:21 -04:00
description ( seconds ) {
2013-08-26 00:52:41 -04:00
return ngettext ( "The system will automatically restart and install updates in %d second." ,
"The system will automatically restart and install updates in %d seconds." ,
seconds ) . format ( seconds ) ;
} ,
2014-02-19 13:59:47 -05:00
showBatteryWarning : true ,
2013-08-26 00:52:41 -04:00
confirmButtons : [ { signal : 'ConfirmedReboot' ,
2019-01-28 20:27:05 -05:00
label : C _ ( "button" , "Restart & Install" ) } ] ,
2014-02-19 17:53:00 -05:00
unusedFutureButtonForTranslation : C _ ( "button" , "Install & Power Off" ) ,
unusedFutureCheckBoxForTranslation : C _ ( "checkbox" , "Power off after updates are installed" ) ,
2013-08-26 00:52:41 -04:00
iconName : 'view-refresh-symbolic' ,
2013-08-30 07:40:40 -04:00
iconStyleClass : 'end-session-dialog-shutdown-icon' ,
showOtherSessions : true ,
2013-08-26 00:52:41 -04:00
} ;
2016-03-15 13:46:40 -04:00
const restartUpgradeDialogContent = {
subject : C _ ( "title" , "Restart & Install Upgrade" ) ,
2017-10-30 20:03:21 -04:00
upgradeDescription ( distroName , distroVersion ) {
2016-03-15 13:46:40 -04:00
/ * T r a n s l a t o r s : T h i s i s t h e t e x t d i s p l a y e d f o r s y s t e m u p g r a d e s i n t h e
shut down dialog . First % s gets replaced with the distro name and
second % s with the distro version to upgrade to * /
return _ ( "%s %s will be installed after restart. Upgrade installation can take a long time: ensure that you have backed up and that the computer is plugged in." ) . format ( distroName , distroVersion ) ;
} ,
disableTimer : true ,
showBatteryWarning : false ,
confirmButtons : [ { signal : 'ConfirmedReboot' ,
2019-01-28 20:27:05 -05:00
label : C _ ( "button" , "Restart & Install" ) } ] ,
2016-03-15 13:46:40 -04:00
iconName : 'view-refresh-symbolic' ,
iconStyleClass : 'end-session-dialog-shutdown-icon' ,
showOtherSessions : true ,
} ;
2014-09-11 09:55:07 -04:00
const DialogType = {
2019-01-29 14:36:54 -05:00
LOGOUT : 0 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_LOGOUT */ ,
SHUTDOWN : 1 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_SHUTDOWN */ ,
RESTART : 2 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_RESTART */ ,
UPDATE _RESTART : 3 ,
UPGRADE _RESTART : 4
2014-09-11 09:55:07 -04:00
} ;
2011-01-06 10:30:15 -05:00
const DialogContent = {
2014-09-11 12:04:36 -04:00
0 /* DialogType.LOGOUT */ : logoutDialogContent ,
1 /* DialogType.SHUTDOWN */ : shutdownDialogContent ,
2 /* DialogType.RESTART */ : restartDialogContent ,
2016-03-15 13:46:40 -04:00
3 /* DialogType.UPDATE_RESTART */ : restartUpdateDialogContent ,
4 /* DialogType.UPGRADE_RESTART */ : restartUpgradeDialogContent
2011-01-06 10:30:15 -05:00
} ;
2017-07-18 13:47:27 -04:00
var MAX _USERS _IN _SESSION _DIALOG = 5 ;
2013-08-22 14:35:28 -04:00
2018-09-05 20:55:20 -04:00
const LogindSessionIface = loadInterfaceXML ( 'org.freedesktop.login1.Session' ) ;
2013-08-22 14:35:28 -04:00
const LogindSession = Gio . DBusProxy . makeProxyWrapper ( LogindSessionIface ) ;
2018-09-05 20:55:20 -04:00
const PkOfflineIface = loadInterfaceXML ( 'org.freedesktop.PackageKit.Offline' ) ;
2014-09-09 07:16:25 -04:00
const PkOfflineProxy = Gio . DBusProxy . makeProxyWrapper ( PkOfflineIface ) ;
2018-09-05 20:55:20 -04:00
const UPowerIface = loadInterfaceXML ( 'org.freedesktop.UPower' ) ;
2014-02-19 13:59:47 -05:00
const UPowerProxy = Gio . DBusProxy . makeProxyWrapper ( UPowerIface ) ;
2011-01-06 10:30:15 -05:00
function findAppFromInhibitor ( inhibitor ) {
2013-08-22 16:14:14 -04:00
let desktopFile ;
try {
[ desktopFile ] = inhibitor . GetAppIdSync ( ) ;
2019-01-28 20:26:39 -05:00
} catch ( e ) {
2013-08-22 16:14:14 -04:00
// XXX -- sometimes JIT inhibitors generated by gnome-session
// get removed too soon. Don't fail in this case.
2013-08-22 17:27:43 -04:00
log ( 'gnome-session gave us a dead inhibitor: %s' . format ( inhibitor . get _object _path ( ) ) ) ;
2013-08-22 16:14:14 -04:00
return null ;
}
2011-01-06 10:30:15 -05:00
if ( ! GLib . str _has _suffix ( desktopFile , '.desktop' ) )
2012-03-16 22:13:37 -04:00
desktopFile += '.desktop' ;
2011-01-06 10:30:15 -05:00
2012-03-16 22:16:30 -04:00
return Shell . AppSystem . get _default ( ) . lookup _heuristic _basename ( desktopFile ) ;
2011-01-06 10:30:15 -05:00
}
// The logout timer only shows updates every 10 seconds
// until the last 10 seconds, then it shows updates every
// second. This function takes a given time and returns
// what we should show to the user for that time.
function _roundSecondsToInterval ( totalSeconds , secondsLeft , interval ) {
let time ;
time = Math . ceil ( secondsLeft ) ;
// Final count down is in decrements of 1
if ( time <= interval )
return time ;
// Round up higher than last displayable time interval
time += interval - 1 ;
// Then round down to that time interval
if ( time > totalSeconds )
time = Math . ceil ( totalSeconds ) ;
else
time -= time % interval ;
return time ;
}
function _setLabelText ( label , text ) {
if ( text ) {
label . set _text ( text ) ;
label . show ( ) ;
} else {
label . set _text ( '' ) ;
label . hide ( ) ;
}
}
2014-02-19 13:58:50 -05:00
function _setCheckBoxLabel ( checkBox , text ) {
let label = checkBox . getLabelActor ( ) ;
if ( text ) {
label . set _text ( text ) ;
checkBox . actor . show ( ) ;
} else {
label . set _text ( '' ) ;
checkBox . actor . hide ( ) ;
}
}
2011-01-06 10:30:15 -05:00
function init ( ) {
// This always returns the same singleton object
// By instantiating it initially, we register the
// bus object, etc.
2019-01-31 09:04:56 -05:00
( new EndSessionDialog ( ) ) ;
2011-01-06 10:30:15 -05:00
}
2019-05-23 16:45:44 -04:00
var EndSessionDialog = GObject . registerClass (
class EndSessionDialog extends ModalDialog . ModalDialog {
_init ( ) {
super . _init ( { styleClass : 'end-session-dialog' ,
destroyOnClose : false } ) ;
2011-01-06 10:30:15 -05:00
2013-08-22 14:35:28 -04:00
this . _loginManager = LoginManager . getLoginManager ( ) ;
this . _userManager = AccountsService . UserManager . get _default ( ) ;
this . _user = this . _userManager . get _user ( GLib . get _user _name ( ) ) ;
2019-07-08 02:51:36 -04:00
this . _updatesPermission = null ;
2011-01-06 10:30:15 -05:00
2014-09-09 07:16:25 -04:00
this . _pkOfflineProxy = new PkOfflineProxy ( Gio . DBus . system ,
'org.freedesktop.PackageKit' ,
'/org/freedesktop/PackageKit' ,
2019-07-08 02:51:36 -04:00
this . _onPkOfflineProxyCreated . bind ( this ) ) ;
2014-02-19 13:59:47 -05:00
this . _powerProxy = new UPowerProxy ( Gio . DBus . system ,
'org.freedesktop.UPower' ,
'/org/freedesktop/UPower' ,
2017-10-30 20:38:18 -04:00
( proxy , error ) => {
2014-02-19 13:59:47 -05:00
if ( error ) {
log ( error . message ) ;
return ;
}
this . _powerProxy . connect ( 'g-properties-changed' ,
2017-12-01 19:27:35 -05:00
this . _sync . bind ( this ) ) ;
2014-02-19 13:59:47 -05:00
this . _sync ( ) ;
2017-10-30 20:38:18 -04:00
} ) ;
2014-02-19 13:59:47 -05:00
2011-01-06 10:30:15 -05:00
this . _secondsLeft = 0 ;
this . _totalSecondsToStayOpen = 0 ;
2013-08-23 12:13:35 -04:00
this . _applications = [ ] ;
2013-08-22 14:35:28 -04:00
this . _sessions = [ ] ;
2011-01-06 10:30:15 -05:00
this . connect ( 'destroy' ,
2017-12-01 19:27:35 -05:00
this . _onDestroy . bind ( this ) ) ;
2011-01-06 10:30:15 -05:00
this . connect ( 'opened' ,
2017-12-01 19:27:35 -05:00
this . _onOpened . bind ( this ) ) ;
2011-01-06 10:30:15 -05:00
2017-12-01 19:27:35 -05:00
this . _userLoadedId = this . _user . connect ( 'notify::is_loaded' , this . _sync . bind ( this ) ) ;
this . _userChangedId = this . _user . connect ( 'changed' , this . _sync . bind ( this ) ) ;
2011-01-06 10:30:15 -05:00
let mainContentLayout = new St . BoxLayout ( { vertical : false } ) ;
this . contentLayout . add ( mainContentLayout ,
{ x _fill : true ,
y _fill : false } ) ;
this . _iconBin = new St . Bin ( ) ;
mainContentLayout . add ( this . _iconBin ,
2019-01-28 20:27:05 -05:00
{ x _fill : true ,
y _fill : false ,
2011-01-06 10:30:15 -05:00
x _align : St . Align . END ,
y _align : St . Align . START } ) ;
2014-02-18 15:49:33 -05:00
let messageLayout = new St . BoxLayout ( { vertical : true ,
style _class : 'end-session-dialog-layout' } ) ;
2011-01-06 10:30:15 -05:00
mainContentLayout . add ( messageLayout ,
{ y _align : St . Align . START } ) ;
this . _subjectLabel = new St . Label ( { style _class : 'end-session-dialog-subject' } ) ;
messageLayout . add ( this . _subjectLabel ,
2013-12-11 15:42:01 -05:00
{ x _fill : false ,
2019-01-28 20:27:05 -05:00
y _fill : false ,
2013-12-11 15:42:01 -05:00
x _align : St . Align . START ,
2011-01-06 10:30:15 -05:00
y _align : St . Align . START } ) ;
this . _descriptionLabel = new St . Label ( { style _class : 'end-session-dialog-description' } ) ;
this . _descriptionLabel . clutter _text . ellipsize = Pango . EllipsizeMode . NONE ;
this . _descriptionLabel . clutter _text . line _wrap = true ;
messageLayout . add ( this . _descriptionLabel ,
2019-01-28 20:27:05 -05:00
{ y _fill : true ,
2011-01-06 10:30:15 -05:00
y _align : St . Align . START } ) ;
2014-02-19 13:58:50 -05:00
this . _checkBox = new CheckBox . CheckBox ( ) ;
2017-12-01 19:27:35 -05:00
this . _checkBox . actor . connect ( 'clicked' , this . _sync . bind ( this ) ) ;
2014-02-19 13:58:50 -05:00
messageLayout . add ( this . _checkBox . actor ) ;
2014-02-19 13:59:47 -05:00
this . _batteryWarning = new St . Label ( { style _class : 'end-session-dialog-warning' ,
text : _ ( "Running on battery power: please plug in before installing updates." ) } ) ;
this . _batteryWarning . clutter _text . ellipsize = Pango . EllipsizeMode . NONE ;
this . _batteryWarning . clutter _text . line _wrap = true ;
messageLayout . add ( this . _batteryWarning ) ;
2013-08-23 12:13:35 -04:00
this . _scrollView = new St . ScrollView ( { style _class : 'end-session-dialog-list' } ) ;
2018-11-27 07:45:36 -05:00
this . _scrollView . set _policy ( St . PolicyType . NEVER , St . PolicyType . AUTOMATIC ) ;
2013-08-23 12:13:35 -04:00
this . contentLayout . add ( this . _scrollView ,
2011-01-06 10:30:15 -05:00
{ x _fill : true ,
y _fill : true } ) ;
2013-08-23 12:13:35 -04:00
this . _scrollView . hide ( ) ;
2011-03-21 16:11:15 -04:00
2013-08-23 12:13:35 -04:00
this . _inhibitorSection = new St . BoxLayout ( { vertical : true ,
style _class : 'end-session-dialog-inhibitor-layout' } ) ;
this . _scrollView . add _actor ( this . _inhibitorSection ) ;
2011-03-21 16:11:15 -04:00
2013-08-23 12:13:35 -04:00
this . _applicationHeader = new St . Label ( { style _class : 'end-session-dialog-list-header' ,
text : _ ( "Some applications are busy or have unsaved work." ) } ) ;
2013-10-20 09:03:18 -04:00
this . _applicationList = new St . BoxLayout ( { style _class : 'end-session-dialog-app-list' ,
vertical : true } ) ;
2013-08-23 12:13:35 -04:00
this . _inhibitorSection . add _actor ( this . _applicationHeader ) ;
this . _inhibitorSection . add _actor ( this . _applicationList ) ;
2011-03-21 16:11:15 -04:00
2013-08-23 12:13:35 -04:00
this . _sessionHeader = new St . Label ( { style _class : 'end-session-dialog-list-header' ,
text : _ ( "Other users are logged in." ) } ) ;
2013-10-20 09:03:18 -04:00
this . _sessionList = new St . BoxLayout ( { style _class : 'end-session-dialog-session-list' ,
vertical : true } ) ;
2013-08-23 12:13:35 -04:00
this . _inhibitorSection . add _actor ( this . _sessionHeader ) ;
this . _inhibitorSection . add _actor ( this . _sessionList ) ;
2011-08-16 08:24:39 -04:00
2019-07-08 02:51:36 -04:00
this . _dbusImpl = Gio . DBusExportedObject . wrapJSObject ( EndSessionDialogIface , this ) ;
this . _dbusImpl . export ( Gio . DBus . session , '/org/gnome/SessionManager/EndSessionDialog' ) ;
}
_onPkOfflineProxyCreated ( proxy , error ) {
if ( error ) {
log ( error . message ) ;
return ;
}
// Creating a D-Bus proxy won't propagate SERVICE_UNKNOWN or NAME_HAS_NO_OWNER
// errors if PackageKit is not available, but the GIO implementation will make
// sure in that case that the proxy's g-name-owner is set to null, so check that.
if ( this . _pkOfflineProxy . g _name _owner === null ) {
this . _pkOfflineProxy = null ;
return ;
}
// It only makes sense to check for this permission if PackageKit is available.
2019-08-23 08:48:36 -04:00
Polkit . Permission . new (
'org.freedesktop.packagekit.trigger-offline-update' , null , null ,
( source , res ) => {
try {
this . _updatesPermission = Polkit . Permission . new _finish ( res ) ;
} catch ( e ) {
log ( ` No permission to trigger offline updates: ${ e } ` ) ;
}
} ) ;
2017-10-30 21:19:44 -04:00
}
2011-01-06 10:30:15 -05:00
2017-10-30 20:03:21 -04:00
_onDestroy ( ) {
2011-01-06 10:30:15 -05:00
this . _user . disconnect ( this . _userLoadedId ) ;
this . _user . disconnect ( this . _userChangedId ) ;
2017-10-30 21:19:44 -04:00
}
2011-01-06 10:30:15 -05:00
2017-10-30 20:03:21 -04:00
_sync ( ) {
2013-08-22 14:48:28 -04:00
let open = ( this . state == ModalDialog . State . OPENING || this . state == ModalDialog . State . OPENED ) ;
if ( ! open )
2011-01-06 10:30:15 -05:00
return ;
let dialogContent = DialogContent [ this . _type ] ;
let subject = dialogContent . subject ;
2014-02-19 13:58:50 -05:00
// Use different title when we are installing updates
if ( dialogContent . subjectWithUpdates && this . _checkBox . actor . checked )
subject = dialogContent . subjectWithUpdates ;
2014-02-19 13:59:47 -05:00
if ( dialogContent . showBatteryWarning ) {
// Warn when running on battery power
if ( this . _powerProxy . OnBattery && this . _checkBox . actor . checked )
this . _batteryWarning . opacity = 255 ;
else
this . _batteryWarning . opacity = 0 ;
}
2013-08-22 14:48:28 -04:00
let description ;
2013-08-23 12:30:30 -04:00
let displayTime = _roundSecondsToInterval ( this . _totalSecondsToStayOpen ,
this . _secondsLeft ,
10 ) ;
2011-01-06 10:30:15 -05:00
2013-08-23 12:30:30 -04:00
if ( this . _user . is _loaded ) {
let realName = this . _user . get _real _name ( ) ;
if ( realName != null ) {
if ( dialogContent . subjectWithUser )
subject = dialogContent . subjectWithUser . format ( realName ) ;
if ( dialogContent . descriptionWithUser )
description = dialogContent . descriptionWithUser ( realName , displayTime ) ;
}
2011-01-06 10:30:15 -05:00
}
2016-03-15 13:46:40 -04:00
// Use a different description when we are installing a system upgrade
2019-07-08 02:51:36 -04:00
// if the PackageKit proxy is available (i.e. PackageKit is available).
if ( this . _pkOfflineProxy && dialogContent . upgradeDescription ) {
2016-03-15 13:46:40 -04:00
let name = this . _pkOfflineProxy . PreparedUpgrade [ 'name' ] . deep _unpack ( ) ;
let version = this . _pkOfflineProxy . PreparedUpgrade [ 'version' ] . deep _unpack ( ) ;
if ( name != null && version != null )
description = dialogContent . upgradeDescription ( name , version ) ;
}
// Fall back to regular description
2013-08-23 12:30:30 -04:00
if ( ! description )
description = dialogContent . description ( displayTime ) ;
2011-01-06 10:30:15 -05:00
_setLabelText ( this . _descriptionLabel , description ) ;
2013-08-22 14:48:28 -04:00
_setLabelText ( this . _subjectLabel , subject ) ;
2012-06-05 05:51:36 -04:00
2012-08-31 17:18:26 -04:00
if ( dialogContent . iconName ) {
this . _iconBin . child = new St . Icon ( { icon _name : dialogContent . iconName ,
icon _size : _DIALOG _ICON _SIZE ,
style _class : dialogContent . iconStyleClass } ) ;
} else {
2013-04-23 22:31:08 -04:00
let avatarWidget = new UserWidget . Avatar ( this . _user ,
{ iconSize : _DIALOG _ICON _SIZE ,
styleClass : dialogContent . iconStyleClass } ) ;
2012-08-31 17:18:26 -04:00
this . _iconBin . child = avatarWidget . actor ;
avatarWidget . update ( ) ;
2012-06-05 05:51:36 -04:00
}
2013-08-23 12:13:35 -04:00
let hasApplications = this . _applications . length > 0 ;
let hasSessions = this . _sessions . length > 0 ;
this . _scrollView . visible = hasApplications || hasSessions ;
this . _applicationHeader . visible = hasApplications ;
this . _sessionHeader . visible = hasSessions ;
2017-10-30 21:19:44 -04:00
}
2012-06-05 05:51:36 -04:00
2017-10-30 20:03:21 -04:00
_updateButtons ( ) {
2011-01-06 10:30:15 -05:00
let dialogContent = DialogContent [ this . _type ] ;
2017-12-01 19:27:35 -05:00
let buttons = [ { action : this . cancel . bind ( this ) ,
2019-01-28 20:27:05 -05:00
label : _ ( "Cancel" ) ,
key : Clutter . Escape } ] ;
2011-03-21 16:12:30 -04:00
for ( let i = 0 ; i < dialogContent . confirmButtons . length ; i ++ ) {
let signal = dialogContent . confirmButtons [ i ] . signal ;
let label = dialogContent . confirmButtons [ i ] . label ;
2019-02-12 09:02:09 -05:00
buttons . push ( {
action : ( ) => {
this . close ( true ) ;
let signalId = this . connect ( 'closed' , ( ) => {
this . disconnect ( signalId ) ;
this . _confirm ( signal ) ;
} ) ;
} ,
label : label ,
} ) ;
2011-03-21 16:12:30 -04:00
}
this . setButtons ( buttons ) ;
2017-10-30 21:19:44 -04:00
}
2011-01-06 10:30:15 -05:00
2017-10-30 20:03:21 -04:00
close ( skipSignal ) {
2017-10-30 21:19:44 -04:00
super . close ( ) ;
2013-02-20 13:30:26 -05:00
if ( ! skipSignal )
this . _dbusImpl . emit _signal ( 'Closed' , null ) ;
2017-10-30 21:19:44 -04:00
}
2011-03-22 12:50:56 -04:00
2017-10-30 20:03:21 -04:00
cancel ( ) {
2011-01-06 10:30:15 -05:00
this . _stopTimer ( ) ;
2011-08-16 08:24:39 -04:00
this . _dbusImpl . emit _signal ( 'Canceled' , null ) ;
2013-02-20 13:12:42 -05:00
this . close ( ) ;
2017-10-30 21:19:44 -04:00
}
2011-01-06 10:30:15 -05:00
2017-10-30 20:03:21 -04:00
_confirm ( signal ) {
2017-10-30 20:38:18 -04:00
let callback = ( ) => {
2014-02-19 13:58:50 -05:00
this . _fadeOutDialog ( ) ;
this . _stopTimer ( ) ;
this . _dbusImpl . emit _signal ( signal , null ) ;
2017-10-30 20:38:18 -04:00
} ;
2014-02-19 13:58:50 -05:00
// Offline update not available; just emit the signal
if ( ! this . _checkBox . actor . visible ) {
callback ( ) ;
return ;
}
// Trigger the offline update as requested
if ( this . _checkBox . actor . checked ) {
switch ( signal ) {
2019-02-01 07:21:00 -05:00
case "ConfirmedReboot" :
this . _triggerOfflineUpdateReboot ( callback ) ;
break ;
case "ConfirmedShutdown" :
// To actually trigger the offline update, we need to
// reboot to do the upgrade. When the upgrade is complete,
// the computer will shut down automatically.
signal = "ConfirmedReboot" ;
this . _triggerOfflineUpdateShutdown ( callback ) ;
break ;
default :
callback ( ) ;
break ;
2014-02-19 13:58:50 -05:00
}
} else {
this . _triggerOfflineUpdateCancel ( callback ) ;
}
2017-10-30 21:19:44 -04:00
}
2011-01-06 10:30:15 -05:00
2017-10-30 20:03:21 -04:00
_onOpened ( ) {
2013-08-22 14:48:28 -04:00
this . _sync ( ) ;
2017-10-30 21:19:44 -04:00
}
2011-01-06 10:30:15 -05:00
2017-10-30 20:03:21 -04:00
_triggerOfflineUpdateReboot ( callback ) {
2019-07-08 02:51:36 -04:00
// Handle this gracefully if PackageKit is not available.
if ( ! this . _pkOfflineProxy ) {
callback ( ) ;
return ;
}
2017-10-30 20:38:18 -04:00
this . _pkOfflineProxy . TriggerRemote ( 'reboot' , ( result , error ) => {
2014-09-09 07:16:25 -04:00
if ( error )
log ( error . message ) ;
2014-02-19 13:58:50 -05:00
2014-09-09 07:16:25 -04:00
callback ( ) ;
} ) ;
2017-10-30 21:19:44 -04:00
}
2014-02-19 13:58:50 -05:00
2017-10-30 20:03:21 -04:00
_triggerOfflineUpdateShutdown ( callback ) {
2019-07-08 02:51:36 -04:00
// Handle this gracefully if PackageKit is not available.
if ( ! this . _pkOfflineProxy ) {
callback ( ) ;
return ;
}
2017-10-30 20:38:18 -04:00
this . _pkOfflineProxy . TriggerRemote ( 'power-off' , ( result , error ) => {
2014-09-09 07:16:25 -04:00
if ( error )
log ( error . message ) ;
2014-02-19 13:58:50 -05:00
callback ( ) ;
2014-09-09 07:16:25 -04:00
} ) ;
2017-10-30 21:19:44 -04:00
}
2014-02-19 13:58:50 -05:00
2017-10-30 20:03:21 -04:00
_triggerOfflineUpdateCancel ( callback ) {
2019-07-08 02:51:36 -04:00
// Handle this gracefully if PackageKit is not available.
if ( ! this . _pkOfflineProxy ) {
callback ( ) ;
return ;
}
2017-10-30 20:38:18 -04:00
this . _pkOfflineProxy . CancelRemote ( ( result , error ) => {
2014-09-09 07:16:25 -04:00
if ( error )
log ( error . message ) ;
2014-02-19 13:58:50 -05:00
callback ( ) ;
} ) ;
2017-10-30 21:19:44 -04:00
}
2014-02-19 13:58:50 -05:00
2017-10-30 20:03:21 -04:00
_startTimer ( ) {
2013-01-26 03:01:41 -05:00
let startTime = GLib . get _monotonic _time ( ) ;
2011-01-06 10:30:15 -05:00
this . _secondsLeft = this . _totalSecondsToStayOpen ;
2013-01-26 03:01:41 -05:00
2019-08-19 14:50:33 -04:00
this . _timerId = GLib . timeout _add _seconds ( GLib . PRIORITY _DEFAULT , 1 , ( ) => {
2017-10-30 20:38:18 -04:00
let currentTime = GLib . get _monotonic _time ( ) ;
let secondsElapsed = ( ( currentTime - startTime ) / 1000000 ) ;
2013-01-26 03:01:41 -05:00
2017-10-30 20:38:18 -04:00
this . _secondsLeft = this . _totalSecondsToStayOpen - secondsElapsed ;
if ( this . _secondsLeft > 0 ) {
this . _sync ( ) ;
return GLib . SOURCE _CONTINUE ;
}
2013-01-26 03:01:41 -05:00
2017-10-30 20:38:18 -04:00
let dialogContent = DialogContent [ this . _type ] ;
let button = dialogContent . confirmButtons [ dialogContent . confirmButtons . length - 1 ] ;
this . _confirm ( button . signal ) ;
this . _timerId = 0 ;
2013-01-26 03:01:41 -05:00
2017-10-30 20:38:18 -04:00
return GLib . SOURCE _REMOVE ;
} ) ;
2014-04-10 13:26:52 -04:00
GLib . Source . set _name _by _id ( this . _timerId , '[gnome-shell] this._confirm' ) ;
2017-10-30 21:19:44 -04:00
}
2011-01-06 10:30:15 -05:00
2017-10-30 20:03:21 -04:00
_stopTimer ( ) {
2013-08-22 16:17:52 -04:00
if ( this . _timerId > 0 ) {
2019-08-19 14:50:33 -04:00
GLib . source _remove ( this . _timerId ) ;
2013-01-26 03:01:41 -05:00
this . _timerId = 0 ;
}
2011-01-06 10:30:15 -05:00
this . _secondsLeft = 0 ;
2017-10-30 21:19:44 -04:00
}
2011-01-06 10:30:15 -05:00
2017-10-30 20:03:21 -04:00
_constructListItemForApp ( inhibitor , app ) {
2013-08-23 12:13:35 -04:00
let actor = new St . BoxLayout ( { style _class : 'end-session-dialog-app-list-item' ,
can _focus : true } ) ;
actor . add ( app . create _icon _texture ( _ITEM _ICON _SIZE ) ) ;
let textLayout = new St . BoxLayout ( { vertical : true ,
y _expand : true ,
y _align : Clutter . ActorAlign . CENTER } ) ;
actor . add ( textLayout ) ;
let nameLabel = new St . Label ( { text : app . get _name ( ) ,
style _class : 'end-session-dialog-app-list-item-name' } ) ;
textLayout . add ( nameLabel ) ;
actor . label _actor = nameLabel ;
let [ reason ] = inhibitor . GetReasonSync ( ) ;
if ( reason ) {
let reasonLabel = new St . Label ( { text : reason ,
style _class : 'end-session-dialog-app-list-item-description' } ) ;
textLayout . add ( reasonLabel ) ;
}
return actor ;
2017-10-30 21:19:44 -04:00
}
2013-08-23 12:13:35 -04:00
2017-10-30 20:03:21 -04:00
_onInhibitorLoaded ( inhibitor ) {
2018-07-14 16:56:22 -04:00
if ( ! this . _applications . includes ( inhibitor ) ) {
2011-01-06 10:30:15 -05:00
// Stale inhibitor
return ;
}
let app = findAppFromInhibitor ( inhibitor ) ;
if ( app ) {
2013-08-23 12:13:35 -04:00
let actor = this . _constructListItemForApp ( inhibitor , app ) ;
this . _applicationList . add ( actor ) ;
2011-01-06 10:30:15 -05:00
} else {
// inhibiting app is a service, not an application
2013-08-23 12:13:35 -04:00
this . _applications . splice ( this . _applications . indexOf ( inhibitor ) , 1 ) ;
2011-01-06 10:30:15 -05:00
}
2013-08-22 14:48:28 -04:00
this . _sync ( ) ;
2017-10-30 21:19:44 -04:00
}
2011-01-06 10:30:15 -05:00
2017-10-30 20:03:21 -04:00
_constructListItemForSession ( session ) {
2013-08-23 12:13:35 -04:00
let avatar = new UserWidget . Avatar ( session . user , { iconSize : _ITEM _ICON _SIZE } ) ;
avatar . update ( ) ;
let userName = session . user . get _real _name ( ) ? session . user . get _real _name ( ) : session . username ;
let userLabelText ;
if ( session . remote )
/* Translators: Remote here refers to a remote session, like a ssh login */
userLabelText = _ ( "%s (remote)" ) . format ( userName ) ;
else if ( session . type == "tty" )
/* Translators: Console here refers to a tty like a VT console */
userLabelText = _ ( "%s (console)" ) . format ( userName ) ;
else
userLabelText = userName ;
let actor = new St . BoxLayout ( { style _class : 'end-session-dialog-session-list-item' ,
can _focus : true } ) ;
actor . add ( avatar . actor ) ;
let nameLabel = new St . Label ( { text : userLabelText ,
style _class : 'end-session-dialog-session-list-item-name' ,
y _expand : true ,
y _align : Clutter . ActorAlign . CENTER } ) ;
actor . add ( nameLabel ) ;
actor . label _actor = nameLabel ;
return actor ;
2017-10-30 21:19:44 -04:00
}
2013-08-23 12:13:35 -04:00
2017-10-30 20:03:21 -04:00
_loadSessions ( ) {
2017-10-30 20:38:18 -04:00
this . _loginManager . listSessions ( result => {
2013-08-22 14:35:28 -04:00
let n = 0 ;
for ( let i = 0 ; i < result . length ; i ++ ) {
2019-01-31 09:08:00 -05:00
let [ id _ , uid _ , userName , seat _ , sessionPath ] = result [ i ] ;
2013-08-22 14:35:28 -04:00
let proxy = new LogindSession ( Gio . DBus . system , 'org.freedesktop.login1' , sessionPath ) ;
if ( proxy . Class != 'user' )
continue ;
if ( proxy . State == 'closing' )
continue ;
2018-01-08 09:23:52 -05:00
let sessionId = GLib . getenv ( 'XDG_SESSION_ID' ) ;
if ( ! sessionId )
this . _loginManager . getCurrentSessionProxy ( currentSessionProxy => {
sessionId = currentSessionProxy . Id ;
log ( ` endSessionDialog: No XDG_SESSION_ID, fetched from logind: ${ sessionId } ` ) ;
} ) ;
if ( proxy . Id == sessionId )
2013-08-22 14:35:28 -04:00
continue ;
let session = { user : this . _userManager . get _user ( userName ) ,
username : userName ,
type : proxy . Type ,
remote : proxy . Remote } ;
this . _sessions . push ( session ) ;
2013-08-23 12:13:35 -04:00
let actor = this . _constructListItemForSession ( session ) ;
this . _sessionList . add ( actor ) ;
2013-08-22 14:35:28 -04:00
// limit the number of entries
n ++ ;
if ( n == MAX _USERS _IN _SESSION _DIALOG )
break ;
}
2013-08-22 14:48:28 -04:00
this . _sync ( ) ;
2017-10-30 20:38:18 -04:00
} ) ;
2017-10-30 21:19:44 -04:00
}
2013-08-22 14:35:28 -04:00
2017-10-30 20:03:21 -04:00
OpenAsync ( parameters , invocation ) {
2011-08-16 08:24:39 -04:00
let [ type , timestamp , totalSecondsToStayOpen , inhibitorObjectPaths ] = parameters ;
2011-01-06 10:30:15 -05:00
this . _totalSecondsToStayOpen = totalSecondsToStayOpen ;
this . _type = type ;
2019-07-08 02:51:36 -04:00
// Only consider updates and upgrades if PackageKit is available.
if ( this . _pkOfflineProxy && this . _type == DialogType . RESTART ) {
2016-03-15 13:46:40 -04:00
if ( this . _pkOfflineProxy . UpdateTriggered )
this . _type = DialogType . UPDATE _RESTART ;
else if ( this . _pkOfflineProxy . UpgradeTriggered )
this . _type = DialogType . UPGRADE _RESTART ;
}
2014-02-18 16:17:58 -05:00
2013-08-23 12:13:35 -04:00
this . _applications = [ ] ;
this . _applicationList . destroy _all _children ( ) ;
this . _sessions = [ ] ;
this . _sessionList . destroy _all _children ( ) ;
2011-08-16 08:24:39 -04:00
if ( ! ( this . _type in DialogContent ) ) {
2012-02-28 18:45:33 -05:00
invocation . return _dbus _error ( 'org.gnome.Shell.ModalDialog.TypeError' ,
2011-08-16 08:24:39 -04:00
"Unknown dialog type requested" ) ;
return ;
}
2011-01-06 10:30:15 -05:00
2014-02-19 13:58:50 -05:00
let dialogContent = DialogContent [ this . _type ] ;
2011-01-06 10:30:15 -05:00
for ( let i = 0 ; i < inhibitorObjectPaths . length ; i ++ ) {
2019-02-04 06:30:53 -05:00
let inhibitor = new GnomeSession . Inhibitor ( inhibitorObjectPaths [ i ] , proxy => {
2011-08-16 08:24:39 -04:00
this . _onInhibitorLoaded ( proxy ) ;
2017-10-30 20:38:18 -04:00
} ) ;
2011-01-06 10:30:15 -05:00
2013-08-23 12:13:35 -04:00
this . _applications . push ( inhibitor ) ;
2011-01-06 10:30:15 -05:00
}
2014-02-19 13:58:50 -05:00
if ( dialogContent . showOtherSessions )
2013-08-30 07:40:40 -04:00
this . _loadSessions ( ) ;
2013-08-22 14:35:28 -04:00
2019-07-08 02:51:36 -04:00
// Only consider updates and upgrades if PackageKit is available.
let updateTriggered = this . _pkOfflineProxy ? this . _pkOfflineProxy . UpdateTriggered : false ;
let updatePrepared = this . _pkOfflineProxy ? this . _pkOfflineProxy . UpdatePrepared : false ;
2014-02-19 13:58:50 -05:00
let updatesAllowed = this . _updatesPermission && this . _updatesPermission . allowed ;
2018-09-25 13:01:36 -04:00
_setCheckBoxLabel ( this . _checkBox , dialogContent . checkBoxText || '' ) ;
2014-09-09 07:16:25 -04:00
this . _checkBox . actor . visible = ( dialogContent . checkBoxText && updatePrepared && updatesAllowed ) ;
2016-03-14 18:55:03 -04:00
this . _checkBox . actor . checked = ( updatePrepared && updateTriggered ) ;
2014-02-19 13:58:50 -05:00
2014-02-19 13:59:47 -05:00
// We show the warning either together with the checkbox, or when
// updates have already been triggered, but the user doesn't have
// enough permissions to cancel them.
this . _batteryWarning . visible = ( dialogContent . showBatteryWarning &&
2016-03-14 18:55:03 -04:00
( this . _checkBox . actor . visible || updatePrepared && updateTriggered && ! updatesAllowed ) ) ;
2014-02-19 13:59:47 -05:00
2011-04-06 12:54:47 -04:00
this . _updateButtons ( ) ;
2011-08-16 08:24:39 -04:00
if ( ! this . open ( timestamp ) ) {
2012-02-28 18:45:33 -05:00
invocation . return _dbus _error ( 'org.gnome.Shell.ModalDialog.GrabError' ,
2011-08-16 08:24:39 -04:00
"Cannot grab pointer and keyboard" ) ;
return ;
}
2011-01-06 10:30:15 -05:00
2016-03-15 13:46:40 -04:00
if ( ! dialogContent . disableTimer )
this . _startTimer ( ) ;
2013-08-22 14:48:28 -04:00
this . _sync ( ) ;
2011-01-06 10:30:15 -05:00
2017-10-30 20:38:18 -04:00
let signalId = this . connect ( 'opened' , ( ) => {
invocation . return _value ( null ) ;
this . disconnect ( signalId ) ;
} ) ;
2017-10-30 21:19:44 -04:00
}
2012-12-04 18:32:59 -05:00
2019-01-31 09:08:10 -05:00
Close ( _parameters , _invocation ) {
2012-12-04 18:32:59 -05:00
this . close ( ) ;
2011-01-06 10:30:15 -05:00
}
2019-05-23 16:45:44 -04:00
} ) ;