1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
|
# SPDX-FileCopyrightText: © 2008-2022 Oprea Dan
# SPDX-FileCopyrightText: © 2008-2022 Bart de Koning
# SPDX-FileCopyrightText: © 2008-2022 Richard Bailey
# SPDX-FileCopyrightText: © 2008-2022 Germar Reitze
#
# SPDX-License-Identifier: GPL-2.0-or-later
#
# This file is part of the program "Back In Time" which is released under GNU
# General Public License v2 (GPLv2). See LICENSES directory or go to
# <https://spdx.org/licenses/GPL-2.0-or-later.html>.
# Known open issues:
# this script should get started and consider some cmd line arguments from BiT
# (parsed via backintime.createParsers()) so that the same paths are used,
# mainly "share-path" and "config" (path to the config file).
# Otherwise e.g. unit tests or special user path settings may lead to
# wrong status info in the systray icon!
"""Plugin starting the systray icon process
Dev note (buhtz, 2025-07): Not sure why this need to be a plugin.
"""
import sys
import os
import gettext
import subprocess
import pluginmanager
import tools
import logger
_ = gettext.gettext
if not os.getenv('DISPLAY', ''):
os.putenv('DISPLAY', ':0.0')
class SysTrayIconPlugin(pluginmanager.Plugin):
"""A Back In Time plugin responsible to start the systray icon instance"""
def __init__(self):
self.process = None
self.snapshots = None
def init(self, snapshots):
self.snapshots = snapshots
# Old implementation disabled:
# Why can a systray icon only be shown on X11 (not wayland)?
# Qt can handle wayland now!
# if not tools.checkXServer():
# return False
# New implementation: Let Qt decide if a system tray icon can be shown.
# See https://doc.qt.io/qt-5/qsystemtrayicon.html#details:
# > To check whether a system tray is present on the user's desktop,
# > call the QSystemTrayIcon::isSystemTrayAvailable() static function.
#
# This requires a QApplication instance (otherwise Qt causes a
# segfault) which we don't have here so we create it to check if a
# window manager ("GUI") is active at all (e.g. in headless
# installations it isn't).
# See: https://forum.qt.io/topic/3852/issystemtrayavailable-
# always-crashes-segfault-on-ubuntu-10-10-desktop/6
try:
if tools.is_Qt_working(systray_required=True):
logger.debug('System tray is available to show the '
'BIT system tray icon')
return True
# pylint: disable-next=broad-exception-caught
except Exception as exc:
logger.debug(
f'Could not ask Qt if system tray is available: {repr(exc)}')
logger.debug(
'No system tray available to show the BIT system tray icon')
return False
def isGui(self): # noqa: N802
"""True"""
return True
def processBegin(self): # noqa: N802
"""Start the process."""
try:
logger.debug('Trying to start systray icon sub process...')
path = os.path.join(
tools.as_backintime_path('qt'), 'qtsystrayicon.py')
cmd = [
sys.executable,
path,
self.snapshots.config.currentProfile()
]
if logger.DEBUG:
# HACK to propagate DEBUG logging level to sub process
cmd.append('--debug')
# pylint: disable-next=consider-using-with
self.process = subprocess.Popen(cmd)
# pylint: disable-next=broad-exception-caught
except Exception as exc:
logger.critical(f'Undefined situation: {exc}', self)
else:
logger.info('Systray icon sub process started.')
# def processEnd(self):
# """Dev note(2025-07, buhtz): Method makes no sense to me anymore.
# Remove it soon.
# """
# if self.process is not None:
# try:
# # The "qtsystrayicon.py" app does terminate itself
# # once the snapshot has been taken so there is no need
# # to do anything here to stop it or clean-up anything.
# # self.process.terminate()
# return
# # ???
# except:
# pass
|