1 """Adding icons and menu items using the freedesktop.org system.
2 (xdg = X Desktop Group)
3 """
4
5
6
7 from zeroinstall import _, logger
8 import shutil, os, tempfile
9
10 from zeroinstall import SafeException
11 from zeroinstall.support import basedir
12 from zeroinstall.injector import namespaces
13
14 _template = """[Desktop Entry]
15 # This file was generated by 0install.
16 # See the Zero Install project for details: http://0install.net
17 Type=Application
18 Version=1.0
19 Name=%(name)s
20 Comment=%(comment)s
21 Exec=%(0launch)s -- %(iface)s %%f
22 Categories=Application;%(category)s
23 """
24
25 _icon_template = """Icon=%s
26 """
27
29 """Write a .desktop file for this application.
30 @param iface: the program being added
31 @param icon_path: the path of the icon, or None
32 @param category: the freedesktop.org menu category"""
33 tmpdir = tempfile.mkdtemp(prefix = 'zero2desktop-')
34 try:
35 desktop_name = os.path.join(tmpdir, 'zeroinstall-%s.desktop' % iface.get_name().lower().replace(os.sep, '-').replace(' ', ''))
36 desktop = open(desktop_name, 'w')
37 desktop.write(_template % {'name': iface.get_name(),
38 'comment': iface.summary,
39 '0launch': zlaunch or '0launch',
40 'iface': iface.uri,
41 'category': category})
42 if icon_path:
43 desktop.write(_icon_template % icon_path)
44 if len(iface.get_metadata(namespaces.XMLNS_IFACE, 'needs-terminal')):
45 desktop.write('Terminal=true\n')
46 desktop.close()
47 status = os.spawnlp(os.P_WAIT, 'xdg-desktop-menu', 'xdg-desktop-menu', 'install', desktop_name)
48 finally:
49 shutil.rmtree(tmpdir)
50
51 if status:
52 raise SafeException(_('Failed to run xdg-desktop-menu (error code %d)') % status)
53
55 """Search through the configured XDG datadirs looking for .desktop files created by L{add_to_menu}.
56 @return: a map from application URIs to .desktop filenames"""
57 already_installed = {}
58 for d in basedir.load_data_paths('applications'):
59 for desktop_file in os.listdir(d):
60 if desktop_file.startswith('zeroinstall-') and desktop_file.endswith('.desktop'):
61 full = os.path.join(d, desktop_file)
62 try:
63 with open(full, 'rt') as stream:
64 for line in stream:
65 line = line.strip()
66 if line.startswith('Exec=0launch '):
67 bits = line.split(' -- ', 1)
68 if ' ' in bits[0]:
69 uri = bits[0].split(' ', 1)[1]
70 else:
71 uri = bits[1].split(' ', 1)[0].strip()
72 already_installed[uri] = full
73 break
74 else:
75 logger.info(_("Failed to find Exec line in %s"), full)
76 except Exception as ex:
77 logger.warning(_("Failed to load .desktop file %(filename)s: %(exceptions"), {'filename': full, 'exception': ex})
78 return already_installed
79