Philipp Hörist pushed to branch master at gajim / gajim

Commits:

5 changed files:

Changes:

  • gajim/gtk/application.py
    ... ... @@ -231,6 +231,10 @@ def _startup(self, _application: GajimApplication) -> None:
    231 231
     
    
    232 232
             self.interface = Interface()
    
    233 233
             self.interface.run(self)
    
    234
    +
    
    235
    +        from gajim.gui.status_icon import StatusIcon
    
    236
    +        self.systray = StatusIcon()
    
    237
    +
    
    234 238
             self.add_actions()
    
    235 239
             self._load_shortcuts()
    
    236 240
             menus.build_accounts_menu()
    

  • gajim/gtk/main.py
    ... ... @@ -30,7 +30,6 @@
    30 30
     
    
    31 31
     from gajim.common import app
    
    32 32
     from gajim.common import ged
    
    33
    -from gajim.common.const import Display
    
    34 33
     from gajim.common.const import Direction
    
    35 34
     from gajim.common.events import ApplicationEvent
    
    36 35
     from gajim.common.events import AllowGajimUpdateCheck
    
    ... ... @@ -141,9 +140,9 @@ def __init__(self) -> None:
    141 140
             self._prepare_window()
    
    142 141
             self._start_timers()
    
    143 142
     
    
    144
    -        if not app.is_display(Display.WAYLAND):
    
    145
    -            app.interface.systray.connect_unread_changed(
    
    146
    -                self._chat_page.get_chat_list_stack())
    
    143
    +        chat_list_stack = self._chat_page.get_chat_list_stack()
    
    144
    +        app.app.systray.connect_unread_widget(chat_list_stack,
    
    145
    +                                              'unread-count-changed')
    
    147 146
     
    
    148 147
         def _start_timers(self) -> None:
    
    149 148
             GLib.timeout_add_seconds(UNLOAD_CHAT_TIME,
    
    ... ... @@ -325,8 +324,7 @@ def _on_window_delete(self,
    325 324
                 self.quit()
    
    326 325
             else:
    
    327 326
                 if (app.settings.get('allow_hide_roster') or
    
    328
    -                    (app.interface.systray_enabled and
    
    329
    -                     app.settings.get('trayicon') != 'on_event')):
    
    327
    +                    app.app.systray.is_visible()):
    
    330 328
                     save_main_window_position()
    
    331 329
                     if (os.name == 'nt' or
    
    332 330
                             app.settings.get('hide_on_main_window_x_button')):
    

  • gajim/gtk/preferences.py
    ... ... @@ -440,8 +440,7 @@ def __init__(self, *args: Any) -> None:
    440 440
                         _('Notification Area Icon'),
    
    441 441
                         SettingType.CONFIG,
    
    442 442
                         'trayicon',
    
    443
    -                    props={'entries': trayicon_items},
    
    444
    -                    callback=self._on_trayicon),
    
    443
    +                    props={'entries': trayicon_items}),
    
    445 444
     
    
    446 445
                 Setting(SettingKind.NOTIFICATIONS,
    
    447 446
                         _('Show Notifications'),
    
    ... ... @@ -451,15 +450,6 @@ def __init__(self, *args: Any) -> None:
    451 450
     
    
    452 451
             PreferenceBox.__init__(self, settings)
    
    453 452
     
    
    454
    -    @staticmethod
    
    455
    -    def _on_trayicon(value: str, *args: Any) -> None:
    
    456
    -        if value == 'never':
    
    457
    -            app.interface.hide_systray()
    
    458
    -        elif value == 'on_event':
    
    459
    -            app.interface.show_systray()
    
    460
    -        else:
    
    461
    -            app.interface.show_systray()
    
    462
    -
    
    463 453
     
    
    464 454
     class NotificationsDialog(SettingsDialog):
    
    465 455
         def __init__(self, account: str, parent: Preferences) -> None:
    

  • gajim/gtk/status_icon.py
    ... ... @@ -19,11 +19,11 @@
    19 19
     # You should have received a copy of the GNU General Public License
    
    20 20
     # along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    21 21
     
    
    22
    -import typing
    
    23 22
     from typing import Any
    
    24 23
     from typing import Union
    
    25 24
     
    
    26 25
     import sys
    
    26
    +import logging
    
    27 27
     
    
    28 28
     from gi.repository import Gtk
    
    29 29
     from gi.repository import GLib
    
    ... ... @@ -31,6 +31,7 @@
    31 31
     from gajim.common import app
    
    32 32
     from gajim.common import configpaths
    
    33 33
     from gajim.common import ged
    
    34
    +from gajim.common.const import Display
    
    34 35
     from gajim.common.i18n import _
    
    35 36
     from gajim.common.events import AccountConnected
    
    36 37
     from gajim.common.events import AccountDisonnected
    
    ... ... @@ -51,52 +52,63 @@
    51 52
     elif app.is_installed('AYATANA_APPINDICATOR'):
    
    52 53
         from gi.repository import AyatanaAppIndicator3 as appindicator  # pylint: disable=ungrouped-imports
    
    53 54
     
    
    54
    -if typing.TYPE_CHECKING:
    
    55
    -    from gi.repository import AyatanaAppIndicator3 as appindicator
    
    55
    +
    
    56
    +log = logging.getLogger('gajim.gui.statusicon')
    
    56 57
     
    
    57 58
     
    
    58 59
     class StatusIcon:
    
    59
    -    def __init__(self):
    
    60
    -        self._backend = None
    
    61
    -
    
    62
    -    def connect_unread_changed(self, chat_list_stack: Gtk.Stack) -> None:
    
    63
    -        # We trigger the signal connection from the main window because it
    
    64
    -        # is not yet available when initializing StatusIcon
    
    65
    -        chat_list_stack.connect(
    
    66
    -            'unread-count-changed', self._on_unread_count_changed)
    
    67
    -
    
    68
    -    def _on_unread_count_changed(self,
    
    69
    -                                 _chat_list_stack: Gtk.Stack,
    
    70
    -                                 _workspace_id: str,
    
    71
    -                                 _count: int) -> None:
    
    72
    -        if app.settings.get('trayicon_notification_on_events'):
    
    73
    -            count = app.window.get_total_unread_count()
    
    74
    -            self._backend._update_icon(count=count)  # type: ignore
    
    75
    -
    
    76
    -    def show_icon(self) -> None:
    
    77
    -        if self._backend is not None:
    
    78
    -            self._backend.show_icon()
    
    60
    +    def __init__(self) -> None:
    
    61
    +        if app.is_display(Display.WAYLAND):
    
    62
    +            self._backend = NoneBackend()
    
    63
    +            log.info('Not supported on Wayland')
    
    79 64
                 return
    
    80 65
     
    
    81
    -        indicator_installed = (app.is_installed('APPINDICATOR') or
    
    82
    -                               app.is_installed('AYATANA_APPINDICATOR'))
    
    83
    -        use_indicator = app.settings.get('use_libappindicator')
    
    84
    -        if indicator_installed and use_indicator:
    
    66
    +        app.settings.connect_signal('trayicon', self._on_setting_changed)
    
    67
    +
    
    68
    +        if self._can_use_libindicator():
    
    85 69
                 self._backend = AppIndicator()
    
    70
    +            log.info('Use AppIndicator3 backend')
    
    71
    +
    
    86 72
             else:
    
    87 73
                 self._backend = GtkStatusIcon()
    
    74
    +            log.info('Use GtkStatusIcon backend')
    
    75
    +
    
    76
    +    @staticmethod
    
    77
    +    def _can_use_libindicator() -> bool:
    
    78
    +        if not app.settings.get('use_libappindicator'):
    
    79
    +            return False
    
    80
    +        return (app.is_installed('APPINDICATOR') or
    
    81
    +                app.is_installed('AYATANA_APPINDICATOR'))
    
    88 82
     
    
    89
    -    def hide_icon(self) -> None:
    
    90
    -        if self._backend is None:
    
    83
    +    def _on_setting_changed(self, *args: Any) -> None:
    
    84
    +        count = app.window.get_total_unread_count()
    
    85
    +        self._backend.update_state(count=count)
    
    86
    +
    
    87
    +    def connect_unread_widget(self, widget: Gtk.Widget, signal: str) -> None:
    
    88
    +        widget.connect(signal, self._on_unread_count_changed)
    
    89
    +
    
    90
    +    def _on_unread_count_changed(self, *args: Any) -> None:
    
    91
    +        if not app.settings.get('trayicon_notification_on_events'):
    
    91 92
                 return
    
    92
    -        self._backend.hide_icon()
    
    93
    +        count = app.window.get_total_unread_count()
    
    94
    +        self._backend.update_state(count=count)
    
    95
    +
    
    96
    +    def is_visible(self) -> bool:
    
    97
    +        return self._backend.is_visible()
    
    98
    +
    
    99
    +
    
    100
    +class NoneBackend:
    
    101
    +    def update_state(self, count: int = 0) -> None:
    
    102
    +        pass
    
    103
    +
    
    104
    +    def is_visible(self) -> bool:
    
    105
    +        return False
    
    93 106
     
    
    94 107
     
    
    95 108
     class GtkMenuBackend(EventHelper):
    
    96
    -    def __init__(self):
    
    109
    +    def __init__(self) -> None:
    
    97 110
             EventHelper.__init__(self)
    
    98 111
             self._popup_menus: list[Gtk.Menu] = []
    
    99
    -        self._enabled = True
    
    100 112
     
    
    101 113
             self._ui = get_builder('systray_context_menu.ui')
    
    102 114
             self._ui.sounds_mute_menuitem.set_active(
    
    ... ... @@ -111,13 +123,10 @@ def __init__(self):
    111 123
                 ('account-disconnected', ged.CORE, self._on_account_state),
    
    112 124
             ])
    
    113 125
     
    
    114
    -    def show_icon(self) -> None:
    
    115
    -        raise NotImplementedError
    
    116
    -
    
    117
    -    def hide_icon(self) -> None:
    
    126
    +    def update_state(self, count: int = 0) -> None:
    
    118 127
             raise NotImplementedError
    
    119 128
     
    
    120
    -    def _update_icon(self, count: int = 0) -> None:
    
    129
    +    def is_visible(self) -> bool:
    
    121 130
             raise NotImplementedError
    
    122 131
     
    
    123 132
         def _add_status_menu(self) -> None:
    
    ... ... @@ -141,7 +150,7 @@ def _add_status_menu(self) -> None:
    141 150
             self._ui.status_menu.set_submenu(sub_menu)
    
    142 151
     
    
    143 152
         def _on_our_show(self, _event: ShowChanged) -> None:
    
    144
    -        self._update_icon()
    
    153
    +        self.update_state()
    
    145 154
     
    
    146 155
         def _on_account_state(self,
    
    147 156
                               _event: Union[AccountConnected, AccountDisonnected]
    
    ... ... @@ -190,8 +199,7 @@ def _on_show(_widget: Gtk.MenuItem, show: str) -> None:
    190 199
     
    
    191 200
     
    
    192 201
     class GtkStatusIcon(GtkMenuBackend):
    
    193
    -
    
    194
    -    def __init__(self):
    
    202
    +    def __init__(self) -> None:
    
    195 203
             GtkMenuBackend.__init__(self)
    
    196 204
             self._hide_menuitem_added = False
    
    197 205
     
    
    ... ... @@ -200,40 +208,30 @@ def __init__(self):
    200 208
             self._status_icon.connect('popup-menu', self._on_popup_menu)
    
    201 209
             self._status_icon.connect('size-changed', self._on_size_changed)
    
    202 210
     
    
    203
    -        self._update_icon()
    
    204
    -
    
    205
    -    def show_icon(self):
    
    206
    -        self._enabled = True
    
    207
    -        self._status_icon.set_visible(True)
    
    208
    -        self._update_icon()
    
    209
    -
    
    210
    -    def hide_icon(self) -> None:
    
    211
    -        self._enabled = False
    
    212
    -        self._status_icon.set_visible(False)
    
    211
    +        self.update_state()
    
    213 212
     
    
    214
    -    def _update_icon(self, count: int = 0):
    
    215
    -        if not self._enabled:
    
    213
    +    def update_state(self, count: int = 0) -> None:
    
    214
    +        if app.settings.get('trayicon') == 'never':
    
    215
    +            self._status_icon.set_visible(False)
    
    216 216
                 return
    
    217 217
     
    
    218
    -        if app.settings.get('trayicon') == 'always':
    
    219
    -            self._status_icon.set_visible(True)
    
    218
    +        self._status_icon.set_visible(True)
    
    220 219
     
    
    221 220
             if count > 0:
    
    222
    -            self._status_icon.set_visible(True)
    
    223 221
                 self._status_icon.set_from_icon_name('dcraven-message-new')
    
    224 222
                 return
    
    225 223
     
    
    226
    -        if app.settings.get('trayicon') == 'on_event':
    
    227
    -            self._status_icon.set_visible(False)
    
    228
    -
    
    229 224
             show = get_global_show()
    
    230 225
             icon_name = get_icon_name(show)
    
    231 226
             self._status_icon.set_from_icon_name(icon_name)
    
    232 227
     
    
    228
    +    def is_visible(self) -> bool:
    
    229
    +        return self._status_icon.get_visible()
    
    230
    +
    
    233 231
         def _on_size_changed(self,
    
    234 232
                              _status_icon: Gtk.StatusIcon,
    
    235 233
                              size: int) -> None:
    
    236
    -        self._update_icon()
    
    234
    +        self.update_state()
    
    237 235
     
    
    238 236
         def _on_popup_menu(self,
    
    239 237
                            _status_icon: Gtk.StatusIcon,
    
    ... ... @@ -271,8 +269,7 @@ def _build_menu(self, event_time: int) -> None:
    271 269
     
    
    272 270
     
    
    273 271
     class AppIndicator(GtkMenuBackend):
    
    274
    -
    
    275
    -    def __init__(self):
    
    272
    +    def __init__(self) -> None:
    
    276 273
             GtkMenuBackend.__init__(self)
    
    277 274
     
    
    278 275
             self._status_icon = appindicator.Indicator.new(
    
    ... ... @@ -287,32 +284,24 @@ def __init__(self):
    287 284
             self._status_icon.set_secondary_activate_target(
    
    288 285
                 self._ui.toggle_window_menuitem)
    
    289 286
     
    
    290
    -        self._update_icon()
    
    291
    -
    
    292
    -    def show_icon(self):
    
    293
    -        self._enabled = True
    
    294
    -        self._status_icon.set_status(appindicator.IndicatorStatus.ACTIVE)
    
    295
    -        self._update_icon()
    
    296
    -
    
    297
    -    def hide_icon(self) -> None:
    
    298
    -        self._enabled = False
    
    299
    -        self._status_icon.set_status(appindicator.IndicatorStatus.PASSIVE)
    
    287
    +        self.update_state()
    
    300 288
     
    
    301
    -    def _update_icon(self, count: int = 0) -> None:
    
    302
    -        if not self._enabled:
    
    289
    +    def update_state(self, count: int = 0) -> None:
    
    290
    +        if app.settings.get('trayicon') == 'never':
    
    291
    +            self._status_icon.set_status(appindicator.IndicatorStatus.PASSIVE)
    
    303 292
                 return
    
    304 293
     
    
    305
    -        if app.settings.get('trayicon') == 'always':
    
    306
    -            self._status_icon.set_status(appindicator.IndicatorStatus.ACTIVE)
    
    294
    +        self._status_icon.set_status(appindicator.IndicatorStatus.ACTIVE)
    
    307 295
     
    
    308 296
             if count > 0:
    
    309 297
                 icon_name = 'dcraven-message-new'
    
    310 298
                 self._status_icon.set_icon_full(icon_name, _('Pending Event'))
    
    311
    -
    
    312
    -        if app.settings.get('trayicon') == 'on_event':
    
    313
    -            self._status_icon.set_status(appindicator.IndicatorStatus.PASSIVE)
    
    299
    +            return
    
    314 300
     
    
    315 301
             show = get_global_show()
    
    316 302
             icon_name = get_icon_name(show)
    
    317 303
             self._status_icon.set_icon_full(icon_name, show)
    
    318
    -        self._status_icon.set_status(appindicator.IndicatorStatus.ACTIVE)
    304
    +
    
    305
    +    def is_visible(self) -> bool:
    
    306
    +        status = self._status_icon.get_status()
    
    307
    +        return status == appindicator.IndicatorStatus.ACTIVE

  • gajim/gui_interface.py
    ... ... @@ -77,7 +77,7 @@
    77 77
     from gajim.common.i18n import _
    
    78 78
     from gajim.common.client import Client
    
    79 79
     from gajim.common.preview import PreviewManager
    
    80
    -from gajim.common.const import Display, FTState
    
    80
    +from gajim.common.const import FTState
    
    81 81
     from gajim.common.file_props import FileProp
    
    82 82
     
    
    83 83
     from gajim.common.modules.contacts import GroupchatContact
    
    ... ... @@ -163,12 +163,6 @@ def __init__(self):
    163 163
                 logind.enable()
    
    164 164
                 music_track.enable()
    
    165 165
     
    
    166
    -        self.systray_enabled: bool = False
    
    167
    -
    
    168
    -        if not app.is_display(Display.WAYLAND):
    
    169
    -            from gajim.gui.status_icon import StatusIcon
    
    170
    -            self.systray = StatusIcon()
    
    171
    -
    
    172 166
         def _create_core_handlers_list(self) -> None:
    
    173 167
             # pylint: disable=line-too-long
    
    174 168
             self.handlers = {
    
    ... ... @@ -857,16 +851,6 @@ def _change_status(account: str, status: str) -> None:
    857 851
     
    
    858 852
             client.change_status(status, message)
    
    859 853
     
    
    860
    -    def show_systray(self) -> None:
    
    861
    -        if not app.is_display(Display.WAYLAND):
    
    862
    -            self.systray_enabled = True
    
    863
    -            self.systray.show_icon()
    
    864
    -
    
    865
    -    def hide_systray(self) -> None:
    
    866
    -        if not app.is_display(Display.WAYLAND):
    
    867
    -            self.systray_enabled = False
    
    868
    -            self.systray.hide_icon()
    
    869
    -
    
    870 854
         def process_connections(self) -> bool:
    
    871 855
             """
    
    872 856
             Called each foo (200) milliseconds. Check for idlequeue timeouts
    
    ... ... @@ -989,9 +973,6 @@ def create_zeroconf_default_config(self) -> None:
    989 973
                                              False)
    
    990 974
     
    
    991 975
         def run(self, _application: Gtk.Application) -> None:
    
    992
    -        if app.settings.get('trayicon') != 'never':
    
    993
    -            self.show_systray()
    
    994
    -
    
    995 976
             # Creating plugin manager
    
    996 977
             from gajim import plugins
    
    997 978
             app.plugin_manager = plugins.PluginManager()