Added a system tray icon in 'standalone' (ie, non-applet) mode. This will only
[memo.git] / Systray.py
blob9cbd41db47bff9e1a14890e3f15af932c90bc669
1 import rox
2 from rox import g, options, app_options
3 from MenuWindow import MenuWindow
4 import main
6 import gobject
8 import sys
9 import os.path
11 systrayEnable = options.Option('systray_enable', True)
12 systrayHideOnStartup = options.Option('systray_hide_on_startup', False)
13 systrayWorkaround = options.Option('systray_workaround', False)
15 # Require gtk version 2.10.x or better for the 'StatusIcon' widget
16 assert( g.gtk_version >= (2,10,0) )
18 menuAdditions={
19 'topActions': [
20 ("/Main Window", "toggle_main", "", ""),
24 mainAdditions = { 'topMain': [
25 (_('Hide Main Window'), "hide", "")
28 class Systray(g.StatusIcon, MenuWindow):
29 def __init__(self, showOnStartup = None):
30 g.StatusIcon.__init__(self)
31 MenuWindow.__init__(self, attach=False, additions=menuAdditions)
32 icon = os.path.join(rox.app_dir, '.DirIcon')
33 self.set_from_file(icon)
34 self.firstChange = True
35 self.showOnStartup = showOnStartup
36 self.was_embedded = None
37 main.memo_list.connect( "MemoListChanged", self.tooltip_refresh )
38 self.tooltip_refresh( main.memo_list )
39 self.connect("popup-menu", self.popup)
40 self.connect("activate", self.toggle_main)
41 self.connect("notify::visible", self.visibility)
42 if g.gtk_version >= (2,12,0):
43 self.connect("notify::embedded", self.check_embed)
44 else:
45 self.connect("size-changed", self.size_change)
46 self.timeout = gobject.timeout_add(500, self.check_embed)
48 def tooltip_refresh(self, memo_list):
49 (all, hidden) = memo_list.count_today()
50 visible = all-hidden
51 vplural = "s"
52 if visible == 1:
53 vplural = ""
54 self.set_tooltip("Memo - %d reminder%s today" % (visible, vplural) )
56 def position_menu(self, menu):
57 return g.status_icon_position_menu(menu, self)
59 def popup(self, status_icon, button, activate_time):
60 # Rox's 'menu' class doesn't actually need a 'gtk.gdk.Event', just an object
61 # with 'button' and 'time' parameters - Which is good, since gtk.gdk.Event
62 # won't accept a 'long' value, which is what both 'button' and
63 # 'activate_time' are (plus activate_time is usually too large to properly
64 # cast into a signed python 'int' type
65 class e: pass;
66 event = e()
67 event.button = button
68 event.time = activate_time
69 self.popup_menu(event, self.position_menu)
71 def size_change(self, icon = None, size = None):
72 self.check_embed()
74 def is_present(self):
75 return self.is_embedded and self.get_visible()
77 def visibility(self, object=None, property=None):
78 if self.get_visible():
79 self._embedded()
80 else:
81 self._unembedded()
83 def _embedded(self):
84 # Systray present, allow main window to hide
85 main.main_window.addAdditions( mainAdditions )
87 def _unembedded(self):
88 # Systray no longer present, show the main window, and disallow hiding
89 main.main_window.removeAdditions( mainAdditions )
90 if not main.main_window.get_property('visible'):
91 main.main_window.present()
93 def check_embed(self, object = None, property = None):
94 if self.is_embedded() and (not self.was_embedded or self.firstChange):
95 self._embedded()
96 # Check for "hide on startup" flag
97 if self.showOnStartup is not None:
98 if not self.showOnStartup:
99 main.main_window.hide()
100 else:
101 if not main.main_window.get_property('visible'):
102 main.main_window.present()
103 self.was_embedded = True
104 elif not self.is_embedded() and (self.was_embedded or self.firstChange):
105 self._unembedded()
106 self.was_embedded = False
107 self.firstChange = False
108 return True
110 def toggle_main(self, event = None):
111 if main.main_window.get_property('visible'):
112 main.main_window.hide()
113 else:
114 main.main_window.present()
116 def quit(self, event = None):
117 main.main_window.destroy()
119 class HideableSystray(object):
120 def __init__(self):
121 if systrayEnable.int_value:
122 self.icon = Systray( showOnStartup = not systrayHideOnStartup.int_value )
123 else:
124 self.icon = None
125 main.main_window.present()
126 app_options.add_notify(self.options_changed)
128 def options_changed(self):
129 if systrayEnable.has_changed:
130 if systrayEnable.int_value:
131 self.show()
132 else:
133 self.hide()
134 if systrayWorkaround.has_changed:
135 if systrayEnable.int_value and systrayWorkaround.int_value:
136 self.hide()
137 self.show()
139 def show(self):
140 if not self.icon:
141 self.icon = Systray()
142 else:
143 self.icon.set_visible(True)
145 def hide(self):
146 if self.icon:
147 self.icon.set_visible(False)
148 # Workaround for broken systrays (like older fluxbox versions) which
149 # may not support set_visible(True) - Delete the systray icon (which
150 # will be re-created at 'show' time.
151 if systrayWorkaround.int_value:
152 del self.icon
153 self.icon = None
155 def is_embedded(self):
156 if self.icon:
157 return self.icon.is_embedded()
158 return False
160 def get_visible(self):
161 if self.icon:
162 return self.icon.get_visible()
163 return False
165 def is_present(self):
166 if self.icon:
167 return self.icon.is_present()
168 return False