In seeking to continue Composite development, I needed a multi-touch environment.  All along, I figured that MeeGo would be that environment.  But the death of MeeGo means that this is no longer an attractive option.  I could do it, but it would be a stagnant OS, forever stuck at release 1.2.0.  I don’t want this for a development environment.

But as far as I know, MeeGo is still the only distro that gives you an out-of-the-box multi-touch experience.

Whatever distro I choose, I’ll need to fiddle with the Qt and Xorg packages on the system.  This is best done by creating new packages to replace the system ones (just in case you mess everything up, you can just revert back the package).  I chose Fedora because it tracks upstream projects very well, and also because I find RPM packaging much more enjoyable than DEB packaging.[2]

Here’s how I got a multi-touch-enabled Qt installed and working on Fedora 16.  I installed the 64-bit OS on my IdeaPad, so replace “x86_64” with “x86” if you’re using the 32-bit version.


If you don’t know how to install a Linux distro, fire off commands on a command line, or boot to single-user mode and fix a couple things — then this will probably be too much for you to take on. (E.g. if you just Googled “single-user mode” — STOP NOW! :-))

After installing Fedora 16, you need to set it up for building rpms. I didn’t keep good notes during this phase, so this is probably not complete:

    $ sudo yum groups install \
        "Development Tools" \
        "X Software Development"
    $ mkdir ~/rpmbuild
    $ cd ~/rpmbuild

Building the MTEV driver

The X11 input driver “mtev” is an interim solution to get multi-touch onto Linux devices like the N900, WeTab, N950, N9, etc. When XInput 2.2 finally hits the main-stream with a matching evdev driver, it will be obsolete.[4]

First, grab the sources and install the mtdev library:

    $ cd ~/code
    $ git clone git://
    $ sudo yum install mtdev-devel

Note that the tarball you need is already in the repository. Also, this has been modified to (a) compile with the 1.11 xserver and (b) it includes my right-click-emulation patch. If you don’t like it… choose the version you want with git.

Build it like this:

    $ cd ~/rpmbuild
    $ cp -f ~/code/xorg-x11-drv-mtev/* SOURCES/
    $ mv -f SOURCES/xorg-x11-drv-mtev.spec SPECS/
    $ rpmbuild -ba SPECS/xorg-x11-drv-mtev.spec 2>&1 | log-50

It only takes a few seconds to build. Then you can install it like this:

    $ sudo rpm -Uvh RPMS/x86_64/xorg-x11-drv-mtev-0.1.13-10.0.x86_64.rpm

Building Qt with Multi-Touch

On my IdeaPad, Qt takes about 9 or 10 hours to compile.  If you have a fast machine with F16, I recommend doing it there.

Start by checking out my source repository and grabbing the Qt sources that you need.  (Note, if the URL’s are cut off in your browser… there are links near the end of the article.  See “Resources.”)

    $ mkdir ~/code
    $ cd ~/code
    $ git clone git://
    $ cd fedora-pkg-qt
    $ git checkout topic/multitouch-00
    $ wget
    $ wget
    $ wget">hi48-app-qt4-logo.png

Now you can build it like this:

    $ cd ~/rpmbuild
    $ cp -f ~/code/fedora-pkg-qt/* SOURCES/
    $ mv -i SOURCES/qt.spec SPECS/
    $ rpmbuild -ba SPECS/qt.spec 2>&1 | tee log-00

Chances are that rpmbuild will choke on you, saying that you’re missing several required packages. You will need to install those. For example if it says that it needs “pkgconfig(foo)”, you can install it like this:

    $ sudo yum install "pkgconfig(foo)"

When done, install the packages in RPMS/. You probably want to do this:

    $ cd RPMS/x86_64/
    $ sudo rpm -Uvh qt{,-x11,-examples,-devel,-demos}-4.8.0-1.1.fc16.x86_64.rpm

To see which Qt packages you already have on your system, do:

    $ rpm -qa | grep qt

You only need to replace the ones that have a “4.8.0” version.

Verifying that it works

Reboot your computer and verify that it works. Run:

    $ /usr/lib64/qt4/examples/touch/fingerpaint/fingerpaint

If you can use 2 fingers to draw, then you are good to go! 🙂


X11 Fails to Start

If you reboot to a black screen, chances are that the MTEV driver is not kosher. Reboot to single-user mode and uninstall it.

    $ rpm -ev xorg-x11-drv-mtev

If you want to debug this… go right ahead. Chances are that its a failure in the driver’s PreInit() or something. However, I’m not going to be able to support you much with this.

No Multi-Touch

Do not be alarmed! Because this is driver is kind of a hack, you have to explicitly declare that the device should be managed by the mtev driver. xorg.conf.d files are installed for Cando, Sitronix, Hanvon, and ILI touchscreens. You might have a different one.

You can find out for sure by inspecting /var/log/Xorg.0.log. You should see something like:

[    26.125] (II) Using input driver 'mtev' for 'Cando Corporation Cando 10.1 Multi Touch Panel with Controller'

This was arranged by the /etc/X11/xorg.conf.d/60-cando-mtev.conf file, which looks like this:

Section "InputClass"
        Identifier              "Cando Multi Touch Panel"
        MatchVendor 		"Cando"
        MatchDevicePath 	"/dev/input/event*"
        Driver                  "mtev"
        Option                  "Ignore"                "off"

Your touchscreen device will need a different Identifier and MatchVendor string. Inspect your /var/log/Xorg.0.log for clues.

Using Right-Click Emulation

Open up the terminal application. Put one finger down and hold it. Now tap the screen with a second finger. The context menu will pop up. This gesture is easier (at first) if you use two hands.


Here are links to (most of) the resources that we used above.

[1] The Xorg devs think this will end with the release of F17.  XInput 2.2 is in the review process to be added to xserver 1.12.  However, I’ve heard that Qt will not add official support for it, instead waiting for Wayland.

[2] I cut my teeth on DEB.  For MeeGo I had to learn RPM, and found that I liked it better.  Less time tracking down opaque debhelper issues and DEB styles.

[3] I don’t know where the original files were served up, these links are to a cached copy at Fedora.  You can also get it from their qt SRPM.

[4] …presuming that someone actually breaks down and adds support to Qt. Otherwise, it’s still useful for Qt dev.

Last time I described how to use LD_LIBRARY_PATH for your private libs in your package. While this will usually get you what you want, it has one extremely big drawback: poisoning 3rd party libs. It also has one minor drawback: applications start up slower.

Starting Slower

When your application starts, a program called looks to see what libraries you need. (E.g. and and so forth.) Since this happens all the time, it keeps an index of these libraries and where they are located. Thus, it’s able to resolve the libraries very fast.

But when you set LD_LIBRARY_PATH, these paths have to be searched first, and this is slower because you actually have to access the file system and search directories.

But this is only a minor problem… the bigger problem is…

Poisoning 3rd Part Libraries

To be MeeGo compliant, there is a prescribed list of libraries that we can depend on. For everything else, we have to bring our own. Suppose, for instance, that MeeGo’s version of does not have all the features that you need. So, you package your own version of with the extra features and ship it as a private library in your package.

Meanwhile, Qt is already linked to libAtion, and you use it (indirectly) in your code. When your program is initialized, it’ll see that Qt needs and use your private version instead of the system version that Qt shipped with. Do you see how this might cause problems?

Or, suppose you had no idea that was in any MeeGo, anywhere. However, DeviceMan, Inc. shipped a MeeGo device where they added as part of their default Qt theme plug-in. Now when your application loads the theme, it is poisoned with your private libAtion.

Solutions to LD_LIBRARY_PATH

So, LD_LIBRARY_PATH isn’t the best solution (and some will say it is to be avoided at all costs). What other options do you have?

  • Statically link your programs to your private libraries — While this isn’t as convenient to your opt/non-opt build workflow, it is effective.
  • Use rpath when you link — the GNU linker has an -rpath option that is like setting LD_LIBRARY_PATH at compile time. The advantage is that it only applies to your binary… and not other 3rd party libs.
  • Do lots of homework — Make sure that your version is compatible with whatever version may be on the system. If possible, prefer the system’s version of the library. However, this option is destined to fail, eventually.

Further Reading

I found the following articles informative:

So last time I convinced you that packaging for /opt is a Good Thing for add-on software (e.g. app store stuff).[1]  But now that you are convinced… this is a total re-think of how packaging works. Here are some tips on how to get it done without totally messing up your non-opt installs.

Suppose our company is and our program is called Floobydust.  On unix-like operating systems we’re used to installing our software like this:

  • Executable programs go in /usr/bin/
  • Libraries go in /usr/lib/
  • Desktop files go in /usr/share/applications/
  • Our extra stuff goes in /usr/share/floobydust/

But now, everything must go in /opt.  This means that:

  • Our program won’t be in $PATH
  • Our libraries won’t be found by [4]
  • Our desktop files won’t be discovered
  • Our hard-coded "/usr/share/floobydust" strings are now bugs

So… how do you handle this?  In fact… how can I handle both cases without having to totally re-write my build system?

Step 1: Use PREFIX

Most build systems allow the user to define a PREFIX at build-time.  This PREFIX will determine the location of the bin, lib, and share folders that we’ll use for install.  All the paths above set PREFIX=/usr.  It typically defaults to PREFIX=/usr/local.  So, what happens when you set PREFIX=/opt/ ?[3]  Then…

  • Executable programs go in /opt/
  • Libraries go in /opt/
  • Desktop files go in /opt/[2]
  • Our extra stuff goes in /opt/

Now, it’s essentially the same thing as if we had set any other prefix.  Note also that you may choose to use PREFIX=/opt/ — as long as you make sure that all your programs cooperate!

Step 2: Use a redirect script to set up your private libraries

When installed in /usr/bin, (the dynamic linker) will search in /usr/local/lib, /usr/lib, and /lib for the shared object (.so) files that you need. However, you have installed them to /opt/ instead. To get to find your libraries, you need to modify LD_LIBRARY_PATH to include your package’s lib folder. You can do this by renaming your program to something like floobydust-1.2.3, and creating a redirect script called floobydust like this:

exec /opt/ "$@"

So, we (a) set LD_LIBRARY_PATH, (b) call our program, and (c) pass it all the command-line arguments (that’s the “$@” thing). However, this script only covers the happy case… so here’s the script that you would really use:


export PATH

exec "${BINDIR}/${EXEFILE}" "$@"

This is something that you could reuse in several different applications. Also note the shell expansion trick for LD_LIBRARY_PATH and PATH that makes sure we don’t end up with a trailing colon ("/opt/").

This method will help no matter where you installed your libs. You can configure the path at compile time.

Step 3: Namespace your .desktop file

Add your organization name to your desktop file Since you are using your domain name, it’s extremely unlikely that you will conflict with anyone else’s .desktop file. Then install the file using the desktop-file-install utility (which will usually install to /usr/share/applications). You can optionally have that command do the file-name mangling for you. (Read the manual page for it.)

Also, be sure to put the full path to your redirect script from Step 2 (/opt/, as well as any icons.  Most build systems will let you make your desktop file a configure script (typ. that gets modified for your compile-time configuration options.

Step 4: Make sure you don’t hard-code paths in your application

This is actually step 1, but it’s boring so I put it last.  If some part of your program looks to /usr/share/floobydust without thinking first… you need to make your application configurable.[5]

What about $PATH??

Are you really shipping command-line apps through an app store? There isn’t really a solution to this (and still be MeeGo Compliant.) The .desktop file is the replacement for a $PATH, and the redirect script from step 2 can reset it if we need it internally. Another option is to create symlinks in /usr/bin. While this makes the app non-compliant, it’s a good compromise for a multi-distribution package.

Wrapping up

Whatever we do to install in /opt can translate back to /usr and /usr/local. Using this strategy not only helps in app-store situations, but also creates a safe practice for application-specific private libraries (.so). With a little extra run-time detection, these can also help in supporting relocatable RPM packages. While there are no good solutions for CLI apps, it seems unlikely that many CLI apps will be targeting app stores.

[1] Yeah, right! 🙂
[2] Not really… but we’ll get to that.
[3] Note that MeeGo compliance says you can install in /opt/<packagename>. Using your organization name is optional, but recommended.
[4] is the dynamic linker.  It’s the program that finds the .so files for your app to use.
[5] You are supposed to do this anyway… since you don’t know what PREFIX will be a priori.

The current MeeGo Compliance Spec will often give developers a start when they read this:

An application shall be installed to /opt/packagename/ and, if necessary to the /etc/opt/packagename/ and /var/opt/packagename/ directories.[1]

Most users reply, “Huh?  Why don’t we install in /usr like a normal Linux distro??”  The rationale is given as follows:

The rationale for these rules is to avoid filename clashes between application packages and with system files, by defining portions of the filesystem certain to be unique to that application.[2]

This leaves most devs a little… underwhelmed.  The first response is to appeal to the FHS/LSB… but lets start with an example.

Suppose I write a MeeGo game called “Zombie Professer Shootout.”  Because I’ve got several modules for this game, I have an internal library called  Because I don’t know any better, I install it in /usr/lib/  Put the package in the App Store.  Done.

Meanwhile, suppose that YOU, Zeek, write a hand MeeGo time management program called “Zeek’s Personal Scheduler.”  For whatever reason, you put a lot of the core functionality in a library called so that other people could reuse it in their code.  So, you install it to /usr/lib/  Put the package in the App Store.  Done.

First, they install my Zombie game.  Then, months later, they install your Personal Scheduler.  However, the app WILL NOT install because it would overwrite /usr/lib/  There’s no way around it.  You have a broken package.

And the user says, “This sucks!”

The whole point of being a MeeGo compliant app is that it’s a single, stand-alone, 3rd party app that can be installed to MeeGo… and it Just Works.  But if we all install in /usr… then we all have to be on the same page with respect to file names, package names, etc.  In a normal linux distro (where all packages are served from one repository), these get discovered and discussed among the developers.  But with MeeGo apps coming from a myriad of sources there is no way that can happen.

So, MeeGo chose to use namespaces by requiring installation to /opt.  The opt folder is defined in the FHS as follows:

/opt is reserved for the installation of add-on application software packages.

A package to be installed in /opt must locate its static files in a separate /opt/<package> or /opt/<provider> directory tree, where <package> is a name that describes the software package and <provider> is the provider’s LANANA registered name.[3]

Note that this is nearly identical to the MeeGo requirement… and serves to solve this exact problem.  It’s a system that allows uncoordinated developers the freedom to organize their package however they need without stepping on anyone else’s toes.  Everything they do is under the namespace of the company’s LANANA registered name (e.g. or something).  Without this, users will be inundated with broken packages and always come to the same conclusion: “This sucks.”

“But how do I find my project’s libs?  What about $PATH?  This is no fun for the developer!”  We’ll talk about that next time.

[1] MeeGo 1.1 Compliance Specification, Section 3.3.4

[2] Ibid.