1 /* windows.c --- turning the screen black; dealing with visuals, virtual roots.
2 * xscreensaver, Copyright (c) 1991-2008 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
1047 which = ssi->number;
1050 /* Find the Xinerama rectangle that contains the mouse position. */
1051 for (i = 0; i < si->nscreens; i++)
1054 target_x >= si->screens[i].x &&
1055 target_y >= si->screens[i].y &&
1056 target_x < si->screens[i].x + si->screens[i].width &&
1057 target_y < si->screens[i].y + si->screens[i].height)
1060 if (which == -1) which = 0; /* didn't find it? Use the first. */
1061 *x_ret = si->screens[which].x;
1062 *y_ret = si->screens[which].y;
1063 *w_ret = si->screens[which].width;
1064 *h_ret = si->screens[which].height;
1068 fprintf (stderr, "%s: %d: xinerama vp: %dx%d+%d+%d",
1070 si->screens[which].width, si->screens[which].height,
1071 si->screens[which].x, si->screens[which].y);
1073 fprintf (stderr, "; mouse at %d,%d", target_x, target_y);
1074 fprintf (stderr, ".\n");
1079 # endif /* HAVE_XINERAMA */
1081 if (!xinerama_p && /* Xinerama + VidMode = broken. */
1082 XF86VidModeQueryExtension (si->dpy, &event, &error) &&
1083 safe_XF86VidModeGetViewPort (si->dpy, ssi->number, &x, &y) &&
1084 XF86VidModeGetModeLine (si->dpy, ssi->number, &dot, &ml))
1089 *w_ret = ml.hdisplay;
1090 *h_ret = ml.vdisplay;
1092 if (*x_ret == 0 && *y_ret == 0 && *w_ret == w && *h_ret == h)
1093 /* There is no viewport -- the screen does not scroll. */
1097 /* Apparently some versions of XFree86 return nonsense here!
1098 I've had reports of 1024x768 viewports at -1936862040, -1953705044.
1099 So, sanity-check the values and give up if they are out of range.
1101 if (*x_ret < 0 || *x_ret >= w ||
1102 *y_ret < 0 || *y_ret >= h ||
1103 *w_ret <= 0 || *w_ret > w ||
1104 *h_ret <= 0 || *h_ret > h)
1106 static int warned_once = 0;
1109 fprintf (stderr, "\n"
1110 "%s: X SERVER BUG: %dx%d viewport at %d,%d is impossible.\n"
1111 "%s: The XVidMode server extension is returning nonsense.\n"
1112 "%s: Please report this bug to your X server vendor.\n\n",
1113 blurb(), *w_ret, *h_ret, *x_ret, *y_ret,
1124 sprintf (msg, "%s: %d: vp is %dx%d+%d+%d",
1125 blurb(), ssi->number,
1126 *w_ret, *h_ret, *x_ret, *y_ret);
1129 if (p->getviewport_full_of_lies_p)
1131 /* XF86VidModeGetViewPort() tends to be full of lies on laptops
1132 that have a docking station or external monitor that runs in
1133 a different resolution than the laptop's screen:
1135 http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=81593
1136 http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=208417
1137 http://bugs.xfree86.org/show_bug.cgi?id=421
1139 The XFree86 developers have closed the bug. As far as I can
1140 tell, their reason for this was, "this is an X server bug,
1141 but it's pretty hard to fix. Therefore, we are closing it."
1143 So, now there's a preference item for those unfortunate users to
1144 tell us not to trust a word that XF86VidModeGetViewPort() says.
1146 static int warned_once = 0;
1147 if (!warned_once && verbose_p)
1151 "%s: %d: XF86VidModeGetViewPort() says vp is %dx%d+%d+%d;\n"
1152 "%s: %d: assuming that is a pack of lies;\n"
1153 "%s: %d: using %dx%d+0+0 instead.\n",
1154 blurb(), ssi->number,
1155 *w_ret, *h_ret, *x_ret, *y_ret,
1156 blurb(), ssi->number,
1157 blurb(), ssi->number, w, h);
1168 /* Apparently, though the server stores the X position in increments of
1169 1 pixel, it will only make changes to the *display* in some other
1170 increment. With XF86_SVGA on a Thinkpad, the display only updates
1171 in multiples of 8 pixels when in 8-bit mode, and in multiples of 4
1172 pixels in 16-bit mode. I don't know what it does in 24- and 32-bit
1173 mode, because I don't have enough video memory to find out.
1175 I consider it a bug that XF86VidModeGetViewPort() is telling me the
1176 server's *target* scroll position rather than the server's *actual*
1177 scroll position. David Dawes agrees, and says they may fix this in
1178 XFree86 4.0, but it's notrivial.
1180 He also confirms that this behavior is server-dependent, so the
1181 actual scroll position cannot be reliably determined by the client.
1182 So... that means the only solution is to provide a ``sandbox''
1183 around the blackout window -- we make the window be up to N pixels
1184 larger than the viewport on both the left and right sides. That
1185 means some part of the outer edges of each hack might not be
1186 visible, but screw it.
1188 I'm going to guess that 16 pixels is enough, and that the Y dimension
1189 doesn't have this problem.
1191 The drawback of doing this, of course, is that some of the screenhacks
1192 will still look pretty stupid -- for example, "slidescreen" will cut
1193 off the left and right edges of the grid, etc.
1196 if (x > 0 && x < w - ml.hdisplay) /* not at left edge or right edge */
1198 /* Round X position down to next lower multiple of FUDGE.
1199 Increase width by 2*FUDGE in case some server rounds up.
1201 *x_ret = ((x - 1) / FUDGE) * FUDGE;
1202 *w_ret += (FUDGE * 2);
1208 *w_ret != ml.hdisplay ||
1209 *h_ret != ml.vdisplay)
1210 sprintf (msg + strlen(msg), "; fudged to %dx%d+%d+%d",
1211 *w_ret, *h_ret, *x_ret, *y_ret);
1214 fprintf (stderr, "%s.\n", msg);
1219 # endif /* HAVE_XF86VMODE */
1228 static Bool error_handler_hit_p = False;
1231 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1233 error_handler_hit_p = True;
1238 /* Returns True if successful, False if an X error occurred.
1239 We need this because other programs might have done things to
1240 our window that will cause XChangeWindowAttributes() to fail:
1241 if that happens, we give up, destroy the window, and re-create
1245 safe_XChangeWindowAttributes (Display *dpy, Window window,
1247 XSetWindowAttributes *attrs)
1249 XErrorHandler old_handler;
1251 error_handler_hit_p = False;
1252 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1254 XChangeWindowAttributes (dpy, window, mask, attrs);
1257 XSetErrorHandler (old_handler);
1260 return (!error_handler_hit_p);
1264 /* This might not be necessary, but just in case. */
1266 safe_XConfigureWindow (Display *dpy, Window window,
1267 unsigned long mask, XWindowChanges *changes)
1269 XErrorHandler old_handler;
1271 error_handler_hit_p = False;
1272 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1274 XConfigureWindow (dpy, window, mask, changes);
1277 XSetErrorHandler (old_handler);
1280 return (!error_handler_hit_p);
1283 /* This might not be necessary, but just in case. */
1285 safe_XDestroyWindow (Display *dpy, Window window)
1287 XErrorHandler old_handler;
1289 error_handler_hit_p = False;
1290 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1292 XDestroyWindow (dpy, window);
1295 XSetErrorHandler (old_handler);
1298 return (!error_handler_hit_p);
1303 safe_XKillClient (Display *dpy, XID id)
1305 XErrorHandler old_handler;
1307 error_handler_hit_p = False;
1308 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1310 XKillClient (dpy, id);
1313 XSetErrorHandler (old_handler);
1316 return (!error_handler_hit_p);
1320 #ifdef HAVE_XF86VMODE
1322 safe_XF86VidModeGetViewPort (Display *dpy, int screen, int *xP, int *yP)
1325 XErrorHandler old_handler;
1327 error_handler_hit_p = False;
1328 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1330 result = XF86VidModeGetViewPort (dpy, screen, xP, yP);
1333 XSetErrorHandler (old_handler);
1336 return (error_handler_hit_p
1341 /* There is no "safe_XF86VidModeGetModeLine" because it fails with an
1342 untrappable I/O error instead of an X error -- so one must call
1343 safe_XF86VidModeGetViewPort first, and assume that both have the
1344 same error condition. Thank you XFree, may I have another.
1347 #endif /* HAVE_XF86VMODE */
1351 initialize_screensaver_window_1 (saver_screen_info *ssi)
1353 saver_info *si = ssi->global;
1354 saver_preferences *p = &si->prefs;
1355 Bool install_cmap_p = ssi->install_cmap_p; /* not p->install_cmap_p */
1357 /* This resets the screensaver window as fully as possible, since there's
1358 no way of knowing what some random client may have done to us in the
1359 meantime. We could just destroy and recreate the window, but that has
1360 its own set of problems...
1363 XSetWindowAttributes attrs;
1364 unsigned long attrmask;
1365 int x, y, width, height;
1366 static Bool printed_visual_info = False; /* only print the message once. */
1367 Window horked_window = 0;
1369 get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
1370 (p->verbose_p && !si->screen_blanked_p));
1372 black.red = black.green = black.blue = 0;
1374 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
1377 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
1378 /* It's not the default visual, so we have no choice but to install. */
1379 install_cmap_p = True;
1385 ssi->cmap = XCreateColormap (si->dpy,
1386 RootWindowOfScreen (ssi->screen),
1387 ssi->current_visual, AllocNone);
1388 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
1389 ssi->black_pixel = black.pixel;
1394 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
1397 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
1398 if (ssi->cmap != ssi->demo_cmap &&
1399 ssi->cmap != def_cmap)
1400 XFreeColormap (si->dpy, ssi->cmap);
1402 ssi->cmap = def_cmap;
1403 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
1406 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
1407 CWBackPixel | CWBackingPixel | CWBorderPixel);
1408 attrs.override_redirect = True;
1410 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
1411 actually be reading these events during normal operation; but we still
1412 need to see Button events for demo-mode to work properly.
1414 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
1415 ButtonPressMask | ButtonReleaseMask |
1418 attrs.backing_store = NotUseful;
1419 attrs.colormap = ssi->cmap;
1420 attrs.background_pixel = ssi->black_pixel;
1421 attrs.backing_pixel = ssi->black_pixel;
1422 attrs.border_pixel = ssi->black_pixel;
1431 if (!p->verbose_p || printed_visual_info)
1433 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
1435 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1436 describe_visual (stderr, ssi->screen, ssi->current_visual,
1441 fprintf (stderr, "%s: using visual: ", blurb());
1442 describe_visual (stderr, ssi->screen, ssi->current_visual,
1444 fprintf (stderr, "%s: default visual: ", blurb());
1445 describe_visual (stderr, ssi->screen,
1446 DefaultVisualOfScreen (ssi->screen),
1447 ssi->install_cmap_p);
1449 printed_visual_info = True;
1451 #ifdef HAVE_MIT_SAVER_EXTENSION
1452 if (si->using_mit_saver_extension)
1454 XScreenSaverInfo *info;
1455 Window root = RootWindowOfScreen (ssi->screen);
1458 /* This call sets the server screensaver timeouts to what we think
1459 they should be (based on the resources and args xscreensaver was
1460 started with.) It's important that we do this to sync back up
1461 with the server - if we have turned on prematurely, as by an
1462 ACTIVATE ClientMessage, then the server may decide to activate
1463 the screensaver while it's already active. That's ok for us,
1464 since we would know to ignore that ScreenSaverActivate event,
1465 but a side effect of this would be that the server would map its
1466 saver window (which we then hide again right away) meaning that
1467 the bits currently on the screen get blown away. Ugly. */
1469 /* #### Ok, that doesn't work - when we tell the server that the
1470 screensaver is "off" it sends us a Deactivate event, which is
1471 sensible... but causes the saver to never come on. Hmm. */
1472 disable_builtin_screensaver (si, True);
1476 /* #### The MIT-SCREEN-SAVER extension gives us access to the
1477 window that the server itself uses for saving the screen.
1478 However, using this window in any way, in particular, calling
1479 XScreenSaverSetAttributes() as below, tends to make the X server
1480 crash. So fuck it, let's try and get along without using it...
1482 It's also inconvenient to use this window because it doesn't
1483 always exist (though the ID is constant.) So to use this
1484 window, we'd have to reimplement the ACTIVATE ClientMessage to
1485 tell the *server* to tell *us* to turn on, to cause the window
1486 to get created at the right time. Gag. */
1487 XScreenSaverSetAttributes (si->dpy, root,
1488 0, 0, width, height, 0,
1489 current_depth, InputOutput, visual,
1491 XSync (si->dpy, False);
1494 info = XScreenSaverAllocInfo ();
1495 XScreenSaverQueryInfo (si->dpy, root, info);
1496 ssi->server_mit_saver_window = info->window;
1497 if (! ssi->server_mit_saver_window) abort ();
1500 #endif /* HAVE_MIT_SAVER_EXTENSION */
1502 if (ssi->screensaver_window)
1504 XWindowChanges changes;
1505 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1508 changes.width = width;
1509 changes.height = height;
1510 changes.border_width = 0;
1512 if (! (safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1513 changesmask, &changes) &&
1514 safe_XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
1517 horked_window = ssi->screensaver_window;
1518 ssi->screensaver_window = 0;
1522 if (!ssi->screensaver_window)
1524 ssi->screensaver_window =
1525 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen),
1526 x, y, width, height,
1527 0, ssi->current_depth, InputOutput,
1528 ssi->current_visual, attrmask, &attrs);
1535 "%s: someone horked our saver window (0x%lx)! Recreating it...\n",
1536 blurb(), (unsigned long) horked_window);
1537 maybe_transfer_grabs (ssi, horked_window, ssi->screensaver_window,
1539 safe_XDestroyWindow (si->dpy, horked_window);
1544 fprintf (stderr, "%s: %d: saver window is 0x%lx.\n",
1545 blurb(), ssi->number,
1546 (unsigned long) ssi->screensaver_window);
1549 store_saver_id (ssi); /* store window name and IDs */
1554 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
1556 BlackPixelOfScreen (ssi->screen),
1557 BlackPixelOfScreen (ssi->screen),
1559 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
1561 XFreePixmap (si->dpy, bit);
1564 XSetWindowBackground (si->dpy, ssi->screensaver_window, ssi->black_pixel);
1567 XUndefineCursor (si->dpy, ssi->screensaver_window);
1569 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
1573 initialize_screensaver_window (saver_info *si)
1576 for (i = 0; i < si->nscreens; i++)
1577 initialize_screensaver_window_1 (&si->screens[i]);
1581 /* Called when the RANDR (Resize and Rotate) extension tells us that the
1582 size of the screen has changed while the screen was blanked. If we
1583 don't do this, then the screen saver will no longer fully fill the
1584 screen, and some of the underlying desktop may be visible.
1587 resize_screensaver_window (saver_info *si)
1589 saver_preferences *p = &si->prefs;
1592 /* First update the size info in the saver_screen_info structs.
1595 # ifdef HAVE_XINERAMA
1598 /* As of XFree86 4.3.0, the RANDR and XINERAMA extensions cannot coexist.
1599 However, maybe they will someday, so I'm guessing that the right thing
1600 to do in that case will be to re-query the Xinerama rectangles after
1601 a RANDR size change is received: presumably, if the resolution of one
1602 or more of the monitors has changed, then the Xinerama rectangle
1603 corresponding to that monitor will also have been updated.
1606 XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
1608 if (nscreens != si->nscreens) {
1609 /* Apparently some Xinerama implementations let you use a hot-key
1610 to change the number of screens in use! This is, of course,
1611 documented nowhere. Let's try to do something marginally less
1614 fprintf (stderr, "%s: bad craziness: xinerama screen count changed "
1615 "from %d to %d!\n", blurb(), si->nscreens, nscreens);
1616 if (nscreens > si->nscreens)
1617 nscreens = si->nscreens;
1621 for (i = 0; i < nscreens; i++)
1623 saver_screen_info *ssi = &si->screens[i];
1625 (ssi->x != xsi[i].x_org ||
1626 ssi->y != xsi[i].y_org ||
1627 ssi->width != xsi[i].width ||
1628 ssi->height != xsi[i].height))
1630 "%s: %d: resize xinerama from %dx%d+%d+%d to %dx%d+%d+%d\n",
1632 ssi->width, ssi->height, ssi->x, ssi->y,
1633 xsi[i].width, xsi[i].height, xsi[i].x_org, xsi[i].y_org);
1635 ssi->x = xsi[i].x_org;
1636 ssi->y = xsi[i].y_org;
1637 ssi->width = xsi[i].width;
1638 ssi->height = xsi[i].height;
1643 # endif /* HAVE_XINERAMA */
1645 /* Not Xinerama -- get the real sizes of the root windows. */
1646 for (i = 0; i < si->nscreens; i++)
1648 saver_screen_info *ssi = &si->screens[i];
1649 XWindowAttributes xgwa;
1650 XGetWindowAttributes (si->dpy, RootWindowOfScreen (ssi->screen),
1654 (ssi->x != xgwa.x ||
1656 ssi->width != xgwa.width ||
1657 ssi->height != xgwa.height))
1659 "%s: %d: resize screen from %dx%d+%d+%d to %dx%d+%d+%d\n",
1661 ssi->width, ssi->height, ssi->x, ssi->y,
1662 xgwa.width, xgwa.height, xgwa.x, xgwa.y);
1666 ssi->width = xgwa.width;
1667 ssi->height = xgwa.height;
1671 /* Next, ensure that the screensaver windows are the right size, taking
1672 into account both the new size of the screen in question's root window,
1673 and any viewport within that.
1676 for (i = 0; i < si->nscreens; i++)
1678 saver_screen_info *ssi = &si->screens[i];
1679 XWindowAttributes xgwa;
1680 XWindowChanges changes;
1681 int x, y, width, height;
1682 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1684 XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
1685 get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
1686 (p->verbose_p && !si->screen_blanked_p));
1689 xgwa.width == width &&
1690 xgwa.height == height)
1691 continue; /* no change! */
1695 changes.width = width;
1696 changes.height = height;
1697 changes.border_width = 0;
1704 changes.width = changes.width / 2;
1708 "%s: %d: resize 0x%lx from %dx%d+%d+%d to %dx%d+%d+%d\n",
1709 blurb(), i, (unsigned long) ssi->screensaver_window,
1710 xgwa.width, xgwa.height, xgwa.x, xgwa.y,
1711 width, height, x, y);
1712 if (! safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1713 changesmask, &changes))
1716 "%s: %d: someone horked our saver window (0x%lx)! Unable to resize it!\n",
1717 blurb(), i, (unsigned long) ssi->screensaver_window);
1724 raise_window (saver_info *si,
1725 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
1727 saver_preferences *p = &si->prefs;
1731 inhibit_fade = True;
1733 if (si->emergency_lock_p)
1734 inhibit_fade = True;
1737 initialize_screensaver_window (si);
1739 reset_watchdog_timer (si, True);
1741 if (p->fade_p && si->fading_possible_p && !inhibit_fade)
1743 Window *current_windows = (Window *)
1744 calloc(sizeof(Window), si->nscreens);
1745 Colormap *current_maps = (Colormap *)
1746 calloc(sizeof(Colormap), si->nscreens);
1748 for (i = 0; i < si->nscreens; i++)
1750 saver_screen_info *ssi = &si->screens[i];
1751 current_windows[i] = ssi->screensaver_window;
1752 current_maps[i] = (between_hacks_p
1754 : DefaultColormapOfScreen (ssi->screen));
1755 /* Ensure that the default background of the window is really black,
1756 not a pixmap or something. (This does not clear the window.) */
1757 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1761 if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
1763 XGrabServer (si->dpy); /* ############ DANGER! */
1765 /* Clear the stderr layer on each screen.
1768 for (i = 0; i < si->nscreens; i++)
1770 saver_screen_info *ssi = &si->screens[i];
1771 if (ssi->stderr_overlay_window)
1772 /* Do this before the fade, since the stderr cmap won't fade
1773 even if we uninstall it (beats me...) */
1777 /* Note! The server is grabbed, and this will take several seconds
1779 fade_screens (si->dpy, current_maps,
1780 current_windows, si->nscreens,
1781 p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
1784 free(current_windows);
1786 current_windows = 0;
1788 if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
1790 #ifdef HAVE_MIT_SAVER_EXTENSION
1791 for (i = 0; i < si->nscreens; i++)
1793 saver_screen_info *ssi = &si->screens[i];
1794 if (ssi->server_mit_saver_window &&
1795 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1796 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1798 #endif /* HAVE_MIT_SAVER_EXTENSION */
1800 XUngrabServer (si->dpy);
1801 XSync (si->dpy, False); /* ###### (danger over) */
1805 for (i = 0; i < si->nscreens; i++)
1807 saver_screen_info *ssi = &si->screens[i];
1809 XClearWindow (si->dpy, ssi->screensaver_window);
1810 if (!dont_clear || ssi->stderr_overlay_window)
1812 XMapRaised (si->dpy, ssi->screensaver_window);
1813 #ifdef HAVE_MIT_SAVER_EXTENSION
1814 if (ssi->server_mit_saver_window &&
1815 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1816 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1817 #endif /* HAVE_MIT_SAVER_EXTENSION */
1821 for (i = 0; i < si->nscreens; i++)
1823 saver_screen_info *ssi = &si->screens[i];
1825 XInstallColormap (si->dpy, ssi->cmap);
1831 mouse_screen (saver_info *si)
1833 saver_preferences *p = &si->prefs;
1834 Window pointer_root, pointer_child;
1835 int root_x, root_y, win_x, win_y;
1839 if (si->nscreens == 1)
1842 for (i = 0; i < si->nscreens; i++)
1844 saver_screen_info *ssi = &si->screens[i];
1845 if (XQueryPointer (si->dpy, RootWindowOfScreen (ssi->screen),
1846 &pointer_root, &pointer_child,
1847 &root_x, &root_y, &win_x, &win_y, &mask) &&
1850 root_x < ssi->x + ssi->width &&
1851 root_y < ssi->y + ssi->height)
1854 fprintf (stderr, "%s: mouse is on screen %d of %d\n",
1855 blurb(), i, si->nscreens);
1860 /* couldn't figure out where the mouse is? Oh well. */
1866 blank_screen (saver_info *si)
1873 /* Note: we do our grabs on the root window, not on the screensaver window.
1874 If we grabbed on the saver window, then the demo mode and lock dialog
1875 boxes wouldn't get any events.
1877 By "the root window", we mean "the root window that contains the mouse."
1878 We use to always grab the mouse on screen 0, but that has the effect of
1879 moving the mouse to screen 0 from whichever screen it was on, on
1882 mscreen = mouse_screen (si);
1883 w = RootWindowOfScreen(si->screens[mscreen].screen);
1884 ok = grab_keyboard_and_mouse (si, w,
1885 (si->demoing_p ? 0 : si->screens[0].cursor),
1890 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1891 /* If we're using a server extension, then failure to get a grab is
1892 not a big deal -- even without the grab, we will still be able
1893 to un-blank when there is user activity, since the server will
1895 /* #### No, that's not true: if we don't have a keyboard grab,
1896 then we can't read passwords to unlock.
1904 for (i = 0; i < si->nscreens; i++)
1906 saver_screen_info *ssi = &si->screens[i];
1907 if (ssi->real_screen_p)
1908 save_real_vroot (ssi);
1909 store_vroot_property (si->dpy,
1910 ssi->screensaver_window,
1911 ssi->screensaver_window);
1913 #ifdef HAVE_XF86VMODE
1916 if (!XF86VidModeQueryExtension (si->dpy, &ev, &er) ||
1917 !safe_XF86VidModeGetViewPort (si->dpy, i,
1920 ssi->blank_vp_x = ssi->blank_vp_y = -1;
1922 #endif /* HAVE_XF86VMODE */
1925 raise_window (si, False, False, False);
1927 si->screen_blanked_p = True;
1928 si->blank_time = time ((time_t) 0);
1929 si->last_wall_clock_time = 0;
1931 store_saver_status (si); /* store blank time */
1938 unblank_screen (saver_info *si)
1940 saver_preferences *p = &si->prefs;
1941 Bool unfade_p = (si->fading_possible_p && p->unfade_p);
1944 monitor_power_on (si);
1945 reset_watchdog_timer (si, False);
1952 Window *current_windows = (Window *)
1953 calloc(sizeof(Window), si->nscreens);
1955 for (i = 0; i < si->nscreens; i++)
1957 saver_screen_info *ssi = &si->screens[i];
1958 current_windows[i] = ssi->screensaver_window;
1959 /* Ensure that the default background of the window is really black,
1960 not a pixmap or something. (This does not clear the window.) */
1961 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1965 if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
1968 XSync (si->dpy, False);
1969 XGrabServer (si->dpy); /* ############ DANGER! */
1970 XSync (si->dpy, False);
1972 /* Clear the stderr layer on each screen.
1974 for (i = 0; i < si->nscreens; i++)
1976 saver_screen_info *ssi = &si->screens[i];
1980 XUngrabServer (si->dpy);
1981 XSync (si->dpy, False); /* ###### (danger over) */
1983 fade_screens (si->dpy, 0,
1984 current_windows, si->nscreens,
1985 p->fade_seconds/1000, p->fade_ticks,
1988 free(current_windows);
1989 current_windows = 0;
1991 if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
1995 for (i = 0; i < si->nscreens; i++)
1997 saver_screen_info *ssi = &si->screens[i];
2000 Colormap c = DefaultColormapOfScreen (ssi->screen);
2001 /* avoid technicolor */
2002 XClearWindow (si->dpy, ssi->screensaver_window);
2003 if (c) XInstallColormap (si->dpy, c);
2005 XUnmapWindow (si->dpy, ssi->screensaver_window);
2010 /* If the focus window does has a non-default colormap, then install
2011 that colormap as well. (On SGIs, this will cause both the root map
2012 and the focus map to be installed simultaneously. It'd be nice to
2013 pick up the other colormaps that had been installed, too; perhaps
2014 XListInstalledColormaps could be used for that?)
2019 XGetInputFocus (si->dpy, &focus, &revert_to);
2020 if (focus && focus != PointerRoot && focus != None)
2022 XWindowAttributes xgwa;
2024 XGetWindowAttributes (si->dpy, focus, &xgwa);
2025 if (xgwa.colormap &&
2026 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
2027 XInstallColormap (si->dpy, xgwa.colormap);
2032 for (i = 0; i < si->nscreens; i++)
2034 saver_screen_info *ssi = &si->screens[i];
2035 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
2038 store_saver_status (si); /* store unblank time */
2039 ungrab_keyboard_and_mouse (si);
2040 restore_real_vroot (si);
2042 /* Unmap the windows a second time, dammit -- just to avoid a race
2043 with the screen-grabbing hacks. (I'm not sure if this is really
2044 necessary; I'm stabbing in the dark now.)
2046 for (i = 0; i < si->nscreens; i++)
2047 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
2049 si->screen_blanked_p = False;
2050 si->blank_time = time ((time_t) 0);
2051 si->last_wall_clock_time = 0;
2053 store_saver_status (si); /* store unblank time */
2057 /* Transfer any grabs from the old window to the new.
2058 Actually I think none of this is necessary, since we always
2059 hold our grabs on the root window, but I wrote this before
2060 re-discovering that...
2063 maybe_transfer_grabs (saver_screen_info *ssi,
2064 Window old_w, Window new_w,
2067 saver_info *si = ssi->global;
2069 /* If the old window held our mouse grab, transfer the grab to the new
2070 window. (Grab the server while so doing, to avoid a race condition.)
2072 if (old_w == si->mouse_grab_window)
2074 XGrabServer (si->dpy); /* ############ DANGER! */
2076 grab_mouse (si, ssi->screensaver_window,
2077 (si->demoing_p ? 0 : ssi->cursor),
2079 XUngrabServer (si->dpy);
2080 XSync (si->dpy, False); /* ###### (danger over) */
2083 /* If the old window held our keyboard grab, transfer the grab to the new
2084 window. (Grab the server while so doing, to avoid a race condition.)
2086 if (old_w == si->keyboard_grab_window)
2088 XGrabServer (si->dpy); /* ############ DANGER! */
2090 grab_kbd(si, ssi->screensaver_window, ssi->number);
2091 XUngrabServer (si->dpy);
2092 XSync (si->dpy, False); /* ###### (danger over) */
2099 select_visual (saver_screen_info *ssi, const char *visual_name)
2101 saver_info *si = ssi->global;
2102 saver_preferences *p = &si->prefs;
2103 Bool install_cmap_p = p->install_cmap_p;
2104 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
2108 /* On some systems (most recently, MacOS X) OpenGL programs get confused
2109 when you kill one and re-start another on the same window. So maybe
2110 it's best to just always destroy and recreate the xscreensaver window
2111 when changing hacks, instead of trying to reuse the old one?
2113 Bool always_recreate_window_p = True;
2115 if (visual_name && *visual_name)
2117 if (!strcmp(visual_name, "default-i") ||
2118 !strcmp(visual_name, "Default-i") ||
2119 !strcmp(visual_name, "Default-I")
2122 visual_name = "default";
2123 install_cmap_p = True;
2125 else if (!strcmp(visual_name, "default-n") ||
2126 !strcmp(visual_name, "Default-n") ||
2127 !strcmp(visual_name, "Default-N"))
2129 visual_name = "default";
2130 install_cmap_p = False;
2132 else if (!strcmp(visual_name, "gl") ||
2133 !strcmp(visual_name, "Gl") ||
2134 !strcmp(visual_name, "GL"))
2136 new_v = ssi->best_gl_visual;
2137 if (!new_v && p->verbose_p)
2138 fprintf (stderr, "%s: no GL visuals.\n", progname);
2142 new_v = get_visual (ssi->screen, visual_name, True, False);
2146 new_v = ssi->default_visual;
2151 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
2152 /* It's not the default visual, so we have no choice but to install. */
2153 install_cmap_p = True;
2155 ssi->install_cmap_p = install_cmap_p;
2158 (always_recreate_window_p ||
2159 (ssi->current_visual != new_v) ||
2160 (install_cmap_p != was_installed_p)))
2162 Colormap old_c = ssi->cmap;
2163 Window old_w = ssi->screensaver_window;
2167 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
2168 describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
2170 fprintf (stderr, "%s: from ", blurb());
2171 describe_visual (stderr, ssi->screen, ssi->current_visual,
2177 ssi->current_visual = new_v;
2178 ssi->current_depth = visual_depth(ssi->screen, new_v);
2180 ssi->screensaver_window = 0;
2182 initialize_screensaver_window_1 (ssi);
2184 /* stderr_overlay_window is a child of screensaver_window, so we need
2185 to destroy that as well (actually, we just need to invalidate and
2186 drop our pointers to it, but this will destroy it, which is ok so
2187 long as it happens before old_w itself is destroyed.) */
2190 raise_window (si, True, True, False);
2191 store_vroot_property (si->dpy,
2192 ssi->screensaver_window, ssi->screensaver_window);
2194 /* Transfer any grabs from the old window to the new. */
2195 maybe_transfer_grabs (ssi, old_w, ssi->screensaver_window, ssi->number);
2197 /* Now we can destroy the old window without horking our grabs. */
2198 XDestroyWindow (si->dpy, old_w);
2201 fprintf (stderr, "%s: %d: destroyed old saver window 0x%lx.\n",
2202 blurb(), ssi->number, (unsigned long) old_w);
2205 old_c != DefaultColormapOfScreen (ssi->screen) &&
2206 old_c != ssi->demo_cmap)
2207 XFreeColormap (si->dpy, old_c);