From 9e3c284b06379754a1478deb8f66c03780fdcf64 Mon Sep 17 00:00:00 2001 From: Thomas Leonard Date: Sun, 1 Mar 2009 11:24:21 +0000 Subject: [PATCH] Added --systray option to the GUI Instead of opening the usual window, display an icon in the system tray and start the download automatically. Needed on Ubuntu/Jaunty because its new notification system doesn't allow asking questions in notification messages. --- zeroinstall/0launch-gui/gui.py | 2 +- zeroinstall/0launch-gui/main.py | 23 ++++++++++++++------ zeroinstall/0launch-gui/mainwindow.py | 40 +++++++++++++++++++++++++++++------ 3 files changed, 51 insertions(+), 14 deletions(-) diff --git a/zeroinstall/0launch-gui/gui.py b/zeroinstall/0launch-gui/gui.py index f542840..ffc22e2 100644 --- a/zeroinstall/0launch-gui/gui.py +++ b/zeroinstall/0launch-gui/gui.py @@ -50,4 +50,4 @@ class GUIHandler(handler.Handler): def report_error(self, ex, tb = None): if isinstance(ex, download.DownloadAborted): return # No need to tell the user about this, since they caused it - dialog.alert(self.mainwindow.window, str(ex)) + self.mainwindow.report_exception(ex) diff --git a/zeroinstall/0launch-gui/main.py b/zeroinstall/0launch-gui/main.py index f026fac..dcbd7c8 100644 --- a/zeroinstall/0launch-gui/main.py +++ b/zeroinstall/0launch-gui/main.py @@ -21,6 +21,7 @@ def run_gui(args): parser.add_option("", "--os", help="target operation system type", metavar='OS') parser.add_option("-r", "--refresh", help="check for updates of all interfaces", action='store_true') parser.add_option("-s", "--source", help="select source code", action='store_true') + parser.add_option("", "--systray", help="download in the background", action='store_true') parser.add_option("-v", "--verbose", help="more verbose output", action='count') parser.add_option("-V", "--version", help="display version information", action='store_true') @@ -111,6 +112,9 @@ def run_gui(args): window.window.connect('destroy', lambda w: handler.abort_all_downloads()) + if options.systray: + window.use_systray_icon() + @tasks.async def main(): force_refresh = bool(options.refresh) @@ -119,17 +123,24 @@ def run_gui(args): solved = policy.solve_with_downloads(force = force_refresh) - window.show() + if not window.systray_icon: + window.show() yield solved try: window.refresh_button.set_sensitive(True) tasks.check(solved) - except model.SafeException, ex: - dialog.alert(window.window, str(ex)) except Exception, ex: - import traceback - traceback.print_exc() - dialog.alert(window.window, str(ex)) + window.report_exception(ex) + + if window.systray_icon and window.systray_icon.get_visible() and \ + window.systray_icon.is_embedded(): + if policy.ready: + window.systray_icon.set_tooltip('Downloading updates for %s' % root_iface.get_name()) + window.run_button.set_active(True) + else: + # Should already be reporting an error, but + # blink it again just in case + window.systray_icon.set_blinking(True) yield dialog.ButtonClickedBlocker(window.refresh_button) force_refresh = True diff --git a/zeroinstall/0launch-gui/mainwindow.py b/zeroinstall/0launch-gui/mainwindow.py index 8bfd807..8aed2cd 100644 --- a/zeroinstall/0launch-gui/mainwindow.py +++ b/zeroinstall/0launch-gui/mainwindow.py @@ -3,9 +3,11 @@ import gtk import sys +from logging import info + from zeroinstall import SafeException from zeroinstall.support import tasks, pretty_size -from zeroinstall.injector import download +from zeroinstall.injector import download, iface_cache from iface_browser import InterfaceBrowser import dialog from zeroinstall.gtkui import gtkutils @@ -23,6 +25,7 @@ class MainWindow: cancel_download_and_run = None policy = None comment = None + systray_icon = None def __init__(self, policy, widgets, download_only): self.policy = policy @@ -54,6 +57,7 @@ class MainWindow: self.window.add_action_widget(run_button, gtk.RESPONSE_OK) run_button.show_all() run_button.set_flags(gtk.CAN_DEFAULT) + self.run_button = run_button self.window.set_default_response(gtk.RESPONSE_OK) self.window.default_widget.grab_focus() @@ -74,6 +78,7 @@ class MainWindow: import preferences preferences.show_preferences(policy) self.window.connect('response', response) + self.window.realize() # Make busy pointer work, even with --systray def destroy(self): self.window.destroy() @@ -108,16 +113,11 @@ class MainWindow: sys.stdout.write(('Length:%8x\n' % len(reply)) + reply) self.window.destroy() sys.exit(0) # Success - except SafeException, ex: - run_button.set_active(False) - self.policy.handler.report_error(ex) except SystemExit: raise except Exception, ex: run_button.set_active(False) - import traceback - traceback.print_exc() - self.policy.handler.report_error(ex) + self.report_exception(ex) def update_download_status(self): """Called at regular intervals while there are downloads in progress, @@ -167,6 +167,32 @@ class MainWindow: self.comment.set_attributes(attrs) self.comment.show() + def use_systray_icon(self): + try: + self.systray_icon = gtk.status_icon_new_from_icon_name("zeroinstall-zero2desktop") + except Exception, ex: + info("No system tray support: %s", ex) + else: + root_iface = iface_cache.iface_cache.get_interface(self.policy.root) + self.systray_icon.set_tooltip('Checking for updates for %s' % root_iface.get_name()) + self.systray_icon.connect('activate', self.remove_systray_icon) + + def remove_systray_icon(self, i = None): + assert self.systray_icon, i + self.show() + self.systray_icon.set_visible(False) + self.systray_icon = None + + def report_exception(self, ex): + if not isinstance(ex, SafeException): + import traceback + traceback.print_exc() + if self.systray_icon: + self.systray_icon.set_blinking(True) + self.systray_icon.set_tooltip(str(ex) + '\n(click for details)') + else: + dialog.alert(self.window, str(ex)) + gui_help = help_box.HelpBox("Injector Help", ('Overview', """ A program is made up of many different components, typically written by different \ -- 2.11.4.GIT