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 /* You might think that to store an array of 32-bit quantities onto a
43 server-side property, you would pass an array of 32-bit data quantities
44 into XChangeProperty(). You would be wrong. You have to use an array
45 of longs, even if long is 64 bits (using 32 of each 64.)
49 #ifdef HAVE_MIT_SAVER_EXTENSION
50 # include <X11/extensions/scrnsaver.h>
51 #endif /* HAVE_MIT_SAVER_EXTENSION */
54 # include <X11/extensions/xf86vmode.h>
55 #endif /* HAVE_XF86VMODE */
58 # include <X11/extensions/Xinerama.h>
59 #endif /* HAVE_XINERAMA */
61 /* This file doesn't need the Xt headers, so stub these types out... */
63 #define XtAppContext void*
64 #define XrmDatabase void*
65 #define XtIntervalId void*
66 #define XtPointer void*
69 #include "xscreensaver.h"
74 extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
76 Atom XA_VROOT, XA_XSETROOT_ID, XA_ESETROOT_PMAP_ID, XA_XROOTPMAP_ID;
77 Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
78 Atom XA_SCREENSAVER_STATUS;
81 extern saver_info *global_si_kludge; /* I hate C so much... */
83 static void maybe_transfer_grabs (saver_screen_info *ssi,
84 Window old_w, Window new_w, int new_screen);
86 #define ALL_POINTER_EVENTS \
87 (ButtonPressMask | ButtonReleaseMask | EnterWindowMask | \
88 LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | \
89 Button1MotionMask | Button2MotionMask | Button3MotionMask | \
90 Button4MotionMask | Button5MotionMask | ButtonMotionMask)
94 grab_string(int status)
98 case GrabSuccess: return "GrabSuccess";
99 case AlreadyGrabbed: return "AlreadyGrabbed";
100 case GrabInvalidTime: return "GrabInvalidTime";
101 case GrabNotViewable: return "GrabNotViewable";
102 case GrabFrozen: return "GrabFrozen";
105 static char foo[255];
106 sprintf(foo, "unknown status: %d", status);
113 grab_kbd(saver_info *si, Window w, int screen_no)
115 saver_preferences *p = &si->prefs;
116 int status = XGrabKeyboard (si->dpy, w, True,
117 /* I don't really understand Sync vs Async,
118 but these seem to work... */
119 GrabModeSync, GrabModeAsync,
121 if (status == GrabSuccess)
123 si->keyboard_grab_window = w;
124 si->keyboard_grab_screen = screen_no;
128 fprintf(stderr, "%s: %d: grabbing keyboard on 0x%lx... %s.\n",
129 blurb(), screen_no, (unsigned long) w, grab_string(status));
135 grab_mouse (saver_info *si, Window w, Cursor cursor, int screen_no)
137 saver_preferences *p = &si->prefs;
138 int status = XGrabPointer (si->dpy, w, True, ALL_POINTER_EVENTS,
139 GrabModeAsync, GrabModeAsync, w,
140 cursor, CurrentTime);
141 if (status == GrabSuccess)
143 si->mouse_grab_window = w;
144 si->mouse_grab_screen = screen_no;
148 fprintf(stderr, "%s: %d: grabbing mouse on 0x%lx... %s.\n",
149 blurb(), screen_no, (unsigned long) w, grab_string(status));
155 ungrab_kbd(saver_info *si)
157 saver_preferences *p = &si->prefs;
158 XUngrabKeyboard(si->dpy, CurrentTime);
160 fprintf(stderr, "%s: %d: ungrabbing keyboard (was 0x%lx).\n",
161 blurb(), si->keyboard_grab_screen,
162 (unsigned long) si->keyboard_grab_window);
163 si->keyboard_grab_window = 0;
168 ungrab_mouse(saver_info *si)
170 saver_preferences *p = &si->prefs;
171 XUngrabPointer(si->dpy, CurrentTime);
173 fprintf(stderr, "%s: %d: ungrabbing mouse (was 0x%lx).\n",
174 blurb(), si->mouse_grab_screen,
175 (unsigned long) si->mouse_grab_window);
176 si->mouse_grab_window = 0;
180 /* Apparently there is this program called "rdesktop" which is a windows
181 terminal server client for Unix. It would seem that this program holds
182 the keyboard GRABBED the whole time it has focus! This is, of course,
183 completely idiotic: the whole point of grabbing is to get events when
184 you do *not* have focus, so grabbing *only when* you have focus is
185 completely redundant -- unless your goal is to make xscreensaver not
186 able to ever lock the screen when your program is running.
188 If xscreensaver blanks while rdesktop still has a keyboard grab, then
189 when we try to prompt for the password, we won't get the characters:
190 they'll be typed into rdesktop.
192 Perhaps rdesktop will release its keyboard grab if it loses focus?
193 What the hell, let's give it a try. If we fail to grab the keyboard
194 four times in a row, we forcibly set focus to "None" and try four
195 more times. (We don't touch focus unless we're already having a hard
196 time getting a grab.)
199 nuke_focus (saver_info *si, int screen_no)
201 saver_preferences *p = &si->prefs;
205 XGetInputFocus (si->dpy, &focus, &rev);
211 if (focus == PointerRoot) strcpy (w, "PointerRoot");
212 else if (focus == None) strcpy (w, "None");
213 else sprintf (w, "0x%lx", (unsigned long) focus);
215 if (rev == RevertToParent) strcpy (r, "RevertToParent");
216 else if (rev == RevertToPointerRoot) strcpy (r, "RevertToPointerRoot");
217 else if (rev == RevertToNone) strcpy (r, "RevertToNone");
218 else sprintf (r, "0x%x", rev);
220 fprintf (stderr, "%s: %d: removing focus from %s / %s.\n",
221 blurb(), screen_no, w, r);
224 XSetInputFocus (si->dpy, None, RevertToNone, CurrentTime);
225 XSync (si->dpy, False);
230 grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor,
233 Status mstatus = 0, kstatus = 0;
236 Bool focus_fuckus = False;
240 for (i = 0; i < retries; i++)
242 XSync (si->dpy, False);
243 kstatus = grab_kbd (si, window, screen_no);
244 if (kstatus == GrabSuccess)
247 /* else, wait a second and try to grab again. */
251 if (kstatus != GrabSuccess)
253 fprintf (stderr, "%s: couldn't grab keyboard! (%s)\n",
254 blurb(), grab_string(kstatus));
259 nuke_focus (si, screen_no);
264 for (i = 0; i < retries; i++)
266 XSync (si->dpy, False);
267 mstatus = grab_mouse (si, window, cursor, screen_no);
268 if (mstatus == GrabSuccess)
271 /* else, wait a second and try to grab again. */
275 if (mstatus != GrabSuccess)
276 fprintf (stderr, "%s: couldn't grab pointer! (%s)\n",
277 blurb(), grab_string(mstatus));
280 /* When should we allow blanking to proceed? The current theory
281 is that a keyboard grab is manditory; a mouse grab is optional.
283 - If we don't have a keyboard grab, then we won't be able to
284 read a password to unlock, so the kbd grab is manditory.
285 (We can't conditionalize this on locked_p, because someone
286 might run "xscreensaver-command -lock" at any time.)
288 - If we don't have a mouse grab, then we might not see mouse
289 clicks as a signal to unblank -- but we will still see kbd
290 activity, so that's not a disaster.
293 if (kstatus != GrabSuccess) /* Do not blank without a kbd grab. */
296 return True; /* Grab is good, go ahead and blank. */
300 ungrab_keyboard_and_mouse (saver_info *si)
308 move_mouse_grab (saver_info *si, Window to, Cursor cursor, int to_screen_no)
310 Window old = si->mouse_grab_window;
313 return grab_mouse (si, to, cursor, to_screen_no);
316 saver_preferences *p = &si->prefs;
319 XSync (si->dpy, False);
320 XGrabServer (si->dpy); /* ############ DANGER! */
321 XSync (si->dpy, False);
324 fprintf(stderr, "%s: grabbing server...\n", blurb());
327 status = grab_mouse (si, to, cursor, to_screen_no);
329 if (status != GrabSuccess) /* Augh! */
331 sleep (1); /* Note dramatic evil of sleeping
332 with server grabbed. */
333 XSync (si->dpy, False);
334 status = grab_mouse (si, to, cursor, to_screen_no);
337 if (status != GrabSuccess) /* Augh! Try to get the old one back... */
338 grab_mouse (si, old, cursor, to_screen_no);
340 XUngrabServer (si->dpy);
341 XSync (si->dpy, False); /* ###### (danger over) */
344 fprintf(stderr, "%s: ungrabbing server.\n", blurb());
351 /* Prints an error message to stderr and returns True if there is another
352 xscreensaver running already. Silently returns False otherwise. */
354 ensure_no_screensaver_running (Display *dpy, Screen *screen)
358 Window root = RootWindowOfScreen (screen);
359 Window root2, parent, *kids;
361 XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler);
363 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
369 for (i = 0; i < nkids; i++)
373 unsigned long nitems, bytesafter;
374 unsigned char *version;
376 if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
377 False, XA_STRING, &type, &format, &nitems,
378 &bytesafter, &version)
383 if (!XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
384 False, XA_STRING, &type, &format, &nitems,
388 id = (unsigned char *) "???";
391 "%s: already running on display %s (window 0x%x)\n from process %s.\n",
392 blurb(), DisplayString (dpy), (int) kids [i],
398 if (kids) XFree ((char *) kids);
400 XSetErrorHandler (old_handler);
406 /* Virtual-root hackery */
409 ERROR! You must not include vroot.h in this file.
413 store_vroot_property (Display *dpy, Window win, Window value)
418 "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", blurb(),
420 (win == screensaver_window ? "ScreenSaver" :
421 (win == real_vroot ? "VRoot" :
422 (win == real_vroot_value ? "Vroot_value" : "???"))),
424 (value == screensaver_window ? "ScreenSaver" :
425 (value == real_vroot ? "VRoot" :
426 (value == real_vroot_value ? "Vroot_value" : "???"))));
428 XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
429 (unsigned char *) &value, 1);
433 remove_vroot_property (Display *dpy, Window win)
437 fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", blurb(), win,
438 (win == screensaver_window ? "ScreenSaver" :
439 (win == real_vroot ? "VRoot" :
440 (win == real_vroot_value ? "Vroot_value" : "???"))));
442 XDeleteProperty (dpy, win, XA_VROOT);
446 static Bool safe_XKillClient (Display *dpy, XID id);
448 #ifdef HAVE_XF86VMODE
449 static Bool safe_XF86VidModeGetViewPort (Display *, int, int *, int *);
450 #endif /* HAVE_XF86VMODE */
454 kill_xsetroot_data_1 (Display *dpy, Window window,
455 Atom prop, const char *atom_name,
460 unsigned long nitems, bytesafter;
461 unsigned char *dataP = 0;
463 /* If the user has been using xv or xsetroot as a screensaver (to display
464 an image on the screensaver window, as a kind of slideshow) then the
465 pixmap and its associated color cells have been put in RetainPermanent
466 CloseDown mode. Since we're not destroying the xscreensaver window,
467 but merely unmapping it, we need to free these resources or those
468 colormap cells will stay allocated while the screensaver is off. (We
469 could just delete the screensaver window and recreate it later, but
470 that could cause other problems.) This code does an atomic read-and-
471 delete of the _XSETROOT_ID property, and if it held a pixmap, then we
472 cause the RetainPermanent resources of the client which created it
473 (and which no longer exists) to be freed.
475 Update: it seems that Gnome and KDE do this same trick, but with the
476 properties "ESETROOT_PMAP_ID" and/or "_XROOTPMAP_ID" instead of
477 "_XSETROOT_ID". So, we'll kill those too.
479 if (XGetWindowProperty (dpy, window, prop, 0, 1,
480 True, AnyPropertyType, &type, &format, &nitems,
485 Pixmap *pixP = (Pixmap *) dataP;
486 if (pixP && *pixP && type == XA_PIXMAP && format == 32 &&
487 nitems == 1 && bytesafter == 0)
490 fprintf (stderr, "%s: destroying %s data (0x%lX).\n",
491 blurb(), atom_name, *pixP);
492 safe_XKillClient (dpy, *pixP);
496 "%s: deleted unrecognised %s property: \n"
497 "\t%lu, %lu; type: %lu, format: %d, "
498 "nitems: %lu, bytesafter %ld\n",
500 (unsigned long) pixP, (pixP ? *pixP : 0), type,
501 format, nitems, bytesafter);
507 kill_xsetroot_data (Display *dpy, Window w, Bool verbose_p)
509 kill_xsetroot_data_1 (dpy, w, XA_XSETROOT_ID, "_XSETROOT_ID", verbose_p);
510 kill_xsetroot_data_1 (dpy, w, XA_ESETROOT_PMAP_ID, "ESETROOT_PMAP_ID",
512 kill_xsetroot_data_1 (dpy, w, XA_XROOTPMAP_ID, "_XROOTPMAP_ID", verbose_p);
517 save_real_vroot (saver_screen_info *ssi)
519 saver_info *si = ssi->global;
520 Display *dpy = si->dpy;
521 Screen *screen = ssi->screen;
523 Window root = RootWindowOfScreen (screen);
524 Window root2, parent, *kids;
526 XErrorHandler old_handler;
528 /* It's possible that a window might be deleted between our call to
529 XQueryTree() and our call to XGetWindowProperty(). Don't die if
530 that happens (but just ignore that window, it's not the one we're
531 interested in anyway.)
534 old_handler = XSetErrorHandler (BadWindow_ehandler);
538 ssi->real_vroot_value = 0;
539 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
545 for (i = 0; i < nkids; i++)
549 unsigned long nitems, bytesafter;
550 unsigned char *dataP = 0;
554 /* Skip this window if it is the xscreensaver window of any other
555 screen (this can happen in the Xinerama case.)
557 for (j = 0; j < si->nscreens; j++)
559 saver_screen_info *ssi2 = &si->screens[j];
560 if (kids[i] == ssi2->screensaver_window)
564 if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
565 &type, &format, &nitems, &bytesafter,
572 vrootP = (Window *) dataP;
575 if (*vrootP == ssi->screensaver_window) abort ();
577 "%s: more than one virtual root window found (0x%x and 0x%x).\n",
578 blurb(), (int) ssi->real_vroot, (int) kids [i]);
581 ssi->real_vroot = kids [i];
582 ssi->real_vroot_value = *vrootP;
588 XSetErrorHandler (old_handler);
593 remove_vroot_property (si->dpy, ssi->real_vroot);
597 XFree ((char *) kids);
602 restore_real_vroot_1 (saver_screen_info *ssi)
604 saver_info *si = ssi->global;
605 saver_preferences *p = &si->prefs;
606 if (p->verbose_p && ssi->real_vroot)
608 "%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
609 blurb(), (unsigned long) ssi->real_vroot);
610 remove_vroot_property (si->dpy, ssi->screensaver_window);
613 store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
615 ssi->real_vroot_value = 0;
616 /* make sure the property change gets there before this process
617 terminates! We might be doing this because we have intercepted
618 SIGTERM or something. */
619 XSync (si->dpy, False);
626 restore_real_vroot (saver_info *si)
629 Bool did_any = False;
630 for (i = 0; i < si->nscreens; i++)
632 saver_screen_info *ssi = &si->screens[i];
633 if (restore_real_vroot_1 (ssi))
640 /* Signal hackery to ensure that the vroot doesn't get left in an
645 signal_name(int signal)
648 case SIGHUP: return "SIGHUP";
649 case SIGINT: return "SIGINT";
650 case SIGQUIT: return "SIGQUIT";
651 case SIGILL: return "SIGILL";
652 case SIGTRAP: return "SIGTRAP";
654 case SIGABRT: return "SIGABRT";
656 case SIGFPE: return "SIGFPE";
657 case SIGKILL: return "SIGKILL";
658 case SIGBUS: return "SIGBUS";
659 case SIGSEGV: return "SIGSEGV";
660 case SIGPIPE: return "SIGPIPE";
661 case SIGALRM: return "SIGALRM";
662 case SIGTERM: return "SIGTERM";
664 case SIGSTOP: return "SIGSTOP";
667 case SIGCONT: return "SIGCONT";
670 case SIGUSR1: return "SIGUSR1";
673 case SIGUSR2: return "SIGUSR2";
676 case SIGEMT: return "SIGEMT";
679 case SIGSYS: return "SIGSYS";
682 case SIGCHLD: return "SIGCHLD";
685 case SIGPWR: return "SIGPWR";
688 case SIGWINCH: return "SIGWINCH";
691 case SIGURG: return "SIGURG";
694 case SIGIO: return "SIGIO";
697 case SIGVTALRM: return "SIGVTALRM";
700 case SIGXCPU: return "SIGXCPU";
703 case SIGXFSZ: return "SIGXFSZ";
706 case SIGDANGER: return "SIGDANGER";
711 sprintf(buf, "signal %d\n", signal);
720 restore_real_vroot_handler (int sig)
722 saver_info *si = global_si_kludge; /* I hate C so much... */
724 signal (sig, SIG_DFL);
725 if (restore_real_vroot (si))
726 fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n",
727 blurb(), signal_name(sig));
728 kill (getpid (), sig);
732 catch_signal (saver_info *si, int sig, RETSIGTYPE (*handler) (int))
734 # ifdef HAVE_SIGACTION
737 a.sa_handler = handler;
738 sigemptyset (&a.sa_mask);
741 /* On Linux 2.4.9 (at least) we need to tell the kernel to not mask delivery
742 of this signal from inside its handler, or else when we execvp() the
743 process again, it starts up with SIGHUP blocked, meaning that killing
744 it with -HUP only works *once*. You'd think that execvp() would reset
745 all the signal masks, but it doesn't.
747 # if defined(SA_NOMASK)
748 a.sa_flags |= SA_NOMASK;
749 # elif defined(SA_NODEFER)
750 a.sa_flags |= SA_NODEFER;
753 if (sigaction (sig, &a, 0) < 0)
754 # else /* !HAVE_SIGACTION */
755 if (((long) signal (sig, handler)) == -1L)
756 # endif /* !HAVE_SIGACTION */
759 sprintf (buf, "%s: couldn't catch %s", blurb(), signal_name(sig));
761 saver_exit (si, 1, 0);
765 static RETSIGTYPE saver_sighup_handler (int sig);
768 handle_signals (saver_info *si)
770 catch_signal (si, SIGHUP, saver_sighup_handler);
772 catch_signal (si, SIGINT, restore_real_vroot_handler);
773 catch_signal (si, SIGQUIT, restore_real_vroot_handler);
774 catch_signal (si, SIGILL, restore_real_vroot_handler);
775 catch_signal (si, SIGTRAP, restore_real_vroot_handler);
777 catch_signal (si, SIGIOT, restore_real_vroot_handler);
779 catch_signal (si, SIGABRT, restore_real_vroot_handler);
781 catch_signal (si, SIGEMT, restore_real_vroot_handler);
783 catch_signal (si, SIGFPE, restore_real_vroot_handler);
784 catch_signal (si, SIGBUS, restore_real_vroot_handler);
785 catch_signal (si, SIGSEGV, restore_real_vroot_handler);
787 catch_signal (si, SIGSYS, restore_real_vroot_handler);
789 catch_signal (si, SIGTERM, restore_real_vroot_handler);
791 catch_signal (si, SIGXCPU, restore_real_vroot_handler);
794 catch_signal (si, SIGXFSZ, restore_real_vroot_handler);
797 catch_signal (si, SIGDANGER, restore_real_vroot_handler);
803 saver_sighup_handler (int sig)
805 saver_info *si = global_si_kludge; /* I hate C so much... */
807 /* Re-establish SIGHUP handler */
808 catch_signal (si, SIGHUP, saver_sighup_handler);
810 fprintf (stderr, "%s: %s received: restarting...\n",
811 blurb(), signal_name(sig));
813 if (si->screen_blanked_p)
816 kill_screenhack (si);
817 XSync (si->dpy, False);
820 restart_process (si); /* Does not return */
827 saver_exit (saver_info *si, int status, const char *dump_core_reason)
829 saver_preferences *p = &si->prefs;
830 static Bool exiting = False;
839 vrs = restore_real_vroot (si);
840 emergency_kill_subproc (si);
841 shutdown_stderr (si);
843 if (p->verbose_p && vrs)
844 fprintf (real_stderr, "%s: old vroot restored.\n", blurb());
848 #ifdef VMS /* on VMS, 1 is the "normal" exit code instead of 0. */
849 if (status == 0) status = 1;
850 else if (status == 1) status = -1;
853 bugp = !!dump_core_reason;
855 if (si->prefs.debug_p && !dump_core_reason)
856 dump_core_reason = "because of -debug";
858 if (dump_core_reason)
860 /* Note that the Linux man page for setuid() says If uid is
861 different from the old effective uid, the process will be
862 forbidden from leaving core dumps.
864 char cwd[4096]; /* should really be PATH_MAX, but who cares. */
866 fprintf(real_stderr, "%s: dumping core (%s)\n", blurb(),
871 "%s: see http://www.jwz.org/xscreensaver/bugs.html\n"
872 "\t\t\tfor bug reporting information.\n\n",
875 # if defined(HAVE_GETCWD)
876 if (!getcwd (cwd, sizeof(cwd)))
877 # elif defined(HAVE_GETWD)
880 strcpy(cwd, "unknown.");
882 fprintf (real_stderr, "%s: current directory is %s\n", blurb(), cwd);
883 describe_uids (si, real_stderr);
885 /* Do this to drop a core file, so that we can get a stack trace. */
893 /* Managing the actual screensaver window */
896 window_exists_p (Display *dpy, Window window)
898 XErrorHandler old_handler;
899 XWindowAttributes xgwa;
901 old_handler = XSetErrorHandler (BadWindow_ehandler);
902 XGetWindowAttributes (dpy, window, &xgwa);
904 XSetErrorHandler (old_handler);
905 return (xgwa.screen != 0);
909 store_saver_id (saver_screen_info *ssi)
911 XClassHint class_hints;
912 saver_info *si = ssi->global;
913 unsigned long pid = (unsigned long) getpid ();
915 struct passwd *p = getpwuid (getuid ());
916 const char *name, *host;
919 /* First store the name and class on the window.
921 class_hints.res_name = progname;
922 class_hints.res_class = progclass;
923 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
924 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
926 /* Then store the xscreensaver version number.
928 XChangeProperty (si->dpy, ssi->screensaver_window,
929 XA_SCREENSAVER_VERSION,
930 XA_STRING, 8, PropModeReplace,
931 (unsigned char *) si->version,
932 strlen (si->version));
934 /* Now store the XSCREENSAVER_ID property, that says what user and host
935 xscreensaver is running as.
938 if (p && p->pw_name && *p->pw_name)
942 sprintf (buf, "%lu", (unsigned long) p->pw_uid);
948 # if defined(HAVE_UNAME)
951 if (uname (&uts) < 0)
957 host = getenv("SYS$NODE");
958 # else /* !HAVE_UNAME && !VMS */
960 # endif /* !HAVE_UNAME && !VMS */
962 id = (char *) malloc (strlen(name) + strlen(host) + 50);
963 sprintf (id, "%lu (%s@%s)", pid, name, host);
965 XChangeProperty (si->dpy, ssi->screensaver_window,
966 XA_SCREENSAVER_ID, XA_STRING,
968 (unsigned char *) id, strlen (id));
974 store_saver_status (saver_info *si)
977 int size = si->nscreens + 2;
980 status = (PROP32 *) calloc (size, sizeof(PROP32));
982 status[0] = (PROP32) (si->screen_blanked_p
983 ? (si->locked_p ? XA_LOCK : XA_BLANK)
985 status[1] = (PROP32) si->blank_time;
987 for (i = 0; i < si->nscreens; i++)
989 saver_screen_info *ssi = &si->screens[i];
990 status [2 + i] = ssi->current_hack + 1;
993 XChangeProperty (si->dpy,
994 RootWindow (si->dpy, 0), /* always screen #0 */
995 XA_SCREENSAVER_STATUS,
996 XA_INTEGER, 32, PropModeReplace,
997 (unsigned char *) status, size);
1003 /* Returns the area of the screen which the xscreensaver window should cover.
1004 Normally this is the whole screen, but if the X server's root window is
1005 actually larger than the monitor's displayable area, then we want to
1006 operate in the currently-visible portion of the desktop instead.
1009 get_screen_viewport (saver_screen_info *ssi,
1010 int *x_ret, int *y_ret,
1011 int *w_ret, int *h_ret,
1012 int target_x, int target_y,
1015 int w = WidthOfScreen (ssi->screen);
1016 int h = HeightOfScreen (ssi->screen);
1018 # ifdef HAVE_XF86VMODE
1019 saver_info *si = ssi->global;
1020 saver_preferences *p = &si->prefs;
1023 XF86VidModeModeLine ml;
1025 Bool xinerama_p = si->xinerama_p;
1027 # ifndef HAVE_XINERAMA
1028 /* Even if we don't have the client-side Xinerama lib, check to see if
1029 the server supports Xinerama, so that we know to ignore the VidMode
1030 extension -- otherwise a server crash could result. Yay. */
1031 xinerama_p = XQueryExtension (si->dpy, "XINERAMA", &error, &event, &error);
1032 # endif /* !HAVE_XINERAMA */
1034 # ifdef HAVE_XINERAMA
1037 int mouse_p = (target_x != -1 && target_y != -1);
1041 /* If a mouse position wasn't passed in, assume we're talking about
1049 /* Find the Xinerama rectangle that contains the mouse position. */
1050 for (i = 0; i < si->nscreens; i++)
1052 if (target_x >= si->screens[i].x &&
1053 target_y >= si->screens[i].y &&
1054 target_x < si->screens[i].x + si->screens[i].width &&
1055 target_y < si->screens[i].y + si->screens[i].height)
1058 if (which == -1) which = 0; /* didn't find it? Use the first. */
1059 *x_ret = si->screens[which].x;
1060 *y_ret = si->screens[which].y;
1061 *w_ret = si->screens[which].width;
1062 *h_ret = si->screens[which].height;
1066 fprintf (stderr, "%s: %d: xinerama vp: %dx%d+%d+%d",
1068 si->screens[which].width, si->screens[which].height,
1069 si->screens[which].x, si->screens[which].y);
1071 fprintf (stderr, "; mouse at %d,%d", target_x, target_y);
1072 fprintf (stderr, ".\n");
1077 # endif /* HAVE_XINERAMA */
1079 if (!xinerama_p && /* Xinerama + VidMode = broken. */
1080 XF86VidModeQueryExtension (si->dpy, &event, &error) &&
1081 safe_XF86VidModeGetViewPort (si->dpy, ssi->number, &x, &y) &&
1082 XF86VidModeGetModeLine (si->dpy, ssi->number, &dot, &ml))
1087 *w_ret = ml.hdisplay;
1088 *h_ret = ml.vdisplay;
1090 if (*x_ret == 0 && *y_ret == 0 && *w_ret == w && *h_ret == h)
1091 /* There is no viewport -- the screen does not scroll. */
1095 /* Apparently some versions of XFree86 return nonsense here!
1096 I've had reports of 1024x768 viewports at -1936862040, -1953705044.
1097 So, sanity-check the values and give up if they are out of range.
1099 if (*x_ret < 0 || *x_ret >= w ||
1100 *y_ret < 0 || *y_ret >= h ||
1101 *w_ret <= 0 || *w_ret > w ||
1102 *h_ret <= 0 || *h_ret > h)
1104 static int warned_once = 0;
1107 fprintf (stderr, "\n"
1108 "%s: X SERVER BUG: %dx%d viewport at %d,%d is impossible.\n"
1109 "%s: The XVidMode server extension is returning nonsense.\n"
1110 "%s: Please report this bug to your X server vendor.\n\n",
1111 blurb(), *w_ret, *h_ret, *x_ret, *y_ret,
1122 sprintf (msg, "%s: %d: vp is %dx%d+%d+%d",
1123 blurb(), ssi->number,
1124 *w_ret, *h_ret, *x_ret, *y_ret);
1127 if (p->getviewport_full_of_lies_p)
1129 /* XF86VidModeGetViewPort() tends to be full of lies on laptops
1130 that have a docking station or external monitor that runs in
1131 a different resolution than the laptop's screen:
1133 http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=81593
1134 http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=208417
1135 http://bugs.xfree86.org/show_bug.cgi?id=421
1137 The XFree86 developers have closed the bug. As far as I can
1138 tell, their reason for this was, "this is an X server bug,
1139 but it's pretty hard to fix. Therefore, we are closing it."
1141 So, now there's a preference item for those unfortunate users to
1142 tell us not to trust a word that XF86VidModeGetViewPort() says.
1144 static int warned_once = 0;
1145 if (!warned_once && verbose_p)
1149 "%s: %d: XF86VidModeGetViewPort() says vp is %dx%d+%d+%d;\n"
1150 "%s: %d: assuming that is a pack of lies;\n"
1151 "%s: %d: using %dx%d+0+0 instead.\n",
1152 blurb(), ssi->number,
1153 *w_ret, *h_ret, *x_ret, *y_ret,
1154 blurb(), ssi->number,
1155 blurb(), ssi->number, w, h);
1166 /* Apparently, though the server stores the X position in increments of
1167 1 pixel, it will only make changes to the *display* in some other
1168 increment. With XF86_SVGA on a Thinkpad, the display only updates
1169 in multiples of 8 pixels when in 8-bit mode, and in multiples of 4
1170 pixels in 16-bit mode. I don't know what it does in 24- and 32-bit
1171 mode, because I don't have enough video memory to find out.
1173 I consider it a bug that XF86VidModeGetViewPort() is telling me the
1174 server's *target* scroll position rather than the server's *actual*
1175 scroll position. David Dawes agrees, and says they may fix this in
1176 XFree86 4.0, but it's notrivial.
1178 He also confirms that this behavior is server-dependent, so the
1179 actual scroll position cannot be reliably determined by the client.
1180 So... that means the only solution is to provide a ``sandbox''
1181 around the blackout window -- we make the window be up to N pixels
1182 larger than the viewport on both the left and right sides. That
1183 means some part of the outer edges of each hack might not be
1184 visible, but screw it.
1186 I'm going to guess that 16 pixels is enough, and that the Y dimension
1187 doesn't have this problem.
1189 The drawback of doing this, of course, is that some of the screenhacks
1190 will still look pretty stupid -- for example, "slidescreen" will cut
1191 off the left and right edges of the grid, etc.
1194 if (x > 0 && x < w - ml.hdisplay) /* not at left edge or right edge */
1196 /* Round X position down to next lower multiple of FUDGE.
1197 Increase width by 2*FUDGE in case some server rounds up.
1199 *x_ret = ((x - 1) / FUDGE) * FUDGE;
1200 *w_ret += (FUDGE * 2);
1206 *w_ret != ml.hdisplay ||
1207 *h_ret != ml.vdisplay)
1208 sprintf (msg + strlen(msg), "; fudged to %dx%d+%d+%d",
1209 *w_ret, *h_ret, *x_ret, *y_ret);
1212 fprintf (stderr, "%s.\n", msg);
1217 # endif /* HAVE_XF86VMODE */
1226 static Bool error_handler_hit_p = False;
1229 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1231 error_handler_hit_p = True;
1236 /* Returns True if successful, False if an X error occurred.
1237 We need this because other programs might have done things to
1238 our window that will cause XChangeWindowAttributes() to fail:
1239 if that happens, we give up, destroy the window, and re-create
1243 safe_XChangeWindowAttributes (Display *dpy, Window window,
1245 XSetWindowAttributes *attrs)
1247 XErrorHandler old_handler;
1249 error_handler_hit_p = False;
1250 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1252 XChangeWindowAttributes (dpy, window, mask, attrs);
1255 XSetErrorHandler (old_handler);
1258 return (!error_handler_hit_p);
1262 /* This might not be necessary, but just in case. */
1264 safe_XConfigureWindow (Display *dpy, Window window,
1265 unsigned long mask, XWindowChanges *changes)
1267 XErrorHandler old_handler;
1269 error_handler_hit_p = False;
1270 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1272 XConfigureWindow (dpy, window, mask, changes);
1275 XSetErrorHandler (old_handler);
1278 return (!error_handler_hit_p);
1281 /* This might not be necessary, but just in case. */
1283 safe_XDestroyWindow (Display *dpy, Window window)
1285 XErrorHandler old_handler;
1287 error_handler_hit_p = False;
1288 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1290 XDestroyWindow (dpy, window);
1293 XSetErrorHandler (old_handler);
1296 return (!error_handler_hit_p);
1301 safe_XKillClient (Display *dpy, XID id)
1303 XErrorHandler old_handler;
1305 error_handler_hit_p = False;
1306 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1308 XKillClient (dpy, id);
1311 XSetErrorHandler (old_handler);
1314 return (!error_handler_hit_p);
1318 #ifdef HAVE_XF86VMODE
1320 safe_XF86VidModeGetViewPort (Display *dpy, int screen, int *xP, int *yP)
1323 XErrorHandler old_handler;
1325 error_handler_hit_p = False;
1326 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1328 result = XF86VidModeGetViewPort (dpy, screen, xP, yP);
1331 XSetErrorHandler (old_handler);
1334 return (error_handler_hit_p
1339 /* There is no "safe_XF86VidModeGetModeLine" because it fails with an
1340 untrappable I/O error instead of an X error -- so one must call
1341 safe_XF86VidModeGetViewPort first, and assume that both have the
1342 same error condition. Thank you XFree, may I have another.
1345 #endif /* HAVE_XF86VMODE */
1349 initialize_screensaver_window_1 (saver_screen_info *ssi)
1351 saver_info *si = ssi->global;
1352 saver_preferences *p = &si->prefs;
1353 Bool install_cmap_p = ssi->install_cmap_p; /* not p->install_cmap_p */
1355 /* This resets the screensaver window as fully as possible, since there's
1356 no way of knowing what some random client may have done to us in the
1357 meantime. We could just destroy and recreate the window, but that has
1358 its own set of problems...
1361 XSetWindowAttributes attrs;
1362 unsigned long attrmask;
1363 int x, y, width, height;
1364 static Bool printed_visual_info = False; /* only print the message once. */
1365 Window horked_window = 0;
1367 get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
1368 (p->verbose_p && !si->screen_blanked_p));
1370 black.red = black.green = black.blue = 0;
1372 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
1375 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
1376 /* It's not the default visual, so we have no choice but to install. */
1377 install_cmap_p = True;
1383 ssi->cmap = XCreateColormap (si->dpy,
1384 RootWindowOfScreen (ssi->screen),
1385 ssi->current_visual, AllocNone);
1386 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
1387 ssi->black_pixel = black.pixel;
1392 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
1395 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
1396 if (ssi->cmap != ssi->demo_cmap &&
1397 ssi->cmap != def_cmap)
1398 XFreeColormap (si->dpy, ssi->cmap);
1400 ssi->cmap = def_cmap;
1401 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
1404 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
1405 CWBackPixel | CWBackingPixel | CWBorderPixel);
1406 attrs.override_redirect = True;
1408 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
1409 actually be reading these events during normal operation; but we still
1410 need to see Button events for demo-mode to work properly.
1412 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
1413 ButtonPressMask | ButtonReleaseMask |
1416 attrs.backing_store = NotUseful;
1417 attrs.colormap = ssi->cmap;
1418 attrs.background_pixel = ssi->black_pixel;
1419 attrs.backing_pixel = ssi->black_pixel;
1420 attrs.border_pixel = ssi->black_pixel;
1422 if (p->debug_p && !p->quad_p) width = width / 2;
1424 if (!p->verbose_p || printed_visual_info)
1426 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
1428 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1429 describe_visual (stderr, ssi->screen, ssi->current_visual,
1434 fprintf (stderr, "%s: using visual: ", blurb());
1435 describe_visual (stderr, ssi->screen, ssi->current_visual,
1437 fprintf (stderr, "%s: default visual: ", blurb());
1438 describe_visual (stderr, ssi->screen,
1439 DefaultVisualOfScreen (ssi->screen),
1440 ssi->install_cmap_p);
1442 printed_visual_info = True;
1444 #ifdef HAVE_MIT_SAVER_EXTENSION
1445 if (si->using_mit_saver_extension)
1447 XScreenSaverInfo *info;
1448 Window root = RootWindowOfScreen (ssi->screen);
1451 /* This call sets the server screensaver timeouts to what we think
1452 they should be (based on the resources and args xscreensaver was
1453 started with.) It's important that we do this to sync back up
1454 with the server - if we have turned on prematurely, as by an
1455 ACTIVATE ClientMessage, then the server may decide to activate
1456 the screensaver while it's already active. That's ok for us,
1457 since we would know to ignore that ScreenSaverActivate event,
1458 but a side effect of this would be that the server would map its
1459 saver window (which we then hide again right away) meaning that
1460 the bits currently on the screen get blown away. Ugly. */
1462 /* #### Ok, that doesn't work - when we tell the server that the
1463 screensaver is "off" it sends us a Deactivate event, which is
1464 sensible... but causes the saver to never come on. Hmm. */
1465 disable_builtin_screensaver (si, True);
1469 /* #### The MIT-SCREEN-SAVER extension gives us access to the
1470 window that the server itself uses for saving the screen.
1471 However, using this window in any way, in particular, calling
1472 XScreenSaverSetAttributes() as below, tends to make the X server
1473 crash. So fuck it, let's try and get along without using it...
1475 It's also inconvenient to use this window because it doesn't
1476 always exist (though the ID is constant.) So to use this
1477 window, we'd have to reimplement the ACTIVATE ClientMessage to
1478 tell the *server* to tell *us* to turn on, to cause the window
1479 to get created at the right time. Gag. */
1480 XScreenSaverSetAttributes (si->dpy, root,
1481 0, 0, width, height, 0,
1482 current_depth, InputOutput, visual,
1484 XSync (si->dpy, False);
1487 info = XScreenSaverAllocInfo ();
1488 XScreenSaverQueryInfo (si->dpy, root, info);
1489 ssi->server_mit_saver_window = info->window;
1490 if (! ssi->server_mit_saver_window) abort ();
1493 #endif /* HAVE_MIT_SAVER_EXTENSION */
1495 if (ssi->screensaver_window)
1497 XWindowChanges changes;
1498 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1501 changes.width = width;
1502 changes.height = height;
1503 changes.border_width = 0;
1505 if (! (safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1506 changesmask, &changes) &&
1507 safe_XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
1510 horked_window = ssi->screensaver_window;
1511 ssi->screensaver_window = 0;
1515 if (!ssi->screensaver_window)
1517 ssi->screensaver_window =
1518 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen),
1519 x, y, width, height,
1520 0, ssi->current_depth, InputOutput,
1521 ssi->current_visual, attrmask, &attrs);
1528 "%s: someone horked our saver window (0x%lx)! Recreating it...\n",
1529 blurb(), (unsigned long) horked_window);
1530 maybe_transfer_grabs (ssi, horked_window, ssi->screensaver_window,
1532 safe_XDestroyWindow (si->dpy, horked_window);
1537 fprintf (stderr, "%s: %d: saver window is 0x%lx.\n",
1538 blurb(), ssi->number,
1539 (unsigned long) ssi->screensaver_window);
1542 store_saver_id (ssi); /* store window name and IDs */
1547 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
1549 BlackPixelOfScreen (ssi->screen),
1550 BlackPixelOfScreen (ssi->screen),
1552 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
1554 XFreePixmap (si->dpy, bit);
1557 XSetWindowBackground (si->dpy, ssi->screensaver_window, ssi->black_pixel);
1560 XUndefineCursor (si->dpy, ssi->screensaver_window);
1562 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
1566 initialize_screensaver_window (saver_info *si)
1569 for (i = 0; i < si->nscreens; i++)
1570 initialize_screensaver_window_1 (&si->screens[i]);
1574 /* Called when the RANDR (Resize and Rotate) extension tells us that the
1575 size of the screen has changed while the screen was blanked. If we
1576 don't do this, then the screen saver will no longer fully fill the
1577 screen, and some of the underlying desktop may be visible.
1580 resize_screensaver_window (saver_info *si)
1582 saver_preferences *p = &si->prefs;
1585 /* First update the size info in the saver_screen_info structs.
1588 # ifdef HAVE_XINERAMA
1591 /* As of XFree86 4.3.0, the RANDR and XINERAMA extensions cannot coexist.
1592 However, maybe they will someday, so I'm guessing that the right thing
1593 to do in that case will be to re-query the Xinerama rectangles after
1594 a RANDR size change is received: presumably, if the resolution of one
1595 or more of the monitors has changed, then the Xinerama rectangle
1596 corresponding to that monitor will also have been updated.
1599 XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
1600 if (nscreens != si->nscreens) abort();
1602 for (i = 0; i < si->nscreens; i++)
1604 saver_screen_info *ssi = &si->screens[i];
1606 (ssi->x != xsi[i].x_org ||
1607 ssi->y != xsi[i].y_org ||
1608 ssi->width != xsi[i].width ||
1609 ssi->height != xsi[i].height))
1611 "%s: %d: resize xinerama from %dx%d+%d+%d to %dx%d+%d+%d\n",
1613 ssi->width, ssi->height, ssi->x, ssi->y,
1614 xsi[i].width, xsi[i].height, xsi[i].x_org, xsi[i].y_org);
1616 ssi->x = xsi[i].x_org;
1617 ssi->y = xsi[i].y_org;
1618 ssi->width = xsi[i].width;
1619 ssi->height = xsi[i].height;
1624 # endif /* HAVE_XINERAMA */
1626 /* Not Xinerama -- get the real sizes of the root windows. */
1627 for (i = 0; i < si->nscreens; i++)
1629 saver_screen_info *ssi = &si->screens[i];
1630 XWindowAttributes xgwa;
1631 XGetWindowAttributes (si->dpy, RootWindowOfScreen (ssi->screen),
1635 (ssi->x != xgwa.x ||
1637 ssi->width != xgwa.width ||
1638 ssi->height != xgwa.height))
1640 "%s: %d: resize screen from %dx%d+%d+%d to %dx%d+%d+%d\n",
1642 ssi->width, ssi->height, ssi->x, ssi->y,
1643 xgwa.width, xgwa.height, xgwa.x, xgwa.y);
1647 ssi->width = xgwa.width;
1648 ssi->height = xgwa.height;
1652 /* Next, ensure that the screensaver windows are the right size, taking
1653 into account both the new size of the screen in question's root window,
1654 and any viewport within that.
1657 for (i = 0; i < si->nscreens; i++)
1659 saver_screen_info *ssi = &si->screens[i];
1660 XWindowAttributes xgwa;
1661 XWindowChanges changes;
1662 int x, y, width, height;
1663 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1665 XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
1666 get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
1667 (p->verbose_p && !si->screen_blanked_p));
1670 xgwa.width == width &&
1671 xgwa.height == height)
1672 continue; /* no change! */
1676 changes.width = width;
1677 changes.height = height;
1678 changes.border_width = 0;
1680 if (p->debug_p && !p->quad_p) changes.width = changes.width / 2;
1684 "%s: %d: resize 0x%lx from %dx%d+%d+%d to %dx%d+%d+%d\n",
1685 blurb(), i, (unsigned long) ssi->screensaver_window,
1686 xgwa.width, xgwa.height, xgwa.x, xgwa.y,
1687 width, height, x, y);
1688 if (! safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1689 changesmask, &changes))
1692 "%s: %d: someone horked our saver window (0x%lx)! Unable to resize it!\n",
1693 blurb(), i, (unsigned long) ssi->screensaver_window);
1700 raise_window (saver_info *si,
1701 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
1703 saver_preferences *p = &si->prefs;
1707 inhibit_fade = True;
1709 if (si->emergency_lock_p)
1710 inhibit_fade = True;
1713 initialize_screensaver_window (si);
1715 reset_watchdog_timer (si, True);
1717 if (p->fade_p && si->fading_possible_p && !inhibit_fade)
1719 Window *current_windows = (Window *)
1720 calloc(sizeof(Window), si->nscreens);
1721 Colormap *current_maps = (Colormap *)
1722 calloc(sizeof(Colormap), si->nscreens);
1724 for (i = 0; i < si->nscreens; i++)
1726 saver_screen_info *ssi = &si->screens[i];
1727 current_windows[i] = ssi->screensaver_window;
1728 current_maps[i] = (between_hacks_p
1730 : DefaultColormapOfScreen (ssi->screen));
1731 /* Ensure that the default background of the window is really black,
1732 not a pixmap or something. (This does not clear the window.) */
1733 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1737 if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
1739 XGrabServer (si->dpy); /* ############ DANGER! */
1741 /* Clear the stderr layer on each screen.
1744 for (i = 0; i < si->nscreens; i++)
1746 saver_screen_info *ssi = &si->screens[i];
1747 if (ssi->stderr_overlay_window)
1748 /* Do this before the fade, since the stderr cmap won't fade
1749 even if we uninstall it (beats me...) */
1753 /* Note! The server is grabbed, and this will take several seconds
1755 fade_screens (si->dpy, current_maps,
1756 current_windows, si->nscreens,
1757 p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
1760 free(current_windows);
1762 current_windows = 0;
1764 if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
1766 #ifdef HAVE_MIT_SAVER_EXTENSION
1767 for (i = 0; i < si->nscreens; i++)
1769 saver_screen_info *ssi = &si->screens[i];
1770 if (ssi->server_mit_saver_window &&
1771 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1772 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1774 #endif /* HAVE_MIT_SAVER_EXTENSION */
1776 XUngrabServer (si->dpy);
1777 XSync (si->dpy, False); /* ###### (danger over) */
1781 for (i = 0; i < si->nscreens; i++)
1783 saver_screen_info *ssi = &si->screens[i];
1785 XClearWindow (si->dpy, ssi->screensaver_window);
1786 if (!dont_clear || ssi->stderr_overlay_window)
1788 XMapRaised (si->dpy, ssi->screensaver_window);
1789 #ifdef HAVE_MIT_SAVER_EXTENSION
1790 if (ssi->server_mit_saver_window &&
1791 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1792 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1793 #endif /* HAVE_MIT_SAVER_EXTENSION */
1797 for (i = 0; i < si->nscreens; i++)
1799 saver_screen_info *ssi = &si->screens[i];
1801 XInstallColormap (si->dpy, ssi->cmap);
1807 mouse_screen (saver_info *si)
1809 saver_preferences *p = &si->prefs;
1810 Window pointer_root, pointer_child;
1811 int root_x, root_y, win_x, win_y;
1815 if (si->nscreens == 1)
1818 for (i = 0; i < si->nscreens; i++)
1820 saver_screen_info *ssi = &si->screens[i];
1821 if (XQueryPointer (si->dpy, RootWindowOfScreen (ssi->screen),
1822 &pointer_root, &pointer_child,
1823 &root_x, &root_y, &win_x, &win_y, &mask) &&
1826 root_x < ssi->x + ssi->width &&
1827 root_y < ssi->y + ssi->height)
1830 fprintf (stderr, "%s: mouse is on screen %d of %d\n",
1831 blurb(), i, si->nscreens);
1836 /* couldn't figure out where the mouse is? Oh well. */
1842 blank_screen (saver_info *si)
1849 /* Note: we do our grabs on the root window, not on the screensaver window.
1850 If we grabbed on the saver window, then the demo mode and lock dialog
1851 boxes wouldn't get any events.
1853 By "the root window", we mean "the root window that contains the mouse."
1854 We use to always grab the mouse on screen 0, but that has the effect of
1855 moving the mouse to screen 0 from whichever screen it was on, on
1858 mscreen = mouse_screen (si);
1859 w = RootWindowOfScreen(si->screens[mscreen].screen);
1860 ok = grab_keyboard_and_mouse (si, w,
1861 (si->demoing_p ? 0 : si->screens[0].cursor),
1866 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1867 /* If we're using a server extension, then failure to get a grab is
1868 not a big deal -- even without the grab, we will still be able
1869 to un-blank when there is user activity, since the server will
1871 /* #### No, that's not true: if we don't have a keyboard grab,
1872 then we can't read passwords to unlock.
1880 for (i = 0; i < si->nscreens; i++)
1882 saver_screen_info *ssi = &si->screens[i];
1883 if (ssi->real_screen_p)
1884 save_real_vroot (ssi);
1885 store_vroot_property (si->dpy,
1886 ssi->screensaver_window,
1887 ssi->screensaver_window);
1889 #ifdef HAVE_XF86VMODE
1892 if (!XF86VidModeQueryExtension (si->dpy, &ev, &er) ||
1893 !safe_XF86VidModeGetViewPort (si->dpy, i,
1896 ssi->blank_vp_x = ssi->blank_vp_y = -1;
1898 #endif /* HAVE_XF86VMODE */
1901 raise_window (si, False, False, False);
1903 si->screen_blanked_p = True;
1904 si->blank_time = time ((time_t) 0);
1905 si->last_wall_clock_time = 0;
1907 store_saver_status (si); /* store blank time */
1914 unblank_screen (saver_info *si)
1916 saver_preferences *p = &si->prefs;
1917 Bool unfade_p = (si->fading_possible_p && p->unfade_p);
1920 monitor_power_on (si);
1921 reset_watchdog_timer (si, False);
1928 Window *current_windows = (Window *)
1929 calloc(sizeof(Window), si->nscreens);
1931 for (i = 0; i < si->nscreens; i++)
1933 saver_screen_info *ssi = &si->screens[i];
1934 current_windows[i] = ssi->screensaver_window;
1935 /* Ensure that the default background of the window is really black,
1936 not a pixmap or something. (This does not clear the window.) */
1937 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1941 if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
1944 XSync (si->dpy, False);
1945 XGrabServer (si->dpy); /* ############ DANGER! */
1946 XSync (si->dpy, False);
1948 /* Clear the stderr layer on each screen.
1950 for (i = 0; i < si->nscreens; i++)
1952 saver_screen_info *ssi = &si->screens[i];
1956 XUngrabServer (si->dpy);
1957 XSync (si->dpy, False); /* ###### (danger over) */
1959 fade_screens (si->dpy, 0,
1960 current_windows, si->nscreens,
1961 p->fade_seconds/1000, p->fade_ticks,
1964 free(current_windows);
1965 current_windows = 0;
1967 if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
1971 for (i = 0; i < si->nscreens; i++)
1973 saver_screen_info *ssi = &si->screens[i];
1976 Colormap c = DefaultColormapOfScreen (ssi->screen);
1977 /* avoid technicolor */
1978 XClearWindow (si->dpy, ssi->screensaver_window);
1979 if (c) XInstallColormap (si->dpy, c);
1981 XUnmapWindow (si->dpy, ssi->screensaver_window);
1986 /* If the focus window does has a non-default colormap, then install
1987 that colormap as well. (On SGIs, this will cause both the root map
1988 and the focus map to be installed simultaneously. It'd be nice to
1989 pick up the other colormaps that had been installed, too; perhaps
1990 XListInstalledColormaps could be used for that?)
1995 XGetInputFocus (si->dpy, &focus, &revert_to);
1996 if (focus && focus != PointerRoot && focus != None)
1998 XWindowAttributes xgwa;
2000 XGetWindowAttributes (si->dpy, focus, &xgwa);
2001 if (xgwa.colormap &&
2002 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
2003 XInstallColormap (si->dpy, xgwa.colormap);
2008 for (i = 0; i < si->nscreens; i++)
2010 saver_screen_info *ssi = &si->screens[i];
2011 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
2014 store_saver_status (si); /* store unblank time */
2015 ungrab_keyboard_and_mouse (si);
2016 restore_real_vroot (si);
2018 /* Unmap the windows a second time, dammit -- just to avoid a race
2019 with the screen-grabbing hacks. (I'm not sure if this is really
2020 necessary; I'm stabbing in the dark now.)
2022 for (i = 0; i < si->nscreens; i++)
2023 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
2025 si->screen_blanked_p = False;
2026 si->blank_time = time ((time_t) 0);
2027 si->last_wall_clock_time = 0;
2029 store_saver_status (si); /* store unblank time */
2033 /* Transfer any grabs from the old window to the new.
2034 Actually I think none of this is necessary, since we always
2035 hold our grabs on the root window, but I wrote this before
2036 re-discovering that...
2039 maybe_transfer_grabs (saver_screen_info *ssi,
2040 Window old_w, Window new_w,
2043 saver_info *si = ssi->global;
2045 /* If the old window held our mouse grab, transfer the grab to the new
2046 window. (Grab the server while so doing, to avoid a race condition.)
2048 if (old_w == si->mouse_grab_window)
2050 XGrabServer (si->dpy); /* ############ DANGER! */
2052 grab_mouse (si, ssi->screensaver_window,
2053 (si->demoing_p ? 0 : ssi->cursor),
2055 XUngrabServer (si->dpy);
2056 XSync (si->dpy, False); /* ###### (danger over) */
2059 /* If the old window held our keyboard grab, transfer the grab to the new
2060 window. (Grab the server while so doing, to avoid a race condition.)
2062 if (old_w == si->keyboard_grab_window)
2064 XGrabServer (si->dpy); /* ############ DANGER! */
2066 grab_kbd(si, ssi->screensaver_window, ssi->number);
2067 XUngrabServer (si->dpy);
2068 XSync (si->dpy, False); /* ###### (danger over) */
2075 select_visual (saver_screen_info *ssi, const char *visual_name)
2077 saver_info *si = ssi->global;
2078 saver_preferences *p = &si->prefs;
2079 Bool install_cmap_p = p->install_cmap_p;
2080 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
2084 /* On some systems (most recently, MacOS X) OpenGL programs get confused
2085 when you kill one and re-start another on the same window. So maybe
2086 it's best to just always destroy and recreate the xscreensaver window
2087 when changing hacks, instead of trying to reuse the old one?
2089 Bool always_recreate_window_p = True;
2091 if (visual_name && *visual_name)
2093 if (!strcmp(visual_name, "default-i") ||
2094 !strcmp(visual_name, "Default-i") ||
2095 !strcmp(visual_name, "Default-I")
2098 visual_name = "default";
2099 install_cmap_p = True;
2101 else if (!strcmp(visual_name, "default-n") ||
2102 !strcmp(visual_name, "Default-n") ||
2103 !strcmp(visual_name, "Default-N"))
2105 visual_name = "default";
2106 install_cmap_p = False;
2108 else if (!strcmp(visual_name, "gl") ||
2109 !strcmp(visual_name, "Gl") ||
2110 !strcmp(visual_name, "GL"))
2112 new_v = ssi->best_gl_visual;
2113 if (!new_v && p->verbose_p)
2114 fprintf (stderr, "%s: no GL visuals.\n", progname);
2118 new_v = get_visual (ssi->screen, visual_name, True, False);
2122 new_v = ssi->default_visual;
2127 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
2128 /* It's not the default visual, so we have no choice but to install. */
2129 install_cmap_p = True;
2131 ssi->install_cmap_p = install_cmap_p;
2134 (always_recreate_window_p ||
2135 (ssi->current_visual != new_v) ||
2136 (install_cmap_p != was_installed_p)))
2138 Colormap old_c = ssi->cmap;
2139 Window old_w = ssi->screensaver_window;
2143 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
2144 describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
2146 fprintf (stderr, "%s: from ", blurb());
2147 describe_visual (stderr, ssi->screen, ssi->current_visual,
2153 ssi->current_visual = new_v;
2154 ssi->current_depth = visual_depth(ssi->screen, new_v);
2156 ssi->screensaver_window = 0;
2158 initialize_screensaver_window_1 (ssi);
2160 /* stderr_overlay_window is a child of screensaver_window, so we need
2161 to destroy that as well (actually, we just need to invalidate and
2162 drop our pointers to it, but this will destroy it, which is ok so
2163 long as it happens before old_w itself is destroyed.) */
2166 raise_window (si, True, True, False);
2167 store_vroot_property (si->dpy,
2168 ssi->screensaver_window, ssi->screensaver_window);
2170 /* Transfer any grabs from the old window to the new. */
2171 maybe_transfer_grabs (ssi, old_w, ssi->screensaver_window, ssi->number);
2173 /* Now we can destroy the old window without horking our grabs. */
2174 XDestroyWindow (si->dpy, old_w);
2177 fprintf (stderr, "%s: %d: destroyed old saver window 0x%lx.\n",
2178 blurb(), ssi->number, (unsigned long) old_w);
2181 old_c != DefaultColormapOfScreen (ssi->screen) &&
2182 old_c != ssi->demo_cmap)
2183 XFreeColormap (si->dpy, old_c);