Libertexto: integrating Evince into Firefox

These months I’ve been collaborating in Libertexto development. Libertexto, a project coordinated by Rafael Ibáñez, will be a Firefox extension whose goal is to allow the user to do some text comprehension tasks (highlight, add annotations and create bookmarks) and concept mapping tasks (manage a tree of “lexias” or units with semantic content) on HTML and PDF documents.

Multiplatform

So far, I’ve mainly been involved in the task of integrating Evince into Firefox. The goal was not only to provide support for PDF document viewing, but also to adapt Evince to manage the communication with the Firefox extension and to provide the required functionalities and GUI interaction. The fact that Libertexto has to work both in Linux (Ubuntu Jaunty) and Windows made the task more challenging and had an important influence in the design decissions.

libertexto_windows

The plugin

The main idea was to write a plugin registered to visualize documents having the “application/pdf” mime type, using Evince for that, and interact with the XUL/Javascript code to coordinate everything. The npsimple (check my npsimple backup link) example was very valuable to learn how to code a multiplatform basic plugin implementing the Netscape Plugin API (NPAPI). These first testings (with the help of Dependency walker) showed me that the plugin code would only load if compiled with the same compiler used to build Firefox. That means forgetting Cygwin, MinGW32 and other Windows platform free stuff and compile using Visual C++, getting the headers from the Mozilla SDK.

Communications: first try

Once I had a plugin that did nothing, I looked for ways to communicate it with Firefox. I tried some XPCOM examples and debug tools without much luck, so I finally decide to use alternative ways of communication when I needed to.

Compiler restrictions

At this point I focused in compiling Evince for Windows. I chose Evince 2.28.0 because it had been already compiled for Windows by Hib Eris. I found him in the #evince IRC channel and he pointed me to the Ubuntu PPA he had used to cross compile for Windows using MinGW32. He also confirmed to me that mixing MinGW32 compiled apps with MSVC compiled apps is a problem because MinGW32 compilations are dependant on msvcrt.dll, while recent MSVC compilations depend on msvcrt80.dll or msvcrt90.dll. That explains why I couldn’t compile the plugin with the MinGW32 toolchain from Windows. Forget also about converting Evince itself into a plugin (implementing NPAPI), because it won’t load. There’s currently no easy solution, but to compile everything with MSVC (not tried before) or keep applications split.

Embedding the window

After having compiled Evince and all its dependencies for both operating systems I modified the plugin to start Evince each time a new document was loaded. Next step was to find a way to embed Evince in Firefox, because having it as an independent window was not an option. The plugin was given a window ID (XID in X11, HWND in Windows), so I modified Evince to receive it as an extra parameter and use gtk_window_reparent() to “hijack” the window that Firefox provided. Of course, using Mozplugger is much easier, but it’s not supported in Windows, so I had to do it by hand. After some tweaking and having to disable DBUS support to get exactly one process per document (in Linux), it worked in both systems. In Windows I ended up with refresh and focus problems, but I didn’t go further.

Communications: second try

At this point, the key was to have a reliable communication system between Evince and the plugin. DBUS would have been good for Linux, but would bring too much problems in Windows (everything should be installed or work from the Firefox extension bundle and I’d need a way to use DBUS from javascript). Standard IPC methods (eg: shared memory) would be a problem too, because I hadn’t managed to successfully develop XPCOM components that could access low level C functions to use that IPC methods. However, there’s one thing that always work: plain old HTTP requests. They are supported in the Firefox side using XMLHttpRequest and in the Evince side using libsoup-2.4. I had experience using libsoup in Meiga, so it wasn’t difficult for me to set up a bidirectional realtime communication middleware using the AJAX paradigm.

The initial port handshake is a bit tricky, though. Remember that there’s no way for the Firefox extension, the plugin and Evince to talk to each other before this handshake. The process is as follows:

  1. The user opens a URL containing a PDF, so the PDF plugin is invoked. If the plugin is in Linux and detects that libertexto hasn’t been installed in /usr/local/libertexto-0.0.5 yet, it triggers the install script and waits until the process is completed. Then continues.
  2. Using dll/so API calls on the first load, the plugin gets the path where nplibertexto.dll/.so is installed (eg: /home/user/.mozilla/firefox/ky712h81.default/extensions/libertexto-0.0.5@libresoft.es/platform/Linux_x86-gcc3). From that path it gets the extension path (...libertexto-0.0.5@libresoft.es) and builds the xid directory path (...libertexto-0.0.5@libresoft.es/xid)
  3. The plugin gets the URL and the downloaded file name through NPAPI. It then launches Evince (fixed location in Linux, variable location under the extension dir in Windows) with the following parameters: evince --xid 0x6800001 --libertexto-path /home/user/.mozilla/firefox/ky712h81.default/extensions/libertexto-0.0.5@libresoft.es/xid /home/user/local_links.pdf.
  4. Evince opens the file, hijacks the window with handler 0x6800001 and starts a web server on a random port of 127.0.0.1 which will wait for incoming connections. Then the port number is written to a file named 0x6800001 in the xid directory.
  5. The plugin has been waiting up to 5 seconds and monitoring the xid directory for new files. When it finds a new one, reads it and inserts the (xid, process id, MD5 sum of the URL, port) into a children array for further use. Each time the children array changes, the file libertexto-0.0.5@libresoft.es/libertexto-docs is regenerated. That file has the URL MD5 sum and port, one line per document.
  6. The file is available as resource://libertexto-docs/ to the Firefox extension and it’s monitored each 5 seconds using XMLHttpRequest (it can also read local files). That way, the extension keeps a table of open documents and their ports.
  7. Each time the extension detects a new entry in the table, it connects to the port using XMLHttpRequest on a special “receive” URL (eg: http://127.0.0.1:53162/receive) and reads and attends any pending messages that Evince would like to communicate. If there are no more messages, just keeps waiting for one to come. When one comes, the network dispatcher in the Libertexto extension attends it, closes the connection and restarts it to wait again. Evince code just enqueues outgoing messages and writes them when the extension (re)opens the connection.
  8. If it’s the extension who wants to send a message to Evince, a request is made to a “send” url (eg: http://127.0.0.1:53162/send?action=test&param1=value1&param2=value2). There’s also another network dispatcher in Evince that processes incoming messages and calls the corresponding function of EvApplication.
  9. When the document is closed, the plugin code is informed by NPAPI and just ensures that Evince is killed, the 0x6800001 xid file is removed and libertexto-docs is rebuilt.

Packaging

It was time to polish a little bit the building and packaging environment. Different binary sets for different platforms can be provided using the platform directory in the Firefox extension package. In Windows, there’s no problem in relocating a GNOME app where you want, as there’s specific code to locate the data and config dirs, but in Linux it has to be installed in a fixed location, so I prepared a very basic installation script for that platform to be executed by the plugin the first time that the user opens a document.

Functionalities

With the infrastructure ready, I started to hack on Evince and implement the required functionalities (and the related middleware messages in both sides):

  • Get the text directly selected by the user
  • Scroll to a specified position of a specified page in a document
  • Highlight some (preselected) text with the specified color
  • Set an “start of selection” internal mark
  • Set an “end of selection” internal mark and then select the text between the start and the end of selection
  • Show the “create new item” option in the context menu and pass that command to the Firefox extension
  • Overimpress an annotation with some arbitrary text
  • Overimpress some icons that would trigger some commands on the current items

For some of them, specially those related to text highlighting and annotations, the advice from Carlos García Campos was very helpful. Shell, view, document and backend layers, the pixbuf cache, the jobs system… Evince is a big project and I needed some time to get used and understand it, but it has a lot of things to learn. I enjoyed very much this development stage. 🙂

When all the PDF side functionalities were completed, I removed all the unneeded GUI options from Evince and adapted the Libertexto extension panel to produce and handle the required middleware messages needed to manage the user interaction.

libertexto_linux

The result

Although the project still lacks part of the control and HTML modules functionalities, I got Evince integration working in this nice prototype.

You can download it as: libertexto.xpi (UPDATE 3/3/2011: you might prefer to download the final Libertexto 1.0 version). Please note that this file will probably evolve, being overwritten with newer versions.

Until the whole project gets released, a shapshot of the Evince branch code is published in Gitorious for you to have a look.

Meiga 0.2.1 released

This is a minor release that includes a couple of bug fixes that will make Meiga to properly work on Fedora systems and also to work with those routers exposing a WANPPPConnection by UPnP instead of a WANIPConnection.

As always, you can download it from http://meiga.igalia.com. This time a new package for Ubuntu Jaunty on amd64 is also available for users having that architecture.

Simple HTTP server in Python

Reading blog comments about Meiga out there, I’ve found one particularly interesting. Python has an embedded HTTP server that can serve the current directory from a given port. It can be instanced for port 8282 simply issuing this command:

  python -m SimpleHTTPServer 8282

The funny thing is that… it works on the N810 also!

More info about SimpleHTTPServer here.

Meiga: lightweight content sharing from the desktop

No, this time I’m not going to talk about the wonderful new Igalia office opening party, nor about the Igalia summit that we’re going to have this weekend in a hotel near Santiago de Compostela. This time I’m going to talk about a new free software project I’ve been working on to take advantage of the paid hackfest ours that our company provides us. Ladies and gentlemen, I’m proud to present the Meiga project to you.

As all of you already know, the current trend in the Internet is to publish contents in centralized servers to be shared to other people. Nevertheless, sometimes it’s handy for users to be able to serve their own contents directly from their desktops in a convenient way (instead of using a pendrive, for instance). Why bothering about publishing your contents if you can share them directly from your desktop to the LAN or even to the whole Internet?

To satisfy this need we’ve created Meiga, a tool that makes possible to share selected local directories via web. But that’s only the beginning. In fact, the ultimate goal of the project is to serve as a common publishing point for other desktop applications, such as the file manager, picture viewers or music players.

Meiga is lightweight, easy to use, network friendly and also application friendly. It’s written in a mix of Vala and pure C code, using existing Gnome technologies to perform its tasks: libsoup is used as a simpler alternative to fat web servers, libgupnp is in charge of doing port redirections if the network router supports UPnP, and DBUS exposes a public API to allow the GUI and third party applications to control what is served. Some advanced publishing features are already implemented, like the feed server that can render an RSS view of a given directory.

From the educational point of view, the source code of this project is a live example of Vala technology usage: pure Vala programming, different alternatives to interface Vala with pure C code (using Vapi files or running a child executable program) or the usage of a “programmable context” to handle sequentiation of asynchronous operations. An autotools based build system completes the set of interesting features. This system uses a Vapi file to pass configuration parameters from the config.h to the Vala program. Finally, some additional rule files allow the building of a Debian package, the last step to make the program available to final users in a convenient way.

Meiga is free software. It’s released under GPL 2.0 and can be downloaded just typing:

git clone http://git.igalia.com/meiga.git

Shell Scripting notes

Eight years ago, back in 2000, I was decided to learn shell scripting. I found the Bourne Shell Programming book by Robert P. Sayle a very good way to start, so I began my way through it, reading the concepts, making the exercises and taking advantage the opportunity to write a sort of personal notes (in Spanish) using LyX (a text processor I liked very much at the moment).

Some time later I submitted the notes to the GPUL mailing list and they were posted at the research groups page. Unfortunately, there’s no way to access the notes from there, because a disk failure and the website revamping got them lost. It’s a pity, because not even the Internet Archive preserves a copy of them.

Those notes have a symbolic value for me. They served as a basis for later bash scripting courses I taught and, after many changes and adaptations, are still the main inspiration for the shell scripting slides used in the Caixanova Free Software Master.

For that reason, today I did a bit of computer archaeology and searched through my old backups until I found it. Now that this material is back, I want to share it with all of you:

Enjoy it!

Spanish version / versión en español:

Hace ocho años, allá por el 2000, me decidí a aprender shell scripting. Descubrí que el libro Bourne Shell Programming de Robert P. Sayle era una muy buena forma de empezar, así que inicié mi camino a través de él, leyendo los conceptos, haciendo ejercicios y aprovechando la oportunidad para escribir una especie notas personales (en español) usando LyX (un procesador de textos que me gustaba mucho en aquel momento).

Algún tiempo después envié las notas a la lista de correo de GPUL y fueron publicadas en la página de grupos de investigación. Por desgracia, no hay forma de acceder a las notas desde allí, porque un fallo de disco y la remodelación del sitio web hicieron que se perdieran. Es una pena, porque ni siquiera el Internet Archive guarda una copia de ellas.

Esas notas tienen un valor simbólico para mi. Sirvieron como base para cursos posteriores de scripting bash que impartí y, tras muchos cambios y adaptaciones, son aún la inspiración principal para las transparencias de shell scripting usadas en el Master de Software Libre de Caixanova.

Por esa razón, hoy hice un poco de arqueología informática y estuve buscando en mis viejos backups hasta que lo encontré. Ahora que este material ha reaparecido, quiero compartirlo con todos vosotros:

  • Notas sobre Shell Scripting (versión PDF): bash.pdf
  • Notas sobre Shell Scripting (archivo con versiones LyX, tex, ps y HTML): articulo_scripting.tgz

Disfrutadlo!

Basic commands and scripting class at Free Software Master

This weekend I’ve taught the first sessions at Caixanova Free Software Master. It consisted of a brief introduction to basic command line tools and some concepts about shell scripting and regular expressions tools.

All the course slides are licensed under a Creative Commons license. Until we finish to set up the course collaborative platform, the slides and exercises will be available in my personal web page. I’ll update this link when a final destination for those materials is found.

In addition, Ive compiled some interesting links related to the subject, which can be found in this dedicated Delicious section.

Teaching at Master on Free Software

Last weekend I taught my first class for the Caixanova Master on Free Software, organized by Universidad Rey Juan Carlos and Igalia. The class is part of the Systems Integration on Free Software subject and covered basic concepts of system administration and scripting. The goal is to provide the students a basic knowledge to be able to face more complex tasks in the Development subject.

All of them showed very interested and I felt quite happy with the results. Some of the students had basic knowledge of scripting, but a comprehensive walk through the concepts unleashed some concepts that they lacked of.

The subjects covered were:

  • Administrative tasks: System startup, Users & groups, Task automating, Auditing, Backups
  • Basic commands: Files & directories, Process control, Documentation, Redirections & pipes
  • Script programming: Environment variables, Input/output, Command grouping, Wildcards, Quoting, Control structures
  • Advanced commands: Regular expressions, Grep, Sed, Awk

All the materials of the Master are published on a Creative Commons by atribution share alike license. You can find them at the web of the Master:

http://gsyc.escet.urjc.es/moodle/course/category.php?id=17

(By the way, this blog aniversary was two days ago. Two years! I wish a long life for it and lots of interesting posts.)