== Dev Week -- Rocking Out with libunity -- kamstrup -- Wed, Mar 2nd, 2011 == {{{#!irc [20:02] Hi all, so I guess I'm next one up... [20:02] And thanks to Terence Simpson for the cool talk [20:02] I am Mikkel Kamstrup Erlandsen [20:02] and I work on the DX team for Canonical [20:03] I am working on the backend side of all things unity [20:03] My work is primarily around the "places" [20:03] and in my spare time I hack on Zeitgeist [20:04] so its all searching and backend code for me :-) [20:04] So for today [20:04] It's about libunity [20:04] Here's what I plan to go over: [20:04] - libunity background [20:04] - libunity feature set [20:04] - the unity launcher integration [20:05] - the unity places integration [20:05] - some working examples of ^^ [20:05] - and finally a bit about what you can expect for the future of libunity [20:05] Hopefully this should empower you all to go out and rock the world with awesome unity integration [20:06] So first item on the agenda: About libunity [20:06] It's a native library written in Vala [20:06] We use Vala to generate GObject Introspection files so we can have automagic bings for Python and friends [20:07] It's important to underline that libunity is strictly a client side library [20:07] that is [20:07] Unity itself does *not* link to it [20:07] We focus on making the API simple and fun [20:07] So we've chosen to very "property based" [20:08] so you get access to a bunch of object on which you set properties [20:08] and that is automatically reflect on unity [20:08] all of the communication it does is pretty much DBus [20:08] and it leverages libdbusmenu and libdee [20:08] to perform some of the more complex dbus-stuff [20:09] Now let's move on to talk about the feature set of libunity [20:09] Right now there are 2 main things supportedd [20:09] - the launcher inetgration [20:10] - with progress, counter, emblems, and quicklist attached to application tiles in the launcher [20:10] - and then place inetgration [20:10] - which allows you to hook into the place framework and write you own places [20:11] Maybe some of you already saw the wiki page about the launccher API: https://wiki.ubuntu.com/Unity/LauncherAPI [20:11] let's slowly step through it [20:11] looking at the first screenshot [20:12] you'll see the progress bar and counter in action [20:12] and the screenie below is a quicklist [20:12] So if you scroll down to the Vala example [20:12] you can see it's all property based [20:13] all of the attributes has a _visible cousin [20:13] like emblem_visible [20:13] these allow you to keep the state of you variables around [20:13] by just hiding the overlay [20:14] there is one thing worth mentioning here [20:14] it is that the quicklists are not 100% wired up on the unity side yet [20:14] there are 2 ways to write quicklists [20:14] "static quicklists" are there even when your app is not running [20:15] these are defined inside the .desktop files for the apps [20:15] then there are "dyanmic quicklists" [20:15] dynamic [20:15] these are created at runtime by your app [20:15] and can be very funky [20:15] they use the Dbusmenu API which some of you may already know from the indicators [20:16] it's a powerful api that let's you create arbitrarily complex menus [20:16] if you want to compile the vala example you'll need the very latest libunity from the archives [20:17] that would be 3.4.6 i believe [20:17] if you run the example as is, you'll need to start evolution before you run the example [20:18] if you want to use the python example [20:18] make sure you have the packages: [20:18] gir1.2-unity-3.0 [20:18] gir1.2-dee-0.5 [20:18] so i hope you don't have trouble running that if you try [20:19] don't hesitate to ask if you have trouble [20:19] chances are that 50% of the other people here have the same problem [20:19] Ok, that was hopefully pretty light [20:19] The next thing we'll look at is the places [20:20] as you may expect that's more complex [20:20] There is a wiki page which gives a rought overview of the places architecture: https://wiki.ubuntu.com/Unity/Places === photerran is now known as lz0 [20:20] it probably can't stand for itself though [20:21] The first thing unity will look for when integrating with a place is a ".place file" [20:21] The .place files define the basic access point for your place [20:22] It's a standard .ini or .desktop format what ever we call it [20:22] [Place] [20:22] DBusName=Well known bus name the place can be found under [20:22] DBusObjectPath=DBus object path the place object lives at [20:22] This is the main section [20:22] defining the dbus name and dbus object path your place can be found on [20:22] doing it like this allows you to have more than one place inside the same process [20:22] although noone is doing that right now === marnux_ is now known as marnux [20:23] A "place" consist of a set of "place entries" [20:23] A place in itself has no icon in the launcher - it's just a container for place entries [20:23] For each Place Entry you implement there will be one icon in the launcher [20:23] (or you can hide it if you want) [20:24] So in the .place files you specify each of the place entries you expose [20:24] It can look like: [20:24] [Entry:Stuff] [20:24] DBusObjectPath=DBus path for the place entry (must be a direct child of Places' DBusPath) [20:24] Icon=Icon for the place entry [20:24] Name=Display name for the entry [20:24] Description=Short description of what the entry provides. Suitable for display as tooltip or other [20:24] ShowGlobal=True|False (defaults to True) [20:24] ShowEntry=True|False (defaults to True) [20:24] In theory Unity could just as well look all this up over DBus once it has your address from the main [Place] group in the .place file [20:25] but [20:25] having it in the .place file allows unity to put icons on screen even before you place has started up [20:25] so this is good for startup time [20:25] So going over the [Entry:Stuff] [20:25] There is another dbus path for the place entry itself [20:26] And you can assign an icon, name, and description [20:26] ShowGlobal tells unity whether or not this entry has search result to show in the Dash [20:26] Dash - aka the homescreen [20:26] you get when you click the ubuntu button in the top left corner [20:27] so setting ShowGlobal=False will make unity not call you when it needs to update the results for the Dash [20:27] Likewise the SHowEntry [20:27] it determines whether you have a tile in the Launcher on the right [20:28] You can check out your current .place files in /usr/share/unity/places [20:28] You'll also notice a "Shortcut" entry in the .place files you have [20:28] It defines the letter you need to press in combo with to bring up the dash showing your particular place [20:29] And you'll also notice [20:29] that since the groups in the .place file are formatted like [Entry:NameOfEntry] === mrjazzcat-lunch is now known as mrjazzcat [20:29] You can define more than one entry per .place file [20:29] so far so good - given a .place file unity can now find you [20:30] so before we proceed I need to talk to you about how unity shares datamodels with the place daemons [20:30] There is a central library called Dee (or libdee if you will) [20:31] Dee implements a set of datamodels you can share across dbus [20:31] And they are like peer-2-peer models [20:31] So both unity and the place daemon can modify the models [20:31] although in practice it's mostly just the place daemons [20:32] This makes implement searching and all that very convenient [20:32] So when you search (fx. with Zzeitgeist) you don't have to collect a result set an send it to unity [20:32] you simply update your model [20:32] this gives a neat way to implement "incremental searches" if you want [20:33] meaning - iteratively removing hits from the result set as the user types [20:33] so we don't have to send the entire result set over and over [20:33] you just update your model removing the rows that no longer match [20:33] under the hood Dee basically sends a "diff" to all the peers sharing the model [20:34] So Dee is very powerful [20:34] If we go back to the wiki page... [20:34] https://wiki.ubuntu.com/Unity/Places [20:35] We need to establish the "terminology" on the top of the page [20:35] There are three words you need to know the meaning of: [20:35] - result model [20:35] - groups model [20:35] - sections model [20:36] It's probably easiest if we take the Apps place as an example [20:36] The "result model" here is (surprise!) what you see when you search [20:36] The "groups model" defines the user visible grouping of the result model [20:36] If you open the apps place [20:37] (super-a) [20:37] You'll see two groups there [20:37] or wait - maybe you don't just yet [20:37] ... sorry [20:37] But there are 3 groups - let me write them for you [20:37] Installed [20:37] Available for Install [20:37] and Most Popular Apps [20:38] These partition the result set in 3 [20:38] So on to the "sections" [20:38] Sections in the apps place are like "Accesories", "Media", "System", ... [20:38] Ie they partition not the result set, but more the "browsable space" [20:38] or the entire set of items you can potentially find [20:39] I think it'll be most easy for all if I spring my surprise now [20:39] So the surprise is that just today I have a fully working stack supporting place daemon implementations in Python! [20:40] This makes playing around with this stuff so much easier [20:40] So let me point you to a fully working place implemented in Python [20:41] Here: http://bazaar.launchpad.net/~unity-team/unity-place-sample/unity-place-python/files [20:41] So let's dig into unity-place-pythhon.py [20:42] Let's start at line 28 http://bazaar.launchpad.net/~unity-team/unity-place-sample/unity-place-python/view/head:/unity-place-python.py#L28 [20:42] Here we create the Place Entry i talked about [20:42] we give it some random dbus path [20:42] The models we create are all DeeSharedModels [20:43] On each of the models we need to call set_schema() [20:43] The schema *must* be like this [20:43] you can see the definitions on https://wiki.ubuntu.com/Unity/Places#Results%20Model [20:44] The "model schemas" is really just a list of GVariant or DBus signatures [20:44] one signature for each column you want to have in the model [20:44] and you can even shove arbitrarily complex variants in the schema [20:44] it works [20:44] but for unity places we only use simple types such as strings "s" and uints "u" [20:45] On line 42 [20:45] I create the sections model [20:45] i give it a bus name [20:45] which the model will use to rendevouz with other models with the same name [20:45] and sync up with them [20:45] and on line 44 i tell the place entry that i want to use this model as my sections [20:46] ditto for all the other models created in there === neversfelde_ is now known as neversfelde [20:46] notice the models with a _global in the variable names [20:46] these models will be used for searches via the Dash [20:47] while those without global_ will be used when you search dedicated within this particular place [20:47] Let's skip a bit forward an look at line 73: http://bazaar.launchpad.net/~unity-team/unity-place-sample/unity-place-python/view/head:/unity-place-python.py#L73 [20:48] here I connect to a bog standard Gobject signal from the place entry [20:48] The notify signal when the "active-search" property changes [20:48] On line 127 http://bazaar.launchpad.net/~unity-team/unity-place-sample/unity-place-python/view/head:/unity-place-python.py#L127 [20:48] you'll see the callback i connect to this signal [20:49] Here i simply figure out what the new search string is and I start updating the model [20:49] the results model that is [20:49] To keep this example simple i always just call model.clear() [20:50] the "real" places - files and apps - don't do this, but they iteratively narrow down the results_model as you type [20:50] but that's quite a lot more complex and it works very well without it [20:50] So what does this particular place do..? [20:51] There are 10 minutes remaining in the current session. [20:51] It simply just splits the search string into letters and adds a hit for each letter pointing to the wikipedia article for that letter [20:51] You can see it splits the results into different groups [20:51] ok, I need to start wrapping up [20:52] One important note: [20:52] If you want to run the Python example you need a small hack for now [20:52] because all the latest jazz isn't in the package archives just yet [20:52] The hack you need is to take this file: http://bazaar.launchpad.net/~unity-team/dee/trunk/view/head:/bindings/python/Dee.py [20:52] and then: [20:53] download it somewhere and copy it to the right location like so: [20:53] sudo cp Dee.py /usr/lib/pymodules/python2.7/gi/overrides/Dee.py [20:53] This is needed to make Dee play well with Python [20:53] With that in place you should follow the guidelines in http://bazaar.launchpad.net/~unity-team/unity-place-sample/unity-place-python/view/head:/README [20:55] We probably don't have a lot of time to debug any problems now, but if you poke at it and find problems don't hesitate to ping me on the #ayatana channel [20:55] While I'm throwing links around - the most basic Vala example is lp:unity-place-sample [20:56] but you can dig in and find an example a tad more complex - doing youtube searches [20:56] There are 5 minutes remaining in the current session. [20:56] You can see the list of example places here https://code.launchpad.net/unity-place-sample [20:56] I'll try and put all illustrative examples there [20:56] when new ones crop up [20:57] So quickly on the future of libunity: [20:57] - We'll have API docs for C, Python, and Vala up very soon [20:57] - Dee already have good docs for C in the libdee-doc package . but we'll have Vala and Python docs for it too [20:58] - the longer term goal for libunity is to be able to integrate and instrument the entire Unity shell from top to bottom [20:58] So launcher and places is just the prelimanry goodies we can deliver for Natty [20:58] For N+1 you see some nice APIs to work with the various indicators and menus [20:59] And lastly - a disclaimer [20:59] Sorry to end with that [20:59] But we can't guarantee API or ABI stability at this point [20:59] we hope there will be no landslide changes [20:59] but small changes will trickle in [21:00] but we we'll provide stability at some point [21:00] Maybe N+1 or +2 [21:00] and that's a wrap! [21:00] Any questions can go in #ayatana }}}