== App Developer Week -- Unity: Integrating with Launcher and Places -- kamstrup -- Wed, Apr 13th, 2011 == {{{#!irc [21:02] <kamstrup> Hi all! [21:02] <kamstrup> So I guess I am up now [21:02] <kamstrup> My name is Mikkel Kamstrup Erlandsen and i work for Canonical on the DX team [21:02] <kamstrup> In my spare time I also dabble with software, namely Zeitgeist and search engines [21:03] <kamstrup> On the DX team I am working on all the backend and infrastructure stuff [21:03] <kamstrup> so not so much all the fancy graphics you see in Unity [21:03] <kamstrup> but all that goes on beneath it :-) [21:03] <kamstrup> In particular relevant for this session libunity [21:04] <kamstrup> libunity is a library with the purpose of instrumenting and integrating with Unity [21:04] <kamstrup> For the Natty cycle you'll be able to integrate with the Launcher and the Places/Lenses [21:05] <kamstrup> (btw for this session I'll call it Places - but in the Oneriric cycle we'll officially change to Lenses) [21:05] <kamstrup> (it's just that "places" is in my muscle memory right now :-)) [21:05] <kamstrup> One big caveat emptor before we proceed too far [21:06] <kamstrup> libunity does not currently have API or ABI stability guarantees [21:06] <kamstrup> we will work on that - promised - but we also want to ensure that the API is really really nice before we freeze it [21:06] <kamstrup> and in fact [21:06] <kamstrup> I can already guarantee that there will be slight changes when we begin the Oneiric cycle [21:07] <kamstrup> but that said [21:07] <kamstrup> You can already take libunity for a spin and do some pretty impressive stuff with it [21:07] <kamstrup> fx. both the Apps and Files places are implemented with libunity [21:07] <kamstrup> there's no "priviledged" Unity API for those two buggers [21:08] <kamstrup> anyone here will be able to do exactly what they do [21:08] <kamstrup> Before we start talking about the places let's talk about the Launcher integration [21:08] <kamstrup> The Launcher integration is a lot simpler than the places [21:09] <kamstrup> So enough with the intro talk [21:09] <kamstrup> -------------------- [21:09] <kamstrup> The Unity Launcher [21:09] <kamstrup> The simplest way you can integrate with the launcher is via what is called "static quicklists" [21:09] <kamstrup> https://wiki.ubuntu.com/Unity/LauncherAPI#Static%20Quicklist%20entries [21:10] <kamstrup> If you follow that link you'll see a snippet from a normal .desktop file [21:10] <kamstrup> If you take a normal .desktop file and add [Foo Shortcut Group] entries to it like shown [21:10] <kamstrup> you can add quicklist right there [21:11] <kamstrup> Look at your own /usr/share/applications/evolution.desktop for a live example [21:12] <kamstrup> What static quicklist elements can basically do is launch an executable [21:12] <kamstrup> so very simple [21:12] <kamstrup> no programming required [21:12] <kamstrup> If you want to get a bit more power [21:12] <kamstrup> you need to use libunity [21:13] <kamstrup> More specifically the LauncherEntry API [21:13] <kamstrup> For the sake of the examples we'll use Python examples today, but you can also code in Vala, C [21:13] <kamstrup> (or C++ if you manually write the C calls out) [21:14] <kamstrup> You'll see the API here http://developer.ubuntu.com/api/ubuntu-11.04/GIR/python/Unity-3.0.html#Unity.LauncherEntry [21:14] <kamstrup> it may deserve mention that we are starting to push up Python docs for the libs generated via GObject Introspection to http://developer.ubuntu.com/api/ [21:14] <kamstrup> Anyway [21:15] <kamstrup> Looking at the LauncherEntry docs you'll see that it only has static constructors - not conventional constructors [21:15] <kamstrup> that's because you always get a "singleton" back for the particular app [21:15] <kamstrup> Let me find an example [21:16] <kamstrup> Here http://bazaar.launchpad.net/~unity-team/libunity/trunk/view/head:/examples/launcher.py [21:16] <kamstrup> You can set 3 main properties on the launcher entry [21:16] <kamstrup> A "count" that will be displayed as a number on the top part of the tile [21:17] <kamstrup> you may have seen this on apps like Evolution displaying the number of unread mails this way [21:17] <kamstrup> Then you can add a progress bar [21:17] <kamstrup> the values for progress must be between 0 and 1 [21:17] <kamstrup> (and it's a float) [21:17] <kamstrup> You can also set the urgency hint [21:18] <kamstrup> Some may know that an "urgency hint" is something you normally have on X11 windows [21:18] <kamstrup> it makes the WM flash the window icon [21:18] <kamstrup> the difference here is that the libunity urgency doesn't require a window on the screen in order to mark an app as requiring attention [21:19] <kamstrup> this can be useful for background processes like Ubuntu One or others that need to draw your attention to their icon when they don't have a window on screen somewhere [21:20] <kamstrup> The last part of the LauncherEntry API is that you can set a "dynamic quicklist" [21:20] <kamstrup> The dynamic quicklists differ from the static ones in that you can build and update them programmatically at runtime [21:21] <kamstrup> You simply have access to a libdbusmenu DbusmenuMenuItem instance that you can populate how you like [21:21] <kamstrup> ok [21:21] <kamstrup> any questions on the laucnher api before we move on? [21:22] <kamstrup> ------------ [21:22] <kamstrup> so now to Places [21:22] <kamstrup> As said before the situation here is slightly regretable [21:22] <kamstrup> It's known both as Lenses and Places in Natty [21:23] <kamstrup> For Oneiric we'll change to Lenses only [21:23] <kamstrup> (also in the all the public APIs) [21:23] <kamstrup> but for now let me call them Places [21:23] <kamstrup> Places run outside the core Unity process [21:24] <kamstrup> Think of them very much like remote database that provides data for Unity to render [21:24] <kamstrup> if you've worked with modern web development frameworks or MVC in UIs think that the place provides the *model* and Unity is a generic View [21:25] <kamstrup> Of course we have the standard Apps and Files places [21:25] <kamstrup> they are not very good beginner examples unfortunately [21:25] <kamstrup> but there are a few simple examples to start from that lots of ppl have found instructive [21:25] <kamstrup> If we stick to the Python example again [21:26] <kamstrup> you can check it out from lp:~unity-team/unity-place-sample/unity-place-python [21:26] <kamstrup> or for now just browse it online at http://bazaar.launchpad.net/~unity-team/unity-place-sample/unity-place-python/files [21:27] <kamstrup> First look at python.place [21:27] <kamstrup> All places register themselves to unity via a .place file [21:27] <kamstrup> installed under /usr/share/unity/places [21:27] <kamstrup> in a .place file you specify some contact info for Unity to find you on dbus [21:28] <kamstrup> Then each place has one or more PlaceEntries [21:28] <kamstrup> A placeentry is prettymuch what maps to an icon in the launcher [21:28] <kamstrup> You'll probably have the Apps and Files entries in your launcher at the bottom [21:29] <kamstrup> For each entry you want to expose from your place's process you need a [Entry:Foo] line in the .place file [21:29] <kamstrup> The only place that actually has more than one place entry is the Apps place [21:30] <kamstrup> although the second one is hidden [21:30] <kamstrup> Try looking at /usr/share/unity/places/applications.place [21:30] <kamstrup> you'll see that [Entry:Runner] has ShowEntry=false and ShowGlobal=false [21:31] <kamstrup> First ShowEntry=false tells unity to not put a tile in the launcher bar for this place entry [21:31] <kamstrup> the ShowGlobal=false clause tells Unity to not include this entry's results when searching from the Dash [21:31] <kamstrup> aka home screen [21:31] <kamstrup> (the one you get when you hit <super>) [21:32] <kamstrup> There is in fact a spec for these .place files [21:32] <kamstrup> Check https://wiki.ubuntu.com/Unity/Lenses#Registration [21:32] <kamstrup> You'll also note that you can define a keyboard shortcut for you place [21:33] <kamstrup> And now we're talking about this [21:33] <kamstrup> A general best-practice is to *not* include your search results in the Dash [21:33] <kamstrup> that is please set ShowGlobal=false [21:34] <kamstrup> When I write my code I am as excited as anyone to get people using it [21:34] <kamstrup> but people really want a fast Dash [21:34] <kamstrup> and if we have Dash searches laucnhing off 3 http requests, 5 disk searches, and whatnot for each letter typed... [21:34] <kamstrup> so if you want to integrate with the Dash results make sure your results are: [21:35] <kamstrup> 1) almost always relevant [21:35] <kamstrup> 2) Super snappy [21:35] <kamstrup> 3) Doesn't use to many resources to compute [21:35] <kamstrup> and 1) is probably the key point [21:35] <kamstrup> So most places would just have their tile in the launcher and a keyboard shortcut [21:36] <kamstrup> Ok back to the code [21:36] <kamstrup> In the .place file you specify the dbus contact details for your place daemon [21:36] <kamstrup> this means that Unity will start your daemon via dbus activation [21:37] <kamstrup> no need to start it yourself on login or anything [21:37] <kamstrup> this way unity has a chance of not starting all daemons at once when you log in [21:37] <kamstrup> which would run the risk of hogging your disk [21:38] <kamstrup> ok [21:38] <kamstrup> now look at http://bazaar.launchpad.net/~unity-team/unity-place-sample/unity-place-python/view/head:/unity-place-python.py [21:38] <kamstrup> This is the code for the sample place daemon [21:38] <kamstrup> There are 3 concepts you need to know about when writing a place dameon [21:38] <kamstrup> that is 1) results 2) groups 3) sections [21:39] <kamstrup> each of these three have a Dee.Model associated with them [21:39] <kamstrup> Dee.Model is implement by a library called libdee which we use for almost all of the data sharing behind Unity [21:39] <kamstrup> Dee.Model is like a table that is shared between multiple processes [21:40] <kamstrup> if any one changes, adds, or removes from the model all the other processes watching that model will be notified of what's changed [21:40] <kamstrup> pretty powerful stuff [21:40] <kamstrup> this allows us to do a kind of "distributed MVC" [21:41] <kamstrup> so in one we have the place daemon that updates the results Dee.Model and Unity is watching that same model, updating the View whenever it changes [21:41] <kamstrup> So obviously the results_model contains all the search results [21:41] <kamstrup> then we have a sections_model [21:42] <kamstrup> the sections partition the results into disjoint logical components [21:42] <kamstrup> A sections should represent a "browsable" subset of the result space [21:42] <kamstrup> If you consider the space of all apps then the sections could be Video, Audio, Games, Office [21:42] <kamstrup> etc [21:43] <kamstrup> The sections contribute the elements of the dropdown embedded in the search bar [21:43] <kamstrup> you can also access the sections of a place via the right-click context menu on a place entry in the laucncher [21:43] <kamstrup> then there a groups [21:44] <kamstrup> the groups partition the visible result set into meaning subgroups [21:44] <kamstrup> If you are watching all hits from a file search the groups could be Today, Yesterdat, Last Week, Last Month, ... etc [21:45] <kamstrup> the groups_model and results_model both have a _global_ counterparts [21:46] <kamstrup> the global models are the ones used for searching from the dash [21:46] <kamstrup> (so you normally don't need those) [21:46] <kamstrup> btw [21:46] <kamstrup> the API docs for Dee.Model are here http://developer.ubuntu.com/api/ubuntu-11.04/GIR/python/Dee-0.5.html#Dee.Model [21:46] <kamstrup> The API docs for Dee are not fully true though [21:47] <kamstrup> it has been augmented with some Python sweetness [21:48] <kamstrup> There is currenlty no easy way to document this Python magic, but you can find a demo of the Python magic for Dee.Model here http://bazaar.launchpad.net/~unity-team/dee/trunk/view/head:/examples/pythontricks.py [21:49] <kamstrup> You can also find the docs for what exactly the columns are in all the different models on https://wiki.ubuntu.com/Unity/Lenses#Results%20Model [21:49] <kamstrup> One last thing I want to mention is "Activation" [21:50] <kamstrup> So places require special callbacks when activating some special results [21:50] <kamstrup> Fx. [21:50] <kamstrup> the apps place returns Apps Available for Download that open in the Software Center when you click the,m [21:50] <kamstrup> this is achieved via the Activation API [21:51] <kamstrup> you basically register a handler for a regex matching URIs or mimetypes [21:51] <ClassBot> There are 10 minutes remaining in the current session. [21:51] <kamstrup> then when unity tries to laucnh a it it looks for any places registered for launchoing that hit [21:51] <kamstrup> and does a Dbus callback to the place daemon giving it the URI to activate [21:52] <kamstrup> the place daemon then responds whether Unity should hide the Dash as a response or if the Dash should still be shown [21:52] <kamstrup> in case for Apps Availabale for Download we ask Unity to hide the dash [21:52] <kamstrup> (so we can load S-C) [21:53] <kamstrup> but if we fx. wanted to implemen [21:53] <kamstrup> implement [21:53] <kamstrup> a file browser fx [21:53] <kamstrup> then we could ask unity to keep the dash on screen, and then just clear our results_model and repopulate it with the contents of the clicked directory [21:54] <kamstrup> I guess I'll leave the rest for your own exploration [21:54] <kamstrup> So if anyone has questions don't hold back [21:55] <kamstrup> if that's not the case then let me take 2 minutes to talk about "renderers" [21:56] <kamstrup> if you browse https://wiki.ubuntu.com/Unity/Lenses#Renderers [21:56] <kamstrup> you'll see that we have a concept called renderers which you can specify in various places in the API [21:56] <ClassBot> There are 5 minutes remaining in the current session. [21:57] <ClassBot> tronda asked: How much focus is the Python based API getting? [21:57] <kamstrup> Almost as much as the C/Vala API [21:58] <kamstrup> we really want it to be a 1st class experience [21:58] <kamstrup> and honestly i almost think that the Python API is better than the Vala/C api right now :-O) [21:58] <ClassBot> tronda asked: Any plans to get browser to work with the libunity for web applications? [21:59] <kamstrup> not short term [21:59] <kamstrup> there are some far out plans, but nothing to hold your breath for :-) [21:59] <ClassBot> tronda asked: If working with a web service which is potentially slow - would one use Tracker/Zeitgest to index content. Any help from Unity to make this simpler? [22:00] <kamstrup> Because the place daemon is another process than Unity it's not super critical if web services are slow [22:00] <kamstrup> so I'd say "don't worry in most cases" [22:01] <ClassBot> alecu asked: when a lens adds item, I see that it can add a url to get the item picture from it, like the books lens does with book covers. Will this be standard? [22:01] <kamstrup> yes, yes it will [22:01] <kamstrup> i believe that you can simply insert a URL as icon and Unity will try and load it }}}