From 15390532d8ac10e06ac6bfe9d14f6d1747fff718 Mon Sep 17 00:00:00 2001 From: Thomas Leonard Date: Mon, 16 Jun 2008 21:49:02 +0100 Subject: [PATCH] Added "0desktop --manage". Displays a list of applications added to the desktop menus. --- 0desktop.1 | 2 + applications/zeroinstall-manage.desktop | 2 +- zeroinstall/gtkui/addbox.py | 22 +++----- zeroinstall/gtkui/applistbox.py | 57 ++++++++++++++++++++ zeroinstall/gtkui/desktop.glade | 93 +++++++++++++++++++++++++++++++++ zeroinstall/gtkui/desktop.py | 12 +++-- zeroinstall/gtkui/icon.py | 24 +++++++++ zeroinstall/gtkui/xdgutils.py | 27 ++++++++++ 8 files changed, 219 insertions(+), 20 deletions(-) create mode 100644 zeroinstall/gtkui/applistbox.py create mode 100644 zeroinstall/gtkui/icon.py diff --git a/0desktop.1 b/0desktop.1 index 0732c36..26f373b 100644 --- a/0desktop.1 +++ b/0desktop.1 @@ -7,6 +7,8 @@ .B 0destkop [ \fBURI\fP ] +.B 0destkop --manage + .SH DESCRIPTION .PP 0desktop can be used to create launchers for Zero Install applications in diff --git a/applications/zeroinstall-manage.desktop b/applications/zeroinstall-manage.desktop index 4a436ab..425f035 100644 --- a/applications/zeroinstall-manage.desktop +++ b/applications/zeroinstall-manage.desktop @@ -4,7 +4,7 @@ Version=1.0 Name=Update or Remove Programs GenericName=Installer Comment=Manage Zero Install programs on your Applications menu -Exec=0launch http://0install.net/2008/interfaces/ZeroInstall-GUI.xml --cache +Exec=0desktop --manage Icon=zeroinstall-zero2desktop Terminal=false Categories=PackageManager;GTK; diff --git a/zeroinstall/gtkui/addbox.py b/zeroinstall/gtkui/addbox.py index c09b717..ac32afe 100644 --- a/zeroinstall/gtkui/addbox.py +++ b/zeroinstall/gtkui/addbox.py @@ -5,7 +5,6 @@ import os, sys import gtk, gobject import gtk.glade -import tempfile, shutil from zeroinstall import SafeException from zeroinstall.injector.namespaces import XMLNS_IFACE @@ -24,15 +23,15 @@ class AddBox: widgets = gtk.glade.XML(gladefile, 'main') self.window = widgets.get_widget('main') + self.set_keep_above(True) def set_uri_ok(uri): text = uri.get_text() self.window.set_response_sensitive(_RESPONSE_NEXT, bool(text)) - drop_uri = widgets.get_widget('drop_uri') uri = widgets.get_widget('interface_uri') about = widgets.get_widget('about') - icon = widgets.get_widget('icon') + icon_widget = widgets.get_widget('icon') category = widgets.get_widget('category') dialog_next = widgets.get_widget('dialog_next') dialog_ok = widgets.get_widget('dialog_ok') @@ -68,19 +67,10 @@ class AddBox: iface = iface_cache.get_interface(uri.get_text()) about.set_text('%s - %s' % (iface.get_name(), iface.summary)) icon_path = iface_cache.get_icon_path(iface) - if icon_path: - try: - # Icon format must be PNG (to avoid attacks) - loader = gtk.gdk.PixbufLoader('png') - try: - loader.write(file(icon_path).read()) - finally: - loader.close() - icon_pixbuf = loader.get_pixbuf() - except Exception, ex: - print >>sys.stderr, "Failed to load cached PNG icon: %s" % ex - else: - icon.set_from_pixbuf(icon_pixbuf) + from zeroinstall.gtkui import icon + icon_pixbuf = icon.load_icon(icon_path) + if icon_pixbuf: + icon_widget.set_from_pixbuf(icon_pixbuf) feed_category = None for meta in iface.get_metadata(XMLNS_IFACE, 'category'): diff --git a/zeroinstall/gtkui/applistbox.py b/zeroinstall/gtkui/applistbox.py new file mode 100644 index 0000000..25a903f --- /dev/null +++ b/zeroinstall/gtkui/applistbox.py @@ -0,0 +1,57 @@ +"""A GTK dialog which displays a list of Zero Install applications in the menu.""" +# Copyright (C) 2008, Thomas Leonard +# See the README file for details, or visit http://0install.net. + +import os +import gtk +import gtk.glade + +from zeroinstall.gtkui import icon, xdgutils + +class AppListBox: + """A dialog box which lists applications already added to the menus.""" + ICON, URI, NAME, MARKUP = range(4) + + def __init__(self, iface_cache): + gladefile = os.path.join(os.path.dirname(__file__), 'desktop.glade') + + widgets = gtk.glade.XML(gladefile, 'applist') + self.window = widgets.get_widget('applist') + tv = widgets.get_widget('treeview') + + model = gtk.ListStore(gtk.gdk.Pixbuf, str, str, str) + apps = xdgutils.discover_existing_apps() + + for uri in apps: + itr = model.append() + model[itr][AppListBox.URI] = uri + + iface = iface_cache.get_interface(uri) + name = iface.get_name() + summary = iface.summary or 'No information available' + summary = summary[:1].capitalize() + summary[1:] + + model[itr][AppListBox.NAME] = name + pixbuf = icon.load_icon(iface_cache.get_icon_path(iface)) + if pixbuf: + model[itr][AppListBox.ICON] = pixbuf + + model[itr][AppListBox.MARKUP] = '%s\n%s' % (name.replace('<', '<'), summary.replace('<', '<')) + + tv.set_model(model) + + cell_icon = gtk.CellRendererPixbuf() + cell_icon.set_property('xpad', 4) + cell_icon.set_property('ypad', 4) + column = gtk.TreeViewColumn('Icon', cell_icon, pixbuf = AppListBox.ICON) + tv.append_column(column) + + cell_text = gtk.CellRendererText() + column = gtk.TreeViewColumn('Name', cell_text, markup = AppListBox.MARKUP) + tv.append_column(column) + + model.set_sort_column_id(AppListBox.NAME, gtk.SORT_ASCENDING) + + def response(box, resp): + box.destroy() + self.window.connect('response', response) diff --git a/zeroinstall/gtkui/desktop.glade b/zeroinstall/gtkui/desktop.glade index b6b8998..be99ec5 100644 --- a/zeroinstall/gtkui/desktop.glade +++ b/zeroinstall/gtkui/desktop.glade @@ -598,4 +598,97 @@ Utility + + True + Zero Install applications + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 500 + 500 + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + False + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + -7 + + + + + 0 + False + True + GTK_PACK_END + + + + + + True + 0 + 0.5 + GTK_SHADOW_NONE + + + + True + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_ALWAYS + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + True + False + True + False + False + False + + + + + + + 0 + True + True + + + + + + diff --git a/zeroinstall/gtkui/desktop.py b/zeroinstall/gtkui/desktop.py index ab24436..5593a70 100644 --- a/zeroinstall/gtkui/desktop.py +++ b/zeroinstall/gtkui/desktop.py @@ -10,7 +10,8 @@ import logging def main(command_args): """Implements the logic of the 0desktop command. @param args: the command-line arguments""" - parser = OptionParser(usage="usage: %prog [options]") + parser = OptionParser(usage="usage: %prog [options] [URI]") + parser.add_option("-m", "--manage", help="manage added applications", 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') @@ -49,9 +50,14 @@ def main(command_args): import pygtk; pygtk.require('2.0') import gtk - from zeroinstall.gtkui.addbox import AddBox + if options.manage: + from zeroinstall.gtkui.applistbox import AppListBox + from zeroinstall.injector.iface_cache import iface_cache + box = AppListBox(iface_cache) + else: + from zeroinstall.gtkui.addbox import AddBox + box = AddBox(interface_uri) - box = AddBox(interface_uri) box.window.connect('destroy', gtk.main_quit) box.window.show() gtk.main() diff --git a/zeroinstall/gtkui/icon.py b/zeroinstall/gtkui/icon.py new file mode 100644 index 0000000..7363b98 --- /dev/null +++ b/zeroinstall/gtkui/icon.py @@ -0,0 +1,24 @@ +"""Loading icons.""" +# Copyright (C) 2008, Thomas Leonard +# See the README file for details, or visit http://0install.net. + +import gtk +from logging import warn + +def load_icon(icon_path): + """Load icon from path. Icon MUST be in PNG format. + @param icon_path: pathname of icon, or None to load nothing + @return: a GdkPixbuf, or None on failure""" + if not icon_path: + return None + try: + # Icon format must be PNG (to avoid attacks) + loader = gtk.gdk.PixbufLoader('png') + try: + loader.write(file(icon_path).read()) + finally: + loader.close() + return loader.get_pixbuf() + except Exception, ex: + warn("Failed to load cached PNG icon: %s" % ex) + return None diff --git a/zeroinstall/gtkui/xdgutils.py b/zeroinstall/gtkui/xdgutils.py index 93b8392..7fa6c0b 100644 --- a/zeroinstall/gtkui/xdgutils.py +++ b/zeroinstall/gtkui/xdgutils.py @@ -5,8 +5,10 @@ # See the README file for details, or visit http://0install.net. import shutil, os, tempfile +from logging import info, warn from zeroinstall import SafeException +from zeroinstall.support import basedir _template = """[Desktop Entry] # This file was generated by zero2desktop. @@ -41,3 +43,28 @@ def add_to_menu(iface, icon_path, category): if status: raise SafeException('Failed to run xdg-desktop-menu (error code %d)' % status) + +def discover_existing_apps(): + """Search through the configured XDG datadirs looking for .desktop files created by us. + @return: a map from application URIs to .desktop filenames""" + already_installed = {} + for d in basedir.load_data_paths('applications'): + for desktop_file in os.listdir(d): + if desktop_file.startswith('zeroinstall-') and desktop_file.endswith('.desktop'): + full = os.path.join(d, desktop_file) + try: + for line in file(full): + line = line.strip() + if line.startswith('Exec=0launch '): + bits = line.split(' -- ', 1) + if ' ' in bits[0]: + uri = bits[0].split(' ', 1)[1] # 0launch URI -- %u + else: + uri = bits[1].split(' ', 1)[0].strip() # 0launch -- URI %u + already_installed[uri] = full + break + else: + info("Failed to find Exec line in %s", full) + except Exception, ex: + warn("Failed to load .desktop file %s: %s", full, ex) + return already_installed -- 2.11.4.GIT