1 /* windows.c --- turning the screen black; dealing with visuals, virtual roots.
2 * xscreensaver, Copyright (c) 1991-2007 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;
1429 if (!p->verbose_p || printed_visual_info)
1431 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
1433 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1434 describe_visual (stderr, ssi->screen, ssi->current_visual,
1439 fprintf (stderr, "%s: using visual: ", blurb());
1440 describe_visual (stderr, ssi->screen, ssi->current_visual,
1442 fprintf (stderr, "%s: default visual: ", blurb());
1443 describe_visual (stderr, ssi->screen,
1444 DefaultVisualOfScreen (ssi->screen),
1445 ssi->install_cmap_p);
1447 printed_visual_info = True;
1449 #ifdef HAVE_MIT_SAVER_EXTENSION
1450 if (si->using_mit_saver_extension)
1452 XScreenSaverInfo *info;
1453 Window root = RootWindowOfScreen (ssi->screen);
1456 /* This call sets the server screensaver timeouts to what we think
1457 they should be (based on the resources and args xscreensaver was
1458 started with.) It's important that we do this to sync back up
1459 with the server - if we have turned on prematurely, as by an
1460 ACTIVATE ClientMessage, then the server may decide to activate
1461 the screensaver while it's already active. That's ok for us,
1462 since we would know to ignore that ScreenSaverActivate event,
1463 but a side effect of this would be that the server would map its
1464 saver window (which we then hide again right away) meaning that
1465 the bits currently on the screen get blown away. Ugly. */
1467 /* #### Ok, that doesn't work - when we tell the server that the
1468 screensaver is "off" it sends us a Deactivate event, which is
1469 sensible... but causes the saver to never come on. Hmm. */
1470 disable_builtin_screensaver (si, True);
1474 /* #### The MIT-SCREEN-SAVER extension gives us access to the
1475 window that the server itself uses for saving the screen.
1476 However, using this window in any way, in particular, calling
1477 XScreenSaverSetAttributes() as below, tends to make the X server
1478 crash. So fuck it, let's try and get along without using it...
1480 It's also inconvenient to use this window because it doesn't
1481 always exist (though the ID is constant.) So to use this
1482 window, we'd have to reimplement the ACTIVATE ClientMessage to
1483 tell the *server* to tell *us* to turn on, to cause the window
1484 to get created at the right time. Gag. */
1485 XScreenSaverSetAttributes (si->dpy, root,
1486 0, 0, width, height, 0,
1487 current_depth, InputOutput, visual,
1489 XSync (si->dpy, False);
1492 info = XScreenSaverAllocInfo ();
1493 XScreenSaverQueryInfo (si->dpy, root, info);
1494 ssi->server_mit_saver_window = info->window;
1495 if (! ssi->server_mit_saver_window) abort ();
1498 #endif /* HAVE_MIT_SAVER_EXTENSION */
1500 if (ssi->screensaver_window)
1502 XWindowChanges changes;
1503 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1506 changes.width = width;
1507 changes.height = height;
1508 changes.border_width = 0;
1510 if (! (safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1511 changesmask, &changes) &&
1512 safe_XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
1515 horked_window = ssi->screensaver_window;
1516 ssi->screensaver_window = 0;
1520 if (!ssi->screensaver_window)
1522 ssi->screensaver_window =
1523 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen),
1524 x, y, width, height,
1525 0, ssi->current_depth, InputOutput,
1526 ssi->current_visual, attrmask, &attrs);
1533 "%s: someone horked our saver window (0x%lx)! Recreating it...\n",
1534 blurb(), (unsigned long) horked_window);
1535 maybe_transfer_grabs (ssi, horked_window, ssi->screensaver_window,
1537 safe_XDestroyWindow (si->dpy, horked_window);
1542 fprintf (stderr, "%s: %d: saver window is 0x%lx.\n",
1543 blurb(), ssi->number,
1544 (unsigned long) ssi->screensaver_window);
1547 store_saver_id (ssi); /* store window name and IDs */
1552 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
1554 BlackPixelOfScreen (ssi->screen),
1555 BlackPixelOfScreen (ssi->screen),
1557 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
1559 XFreePixmap (si->dpy, bit);
1562 XSetWindowBackground (si->dpy, ssi->screensaver_window, ssi->black_pixel);
1565 XUndefineCursor (si->dpy, ssi->screensaver_window);
1567 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
1571 initialize_screensaver_window (saver_info *si)
1574 for (i = 0; i < si->nscreens; i++)
1575 initialize_screensaver_window_1 (&si->screens[i]);
1579 /* Called when the RANDR (Resize and Rotate) extension tells us that the
1580 size of the screen has changed while the screen was blanked. If we
1581 don't do this, then the screen saver will no longer fully fill the
1582 screen, and some of the underlying desktop may be visible.
1585 resize_screensaver_window (saver_info *si)
1587 saver_preferences *p = &si->prefs;
1590 /* First update the size info in the saver_screen_info structs.
1593 # ifdef HAVE_XINERAMA
1596 /* As of XFree86 4.3.0, the RANDR and XINERAMA extensions cannot coexist.
1597 However, maybe they will someday, so I'm guessing that the right thing
1598 to do in that case will be to re-query the Xinerama rectangles after
1599 a RANDR size change is received: presumably, if the resolution of one
1600 or more of the monitors has changed, then the Xinerama rectangle
1601 corresponding to that monitor will also have been updated.
1604 XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
1606 if (nscreens != si->nscreens) {
1607 /* Apparently some Xinerama implementations let you use a hot-key
1608 to change the number of screens in use! This is, of course,
1609 documented nowhere. Let's try to do something marginally less
1612 fprintf (stderr, "%s: bad craziness: xinerama screen count changed "
1613 "from %d to %d!\n", blurb(), si->nscreens, nscreens);
1614 if (nscreens > si->nscreens)
1615 nscreens = si->nscreens;
1619 for (i = 0; i < nscreens; i++)
1621 saver_screen_info *ssi = &si->screens[i];
1623 (ssi->x != xsi[i].x_org ||
1624 ssi->y != xsi[i].y_org ||
1625 ssi->width != xsi[i].width ||
1626 ssi->height != xsi[i].height))
1628 "%s: %d: resize xinerama from %dx%d+%d+%d to %dx%d+%d+%d\n",
1630 ssi->width, ssi->height, ssi->x, ssi->y,
1631 xsi[i].width, xsi[i].height, xsi[i].x_org, xsi[i].y_org);
1633 ssi->x = xsi[i].x_org;
1634 ssi->y = xsi[i].y_org;
1635 ssi->width = xsi[i].width;
1636 ssi->height = xsi[i].height;
1641 # endif /* HAVE_XINERAMA */
1643 /* Not Xinerama -- get the real sizes of the root windows. */
1644 for (i = 0; i < si->nscreens; i++)
1646 saver_screen_info *ssi = &si->screens[i];
1647 XWindowAttributes xgwa;
1648 XGetWindowAttributes (si->dpy, RootWindowOfScreen (ssi->screen),
1652 (ssi->x != xgwa.x ||
1654 ssi->width != xgwa.width ||
1655 ssi->height != xgwa.height))
1657 "%s: %d: resize screen from %dx%d+%d+%d to %dx%d+%d+%d\n",
1659 ssi->width, ssi->height, ssi->x, ssi->y,
1660 xgwa.width, xgwa.height, xgwa.x, xgwa.y);
1664 ssi->width = xgwa.width;
1665 ssi->height = xgwa.height;
1669 /* Next, ensure that the screensaver windows are the right size, taking
1670 into account both the new size of the screen in question's root window,
1671 and any viewport within that.
1674 for (i = 0; i < si->nscreens; i++)
1676 saver_screen_info *ssi = &si->screens[i];
1677 XWindowAttributes xgwa;
1678 XWindowChanges changes;
1679 int x, y, width, height;
1680 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1682 XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
1683 get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
1684 (p->verbose_p && !si->screen_blanked_p));
1687 xgwa.width == width &&
1688 xgwa.height == height)
1689 continue; /* no change! */
1693 changes.width = width;
1694 changes.height = height;
1695 changes.border_width = 0;
1702 changes.width = changes.width / 2;
1706 "%s: %d: resize 0x%lx from %dx%d+%d+%d to %dx%d+%d+%d\n",
1707 blurb(), i, (unsigned long) ssi->screensaver_window,
1708 xgwa.width, xgwa.height, xgwa.x, xgwa.y,
1709 width, height, x, y);
1710 if (! safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1711 changesmask, &changes))
1714 "%s: %d: someone horked our saver window (0x%lx)! Unable to resize it!\n",
1715 blurb(), i, (unsigned long) ssi->screensaver_window);
1722 raise_window (saver_info *si,
1723 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
1725 saver_preferences *p = &si->prefs;
1729 inhibit_fade = True;
1731 if (si->emergency_lock_p)
1732 inhibit_fade = True;
1735 initialize_screensaver_window (si);
1737 reset_watchdog_timer (si, True);
1739 if (p->fade_p && si->fading_possible_p && !inhibit_fade)
1741 Window *current_windows = (Window *)
1742 calloc(sizeof(Window), si->nscreens);
1743 Colormap *current_maps = (Colormap *)
1744 calloc(sizeof(Colormap), si->nscreens);
1746 for (i = 0; i < si->nscreens; i++)
1748 saver_screen_info *ssi = &si->screens[i];
1749 current_windows[i] = ssi->screensaver_window;
1750 current_maps[i] = (between_hacks_p
1752 : DefaultColormapOfScreen (ssi->screen));
1753 /* Ensure that the default background of the window is really black,
1754 not a pixmap or something. (This does not clear the window.) */
1755 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1759 if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
1761 XGrabServer (si->dpy); /* ############ DANGER! */
1763 /* Clear the stderr layer on each screen.
1766 for (i = 0; i < si->nscreens; i++)
1768 saver_screen_info *ssi = &si->screens[i];
1769 if (ssi->stderr_overlay_window)
1770 /* Do this before the fade, since the stderr cmap won't fade
1771 even if we uninstall it (beats me...) */
1775 /* Note! The server is grabbed, and this will take several seconds
1777 fade_screens (si->dpy, current_maps,
1778 current_windows, si->nscreens,
1779 p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
1782 free(current_windows);
1784 current_windows = 0;
1786 if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
1788 #ifdef HAVE_MIT_SAVER_EXTENSION
1789 for (i = 0; i < si->nscreens; i++)
1791 saver_screen_info *ssi = &si->screens[i];
1792 if (ssi->server_mit_saver_window &&
1793 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1794 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1796 #endif /* HAVE_MIT_SAVER_EXTENSION */
1798 XUngrabServer (si->dpy);
1799 XSync (si->dpy, False); /* ###### (danger over) */
1803 for (i = 0; i < si->nscreens; i++)
1805 saver_screen_info *ssi = &si->screens[i];
1807 XClearWindow (si->dpy, ssi->screensaver_window);
1808 if (!dont_clear || ssi->stderr_overlay_window)
1810 XMapRaised (si->dpy, ssi->screensaver_window);
1811 #ifdef HAVE_MIT_SAVER_EXTENSION
1812 if (ssi->server_mit_saver_window &&
1813 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1814 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1815 #endif /* HAVE_MIT_SAVER_EXTENSION */
1819 for (i = 0; i < si->nscreens; i++)
1821 saver_screen_info *ssi = &si->screens[i];
1823 XInstallColormap (si->dpy, ssi->cmap);
1829 mouse_screen (saver_info *si)
1831 saver_preferences *p = &si->prefs;
1832 Window pointer_root, pointer_child;
1833 int root_x, root_y, win_x, win_y;
1837 if (si->nscreens == 1)
1840 for (i = 0; i < si->nscreens; i++)
1842 saver_screen_info *ssi = &si->screens[i];
1843 if (XQueryPointer (si->dpy, RootWindowOfScreen (ssi->screen),
1844 &pointer_root, &pointer_child,
1845 &root_x, &root_y, &win_x, &win_y, &mask) &&
1848 root_x < ssi->x + ssi->width &&
1849 root_y < ssi->y + ssi->height)
1852 fprintf (stderr, "%s: mouse is on screen %d of %d\n",
1853 blurb(), i, si->nscreens);
1858 /* couldn't figure out where the mouse is? Oh well. */
1864 blank_screen (saver_info *si)
1871 /* Note: we do our grabs on the root window, not on the screensaver window.
1872 If we grabbed on the saver window, then the demo mode and lock dialog
1873 boxes wouldn't get any events.
1875 By "the root window", we mean "the root window that contains the mouse."
1876 We use to always grab the mouse on screen 0, but that has the effect of
1877 moving the mouse to screen 0 from whichever screen it was on, on
1880 mscreen = mouse_screen (si);
1881 w = RootWindowOfScreen(si->screens[mscreen].screen);
1882 ok = grab_keyboard_and_mouse (si, w,
1883 (si->demoing_p ? 0 : si->screens[0].cursor),
1888 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1889 /* If we're using a server extension, then failure to get a grab is
1890 not a big deal -- even without the grab, we will still be able
1891 to un-blank when there is user activity, since the server will
1893 /* #### No, that's not true: if we don't have a keyboard grab,
1894 then we can't read passwords to unlock.
1902 for (i = 0; i < si->nscreens; i++)
1904 saver_screen_info *ssi = &si->screens[i];
1905 if (ssi->real_screen_p)
1906 save_real_vroot (ssi);
1907 store_vroot_property (si->dpy,
1908 ssi->screensaver_window,
1909 ssi->screensaver_window);
1911 #ifdef HAVE_XF86VMODE
1914 if (!XF86VidModeQueryExtension (si->dpy, &ev, &er) ||
1915 !safe_XF86VidModeGetViewPort (si->dpy, i,
1918 ssi->blank_vp_x = ssi->blank_vp_y = -1;
1920 #endif /* HAVE_XF86VMODE */
1923 raise_window (si, False, False, False);
1925 si->screen_blanked_p = True;
1926 si->blank_time = time ((time_t) 0);
1927 si->last_wall_clock_time = 0;
1929 store_saver_status (si); /* store blank time */
1936 unblank_screen (saver_info *si)
1938 saver_preferences *p = &si->prefs;
1939 Bool unfade_p = (si->fading_possible_p && p->unfade_p);
1942 monitor_power_on (si);
1943 reset_watchdog_timer (si, False);
1950 Window *current_windows = (Window *)
1951 calloc(sizeof(Window), si->nscreens);
1953 for (i = 0; i < si->nscreens; i++)
1955 saver_screen_info *ssi = &si->screens[i];
1956 current_windows[i] = ssi->screensaver_window;
1957 /* Ensure that the default background of the window is really black,
1958 not a pixmap or something. (This does not clear the window.) */
1959 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1963 if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
1966 XSync (si->dpy, False);
1967 XGrabServer (si->dpy); /* ############ DANGER! */
1968 XSync (si->dpy, False);
1970 /* Clear the stderr layer on each screen.
1972 for (i = 0; i < si->nscreens; i++)
1974 saver_screen_info *ssi = &si->screens[i];
1978 XUngrabServer (si->dpy);
1979 XSync (si->dpy, False); /* ###### (danger over) */
1981 fade_screens (si->dpy, 0,
1982 current_windows, si->nscreens,
1983 p->fade_seconds/1000, p->fade_ticks,
1986 free(current_windows);
1987 current_windows = 0;
1989 if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
1993 for (i = 0; i < si->nscreens; i++)
1995 saver_screen_info *ssi = &si->screens[i];
1998 Colormap c = DefaultColormapOfScreen (ssi->screen);
1999 /* avoid technicolor */
2000 XClearWindow (si->dpy, ssi->screensaver_window);
2001 if (c) XInstallColormap (si->dpy, c);
2003 XUnmapWindow (si->dpy, ssi->screensaver_window);
2008 /* If the focus window does has a non-default colormap, then install
2009 that colormap as well. (On SGIs, this will cause both the root map
2010 and the focus map to be installed simultaneously. It'd be nice to
2011 pick up the other colormaps that had been installed, too; perhaps
2012 XListInstalledColormaps could be used for that?)
2017 XGetInputFocus (si->dpy, &focus, &revert_to);
2018 if (focus && focus != PointerRoot && focus != None)
2020 XWindowAttributes xgwa;
2022 XGetWindowAttributes (si->dpy, focus, &xgwa);
2023 if (xgwa.colormap &&
2024 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
2025 XInstallColormap (si->dpy, xgwa.colormap);
2030 for (i = 0; i < si->nscreens; i++)
2032 saver_screen_info *ssi = &si->screens[i];
2033 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
2036 store_saver_status (si); /* store unblank time */
2037 ungrab_keyboard_and_mouse (si);
2038 restore_real_vroot (si);
2040 /* Unmap the windows a second time, dammit -- just to avoid a race
2041 with the screen-grabbing hacks. (I'm not sure if this is really
2042 necessary; I'm stabbing in the dark now.)
2044 for (i = 0; i < si->nscreens; i++)
2045 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
2047 si->screen_blanked_p = False;
2048 si->blank_time = time ((time_t) 0);
2049 si->last_wall_clock_time = 0;
2051 store_saver_status (si); /* store unblank time */
2055 /* Transfer any grabs from the old window to the new.
2056 Actually I think none of this is necessary, since we always
2057 hold our grabs on the root window, but I wrote this before
2058 re-discovering that...
2061 maybe_transfer_grabs (saver_screen_info *ssi,
2062 Window old_w, Window new_w,
2065 saver_info *si = ssi->global;
2067 /* If the old window held our mouse grab, transfer the grab to the new
2068 window. (Grab the server while so doing, to avoid a race condition.)
2070 if (old_w == si->mouse_grab_window)
2072 XGrabServer (si->dpy); /* ############ DANGER! */
2074 grab_mouse (si, ssi->screensaver_window,
2075 (si->demoing_p ? 0 : ssi->cursor),
2077 XUngrabServer (si->dpy);
2078 XSync (si->dpy, False); /* ###### (danger over) */
2081 /* If the old window held our keyboard grab, transfer the grab to the new
2082 window. (Grab the server while so doing, to avoid a race condition.)
2084 if (old_w == si->keyboard_grab_window)
2086 XGrabServer (si->dpy); /* ############ DANGER! */
2088 grab_kbd(si, ssi->screensaver_window, ssi->number);
2089 XUngrabServer (si->dpy);
2090 XSync (si->dpy, False); /* ###### (danger over) */
2097 select_visual (saver_screen_info *ssi, const char *visual_name)
2099 saver_info *si = ssi->global;
2100 saver_preferences *p = &si->prefs;
2101 Bool install_cmap_p = p->install_cmap_p;
2102 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
2106 /* On some systems (most recently, MacOS X) OpenGL programs get confused
2107 when you kill one and re-start another on the same window. So maybe
2108 it's best to just always destroy and recreate the xscreensaver window
2109 when changing hacks, instead of trying to reuse the old one?
2111 Bool always_recreate_window_p = True;
2113 if (visual_name && *visual_name)
2115 if (!strcmp(visual_name, "default-i") ||
2116 !strcmp(visual_name, "Default-i") ||
2117 !strcmp(visual_name, "Default-I")
2120 visual_name = "default";
2121 install_cmap_p = True;
2123 else if (!strcmp(visual_name, "default-n") ||
2124 !strcmp(visual_name, "Default-n") ||
2125 !strcmp(visual_name, "Default-N"))
2127 visual_name = "default";
2128 install_cmap_p = False;
2130 else if (!strcmp(visual_name, "gl") ||
2131 !strcmp(visual_name, "Gl") ||
2132 !strcmp(visual_name, "GL"))
2134 new_v = ssi->best_gl_visual;
2135 if (!new_v && p->verbose_p)
2136 fprintf (stderr, "%s: no GL visuals.\n", progname);
2140 new_v = get_visual (ssi->screen, visual_name, True, False);
2144 new_v = ssi->default_visual;
2149 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
2150 /* It's not the default visual, so we have no choice but to install. */
2151 install_cmap_p = True;
2153 ssi->install_cmap_p = install_cmap_p;
2156 (always_recreate_window_p ||
2157 (ssi->current_visual != new_v) ||
2158 (install_cmap_p != was_installed_p)))
2160 Colormap old_c = ssi->cmap;
2161 Window old_w = ssi->screensaver_window;
2165 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
2166 describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
2168 fprintf (stderr, "%s: from ", blurb());
2169 describe_visual (stderr, ssi->screen, ssi->current_visual,
2175 ssi->current_visual = new_v;
2176 ssi->current_depth = visual_depth(ssi->screen, new_v);
2178 ssi->screensaver_window = 0;
2180 initialize_screensaver_window_1 (ssi);
2182 /* stderr_overlay_window is a child of screensaver_window, so we need
2183 to destroy that as well (actually, we just need to invalidate and
2184 drop our pointers to it, but this will destroy it, which is ok so
2185 long as it happens before old_w itself is destroyed.) */
2188 raise_window (si, True, True, False);
2189 store_vroot_property (si->dpy,
2190 ssi->screensaver_window, ssi->screensaver_window);
2192 /* Transfer any grabs from the old window to the new. */
2193 maybe_transfer_grabs (ssi, old_w, ssi->screensaver_window, ssi->number);
2195 /* Now we can destroy the old window without horking our grabs. */
2196 XDestroyWindow (si->dpy, old_w);
2199 fprintf (stderr, "%s: %d: destroyed old saver window 0x%lx.\n",
2200 blurb(), ssi->number, (unsigned long) old_w);
2203 old_c != DefaultColormapOfScreen (ssi->screen) &&
2204 old_c != ssi->demo_cmap)
2205 XFreeColormap (si->dpy, old_c);