1 /* windows.c --- turning the screen black; dealing with visuals, virtual roots.
2 * xscreensaver, Copyright (c) 1991-2004 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
18 # include <unixlib.h> /* for getpid() */
19 # include "vms-gtod.h" /* for gettimeofday() */
23 # include <pwd.h> /* for getpwuid() */
29 # include <sys/utsname.h> /* for uname() */
30 #endif /* HAVE_UNAME */
33 #include <X11/Xproto.h> /* for CARD32 */
35 #include <X11/Xutil.h> /* for XSetClassHint() */
36 #include <X11/Xatom.h>
37 #include <X11/Xos.h> /* for time() */
38 #include <signal.h> /* for the signal names */
42 #ifdef HAVE_MIT_SAVER_EXTENSION
43 # include <X11/extensions/scrnsaver.h>
44 #endif /* HAVE_MIT_SAVER_EXTENSION */
47 # include <X11/extensions/xf86vmode.h>
48 #endif /* HAVE_XF86VMODE */
51 # include <X11/extensions/Xinerama.h>
52 #endif /* HAVE_XINERAMA */
54 /* This file doesn't need the Xt headers, so stub these types out... */
56 #define XtAppContext void*
57 #define XrmDatabase void*
58 #define XtIntervalId void*
59 #define XtPointer void*
62 #include "xscreensaver.h"
67 extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
69 Atom XA_VROOT, XA_XSETROOT_ID, XA_ESETROOT_PMAP_ID, XA_XROOTPMAP_ID;
70 Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
71 Atom XA_SCREENSAVER_STATUS;
74 extern saver_info *global_si_kludge; /* I hate C so much... */
76 static void maybe_transfer_grabs (saver_screen_info *ssi,
77 Window old_w, Window new_w, int new_screen);
79 #define ALL_POINTER_EVENTS \
80 (ButtonPressMask | ButtonReleaseMask | EnterWindowMask | \
81 LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | \
82 Button1MotionMask | Button2MotionMask | Button3MotionMask | \
83 Button4MotionMask | Button5MotionMask | ButtonMotionMask)
87 grab_string(int status)
91 case GrabSuccess: return "GrabSuccess";
92 case AlreadyGrabbed: return "AlreadyGrabbed";
93 case GrabInvalidTime: return "GrabInvalidTime";
94 case GrabNotViewable: return "GrabNotViewable";
95 case GrabFrozen: return "GrabFrozen";
99 sprintf(foo, "unknown status: %d", status);
106 grab_kbd(saver_info *si, Window w, int screen_no)
108 saver_preferences *p = &si->prefs;
109 int status = XGrabKeyboard (si->dpy, w, True,
110 /* I don't really understand Sync vs Async,
111 but these seem to work... */
112 GrabModeSync, GrabModeAsync,
114 if (status == GrabSuccess)
116 si->keyboard_grab_window = w;
117 si->keyboard_grab_screen = screen_no;
121 fprintf(stderr, "%s: %d: grabbing keyboard on 0x%lx... %s.\n",
122 blurb(), screen_no, (unsigned long) w, grab_string(status));
128 grab_mouse (saver_info *si, Window w, Cursor cursor, int screen_no)
130 saver_preferences *p = &si->prefs;
131 int status = XGrabPointer (si->dpy, w, True, ALL_POINTER_EVENTS,
132 GrabModeAsync, GrabModeAsync, w,
133 cursor, CurrentTime);
134 if (status == GrabSuccess)
136 si->mouse_grab_window = w;
137 si->mouse_grab_screen = screen_no;
141 fprintf(stderr, "%s: %d: grabbing mouse on 0x%lx... %s.\n",
142 blurb(), screen_no, (unsigned long) w, grab_string(status));
148 ungrab_kbd(saver_info *si)
150 saver_preferences *p = &si->prefs;
151 XUngrabKeyboard(si->dpy, CurrentTime);
153 fprintf(stderr, "%s: %d: ungrabbing keyboard (was 0x%lx).\n",
154 blurb(), si->keyboard_grab_screen,
155 (unsigned long) si->keyboard_grab_window);
156 si->keyboard_grab_window = 0;
161 ungrab_mouse(saver_info *si)
163 saver_preferences *p = &si->prefs;
164 XUngrabPointer(si->dpy, CurrentTime);
166 fprintf(stderr, "%s: %d: ungrabbing mouse (was 0x%lx).\n",
167 blurb(), si->mouse_grab_screen,
168 (unsigned long) si->mouse_grab_window);
169 si->mouse_grab_window = 0;
173 /* Apparently there is this program called "rdesktop" which is a windows
174 terminal server client for Unix. It would seem that this program holds
175 the keyboard GRABBED the whole time it has focus! This is, of course,
176 completely idiotic: the whole point of grabbing is to get events when
177 you do *not* have focus, so grabbing *only when* you have focus is
178 completely redundant -- unless your goal is to make xscreensaver not
179 able to ever lock the screen when your program is running.
181 If xscreensaver blanks while rdesktop still has a keyboard grab, then
182 when we try to prompt for the password, we won't get the characters:
183 they'll be typed into rdesktop.
185 Perhaps rdesktop will release its keyboard grab if it loses focus?
186 What the hell, let's give it a try. If we fail to grab the keyboard
187 four times in a row, we forcibly set focus to "None" and try four
188 more times. (We don't touch focus unless we're already having a hard
189 time getting a grab.)
192 nuke_focus (saver_info *si, int screen_no)
194 saver_preferences *p = &si->prefs;
198 XGetInputFocus (si->dpy, &focus, &rev);
204 if (focus == PointerRoot) strcpy (w, "PointerRoot");
205 else if (focus == None) strcpy (w, "None");
206 else sprintf (w, "0x%lx", (unsigned long) focus);
208 if (rev == RevertToParent) strcpy (r, "RevertToParent");
209 else if (rev == RevertToPointerRoot) strcpy (r, "RevertToPointerRoot");
210 else if (rev == RevertToNone) strcpy (r, "RevertToNone");
211 else sprintf (r, "0x%x", rev);
213 fprintf (stderr, "%s: %d: removing focus from %s / %s.\n",
214 blurb(), screen_no, w, r);
217 XSetInputFocus (si->dpy, None, RevertToNone, CurrentTime);
218 XSync (si->dpy, False);
223 grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor,
226 Status mstatus = 0, kstatus = 0;
229 Bool focus_fuckus = False;
233 for (i = 0; i < retries; i++)
235 XSync (si->dpy, False);
236 kstatus = grab_kbd (si, window, screen_no);
237 if (kstatus == GrabSuccess)
240 /* else, wait a second and try to grab again. */
244 if (kstatus != GrabSuccess)
246 fprintf (stderr, "%s: couldn't grab keyboard! (%s)\n",
247 blurb(), grab_string(kstatus));
252 nuke_focus (si, screen_no);
257 for (i = 0; i < retries; i++)
259 XSync (si->dpy, False);
260 mstatus = grab_mouse (si, window, cursor, screen_no);
261 if (mstatus == GrabSuccess)
264 /* else, wait a second and try to grab again. */
268 if (mstatus != GrabSuccess)
269 fprintf (stderr, "%s: couldn't grab pointer! (%s)\n",
270 blurb(), grab_string(mstatus));
272 return (kstatus == GrabSuccess ||
273 mstatus == GrabSuccess);
277 ungrab_keyboard_and_mouse (saver_info *si)
285 move_mouse_grab (saver_info *si, Window to, Cursor cursor, int to_screen_no)
287 Window old = si->mouse_grab_window;
290 return grab_mouse (si, to, cursor, to_screen_no);
293 saver_preferences *p = &si->prefs;
296 XSync (si->dpy, False);
297 XGrabServer (si->dpy); /* ############ DANGER! */
298 XSync (si->dpy, False);
301 fprintf(stderr, "%s: grabbing server...\n", blurb());
304 status = grab_mouse (si, to, cursor, to_screen_no);
306 if (status != GrabSuccess) /* Augh! */
308 sleep (1); /* Note dramatic evil of sleeping
309 with server grabbed. */
310 XSync (si->dpy, False);
311 status = grab_mouse (si, to, cursor, to_screen_no);
314 if (status != GrabSuccess) /* Augh! Try to get the old one back... */
315 grab_mouse (si, old, cursor, to_screen_no);
317 XUngrabServer (si->dpy);
318 XSync (si->dpy, False); /* ###### (danger over) */
321 fprintf(stderr, "%s: ungrabbing server.\n", blurb());
328 /* Prints an error message to stderr and returns True if there is another
329 xscreensaver running already. Silently returns False otherwise. */
331 ensure_no_screensaver_running (Display *dpy, Screen *screen)
335 Window root = RootWindowOfScreen (screen);
336 Window root2, parent, *kids;
338 XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler);
340 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
346 for (i = 0; i < nkids; i++)
350 unsigned long nitems, bytesafter;
353 if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
354 False, XA_STRING, &type, &format, &nitems,
355 &bytesafter, (unsigned char **) &version)
360 if (!XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
361 False, XA_STRING, &type, &format, &nitems,
362 &bytesafter, (unsigned char **) &id)
368 "%s: already running on display %s (window 0x%x)\n from process %s.\n",
369 blurb(), DisplayString (dpy), (int) kids [i], id);
374 if (kids) XFree ((char *) kids);
376 XSetErrorHandler (old_handler);
382 /* Virtual-root hackery */
385 ERROR! You must not include vroot.h in this file.
389 store_vroot_property (Display *dpy, Window win, Window value)
394 "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", blurb(),
396 (win == screensaver_window ? "ScreenSaver" :
397 (win == real_vroot ? "VRoot" :
398 (win == real_vroot_value ? "Vroot_value" : "???"))),
400 (value == screensaver_window ? "ScreenSaver" :
401 (value == real_vroot ? "VRoot" :
402 (value == real_vroot_value ? "Vroot_value" : "???"))));
404 XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
405 (unsigned char *) &value, 1);
409 remove_vroot_property (Display *dpy, Window win)
413 fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", blurb(), win,
414 (win == screensaver_window ? "ScreenSaver" :
415 (win == real_vroot ? "VRoot" :
416 (win == real_vroot_value ? "Vroot_value" : "???"))));
418 XDeleteProperty (dpy, win, XA_VROOT);
422 static Bool safe_XKillClient (Display *dpy, XID id);
424 #ifdef HAVE_XF86VMODE
425 static Bool safe_XF86VidModeGetViewPort (Display *, int, int *, int *);
426 #endif /* HAVE_XF86VMODE */
430 kill_xsetroot_data_1 (Display *dpy, Window window,
431 Atom prop, const char *atom_name,
436 unsigned long nitems, bytesafter;
439 /* If the user has been using xv or xsetroot as a screensaver (to display
440 an image on the screensaver window, as a kind of slideshow) then the
441 pixmap and its associated color cells have been put in RetainPermanent
442 CloseDown mode. Since we're not destroying the xscreensaver window,
443 but merely unmapping it, we need to free these resources or those
444 colormap cells will stay allocated while the screensaver is off. (We
445 could just delete the screensaver window and recreate it later, but
446 that could cause other problems.) This code does an atomic read-and-
447 delete of the _XSETROOT_ID property, and if it held a pixmap, then we
448 cause the RetainPermanent resources of the client which created it
449 (and which no longer exists) to be freed.
451 Update: it seems that Gnome and KDE do this same trick, but with the
452 properties "ESETROOT_PMAP_ID" and/or "_XROOTPMAP_ID" instead of
453 "_XSETROOT_ID". So, we'll kill those too.
455 if (XGetWindowProperty (dpy, window, prop, 0, 1,
456 True, AnyPropertyType, &type, &format, &nitems,
457 &bytesafter, (unsigned char **) &dataP)
461 if (dataP && *dataP && type == XA_PIXMAP && format == 32 &&
462 nitems == 1 && bytesafter == 0)
465 fprintf (stderr, "%s: destroying %s data (0x%lX).\n",
466 blurb(), atom_name, *dataP);
467 safe_XKillClient (dpy, *dataP);
471 "%s: deleted unrecognised %s property: \n"
472 "\t%lu, %lu; type: %lu, format: %d, "
473 "nitems: %lu, bytesafter %ld\n",
475 (unsigned long) dataP, (dataP ? *dataP : 0), type,
476 format, nitems, bytesafter);
482 kill_xsetroot_data (Display *dpy, Window w, Bool verbose_p)
484 kill_xsetroot_data_1 (dpy, w, XA_XSETROOT_ID, "_XSETROOT_ID", verbose_p);
485 kill_xsetroot_data_1 (dpy, w, XA_ESETROOT_PMAP_ID, "ESETROOT_PMAP_ID",
487 kill_xsetroot_data_1 (dpy, w, XA_XROOTPMAP_ID, "_XROOTPMAP_ID", verbose_p);
492 save_real_vroot (saver_screen_info *ssi)
494 saver_info *si = ssi->global;
495 Display *dpy = si->dpy;
496 Screen *screen = ssi->screen;
498 Window root = RootWindowOfScreen (screen);
499 Window root2, parent, *kids;
501 XErrorHandler old_handler;
503 /* It's possible that a window might be deleted between our call to
504 XQueryTree() and our call to XGetWindowProperty(). Don't die if
505 that happens (but just ignore that window, it's not the one we're
506 interested in anyway.)
509 old_handler = XSetErrorHandler (BadWindow_ehandler);
513 ssi->real_vroot_value = 0;
514 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
520 for (i = 0; i < nkids; i++)
524 unsigned long nitems, bytesafter;
528 /* Skip this window if it is the xscreensaver window of any other
529 screen (this can happen in the Xinerama case.)
531 for (j = 0; j < si->nscreens; j++)
533 saver_screen_info *ssi2 = &si->screens[j];
534 if (kids[i] == ssi2->screensaver_window)
538 if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
539 &type, &format, &nitems, &bytesafter,
540 (unsigned char **) &vrootP)
547 if (*vrootP == ssi->screensaver_window) abort ();
549 "%s: more than one virtual root window found (0x%x and 0x%x).\n",
550 blurb(), (int) ssi->real_vroot, (int) kids [i]);
553 ssi->real_vroot = kids [i];
554 ssi->real_vroot_value = *vrootP;
560 XSetErrorHandler (old_handler);
565 remove_vroot_property (si->dpy, ssi->real_vroot);
569 XFree ((char *) kids);
574 restore_real_vroot_1 (saver_screen_info *ssi)
576 saver_info *si = ssi->global;
577 saver_preferences *p = &si->prefs;
578 if (p->verbose_p && ssi->real_vroot)
580 "%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
581 blurb(), (unsigned long) ssi->real_vroot);
582 remove_vroot_property (si->dpy, ssi->screensaver_window);
585 store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
587 ssi->real_vroot_value = 0;
588 /* make sure the property change gets there before this process
589 terminates! We might be doing this because we have intercepted
590 SIGTERM or something. */
591 XSync (si->dpy, False);
598 restore_real_vroot (saver_info *si)
601 Bool did_any = False;
602 for (i = 0; i < si->nscreens; i++)
604 saver_screen_info *ssi = &si->screens[i];
605 if (restore_real_vroot_1 (ssi))
612 /* Signal hackery to ensure that the vroot doesn't get left in an
617 signal_name(int signal)
620 case SIGHUP: return "SIGHUP";
621 case SIGINT: return "SIGINT";
622 case SIGQUIT: return "SIGQUIT";
623 case SIGILL: return "SIGILL";
624 case SIGTRAP: return "SIGTRAP";
626 case SIGABRT: return "SIGABRT";
628 case SIGFPE: return "SIGFPE";
629 case SIGKILL: return "SIGKILL";
630 case SIGBUS: return "SIGBUS";
631 case SIGSEGV: return "SIGSEGV";
632 case SIGPIPE: return "SIGPIPE";
633 case SIGALRM: return "SIGALRM";
634 case SIGTERM: return "SIGTERM";
636 case SIGSTOP: return "SIGSTOP";
639 case SIGCONT: return "SIGCONT";
642 case SIGUSR1: return "SIGUSR1";
645 case SIGUSR2: return "SIGUSR2";
648 case SIGEMT: return "SIGEMT";
651 case SIGSYS: return "SIGSYS";
654 case SIGCHLD: return "SIGCHLD";
657 case SIGPWR: return "SIGPWR";
660 case SIGWINCH: return "SIGWINCH";
663 case SIGURG: return "SIGURG";
666 case SIGIO: return "SIGIO";
669 case SIGVTALRM: return "SIGVTALRM";
672 case SIGXCPU: return "SIGXCPU";
675 case SIGXFSZ: return "SIGXFSZ";
678 case SIGDANGER: return "SIGDANGER";
683 sprintf(buf, "signal %d\n", signal);
692 restore_real_vroot_handler (int sig)
694 saver_info *si = global_si_kludge; /* I hate C so much... */
696 signal (sig, SIG_DFL);
697 if (restore_real_vroot (si))
698 fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n",
699 blurb(), signal_name(sig));
700 kill (getpid (), sig);
704 catch_signal (saver_info *si, int sig, RETSIGTYPE (*handler) (int))
706 # ifdef HAVE_SIGACTION
709 a.sa_handler = handler;
710 sigemptyset (&a.sa_mask);
713 /* On Linux 2.4.9 (at least) we need to tell the kernel to not mask delivery
714 of this signal from inside its handler, or else when we execvp() the
715 process again, it starts up with SIGHUP blocked, meaning that killing
716 it with -HUP only works *once*. You'd think that execvp() would reset
717 all the signal masks, but it doesn't.
719 # if defined(SA_NOMASK)
720 a.sa_flags |= SA_NOMASK;
721 # elif defined(SA_NODEFER)
722 a.sa_flags |= SA_NODEFER;
725 if (sigaction (sig, &a, 0) < 0)
726 # else /* !HAVE_SIGACTION */
727 if (((long) signal (sig, handler)) == -1L)
728 # endif /* !HAVE_SIGACTION */
731 sprintf (buf, "%s: couldn't catch %s", blurb(), signal_name(sig));
733 saver_exit (si, 1, 0);
737 static RETSIGTYPE saver_sighup_handler (int sig);
740 handle_signals (saver_info *si)
742 catch_signal (si, SIGHUP, saver_sighup_handler);
744 catch_signal (si, SIGINT, restore_real_vroot_handler);
745 catch_signal (si, SIGQUIT, restore_real_vroot_handler);
746 catch_signal (si, SIGILL, restore_real_vroot_handler);
747 catch_signal (si, SIGTRAP, restore_real_vroot_handler);
749 catch_signal (si, SIGIOT, restore_real_vroot_handler);
751 catch_signal (si, SIGABRT, restore_real_vroot_handler);
753 catch_signal (si, SIGEMT, restore_real_vroot_handler);
755 catch_signal (si, SIGFPE, restore_real_vroot_handler);
756 catch_signal (si, SIGBUS, restore_real_vroot_handler);
757 catch_signal (si, SIGSEGV, restore_real_vroot_handler);
759 catch_signal (si, SIGSYS, restore_real_vroot_handler);
761 catch_signal (si, SIGTERM, restore_real_vroot_handler);
763 catch_signal (si, SIGXCPU, restore_real_vroot_handler);
766 catch_signal (si, SIGXFSZ, restore_real_vroot_handler);
769 catch_signal (si, SIGDANGER, restore_real_vroot_handler);
775 saver_sighup_handler (int sig)
777 saver_info *si = global_si_kludge; /* I hate C so much... */
779 /* Re-establish SIGHUP handler */
780 catch_signal (si, SIGHUP, saver_sighup_handler);
782 fprintf (stderr, "%s: %s received: restarting...\n",
783 blurb(), signal_name(sig));
785 kill_screenhack (si);
786 XSync (si->dpy, False);
787 restart_process (si); /* Does not return */
794 saver_exit (saver_info *si, int status, const char *dump_core_reason)
796 saver_preferences *p = &si->prefs;
797 static Bool exiting = False;
806 vrs = restore_real_vroot (si);
807 emergency_kill_subproc (si);
808 shutdown_stderr (si);
810 if (p->verbose_p && vrs)
811 fprintf (real_stderr, "%s: old vroot restored.\n", blurb());
815 #ifdef VMS /* on VMS, 1 is the "normal" exit code instead of 0. */
816 if (status == 0) status = 1;
817 else if (status == 1) status = -1;
820 bugp = !!dump_core_reason;
822 if (si->prefs.debug_p && !dump_core_reason)
823 dump_core_reason = "because of -debug";
825 if (dump_core_reason)
827 /* Note that the Linux man page for setuid() says If uid is
828 different from the old effective uid, the process will be
829 forbidden from leaving core dumps.
831 char cwd[4096]; /* should really be PATH_MAX, but who cares. */
833 fprintf(real_stderr, "%s: dumping core (%s)\n", blurb(),
838 "%s: see http://www.jwz.org/xscreensaver/bugs.html\n"
839 "\t\t\tfor bug reporting information.\n\n",
842 # if defined(HAVE_GETCWD)
843 if (!getcwd (cwd, sizeof(cwd)))
844 # elif defined(HAVE_GETWD)
847 strcpy(cwd, "unknown.");
849 fprintf (real_stderr, "%s: current directory is %s\n", blurb(), cwd);
850 describe_uids (si, real_stderr);
852 /* Do this to drop a core file, so that we can get a stack trace. */
860 /* Managing the actual screensaver window */
863 window_exists_p (Display *dpy, Window window)
865 XErrorHandler old_handler;
866 XWindowAttributes xgwa;
868 old_handler = XSetErrorHandler (BadWindow_ehandler);
869 XGetWindowAttributes (dpy, window, &xgwa);
871 XSetErrorHandler (old_handler);
872 return (xgwa.screen != 0);
876 store_saver_id (saver_screen_info *ssi)
878 XClassHint class_hints;
879 saver_info *si = ssi->global;
880 unsigned long pid = (unsigned long) getpid ();
882 struct passwd *p = getpwuid (getuid ());
883 const char *name, *host;
886 /* First store the name and class on the window.
888 class_hints.res_name = progname;
889 class_hints.res_class = progclass;
890 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
891 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
893 /* Then store the xscreensaver version number.
895 XChangeProperty (si->dpy, ssi->screensaver_window,
896 XA_SCREENSAVER_VERSION,
897 XA_STRING, 8, PropModeReplace,
898 (unsigned char *) si->version,
899 strlen (si->version));
901 /* Now store the XSCREENSAVER_ID property, that says what user and host
902 xscreensaver is running as.
905 if (p && p->pw_name && *p->pw_name)
909 sprintf (buf, "%lu", (unsigned long) p->pw_uid);
915 # if defined(HAVE_UNAME)
918 if (uname (&uts) < 0)
924 host = getenv("SYS$NODE");
925 # else /* !HAVE_UNAME && !VMS */
927 # endif /* !HAVE_UNAME && !VMS */
929 id = (char *) malloc (strlen(name) + strlen(host) + 50);
930 sprintf (id, "%lu (%s@%s)", pid, name, host);
932 XChangeProperty (si->dpy, ssi->screensaver_window,
933 XA_SCREENSAVER_ID, XA_STRING,
935 (unsigned char *) id, strlen (id));
941 store_saver_status (saver_info *si)
944 int size = si->nscreens + 2;
947 status = (CARD32 *) calloc (size, sizeof(CARD32));
949 status[0] = (CARD32) (si->screen_blanked_p
950 ? (si->locked_p ? XA_LOCK : XA_BLANK)
952 status[1] = (CARD32) si->blank_time;
954 for (i = 0; i < si->nscreens; i++)
956 saver_screen_info *ssi = &si->screens[i];
957 status [2 + i] = ssi->current_hack + 1;
960 XChangeProperty (si->dpy,
961 RootWindow (si->dpy, 0), /* always screen #0 */
962 XA_SCREENSAVER_STATUS,
963 XA_INTEGER, 32, PropModeReplace,
964 (unsigned char *) status, size);
970 /* Returns the area of the screen which the xscreensaver window should cover.
971 Normally this is the whole screen, but if the X server's root window is
972 actually larger than the monitor's displayable area, then we want to
973 operate in the currently-visible portion of the desktop instead.
976 get_screen_viewport (saver_screen_info *ssi,
977 int *x_ret, int *y_ret,
978 int *w_ret, int *h_ret,
979 int target_x, int target_y,
982 int w = WidthOfScreen (ssi->screen);
983 int h = HeightOfScreen (ssi->screen);
985 # ifdef HAVE_XF86VMODE
986 saver_info *si = ssi->global;
987 saver_preferences *p = &si->prefs;
990 XF86VidModeModeLine ml;
992 Bool xinerama_p = si->xinerama_p;
994 # ifndef HAVE_XINERAMA
995 /* Even if we don't have the client-side Xinerama lib, check to see if
996 the server supports Xinerama, so that we know to ignore the VidMode
997 extension -- otherwise a server crash could result. Yay. */
998 xinerama_p = XQueryExtension (si->dpy, "XINERAMA", &error, &event, &error);
999 # endif /* !HAVE_XINERAMA */
1001 # ifdef HAVE_XINERAMA
1004 int mouse_p = (target_x != -1 && target_y != -1);
1008 /* If a mouse position wasn't passed in, assume we're talking about
1016 /* Find the Xinerama rectangle that contains the mouse position. */
1017 for (i = 0; i < si->nscreens; i++)
1019 if (target_x >= si->screens[i].x &&
1020 target_y >= si->screens[i].y &&
1021 target_x < si->screens[i].x + si->screens[i].width &&
1022 target_y < si->screens[i].y + si->screens[i].height)
1025 if (which == -1) which = 0; /* didn't find it? Use the first. */
1026 *x_ret = si->screens[which].x;
1027 *y_ret = si->screens[which].y;
1028 *w_ret = si->screens[which].width;
1029 *h_ret = si->screens[which].height;
1033 fprintf (stderr, "%s: %d: xinerama vp: %dx%d+%d+%d",
1035 si->screens[which].width, si->screens[which].height,
1036 si->screens[which].x, si->screens[which].y);
1038 fprintf (stderr, "; mouse at %d,%d", target_x, target_y);
1039 fprintf (stderr, ".\n");
1044 # endif /* HAVE_XINERAMA */
1046 if (!xinerama_p && /* Xinerama + VidMode = broken. */
1047 XF86VidModeQueryExtension (si->dpy, &event, &error) &&
1048 safe_XF86VidModeGetViewPort (si->dpy, ssi->number, &x, &y) &&
1049 XF86VidModeGetModeLine (si->dpy, ssi->number, &dot, &ml))
1054 *w_ret = ml.hdisplay;
1055 *h_ret = ml.vdisplay;
1057 if (*x_ret == 0 && *y_ret == 0 && *w_ret == w && *h_ret == h)
1058 /* There is no viewport -- the screen does not scroll. */
1062 /* Apparently some versions of XFree86 return nonsense here!
1063 I've had reports of 1024x768 viewports at -1936862040, -1953705044.
1064 So, sanity-check the values and give up if they are out of range.
1066 if (*x_ret < 0 || *x_ret >= w ||
1067 *y_ret < 0 || *y_ret >= h ||
1068 *w_ret <= 0 || *w_ret > w ||
1069 *h_ret <= 0 || *h_ret > h)
1071 static int warned_once = 0;
1074 fprintf (stderr, "\n"
1075 "%s: X SERVER BUG: %dx%d viewport at %d,%d is impossible.\n"
1076 "%s: The XVidMode server extension is returning nonsense.\n"
1077 "%s: Please report this bug to your X server vendor.\n\n",
1078 blurb(), *w_ret, *h_ret, *x_ret, *y_ret,
1089 sprintf (msg, "%s: %d: vp is %dx%d+%d+%d",
1090 blurb(), ssi->number,
1091 *w_ret, *h_ret, *x_ret, *y_ret);
1094 if (p->getviewport_full_of_lies_p)
1096 /* XF86VidModeGetViewPort() tends to be full of lies on laptops
1097 that have a docking station or external monitor that runs in
1098 a different resolution than the laptop's screen:
1100 http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=81593
1101 http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=208417
1102 http://bugs.xfree86.org/show_bug.cgi?id=421
1104 The XFree86 developers have closed the bug. As far as I can
1105 tell, their reason for this was, "this is an X server bug,
1106 but it's pretty hard to fix. Therefore, we are closing it."
1108 So, now there's a preference item for those unfortunate users to
1109 tell us not to trust a word that XF86VidModeGetViewPort() says.
1111 static int warned_once = 0;
1112 if (!warned_once && verbose_p)
1116 "%s: %d: XF86VidModeGetViewPort() says vp is %dx%d+%d+%d;\n"
1117 "%s: %d: assuming that is a pack of lies;\n"
1118 "%s: %d: using %dx%d+0+0 instead.\n",
1119 blurb(), ssi->number,
1120 *w_ret, *h_ret, *x_ret, *y_ret,
1121 blurb(), ssi->number,
1122 blurb(), ssi->number, w, h);
1133 /* Apparently, though the server stores the X position in increments of
1134 1 pixel, it will only make changes to the *display* in some other
1135 increment. With XF86_SVGA on a Thinkpad, the display only updates
1136 in multiples of 8 pixels when in 8-bit mode, and in multiples of 4
1137 pixels in 16-bit mode. I don't know what it does in 24- and 32-bit
1138 mode, because I don't have enough video memory to find out.
1140 I consider it a bug that XF86VidModeGetViewPort() is telling me the
1141 server's *target* scroll position rather than the server's *actual*
1142 scroll position. David Dawes agrees, and says they may fix this in
1143 XFree86 4.0, but it's notrivial.
1145 He also confirms that this behavior is server-dependent, so the
1146 actual scroll position cannot be reliably determined by the client.
1147 So... that means the only solution is to provide a ``sandbox''
1148 around the blackout window -- we make the window be up to N pixels
1149 larger than the viewport on both the left and right sides. That
1150 means some part of the outer edges of each hack might not be
1151 visible, but screw it.
1153 I'm going to guess that 16 pixels is enough, and that the Y dimension
1154 doesn't have this problem.
1156 The drawback of doing this, of course, is that some of the screenhacks
1157 will still look pretty stupid -- for example, "slidescreen" will cut
1158 off the left and right edges of the grid, etc.
1161 if (x > 0 && x < w - ml.hdisplay) /* not at left edge or right edge */
1163 /* Round X position down to next lower multiple of FUDGE.
1164 Increase width by 2*FUDGE in case some server rounds up.
1166 *x_ret = ((x - 1) / FUDGE) * FUDGE;
1167 *w_ret += (FUDGE * 2);
1173 *w_ret != ml.hdisplay ||
1174 *h_ret != ml.vdisplay)
1175 sprintf (msg + strlen(msg), "; fudged to %dx%d+%d+%d",
1176 *w_ret, *h_ret, *x_ret, *y_ret);
1179 fprintf (stderr, "%s.\n", msg);
1184 # endif /* HAVE_XF86VMODE */
1193 static Bool error_handler_hit_p = False;
1196 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1198 error_handler_hit_p = True;
1203 /* Returns True if successful, False if an X error occurred.
1204 We need this because other programs might have done things to
1205 our window that will cause XChangeWindowAttributes() to fail:
1206 if that happens, we give up, destroy the window, and re-create
1210 safe_XChangeWindowAttributes (Display *dpy, Window window,
1212 XSetWindowAttributes *attrs)
1214 XErrorHandler old_handler;
1216 error_handler_hit_p = False;
1217 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1219 XChangeWindowAttributes (dpy, window, mask, attrs);
1222 XSetErrorHandler (old_handler);
1225 return (!error_handler_hit_p);
1229 /* This might not be necessary, but just in case. */
1231 safe_XConfigureWindow (Display *dpy, Window window,
1232 unsigned long mask, XWindowChanges *changes)
1234 XErrorHandler old_handler;
1236 error_handler_hit_p = False;
1237 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1239 XConfigureWindow (dpy, window, mask, changes);
1242 XSetErrorHandler (old_handler);
1245 return (!error_handler_hit_p);
1248 /* This might not be necessary, but just in case. */
1250 safe_XDestroyWindow (Display *dpy, Window window)
1252 XErrorHandler old_handler;
1254 error_handler_hit_p = False;
1255 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1257 XDestroyWindow (dpy, window);
1260 XSetErrorHandler (old_handler);
1263 return (!error_handler_hit_p);
1268 safe_XKillClient (Display *dpy, XID id)
1270 XErrorHandler old_handler;
1272 error_handler_hit_p = False;
1273 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1275 XKillClient (dpy, id);
1278 XSetErrorHandler (old_handler);
1281 return (!error_handler_hit_p);
1285 #ifdef HAVE_XF86VMODE
1287 safe_XF86VidModeGetViewPort (Display *dpy, int screen, int *xP, int *yP)
1290 XErrorHandler old_handler;
1292 error_handler_hit_p = False;
1293 old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1295 result = XF86VidModeGetViewPort (dpy, screen, xP, yP);
1298 XSetErrorHandler (old_handler);
1301 return (error_handler_hit_p
1306 /* There is no "safe_XF86VidModeGetModeLine" because it fails with an
1307 untrappable I/O error instead of an X error -- so one must call
1308 safe_XF86VidModeGetViewPort first, and assume that both have the
1309 same error condition. Thank you XFree, may I have another.
1312 #endif /* HAVE_XF86VMODE */
1316 initialize_screensaver_window_1 (saver_screen_info *ssi)
1318 saver_info *si = ssi->global;
1319 saver_preferences *p = &si->prefs;
1320 Bool install_cmap_p = ssi->install_cmap_p; /* not p->install_cmap_p */
1322 /* This resets the screensaver window as fully as possible, since there's
1323 no way of knowing what some random client may have done to us in the
1324 meantime. We could just destroy and recreate the window, but that has
1325 its own set of problems...
1328 XSetWindowAttributes attrs;
1329 unsigned long attrmask;
1330 int x, y, width, height;
1331 static Bool printed_visual_info = False; /* only print the message once. */
1332 Window horked_window = 0;
1334 get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
1335 (p->verbose_p && !si->screen_blanked_p));
1337 black.red = black.green = black.blue = 0;
1339 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
1342 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
1343 /* It's not the default visual, so we have no choice but to install. */
1344 install_cmap_p = True;
1350 ssi->cmap = XCreateColormap (si->dpy,
1351 RootWindowOfScreen (ssi->screen),
1352 ssi->current_visual, AllocNone);
1353 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
1354 ssi->black_pixel = black.pixel;
1359 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
1362 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
1363 if (ssi->cmap != ssi->demo_cmap &&
1364 ssi->cmap != def_cmap)
1365 XFreeColormap (si->dpy, ssi->cmap);
1367 ssi->cmap = def_cmap;
1368 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
1371 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
1372 CWBackPixel | CWBackingPixel | CWBorderPixel);
1373 attrs.override_redirect = True;
1375 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
1376 actually be reading these events during normal operation; but we still
1377 need to see Button events for demo-mode to work properly.
1379 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
1380 ButtonPressMask | ButtonReleaseMask |
1383 attrs.backing_store = NotUseful;
1384 attrs.colormap = ssi->cmap;
1385 attrs.background_pixel = ssi->black_pixel;
1386 attrs.backing_pixel = ssi->black_pixel;
1387 attrs.border_pixel = ssi->black_pixel;
1389 if (p->debug_p && !p->quad_p) width = width / 2;
1391 if (!p->verbose_p || printed_visual_info)
1393 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
1395 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1396 describe_visual (stderr, ssi->screen, ssi->current_visual,
1401 fprintf (stderr, "%s: using visual: ", blurb());
1402 describe_visual (stderr, ssi->screen, ssi->current_visual,
1404 fprintf (stderr, "%s: default visual: ", blurb());
1405 describe_visual (stderr, ssi->screen,
1406 DefaultVisualOfScreen (ssi->screen),
1407 ssi->install_cmap_p);
1409 printed_visual_info = True;
1411 #ifdef HAVE_MIT_SAVER_EXTENSION
1412 if (si->using_mit_saver_extension)
1414 XScreenSaverInfo *info;
1415 Window root = RootWindowOfScreen (ssi->screen);
1418 /* This call sets the server screensaver timeouts to what we think
1419 they should be (based on the resources and args xscreensaver was
1420 started with.) It's important that we do this to sync back up
1421 with the server - if we have turned on prematurely, as by an
1422 ACTIVATE ClientMessage, then the server may decide to activate
1423 the screensaver while it's already active. That's ok for us,
1424 since we would know to ignore that ScreenSaverActivate event,
1425 but a side effect of this would be that the server would map its
1426 saver window (which we then hide again right away) meaning that
1427 the bits currently on the screen get blown away. Ugly. */
1429 /* #### Ok, that doesn't work - when we tell the server that the
1430 screensaver is "off" it sends us a Deactivate event, which is
1431 sensible... but causes the saver to never come on. Hmm. */
1432 disable_builtin_screensaver (si, True);
1436 /* #### The MIT-SCREEN-SAVER extension gives us access to the
1437 window that the server itself uses for saving the screen.
1438 However, using this window in any way, in particular, calling
1439 XScreenSaverSetAttributes() as below, tends to make the X server
1440 crash. So fuck it, let's try and get along without using it...
1442 It's also inconvenient to use this window because it doesn't
1443 always exist (though the ID is constant.) So to use this
1444 window, we'd have to reimplement the ACTIVATE ClientMessage to
1445 tell the *server* to tell *us* to turn on, to cause the window
1446 to get created at the right time. Gag. */
1447 XScreenSaverSetAttributes (si->dpy, root,
1448 0, 0, width, height, 0,
1449 current_depth, InputOutput, visual,
1451 XSync (si->dpy, False);
1454 info = XScreenSaverAllocInfo ();
1455 XScreenSaverQueryInfo (si->dpy, root, info);
1456 ssi->server_mit_saver_window = info->window;
1457 if (! ssi->server_mit_saver_window) abort ();
1460 #endif /* HAVE_MIT_SAVER_EXTENSION */
1462 if (ssi->screensaver_window)
1464 XWindowChanges changes;
1465 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1468 changes.width = width;
1469 changes.height = height;
1470 changes.border_width = 0;
1472 if (! (safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1473 changesmask, &changes) &&
1474 safe_XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
1477 horked_window = ssi->screensaver_window;
1478 ssi->screensaver_window = 0;
1482 if (!ssi->screensaver_window)
1484 ssi->screensaver_window =
1485 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen),
1486 x, y, width, height,
1487 0, ssi->current_depth, InputOutput,
1488 ssi->current_visual, attrmask, &attrs);
1495 "%s: someone horked our saver window (0x%lx)! Recreating it...\n",
1496 blurb(), (unsigned long) horked_window);
1497 maybe_transfer_grabs (ssi, horked_window, ssi->screensaver_window,
1499 safe_XDestroyWindow (si->dpy, horked_window);
1504 fprintf (stderr, "%s: %d: saver window is 0x%lx.\n",
1505 blurb(), ssi->number,
1506 (unsigned long) ssi->screensaver_window);
1509 store_saver_id (ssi); /* store window name and IDs */
1514 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
1516 BlackPixelOfScreen (ssi->screen),
1517 BlackPixelOfScreen (ssi->screen),
1519 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
1521 XFreePixmap (si->dpy, bit);
1524 XSetWindowBackground (si->dpy, ssi->screensaver_window, ssi->black_pixel);
1527 XUndefineCursor (si->dpy, ssi->screensaver_window);
1529 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
1533 initialize_screensaver_window (saver_info *si)
1536 for (i = 0; i < si->nscreens; i++)
1537 initialize_screensaver_window_1 (&si->screens[i]);
1541 /* Called when the RANDR (Resize and Rotate) extension tells us that the
1542 size of the screen has changed while the screen was blanked. If we
1543 don't do this, then the screen saver will no longer fully fill the
1544 screen, and some of the underlying desktop may be visible.
1547 resize_screensaver_window (saver_info *si)
1549 saver_preferences *p = &si->prefs;
1552 /* First update the size info in the saver_screen_info structs.
1555 # ifdef HAVE_XINERAMA
1558 /* As of XFree86 4.3.0, the RANDR and XINERAMA extensions cannot coexist.
1559 However, maybe they will someday, so I'm guessing that the right thing
1560 to do in that case will be to re-query the Xinerama rectangles after
1561 a RANDR size change is received: presumably, if the resolution of one
1562 or more of the monitors has changed, then the Xinerama rectangle
1563 corresponding to that monitor will also have been updated.
1566 XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
1567 if (nscreens != si->nscreens) abort();
1569 for (i = 0; i < si->nscreens; i++)
1571 saver_screen_info *ssi = &si->screens[i];
1573 (ssi->x != xsi[i].x_org ||
1574 ssi->y != xsi[i].y_org ||
1575 ssi->width != xsi[i].width ||
1576 ssi->height != xsi[i].height))
1578 "%s: %d: resize xinerama from %dx%d+%d+%d to %dx%d+%d+%d\n",
1580 ssi->width, ssi->height, ssi->x, ssi->y,
1581 xsi[i].width, xsi[i].height, xsi[i].x_org, xsi[i].y_org);
1583 ssi->x = xsi[i].x_org;
1584 ssi->y = xsi[i].y_org;
1585 ssi->width = xsi[i].width;
1586 ssi->height = xsi[i].height;
1591 # endif /* HAVE_XINERAMA */
1593 /* Not Xinerama -- get the real sizes of the root windows. */
1594 for (i = 0; i < si->nscreens; i++)
1596 saver_screen_info *ssi = &si->screens[i];
1597 XWindowAttributes xgwa;
1598 XGetWindowAttributes (si->dpy, RootWindowOfScreen (ssi->screen),
1602 (ssi->x != xgwa.x ||
1604 ssi->width != xgwa.width ||
1605 ssi->height != xgwa.height))
1607 "%s: %d: resize screen from %dx%d+%d+%d to %dx%d+%d+%d\n",
1609 ssi->width, ssi->height, ssi->x, ssi->y,
1610 xgwa.width, xgwa.height, xgwa.x, xgwa.y);
1614 ssi->width = xgwa.width;
1615 ssi->height = xgwa.height;
1619 /* Next, ensure that the screensaver windows are the right size, taking
1620 into account both the new size of the screen in question's root window,
1621 and any viewport within that.
1624 for (i = 0; i < si->nscreens; i++)
1626 saver_screen_info *ssi = &si->screens[i];
1627 XWindowAttributes xgwa;
1628 XWindowChanges changes;
1629 int x, y, width, height;
1630 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1632 XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
1633 get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
1634 (p->verbose_p && !si->screen_blanked_p));
1637 xgwa.width == width &&
1638 xgwa.height == height)
1639 continue; /* no change! */
1643 changes.width = width;
1644 changes.height = height;
1645 changes.border_width = 0;
1647 if (p->debug_p && !p->quad_p) changes.width = changes.width / 2;
1651 "%s: %d: resize 0x%lx from %dx%d+%d+%d to %dx%d+%d+%d\n",
1652 blurb(), i, (unsigned long) ssi->screensaver_window,
1653 xgwa.width, xgwa.height, xgwa.x, xgwa.y,
1654 width, height, x, y);
1655 if (! safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1656 changesmask, &changes))
1659 "%s: %d: someone horked our saver window (0x%lx)! Unable to resize it!\n",
1660 blurb(), i, (unsigned long) ssi->screensaver_window);
1667 raise_window (saver_info *si,
1668 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
1670 saver_preferences *p = &si->prefs;
1674 inhibit_fade = True;
1676 if (si->emergency_lock_p)
1677 inhibit_fade = True;
1680 initialize_screensaver_window (si);
1682 reset_watchdog_timer (si, True);
1684 if (p->fade_p && si->fading_possible_p && !inhibit_fade)
1686 Window *current_windows = (Window *)
1687 calloc(sizeof(Window), si->nscreens);
1688 Colormap *current_maps = (Colormap *)
1689 calloc(sizeof(Colormap), si->nscreens);
1691 for (i = 0; i < si->nscreens; i++)
1693 saver_screen_info *ssi = &si->screens[i];
1694 current_windows[i] = ssi->screensaver_window;
1695 current_maps[i] = (between_hacks_p
1697 : DefaultColormapOfScreen (ssi->screen));
1698 /* Ensure that the default background of the window is really black,
1699 not a pixmap or something. (This does not clear the window.) */
1700 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1704 if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
1706 XGrabServer (si->dpy); /* ############ DANGER! */
1708 /* Clear the stderr layer on each screen.
1711 for (i = 0; i < si->nscreens; i++)
1713 saver_screen_info *ssi = &si->screens[i];
1714 if (ssi->stderr_overlay_window)
1715 /* Do this before the fade, since the stderr cmap won't fade
1716 even if we uninstall it (beats me...) */
1720 /* Note! The server is grabbed, and this will take several seconds
1722 fade_screens (si->dpy, current_maps,
1723 current_windows, si->nscreens,
1724 p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
1727 free(current_windows);
1729 current_windows = 0;
1731 if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
1733 #ifdef HAVE_MIT_SAVER_EXTENSION
1734 for (i = 0; i < si->nscreens; i++)
1736 saver_screen_info *ssi = &si->screens[i];
1737 if (ssi->server_mit_saver_window &&
1738 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1739 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1741 #endif /* HAVE_MIT_SAVER_EXTENSION */
1743 XUngrabServer (si->dpy);
1744 XSync (si->dpy, False); /* ###### (danger over) */
1748 for (i = 0; i < si->nscreens; i++)
1750 saver_screen_info *ssi = &si->screens[i];
1752 XClearWindow (si->dpy, ssi->screensaver_window);
1753 if (!dont_clear || ssi->stderr_overlay_window)
1755 XMapRaised (si->dpy, ssi->screensaver_window);
1756 #ifdef HAVE_MIT_SAVER_EXTENSION
1757 if (ssi->server_mit_saver_window &&
1758 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1759 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1760 #endif /* HAVE_MIT_SAVER_EXTENSION */
1764 for (i = 0; i < si->nscreens; i++)
1766 saver_screen_info *ssi = &si->screens[i];
1768 XInstallColormap (si->dpy, ssi->cmap);
1774 mouse_screen (saver_info *si)
1776 saver_preferences *p = &si->prefs;
1777 Window pointer_root, pointer_child;
1778 int root_x, root_y, win_x, win_y;
1782 if (si->nscreens == 1)
1785 for (i = 0; i < si->nscreens; i++)
1787 saver_screen_info *ssi = &si->screens[i];
1788 if (XQueryPointer (si->dpy, RootWindowOfScreen (ssi->screen),
1789 &pointer_root, &pointer_child,
1790 &root_x, &root_y, &win_x, &win_y, &mask) &&
1793 root_x < ssi->x + ssi->width &&
1794 root_y < ssi->y + ssi->height)
1797 fprintf (stderr, "%s: mouse is on screen %d of %d\n",
1798 blurb(), i, si->nscreens);
1803 /* couldn't figure out where the mouse is? Oh well. */
1809 blank_screen (saver_info *si)
1816 /* Note: we do our grabs on the root window, not on the screensaver window.
1817 If we grabbed on the saver window, then the demo mode and lock dialog
1818 boxes wouldn't get any events.
1820 By "the root window", we mean "the root window that contains the mouse."
1821 We use to always grab the mouse on screen 0, but that has the effect of
1822 moving the mouse to screen 0 from whichever screen it was on, on
1825 mscreen = mouse_screen (si);
1826 w = RootWindowOfScreen(si->screens[mscreen].screen);
1827 ok = grab_keyboard_and_mouse (si, w,
1828 (si->demoing_p ? 0 : si->screens[0].cursor),
1832 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1833 /* If we're using a server extension, then failure to get a grab is
1834 not a big deal -- even without the grab, we will still be able
1835 to un-blank when there is user activity, since the server will
1842 for (i = 0; i < si->nscreens; i++)
1844 saver_screen_info *ssi = &si->screens[i];
1845 if (ssi->real_screen_p)
1846 save_real_vroot (ssi);
1847 store_vroot_property (si->dpy,
1848 ssi->screensaver_window,
1849 ssi->screensaver_window);
1851 #ifdef HAVE_XF86VMODE
1854 if (!XF86VidModeQueryExtension (si->dpy, &ev, &er) ||
1855 !safe_XF86VidModeGetViewPort (si->dpy, i,
1858 ssi->blank_vp_x = ssi->blank_vp_y = -1;
1860 #endif /* HAVE_XF86VMODE */
1863 raise_window (si, False, False, False);
1865 si->screen_blanked_p = True;
1866 si->blank_time = time ((time_t) 0);
1867 si->last_wall_clock_time = 0;
1869 store_saver_status (si); /* store blank time */
1876 unblank_screen (saver_info *si)
1878 saver_preferences *p = &si->prefs;
1879 Bool unfade_p = (si->fading_possible_p && p->unfade_p);
1882 monitor_power_on (si);
1883 reset_watchdog_timer (si, False);
1890 Window *current_windows = (Window *)
1891 calloc(sizeof(Window), si->nscreens);
1893 for (i = 0; i < si->nscreens; i++)
1895 saver_screen_info *ssi = &si->screens[i];
1896 current_windows[i] = ssi->screensaver_window;
1897 /* Ensure that the default background of the window is really black,
1898 not a pixmap or something. (This does not clear the window.) */
1899 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1903 if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
1906 XSync (si->dpy, False);
1907 XGrabServer (si->dpy); /* ############ DANGER! */
1908 XSync (si->dpy, False);
1910 /* Clear the stderr layer on each screen.
1912 for (i = 0; i < si->nscreens; i++)
1914 saver_screen_info *ssi = &si->screens[i];
1918 XUngrabServer (si->dpy);
1919 XSync (si->dpy, False); /* ###### (danger over) */
1921 fade_screens (si->dpy, 0,
1922 current_windows, si->nscreens,
1923 p->fade_seconds/1000, p->fade_ticks,
1926 free(current_windows);
1927 current_windows = 0;
1929 if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
1933 for (i = 0; i < si->nscreens; i++)
1935 saver_screen_info *ssi = &si->screens[i];
1938 Colormap c = DefaultColormapOfScreen (ssi->screen);
1939 /* avoid technicolor */
1940 XClearWindow (si->dpy, ssi->screensaver_window);
1941 if (c) XInstallColormap (si->dpy, c);
1943 XUnmapWindow (si->dpy, ssi->screensaver_window);
1948 /* If the focus window does has a non-default colormap, then install
1949 that colormap as well. (On SGIs, this will cause both the root map
1950 and the focus map to be installed simultaniously. It'd be nice to
1951 pick up the other colormaps that had been installed, too; perhaps
1952 XListInstalledColormaps could be used for that?)
1957 XGetInputFocus (si->dpy, &focus, &revert_to);
1958 if (focus && focus != PointerRoot && focus != None)
1960 XWindowAttributes xgwa;
1962 XGetWindowAttributes (si->dpy, focus, &xgwa);
1963 if (xgwa.colormap &&
1964 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1965 XInstallColormap (si->dpy, xgwa.colormap);
1970 for (i = 0; i < si->nscreens; i++)
1972 saver_screen_info *ssi = &si->screens[i];
1973 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
1976 store_saver_status (si); /* store unblank time */
1977 ungrab_keyboard_and_mouse (si);
1978 restore_real_vroot (si);
1980 /* Unmap the windows a second time, dammit -- just to avoid a race
1981 with the screen-grabbing hacks. (I'm not sure if this is really
1982 necessary; I'm stabbing in the dark now.)
1984 for (i = 0; i < si->nscreens; i++)
1985 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
1987 si->screen_blanked_p = False;
1988 si->blank_time = time ((time_t) 0);
1989 si->last_wall_clock_time = 0;
1991 store_saver_status (si); /* store unblank time */
1995 /* Transfer any grabs from the old window to the new.
1996 Actually I think none of this is necessary, since we always
1997 hold our grabs on the root window, but I wrote this before
1998 re-discovering that...
2001 maybe_transfer_grabs (saver_screen_info *ssi,
2002 Window old_w, Window new_w,
2005 saver_info *si = ssi->global;
2007 /* If the old window held our mouse grab, transfer the grab to the new
2008 window. (Grab the server while so doing, to avoid a race condition.)
2010 if (old_w == si->mouse_grab_window)
2012 XGrabServer (si->dpy); /* ############ DANGER! */
2014 grab_mouse (si, ssi->screensaver_window,
2015 (si->demoing_p ? 0 : ssi->cursor),
2017 XUngrabServer (si->dpy);
2018 XSync (si->dpy, False); /* ###### (danger over) */
2021 /* If the old window held our keyboard grab, transfer the grab to the new
2022 window. (Grab the server while so doing, to avoid a race condition.)
2024 if (old_w == si->keyboard_grab_window)
2026 XGrabServer (si->dpy); /* ############ DANGER! */
2028 grab_kbd(si, ssi->screensaver_window, ssi->number);
2029 XUngrabServer (si->dpy);
2030 XSync (si->dpy, False); /* ###### (danger over) */
2037 select_visual (saver_screen_info *ssi, const char *visual_name)
2039 saver_info *si = ssi->global;
2040 saver_preferences *p = &si->prefs;
2041 Bool install_cmap_p = p->install_cmap_p;
2042 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
2046 if (visual_name && *visual_name)
2048 if (!strcmp(visual_name, "default-i") ||
2049 !strcmp(visual_name, "Default-i") ||
2050 !strcmp(visual_name, "Default-I")
2053 visual_name = "default";
2054 install_cmap_p = True;
2056 else if (!strcmp(visual_name, "default-n") ||
2057 !strcmp(visual_name, "Default-n") ||
2058 !strcmp(visual_name, "Default-N"))
2060 visual_name = "default";
2061 install_cmap_p = False;
2063 else if (!strcmp(visual_name, "gl") ||
2064 !strcmp(visual_name, "Gl") ||
2065 !strcmp(visual_name, "GL"))
2067 new_v = ssi->best_gl_visual;
2068 if (!new_v && p->verbose_p)
2069 fprintf (stderr, "%s: no GL visuals.\n", progname);
2073 new_v = get_visual (ssi->screen, visual_name, True, False);
2077 new_v = ssi->default_visual;
2082 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
2083 /* It's not the default visual, so we have no choice but to install. */
2084 install_cmap_p = True;
2086 ssi->install_cmap_p = install_cmap_p;
2089 ((ssi->current_visual != new_v) ||
2090 (install_cmap_p != was_installed_p)))
2092 Colormap old_c = ssi->cmap;
2093 Window old_w = ssi->screensaver_window;
2097 fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
2098 describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
2100 fprintf (stderr, "%s: from ", blurb());
2101 describe_visual (stderr, ssi->screen, ssi->current_visual,
2107 ssi->current_visual = new_v;
2108 ssi->current_depth = visual_depth(ssi->screen, new_v);
2110 ssi->screensaver_window = 0;
2112 initialize_screensaver_window_1 (ssi);
2114 /* stderr_overlay_window is a child of screensaver_window, so we need
2115 to destroy that as well (actually, we just need to invalidate and
2116 drop our pointers to it, but this will destroy it, which is ok so
2117 long as it happens before old_w itself is destroyed.) */
2120 raise_window (si, True, True, False);
2121 store_vroot_property (si->dpy,
2122 ssi->screensaver_window, ssi->screensaver_window);
2124 /* Transfer any grabs from the old window to the new. */
2125 maybe_transfer_grabs (ssi, old_w, ssi->screensaver_window, ssi->number);
2127 /* Now we can destroy the old window without horking our grabs. */
2128 XDestroyWindow (si->dpy, old_w);
2131 fprintf (stderr, "%s: %d: destroyed old saver window 0x%lx.\n",
2132 blurb(), ssi->number, (unsigned long) old_w);
2135 old_c != DefaultColormapOfScreen (ssi->screen) &&
2136 old_c != ssi->demo_cmap)
2137 XFreeColormap (si->dpy, old_c);