Skip to content

Commit

Permalink
Merge branch 'dev' into Give-option-to-display-text-in-toolbar-items
Browse files Browse the repository at this point in the history
  • Loading branch information
vozellad committed Apr 27, 2024
2 parents 765dd6f + 4a96d13 commit 796b749
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 14 deletions.
54 changes: 54 additions & 0 deletions common/backintime.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,16 @@ def createParsers(app_name = 'backintime'):
snapshotsPathCP.set_defaults(func = snapshotsPath)
parsers[command] = snapshotsPathCP

command = 'suspend'
nargs = 0
description = 'Suspend the computer after the snapshot is done.'
suspendCP = subparsers.add_parser(command,
epilog=epilogCommon,
help=description,
description=description)
suspendCP.set_defaults(func=suspend)
parsers[command] = suspendCP

command = 'unmount'
nargs = 0
aliases.append((command, nargs))
Expand Down Expand Up @@ -837,6 +847,50 @@ def shutdown(args):
sd.shutdown()
sys.exit(RETURN_OK)

def suspend(args):
"""
Command for suspending the computer after the current snapshot has
finished.
Args:
args (argparse.Namespace):
previously parsed arguments
Raises:
SystemExit: 0 if successful; 1 if it failed either because there is
no active snapshot for this profile or suspend is not
supported.
"""
setQuiet(args)
printHeader()
cfg = getConfig(args)

sd = tools.ShutDown()
if not sd.canShutdown():
logger.warning('Suspend is not supported.')
sys.exit(RETURN_ERR)

instance = ApplicationInstance(cfg.takeSnapshotInstanceFile(), False)
profile = '='.join((cfg.currentProfile(), cfg.profileName()))
if not instance.busy():
logger.info('There is no active snapshot for profile %s. Skip suspend.'
% profile)
sys.exit(RETURN_ERR)

print('Suspend is waiting for the snapshot in profile %s to end.\nPress CTRL+C to interrupt suspend.\n'
% profile)
sd.activate_suspend = True
try:
while instance.busy():
logger.debug('Snapshot is still active. Wait for suspend.')
sleep(5)
except KeyboardInterrupt:
print('Suspend interrupted.')
else:
logger.info('Suspend now.')
sd.suspend()
sys.exit(RETURN_OK)

def snapshotsPath(args):
"""
Command for printing the full snapshot path of current profile.
Expand Down
56 changes: 45 additions & 11 deletions common/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -2078,7 +2078,7 @@ class ShutDown(object):
DBUS_SHUTDOWN ={'gnome': {'bus': 'sessionbus',
'service': 'org.gnome.SessionManager',
'objectPath': '/org/gnome/SessionManager',
'method': 'Shutdown',
'method': ['Shutdown'],
#methods Shutdown
# Reboot
# Logout
Expand All @@ -2092,7 +2092,7 @@ class ShutDown(object):
'kde': {'bus': 'sessionbus',
'service': 'org.kde.ksmserver',
'objectPath': '/KSMServer',
'method': 'logout',
'method': ['logout'],
'interface': 'org.kde.KSMServerInterface',
'arguments': (-1, 2, -1)
#1st arg -1 confirm
Expand All @@ -2107,8 +2107,8 @@ class ShutDown(object):
'xfce': {'bus': 'sessionbus',
'service': 'org.xfce.SessionManager',
'objectPath': '/org/xfce/SessionManager',
'method': 'Shutdown',
#methods Shutdown
'method': ['Shutdown',
'Suspend'],
# Restart
# Suspend (no args)
# Hibernate (no args)
Expand All @@ -2127,7 +2127,7 @@ class ShutDown(object):
'mate': {'bus': 'sessionbus',
'service': 'org.mate.SessionManager',
'objectPath': '/org/mate/SessionManager',
'method': 'Shutdown',
'method': ['Shutdown'],
#methods Shutdown
# Logout
'interface': 'org.mate.SessionManager',
Expand All @@ -2140,7 +2140,8 @@ class ShutDown(object):
'e17': {'bus': 'sessionbus',
'service': 'org.enlightenment.Remote.service',
'objectPath': '/org/enlightenment/Remote/RemoteObject',
'method': 'Halt',
'method': ['Halt',
'Suspend'],
#methods Halt -> Shutdown
# Reboot
# Logout
Expand All @@ -2152,7 +2153,7 @@ class ShutDown(object):
'e19': {'bus': 'sessionbus',
'service': 'org.enlightenment.wm.service',
'objectPath': '/org/enlightenment/wm/RemoteObject',
'method': 'Shutdown',
'method': ['Shutdown'],
#methods Shutdown
# Restart
'interface': 'org.enlightenment.wm.Core',
Expand All @@ -2161,22 +2162,26 @@ class ShutDown(object):
'z_freed': {'bus': 'systembus',
'service': 'org.freedesktop.login1',
'objectPath': '/org/freedesktop/login1',
'method': 'PowerOff',
'method': ['PowerOff'],
'interface': 'org.freedesktop.login1.Manager',
'arguments': (True,)
}
}

def __init__(self):
self.can_suspend = False
self.is_root = isRoot()
if self.is_root:
self.proxy, self.args = None, None
else:
self.proxy, self.args = self._prepair()
self.proxy, self.args = self._prepair(0)
self.shutdown_params = None
self.suspend_params = None
self.activate_shutdown = False
self.activate_suspend = False
self.started = False

def _prepair(self):
def _prepair(self,method_num):
"""
Try to connect to the given dbus services. If successful it will
return a callable dbus proxy and those arguments.
Expand All @@ -2201,7 +2206,8 @@ def _prepair(self):
else:
bus = systembus
interface = bus.get_object(dbus_props['service'], dbus_props['objectPath'])
proxy = interface.get_dbus_method(dbus_props['method'], dbus_props['interface'])
self.can_suspend = len(dbus_props['method']) > 1
proxy = interface.get_dbus_method(dbus_props['method'][method_num], dbus_props['interface'])
return((proxy, dbus_props['arguments']))
except dbus.exceptions.DBusException:
continue
Expand All @@ -2213,6 +2219,12 @@ def canShutdown(self):
"""
return(not self.proxy is None or self.is_root)

def canSuspend(self):
"""
Indicate if user's desktop environment support suspend.
"""
return self.canShutdown() and self.can_suspend

def askBeforeQuit(self):
"""
Indicate if ShutDown is ready to fire and so the application
Expand All @@ -2236,6 +2248,28 @@ def shutdown(self):
if self.proxy is None:
return(False)
else:
self.proxy, self.args = self._prepair(0)
syncfs()
self.started = True
return(self.proxy(*self.args))

def suspend(self):
"""
Run 'systemctl suspend' if we are root or
call the dbus proxy to trigger suspend.
"""
if not self.activate_suspend or not self.can_suspend:
return(False)
if self.is_root:
syncfs()
self.started = True
proc = subprocess.Popen(['systemctl', 'suspend'])
proc.communicate()
return proc.returncode
if self.proxy is None:
return(False)
else:
self.proxy,self.args = self._prepair(1)
syncfs()
self.started = True
return(self.proxy(*self.args))
Expand Down
44 changes: 41 additions & 3 deletions qt/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,16 @@ def __init__(self, config, appInstance, qapp):
self.statusBar().addWidget(layoutWidget, 100)
self.status.setText(_('Done'))

self.free_diskspace = QLabel(self)

# Add the "Blah" label
self.statusBar().addWidget(self.free_diskspace)
self.snap = snapshots.Snapshots()
self.snapshot_path = config.snapshotsFullPath()
self.free_space = self.snap.statFreeSpaceLocal(self.snapshot_path)
self.free_diskspace.setText(f'Free Disk Space (mb): {self.free_space}')


self.snapshotsList = []
self.sid = snapshots.RootSnapshot(self.config)
self.path = self.config.profileStrValue(
Expand Down Expand Up @@ -525,6 +535,11 @@ def _create_actions(self):
icon.SHUTDOWN, _('Shutdown'),
None, None,
_('Shut down system after snapshot has finished.')),
'act_suspend': (
icon.SUSPEND, _('Suspend'),
None, None,
_('Suspend system after snapshot has finished.')
),
'act_setup_language': (
None, _('Setup language…'),
self.slot_setup_language, None,
Expand Down Expand Up @@ -598,6 +613,9 @@ def _create_actions(self):
}

for attr in action_dict:
if attr == 'act_suspend' and not self.shutdown.canSuspend():
continue # Don't let user suspend if their desktop environment can't

ico, txt, slot, keys, tip = action_dict[attr]

# Create action (with icon)
Expand Down Expand Up @@ -631,6 +649,10 @@ def _create_actions(self):
self.act_shutdown.toggled.connect(self.btnShutdownToggled)
self.act_shutdown.setCheckable(True)
self.act_shutdown.setEnabled(self.shutdown.canShutdown())
if self.shutdown.canSuspend():
self.act_suspend.toggled.connect(self.btnSuspendToggled)
self.act_suspend.setCheckable(True)
self.act_suspend.setEnabled(self.shutdown.canShutdown())
self.act_pause_take_snapshot.setVisible(False)
self.act_resume_take_snapshot.setVisible(False)
self.act_stop_take_snapshot.setVisible(False)
Expand Down Expand Up @@ -660,6 +682,7 @@ def _create_menubar(self):
'Back In &Time': (
self.act_setup_language,
self.act_shutdown,
self.act_suspend if hasattr(self, 'act_suspend') else None,
self.act_quit,
),
_('&Backup'): (
Expand Down Expand Up @@ -694,6 +717,8 @@ def _create_menubar(self):
self.act_help_about,
)
}
# Filter out 'None' from 'Back In &Time'
menu_dict['Back In &Time'] = tuple(a for a in menu_dict['Back In &Time'] if a is not None)

for key, actions in menu_dict.items():
menu = self.menuBar().addMenu(key)
Expand Down Expand Up @@ -743,6 +768,8 @@ def _create_main_toolbar(self):
self.act_settings,
self.act_shutdown,
]
if self.shutdown.canSuspend():
actions_for_toolbar.append(self.act_suspend)

# Add each action to toolbar
for act in self.actions_for_toolbar:
Expand Down Expand Up @@ -776,9 +803,11 @@ def _create_main_toolbar(self):
QToolButton.ToolButtonPopupMode.MenuButtonPopup)

# separators and stretchers
self.toolbar.insertSeparator(self.act_settings)
self.toolbar.insertSeparator(self.act_shutdown)

toolbar.insertSeparator(self.act_settings)
toolbar.insertSeparator(self.act_shutdown)
if self.shutdown.canSuspend():
toolbar.insertSeparator(self.act_suspend)

self.set_toolbar_icon_text()

def _create_and_get_filesview_toolbar(self):
Expand Down Expand Up @@ -1028,6 +1057,7 @@ def updateTakeSnapshot(self, force_wait_lock=False):
takeSnapshotMessage = (0, _('Done, no backup needed'))

self.shutdown.shutdown()
self.shutdown.suspend()

if takeSnapshotMessage != self.lastTakeSnapshotMessage or force_update:
self.lastTakeSnapshotMessage = takeSnapshotMessage
Expand Down Expand Up @@ -1060,6 +1090,8 @@ def updateTakeSnapshot(self, force_wait_lock=False):
else:
self.progressBar.setVisible(False)
self.progressBarDummy.setVisible(True)
self.free_space = self.snap.statFreeSpaceLocal(self.config.snapshotsFullPath())
self.free_diskspace.setText(f'Free Disk Space (mb): {self.free_space}')

#if not fake_busy:
# self.lastTakeSnapshotMessage = None
Expand Down Expand Up @@ -1323,6 +1355,12 @@ def btnSettingsClicked(self):

def btnShutdownToggled(self, checked):
self.shutdown.activate_shutdown = checked
if self.shutdown.canSuspend():
self.act_suspend.setEnabled(not checked)

def btnSuspendToggled(self, checked):
self.shutdown.activate_suspend = checked
self.act_shutdown.setEnabled(not checked)

def contextMenuClicked(self, point):
self.contextMenu.exec(self.filesView.mapToGlobal(point))
Expand Down
1 change: 1 addition & 0 deletions qt/icon.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
SETTINGS = QIcon.fromTheme('gtk-preferences',
QIcon.fromTheme('configure'))
SHUTDOWN = QIcon.fromTheme('system-shutdown')
SUSPEND = QIcon.fromTheme('system-suspend')
EXIT = QIcon.fromTheme('gtk-close',
QIcon.fromTheme('application-exit'))

Expand Down

0 comments on commit 796b749

Please sign in to comment.