1 /* windows.c --- turning the screen black; dealing with visuals, virtual roots.
2 * xscreensaver, Copyright (c) 1991-2001 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
18 # include <unixlib.h> /* for getpid() */
19 # include "vms-gtod.h" /* for gettimeofday() */
23 # include <pwd.h> /* for getpwuid() */
29 # include <sys/utsname.h> /* for uname() */
30 #endif /* HAVE_UNAME */
33 #include <X11/Xproto.h> /* for CARD32 */
35 #include <X11/Xutil.h> /* for XSetClassHint() */
36 #include <X11/Xatom.h>
37 #include <X11/Xos.h> /* for time() */
38 #include <signal.h> /* for the signal names */
40 #ifdef HAVE_MIT_SAVER_EXTENSION
41 # include <X11/extensions/scrnsaver.h>
42 #endif /* HAVE_MIT_SAVER_EXTENSION */
45 # include <X11/extensions/xf86vmode.h>
46 #endif /* HAVE_XF86VMODE */
49 # include <X11/extensions/Xinerama.h>
50 #endif /* HAVE_XINERAMA */
53 /* This file doesn't need the Xt headers, so stub these types out... */
55 #define XtAppContext void*
56 #define XrmDatabase void*
57 #define XtIntervalId void*
58 #define XtPointer void*
61 #include "xscreensaver.h"
66 extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
68 Atom XA_VROOT, XA_XSETROOT_ID;
69 Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
70 Atom XA_SCREENSAVER_STATUS;
73 extern saver_info *global_si_kludge; /* I hate C so much... */
75 static void maybe_transfer_grabs (saver_screen_info *ssi,
76 Window old_w, Window new_w, int new_screen);
78 #define ALL_POINTER_EVENTS \
79 (ButtonPressMask | ButtonReleaseMask | EnterWindowMask | \
80 LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | \
81 Button1MotionMask | Button2MotionMask | Button3MotionMask | \
82 Button4MotionMask | Button5MotionMask | ButtonMotionMask)
86 grab_string(int status)
90 case GrabSuccess: return "GrabSuccess";
91 case AlreadyGrabbed: return "AlreadyGrabbed";
92 case GrabInvalidTime: return "GrabInvalidTime";
93 case GrabNotViewable: return "GrabNotViewable";
94 case GrabFrozen: return "GrabFrozen";
98 sprintf(foo, "unknown status: %d", status);
105 grab_kbd(saver_info *si, Window w, int screen_no)
107 saver_preferences *p = &si->prefs;
108 int status = XGrabKeyboard (si->dpy, w, True,
109 /* I don't really understand Sync vs Async,
110 but these seem to work... */
111 GrabModeSync, GrabModeAsync,
113 if (status == GrabSuccess)
115 si->keyboard_grab_window = w;
116 si->keyboard_grab_screen = screen_no;
120 fprintf(stderr, "%s: %d: grabbing keyboard on 0x%x... %s.\n",
121 blurb(), screen_no, (unsigned long) w, grab_string(status));
127 grab_mouse (saver_info *si, Window w, Cursor cursor, int screen_no)
129 saver_preferences *p = &si->prefs;
130 int status = XGrabPointer (si->dpy, w, True, ALL_POINTER_EVENTS,
131 GrabModeAsync, GrabModeAsync, w,
132 cursor, CurrentTime);
133 if (status == GrabSuccess)
135 si->mouse_grab_window = w;
136 si->mouse_grab_screen = screen_no;
140 fprintf(stderr, "%s: %d: grabbing mouse on 0x%x... %s.\n",
141 blurb(), screen_no, (unsigned long) w, grab_string(status));
147 ungrab_kbd(saver_info *si)
149 saver_preferences *p = &si->prefs;
150 XUngrabKeyboard(si->dpy, CurrentTime);
152 fprintf(stderr, "%s: %d: ungrabbing keyboard (was 0x%x).\n",
153 blurb(), si->keyboard_grab_screen,
154 (unsigned long) si->keyboard_grab_window);
155 si->keyboard_grab_window = 0;
160 ungrab_mouse(saver_info *si)
162 saver_preferences *p = &si->prefs;
163 XUngrabPointer(si->dpy, CurrentTime);
165 fprintf(stderr, "%s: %d: ungrabbing mouse (was 0x%x).\n",
166 blurb(), si->mouse_grab_screen,
167 (unsigned long) si->mouse_grab_window);
168 si->mouse_grab_window = 0;
173 grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor,
176 Status mstatus, kstatus;
180 for (i = 0; i < retries; i++)
182 XSync (si->dpy, False);
183 kstatus = grab_kbd (si, window, screen_no);
184 if (kstatus == GrabSuccess)
187 /* else, wait a second and try to grab again. */
191 if (kstatus != GrabSuccess)
192 fprintf (stderr, "%s: couldn't grab keyboard! (%s)\n",
193 blurb(), grab_string(kstatus));
195 for (i = 0; i < retries; i++)
197 XSync (si->dpy, False);
198 mstatus = grab_mouse (si, window, cursor, screen_no);
199 if (mstatus == GrabSuccess)
202 /* else, wait a second and try to grab again. */
206 if (mstatus != GrabSuccess)
207 fprintf (stderr, "%s: couldn't grab pointer! (%s)\n",
208 blurb(), grab_string(mstatus));
210 return (kstatus == GrabSuccess ||
211 mstatus == GrabSuccess);
215 ungrab_keyboard_and_mouse (saver_info *si)
223 move_mouse_grab (saver_info *si, Window to, Cursor cursor, int to_screen_no)
225 Window old = si->mouse_grab_window;
228 return grab_mouse (si, to, cursor, to_screen_no);
231 saver_preferences *p = &si->prefs;
234 XSync (si->dpy, False);
235 XGrabServer (si->dpy); /* ############ DANGER! */
236 XSync (si->dpy, False);
239 fprintf(stderr, "%s: grabbing server...\n", blurb());
242 status = grab_mouse (si, to, cursor, to_screen_no);
244 if (status != GrabSuccess) /* Augh! */
246 sleep (1); /* Note dramatic evil of sleeping
247 with server grabbed. */
248 XSync (si->dpy, False);
249 status = grab_mouse (si, to, cursor, to_screen_no);
252 if (status != GrabSuccess) /* Augh! Try to get the old one back... */
253 grab_mouse (si, old, cursor, to_screen_no);
255 XUngrabServer (si->dpy);
256 XSync (si->dpy, False); /* ###### (danger over) */
259 fprintf(stderr, "%s: ungrabbing server.\n", blurb());
266 /* Prints an error message to stderr and returns True if there is another
267 xscreensaver running already. Silently returns False otherwise. */
269 ensure_no_screensaver_running (Display *dpy, Screen *screen)
273 Window root = RootWindowOfScreen (screen);
274 Window root2, parent, *kids;
276 XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler);
278 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
284 for (i = 0; i < nkids; i++)
288 unsigned long nitems, bytesafter;
291 if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
292 False, XA_STRING, &type, &format, &nitems,
293 &bytesafter, (unsigned char **) &version)
298 if (!XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
299 False, XA_STRING, &type, &format, &nitems,
300 &bytesafter, (unsigned char **) &id)
306 "%s: already running on display %s (window 0x%x)\n from process %s.\n",
307 blurb(), DisplayString (dpy), (int) kids [i], id);
312 if (kids) XFree ((char *) kids);
314 XSetErrorHandler (old_handler);
320 /* Virtual-root hackery */
323 ERROR! You must not include vroot.h in this file.
327 store_vroot_property (Display *dpy, Window win, Window value)
332 "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", blurb(),
334 (win == screensaver_window ? "ScreenSaver" :
335 (win == real_vroot ? "VRoot" :
336 (win == real_vroot_value ? "Vroot_value" : "???"))),
338 (value == screensaver_window ? "ScreenSaver" :
339 (value == real_vroot ? "VRoot" :
340 (value == real_vroot_value ? "Vroot_value" : "???"))));
342 XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
343 (unsigned char *) &value, 1);
347 remove_vroot_property (Display *dpy, Window win)
351 fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", blurb(), win,
352 (win == screensaver_window ? "ScreenSaver" :
353 (win == real_vroot ? "VRoot" :
354 (win == real_vroot_value ? "Vroot_value" : "???"))));
356 XDeleteProperty (dpy, win, XA_VROOT);
361 kill_xsetroot_data (Display *dpy, Window window, Bool verbose_p)
365 unsigned long nitems, bytesafter;
368 /* If the user has been using xv or xsetroot as a screensaver (to display
369 an image on the screensaver window, as a kind of slideshow) then the
370 pixmap and its associated color cells have been put in RetainPermanent
371 CloseDown mode. Since we're not destroying the xscreensaver window,
372 but merely unmapping it, we need to free these resources or those
373 colormap cells will stay allocated while the screensaver is off. (We
374 could just delete the screensaver window and recreate it later, but
375 that could cause other problems.) This code does an atomic read-and-
376 delete of the _XSETROOT_ID property, and if it held a pixmap, then we
377 cause the RetainPermanent resources of the client which created it
378 (and which no longer exists) to be freed.
380 if (XGetWindowProperty (dpy, window, XA_XSETROOT_ID, 0, 1,
381 True, AnyPropertyType, &type, &format, &nitems,
382 &bytesafter, (unsigned char **) &dataP)
386 if (dataP && *dataP && type == XA_PIXMAP && format == 32 &&
387 nitems == 1 && bytesafter == 0)
390 fprintf (stderr, "%s: destroying xsetroot data (0x%lX).\n",
392 XKillClient (dpy, *dataP);
395 fprintf (stderr, "%s: deleted unrecognised _XSETROOT_ID property: \n\
396 %lu, %lu; type: %lu, format: %d, nitems: %lu, bytesafter %ld\n",
397 blurb(), (unsigned long) dataP, (dataP ? *dataP : 0), type,
398 format, nitems, bytesafter);
403 static void handle_signals (saver_info *si, Bool on_p);
406 save_real_vroot (saver_screen_info *ssi)
408 saver_info *si = ssi->global;
409 Display *dpy = si->dpy;
410 Screen *screen = ssi->screen;
412 Window root = RootWindowOfScreen (screen);
413 Window root2, parent, *kids;
415 XErrorHandler old_handler;
417 /* It's possible that a window might be deleted between our call to
418 XQueryTree() and our call to XGetWindowProperty(). Don't die if
419 that happens (but just ignore that window, it's not the one we're
420 interested in anyway.)
423 old_handler = XSetErrorHandler (BadWindow_ehandler);
427 ssi->real_vroot_value = 0;
428 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
434 for (i = 0; i < nkids; i++)
438 unsigned long nitems, bytesafter;
441 if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
442 &type, &format, &nitems, &bytesafter,
443 (unsigned char **) &vrootP)
450 if (*vrootP == ssi->screensaver_window) abort ();
452 "%s: more than one virtual root window found (0x%x and 0x%x).\n",
453 blurb(), (int) ssi->real_vroot, (int) kids [i]);
456 ssi->real_vroot = kids [i];
457 ssi->real_vroot_value = *vrootP;
461 XSetErrorHandler (old_handler);
466 handle_signals (si, True);
467 remove_vroot_property (si->dpy, ssi->real_vroot);
471 XFree ((char *) kids);
476 restore_real_vroot_2 (saver_screen_info *ssi)
478 saver_info *si = ssi->global;
479 saver_preferences *p = &si->prefs;
480 if (p->verbose_p && ssi->real_vroot)
482 "%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
483 blurb(), (unsigned long) ssi->real_vroot);
484 remove_vroot_property (si->dpy, ssi->screensaver_window);
487 store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
489 ssi->real_vroot_value = 0;
490 /* make sure the property change gets there before this process
491 terminates! We might be doing this because we have intercepted
492 SIGTERM or something. */
493 XSync (si->dpy, False);
500 restore_real_vroot_1 (saver_info *si)
503 Bool did_any = False;
504 for (i = 0; i < si->nscreens; i++)
506 saver_screen_info *ssi = &si->screens[i];
507 if (restore_real_vroot_2 (ssi))
514 restore_real_vroot (saver_info *si)
516 if (restore_real_vroot_1 (si))
517 handle_signals (si, False);
521 /* Signal hackery to ensure that the vroot doesn't get left in an
526 signal_name(int signal)
529 case SIGHUP: return "SIGHUP";
530 case SIGINT: return "SIGINT";
531 case SIGQUIT: return "SIGQUIT";
532 case SIGILL: return "SIGILL";
533 case SIGTRAP: return "SIGTRAP";
535 case SIGABRT: return "SIGABRT";
537 case SIGFPE: return "SIGFPE";
538 case SIGKILL: return "SIGKILL";
539 case SIGBUS: return "SIGBUS";
540 case SIGSEGV: return "SIGSEGV";
541 case SIGPIPE: return "SIGPIPE";
542 case SIGALRM: return "SIGALRM";
543 case SIGTERM: return "SIGTERM";
545 case SIGSTOP: return "SIGSTOP";
548 case SIGCONT: return "SIGCONT";
551 case SIGUSR1: return "SIGUSR1";
554 case SIGUSR2: return "SIGUSR2";
557 case SIGEMT: return "SIGEMT";
560 case SIGSYS: return "SIGSYS";
563 case SIGCHLD: return "SIGCHLD";
566 case SIGPWR: return "SIGPWR";
569 case SIGWINCH: return "SIGWINCH";
572 case SIGURG: return "SIGURG";
575 case SIGIO: return "SIGIO";
578 case SIGVTALRM: return "SIGVTALRM";
581 case SIGXCPU: return "SIGXCPU";
584 case SIGXFSZ: return "SIGXFSZ";
587 case SIGDANGER: return "SIGDANGER";
592 sprintf(buf, "signal %d\n", signal);
601 restore_real_vroot_handler (int sig)
603 saver_info *si = global_si_kludge; /* I hate C so much... */
605 signal (sig, SIG_DFL);
606 if (restore_real_vroot_1 (si))
607 fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n",
608 blurb(), signal_name(sig));
609 kill (getpid (), sig);
613 catch_signal (saver_info *si, int sig, Bool on_p)
616 signal (sig, SIG_DFL);
619 if (((long) signal (sig, restore_real_vroot_handler)) == -1L)
622 sprintf (buf, "%s: couldn't catch %s", blurb(), signal_name(sig));
624 saver_exit (si, 1, 0);
630 handle_signals (saver_info *si, Bool on_p)
633 if (on_p) fprintf (stderr, "handling signals\n");
634 else fprintf (stderr, "unhandling signals\n");
637 catch_signal (si, SIGHUP, on_p);
638 catch_signal (si, SIGINT, on_p);
639 catch_signal (si, SIGQUIT, on_p);
640 catch_signal (si, SIGILL, on_p);
641 catch_signal (si, SIGTRAP, on_p);
643 catch_signal (si, SIGIOT, on_p);
645 catch_signal (si, SIGABRT, on_p);
647 catch_signal (si, SIGEMT, on_p);
649 catch_signal (si, SIGFPE, on_p);
650 catch_signal (si, SIGBUS, on_p);
651 catch_signal (si, SIGSEGV, on_p);
653 catch_signal (si, SIGSYS, on_p);
655 catch_signal (si, SIGTERM, on_p);
657 catch_signal (si, SIGXCPU, on_p);
660 catch_signal (si, SIGXFSZ, on_p);
663 catch_signal (si, SIGDANGER, on_p);
668 saver_exit (saver_info *si, int status, const char *dump_core_reason)
670 saver_preferences *p = &si->prefs;
671 static Bool exiting = False;
680 vrs = restore_real_vroot_1 (si);
681 emergency_kill_subproc (si);
682 shutdown_stderr (si);
684 if (p->verbose_p && vrs)
685 fprintf (real_stderr, "%s: old vroot restored.\n", blurb());
689 #ifdef VMS /* on VMS, 1 is the "normal" exit code instead of 0. */
690 if (status == 0) status = 1;
691 else if (status == 1) status = -1;
694 bugp = !!dump_core_reason;
696 if (si->prefs.debug_p && !dump_core_reason)
697 dump_core_reason = "because of -debug";
699 if (dump_core_reason)
701 /* Note that the Linux man page for setuid() says If uid is
702 different from the old effective uid, the process will be
703 forbidden from leaving core dumps.
705 char cwd[4096]; /* should really be PATH_MAX, but who cares. */
707 fprintf(real_stderr, "%s: dumping core (%s)\n", blurb(),
712 "%s: see http://www.jwz.org/xscreensaver/bugs.html\n"
713 "\t\tfor bug reporting information.\n\n",
716 # if defined(HAVE_GETCWD)
717 if (!getcwd (cwd, sizeof(cwd)))
718 # elif defined(HAVE_GETWD)
721 strcpy(cwd, "unknown.");
723 fprintf (real_stderr, "%s: current directory is %s\n", blurb(), cwd);
724 describe_uids (si, real_stderr);
726 /* Do this to drop a core file, so that we can get a stack trace. */
734 /* Managing the actual screensaver window */
737 window_exists_p (Display *dpy, Window window)
739 XErrorHandler old_handler;
740 XWindowAttributes xgwa;
742 old_handler = XSetErrorHandler (BadWindow_ehandler);
743 XGetWindowAttributes (dpy, window, &xgwa);
745 XSetErrorHandler (old_handler);
746 return (xgwa.screen != 0);
750 store_saver_id (saver_screen_info *ssi)
752 XClassHint class_hints;
753 saver_info *si = ssi->global;
754 unsigned long pid = (unsigned long) getpid ();
756 struct passwd *p = getpwuid (getuid ());
757 const char *name, *host;
760 /* First store the name and class on the window.
762 class_hints.res_name = progname;
763 class_hints.res_class = progclass;
764 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
765 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
767 /* Then store the xscreensaver version number.
769 XChangeProperty (si->dpy, ssi->screensaver_window,
770 XA_SCREENSAVER_VERSION,
771 XA_STRING, 8, PropModeReplace,
772 (unsigned char *) si->version,
773 strlen (si->version));
775 /* Now store the XSCREENSAVER_ID property, that says what user and host
776 xscreensaver is running as.
779 if (p && p->pw_name && *p->pw_name)
783 sprintf (buf, "%lu", (unsigned long) p->pw_uid);
789 # if defined(HAVE_UNAME)
792 if (uname (&uts) < 0)
798 host = getenv("SYS$NODE");
799 # else /* !HAVE_UNAME && !VMS */
801 # endif /* !HAVE_UNAME && !VMS */
803 id = (char *) malloc (strlen(name) + strlen(host) + 50);
804 sprintf (id, "%lu (%s@%s)", pid, name, host);
806 XChangeProperty (si->dpy, ssi->screensaver_window,
807 XA_SCREENSAVER_ID, XA_STRING,
809 (unsigned char *) id, strlen (id));
815 store_saver_status (saver_info *si)
818 int size = si->nscreens + 2;
821 status = (CARD32 *) calloc (size, sizeof(CARD32));
823 status[0] = (CARD32) (si->screen_blanked_p
824 ? (si->locked_p ? XA_LOCK : XA_BLANK)
826 status[1] = (CARD32) si->blank_time;
828 for (i = 0; i < si->nscreens; i++)
830 saver_screen_info *ssi = &si->screens[i];
831 status [2 + i] = ssi->current_hack + 1;
834 XChangeProperty (si->dpy,
835 RootWindow (si->dpy, 0), /* always screen #0 */
836 XA_SCREENSAVER_STATUS,
837 XA_INTEGER, 32, PropModeReplace,
838 (unsigned char *) status, size);
843 /* Returns the area of the screen which the xscreensaver window should cover.
844 Normally this is the whole screen, but if the X server's root window is
845 actually larger than the monitor's displayable area, then we want to
846 operate in the currently-visible portion of the desktop instead.
849 get_screen_viewport (saver_screen_info *ssi,
850 int *x_ret, int *y_ret,
851 int *w_ret, int *h_ret,
852 int target_x, int target_y,
855 int w = WidthOfScreen (ssi->screen);
856 int h = HeightOfScreen (ssi->screen);
858 #ifdef HAVE_XF86VMODE
859 saver_info *si = ssi->global;
862 XF86VidModeModeLine ml;
865 Bool placement_only_p = (target_x != -1 && target_y != -1);
868 xinerama_p = (XineramaQueryExtension (si->dpy, &event, &error) &&
869 XineramaIsActive (si->dpy));
870 #else /* !HAVE_XINERAMA */
871 /* Even if we don't have the client-side Xinerama lib, check to see if
872 the server supports Xinerama, so that we know to ignore the VidMode
873 extension -- otherwise a server crash could result. Yay. */
874 xinerama_p = XQueryExtension (si->dpy, "XINERAMA", &error, &event, &error);
876 #endif /* !HAVE_XINERAMA */
879 if (xinerama_p && placement_only_p)
882 XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
885 /* Find the screen that contains the mouse. */
888 for (i = 0; i < nscreens; i++)
890 if (target_x >= xsi[i].x_org &&
891 target_y >= xsi[i].y_org &&
892 target_x < xsi[i].x_org + xsi[i].width &&
893 target_y < xsi[i].y_org + xsi[i].height)
897 fprintf (stderr, "%s: %d: xinerama vp: %dx%d+%d+%d",
899 xsi[which].width, xsi[which].height,
900 xsi[i].x_org, xsi[i].y_org);
902 fprintf (stderr, "; mouse at %d,%d",
904 fprintf (stderr, ".\n");
907 if (which == -1) which = 0; /* didn't find it? Use the first. */
908 *x_ret = xsi[which].x_org;
909 *y_ret = xsi[which].y_org;
910 *w_ret = xsi[which].width;
911 *h_ret = xsi[which].height;
916 #endif /* HAVE_XINERAMA */
918 if (!xinerama_p && /* Xinerama + VidMode = broken. */
919 XF86VidModeQueryExtension (si->dpy, &event, &error) &&
920 XF86VidModeGetModeLine (si->dpy, ssi->number, &dot, &ml) &&
921 XF86VidModeGetViewPort (si->dpy, ssi->number, &x, &y))
926 *w_ret = ml.hdisplay;
927 *h_ret = ml.vdisplay;
929 if (*x_ret == 0 && *y_ret == 0 && *w_ret == w && *h_ret == h)
930 /* There is no viewport -- the screen does not scroll. */
934 /* Apparently some versions of XFree86 return nonsense here!
935 I've had reports of 1024x768 viewports at -1936862040, -1953705044.
936 So, sanity-check the values and give up if they are out of range.
938 if (*x_ret < 0 || *x_ret >= w ||
939 *y_ret < 0 || *y_ret >= h ||
940 *w_ret <= 0 || *w_ret > w ||
941 *h_ret <= 0 || *h_ret > h)
943 static int warned_once = 0;
946 fprintf (stderr, "\n"
947 "%s: X SERVER BUG: %dx%d viewport at %d,%d is impossible.\n"
948 "%s: The XVidMode server extension is returning nonsense.\n"
949 "%s: Please report this bug to your X server vendor.\n\n",
950 blurb(), *w_ret, *h_ret, *x_ret, *y_ret,
961 sprintf (msg, "%s: %d: vp is %dx%d+%d+%d",
962 blurb(), ssi->number,
963 *w_ret, *h_ret, *x_ret, *y_ret);
966 /* Apparently, though the server stores the X position in increments of
967 1 pixel, it will only make changes to the *display* in some other
968 increment. With XF86_SVGA on a Thinkpad, the display only updates
969 in multiples of 8 pixels when in 8-bit mode, and in multiples of 4
970 pixels in 16-bit mode. I don't know what it does in 24- and 32-bit
971 mode, because I don't have enough video memory to find out.
973 I consider it a bug that XF86VidModeGetViewPort() is telling me the
974 server's *target* scroll position rather than the server's *actual*
975 scroll position. David Dawes agrees, and says they may fix this in
976 XFree86 4.0, but it's notrivial.
978 He also confirms that this behavior is server-dependent, so the
979 actual scroll position cannot be reliably determined by the client.
980 So... that means the only solution is to provide a ``sandbox''
981 around the blackout window -- we make the window be up to N pixels
982 larger than the viewport on both the left and right sides. That
983 means some part of the outer edges of each hack might not be
984 visible, but screw it.
986 I'm going to guess that 16 pixels is enough, and that the Y dimension
987 doesn't have this problem.
989 The drawback of doing this, of course, is that some of the screenhacks
990 will still look pretty stupid -- for example, "slidescreen" will cut
991 off the left and right edges of the grid, etc.
994 if (x > 0 && x < w - ml.hdisplay) /* not at left edge or right edge */
996 /* Round X position down to next lower multiple of FUDGE.
997 Increase width by 2*FUDGE in case some server rounds up.
999 *x_ret = ((x - 1) / FUDGE) * FUDGE;
1000 *w_ret += (FUDGE * 2);
1006 *w_ret != ml.hdisplay ||
1007 *h_ret != ml.vdisplay)
1008 sprintf (msg + strlen(msg), "; fudged to %dx%d+%d+%d",
1009 *w_ret, *h_ret, *x_ret, *y_ret);
1012 fprintf (stderr, "%s.\n", msg);
1017 #endif /* HAVE_XF86VMODE */
1026 static Bool error_handler_hit_p = False;
1029 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1031 error_handler_hit_p = True;
1036 /* Returns True if successful, False if an X error occurred.
1037 We need this because other programs might have done things to
1038 our window that will cause XChangeWindowAttributes() to fail:
1039 if that happens, we give up, destroy the window, and re-create
1043 safe_XChangeWindowAttributes (Display *dpy, Window window,
1045 XSetWindowAttributes *attrs)
1047 XErrorHandler old_handler;
1049 error_handler_hit_p = False;
1050 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1052 XChangeWindowAttributes (dpy, window, mask, attrs);
1055 XSetErrorHandler (old_handler);
1058 return (!error_handler_hit_p);
1062 /* This might not be necessary, but just in case. */
1064 safe_XConfigureWindow (Display *dpy, Window window,
1065 unsigned long mask, XWindowChanges *changes)
1067 XErrorHandler old_handler;
1069 error_handler_hit_p = False;
1070 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1072 XConfigureWindow (dpy, window, mask, changes);
1075 XSetErrorHandler (old_handler);
1078 return (!error_handler_hit_p);
1081 /* This might not be necessary, but just in case. */
1083 safe_XDestroyWindow (Display *dpy, Window window)
1085 XErrorHandler old_handler;
1087 error_handler_hit_p = False;
1088 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1090 XDestroyWindow (dpy, window);
1093 XSetErrorHandler (old_handler);
1096 return (!error_handler_hit_p);
1101 initialize_screensaver_window_1 (saver_screen_info *ssi)
1103 saver_info *si = ssi->global;
1104 saver_preferences *p = &si->prefs;
1105 Bool install_cmap_p = ssi->install_cmap_p; /* not p->install_cmap_p */
1107 /* This resets the screensaver window as fully as possible, since there's
1108 no way of knowing what some random client may have done to us in the
1109 meantime. We could just destroy and recreate the window, but that has
1110 its own set of problems...
1113 XSetWindowAttributes attrs;
1114 unsigned long attrmask;
1115 int x, y, width, height;
1116 static Bool printed_visual_info = False; /* only print the message once. */
1117 Window horked_window = 0;
1119 get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
1120 (p->verbose_p && !si->screen_blanked_p));
1122 black.red = black.green = black.blue = 0;
1124 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
1127 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
1128 /* It's not the default visual, so we have no choice but to install. */
1129 install_cmap_p = True;
1135 ssi->cmap = XCreateColormap (si->dpy,
1136 RootWindowOfScreen (ssi->screen),
1137 ssi->current_visual, AllocNone);
1138 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
1139 ssi->black_pixel = black.pixel;
1144 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
1147 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
1148 if (ssi->cmap != ssi->demo_cmap &&
1149 ssi->cmap != def_cmap)
1150 XFreeColormap (si->dpy, ssi->cmap);
1152 ssi->cmap = def_cmap;
1153 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
1156 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
1157 CWBackPixel | CWBackingPixel | CWBorderPixel);
1158 attrs.override_redirect = True;
1160 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
1161 actually be reading these events during normal operation; but we still
1162 need to see Button events for demo-mode to work properly.
1164 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
1165 ButtonPressMask | ButtonReleaseMask |
1168 attrs.backing_store = NotUseful;
1169 attrs.colormap = ssi->cmap;
1170 attrs.background_pixel = ssi->black_pixel;
1171 attrs.backing_pixel = ssi->black_pixel;
1172 attrs.border_pixel = ssi->black_pixel;
1174 if (p->debug_p) width = width / 2;
1176 if (!p->verbose_p || printed_visual_info)
1178 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
1180 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1181 describe_visual (stderr, ssi->screen, ssi->current_visual,
1186 fprintf (stderr, "%s: using visual: ", blurb());
1187 describe_visual (stderr, ssi->screen, ssi->current_visual,
1189 fprintf (stderr, "%s: default visual: ", blurb());
1190 describe_visual (stderr, ssi->screen,
1191 DefaultVisualOfScreen (ssi->screen),
1192 ssi->install_cmap_p);
1194 printed_visual_info = True;
1196 #ifdef HAVE_MIT_SAVER_EXTENSION
1197 if (si->using_mit_saver_extension)
1199 XScreenSaverInfo *info;
1200 Window root = RootWindowOfScreen (ssi->screen);
1203 /* This call sets the server screensaver timeouts to what we think
1204 they should be (based on the resources and args xscreensaver was
1205 started with.) It's important that we do this to sync back up
1206 with the server - if we have turned on prematurely, as by an
1207 ACTIVATE ClientMessage, then the server may decide to activate
1208 the screensaver while it's already active. That's ok for us,
1209 since we would know to ignore that ScreenSaverActivate event,
1210 but a side effect of this would be that the server would map its
1211 saver window (which we then hide again right away) meaning that
1212 the bits currently on the screen get blown away. Ugly. */
1214 /* #### Ok, that doesn't work - when we tell the server that the
1215 screensaver is "off" it sends us a Deactivate event, which is
1216 sensible... but causes the saver to never come on. Hmm. */
1217 disable_builtin_screensaver (si, True);
1221 /* #### The MIT-SCREEN-SAVER extension gives us access to the
1222 window that the server itself uses for saving the screen.
1223 However, using this window in any way, in particular, calling
1224 XScreenSaverSetAttributes() as below, tends to make the X server
1225 crash. So fuck it, let's try and get along without using it...
1227 It's also inconvenient to use this window because it doesn't
1228 always exist (though the ID is constant.) So to use this
1229 window, we'd have to reimplement the ACTIVATE ClientMessage to
1230 tell the *server* to tell *us* to turn on, to cause the window
1231 to get created at the right time. Gag. */
1232 XScreenSaverSetAttributes (si->dpy, root,
1233 0, 0, width, height, 0,
1234 current_depth, InputOutput, visual,
1236 XSync (si->dpy, False);
1239 info = XScreenSaverAllocInfo ();
1240 XScreenSaverQueryInfo (si->dpy, root, info);
1241 ssi->server_mit_saver_window = info->window;
1242 if (! ssi->server_mit_saver_window) abort ();
1245 #endif /* HAVE_MIT_SAVER_EXTENSION */
1247 if (ssi->screensaver_window)
1249 XWindowChanges changes;
1250 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1253 changes.width = width;
1254 changes.height = height;
1255 changes.border_width = 0;
1257 if (! (safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1258 changesmask, &changes) &&
1259 safe_XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
1262 horked_window = ssi->screensaver_window;
1263 ssi->screensaver_window = 0;
1267 if (!ssi->screensaver_window)
1269 ssi->screensaver_window =
1270 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen),
1271 x, y, width, height,
1272 0, ssi->current_depth, InputOutput,
1273 ssi->current_visual, attrmask, &attrs);
1280 "%s: someone horked our saver window (0x%lx)! Recreating it...\n",
1281 blurb(), (unsigned long) horked_window);
1282 maybe_transfer_grabs (ssi, horked_window, ssi->screensaver_window,
1284 safe_XDestroyWindow (si->dpy, horked_window);
1289 fprintf (stderr, "%s: %d: saver window is 0x%lx.\n",
1290 blurb(), ssi->number,
1291 (unsigned long) ssi->screensaver_window);
1294 store_saver_id (ssi); /* store window name and IDs */
1299 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
1301 BlackPixelOfScreen (ssi->screen),
1302 BlackPixelOfScreen (ssi->screen),
1304 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
1306 XFreePixmap (si->dpy, bit);
1309 XSetWindowBackground (si->dpy, ssi->screensaver_window, ssi->black_pixel);
1312 XUndefineCursor (si->dpy, ssi->screensaver_window);
1314 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
1318 initialize_screensaver_window (saver_info *si)
1321 for (i = 0; i < si->nscreens; i++)
1322 initialize_screensaver_window_1 (&si->screens[i]);
1327 raise_window (saver_info *si,
1328 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
1330 saver_preferences *p = &si->prefs;
1334 inhibit_fade = True;
1336 if (si->emergency_lock_p)
1337 inhibit_fade = True;
1340 initialize_screensaver_window (si);
1342 reset_watchdog_timer (si, True);
1344 if (p->fade_p && si->fading_possible_p && !inhibit_fade)
1346 Window *current_windows = (Window *)
1347 calloc(sizeof(Window), si->nscreens);
1348 Colormap *current_maps = (Colormap *)
1349 calloc(sizeof(Colormap), si->nscreens);
1351 for (i = 0; i < si->nscreens; i++)
1353 saver_screen_info *ssi = &si->screens[i];
1354 current_windows[i] = ssi->screensaver_window;
1355 current_maps[i] = (between_hacks_p
1357 : DefaultColormapOfScreen (ssi->screen));
1358 /* Ensure that the default background of the window is really black,
1359 not a pixmap or something. (This does not clear the window.) */
1360 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1364 if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
1366 XGrabServer (si->dpy); /* ############ DANGER! */
1368 /* Clear the stderr layer on each screen.
1371 for (i = 0; i < si->nscreens; i++)
1373 saver_screen_info *ssi = &si->screens[i];
1374 if (ssi->stderr_overlay_window)
1375 /* Do this before the fade, since the stderr cmap won't fade
1376 even if we uninstall it (beats me...) */
1380 /* Note! The server is grabbed, and this will take several seconds
1382 fade_screens (si->dpy, current_maps, current_windows,
1383 p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
1386 free(current_windows);
1388 current_windows = 0;
1390 if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
1392 #ifdef HAVE_MIT_SAVER_EXTENSION
1393 for (i = 0; i < si->nscreens; i++)
1395 saver_screen_info *ssi = &si->screens[i];
1396 if (ssi->server_mit_saver_window &&
1397 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1398 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1400 #endif /* HAVE_MIT_SAVER_EXTENSION */
1402 XUngrabServer (si->dpy);
1403 XSync (si->dpy, False); /* ###### (danger over) */
1407 for (i = 0; i < si->nscreens; i++)
1409 saver_screen_info *ssi = &si->screens[i];
1411 XClearWindow (si->dpy, ssi->screensaver_window);
1412 if (!dont_clear || ssi->stderr_overlay_window)
1414 XMapRaised (si->dpy, ssi->screensaver_window);
1415 #ifdef HAVE_MIT_SAVER_EXTENSION
1416 if (ssi->server_mit_saver_window &&
1417 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1418 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1419 #endif /* HAVE_MIT_SAVER_EXTENSION */
1423 for (i = 0; i < si->nscreens; i++)
1425 saver_screen_info *ssi = &si->screens[i];
1427 XInstallColormap (si->dpy, ssi->cmap);
1433 mouse_screen (saver_info *si)
1435 saver_preferences *p = &si->prefs;
1437 if (si->nscreens == 1)
1442 for (i = 0; i < si->nscreens; i++)
1444 saver_screen_info *ssi = &si->screens[i];
1445 Window pointer_root, pointer_child;
1446 int root_x, root_y, win_x, win_y;
1448 if (XQueryPointer (si->dpy,
1449 RootWindowOfScreen (ssi->screen),
1450 &pointer_root, &pointer_child,
1451 &root_x, &root_y, &win_x, &win_y, &mask))
1454 fprintf (stderr, "%s: mouse is on screen %d\n",
1455 blurb(), i, si->nscreens);
1460 /* couldn't figure out where the mouse is? Oh well. */
1467 blank_screen (saver_info *si)
1474 /* Note: we do our grabs on the root window, not on the screensaver window.
1475 If we grabbed on the saver window, then the demo mode and lock dialog
1476 boxes wouldn't get any events.
1478 By "the root window", we mean "the root window that contains the mouse."
1479 We use to always grab the mouse on screen 0, but that has the effect of
1480 moving the mouse to screen 0 from whichever screen it was on, on
1483 mscreen = mouse_screen (si);
1484 w = RootWindowOfScreen(si->screens[mscreen].screen);
1485 ok = grab_keyboard_and_mouse (si, w,
1486 (si->demoing_p ? 0 : si->screens[0].cursor),
1490 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1491 /* If we're using a server extension, then failure to get a grab is
1492 not a big deal -- even without the grab, we will still be able
1493 to un-blank when there is user activity, since the server will
1500 for (i = 0; i < si->nscreens; i++)
1502 saver_screen_info *ssi = &si->screens[i];
1504 save_real_vroot (ssi);
1505 store_vroot_property (si->dpy,
1506 ssi->screensaver_window,
1507 ssi->screensaver_window);
1509 #ifdef HAVE_XF86VMODE
1512 if (!XF86VidModeQueryExtension (si->dpy, &ev, &er) ||
1513 !XF86VidModeGetViewPort (si->dpy, i,
1516 ssi->blank_vp_x = ssi->blank_vp_y = -1;
1518 #endif /* HAVE_XF86VMODE */
1521 raise_window (si, False, False, False);
1523 si->screen_blanked_p = True;
1524 si->blank_time = time ((time_t) 0);
1525 si->last_wall_clock_time = 0;
1527 store_saver_status (si); /* store blank time */
1534 unblank_screen (saver_info *si)
1536 saver_preferences *p = &si->prefs;
1537 Bool unfade_p = (si->fading_possible_p && p->unfade_p);
1540 monitor_power_on (si);
1541 reset_watchdog_timer (si, False);
1548 Window *current_windows = (Window *)
1549 calloc(sizeof(Window), si->nscreens);
1551 for (i = 0; i < si->nscreens; i++)
1553 saver_screen_info *ssi = &si->screens[i];
1554 current_windows[i] = ssi->screensaver_window;
1555 /* Ensure that the default background of the window is really black,
1556 not a pixmap or something. (This does not clear the window.) */
1557 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1561 if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
1564 XSync (si->dpy, False);
1565 XGrabServer (si->dpy); /* ############ DANGER! */
1566 XSync (si->dpy, False);
1568 /* Clear the stderr layer on each screen.
1570 for (i = 0; i < si->nscreens; i++)
1572 saver_screen_info *ssi = &si->screens[i];
1576 XUngrabServer (si->dpy);
1577 XSync (si->dpy, False); /* ###### (danger over) */
1580 fade_screens (si->dpy, 0, current_windows,
1581 p->fade_seconds/1000, p->fade_ticks,
1584 free(current_windows);
1585 current_windows = 0;
1587 if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
1591 for (i = 0; i < si->nscreens; i++)
1593 saver_screen_info *ssi = &si->screens[i];
1596 Colormap c = DefaultColormapOfScreen (ssi->screen);
1597 /* avoid technicolor */
1598 XClearWindow (si->dpy, ssi->screensaver_window);
1599 if (c) XInstallColormap (si->dpy, c);
1601 XUnmapWindow (si->dpy, ssi->screensaver_window);
1606 /* If the focus window does has a non-default colormap, then install
1607 that colormap as well. (On SGIs, this will cause both the root map
1608 and the focus map to be installed simultaniously. It'd be nice to
1609 pick up the other colormaps that had been installed, too; perhaps
1610 XListInstalledColormaps could be used for that?)
1615 XGetInputFocus (si->dpy, &focus, &revert_to);
1616 if (focus && focus != PointerRoot && focus != None)
1618 XWindowAttributes xgwa;
1620 XGetWindowAttributes (si->dpy, focus, &xgwa);
1621 if (xgwa.colormap &&
1622 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1623 XInstallColormap (si->dpy, xgwa.colormap);
1628 for (i = 0; i < si->nscreens; i++)
1630 saver_screen_info *ssi = &si->screens[i];
1631 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
1634 store_saver_status (si); /* store unblank time */
1635 ungrab_keyboard_and_mouse (si);
1636 restore_real_vroot (si);
1638 /* Unmap the windows a second time, dammit -- just to avoid a race
1639 with the screen-grabbing hacks. (I'm not sure if this is really
1640 necessary; I'm stabbing in the dark now.)
1642 for (i = 0; i < si->nscreens; i++)
1643 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
1645 si->screen_blanked_p = False;
1646 si->blank_time = time ((time_t) 0);
1647 si->last_wall_clock_time = 0;
1649 store_saver_status (si); /* store unblank time */
1653 /* Transfer any grabs from the old window to the new.
1654 Actually I think none of this is necessary, since we always
1655 hold our grabs on the root window, but I wrote this before
1656 re-discovering that...
1659 maybe_transfer_grabs (saver_screen_info *ssi,
1660 Window old_w, Window new_w,
1663 saver_info *si = ssi->global;
1665 /* If the old window held our mouse grab, transfer the grab to the new
1666 window. (Grab the server while so doing, to avoid a race condition.)
1668 if (old_w == si->mouse_grab_window)
1670 XGrabServer (si->dpy); /* ############ DANGER! */
1672 grab_mouse (si, ssi->screensaver_window,
1673 (si->demoing_p ? 0 : ssi->cursor),
1675 XUngrabServer (si->dpy);
1676 XSync (si->dpy, False); /* ###### (danger over) */
1679 /* If the old window held our keyboard grab, transfer the grab to the new
1680 window. (Grab the server while so doing, to avoid a race condition.)
1682 if (old_w == si->keyboard_grab_window)
1684 XGrabServer (si->dpy); /* ############ DANGER! */
1686 grab_kbd(si, ssi->screensaver_window, ssi->number);
1687 XUngrabServer (si->dpy);
1688 XSync (si->dpy, False); /* ###### (danger over) */
1695 select_visual (saver_screen_info *ssi, const char *visual_name)
1697 saver_info *si = ssi->global;
1698 saver_preferences *p = &si->prefs;
1699 Bool install_cmap_p = p->install_cmap_p;
1700 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
1704 if (visual_name && *visual_name)
1706 if (!strcmp(visual_name, "default-i") ||
1707 !strcmp(visual_name, "Default-i") ||
1708 !strcmp(visual_name, "Default-I")
1711 visual_name = "default";
1712 install_cmap_p = True;
1714 else if (!strcmp(visual_name, "default-n") ||
1715 !strcmp(visual_name, "Default-n") ||
1716 !strcmp(visual_name, "Default-N"))
1718 visual_name = "default";
1719 install_cmap_p = False;
1721 else if (!strcmp(visual_name, "gl") ||
1722 !strcmp(visual_name, "Gl") ||
1723 !strcmp(visual_name, "GL"))
1725 new_v = ssi->best_gl_visual;
1726 if (!new_v && p->verbose_p)
1727 fprintf (stderr, "%s: no GL visuals.\n", progname);
1731 new_v = get_visual (ssi->screen, visual_name, True, False);
1735 new_v = ssi->default_visual;
1740 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
1741 /* It's not the default visual, so we have no choice but to install. */
1742 install_cmap_p = True;
1744 ssi->install_cmap_p = install_cmap_p;
1747 ((ssi->current_visual != new_v) ||
1748 (install_cmap_p != was_installed_p)))
1750 Colormap old_c = ssi->cmap;
1751 Window old_w = ssi->screensaver_window;
1755 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1756 describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
1758 fprintf (stderr, "%s: from ", blurb());
1759 describe_visual (stderr, ssi->screen, ssi->current_visual,
1765 ssi->current_visual = new_v;
1766 ssi->current_depth = visual_depth(ssi->screen, new_v);
1768 ssi->screensaver_window = 0;
1770 initialize_screensaver_window_1 (ssi);
1772 /* stderr_overlay_window is a child of screensaver_window, so we need
1773 to destroy that as well (actually, we just need to invalidate and
1774 drop our pointers to it, but this will destroy it, which is ok so
1775 long as it happens before old_w itself is destroyed.) */
1778 raise_window (si, True, True, False);
1779 store_vroot_property (si->dpy,
1780 ssi->screensaver_window, ssi->screensaver_window);
1782 /* Transfer any grabs from the old window to the new. */
1783 maybe_transfer_grabs (ssi, old_w, ssi->screensaver_window, ssi->number);
1785 /* Now we can destroy the old window without horking our grabs. */
1786 XDestroyWindow (si->dpy, old_w);
1789 fprintf (stderr, "%s: %d: destroyed old saver window 0x%lx.\n",
1790 blurb(), ssi->number, (unsigned long) old_w);
1793 old_c != DefaultColormapOfScreen (ssi->screen) &&
1794 old_c != ssi->demo_cmap)
1795 XFreeColormap (si->dpy, old_c);