Merge lp:~stolowski/unity-lens-applications/unity-lens-applications.previews into lp:unity-lens-applications

Proposed by Paweł Stołowski
Status: Merged
Approved by: Michal Hruby
Approved revision: 326
Merged at revision: 289
Proposed branch: lp:~stolowski/unity-lens-applications/unity-lens-applications.previews
Merge into: lp:unity-lens-applications
Diff against target: 1283 lines (+802/-123)
10 files modified
configure.ac (+3/-3)
src/Makefile.am (+5/-2)
src/aptd-client.vala (+97/-0)
src/daemon.vala (+365/-1)
src/launcher-client.vala (+45/-0)
src/runner.vala (+4/-4)
src/software-center-data-provider.vala (+128/-0)
src/unity-package-search.cc (+141/-103)
src/unity-package-search.h (+12/-9)
vapi/unity-package-search.vapi (+2/-1)
To merge this branch: bzr merge lp:~stolowski/unity-lens-applications/unity-lens-applications.previews
Reviewer Review Type Date Requested Status
Michal Hruby (community) Approve
Review via email: mp+118772@code.launchpad.net

Commit message

Implemented previews

Description of the change

Implemented previews. WARNING! Requires new Software-Center DBus Data Provider.

There are some formatting issues, they will be fixed in a separate review as I cleaned entire unity-package-search.cc and it would result in too much noise.

To post a comment you must log in.
Revision history for this message
Michal Hruby (mhr3) wrote :

434 + sc_data_provider = new SoftwareCenterDataProviderProxy ();

Can we cache this? It's not nice that the proxy is re-created every time.

633 + public HashTable<string, Variant> get_app_details (string appname, string pkgname)

Should be propagating the error that can happen.

637 + name = data.get ("name").get_string ();

The awesome thing about vala's get method is that it's an alias for indexing - ie. `name = data["name"].get_string ();` Doesn't that look much nicer? :)

459 + preview.add_info (new InfoHint.with_variant ("size", _("Size"), null, new GLib.Variant.int64 (sc_data_provider.size)));

Shouldn't we use the same pretty printing as in files lens?

463 + preview.add_info (new InfoHint ("price", _("Price"), null, sc_data_provider.price));

I think we shouldn't add hints if they're empty.

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

460 + string subtitle = _("Version %s").printf (sc_data_provider.version) + ", " + _("Size %s").printf (GLib.format_size (sc_data_provider.size));

Needs check for size > 0.

488 + var buy_action = new Unity.PreviewAction ("buy", _("Buy") + " " + sc_data_provider.price, null);

Noticed that the price doesn't include currency symbol (though I guess this is for mvo?)

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

701 + public abstract HashTable<string, Variant> get_app_details (string appname, string pkgname) throws IOError;

By defining dbus interfaces as throwing just IOError all other types of errors are then ignored (plus a critical is logged), we're not registering any special dbus error types, so errors from the services themselves will use IOError.UnmappedError, but standard DBusError (org.freedesktop.DBus.Error.*) - ie timeout / service unknown etc. will all get ignored.

You can either use "throws IOError, DBusError" or just "throws Error" and this won't ignore anything (of course only if there will be catch (Error) {} block)

563 + catch (IOError e)
564 + {
565 + warning ("Failed to get package details for '%s': %s", uri, e.message);
566 + }

Let's set a flag here if an error occurred and use the fallback desktop file-based app preview in that case.

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

Cool, let's get this in!

review: Approve
Revision history for this message
Unity Merger (unity-merger) wrote :

There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.

Revision history for this message
Michal Hruby (mhr3) :
review: Approve

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 2012-08-10 09:07:03 +0000
3+++ configure.ac 2012-08-16 08:33:21 +0000
4@@ -103,9 +103,9 @@
5 # look for dbus service dir
6 #############################################
7 if test "x$with_localinstall" = "xyes"; then
8- DBUSSERVICEDIR="${datadir}/dbus-1/services/"
9+ DBUSSERVICEDIR="${datadir}/dbus-1/services/"
10 else
11- DBUSSERVICEDIR=`$PKG_CONFIG --variable=session_bus_services_dir dbus-1`
12+ DBUSSERVICEDIR=`$PKG_CONFIG --variable=session_bus_services_dir dbus-1`
13 fi
14 AC_SUBST(DBUSSERVICEDIR)
15
16@@ -140,7 +140,7 @@
17
18 Prefix : ${prefix}
19 Sysconfdir : ${sysconfdir}
20-
21+
22 Local install : ${with_localinstall}
23
24 Extra CFlags : ${CPPFLAGS} $MAINTAINER_CFLAGS
25
26=== modified file 'src/Makefile.am'
27--- src/Makefile.am 2012-01-24 11:30:08 +0000
28+++ src/Makefile.am 2012-08-16 08:33:21 +0000
29@@ -19,7 +19,7 @@
30 -I$(srcdir) \
31 -g
32
33-# Note that we require the GLIB_2_22 flag for Valac because libzeitgeist
34+# Note that we require glib 2.26 because libzeitgeist
35 # expects us to use g_ptr_array_unref instead of g_ptr_array_free.
36 unity_applications_daemon_VALAFLAGS = \
37 -C \
38@@ -35,7 +35,7 @@
39 --pkg libgnome-menu \
40 --pkg unity-package-search \
41 --pkg unity-ratings-db \
42- --define=GLIB_2_22 \
43+ --target-glib=2.26 \
44 $(MAINTAINER_VALAFLAGS)
45
46 unity_package_search_libs = -lxapian -lstdc++
47@@ -54,10 +54,13 @@
48 app-watcher.vala \
49 config.vala \
50 daemon.vala \
51+ launcher-client.vala \
52 main.vala \
53 runner.vala \
54 schemas.vala \
55 utils.vala \
56+ aptd-client.vala \
57+ software-center-data-provider.vala \
58 $(NULL)
59
60 unity-package-search.o : $(srcdir)/unity-package-search.cc $(srcdir)/unity-package-search.h
61
62=== added file 'src/aptd-client.vala'
63--- src/aptd-client.vala 1970-01-01 00:00:00 +0000
64+++ src/aptd-client.vala 2012-08-16 08:33:21 +0000
65@@ -0,0 +1,97 @@
66+/*
67+ * Copyright (C) 2012 Canonical Ltd
68+ *
69+ * This program is free software: you can redistribute it and/or modify
70+ * it under the terms of the GNU General Public License version 3 as
71+ * published by the Free Software Foundation.
72+ *
73+ * This program is distributed in the hope that it will be useful,
74+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
75+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
76+ * GNU General Public License for more details.
77+ *
78+ * You should have received a copy of the GNU General Public License
79+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
80+ *
81+ * Authored by Pawel Stolowski <pawel.stolowski@canonical.com>
82+ */
83+
84+namespace Unity.ApplicationsLens {
85+
86+ static const string APTD_DBUS_NAME = "org.debian.apt";
87+ static const string APTD_DBUS_PATH = "/org/debian/apt";
88+
89+ /**
90+ * Expose a subset of org.debian.apt interfaces -- only what's needed by applications lens.
91+ */
92+ [DBus (name = "org.debian.apt")]
93+ public interface AptdService: GLib.Object
94+ {
95+ public abstract async string install_packages (string[] packages) throws IOError;
96+ public abstract async string remove_packages (string[] packages) throws IOError;
97+ public abstract async void quit () throws IOError;
98+ }
99+
100+ [DBus (name = "org.debian.apt.transaction")]
101+ public interface AptdTransactionService: GLib.Object
102+ {
103+ public abstract void run () throws IOError;
104+ public abstract void simulate () throws IOError;
105+ public abstract void cancel () throws IOError;
106+ public signal void finished (string exit_state);
107+ }
108+
109+ public class AptdProxy: GLib.Object
110+ {
111+ public void connect_to_aptd () throws IOError
112+ {
113+ _aptd_service = Bus.get_proxy_sync (BusType.SYSTEM, APTD_DBUS_NAME, APTD_DBUS_PATH);
114+ }
115+
116+ public async string install_packages (string[] packages) throws IOError
117+ {
118+ string res = yield _aptd_service.install_packages (packages);
119+ return res;
120+ }
121+
122+ public async string remove_packages (string[] packages) throws IOError
123+ {
124+ string res = yield _aptd_service.remove_packages (packages);
125+ return res;
126+ }
127+
128+ public async void quit () throws IOError
129+ {
130+ yield _aptd_service.quit ();
131+ }
132+
133+ private AptdService _aptd_service;
134+ }
135+
136+ public class AptdTransactionProxy: GLib.Object
137+ {
138+ public signal void finished (string transaction_id);
139+
140+ public void connect_to_aptd (string transaction_id) throws IOError
141+ {
142+ _aptd_service = Bus.get_proxy_sync (BusType.SYSTEM, APTD_DBUS_NAME, transaction_id);
143+ _aptd_service.finished.connect ((exit_state) =>
144+ {
145+ debug ("aptd transaction finished: %s\n", exit_state);
146+ finished (transaction_id);
147+ });
148+ }
149+
150+ public void simulate () throws IOError
151+ {
152+ _aptd_service.simulate ();
153+ }
154+
155+ public void run () throws IOError
156+ {
157+ _aptd_service.run ();
158+ }
159+
160+ private AptdTransactionService _aptd_service;
161+ }
162+}
163
164=== modified file 'src/daemon.vala'
165--- src/daemon.vala 2012-04-23 13:58:42 +0000
166+++ src/daemon.vala 2012-08-16 08:33:21 +0000
167@@ -27,6 +27,7 @@
168 namespace Unity.ApplicationsLens {
169
170 const string ICON_PATH = Config.DATADIR + "/icons/unity-icon-theme/places/svg/";
171+ const string ICON_APP_INSTALL_PATH = Config.DATADIR + "/app-install/icons";
172
173 public class Daemon : GLib.Object
174 {
175@@ -48,6 +49,28 @@
176 private Unity.Lens lens;
177 private Unity.Scope scope;
178
179+ /* Support aptd dbus interface; created when application install/remove was requested by preview action */
180+ private AptdProxy aptdclient;
181+ private AptdTransactionProxy aptd_transaction;
182+
183+ /* Maps demangled names to mangled names expected by S-C xapian DB (e.g. kde4-KCharSelect.desktop -> kde4__KCharSelect.desktop).
184+ There are very few apps that need this and we only store mappings when needed, so it takes very little memory.
185+ */
186+ private HashTable<string, string> mangled_desktop_ids;
187+
188+ /* Used for adding launcher icon on app installation from the preview */
189+ private LauncherProxy launcherservice;
190+
191+ /* Desktop file & icon name for unity-install:// install candidate displayed in last preview; we store
192+ * them here to avoid extra query for app details if app install action is activated */
193+ private string preview_installable_desktop_file;
194+ private string preview_installable_icon_file;
195+
196+ private string preview_developer_website;
197+
198+ /* SoftwareCenter data provider used for app preview details */
199+ private SoftwareCenterDataProviderProxy sc_data_provider;
200+
201 private Unity.ApplicationsLens.Runner runner;
202
203 /* Keep references to the FilterOptions for sources */
204@@ -135,6 +158,7 @@
205 build_app_menu_index ();
206
207 file_icon_cache = new HashTable<string,Icon>(str_hash, str_equal);
208+ mangled_desktop_ids = new HashTable<string, string>(str_hash, str_equal);
209
210 scope = new Unity.Scope ("/com/canonical/unity/scope/applications");
211 //scope.icon = @"$(Config.PREFIX)/share/unity/themes/applications.png";
212@@ -172,6 +196,7 @@
213 });
214
215 scope.activate_uri.connect (activate);
216+ scope.preview_uri.connect (preview);
217
218 /* Listen for changes in the installed applications */
219 AppInfoManager.get_default().changed.connect (mark_dirty);
220@@ -193,6 +218,8 @@
221 app_watcher = new AppWatcher ();
222 app_watcher.running_applications_changed.connect (mark_dirty);
223
224+ aptdclient = new AptdProxy ();
225+ launcherservice = new LauncherProxy ();
226
227 lens = new Unity.Lens ("/com/canonical/unity/lens/applications", "applications");
228 lens.search_hint = _("Search Applications");
229@@ -709,6 +736,27 @@
230 }
231 }
232
233+ /**
234+ * Find app icon in DATADIR/app-install/icons based on preview_installable_icon_file
235+ * obtained from S-C data provider.
236+ * trying all supported image extensions.
237+ */
238+ private string find_app_install_icon_path ()
239+ {
240+ string icon = @"$ICON_APP_INSTALL_PATH/$preview_installable_icon_file.";
241+
242+ foreach (string ext in image_extensions)
243+ {
244+ string path = icon + ext;
245+ if (FileUtils.test (path, FileTest.EXISTS))
246+ {
247+ return path;
248+ }
249+ }
250+ var default_icon = new ThemedIcon ("applications-other");
251+ return default_icon.to_string ();
252+ }
253+
254 public Icon find_pkg_icon (Unity.Package.PackageInfo pkginfo)
255 {
256 string desktop_id = Path.get_basename (pkginfo.desktop_file);
257@@ -791,7 +839,14 @@
258 desktop_id = desktop_id[colon_pos+1:desktop_id.length];
259 /* well it's still not real desktop_id, S-C converts slashes to "__"
260 * if the desktop file is in /usr/share/applications */
261- desktop_id = desktop_id.replace ("__", "-");
262+ string demangled_desktop_id = desktop_id.replace ("__", "-");
263+
264+ // store demangled name -> mangled name mapping
265+ if (desktop_id != demangled_desktop_id)
266+ {
267+ mangled_desktop_ids.replace (demangled_desktop_id, desktop_id);
268+ }
269+ desktop_id = demangled_desktop_id;
270 }
271
272 return desktop_id;
273@@ -927,6 +982,315 @@
274 }
275 }
276
277+ private async void call_install_packages (string package_name, out string tid) throws IOError
278+ {
279+ tid = yield aptdclient.install_packages ({package_name});
280+ }
281+
282+ private async void call_remove_packages (string package_name, out string tid) throws IOError
283+ {
284+ tid = yield aptdclient.remove_packages ({package_name});
285+ }
286+
287+ /**
288+ * Handler for free apps installation.
289+ * Triggers package installation via apt-daemon DBus service
290+ */
291+ private Unity.ActivationResponse app_preview_install (string uri)
292+ {
293+ if (uri.has_prefix ("unity-install://"))
294+ {
295+ string app = uri.substring (16); // trim "unity-install://"
296+ string[] parts = app.split ("/");
297+
298+ if (parts.length > 1)
299+ {
300+ string pkgname = parts[0];
301+ string appname = parts[1];
302+ try
303+ {
304+ aptdclient.connect_to_aptd ();
305+ }
306+ catch (IOError e)
307+ {
308+ warning ("Failed to connect to aptd: '%s'", e.message);
309+ return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED);
310+ }
311+ call_install_packages.begin (pkgname, (obj, res) =>
312+ {
313+ try {
314+ string tid;
315+ call_install_packages.end (res, out tid);
316+ debug ("transaction started: %s, pkg: %s\n", tid, pkgname);
317+ aptd_transaction = new AptdTransactionProxy ();
318+ aptd_transaction.connect_to_aptd (tid);
319+ aptd_transaction.simulate ();
320+ aptd_transaction.run ();
321+
322+ launcherservice.connect_to_launcher ();
323+ string desktop_file = preview_installable_desktop_file;
324+ string icon = find_app_install_icon_path ();
325+
326+ launcherservice.add_launcher_item_from_position (appname, icon, 0, 0, 32, desktop_file, tid);
327+ }
328+ catch (IOError e)
329+ {
330+ warning ("Package '%s' installation failed: %s", pkgname, e.message);
331+ }
332+ });
333+ }
334+ else
335+ {
336+ warning ("Bad install uri: '%s'", uri);
337+ }
338+ }
339+ else
340+ {
341+ warning ("Can't handle '%s' in app_preview_install handler", uri);
342+ return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED);
343+ }
344+ return new Unity.ActivationResponse(Unity.HandledType.HIDE_DASH);
345+ }
346+
347+ private Unity.ActivationResponse app_preview_install_commercial (string uri)
348+ {
349+ return activate (uri); //this will just launch Software-Center
350+ }
351+
352+ private Unity.ActivationResponse app_preview_buy (string uri)
353+ {
354+ return activate (uri); //this will just launch Software-Center
355+ }
356+
357+ private Unity.ActivationResponse app_preview_website (string uri)
358+ {
359+ try
360+ {
361+ AppInfo.launch_default_for_uri (preview_developer_website, null);
362+ return new Unity.ActivationResponse(Unity.HandledType.HIDE_DASH);
363+ }
364+ catch (Error e)
365+ {
366+ warning ("Failed to launch a web browser for uri '%s': '%s'", uri, e.message);
367+ }
368+ return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED);
369+ }
370+
371+ private Unity.ActivationResponse app_preview_uninstall (string uri)
372+ {
373+ if (uri.has_prefix ("application://"))
374+ {
375+ string desktopfile = uri.substring (14); // trim "application://"
376+
377+ // de-mangle desktop file names back to what S-C expects
378+ if (mangled_desktop_ids.contains (desktopfile))
379+ {
380+ desktopfile = mangled_desktop_ids.get (desktopfile);
381+ }
382+
383+ var pkginfo = pkgsearcher.get_by_desktop_file (desktopfile);
384+
385+ if (pkginfo != null && pkginfo.package_name != null)
386+ {
387+ try
388+ {
389+ aptdclient.connect_to_aptd ();
390+ }
391+ catch (IOError e)
392+ {
393+ warning ("Failed to connect to aptd: '%s'", e.message);
394+ return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED);
395+ }
396+
397+ call_remove_packages.begin (pkginfo.package_name, (obj, res) =>
398+ {
399+ try {
400+ string tid;
401+ call_remove_packages.end (res, out tid);
402+ debug ("transaction started: %s, pkg: %s\n", tid, pkginfo.package_name);
403+ aptd_transaction = new AptdTransactionProxy ();
404+ aptd_transaction.connect_to_aptd (tid);
405+ aptd_transaction.simulate ();
406+ aptd_transaction.run ();
407+ }
408+ catch (IOError e)
409+ {
410+ warning (@"Package '$(pkginfo.package_name)' removal failed: $(e.message)");
411+ }
412+ });
413+ return new Unity.ActivationResponse(Unity.HandledType.HIDE_DASH);
414+ }
415+ else
416+ {
417+ warning (@"Cannot find package info for $uri");
418+ }
419+ }
420+ warning (@"Can't handle '%s' in app_preview_uninstall handler", uri);
421+ return new Unity.ActivationResponse(Unity.HandledType.NOT_HANDLED);
422+ }
423+
424+ public Unity.Preview preview (string uri)
425+ {
426+ Unity.ApplicationPreview? preview = null;
427+
428+ string pkgname = "";
429+ string appname = "";
430+
431+ if (uri.has_prefix ("application://") || uri.has_prefix ("unity-install://"))
432+ {
433+ string desktopfile = null;
434+ if (uri.has_prefix ("application://"))
435+ {
436+ desktopfile = uri.substring (14); //remove "application://" prefix
437+
438+ // de-mangle desktop file names back to what S-C expects
439+ if (mangled_desktop_ids.contains (desktopfile))
440+ {
441+ desktopfile = mangled_desktop_ids.get (desktopfile);
442+ }
443+
444+ Unity.Package.PackageInfo pkginfo = pkgsearcher.get_by_desktop_file (desktopfile);
445+ if (pkginfo != null)
446+ {
447+ appname = pkginfo.application_name;
448+ pkgname = pkginfo.package_name;
449+ }
450+ }
451+ else // unity-install
452+ {
453+ string app = uri.substring (16); //remove "unity-install://" prefix
454+ string[] parts = app.split ("/");
455+ if (parts.length > 1)
456+ {
457+ pkgname = parts[0];
458+ appname = parts[1];
459+ }
460+ }
461+
462+ if (pkgname != "")
463+ {
464+ try {
465+ if (sc_data_provider == null)
466+ {
467+ sc_data_provider = new SoftwareCenterDataProviderProxy ();
468+ sc_data_provider.connect_to ();
469+ }
470+
471+ debug ("Requesting pkg info: %s, %s\n", pkgname, appname);
472+ sc_data_provider.get_app_details (appname, pkgname);
473+
474+ Icon icon = new GLib.ThemedIcon (sc_data_provider.icon);
475+ Icon? screenshot = null;
476+
477+ if (sc_data_provider.screenshot != null)
478+ {
479+ File scr_file = File.new_for_uri (sc_data_provider.screenshot);
480+ screenshot = new FileIcon (scr_file);
481+ }
482+
483+ string subtitle = "";
484+ if (sc_data_provider.version != "")
485+ subtitle = _("Version %s").printf (sc_data_provider.version);
486+ if (sc_data_provider.size > 0)
487+ {
488+ if (subtitle != "")
489+ subtitle += ", ";
490+ subtitle += ("Size %s").printf (GLib.format_size (sc_data_provider.size));
491+ }
492+ preview = new Unity.ApplicationPreview (sc_data_provider.name, subtitle, sc_data_provider.description, icon, screenshot);
493+ preview.license = sc_data_provider.license;
494+
495+ if (ratings !=null)
496+ {
497+ Unity.Ratings.Result result;
498+ ratings.query (pkgname, out result);
499+ preview.set_rating (result.average_rating, result.total_rating);
500+ }
501+
502+ if (sc_data_provider.hardware_requirements != "")
503+ preview.add_info (new InfoHint ("hardware-requirements", _("Hardware requirements"), null, sc_data_provider.hardware_requirements));
504+
505+ if (uri.has_prefix ("unity-install://")) // application needs to be purchased/installed
506+ {
507+ if (sc_data_provider.website != null && sc_data_provider.website != "")
508+ {
509+ preview_developer_website = sc_data_provider.website;
510+ var website_action = new Unity.PreviewAction ("website", _("Developer Site"), null);
511+ website_action.activated.connect (app_preview_website);
512+ preview.add_action (website_action);
513+ }
514+
515+ // uninstalled and not purchased before
516+ if (sc_data_provider.pkg_state == SoftwareCenterDataProviderProxy.PackageState.NEEDS_PURCHASE)
517+ {
518+ var buy_str = _("Buy");
519+ if (sc_data_provider.price != null && sc_data_provider.price != "")
520+ {
521+ buy_str += " " + sc_data_provider.price; //FIXME: implement action hints
522+ }
523+ var buy_action = new Unity.PreviewAction ("buy", buy_str, null);
524+ buy_action.activated.connect (app_preview_buy);
525+ preview.add_action (buy_action);
526+ }
527+ else // uninstalled, purchased before
528+ {
529+
530+ Unity.PreviewAction install_action = null;
531+ if (sc_data_provider.price == "")
532+ {
533+ install_action = new Unity.PreviewAction ("install", _("Free Download"), null);
534+ install_action.activated.connect (app_preview_install);
535+ }
536+ else
537+ {
538+ install_action = new Unity.PreviewAction ("install", _("Install"), null);
539+ install_action.activated.connect (app_preview_install_commercial);
540+ install_action.activated.connect (app_preview_install);
541+ }
542+ preview.add_action (install_action);
543+ }
544+ }
545+ else // application is already installed
546+ {
547+ preview.add_info (new InfoHint ("date-installed", _("Installed on"), null, sc_data_provider.installation_date));
548+ var launch_action = new Unity.PreviewAction ("launch", _("Launch"), null);
549+ preview.add_action (launch_action);
550+ var uninstall_action = new Unity.PreviewAction ("uninstall", _("Uninstall"), null);
551+ uninstall_action.activated.connect (app_preview_uninstall);
552+ preview.add_action (uninstall_action);
553+ }
554+
555+ preview_installable_desktop_file = sc_data_provider.desktop_file;
556+ preview_installable_icon_file = sc_data_provider.icon;
557+ }
558+ catch (Error e)
559+ {
560+ warning ("Failed to get package details for '%s': %s", uri, e.message);
561+ preview = null;
562+ }
563+ }
564+
565+ // xapian db doesn't know this .desktop file or S-C dbus data provider fails,
566+ // fallback to DesktopAppInfo (based on installed .desktop file) if available
567+ if (preview == null && desktopfile != null)
568+ {
569+ var app_info = new DesktopAppInfo (desktopfile);
570+ if (app_info != null)
571+ {
572+ preview = new Unity.ApplicationPreview (app_info.get_display_name (), "", app_info.get_description () ?? "", app_info.get_icon (), null);
573+ var launch_action = new Unity.PreviewAction ("launch", _("Launch"), null);
574+ preview.add_action (launch_action);
575+ }
576+ }
577+
578+ if (preview == null)
579+ {
580+ warning ("No pksearcher nor desktop app info for '%s'", uri);
581+ }
582+ }
583+ return preview;
584+ }
585+
586 /**
587 * Override of the default activation handler. The apps lens daemon
588 * can handle activation of installable apps using the Software Center
589
590=== added file 'src/launcher-client.vala'
591--- src/launcher-client.vala 1970-01-01 00:00:00 +0000
592+++ src/launcher-client.vala 2012-08-16 08:33:21 +0000
593@@ -0,0 +1,45 @@
594+/*
595+ * Copyright (C) 2012 Canonical Ltd
596+ *
597+ * This program is free software: you can redistribute it and/or modify
598+ * it under the terms of the GNU General Public License version 3 as
599+ * published by the Free Software Foundation.
600+ *
601+ * This program is distributed in the hope that it will be useful,
602+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
603+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
604+ * GNU General Public License for more details.
605+ *
606+ * You should have received a copy of the GNU General Public License
607+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
608+ *
609+ * Authored by Pawel Stolowski <pawel.stolowski@canonical.com>
610+ */
611+
612+namespace Unity.ApplicationsLens {
613+
614+ static const string LAUNCHER_DBUS_NAME = "com.canonical.Unity.Launcher";
615+ static const string LAUNCHER_DBUS_PATH = "/com/canonical/Unity/Launcher";
616+
617+ [DBus (name = "com.canonical.Unity.Launcher")]
618+ public interface LauncherService: GLib.Object
619+ {
620+ public abstract async void add_launcher_item_from_position (string title, string icon, int icon_x, int icon_y, int icon_size, string desktop_file, string aptdaemon_task) throws IOError;
621+ }
622+
623+ public class LauncherProxy: GLib.Object
624+ {
625+ public void connect_to_launcher () throws IOError
626+ {
627+ _launcher_service = Bus.get_proxy_sync (BusType.SESSION, LAUNCHER_DBUS_NAME, LAUNCHER_DBUS_PATH);
628+ }
629+
630+ public async void add_launcher_item_from_position (string title, string icon, int icon_x, int icon_y, int icon_size, string desktop_file, string aptdaemon_task) throws IOError
631+ {
632+ yield _launcher_service.add_launcher_item_from_position (title, icon, icon_x, icon_y, icon_size, desktop_file, aptdaemon_task);
633+ }
634+
635+ private LauncherService _launcher_service;
636+ }
637+
638+}
639\ No newline at end of file
640
641=== modified file 'src/runner.vala'
642--- src/runner.vala 2012-04-26 07:03:41 +0000
643+++ src/runner.vala 2012-08-16 08:33:21 +0000
644@@ -201,7 +201,7 @@
645 }
646
647 try {
648- var iterator = directory.enumerate_children (FILE_ATTRIBUTE_STANDARD_NAME + "," + FILE_ATTRIBUTE_STANDARD_TYPE + "," + FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE,
649+ var iterator = directory.enumerate_children (FileAttribute.STANDARD_NAME + "," + FileAttribute.STANDARD_TYPE + "," + FileAttribute.ACCESS_CAN_EXECUTE,
650 0, null);
651 while (true)
652 {
653@@ -216,7 +216,7 @@
654 {
655 dirs_match.add (complete_path);
656 }
657- else if (subelem_info.get_attribute_boolean (FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE))
658+ else if (subelem_info.get_attribute_boolean (FileAttribute.ACCESS_CAN_EXECUTE))
659 {
660 // only include exec name if we are in the PATH
661 if (search_dirname_in_path)
662@@ -316,7 +316,7 @@
663 {
664 var dir = File.new_for_path (path_directory);
665 try {
666- var e = yield dir.enumerate_children_async (FILE_ATTRIBUTE_STANDARD_NAME + "," + FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE,
667+ var e = yield dir.enumerate_children_async (FileAttribute.STANDARD_NAME + "," + FileAttribute.ACCESS_CAN_EXECUTE,
668 0, Priority.DEFAULT, null);
669 while (true) {
670 var files = yield e.next_files_async (64, Priority.DEFAULT, null);
671@@ -324,7 +324,7 @@
672 break;
673
674 foreach (var info in files) {
675- if (info.get_attribute_boolean (FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE))
676+ if (info.get_attribute_boolean (FileAttribute.ACCESS_CAN_EXECUTE))
677 {
678 this.executables.add (info.get_name ());
679 }
680
681=== added file 'src/software-center-data-provider.vala'
682--- src/software-center-data-provider.vala 1970-01-01 00:00:00 +0000
683+++ src/software-center-data-provider.vala 2012-08-16 08:33:21 +0000
684@@ -0,0 +1,128 @@
685+/*
686+ * Copyright (C) 2012 Canonical Ltd
687+ *
688+ * This program is free software: you can redistribute it and/or modify
689+ * it under the terms of the GNU General Public License version 3 as
690+ * published by the Free Software Foundation.
691+ *
692+ * This program is distributed in the hope that it will be useful,
693+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
694+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
695+ * GNU General Public License for more details.
696+ *
697+ * You should have received a copy of the GNU General Public License
698+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
699+ *
700+ * Authored by Pawel Stolowski <pawel.stolowski@canonical.com>
701+ */
702+
703+namespace Unity.ApplicationsLens {
704+
705+ static const string SCDP_DBUS_NAME = "com.ubuntu.SoftwareCenterDataProvider";
706+ static const string SCDP_DBUS_PATH = "/com/ubuntu/SoftwareCenterDataProvider";
707+
708+ [DBus (name = "com.ubuntu.SoftwareCenterDataProvider")]
709+ public interface SoftwareCenterDataProviderService: GLib.Object
710+ {
711+ public abstract HashTable<string, Variant> get_app_details (string appname, string pkgname) throws Error;
712+ }
713+
714+ public class SoftwareCenterDataProviderProxy: GLib.Object
715+ {
716+ public enum PackageState
717+ {
718+ UNINSTALLED,
719+ INSTALLED,
720+ NEEDS_PURCHASE,
721+ UNKNOWN
722+ }
723+
724+ public string name { get; set; }
725+ public string summary { get; set; }
726+ public string description { get; set; }
727+ public string version { get; set; }
728+ public string screenshot { get; set; }
729+ public string desktop_file { get; set; }
730+ public string license { get; set; }
731+ public string icon { get; set; }
732+ public string price { get; set; }
733+ public PackageState pkg_state { get; set; }
734+ public string installation_date { get; set; }
735+ public string website { get; set; }
736+ public int64 size { get; set; }
737+ public string hardware_requirements { get; set; }
738+
739+ public SoftwareCenterDataProviderProxy ()
740+ {
741+ Bus.watch_name (BusType.SESSION, SCDP_DBUS_NAME, BusNameWatcherFlags.NONE, null, on_sc_dbus_name_vanished);
742+ }
743+
744+ public void connect_to () throws Error
745+ {
746+ _service = Bus.get_proxy_sync (BusType.SESSION, SCDP_DBUS_NAME, SCDP_DBUS_PATH);
747+ }
748+
749+ private void on_sc_dbus_name_vanished (DBusConnection conn, string name)
750+ {
751+ _service = null;
752+ }
753+
754+ public HashTable<string, Variant> get_app_details (string appname, string pkgname) throws Error
755+ {
756+ if (_service == null)
757+ connect_to ();
758+
759+ HashTable<string, Variant> data = _service.get_app_details (appname, pkgname);
760+
761+ name = data["name"].get_string ();
762+ summary = data["summary"].get_string ();
763+ description = data["description"].get_string ();
764+ version = data["version"].get_string ();
765+ desktop_file = data["desktop_file"].get_string ();
766+ license = data["license"].get_string ();
767+ icon = data["icon_file_name"].get_string ();
768+ price = data["price"].get_string ();
769+ installation_date = data["installation_date"].get_string ();
770+ website = data["website"].get_string ();
771+ hardware_requirements = data["hardware_requirements"].get_string ();
772+ size = int64.parse (data["size"].get_string ());
773+
774+ var state = data["pkg_state"].get_string ();
775+
776+ if (state == "installed")
777+ {
778+ pkg_state = PackageState.INSTALLED;
779+ }
780+ else if (state == "uninstalled")
781+ {
782+ pkg_state = PackageState.UNINSTALLED;
783+ }
784+ else if (state == "needs_purchase")
785+ {
786+ pkg_state = PackageState.NEEDS_PURCHASE;
787+ }
788+ else
789+ {
790+ pkg_state = PackageState.UNKNOWN;
791+ }
792+
793+ screenshot = null;
794+
795+ if (data.contains ("screenshots"))
796+ {
797+ var screenshot_var = data["screenshots"].get_child_value (0).lookup_value ("large_image_url", VariantType.STRING);
798+ if (screenshot_var != null)
799+ {
800+ screenshot = screenshot_var.get_string ();
801+ }
802+ }
803+ if (screenshot == null)
804+ {
805+ screenshot = "";
806+ }
807+ return data;
808+ }
809+
810+ private SoftwareCenterDataProviderService _service;
811+ }
812+}
813
814=== modified file 'src/unity-package-search.cc'
815--- src/unity-package-search.cc 2012-03-27 10:49:37 +0000
816+++ src/unity-package-search.cc 2012-08-16 08:33:21 +0000
817@@ -50,6 +50,9 @@
818 #define XAPIAN_VALUE_SUMMARY 177
819 #define XAPIAN_VALUE_ARCHIVE_CHANNEL 178
820 #define XAPIAN_VALUE_DESKTOP_FILE 179
821+#define XAPIAN_VALUE_SCREENSHOT_URLS 185
822+#define XAPIAN_VALUE_DESCRIPTION 188
823+#define XAPIAN_VALUE_VERSION_INFO 198
824
825 #include "unity-package-search.h"
826
827@@ -72,16 +75,16 @@
828 {
829 private:
830 Xapian::valueno value;
831-
832+
833 public:
834-
835+
836 LocaleKeyMaker (Xapian::valueno value)
837 {
838 this->value = value;
839 }
840-
841+
842 virtual ~LocaleKeyMaker() { }
843-
844+
845 virtual std::string operator() (const Xapian::Document &doc) const
846 {
847 string val = doc.get_value (value);
848@@ -89,21 +92,21 @@
849 string col_key_mm = col_key_c;
850 g_free (col_key_c);
851 return col_key_mm;
852- }
853+ }
854 };
855
856 /* Do generic searcher setup */
857 static void
858 init_searcher (UnityPackageSearcher *searcher)
859 {
860- // Activate Xapian CJK support
861+ // Activate Xapian CJK support
862 setenv("XAPIAN_CJK_NGRAM", "1", 1);
863
864- Xapian::Database db = *searcher->db;
865+ Xapian::Database db = *searcher->db;
866
867 // Start an enquire session
868 Xapian::Enquire *enquire = new Xapian::Enquire (db);
869- //enquire->set_sort_by_value (XAPIAN_VALUE_APPNAME, FALSE);
870+ enquire->set_sort_by_value (XAPIAN_VALUE_APPNAME, FALSE);
871 searcher->enquire = enquire;
872
873 // Make sure we respect sorting rules for the current locale
874@@ -122,7 +125,7 @@
875 query_parser->set_default_op (Xapian::Query::OP_AND);
876 query_parser->set_database (db);
877 searcher->query_parser = query_parser;
878-
879+
880 // Init random number generator from 32 lowest bits of system time
881 searcher->random = g_rand_new_with_seed (g_get_monotonic_time ());
882 }
883@@ -141,39 +144,39 @@
884 gchar *dum1, *dum2, *dum3;
885 gint i, len;
886
887- g_return_if_fail (db != NULL);
888- g_return_if_fail (indexer != NULL);
889- g_return_if_fail (item != NULL);
890-
891- switch (gmenu_tree_item_get_type (item))
892- {
893- case GMENU_TREE_ITEM_INVALID:
894- return;
895- case GMENU_TREE_ITEM_DIRECTORY:
896- /* Recurse into directory */
897- iter = gmenu_tree_directory_get_contents (GMENU_TREE_DIRECTORY (item));
898- for (; iter != NULL; iter = iter->next)
899- {
900- index_menu_item (db, indexer, GMENU_TREE_ITEM (iter->data));
901- }
902- break;
903- case GMENU_TREE_ITEM_ENTRY:
904- /* Add this entry to the index */
905- entry = GMENU_TREE_ENTRY (item);
906-
907- /* Store relevant values */
908- if (gmenu_tree_entry_get_display_name (entry))
909- doc.add_value (XAPIAN_VALUE_APPNAME,
910- gmenu_tree_entry_get_display_name (entry));
911- if (gmenu_tree_entry_get_icon (entry))
912+ g_return_if_fail (db != NULL);
913+ g_return_if_fail (indexer != NULL);
914+ g_return_if_fail (item != NULL);
915+
916+ switch (gmenu_tree_item_get_type (item))
917+ {
918+ case GMENU_TREE_ITEM_INVALID:
919+ return;
920+ case GMENU_TREE_ITEM_DIRECTORY:
921+ /* Recurse into directory */
922+ iter = gmenu_tree_directory_get_contents (GMENU_TREE_DIRECTORY (item));
923+ for (; iter != NULL; iter = iter->next)
924+ {
925+ index_menu_item (db, indexer, GMENU_TREE_ITEM (iter->data));
926+ }
927+ break;
928+ case GMENU_TREE_ITEM_ENTRY:
929+ /* Add this entry to the index */
930+ entry = GMENU_TREE_ENTRY (item);
931+
932+ /* Store relevant values */
933+ if (gmenu_tree_entry_get_display_name (entry))
934+ doc.add_value (XAPIAN_VALUE_APPNAME,
935+ gmenu_tree_entry_get_display_name (entry));
936+ if (gmenu_tree_entry_get_icon (entry))
937 doc.add_value (XAPIAN_VALUE_ICON,
938 gmenu_tree_entry_get_icon (entry));
939 if (gmenu_tree_entry_get_desktop_file_id (entry))
940 doc.add_value (XAPIAN_VALUE_DESKTOP_FILE,
941 gmenu_tree_entry_get_desktop_file_id (entry));
942-
943- /* Index full text data */
944- indexer->set_document(doc);
945+
946+ /* Index full text data */
947+ indexer->set_document(doc);
948 if (gmenu_tree_entry_get_display_name (entry))
949 {
950 dum1 = unity_applications_lens_utils_preprocess_string (
951@@ -195,56 +198,56 @@
952 indexer->index_text (dum1, 0);
953 g_free (dum1);
954 }
955-
956- /* Index the XDG categories */
957- appman = unity_app_info_manager_get_default ();
958- cats = unity_app_info_manager_get_categories (appman, // const return
959- gmenu_tree_entry_get_desktop_file_id (entry),
960- &len);
961-
962- /* Note: Wine apps and app launchers created with Alacarte commonly
963- * don't have any category metadata, so they'll only show up under
964- * All Applications */
965- for (i = 0; i < len; i++)
966- {
967- dum1 = g_ascii_strdown (cats[i], -1);
968- dum2 = g_strconcat ("AC", dum1, NULL);
969- doc.add_term (dum2);
970- g_free (dum1);
971- g_free (dum2);
972- }
973-
974- /* Index Keywords*/
975- keywords = unity_app_info_manager_get_keywords (appman, // const return
976- gmenu_tree_entry_get_desktop_file_id (entry),
977- &len);
978- for (i = 0; i < len; i++)
979- {
980+
981+ /* Index the XDG categories */
982+ appman = unity_app_info_manager_get_default ();
983+ cats = unity_app_info_manager_get_categories (appman, // const return
984+ gmenu_tree_entry_get_desktop_file_id (entry),
985+ &len);
986+
987+ /* Note: Wine apps and app launchers created with Alacarte commonly
988+ * don't have any category metadata, so they'll only show up under
989+ * All Applications */
990+ for (i = 0; i < len; i++)
991+ {
992+ dum1 = g_ascii_strdown (cats[i], -1);
993+ dum2 = g_strconcat ("AC", dum1, NULL);
994+ doc.add_term (dum2);
995+ g_free (dum1);
996+ g_free (dum2);
997+ }
998+
999+ /* Index Keywords*/
1000+ keywords = unity_app_info_manager_get_keywords (appman, // const return
1001+ gmenu_tree_entry_get_desktop_file_id (entry),
1002+ &len);
1003+ for (i = 0; i < len; i++)
1004+ {
1005 dum1 = unity_applications_lens_utils_preprocess_string (keywords[i]);
1006- indexer->index_text (dum1, 0);
1007- indexer->index_text (dum1, 0, "KW");
1008+ indexer->index_text (dum1, 0);
1009+ indexer->index_text (dum1, 0, "KW");
1010 g_free (dum1);
1011- }
1012-
1013-
1014- g_object_unref (appman);
1015-
1016- /* Always assume Type=Application for items in a menu... */
1017- doc.add_term ("ATapplication");
1018-
1019- /* Index application names */
1020- dum1 = (gchar *) gmenu_tree_entry_get_display_name (entry); // const
1021- dum2 = g_strconcat ("AA", dum1, NULL);
1022+ }
1023+
1024+
1025+ g_object_unref (appman);
1026+
1027+ /* Always assume Type=Application for items in a menu... */
1028+ doc.add_term ("ATapplication");
1029+
1030+ /* Index application names */
1031+ dum1 = (gchar *) gmenu_tree_entry_get_display_name (entry); // const
1032+ dum2 = g_strconcat ("AA", dum1, NULL);
1033 doc.add_term (dum2);
1034 g_free (dum2);
1035-
1036+
1037 dum1 = (gchar *) gmenu_tree_entry_get_name (entry); // const
1038- dum2 = g_strconcat ("AA", dum1, NULL);
1039+ dum2 = g_strconcat ("AA", dum1, NULL);
1040 doc.add_term (dum2);
1041 g_free (dum2);
1042
1043 /* Index executable name, change - in _ for exec */
1044- dum1 = g_strdup (gmenu_tree_entry_get_exec (entry)); // alloc
1045+ dum1 = g_strdup (gmenu_tree_entry_get_exec (entry)); // alloc
1046 if (dum1) {
1047 dum2 = strstr (dum1, " "); // const
1048 dum2 == NULL ? : *dum2 = '\0'; // const
1049@@ -256,25 +259,25 @@
1050 doc.add_term (dum2);
1051 g_free (dum2);
1052 dum2 = g_strconcat ("XX", dum1, NULL); // alloc
1053- doc.add_term (dum2);
1054+ doc.add_term (dum2);
1055 g_free (dum2);
1056- g_free (dum1);
1057- }
1058-
1059+ g_free (dum1);
1060+ }
1061+
1062 db->add_document(doc);
1063- break;
1064- case GMENU_TREE_ITEM_SEPARATOR:
1065- case GMENU_TREE_ITEM_HEADER:
1066- case GMENU_TREE_ITEM_ALIAS:
1067- break;
1068- default:
1069- g_warning ("Unexpected GMenuTreeItemType %u",
1070- gmenu_tree_item_get_type (item));
1071- return;
1072+ break;
1073+ case GMENU_TREE_ITEM_SEPARATOR:
1074+ case GMENU_TREE_ITEM_HEADER:
1075+ case GMENU_TREE_ITEM_ALIAS:
1076+ break;
1077+ default:
1078+ g_warning ("Unexpected GMenuTreeItemType %u",
1079+ gmenu_tree_item_get_type (item));
1080+ return;
1081 }
1082
1083 // Add the document to the database.
1084-
1085+
1086 }
1087
1088 /* Create a searcher that searches in a menu tree. The menu tree
1089@@ -289,16 +292,16 @@
1090 db = new Xapian::WritableDatabase ();
1091 searcher->db = db;
1092 searcher->db->add_database (Xapian::InMemory::open ());
1093-
1094+
1095 init_searcher (searcher);
1096-
1097+
1098 /* Index the menu recursively */
1099 Xapian::TermGenerator *indexer = new Xapian::TermGenerator ();
1100 index_menu_item (db, indexer,
1101 GMENU_TREE_ITEM (gmenu_tree_get_root_directory (menu)));
1102 delete indexer;
1103 db->flush ();
1104-
1105+
1106 return searcher;
1107 }
1108
1109@@ -373,13 +376,17 @@
1110 static void _free_package_info (gpointer pkg)
1111 {
1112 UnityPackageInfo *pkginfo = (UnityPackageInfo*) pkg;
1113+ unity_package_package_info_free (pkginfo);
1114+}
1115
1116+void unity_package_package_info_free (UnityPackageInfo *pkginfo)
1117+{
1118 g_free (pkginfo->package_name);
1119 g_free (pkginfo->application_name);
1120 g_free (pkginfo->desktop_file);
1121 g_free (pkginfo->icon);
1122
1123- g_slice_free (UnityPackageInfo, pkg);
1124+ g_slice_free (UnityPackageInfo, pkginfo);
1125 }
1126
1127 UnityPackageSearchResult*
1128@@ -432,7 +439,7 @@
1129 searcher->enquire->set_sort_by_relevance ();
1130 break;
1131 }
1132-
1133+
1134 result = g_slice_new0 (UnityPackageSearchResult);
1135 try
1136 {
1137@@ -470,7 +477,7 @@
1138 {
1139 g_warning ("Error running query '%s': %s", search_string, e.get_msg().c_str());
1140 }
1141-
1142+
1143 return result;
1144 }
1145
1146@@ -486,12 +493,12 @@
1147 g_return_val_if_fail (searcher != NULL, NULL);
1148
1149 result = g_slice_new0 (UnityPackageSearchResult);
1150- result->num_hits = n_apps;
1151+ result->num_hits = n_apps;
1152 lastdocid = searcher->db->get_lastdocid ();
1153-
1154+
1155 /* Since we really just pick random apps we may end up with dupes */
1156 unique = g_hash_table_new (g_str_hash, g_str_equal);
1157-
1158+
1159 /* When looking for random apps we check up to twice the number of
1160 * requested apps in order to try and avoid dupes. This is a sloppy
1161 * check, but works well enough in practice */
1162@@ -499,7 +506,7 @@
1163 {
1164 g_debug ("RANDOM");
1165 for (i = 0, n_unique = 0; i < n_apps*2, n_unique < n_apps; i++)
1166- {
1167+ {
1168 Xapian::Document doc;
1169 try
1170 {
1171@@ -566,6 +573,38 @@
1172 return result;
1173 }
1174
1175+UnityPackageInfo *
1176+unity_package_searcher_get_by_desktop_file (UnityPackageSearcher *searcher, const gchar *desktop_file)
1177+{
1178+ g_return_val_if_fail (searcher != NULL, NULL);
1179+
1180+ UnityPackageInfo *pkginfo = NULL;
1181+
1182+ Xapian::PostingIterator it = searcher->db->postlist_begin ("");
1183+ Xapian::PostingIterator end_it = searcher->db->postlist_end ("");
1184+
1185+ const string query = desktop_file;
1186+
1187+ while (it != end_it)
1188+ {
1189+ Xapian::Document doc = searcher->db->get_document (*it);
1190+ string value = doc.get_value (XAPIAN_VALUE_DESKTOP_FILE);
1191+
1192+ size_t sep = value.find (':');
1193+ if (sep != string::npos)
1194+ {
1195+ if (value.compare (sep+1, value.size() - sep, query) == 0)
1196+ {
1197+ pkginfo = _pkginfo_from_document (doc);
1198+ return pkginfo;
1199+ }
1200+ }
1201+ ++it;
1202+ }
1203+
1204+ return pkginfo;
1205+}
1206+
1207 void
1208 unity_package_search_result_free (UnityPackageSearchResult *result)
1209 {
1210@@ -574,4 +613,3 @@
1211 g_slist_free_full (result->results, _free_package_info);
1212 g_slice_free (UnityPackageSearchResult, result);
1213 }
1214-
1215
1216=== modified file 'src/unity-package-search.h'
1217--- src/unity-package-search.h 2012-03-09 17:44:30 +0000
1218+++ src/unity-package-search.h 2012-08-16 08:33:21 +0000
1219@@ -36,23 +36,23 @@
1220
1221 typedef struct
1222 {
1223- GSList *results;
1224- gint num_hits;
1225+ GSList *results;
1226+ gint num_hits;
1227 } UnityPackageSearchResult;
1228
1229 typedef struct
1230 {
1231- gchar *package_name;
1232- gchar *application_name;
1233- gchar *desktop_file;
1234- gchar *icon;
1235- gint relevancy;
1236+ gchar *package_name;
1237+ gchar *application_name;
1238+ gchar *desktop_file;
1239+ gchar *icon;
1240+ gint relevancy;
1241 } UnityPackageInfo;
1242
1243 #ifdef __cplusplus
1244 extern "C" {
1245 #endif
1246-
1247+
1248 UnityPackageSearcher* unity_package_searcher_new ();
1249
1250 UnityPackageSearcher* unity_package_searcher_new_for_menu (GMenuTree *menu);
1251@@ -71,7 +71,10 @@
1252
1253 void unity_package_search_result_free (UnityPackageSearchResult *result);
1254
1255+void unity_package_package_info_free (UnityPackageInfo *pkginfo);
1256+
1257+UnityPackageInfo* unity_package_searcher_get_by_desktop_file (UnityPackageSearcher *searcher, const gchar *desktop_file);
1258+
1259 #ifdef __cplusplus
1260 }
1261 #endif
1262-
1263
1264=== modified file 'vapi/unity-package-search.vapi'
1265--- vapi/unity-package-search.vapi 2012-03-09 17:44:30 +0000
1266+++ vapi/unity-package-search.vapi 2012-08-16 08:33:21 +0000
1267@@ -27,6 +27,7 @@
1268 public Searcher.for_menu(GMenu.Tree menu);
1269 public SearchResult search (string search_string, uint max_hits, Unity.Package.SearchType search_type, Unity.Package.Sort sort);
1270 public SearchResult get_random_apps (string? filter_query, uint n_apps);
1271+ public PackageInfo? get_by_desktop_file (string desktop_file);
1272 }
1273
1274 [Compact]
1275@@ -37,7 +38,7 @@
1276 }
1277
1278 [Compact]
1279- [CCode (cname = "UnityPackageInfo", cheader_filename = "unity-package-search.h")]
1280+ [CCode (cname = "UnityPackageInfo", free_function = "unity_package_package_info_free", cheader_filename = "unity-package-search.h")]
1281 public class PackageInfo {
1282 public string package_name;
1283 public string application_name;

Subscribers

People subscribed via source and target branches