ThunderbirdUnity

App Developer Week -- Thunderbird + Unity = Awesome, and how JSCtypes lets you get to the candy -- m_conley -- Mon, Apr 12th, 2011

   1 [21:01] <ClassBot> Logs for this session will be available at http://irclogs.ubuntu.com/2011/04/12/%23ubuntu-classroom.html following the conclusion of the session.
   2 [21:02] <m_conley> hey everybody!
   3 [21:02] <m_conley> My name is Mike Conley, and I work for Mozilla as a developer on the Thunderbird e-mail client.  I was hired about 3 months ago, so I'm still learning my way around the Thunderbird codebase, but I think I'm starting to get the hang of it.
   4 [21:02] <m_conley> I've never given one of these sessions before, so I'm just going to play it by ear.  I have my talk more or less planned, but I might run short, seeing as I don't really know how much written material fits into an hour.
   5 [21:03] <m_conley> So please, feel free to ask questions if you have any in #ubuntu-classroom-chat.  I'll try to answer as many as I can.
   6 [21:03] <m_conley> Also, let me know if I'm going too fast or too slow.  I'll adjust my speed accordingly.  :D
   7 [21:03] <m_conley> First, I'm going to talk about what I've been working on over the past few months.  Second, I'm going to show you some of the code I've written, and walk you through how it more or less works.  Then I'll try to answer any questions you all might have.
   8 [21:04] <m_conley> == INTRO ==
   9 [21:04] <m_conley> So, over the past 3 months, I've been working on ways for Thunderbird to integrate nicely into the shiny new Ubuntu Unity interface.  There are three integration points that I've been working on:
  10 [21:04] <m_conley> 1)  The Messaging Menu:  we want quick access to compose and address book functions here, as well as indications for when new messages arrive.
  11 [21:04] <m_conley> 2)  The Unity Launcher:  we want to display the number of new, unread messages overtop of the Thunderbird icon in the launcher.
  12 [21:04] <m_conley> 3)  Ubuntu One:  we want Ubuntu One contacts synchronization support baked into Thunderbird
  13 [21:05] <m_conley> For additional reading, here's a blog post discussing my work for #1 and #2, in case you want to know a little more about those projects:  http://mikeconley.ca/blog/2011/01/11/starting-work-on-mozilla-thunderbird/
  14 [21:05] <m_conley> #3 is a relatively new project, and I only mention it for buzz.  :)  I won't be covering it today.
  15 [21:06] <m_conley> #1 and #2 are the furthest along, and the ones I want to focus on today.  Extensions to integrate those features are available in Mozilla Labs for you to try if you'd like:  http://mzl.la/unitylauncher  http://mzl.la/messagingmenu .
  16 [21:06] <m_conley> Note that both require Thunderbird 3.3, and assume that you're running Ubuntu Natty.  Instructions for installing Thunderbird 3.3 are here:  http://www.liberiangeek.net/2011/03/install-latest-version-thunderbird-ubuntu-10-10-maverick-meerkat/
  17 [21:06] <m_conley> (I know the instructions are for Maverick, but they'll work in Natty too, once you get to the Software Center)
  18 [21:06] <m_conley> Before I continue, it's possible that some of you might not know what an extension for Thunderbird is made up of.  I'm going to go through that real quick.
  19 [21:07] <m_conley> == What is a Thunderbird Extension Made Of? ==
  20 [21:07] <m_conley> I'm going to blast through this.  More deep, detailed documentation is available here:  Thunderbird extensions: https://developer.mozilla.org/en/Extensions/Thunderbird
  21 [21:07] <m_conley> It might surprise you to know that large parts of Thunderbird are written in Javascript and a mark-up language called XUL (which is strikingly similar to HTML), and styled with CSS.
  22 [21:08] <m_conley> The Javascript/XUL/CSS is then executed/rendered by the C++ engine (called "Gecko"), and boom:  Thunderbird.
  23 [21:08] <m_conley> Imagine my surprise when I opened up the Thunderbird source code and saw Javascript staring back at me.  :D  Not what I expected.
  24 [21:08] <m_conley> Thunderbird extensions also use Javascript, XUL and CSS.  This means that if you have web development skills, chances are you can build a Thunderbird extension.
  25 [21:09] <m_conley> It's also possible to add C++ code to an extension to access more low-level libraries (such as libunity, or libindicate-gtk).  That's how I started with my Messaging Menu and Unity Launcher extensions - I wrote chunks of C++, and launched them from the Javascript portion of my extension.
  26 [21:09] <m_conley> As far as I knew, this was the only way to do things:  I mean, how else am I supposed to talk to C libraries from a Thunderbird extension?
  27 [21:09] <m_conley> == Introducing:  JS-Ctypes ==
  28 [21:09] <m_conley> And here is where JS-Ctypes comes in: https://developer.mozilla.org/en/js-ctypes
  29 [21:09] <m_conley> JS-Ctypes allows add-on developers to access and call C libraries from within the safety of Javascript.  And of course, this is Chrome-level Javascript - not the Javascript that is executed on webpages.
  30 [21:10] <m_conley> Don't worry - we're not letting web-site owners access system libraries here - we don't want an ActiveX fiasco. :p
  31 [21:10] <m_conley> So now I'm going to show you how I interact with the Unity Launcher.  First, note the Unity Launcher API here: https://wiki.ubuntu.com/Unity/LauncherAPI .  I used the Python example as a skeleton in order to set up the way my Javascript implementation works.
  32 [21:11] <m_conley> The basic idea is, get the launcher entry for a particular application, set properties on it (like the count), and make sure those properties are visible (set count_visible to true).  That's all it takes to get the count up on the Launcher icon.
  33 [21:11] <m_conley> So, next I'm going to show you some of the code I wrote...
  34 [21:11] <m_conley> This is UnityLauncherLib.jsm:  http://www.pastie.org/1785131
  35 [21:12] <m_conley> (Note the .jsm extension - this is a Javascript Module.  See https://developer.mozilla.org/en/JavaScript_code_modules/Using)
  36 [21:12] <m_conley> UnityLauncherLib.jsm is responsible for wrapping up all of the C library stuff for me.  The init and shutdown function do (as you've probably gathered) the set-up and teardowns for the library connection.
  37 [21:12] <m_conley> You can look at that stuff later - what I'm interested in showing you starts on line 71 (the _declare function).
  38 [21:13] <m_conley> The first thing you need to do when working with JS-Ctypes is to declare the types you're working with. Using library calls like unity_launcher_entry_get_for_desktop_file and unity_launcher_entry_set_count means manipulating UnityLauncherEntry objects.  We have to tell JS-Ctypes about those objects in order to manipulate them - the same way you'd declare a struct or class in a C++ header.
  39 [21:13] <m_conley> But that'd mean declaring every single member of every single object that we'd have to manipulate, right?
  40 [21:13] <m_conley> Wrong!
  41 [21:14] <m_conley> The good news is that, with the way the Unity Launcher API is set up, I just have to pass a pointer to a UnityLauncherEntry to various functions.  I don't need to do any direct manipulation of the UnityLauncherEntry - I just pass it around.
  42 [21:14] <m_conley> So on line 73 of http://www.pastie.org/1785131, I declare an empty StructType called UnityLauncherEntry, and then a pointer type called UnityLauncherEntryRef.  UnityLauncherEntryRef is all I'll be passing around.  I suppose I also could have also used the type ctypes.voidptr_t.  That probably would work too.
  43 [21:15] <m_conley> Ok, now I can declare the various functions I'm going to use, like unity_launcher_entry_set_count.  Line 91 is where I declare that function.
  44 [21:16] <m_conley> The structure for that declaration is: I provide the name of the function call, the type of function (we're not on Windows, so it's default_abi), the return type (void), and then the argument types (UnityLauncherEntryRef and an unsigned integer).
  45 [21:16] <m_conley> The following is then possible inside Javascript:
  46 [21:16] <m_conley> mLauncher = UnityLauncherLib.ULEntryGetForDesktopFile("/usr/share/applications/thunderbird.desktop");
  47 [21:16] <m_conley> UnityLauncherLib.ULEntrySetCount(mLauncher, 1234);
  48 [21:16] <m_conley> UnityLauncherLib.ULEntrySetCountVisible(mLauncher, true);
  49 [21:17] <m_conley> And that would display a count of 1234 overtop of the Thunderbird icon in the Unity launcher.
  50 [21:17] <m_conley> Similar manipulation can be done to show a progress bar over the Unity launcher icon.  It's easy to imagine a progress bar to show how far along inbox syncing is.
  51 [21:18] <m_conley> And that's how I can interact with things like the Unity Launcher from the safety of Javascript.
  52 [21:18] <m_conley> Any questions so far?
  53 [21:18] <m_conley> Am I going too fast?  Am I breezing past things that you all want to talk about?
  54 [21:19] <m_conley> No?
  55 [21:19] <m_conley> Ok.  :)
  56 [21:19] <m_conley> So that's an example of how I can interact with things like the Unity Launcher from the safety of Javascript.
  57 [21:20] <m_conley> So we can call C function from within Javascript - but can we call Javascript functions from C?  Yes we can!
  58 [21:20] <m_conley> When indicators in the Messaging Menu are clicked, we want a callback function to be run.  In C/C++ this is done by using g_signal_connect to connect a function to the "user-display" event for an indicator.
  59 [21:21] <m_conley> I was able to use JS-Ctypes to wrap several GObject functions, including g_signal_connect (which is actually just a macro wrapping g_signal_connect_data).  Here's the GObjectLib.jsm file:  http://www.pastie.org/1787573
  60 [21:21] <m_conley> Once again, the interesting stuff is in _declare.  On line 42, I am able to define what the structure of a callback function looks like, and I use that in the definition of GSignalConnectData.
  61 [21:22] <m_conley> So, in my Messaging Menu extension code, with my GObjectLib loaded, I'm able to do this:
  62 [21:22] <m_conley> var myCallback = function myCallback(aInstance, aTimestamp, aUserData) {
  63 [21:22] <m_conley>   alert("Hello, callback world!");
  64 [21:23] <m_conley> }
  65 [21:23] <m_conley> myCallbackFunction = GObjectLib.GCallbackFunction(myCallback);
  66 [21:23] <m_conley> GObjectLib.GSignalConnect(indicator, "user-display", myCallbackFunction, null);
  67 [21:23] <m_conley> Where "indicator" is some indicator that's been spawned using a wrapped indicate_indicator_new.  (See http://www.pastie.org/1787649)
  68 [21:24] <m_conley> Now, when that indicator is clicked, the Javascript callback will be fired, and we'll get our alert box.
  69 [21:24] <m_conley> This is pretty powerful stuff.  You get the full power of the system libraries, while staying within the managed environment of Javascript.
  70 [21:26] <m_conley> So that's how I'm using JS-Ctypes.
  71 [21:27] <m_conley> I suppose I'll talk about my work integrating with Ubuntu One next.
  72 [21:28] <m_conley> So, a bunch of you probably know this already, but Canonical offers a service called Ubuntu One
  73 [21:28] <m_conley> Among other things, Ubuntu One offers contacts synchronization support
  74 [21:30] <m_conley> Currently, Thunderbird allows users to connect to LDAP address books, and local storage address books.  On OSX, there's a system address book that we also connect to.
  75 [21:30] <m_conley> I'm working on adding an Ubuntu One Contacts address book to Thunderbird, to show the contacts that are stored via the Ubuntu One service
  76 [21:30] <m_conley> So, imagine this:
  77 [21:31] <m_conley> You've been using Thunderbird for a while now on your laptop, and you've built up quite a large address book, with all of your friends and workmates organized into their groups
  78 [21:31] <m_conley> and then you go and drop your laptop into a lake
  79 [21:32] <m_conley> Thankfully, once we've got Ubuntu One contacts support baked in, all you'd need to do is log into your Ubuntu One account on your new computer (because you'd probably get a new computer after that...)
  80 [21:32] <m_conley> magic synchronization happens, and bam:  your contacts are back in Thunderbird.
  81 [21:32] <m_conley> The other nice thing about Ubuntu One contacts, is that it's built for *sharing*
  82 [21:32] <m_conley> and by sharing, I mean, sharing between applications
  83 [21:33] <m_conley> Evolution, for example, has the option of storing contacts via the Ubuntu One contacts synchronization service
  84 [21:33] <m_conley> If you want to migrate from Evolution to Thunderbird, you just need to make sure all of your contacts are synchronized, and that's it.
  85 [21:34] <m_conley> Thunderbird will start up, find your Evolution contacts, and away you go.
  86 [21:36] <m_conley> So that's what I'm working on, for Thunderbird + Unity integration
  87 [21:37] <m_conley> Going back to JS-Ctypes - this doesn't just work in Thunderbird
  88 [21:37] <m_conley> it works in Firefox as well
  89 [21:38] <m_conley> In fact, JS-Ctypes has been shipping in Firefox for quite a while.  So, some pretty powerful extensions are now possible.
  90 [21:39] <m_conley> Imagine, for example, connecting the download manager to an Arduino via JS-Ctypes
  91 [21:39] <m_conley> You could get a big light to flash once all of your downloads are completed.
  92 [21:39] <m_conley> That's just off of the top of my head.
  93 [21:40] <m_conley> So, I guess I'll go into the declaration of types for a little bit.
  94 [21:41] <m_conley> So, JS-Ctypes wraps up the platform-specific fuzziness of types, and gives you a set of platform agnostic ones:  for example:
  95 [21:41] <m_conley> ctypes.unsigned_int is your basic unsigned integer.  Cross-plat.
  96 [21:42] <m_conley> Similarly, ctypes.unsigned_char is your basic unsigned_char.
  97 [21:42] <m_conley> You can declare entire objects with JS-Ctypes too, for example:
  98 [21:44] <m_conley> Suppose we're attempting to work with a C library that manipulates a struct called Person, with a Name and an Age
  99 [21:44] <m_conley> we can define this using:
 100 [21:44] <m_conley> var Person = new ctypes.StructType("Person", [{'name': ctypes.unsigned_char.ptr}, {'age': ctypes.unsigned_int}]);
 101 [21:45] <m_conley> We could then pass that structure to the library, and it'll treat it just like it would if it was called from C or C++
 102 [21:46] <m_conley> Of course, once we start dealing C / C++ libraries, we get back into the issue of memory management
 103 [21:46] <m_conley> In my Indicator library, for example, I create indicators using indicate_indicator_new
 104 [21:47] <m_conley> After instantiation, I'm responsible for freeing that memory.  I therefore had to wrap g_object_unref in my GObjectLib
 105 [21:48] <m_conley> and it works as you'd expect - I pass it a pointer to something I've allocated for (using the handy ctypes.voidptr_t - which is the equivalent of void *), and it'll do the rest.
 106 [21:48] <m_conley> It's also important to close the connections to the libraries once you're finished with them
 107 [21:49] <m_conley> For example, if I open up libgobject, like so:  lib = ctypes.open("libgobject-2.0.so"), I have to close it via lib.close().
 108 [21:49] <m_conley> It's again worth emphasizing that JS-Ctypes is cross-platform.  That means that you can connect to Windows libraries and OSX libraries as well.
 109 [21:50] <m_conley> I don't use OSX myself, and I don't imagine most of you either (this *is* #ubuntu-classroom afterall), but I thought this was kind of neat:
 110 [21:50] <m_conley> https://developer.mozilla.org/en/js-ctypes/Examples/Add_to_iPhoto
 111 [21:51] <m_conley> This example is for a Firefox extension that adds a context menu item to images
 112 [21:51] <ClassBot> There are 10 minutes remaining in the current session.
 113 [21:51] <m_conley> The extension makes it so that right clicking on an image gives you the option to send that image directly to the built in photo program.
 114 [21:52] <m_conley> Something similar could be done with F-Spot, for example - though you might not need JS-Ctypes to do it.  I'm not familiar enough with the F-Spot API (if it has one) to say for certain.
 115 [21:53] <m_conley> So that's my talk.  I'll stick around for the next 10 minutes to answer any questions you might have.  Thanks for listening/reading!
 116 [21:56] <ClassBot> There are 5 minutes remaining in the current session.
 117 [21:59] <m_conley> Alright, I'll assume there aren't any questions.  Thanks for listening everyone!  Enjoy the rest of the talks!

MeetingLogs/appdevweek1104/ThunderbirdUnity (last edited 2011-04-13 07:36:24 by 178)