Merge lp:~mhr3/dockmanager/metadata-update into lp:dockmanager

Proposed by Michal Hruby
Status: Merged
Merged at revision: 32
Proposed branch: lp:~mhr3/dockmanager/metadata-update
Merge into: lp:dockmanager
Diff against target: 497 lines (+260/-74)
16 files modified
configure.ac (+4/-5)
daemon/dockmanager-daemon.vala (+188/-15)
metadata/banshee_control.py.info (+5/-4)
metadata/deluge_badge.py.info (+5/-4)
metadata/emesene_control.py.info (+5/-4)
metadata/gajim_badge.py.info (+5/-4)
metadata/gtg_menus.py.info (+5/-4)
metadata/liferea_badge.py.info (+5/-4)
metadata/open_terminal_here.py.info (+5/-4)
metadata/pidgin_control.py.info (+5/-4)
metadata/rhythmbox_control.py.info (+5/-4)
metadata/tomboy_menus.py.info (+5/-4)
metadata/transmission_badge.py.info (+5/-4)
metadata/tsclient_menus.py.info (+5/-4)
metadata/zeitgeist_journal.py.info (+4/-3)
metadata/zeitgeist_menus.py.info (+4/-3)
To merge this branch: bzr merge lp:~mhr3/dockmanager/metadata-update
Reviewer Review Type Date Requested Status
Robert Dyer (community) Needs Fixing
Review via email: mp+26745@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Robert Dyer (psybers) wrote :

First of all, your diff includes way more than what you wanted. You should fix that up.

Second, what is the point to the metadata changes? What is the format used? Is it just a true INI file format? Must we verify the section is named 'DEFAULT'? What if it isnt, do we still use it? Will we allow other sections, if so what are those?

review: Needs Fixing
Revision history for this message
Michal Hruby (mhr3) wrote :

It includes changes to the daemon which read this format, so it's related.

It's standard key-file format used everywhere (and parser for it available in glib), section name is required in keyfiles, therefore if it's not there, it's invalid. As for supporting more sections and/or keys it's easily possible when needed.

Revision history for this message
Robert Dyer (psybers) wrote :

Ok but the name of the section, is that a standard? Or are we going to just grab the first section in the file? What if there are more sections?

Revision history for this message
Michal Hruby (mhr3) wrote :

The APIs reading keyfiles usually need both group name and key name, so you shouldn't just grab the first one, anyway maybe we should use something more specific than "DEFAULT" (for example .desktop files use "DesktopEntry"), perhaps "DockmanagerHelper"?

Revision history for this message
Rico Tzschichholz (ricotz) wrote :

The new metadata-file format is fine. "DockmanagerHelper" sounds good.

lp:~mhr3/dockmanager/metadata-update updated
32. By Michal Hruby

Use DockmanagerHelper

Revision history for this message
Michal Hruby (mhr3) wrote :

Branch updated, please merge when Docky is ready to handle it.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'configure.ac'
2--- configure.ac 2010-06-02 11:27:12 +0000
3+++ configure.ac 2010-06-05 13:05:33 +0000
4@@ -13,18 +13,17 @@
5
6 dnl Bzr Revno, if release set BZR_REVNO to the release version number
7 if test -d $top_srcdir/.bzr ; then
8- BZR_REVNO=`bzr version-info --custom \
9- --template="{revno}"`
10+ BZR_REVNO=`bzr revno`
11 else
12 BZR_REVNO=0.1
13 fi
14 AC_SUBST(BZR_REVNO)
15
16-if test -d $top_srcdir/.bzr ; then
17+if test -e $top_srcdir/.version_info ; then
18+ VERSION_INFO=`cat .version_info`
19+elif test -d $top_srcdir/.bzr ; then
20 VERSION_INFO=`bzr version-info --custom \
21 --template="bzr {branch_nick} r{revno}"`
22-elif test -e $top_srcdir/.version_info ; then
23- VERSION_INFO=`cat .version_info`
24 else
25 VERSION_INFO="Release"
26 fi
27
28=== modified file 'daemon/dockmanager-daemon.vala'
29--- daemon/dockmanager-daemon.vala 2010-06-02 09:39:27 +0000
30+++ daemon/dockmanager-daemon.vala 2010-06-05 13:05:33 +0000
31@@ -24,12 +24,35 @@
32
33 namespace DockManager
34 {
35+ const string GROUP_NAME = "DockmanagerHelper";
36+
37+ public struct HelperInfo
38+ {
39+ string path;
40+ string? name;
41+ string? description;
42+ string? icon_name;
43+ string? app_name;
44+ bool app_available;
45+ }
46+
47+ private struct HelperProcessInfo
48+ {
49+ int pid;
50+ uint timer_id;
51+ }
52+
53 [DBus (name = "org.dockmanager.Daemon")]
54 public interface DaemonInterface: GLib.Object
55 {
56+ public abstract HelperInfo[] get_all_helpers () throws DBus.Error;
57+ public abstract void run_helper (string path) throws DBus.Error;
58+ public abstract void stop_helper (string path) throws DBus.Error;
59+ public abstract void restart_all () throws DBus.Error;
60 public abstract void show_preferences () throws DBus.Error;
61 public abstract void embed_preferences (int64 xid) throws DBus.Error;
62- public abstract void restart_all () throws DBus.Error;
63+
64+ public signal void helper_stopped (string path);
65 }
66
67 const string DBUS_UNIQUE_NAME = "org.dockmanager.Daemon";
68@@ -50,11 +73,14 @@
69 }
70 }
71
72- private HashTable<string, int> helpers;
73+ private HashTable<string, HelperProcessInfo?> helper_process_info;
74+ private List<HelperInfo?> all_scripts;
75
76 public HelperDaemon ()
77 {
78- helpers = new HashTable<string, int> (str_hash, str_equal);
79+ helper_process_info =
80+ new HashTable<string, HelperProcessInfo?> (str_hash, str_equal);
81+ all_scripts = new List<HelperInfo?> ();
82 }
83
84 public override void constructed ()
85@@ -92,6 +118,7 @@
86 {
87 connection.register_object ("/org/dockmanager/Daemon", this);
88
89+ this.init ();
90 this.run_helpers ();
91
92 Gtk.main ();
93@@ -107,47 +134,172 @@
94 }
95 }
96
97+ private void init ()
98+ {
99+ string[] prefixes =
100+ {
101+ Build.PKGDATADIR,
102+ Environment.get_user_data_dir () + "/dockmanager"
103+ };
104+
105+ foreach (unowned string prefix in prefixes)
106+ {
107+ string path = prefix + "/scripts";
108+ string metadata_dir = prefix + "/metadata/";
109+ var scripts_dir = DesktopAgnostic.VFS.file_new_for_path (path);
110+ if (!scripts_dir.exists ()) continue;
111+
112+ foreach (var f in scripts_dir.enumerate_children ())
113+ {
114+ var hi = HelperInfo ();
115+ hi.path = f.path;
116+ hi.app_available = true; // probably... we'll set it later
117+ all_scripts.append (hi);
118+ }
119+
120+ foreach (unowned HelperInfo? hi in all_scripts)
121+ {
122+ string metadata = metadata_dir + Path.get_basename (hi.path) + ".info";
123+ var metadata_file = DesktopAgnostic.VFS.file_new_for_path (metadata);
124+ if (!metadata_file.exists ()) continue;
125+
126+ string contents;
127+ size_t length;
128+ metadata_file.load_contents (out contents, out length);
129+
130+ var keyfile = new KeyFile ();
131+ try
132+ {
133+ keyfile.load_from_data (contents, length, KeyFileFlags.NONE);
134+ }
135+ catch (KeyFileError err)
136+ {
137+ warning ("Cannot load %s: %s", metadata, err.message);
138+ continue;
139+ }
140+
141+ try
142+ {
143+ hi.name = keyfile.get_string (GROUP_NAME, "Name");
144+ hi.description = keyfile.get_string (GROUP_NAME, "Description");
145+ }
146+ catch (KeyFileError err)
147+ {
148+ warning ("Required key missing in %s", metadata);
149+ continue;
150+ }
151+ try
152+ {
153+ hi.icon_name = keyfile.get_string (GROUP_NAME, "Icon");
154+ }
155+ catch (KeyFileError err) { }
156+ try
157+ {
158+ int status;
159+ hi.app_name = keyfile.get_string (GROUP_NAME, "AppName");
160+ Process.spawn_command_line_sync ("which " + hi.app_name, null, null,
161+ out status);
162+ hi.app_available = status == 0;
163+ }
164+ catch (GLib.Error err)
165+ {
166+ warning ("%s", err.message);
167+ }
168+ }
169+ }
170+ }
171+
172 public void run_helpers ()
173 {
174 foreach (Value v in _helper_list)
175 {
176 unowned string helper = v.get_string ();
177- int pid = run_helper (helper);
178- helpers.insert (helper, pid);
179+ run_helper (helper);
180 }
181
182- helpers.@foreach ((k, v) =>
183+ helper_process_info.@foreach ((k, v) =>
184 {
185 unowned string key = (string) k;
186- int val = (int)(long) v;
187- debug ("%s: %d", key, val);
188+ unowned HelperProcessInfo? val = (HelperProcessInfo?) v;
189+ debug ("%s: %d", key, val.pid);
190 });
191 }
192
193- public int run_helper (string uri)
194+ private int get_helper_pid (string path)
195+ {
196+ unowned HelperProcessInfo? hpi = helper_process_info.lookup (path);
197+ return hpi != null ? hpi.pid : 0;
198+ }
199+
200+ public void run_helper (string path) throws DBus.Error
201 {
202 Pid child_pid = 0;
203 string[] argv;
204
205+ if (get_helper_pid (path) != 0)
206+ {
207+ debug ("%s is already running", path);
208+ return;
209+ }
210+
211 try
212 {
213- Shell.parse_argv (uri, out argv);
214+ Shell.parse_argv (path, out argv);
215 var flags = SpawnFlags.DO_NOT_REAP_CHILD | SpawnFlags.SEARCH_PATH;
216 Process.spawn_async (null, argv, null, flags, null, out child_pid);
217- ChildWatch.add (child_pid, this.child_died);
218+ ChildWatch.add_full (Priority.DEFAULT, child_pid, (pid, status) =>
219+ {
220+ debug ("[%d] \"%s\" exitted", pid, Path.get_basename (path));
221+ unowned HelperProcessInfo? hpi = helper_process_info.lookup (path);
222+ if (hpi != null)
223+ {
224+ if (hpi.timer_id != 0)
225+ {
226+ Source.remove (hpi.timer_id);
227+ }
228+ hpi.pid = 0;
229+ hpi.timer_id = 0;
230+ }
231+ Process.close_pid (pid);
232+ helper_stopped (path);
233+ });
234 }
235 catch (GLib.Error err)
236 {
237 warning ("%s", err.message);
238- return 0;
239+ throw new DBus.Error.SPAWN_FAILED (err.message);
240 }
241
242- return (int)child_pid;
243+ unowned HelperProcessInfo? hpi = helper_process_info.lookup (path);
244+ if (hpi != null)
245+ {
246+ hpi.pid = (int) child_pid;
247+ }
248+ else
249+ {
250+ var pi = HelperProcessInfo ();
251+ pi.pid = (int) child_pid;
252+ helper_process_info.insert (path, pi);
253+ }
254 }
255
256- private void child_died (Pid pid, int status)
257+ public void stop_helper (string path) throws DBus.Error
258 {
259- debug ("[%d] died, status: %d", pid, status);
260+ int pid = get_helper_pid (path);
261+ if (pid == 0) return;
262+
263+ unowned HelperProcessInfo? hpi = helper_process_info.lookup (path);
264+ Posix.kill ((Posix.pid_t)pid, Posix.SIGTERM);
265+
266+ hpi.timer_id = Timeout.add (2000, () =>
267+ {
268+ if (hpi.pid != 0)
269+ {
270+ Posix.kill ((Posix.pid_t)hpi.pid, Posix.SIGKILL);
271+ }
272+ hpi.timer_id = 0;
273+ return false;
274+ });
275 }
276
277 public void show_preferences ()
278@@ -158,6 +310,27 @@
279 {
280 }
281
282+ public HelperInfo[] get_all_helpers ()
283+ {
284+ int i = 0;
285+
286+ HelperInfo[] helpers = new HelperInfo [all_scripts.length ()];
287+ foreach (unowned HelperInfo hi in all_scripts)
288+ {
289+ // our custom copy, dbus doesn't like NULLs
290+ helpers[i].path = hi.path;
291+ helpers[i].name = hi.name != null ? hi.name : "";
292+ helpers[i].description = hi.description != null ? hi.description : "";
293+ helpers[i].icon_name = hi.icon_name != null ? hi.icon_name : "";
294+ helpers[i].app_name = hi.app_name != null ? hi.app_name : "";
295+ helpers[i].app_available = hi.app_available;
296+
297+ i++;
298+ }
299+
300+ return helpers;
301+ }
302+
303 public void restart_all ()
304 {
305 }
306
307=== modified file 'metadata/banshee_control.py.info'
308--- metadata/banshee_control.py.info 2010-06-02 02:54:39 +0000
309+++ metadata/banshee_control.py.info 2010-06-05 13:05:33 +0000
310@@ -1,4 +1,5 @@
311-NAME="Banshee Controls"
312-DESCRIPTION="Control Banshee media playback"
313-ICON="banshee"
314-APPURI="/usr/bin/banshee"
315+[DockmanagerHelper]
316+Name=Banshee Controls
317+Description=Control Banshee media playback
318+Icon=banshee
319+AppName=banshee
320
321=== modified file 'metadata/deluge_badge.py.info'
322--- metadata/deluge_badge.py.info 2010-06-02 02:54:39 +0000
323+++ metadata/deluge_badge.py.info 2010-06-05 13:05:33 +0000
324@@ -1,4 +1,5 @@
325-NAME="Deluge"
326-DESCRIPTION="Show transfer rates"
327-ICON="deluge"
328-APPURI="/usr/bin/deluge"
329+[DockmanagerHelper]
330+Name=Deluge
331+Description=Show transfer rates
332+Icon=deluge
333+AppName=deluge
334
335=== modified file 'metadata/emesene_control.py.info'
336--- metadata/emesene_control.py.info 2010-06-02 02:54:39 +0000
337+++ metadata/emesene_control.py.info 2010-06-05 13:05:33 +0000
338@@ -1,4 +1,5 @@
339-NAME="Emesene Controls"
340-DESCRIPTION="See your message count status on Emesene"
341-ICON="emesene"
342-APPURI="/usr/bin/emesene"
343+[DockmanagerHelper]
344+Name=Emesene Controls
345+Description=See your message count status on Emesene
346+Icon=emesene
347+AppName=emesene
348
349=== modified file 'metadata/gajim_badge.py.info'
350--- metadata/gajim_badge.py.info 2010-06-02 02:54:39 +0000
351+++ metadata/gajim_badge.py.info 2010-06-05 13:05:33 +0000
352@@ -1,4 +1,5 @@
353-NAME="Gajim"
354-DESCRIPTION="Shows new messages count"
355-ICON="gajim"
356-APPURI="/usr/bin/gajim"
357+[DockmanagerHelper]
358+Name=Gajim
359+Description=Shows new messages count
360+Icon=gajim
361+AppName=gajim
362
363=== modified file 'metadata/gtg_menus.py.info'
364--- metadata/gtg_menus.py.info 2010-06-02 02:54:39 +0000
365+++ metadata/gtg_menus.py.info 2010-06-05 13:05:33 +0000
366@@ -1,4 +1,5 @@
367-NAME="Getting Things GNOME!"
368-DESCRIPTION="Access your tasks"
369-ICON="gtg"
370-APPURI="/usr/bin/gtg"
371+[DockmanagerHelper]
372+Name=Getting Things GNOME!
373+Description=Access your tasks
374+Icon=gtg
375+AppName=gtg
376
377=== modified file 'metadata/liferea_badge.py.info'
378--- metadata/liferea_badge.py.info 2010-06-02 02:54:39 +0000
379+++ metadata/liferea_badge.py.info 2010-06-05 13:05:33 +0000
380@@ -1,4 +1,5 @@
381-NAME="Liferea"
382-DESCRIPTION="Shows unread messages count"
383-ICON="liferea"
384-APPURI="/usr/bin/liferea"
385+[DockmanagerHelper]
386+Name=Liferea
387+Description=Shows unread messages count
388+Icon=liferea
389+AppName=liferea
390
391=== modified file 'metadata/open_terminal_here.py.info'
392--- metadata/open_terminal_here.py.info 2010-06-02 02:54:39 +0000
393+++ metadata/open_terminal_here.py.info 2010-06-05 13:05:33 +0000
394@@ -1,4 +1,5 @@
395-NAME="Open Terminal Here"
396-DESCRIPTION="Opens a terminal at the selected location"
397-ICON="gnome-terminal"
398-APPURI="/usr/bin/gnome-terminal"
399+[DockmanagerHelper]
400+Name=Open Terminal Here
401+Description=Opens a terminal at the selected location
402+Icon=gnome-terminal
403+AppName=gnome-terminal
404
405=== modified file 'metadata/pidgin_control.py.info'
406--- metadata/pidgin_control.py.info 2010-06-02 02:54:39 +0000
407+++ metadata/pidgin_control.py.info 2010-06-05 13:05:33 +0000
408@@ -1,4 +1,5 @@
409-NAME="Pidgin Controls"
410-DESCRIPTION="Control your availability and connectivity status on Pidgin"
411-ICON="pidgin"
412-APPURI="/usr/bin/pidgin"
413+[DockmanagerHelper]
414+Name=Pidgin Controls
415+Description=Control your availability and connectivity status on Pidgin
416+Icon=pidgin
417+AppName=pidgin
418
419=== modified file 'metadata/rhythmbox_control.py.info'
420--- metadata/rhythmbox_control.py.info 2010-06-02 02:54:39 +0000
421+++ metadata/rhythmbox_control.py.info 2010-06-05 13:05:33 +0000
422@@ -1,4 +1,5 @@
423-NAME="Rhythmbox Controls"
424-DESCRIPTION="Control Rhythmbox media playback"
425-ICON="rhythmbox"
426-APPURI="/usr/bin/rhythmbox"
427+[DockmanagerHelper]
428+Name=Rhythmbox Controls
429+Description=Control Rhythmbox media playback
430+Icon=rhythmbox
431+AppName=rhythmbox
432
433=== modified file 'metadata/tomboy_menus.py.info'
434--- metadata/tomboy_menus.py.info 2010-06-02 02:54:39 +0000
435+++ metadata/tomboy_menus.py.info 2010-06-05 13:05:33 +0000
436@@ -1,4 +1,5 @@
437-NAME="Tomboy Notes"
438-DESCRIPTION="Access your Tomboy notes"
439-ICON="tomboy"
440-APPURI="/usr/bin/tomboy"
441+[DockmanagerHelper]
442+Name=Tomboy Notes
443+Description=Access your Tomboy notes
444+Icon=tomboy
445+AppName=tomboy
446
447=== modified file 'metadata/transmission_badge.py.info'
448--- metadata/transmission_badge.py.info 2010-06-02 02:54:39 +0000
449+++ metadata/transmission_badge.py.info 2010-06-05 13:05:33 +0000
450@@ -1,4 +1,5 @@
451-NAME="Transmission"
452-DESCRIPTION="Show transfer rates"
453-ICON="transmission"
454-APPURI="/usr/bin/transmission"
455+[DockmanagerHelper]
456+Name=Transmission
457+Description=Show transfer rates
458+Icon=transmission
459+AppName=transmission
460
461=== modified file 'metadata/tsclient_menus.py.info'
462--- metadata/tsclient_menus.py.info 2010-06-02 02:54:39 +0000
463+++ metadata/tsclient_menus.py.info 2010-06-05 13:05:33 +0000
464@@ -1,4 +1,5 @@
465-NAME="Terminal Server Client"
466-DESCRIPTION="Jump directly to Terminal Server Client bookmarks"
467-ICON="tsclient"
468-APPURI="/usr/bin/tsclient"
469+[DockmanagerHelper]
470+Name=Terminal Server Client
471+Description=Jump directly to Terminal Server Client bookmarks
472+Icon=tsclient
473+AppName=tsclient
474
475=== modified file 'metadata/zeitgeist_journal.py.info'
476--- metadata/zeitgeist_journal.py.info 2010-06-02 10:08:48 +0000
477+++ metadata/zeitgeist_journal.py.info 2010-06-05 13:05:33 +0000
478@@ -1,3 +1,4 @@
479-NAME="Zeitgeist Journal"
480-DESCRIPTION="Provides a journal of all activity for the selected application supplied by Zeitgeist"
481-APPURI="/usr/bin/zeitgeist-daemon"
482+[DockmanagerHelper]
483+Name=Zeitgeist Journal
484+Description=Provides a journal of all activity for the selected application supplied by Zeitgeist
485+AppName=zeitgeist-daemon
486
487=== modified file 'metadata/zeitgeist_menus.py.info'
488--- metadata/zeitgeist_menus.py.info 2010-06-02 10:08:48 +0000
489+++ metadata/zeitgeist_menus.py.info 2010-06-05 13:05:33 +0000
490@@ -1,3 +1,4 @@
491-NAME="Zeitgeist Integration"
492-DESCRIPTION="Interfaces with Zeitgeist to supply a list of most used items for an application"
493-APPURI="/usr/bin/zeitgeist-daemon"
494+[DockmanagerHelper]
495+Name=Zeitgeist Integration
496+Description=Interfaces with Zeitgeist to supply a list of most used items for an application
497+AppName=zeitgeist-daemon

Subscribers

People subscribed via source and target branches

to status/vote changes: