1 /* windows.c --- turning the screen black; dealing with visuals, virtual roots.
2 * xscreensaver, Copyright (c) 1991-1998 Jamie Zawinski <jwz@netscape.com>
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() */
20 # if !defined(HAVE_UNAME) && (__VMS_VER >= 70000000)
22 # endif /* !HAVE_UNAME */
26 # include <sys/utsname.h> /* for uname() */
27 # endif /* HAVE_UNAME */
30 #include <X11/Xproto.h> /* for CARD32 */
32 #include <X11/Xutil.h> /* for XSetClassHint() */
33 #include <X11/Xatom.h>
34 #include <X11/Xos.h> /* for time() */
35 #include <signal.h> /* for the signal names */
37 #ifdef HAVE_MIT_SAVER_EXTENSION
38 # include <X11/extensions/scrnsaver.h>
39 #endif /* HAVE_MIT_SAVER_EXTENSION */
42 #ifdef HAVE_XHPDISABLERESET
43 # include <X11/XHPlib.h>
45 /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
46 or BadAccess errors occur. (Ok for this to be global, since it
47 affects the whole machine, not just the current screen.) */
48 Bool hp_locked_p = False;
50 #endif /* HAVE_XHPDISABLERESET */
53 /* This file doesn't need the Xt headers, so stub these types out... */
55 #define XtAppContext void*
56 #define XrmDatabase void*
57 #define XtIntervalId void*
58 #define XtPointer void*
61 #include "xscreensaver.h"
65 extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
67 Atom XA_VROOT, XA_XSETROOT_ID;
68 Atom XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
69 Atom XA_SCREENSAVER_TIME;
72 extern saver_info *global_si_kludge; /* I hate C so much... */
75 static void store_activate_time (saver_info *si, Bool use_last_p);
77 #define ALL_POINTER_EVENTS \
78 (ButtonPressMask | ButtonReleaseMask | EnterWindowMask | \
79 LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | \
80 Button1MotionMask | Button2MotionMask | Button3MotionMask | \
81 Button4MotionMask | Button5MotionMask | ButtonMotionMask)
85 grab_kbd(saver_info *si, Window w)
87 saver_preferences *p = &si->prefs;
88 int status = XGrabKeyboard (si->dpy, w, True,
89 /* I don't really understand Sync vs Async,
90 but these seem to work... */
91 GrabModeSync, GrabModeAsync,
94 fprintf(real_stderr, "%s: XGrabKeyboard(... 0x%x ...) ==> %s\n",
95 progname, (unsigned long) w,
96 (status == GrabSuccess ? "GrabSuccess" :
97 status == AlreadyGrabbed ? "AlreadyGrabbed" :
98 status == GrabInvalidTime ? "GrabInvalidTime" :
99 status == GrabNotViewable ? "GrabNotViewable" :
100 status == GrabFrozen ? "GrabFrozen" :
107 grab_mouse (saver_info *si, Window w, Cursor cursor)
109 saver_preferences *p = &si->prefs;
110 int status = XGrabPointer (si->dpy, w, True, ALL_POINTER_EVENTS,
111 GrabModeAsync, GrabModeAsync, None,
112 cursor, CurrentTime);
114 fprintf(real_stderr, "%s: XGrabPointer(... 0x%x, 0x%x ...) ==> %s\n",
115 progname, (unsigned long) w, (unsigned long) cursor,
116 (status == GrabSuccess ? "GrabSuccess" :
117 status == AlreadyGrabbed ? "AlreadyGrabbed" :
118 status == GrabInvalidTime ? "GrabInvalidTime" :
119 status == GrabNotViewable ? "GrabNotViewable" :
120 status == GrabFrozen ? "GrabFrozen" :
127 grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor)
130 XSync (si->dpy, False);
132 status = grab_kbd (si, window);
133 if (status != GrabSuccess)
134 { /* try again in a second */
136 status = grab_kbd (si, window);
137 if (status != GrabSuccess)
138 fprintf (stderr, "%s: couldn't grab keyboard! (%d)\n",
141 status = grab_mouse (si, window, cursor);
142 if (status != GrabSuccess)
143 { /* try again in a second */
145 status = grab_mouse (si, window, cursor);
146 if (status != GrabSuccess)
147 fprintf (stderr, "%s: couldn't grab pointer! (%d)\n",
153 ungrab_keyboard_and_mouse (saver_info *si)
155 saver_preferences *p = &si->prefs;
157 XUngrabPointer (si->dpy, CurrentTime);
158 XUngrabKeyboard (si->dpy, CurrentTime);
161 fprintf(real_stderr, "%s: XungrabPointer / XUngrabKeyboard\n", progname);
166 ensure_no_screensaver_running (Display *dpy, Screen *screen)
169 Window root = RootWindowOfScreen (screen);
170 Window root2, parent, *kids;
172 XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler);
174 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
180 for (i = 0; i < nkids; i++)
184 unsigned long nitems, bytesafter;
187 if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
188 False, XA_STRING, &type, &format, &nitems,
189 &bytesafter, (unsigned char **) &version)
194 if (!XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
195 False, XA_STRING, &type, &format, &nitems,
196 &bytesafter, (unsigned char **) &id)
202 "%s: already running on display %s (window 0x%x)\n from process %s.\n",
203 progname, DisplayString (dpy), (int) kids [i], id);
208 if (kids) XFree ((char *) kids);
210 XSetErrorHandler (old_handler);
215 /* Virtual-root hackery */
218 ERROR! You must not include vroot.h in this file.
222 store_vroot_property (Display *dpy, Window win, Window value)
227 "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", progname,
229 (win == screensaver_window ? "ScreenSaver" :
230 (win == real_vroot ? "VRoot" :
231 (win == real_vroot_value ? "Vroot_value" : "???"))),
233 (value == screensaver_window ? "ScreenSaver" :
234 (value == real_vroot ? "VRoot" :
235 (value == real_vroot_value ? "Vroot_value" : "???"))));
237 XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
238 (unsigned char *) &value, 1);
242 remove_vroot_property (Display *dpy, Window win)
246 fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", progname, win,
247 (win == screensaver_window ? "ScreenSaver" :
248 (win == real_vroot ? "VRoot" :
249 (win == real_vroot_value ? "Vroot_value" : "???"))));
251 XDeleteProperty (dpy, win, XA_VROOT);
256 kill_xsetroot_data (Display *dpy, Window window, Bool verbose_p)
260 unsigned long nitems, bytesafter;
263 /* If the user has been using xv or xsetroot as a screensaver (to display
264 an image on the screensaver window, as a kind of slideshow) then the
265 pixmap and its associated color cells have been put in RetainPermanent
266 CloseDown mode. Since we're not destroying the xscreensaver window,
267 but merely unmapping it, we need to free these resources or those
268 colormap cells will stay allocated while the screensaver is off. (We
269 could just delete the screensaver window and recreate it later, but
270 that could cause other problems.) This code does an atomic read-and-
271 delete of the _XSETROOT_ID property, and if it held a pixmap, then we
272 cause the RetainPermanent resources of the client which created it
273 (and which no longer exists) to be freed.
275 if (XGetWindowProperty (dpy, window, XA_XSETROOT_ID, 0, 1,
276 True, AnyPropertyType, &type, &format, &nitems,
277 &bytesafter, (unsigned char **) &dataP)
281 if (dataP && *dataP && type == XA_PIXMAP && format == 32 &&
282 nitems == 1 && bytesafter == 0)
285 printf ("%s: destroying xsetroot data (0x%lX).\n",
287 XKillClient (dpy, *dataP);
290 fprintf (stderr, "%s: deleted unrecognised _XSETROOT_ID property: \n\
291 %lu, %lu; type: %lu, format: %d, nitems: %lu, bytesafter %ld\n",
292 progname, (unsigned long) dataP, (dataP ? *dataP : 0), type,
293 format, nitems, bytesafter);
298 static void handle_signals (saver_info *si, Bool on_p);
301 save_real_vroot (saver_screen_info *ssi)
303 saver_info *si = ssi->global;
304 Display *dpy = si->dpy;
305 Screen *screen = ssi->screen;
307 Window root = RootWindowOfScreen (screen);
308 Window root2, parent, *kids;
312 ssi->real_vroot_value = 0;
313 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
319 for (i = 0; i < nkids; i++)
323 unsigned long nitems, bytesafter;
326 if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
327 &type, &format, &nitems, &bytesafter,
328 (unsigned char **) &vrootP)
335 if (*vrootP == ssi->screensaver_window) abort ();
337 "%s: more than one virtual root window found (0x%x and 0x%x).\n",
338 progname, (int) ssi->real_vroot, (int) kids [i]);
341 ssi->real_vroot = kids [i];
342 ssi->real_vroot_value = *vrootP;
347 handle_signals (si, True);
348 remove_vroot_property (si->dpy, ssi->real_vroot);
352 XFree ((char *) kids);
357 restore_real_vroot_2 (saver_screen_info *ssi)
359 saver_info *si = ssi->global;
360 saver_preferences *p = &si->prefs;
361 if (p->verbose_p && ssi->real_vroot)
362 printf ("%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
363 progname, (unsigned long) ssi->real_vroot);
364 remove_vroot_property (si->dpy, ssi->screensaver_window);
367 store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
369 ssi->real_vroot_value = 0;
370 /* make sure the property change gets there before this process
371 terminates! We might be doing this because we have intercepted
372 SIGTERM or something. */
373 XSync (si->dpy, False);
380 restore_real_vroot_1 (saver_info *si)
383 Bool did_any = False;
384 for (i = 0; i < si->nscreens; i++)
386 saver_screen_info *ssi = &si->screens[i];
387 if (restore_real_vroot_2 (ssi))
394 restore_real_vroot (saver_info *si)
396 if (restore_real_vroot_1 (si))
397 handle_signals (si, False);
401 /* Signal hackery to ensure that the vroot doesn't get left in an
406 signal_name(int signal)
409 case SIGHUP: return "SIGHUP";
410 case SIGINT: return "SIGINT";
411 case SIGQUIT: return "SIGQUIT";
412 case SIGILL: return "SIGILL";
413 case SIGTRAP: return "SIGTRAP";
415 case SIGABRT: return "SIGABRT";
417 case SIGFPE: return "SIGFPE";
418 case SIGKILL: return "SIGKILL";
419 case SIGBUS: return "SIGBUS";
420 case SIGSEGV: return "SIGSEGV";
421 case SIGPIPE: return "SIGPIPE";
422 case SIGALRM: return "SIGALRM";
423 case SIGTERM: return "SIGTERM";
425 case SIGSTOP: return "SIGSTOP";
428 case SIGCONT: return "SIGCONT";
431 case SIGUSR1: return "SIGUSR1";
434 case SIGUSR2: return "SIGUSR2";
437 case SIGEMT: return "SIGEMT";
440 case SIGSYS: return "SIGSYS";
443 case SIGCHLD: return "SIGCHLD";
446 case SIGPWR: return "SIGPWR";
449 case SIGWINCH: return "SIGWINCH";
452 case SIGURG: return "SIGURG";
455 case SIGIO: return "SIGIO";
458 case SIGVTALRM: return "SIGVTALRM";
461 case SIGXCPU: return "SIGXCPU";
464 case SIGXFSZ: return "SIGXFSZ";
467 case SIGDANGER: return "SIGDANGER";
472 sprintf(buf, "signal %d\n", signal);
481 restore_real_vroot_handler (int sig)
483 saver_info *si = global_si_kludge; /* I hate C so much... */
485 signal (sig, SIG_DFL);
486 if (restore_real_vroot_1 (si))
487 fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n",
488 progname, signal_name(sig));
489 kill (getpid (), sig);
493 catch_signal (saver_info *si, int sig, Bool on_p)
496 signal (sig, SIG_DFL);
499 if (((long) signal (sig, restore_real_vroot_handler)) == -1L)
502 sprintf (buf, "%s: couldn't catch %s", progname, signal_name(sig));
510 handle_signals (saver_info *si, Bool on_p)
513 if (on_p) printf ("handling signals\n");
514 else printf ("unhandling signals\n");
517 catch_signal (si, SIGHUP, on_p);
518 catch_signal (si, SIGINT, on_p);
519 catch_signal (si, SIGQUIT, on_p);
520 catch_signal (si, SIGILL, on_p);
521 catch_signal (si, SIGTRAP, on_p);
522 catch_signal (si, SIGIOT, on_p);
523 catch_signal (si, SIGABRT, on_p);
525 catch_signal (si, SIGEMT, on_p);
527 catch_signal (si, SIGFPE, on_p);
528 catch_signal (si, SIGBUS, on_p);
529 catch_signal (si, SIGSEGV, on_p);
531 catch_signal (si, SIGSYS, on_p);
533 catch_signal (si, SIGTERM, on_p);
535 catch_signal (si, SIGXCPU, on_p);
538 catch_signal (si, SIGXFSZ, on_p);
541 catch_signal (si, SIGDANGER, on_p);
546 saver_exit (saver_info *si, int status)
548 saver_preferences *p = &si->prefs;
549 static Bool exiting = False;
557 vrs = restore_real_vroot_1 (si);
558 emergency_kill_subproc (si);
560 if (vrs && (p->verbose_p || status != 0))
561 fprintf (real_stderr, "%s: vroot restored, exiting.\n", progname);
562 else if (p->verbose_p)
563 fprintf (real_stderr, "%s: no vroot to restore; exiting.\n", progname);
567 #ifdef VMS /* on VMS, 1 is the "normal" exit code instead of 0. */
568 if (status == 0) status = 1;
569 else if (status == 1) status = -1;
572 if (si->prefs.debug_p)
574 fprintf(real_stderr, "%s: dumping core (because of -debug)\n", progname);
575 /* Do this to drop a core file, so that we can get a stack trace. */
583 /* Managing the actual screensaver window */
586 window_exists_p (Display *dpy, Window window)
588 XErrorHandler old_handler;
589 XWindowAttributes xgwa;
591 old_handler = XSetErrorHandler (BadWindow_ehandler);
592 XGetWindowAttributes (dpy, window, &xgwa);
594 XSetErrorHandler (old_handler);
595 return (xgwa.screen != 0);
599 initialize_screensaver_window_1 (saver_screen_info *ssi)
601 saver_info *si = ssi->global;
602 saver_preferences *p = &si->prefs;
603 Bool install_cmap_p = ssi->install_cmap_p;
605 /* This resets the screensaver window as fully as possible, since there's
606 no way of knowing what some random client may have done to us in the
607 meantime. We could just destroy and recreate the window, but that has
608 its own set of problems...
611 XClassHint class_hints;
612 XSetWindowAttributes attrs;
613 unsigned long attrmask;
614 int width = WidthOfScreen (ssi->screen);
615 int height = HeightOfScreen (ssi->screen);
617 static Bool printed_visual_info = False; /* only print the message once. */
619 black.red = black.green = black.blue = 0;
621 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
624 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
625 install_cmap_p = True;
631 ssi->cmap = XCreateColormap (si->dpy, RootWindowOfScreen (ssi->screen),
632 ssi->current_visual, AllocNone);
633 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
634 ssi->black_pixel = black.pixel;
639 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
642 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
643 if (ssi->cmap != ssi->demo_cmap &&
644 ssi->cmap != def_cmap)
645 XFreeColormap (si->dpy, ssi->cmap);
647 ssi->cmap = def_cmap;
648 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
651 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
652 CWBackPixel | CWBackingPixel | CWBorderPixel);
653 attrs.override_redirect = True;
655 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
656 actually be reading these events during normal operation; but we still
657 need to see Button events for demo-mode to work properly.
659 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
660 ButtonPressMask | ButtonReleaseMask |
663 attrs.backing_store = NotUseful;
664 attrs.colormap = ssi->cmap;
665 attrs.background_pixel = ssi->black_pixel;
666 attrs.backing_pixel = ssi->black_pixel;
667 attrs.border_pixel = ssi->black_pixel;
669 if (p->debug_p) width = width / 2;
671 if (!p->verbose_p || printed_visual_info)
673 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
675 fprintf (stderr, "%s: using default visual ", progname);
676 describe_visual (stderr, ssi->screen, ssi->current_visual);
680 fprintf (stderr, "%s: using visual: ", progname);
681 describe_visual (stderr, ssi->screen, ssi->current_visual);
682 fprintf (stderr, "%s: default visual: ", progname);
683 describe_visual (stderr, ssi->screen,
684 DefaultVisualOfScreen (ssi->screen));
686 printed_visual_info = True;
688 #ifdef HAVE_MIT_SAVER_EXTENSION
689 if (p->use_mit_saver_extension)
691 XScreenSaverInfo *info;
692 Window root = RootWindowOfScreen (ssi->screen);
695 /* This call sets the server screensaver timeouts to what we think
696 they should be (based on the resources and args xscreensaver was
697 started with.) It's important that we do this to sync back up
698 with the server - if we have turned on prematurely, as by an
699 ACTIVATE ClientMessage, then the server may decide to activate
700 the screensaver while it's already active. That's ok for us,
701 since we would know to ignore that ScreenSaverActivate event,
702 but a side effect of this would be that the server would map its
703 saver window (which we then hide again right away) meaning that
704 the bits currently on the screen get blown away. Ugly. */
706 /* #### Ok, that doesn't work - when we tell the server that the
707 screensaver is "off" it sends us a Deactivate event, which is
708 sensible... but causes the saver to never come on. Hmm. */
709 disable_builtin_screensaver (si, True);
713 /* #### The MIT-SCREEN-SAVER extension gives us access to the
714 window that the server itself uses for saving the screen.
715 However, using this window in any way, in particular, calling
716 XScreenSaverSetAttributes() as below, tends to make the X server
717 crash. So fuck it, let's try and get along without using it...
719 It's also inconvenient to use this window because it doesn't
720 always exist (though the ID is constant.) So to use this
721 window, we'd have to reimplement the ACTIVATE ClientMessage to
722 tell the *server* to tell *us* to turn on, to cause the window
723 to get created at the right time. Gag. */
724 XScreenSaverSetAttributes (si->dpy, root,
725 0, 0, width, height, 0,
726 current_depth, InputOutput, visual,
728 XSync (si->dpy, False);
731 info = XScreenSaverAllocInfo ();
732 XScreenSaverQueryInfo (si->dpy, root, info);
733 ssi->server_mit_saver_window = info->window;
734 if (! ssi->server_mit_saver_window) abort ();
737 #endif /* HAVE_MIT_SAVER_EXTENSION */
739 if (ssi->screensaver_window)
741 XWindowChanges changes;
742 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
745 changes.width = width;
746 changes.height = height;
747 changes.border_width = 0;
749 XConfigureWindow (si->dpy, ssi->screensaver_window,
750 changesmask, &changes);
751 XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
756 ssi->screensaver_window =
757 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen), 0, 0,
758 width, height, 0, ssi->current_depth, InputOutput,
759 ssi->current_visual, attrmask, &attrs);
761 store_activate_time(si, True);
763 fprintf (stderr, "%s: saver window is 0x%lx.\n",
764 progname, (unsigned long) ssi->screensaver_window);
767 #ifdef HAVE_MIT_SAVER_EXTENSION
768 if (!p->use_mit_saver_extension ||
769 window_exists_p (si->dpy, ssi->screensaver_window))
770 /* When using the MIT-SCREEN-SAVER extension, the window pointed to
771 by screensaver_window only exists while the saver is active.
772 So we must be careful to only try and manipulate it while it
774 (#### The above comment would be true if the MIT extension actually
775 worked, but it's not true today -- see `server_mit_saver_window'.)
777 #endif /* HAVE_MIT_SAVER_EXTENSION */
779 class_hints.res_name = progname;
780 class_hints.res_class = progclass;
781 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
782 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
783 XChangeProperty (si->dpy, ssi->screensaver_window,
784 XA_SCREENSAVER_VERSION,
785 XA_STRING, 8, PropModeReplace,
786 (unsigned char *) si->version,
787 strlen (si->version));
789 sprintf (id, "%lu on host ", (unsigned long) getpid ());
791 # if defined(HAVE_UNAME)
794 if (uname (&uts) < 0)
797 strcat (id, uts.nodename);
800 strcat (id, getenv("SYS$NODE"));
801 # else /* !HAVE_UNAME && !VMS */
803 # endif /* !HAVE_UNAME && !VMS */
805 XChangeProperty (si->dpy, ssi->screensaver_window,
806 XA_SCREENSAVER_ID, XA_STRING,
807 8, PropModeReplace, (unsigned char *) id, strlen (id));
812 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
814 BlackPixelOfScreen (ssi->screen),
815 BlackPixelOfScreen (ssi->screen),
817 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
819 XFreePixmap (si->dpy, bit);
822 XSetWindowBackground (si->dpy, ssi->screensaver_window,
825 XUndefineCursor (si->dpy, ssi->screensaver_window);
827 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
832 initialize_screensaver_window (saver_info *si)
835 for (i = 0; i < si->nscreens; i++)
836 initialize_screensaver_window_1 (&si->screens[i]);
841 raise_window (saver_info *si,
842 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
844 saver_preferences *p = &si->prefs;
847 initialize_screensaver_window (si);
848 reset_watchdog_timer (si, True);
850 if (p->fade_p && !inhibit_fade && !si->demo_mode_p)
853 Window *current_windows = (Window *)
854 calloc(sizeof(Window), si->nscreens);
855 Colormap *current_maps = (Colormap *)
856 calloc(sizeof(Colormap), si->nscreens);
858 for (i = 0; i < si->nscreens; i++)
860 saver_screen_info *ssi = &si->screens[i];
861 current_windows[i] = ssi->screensaver_window;
862 current_maps[i] = (between_hacks_p
864 : DefaultColormapOfScreen (ssi->screen));
865 /* Ensure that the default background of the window is really black,
866 not a pixmap or something. (This does not clear the window.) */
867 XSetWindowBackground (si->dpy, ssi->screensaver_window,
871 if (p->verbose_p) fprintf (stderr, "%s: fading... ", progname);
873 XGrabServer (si->dpy);
875 for (i = 0; i < si->nscreens; i++)
877 saver_screen_info *ssi = &si->screens[i];
879 /* grab and blacken mouse on the root window (saver not mapped yet)
881 if (grabbed != GrabSuccess)
882 grabbed = grab_mouse (si, ssi->screensaver_window,
883 (si->demo_mode_p ? 0 : ssi->cursor));
885 if (!dont_clear || ssi->stderr_overlay_window)
886 /* Do this before the fade, since the stderr cmap won't fade
887 even if we uninstall it (beats me...) */
891 fade_screens (si->dpy, current_maps, current_windows,
892 p->fade_seconds, p->fade_ticks, True, !dont_clear);
894 free(current_windows);
898 if (p->verbose_p) fprintf (stderr, "fading done.\n");
900 #ifdef HAVE_MIT_SAVER_EXTENSION
901 for (i = 0; i < si->nscreens; i++)
903 saver_screen_info *ssi = &si->screens[i];
904 if (ssi->server_mit_saver_window &&
905 window_exists_p (si->dpy, ssi->server_mit_saver_window))
906 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
908 #endif /* HAVE_MIT_SAVER_EXTENSION */
910 if (grabbed == GrabSuccess)
911 XUngrabPointer (si->dpy, CurrentTime);
912 XUngrabServer (si->dpy);
916 for (i = 0; i < si->nscreens; i++)
918 saver_screen_info *ssi = &si->screens[i];
920 XClearWindow (si->dpy, ssi->screensaver_window);
921 if (!dont_clear || ssi->stderr_overlay_window)
923 XMapRaised (si->dpy, ssi->screensaver_window);
924 #ifdef HAVE_MIT_SAVER_EXTENSION
925 if (ssi->server_mit_saver_window &&
926 window_exists_p (si->dpy, ssi->server_mit_saver_window))
927 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
928 #endif /* HAVE_MIT_SAVER_EXTENSION */
932 for (i = 0; i < si->nscreens; i++)
934 saver_screen_info *ssi = &si->screens[i];
936 XInstallColormap (si->dpy, ssi->cmap);
941 blank_screen (saver_info *si)
944 for (i = 0; i < si->nscreens; i++)
946 saver_screen_info *ssi = &si->screens[i];
948 save_real_vroot (ssi);
949 store_vroot_property (si->dpy,
950 ssi->screensaver_window,
951 ssi->screensaver_window);
953 store_activate_time (si, si->screen_blanked_p);
954 raise_window (si, False, False, False);
956 grab_keyboard_and_mouse (si, si->screens[0].screensaver_window,
957 (si->demo_mode_p ? 0 : si->screens[0].cursor));
958 #ifdef HAVE_XHPDISABLERESET
959 if (si->locked_p && !hp_locked_p)
961 XHPDisableReset (si->dpy); /* turn off C-Sh-Reset */
966 si->screen_blanked_p = True;
970 unblank_screen (saver_info *si)
972 saver_preferences *p = &si->prefs;
975 store_activate_time (si, True);
976 reset_watchdog_timer (si, False);
978 if (p->unfade_p && !si->demo_mode_p)
981 Window *current_windows = (Window *)
982 calloc(sizeof(Window), si->nscreens);
984 for (i = 0; i < si->nscreens; i++)
986 saver_screen_info *ssi = &si->screens[i];
987 current_windows[i] = ssi->screensaver_window;
988 /* Ensure that the default background of the window is really black,
989 not a pixmap or something. (This does not clear the window.) */
990 XSetWindowBackground (si->dpy, ssi->screensaver_window,
994 if (p->verbose_p) fprintf (stderr, "%s: unfading... ", progname);
997 XSync (si->dpy, False);
998 XGrabServer (si->dpy); /* ############ DANGER! */
999 XSync (si->dpy, False);
1001 for (i = 0; i < si->nscreens; i++)
1003 saver_screen_info *ssi = &si->screens[i];
1004 if (grabbed != GrabSuccess)
1005 grabbed = grab_mouse (si, RootWindowOfScreen (ssi->screen),
1010 XUngrabServer (si->dpy);
1011 XSync (si->dpy, False); /* ###### (danger over) */
1014 fade_screens (si->dpy, 0, current_windows,
1015 p->fade_seconds, p->fade_ticks,
1018 free(current_windows);
1019 current_windows = 0;
1021 if (p->verbose_p) fprintf (stderr, "unfading done.\n");
1022 if (grabbed == GrabSuccess)
1023 XUngrabPointer (si->dpy, CurrentTime);
1027 for (i = 0; i < si->nscreens; i++)
1029 saver_screen_info *ssi = &si->screens[i];
1032 Colormap c = DefaultColormapOfScreen (ssi->screen);
1033 /* avoid technicolor */
1034 XClearWindow (si->dpy, ssi->screensaver_window);
1035 if (c) XInstallColormap (si->dpy, c);
1037 XUnmapWindow (si->dpy, ssi->screensaver_window);
1042 /* If the focus window does has a non-default colormap, then install
1043 that colormap as well. (On SGIs, this will cause both the root map
1044 and the focus map to be installed simultaniously. It'd be nice to
1045 pick up the other colormaps that had been installed, too; perhaps
1046 XListInstalledColormaps could be used for that?)
1051 XGetInputFocus (si->dpy, &focus, &revert_to);
1052 if (focus && focus != PointerRoot && focus != None)
1054 XWindowAttributes xgwa;
1056 XGetWindowAttributes (si->dpy, focus, &xgwa);
1057 if (xgwa.colormap &&
1058 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1059 XInstallColormap (si->dpy, xgwa.colormap);
1064 for (i = 0; i < si->nscreens; i++)
1066 saver_screen_info *ssi = &si->screens[i];
1067 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
1070 store_activate_time(si, False); /* store unblank time */
1072 ungrab_keyboard_and_mouse (si);
1073 restore_real_vroot (si);
1075 #ifdef HAVE_XHPDISABLERESET
1078 XHPEnableReset (si->dpy); /* turn C-Sh-Reset back on */
1079 hp_locked_p = False;
1083 /* Unmap the windows a second time, dammit -- just to avoid a race
1084 with the screen-grabbing hacks. (I'm not sure if this is really
1085 necessary; I'm stabbing in the dark now.)
1087 for (i = 0; i < si->nscreens; i++)
1088 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
1090 si->screen_blanked_p = False;
1095 store_activate_time (saver_info *si, Bool use_last_p)
1097 static time_t last_time = 0;
1098 time_t now = ((use_last_p && last_time) ? last_time : time ((time_t) 0));
1099 CARD32 now32 = (CARD32) now;
1103 for (i = 0; i < si->nscreens; i++)
1105 saver_screen_info *ssi = &si->screens[i];
1106 if (!ssi->screensaver_window) continue;
1107 XChangeProperty (si->dpy, ssi->screensaver_window, XA_SCREENSAVER_TIME,
1108 XA_INTEGER, 32, PropModeReplace,
1109 (unsigned char *) &now32, 1);
1115 select_visual (saver_screen_info *ssi, const char *visual_name)
1117 saver_info *si = ssi->global;
1118 saver_preferences *p = &si->prefs;
1119 Bool install_cmap_p = p->install_cmap_p;
1120 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
1124 if (visual_name && *visual_name)
1126 if (!strcmp(visual_name, "default-i"))
1128 visual_name = "default";
1129 install_cmap_p = True;
1131 else if (!strcmp(visual_name, "default-n"))
1133 visual_name = "default";
1134 install_cmap_p = False;
1136 new_v = get_visual (ssi->screen, visual_name, True, False);
1140 new_v = ssi->default_visual;
1145 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
1146 install_cmap_p = True;
1148 ssi->install_cmap_p = install_cmap_p;
1151 ((ssi->current_visual != new_v) ||
1152 (install_cmap_p != was_installed_p)))
1154 Colormap old_c = ssi->cmap;
1155 Window old_w = ssi->screensaver_window;
1160 fprintf (stderr, "%s: switching visuals\tfrom: ", progname);
1161 describe_visual (stderr, ssi->screen, ssi->current_visual);
1162 fprintf (stderr, "\t\t\t\tto: ");
1163 describe_visual (stderr, ssi->screen, new_v);
1164 fprintf (stderr, "\t\t\t\t install cmap: %s\n",
1165 (install_cmap_p ? "yes" : "no"));
1167 fprintf (stderr, "%s: switching to visual ", progname);
1168 describe_visual (stderr, ssi->screen, new_v);
1173 ssi->current_visual = new_v;
1174 ssi->current_depth = visual_depth(ssi->screen, new_v);
1176 ssi->screensaver_window = 0;
1178 initialize_screensaver_window_1 (ssi);
1179 raise_window (si, True, True, False);
1180 store_vroot_property (si->dpy,
1181 ssi->screensaver_window, ssi->screensaver_window);
1182 store_activate_time (si, True);
1184 XDestroyWindow (si->dpy, old_w);
1186 old_c != DefaultColormapOfScreen (ssi->screen) &&
1187 old_c != ssi->demo_cmap)
1188 XFreeColormap (si->dpy, old_c);