Tuesday, March 22, 2011

Custom input device configuration in GNOME

Thanks largely to Bastien, Gnome Bug 635486 just got committed, in time for GNOME3.

It adds is the ability for custom configuration of input devices from within GNOME, especially for settings that are not handled by the GNOME UI tools. It's principle is quite simple. A new gsettings key hotplug-command in the org.gnome.settings-daemon.peripherals.input-devices schema points to an executable. This executable is called at gnome-settings-daemon startup, whenever a device has been added and whenever a device has been removed. Something like this:


$HOME/executable -t added -i 12 My device name


So the device with the ID 12 and the name "My device name" just got added. Other types are "removed" and "present" for those device that are already present when g-s-d starts up. It's quite simple to configure any device to your liking now. Have a look at the input-device-example.sh script shipped with gnome-settings-daemon. I'll give you two examples of what you could add to the script and the rest should be easy enough to figure out:


# Map stylus button 1 to button 8
if [ "$device" = "Wacom Intuos4 6x9 stylus" ]; then
xsetwacom set "$device" Button 1 8
fi

# map tapping to LMR instead of default LRM
if [ "$device" = "SynPS/2 Synaptics TouchPad" ]; then
xinput set-prop $id "Synaptics Tap Action" 0 0 0 0 1 2 3
fi

Friday, March 4, 2011

How to DOS a developer

So you think your favourite FOSS project is moving too fast? Easy, just DOS the developers. Here's a few tips on how to achieve this:

On IRC



  • If you have a problem, just state that you have a problem. Let the developer ask for what exactly it is. Then answer every question with the minimum amount of information possible and let the developer keep asking.

  • Wait 5 minutes before answering but keep asking why the developer doesn't answer immediately. That way you can maximise the context switching costs of the developer, ensuring he or she can't get anything else done while waiting for you.

  • If the developer asks for version numbers, be vague. Things like "whatever was in $DISTRO three days ago" is best because unless the developer is also the distro maintainer, you've answered the question without providing any information.

  • Don't stay on IRC. Just go offline whenever your computer goes to sleep and re-ask the question every time you reconnect. This way you ensure that those not monitoring the channel will try to answer the questions whenever you're currently offline. Never send email to the list, because others could answer it in their own time.



Via email



  • Send bug reports to the developers directly. That way you force them to reply with at least "please file a bug in $BUGZILLA". That takes 2 min of their time, not counting context switches. Make sure you reply with more than one "thank you" email so they need to deal with more email.

  • Randomly remove the CC from mailing lists during discussions. That way you make sure the developer has to answer twice if they didn't notice the CC was missing.

  • When taking discussions back onto the list, misquote (or purposely misinterpret) the results of the private discussion. Force the developer to justify themselves in public.

  • Be verbose. As verbose you can be. If you can say something in one sentence or three paragraphs (with three overlapping or identical examples), choose the latter. Searching for signal in lots of noise is a favourite pasttime of many developers.

  • If you change the subject of a discussion, leave the email subject as-is. This way you ensure that the email cannot easily be found later. Wait for a few weeks, then refer to this discussion, but not in the same thread.

  • Pastebin everything instead of including it in emails. Links to websites, backtraces, log files, patches, etc. Make sure the pastebin has a short expiry date.

  • If you must include something as attachment, make sure it's at least in a zipfile so no-one can look at it without a few mouse-clicks first.



Via code



  • When commenting on patches, reply with vague statements on how the patch doesn't work. This way, the patch is made to look bad and the developer now has to spend time making sure your vague statements weren't just unfounded.

  • When testing code, make sure you don't explain how a bug happend. Just say "after a while it crashed", that's enough information for anyone to figure out what's going wrong.

  • Read The Daily WTF and gain inspiration for your next open source project. If you ever get other people helping you, you maximise their pain.

  • Don't document anything. Just use arbitrary hardcoded values, with no explanation.

  • Never, ever, explain why you're doing something. Code is not meant to be self-explanatory.

  • Don't follow anything I said in on commit messages

  • Do everything as complicated as possible but don't explain why. Obfuscating that you're flipping the sign of a variable three to four times is a good example, anyone reading the code is sure to spend hours on it

  • Use numbers as both bools and numbers. C is great for that, you can return 2 and then use it as Boolean and as actual numeric value lateron. Hide any such usage as well as you can.

  • When sending patches, mix code changes with arbitrary whitespace changes. Fun minutes can be spend looking at two identical lines trying to find the difference that's missing.

  • When sending updated versions of a patch, don't tell anyone what has changed. That way, you force your reviewers to review the whole patch, every time you change a single character.

  • When sending patches, make sure that it only fixes the problem on your specific setup. That way you also can tell the developers off for not merging an important bugfix that clearly works when you tested it. And you force them to reply to you.



Those are just the immediate things that come to my mind. If the project is already low on manpower, any of these will have a high impact. If it has enough developers, you may need to use several of them at once to tie up the most resources. Of course all this requires developers that still think that communicating with users is worthwile and that other people generally tell the truth. If they have given up on humanity, they may just ignore you and keep improving the project. In that case, you can at least badmouth everyone on tech "news" sites forums and comments.

Oh, in case you're wondering why I don't get anything done lately, see above. I realise that probably none of it is intentional, though the net effect is the same.

Friday, February 18, 2011

evtest is now on freedesktop.org

evtest, that little program that displays kernel input events and information about input devices now has a home on freedesktop.org. I hope this helps to reduce the number of different upstreams and distro-specific patches that float around.

Code: http://cgit.freedesktop.org/evtest/

Bugzilla: https://bugzilla.freedesktop.org/enter_bug.cgi?product=evtest

Friday, February 11, 2011

Relative and absolute devices in X

One of the recurring questions about to input event handling is how relative and absolute devices are handled in X. Surprisingly, the answer is "that's complicated" and it took me a while to wrap my head around this.

Back in the days of yonder, devices had no mode. X (the coordinate, not the window system) was x, y was usually y unless bugs intervened and we all had mice, computers the size of fridges and fridges the size of, well, fridges. Such was the lore, blah blah (those of us who are old enough to actually remember those days, which excludes myself for example, may remember them fondly).

In 1994, the new kid on the block (not one of the singing ones, they disbanded that same year1, presumably for other reasons. Though that'd be one thing I'd love to be credited with...), the X Input Extension protocol added support for device mode and the notion of relative and absolute devices was born (within the Xiverse, anyway). Fast-forward half a lifetime of something that lives for 30 years and XI2 added to that per-valuator modes. i.e. a device may have an absolute X axis and a relative Y axis.

But: the device mode in X describes the behaviour of a device only. On an absolute device, the pointer is expected to jump to the position the device tells it. On a relative device, the pointer is expected to move by the coordinates provided, based on the current pointer position (and accounting for pointer acceleration).

However, there are no requirements for how to send coordinates and absolute devices may send relative data and vice versa. So inside the server, the mode of a device (or a valuator) has no meaning. It's merely a flag sent to the client.

Which makes mode processing a bit tricky because the only time we know if an event was relative or absolute is when we receive the actual event (events include a absolute/relative flag). An absolute device may calculate deltas based on the previous position and then submit the new position as absolute coordinate - and thus feel like a relative device to the user. For whatever reason you'd want to do this, I don't think any driver does it atm (though I have vague recollections of having done this in the past). But it just adds to the insanity that is input in X.

Either way, we cannot rely on the device mode for anything in the server, and the actual device mode is just a hint to the client.

1I had to wikipedia this. I wonder what that does to my reputation when the admins see the logs.

Friday, February 4, 2011

Reviewing patches backwards

Though this may be obvious to some, I only learned a short while ago that it's much easier to review patches bottom to top. Why? Because much code is written bottom to top.

In C, one uses static functions for code that doesn't need to be exported. Because we're lazy and try to group code together, many statics don't have a separate declaration. So you end up writing with code like this:


static void cure_world_peace(void) {
...
}

static void save_cancer(void) {
...
}

static void solve_all_problems(void) {
cure_world_peace();
save_cancer();
}

void foo(void) {
...
solve_all_problems();
...
}


When you're reviewing top to bottom, you see the new feature first but lack the context. This gets more and more confusing the more functions you see because you have to keep in mind what they're doing. Reviewing bottom to top means you'll see the context first and you can tick it off mentally. Only then will get to the static functions and see the details.

And coincidentally, this is also how I write code - smack the hooks where they belong and then implement the details.

Tuesday, January 18, 2011

The deficiency argument

There are many good reasons for bugs not getting addressed. One of them is the design argument ("this system isn't designed for this feature") or the dependency argument ("this bug is in this library we link against"). Both are valid explanations for why a software project does not address a bug directly. And of course the ever-present reasons "lack of time" and "not enough manpower". However, quite often the defence for a bug in some software is along the lines of "Windows can't do this either".

If you explain a deficiency in your software through the deficiencies of competing software, you still have a problem.

I don't care whether other implementations are buggy when I'm using some software. I care about what I'm using because there's a compelling reason why I chose this one. And if it doesn't do the job, it needs to be fixed.

Always strive for your software to be excellent and look to other software for inspiration, not excuses.

Monday, November 22, 2010

A High-Level Overview of Grabs

One of the most common topics coming up in X input is grabs. This is a high-level overview of input device grabs and how they affect input event processing. Note that the examples here are simplified, grabs are probably the most complicated topic in input processing.

By default, X input events are delivered to all clients that registered for a specific event on a window. The basic premise of a grab is that it affects event delivery to deliver events exclusively to one client only.
There are three types of grabs, two classes of grabs, and two modes for a grab. The three types are:

  • active grabs

  • passive grabs

  • implicit passive grab



The two classes are core grabs and device grabs and the two modes are synchronous and asynchronous.
A grab comes in a combination of type + class + mode, so a grab may be an "active synchronous device grab".

Grab Types


Let's look at the difference between types first.

Active Grabs


An active grab is a direct result of a client request. The client requests "Grab this device and deliver its events exclusively to me". Future events are then delivered to this client until the client "ungrabs" the device again.
From a UI point-of-view, active grabs are commonly used when events must go to one specific application, regardless of the pointer or keyboard focus. One example are popup menus, where you want the next click to either activate a field or remove the window when clicking outside of the popup menu.

Passive Grabs


A passive grab is a promise by the X server to grab the device next time a button or key is pressed. The client essentially requests "grab the button when it is on window W and Alt and Shift are down". This request is stored and in the future when the pointer moves into window W, the specified modifiers are down and the user presses the button, the passive grab is activated (so now we have an "activated passive grab") and events are delivered exclusively to the client that requested the passive grab. Once the button or key is released, the passive grab is released again (and events are sent to all applicable clients). Unlike active grabs, passive grabs will activate repeatedly whenever the conditions are met. Ungrabbing a passive grab means to remove the conditions that trigger the activation of a passive grab.

XI2 added enter/leave and focus in/out passive grabs in addition to the already common button and key grabs. So a passive grab may activate when a pointer enters the window now.

Implicit Passive Grabs


These are a special type of passive grabs that are not under the direct influence of clients. Whenever a button press event is delivered normally to a client (i.e. no passive grab activated), this client gets an implicit passive grab on the device to ensure that future events, most notably the release event, is also delivered to the same client. Implicit passive grabs only come in synchronous mode, more on that later.


Grab Classes


In the core X protocol, only pointer and keyboard grabs are defined. With the addition of the X Input Extension, the device grabs were added as well. The only real difference is that with the latter a client explicitly specifies which device to grab. In the case of a core grab, the client simply says "grab the pointer" or "grab the keyboard", in the case of a device grab, the client must specify a valid device to grab. The class of a grab affects the events being sent to the client. A client with a core grab cannot receive X Input events from this device and vice versa.
With the addition of MPX and XI2 to the server, core grabs now work according to the ClientPointer principle. Since one of the requirements for MPX/XI2 was to not interfere with core applications, the behaviour of the two classes of grabs differs slightly.


  • A core grab is a promise that the device will only send events to the grabbing client, and that no other device may interact with the client while the grab is active.

  • A device grab is a promise that the device will only send events to the grabbing client but other devices may still send events to this client too.



The basic assumption here is that core applications do not know about the existence of multiple devices, but XI-aware applications do. Other than that, the two classes behave mostly identical.

Grab Modes


Grabs, with the exception of implicit passive grabs, may come as synchronous or asynchronous grabs. Asynchronous are simple: the event stream is processed by the X server and sent to the grabbing client immediately. During synchronous grabs, the server will queue up events internally and ask the client how to continue for each event. On a synchronous passive button grab for example, the client will receive the first event (the button press) but no more. It can then decide what to do and instruct the server how to proceed with the events. One common instruction is to "thaw" the device, i.e. release the event stream and continue in asynchronous mode. The other common instruction is to "replay" the event. This is a common operation for window managers which put a grab on mouse buttons as it allows them to reshuffle windows before the event is seen by an application. The list of actions is essentially this:


  1. Button press occurs on window W.

  2. Synchronised passive grab for window manager WM activates.

  3. WM receives button event.

  4. WM brings window W to the foreground.

  5. WM requests to "replay" the event.

  6. X server deactivates passive grab.

  7. The same button press event is now sent to W and the clients listening for button events on W.



Misc Other Info


If a client requests an active grab, you are at the mercy of this client. If the client decides to not ungrab (for whatever reason, usually a bug), then you will not be able to use the device on any other application. This is what's commonly referred to as "stuck grab". The only way to get out of this at the moment is to find the offending client and kill it. All grabs for a client are automatically terminated when a client exits.

A passive grab may be converted into an active grab. If a client already has a passive grab and requests an active grab on the same device, this active passive grab is converted to an active grab and thus does not terminate automatically anymore. The client then has to send an ungrab request to the server. This is a common operation for popup menus, a client has a synchronised passive grab that is converted into an asynchronous active grab once the passive grab activates. It only works passive → active though, an active grab cannot be converted into a passive grab.

All grabs are based on to a window and the event coordinates in the subsequent events are relative to that window's origin. During a grab, the pointer or keyboard is regarded as inside this window (even when outside the window's boundaries) and thus enter/leave and focus in/out events are sent as if the device had left the previous window. These event will have a flag set to notify other clients that the leave or focus out event was caused by a grab.

If you think all this is confusing, look at the code that implements this :)
Also note that this post skips on a number of details and contains some amount of handwaving and sticking fingers in your ears and going "lalalala".


[edit] fix typo, on synchronous button grabs the client receives only the first event.