Snow issues

Technical issues

C vs C++

Xsnow is written in C. However, because I needed a reliable hash function to maintain a cache of bird surfaces, some C++ has been crept in. To store the bird surfaces, an 'unordered_map' is used if available. Otherwise, 'map' is used, which is not implemented as a hash function but as a binary tree. For housekeeping of the snow flakes, an '(unordered) set' is used. The WWW recommends to compile the main program with C++ when using a mix of C and C++, so a very small main() is written in C++, which calls the original C main() function. All sources have been adapted to compile using C++, so, if you are a C++ adept, you can do:

   CC=g++ ./configure
   make install


The original xsnow-1.42 has an more or less ad-hoc timing mechanism. The program offers many flags to tweak the speed of Santa, the speed of snow and the like. Xsnow-2.0 has a more straight forward timing mechanism, in principle, every speed is defined in pixels/second.

The updating and drawing of Santa are decoupled, so the refreshing rate of Santa does not affect His speed.

Fallen snow (bottom and on windows) is nice in xsnow-1.42, but after running for some time, the visualization of fallen snow is not realistic. Therefore I use now a complete new strategy for the handling of fallen snow.

The handling of wind is changed in xsnow-2.0: it is now more or less windy all the time, but the original code from xsnow-1.42 is still used to experience more dramatic wind effects. The algorithm for the sensibility to wind of Santa and snow has been changed: The velocities of Santa and snow are changed by the wind.

In xsnow-1.42 an fixed-length array was used to hold the snow flakes. In xsnow-2.0, the flakes are in a double-linked list. But now, the housekeeping is done with a C++ 'set' or 'unordered set'. This makes it possible to add snow flakes at random times, for example when converting fallen snow to snow flakes. Furthermore, the amount of snow is now determined by the rate the flakes are produced and removed. The production rate is given in flakes per second per pixel (i.e. the width of the window measured in pixels). This has the effect that, in a steady state situation, a larger window shows more flakes than a smaller one.

Inspired by project wsnow, written in JavaScript, I searched for an equivalent for setTimeout() in gdk/gtk. Indeed there is g_timeout_add_full(), which I overlooked or did not understand in the past. For 2.0.20 I rewrote all timed events using that function, which led to a better readable and simpler code. No double linked list any more for snow.

Since I stumbled upon https://www.cairographics.org/Xlib/, I decided to use only GTK/cairo to make the animations.

The preferred way for xsnow to make it's drawings is to use a transparent, click-through window that covers the whole screen.

This requires a compositing window manager, which is not always available. In those cases painting is done at the root-window (or window 'pcmanfm' when running LXDE). Using XdbeSwapBuffers and friends a double buffer is used. When this is not desirable (for example when running xsnow together with xpenguins), then you can specify the flag '--doublebuffer 0', at the cost of some flicker in the animations. Also, when you specify '-xwininfo' or '-id ', painting in the chosen window is done using double buffering, unless '-doublebuffer 0' is specified.


Before version 2.10, xsnow refused to run on Wayland (that is the proposed successor of X11 and is the default on recent Debian-derived installations). I was prepared for major code changes in xsnow, but, after lots of googling, I found a solution, at least for xsnow: simply set the environment variable GDK_BACKEND=x11. So, before the gtk environment is initialized (using gtk_init()), xsnow sets (using setenv()) that variable to the desired value. Of course, the official GDK documentation has something about the issue . It could very well be that things work thanks to XWayland, I really don't know very much about X11 and Wayland. In Wayland, applications have only a restricted control over the windows that are not owned by the application. So, xsnow cannot snow in other windows. But for many of the windows the information about the where-abouts are available to xsnow. For example, xsnow is snowing on the windows of firefox, gimp, gvim, xsnow, xterm, xclock and xcalc, but not on the windows of aislerioth, gedit, nautilus and gnome-terminal.

Other desktops

  • In KDE works.

  • In FVWM, TWM and the like, there are no problems.

  • In LXDE and XFCE there are no problems.

  • In Mint xsnow works the same as in Gnome.

  • In Raspbian (Raspberry pi's default desktop) xsnow runs by detecting the desktop is LXDE.

Desktop issues

  • Xsnow tries to find out if it can create a transparent click-through window. If successful, xsnow will create one. If not successful, xsnow will use the root window, except:

    • In LXDE, xsnow detects this environment and will snow on the window with the name 'pcmanfm'.

    • In XFCE, xsnow detects this environment and will snow on the window with the name 'Desktop'.

  • It seems there is something wrong with the Breeze theme: xsnow works, but the buttons behave strangely.

  • Xsnow can use arbitrary windows, you can choose one (using xsnow -xwininfo), or you can specify a window-id (using xsnow -id window-id). This feature does not always works perfect.

  • The location of the top of the windows (we need that to figure out where snow should fall on), including the decorations, is a known issue on the web. I found a solution for this issue: see the code in wmctrl.c (from the xsnow tarball). And, by looking at the code of the programs wmctrl and xwininfo and xprop, I was able to incorporate the things I need in xsnow with respect to choosing a window, locate a window etc.

  • In FVWM-like environments, xsnow starts on all workspaces. You can choose: run on all workspaces or run only in the current workspace. Among the downloads I included shell scripts 'startondesktop' and 'startonalldesktops' (I should have called then 'startonworkspace' and 'startonworkspaces'...) that you can try to start xsnow on (a subset of) all workspaces if xsnow itself does not run in all workspaces on your system.

  • Raspberry 64 bit, and maybe others: xsnow is confused by the 'xcompmgr' daemon, which results in a black background. The reason: xcompmgr is started by default with the flag -a, this seems to be beneficial for Openbox, but is detrimental for xsnow and others. I hope to find a fix for this, for now I have this remedy (I don't know if this is detrimental for Openbox...):

    • On the command line, before starting xsnow:
         killall xcompmgr
         nohup xcompmgr -n &
    • Or: start xsnow with xsnow -xwininfo and click on the desktop for a less than perfect xsnow experience.
    • Or (permanent solution): edit /usr/lib/raspi-config/cmstart.sh, change the flag -a for xcompmgr into -n and restart your system. I don't know if this is detrimental for Openbox...