Posts

Fixing the XAnalogTV Screensaver

in Technical Articles

A few days ago, I discovered the awesome XAnalogTV screensaver included with XScreenSaver. I was very impressed with the visuals, which include a very accurate simulation of a conventional “tube” television implementing the analog NTSC TV standard. There was just one problem – I couldn’t get XAnalogTV to fill my screen:

XAnalogTV with Incorrect Scaling

In the source code, the virtual "display" is forced to be within 15% of a standard 4:3 display. Any screen which is outside of this 15% range is just clipped, as shown in this image.

In the above screenshot, pay attention to the edges of the screen. For some reason, the way the scaling/clipping was implemented caused the clipped portions on the screen’s edges to simply not be drawn (as they should be drawn or cleared to pure black). This causes the screensaver to look quite odd, especially when there’s perfectly drawn digital graphics being rendered behind the wonderful analog “snow”. I found this only happens when the aspect ratio of the XAnalogTV window was very different than 4:3. Thus, in my quest for beautifully simulated analog graphics, I set out to fix this error.

I set out to download the source code from Jamie Zawinski’s website, but at the time I wrote the post, the file he uploaded was corrupted (it has since been fixed). My next stop to find the source code lead me to the Ubuntu Package Repository, where I was able to download the source code (xscreensaver_5.15.orig.tar.gz). If you have a different Linux distribution, you should be able to get the source code from the distribution repository’s website.

After extracting the source code, I went into the source directory, and called ./configure. After it figured out I was missing a bunch of packages, I got all of the build dependencies via apt, and re-ran ./configure successfully:

sudo apt-get build-dep xscreensaver
./configure

Now, it was time to start analyzing the source code. I figured the best area to start looking at would be the code that gets executed when the screen is resized from xanalogtv.c:

static void
xanalogtv_reshape (Display *dpy,   Window window, void *closure, 
                   unsigned int w, unsigned int h)
{
    struct state *st = (struct state *) closure;
    analogtv_reconfigure(st->tv);
}

So, XAnalogTV uses helper functions embedded in another file, analogtv.c. Looking at the analogtv_reconfigure() function, all it does is pass an object to the analogtv_configure() function. There, I found the following code near the beginning of the function (comments removed):

    float percent = 0.15;  /* jwz: 20% caused severe top/bottom clipping
                                   in Pong on 1680x1050 iMac screen.    */
    float min_ratio = 4.0 / 3.0 * (1 - percent);
    float max_ratio = 4.0 / 3.0 * (1 + percent);
    float ratio;
    float height_snap=0.025;
 
    hlim = it->xgwa.height;
    wlim = it->xgwa.width;
    ratio = wlim / (float) hlim;
 
    if (wlim < 266 || hlim < 200)
    {
        wlim = 266;
        hlim = 200;
# ifdef DEBUG
        fprintf (stderr,
                 "size: minimal: %dx%d in %dx%d (%.3f < %.3f < %.3f)\n",
                 wlim, hlim, it->xgwa.width, it->xgwa.height,
                 min_ratio, ratio, max_ratio);
# endif
    }
    else if (ratio > min_ratio && ratio < max_ratio)
    {
# ifdef DEBUG
        fprintf (stderr,
                 "size: close enough: %dx%d (%.3f < %.3f < %.3f)\n",
                 wlim, hlim, min_ratio, ratio, max_ratio);
# endif
    }
    else if (ratio > max_ratio)
    {
        wlim = hlim*max_ratio;
# ifdef DEBUG
        fprintf (stderr,
                 "size: center H: %dx%d in %dx%d (%.3f < %.3f < %.3f)\n",
                 wlim, hlim, it->xgwa.width, it->xgwa.height,
                 min_ratio, ratio, max_ratio);
# endif
    }
    else /* ratio < min_ratio */
    {
        hlim = wlim/min_ratio; 
# ifdef DEBUG
        fprintf (stderr,
                 "size: center V: %dx%d in %dx%d (%.3f < %.3f < %.3f)\n",
                 wlim, hlim, it->xgwa.width, it->xgwa.height,
                 min_ratio, ratio, max_ratio);
# endif
    }

From the above code, you can see that the author has constrained the displayed picture’s aspect ratio to be within ± 15% of a typical 4:3 NTSC TV. This is fine, although something must be happening in the draw function to prevent the clipped parts of the screen from actually being updated/blitted.

As a temporary fix, I modified XAnalogTV to stretch to the window/screen resolution by commenting out lines 328 and 338 in analogtv.c, which are listed below (respectively):

      wlim = hlim*max_ratio;    /* Comment these two lines out (or remove them entirely) */
      hlim = wlim/min_ratio;    /* to prevent XAnalogTV from reshaping the display.      */

After that, I recompiled xscreensaver using make. Instead of calling make-install, however, I simply copied my newly compiled version of the XAnalogTV binary overtop of the older one (which was found in /usr/lib/xscreensaver/xanalogtv):

cp /usr/lib/xscreensaver/xanalogtv /usr/lib/xscreensaver/xanalogtv.bak
sudo cp ./hacks/xanalogtv /usr/lib/xscreensaver/

After restarting the xscreensaver daemon, the screensaver now works as expected:

XAnalogTV with Correct Scaling

After making the fix to the code, the XAnalogTV screensaver will properly stretch-to-fit any display or aspect ratio.



7 Comments

  1. Dan Schmidt Reply September 14, 2012 2:03 PM

    Finally – sombody found the solution! Much thanks. However, there was no space, it’s “wlim = hlim*max_ratio;”

  2. lexi Reply October 21, 2012 1:13 PM

    thats great, those visible borders are really annoying! i cant work out this make thing though :(

    • Brandon Castellano Reply October 21, 2012 2:12 PM

      Hi Lexi;

      Sounds like you might not have some of the required build dependencies. Check the output from make, and see if it says anything regarding missing libraries or header files (indicating you might need the -dev versions of some packages).

      Thanks,
      Brandon

  3. Matthew R Giese Reply October 21, 2012 7:14 PM

    I enjoyed reading the write-up, hope I can discover a lot more articles like this one. Thanks for posting.

  4. harpreet Reply October 13, 2013 1:25 PM

    Thank you so much.
    That just did the job.

  5. harpreet Reply December 26, 2013 10:49 AM

    can you please also fix the
    BSOD screensaver.

Post a Comment

Your email address will not be published. Required fields are marked *

*