Skip to content

Commit dc9427e

Browse files
author
Jonathan Ballet
committed
Improved support for Gtk Status icon
It should now have the same functionalities as the old Egg tray icon.
1 parent 3ca820b commit dc9427e

File tree

2 files changed

+260
-196
lines changed

2 files changed

+260
-196
lines changed

sonata/main.py

Lines changed: 44 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,6 @@
2727

2828
import gobject, gtk, pango
2929

30-
# Prevent deprecation warning for egg:
31-
warnings.simplefilter('ignore', DeprecationWarning)
32-
try:
33-
import egg.trayicon
34-
HAVE_EGG = True
35-
HAVE_STATUS_ICON = False
36-
except ImportError:
37-
HAVE_EGG = False
38-
HAVE_STATUS_ICON = True
39-
# Reset so that we can see any other deprecation warnings
40-
warnings.simplefilter('default', DeprecationWarning)
4130

4231
# Default to no sugar, then test...
4332
HAVE_SUGAR = False
@@ -90,10 +79,6 @@ def __init__(self, args, window=None, _sugar=False):
9079
self.remote_dest_filename = None
9180
self.remotefilelist = None
9281
self.seekidle = None
93-
self.statusicon = None
94-
self.trayeventbox = None
95-
self.trayicon = None
96-
self.trayimage = None
9782
self.artwork = None
9883

9984
self.client = mpd.MPDClient()
@@ -161,9 +146,6 @@ def __init__(self, args, window=None, _sugar=False):
161146

162147
self.last_status_text = ""
163148

164-
self.eggtrayfile = None
165-
self.eggtrayheight = None
166-
167149
self.img_clicked = False
168150

169151
self.mpd_update_queued = False
@@ -494,6 +476,9 @@ def __init__(self, args, window=None, _sugar=False):
494476
mainvbox = gtk.VBox()
495477
tophbox = gtk.HBox()
496478

479+
TrayFactory = tray.get_tray_icon_factory()
480+
self.tray_icon = TrayFactory(self.window, self.traymenu, self.traytips)
481+
497482
self.albumimage = self.artwork.get_albumimage()
498483

499484
self.imageeventbox = ui.eventbox(add=self.albumimage)
@@ -725,7 +710,7 @@ def __init__(self, args, window=None, _sugar=False):
725710
self.iterate_now()
726711
if self.window_owner:
727712
if self.config.withdrawn:
728-
if (HAVE_EGG and self.trayicon.get_property('visible')) or (HAVE_STATUS_ICON and self.statusicon.is_embedded() and self.statusicon.get_visible()):
713+
if self.tray_icon.is_visible():
729714
ui.hide(self.window)
730715
self.window.show_all()
731716

@@ -748,9 +733,6 @@ def __init__(self, args, window=None, _sugar=False):
748733
self.on_currsong_notify()
749734
self.current.center_song_in_list()
750735

751-
if HAVE_STATUS_ICON:
752-
gobject.timeout_add(250, self.iterate_status_icon)
753-
754736
gc.disable()
755737

756738
gobject.idle_add(self.header_save_column_widths)
@@ -1032,17 +1014,12 @@ def iterate(self):
10321014
self.iterate_handler = gobject.timeout_add(self.iterate_time, self.iterate) # Repeat ad infitum..
10331015

10341016
if self.config.show_trayicon:
1035-
if HAVE_STATUS_ICON:
1036-
if self.statusicon.is_embedded() and not self.statusicon.get_visible():
1037-
# Systemtray appears, add icon:
1038-
self.systemtray_initialize()
1039-
elif not self.statusicon.is_embedded() and self.config.withdrawn:
1040-
# Systemtray gone, unwithdraw app:
1041-
self.withdraw_app_undo()
1042-
elif HAVE_EGG:
1043-
if not self.trayicon.get_property('visible'):
1044-
# Systemtray appears, add icon:
1045-
self.systemtray_initialize()
1017+
if self.tray_icon.is_available() and not self.tray_icon.is_visible():
1018+
# Systemtray appears, add icon
1019+
self.systemtray_initialize()
1020+
elif not self.tray_icon.is_available() and self.config.withdrawn:
1021+
# Systemtray gone, unwithdraw app
1022+
self.withdraw_app_undo()
10461023

10471024
if self.call_gc_collect:
10481025
gc.collect()
@@ -1065,15 +1042,6 @@ def iterate_now(self):
10651042
self.iterate_stop()
10661043
self.iterate()
10671044

1068-
def iterate_status_icon(self):
1069-
# Polls for the users' cursor position to display the custom tooltip window when over the
1070-
# gtk.StatusIcon. We use this instead of self.iterate() in order to poll more often and
1071-
# increase responsiveness.
1072-
if self.config.show_trayicon:
1073-
if self.statusicon.is_embedded() and self.statusicon.get_visible():
1074-
self.tooltip_show_manually()
1075-
gobject.timeout_add(250, self.iterate_status_icon)
1076-
10771045
def on_topwindow_keypress(self, _widget, event):
10781046
shortcut = gtk.accelerator_name(event.keyval, event.state)
10791047
shortcut = shortcut.replace("<Mod2>", "")
@@ -1085,11 +1053,9 @@ def on_topwindow_keypress(self, _widget, event):
10851053
self.library.on_search_end(None)
10861054
elif self.current_tab == self.TAB_CURRENT and self.current.filterbox_visible:
10871055
self.current.searchfilter_toggle(None)
1088-
elif self.config.minimize_to_systray:
1089-
if HAVE_STATUS_ICON and self.statusicon.is_embedded() and self.statusicon.get_visible():
1090-
self.withdraw_app()
1091-
elif HAVE_EGG and self.trayicon.get_property('visible'):
1092-
self.withdraw_app()
1056+
elif self.config.minimize_to_systray and \
1057+
self.tray_icon.is_visible():
1058+
self.withdraw_app()
10931059
return
10941060
elif shortcut == 'Delete':
10951061
self.on_remove(None)
@@ -1136,11 +1102,7 @@ def handle_change_conn(self):
11361102
self.currentdata.clear()
11371103
if self.current_treeview.get_model():
11381104
self.current_treeview.get_model().clear()
1139-
if HAVE_STATUS_ICON:
1140-
self.statusicon.set_from_file(self.find_path('sonata_disconnect.png'))
1141-
elif HAVE_EGG and self.eggtrayheight:
1142-
self.eggtrayfile = self.find_path('sonata_disconnect.png')
1143-
self.trayimage.set_from_pixbuf(img.get_pixbuf_of_size(gtk.gdk.pixbuf_new_from_file(self.eggtrayfile), self.eggtrayheight)[0])
1105+
self.tray_icon.update_icon(self.find_path('sonata_disconnect.png'))
11441106
self.info_update(True)
11451107
if self.current.filterbox_visible:
11461108
gobject.idle_add(self.current.searchfilter_toggle, None)
@@ -1428,21 +1390,13 @@ def handle_change_status(self):
14281390
self.ppbutton.get_child().get_child().get_children()[1].set_text('')
14291391
self.UIManager.get_widget('/traymenu/playmenu').show()
14301392
self.UIManager.get_widget('/traymenu/pausemenu').hide()
1431-
if HAVE_STATUS_ICON:
1432-
self.statusicon.set_from_file(self.find_path('sonata.png'))
1433-
elif HAVE_EGG and self.eggtrayheight:
1434-
self.eggtrayfile = self.find_path('sonata.png')
1435-
self.trayimage.set_from_pixbuf(img.get_pixbuf_of_size(gtk.gdk.pixbuf_new_from_file(self.eggtrayfile), self.eggtrayheight)[0])
1393+
self.tray_icon.update_icon(self.find_path('sonata.png'))
14361394
elif self.status['state'] == 'pause':
14371395
self.ppbutton.set_image(ui.image(stock=gtk.STOCK_MEDIA_PLAY, stocksize=gtk.ICON_SIZE_BUTTON))
14381396
self.ppbutton.get_child().get_child().get_children()[1].set_text('')
14391397
self.UIManager.get_widget('/traymenu/playmenu').show()
14401398
self.UIManager.get_widget('/traymenu/pausemenu').hide()
1441-
if HAVE_STATUS_ICON:
1442-
self.statusicon.set_from_file(self.find_path('sonata_pause.png'))
1443-
elif HAVE_EGG and self.eggtrayheight:
1444-
self.eggtrayfile = self.find_path('sonata_pause.png')
1445-
self.trayimage.set_from_pixbuf(img.get_pixbuf_of_size(gtk.gdk.pixbuf_new_from_file(self.eggtrayfile), self.eggtrayheight)[0])
1399+
self.tray_icon.update_icon(self.find_path('sonata_pause.png'))
14461400
elif self.status['state'] == 'play':
14471401
self.ppbutton.set_image(ui.image(stock=gtk.STOCK_MEDIA_PAUSE, stocksize=gtk.ICON_SIZE_BUTTON))
14481402
self.ppbutton.get_child().get_child().get_children()[1].set_text('')
@@ -1452,11 +1406,7 @@ def handle_change_status(self):
14521406
if self.prevstatus['state'] == 'pause':
14531407
# Forces the notification to popup if specified
14541408
self.on_currsong_notify()
1455-
if HAVE_STATUS_ICON:
1456-
self.statusicon.set_from_file(self.find_path('sonata_play.png'))
1457-
elif HAVE_EGG and self.eggtrayheight:
1458-
self.eggtrayfile = self.find_path('sonata_play.png')
1459-
self.trayimage.set_from_pixbuf(img.get_pixbuf_of_size(gtk.gdk.pixbuf_new_from_file(self.eggtrayfile), self.eggtrayheight)[0])
1409+
self.tray_icon.update_icon(self.find_path('sonata_play.png'))
14601410

14611411
self.playing_song_change()
14621412
if self.status_is_play_or_pause():
@@ -1737,10 +1687,8 @@ def on_currsong_notify(self, _foo=None, _bar=None, force_popup=False):
17371687
try:
17381688
self.traytips.notifications_location = self.config.traytips_notifications_location
17391689
self.traytips.use_notifications_location = True
1740-
if HAVE_STATUS_ICON and self.statusicon.is_embedded() and self.statusicon.get_visible():
1741-
self.traytips._real_display(self.statusicon)
1742-
elif HAVE_EGG and self.trayicon.get_property('visible'):
1743-
self.traytips._real_display(self.trayeventbox)
1690+
if self.tray_icon.is_visible():
1691+
self.traytips._real_display(self.tray_icon)
17441692
else:
17451693
self.traytips._real_display(None)
17461694
if self.config.popup_option != len(self.popuptimes)-1:
@@ -1761,10 +1709,7 @@ def on_currsong_notify(self, _foo=None, _bar=None, force_popup=False):
17611709
else:
17621710
self.traytips.hide()
17631711
elif self.traytips.get_property('visible'):
1764-
try:
1765-
self.traytips._real_display(self.trayeventbox)
1766-
except:
1767-
pass
1712+
self.traytips._real_display(self.tray_icon)
17681713

17691714
def on_progressbar_notify_fraction(self, *_args):
17701715
self.trayprogressbar.set_fraction(self.progressbar.get_fraction())
@@ -1812,11 +1757,7 @@ def on_delete_event_yes(self, _widget):
18121757
# This one makes sure the program exits when the window is closed
18131758
def on_delete_event(self, _widget, _data=None):
18141759
if not self.exit_now and self.config.minimize_to_systray:
1815-
if HAVE_STATUS_ICON and self.statusicon.is_embedded() and self.statusicon.get_visible():
1816-
self.withdraw_app()
1817-
return True
1818-
elif HAVE_EGG and self.trayicon.get_property('visible'):
1819-
self.withdraw_app()
1760+
if self.tray_icon.is_visible():
18201761
return True
18211762
self.settings_save()
18221763
self.artwork.artwork_save_cache()
@@ -2469,35 +2410,13 @@ def systemtray_activate(self, _status_icon):
24692410
#self.traytips._remove_timer()
24702411
gobject.timeout_add(100, self.tooltip_set_ignore_toggle_signal_false)
24712412

2472-
def tooltip_show_manually(self):
2473-
# Since there is no signal to connect to when the user puts their
2474-
# mouse over the trayicon, we will check the mouse position
2475-
# manually and show/hide the window as appropriate. This is called
2476-
# every iteration. Note: This should not occur if self.traytips.notif_
2477-
# handler has a value, because that means that the tooltip is already
2478-
# visible, and we don't want to override that setting simply because
2479-
# the user's cursor is not over the tooltip.
2480-
if self.traymenu.get_property('visible') and self.traytips.notif_handler != -1:
2481-
self.traytips._remove_timer()
2482-
elif not self.traytips.notif_handler:
2483-
_pscreen, px, py, _mods = self.window.get_screen().get_display().get_pointer()
2484-
_icon_screen, icon_rect, _icon_orient = self.statusicon.get_geometry()
2485-
x = icon_rect[0]
2486-
y = icon_rect[1]
2487-
width = icon_rect[2]
2488-
height = icon_rect[3]
2489-
if px >= x and px <= x+width and py >= y and py <= y+height:
2490-
self.traytips._start_delay(self.statusicon)
2491-
else:
2492-
self.traytips._remove_timer()
2493-
24942413
def systemtray_click(self, _widget, event):
24952414
# Clicking on an egg system tray icon:
24962415
if event.button == 1 and not self.ignore_toggle_signal: # Left button shows/hides window(s)
24972416
self.systemtray_activate(None)
24982417
elif event.button == 2: # Middle button will play/pause
24992418
if self.conn:
2500-
self.mpd_pp(self.trayeventbox)
2419+
self.mpd_pp(None)
25012420
elif event.button == 3: # Right button pops up menu
25022421
self.traymenu.popup(None, None, None, event.button, event.time)
25032422
return False
@@ -2531,7 +2450,7 @@ def withdraw_app_undo_present_and_focus(self):
25312450
self.window.set_keep_above(True)
25322451

25332452
def withdraw_app(self):
2534-
if HAVE_EGG or HAVE_STATUS_ICON:
2453+
if self.tray_icon.is_available():
25352454
# Save the playlist column widths before withdrawing the app.
25362455
# Otherwise we will not be able to correctly save the column
25372456
# widths if the user quits sonata while it is withdrawn.
@@ -2558,17 +2477,6 @@ def systemtray_scroll(self, widget, event):
25582477
if self.conn:
25592478
self.volumebutton.emit("scroll-event", event)
25602479

2561-
def systemtray_size(self, widget, _allocation):
2562-
if widget.allocation.height <= 5:
2563-
# For vertical panels, height can be 1px, so use width
2564-
size = widget.allocation.width
2565-
else:
2566-
size = widget.allocation.height
2567-
if not self.eggtrayheight or self.eggtrayheight != size:
2568-
self.eggtrayheight = size
2569-
if size > 5 and self.eggtrayfile:
2570-
self.trayimage.set_from_pixbuf(img.get_pixbuf_of_size(gtk.gdk.pixbuf_new_from_file(self.eggtrayfile), self.eggtrayheight)[0])
2571-
25722480
def switch_to_tab_name(self, tab_name):
25732481
self.notebook.set_current_page(self.notebook_get_tab_num(self.notebook, tab_name))
25742482

@@ -2679,7 +2587,6 @@ def on_random_clicked(self, widget):
26792587
self._toggle_clicked('random', widget)
26802588

26812589
def setup_prefs_callbacks(self):
2682-
trayicon_available = HAVE_EGG or HAVE_STATUS_ICON
26832590
extras = preferences.Extras_cbs
26842591
extras.popuptimes = self.popuptimes
26852592
extras.notif_toggled = self.prefs_notif_toggled
@@ -2693,7 +2600,11 @@ def setup_prefs_callbacks(self):
26932600
display.progress_toggled = self.prefs_progress_toggled
26942601
display.statusbar_toggled = self.prefs_statusbar_toggled
26952602
display.lyrics_toggled = self.prefs_lyrics_toggled
2696-
display.trayicon_available = trayicon_available
2603+
# TODO: the tray icon object has not been build yet, so we don't know if
2604+
# the tray icon will be available at this time.
2605+
# We should find a way to update this when the tray icon will be
2606+
# initialized.
2607+
display.trayicon_available = True
26972608

26982609
behavior = preferences.Behavior_cbs
26992610
behavior.trayicon_toggled = self.prefs_trayicon_toggled
@@ -2710,14 +2621,7 @@ def setup_prefs_callbacks(self):
27102621
format.currsongoptions2_changed = self.prefs_currsongoptions2_changed
27112622

27122623
def on_prefs(self, _widget):
2713-
trayicon_in_use = ((HAVE_STATUS_ICON and
2714-
self.statusicon.is_embedded() and
2715-
self.statusicon.get_visible())
2716-
or
2717-
(HAVE_EGG and
2718-
self.trayicon.get_property('visible')))
2719-
2720-
preferences.Behavior_cbs.trayicon_in_use = trayicon_in_use
2624+
preferences.Behavior_cbs.trayicon_in_use = self.tray_icon.is_visible()
27212625
self.preferences.on_prefs_real()
27222626

27232627
def prefs_currentoptions_changed(self, entry, _event):
@@ -2866,21 +2770,12 @@ def prefs_trayicon_toggled(self, button, minimize):
28662770
# CheckButton to reflect if the trayicon is visible.
28672771
if button.get_active():
28682772
self.config.show_trayicon = True
2869-
if HAVE_STATUS_ICON:
2870-
self.statusicon.set_visible(True)
2871-
if self.statusicon.is_embedded() or self.statusicon.get_visible():
2872-
minimize.set_sensitive(True)
2873-
elif HAVE_EGG:
2874-
self.trayicon.show_all()
2875-
if self.trayicon.get_property('visible'):
2876-
minimize.set_sensitive(True)
2773+
self.tray_icon.show()
2774+
minimize.set_sensitive(True)
28772775
else:
28782776
self.config.show_trayicon = False
28792777
minimize.set_sensitive(False)
2880-
if HAVE_STATUS_ICON:
2881-
self.statusicon.set_visible(False)
2882-
elif HAVE_EGG:
2883-
self.trayicon.hide_all()
2778+
self.tray_icon.hide()
28842779

28852780
def seek(self, song, seektime):
28862781
mpdh.call(self.client, 'seek', song, seektime)
@@ -3140,30 +3035,18 @@ def on_about(self, _action):
31403035

31413036
def systemtray_initialize(self):
31423037
# Make system tray 'icon' to sit in the system tray
3143-
if HAVE_STATUS_ICON:
3144-
self.statusicon = gtk.StatusIcon()
3145-
self.statusicon.set_from_file(self.find_path('sonata.png'))
3146-
self.statusicon.set_visible(self.config.show_trayicon)
3147-
self.statusicon.connect('popup_menu', self.systemtray_menu)
3148-
self.statusicon.connect('activate', self.systemtray_activate)
3149-
elif HAVE_EGG:
3150-
self.trayimage = ui.image()
3151-
self.trayeventbox = ui.eventbox(add=self.trayimage)
3152-
self.trayeventbox.connect('button_press_event', self.systemtray_click)
3153-
self.trayeventbox.connect('scroll-event', self.systemtray_scroll)
3154-
self.trayeventbox.connect('size-allocate', self.systemtray_size)
3155-
self.traytips.set_tip(self.trayeventbox)
3156-
try:
3157-
self.trayicon = egg.trayicon.TrayIcon("TrayIcon")
3158-
self.trayicon.add(self.trayeventbox)
3159-
if self.config.show_trayicon:
3160-
self.trayicon.show_all()
3161-
self.eggtrayfile = self.find_path('sonata.png')
3162-
self.trayimage.set_from_pixbuf(img.get_pixbuf_of_size(gtk.gdk.pixbuf_new_from_file(self.eggtrayfile), self.eggtrayheight)[0])
3163-
else:
3164-
self.trayicon.hide_all()
3165-
except:
3166-
pass
3038+
self.tray_icon.initialize(
3039+
self.systemtray_menu,
3040+
self.systemtray_click,
3041+
self.systemtray_scroll,
3042+
self.systemtray_activate,
3043+
)
3044+
3045+
if self.config.show_trayicon:
3046+
self.tray_icon.show()
3047+
else:
3048+
self.tray_icon.hide()
3049+
self.tray_icon.update_icon(self.find_path('sonata.png'))
31673050

31683051
def dbus_show(self):
31693052
self.window.hide()

0 commit comments

Comments
 (0)