Quickly Changing Display Outputs

Please ignore the messy deskMultiple-monitor support for X11 has greatly improved from when I started using it. For starters, you no longer have to edit a root-owned text file and restart your Xserver. Now we have the X11 RandR 1.2 extenstion and you can used use the command line on-the-fly or one of the many GUIs to change your output configuration. (If you don’t think this feature is that amazing, fair enough.)

All the major desktop environments have GUIs for display output configuration. Many times these desktop environments attempt to set output configuration at login. My primary computer is a laptop. At home I have a dock with an external monitor. Thus, 90% of the time my display output is in one of the two configurations: single headed laptop panel, or dual-headed laptop panel and external monitor. All the functionality I require is to toggle these modes. In Windows one can use the keystroke Super+P to quickly do so. In Gnome, whatever key generates XF86Display does this as well (if the gnome-settings-daemon xrandr plugin is enabled, which it is by default.)

The catch is that sometimes Gnome’s display output applet gets things wrong, or annoyingly my hardware likes to the generate the XF86Display keystroke when pressing Fn+F7, Dock Eject, Lid Open, Lid Close… etc. This causes my display configuration to change when I shut the lid (annoying), put the machine to sleep (annoying) or when I eject it from my dock (annoying if it didn’t notice that the external monitor isn’t there anymore.) I often find myself going to the command line and doing my output configuration manually.

Then a thought occurred; since I really only use two xrandr commands, there has to be a way to automate the process. One shell script plus Zenity later and this is the result:

#!/bin/bash
# multiple-monitors.sh: Quick-and-easy xrandr(1) arguments picker.
# (c) 2012 Arthur Taylor Permission is granted to any person to use, copy,
# modify, merge, publish, distribute, sublicense, and/or sell this script.
# This script is provided "as is", without warranty of any kind.

ICON="/usr/share/icons/gnome/48x48/devices/video-display.png"

XRANDR_COMMAND[0]=" --output LVDS1 --mode 1440x900 --output VGA1 --off"
XRANDR_COMMAND[1]=" --output LVDS1 --mode 1440x900 --output VGA1 --mode 1280x1024 --right-of LVDS1"
XRANDR_COMMAND[2]=" --output LVDS1 --off --output VGA1 --mode 1280x1024"
XRANDR_COMMAND[3]=" --auto"

TO_RUN=`zenity --list --width=640 --height=240 --window-icon $ICON --title="XRandR Settings" --text="Pick (or edit) an XRandR configuration:" --column="command" --hide-header --editable "${XRANDR_COMMAND[@]}"`

if [ "$TO_RUN" != "" ]; then
    xrandr $TO_RUN
fi

All this script does is take chose text from the chosen list entry and pass it as arguments to the xrandr command (see xrandr(1) man page.) I know this isn’t to most user-friendly method of changing display outputs, and it doesn’t provide failure feed-back, but is quicker than opening a terminal and typing it from scratch.

If you use Openbox, then a keboard shortcut for can be done by simply adding the following to your rc.xml keybindings section:

<keybind key="XF86Display">
  <action name="Execute">
    <execute>bash /the/path/to/multiple-monitors</execute>
  </action>
</keybind>

Linux Console K_OFF Mode in X.org

A patch I submitted to the xorg-devel mailing list marks the end of the K_OFF story described in my previous post <link>. Almost a year later and the xserver handler to vacuum away needless buffered key events, preventing a kworker kernel thread going nuts, is no longer needed. Shortly after it was reviewed and pulled into X.org 1.12-rc1. The commit is fairly small: ff891bbf68caefc22cabb541b6b56af086ac2280.

On a whole, I’m proud to have contributed to two major open source projects, the Linux kernel and the X.org Xserver, albeit only two small patches. During the process I learnt a lot about how F/OSS projects organize themselves and how to communicate with developers and project leaders. I would like to state that the responses I got back from both projects were patient and helpful, and on the whole the process, while a learning experience, was quite easy.

Specifically, I now know about git-format-patch and git-send-email. Also useful to know is that you can setup Git to send through Google’s SMTP servers if you have a GMail (or a GMail based domain email) account. The settings (for the record so I don’t lose them) are:

sendemail.smtpserver = smtp.gmail.com
sendemail.smtpserverport = 587
sendemail.smtpencryption = tls
sendemail.smtpuser = <your Google domain account>

Linux Virtual Terminal Keyboard Mode “Off” Patch

Last December I noticed a strange problem with my Linux system. Every once in a while I would experience about 1000 wakeups/second, a condition that would persist until I restarted my Xserver. These wakeups seemed pointless, failing to use more than 1% CPU usage, but none the less would cause it never to enter lower sleep states, and as this is on a laptop, eat more battery power. I was confused as my friend had similar hardware to mine, but failed to experience the intermittent wakeup problem. A little bit of investigation revealed that this was caused by the kernel tty-layer helper workqueue named “flush_to_ldisc” spinning in an infinite wake up, do no work and reschedule loop. More investigation showed that the loop was caused by my non-standard Xserver configuration not enabling a workaround of an old kernel behaviour.

Previously the Xserver on Linux received its keyboard events by reading from the virtual terminal device. The Linux console works by having a range of virtual terminals, only one of which is connected to the actual console at a time. Each VT has its own input and output buffers and also maintains its own state. The way that keyboard events are handled in the VT is called the keyboard mode. The normal keyboard mode, the one used by a text console, is translate mode, in which the kernel translates scancodes to characters, handling special keys and buffering the rest in the VT. As the Xserver does its own keycode handling and translation it uses raw mode in which raw key up and down events are buffered in the VT.

A new way to handle input devices, the Linux Input Subsystem, became the input base for kernels since 2.5. This subsystem, among other things, exposes the individual input devices to userspace as individual character devices. The X.org Xserver by default now only uses the input-evdev driver to get all keyboard input directly from the input subsystem rather than through the VT. This is great except for a few, shall we say growing problems. First, if the virtual terminal’s mode isn’t set away from translate, special keys are still handled by the kernel, causing ctrl+c to kill the Xserver and other shenanigans. The second problem is that while the Xserver opens a VT, it no longer reads input from it. Every key press gets buffered in the VT and as nothing reads from it, eventually overflows.

The infinite work queue I witnessed was caused by the VT input buffer trying to flush new key events when full.

The first problem I listed with fixed in the Xserver by setting the current VT to always be in raw mode [1]. The second problem was fixed in most cases by setting up a separate task to call flush on the VT input buffer whenever stuff appeared in it [2]. The Xserver would only do this if the server option “AllowEmptyInput” was true, in which case the Xserver knew that input-kbd wouldn’t be in use. If AllowEmptyInput was false but input-kbd wasn’t used the input buffer would fill up. This latter configuration was what triggered the bug for me.

All of this seems rather hack-y and sub par. Surely their should be a way to simply disable the VT input buffer? This being open-source, I took it upon myself to fix the issue. The simplest way would be to create a new console keyboard mode called “off” in which both kernel special keys are ignored and the input buffer remains empty.

My first try was to deregister the tty layer’s input subsystem handler if the current terminal’s keyboard was in off mode. This solution is nice in the sense that it stops a lot of redundant code from being executed per keyevent at the source. Unfortunately there was a complication with shift (or modifier in X11 parlance) keys and shift states.

The second try simply returns early before key events are buffered or special keys are handled. This solution was cleaner, always worked, and only involved nine lines of changes.

After testing the different situations and using it for a month and a bit I decided to try and get the changes into the main kernel tree. A few emails and two weeks later, boom, my patch was accepted by Greg KH into the tty-next branch [3], then pulled into the linux-next branch awaiting the next merge window for linux 2.6.39. The whole affair was quite easy and satisfying. The next step now is to write up a more formal patch for the X.org Xserver. The changes to the Xserver are quite minimal but will require that the updated kernel headers to be installed at compilation time.

[1] X.org X server commit 446d9443cea31e493d05c939d0128a8116788468
[2] X.org X server commit d936a4235c9625bd41569cef3452dd086284e0d7
[3] Linux tty-next commit 9fc3de9c83565fcaa23df74c2fc414bb6e7efb0a

Winter Snow in Victoria

Being one of the warmest cities in Canada, ocean-surrounded Victoria rarely gets much snow. When it does snow, it doesn’t usually stick. On Wednesday I woke up to a bit of a surprise, worthy of photographing. After snapping some photos I tried out my new skis for the first time, skiing down Mt Tolmie. That marks another completed goal from my list of things to do in Victoria.

[nggallery id=4]

Thinkpad BIOS Hacking

In November I had to take my Thinkpad in for servicing. Unfortunately the wifi card I had in it wasn’t supposed to be there by warranty, and further was hacked into the wrong slot with a piece of tape over one pin to keep the BIOS happy. After I got my system back (three 3 business days later!) it seemed like the perfect chance to hack the BIOS to make it get along with my wifi card. I decided to document my efforts. Here is the result.