Setting app name and class in Xlib
I was looking at Dave's little phase-of-the-moon Mac application, and got the urge to play with moonroot, the little xlib ditty I wrote several years ago to put a moon (showing the right phase) on the desktop.I fired it up, and got the nice moon-shaped window ... but with a titlebar. I didn't want that! Figuring out how to get rid of the titlebar in openbox was easy, just
<application name="moonroot"> <decor>no</decor> <desktop>all</desktop> </application>... but it didn't work! A poke with xwininfo showed the likely cause: instead of "moonroot", the window was listed as "Unnamed window". Whoops!
A little poking around revealed three different ways to set "name" for a window: XStoreName, XSetClassHint (which sets both class name and app name), and XSetWMName. Available online documentation on these functions was not very helpful in explaining the differences; fortunately someone hanging out on the openbox channel knew the difference (thanks, Crazy_Hopper). Thus:
- XSetWMName sets a property called XA_NAME which is primarily used to update the window's titlebar. Note that this may be more than the app name (for instance, Firefox puts the title of the current page in the titlebar). To use XSetWMName, you have to set up and populate an XTextProperty structure, which first requires that you set up a string list then run XStringListToTextProperty -- not difficult but it's several annoying steps.
- XStoreName is a shortcut to XSetWMName, a way to set the XA_NAME (titlebar name) in one step.
- XSetClassHint sets two properties at once: a name hint and a class hint. This is the name and class that the window manager uses for directives like suppressing the titlebar.
I didn't see much in the way of example code for what an app ought to do with these, so I'll post mine here:
char* appname; XClassHint* classHint; [ ... ] if (argv && argc > 1) appname = basename(argv[0]); else appname = "moonroot"; /* set the titlebar name */ XStoreName(dpy, win, appname); /* set the name and class hints for the window manager to use */ classHint = XAllocClassHint(); if (classHint) { classHint->res_name = appname; classHint->res_class = "MoonRoot"; } XSetClassHint(dpy, win, classHint); XFree(classHint);
And if anyone is interested in my silly moon program, it's at moonroot-0.3.tar.gz. moonroot gives you a large moon, moonroot -s gives a smaller one. I'm not terribly happy with its accuracy and wasted too much time today fiddling with it and verifying that it's doing the right time conversions. All I can figure is that the approximation in Meeus' Astronomical Algorithms is way too approximate (it's sometimes off by more than a day) and I should just rewrite all my moon programs to calculate moon phase the hard (and slow) way.
[ 21:15 Mar 18, 2008 More programming | permalink to this entry | ]