Mercurial > audlegacy-plugins
comparison src/rootvis/getroot.c @ 900:d985f0dcdeb0 trunk
[svn] - add a starting point for xmms-rootvis port. giacomo will need to
finish this up, as my XLib skills are not enough at this time.
| author | nenolod |
|---|---|
| date | Mon, 26 Mar 2007 01:19:26 -0700 |
| parents | |
| children | f1b6f1b2cdb3 |
comparison
equal
deleted
inserted
replaced
| 899:68508f8cdf25 | 900:d985f0dcdeb0 |
|---|---|
| 1 /* I've modified the following file and renamed it. My modifications were just | |
| 2 * about getting rid of some toon.h dependants. If you're interested in the | |
| 3 * original version of the file, you can find it either in the sources of | |
| 4 * xpenguins or of xsnow. | |
| 5 * http://xpenguins.seul.org/ is my actual source. | |
| 6 * | |
| 7 * Johannes Jordan | |
| 8 */ | |
| 9 | |
| 10 /* toon_root.c - finding the correct background window / virtual root | |
| 11 * Copyright (C) 1999-2001 Robin Hogan | |
| 12 * | |
| 13 * This program is free software; you can redistribute it and/or modify | |
| 14 * it under the terms of the GNU General Public License as published by | |
| 15 * the Free Software Foundation; either version 2 of the License, or | |
| 16 * (at your option) any later version. | |
| 17 * | |
| 18 * This program is distributed in the hope that it will be useful, | |
| 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 21 * GNU General Public License for more details. | |
| 22 * | |
| 23 * You should have received a copy of the GNU General Public License | |
| 24 * along with this program; if not, write to the Free Software | |
| 25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 26 */ | |
| 27 | |
| 28 /* Since xpenguins version 2.1, the ToonGetRootWindow() function | |
| 29 * attempts to find the window IDs of | |
| 30 * | |
| 31 * 1) The background window that is behind the toplevel client | |
| 32 * windows; this is the window that we draw the toons on. | |
| 33 * | |
| 34 * 2) The parent window of the toplevel client windows; this is used | |
| 35 * by ToonLocateWindows() to build up a map of the space that the | |
| 36 * toons can occupy. | |
| 37 * | |
| 38 * In simple (sensible?) window managers (e.g. blackbox, sawfish, fvwm | |
| 39 * and countless others), both of these are the root window. The other | |
| 40 * more complex scenarios that ToonGetRootWindow() attempts to cope | |
| 41 * with are: | |
| 42 * | |
| 43 * Some `virtual' window managers (e.g. amiwm, swm and tvtwm) that | |
| 44 * reparent all client windows to a desktop window that sits on top of | |
| 45 * the root window. This desktop window is easy to find - we just look | |
| 46 * for a property __SWM_VROOT in the immediate children of the root | |
| 47 * window that contains the window ID of this desktop window. The | |
| 48 * desktop plays both roles (1 and 2 above). This functionality was | |
| 49 * detected in xpenguins 1.x with the vroot.h header file. | |
| 50 * | |
| 51 * Enlightenment (0.16) can have a number of desktops with different | |
| 52 * backgrounds; client windows on these are reparented, except for | |
| 53 * Desktop 0 which is the root window. Therefore versions less than | |
| 54 * 2.1 of xpenguins worked on Desktop 0 but not on any others. To fix | |
| 55 * this we look for a root-window property _WIN_WORKSPACE which | |
| 56 * contains the numerical index of the currently active desktop. The | |
| 57 * active desktop is then simply the immediate child of the root | |
| 58 * window that has a property ENLIGHTENMENT_DESKTOP set to this value. | |
| 59 * | |
| 60 * KDE 2.0: Oh dear. The kdesktop is a program separate from the | |
| 61 * window manager that launches a window which sits behind all the | |
| 62 * other client windows and has all the icons on it. Thus the other | |
| 63 * client windows are still children of the root window, but we want | |
| 64 * to draw to the uppermost window of the kdesktop. This is difficult | |
| 65 * to find - it is the great-great-grandchild of the root window and | |
| 66 * in KDE 2.0 has nothing to identify it from its siblings other than | |
| 67 * its size. KDE 2.1+ usefully implements the __SWM_VROOT property in | |
| 68 * a child of the root window, but the client windows are still | |
| 69 * children of the root window. A problem is that the penguins erase | |
| 70 * the desktop icons when they walk which is a bit messy. The icons | |
| 71 * are not lost - they reappear when the desktop window gets an expose | |
| 72 * event (i.e. move some windows over where they were and back again). | |
| 73 * | |
| 74 * Nautilus (GNOME 1.4+): Creates a background window to draw icons | |
| 75 * on, but does not reparent the client windows. The toplevel window | |
| 76 * of the desktop is indicated by the root window property | |
| 77 * NAUTILUS_DESKTOP_WINDOW_ID, but then we must descend down the tree | |
| 78 * from this toplevel window looking for subwindows that are the same | |
| 79 * size as the screen. The bottom one is the one to draw to. Hopefully | |
| 80 * one day Nautilus will implement __SWM_VROOT in exactly the same way | |
| 81 * as KDE 2.1+. | |
| 82 * | |
| 83 * Other cases: CDE, the common desktop environment. This is a | |
| 84 * commercial product that has been packaged with Sun (and other) | |
| 85 * workstations. It typically implements four virtual desktops but | |
| 86 * provides NO properties at all for apps such as xpenguins to use to | |
| 87 * work out where to draw to. Seeing as Sun are moving over to GNOME, | |
| 88 * CDE use is on the decline so I don't have any current plans to try | |
| 89 * and get xpenguins to work with it. | |
| 90 * | |
| 91 * As a note to developers of window managers and big screen hoggers | |
| 92 * like kdesktop, please visit www.freedesktop.org and implement their | |
| 93 * Extended Window Manager Hints spec that help pagers and apps like | |
| 94 * xpenguins and xearth to find their way around. In particular, | |
| 95 * please use the _NET_CURRENT_DESKTOP and _NET_VIRTUAL_ROOTS | |
| 96 * properties if you reparent any windows (e.g. Enlightenment). Since | |
| 97 * no window managers that I know yet use these particular hints, I | |
| 98 * haven't yet added any code to parse them. */ | |
| 99 | |
| 100 #include <X11/Xlib.h> | |
| 101 #include <X11/Xatom.h> | |
| 102 #include <X11/Xproto.h> | |
| 103 #include <string.h> | |
| 104 | |
| 105 /* Time to throw up. Here is a kludgey function that recursively calls | |
| 106 * itself (up to a limit) to find the window ID of the KDE desktop to | |
| 107 * draw on. It works with KDE 2.0, but since KDE 2.0 is less stable | |
| 108 * than Windows 95, I don't expect many people to remain using it now | |
| 109 * that 2.1 is available, which implements __SWM_VROOT and makes this | |
| 110 * function redundant. This is the hierarchy we're trying to traverse: | |
| 111 * | |
| 112 * -> The root window | |
| 113 * 0 -> window with name="KDE Desktop" | |
| 114 * 1 -> window with no name | |
| 115 * 2 -> window with name="KDE Desktop" & _NET_WM_WINDOW_TYPE_DESKTOP | |
| 116 * 3 -> window with no name and width >= width of screen | |
| 117 * | |
| 118 * The last window in the hierarchy is the one to draw to. The | |
| 119 * numbers show the value of the `depth' argument. */ | |
| 120 static | |
| 121 Window | |
| 122 __ToonGetKDEDesktop(Display *display, int screen, Window window, | |
| 123 Atom atom, char *atomname, int depth) | |
| 124 { | |
| 125 char *name = NULL; | |
| 126 unsigned char *wintype = NULL; | |
| 127 Window winreturn = 0; | |
| 128 unsigned long nitems, bytesafter; | |
| 129 Atom actual_type; | |
| 130 int actual_format; | |
| 131 Window rootReturn, parentReturn, *children; | |
| 132 unsigned int nChildren; | |
| 133 char go_deeper = 0; | |
| 134 | |
| 135 if (XFetchName(display, window, &name)) { | |
| 136 if (strcasecmp(name, "KDE Desktop") == 0) { | |
| 137 /* Presumably either at depth 0 or 2 */ | |
| 138 if (XGetWindowProperty(display, window, atom, 0, 1, | |
| 139 False, XA_ATOM, | |
| 140 &actual_type, &actual_format, | |
| 141 &nitems, &bytesafter, | |
| 142 &wintype) == Success | |
| 143 && wintype) { | |
| 144 char *tmpatomname = XGetAtomName(display, *(Atom*)wintype); | |
| 145 if (tmpatomname) { | |
| 146 if (strcmp(atomname, tmpatomname) == 0 && depth == 2) { | |
| 147 /* OK, at depth 2 */ | |
| 148 go_deeper = 1; | |
| 149 } | |
| 150 XFree((char *) tmpatomname); | |
| 151 } | |
| 152 } | |
| 153 else if (depth < 2) { | |
| 154 go_deeper = 1; | |
| 155 } | |
| 156 } | |
| 157 else if (depth == 1) { | |
| 158 go_deeper = 1; | |
| 159 } | |
| 160 XFree((char *) name); | |
| 161 } | |
| 162 else if (depth == 1) { | |
| 163 go_deeper = 1; | |
| 164 } | |
| 165 | |
| 166 /* If go_deeper is 1 then there is a possibility that the background | |
| 167 * window is a descendant of the current window; otherwise we're | |
| 168 * barking up the wrong tree. */ | |
| 169 if (go_deeper && XQueryTree(display, window, &rootReturn, | |
| 170 &parentReturn, &children, | |
| 171 &nChildren)) { | |
| 172 int i; | |
| 173 for (i = 0; i < nChildren; ++i) { | |
| 174 /* children[i] is now at depth 3 */ | |
| 175 if (depth == 2) { | |
| 176 XWindowAttributes attributes; | |
| 177 if (XGetWindowAttributes(display, children[i], &attributes)) { | |
| 178 if (attributes.width >= DisplayWidth(display, screen)/2 | |
| 179 && attributes.height > 0) { | |
| 180 /* Found it! */ | |
| 181 winreturn = children[i]; | |
| 182 break; | |
| 183 } | |
| 184 } | |
| 185 } | |
| 186 else if ((winreturn = __ToonGetKDEDesktop(display, screen, | |
| 187 children[i], | |
| 188 atom, atomname, | |
| 189 depth+1))) { | |
| 190 break; | |
| 191 } | |
| 192 } | |
| 193 XFree((char *) children); | |
| 194 } | |
| 195 | |
| 196 return winreturn; | |
| 197 } | |
| 198 | |
| 199 /* Look for the Nautilus desktop window to draw to, given the toplevel | |
| 200 * window of the Nautilus desktop. Basically recursively calls itself | |
| 201 * looking for subwindows the same size as the root window. */ | |
| 202 static | |
| 203 Window | |
| 204 __ToonGetNautilusDesktop(Display *display, int screen, Window window, | |
| 205 int depth) | |
| 206 { | |
| 207 Window rootReturn, parentReturn, *children; | |
| 208 Window winreturn = window; | |
| 209 unsigned int nChildren; | |
| 210 | |
| 211 if (depth > 5) { | |
| 212 return ((Window) 0); | |
| 213 } | |
| 214 else if (XQueryTree(display, window, &rootReturn, &parentReturn, | |
| 215 &children, &nChildren)) { | |
| 216 int i; | |
| 217 for (i = 0; i < nChildren; ++i) { | |
| 218 XWindowAttributes attributes; | |
| 219 if (XGetWindowAttributes(display, children[i], &attributes)) { | |
| 220 if (attributes.width == DisplayWidth(display, screen) | |
| 221 && attributes.height == DisplayHeight(display, screen)) { | |
| 222 /* Found a possible desktop window */ | |
| 223 winreturn = __ToonGetNautilusDesktop(display, screen, | |
| 224 children[i], depth+1); | |
| 225 } | |
| 226 } | |
| 227 } | |
| 228 XFree((char *) children); | |
| 229 } | |
| 230 return winreturn; | |
| 231 } | |
| 232 | |
| 233 | |
| 234 /* | |
| 235 * Returns the window ID of the `background' window on to which the | |
| 236 * toons should be drawn. Also returned (in clientparent) is the ID of | |
| 237 * the parent of all the client windows, since this may not be the | |
| 238 * same as the background window. If no recognised virtual window | |
| 239 * manager or desktop environment is found then the root window is | |
| 240 * returned in both cases. The string toon_message contains | |
| 241 * information about the window manager that was found. | |
| 242 */ | |
| 243 Window | |
| 244 ToonGetRootWindow(Display *display, int screen, Window *clientparent) | |
| 245 { | |
| 246 Window background = 0; /* The return value */ | |
| 247 Window root = RootWindow(display, screen); | |
| 248 Window rootReturn, parentReturn, *children; | |
| 249 unsigned char *toplevel = NULL; | |
| 250 unsigned int nChildren; | |
| 251 unsigned long nitems, bytesafter; | |
| 252 Atom actual_type; | |
| 253 int actual_format; | |
| 254 unsigned char *workspace = NULL; | |
| 255 unsigned char *desktop = NULL; | |
| 256 Atom NAUTILUS_DESKTOP_WINDOW_ID = XInternAtom(display, | |
| 257 "NAUTILUS_DESKTOP_WINDOW_ID", | |
| 258 False); | |
| 259 | |
| 260 *clientparent = root; | |
| 261 | |
| 262 if (XGetWindowProperty(display, root, | |
| 263 NAUTILUS_DESKTOP_WINDOW_ID, | |
| 264 0, 1, False, XA_WINDOW, | |
| 265 &actual_type, &actual_format, | |
| 266 &nitems, &bytesafter, | |
| 267 &toplevel) == Success | |
| 268 && toplevel) { | |
| 269 /* Nautilus is running */ | |
| 270 background = __ToonGetNautilusDesktop(display, screen, | |
| 271 *(Window*)toplevel, 0); | |
| 272 XFree(toplevel); | |
| 273 } | |
| 274 | |
| 275 /* Next look for a virtual root or a KDE Desktop */ | |
| 276 if (!background | |
| 277 && XQueryTree(display, root, &rootReturn, &parentReturn, | |
| 278 &children, &nChildren)) { | |
| 279 int i; | |
| 280 Atom _NET_WM_WINDOW_TYPE = XInternAtom(display, | |
| 281 "_NET_WM_WINDOW_TYPE", | |
| 282 False); | |
| 283 Atom __SWM_VROOT = XInternAtom(display, "__SWM_VROOT", False); | |
| 284 | |
| 285 for (i = 0; i < nChildren && !background; ++i) { | |
| 286 unsigned char *newroot = NULL; | |
| 287 if (XGetWindowProperty(display, children[i], | |
| 288 __SWM_VROOT, 0, 1, False, XA_WINDOW, | |
| 289 &actual_type, &actual_format, | |
| 290 &nitems, &bytesafter, | |
| 291 &newroot) == Success | |
| 292 && newroot) { | |
| 293 /* Found a window with a __SWM_VROOT property that contains | |
| 294 * the window ID of the virtual root. Now we must check | |
| 295 * whether it is KDE (2.1+) or not. If it is KDE then it does | |
| 296 * not reparent the clients. If the root window has the | |
| 297 * _NET_SUPPORTED property but not the _NET_VIRTUAL_ROOTS | |
| 298 * property then we assume it is KDE. */ | |
| 299 Atom _NET_SUPPORTED = XInternAtom(display, | |
| 300 "_NET_SUPPORTED", | |
| 301 False); | |
| 302 unsigned char *tmpatom; | |
| 303 if (XGetWindowProperty(display, root, | |
| 304 _NET_SUPPORTED, 0, 1, False, | |
| 305 XA_ATOM, &actual_type, &actual_format, | |
| 306 &nitems, &bytesafter, | |
| 307 &tmpatom) == Success | |
| 308 && tmpatom) { | |
| 309 unsigned char *tmpwindow = NULL; | |
| 310 Atom _NET_VIRTUAL_ROOTS = XInternAtom(display, | |
| 311 "_NET_VIRTUAL_ROOTS", | |
| 312 False); | |
| 313 XFree(tmpatom); | |
| 314 if (XGetWindowProperty(display, root, | |
| 315 _NET_VIRTUAL_ROOTS, 0, 1, False, | |
| 316 XA_WINDOW, &actual_type, &actual_format, | |
| 317 &nitems, &bytesafter, | |
| 318 &tmpwindow) != Success | |
| 319 || !tmpwindow) { | |
| 320 /* Must be KDE 2.1+ */ | |
| 321 background = *(Window*)newroot; | |
| 322 } | |
| 323 else if (tmpwindow) { | |
| 324 XFree(tmpwindow); | |
| 325 } | |
| 326 } | |
| 327 | |
| 328 if (!background) { | |
| 329 /* Not KDE: assume windows are reparented */ | |
| 330 background = *clientparent = *newroot; | |
| 331 } | |
| 332 XFree((char *) newroot); | |
| 333 } | |
| 334 else background = __ToonGetKDEDesktop(display, screen, children[i], | |
| 335 _NET_WM_WINDOW_TYPE, | |
| 336 "_NET_WM_WINDOW_TYPE_DESKTOP", | |
| 337 0); | |
| 338 } | |
| 339 XFree((char *) children); | |
| 340 } | |
| 341 | |
| 342 if (!background) { | |
| 343 /* Look for a _WIN_WORKSPACE property, used by Enlightenment */ | |
| 344 Atom _WIN_WORKSPACE = XInternAtom(display, "_WIN_WORKSPACE", False); | |
| 345 if (XGetWindowProperty(display, root, _WIN_WORKSPACE, | |
| 346 0, 1, False, XA_CARDINAL, | |
| 347 &actual_type, &actual_format, | |
| 348 &nitems, &bytesafter, | |
| 349 &workspace) == Success | |
| 350 && workspace) { | |
| 351 /* Found a _WIN_WORKSPACE property - this is the desktop to look for. | |
| 352 * For now assume that this is Enlightenment. | |
| 353 * We're looking for a child of the root window that has an | |
| 354 * ENLIGHTENMENT_DESKTOP atom with a value equal to the root window's | |
| 355 * _WIN_WORKSPACE atom. */ | |
| 356 Atom ENLIGHTENMENT_DESKTOP = XInternAtom(display, | |
| 357 "ENLIGHTENMENT_DESKTOP", | |
| 358 False); | |
| 359 /* First check to see if the root window is the current desktop... */ | |
| 360 if (XGetWindowProperty(display, root, | |
| 361 ENLIGHTENMENT_DESKTOP, 0, 1, | |
| 362 False, XA_CARDINAL, | |
| 363 &actual_type, &actual_format, | |
| 364 &nitems, &bytesafter, | |
| 365 &desktop) == Success | |
| 366 && desktop && *desktop == *workspace) { | |
| 367 /* The root window is the current Enlightenment desktop */ | |
| 368 background = root; | |
| 369 XFree(desktop); | |
| 370 } | |
| 371 /* Now look at each immediate child window of root to see if it is | |
| 372 * the current desktop */ | |
| 373 else if (XQueryTree(display, root, &rootReturn, &parentReturn, | |
| 374 &children, &nChildren)) { | |
| 375 int i; | |
| 376 for (i = 0; i < nChildren; ++i) { | |
| 377 if (XGetWindowProperty(display, children[i], | |
| 378 ENLIGHTENMENT_DESKTOP, 0, 1, | |
| 379 False, XA_CARDINAL, | |
| 380 &actual_type, &actual_format, | |
| 381 &nitems, &bytesafter, | |
| 382 &desktop) == Success | |
| 383 && desktop && *desktop == *workspace) { | |
| 384 /* Found current Enlightenment desktop */ | |
| 385 background = *clientparent = children[i]; | |
| 386 XFree(desktop); | |
| 387 } | |
| 388 } | |
| 389 XFree((char *) children); | |
| 390 } | |
| 391 XFree(workspace); | |
| 392 } | |
| 393 } | |
| 394 if (background) { | |
| 395 return background; | |
| 396 } | |
| 397 else { | |
| 398 return root; | |
| 399 } | |
| 400 } |
