Monday, February 28, 2011

Variable scope, require, and use

I ran into some interesting problems in Perl, which invoked more learning around the require/use mechanisms and how constants are interpreted.  In this post, I'll lay out some general terms about variable scoping, such as lexical scope, dynamic scope, the differences between them, and how they all interact in Perl.  And then I'll cover require and use with that foundation in place.

If you've been wondering about lexicals or closures, this is your post.  I've tried to lay things out more or less from basic principles, despite the verbosity of the approach, because this has taken me years to understand.  I started programming with Perl in 2000 and still learned a bit more about it today.  Yes, it's 2011 now.  Hopefully, you can read this and get it in less time.

Saturday, February 19, 2011

Changing a Tablet's Active Area in Ubuntu Lucid

The following information applies to Ubuntu 10.04 LTS, Lucid Lynx, with xserver-xorg-input-wacom installed to provide xsetwacom.  This is about fine-tuning your tablet; if your tablet isn't working at all, you probably need bug #568064.

There used to be a wacomcpl program to graphically configure a Wacom tablet; this quit working with changes to the upstream project and/or the Tcl dependency, so it hasn't been working for me for some time.  Before it quit working, I set up a script to call the xsetwacom command-line program with the desired results, so the loss didn't affect me.  Mainly, I had adjusted the active area so that tracing a circle on the tablet would result in a circular shape on the monitor.

With a new monitor came a new need to reconfigure the tablet, without using wacomcpl this time.  I ultimately created a couple of formulas to make a strip of the tablet inactive.  Without further ado, these are the formulas:

 $x_offset = $w - ($h * $aspect) # narrower monitor
 $y_offset = $h - ($w / $aspect) # wider monitor

$aspect is the aspect ratio of the monitor, obtained by dividing where you write the colon.  For example, 16:10 = 16/10 = 1.6.  Alternatively, you can divide the width in pixels by the height, so a 2560x1600 display has an aspect of 2560/1600 = 1.6.  (If you have square pixels, which practically everyone does because they're so convenient.)  The monitor being narrower or wider refers to whether the monitor's aspect is lower or higher than the tablet's, respectively.  You can calculate the tablet's aspect by dividing $w by $h; obtaining them is the subject of the next section.

$w and $h come from the actual tablet, which you can find easily enough.  In these commands, $T represents your tablet's name, which you can get from `xsetwacom list dev`.  In my case, there's a tool name attached, so it prints "Wacom Bamboo 4x5 Pen STYLUS" (among other things) but only the "Wacom Bamboo 4x5 Pen" portion is the actual device name.  The first command simply resets the coordinates to cover the full tablet, just in case they have been changed.

 xsetwacom set "$T" xyDefault 1
 xsetwacom get "$T" BottomX
 xsetwacom get "$T" TopX
 xsetwacom get "$T" BottomY
 xsetwacom get "$T" TopY

$w is BottomX-TopX, and $h is BottomY-TopY. 

Armed with this information, you should now choose the correct formula from above, and substitute all the numbers.  In my case, the top coordinates are both 0, so BottomX=$w=14720, and BottomY=$h=9200.

My old monitor was much narrower (at 1280/1024=1.25) than the tablet (at 14720/9200=1.6), so I used the first formula, thus:

 $x_offset = 14720 - (9400*1.25) = 3220

And to set that value:

 xsetwacom set "$T" TopX 3220

My new monitor runs at 1920x1080, which yields 1.7778 for aspect.  The monitor is wider than the tablet, so now I need the second formula:

 $y_offset = 9200 - (14720/1.7778) = 920

Now that the offset is known, it's a simple matter to set up.  I just add it to the original TopY value (zero for me, so no different) and set that as the new TopY:

 xsetwacom set "$T" TopY 920

Altering TopX or TopY means that the inactive portion of the tablet runs down the left or across the top.  I don't really care where the dead zone ends up, so I chose the method that results in the fewest calculations needed.  You could just as easily set BottomX to BottomX-$x_offset to move the dead zone to the right side of the tablet, or adjust both TopX and BottomX by half of the $x_offset to keep the active area centered.