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, 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,
93 if (status == GrabSuccess)
94 si->keyboard_grab_window = w;
97 fprintf(stderr, "%s: XGrabKeyboard(... 0x%x ...) ==> %s\n",
98 progname, (unsigned long) w,
99 (status == GrabSuccess ? "GrabSuccess" :
100 status == AlreadyGrabbed ? "AlreadyGrabbed" :
101 status == GrabInvalidTime ? "GrabInvalidTime" :
102 status == GrabNotViewable ? "GrabNotViewable" :
103 status == GrabFrozen ? "GrabFrozen" :
110 grab_string(int status)
114 case GrabSuccess: return "GrabSuccess"; break;
115 case AlreadyGrabbed: return "AlreadyGrabbed"; break;
116 case GrabInvalidTime: return "GrabInvalidTime"; break;
117 case GrabNotViewable: return "GrabNotViewable"; break;
118 case GrabFrozen: return "GrabFrozen"; break;
121 static char foo[255];
122 sprintf(foo, "unknown status: %d", status);
130 grab_mouse (saver_info *si, Window w, Cursor cursor)
132 saver_preferences *p = &si->prefs;
133 int status = XGrabPointer (si->dpy, w, True, ALL_POINTER_EVENTS,
134 GrabModeAsync, GrabModeAsync, None,
135 cursor, CurrentTime);
136 if (status == GrabSuccess)
137 si->mouse_grab_window = w;
140 fprintf(stderr, "%s: XGrabPointer(... 0x%x, 0x%x ...) ==> %s\n",
141 progname, (unsigned long) w, (unsigned long) cursor,
142 grab_string(status));
148 ungrab_kbd(saver_info *si)
150 saver_preferences *p = &si->prefs;
151 XUngrabKeyboard(si->dpy, CurrentTime);
153 fprintf(stderr, "%s: XUngrabKeyboard (was 0x%x)\n", progname,
154 (unsigned long) si->keyboard_grab_window);
155 si->keyboard_grab_window = 0;
160 ungrab_mouse(saver_info *si)
162 saver_preferences *p = &si->prefs;
163 XUngrabPointer(si->dpy, CurrentTime);
165 fprintf(stderr, "%s: XUngrabPointer (was 0x%x)\n", progname,
166 (unsigned long) si->mouse_grab_window);
167 si->mouse_grab_window = 0;
172 grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor)
175 XSync (si->dpy, False);
177 status = grab_kbd (si, window);
178 if (status != GrabSuccess)
179 { /* try again in a second */
181 status = grab_kbd (si, window);
182 if (status != GrabSuccess)
183 fprintf (stderr, "%s: couldn't grab keyboard! (%s)\n",
184 progname, grab_string(status));
187 status = grab_mouse (si, window, cursor);
188 if (status != GrabSuccess)
189 { /* try again in a second */
191 status = grab_mouse (si, window, cursor);
192 if (status != GrabSuccess)
193 fprintf (stderr, "%s: couldn't grab pointer! (%s)\n",
194 progname, grab_string(status));
199 ungrab_keyboard_and_mouse (saver_info *si)
206 /* Prints an error message to stderr and returns True if there is another
207 xscreensaver running already. Silently returns False otherwise. */
209 ensure_no_screensaver_running (Display *dpy, Screen *screen)
213 Window root = RootWindowOfScreen (screen);
214 Window root2, parent, *kids;
216 XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler);
218 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
224 for (i = 0; i < nkids; i++)
228 unsigned long nitems, bytesafter;
231 if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
232 False, XA_STRING, &type, &format, &nitems,
233 &bytesafter, (unsigned char **) &version)
238 if (!XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
239 False, XA_STRING, &type, &format, &nitems,
240 &bytesafter, (unsigned char **) &id)
246 "%s: already running on display %s (window 0x%x)\n from process %s.\n",
247 progname, DisplayString (dpy), (int) kids [i], id);
252 if (kids) XFree ((char *) kids);
254 XSetErrorHandler (old_handler);
260 /* Virtual-root hackery */
263 ERROR! You must not include vroot.h in this file.
267 store_vroot_property (Display *dpy, Window win, Window value)
272 "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", progname,
274 (win == screensaver_window ? "ScreenSaver" :
275 (win == real_vroot ? "VRoot" :
276 (win == real_vroot_value ? "Vroot_value" : "???"))),
278 (value == screensaver_window ? "ScreenSaver" :
279 (value == real_vroot ? "VRoot" :
280 (value == real_vroot_value ? "Vroot_value" : "???"))));
282 XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
283 (unsigned char *) &value, 1);
287 remove_vroot_property (Display *dpy, Window win)
291 fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", progname, win,
292 (win == screensaver_window ? "ScreenSaver" :
293 (win == real_vroot ? "VRoot" :
294 (win == real_vroot_value ? "Vroot_value" : "???"))));
296 XDeleteProperty (dpy, win, XA_VROOT);
301 kill_xsetroot_data (Display *dpy, Window window, Bool verbose_p)
305 unsigned long nitems, bytesafter;
308 /* If the user has been using xv or xsetroot as a screensaver (to display
309 an image on the screensaver window, as a kind of slideshow) then the
310 pixmap and its associated color cells have been put in RetainPermanent
311 CloseDown mode. Since we're not destroying the xscreensaver window,
312 but merely unmapping it, we need to free these resources or those
313 colormap cells will stay allocated while the screensaver is off. (We
314 could just delete the screensaver window and recreate it later, but
315 that could cause other problems.) This code does an atomic read-and-
316 delete of the _XSETROOT_ID property, and if it held a pixmap, then we
317 cause the RetainPermanent resources of the client which created it
318 (and which no longer exists) to be freed.
320 if (XGetWindowProperty (dpy, window, XA_XSETROOT_ID, 0, 1,
321 True, AnyPropertyType, &type, &format, &nitems,
322 &bytesafter, (unsigned char **) &dataP)
326 if (dataP && *dataP && type == XA_PIXMAP && format == 32 &&
327 nitems == 1 && bytesafter == 0)
330 printf ("%s: destroying xsetroot data (0x%lX).\n",
332 XKillClient (dpy, *dataP);
335 fprintf (stderr, "%s: deleted unrecognised _XSETROOT_ID property: \n\
336 %lu, %lu; type: %lu, format: %d, nitems: %lu, bytesafter %ld\n",
337 progname, (unsigned long) dataP, (dataP ? *dataP : 0), type,
338 format, nitems, bytesafter);
343 static void handle_signals (saver_info *si, Bool on_p);
346 save_real_vroot (saver_screen_info *ssi)
348 saver_info *si = ssi->global;
349 Display *dpy = si->dpy;
350 Screen *screen = ssi->screen;
352 Window root = RootWindowOfScreen (screen);
353 Window root2, parent, *kids;
357 ssi->real_vroot_value = 0;
358 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
364 for (i = 0; i < nkids; i++)
368 unsigned long nitems, bytesafter;
371 if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
372 &type, &format, &nitems, &bytesafter,
373 (unsigned char **) &vrootP)
380 if (*vrootP == ssi->screensaver_window) abort ();
382 "%s: more than one virtual root window found (0x%x and 0x%x).\n",
383 progname, (int) ssi->real_vroot, (int) kids [i]);
386 ssi->real_vroot = kids [i];
387 ssi->real_vroot_value = *vrootP;
392 handle_signals (si, True);
393 remove_vroot_property (si->dpy, ssi->real_vroot);
397 XFree ((char *) kids);
402 restore_real_vroot_2 (saver_screen_info *ssi)
404 saver_info *si = ssi->global;
405 saver_preferences *p = &si->prefs;
406 if (p->verbose_p && ssi->real_vroot)
407 printf ("%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
408 progname, (unsigned long) ssi->real_vroot);
409 remove_vroot_property (si->dpy, ssi->screensaver_window);
412 store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
414 ssi->real_vroot_value = 0;
415 /* make sure the property change gets there before this process
416 terminates! We might be doing this because we have intercepted
417 SIGTERM or something. */
418 XSync (si->dpy, False);
425 restore_real_vroot_1 (saver_info *si)
428 Bool did_any = False;
429 for (i = 0; i < si->nscreens; i++)
431 saver_screen_info *ssi = &si->screens[i];
432 if (restore_real_vroot_2 (ssi))
439 restore_real_vroot (saver_info *si)
441 if (restore_real_vroot_1 (si))
442 handle_signals (si, False);
446 /* Signal hackery to ensure that the vroot doesn't get left in an
451 signal_name(int signal)
454 case SIGHUP: return "SIGHUP";
455 case SIGINT: return "SIGINT";
456 case SIGQUIT: return "SIGQUIT";
457 case SIGILL: return "SIGILL";
458 case SIGTRAP: return "SIGTRAP";
460 case SIGABRT: return "SIGABRT";
462 case SIGFPE: return "SIGFPE";
463 case SIGKILL: return "SIGKILL";
464 case SIGBUS: return "SIGBUS";
465 case SIGSEGV: return "SIGSEGV";
466 case SIGPIPE: return "SIGPIPE";
467 case SIGALRM: return "SIGALRM";
468 case SIGTERM: return "SIGTERM";
470 case SIGSTOP: return "SIGSTOP";
473 case SIGCONT: return "SIGCONT";
476 case SIGUSR1: return "SIGUSR1";
479 case SIGUSR2: return "SIGUSR2";
482 case SIGEMT: return "SIGEMT";
485 case SIGSYS: return "SIGSYS";
488 case SIGCHLD: return "SIGCHLD";
491 case SIGPWR: return "SIGPWR";
494 case SIGWINCH: return "SIGWINCH";
497 case SIGURG: return "SIGURG";
500 case SIGIO: return "SIGIO";
503 case SIGVTALRM: return "SIGVTALRM";
506 case SIGXCPU: return "SIGXCPU";
509 case SIGXFSZ: return "SIGXFSZ";
512 case SIGDANGER: return "SIGDANGER";
517 sprintf(buf, "signal %d\n", signal);
526 restore_real_vroot_handler (int sig)
528 saver_info *si = global_si_kludge; /* I hate C so much... */
530 signal (sig, SIG_DFL);
531 if (restore_real_vroot_1 (si))
532 fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n",
533 progname, signal_name(sig));
534 kill (getpid (), sig);
538 catch_signal (saver_info *si, int sig, Bool on_p)
541 signal (sig, SIG_DFL);
544 if (((long) signal (sig, restore_real_vroot_handler)) == -1L)
547 sprintf (buf, "%s: couldn't catch %s", progname, signal_name(sig));
555 handle_signals (saver_info *si, Bool on_p)
558 if (on_p) printf ("handling signals\n");
559 else printf ("unhandling signals\n");
562 catch_signal (si, SIGHUP, on_p);
563 catch_signal (si, SIGINT, on_p);
564 catch_signal (si, SIGQUIT, on_p);
565 catch_signal (si, SIGILL, on_p);
566 catch_signal (si, SIGTRAP, on_p);
567 catch_signal (si, SIGIOT, on_p);
568 catch_signal (si, SIGABRT, on_p);
570 catch_signal (si, SIGEMT, on_p);
572 catch_signal (si, SIGFPE, on_p);
573 catch_signal (si, SIGBUS, on_p);
574 catch_signal (si, SIGSEGV, on_p);
576 catch_signal (si, SIGSYS, on_p);
578 catch_signal (si, SIGTERM, on_p);
580 catch_signal (si, SIGXCPU, on_p);
583 catch_signal (si, SIGXFSZ, on_p);
586 catch_signal (si, SIGDANGER, on_p);
591 saver_exit (saver_info *si, int status)
593 saver_preferences *p = &si->prefs;
594 static Bool exiting = False;
602 vrs = restore_real_vroot_1 (si);
603 emergency_kill_subproc (si);
605 if (vrs && (p->verbose_p || status != 0))
606 fprintf (real_stderr, "%s: vroot restored, exiting.\n", progname);
607 else if (p->verbose_p)
608 fprintf (real_stderr, "%s: no vroot to restore; exiting.\n", progname);
612 #ifdef VMS /* on VMS, 1 is the "normal" exit code instead of 0. */
613 if (status == 0) status = 1;
614 else if (status == 1) status = -1;
617 if (si->prefs.debug_p)
619 fprintf(real_stderr, "%s: dumping core (because of -debug)\n", progname);
620 /* Do this to drop a core file, so that we can get a stack trace. */
628 /* Managing the actual screensaver window */
631 window_exists_p (Display *dpy, Window window)
633 XErrorHandler old_handler;
634 XWindowAttributes xgwa;
636 old_handler = XSetErrorHandler (BadWindow_ehandler);
637 XGetWindowAttributes (dpy, window, &xgwa);
639 XSetErrorHandler (old_handler);
640 return (xgwa.screen != 0);
644 initialize_screensaver_window_1 (saver_screen_info *ssi)
646 saver_info *si = ssi->global;
647 saver_preferences *p = &si->prefs;
648 Bool install_cmap_p = ssi->install_cmap_p;
650 /* This resets the screensaver window as fully as possible, since there's
651 no way of knowing what some random client may have done to us in the
652 meantime. We could just destroy and recreate the window, but that has
653 its own set of problems...
656 XClassHint class_hints;
657 XSetWindowAttributes attrs;
658 unsigned long attrmask;
659 int width = WidthOfScreen (ssi->screen);
660 int height = HeightOfScreen (ssi->screen);
662 static Bool printed_visual_info = False; /* only print the message once. */
664 black.red = black.green = black.blue = 0;
666 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
669 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
670 install_cmap_p = True;
676 ssi->cmap = XCreateColormap (si->dpy, RootWindowOfScreen (ssi->screen),
677 ssi->current_visual, AllocNone);
678 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
679 ssi->black_pixel = black.pixel;
684 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
687 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
688 if (ssi->cmap != ssi->demo_cmap &&
689 ssi->cmap != def_cmap)
690 XFreeColormap (si->dpy, ssi->cmap);
692 ssi->cmap = def_cmap;
693 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
696 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
697 CWBackPixel | CWBackingPixel | CWBorderPixel);
698 attrs.override_redirect = True;
700 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
701 actually be reading these events during normal operation; but we still
702 need to see Button events for demo-mode to work properly.
704 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
705 ButtonPressMask | ButtonReleaseMask |
708 attrs.backing_store = NotUseful;
709 attrs.colormap = ssi->cmap;
710 attrs.background_pixel = ssi->black_pixel;
711 attrs.backing_pixel = ssi->black_pixel;
712 attrs.border_pixel = ssi->black_pixel;
714 if (p->debug_p) width = width / 2;
716 if (!p->verbose_p || printed_visual_info)
718 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
720 fprintf (stderr, "%s: using default visual ", progname);
721 describe_visual (stderr, ssi->screen, ssi->current_visual);
725 fprintf (stderr, "%s: using visual: ", progname);
726 describe_visual (stderr, ssi->screen, ssi->current_visual);
727 fprintf (stderr, "%s: default visual: ", progname);
728 describe_visual (stderr, ssi->screen,
729 DefaultVisualOfScreen (ssi->screen));
731 printed_visual_info = True;
733 #ifdef HAVE_MIT_SAVER_EXTENSION
734 if (p->use_mit_saver_extension)
736 XScreenSaverInfo *info;
737 Window root = RootWindowOfScreen (ssi->screen);
740 /* This call sets the server screensaver timeouts to what we think
741 they should be (based on the resources and args xscreensaver was
742 started with.) It's important that we do this to sync back up
743 with the server - if we have turned on prematurely, as by an
744 ACTIVATE ClientMessage, then the server may decide to activate
745 the screensaver while it's already active. That's ok for us,
746 since we would know to ignore that ScreenSaverActivate event,
747 but a side effect of this would be that the server would map its
748 saver window (which we then hide again right away) meaning that
749 the bits currently on the screen get blown away. Ugly. */
751 /* #### Ok, that doesn't work - when we tell the server that the
752 screensaver is "off" it sends us a Deactivate event, which is
753 sensible... but causes the saver to never come on. Hmm. */
754 disable_builtin_screensaver (si, True);
758 /* #### The MIT-SCREEN-SAVER extension gives us access to the
759 window that the server itself uses for saving the screen.
760 However, using this window in any way, in particular, calling
761 XScreenSaverSetAttributes() as below, tends to make the X server
762 crash. So fuck it, let's try and get along without using it...
764 It's also inconvenient to use this window because it doesn't
765 always exist (though the ID is constant.) So to use this
766 window, we'd have to reimplement the ACTIVATE ClientMessage to
767 tell the *server* to tell *us* to turn on, to cause the window
768 to get created at the right time. Gag. */
769 XScreenSaverSetAttributes (si->dpy, root,
770 0, 0, width, height, 0,
771 current_depth, InputOutput, visual,
773 XSync (si->dpy, False);
776 info = XScreenSaverAllocInfo ();
777 XScreenSaverQueryInfo (si->dpy, root, info);
778 ssi->server_mit_saver_window = info->window;
779 if (! ssi->server_mit_saver_window) abort ();
782 #endif /* HAVE_MIT_SAVER_EXTENSION */
784 if (ssi->screensaver_window)
786 XWindowChanges changes;
787 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
790 changes.width = width;
791 changes.height = height;
792 changes.border_width = 0;
794 XConfigureWindow (si->dpy, ssi->screensaver_window,
795 changesmask, &changes);
796 XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
801 ssi->screensaver_window =
802 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen), 0, 0,
803 width, height, 0, ssi->current_depth, InputOutput,
804 ssi->current_visual, attrmask, &attrs);
806 store_activate_time(si, True);
808 fprintf (stderr, "%s: saver window is 0x%lx.\n",
809 progname, (unsigned long) ssi->screensaver_window);
812 #ifdef HAVE_MIT_SAVER_EXTENSION
813 if (!p->use_mit_saver_extension ||
814 window_exists_p (si->dpy, ssi->screensaver_window))
815 /* When using the MIT-SCREEN-SAVER extension, the window pointed to
816 by screensaver_window only exists while the saver is active.
817 So we must be careful to only try and manipulate it while it
819 (#### The above comment would be true if the MIT extension actually
820 worked, but it's not true today -- see `server_mit_saver_window'.)
822 #endif /* HAVE_MIT_SAVER_EXTENSION */
824 class_hints.res_name = progname;
825 class_hints.res_class = progclass;
826 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
827 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
828 XChangeProperty (si->dpy, ssi->screensaver_window,
829 XA_SCREENSAVER_VERSION,
830 XA_STRING, 8, PropModeReplace,
831 (unsigned char *) si->version,
832 strlen (si->version));
834 sprintf (id, "%lu on host ", (unsigned long) getpid ());
836 # if defined(HAVE_UNAME)
839 if (uname (&uts) < 0)
842 strcat (id, uts.nodename);
845 strcat (id, getenv("SYS$NODE"));
846 # else /* !HAVE_UNAME && !VMS */
848 # endif /* !HAVE_UNAME && !VMS */
850 XChangeProperty (si->dpy, ssi->screensaver_window,
851 XA_SCREENSAVER_ID, XA_STRING,
852 8, PropModeReplace, (unsigned char *) id, strlen (id));
857 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
859 BlackPixelOfScreen (ssi->screen),
860 BlackPixelOfScreen (ssi->screen),
862 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
864 XFreePixmap (si->dpy, bit);
867 XSetWindowBackground (si->dpy, ssi->screensaver_window,
870 XUndefineCursor (si->dpy, ssi->screensaver_window);
872 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
877 initialize_screensaver_window (saver_info *si)
880 for (i = 0; i < si->nscreens; i++)
881 initialize_screensaver_window_1 (&si->screens[i]);
886 raise_window (saver_info *si,
887 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
889 saver_preferences *p = &si->prefs;
892 initialize_screensaver_window (si);
893 reset_watchdog_timer (si, True);
895 if (p->fade_p && !inhibit_fade && !si->demo_mode_p)
898 Window *current_windows = (Window *)
899 calloc(sizeof(Window), si->nscreens);
900 Colormap *current_maps = (Colormap *)
901 calloc(sizeof(Colormap), si->nscreens);
903 for (i = 0; i < si->nscreens; i++)
905 saver_screen_info *ssi = &si->screens[i];
906 current_windows[i] = ssi->screensaver_window;
907 current_maps[i] = (between_hacks_p
909 : DefaultColormapOfScreen (ssi->screen));
910 /* Ensure that the default background of the window is really black,
911 not a pixmap or something. (This does not clear the window.) */
912 XSetWindowBackground (si->dpy, ssi->screensaver_window,
916 if (p->verbose_p) fprintf (stderr, "%s: fading... ", progname);
918 XGrabServer (si->dpy); /* ############ DANGER! */
920 /* Clear the stderr layer on each screen.
921 Grab the mouse on the first screen on which the mouse is grabbable
922 (if there are multiple heads, I think you might only be able to
923 grab the mouse on the screen that currently has the mouse? Anyway,
924 we only grab the mouse once, and don't try again after the grab
925 has succeeded.) We grab the mouse on the root window of the screen,
926 not on the screensaver window, since the screensaver window is not
929 for (i = 0; i < si->nscreens; i++)
931 saver_screen_info *ssi = &si->screens[i];
933 /* grab and blacken mouse on the root window (saver not mapped yet)
935 if (grabbed != GrabSuccess)
937 Window root = RootWindowOfScreen(ssi->screen);
938 grabbed = grab_mouse (si, root,
939 (si->demo_mode_p ? 0 : ssi->cursor));
942 if (!dont_clear || ssi->stderr_overlay_window)
943 /* Do this before the fade, since the stderr cmap won't fade
944 even if we uninstall it (beats me...) */
948 /* Note! The server is grabbed, and this will take several seconds
950 fade_screens (si->dpy, current_maps, current_windows,
951 p->fade_seconds, p->fade_ticks, True, !dont_clear);
954 free(current_windows);
958 if (p->verbose_p) fprintf (stderr, "fading done.\n");
960 #ifdef HAVE_MIT_SAVER_EXTENSION
961 for (i = 0; i < si->nscreens; i++)
963 saver_screen_info *ssi = &si->screens[i];
964 if (ssi->server_mit_saver_window &&
965 window_exists_p (si->dpy, ssi->server_mit_saver_window))
966 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
968 #endif /* HAVE_MIT_SAVER_EXTENSION */
970 /* If we had successfully grabbed the mouse, let it go now. */
971 if (grabbed == GrabSuccess)
974 XUngrabServer (si->dpy);
975 XSync (si->dpy, False); /* ###### (danger over) */
979 for (i = 0; i < si->nscreens; i++)
981 saver_screen_info *ssi = &si->screens[i];
983 XClearWindow (si->dpy, ssi->screensaver_window);
984 if (!dont_clear || ssi->stderr_overlay_window)
986 XMapRaised (si->dpy, ssi->screensaver_window);
987 #ifdef HAVE_MIT_SAVER_EXTENSION
988 if (ssi->server_mit_saver_window &&
989 window_exists_p (si->dpy, ssi->server_mit_saver_window))
990 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
991 #endif /* HAVE_MIT_SAVER_EXTENSION */
995 for (i = 0; i < si->nscreens; i++)
997 saver_screen_info *ssi = &si->screens[i];
999 XInstallColormap (si->dpy, ssi->cmap);
1004 blank_screen (saver_info *si)
1007 for (i = 0; i < si->nscreens; i++)
1009 saver_screen_info *ssi = &si->screens[i];
1011 save_real_vroot (ssi);
1012 store_vroot_property (si->dpy,
1013 ssi->screensaver_window,
1014 ssi->screensaver_window);
1016 store_activate_time (si, si->screen_blanked_p);
1017 raise_window (si, False, False, False);
1019 /* Note: we do our grabs on the root window, not on the screensaver window.
1020 If we grabbed on the saver window, then the demo mode and lock dialog
1021 boxes wouldn't get any events.
1023 grab_keyboard_and_mouse (si,
1024 /*si->screens[0].screensaver_window,*/
1025 RootWindowOfScreen(si->screens[0].screen),
1026 (si->demo_mode_p ? 0 : si->screens[0].cursor));
1028 #ifdef HAVE_XHPDISABLERESET
1029 if (si->locked_p && !hp_locked_p)
1031 XHPDisableReset (si->dpy); /* turn off C-Sh-Reset */
1036 si->screen_blanked_p = True;
1040 unblank_screen (saver_info *si)
1042 saver_preferences *p = &si->prefs;
1045 monitor_power_on (si);
1047 store_activate_time (si, True);
1048 reset_watchdog_timer (si, False);
1050 if (p->unfade_p && !si->demo_mode_p)
1053 Window *current_windows = (Window *)
1054 calloc(sizeof(Window), si->nscreens);
1056 for (i = 0; i < si->nscreens; i++)
1058 saver_screen_info *ssi = &si->screens[i];
1059 current_windows[i] = ssi->screensaver_window;
1060 /* Ensure that the default background of the window is really black,
1061 not a pixmap or something. (This does not clear the window.) */
1062 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1066 if (p->verbose_p) fprintf (stderr, "%s: unfading... ", progname);
1069 XSync (si->dpy, False);
1070 XGrabServer (si->dpy); /* ############ DANGER! */
1071 XSync (si->dpy, False);
1073 /* Clear the stderr layer on each screen.
1074 Grab the mouse on the first screen on which the mouse is grabbable
1075 (if there are multiple heads, I think you might only be able to
1076 grab the mouse on the screen that currently has the mouse? Anyway,
1077 we only grab the mouse once, and don't try again after the grab
1080 for (i = 0; i < si->nscreens; i++)
1082 saver_screen_info *ssi = &si->screens[i];
1083 if (grabbed != GrabSuccess)
1084 grabbed = grab_mouse (si, RootWindowOfScreen (ssi->screen),
1089 XUngrabServer (si->dpy);
1090 XSync (si->dpy, False); /* ###### (danger over) */
1093 fade_screens (si->dpy, 0, current_windows,
1094 p->fade_seconds, p->fade_ticks,
1097 free(current_windows);
1098 current_windows = 0;
1100 if (p->verbose_p) fprintf (stderr, "unfading done.\n");
1102 /* If we had successfully grabbed the mouse, let it go now. */
1103 if (grabbed == GrabSuccess)
1108 for (i = 0; i < si->nscreens; i++)
1110 saver_screen_info *ssi = &si->screens[i];
1113 Colormap c = DefaultColormapOfScreen (ssi->screen);
1114 /* avoid technicolor */
1115 XClearWindow (si->dpy, ssi->screensaver_window);
1116 if (c) XInstallColormap (si->dpy, c);
1118 XUnmapWindow (si->dpy, ssi->screensaver_window);
1123 /* If the focus window does has a non-default colormap, then install
1124 that colormap as well. (On SGIs, this will cause both the root map
1125 and the focus map to be installed simultaniously. It'd be nice to
1126 pick up the other colormaps that had been installed, too; perhaps
1127 XListInstalledColormaps could be used for that?)
1132 XGetInputFocus (si->dpy, &focus, &revert_to);
1133 if (focus && focus != PointerRoot && focus != None)
1135 XWindowAttributes xgwa;
1137 XGetWindowAttributes (si->dpy, focus, &xgwa);
1138 if (xgwa.colormap &&
1139 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1140 XInstallColormap (si->dpy, xgwa.colormap);
1145 for (i = 0; i < si->nscreens; i++)
1147 saver_screen_info *ssi = &si->screens[i];
1148 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
1151 store_activate_time(si, False); /* store unblank time */
1153 ungrab_keyboard_and_mouse (si);
1154 restore_real_vroot (si);
1156 #ifdef HAVE_XHPDISABLERESET
1159 XHPEnableReset (si->dpy); /* turn C-Sh-Reset back on */
1160 hp_locked_p = False;
1164 /* Unmap the windows a second time, dammit -- just to avoid a race
1165 with the screen-grabbing hacks. (I'm not sure if this is really
1166 necessary; I'm stabbing in the dark now.)
1168 for (i = 0; i < si->nscreens; i++)
1169 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
1171 si->screen_blanked_p = False;
1176 store_activate_time (saver_info *si, Bool use_last_p)
1178 static time_t last_time = 0;
1179 time_t now = ((use_last_p && last_time) ? last_time : time ((time_t) 0));
1180 CARD32 now32 = (CARD32) now;
1184 for (i = 0; i < si->nscreens; i++)
1186 saver_screen_info *ssi = &si->screens[i];
1187 if (!ssi->screensaver_window) continue;
1188 XChangeProperty (si->dpy, ssi->screensaver_window, XA_SCREENSAVER_TIME,
1189 XA_INTEGER, 32, PropModeReplace,
1190 (unsigned char *) &now32, 1);
1196 select_visual (saver_screen_info *ssi, const char *visual_name)
1198 saver_info *si = ssi->global;
1199 saver_preferences *p = &si->prefs;
1200 Bool install_cmap_p = p->install_cmap_p;
1201 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
1205 if (visual_name && *visual_name)
1207 if (!strcmp(visual_name, "default-i"))
1209 visual_name = "default";
1210 install_cmap_p = True;
1212 else if (!strcmp(visual_name, "default-n"))
1214 visual_name = "default";
1215 install_cmap_p = False;
1217 new_v = get_visual (ssi->screen, visual_name, True, False);
1221 new_v = ssi->default_visual;
1226 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
1227 install_cmap_p = True;
1229 ssi->install_cmap_p = install_cmap_p;
1232 ((ssi->current_visual != new_v) ||
1233 (install_cmap_p != was_installed_p)))
1235 Colormap old_c = ssi->cmap;
1236 Window old_w = ssi->screensaver_window;
1241 fprintf (stderr, "%s: switching visuals\tfrom: ", progname);
1242 describe_visual (stderr, ssi->screen, ssi->current_visual);
1243 fprintf (stderr, "\t\t\t\tto: ");
1244 describe_visual (stderr, ssi->screen, new_v);
1245 fprintf (stderr, "\t\t\t\t install cmap: %s\n",
1246 (install_cmap_p ? "yes" : "no"));
1248 fprintf (stderr, "%s: switching to visual ", progname);
1249 describe_visual (stderr, ssi->screen, new_v);
1254 ssi->current_visual = new_v;
1255 ssi->current_depth = visual_depth(ssi->screen, new_v);
1257 ssi->screensaver_window = 0;
1259 initialize_screensaver_window_1 (ssi);
1260 raise_window (si, True, True, False);
1261 store_vroot_property (si->dpy,
1262 ssi->screensaver_window, ssi->screensaver_window);
1263 store_activate_time (si, True);
1267 /* Transfer the grabs from the old window to the new.
1268 Actually I think none of this is necessary, since we always
1269 hold our grabs on the root window, but I wrote this before
1270 re-discovering that...
1274 /* If we're destroying the window that holds our mouse grab,
1275 transfer the grab to the new window. (Grab the server while
1276 so doing, to avoid a race condition.)
1278 if (old_w == si->mouse_grab_window)
1280 XGrabServer (si->dpy); /* ############ DANGER! */
1282 grab_mouse(si, ssi->screensaver_window,
1283 (si->demo_mode_p ? 0 : ssi->cursor));
1284 XUngrabServer (si->dpy);
1285 XSync (si->dpy, False); /* ###### (danger over) */
1288 /* If we're destroying the window that holds our keyboard grab,
1289 transfer the grab to the new window. (Grab the server while
1290 so doing, to avoid a race condition.)
1292 if (old_w == si->keyboard_grab_window)
1294 XGrabServer (si->dpy); /* ############ DANGER! */
1296 grab_kbd(si, ssi->screensaver_window);
1297 XUngrabServer (si->dpy);
1298 XSync (si->dpy, False); /* ###### (danger over) */
1301 /* Now we can destroy this window without horking our grabs. */
1303 XDestroyWindow (si->dpy, old_w);
1306 fprintf (stderr, "%s: destroyed old saver window 0x%lx.\n",
1307 progname, (unsigned long) old_w);
1310 old_c != DefaultColormapOfScreen (ssi->screen) &&
1311 old_c != ssi->demo_cmap)
1312 XFreeColormap (si->dpy, old_c);