Thursday, September 29, 2011

Mediawiki for personal notes

For years, I've had the problem of how to store my notes but finally found something that is usable.

I've tried a few variations over time, but none suited my use-case sufficiently. Textfiles are too limited and become unmanageable quick. Org-Mode requires Emacs (Emacs and I disagree on how much pain I'm willing to accept in my hands), Zim wasn't available on RHEL and didn't scale well after a while. TomBoy and Gnote require GNOME which doesn't work on the Mac*, aside from me always running into synchronization issues using it on three machines. I toyed with ideas like Evernote but keeping notes in the cloud makes me slightly nervous and doesn't work for confidential stuff anyway. Other wikis I tried over the last few years were dokuwiki, ikiwiki and tiddlywiki.

Many moons ago, Aaron Stafford showed me how he used MediaWiki. At first that didn't seem viable since it didn't cover a few things I wanted: portability, git-based backups that I can take to work and back and use on any machine I care about. Anyway, I've used this for well over a year now and it works for me.

The ingredients:

  • one usb stick

  • truecrupt (realcrypt in Fedora's rpmfusion)

  • mediawiki

(Note: I'm not giving step-by-step instructions because if you're setting this up, you should understand what you're doing instead of just copying commands from a random website)

Preparing the USB stick is easy enough. Format it with FAT32 (if you're not suffering from having a Mac, you can use a better file system). Create a massive file with truecrypt, encrypt it. You can encrypt the entire stick but having the in-file option allows multiple encrypted files on the same stick.

The filesystem for the encrypted file should be FAT32 again. Then install mediawiki in a directory, point apache to it and run through the mediawiki install process. Set the mediawiki up to use an sqlite database. Finally, set up a cron job that essentially runs git add * && git commit -am "Autocommit $date" every hour. Backup is simply done by running git push remote.

I recommend writing a few scripts that automount the stick once you plug it in. Once that's done and on all machines you care about, you just need to plug the stick in, start httpd and off you go. Of course, if you trust your hosting provider enough you could also set it up somewhere on the web and you can skip the USB stick madness.

Now, is this setup perfect? No, by far not. Issues that I see with it:

  • no text-based backend. Now that my X server is decidedly more stable that doesn't matter that much anymore

  • interface decidedly Web 1.0 (TiddlyWiki is much nicer here)

  • no real database merging, essentially requiring a single install instead of several synchronising ones

  • the mediawiki syntax is random at best, and chaotic at worst. As you get used to it becomes less of a problem

  • search hardly works. Not sure if that's a sqlite issue or a broken setup

Lessons learned

Forgetting the USB stick at work means you can't take notes at home for that evening or weekend. I now have a repeating event in my calendar to remind me to take it home.

Databases don't merge and git won't help with a binary file. For a while, I kept two wikis, one for work notes, one for private stuff. But then you have something that overlaps both (e.g. a computer setup that you use at work and at home). Eventually I ended up dumping the smaller database and importing it into the other one before I had too much overlap.

Categories are awesome. They're essentially tags, add [[Category:Foobar]] to any page and the matching Category page lists all pages in that category (plus, that page can also be a page with other info). Categories can be nested.

Everything must be written down. This is something of a golden rule for any note-taking attempt. Unless you take notes, your notes won't be useful.

I still use a normal pencil and paper notebook. Especially when debugging I use pen and paper and then transfer the final result over to the mediawiki.

Install Lazarus. It has saved me a few times.

Redirects help finding pages. Whenever I search for a page with a certain title and it's not there, I add a redirect from that title to the real page. So next time, I'm sorted.

I'm now re-learning how to navigate pages instead of just searching through them. This has one big benefit: on the path to a page you may encounter another page you've forgotten about and that you can now deal with again.

Keep a "Log" (or "Diary") page, with short comments of what you did on each day. I've set this to my home page now and it consists of entries like "Looked at [[Fedora 16 Blocker Bugs]]". It's a quick way to jot down what you're doing, pointing to the pages that contain the actual information.

As said above, I've been using this setup for quite a while now. It's not perfect but software hardly ever is. The final ingredient though I only found last week: the LACIE MosKeyTo, a USB stick that sticks out by only a few mm. Before that I was always worried about breaking off the stick when I carried the laptop around.

So if you're looking for note-taking software, I can't say mediawiki is perfect. But it is the most usable one I've found for me.

* My Mac is essentially a netbook and I don't really install anything on it. It keeps me from working too much at home.

Friday, September 9, 2011

Natural scrolling in the synaptics driver

[updated Apr 16 2012 for smooth scrolling]
The latest version of Mac OSX (Lion) introduced a feature referred to natural scrolling. Since I've been getting a few requests to add the same feature to the synaptics driver. At it's base natural scrolling is an inversion of the scroll direction*. We've had the ability to do this for years, though more by accident than intent.
The synaptics driver (until X server 1.12's smooth scrolling) uses buttons 4/5/6/7 for up/down/left/right scrolling. If you want up to scroll down, just swap them and you're good to go.
xinput set-button-map <device name> 1 2 3 5 4
Now down is up and up is down. The device name can be obtained as usual with xinput list. This will work for servers up to including 1.11.
As of synaptics 1.6RC3 (, the options VertScrollDelta and HorizScrollDelta can now be set to a negative value. For servers supporting smooth scrolling (X server 1.12+), this effectively inverts the scroll direction.
* I realise that natural scrolling in OSX may have a few other details to make it do whatever it does. Synaptics supports scroll inversion and scrolling inertia.

Monday, September 5, 2011

What's new in XI 2.1 - smooth scrolling

This post is the last part of a series about new changes in XI 2.1. See also:

The core protocol allows for up to 255 buttons but only two axes: x and y. When scroll wheels became ubiquitous, the solution was to send button events for the four scroll wheel directions. Even today, a logical button click 4 results in scroll down, 5, 6, and 7 result in scroll up, left, and right, respectively.

However, scrolling is more complex than that. Velocity information and subpixel scrolling are handy to have on scroll axes. With XI 2.1, servers may now mark some axes as axes providing scrolling information. These axes may represent real axes on the device (e.g. a mouse wheel) or be virtual axes (e.g. the edge scrolling on synaptics devices). For each scrolling axis, XIQueryDevice(3) provides an XIScrollClassInfo.

XIDeviceInfo *info;

int ndevices;

info = XIQueryDevice(display, XIAllDevices, &ndevices);
for (i = 0; i < ndevices; i++) {
XIScrollClassInfo *scroll;
for (j = 0; j < info[i].num_classes; j++) {
scroll = info[i].classes[j];
if (scroll->type != XIScrollClass)
continue; /* Not interested in others */

printf("Valuator %d is a valuator for ", scroll->number);
switch(scroll->scroll_type) {
case XIScrollTypeVertical: printf("vertical"); break;
case XIScrollTypeHorizontal: printf("horizontal"); break;
printf(" scrolling\n");
printf("Increment of %d is one scroll event\n", scroll->increment);
if (scroll->flags & XIScrollFlagsNoEmulation)
printf("No emulated button events for this axis\n");
if (scroll->flags & XIScrollFlagsPreferred)
printf("No emulated button events for this axis\n");


The above code example runs through each class on each device, printing only the scrolling information bit. Note that for each XIScrollClassInfo, a XIValuatorClassInfo with the same axis number must be present. That valuator info then contains the actual details of the device.

Let's say a XIScrollClassInfo is available for valuator 3. This simply means that any coordinates on valuator 3 should be interpreted as scrolling events. The increment defines what delta the driver considers to be one scroll event. For an increment of +5, each delta of 5 should be regarded as one scroll unit down. For an increment of -3, each delta of 3 should be regarded as one scroll unit up (i.e. inverted).

Note that a driver may change this at run-time. As always, a client should listen to XIDeviceChangedEvents.

Scroll button emulation

If a driver provides smooth-scrolling valuators, the server provides two-way emulation of scroll events to remain backwards-compatible to existing X clients. For any button 4-7 event from the device, the server emulates a scroll event with the right increment on the respective axis. (Note that drivers are discouraged to use button events for scrolling if they support smooth scrolling). For any scroll event on a scroll axis axis, the server emulates the matching button 4-7 events. If the scroll event has an abs(value) less than the increment on this axis, the server only emulates once the cumulative value of several events hits a multiple of the increment (positive or negative).

For clients, this means they get two events for each hardware scrolling event. The one that was emulated by the server has the XIPointerEmulated flag set and can be safely ignored by the client. The same flag is set for XIRawEvents as well.

A device may have multiple scoll axes of the same type. If so, one of them is marked as XIScrollFlagsPreferred and any legacy button events will be emulated on that axis. This bit is informative only, I don't think clients need to care about it. Plus, we're aiming for drivers to do smooth scrolling only, so hopefully we don't need to do button → scroll valuator emulation.

Potential side-effects

  • Pre-2.1 clients may now get valuator information from a scroll axis that they don't identify as scroll axis. For 1.x clients, this is not much of an issue. 1.x clients never knew what an axis represented anyway and needed a UI for users to select what an axis meant. 2.0 clients have axis labels and should act on those. So I think this is mostly a non-issue.

  • Clients that implement smooth-scrolling may act on information less than one increment. Permanent up/down movement of values less than one increment may then cause smooth scrolling events but no legacy events. I don't think this is an issue, users usually trigger the scrolling axis until they see the effect on-screen. The worst-case scenario here is that scrolling in one client requires more finger movement than in another client.

  • Clients cannot yet change the increment. I don't know if this will be an issue in the real world given that the actual interpretation is in the client anyway.

Saturday, September 3, 2011

What's new in XI 2.1 - raw events

This post is part of a series about new changes in XI 2.1. See also:

Raw events were introduced in XI 2.0 to allow clients to track direct device data, before the server gets its hands on it. The prime target for these was games that needed relative mouse events.

However, there was one flaw with raw events: they were delivered either to the root window or to the grabbing client only. Which made them less-than-useful, since grabs are virtually everywhere: active grabs by clients, passive grabs whenever a popup or dropdown menu appears, implicit grabs whenever the button is down.

This behaviour changes in XI 2.1. If a client announces support for XI 2.1, it will get raw events delivered to the root window at all times.

The second change to raw event behaviour is that the events now have the sourceid set (Bug 34420). The libXi interface catered for this but we never sent the value down the wire. This is fixed now in XI 2.1.

Friday, September 2, 2011

What's new in XI 2.1 - XI2 defines

This post is part of a series about new changes in XI 2.1. See also:

A while ago, I spent some time staring at gdb wondering why a passive grab didn't activate. Turns out it wasn't a bug in the server after all, it was a bug in the program. The modifiers were set like this:

XIGrabModifiers modifiers[1];
modifiers[0].modifiers = AnyModifier;

AnyModifier is a define that comes from the core protocol:
#define AnyModifier             (1<<15)  /* used in GrabButton, GrabKey */

but XI2 provides its own define:
#define XIAnyModifier           (1U << 31)

Passive grabs only activate if the modifiers match the current modifier state. An XI2 grab that uses AnyModifier won't activate as expected - AnyModifier looks like a normal modifier bitmask to the server.

I wanted to reply to the reporter with "don't mix core and XI2 defines" but there's one problem: you couldn't currently write an XI2 application without using some core defines (e.g. GrabModeAsync). I've looked through the protocol spec and added those defines that previously forced clients to mix input-related constants. New defines now available are:

  • XIPropModeReplace, XIPropModePrepend, and XIPropModeAppend

  • XIAnyPropertyType

  • XIGrabModeSync and XIGrabModeAsync

  • XIGrabSuccess, XIAlreadyGrabbed, XIGrabInvalidTime, XIGrabNotViewable, and

  • XIOwnerEvents, XINoOwnerEvents

These will be available to any application compiling against XI 2.1 headers. All the above are identical to the core defines. Clients are still expected to use CurrentTime and None from the core protocol headers since neither of those two is input-related. For applications building against 2.1, the guideline to using XI2 can only be summarised as: Only use a define Foo if there is no equivalent XIFoo version.

The libXi man pages have also been updated where applicable to point out the new defines.
Many thanks to Timur Kristóf for uncovering this.

XIOwnerEvents and XINoOwnerEvents are new additions to improve readability. They simply map to True/False.

What's new in XI 2.1 - versioning

This post is the start of a mini-series describing the new features added to the X Input Extension version 2.1, or short XI 2.1.

Also, I need to point out that XI 2.1 is not yet released, some minor changes may still be added. Nonetheless, this series should help you understand the new additions and if you see any issues - by all means let me know so we can amend before it is set in stone.

In this post, I'll talk about versioning.

First, for all those looking for big headlines: multitouch in X has been postponed to XI 2.2. XI 2.1 is a small incremental change with two bugfixes and one new feature. These are uncontroversial and more importantly, they are ready now. So XI 2.1 is released as a small change, with bigger changes coming for XI 2.2. We currently still plan to get XI 2.2 into server 1.12 so this is really just a numbers game and ticking off work that is complete.

The small list of changes for XI 2.1:

  • New raw events behaviour

  • Smooth scrolling

  • XI2 defines

I'll describe each of those in a separate post.

Announcing support for XI 2.1

Any client that supports XI2 must already announce so with XIQueryVersion(3). To unlock XI 2.1 behaviour, a client must announce support for XI 2.1 or later.

int major = 2;
int minor = 1;
int rc;

rc = XIQueryVersion(display, &major, &minor);
if (rc == Success)
printf("Server supports XI %d.%d\n", major, minor);
else if (rc == BadRequest)
printf("Server does not support XI2.\n");
printf("Internal error\n");

The server is compatible with XI 2.0 and XI 2.1. Thus, a client that does not announce XI 2.1 support will get XI 2.0 behaviour.

Using XI2 version defines

Because I fell into this trap myself, a word of warning about a potential bug. If you are currently using the XI_2_Major and XI_2_Minor defines for versioning, recompiling against new inputproto headers will automatically bump your client up to the latest version, including possible unexpected behaviours. Don't do this, XI2 is versioned through numbers, not defines. Have a look at this xinput commit to get a better idea.

Making git reset less dangerous

If you've ever fat-fingered a git reset HEAD~2 into a git reset HEAD~23 then this may be of interest to you. If you have, add this to your .gitconfig:

r = !sh -c \"git log -1 --format=oneline\" && git reset

Using git r instead of git reset now prints the current HEAD before resetting.

$ git r --hard HEAD~23
9d09ffc3ba1a65fc7feefd21abd5adacf3274628 dix: NewCurrentScreen must work on pointers where possible
HEAD is now at 5083b56 Revert "mi: move switching screen on dequeue to separate helper function"

Whoops. Fat-fingered. A git r --hard 9d09ffc3ba1a65fc7feefd21abd5adacf3274628 will undo the above and get you back to your previous HEAD.

Note: git fsck --lost-found will also help you to find the commit again, but it'll take more time and effort.

Update: as mjg59 pointed out to me, git reflog records git resets, thus making it easy to find the previous HEAD too. Wish I'd known that command sooner ;)