Imported PyGObject's pygtkcompat.py for better compatibility
[zeroinstall.git] / zeroinstall / 0launch-gui / main.py
blob92833b7e495fc72e0fc7cc5d992c6f9ae6cce5e6
1 # Copyright (C) 2009, Thomas Leonard
2 # See the README file for details, or visit http://0install.net.
4 from __future__ import print_function
6 import os, sys
8 from optparse import OptionParser
10 from zeroinstall import _
11 from zeroinstall.injector import requirements
12 from zeroinstall.injector.driver import Driver
13 from zeroinstall.injector.config import load_config
14 from zeroinstall.support import tasks
16 _recalculate = tasks.Blocker('recalculate')
18 def recalculate():
19 """Ask the mainloop to recalculate. If we're already recalculating, wait for that to finish
20 and then do it again."""
21 global _recalculate
22 _recalculate.trigger()
23 _recalculate = tasks.Blocker('recalculate')
25 def run_gui(args):
26 parser = OptionParser(usage=_("usage: %prog [options] interface"))
27 parser.add_option("", "--before", help=_("choose a version before this"), metavar='VERSION')
28 parser.add_option("", "--cpu", help=_("target CPU type"), metavar='CPU')
29 parser.add_option("", "--command", help=_("command to select"), metavar='COMMAND')
30 parser.add_option("-d", "--download-only", help=_("fetch but don't run"), action='store_true')
31 parser.add_option("", "--message", help=_("message to display when interacting with user"))
32 parser.add_option("", "--not-before", help=_("minimum version to choose"), metavar='VERSION')
33 parser.add_option("", "--os", help=_("target operation system type"), metavar='OS')
34 parser.add_option("-r", "--refresh", help=_("check for updates of all interfaces"), action='store_true')
35 parser.add_option("", "--select-only", help=_("only download the feeds"), action='store_true')
36 parser.add_option("-s", "--source", help=_("select source code"), action='store_true')
37 parser.add_option("", "--systray", help=_("download in the background"), action='store_true')
38 parser.add_option("-v", "--verbose", help=_("more verbose output"), action='count')
39 parser.add_option("-V", "--version", help=_("display version information"), action='store_true')
40 parser.add_option("", "--with-store", help=_("add an implementation cache"), action='append', metavar='DIR')
42 parser.disable_interspersed_args()
44 (options, args) = parser.parse_args(args)
46 if options.verbose:
47 import logging
48 logger = logging.getLogger()
49 if options.verbose == 1:
50 logger.setLevel(logging.INFO)
51 else:
52 logger.setLevel(logging.DEBUG)
54 import gui
56 if options.version:
57 print("0launch-gui (zero-install) " + gui.version)
58 print("Copyright (C) 2010 Thomas Leonard")
59 print(_("This program comes with ABSOLUTELY NO WARRANTY,"
60 "\nto the extent permitted by law."
61 "\nYou may redistribute copies of this program"
62 "\nunder the terms of the GNU Lesser General Public License."
63 "\nFor more information about these matters, see the file named COPYING."))
64 sys.exit(0)
66 if sys.version_info[0] > 2:
67 from zeroinstall.gtkui import pygtkcompat
68 pygtkcompat.enable()
69 pygtkcompat.enable_gtk(version = '3.0')
70 import gtk
71 if gtk.gdk.get_display() is None:
72 print("Failed to connect to display. Aborting.", file=sys.stderr)
73 sys.exit(1)
75 handler = gui.GUIHandler()
77 config = load_config(handler)
79 if options.with_store:
80 from zeroinstall import zerostore
81 for x in options.with_store:
82 config.stores.stores.append(zerostore.Store(os.path.abspath(x)))
84 if len(args) < 1:
85 @tasks.async
86 def prefs_main():
87 import preferences
88 box = preferences.show_preferences(config)
89 done = tasks.Blocker('close preferences')
90 box.connect('destroy', lambda w: done.trigger())
91 yield done
92 tasks.wait_for_blocker(prefs_main())
93 sys.exit(0)
95 interface_uri = args[0]
97 if len(args) > 1:
98 parser.print_help()
99 sys.exit(1)
101 import mainwindow, dialog
103 r = requirements.Requirements(interface_uri)
104 r.parse_options(options)
106 widgets = dialog.Template('main')
108 driver = Driver(config = config, requirements = r)
109 root_iface = config.iface_cache.get_interface(interface_uri)
110 driver.solver.record_details = True
112 window = mainwindow.MainWindow(driver, widgets, download_only = bool(options.download_only), select_only = bool(options.select_only))
113 handler.mainwindow = window
115 if options.message:
116 window.set_message(options.message)
118 root = config.iface_cache.get_interface(r.interface_uri)
119 window.browser.set_root(root)
121 window.window.connect('destroy', lambda w: handler.abort_all_downloads())
123 if options.systray:
124 window.use_systray_icon()
126 @tasks.async
127 def main():
128 force_refresh = bool(options.refresh)
129 while True:
130 window.refresh_button.set_sensitive(False)
131 window.browser.set_update_icons(force_refresh)
133 solved = driver.solve_with_downloads(force = force_refresh, update_local = True)
135 if not window.systray_icon:
136 window.show()
137 yield solved
138 try:
139 window.refresh_button.set_sensitive(True)
140 window.browser.highlight_problems()
141 tasks.check(solved)
142 except Exception as ex:
143 window.report_exception(ex)
145 if window.systray_icon and window.systray_icon.get_visible() and \
146 window.systray_icon.is_embedded():
147 if driver.solver.ready:
148 window.systray_icon.set_tooltip(_('Downloading updates for %s') % root_iface.get_name())
149 window.run_button.set_active(True)
150 else:
151 # Should already be reporting an error, but
152 # blink it again just in case
153 window.systray_icon.set_blinking(True)
155 refresh_clicked = dialog.ButtonClickedBlocker(window.refresh_button)
156 yield refresh_clicked, _recalculate
158 if refresh_clicked.happened:
159 force_refresh = True
161 tasks.wait_for_blocker(main())