1 /* windows.c --- turning the screen black; dealing with visuals, virtual roots.
2 * xscreensaver, Copyright (c) 1991-1997 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)
83 /* I don't really understand Sync vs Async, but these seem to work... */
84 #define grab_kbd(dpy,win) \
85 XGrabKeyboard ((dpy), (win), True, GrabModeSync, GrabModeAsync, CurrentTime)
86 #define grab_mouse(dpy,win,cursor) \
87 XGrabPointer ((dpy), (win), True, ALL_POINTER_EVENTS, \
88 GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime)
91 grab_keyboard_and_mouse (Display *dpy, Window window, Cursor cursor)
96 status = grab_kbd (dpy, window);
97 if (status != GrabSuccess)
98 { /* try again in a second */
100 status = grab_kbd (dpy, window);
101 if (status != GrabSuccess)
102 fprintf (stderr, "%s: couldn't grab keyboard! (%d)\n",
105 status = grab_mouse (dpy, window, cursor);
106 if (status != GrabSuccess)
107 { /* try again in a second */
109 status = grab_mouse (dpy, window, cursor);
110 if (status != GrabSuccess)
111 fprintf (stderr, "%s: couldn't grab pointer! (%d)\n",
117 ungrab_keyboard_and_mouse (Display *dpy)
119 XUngrabPointer (dpy, CurrentTime);
120 XUngrabKeyboard (dpy, CurrentTime);
125 ensure_no_screensaver_running (Display *dpy, Screen *screen)
128 Window root = RootWindowOfScreen (screen);
129 Window root2, parent, *kids;
131 XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler);
133 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
139 for (i = 0; i < nkids; i++)
143 unsigned long nitems, bytesafter;
146 if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
147 False, XA_STRING, &type, &format, &nitems,
148 &bytesafter, (unsigned char **) &version)
153 if (!XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
154 False, XA_STRING, &type, &format, &nitems,
155 &bytesafter, (unsigned char **) &id)
161 "%s: already running on display %s (window 0x%x)\n from process %s.\n",
162 progname, DisplayString (dpy), (int) kids [i], id);
167 if (kids) XFree ((char *) kids);
169 XSetErrorHandler (old_handler);
174 /* Virtual-root hackery */
177 ERROR! You must not include vroot.h in this file.
181 store_vroot_property (Display *dpy, Window win, Window value)
186 "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", progname,
188 (win == screensaver_window ? "ScreenSaver" :
189 (win == real_vroot ? "VRoot" :
190 (win == real_vroot_value ? "Vroot_value" : "???"))),
192 (value == screensaver_window ? "ScreenSaver" :
193 (value == real_vroot ? "VRoot" :
194 (value == real_vroot_value ? "Vroot_value" : "???"))));
196 XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
197 (unsigned char *) &value, 1);
201 remove_vroot_property (Display *dpy, Window win)
205 fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", progname, win,
206 (win == screensaver_window ? "ScreenSaver" :
207 (win == real_vroot ? "VRoot" :
208 (win == real_vroot_value ? "Vroot_value" : "???"))));
210 XDeleteProperty (dpy, win, XA_VROOT);
215 kill_xsetroot_data (Display *dpy, Window window, Bool verbose_p)
219 unsigned long nitems, bytesafter;
222 /* If the user has been using xv or xsetroot as a screensaver (to display
223 an image on the screensaver window, as a kind of slideshow) then the
224 pixmap and its associated color cells have been put in RetainPermanent
225 CloseDown mode. Since we're not destroying the xscreensaver window,
226 but merely unmapping it, we need to free these resources or those
227 colormap cells will stay allocated while the screensaver is off. (We
228 could just delete the screensaver window and recreate it later, but
229 that could cause other problems.) This code does an atomic read-and-
230 delete of the _XSETROOT_ID property, and if it held a pixmap, then we
231 cause the RetainPermanent resources of the client which created it
232 (and which no longer exists) to be freed.
234 if (XGetWindowProperty (dpy, window, XA_XSETROOT_ID, 0, 1,
235 True, AnyPropertyType, &type, &format, &nitems,
236 &bytesafter, (unsigned char **) &dataP)
240 if (dataP && *dataP && type == XA_PIXMAP && format == 32 &&
241 nitems == 1 && bytesafter == 0)
244 printf ("%s: destroying xsetroot data (0x%lX).\n",
246 XKillClient (dpy, *dataP);
249 fprintf (stderr, "%s: deleted unrecognised _XSETROOT_ID property: \n\
250 %lu, %lu; type: %lu, format: %d, nitems: %lu, bytesafter %ld\n",
251 progname, (unsigned long) dataP, (dataP ? *dataP : 0), type,
252 format, nitems, bytesafter);
257 static void handle_signals (saver_info *si, Bool on_p);
260 save_real_vroot (saver_screen_info *ssi)
262 saver_info *si = ssi->global;
263 Display *dpy = si->dpy;
264 Screen *screen = ssi->screen;
266 Window root = RootWindowOfScreen (screen);
267 Window root2, parent, *kids;
271 ssi->real_vroot_value = 0;
272 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
278 for (i = 0; i < nkids; i++)
282 unsigned long nitems, bytesafter;
285 if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
286 &type, &format, &nitems, &bytesafter,
287 (unsigned char **) &vrootP)
294 if (*vrootP == ssi->screensaver_window) abort ();
296 "%s: more than one virtual root window found (0x%x and 0x%x).\n",
297 progname, (int) ssi->real_vroot, (int) kids [i]);
300 ssi->real_vroot = kids [i];
301 ssi->real_vroot_value = *vrootP;
306 handle_signals (si, True);
307 remove_vroot_property (si->dpy, ssi->real_vroot);
311 XFree ((char *) kids);
316 restore_real_vroot_2 (saver_screen_info *ssi)
318 saver_info *si = ssi->global;
319 saver_preferences *p = &si->prefs;
320 if (p->verbose_p && ssi->real_vroot)
321 printf ("%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
322 progname, (unsigned long) ssi->real_vroot);
323 remove_vroot_property (si->dpy, ssi->screensaver_window);
326 store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
328 ssi->real_vroot_value = 0;
329 /* make sure the property change gets there before this process
330 terminates! We might be doing this because we have intercepted
331 SIGTERM or something. */
332 XSync (si->dpy, False);
339 restore_real_vroot_1 (saver_info *si)
342 Bool did_any = False;
343 for (i = 0; i < si->nscreens; i++)
345 saver_screen_info *ssi = &si->screens[i];
346 if (restore_real_vroot_2 (ssi))
353 restore_real_vroot (saver_info *si)
355 if (restore_real_vroot_1 (si))
356 handle_signals (si, False);
360 /* Signal hackery to ensure that the vroot doesn't get left in an
365 signal_name(int signal)
368 case SIGHUP: return "SIGHUP";
369 case SIGINT: return "SIGINT";
370 case SIGQUIT: return "SIGQUIT";
371 case SIGILL: return "SIGILL";
372 case SIGTRAP: return "SIGTRAP";
374 case SIGABRT: return "SIGABRT";
376 case SIGFPE: return "SIGFPE";
377 case SIGKILL: return "SIGKILL";
378 case SIGBUS: return "SIGBUS";
379 case SIGSEGV: return "SIGSEGV";
380 case SIGPIPE: return "SIGPIPE";
381 case SIGALRM: return "SIGALRM";
382 case SIGTERM: return "SIGTERM";
384 case SIGSTOP: return "SIGSTOP";
387 case SIGCONT: return "SIGCONT";
390 case SIGUSR1: return "SIGUSR1";
393 case SIGUSR2: return "SIGUSR2";
396 case SIGEMT: return "SIGEMT";
399 case SIGSYS: return "SIGSYS";
402 case SIGCHLD: return "SIGCHLD";
405 case SIGPWR: return "SIGPWR";
408 case SIGWINCH: return "SIGWINCH";
411 case SIGURG: return "SIGURG";
414 case SIGIO: return "SIGIO";
417 case SIGVTALRM: return "SIGVTALRM";
420 case SIGXCPU: return "SIGXCPU";
423 case SIGXFSZ: return "SIGXFSZ";
426 case SIGDANGER: return "SIGDANGER";
431 sprintf(buf, "signal %d\n", signal);
440 restore_real_vroot_handler (int sig)
442 saver_info *si = global_si_kludge; /* I hate C so much... */
444 signal (sig, SIG_DFL);
445 if (restore_real_vroot_1 (si))
446 fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n",
447 progname, signal_name(sig));
448 kill (getpid (), sig);
452 catch_signal (saver_info *si, int sig, Bool on_p)
455 signal (sig, SIG_DFL);
458 if (((long) signal (sig, restore_real_vroot_handler)) == -1L)
461 sprintf (buf, "%s: couldn't catch %s", progname, signal_name(sig));
469 handle_signals (saver_info *si, Bool on_p)
472 if (on_p) printf ("handling signals\n");
473 else printf ("unhandling signals\n");
476 catch_signal (si, SIGHUP, on_p);
477 catch_signal (si, SIGINT, on_p);
478 catch_signal (si, SIGQUIT, on_p);
479 catch_signal (si, SIGILL, on_p);
480 catch_signal (si, SIGTRAP, on_p);
481 catch_signal (si, SIGIOT, on_p);
482 catch_signal (si, SIGABRT, on_p);
484 catch_signal (si, SIGEMT, on_p);
486 catch_signal (si, SIGFPE, on_p);
487 catch_signal (si, SIGBUS, on_p);
488 catch_signal (si, SIGSEGV, on_p);
490 catch_signal (si, SIGSYS, on_p);
492 catch_signal (si, SIGTERM, on_p);
494 catch_signal (si, SIGXCPU, on_p);
497 catch_signal (si, SIGXFSZ, on_p);
500 catch_signal (si, SIGDANGER, on_p);
505 saver_exit (saver_info *si, int status)
507 saver_preferences *p = &si->prefs;
508 static Bool exiting = False;
516 vrs = restore_real_vroot_1 (si);
517 emergency_kill_subproc (si);
519 if (vrs && (p->verbose_p || status != 0))
520 fprintf (real_stderr, "%s: vroot restored, exiting.\n", progname);
521 else if (p->verbose_p)
522 fprintf (real_stderr, "%s: no vroot to restore; exiting.\n", progname);
526 #ifdef VMS /* on VMS, 1 is the "normal" exit code instead of 0. */
527 if (status == 0) status = 1;
528 else if (status == 1) status = -1;
532 if (si->prefs.debug_p)
533 /* Do this to drop a core file, so that we can get a stack trace. */
541 /* Managing the actual screensaver window */
544 window_exists_p (Display *dpy, Window window)
546 XErrorHandler old_handler;
547 XWindowAttributes xgwa;
549 old_handler = XSetErrorHandler (BadWindow_ehandler);
550 XGetWindowAttributes (dpy, window, &xgwa);
552 XSetErrorHandler (old_handler);
553 return (xgwa.screen != 0);
557 initialize_screensaver_window_1 (saver_screen_info *ssi)
559 saver_info *si = ssi->global;
560 saver_preferences *p = &si->prefs;
562 /* This resets the screensaver window as fully as possible, since there's
563 no way of knowing what some random client may have done to us in the
564 meantime. We could just destroy and recreate the window, but that has
565 its own set of problems...
568 XClassHint class_hints;
569 XSetWindowAttributes attrs;
570 unsigned long attrmask;
571 int width = WidthOfScreen (ssi->screen);
572 int height = HeightOfScreen (ssi->screen);
574 static Bool printed_visual_info = False; /* only print the message once. */
576 black.red = black.green = black.blue = 0;
578 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
581 if (p->install_cmap_p ||
582 ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
586 ssi->cmap = XCreateColormap (si->dpy, RootWindowOfScreen (ssi->screen),
587 ssi->current_visual, AllocNone);
588 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
589 ssi->black_pixel = black.pixel;
596 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
597 if (ssi->cmap != ssi->demo_cmap)
598 XFreeColormap (si->dpy, ssi->cmap);
600 ssi->cmap = DefaultColormapOfScreen (ssi->screen);
601 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
607 XFreeColormap (si->dpy, cmap2);
613 cmap2 = copy_colormap (si->screen, ssi->current_visual, ssi->cmap, 0);
615 p->fade_p = p->unfade_p = 0;
619 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
620 CWBackPixel | CWBackingPixel | CWBorderPixel);
621 attrs.override_redirect = True;
623 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
624 actually be reading these events during normal operation; but we still
625 need to see Button events for demo-mode to work properly.
627 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
628 ButtonPressMask | ButtonReleaseMask |
631 attrs.backing_store = NotUseful;
632 attrs.colormap = ssi->cmap;
633 attrs.background_pixel = ssi->black_pixel;
634 attrs.backing_pixel = ssi->black_pixel;
635 attrs.border_pixel = ssi->black_pixel;
638 if (p->debug_p) width = width / 2;
641 if (!p->verbose_p || printed_visual_info)
643 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
645 fprintf (stderr, "%s: using default visual ", progname);
646 describe_visual (stderr, ssi->screen, ssi->current_visual);
650 fprintf (stderr, "%s: using visual: ", progname);
651 describe_visual (stderr, ssi->screen, ssi->current_visual);
652 fprintf (stderr, "%s: default visual: ", progname);
653 describe_visual (stderr, ssi->screen,
654 DefaultVisualOfScreen (ssi->screen));
656 printed_visual_info = True;
658 #ifdef HAVE_MIT_SAVER_EXTENSION
659 if (p->use_mit_saver_extension)
661 XScreenSaverInfo *info;
662 Window root = RootWindowOfScreen (ssi->screen);
665 /* This call sets the server screensaver timeouts to what we think
666 they should be (based on the resources and args xscreensaver was
667 started with.) It's important that we do this to sync back up
668 with the server - if we have turned on prematurely, as by an
669 ACTIVATE ClientMessage, then the server may decide to activate
670 the screensaver while it's already active. That's ok for us,
671 since we would know to ignore that ScreenSaverActivate event,
672 but a side effect of this would be that the server would map its
673 saver window (which we then hide again right away) meaning that
674 the bits currently on the screen get blown away. Ugly. */
676 /* #### Ok, that doesn't work - when we tell the server that the
677 screensaver is "off" it sends us a Deactivate event, which is
678 sensible... but causes the saver to never come on. Hmm. */
679 disable_builtin_screensaver (si, True);
683 /* #### The MIT-SCREEN-SAVER extension gives us access to the
684 window that the server itself uses for saving the screen.
685 However, using this window in any way, in particular, calling
686 XScreenSaverSetAttributes() as below, tends to make the X server
687 crash. So fuck it, let's try and get along without using it...
689 It's also inconvenient to use this window because it doesn't
690 always exist (though the ID is constant.) So to use this
691 window, we'd have to reimplement the ACTIVATE ClientMessage to
692 tell the *server* to tell *us* to turn on, to cause the window
693 to get created at the right time. Gag. */
694 XScreenSaverSetAttributes (si->dpy, root,
695 0, 0, width, height, 0,
696 current_depth, InputOutput, visual,
698 XSync (si->dpy, False);
701 info = XScreenSaverAllocInfo ();
702 XScreenSaverQueryInfo (si->dpy, root, info);
703 ssi->server_mit_saver_window = info->window;
704 if (! ssi->server_mit_saver_window) abort ();
707 #endif /* HAVE_MIT_SAVER_EXTENSION */
709 if (ssi->screensaver_window)
711 XWindowChanges changes;
712 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
715 changes.width = width;
716 changes.height = height;
717 changes.border_width = 0;
719 XConfigureWindow (si->dpy, ssi->screensaver_window,
720 changesmask, &changes);
721 XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
726 ssi->screensaver_window =
727 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen), 0, 0,
728 width, height, 0, ssi->current_depth, InputOutput,
729 ssi->current_visual, attrmask, &attrs);
731 store_activate_time(si, True);
733 fprintf (stderr, "%s: saver window is 0x%lx.\n",
734 progname, (unsigned long) ssi->screensaver_window);
737 #ifdef HAVE_MIT_SAVER_EXTENSION
738 if (!p->use_mit_saver_extension ||
739 window_exists_p (si->dpy, ssi->screensaver_window))
740 /* When using the MIT-SCREEN-SAVER extension, the window pointed to
741 by screensaver_window only exists while the saver is active.
742 So we must be careful to only try and manipulate it while it
744 (#### The above comment would be true if the MIT extension actually
745 worked, but it's not true today -- see `server_mit_saver_window'.)
747 #endif /* HAVE_MIT_SAVER_EXTENSION */
749 class_hints.res_name = progname;
750 class_hints.res_class = progclass;
751 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
752 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
753 XChangeProperty (si->dpy, ssi->screensaver_window,
754 XA_SCREENSAVER_VERSION,
755 XA_STRING, 8, PropModeReplace,
756 (unsigned char *) si->version,
757 strlen (si->version));
759 sprintf (id, "%lu on host ", (unsigned long) getpid ());
761 # if defined(HAVE_UNAME)
764 if (uname (&uts) < 0)
767 strcat (id, uts.nodename);
770 strcat (id, getenv("SYS$NODE"));
771 # else /* !HAVE_UNAME && !VMS */
773 # endif /* !HAVE_UNAME && !VMS */
775 XChangeProperty (si->dpy, ssi->screensaver_window,
776 XA_SCREENSAVER_ID, XA_STRING,
777 8, PropModeReplace, (unsigned char *) id, strlen (id));
782 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
784 BlackPixelOfScreen (ssi->screen),
785 BlackPixelOfScreen (ssi->screen),
787 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
789 XFreePixmap (si->dpy, bit);
792 XSetWindowBackground (si->dpy, ssi->screensaver_window,
795 XUndefineCursor (si->dpy, ssi->screensaver_window);
797 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
802 initialize_screensaver_window (saver_info *si)
805 for (i = 0; i < si->nscreens; i++)
806 initialize_screensaver_window_1 (&si->screens[i]);
811 raise_window (saver_info *si,
812 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
814 saver_preferences *p = &si->prefs;
817 initialize_screensaver_window (si);
818 reset_watchdog_timer (si, True);
820 if (p->fade_p && !inhibit_fade && !si->demo_mode_p)
823 Colormap *current_maps = (Colormap *)
824 calloc(sizeof(Colormap), si->nscreens);
826 for (i = 0; i < si->nscreens; i++)
828 saver_screen_info *ssi = &si->screens[i];
829 current_maps[i] = (between_hacks_p
831 : DefaultColormapOfScreen (ssi->screen));
834 if (p->verbose_p) fprintf (stderr, "%s: fading... ", progname);
836 XGrabServer (si->dpy);
838 for (i = 0; i < si->nscreens; i++)
840 saver_screen_info *ssi = &si->screens[i];
842 /* grab and blacken mouse on the root window (saver not mapped yet)
844 if (grabbed != GrabSuccess)
845 grabbed = grab_mouse (si->dpy, ssi->screensaver_window,
846 (si->demo_mode_p ? 0 : ssi->cursor));
848 if (!dont_clear || ssi->stderr_overlay_window)
849 /* Do this before the fade, since the stderr cmap won't fade
850 even if we uninstall it (beats me...) */
854 fade_screens (si->dpy, current_maps, p->fade_seconds, p->fade_ticks,
857 if (p->verbose_p) fprintf (stderr, "fading done.\n");
859 for (i = 0; i < si->nscreens; i++)
861 saver_screen_info *ssi = &si->screens[i];
863 XClearWindow (si->dpy, ssi->screensaver_window);
864 XMapRaised (si->dpy, ssi->screensaver_window);
866 #ifdef HAVE_MIT_SAVER_EXTENSION
867 if (ssi->server_mit_saver_window &&
868 window_exists_p (si->dpy, ssi->server_mit_saver_window))
869 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
870 #endif /* HAVE_MIT_SAVER_EXTENSION */
872 /* Once the saver window is up, restore the colormap.
873 (The "black" pixels of the two colormaps are compatible.) */
875 XInstallColormap (si->dpy, ssi->cmap);
878 if (grabbed == GrabSuccess)
879 XUngrabPointer (si->dpy, CurrentTime);
880 XUngrabServer (si->dpy);
884 for (i = 0; i < si->nscreens; i++)
886 saver_screen_info *ssi = &si->screens[i];
888 XClearWindow (si->dpy, ssi->screensaver_window);
889 if (!dont_clear || ssi->stderr_overlay_window)
891 XMapRaised (si->dpy, ssi->screensaver_window);
892 #ifdef HAVE_MIT_SAVER_EXTENSION
893 if (ssi->server_mit_saver_window &&
894 window_exists_p (si->dpy, ssi->server_mit_saver_window))
895 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
896 #endif /* HAVE_MIT_SAVER_EXTENSION */
900 for (i = 0; i < si->nscreens; i++)
902 saver_screen_info *ssi = &si->screens[i];
904 XInstallColormap (si->dpy, ssi->cmap);
909 blank_screen (saver_info *si)
912 for (i = 0; i < si->nscreens; i++)
914 saver_screen_info *ssi = &si->screens[i];
916 save_real_vroot (ssi);
917 store_vroot_property (si->dpy,
918 ssi->screensaver_window,
919 ssi->screensaver_window);
921 store_activate_time (si, True);
922 raise_window (si, False, False, False);
924 grab_keyboard_and_mouse (si->dpy, si->screens[0].screensaver_window,
925 (si->demo_mode_p ? 0 : si->screens[0].cursor));
926 #ifdef HAVE_XHPDISABLERESET
927 if (si->locked_p && !hp_locked_p)
929 XHPDisableReset (si->dpy); /* turn off C-Sh-Reset */
934 si->screen_blanked_p = True;
938 unblank_screen (saver_info *si)
940 saver_preferences *p = &si->prefs;
943 store_activate_time (si, True);
944 reset_watchdog_timer (si, False);
946 if (p->unfade_p && !si->demo_mode_p)
950 int ncmaps = si->nscreens * (extra_cmaps + 1);
951 Colormap *cmaps = (Colormap *) calloc(sizeof(Colormap), ncmaps);
953 if (p->verbose_p) fprintf (stderr, "%s: unfading... ", progname);
955 /* Fake out SGI's multi-colormap hardware; see utils/fade.c
956 for an explanation. */
957 for (i = 0; i < ncmaps; i += (extra_cmaps + 1))
958 for (j = 0; j < (extra_cmaps + 1); j++)
960 cmaps[i+j] = XCreateColormap (si->dpy,
961 RootWindow (si->dpy, i),
962 DefaultVisual(si->dpy, i),
966 blacken_colormap (ScreenOfDisplay(si->dpy, i), cmaps[i+j]);
967 XInstallColormap (si->dpy, cmaps[i+j]);
971 XGrabServer (si->dpy);
972 for (i = 0; i < si->nscreens; i++)
974 saver_screen_info *ssi = &si->screens[i];
975 if (grabbed != GrabSuccess)
976 grabbed = grab_mouse (si->dpy, RootWindowOfScreen (ssi->screen),
978 XUnmapWindow (si->dpy, ssi->screensaver_window);
981 XUngrabServer (si->dpy);
983 fade_screens (si->dpy, 0, p->fade_seconds, p->fade_ticks, False);
985 for (i = 0; i < ncmaps; i++)
986 if (cmaps[i]) XFreeColormap (si->dpy, cmaps[i]);
989 if (p->verbose_p) fprintf (stderr, "unfading done.\n");
990 if (grabbed == GrabSuccess)
991 XUngrabPointer (si->dpy, CurrentTime);
995 for (i = 0; i < si->nscreens; i++)
997 saver_screen_info *ssi = &si->screens[i];
1000 Colormap c = DefaultColormapOfScreen (ssi->screen);
1001 /* avoid technicolor */
1002 XClearWindow (si->dpy, ssi->screensaver_window);
1003 if (c) XInstallColormap (si->dpy, c);
1005 XUnmapWindow (si->dpy, ssi->screensaver_window);
1010 /* If the focus window does has a non-default colormap, then install
1011 that colormap as well. (On SGIs, this will cause both the root map
1012 and the focus map to be installed simultaniously. It'd be nice to
1013 pick up the other colormaps that had been installed, too; perhaps
1014 XListInstalledColormaps could be used for that?)
1019 XGetInputFocus (si->dpy, &focus, &revert_to);
1020 if (focus && focus != PointerRoot && focus != None)
1022 XWindowAttributes xgwa;
1024 XGetWindowAttributes (si->dpy, focus, &xgwa);
1025 if (xgwa.colormap &&
1026 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1027 XInstallColormap (si->dpy, xgwa.colormap);
1032 for (i = 0; i < si->nscreens; i++)
1034 saver_screen_info *ssi = &si->screens[i];
1035 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
1038 ungrab_keyboard_and_mouse (si->dpy);
1039 restore_real_vroot (si);
1041 #ifdef HAVE_XHPDISABLERESET
1044 XHPEnableReset (si->dpy); /* turn C-Sh-Reset back on */
1045 hp_locked_p = False;
1049 si->screen_blanked_p = False;
1054 store_activate_time (saver_info *si, Bool use_last_p)
1056 static time_t last_time = 0;
1057 time_t now = ((use_last_p && last_time) ? last_time : time ((time_t) 0));
1058 CARD32 now32 = (CARD32) now;
1062 for (i = 0; i < si->nscreens; i++)
1064 saver_screen_info *ssi = &si->screens[i];
1065 if (!ssi->screensaver_window) continue;
1066 XChangeProperty (si->dpy, ssi->screensaver_window, XA_SCREENSAVER_TIME,
1067 XA_INTEGER, 32, PropModeReplace,
1068 (unsigned char *) &now32, 1);
1074 select_visual (saver_screen_info *ssi, const char *visual_name)
1076 saver_info *si = ssi->global;
1077 saver_preferences *p = &si->prefs;
1081 if (visual_name && *visual_name)
1082 new_v = get_visual (ssi->screen, visual_name, True, False);
1084 new_v = ssi->default_visual;
1088 if (new_v && ssi->current_visual != new_v)
1090 Colormap old_c = ssi->cmap;
1091 Window old_w = ssi->screensaver_window;
1096 fprintf (stderr, "%s: switching visuals\tfrom: ", progname);
1097 describe_visual (stderr, ssi->screen, ssi->current_visual);
1098 fprintf (stderr, "\t\t\t\tto: ");
1099 describe_visual (stderr, ssi->screen, new_v);
1101 fprintf (stderr, "%s: switching to visual ", progname);
1102 describe_visual (stderr, ssi->screen, new_v);
1107 ssi->current_visual = new_v;
1108 ssi->current_depth = visual_depth(ssi->screen, new_v);
1110 ssi->screensaver_window = 0;
1112 initialize_screensaver_window_1 (ssi);
1113 raise_window (si, True, True, False);
1114 store_vroot_property (si->dpy,
1115 ssi->screensaver_window, ssi->screensaver_window);
1116 store_activate_time (si, False);
1118 XDestroyWindow (si->dpy, old_w);
1120 old_c != DefaultColormapOfScreen (ssi->screen) &&
1121 old_c != ssi->demo_cmap)
1122 XFreeColormap (si->dpy, old_c);