Added --systray option to the GUI
[zeroinstall/zeroinstall-rsl.git] / zeroinstall / 0launch-gui / main.py
blobdcbd7c8d33f6eabbe7d75d01ac553bd5b8c77257
1 # Copyright (C) 2009, Thomas Leonard
2 # See the README file for details, or visit http://0install.net.
4 import os, sys
6 from optparse import OptionParser
8 from zeroinstall.injector import model, arch
9 from zeroinstall.injector.policy import Policy
10 from zeroinstall.injector.iface_cache import iface_cache
11 from zeroinstall.support import tasks
13 def run_gui(args):
14 parser = OptionParser(usage="usage: %prog [options] interface")
15 parser.add_option("", "--before", help="choose a version before this", metavar='VERSION')
16 parser.add_option("", "--cpu", help="target CPU type", metavar='CPU')
17 parser.add_option("-c", "--cache", help="show the cache", action='store_true')
18 parser.add_option("-d", "--download-only", help="fetch but don't run", action='store_true')
19 parser.add_option("", "--message", help="message to display when interacting with user")
20 parser.add_option("", "--not-before", help="minimum version to choose", metavar='VERSION')
21 parser.add_option("", "--os", help="target operation system type", metavar='OS')
22 parser.add_option("-r", "--refresh", help="check for updates of all interfaces", action='store_true')
23 parser.add_option("-s", "--source", help="select source code", action='store_true')
24 parser.add_option("", "--systray", help="download in the background", action='store_true')
25 parser.add_option("-v", "--verbose", help="more verbose output", action='count')
26 parser.add_option("-V", "--version", help="display version information", action='store_true')
28 parser.disable_interspersed_args()
30 (options, args) = parser.parse_args(args)
32 if options.verbose:
33 import logging
34 logger = logging.getLogger()
35 if options.verbose == 1:
36 logger.setLevel(logging.INFO)
37 else:
38 logger.setLevel(logging.DEBUG)
40 if options.cache:
41 # Must fork before importing gtk, or ATK dies
42 if os.fork():
43 # We exit, so our parent can call waitpid and unblock.
44 sys.exit(0)
45 # The grandchild continues...
47 import gui
49 if options.version:
50 print "0launch-gui (zero-install) " + gui.version
51 print "Copyright (C) 2007 Thomas Leonard"
52 print "This program comes with ABSOLUTELY NO WARRANTY,"
53 print "to the extent permitted by law."
54 print "You may redistribute copies of this program"
55 print "under the terms of the GNU General Public License."
56 print "For more information about these matters, see the file named COPYING."
57 sys.exit(0)
59 import gtk
60 if gtk.gdk.get_display() is None:
61 print >>sys.stderr, "Failed to connect to display. Aborting."
62 sys.exit(1)
64 if not hasattr(gtk, 'combo_box_new_text'):
65 import combo_compat
67 if options.cache:
68 import cache
69 cache_explorer = cache.CacheExplorer()
70 cache_explorer.show()
71 cache_explorer.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
72 gtk.gdk.flush()
73 cache_explorer.populate_model()
74 cache_explorer.window.set_cursor(None)
75 gtk.main()
76 sys.exit(0)
78 if len(args) < 1:
79 parser.print_help()
80 sys.exit(1)
82 interface_uri = args[0]
84 if len(args) > 1:
85 parser.print_help()
86 sys.exit(1)
88 import mainwindow, dialog
90 restrictions = []
91 if options.before or options.not_before:
92 restrictions.append(model.VersionRangeRestriction(model.parse_version(options.before),
93 model.parse_version(options.not_before)))
95 widgets = dialog.Template('main')
97 handler = gui.GUIHandler()
98 policy = Policy(interface_uri, handler, src = bool(options.source))
99 policy.target_arch = arch.get_architecture(options.os, options.cpu)
100 root_iface = iface_cache.get_interface(interface_uri)
101 policy.solver.extra_restrictions[root_iface] = restrictions
102 policy.solver.record_details = True
104 window = mainwindow.MainWindow(policy, widgets, download_only = bool(options.download_only))
105 handler.mainwindow = window
107 if options.message:
108 window.set_message(options.message)
110 root = iface_cache.get_interface(policy.root)
111 window.browser.set_root(root)
113 window.window.connect('destroy', lambda w: handler.abort_all_downloads())
115 if options.systray:
116 window.use_systray_icon()
118 @tasks.async
119 def main():
120 force_refresh = bool(options.refresh)
121 while True:
122 window.refresh_button.set_sensitive(False)
124 solved = policy.solve_with_downloads(force = force_refresh)
126 if not window.systray_icon:
127 window.show()
128 yield solved
129 try:
130 window.refresh_button.set_sensitive(True)
131 tasks.check(solved)
132 except Exception, ex:
133 window.report_exception(ex)
135 if window.systray_icon and window.systray_icon.get_visible() and \
136 window.systray_icon.is_embedded():
137 if policy.ready:
138 window.systray_icon.set_tooltip('Downloading updates for %s' % root_iface.get_name())
139 window.run_button.set_active(True)
140 else:
141 # Should already be reporting an error, but
142 # blink it again just in case
143 window.systray_icon.set_blinking(True)
145 yield dialog.ButtonClickedBlocker(window.refresh_button)
146 force_refresh = True
148 handler.wait_for_blocker(main())