SPY HILL Research
Spy-Hill.com

Poughkeepsie, New York [DIR] [UP]

Notes on developing
a Unix Screensaver for BOINC


This page contains a collection of what I've learned about screensavers for Unix and X11, and some ideas on how best to proceede to create the screensaver code for BOINC for Unix systems.

Last modified: 16 March 2010
The goal of these notes is to write down what I know about screensaver graphics for Unix computers using the X11 window system. As I'm putting this together I don't have any particular recomendations, but I'm hoping that writing this all down will result in a clear path to how to best develop the screensaver code for BOINC for Linux.

This document is still a draft and is quite incomplete.

Overview of BOINC graphics with OpenGL and GLUT

BOINC screensaver graphics are written using OpenGL, which has several advantages. OpenGL is common to a wide variety of platforms, including the primary BOINC platforms: Windows, Mac, and Linux. OpenGL, or at least an important subset of it, is also implemented in hardware in many computer graphics cards, which means the graphics can run on a computer's GPU rather than the CPU, allowing the CPU to work on the computation thread, or at least taking some load off the CPU.

The OpenGL library contains basic rendering functions, but a collection of commonly used but more complicated functions is provided by an additional library, called the GL Utilities (GLU). The GLU library is the same for all platforms. All of the GLU functions are written in terms of OpenGL primatives.

OpenGL handles graphics rendering, but it does not deal with system-dependent aspects of dealing with the windowing system, such as creating, resizing or destroying a window, getting input from the keyboard or mouse, or writing text to the screen (ie., fonts). These tasks are handled by different libraries written for the different platforms: For Windows there is wgl, for the Mac there is agl, and for X11 there is glX.

A convenient way to write OpenGL programs which are portable across all platforms is to use a library written by Mark J. Kilgard called the OpenGL Utility Toolkit, GLUT. GLUT presents a common API for the programmer but takes care of the system-dependent tasks of opening or managing windows, keyboard and mouse input, and text. GLUT on Windows is implemented using wgl, while on a Mac it is implemented using agl, and on X11 it it implemented with glX. GLUT also takes care of other common graphics tasks, such as creating the event loop and handling windowing events. GLUT makes it much easier to write OpenGL programs quickly while focusing on the graphics, not the underlying structure to support graphics with event processing, and your programs are more readily portable.

BOINC presently uses GLUT for graphics on Linux and the Mac. BOINC presently does not use GLUT on Windows, except for some reference to GLUT fonts in the file gutil.C.

Although GLUT provides many advantages, there are also some drawbacks. One is that the way keyboard input is handled in GLUT is slightly different from how it is handled (without GLUT) on Windows, and is somewhat restrictive. On Windows a keyboard event routine is called whenever an individual key is pressed (or released), and the keycode for that key is passed as an argument. With GLUT, the key-pressed routine is only invoked when certain keys are pressed, and in this case the character code is passed as an argument. The difference is subtle but important. For example, on Windows if you press and hold the control key and then press the C key, the key-pressed routine is called first for the control key, then for the C key. Using GLUT on Linux, the key-pressed routine is only called once, sending the character code for ctrl-C, only after the C key has been pressed.

The BOINC code for Windows now has a feature which allows one to hold down the control key and then manipulate the screensaver image with the mouse or keyboard, without terminating the screensaver. (Actually, this is only possible right now if you have selected "Run Always", but it may be possible to extend this feature even to when "Run according to user preferences" is selected. This will likely require a change to the BOINC core client, not just the graphics routines used by the application.) In Linux, since GLUT is used for keyboard input, it is not possible to sense when just the control key has been pressed, so this screensaver manipulations feature is not possible.

GLUT also has problems with creating a full-screen borderless window on some X11 desktops. You get a window the size of the screen, but it has a border and it does not exactly cover the screen, but instead exends off the screen onto the next desktop segment (this is observed with fvwm2).

It turns out that in X11 there are some conventions used by screensaver programs like xscreeensver and desktop environments and window managers such as Gnome, KDE, and fvwm, and GLUT does not pay any attention to these conventions.

Thus it may be desirable to abandon GLUT for Unix screensaver graphics for BOINC, and instead replace the relevant code with the appropriate glX code, or with code based on SDL (the Simple Directmedia Layer). Potential options are discussed further below.

It should be noted for the discussion below that each platform also has it's own graphics functions which are a part of the native window system, separate from OpenGL. X has it's own graphics API which is separate from OpenGL on X. Windows has GDI, the Graphics Device Interface. Mac has it's own graphics system, called Aqua(?). But each also has an API for OpenGL on that platform.

xscreensaver

Xscreensaver is a popular and versitile screensaver framework for Unix computers which use the X11 window system. It was written by Jamie Zawinski, and the code is freely available for download from www.jwz.org/xscreensaver The primary component of xscreensaver is a program which runs in the background and waits until the keyboard and mouse are idle for a given period. It then runs one of a variety of graphics demos, chosen at random, until someone uses the mouse or keyboard.

Each graphics program used by xscreensaver is called a 'hack'. There are about 180 graphical hacks included in the latest xscreensaver distribution. The graphical hacks are modular. Each is compiled with common code for the main program, resulting in a separate standalone program. If you just run this standalone program from the command line then a new window pops up on your screen containing the graphics demo. If you run one of the programs with the -root flag then the graphics appear in the "root" window, which in X11 is the rearmost window. However, if the program is run with the -root flag by the xscreensaver daemon then they appear in a full screen window in front of all other windows -- thus a "screen saver" graphic.

The Virtual ROOT window

The way xscreensaver puts the graphics into this frontmost window is a bit clever, but also a bit complicated. There are simple, standard macros in X11 to determine the root window for a given X11 screen, and all the hacks use one of these when the -root flag is given. This was a common thing for many X11 graphics programs to do. When xscreensaver wants to display the screensaver it opens a borderless window the size of the screen and in front of all other windows, and it gives this window a special property which marks it as the "virtual root" window.

The graphical hacks are also compiled with a special header file, vroot.h, written by Andreas Stolcke, which redefines the X11 macros RootWindow and DefaultRootWindow to make them look for a virtual root window. If none is found, the ordinary root window is returned which retains backward compatibility with standard window managers.

The whole idea of this "vroot hack" is to leverage backward compatibility with existing graphics programs and window managers. Many graphics programs already drew to the root window if the -root flag was given on the command line, and several window managers put screensaver graphics in a virtual root window. The "vroot.h" hack just brought the two ideas together.

More modern window managers still "play nice" with virtual root windows. Thus xscreensaver works with the Gnome and KDE desktop environments, and the twm, fvwm1 and fvwm2 window managers. Some of these may also have other mechanisms for indicating that a window is to be considered a screensaver window. In any case, a Unix screensaver for BOINC should therefore utilize the same mechanism(s).

GLUT and the VROOT window?

Since BOINC currently uses GLUT to create the screensaver window I have tried to create a replacement for the function glutFullScreen() which would detect an existing vroot window and somehow "attach" the graphics to this window, instead of just creating a completely new window. I've been able to detect the presences of a VROOT window, but I have not yet been able to get GLUT to use it. The problems might be due to inherent protections between several users modifying the same window, or it could be as simple as not correctly setting up the GL context.

My inability to get this to work may be due to my inexperience with X11 graphics. However, I recall finding comments in the xscreensaver code saying it wasn't likely that GLUT graphics could ever be made to work with xscreensaver. If Jamie Zawinski can't do it then I doubt that I can, at least not yet. So right now I'm not pursuing this idea any further.

OpenGL screensaver 'hacks' from xlock 'modules'

Most of the xscreensaver graphical hacks, about 130 of them, are written in pure X11 graphics, but about 60 of them are written in OpenGL. The code for all the hacks is found in the hacks subdirectory, while the OpenGL hacks are found under this in hacks/glx (since they use glX to open windows and read input and window events). These are yet another example of a clever bit of interface code making it possible to use a large existing base of graphics code. Most of the glX hacks are actually from a competing screensaver program, called xlockmore, which is the successor to another screen locking program, called xlock. The structure of xlockmore is slightly different from xscreensaver. Each separate graphics demo is a 'module', and they all are compiled together into one monolithic program. Jamie Zawinski, the author of xscreensaver, wrote a bit of interface code which allows the xlockmore 'modules' to be compiled as standlone graphical 'hacks' for xscreensaver. This might be considered a kludge, but it's a very useful and clever kludge.

OpenGL for BOINC without GLUT

In the event that we decide to stop using GLUT for BOINC graphics on Linux then we will have to write our own replacement code. This code will have to find the VROOT window (if such exists, otherwise create a fullscreen window), create an X11 "Visual" to go with it, create a GL graphical "context", and then run an event loop which renders a single frame of graphics and then processes input events or window events. This is already done for BOINC in Windows (see the file windows_opengl.C), so emulating that file would be helpful.

If we go this way then the easiest way to do it would be to also emulate the glX code which already exists in xscreensaver. In particular, the event loop and window initialization are in the file screenhack.C, with the GL code enabled when the macro USE_GL is defined. Some additional functions required just for GL are in the file xlock-gl.C, and some important headers are in xlockmore.h and xlockmoreI.h, though not everything in those files is actually need.

The Microsoft Developers Network site has some useful notes on the correspondence between glX and wgl/WIN32 functions here. (You probably have to select the item "GLX and WGL/Win32" after you get there.)

An alternative to GLUT which might do the job without requiring us to rewrite the event loop and window initialization is to use SDL [www.libsdl.org]. I've just learned about this library so I don't know if it would be easier to code with this library or if it handles keyboard input and full screen windows the way we need them. It should be investigated. SDL is available for Windows, Mac and Unix, so anything written with SDL should be portable across all these platforms.

OpenGL for BOINC with freeglut

An alternative to GLUT is freeglut...
  • Freeglut documentation is incomplete
  • Freeglut adds some extentions beyond traditional GLUT, which may be of use.
  • Freeglut may have key release routines like Windows, so that we can detect ctrl key down.
  • Freeglut "game mode" already exists to do full-screen take-over (how is that different from glutFullscreen()?)
    
    
    

    starboard - using the GL 'hacks' with BOINC

    As already demonstrated above, there is a long tradition in the field of X11 screensavers of writing a layer of interface code which enables one to use a wide variety of pre-existing graphics routines in a new way. Following this tradition, I propose to write a layer of interface code which will allow any of the glX graphics hacks from xscreensaver to be used as screensaver graphics threads in BOINC applications.

    I haven't quite gotten it working yet, but as of this writing I feel like I'm close. Here is how it works:

    1. Select the particular glx hack you wish to use, and identify the files it uses. The simplest hacks are in only one file, maybe with supporting headers. The more involved screensavers are spread out over several files. The first example I'm trying this out on is the M.C. Escher "impossible cage" demo, which is in the file cage.c and uses the wood texture informaiton in the file e_texture.h

    2. Compile these hack files along with a modified version of the header file xlockmore.h. This header in turn includes "fake" versions of X11 declarations and some entry points from the files Xfake.h and glXfake.h. Then xlockmore.h includes an unmodified version of xlockmoreI.h, which primarily defines an internal structure called ModeInfo which is used to recored window state information.

    3. Compile the interface layer glxhack2boinc.C with the unmodified xlockmoreI.h header file. This creates function callbacks for the BOINC initialization, drawing, and reshape routines.

    4. Compile with your BOINC application, or with the "boinclet" test program to test just the graphics.
    An additional complication is that BOINC is written in C++, while screensaver is in strict ANSI C.  

      Copyright © 2010 by Spy Hill Research http://www.Spy-Hill.com/~myers/help/boinc/unix-screensaver.html (served by Islay.spy-hill.com) Last modified: 16 March 2010