1 /* windows.c --- turning the screen black; dealing with visuals, virtual roots.
2 * xscreensaver, Copyright (c) 1991-2004 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 */
42 #ifdef HAVE_MIT_SAVER_EXTENSION
43 # include <X11/extensions/scrnsaver.h>
44 #endif /* HAVE_MIT_SAVER_EXTENSION */
47 # include <X11/extensions/xf86vmode.h>
48 #endif /* HAVE_XF86VMODE */
51 # include <X11/extensions/Xinerama.h>
52 #endif /* HAVE_XINERAMA */
54 /* This file doesn't need the Xt headers, so stub these types out... */
56 #define XtAppContext void*
57 #define XrmDatabase void*
58 #define XtIntervalId void*
59 #define XtPointer void*
62 #include "xscreensaver.h"
67 extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
69 Atom XA_VROOT, XA_XSETROOT_ID, XA_ESETROOT_PMAP_ID, XA_XROOTPMAP_ID;
70 Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
71 Atom XA_SCREENSAVER_STATUS;
74 extern saver_info *global_si_kludge; /* I hate C so much... */
76 static void maybe_transfer_grabs (saver_screen_info *ssi,
77 Window old_w, Window new_w, int new_screen);
79 #define ALL_POINTER_EVENTS \
80 (ButtonPressMask | ButtonReleaseMask | EnterWindowMask | \
81 LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | \
82 Button1MotionMask | Button2MotionMask | Button3MotionMask | \
83 Button4MotionMask | Button5MotionMask | ButtonMotionMask)
87 grab_string(int status)
91 case GrabSuccess: return "GrabSuccess";
92 case AlreadyGrabbed: return "AlreadyGrabbed";
93 case GrabInvalidTime: return "GrabInvalidTime";
94 case GrabNotViewable: return "GrabNotViewable";
95 case GrabFrozen: return "GrabFrozen";
99 sprintf(foo, "unknown status: %d", status);
106 grab_kbd(saver_info *si, Window w, int screen_no)
108 saver_preferences *p = &si->prefs;
109 int status = XGrabKeyboard (si->dpy, w, True,
110 /* I don't really understand Sync vs Async,
111 but these seem to work... */
112 GrabModeSync, GrabModeAsync,
114 if (status == GrabSuccess)
116 si->keyboard_grab_window = w;
117 si->keyboard_grab_screen = screen_no;
121 fprintf(stderr, "%s: %d: grabbing keyboard on 0x%lx... %s.\n",
122 blurb(), screen_no, (unsigned long) w, grab_string(status));
128 grab_mouse (saver_info *si, Window w, Cursor cursor, int screen_no)
130 saver_preferences *p = &si->prefs;
131 int status = XGrabPointer (si->dpy, w, True, ALL_POINTER_EVENTS,
132 GrabModeAsync, GrabModeAsync, w,
133 cursor, CurrentTime);
134 if (status == GrabSuccess)
136 si->mouse_grab_window = w;
137 si->mouse_grab_screen = screen_no;
141 fprintf(stderr, "%s: %d: grabbing mouse on 0x%lx... %s.\n",
142 blurb(), screen_no, (unsigned long) w, grab_string(status));
148 ungrab_kbd(saver_info *si)
150 saver_preferences *p = &si->prefs;
151 XUngrabKeyboard(si->dpy, CurrentTime);
153 fprintf(stderr, "%s: %d: ungrabbing keyboard (was 0x%lx).\n",
154 blurb(), si->keyboard_grab_screen,
155 (unsigned long) si->keyboard_grab_window);
156 si->keyboard_grab_window = 0;
161 ungrab_mouse(saver_info *si)
163 saver_preferences *p = &si->prefs;
164 XUngrabPointer(si->dpy, CurrentTime);
166 fprintf(stderr, "%s: %d: ungrabbing mouse (was 0x%lx).\n",
167 blurb(), si->mouse_grab_screen,
168 (unsigned long) si->mouse_grab_window);
169 si->mouse_grab_window = 0;
173 /* Apparently there is this program called "rdesktop" which is a windows
174 terminal server client for Unix. It would seem that this program holds
175 the keyboard GRABBED the whole time it has focus! This is, of course,
176 completely idiotic: the whole point of grabbing is to get events when
177 you do *not* have focus, so grabbing *only when* you have focus is
178 completely redundant -- unless your goal is to make xscreensaver not
179 able to ever lock the screen when your program is running.
181 If xscreensaver blanks while rdesktop still has a keyboard grab, then
182 when we try to prompt for the password, we won't get the characters:
183 they'll be typed into rdesktop.
185 Perhaps rdesktop will release its keyboard grab if it loses focus?
186 What the hell, let's give it a try. If we fail to grab the keyboard
187 four times in a row, we forcibly set focus to "None" and try four
188 more times. (We don't touch focus unless we're already having a hard
189 time getting a grab.)
192 nuke_focus (saver_info *si, int screen_no)
194 saver_preferences *p = &si->prefs;
198 XGetInputFocus (si->dpy, &focus, &rev);
204 if (focus == PointerRoot) strcpy (w, "PointerRoot");
205 else if (focus == None) strcpy (w, "None");
206 else sprintf (w, "0x%lx", (unsigned long) focus);
208 if (rev == RevertToParent) strcpy (r, "RevertToParent");
209 else if (rev == RevertToPointerRoot) strcpy (r, "RevertToPointerRoot");
210 else if (rev == RevertToNone) strcpy (r, "RevertToNone");
211 else sprintf (r, "0x%x", rev);
213 fprintf (stderr, "%s: %d: removing focus from %s / %s.\n",
214 blurb(), screen_no, w, r);
217 XSetInputFocus (si->dpy, None, RevertToNone, CurrentTime);
218 XSync (si->dpy, False);
223 grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor,
226 Status mstatus = 0, kstatus = 0;
229 Bool focus_fuckus = False;
233 for (i = 0; i < retries; i++)
235 XSync (si->dpy, False);
236 kstatus = grab_kbd (si, window, screen_no);
237 if (kstatus == GrabSuccess)
240 /* else, wait a second and try to grab again. */
244 if (kstatus != GrabSuccess)
246 fprintf (stderr, "%s: couldn't grab keyboard! (%s)\n",
247 blurb(), grab_string(kstatus));
252 nuke_focus (si, screen_no);
257 for (i = 0; i < retries; i++)
259 XSync (si->dpy, False);
260 mstatus = grab_mouse (si, window, cursor, screen_no);
261 if (mstatus == GrabSuccess)
264 /* else, wait a second and try to grab again. */
268 if (mstatus != GrabSuccess)
269 fprintf (stderr, "%s: couldn't grab pointer! (%s)\n",
270 blurb(), grab_string(mstatus));
273 /* When should we allow blanking to proceed? The current theory
274 is that a keyboard grab is manditory; a mouse grab is optional.
276 - If we don't have a keyboard grab, then we won't be able to
277 read a password to unlock, so the kbd grab is manditory.
278 (We can't conditionalize this on locked_p, because someone
279 might run "xscreensaver-command -lock" at any time.)
281 - If we don't have a mouse grab, then we might not see mouse
282 clicks as a signal to unblank -- but we will still see kbd
283 activity, so that's not a disaster.
286 if (kstatus != GrabSuccess) /* Do not blank without a kbd grab. */
289 return True; /* Grab is good, go ahead and blank. */
293 ungrab_keyboard_and_mouse (saver_info *si)
301 move_mouse_grab (saver_info *si, Window to, Cursor cursor, int to_screen_no)
303 Window old = si->mouse_grab_window;
306 return grab_mouse (si, to, cursor, to_screen_no);
309 saver_preferences *p = &si->prefs;
312 XSync (si->dpy, False);
313 XGrabServer (si->dpy); /* ############ DANGER! */
314 XSync (si->dpy, False);
317 fprintf(stderr, "%s: grabbing server...\n", blurb());
320 status = grab_mouse (si, to, cursor, to_screen_no);
322 if (status != GrabSuccess) /* Augh! */
324 sleep (1); /* Note dramatic evil of sleeping
325 with server grabbed. */
326 XSync (si->dpy, False);
327 status = grab_mouse (si, to, cursor, to_screen_no);
330 if (status != GrabSuccess) /* Augh! Try to get the old one back... */
331 grab_mouse (si, old, cursor, to_screen_no);
333 XUngrabServer (si->dpy);
334 XSync (si->dpy, False); /* ###### (danger over) */
337 fprintf(stderr, "%s: ungrabbing server.\n", blurb());
344 /* Prints an error message to stderr and returns True if there is another
345 xscreensaver running already. Silently returns False otherwise. */
347 ensure_no_screensaver_running (Display *dpy, Screen *screen)
351 Window root = RootWindowOfScreen (screen);
352 Window root2, parent, *kids;
354 XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler);
356 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
362 for (i = 0; i < nkids; i++)
366 unsigned long nitems, bytesafter;
367 unsigned char *version;
369 if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
370 False, XA_STRING, &type, &format, &nitems,
371 &bytesafter, &version)
376 if (!XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
377 False, XA_STRING, &type, &format, &nitems,
381 id = (unsigned char *) "???";
384 "%s: already running on display %s (window 0x%x)\n from process %s.\n",
385 blurb(), DisplayString (dpy), (int) kids [i],
391 if (kids) XFree ((char *) kids);
393 XSetErrorHandler (old_handler);
399 /* Virtual-root hackery */
402 ERROR! You must not include vroot.h in this file.
406 store_vroot_property (Display *dpy, Window win, Window value)
411 "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", blurb(),
413 (win == screensaver_window ? "ScreenSaver" :
414 (win == real_vroot ? "VRoot" :
415 (win == real_vroot_value ? "Vroot_value" : "???"))),
417 (value == screensaver_window ? "ScreenSaver" :
418 (value == real_vroot ? "VRoot" :
419 (value == real_vroot_value ? "Vroot_value" : "???"))));
421 XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
422 (unsigned char *) &value, 1);
426 remove_vroot_property (Display *dpy, Window win)
430 fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", blurb(), win,
431 (win == screensaver_window ? "ScreenSaver" :
432 (win == real_vroot ? "VRoot" :
433 (win == real_vroot_value ? "Vroot_value" : "???"))));
435 XDeleteProperty (dpy, win, XA_VROOT);
439 static Bool safe_XKillClient (Display *dpy, XID id);
441 #ifdef HAVE_XF86VMODE
442 static Bool safe_XF86VidModeGetViewPort (Display *, int, int *, int *);
443 #endif /* HAVE_XF86VMODE */
447 kill_xsetroot_data_1 (Display *dpy, Window window,
448 Atom prop, const char *atom_name,
453 unsigned long nitems, bytesafter;
454 unsigned char *dataP = 0;
456 /* If the user has been using xv or xsetroot as a screensaver (to display
457 an image on the screensaver window, as a kind of slideshow) then the
458 pixmap and its associated color cells have been put in RetainPermanent
459 CloseDown mode. Since we're not destroying the xscreensaver window,
460 but merely unmapping it, we need to free these resources or those
461 colormap cells will stay allocated while the screensaver is off. (We
462 could just delete the screensaver window and recreate it later, but
463 that could cause other problems.) This code does an atomic read-and-
464 delete of the _XSETROOT_ID property, and if it held a pixmap, then we
465 cause the RetainPermanent resources of the client which created it
466 (and which no longer exists) to be freed.
468 Update: it seems that Gnome and KDE do this same trick, but with the
469 properties "ESETROOT_PMAP_ID" and/or "_XROOTPMAP_ID" instead of
470 "_XSETROOT_ID". So, we'll kill those too.
472 if (XGetWindowProperty (dpy, window, prop, 0, 1,
473 True, AnyPropertyType, &type, &format, &nitems,
478 Pixmap *pixP = (Pixmap *) dataP;
479 if (pixP && *pixP && type == XA_PIXMAP && format == 32 &&
480 nitems == 1 && bytesafter == 0)
483 fprintf (stderr, "%s: destroying %s data (0x%lX).\n",
484 blurb(), atom_name, *pixP);
485 safe_XKillClient (dpy, *pixP);
489 "%s: deleted unrecognised %s property: \n"
490 "\t%lu, %lu; type: %lu, format: %d, "
491 "nitems: %lu, bytesafter %ld\n",
493 (unsigned long) pixP, (pixP ? *pixP : 0), type,
494 format, nitems, bytesafter);
500 kill_xsetroot_data (Display *dpy, Window w, Bool verbose_p)
502 kill_xsetroot_data_1 (dpy, w, XA_XSETROOT_ID, "_XSETROOT_ID", verbose_p);
503 kill_xsetroot_data_1 (dpy, w, XA_ESETROOT_PMAP_ID, "ESETROOT_PMAP_ID",
505 kill_xsetroot_data_1 (dpy, w, XA_XROOTPMAP_ID, "_XROOTPMAP_ID", verbose_p);
510 save_real_vroot (saver_screen_info *ssi)
512 saver_info *si = ssi->global;
513 Display *dpy = si->dpy;
514 Screen *screen = ssi->screen;
516 Window root = RootWindowOfScreen (screen);
517 Window root2, parent, *kids;
519 XErrorHandler old_handler;
521 /* It's possible that a window might be deleted between our call to
522 XQueryTree() and our call to XGetWindowProperty(). Don't die if
523 that happens (but just ignore that window, it's not the one we're
524 interested in anyway.)
527 old_handler = XSetErrorHandler (BadWindow_ehandler);
531 ssi->real_vroot_value = 0;
532 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
538 for (i = 0; i < nkids; i++)
542 unsigned long nitems, bytesafter;
543 unsigned char *dataP = 0;
547 /* Skip this window if it is the xscreensaver window of any other
548 screen (this can happen in the Xinerama case.)
550 for (j = 0; j < si->nscreens; j++)
552 saver_screen_info *ssi2 = &si->screens[j];
553 if (kids[i] == ssi2->screensaver_window)
557 if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
558 &type, &format, &nitems, &bytesafter,
565 vrootP = (Window *) dataP;
568 if (*vrootP == ssi->screensaver_window) abort ();
570 "%s: more than one virtual root window found (0x%x and 0x%x).\n",
571 blurb(), (int) ssi->real_vroot, (int) kids [i]);
574 ssi->real_vroot = kids [i];
575 ssi->real_vroot_value = *vrootP;
581 XSetErrorHandler (old_handler);
586 remove_vroot_property (si->dpy, ssi->real_vroot);
590 XFree ((char *) kids);
595 restore_real_vroot_1 (saver_screen_info *ssi)
597 saver_info *si = ssi->global;
598 saver_preferences *p = &si->prefs;
599 if (p->verbose_p && ssi->real_vroot)
601 "%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
602 blurb(), (unsigned long) ssi->real_vroot);
603 remove_vroot_property (si->dpy, ssi->screensaver_window);
606 store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
608 ssi->real_vroot_value = 0;
609 /* make sure the property change gets there before this process
610 terminates! We might be doing this because we have intercepted
611 SIGTERM or something. */
612 XSync (si->dpy, False);
619 restore_real_vroot (saver_info *si)
622 Bool did_any = False;
623 for (i = 0; i < si->nscreens; i++)
625 saver_screen_info *ssi = &si->screens[i];
626 if (restore_real_vroot_1 (ssi))
633 /* Signal hackery to ensure that the vroot doesn't get left in an
638 signal_name(int signal)
641 case SIGHUP: return "SIGHUP";
642 case SIGINT: return "SIGINT";
643 case SIGQUIT: return "SIGQUIT";
644 case SIGILL: return "SIGILL";
645 case SIGTRAP: return "SIGTRAP";
647 case SIGABRT: return "SIGABRT";
649 case SIGFPE: return "SIGFPE";
650 case SIGKILL: return "SIGKILL";
651 case SIGBUS: return "SIGBUS";
652 case SIGSEGV: return "SIGSEGV";
653 case SIGPIPE: return "SIGPIPE";
654 case SIGALRM: return "SIGALRM";
655 case SIGTERM: return "SIGTERM";
657 case SIGSTOP: return "SIGSTOP";
660 case SIGCONT: return "SIGCONT";
663 case SIGUSR1: return "SIGUSR1";
666 case SIGUSR2: return "SIGUSR2";
669 case SIGEMT: return "SIGEMT";
672 case SIGSYS: return "SIGSYS";
675 case SIGCHLD: return "SIGCHLD";
678 case SIGPWR: return "SIGPWR";
681 case SIGWINCH: return "SIGWINCH";
684 case SIGURG: return "SIGURG";
687 case SIGIO: return "SIGIO";
690 case SIGVTALRM: return "SIGVTALRM";
693 case SIGXCPU: return "SIGXCPU";
696 case SIGXFSZ: return "SIGXFSZ";
699 case SIGDANGER: return "SIGDANGER";
704 sprintf(buf, "signal %d\n", signal);
713 restore_real_vroot_handler (int sig)
715 saver_info *si = global_si_kludge; /* I hate C so much... */
717 signal (sig, SIG_DFL);
718 if (restore_real_vroot (si))
719 fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n",
720 blurb(), signal_name(sig));
721 kill (getpid (), sig);
725 catch_signal (saver_info *si, int sig, RETSIGTYPE (*handler) (int))
727 # ifdef HAVE_SIGACTION
730 a.sa_handler = handler;
731 sigemptyset (&a.sa_mask);
734 /* On Linux 2.4.9 (at least) we need to tell the kernel to not mask delivery
735 of this signal from inside its handler, or else when we execvp() the
736 process again, it starts up with SIGHUP blocked, meaning that killing
737 it with -HUP only works *once*. You'd think that execvp() would reset
738 all the signal masks, but it doesn't.
740 # if defined(SA_NOMASK)
741 a.sa_flags |= SA_NOMASK;
742 # elif defined(SA_NODEFER)
743 a.sa_flags |= SA_NODEFER;
746 if (sigaction (sig, &a, 0) < 0)
747 # else /* !HAVE_SIGACTION */
748 if (((long) signal (sig, handler)) == -1L)
749 # endif /* !HAVE_SIGACTION */
752 sprintf (buf, "%s: couldn't catch %s", blurb(), signal_name(sig));
754 saver_exit (si, 1, 0);
758 static RETSIGTYPE saver_sighup_handler (int sig);
761 handle_signals (saver_info *si)
763 catch_signal (si, SIGHUP, saver_sighup_handler);
765 catch_signal (si, SIGINT, restore_real_vroot_handler);
766 catch_signal (si, SIGQUIT, restore_real_vroot_handler);
767 catch_signal (si, SIGILL, restore_real_vroot_handler);
768 catch_signal (si, SIGTRAP, restore_real_vroot_handler);
770 catch_signal (si, SIGIOT, restore_real_vroot_handler);
772 catch_signal (si, SIGABRT, restore_real_vroot_handler);
774 catch_signal (si, SIGEMT, restore_real_vroot_handler);
776 catch_signal (si, SIGFPE, restore_real_vroot_handler);
777 catch_signal (si, SIGBUS, restore_real_vroot_handler);
778 catch_signal (si, SIGSEGV, restore_real_vroot_handler);
780 catch_signal (si, SIGSYS, restore_real_vroot_handler);
782 catch_signal (si, SIGTERM, restore_real_vroot_handler);
784 catch_signal (si, SIGXCPU, restore_real_vroot_handler);
787 catch_signal (si, SIGXFSZ, restore_real_vroot_handler);
790 catch_signal (si, SIGDANGER, restore_real_vroot_handler);
796 saver_sighup_handler (int sig)
798 saver_info *si = global_si_kludge; /* I hate C so much... */
800 /* Re-establish SIGHUP handler */
801 catch_signal (si, SIGHUP, saver_sighup_handler);
803 fprintf (stderr, "%s: %s received: restarting...\n",
804 blurb(), signal_name(sig));
806 if (si->screen_blanked_p)
809 kill_screenhack (si);
810 XSync (si->dpy, False);
813 restart_process (si); /* Does not return */
820 saver_exit (saver_info *si, int status, const char *dump_core_reason)
822 saver_preferences *p = &si->prefs;
823 static Bool exiting = False;
832 vrs = restore_real_vroot (si);
833 emergency_kill_subproc (si);
834 shutdown_stderr (si);
836 if (p->verbose_p && vrs)
837 fprintf (real_stderr, "%s: old vroot restored.\n", blurb());
841 #ifdef VMS /* on VMS, 1 is the "normal" exit code instead of 0. */
842 if (status == 0) status = 1;
843 else if (status == 1) status = -1;
846 bugp = !!dump_core_reason;
848 if (si->prefs.debug_p && !dump_core_reason)
849 dump_core_reason = "because of -debug";
851 if (dump_core_reason)
853 /* Note that the Linux man page for setuid() says If uid is
854 different from the old effective uid, the process will be
855 forbidden from leaving core dumps.
857 char cwd[4096]; /* should really be PATH_MAX, but who cares. */
859 fprintf(real_stderr, "%s: dumping core (%s)\n", blurb(),
864 "%s: see http://www.jwz.org/xscreensaver/bugs.html\n"
865 "\t\t\tfor bug reporting information.\n\n",
868 # if defined(HAVE_GETCWD)
869 if (!getcwd (cwd, sizeof(cwd)))
870 # elif defined(HAVE_GETWD)
873 strcpy(cwd, "unknown.");
875 fprintf (real_stderr, "%s: current directory is %s\n", blurb(), cwd);
876 describe_uids (si, real_stderr);
878 /* Do this to drop a core file, so that we can get a stack trace. */
886 /* Managing the actual screensaver window */
889 window_exists_p (Display *dpy, Window window)
891 XErrorHandler old_handler;
892 XWindowAttributes xgwa;
894 old_handler = XSetErrorHandler (BadWindow_ehandler);
895 XGetWindowAttributes (dpy, window, &xgwa);
897 XSetErrorHandler (old_handler);
898 return (xgwa.screen != 0);
902 store_saver_id (saver_screen_info *ssi)
904 XClassHint class_hints;
905 saver_info *si = ssi->global;
906 unsigned long pid = (unsigned long) getpid ();
908 struct passwd *p = getpwuid (getuid ());
909 const char *name, *host;
912 /* First store the name and class on the window.
914 class_hints.res_name = progname;
915 class_hints.res_class = progclass;
916 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
917 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
919 /* Then store the xscreensaver version number.
921 XChangeProperty (si->dpy, ssi->screensaver_window,
922 XA_SCREENSAVER_VERSION,
923 XA_STRING, 8, PropModeReplace,
924 (unsigned char *) si->version,
925 strlen (si->version));
927 /* Now store the XSCREENSAVER_ID property, that says what user and host
928 xscreensaver is running as.
931 if (p && p->pw_name && *p->pw_name)
935 sprintf (buf, "%lu", (unsigned long) p->pw_uid);
941 # if defined(HAVE_UNAME)
944 if (uname (&uts) < 0)
950 host = getenv("SYS$NODE");
951 # else /* !HAVE_UNAME && !VMS */
953 # endif /* !HAVE_UNAME && !VMS */
955 id = (char *) malloc (strlen(name) + strlen(host) + 50);
956 sprintf (id, "%lu (%s@%s)", pid, name, host);
958 XChangeProperty (si->dpy, ssi->screensaver_window,
959 XA_SCREENSAVER_ID, XA_STRING,
961 (unsigned char *) id, strlen (id));
967 store_saver_status (saver_info *si)
970 int size = si->nscreens + 2;
973 status = (CARD32 *) calloc (size, sizeof(CARD32));
975 status[0] = (CARD32) (si->screen_blanked_p
976 ? (si->locked_p ? XA_LOCK : XA_BLANK)
978 status[1] = (CARD32) si->blank_time;
980 for (i = 0; i < si->nscreens; i++)
982 saver_screen_info *ssi = &si->screens[i];
983 status [2 + i] = ssi->current_hack + 1;
986 XChangeProperty (si->dpy,
987 RootWindow (si->dpy, 0), /* always screen #0 */
988 XA_SCREENSAVER_STATUS,
989 XA_INTEGER, 32, PropModeReplace,
990 (unsigned char *) status, size);
996 /* Returns the area of the screen which the xscreensaver window should cover.
997 Normally this is the whole screen, but if the X server's root window is
998 actually larger than the monitor's displayable area, then we want to
999 operate in the currently-visible portion of the desktop instead.
1002 get_screen_viewport (saver_screen_info *ssi,
1003 int *x_ret, int *y_ret,
1004 int *w_ret, int *h_ret,
1005 int target_x, int target_y,
1008 int w = WidthOfScreen (ssi->screen);
1009 int h = HeightOfScreen (ssi->screen);
1011 # ifdef HAVE_XF86VMODE
1012 saver_info *si = ssi->global;
1013 saver_preferences *p = &si->prefs;
1016 XF86VidModeModeLine ml;
1018 Bool xinerama_p = si->xinerama_p;
1020 # ifndef HAVE_XINERAMA
1021 /* Even if we don't have the client-side Xinerama lib, check to see if
1022 the server supports Xinerama, so that we know to ignore the VidMode
1023 extension -- otherwise a server crash could result. Yay. */
1024 xinerama_p = XQueryExtension (si->dpy, "XINERAMA", &error, &event, &error);
1025 # endif /* !HAVE_XINERAMA */
1027 # ifdef HAVE_XINERAMA
1030 int mouse_p = (target_x != -1 && target_y != -1);
1034 /* If a mouse position wasn't passed in, assume we're talking about
1042 /* Find the Xinerama rectangle that contains the mouse position. */
1043 for (i = 0; i < si->nscreens; i++)
1045 if (target_x >= si->screens[i].x &&
1046 target_y >= si->screens[i].y &&
1047 target_x < si->screens[i].x + si->screens[i].width &&
1048 target_y < si->screens[i].y + si->screens[i].height)
1051 if (which == -1) which = 0; /* didn't find it? Use the first. */
1052 *x_ret = si->screens[which].x;
1053 *y_ret = si->screens[which].y;
1054 *w_ret = si->screens[which].width;
1055 *h_ret = si->screens[which].height;
1059 fprintf (stderr, "%s: %d: xinerama vp: %dx%d+%d+%d",
1061 si->screens[which].width, si->screens[which].height,
1062 si->screens[which].x, si->screens[which].y);
1064 fprintf (stderr, "; mouse at %d,%d", target_x, target_y);
1065 fprintf (stderr, ".\n");
1070 # endif /* HAVE_XINERAMA */
1072 if (!xinerama_p && /* Xinerama + VidMode = broken. */
1073 XF86VidModeQueryExtension (si->dpy, &event, &error) &&
1074 safe_XF86VidModeGetViewPort (si->dpy, ssi->number, &x, &y) &&
1075 XF86VidModeGetModeLine (si->dpy, ssi->number, &dot, &ml))
1080 *w_ret = ml.hdisplay;
1081 *h_ret = ml.vdisplay;
1083 if (*x_ret == 0 && *y_ret == 0 && *w_ret == w && *h_ret == h)
1084 /* There is no viewport -- the screen does not scroll. */
1088 /* Apparently some versions of XFree86 return nonsense here!
1089 I've had reports of 1024x768 viewports at -1936862040, -1953705044.
1090 So, sanity-check the values and give up if they are out of range.
1092 if (*x_ret < 0 || *x_ret >= w ||
1093 *y_ret < 0 || *y_ret >= h ||
1094 *w_ret <= 0 || *w_ret > w ||
1095 *h_ret <= 0 || *h_ret > h)
1097 static int warned_once = 0;
1100 fprintf (stderr, "\n"
1101 "%s: X SERVER BUG: %dx%d viewport at %d,%d is impossible.\n"
1102 "%s: The XVidMode server extension is returning nonsense.\n"
1103 "%s: Please report this bug to your X server vendor.\n\n",
1104 blurb(), *w_ret, *h_ret, *x_ret, *y_ret,
1115 sprintf (msg, "%s: %d: vp is %dx%d+%d+%d",
1116 blurb(), ssi->number,
1117 *w_ret, *h_ret, *x_ret, *y_ret);
1120 if (p->getviewport_full_of_lies_p)
1122 /* XF86VidModeGetViewPort() tends to be full of lies on laptops
1123 that have a docking station or external monitor that runs in
1124 a different resolution than the laptop's screen:
1126 http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=81593
1127 http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=208417
1128 http://bugs.xfree86.org/show_bug.cgi?id=421
1130 The XFree86 developers have closed the bug. As far as I can
1131 tell, their reason for this was, "this is an X server bug,
1132 but it's pretty hard to fix. Therefore, we are closing it."
1134 So, now there's a preference item for those unfortunate users to
1135 tell us not to trust a word that XF86VidModeGetViewPort() says.
1137 static int warned_once = 0;
1138 if (!warned_once && verbose_p)
1142 "%s: %d: XF86VidModeGetViewPort() says vp is %dx%d+%d+%d;\n"
1143 "%s: %d: assuming that is a pack of lies;\n"
1144 "%s: %d: using %dx%d+0+0 instead.\n",
1145 blurb(), ssi->number,
1146 *w_ret, *h_ret, *x_ret, *y_ret,
1147 blurb(), ssi->number,
1148 blurb(), ssi->number, w, h);
1159 /* Apparently, though the server stores the X position in increments of
1160 1 pixel, it will only make changes to the *display* in some other
1161 increment. With XF86_SVGA on a Thinkpad, the display only updates
1162 in multiples of 8 pixels when in 8-bit mode, and in multiples of 4
1163 pixels in 16-bit mode. I don't know what it does in 24- and 32-bit
1164 mode, because I don't have enough video memory to find out.
1166 I consider it a bug that XF86VidModeGetViewPort() is telling me the
1167 server's *target* scroll position rather than the server's *actual*
1168 scroll position. David Dawes agrees, and says they may fix this in
1169 XFree86 4.0, but it's notrivial.
1171 He also confirms that this behavior is server-dependent, so the
1172 actual scroll position cannot be reliably determined by the client.
1173 So... that means the only solution is to provide a ``sandbox''
1174 around the blackout window -- we make the window be up to N pixels
1175 larger than the viewport on both the left and right sides. That
1176 means some part of the outer edges of each hack might not be
1177 visible, but screw it.
1179 I'm going to guess that 16 pixels is enough, and that the Y dimension
1180 doesn't have this problem.
1182 The drawback of doing this, of course, is that some of the screenhacks
1183 will still look pretty stupid -- for example, "slidescreen" will cut
1184 off the left and right edges of the grid, etc.
1187 if (x > 0 && x < w - ml.hdisplay) /* not at left edge or right edge */
1189 /* Round X position down to next lower multiple of FUDGE.
1190 Increase width by 2*FUDGE in case some server rounds up.
1192 *x_ret = ((x - 1) / FUDGE) * FUDGE;
1193 *w_ret += (FUDGE * 2);
1199 *w_ret != ml.hdisplay ||
1200 *h_ret != ml.vdisplay)
1201 sprintf (msg + strlen(msg), "; fudged to %dx%d+%d+%d",
1202 *w_ret, *h_ret, *x_ret, *y_ret);
1205 fprintf (stderr, "%s.\n", msg);
1210 # endif /* HAVE_XF86VMODE */
1219 static Bool error_handler_hit_p = False;
1222 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1224 error_handler_hit_p = True;
1229 /* Returns True if successful, False if an X error occurred.
1230 We need this because other programs might have done things to
1231 our window that will cause XChangeWindowAttributes() to fail:
1232 if that happens, we give up, destroy the window, and re-create
1236 safe_XChangeWindowAttributes (Display *dpy, Window window,
1238 XSetWindowAttributes *attrs)
1240 XErrorHandler old_handler;
1242 error_handler_hit_p = False;
1243 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1245 XChangeWindowAttributes (dpy, window, mask, attrs);
1248 XSetErrorHandler (old_handler);
1251 return (!error_handler_hit_p);
1255 /* This might not be necessary, but just in case. */
1257 safe_XConfigureWindow (Display *dpy, Window window,
1258 unsigned long mask, XWindowChanges *changes)
1260 XErrorHandler old_handler;
1262 error_handler_hit_p = False;
1263 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1265 XConfigureWindow (dpy, window, mask, changes);
1268 XSetErrorHandler (old_handler);
1271 return (!error_handler_hit_p);
1274 /* This might not be necessary, but just in case. */
1276 safe_XDestroyWindow (Display *dpy, Window window)
1278 XErrorHandler old_handler;
1280 error_handler_hit_p = False;
1281 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1283 XDestroyWindow (dpy, window);
1286 XSetErrorHandler (old_handler);
1289 return (!error_handler_hit_p);
1294 safe_XKillClient (Display *dpy, XID id)
1296 XErrorHandler old_handler;
1298 error_handler_hit_p = False;
1299 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1301 XKillClient (dpy, id);
1304 XSetErrorHandler (old_handler);
1307 return (!error_handler_hit_p);
1311 #ifdef HAVE_XF86VMODE
1313 safe_XF86VidModeGetViewPort (Display *dpy, int screen, int *xP, int *yP)
1316 XErrorHandler old_handler;
1318 error_handler_hit_p = False;
1319 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1321 result = XF86VidModeGetViewPort (dpy, screen, xP, yP);
1324 XSetErrorHandler (old_handler);
1327 return (error_handler_hit_p
1332 /* There is no "safe_XF86VidModeGetModeLine" because it fails with an
1333 untrappable I/O error instead of an X error -- so one must call
1334 safe_XF86VidModeGetViewPort first, and assume that both have the
1335 same error condition. Thank you XFree, may I have another.
1338 #endif /* HAVE_XF86VMODE */
1342 initialize_screensaver_window_1 (saver_screen_info *ssi)
1344 saver_info *si = ssi->global;
1345 saver_preferences *p = &si->prefs;
1346 Bool install_cmap_p = ssi->install_cmap_p; /* not p->install_cmap_p */
1348 /* This resets the screensaver window as fully as possible, since there's
1349 no way of knowing what some random client may have done to us in the
1350 meantime. We could just destroy and recreate the window, but that has
1351 its own set of problems...
1354 XSetWindowAttributes attrs;
1355 unsigned long attrmask;
1356 int x, y, width, height;
1357 static Bool printed_visual_info = False; /* only print the message once. */
1358 Window horked_window = 0;
1360 get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
1361 (p->verbose_p && !si->screen_blanked_p));
1363 black.red = black.green = black.blue = 0;
1365 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
1368 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
1369 /* It's not the default visual, so we have no choice but to install. */
1370 install_cmap_p = True;
1376 ssi->cmap = XCreateColormap (si->dpy,
1377 RootWindowOfScreen (ssi->screen),
1378 ssi->current_visual, AllocNone);
1379 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
1380 ssi->black_pixel = black.pixel;
1385 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
1388 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
1389 if (ssi->cmap != ssi->demo_cmap &&
1390 ssi->cmap != def_cmap)
1391 XFreeColormap (si->dpy, ssi->cmap);
1393 ssi->cmap = def_cmap;
1394 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
1397 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
1398 CWBackPixel | CWBackingPixel | CWBorderPixel);
1399 attrs.override_redirect = True;
1401 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
1402 actually be reading these events during normal operation; but we still
1403 need to see Button events for demo-mode to work properly.
1405 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
1406 ButtonPressMask | ButtonReleaseMask |
1409 attrs.backing_store = NotUseful;
1410 attrs.colormap = ssi->cmap;
1411 attrs.background_pixel = ssi->black_pixel;
1412 attrs.backing_pixel = ssi->black_pixel;
1413 attrs.border_pixel = ssi->black_pixel;
1415 if (p->debug_p && !p->quad_p) width = width / 2;
1417 if (!p->verbose_p || printed_visual_info)
1419 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
1421 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1422 describe_visual (stderr, ssi->screen, ssi->current_visual,
1427 fprintf (stderr, "%s: using visual: ", blurb());
1428 describe_visual (stderr, ssi->screen, ssi->current_visual,
1430 fprintf (stderr, "%s: default visual: ", blurb());
1431 describe_visual (stderr, ssi->screen,
1432 DefaultVisualOfScreen (ssi->screen),
1433 ssi->install_cmap_p);
1435 printed_visual_info = True;
1437 #ifdef HAVE_MIT_SAVER_EXTENSION
1438 if (si->using_mit_saver_extension)
1440 XScreenSaverInfo *info;
1441 Window root = RootWindowOfScreen (ssi->screen);
1444 /* This call sets the server screensaver timeouts to what we think
1445 they should be (based on the resources and args xscreensaver was
1446 started with.) It's important that we do this to sync back up
1447 with the server - if we have turned on prematurely, as by an
1448 ACTIVATE ClientMessage, then the server may decide to activate
1449 the screensaver while it's already active. That's ok for us,
1450 since we would know to ignore that ScreenSaverActivate event,
1451 but a side effect of this would be that the server would map its
1452 saver window (which we then hide again right away) meaning that
1453 the bits currently on the screen get blown away. Ugly. */
1455 /* #### Ok, that doesn't work - when we tell the server that the
1456 screensaver is "off" it sends us a Deactivate event, which is
1457 sensible... but causes the saver to never come on. Hmm. */
1458 disable_builtin_screensaver (si, True);
1462 /* #### The MIT-SCREEN-SAVER extension gives us access to the
1463 window that the server itself uses for saving the screen.
1464 However, using this window in any way, in particular, calling
1465 XScreenSaverSetAttributes() as below, tends to make the X server
1466 crash. So fuck it, let's try and get along without using it...
1468 It's also inconvenient to use this window because it doesn't
1469 always exist (though the ID is constant.) So to use this
1470 window, we'd have to reimplement the ACTIVATE ClientMessage to
1471 tell the *server* to tell *us* to turn on, to cause the window
1472 to get created at the right time. Gag. */
1473 XScreenSaverSetAttributes (si->dpy, root,
1474 0, 0, width, height, 0,
1475 current_depth, InputOutput, visual,
1477 XSync (si->dpy, False);
1480 info = XScreenSaverAllocInfo ();
1481 XScreenSaverQueryInfo (si->dpy, root, info);
1482 ssi->server_mit_saver_window = info->window;
1483 if (! ssi->server_mit_saver_window) abort ();
1486 #endif /* HAVE_MIT_SAVER_EXTENSION */
1488 if (ssi->screensaver_window)
1490 XWindowChanges changes;
1491 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1494 changes.width = width;
1495 changes.height = height;
1496 changes.border_width = 0;
1498 if (! (safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1499 changesmask, &changes) &&
1500 safe_XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
1503 horked_window = ssi->screensaver_window;
1504 ssi->screensaver_window = 0;
1508 if (!ssi->screensaver_window)
1510 ssi->screensaver_window =
1511 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen),
1512 x, y, width, height,
1513 0, ssi->current_depth, InputOutput,
1514 ssi->current_visual, attrmask, &attrs);
1521 "%s: someone horked our saver window (0x%lx)! Recreating it...\n",
1522 blurb(), (unsigned long) horked_window);
1523 maybe_transfer_grabs (ssi, horked_window, ssi->screensaver_window,
1525 safe_XDestroyWindow (si->dpy, horked_window);
1530 fprintf (stderr, "%s: %d: saver window is 0x%lx.\n",
1531 blurb(), ssi->number,
1532 (unsigned long) ssi->screensaver_window);
1535 store_saver_id (ssi); /* store window name and IDs */
1540 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
1542 BlackPixelOfScreen (ssi->screen),
1543 BlackPixelOfScreen (ssi->screen),
1545 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
1547 XFreePixmap (si->dpy, bit);
1550 XSetWindowBackground (si->dpy, ssi->screensaver_window, ssi->black_pixel);
1553 XUndefineCursor (si->dpy, ssi->screensaver_window);
1555 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
1559 initialize_screensaver_window (saver_info *si)
1562 for (i = 0; i < si->nscreens; i++)
1563 initialize_screensaver_window_1 (&si->screens[i]);
1567 /* Called when the RANDR (Resize and Rotate) extension tells us that the
1568 size of the screen has changed while the screen was blanked. If we
1569 don't do this, then the screen saver will no longer fully fill the
1570 screen, and some of the underlying desktop may be visible.
1573 resize_screensaver_window (saver_info *si)
1575 saver_preferences *p = &si->prefs;
1578 /* First update the size info in the saver_screen_info structs.
1581 # ifdef HAVE_XINERAMA
1584 /* As of XFree86 4.3.0, the RANDR and XINERAMA extensions cannot coexist.
1585 However, maybe they will someday, so I'm guessing that the right thing
1586 to do in that case will be to re-query the Xinerama rectangles after
1587 a RANDR size change is received: presumably, if the resolution of one
1588 or more of the monitors has changed, then the Xinerama rectangle
1589 corresponding to that monitor will also have been updated.
1592 XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
1593 if (nscreens != si->nscreens) abort();
1595 for (i = 0; i < si->nscreens; i++)
1597 saver_screen_info *ssi = &si->screens[i];
1599 (ssi->x != xsi[i].x_org ||
1600 ssi->y != xsi[i].y_org ||
1601 ssi->width != xsi[i].width ||
1602 ssi->height != xsi[i].height))
1604 "%s: %d: resize xinerama from %dx%d+%d+%d to %dx%d+%d+%d\n",
1606 ssi->width, ssi->height, ssi->x, ssi->y,
1607 xsi[i].width, xsi[i].height, xsi[i].x_org, xsi[i].y_org);
1609 ssi->x = xsi[i].x_org;
1610 ssi->y = xsi[i].y_org;
1611 ssi->width = xsi[i].width;
1612 ssi->height = xsi[i].height;
1617 # endif /* HAVE_XINERAMA */
1619 /* Not Xinerama -- get the real sizes of the root windows. */
1620 for (i = 0; i < si->nscreens; i++)
1622 saver_screen_info *ssi = &si->screens[i];
1623 XWindowAttributes xgwa;
1624 XGetWindowAttributes (si->dpy, RootWindowOfScreen (ssi->screen),
1628 (ssi->x != xgwa.x ||
1630 ssi->width != xgwa.width ||
1631 ssi->height != xgwa.height))
1633 "%s: %d: resize screen from %dx%d+%d+%d to %dx%d+%d+%d\n",
1635 ssi->width, ssi->height, ssi->x, ssi->y,
1636 xgwa.width, xgwa.height, xgwa.x, xgwa.y);
1640 ssi->width = xgwa.width;
1641 ssi->height = xgwa.height;
1645 /* Next, ensure that the screensaver windows are the right size, taking
1646 into account both the new size of the screen in question's root window,
1647 and any viewport within that.
1650 for (i = 0; i < si->nscreens; i++)
1652 saver_screen_info *ssi = &si->screens[i];
1653 XWindowAttributes xgwa;
1654 XWindowChanges changes;
1655 int x, y, width, height;
1656 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1658 XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
1659 get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
1660 (p->verbose_p && !si->screen_blanked_p));
1663 xgwa.width == width &&
1664 xgwa.height == height)
1665 continue; /* no change! */
1669 changes.width = width;
1670 changes.height = height;
1671 changes.border_width = 0;
1673 if (p->debug_p && !p->quad_p) changes.width = changes.width / 2;
1677 "%s: %d: resize 0x%lx from %dx%d+%d+%d to %dx%d+%d+%d\n",
1678 blurb(), i, (unsigned long) ssi->screensaver_window,
1679 xgwa.width, xgwa.height, xgwa.x, xgwa.y,
1680 width, height, x, y);
1681 if (! safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1682 changesmask, &changes))
1685 "%s: %d: someone horked our saver window (0x%lx)! Unable to resize it!\n",
1686 blurb(), i, (unsigned long) ssi->screensaver_window);
1693 raise_window (saver_info *si,
1694 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
1696 saver_preferences *p = &si->prefs;
1700 inhibit_fade = True;
1702 if (si->emergency_lock_p)
1703 inhibit_fade = True;
1706 initialize_screensaver_window (si);
1708 reset_watchdog_timer (si, True);
1710 if (p->fade_p && si->fading_possible_p && !inhibit_fade)
1712 Window *current_windows = (Window *)
1713 calloc(sizeof(Window), si->nscreens);
1714 Colormap *current_maps = (Colormap *)
1715 calloc(sizeof(Colormap), si->nscreens);
1717 for (i = 0; i < si->nscreens; i++)
1719 saver_screen_info *ssi = &si->screens[i];
1720 current_windows[i] = ssi->screensaver_window;
1721 current_maps[i] = (between_hacks_p
1723 : DefaultColormapOfScreen (ssi->screen));
1724 /* Ensure that the default background of the window is really black,
1725 not a pixmap or something. (This does not clear the window.) */
1726 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1730 if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
1732 XGrabServer (si->dpy); /* ############ DANGER! */
1734 /* Clear the stderr layer on each screen.
1737 for (i = 0; i < si->nscreens; i++)
1739 saver_screen_info *ssi = &si->screens[i];
1740 if (ssi->stderr_overlay_window)
1741 /* Do this before the fade, since the stderr cmap won't fade
1742 even if we uninstall it (beats me...) */
1746 /* Note! The server is grabbed, and this will take several seconds
1748 fade_screens (si->dpy, current_maps,
1749 current_windows, si->nscreens,
1750 p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
1753 free(current_windows);
1755 current_windows = 0;
1757 if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
1759 #ifdef HAVE_MIT_SAVER_EXTENSION
1760 for (i = 0; i < si->nscreens; i++)
1762 saver_screen_info *ssi = &si->screens[i];
1763 if (ssi->server_mit_saver_window &&
1764 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1765 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1767 #endif /* HAVE_MIT_SAVER_EXTENSION */
1769 XUngrabServer (si->dpy);
1770 XSync (si->dpy, False); /* ###### (danger over) */
1774 for (i = 0; i < si->nscreens; i++)
1776 saver_screen_info *ssi = &si->screens[i];
1778 XClearWindow (si->dpy, ssi->screensaver_window);
1779 if (!dont_clear || ssi->stderr_overlay_window)
1781 XMapRaised (si->dpy, ssi->screensaver_window);
1782 #ifdef HAVE_MIT_SAVER_EXTENSION
1783 if (ssi->server_mit_saver_window &&
1784 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1785 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1786 #endif /* HAVE_MIT_SAVER_EXTENSION */
1790 for (i = 0; i < si->nscreens; i++)
1792 saver_screen_info *ssi = &si->screens[i];
1794 XInstallColormap (si->dpy, ssi->cmap);
1800 mouse_screen (saver_info *si)
1802 saver_preferences *p = &si->prefs;
1803 Window pointer_root, pointer_child;
1804 int root_x, root_y, win_x, win_y;
1808 if (si->nscreens == 1)
1811 for (i = 0; i < si->nscreens; i++)
1813 saver_screen_info *ssi = &si->screens[i];
1814 if (XQueryPointer (si->dpy, RootWindowOfScreen (ssi->screen),
1815 &pointer_root, &pointer_child,
1816 &root_x, &root_y, &win_x, &win_y, &mask) &&
1819 root_x < ssi->x + ssi->width &&
1820 root_y < ssi->y + ssi->height)
1823 fprintf (stderr, "%s: mouse is on screen %d of %d\n",
1824 blurb(), i, si->nscreens);
1829 /* couldn't figure out where the mouse is? Oh well. */
1835 blank_screen (saver_info *si)
1842 /* Note: we do our grabs on the root window, not on the screensaver window.
1843 If we grabbed on the saver window, then the demo mode and lock dialog
1844 boxes wouldn't get any events.
1846 By "the root window", we mean "the root window that contains the mouse."
1847 We use to always grab the mouse on screen 0, but that has the effect of
1848 moving the mouse to screen 0 from whichever screen it was on, on
1851 mscreen = mouse_screen (si);
1852 w = RootWindowOfScreen(si->screens[mscreen].screen);
1853 ok = grab_keyboard_and_mouse (si, w,
1854 (si->demoing_p ? 0 : si->screens[0].cursor),
1859 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1860 /* If we're using a server extension, then failure to get a grab is
1861 not a big deal -- even without the grab, we will still be able
1862 to un-blank when there is user activity, since the server will
1864 /* #### No, that's not true: if we don't have a keyboard grab,
1865 then we can't read passwords to unlock.
1873 for (i = 0; i < si->nscreens; i++)
1875 saver_screen_info *ssi = &si->screens[i];
1876 if (ssi->real_screen_p)
1877 save_real_vroot (ssi);
1878 store_vroot_property (si->dpy,
1879 ssi->screensaver_window,
1880 ssi->screensaver_window);
1882 #ifdef HAVE_XF86VMODE
1885 if (!XF86VidModeQueryExtension (si->dpy, &ev, &er) ||
1886 !safe_XF86VidModeGetViewPort (si->dpy, i,
1889 ssi->blank_vp_x = ssi->blank_vp_y = -1;
1891 #endif /* HAVE_XF86VMODE */
1894 raise_window (si, False, False, False);
1896 si->screen_blanked_p = True;
1897 si->blank_time = time ((time_t) 0);
1898 si->last_wall_clock_time = 0;
1900 store_saver_status (si); /* store blank time */
1907 unblank_screen (saver_info *si)
1909 saver_preferences *p = &si->prefs;
1910 Bool unfade_p = (si->fading_possible_p && p->unfade_p);
1913 monitor_power_on (si);
1914 reset_watchdog_timer (si, False);
1921 Window *current_windows = (Window *)
1922 calloc(sizeof(Window), si->nscreens);
1924 for (i = 0; i < si->nscreens; i++)
1926 saver_screen_info *ssi = &si->screens[i];
1927 current_windows[i] = ssi->screensaver_window;
1928 /* Ensure that the default background of the window is really black,
1929 not a pixmap or something. (This does not clear the window.) */
1930 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1934 if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
1937 XSync (si->dpy, False);
1938 XGrabServer (si->dpy); /* ############ DANGER! */
1939 XSync (si->dpy, False);
1941 /* Clear the stderr layer on each screen.
1943 for (i = 0; i < si->nscreens; i++)
1945 saver_screen_info *ssi = &si->screens[i];
1949 XUngrabServer (si->dpy);
1950 XSync (si->dpy, False); /* ###### (danger over) */
1952 fade_screens (si->dpy, 0,
1953 current_windows, si->nscreens,
1954 p->fade_seconds/1000, p->fade_ticks,
1957 free(current_windows);
1958 current_windows = 0;
1960 if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
1964 for (i = 0; i < si->nscreens; i++)
1966 saver_screen_info *ssi = &si->screens[i];
1969 Colormap c = DefaultColormapOfScreen (ssi->screen);
1970 /* avoid technicolor */
1971 XClearWindow (si->dpy, ssi->screensaver_window);
1972 if (c) XInstallColormap (si->dpy, c);
1974 XUnmapWindow (si->dpy, ssi->screensaver_window);
1979 /* If the focus window does has a non-default colormap, then install
1980 that colormap as well. (On SGIs, this will cause both the root map
1981 and the focus map to be installed simultaneously. It'd be nice to
1982 pick up the other colormaps that had been installed, too; perhaps
1983 XListInstalledColormaps could be used for that?)
1988 XGetInputFocus (si->dpy, &focus, &revert_to);
1989 if (focus && focus != PointerRoot && focus != None)
1991 XWindowAttributes xgwa;
1993 XGetWindowAttributes (si->dpy, focus, &xgwa);
1994 if (xgwa.colormap &&
1995 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1996 XInstallColormap (si->dpy, xgwa.colormap);
2001 for (i = 0; i < si->nscreens; i++)
2003 saver_screen_info *ssi = &si->screens[i];
2004 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
2007 store_saver_status (si); /* store unblank time */
2008 ungrab_keyboard_and_mouse (si);
2009 restore_real_vroot (si);
2011 /* Unmap the windows a second time, dammit -- just to avoid a race
2012 with the screen-grabbing hacks. (I'm not sure if this is really
2013 necessary; I'm stabbing in the dark now.)
2015 for (i = 0; i < si->nscreens; i++)
2016 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
2018 si->screen_blanked_p = False;
2019 si->blank_time = time ((time_t) 0);
2020 si->last_wall_clock_time = 0;
2022 store_saver_status (si); /* store unblank time */
2026 /* Transfer any grabs from the old window to the new.
2027 Actually I think none of this is necessary, since we always
2028 hold our grabs on the root window, but I wrote this before
2029 re-discovering that...
2032 maybe_transfer_grabs (saver_screen_info *ssi,
2033 Window old_w, Window new_w,
2036 saver_info *si = ssi->global;
2038 /* If the old window held our mouse grab, transfer the grab to the new
2039 window. (Grab the server while so doing, to avoid a race condition.)
2041 if (old_w == si->mouse_grab_window)
2043 XGrabServer (si->dpy); /* ############ DANGER! */
2045 grab_mouse (si, ssi->screensaver_window,
2046 (si->demoing_p ? 0 : ssi->cursor),
2048 XUngrabServer (si->dpy);
2049 XSync (si->dpy, False); /* ###### (danger over) */
2052 /* If the old window held our keyboard grab, transfer the grab to the new
2053 window. (Grab the server while so doing, to avoid a race condition.)
2055 if (old_w == si->keyboard_grab_window)
2057 XGrabServer (si->dpy); /* ############ DANGER! */
2059 grab_kbd(si, ssi->screensaver_window, ssi->number);
2060 XUngrabServer (si->dpy);
2061 XSync (si->dpy, False); /* ###### (danger over) */
2068 select_visual (saver_screen_info *ssi, const char *visual_name)
2070 saver_info *si = ssi->global;
2071 saver_preferences *p = &si->prefs;
2072 Bool install_cmap_p = p->install_cmap_p;
2073 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
2077 /* On some systems (most recently, MacOS X) OpenGL programs get confused
2078 when you kill one and re-start another on the same window. So maybe
2079 it's best to just always destroy and recreate the xscreensaver window
2080 when changing hacks, instead of trying to reuse the old one?
2082 Bool always_recreate_window_p = True;
2084 if (visual_name && *visual_name)
2086 if (!strcmp(visual_name, "default-i") ||
2087 !strcmp(visual_name, "Default-i") ||
2088 !strcmp(visual_name, "Default-I")
2091 visual_name = "default";
2092 install_cmap_p = True;
2094 else if (!strcmp(visual_name, "default-n") ||
2095 !strcmp(visual_name, "Default-n") ||
2096 !strcmp(visual_name, "Default-N"))
2098 visual_name = "default";
2099 install_cmap_p = False;
2101 else if (!strcmp(visual_name, "gl") ||
2102 !strcmp(visual_name, "Gl") ||
2103 !strcmp(visual_name, "GL"))
2105 new_v = ssi->best_gl_visual;
2106 if (!new_v && p->verbose_p)
2107 fprintf (stderr, "%s: no GL visuals.\n", progname);
2111 new_v = get_visual (ssi->screen, visual_name, True, False);
2115 new_v = ssi->default_visual;
2120 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
2121 /* It's not the default visual, so we have no choice but to install. */
2122 install_cmap_p = True;
2124 ssi->install_cmap_p = install_cmap_p;
2127 (always_recreate_window_p ||
2128 (ssi->current_visual != new_v) ||
2129 (install_cmap_p != was_installed_p)))
2131 Colormap old_c = ssi->cmap;
2132 Window old_w = ssi->screensaver_window;
2136 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
2137 describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
2139 fprintf (stderr, "%s: from ", blurb());
2140 describe_visual (stderr, ssi->screen, ssi->current_visual,
2146 ssi->current_visual = new_v;
2147 ssi->current_depth = visual_depth(ssi->screen, new_v);
2149 ssi->screensaver_window = 0;
2151 initialize_screensaver_window_1 (ssi);
2153 /* stderr_overlay_window is a child of screensaver_window, so we need
2154 to destroy that as well (actually, we just need to invalidate and
2155 drop our pointers to it, but this will destroy it, which is ok so
2156 long as it happens before old_w itself is destroyed.) */
2159 raise_window (si, True, True, False);
2160 store_vroot_property (si->dpy,
2161 ssi->screensaver_window, ssi->screensaver_window);
2163 /* Transfer any grabs from the old window to the new. */
2164 maybe_transfer_grabs (ssi, old_w, ssi->screensaver_window, ssi->number);
2166 /* Now we can destroy the old window without horking our grabs. */
2167 XDestroyWindow (si->dpy, old_w);
2170 fprintf (stderr, "%s: %d: destroyed old saver window 0x%lx.\n",
2171 blurb(), ssi->number, (unsigned long) old_w);
2174 old_c != DefaultColormapOfScreen (ssi->screen) &&
2175 old_c != ssi->demo_cmap)
2176 XFreeColormap (si->dpy, old_c);