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)
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;
561 Bool install_cmap_p = ssi->install_cmap_p;
563 /* This resets the screensaver window as fully as possible, since there's
564 no way of knowing what some random client may have done to us in the
565 meantime. We could just destroy and recreate the window, but that has
566 its own set of problems...
569 XClassHint class_hints;
570 XSetWindowAttributes attrs;
571 unsigned long attrmask;
572 int width = WidthOfScreen (ssi->screen);
573 int height = HeightOfScreen (ssi->screen);
575 static Bool printed_visual_info = False; /* only print the message once. */
577 black.red = black.green = black.blue = 0;
579 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
582 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
583 install_cmap_p = True;
589 ssi->cmap = XCreateColormap (si->dpy, RootWindowOfScreen (ssi->screen),
590 ssi->current_visual, AllocNone);
591 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
592 ssi->black_pixel = black.pixel;
597 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
600 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
601 if (ssi->cmap != ssi->demo_cmap &&
602 ssi->cmap != def_cmap)
603 XFreeColormap (si->dpy, ssi->cmap);
605 ssi->cmap = def_cmap;
606 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
609 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
610 CWBackPixel | CWBackingPixel | CWBorderPixel);
611 attrs.override_redirect = True;
613 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
614 actually be reading these events during normal operation; but we still
615 need to see Button events for demo-mode to work properly.
617 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
618 ButtonPressMask | ButtonReleaseMask |
621 attrs.backing_store = NotUseful;
622 attrs.colormap = ssi->cmap;
623 attrs.background_pixel = ssi->black_pixel;
624 attrs.backing_pixel = ssi->black_pixel;
625 attrs.border_pixel = ssi->black_pixel;
628 if (p->debug_p) width = width / 2;
631 if (!p->verbose_p || printed_visual_info)
633 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
635 fprintf (stderr, "%s: using default visual ", progname);
636 describe_visual (stderr, ssi->screen, ssi->current_visual);
640 fprintf (stderr, "%s: using visual: ", progname);
641 describe_visual (stderr, ssi->screen, ssi->current_visual);
642 fprintf (stderr, "%s: default visual: ", progname);
643 describe_visual (stderr, ssi->screen,
644 DefaultVisualOfScreen (ssi->screen));
646 printed_visual_info = True;
648 #ifdef HAVE_MIT_SAVER_EXTENSION
649 if (p->use_mit_saver_extension)
651 XScreenSaverInfo *info;
652 Window root = RootWindowOfScreen (ssi->screen);
655 /* This call sets the server screensaver timeouts to what we think
656 they should be (based on the resources and args xscreensaver was
657 started with.) It's important that we do this to sync back up
658 with the server - if we have turned on prematurely, as by an
659 ACTIVATE ClientMessage, then the server may decide to activate
660 the screensaver while it's already active. That's ok for us,
661 since we would know to ignore that ScreenSaverActivate event,
662 but a side effect of this would be that the server would map its
663 saver window (which we then hide again right away) meaning that
664 the bits currently on the screen get blown away. Ugly. */
666 /* #### Ok, that doesn't work - when we tell the server that the
667 screensaver is "off" it sends us a Deactivate event, which is
668 sensible... but causes the saver to never come on. Hmm. */
669 disable_builtin_screensaver (si, True);
673 /* #### The MIT-SCREEN-SAVER extension gives us access to the
674 window that the server itself uses for saving the screen.
675 However, using this window in any way, in particular, calling
676 XScreenSaverSetAttributes() as below, tends to make the X server
677 crash. So fuck it, let's try and get along without using it...
679 It's also inconvenient to use this window because it doesn't
680 always exist (though the ID is constant.) So to use this
681 window, we'd have to reimplement the ACTIVATE ClientMessage to
682 tell the *server* to tell *us* to turn on, to cause the window
683 to get created at the right time. Gag. */
684 XScreenSaverSetAttributes (si->dpy, root,
685 0, 0, width, height, 0,
686 current_depth, InputOutput, visual,
688 XSync (si->dpy, False);
691 info = XScreenSaverAllocInfo ();
692 XScreenSaverQueryInfo (si->dpy, root, info);
693 ssi->server_mit_saver_window = info->window;
694 if (! ssi->server_mit_saver_window) abort ();
697 #endif /* HAVE_MIT_SAVER_EXTENSION */
699 if (ssi->screensaver_window)
701 XWindowChanges changes;
702 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
705 changes.width = width;
706 changes.height = height;
707 changes.border_width = 0;
709 XConfigureWindow (si->dpy, ssi->screensaver_window,
710 changesmask, &changes);
711 XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
716 ssi->screensaver_window =
717 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen), 0, 0,
718 width, height, 0, ssi->current_depth, InputOutput,
719 ssi->current_visual, attrmask, &attrs);
721 store_activate_time(si, True);
723 fprintf (stderr, "%s: saver window is 0x%lx.\n",
724 progname, (unsigned long) ssi->screensaver_window);
727 #ifdef HAVE_MIT_SAVER_EXTENSION
728 if (!p->use_mit_saver_extension ||
729 window_exists_p (si->dpy, ssi->screensaver_window))
730 /* When using the MIT-SCREEN-SAVER extension, the window pointed to
731 by screensaver_window only exists while the saver is active.
732 So we must be careful to only try and manipulate it while it
734 (#### The above comment would be true if the MIT extension actually
735 worked, but it's not true today -- see `server_mit_saver_window'.)
737 #endif /* HAVE_MIT_SAVER_EXTENSION */
739 class_hints.res_name = progname;
740 class_hints.res_class = progclass;
741 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
742 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
743 XChangeProperty (si->dpy, ssi->screensaver_window,
744 XA_SCREENSAVER_VERSION,
745 XA_STRING, 8, PropModeReplace,
746 (unsigned char *) si->version,
747 strlen (si->version));
749 sprintf (id, "%lu on host ", (unsigned long) getpid ());
751 # if defined(HAVE_UNAME)
754 if (uname (&uts) < 0)
757 strcat (id, uts.nodename);
760 strcat (id, getenv("SYS$NODE"));
761 # else /* !HAVE_UNAME && !VMS */
763 # endif /* !HAVE_UNAME && !VMS */
765 XChangeProperty (si->dpy, ssi->screensaver_window,
766 XA_SCREENSAVER_ID, XA_STRING,
767 8, PropModeReplace, (unsigned char *) id, strlen (id));
772 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
774 BlackPixelOfScreen (ssi->screen),
775 BlackPixelOfScreen (ssi->screen),
777 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
779 XFreePixmap (si->dpy, bit);
782 XSetWindowBackground (si->dpy, ssi->screensaver_window,
785 XUndefineCursor (si->dpy, ssi->screensaver_window);
787 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
792 initialize_screensaver_window (saver_info *si)
795 for (i = 0; i < si->nscreens; i++)
796 initialize_screensaver_window_1 (&si->screens[i]);
801 raise_window (saver_info *si,
802 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
804 saver_preferences *p = &si->prefs;
807 initialize_screensaver_window (si);
808 reset_watchdog_timer (si, True);
810 if (p->fade_p && !inhibit_fade && !si->demo_mode_p)
813 Window *current_windows = (Window *)
814 calloc(sizeof(Window), si->nscreens);
815 Colormap *current_maps = (Colormap *)
816 calloc(sizeof(Colormap), si->nscreens);
818 for (i = 0; i < si->nscreens; i++)
820 saver_screen_info *ssi = &si->screens[i];
821 current_windows[i] = ssi->screensaver_window;
822 current_maps[i] = (between_hacks_p
824 : DefaultColormapOfScreen (ssi->screen));
825 /* Ensure that the default background of the window is really black,
826 not a pixmap or something. (This does not clear the window.) */
827 XSetWindowBackground (si->dpy, ssi->screensaver_window,
831 if (p->verbose_p) fprintf (stderr, "%s: fading... ", progname);
833 XGrabServer (si->dpy);
835 for (i = 0; i < si->nscreens; i++)
837 saver_screen_info *ssi = &si->screens[i];
839 /* grab and blacken mouse on the root window (saver not mapped yet)
841 if (grabbed != GrabSuccess)
842 grabbed = grab_mouse (si->dpy, ssi->screensaver_window,
843 (si->demo_mode_p ? 0 : ssi->cursor));
845 if (!dont_clear || ssi->stderr_overlay_window)
846 /* Do this before the fade, since the stderr cmap won't fade
847 even if we uninstall it (beats me...) */
851 fade_screens (si->dpy, current_maps, current_windows,
852 p->fade_seconds, p->fade_ticks, True, !dont_clear);
854 free(current_windows);
858 if (p->verbose_p) fprintf (stderr, "fading done.\n");
860 #ifdef HAVE_MIT_SAVER_EXTENSION
861 for (i = 0; i < si->nscreens; i++)
863 saver_screen_info *ssi = &si->screens[i];
864 if (ssi->server_mit_saver_window &&
865 window_exists_p (si->dpy, ssi->server_mit_saver_window))
866 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
868 #endif /* HAVE_MIT_SAVER_EXTENSION */
870 if (grabbed == GrabSuccess)
871 XUngrabPointer (si->dpy, CurrentTime);
872 XUngrabServer (si->dpy);
876 for (i = 0; i < si->nscreens; i++)
878 saver_screen_info *ssi = &si->screens[i];
880 XClearWindow (si->dpy, ssi->screensaver_window);
881 if (!dont_clear || ssi->stderr_overlay_window)
883 XMapRaised (si->dpy, ssi->screensaver_window);
884 #ifdef HAVE_MIT_SAVER_EXTENSION
885 if (ssi->server_mit_saver_window &&
886 window_exists_p (si->dpy, ssi->server_mit_saver_window))
887 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
888 #endif /* HAVE_MIT_SAVER_EXTENSION */
892 for (i = 0; i < si->nscreens; i++)
894 saver_screen_info *ssi = &si->screens[i];
896 XInstallColormap (si->dpy, ssi->cmap);
901 blank_screen (saver_info *si)
904 for (i = 0; i < si->nscreens; i++)
906 saver_screen_info *ssi = &si->screens[i];
908 save_real_vroot (ssi);
909 store_vroot_property (si->dpy,
910 ssi->screensaver_window,
911 ssi->screensaver_window);
913 store_activate_time (si, si->screen_blanked_p);
914 raise_window (si, False, False, False);
916 grab_keyboard_and_mouse (si->dpy, si->screens[0].screensaver_window,
917 (si->demo_mode_p ? 0 : si->screens[0].cursor));
918 #ifdef HAVE_XHPDISABLERESET
919 if (si->locked_p && !hp_locked_p)
921 XHPDisableReset (si->dpy); /* turn off C-Sh-Reset */
926 si->screen_blanked_p = True;
930 unblank_screen (saver_info *si)
932 saver_preferences *p = &si->prefs;
935 store_activate_time (si, True);
936 reset_watchdog_timer (si, False);
938 if (p->unfade_p && !si->demo_mode_p)
941 Window *current_windows = (Window *)
942 calloc(sizeof(Window), si->nscreens);
944 for (i = 0; i < si->nscreens; i++)
946 saver_screen_info *ssi = &si->screens[i];
947 current_windows[i] = ssi->screensaver_window;
948 /* Ensure that the default background of the window is really black,
949 not a pixmap or something. (This does not clear the window.) */
950 XSetWindowBackground (si->dpy, ssi->screensaver_window,
954 if (p->verbose_p) fprintf (stderr, "%s: unfading... ", progname);
956 XSync (si->dpy, False);
957 XGrabServer (si->dpy);
958 XSync (si->dpy, False);
959 for (i = 0; i < si->nscreens; i++)
961 saver_screen_info *ssi = &si->screens[i];
962 if (grabbed != GrabSuccess)
963 grabbed = grab_mouse (si->dpy, RootWindowOfScreen (ssi->screen),
967 XUngrabServer (si->dpy);
968 XSync (si->dpy, False);
970 fade_screens (si->dpy, 0, current_windows,
971 p->fade_seconds, p->fade_ticks,
974 free(current_windows);
977 if (p->verbose_p) fprintf (stderr, "unfading done.\n");
978 if (grabbed == GrabSuccess)
979 XUngrabPointer (si->dpy, CurrentTime);
983 for (i = 0; i < si->nscreens; i++)
985 saver_screen_info *ssi = &si->screens[i];
988 Colormap c = DefaultColormapOfScreen (ssi->screen);
989 /* avoid technicolor */
990 XClearWindow (si->dpy, ssi->screensaver_window);
991 if (c) XInstallColormap (si->dpy, c);
993 XUnmapWindow (si->dpy, ssi->screensaver_window);
998 /* If the focus window does has a non-default colormap, then install
999 that colormap as well. (On SGIs, this will cause both the root map
1000 and the focus map to be installed simultaniously. It'd be nice to
1001 pick up the other colormaps that had been installed, too; perhaps
1002 XListInstalledColormaps could be used for that?)
1007 XGetInputFocus (si->dpy, &focus, &revert_to);
1008 if (focus && focus != PointerRoot && focus != None)
1010 XWindowAttributes xgwa;
1012 XGetWindowAttributes (si->dpy, focus, &xgwa);
1013 if (xgwa.colormap &&
1014 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1015 XInstallColormap (si->dpy, xgwa.colormap);
1020 for (i = 0; i < si->nscreens; i++)
1022 saver_screen_info *ssi = &si->screens[i];
1023 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
1026 store_activate_time(si, False); /* store unblank time */
1028 ungrab_keyboard_and_mouse (si->dpy);
1029 restore_real_vroot (si);
1031 #ifdef HAVE_XHPDISABLERESET
1034 XHPEnableReset (si->dpy); /* turn C-Sh-Reset back on */
1035 hp_locked_p = False;
1039 /* Unmap the windows a second time, dammit -- just to avoid a race
1040 with the screen-grabbing hacks. (I'm not sure if this is really
1041 necessary; I'm stabbing in the dark now.)
1043 for (i = 0; i < si->nscreens; i++)
1044 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
1046 si->screen_blanked_p = False;
1051 store_activate_time (saver_info *si, Bool use_last_p)
1053 static time_t last_time = 0;
1054 time_t now = ((use_last_p && last_time) ? last_time : time ((time_t) 0));
1055 CARD32 now32 = (CARD32) now;
1059 for (i = 0; i < si->nscreens; i++)
1061 saver_screen_info *ssi = &si->screens[i];
1062 if (!ssi->screensaver_window) continue;
1063 XChangeProperty (si->dpy, ssi->screensaver_window, XA_SCREENSAVER_TIME,
1064 XA_INTEGER, 32, PropModeReplace,
1065 (unsigned char *) &now32, 1);
1071 select_visual (saver_screen_info *ssi, const char *visual_name)
1073 saver_info *si = ssi->global;
1074 saver_preferences *p = &si->prefs;
1075 Bool install_cmap_p = p->install_cmap_p;
1076 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
1080 if (visual_name && *visual_name)
1082 if (!strcmp(visual_name, "default-i"))
1084 visual_name = "default";
1085 install_cmap_p = True;
1087 else if (!strcmp(visual_name, "default-n"))
1089 visual_name = "default";
1090 install_cmap_p = False;
1092 new_v = get_visual (ssi->screen, visual_name, True, False);
1096 new_v = ssi->default_visual;
1101 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
1102 install_cmap_p = True;
1104 ssi->install_cmap_p = install_cmap_p;
1107 ((ssi->current_visual != new_v) ||
1108 (install_cmap_p != was_installed_p)))
1110 Colormap old_c = ssi->cmap;
1111 Window old_w = ssi->screensaver_window;
1116 fprintf (stderr, "%s: switching visuals\tfrom: ", progname);
1117 describe_visual (stderr, ssi->screen, ssi->current_visual);
1118 fprintf (stderr, "\t\t\t\tto: ");
1119 describe_visual (stderr, ssi->screen, new_v);
1120 fprintf (stderr, "\t\t\t\t install cmap: %s\n",
1121 (install_cmap_p ? "yes" : "no"));
1123 fprintf (stderr, "%s: switching to visual ", progname);
1124 describe_visual (stderr, ssi->screen, new_v);
1129 ssi->current_visual = new_v;
1130 ssi->current_depth = visual_depth(ssi->screen, new_v);
1132 ssi->screensaver_window = 0;
1134 initialize_screensaver_window_1 (ssi);
1135 raise_window (si, True, True, False);
1136 store_vroot_property (si->dpy,
1137 ssi->screensaver_window, ssi->screensaver_window);
1138 store_activate_time (si, True);
1140 XDestroyWindow (si->dpy, old_w);
1142 old_c != DefaultColormapOfScreen (ssi->screen) &&
1143 old_c != ssi->demo_cmap)
1144 XFreeColormap (si->dpy, old_c);