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 ,
2020-07-24 20:08:16 -04:00
GLib , GObject , Pango , Polkit , Shell , St , UPowerGlib : UPower } = imports . gi ;
2011-01-06 10:30:15 -05:00
2014-02-19 13:58:50 -05:00
const CheckBox = imports . ui . checkBox ;
2019-10-18 17:18:10 -04:00
const Dialog = imports . ui . dialog ;
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 ;
2019-10-18 17:18:10 -04:00
const _ITEM _ICON _SIZE = 64 ;
2011-01-06 10:30:15 -05:00
2020-07-24 20:08:16 -04:00
const LOW _BATTERY _THRESHOLD = 30 ;
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 ) {
2020-07-01 10:44:16 -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 ) ;
2011-09-07 07:34:48 -04:00
} ,
2017-10-30 20:03:21 -04:00
description ( seconds ) {
2020-07-01 10:44:16 -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 ) ;
2011-09-07 07:34:48 -04:00
} ,
2014-02-19 13:59:47 -05:00
showBatteryWarning : false ,
2020-07-01 10:44:16 -04:00
confirmButtons : [ {
signal : 'ConfirmedLogout' ,
label : C _ ( 'button' , 'Log Out' ) ,
} ] ,
2013-08-30 07:40:40 -04:00
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 ) {
2020-07-01 10:44:16 -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 ) ;
2011-09-07 07:34:48 -04:00
} ,
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 ,
2020-07-01 10:44:16 -04:00
confirmButtons : [ {
signal : 'ConfirmedShutdown' ,
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
showOtherSessions : true ,
2011-01-06 10:30:15 -05:00
} ;
const restartDialogContent = {
2011-10-21 16:29:13 -04:00
subject : C _ ( "title" , "Restart" ) ,
2020-07-01 10:49:17 -04:00
subjectWithUpdates : C _ ( 'title' , 'Install Updates & Restart' ) ,
2017-10-30 20:03:21 -04:00
description ( seconds ) {
2020-07-01 10:44:16 -04:00
return ngettext (
'The system will restart automatically in %d second.' ,
'The system will restart automatically in %d seconds.' ,
seconds ) . format ( seconds ) ;
2011-09-07 07:34:48 -04:00
} ,
2020-07-01 10:49:17 -04:00
checkBoxText : C _ ( 'checkbox' , 'Install pending software updates' ) ,
showBatteryWarning : true ,
2020-07-01 10:44:16 -04:00
confirmButtons : [ {
signal : 'ConfirmedReboot' ,
label : C _ ( 'button' , 'Restart' ) ,
} ] ,
2012-11-01 12:18:32 -04:00
iconName : 'view-refresh-symbolic' ,
2013-08-30 07:40:40 -04:00
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 ) {
2020-07-01 10:44:16 -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 ) ;
2013-08-26 00:52:41 -04:00
} ,
2014-02-19 13:59:47 -05:00
showBatteryWarning : true ,
2020-07-01 10:44:16 -04:00
confirmButtons : [ {
signal : 'ConfirmedReboot' ,
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
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 ,
2020-07-01 10:44:16 -04:00
confirmButtons : [ {
signal : 'ConfirmedReboot' ,
label : C _ ( 'button' , 'Restart & Install' ) ,
} ] ,
2016-03-15 13:46:40 -04:00
iconName : 'view-refresh-symbolic' ,
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 ,
2019-08-20 17:43:54 -04:00
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 ,
2019-08-20 17:43:54 -04:00
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 ) ;
2020-07-24 20:08:16 -04:00
const UPowerIface = loadInterfaceXML ( 'org.freedesktop.UPower.Device' ) ;
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 ;
}
2014-02-19 13:58:50 -05:00
function _setCheckBoxLabel ( checkBox , text ) {
let label = checkBox . getLabelActor ( ) ;
if ( text ) {
label . set _text ( text ) ;
2019-07-16 05:24:13 -04:00
checkBox . show ( ) ;
2014-02-19 13:58:50 -05:00
} else {
label . set _text ( '' ) ;
2019-07-16 05:24:13 -04:00
checkBox . hide ( ) ;
2014-02-19 13:58:50 -05:00
}
}
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-08-19 15:38:51 -04: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 ( ) ;
2018-08-15 09:03:56 -04:00
this . _loginManager . canRebootToBootLoaderMenu (
( canRebootToBootLoaderMenu , unusedNeedsAuth ) => {
this . _canRebootToBootLoaderMenu = canRebootToBootLoaderMenu ;
} ) ;
2013-08-22 14:35:28 -04:00
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' ,
2020-07-24 20:08:16 -04:00
'/org/freedesktop/UPower/devices/DisplayDevice' ,
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 = [ ] ;
2018-08-15 09:03:56 -04:00
this . _capturedEventId = 0 ;
this . _rebootButton = null ;
this . _rebootButtonAlt = null ;
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
2019-12-05 07:06:35 -05:00
this . _userLoadedId = this . _user . connect ( 'notify::is-loaded' , this . _sync . bind ( this ) ) ;
2017-12-01 19:27:35 -05:00
this . _userChangedId = this . _user . connect ( 'changed' , this . _sync . bind ( this ) ) ;
2011-01-06 10:30:15 -05:00
2019-10-18 17:18:10 -04:00
this . _messageDialogContent = new Dialog . MessageDialogContent ( ) ;
2011-01-06 10:30:15 -05:00
2014-02-19 13:58:50 -05:00
this . _checkBox = new CheckBox . CheckBox ( ) ;
2019-07-16 05:24:13 -04:00
this . _checkBox . connect ( 'clicked' , this . _sync . bind ( this ) ) ;
2019-10-18 17:18:10 -04:00
this . _messageDialogContent . add _child ( this . _checkBox ) ;
2014-02-19 13:58:50 -05:00
2019-10-18 17:18:10 -04:00
this . _batteryWarning = new St . Label ( {
style _class : 'end-session-dialog-battery-warning' ,
2020-07-24 20:08:16 -04:00
text : _ ( 'Low battery power: please plug in before installing updates.' ) ,
2019-10-18 17:18:10 -04:00
} ) ;
2014-02-19 13:59:47 -05:00
this . _batteryWarning . clutter _text . ellipsize = Pango . EllipsizeMode . NONE ;
this . _batteryWarning . clutter _text . line _wrap = true ;
2019-10-18 17:18:10 -04:00
this . _messageDialogContent . add _child ( this . _batteryWarning ) ;
this . contentLayout . add _child ( this . _messageDialogContent ) ;
2014-02-19 13:59:47 -05:00
2020-01-17 08:07:57 -05:00
this . _applicationSection = new Dialog . ListSection ( {
title : _ ( 'Some applications are busy or have unsaved work' ) ,
} ) ;
this . contentLayout . add _child ( this . _applicationSection ) ;
this . _sessionSection = new Dialog . ListSection ( {
title : _ ( 'Other users are logged in' ) ,
2019-10-21 14:44:00 -04:00
} ) ;
2020-01-17 08:07:57 -05:00
this . contentLayout . add _child ( this . _sessionSection ) ;
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' ) ;
}
2019-12-19 14:50:37 -05:00
async _onPkOfflineProxyCreated ( proxy , error ) {
2019-07-08 02:51:36 -04:00
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-12-19 14:50:37 -05:00
try {
this . _updatesPermission = await Polkit . Permission . new (
'org.freedesktop.packagekit.trigger-offline-update' , null , null ) ;
} catch ( e ) {
log ( 'No permission to trigger offline updates: %s' . format ( e . toString ( ) ) ) ;
}
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
2020-07-24 20:08:16 -04:00
_isDischargingBattery ( ) {
return this . _powerProxy . IsPresent &&
this . _powerProxy . State !== UPower . DeviceState . CHARGING &&
this . _powerProxy . State !== UPower . DeviceState . FULLY _CHARGED ;
}
_isBatteryLow ( ) {
return this . _isDischargingBattery ( ) && this . _powerProxy . Percentage < LOW _BATTERY _THRESHOLD ;
}
_shouldShowLowBatteryWarning ( dialogContent ) {
if ( ! dialogContent . showBatteryWarning )
return false ;
if ( ! this . _isBatteryLow ( ) )
return false ;
if ( this . _checkBox . checked )
return true ;
// Show the warning if updates have already been triggered, but
// the user doesn't have enough permissions to cancel them.
let updatesAllowed = this . _updatesPermission && this . _updatesPermission . allowed ;
return this . _updateInfo . UpdatePrepared && this . _updateInfo . UpdateTriggered && ! updatesAllowed ;
}
2017-10-30 20:03:21 -04:00
_sync ( ) {
2019-08-19 15:38:51 -04:00
let open = this . state == ModalDialog . State . OPENING || this . state == ModalDialog . State . OPENED ;
2013-08-22 14:48:28 -04:00
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
2019-07-16 05:24:13 -04:00
if ( dialogContent . subjectWithUpdates && this . _checkBox . checked )
2014-02-19 13:58:50 -05:00
subject = dialogContent . subjectWithUpdates ;
2020-07-24 20:08:16 -04:00
this . _batteryWarning . visible = this . _shouldShowLowBatteryWarning ( dialogContent ) ;
2014-02-19 13:59:47 -05:00
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).
2020-03-17 21:56:33 -04:00
if ( dialogContent . upgradeDescription ) {
const { name , version } = this . _updateInfo . PreparedUpgrade ;
2016-03-15 13:46:40 -04:00
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 ) ;
2019-10-18 17:18:10 -04:00
this . _messageDialogContent . title = subject ;
this . _messageDialogContent . description = description ;
2013-08-23 12:13:35 -04:00
let hasApplications = this . _applications . length > 0 ;
let hasSessions = this . _sessions . length > 0 ;
2020-01-17 08:07:57 -05:00
this . _applicationSection . visible = hasApplications ;
this . _sessionSection . visible = hasSessions ;
2017-10-30 21:19:44 -04:00
}
2012-06-05 05:51:36 -04:00
2018-08-15 09:03:56 -04:00
_onCapturedEvent ( actor , event ) {
let altEnabled = false ;
let type = event . type ( ) ;
if ( type !== Clutter . EventType . KEY _PRESS && type !== Clutter . EventType . KEY _RELEASE )
return Clutter . EVENT _PROPAGATE ;
let key = event . get _key _symbol ( ) ;
if ( key !== Clutter . KEY _Alt _L && key !== Clutter . KEY _Alt _R )
return Clutter . EVENT _PROPAGATE ;
if ( type === Clutter . EventType . KEY _PRESS )
altEnabled = true ;
this . _rebootButton . visible = ! altEnabled ;
this . _rebootButtonAlt . visible = altEnabled ;
return Clutter . EVENT _PROPAGATE ;
}
2017-10-30 20:03:21 -04:00
_updateButtons ( ) {
2018-08-15 08:26:19 -04:00
this . clearButtons ( ) ;
this . addButton ( { action : this . cancel . bind ( this ) ,
2019-01-28 20:27:05 -05:00
label : _ ( "Cancel" ) ,
2018-08-15 08:26:19 -04:00
key : Clutter . KEY _Escape } ) ;
2011-03-21 16:12:30 -04:00
2018-08-15 08:26:19 -04:00
let dialogContent = DialogContent [ this . _type ] ;
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 ;
2018-08-15 08:26:19 -04:00
let button = this . addButton ( {
2019-02-12 09:02:09 -05:00
action : ( ) => {
this . close ( true ) ;
let signalId = this . connect ( 'closed' , ( ) => {
this . disconnect ( signalId ) ;
this . _confirm ( signal ) ;
} ) ;
} ,
2019-08-19 15:06:04 -04:00
label ,
2019-02-12 09:02:09 -05:00
} ) ;
2018-08-15 09:03:56 -04:00
// Add Alt "Boot Options" option to the Reboot button
if ( this . _canRebootToBootLoaderMenu && signal === 'ConfirmedReboot' ) {
this . _rebootButton = button ;
this . _rebootButtonAlt = this . addButton ( {
action : ( ) => {
this . close ( true ) ;
let signalId = this . connect ( 'closed' , ( ) => {
this . disconnect ( signalId ) ;
this . _confirmRebootToBootLoaderMenu ( ) ;
} ) ;
} ,
label : C _ ( 'button' , 'Boot Options' ) ,
} ) ;
this . _rebootButtonAlt . visible = false ;
this . _capturedEventId = global . stage . connect ( 'captured-event' ,
this . _onCapturedEvent . bind ( this ) ) ;
}
}
}
_stopAltCapture ( ) {
if ( this . _capturedEventId > 0 ) {
global . stage . disconnect ( this . _capturedEventId ) ;
this . _capturedEventId = 0 ;
2011-03-21 16:12:30 -04:00
}
2018-08-15 09:03:56 -04:00
this . _rebootButton = null ;
this . _rebootButtonAlt = null ;
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 ( ) ;
2018-08-15 09:03:56 -04:00
this . _stopAltCapture ( ) ;
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
2018-08-15 09:03:56 -04:00
_confirmRebootToBootLoaderMenu ( ) {
this . _loginManager . setRebootToBootLoaderMenu ( ) ;
this . _confirm ( 'ConfirmedReboot' ) ;
}
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 ( ) ;
2018-08-15 09:03:56 -04:00
this . _stopAltCapture ( ) ;
2014-02-19 13:58:50 -05:00
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
2019-07-16 05:24:13 -04:00
if ( ! this . _checkBox . visible ) {
2014-02-19 13:58:50 -05:00
callback ( ) ;
return ;
}
// Trigger the offline update as requested
2019-07-16 05:24:13 -04:00
if ( this . _checkBox . checked ) {
2014-02-19 13:58:50 -05:00
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 ( ) ;
2019-08-19 15:38:51 -04:00
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
_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 ) ;
2020-08-30 12:57:19 -04:00
const [ flags ] = app ? inhibitor . GetFlagsSync ( ) : [ 0 ] ;
2011-01-06 10:30:15 -05:00
2020-08-30 12:57:19 -04:00
if ( app && flags & GnomeSession . InhibitFlags . LOGOUT ) {
2020-01-17 08:07:57 -05:00
let [ description ] = inhibitor . GetReasonSync ( ) ;
let listItem = new Dialog . ListSectionItem ( {
icon _actor : app . create _icon _texture ( _ITEM _ICON _SIZE ) ,
title : app . get _name ( ) ,
description ,
} ) ;
this . _applicationSection . list . add _child ( listItem ) ;
2011-01-06 10:30:15 -05:00
} else {
2020-08-30 12:57:19 -04:00
// inhibiting app is a service (not an application) or is not
// inhibiting logout/shutdown
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
_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' ) ;
2019-08-19 20:51:42 -04:00
if ( ! sessionId ) {
2018-01-08 09:23:52 -05:00
this . _loginManager . getCurrentSessionProxy ( currentSessionProxy => {
sessionId = currentSessionProxy . Id ;
2020-02-14 10:10:34 -05:00
log ( 'endSessionDialog: No XDG_SESSION_ID, fetched from logind: %d' . format ( sessionId ) ) ;
2018-01-08 09:23:52 -05:00
} ) ;
2019-08-19 20:51:42 -04:00
}
2018-01-08 09:23:52 -05:00
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 ) ;
2020-01-17 08:07:57 -05:00
let userAvatar = new UserWidget . Avatar ( session . user , { iconSize : _ITEM _ICON _SIZE } ) ;
userAvatar . update ( ) ;
2020-08-12 14:59:01 -04:00
userName = session . user . get _real _name ( ) ? ? session . username ;
2020-01-17 08:07:57 -05:00
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 listItem = new Dialog . ListSectionItem ( {
icon _actor : userAvatar ,
title : userLabelText ,
} ) ;
this . _sessionSection . list . add _child ( listItem ) ;
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
2020-03-17 21:56:33 -04:00
async _getUpdateInfo ( ) {
const connection = this . _pkOfflineProxy . get _connection ( ) ;
const reply = await connection . call (
this . _pkOfflineProxy . g _name ,
this . _pkOfflineProxy . g _object _path ,
'org.freedesktop.DBus.Properties' ,
'GetAll' ,
new GLib . Variant ( '(s)' , [ this . _pkOfflineProxy . g _interface _name ] ) ,
null ,
Gio . DBusCallFlags . NONE ,
- 1 ,
null ) ;
const [ info ] = reply . recursiveUnpack ( ) ;
return info ;
}
async 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 ;
2020-03-17 21:56:33 -04:00
try {
this . _updateInfo = await this . _getUpdateInfo ( ) ;
} catch ( e ) {
if ( this . _pkOfflineProxy !== null )
log ( 'Failed to get update info from PackageKit: %s' . format ( e . message ) ) ;
this . _updateInfo = {
UpdateTriggered : false ,
UpdatePrepared : false ,
UpgradeTriggered : false ,
PreparedUpgrade : { } ,
} ;
}
2019-07-08 02:51:36 -04:00
// Only consider updates and upgrades if PackageKit is available.
if ( this . _pkOfflineProxy && this . _type == DialogType . RESTART ) {
2020-03-17 21:56:33 -04:00
if ( this . _updateInfo . UpdateTriggered )
2016-03-15 13:46:40 -04:00
this . _type = DialogType . UPDATE _RESTART ;
2020-03-17 21:56:33 -04:00
else if ( this . _updateInfo . UpgradeTriggered )
2016-03-15 13:46:40 -04:00
this . _type = DialogType . UPGRADE _RESTART ;
}
2014-02-18 16:17:58 -05:00
2013-08-23 12:13:35 -04:00
this . _applications = [ ] ;
2020-01-17 08:07:57 -05:00
this . _applicationSection . list . destroy _all _children ( ) ;
2013-08-23 12:13:35 -04:00
this . _sessions = [ ] ;
2020-01-17 08:07:57 -05:00
this . _sessionSection . list . destroy _all _children ( ) ;
2013-08-23 12:13:35 -04:00
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
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 || '' ) ;
2020-07-24 20:08:16 -04:00
this . _checkBox . visible = dialogContent . checkBoxText && this . _updateInfo . UpdatePrepared && updatesAllowed ;
if ( this . _type === DialogType . UPGRADE _RESTART )
this . _checkBox . checked = this . _checkBox . visible && this . _updateInfo . UpdateTriggered && ! this . _isDischargingBattery ( ) ;
else
this . _checkBox . checked = this . _checkBox . visible && ! this . _isBatteryLow ( ) ;
this . _batteryWarning . visible = this . _shouldShowLowBatteryWarning ( dialogContent ) ;
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
} ) ;