1 /* windows.c --- turning the screen black; dealing with visuals, virtual roots.
2 * xscreensaver, Copyright (c) 1991-1998 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 */
40 #ifdef HAVE_MIT_SAVER_EXTENSION
41 # include <X11/extensions/scrnsaver.h>
42 #endif /* HAVE_MIT_SAVER_EXTENSION */
45 # include <X11/extensions/xf86vmode.h>
46 #endif /* HAVE_XF86VMODE */
49 /* This file doesn't need the Xt headers, so stub these types out... */
51 #define XtAppContext void*
52 #define XrmDatabase void*
53 #define XtIntervalId void*
54 #define XtPointer void*
57 #include "xscreensaver.h"
62 extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
64 Atom XA_VROOT, XA_XSETROOT_ID;
65 Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
66 Atom XA_SCREENSAVER_TIME;
69 extern saver_info *global_si_kludge; /* I hate C so much... */
72 static void store_activate_time (saver_info *si, Bool use_last_p);
74 #define ALL_POINTER_EVENTS \
75 (ButtonPressMask | ButtonReleaseMask | EnterWindowMask | \
76 LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | \
77 Button1MotionMask | Button2MotionMask | Button3MotionMask | \
78 Button4MotionMask | Button5MotionMask | ButtonMotionMask)
82 grab_string(int status)
86 case GrabSuccess: return "GrabSuccess";
87 case AlreadyGrabbed: return "AlreadyGrabbed";
88 case GrabInvalidTime: return "GrabInvalidTime";
89 case GrabNotViewable: return "GrabNotViewable";
90 case GrabFrozen: return "GrabFrozen";
94 sprintf(foo, "unknown status: %d", status);
101 grab_kbd(saver_info *si, Window w)
103 saver_preferences *p = &si->prefs;
104 int status = XGrabKeyboard (si->dpy, w, True,
105 /* I don't really understand Sync vs Async,
106 but these seem to work... */
107 GrabModeSync, GrabModeAsync,
109 if (status == GrabSuccess)
110 si->keyboard_grab_window = w;
113 fprintf(stderr, "%s: grabbing keyboard on 0x%x... %s.\n",
114 blurb(), (unsigned long) w, grab_string(status));
120 grab_mouse (saver_info *si, Window w, Cursor cursor)
122 saver_preferences *p = &si->prefs;
123 int status = XGrabPointer (si->dpy, w, True, ALL_POINTER_EVENTS,
124 GrabModeAsync, GrabModeAsync, w,
125 cursor, CurrentTime);
126 if (status == GrabSuccess)
127 si->mouse_grab_window = w;
130 fprintf(stderr, "%s: grabbing mouse on 0x%x... %s.\n",
131 blurb(), (unsigned long) w, grab_string(status));
137 ungrab_kbd(saver_info *si)
139 saver_preferences *p = &si->prefs;
140 XUngrabKeyboard(si->dpy, CurrentTime);
142 fprintf(stderr, "%s: ungrabbing keyboard (was 0x%x).\n", blurb(),
143 (unsigned long) si->keyboard_grab_window);
144 si->keyboard_grab_window = 0;
149 ungrab_mouse(saver_info *si)
151 saver_preferences *p = &si->prefs;
152 XUngrabPointer(si->dpy, CurrentTime);
154 fprintf(stderr, "%s: ungrabbing mouse (was 0x%x).\n", blurb(),
155 (unsigned long) si->mouse_grab_window);
156 si->mouse_grab_window = 0;
161 grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor)
163 Status mstatus, kstatus;
164 XSync (si->dpy, False);
166 kstatus = grab_kbd (si, window);
167 if (kstatus != GrabSuccess)
168 { /* try again in a second */
170 kstatus = grab_kbd (si, window);
171 if (kstatus != GrabSuccess)
172 fprintf (stderr, "%s: couldn't grab keyboard! (%s)\n",
173 blurb(), grab_string(kstatus));
176 mstatus = grab_mouse (si, window, cursor);
177 if (mstatus != GrabSuccess)
178 { /* try again in a second */
180 mstatus = grab_mouse (si, window, cursor);
181 if (mstatus != GrabSuccess)
182 fprintf (stderr, "%s: couldn't grab pointer! (%s)\n",
183 blurb(), grab_string(mstatus));
186 return (kstatus == GrabSuccess ||
187 mstatus == GrabSuccess);
191 ungrab_keyboard_and_mouse (saver_info *si)
199 move_mouse_grab (saver_info *si, Window to, Cursor cursor)
201 Window old = si->mouse_grab_window;
204 return grab_mouse (si, to, cursor);
207 saver_preferences *p = &si->prefs;
210 XSync (si->dpy, False);
211 XGrabServer (si->dpy); /* ############ DANGER! */
212 XSync (si->dpy, False);
215 fprintf(stderr, "%s: grabbing server...\n", blurb());
218 status = grab_mouse (si, to, cursor);
220 if (status != GrabSuccess) /* Augh! */
222 sleep (1); /* Note dramatic evil of sleeping
223 with server grabbed. */
224 XSync (si->dpy, False);
225 status = grab_mouse (si, to, cursor);
228 if (status != GrabSuccess) /* Augh! Try to get the old one back... */
229 grab_mouse (si, to, cursor);
231 XUngrabServer (si->dpy);
232 XSync (si->dpy, False); /* ###### (danger over) */
235 fprintf(stderr, "%s: ungrabbing server.\n", blurb());
242 /* Prints an error message to stderr and returns True if there is another
243 xscreensaver running already. Silently returns False otherwise. */
245 ensure_no_screensaver_running (Display *dpy, Screen *screen)
249 Window root = RootWindowOfScreen (screen);
250 Window root2, parent, *kids;
252 XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler);
254 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
260 for (i = 0; i < nkids; i++)
264 unsigned long nitems, bytesafter;
267 if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
268 False, XA_STRING, &type, &format, &nitems,
269 &bytesafter, (unsigned char **) &version)
274 if (!XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
275 False, XA_STRING, &type, &format, &nitems,
276 &bytesafter, (unsigned char **) &id)
282 "%s: already running on display %s (window 0x%x)\n from process %s.\n",
283 blurb(), DisplayString (dpy), (int) kids [i], id);
288 if (kids) XFree ((char *) kids);
290 XSetErrorHandler (old_handler);
296 /* Virtual-root hackery */
299 ERROR! You must not include vroot.h in this file.
303 store_vroot_property (Display *dpy, Window win, Window value)
308 "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", blurb(),
310 (win == screensaver_window ? "ScreenSaver" :
311 (win == real_vroot ? "VRoot" :
312 (win == real_vroot_value ? "Vroot_value" : "???"))),
314 (value == screensaver_window ? "ScreenSaver" :
315 (value == real_vroot ? "VRoot" :
316 (value == real_vroot_value ? "Vroot_value" : "???"))));
318 XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
319 (unsigned char *) &value, 1);
323 remove_vroot_property (Display *dpy, Window win)
327 fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", blurb(), win,
328 (win == screensaver_window ? "ScreenSaver" :
329 (win == real_vroot ? "VRoot" :
330 (win == real_vroot_value ? "Vroot_value" : "???"))));
332 XDeleteProperty (dpy, win, XA_VROOT);
337 kill_xsetroot_data (Display *dpy, Window window, Bool verbose_p)
341 unsigned long nitems, bytesafter;
344 /* If the user has been using xv or xsetroot as a screensaver (to display
345 an image on the screensaver window, as a kind of slideshow) then the
346 pixmap and its associated color cells have been put in RetainPermanent
347 CloseDown mode. Since we're not destroying the xscreensaver window,
348 but merely unmapping it, we need to free these resources or those
349 colormap cells will stay allocated while the screensaver is off. (We
350 could just delete the screensaver window and recreate it later, but
351 that could cause other problems.) This code does an atomic read-and-
352 delete of the _XSETROOT_ID property, and if it held a pixmap, then we
353 cause the RetainPermanent resources of the client which created it
354 (and which no longer exists) to be freed.
356 if (XGetWindowProperty (dpy, window, XA_XSETROOT_ID, 0, 1,
357 True, AnyPropertyType, &type, &format, &nitems,
358 &bytesafter, (unsigned char **) &dataP)
362 if (dataP && *dataP && type == XA_PIXMAP && format == 32 &&
363 nitems == 1 && bytesafter == 0)
366 fprintf (stderr, "%s: destroying xsetroot data (0x%lX).\n",
368 XKillClient (dpy, *dataP);
371 fprintf (stderr, "%s: deleted unrecognised _XSETROOT_ID property: \n\
372 %lu, %lu; type: %lu, format: %d, nitems: %lu, bytesafter %ld\n",
373 blurb(), (unsigned long) dataP, (dataP ? *dataP : 0), type,
374 format, nitems, bytesafter);
379 static void handle_signals (saver_info *si, Bool on_p);
382 save_real_vroot (saver_screen_info *ssi)
384 saver_info *si = ssi->global;
385 Display *dpy = si->dpy;
386 Screen *screen = ssi->screen;
388 Window root = RootWindowOfScreen (screen);
389 Window root2, parent, *kids;
391 XErrorHandler old_handler;
393 /* It's possible that a window might be deleted between our call to
394 XQueryTree() and our call to XGetWindowProperty(). Don't die if
395 that happens (but just ignore that window, it's not the one we're
396 interested in anyway.)
399 old_handler = XSetErrorHandler (BadWindow_ehandler);
403 ssi->real_vroot_value = 0;
404 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
410 for (i = 0; i < nkids; i++)
414 unsigned long nitems, bytesafter;
417 if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
418 &type, &format, &nitems, &bytesafter,
419 (unsigned char **) &vrootP)
426 if (*vrootP == ssi->screensaver_window) abort ();
428 "%s: more than one virtual root window found (0x%x and 0x%x).\n",
429 blurb(), (int) ssi->real_vroot, (int) kids [i]);
432 ssi->real_vroot = kids [i];
433 ssi->real_vroot_value = *vrootP;
437 XSetErrorHandler (old_handler);
442 handle_signals (si, True);
443 remove_vroot_property (si->dpy, ssi->real_vroot);
447 XFree ((char *) kids);
452 restore_real_vroot_2 (saver_screen_info *ssi)
454 saver_info *si = ssi->global;
455 saver_preferences *p = &si->prefs;
456 if (p->verbose_p && ssi->real_vroot)
458 "%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
459 blurb(), (unsigned long) ssi->real_vroot);
460 remove_vroot_property (si->dpy, ssi->screensaver_window);
463 store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
465 ssi->real_vroot_value = 0;
466 /* make sure the property change gets there before this process
467 terminates! We might be doing this because we have intercepted
468 SIGTERM or something. */
469 XSync (si->dpy, False);
476 restore_real_vroot_1 (saver_info *si)
479 Bool did_any = False;
480 for (i = 0; i < si->nscreens; i++)
482 saver_screen_info *ssi = &si->screens[i];
483 if (restore_real_vroot_2 (ssi))
490 restore_real_vroot (saver_info *si)
492 if (restore_real_vroot_1 (si))
493 handle_signals (si, False);
497 /* Signal hackery to ensure that the vroot doesn't get left in an
502 signal_name(int signal)
505 case SIGHUP: return "SIGHUP";
506 case SIGINT: return "SIGINT";
507 case SIGQUIT: return "SIGQUIT";
508 case SIGILL: return "SIGILL";
509 case SIGTRAP: return "SIGTRAP";
511 case SIGABRT: return "SIGABRT";
513 case SIGFPE: return "SIGFPE";
514 case SIGKILL: return "SIGKILL";
515 case SIGBUS: return "SIGBUS";
516 case SIGSEGV: return "SIGSEGV";
517 case SIGPIPE: return "SIGPIPE";
518 case SIGALRM: return "SIGALRM";
519 case SIGTERM: return "SIGTERM";
521 case SIGSTOP: return "SIGSTOP";
524 case SIGCONT: return "SIGCONT";
527 case SIGUSR1: return "SIGUSR1";
530 case SIGUSR2: return "SIGUSR2";
533 case SIGEMT: return "SIGEMT";
536 case SIGSYS: return "SIGSYS";
539 case SIGCHLD: return "SIGCHLD";
542 case SIGPWR: return "SIGPWR";
545 case SIGWINCH: return "SIGWINCH";
548 case SIGURG: return "SIGURG";
551 case SIGIO: return "SIGIO";
554 case SIGVTALRM: return "SIGVTALRM";
557 case SIGXCPU: return "SIGXCPU";
560 case SIGXFSZ: return "SIGXFSZ";
563 case SIGDANGER: return "SIGDANGER";
568 sprintf(buf, "signal %d\n", signal);
577 restore_real_vroot_handler (int sig)
579 saver_info *si = global_si_kludge; /* I hate C so much... */
581 signal (sig, SIG_DFL);
582 if (restore_real_vroot_1 (si))
583 fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n",
584 blurb(), signal_name(sig));
585 kill (getpid (), sig);
589 catch_signal (saver_info *si, int sig, Bool on_p)
592 signal (sig, SIG_DFL);
595 if (((long) signal (sig, restore_real_vroot_handler)) == -1L)
598 sprintf (buf, "%s: couldn't catch %s", blurb(), signal_name(sig));
600 saver_exit (si, 1, 0);
606 handle_signals (saver_info *si, Bool on_p)
609 if (on_p) fprintf (stderr, "handling signals\n");
610 else fprintf (stderr, "unhandling signals\n");
613 catch_signal (si, SIGHUP, on_p);
614 catch_signal (si, SIGINT, on_p);
615 catch_signal (si, SIGQUIT, on_p);
616 catch_signal (si, SIGILL, on_p);
617 catch_signal (si, SIGTRAP, on_p);
618 catch_signal (si, SIGIOT, on_p);
619 catch_signal (si, SIGABRT, on_p);
621 catch_signal (si, SIGEMT, on_p);
623 catch_signal (si, SIGFPE, on_p);
624 catch_signal (si, SIGBUS, on_p);
625 catch_signal (si, SIGSEGV, on_p);
627 catch_signal (si, SIGSYS, on_p);
629 catch_signal (si, SIGTERM, on_p);
631 catch_signal (si, SIGXCPU, on_p);
634 catch_signal (si, SIGXFSZ, on_p);
637 catch_signal (si, SIGDANGER, on_p);
642 saver_exit (saver_info *si, int status, const char *dump_core_reason)
644 saver_preferences *p = &si->prefs;
645 static Bool exiting = False;
654 vrs = restore_real_vroot_1 (si);
655 emergency_kill_subproc (si);
657 if (vrs && (p->verbose_p || status != 0))
658 fprintf (real_stderr, "%s: vroot restored, exiting.\n", blurb());
659 else if (p->verbose_p)
660 fprintf (real_stderr, "%s: no vroot to restore; exiting.\n", blurb());
664 #ifdef VMS /* on VMS, 1 is the "normal" exit code instead of 0. */
665 if (status == 0) status = 1;
666 else if (status == 1) status = -1;
669 bugp = !!dump_core_reason;
671 if (si->prefs.debug_p && !dump_core_reason)
672 dump_core_reason = "because of -debug";
674 if (dump_core_reason)
676 /* Note that the Linux man page for setuid() says If uid is
677 different from the old effective uid, the process will be
678 forbidden from leaving core dumps.
680 char cwd[4096]; /* should really be PATH_MAX, but who cares. */
682 fprintf(real_stderr, "%s: dumping core (%s)\n", blurb(),
687 "%s: see http://www.jwz.org/xscreensaver/bugs.html\n"
688 "\t\tfor bug reporting information.\n\n",
691 # if defined(HAVE_GETCWD)
692 if (!getcwd (cwd, sizeof(cwd)))
693 # elif defined(HAVE_GETWD)
696 strcpy(cwd, "unknown.");
698 fprintf (real_stderr, "%s: current directory is %s\n", blurb(), cwd);
699 describe_uids (si, real_stderr);
701 /* Do this to drop a core file, so that we can get a stack trace. */
709 /* Managing the actual screensaver window */
712 window_exists_p (Display *dpy, Window window)
714 XErrorHandler old_handler;
715 XWindowAttributes xgwa;
717 old_handler = XSetErrorHandler (BadWindow_ehandler);
718 XGetWindowAttributes (dpy, window, &xgwa);
720 XSetErrorHandler (old_handler);
721 return (xgwa.screen != 0);
725 store_saver_id (saver_screen_info *ssi)
727 XClassHint class_hints;
728 saver_info *si = ssi->global;
729 unsigned long pid = (unsigned long) getpid ();
731 struct passwd *p = getpwuid (getuid ());
732 const char *name, *host;
735 /* First store the name and class on the window.
737 class_hints.res_name = progname;
738 class_hints.res_class = progclass;
739 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
740 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
742 /* Then store the xscreensaver version number.
744 XChangeProperty (si->dpy, ssi->screensaver_window,
745 XA_SCREENSAVER_VERSION,
746 XA_STRING, 8, PropModeReplace,
747 (unsigned char *) si->version,
748 strlen (si->version));
750 /* Now store the XSCREENSAVER_ID property, that says what user and host
751 xscreensaver is running as.
754 if (p && p->pw_name && *p->pw_name)
758 sprintf (buf, "%lu", (unsigned long) p->pw_uid);
764 # if defined(HAVE_UNAME)
767 if (uname (&uts) < 0)
773 host = getenv("SYS$NODE");
774 # else /* !HAVE_UNAME && !VMS */
776 # endif /* !HAVE_UNAME && !VMS */
778 id = (char *) malloc (strlen(name) + strlen(host) + 50);
779 sprintf (id, "%lu (%s@%s)", pid, name, host);
781 XChangeProperty (si->dpy, ssi->screensaver_window,
782 XA_SCREENSAVER_ID, XA_STRING,
784 (unsigned char *) id, strlen (id));
789 /* Returns the area of the screen which the xscreensaver window should cover.
790 Normally this is the whole screen, but if the X server's root window is
791 actually larger than the monitor's displayable area, then we want to
792 operate in the currently-visible portion of the desktop instead.
795 get_screen_viewport (saver_screen_info *ssi,
796 int *x_ret, int *y_ret,
797 int *w_ret, int *h_ret,
800 int w = WidthOfScreen (ssi->screen);
801 int h = HeightOfScreen (ssi->screen);
803 #ifdef HAVE_XF86VMODE
804 saver_info *si = ssi->global;
805 int screen_no = screen_number (ssi->screen);
808 XF86VidModeModeLine ml;
811 if (XF86VidModeQueryExtension (si->dpy, &event, &error) &&
812 XF86VidModeGetModeLine (si->dpy, screen_no, &dot, &ml) &&
813 XF86VidModeGetViewPort (si->dpy, screen_no, &x, &y))
818 *w_ret = ml.hdisplay;
819 *h_ret = ml.vdisplay;
821 if (*x_ret == 0 && *y_ret == 0 && *w_ret == w && *h_ret == h)
822 /* There is no viewport -- the screen does not scroll. */
825 sprintf (msg, "%s: vp is %dx%d+%d+%d",
826 blurb(), *w_ret, *h_ret, *x_ret, *y_ret);
829 /* Apparently, though the server stores the X position in increments of
830 1 pixel, it will only make changes to the *display* in some other
831 increment. With XF86_SVGA on a Thinkpad, the display only updates
832 in multiples of 8 pixels when in 8-bit mode, and in multiples of 4
833 pixels in 16-bit mode. I don't know what it does in 24- and 32-bit
834 mode, because I don't have enough video memory to find out.
836 I consider it a bug that XF86VidModeGetViewPort() is telling me the
837 server's *target* scroll position rather than the server's *actual*
838 scroll position. David Dawes agrees, and says they may fix this in
839 XFree86 4.0, but it's notrivial.
841 He also confirms that this behavior is server-dependent, so the
842 actual scroll position cannot be reliably determined by the client.
843 So... that means the only solution is to provide a ``sandbox''
844 around the blackout window -- we make the window be up to N pixels
845 larger than the viewport on both the left and right sides. That
846 means some part of the outer edges of each hack might not be
847 visible, but screw it.
849 I'm going to guess that 16 pixels is enough, and that the Y dimension
850 doesn't have this problem.
852 The drawback of doing this, of course, is that some of the screenhacks
853 will still look pretty stupid -- for example, "slidescreen" will cut
854 off the left and right edges of the grid, etc.
857 if (x > 0 && x < w - ml.hdisplay) /* not at left edge or right edge */
859 /* Round X position down to next lower multiple of FUDGE.
860 Increase width by 2*FUDGE in case some server rounds up.
862 *x_ret = ((x - 1) / FUDGE) * FUDGE;
863 *w_ret += (FUDGE * 2);
869 *w_ret != ml.hdisplay ||
870 *h_ret != ml.vdisplay)
871 sprintf (msg + strlen(msg), "; fudged to %dx%d+%d+%d",
872 *w_ret, *h_ret, *x_ret, *y_ret);
875 fprintf (stderr, "%s.\n", msg);
880 #endif /* HAVE_XF86VMODE */
890 initialize_screensaver_window_1 (saver_screen_info *ssi)
892 saver_info *si = ssi->global;
893 saver_preferences *p = &si->prefs;
894 Bool install_cmap_p = ssi->install_cmap_p; /* not p->install_cmap_p */
896 /* This resets the screensaver window as fully as possible, since there's
897 no way of knowing what some random client may have done to us in the
898 meantime. We could just destroy and recreate the window, but that has
899 its own set of problems...
902 XSetWindowAttributes attrs;
903 unsigned long attrmask;
904 int x, y, width, height;
905 static Bool printed_visual_info = False; /* only print the message once. */
907 get_screen_viewport (ssi, &x, &y, &width, &height,
908 (p->verbose_p && !si->screen_blanked_p));
910 black.red = black.green = black.blue = 0;
912 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
915 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
916 /* It's not the default visual, so we have no choice but to install. */
917 install_cmap_p = True;
923 ssi->cmap = XCreateColormap (si->dpy,
924 RootWindowOfScreen (ssi->screen),
925 ssi->current_visual, AllocNone);
926 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
927 ssi->black_pixel = black.pixel;
932 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
935 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
936 if (ssi->cmap != ssi->demo_cmap &&
937 ssi->cmap != def_cmap)
938 XFreeColormap (si->dpy, ssi->cmap);
940 ssi->cmap = def_cmap;
941 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
944 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
945 CWBackPixel | CWBackingPixel | CWBorderPixel);
946 attrs.override_redirect = True;
948 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
949 actually be reading these events during normal operation; but we still
950 need to see Button events for demo-mode to work properly.
952 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
953 ButtonPressMask | ButtonReleaseMask |
956 attrs.backing_store = NotUseful;
957 attrs.colormap = ssi->cmap;
958 attrs.background_pixel = ssi->black_pixel;
959 attrs.backing_pixel = ssi->black_pixel;
960 attrs.border_pixel = ssi->black_pixel;
962 if (p->debug_p) width = width / 2;
964 if (!p->verbose_p || printed_visual_info)
966 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
968 fprintf (stderr, "%s: using default visual ", blurb());
969 describe_visual (stderr, ssi->screen, ssi->current_visual,
974 fprintf (stderr, "%s: using visual: ", blurb());
975 describe_visual (stderr, ssi->screen, ssi->current_visual,
977 fprintf (stderr, "%s: default visual: ", blurb());
978 describe_visual (stderr, ssi->screen,
979 DefaultVisualOfScreen (ssi->screen),
980 ssi->install_cmap_p);
982 printed_visual_info = True;
984 #ifdef HAVE_MIT_SAVER_EXTENSION
985 if (si->using_mit_saver_extension)
987 XScreenSaverInfo *info;
988 Window root = RootWindowOfScreen (ssi->screen);
991 /* This call sets the server screensaver timeouts to what we think
992 they should be (based on the resources and args xscreensaver was
993 started with.) It's important that we do this to sync back up
994 with the server - if we have turned on prematurely, as by an
995 ACTIVATE ClientMessage, then the server may decide to activate
996 the screensaver while it's already active. That's ok for us,
997 since we would know to ignore that ScreenSaverActivate event,
998 but a side effect of this would be that the server would map its
999 saver window (which we then hide again right away) meaning that
1000 the bits currently on the screen get blown away. Ugly. */
1002 /* #### Ok, that doesn't work - when we tell the server that the
1003 screensaver is "off" it sends us a Deactivate event, which is
1004 sensible... but causes the saver to never come on. Hmm. */
1005 disable_builtin_screensaver (si, True);
1009 /* #### The MIT-SCREEN-SAVER extension gives us access to the
1010 window that the server itself uses for saving the screen.
1011 However, using this window in any way, in particular, calling
1012 XScreenSaverSetAttributes() as below, tends to make the X server
1013 crash. So fuck it, let's try and get along without using it...
1015 It's also inconvenient to use this window because it doesn't
1016 always exist (though the ID is constant.) So to use this
1017 window, we'd have to reimplement the ACTIVATE ClientMessage to
1018 tell the *server* to tell *us* to turn on, to cause the window
1019 to get created at the right time. Gag. */
1020 XScreenSaverSetAttributes (si->dpy, root,
1021 0, 0, width, height, 0,
1022 current_depth, InputOutput, visual,
1024 XSync (si->dpy, False);
1027 info = XScreenSaverAllocInfo ();
1028 XScreenSaverQueryInfo (si->dpy, root, info);
1029 ssi->server_mit_saver_window = info->window;
1030 if (! ssi->server_mit_saver_window) abort ();
1033 #endif /* HAVE_MIT_SAVER_EXTENSION */
1035 if (ssi->screensaver_window)
1037 XWindowChanges changes;
1038 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1041 changes.width = width;
1042 changes.height = height;
1043 changes.border_width = 0;
1045 XConfigureWindow (si->dpy, ssi->screensaver_window,
1046 changesmask, &changes);
1047 XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
1052 ssi->screensaver_window =
1053 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen),
1054 x, y, width, height,
1055 0, ssi->current_depth, InputOutput,
1056 ssi->current_visual, attrmask, &attrs);
1059 store_activate_time(si, True);
1061 fprintf (stderr, "%s: saver window is 0x%lx.\n",
1062 blurb(), (unsigned long) ssi->screensaver_window);
1066 store_saver_id (ssi);
1071 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
1073 BlackPixelOfScreen (ssi->screen),
1074 BlackPixelOfScreen (ssi->screen),
1076 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
1078 XFreePixmap (si->dpy, bit);
1081 XSetWindowBackground (si->dpy, ssi->screensaver_window, ssi->black_pixel);
1084 XUndefineCursor (si->dpy, ssi->screensaver_window);
1086 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
1090 initialize_screensaver_window (saver_info *si)
1093 for (i = 0; i < si->nscreens; i++)
1094 initialize_screensaver_window_1 (&si->screens[i]);
1099 raise_window (saver_info *si,
1100 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
1102 saver_preferences *p = &si->prefs;
1106 inhibit_fade = True;
1108 if (si->emergency_lock_p)
1109 inhibit_fade = True;
1112 initialize_screensaver_window (si);
1114 reset_watchdog_timer (si, True);
1116 if (p->fade_p && si->fading_possible_p && !inhibit_fade)
1118 Window *current_windows = (Window *)
1119 calloc(sizeof(Window), si->nscreens);
1120 Colormap *current_maps = (Colormap *)
1121 calloc(sizeof(Colormap), si->nscreens);
1123 for (i = 0; i < si->nscreens; i++)
1125 saver_screen_info *ssi = &si->screens[i];
1126 current_windows[i] = ssi->screensaver_window;
1127 current_maps[i] = (between_hacks_p
1129 : DefaultColormapOfScreen (ssi->screen));
1130 /* Ensure that the default background of the window is really black,
1131 not a pixmap or something. (This does not clear the window.) */
1132 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1136 if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
1138 XGrabServer (si->dpy); /* ############ DANGER! */
1140 /* Clear the stderr layer on each screen.
1143 for (i = 0; i < si->nscreens; i++)
1145 saver_screen_info *ssi = &si->screens[i];
1146 if (ssi->stderr_overlay_window)
1147 /* Do this before the fade, since the stderr cmap won't fade
1148 even if we uninstall it (beats me...) */
1152 /* Note! The server is grabbed, and this will take several seconds
1154 fade_screens (si->dpy, current_maps, current_windows,
1155 p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
1158 free(current_windows);
1160 current_windows = 0;
1162 if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
1164 #ifdef HAVE_MIT_SAVER_EXTENSION
1165 for (i = 0; i < si->nscreens; i++)
1167 saver_screen_info *ssi = &si->screens[i];
1168 if (ssi->server_mit_saver_window &&
1169 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1170 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1172 #endif /* HAVE_MIT_SAVER_EXTENSION */
1174 XUngrabServer (si->dpy);
1175 XSync (si->dpy, False); /* ###### (danger over) */
1179 for (i = 0; i < si->nscreens; i++)
1181 saver_screen_info *ssi = &si->screens[i];
1183 XClearWindow (si->dpy, ssi->screensaver_window);
1184 if (!dont_clear || ssi->stderr_overlay_window)
1186 XMapRaised (si->dpy, ssi->screensaver_window);
1187 #ifdef HAVE_MIT_SAVER_EXTENSION
1188 if (ssi->server_mit_saver_window &&
1189 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1190 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1191 #endif /* HAVE_MIT_SAVER_EXTENSION */
1195 for (i = 0; i < si->nscreens; i++)
1197 saver_screen_info *ssi = &si->screens[i];
1199 XInstallColormap (si->dpy, ssi->cmap);
1204 blank_screen (saver_info *si)
1209 /* Note: we do our grabs on the root window, not on the screensaver window.
1210 If we grabbed on the saver window, then the demo mode and lock dialog
1211 boxes wouldn't get any events.
1213 ok = grab_keyboard_and_mouse (si,
1214 /*si->screens[0].screensaver_window,*/
1215 RootWindowOfScreen(si->screens[0].screen),
1218 : si->screens[0].cursor));
1221 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1222 /* If we're using a server extension, then failure to get a grab is
1223 not a big deal -- even without the grab, we will still be able
1224 to un-blank when there is user activity, since the server will
1231 for (i = 0; i < si->nscreens; i++)
1233 saver_screen_info *ssi = &si->screens[i];
1235 save_real_vroot (ssi);
1236 store_vroot_property (si->dpy,
1237 ssi->screensaver_window,
1238 ssi->screensaver_window);
1240 #ifdef HAVE_XF86VMODE
1243 if (!XF86VidModeQueryExtension (si->dpy, &ev, &er) ||
1244 !XF86VidModeGetViewPort (si->dpy, i,
1247 ssi->blank_vp_x = ssi->blank_vp_y = -1;
1249 #endif /* HAVE_XF86VMODE */
1251 store_activate_time (si, si->screen_blanked_p);
1252 raise_window (si, False, False, False);
1254 si->screen_blanked_p = True;
1255 si->last_wall_clock_time = 0;
1261 unblank_screen (saver_info *si)
1263 saver_preferences *p = &si->prefs;
1264 Bool unfade_p = (si->fading_possible_p && p->unfade_p);
1267 monitor_power_on (si);
1269 store_activate_time (si, True);
1270 reset_watchdog_timer (si, False);
1277 Window *current_windows = (Window *)
1278 calloc(sizeof(Window), si->nscreens);
1280 for (i = 0; i < si->nscreens; i++)
1282 saver_screen_info *ssi = &si->screens[i];
1283 current_windows[i] = ssi->screensaver_window;
1284 /* Ensure that the default background of the window is really black,
1285 not a pixmap or something. (This does not clear the window.) */
1286 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1290 if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
1293 XSync (si->dpy, False);
1294 XGrabServer (si->dpy); /* ############ DANGER! */
1295 XSync (si->dpy, False);
1297 /* Clear the stderr layer on each screen.
1299 for (i = 0; i < si->nscreens; i++)
1301 saver_screen_info *ssi = &si->screens[i];
1305 XUngrabServer (si->dpy);
1306 XSync (si->dpy, False); /* ###### (danger over) */
1309 fade_screens (si->dpy, 0, current_windows,
1310 p->fade_seconds/1000, p->fade_ticks,
1313 free(current_windows);
1314 current_windows = 0;
1316 if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
1320 for (i = 0; i < si->nscreens; i++)
1322 saver_screen_info *ssi = &si->screens[i];
1325 Colormap c = DefaultColormapOfScreen (ssi->screen);
1326 /* avoid technicolor */
1327 XClearWindow (si->dpy, ssi->screensaver_window);
1328 if (c) XInstallColormap (si->dpy, c);
1330 XUnmapWindow (si->dpy, ssi->screensaver_window);
1335 /* If the focus window does has a non-default colormap, then install
1336 that colormap as well. (On SGIs, this will cause both the root map
1337 and the focus map to be installed simultaniously. It'd be nice to
1338 pick up the other colormaps that had been installed, too; perhaps
1339 XListInstalledColormaps could be used for that?)
1344 XGetInputFocus (si->dpy, &focus, &revert_to);
1345 if (focus && focus != PointerRoot && focus != None)
1347 XWindowAttributes xgwa;
1349 XGetWindowAttributes (si->dpy, focus, &xgwa);
1350 if (xgwa.colormap &&
1351 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1352 XInstallColormap (si->dpy, xgwa.colormap);
1357 for (i = 0; i < si->nscreens; i++)
1359 saver_screen_info *ssi = &si->screens[i];
1360 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
1363 store_activate_time(si, False); /* store unblank time */
1365 ungrab_keyboard_and_mouse (si);
1366 restore_real_vroot (si);
1368 /* Unmap the windows a second time, dammit -- just to avoid a race
1369 with the screen-grabbing hacks. (I'm not sure if this is really
1370 necessary; I'm stabbing in the dark now.)
1372 for (i = 0; i < si->nscreens; i++)
1373 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
1375 si->screen_blanked_p = False;
1376 si->last_wall_clock_time = 0;
1381 store_activate_time (saver_info *si, Bool use_last_p)
1383 static time_t last_time = 0;
1384 time_t now = ((use_last_p && last_time) ? last_time : time ((time_t) 0));
1385 CARD32 now32 = (CARD32) now;
1389 for (i = 0; i < si->nscreens; i++)
1391 saver_screen_info *ssi = &si->screens[i];
1392 if (!ssi->screensaver_window) continue;
1393 XChangeProperty (si->dpy, ssi->screensaver_window, XA_SCREENSAVER_TIME,
1394 XA_INTEGER, 32, PropModeReplace,
1395 (unsigned char *) &now32, 1);
1401 select_visual (saver_screen_info *ssi, const char *visual_name)
1403 saver_info *si = ssi->global;
1404 saver_preferences *p = &si->prefs;
1405 Bool install_cmap_p = p->install_cmap_p;
1406 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
1410 if (visual_name && *visual_name)
1412 if (!strcmp(visual_name, "default-i"))
1414 visual_name = "default";
1415 install_cmap_p = True;
1417 else if (!strcmp(visual_name, "default-n"))
1419 visual_name = "default";
1420 install_cmap_p = False;
1422 #ifdef DAEMON_USE_GL
1423 else if (!strcmp(visual_name, "gl") ||
1424 !strcmp(visual_name, "GL"))
1426 new_v = get_gl_visual (ssi->screen);
1427 if (!new_v && p->verbose_p)
1428 fprintf (stderr, "%s: no GL visuals.\n", progname);
1430 #endif /* DAEMON_USE_GL */
1433 new_v = get_visual (ssi->screen, visual_name, True, False);
1437 new_v = ssi->default_visual;
1442 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
1443 /* It's not the default visual, so we have no choice but to install. */
1444 install_cmap_p = True;
1446 ssi->install_cmap_p = install_cmap_p;
1449 ((ssi->current_visual != new_v) ||
1450 (install_cmap_p != was_installed_p)))
1452 Colormap old_c = ssi->cmap;
1453 Window old_w = ssi->screensaver_window;
1457 fprintf (stderr, "%s: switching to visual ", blurb());
1458 describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
1460 fprintf (stderr, "%s: from ", blurb());
1461 describe_visual (stderr, ssi->screen, ssi->current_visual,
1467 ssi->current_visual = new_v;
1468 ssi->current_depth = visual_depth(ssi->screen, new_v);
1470 ssi->screensaver_window = 0;
1472 initialize_screensaver_window_1 (ssi);
1474 /* stderr_overlay_window is a child of screensaver_window, so we need
1475 to destroy that as well (actually, we just need to invalidate and
1476 drop our pointers to it, but this will destroy it, which is ok so
1477 long as it happens before old_w itself is destroyed.) */
1480 raise_window (si, True, True, False);
1481 store_vroot_property (si->dpy,
1482 ssi->screensaver_window, ssi->screensaver_window);
1483 store_activate_time (si, True);
1487 /* Transfer the grabs from the old window to the new.
1488 Actually I think none of this is necessary, since we always
1489 hold our grabs on the root window, but I wrote this before
1490 re-discovering that...
1494 /* If we're destroying the window that holds our mouse grab,
1495 transfer the grab to the new window. (Grab the server while
1496 so doing, to avoid a race condition.)
1498 if (old_w == si->mouse_grab_window)
1500 XGrabServer (si->dpy); /* ############ DANGER! */
1502 grab_mouse (si, ssi->screensaver_window,
1506 XUngrabServer (si->dpy);
1507 XSync (si->dpy, False); /* ###### (danger over) */
1510 /* If we're destroying the window that holds our keyboard grab,
1511 transfer the grab to the new window. (Grab the server while
1512 so doing, to avoid a race condition.)
1514 if (old_w == si->keyboard_grab_window)
1516 XGrabServer (si->dpy); /* ############ DANGER! */
1518 grab_kbd(si, ssi->screensaver_window);
1519 XUngrabServer (si->dpy);
1520 XSync (si->dpy, False); /* ###### (danger over) */
1523 /* Now we can destroy this window without horking our grabs. */
1525 XDestroyWindow (si->dpy, old_w);
1528 fprintf (stderr, "%s: destroyed old saver window 0x%lx.\n",
1529 blurb(), (unsigned long) old_w);
1532 old_c != DefaultColormapOfScreen (ssi->screen) &&
1533 old_c != ssi->demo_cmap)
1534 XFreeColormap (si->dpy, old_c);