File: systrayiconplugin.py

package info (click to toggle)
backintime 1.6.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 10,424 kB
  • sloc: python: 27,312; sh: 886; makefile: 174; xml: 62
file content (127 lines) | stat: -rw-r--r-- 4,343 bytes parent folder | download
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