Patching X11::GUITest

Tags:

The Problem

I'm automating my X11 desktop and watch for windows with certain titles. But sometimes X11::GUITest doesn't find a given window anymore and then xlib takes the complete Perl process with it because X11::GUITest doesn't install the appropriate error handler for missing windows or windows without window decoration.

Error message:

X Error of failed request:  BadWindow (invalid Window parameter)
  Major opcode of failed request:  15 (X_QueryTree)
  Resource id in failed request:  0x0
  Serial number of failed request:  22767
  Current serial number in output stream:  22767

To debug this, I first need a way to somewhat reliably reproduce the problem. It seems that Steam is a good candidate, so I'll (re)launch it. It turns out that merely switching to the Steam window is enough.

I have a short Perl program that runs the query every second:

#!perl
use strict;
use warnings;
use X11::GUITest qw(GetInputFocus GetWindowName GetParentWindow);
sub get_named_focus_window {
    my $win = GetInputFocus();
    my $name;
    # We return undef if the window has gone away
    eval {
        do {
            $name = GetWindowName($win);
            unless ($name) {
                $win = GetParentWindow($win);
            }
        } until $name or ($win == 0);
    };
    return $win
}
while(1) {
  get_named_focus_window();
}

Patching the repository

The link to the repository of X11::GUITest is now at http://svn.code.sf.net/p/x11guitest/code/trunk/ due to some internal shuffling by Sourceforge... Instead of using the CPAN tarballs for patching, I will try to use the SVN repository. This takes substantially longer to clone at 1 second per revision but I can wait the 248 seconds.

Submitting the patch via SVN means we also can't use the convenience of git format-patch maybe but we'll find that out shortly.

The fix itself is fairly trivial. My test program shows me that the problem occurs whenever I call GetParentWindow() while the Steam window is active, so I add the appropriate guard around the call:

CODE:
  RETVAL = 0;
+ OldErrorHandler = XSetErrorHandler(IgnoreBadWindow);
  if (XQueryTree(TheXDisplay, win, &root, &parent, &children, &childcount)) {
    XFree(children);
    RETVAL = parent;
  }
+ XSetErrorHandler(OldErrorHandler);
 OUTPUT:

The bug report and patch are on rt.cpan.org now at RT ticket 139373