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