ftp://ftp.uni-heidelberg.de/pub/X11/contrib/applications/xscreensaver-1.27.tar.Z
[xscreensaver] / driver / windows.c
1 /* xscreensaver, Copyright (c) 1991-1996 Jamie Zawinski <jwz@netscape.com>
2  *
3  * Permission to use, copy, modify, distribute, and sell this software and its
4  * documentation for any purpose is hereby granted without fee, provided that
5  * the above copyright notice appear in all copies and that both that
6  * copyright notice and this permission notice appear in supporting
7  * documentation.  No representations are made about the suitability of this
8  * software for any purpose.  It is provided "as is" without express or 
9  * implied warranty.
10  */
11
12 #include <stdio.h>
13 #include <X11/Xlib.h>
14 #include <X11/Xutil.h>
15 #include <X11/Xatom.h>
16 #include <X11/Xos.h>
17 #include <X11/Xmu/SysUtil.h>
18
19 #include <signal.h>             /* for the signal names */
20
21 #include "xscreensaver.h"
22
23 #ifdef HAVE_MIT_SAVER_EXTENSION
24 #include <X11/extensions/scrnsaver.h>
25 #endif /* HAVE_MIT_SAVER_EXTENSION */
26
27 #ifdef HAVE_SGI_SAVER_EXTENSION
28 #include <X11/extensions/XScreenSaver.h>
29 #endif /* HAVE_SGI_SAVER_EXTENSION */
30
31 extern Bool use_mit_saver_extension;
32 extern Bool use_sgi_saver_extension;
33
34 #if __STDC__
35 extern int kill (pid_t, int);           /* signal() is in sys/signal.h... */
36 #endif /* __STDC__ */
37
38 extern Time timeout;
39
40 extern Bool lock_p, demo_mode_p;
41
42 Atom XA_VROOT, XA_XSETROOT_ID;
43 Atom XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
44
45 #if __STDC__
46 extern void describe_visual (FILE *, Display *, Visual *);
47 extern void reset_stderr (void);
48 #endif
49
50 Window screensaver_window = 0;
51 Cursor cursor;
52 Colormap cmap, cmap2;
53 Bool install_cmap_p;
54 Bool fade_p, unfade_p;
55 int fade_seconds, fade_ticks;
56
57 static unsigned long black_pixel;
58 static Window real_vroot, real_vroot_value;
59
60 #ifdef HAVE_MIT_SAVER_EXTENSION
61 Window server_mit_saver_window = 0;
62 #endif /* HAVE_MIT_SAVER_EXTENSION */
63
64 #define ALL_POINTER_EVENTS \
65         (ButtonPressMask | ButtonReleaseMask | EnterWindowMask | \
66          LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | \
67          Button1MotionMask | Button2MotionMask | Button3MotionMask | \
68          Button4MotionMask | Button5MotionMask | ButtonMotionMask)
69
70 /* I don't really understand Sync vs Async, but these seem to work... */
71 #define grab_kbd(win) \
72   XGrabKeyboard (dpy, (win), True, GrabModeSync, GrabModeAsync, CurrentTime)
73 #define grab_mouse(win) \
74   XGrabPointer (dpy, (win), True, ALL_POINTER_EVENTS, \
75                 GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime)
76
77 void
78 grab_keyboard_and_mouse P((void))
79 {
80   Status status;
81   XSync (dpy, False);
82
83   if (demo_mode_p) return;
84
85   status = grab_kbd (screensaver_window);
86   if (status != GrabSuccess)
87     {   /* try again in a second */
88       sleep (1);
89       status = grab_kbd (screensaver_window);
90       if (status != GrabSuccess)
91         fprintf (stderr, "%s: %scouldn't grab keyboard!  (%d)\n",
92                  progname, (verbose_p ? "## " : ""), status);
93     }
94   status = grab_mouse (screensaver_window);
95   if (status != GrabSuccess)
96     {   /* try again in a second */
97       sleep (1);
98       status = grab_mouse (screensaver_window);
99       if (status != GrabSuccess)
100         fprintf (stderr, "%s: %scouldn't grab pointer!  (%d)\n",
101                  progname, (verbose_p ? "## " : ""), status);
102     }
103 }
104
105 void
106 ungrab_keyboard_and_mouse P((void))
107 {
108   XUngrabPointer (dpy, CurrentTime);
109   XUngrabKeyboard (dpy, CurrentTime);
110 }
111
112
113 void
114 ensure_no_screensaver_running ()
115 {
116   int i;
117   Window root = RootWindowOfScreen (screen);
118   Window root2, parent, *kids;
119   unsigned int nkids;
120   int (*old_handler) ();
121
122   old_handler = XSetErrorHandler (BadWindow_ehandler);
123
124   if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
125     abort ();
126   if (root != root2)
127     abort ();
128   if (parent)
129     abort ();
130   for (i = 0; i < nkids; i++)
131     {
132       Atom type;
133       int format;
134       unsigned long nitems, bytesafter;
135       char *version;
136
137       if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
138                               False, XA_STRING, &type, &format, &nitems,
139                               &bytesafter, (unsigned char **) &version)
140           == Success
141           && type != None)
142         {
143           char *id;
144           if (!XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
145                                    False, XA_STRING, &type, &format, &nitems,
146                                    &bytesafter, (unsigned char **) &id)
147               == Success
148               || type == None)
149             id = "???";
150
151           fprintf (stderr,
152       "%s: %salready running on display %s (window 0x%x)\n from process %s.\n",
153                    progname, (verbose_p ? "## " : ""), DisplayString (dpy),
154                    (int) kids [i], id);
155           exit (1);
156         }
157     }
158
159   if (kids) XFree ((char *) kids);
160   XSync (dpy, False);
161   XSetErrorHandler (old_handler);
162 }
163
164
165 void
166 disable_builtin_screensaver ()
167 {
168   int server_timeout, server_interval, prefer_blank, allow_exp;
169   /* Turn off the server builtin saver if it is now running. */
170   XForceScreenSaver (dpy, ScreenSaverReset);
171   XGetScreenSaver (dpy, &server_timeout, &server_interval,
172                    &prefer_blank, &allow_exp);
173
174 #if defined(HAVE_MIT_SAVER_EXTENSION) || defined(HAVE_SGI_SAVER_EXTENSION)
175   if (use_mit_saver_extension || use_sgi_saver_extension)
176     {
177       /* Override the values specified with "xset" with our own parameters. */
178       allow_exp = True;
179       server_interval = 0;
180       server_timeout = (timeout / 1000);
181
182       /* The SGI extension won't give us events unless blanking is on.
183          I think (unsure right now) that the MIT extension is the opposite. */
184       prefer_blank = (use_sgi_saver_extension ? True : False);
185
186       if (verbose_p)
187         fprintf (stderr,
188                  "%s: configuring server for saver timeout of %d seconds.\n",
189                  progname, server_timeout);
190       XSetScreenSaver (dpy, server_timeout, server_interval,
191                        prefer_blank, allow_exp);
192     }
193   else
194 #endif /* HAVE_MIT_SAVER_EXTENSION || HAVE_SGI_SAVER_EXTENSION */
195   if (server_timeout != 0)
196     {
197       server_timeout = 0;
198       XSetScreenSaver (dpy, server_timeout, server_interval,
199                        prefer_blank, allow_exp);
200       printf ("%s%sisabling server builtin screensaver.\n\
201         You can re-enable it with \"xset s on\".\n",
202               (verbose_p ? "" : progname), (verbose_p ? "\n\tD" : ": d"));
203     }
204 }
205
206 \f
207 /* Virtual-root hackery */
208
209 #ifdef _VROOT_H_
210 ERROR!  You must not include vroot.h in this file.
211 #endif
212
213 static void
214 #if __STDC__
215 store_vroot_property (Window win, Window value)
216 #else
217 store_vroot_property (win, value)
218      Window win, value;
219 #endif
220 {
221 #if 0
222   printf ("%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", progname, 
223           win,
224           (win == screensaver_window ? "ScreenSaver" :
225            (win == real_vroot ? "VRoot" :
226             (win == real_vroot_value ? "Vroot_value" : "???"))),
227           value,
228           (value == screensaver_window ? "ScreenSaver" :
229            (value == real_vroot ? "VRoot" :
230             (value == real_vroot_value ? "Vroot_value" : "???"))));
231 #endif
232   XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
233                    (unsigned char *) &value, 1);
234 }
235
236 static void
237 #if __STDC__
238 remove_vroot_property (Window win)
239 #else
240 remove_vroot_property (win)
241      Window win;
242 #endif
243 {
244 #if 0
245   printf ("%s: removing XA_VROOT from 0x%x (%s)\n", progname, win, 
246           (win == screensaver_window ? "ScreenSaver" :
247            (win == real_vroot ? "VRoot" :
248             (win == real_vroot_value ? "Vroot_value" : "???"))));
249 #endif
250   XDeleteProperty (dpy, win, XA_VROOT);
251 }
252
253
254 static void
255 kill_xsetroot_data P((void))
256 {
257   Atom type;
258   int format;
259   unsigned long nitems, bytesafter;
260   Pixmap *dataP = 0;
261
262   /* If the user has been using xv or xsetroot as a screensaver (to display
263      an image on the screensaver window, as a kind of slideshow) then the
264      pixmap and its associated color cells have been put in RetainPermanent
265      CloseDown mode.  Since we're not destroying the xscreensaver window,
266      but merely unmapping it, we need to free these resources or those
267      colormap cells will stay allocated while the screensaver is off.  (We
268      could just delete the screensaver window and recreate it later, but
269      that could cause other problems.)  This code does an atomic read-and-
270      delete of the _XSETROOT_ID property, and if it held a pixmap, then we
271      cause the RetainPermanent resources of the client which created it
272      (and which no longer exists) to be freed.
273    */
274   if (XGetWindowProperty (dpy, screensaver_window, XA_XSETROOT_ID, 0, 1,
275                           True, AnyPropertyType, &type, &format, &nitems, 
276                           &bytesafter, (unsigned char **) &dataP)
277       == Success
278       && type != None)
279     {
280       if (dataP && *dataP && type == XA_PIXMAP && format == 32 &&
281           nitems == 1 && bytesafter == 0)
282         {
283           if (verbose_p)
284             printf ("%s: destroying xsetroot data (0x%lX).\n",
285                     progname, *dataP);
286           XKillClient (dpy, *dataP);
287         }
288       else
289         fprintf (stderr, "%s: %sdeleted unrecognised _XSETROOT_ID property: \n\
290         %lu, %lu; type: %lu, format: %d, nitems: %lu, bytesafter %ld\n",
291                  progname, (verbose_p ? "## " : ""),
292                  (unsigned long) dataP, (dataP ? *dataP : 0), type,
293                  format, nitems, bytesafter);
294     }
295 }
296
297
298 static void handle_signals P((Bool on_p));
299
300 static void
301 save_real_vroot P((void))
302 {
303   int i;
304   Window root = RootWindowOfScreen (screen);
305   Window root2, parent, *kids;
306   unsigned int nkids;
307
308   real_vroot = 0;
309   real_vroot_value = 0;
310   if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
311     abort ();
312   if (root != root2)
313     abort ();
314   if (parent)
315     abort ();
316   for (i = 0; i < nkids; i++)
317     {
318       Atom type;
319       int format;
320       unsigned long nitems, bytesafter;
321       Window *vrootP = 0;
322
323       if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
324                               &type, &format, &nitems, &bytesafter,
325                               (unsigned char **) &vrootP)
326           != Success)
327         continue;
328       if (! vrootP)
329         continue;
330       if (real_vroot)
331         {
332           if (*vrootP == screensaver_window) abort ();
333           fprintf (stderr,
334             "%s: %smore than one virtual root window found (0x%x and 0x%x).\n",
335                    progname, (verbose_p ? "## " : ""),
336                    (int) real_vroot, (int) kids [i]);
337           exit (1);
338         }
339       real_vroot = kids [i];
340       real_vroot_value = *vrootP;
341     }
342
343   if (real_vroot)
344     {
345       handle_signals (True);
346       remove_vroot_property (real_vroot);
347       XSync (dpy, False);
348     }
349
350   XFree ((char *) kids);
351 }
352
353 static Bool
354 restore_real_vroot_1 P((void))
355 {
356   if (verbose_p && real_vroot)
357     printf ("%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
358             progname, (unsigned long) real_vroot);
359   remove_vroot_property (screensaver_window);
360   if (real_vroot)
361     {
362       store_vroot_property (real_vroot, real_vroot_value);
363       real_vroot = 0;
364       real_vroot_value = 0;
365       /* make sure the property change gets there before this process
366          terminates!  We might be doing this because we have intercepted
367          SIGTERM or something. */
368       XSync (dpy, False);
369       return True;
370     }
371   return False;
372 }
373
374 void
375 restore_real_vroot ()
376 {
377   if (restore_real_vroot_1 ())
378     handle_signals (False);
379 }
380
381 \f
382 /* Signal hackery to ensure that the vroot doesn't get left in an 
383    inconsistent state
384  */
385
386 static const char *sig_names [255] = { 0 };
387
388 static void
389 restore_real_vroot_handler (sig)
390      int sig;
391 {
392   signal (sig, SIG_DFL);
393   if (restore_real_vroot_1 ())
394     fprintf (stderr, "\n%s: %s%s (%d) intercepted, vroot restored.\n",
395              progname, (verbose_p ? "## " : ""),
396              ((sig < sizeof(sig_names) && sig >= 0 && sig_names [sig])
397               ? sig_names [sig] : "unknown signal"),
398              sig);
399   kill (getpid (), sig);
400 }
401
402
403 static void
404 #if __STDC__
405 catch_signal (int sig, char *signame, Bool on_p)
406 #else
407 catch_signal (sig, signame, on_p)
408      int sig;
409      char *signame;
410      Bool on_p;
411 #endif
412 {
413   if (! on_p)
414     signal (sig, SIG_DFL);
415   else
416     {
417       sig_names [sig] = signame;
418       if (((int) signal (sig, restore_real_vroot_handler)) == -1)
419         {
420           char buf [255];
421           sprintf (buf, "%s: %scouldn't catch %s (%d)", progname,
422                    (verbose_p ? "## " : ""), signame, sig);
423           perror (buf);
424           restore_real_vroot ();
425           exit (1);
426         }
427     }
428 }
429
430 static void
431 handle_signals (on_p)
432      Bool on_p;
433 {
434 #if 0
435   if (on_p) printf ("handling signals\n");
436   else printf ("unhandling signals\n");
437 #endif
438
439   catch_signal (SIGHUP,  "SIGHUP",  on_p);
440   catch_signal (SIGINT,  "SIGINT",  on_p);
441   catch_signal (SIGQUIT, "SIGQUIT", on_p);
442   catch_signal (SIGILL,  "SIGILL",  on_p);
443   catch_signal (SIGTRAP, "SIGTRAP", on_p);
444   catch_signal (SIGIOT,  "SIGIOT",  on_p);
445   catch_signal (SIGABRT, "SIGABRT", on_p);
446 #ifdef SIGEMT
447   catch_signal (SIGEMT,  "SIGEMT",  on_p);
448 #endif
449   catch_signal (SIGFPE,  "SIGFPE",  on_p);
450   catch_signal (SIGBUS,  "SIGBUS",  on_p);
451   catch_signal (SIGSEGV, "SIGSEGV", on_p);
452 #ifdef SIGSYS
453   catch_signal (SIGSYS,  "SIGSYS",  on_p);
454 #endif
455   catch_signal (SIGTERM, "SIGTERM", on_p);
456 #ifdef SIGXCPU
457   catch_signal (SIGXCPU, "SIGXCPU", on_p);
458 #endif
459 #ifdef SIGXFSZ
460   catch_signal (SIGXFSZ, "SIGXFSZ", on_p);
461 #endif
462 #ifdef SIGDANGER
463   catch_signal (SIGDANGER, "SIGDANGER", on_p);
464 #endif
465 }
466
467 \f
468 /* Managing the actual screensaver window */
469
470 Bool
471 window_exists_p (dpy, window)
472      Display *dpy;
473      Window window;
474 {
475   int (*old_handler) ();
476   XWindowAttributes xgwa;
477   xgwa.screen = 0;
478   old_handler = XSetErrorHandler (BadWindow_ehandler);
479   XGetWindowAttributes (dpy, window, &xgwa);
480   XSync (dpy, False);
481   XSetErrorHandler (old_handler);
482   return (xgwa.screen != 0);
483 }
484
485 void
486 initialize_screensaver_window P((void))
487 {
488   /* This resets the screensaver window as fully as possible, since there's
489      no way of knowing what some random client may have done to us in the
490      meantime.  We could just destroy and recreate the window, but that has
491      its own set of problems...
492    */
493   XColor black;
494   XClassHint class_hints;
495   XSetWindowAttributes attrs;
496   unsigned long attrmask;
497   int width = WidthOfScreen (screen);
498   int height = HeightOfScreen (screen);
499   char id [2048];
500
501   reset_stderr ();
502
503   black.red = black.green = black.blue = 0;
504
505   if (cmap == DefaultColormapOfScreen (screen))
506     cmap = 0;
507
508   if (install_cmap_p || visual != DefaultVisualOfScreen (screen))
509     {
510       if (! cmap)
511         {
512           cmap = XCreateColormap (dpy, RootWindowOfScreen (screen),
513                                   visual, AllocNone);
514           if (! XAllocColor (dpy, cmap, &black)) abort ();
515           black_pixel = black.pixel;
516         }
517     }
518   else
519     {
520       if (cmap)
521         {
522           XFreeColors (dpy, cmap, &black_pixel, 1, 0);
523           XFreeColormap (dpy, cmap);
524         }
525       cmap = DefaultColormapOfScreen (screen);
526       black_pixel = BlackPixelOfScreen (screen);
527     }
528
529   if (cmap2)
530     {
531       XFreeColormap (dpy, cmap2);
532       cmap2 = 0;
533     }
534
535   if (fade_p)
536     {
537       cmap2 = copy_colormap (dpy, cmap, 0);
538       if (! cmap2)
539         fade_p = unfade_p = 0;
540     }
541
542   attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
543               CWBackPixel | CWBackingPixel | CWBorderPixel);
544   attrs.override_redirect = True;
545
546   /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
547      actually be reading these events during normal operation; but we still
548      need to see Button events for demo-mode to work properly.
549    */
550   attrs.event_mask = (KeyPressMask | KeyReleaseMask |
551                       ButtonPressMask | ButtonReleaseMask |
552                       PointerMotionMask);
553
554   attrs.backing_store = NotUseful;
555   attrs.colormap = cmap;
556   attrs.background_pixel = black_pixel;
557   attrs.backing_pixel = black_pixel;
558   attrs.border_pixel = black_pixel;
559
560 #if 0
561   if (demo_mode_p || lock_p) width = width / 2;  /* #### */
562 #endif
563
564   if (screensaver_window || !verbose_p)
565     ;
566   else if (visual == DefaultVisualOfScreen (screen))
567     {
568       fprintf (stderr, "%s: using default visual ", progname);
569       describe_visual (stderr, dpy, visual);
570     }
571   else
572     {
573       fprintf (stderr, "%s: using visual:   ", progname);
574       describe_visual (stderr, dpy, visual);
575       fprintf (stderr, "%s: default visual: ", progname);
576       describe_visual (stderr, dpy, DefaultVisualOfScreen (screen));
577     }
578
579 #ifdef HAVE_MIT_SAVER_EXTENSION
580   if (use_mit_saver_extension)
581     {
582       XScreenSaverInfo *info;
583       Window root = RootWindowOfScreen (screen);
584
585       /* This call sets the server screensaver timeouts to what we think
586          they should be (based on the resources and args xscreensaver was
587          started with.)  It's important that we do this to sync back up
588          with the server - if we have turned on prematurely, as by an
589          ACTIVATE ClientMessage, then the server may decide to activate
590          the screensaver while it's already active.  That's ok for us,
591          since we would know to ignore that ScreenSaverActivate event,
592          but a side effect of this would be that the server would map its
593          saver window (which we then hide again right away) meaning that
594          the bits currently on the screen get blown away.  Ugly. */
595 #if 0
596       /* #### Ok, that doesn't work - when we tell the server that the
597          screensaver is "off" it sends us a Deactivate event, which is
598          sensible... but causes the saver to never come on.  Hmm. */
599       disable_builtin_screensaver ();
600 #endif /* 0 */
601
602 #if 0
603       /* #### The MIT-SCREEN-SAVER extension gives us access to the
604          window that the server itself uses for saving the screen.
605          However, using this window in any way, in particular, calling
606          XScreenSaverSetAttributes() as below, tends to make the X server
607          crash.  So fuck it, let's try and get along without using it...
608
609          It's also inconvenient to use this window because it doesn't
610          always exist (though the ID is constant.)  So to use this
611          window, we'd have to reimplement the ACTIVATE ClientMessage to
612          tell the *server* to tell *us* to turn on, to cause the window
613          to get created at the right time.  Gag.  */
614       XScreenSaverSetAttributes (dpy, root,
615                                  0, 0, width, height, 0,
616                                  visual_depth, InputOutput, visual,
617                                  attrmask, &attrs);
618       XSync (dpy, False);
619 #endif /* 0 */
620
621       info = XScreenSaverAllocInfo ();
622       XScreenSaverQueryInfo (dpy, root, info);
623       server_mit_saver_window = info->window;
624       if (! server_mit_saver_window) abort ();
625       XFree (info);
626     }
627 #endif /* HAVE_MIT_SAVER_EXTENSION */
628
629   if (screensaver_window)
630     {
631       XWindowChanges changes;
632       unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
633       changes.x = 0;
634       changes.y = 0;
635       changes.width = width;
636       changes.height = height;
637       changes.border_width = 0;
638
639       XConfigureWindow (dpy, screensaver_window, changesmask, &changes);
640       XChangeWindowAttributes (dpy, screensaver_window, attrmask, &attrs);
641     }
642   else
643     {
644       screensaver_window =
645         XCreateWindow (dpy, RootWindowOfScreen (screen), 0, 0, width, height,
646                        0, visual_depth, InputOutput, visual, attrmask,
647                        &attrs);
648     }
649
650 #ifdef HAVE_MIT_SAVER_EXTENSION
651   if (!use_mit_saver_extension ||
652       window_exists_p (dpy, screensaver_window))
653     /* When using the MIT-SCREEN-SAVER extension, the window pointed to
654        by screensaver_window only exists while the saver is active.
655        So we must be careful to only try and manipulate it while it
656        exists...
657      */
658 #endif /* HAVE_MIT_SAVER_EXTENSION */
659     {
660       class_hints.res_name = progname;
661       class_hints.res_class = progclass;
662       XSetClassHint (dpy, screensaver_window, &class_hints);
663       XStoreName (dpy, screensaver_window, "screensaver");
664       XChangeProperty (dpy, screensaver_window, XA_SCREENSAVER_VERSION,
665                        XA_STRING, 8, PropModeReplace,
666                        (unsigned char *) screensaver_version,
667                        strlen (screensaver_version));
668
669       sprintf (id, "%d on host ", getpid ());
670       if (! XmuGetHostname (id + strlen (id), sizeof (id) - strlen (id) - 1))
671         strcat (id, "???");
672       XChangeProperty (dpy, screensaver_window, XA_SCREENSAVER_ID, XA_STRING,
673                        8, PropModeReplace, (unsigned char *) id, strlen (id));
674
675       if (!cursor)
676         {
677           Pixmap bit;
678           bit = XCreatePixmapFromBitmapData (dpy, screensaver_window, "\000",
679                                              1, 1,
680                                              BlackPixelOfScreen (screen),
681                                              BlackPixelOfScreen (screen), 1);
682           cursor = XCreatePixmapCursor (dpy, bit, bit, &black, &black, 0, 0);
683           XFreePixmap (dpy, bit);
684         }
685
686       XSetWindowBackground (dpy, screensaver_window, black_pixel);
687       if (! demo_mode_p)
688         XDefineCursor (dpy, screensaver_window, cursor);
689       else
690         XUndefineCursor (dpy, screensaver_window);
691     }
692 }
693
694
695 void 
696 raise_window (inhibit_fade, between_hacks_p)
697      Bool inhibit_fade, between_hacks_p;
698 {
699   initialize_screensaver_window ();
700
701   if (fade_p && !inhibit_fade && !demo_mode_p)
702     {
703       int grabbed;
704       Colormap current_map = (between_hacks_p
705                               ? cmap
706                               : DefaultColormapOfScreen (screen));
707       copy_colormap (dpy, current_map, cmap2);
708       if (verbose_p) fprintf (stderr, "%s: fading... ", progname);
709       XGrabServer (dpy);
710       /* grab and blacken mouse on the root window (saver not mapped yet) */
711       grabbed = grab_mouse (RootWindowOfScreen (screen));
712       /* fade what's on the screen to black */
713       XInstallColormap (dpy, cmap2);
714       fade_colormap (dpy, current_map, cmap2, fade_seconds, fade_ticks,
715                      True, True);
716       if (verbose_p) fprintf (stderr, "fading done.\n");
717       XClearWindow (dpy, screensaver_window);
718       XMapRaised (dpy, screensaver_window);
719
720 #ifdef HAVE_MIT_SAVER_EXTENSION
721       if (server_mit_saver_window &&
722           window_exists_p (dpy, server_mit_saver_window))
723         XUnmapWindow (dpy, server_mit_saver_window);
724 #endif /* HAVE_MIT_SAVER_EXTENSION */
725
726       /* Once the saver window is up, restore the colormap.
727          (The "black" pixels of the two colormaps are compatible.) */
728       XInstallColormap (dpy, cmap);
729       if (grabbed == GrabSuccess)
730         XUngrabPointer (dpy, CurrentTime);
731       XUngrabServer (dpy);
732     }
733   else
734     {
735       XClearWindow (dpy, screensaver_window);
736       XMapRaised (dpy, screensaver_window);
737 #ifdef HAVE_MIT_SAVER_EXTENSION
738       if (server_mit_saver_window &&
739           window_exists_p (dpy, server_mit_saver_window))
740         XUnmapWindow (dpy, server_mit_saver_window);
741 #endif /* HAVE_MIT_SAVER_EXTENSION */
742     }
743
744   if (install_cmap_p)
745     XInstallColormap (dpy, cmap);
746 }
747
748 #ifdef __hpux
749  /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
750     or BadAccess errors occur. */
751 static Bool hp_locked_p = False;
752 #endif /* __hpux */
753
754 void
755 blank_screen ()
756 {
757   save_real_vroot ();
758   store_vroot_property (screensaver_window, screensaver_window);
759   raise_window (False, False);
760   grab_keyboard_and_mouse ();
761 #ifdef __hpux
762   if (lock_p && !hp_locked_p)
763     XHPDisableReset (dpy);      /* turn off C-Sh-Reset */
764   hp_locked_p = True;
765 #endif
766 }
767
768 void
769 unblank_screen ()
770 {
771   if (unfade_p && !demo_mode_p)
772     {
773       int grabbed;
774       Colormap default_map = DefaultColormapOfScreen (screen);
775       blacken_colormap (dpy, cmap2);
776       if (verbose_p) fprintf (stderr, "%s: unfading... ", progname);
777       XGrabServer (dpy);
778       /* grab and blacken mouse on the root window. */
779       grabbed = grab_mouse (RootWindowOfScreen (screen));
780       XInstallColormap (dpy, cmap2);
781       XUnmapWindow (dpy, screensaver_window);
782       fade_colormap (dpy, default_map, cmap2, fade_seconds, fade_ticks,
783                      False, True);
784       XInstallColormap (dpy, default_map);
785       if (verbose_p) fprintf (stderr, "unfading done.\n");
786       if (grabbed == GrabSuccess)
787         XUngrabPointer (dpy, CurrentTime);
788       XUngrabServer (dpy);
789     }
790   else
791     {
792       if (install_cmap_p)
793         {
794           XClearWindow (dpy, screensaver_window); /* avoid technicolor */
795           XInstallColormap (dpy, DefaultColormapOfScreen (screen));
796         }
797       XUnmapWindow (dpy, screensaver_window);
798     }
799
800
801   /* If the focus window does has a non-default colormap, then install
802      that colormap as well.  (On SGIs, this will cause both the root map
803      and the focus map to be installed simultaniously.  It'd be nice to
804      pick up the other colormaps that had been installed, too; perhaps
805      XListInstalledColormaps could be used for that?)
806    */
807   {
808     Window focus = 0;
809     int revert_to;
810     XGetInputFocus (dpy, &focus, &revert_to);
811     if (focus && focus != PointerRoot && focus != None)
812       {
813         XWindowAttributes xgwa;
814         Colormap default_map = DefaultColormapOfScreen (screen);
815         xgwa.colormap = 0;
816         XGetWindowAttributes (dpy, focus, &xgwa);
817         if (xgwa.colormap &&
818             xgwa.colormap != default_map)
819           XInstallColormap (dpy, xgwa.colormap);
820       }
821   }
822
823
824   kill_xsetroot_data ();
825   ungrab_keyboard_and_mouse ();
826   restore_real_vroot ();
827
828 #ifdef __hpux
829   if (lock_p && hp_locked_p)
830     XHPEnableReset (dpy);       /* turn C-Sh-Reset back on */
831   hp_locked_p = False;
832 #endif
833 }