1from functools import wraps
2import logging
3
4import gi
5gi.require_version('Gtk', '3.0')
6
7# AppIndicator support is optional. It'll work if you install
8# gir1.2-ayatanaappindicator3-0.1 or an equivalent package for your distro
9# pylint: disable=wrong-import-position
10appIndicatorSupported = False
11try:
12    gi.require_version('AppIndicator3', '0.1')
13    appIndicatorSupported = True
14except ValueError:
15    pass
16
17try:
18    gi.require_version('AyatanaAppIndicator3', '0.1')
19    appIndicatorSupported = True
20except ValueError:
21    pass
22
23try:
24    from gi.repository import AppIndicator3
25except ImportError:
26    pass
27
28try:
29    from gi.repository import AyatanaAppIndicator3 as AppIndicator3  # noqa: F811
30except ImportError:
31    pass
32
33from gi.repository import Gtk
34from ulauncher.utils.decorator.singleton import singleton
35
36logger = logging.getLogger(__name__)
37
38
39def onlyIfAppindicatorIsSupported(func):
40    @wraps(func)
41    def wrapped(*args, **kwargs):
42        if appIndicatorSupported:
43            return func(*args, **kwargs)
44        return None
45    return wrapped
46
47
48class AppIndicator:
49
50    @classmethod
51    @singleton
52    def get_instance(cls):
53        from ulauncher.ui.windows.UlauncherWindow import UlauncherWindow
54        window = UlauncherWindow.get_instance()
55        indicator = cls("ulauncher")
56        indicator.set_icon('ulauncher-indicator')
57        indicator.add_menu_item(window.on_mnu_preferences_activate, "Preferences")
58        indicator.add_menu_item(window.on_mnu_about_activate, "About")
59        indicator.add_seperator()
60        indicator.add_menu_item(Gtk.main_quit, "Exit")
61        return indicator
62
63    def __init__(self, iconname):
64        if appIndicatorSupported:
65            self.__menu = Gtk.Menu()
66            self.__indicator = AppIndicator3.Indicator.new(
67                iconname,
68                "",
69                AppIndicator3.IndicatorCategory.APPLICATION_STATUS
70            )
71            self.__indicator.set_menu(self.__menu)
72
73    @onlyIfAppindicatorIsSupported
74    def set_icon(self, path):
75        self.__indicator.set_icon(path)
76
77    @onlyIfAppindicatorIsSupported
78    def switch(self, on=False):
79        if on:
80            self.show()
81        else:
82            self.hide()
83
84    @onlyIfAppindicatorIsSupported
85    def add_menu_item(self, command, title):
86        menu_item = Gtk.MenuItem()
87        menu_item.set_label(title)
88        menu_item.connect("activate", command)
89        self.__menu.append(menu_item)
90
91    @onlyIfAppindicatorIsSupported
92    def add_seperator(self):
93        menu_item = Gtk.SeparatorMenuItem()
94        self.__menu.append(menu_item)
95
96    @onlyIfAppindicatorIsSupported
97    def show(self):
98        self.__indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)
99        self.__menu.show_all()
100
101    @onlyIfAppindicatorIsSupported
102    def hide(self):
103        self.__indicator.set_status(AppIndicator3.IndicatorStatus.PASSIVE)
104
105    @onlyIfAppindicatorIsSupported
106    def right_click_event_statusicon(self, icon, button, time):
107        self._get_tray_menu()
108
109        def pos(menu, aicon):
110            return Gtk.StatusIcon.position_menu(menu, aicon)
111
112        self.__menu.popup(None, None, pos, icon, button, time)
113
114    def _get_tray_menu(self):
115        return self.__menu
116