http://slackware.bholcomb.com/slackware/slackware-11.0/source/xap/xscreensaver/xscree...
[xscreensaver] / driver / windows.c
1 /* windows.c --- turning the screen black; dealing with visuals, virtual roots.
2  * xscreensaver, Copyright (c) 1991-2006 Jamie Zawinski <jwz@jwz.org>
3  *
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 
10  * implied warranty.
11  */
12
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
16
17 #ifdef VMS
18 # include <unixlib.h>           /* for getpid() */
19 # include "vms-gtod.h"          /* for gettimeofday() */
20 #endif /* VMS */
21
22 #ifndef VMS
23 # include <pwd.h>               /* for getpwuid() */
24 #else /* VMS */
25 # include "vms-pwd.h"
26 #endif /* VMS */
27
28 #ifdef HAVE_UNAME
29 # include <sys/utsname.h>       /* for uname() */
30 #endif /* HAVE_UNAME */
31
32 #include <stdio.h>
33 /* #include <X11/Xproto.h>      / * for CARD32 */
34 #include <X11/Xlib.h>
35 #include <X11/Xutil.h>          /* for XSetClassHint() */
36 #include <X11/Xatom.h>
37 #include <X11/Xos.h>            /* for time() */
38 #include <signal.h>             /* for the signal names */
39 #include <time.h>
40 #include <sys/time.h>
41
42 /* You might think that to store an array of 32-bit quantities onto a
43    server-side property, you would pass an array of 32-bit data quantities
44    into XChangeProperty().  You would be wrong.  You have to use an array
45    of longs, even if long is 64 bits (using 32 of each 64.)
46  */
47 typedef long PROP32;
48
49 #ifdef HAVE_MIT_SAVER_EXTENSION
50 # include <X11/extensions/scrnsaver.h>
51 #endif /* HAVE_MIT_SAVER_EXTENSION */
52
53 #ifdef HAVE_XF86VMODE
54 # include <X11/extensions/xf86vmode.h>
55 #endif /* HAVE_XF86VMODE */
56
57 #ifdef HAVE_XINERAMA
58 # include <X11/extensions/Xinerama.h>
59 #endif /* HAVE_XINERAMA */
60
61 /* This file doesn't need the Xt headers, so stub these types out... */
62 #undef XtPointer
63 #define XtAppContext void*
64 #define XrmDatabase  void*
65 #define XtIntervalId void*
66 #define XtPointer    void*
67 #define Widget       void*
68
69 #include "xscreensaver.h"
70 #include "visual.h"
71 #include "fade.h"
72
73
74 extern int kill (pid_t, int);           /* signal() is in sys/signal.h... */
75
76 Atom XA_VROOT, XA_XSETROOT_ID, XA_ESETROOT_PMAP_ID, XA_XROOTPMAP_ID;
77 Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
78 Atom XA_SCREENSAVER_STATUS;
79
80
81 extern saver_info *global_si_kludge;    /* I hate C so much... */
82
83 static void maybe_transfer_grabs (saver_screen_info *ssi,
84                                   Window old_w, Window new_w, int new_screen);
85
86 #define ALL_POINTER_EVENTS \
87         (ButtonPressMask | ButtonReleaseMask | EnterWindowMask | \
88          LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | \
89          Button1MotionMask | Button2MotionMask | Button3MotionMask | \
90          Button4MotionMask | Button5MotionMask | ButtonMotionMask)
91
92
93 static const char *
94 grab_string(int status)
95 {
96   switch (status)
97     {
98     case GrabSuccess:     return "GrabSuccess";
99     case AlreadyGrabbed:  return "AlreadyGrabbed";
100     case GrabInvalidTime: return "GrabInvalidTime";
101     case GrabNotViewable: return "GrabNotViewable";
102     case GrabFrozen:      return "GrabFrozen";
103     default:
104       {
105         static char foo[255];
106         sprintf(foo, "unknown status: %d", status);
107         return foo;
108       }
109     }
110 }
111
112 static int
113 grab_kbd(saver_info *si, Window w, int screen_no)
114 {
115   saver_preferences *p = &si->prefs;
116   int status = XGrabKeyboard (si->dpy, w, True,
117                               /* I don't really understand Sync vs Async,
118                                  but these seem to work... */
119                               GrabModeSync, GrabModeAsync,
120                               CurrentTime);
121   if (status == GrabSuccess)
122     {
123       si->keyboard_grab_window = w;
124       si->keyboard_grab_screen = screen_no;
125     }
126
127   if (p->verbose_p)
128     fprintf(stderr, "%s: %d: grabbing keyboard on 0x%lx... %s.\n",
129             blurb(), screen_no, (unsigned long) w, grab_string(status));
130   return status;
131 }
132
133
134 static int
135 grab_mouse (saver_info *si, Window w, Cursor cursor, int screen_no)
136 {
137   saver_preferences *p = &si->prefs;
138   int status = XGrabPointer (si->dpy, w, True, ALL_POINTER_EVENTS,
139                              GrabModeAsync, GrabModeAsync, w,
140                              cursor, CurrentTime);
141   if (status == GrabSuccess)
142     {
143       si->mouse_grab_window = w;
144       si->mouse_grab_screen = screen_no;
145     }
146
147   if (p->verbose_p)
148     fprintf(stderr, "%s: %d: grabbing mouse on 0x%lx... %s.\n",
149             blurb(), screen_no, (unsigned long) w, grab_string(status));
150   return status;
151 }
152
153
154 static void
155 ungrab_kbd(saver_info *si)
156 {
157   saver_preferences *p = &si->prefs;
158   XUngrabKeyboard(si->dpy, CurrentTime);
159   if (p->verbose_p)
160     fprintf(stderr, "%s: %d: ungrabbing keyboard (was 0x%lx).\n",
161             blurb(), si->keyboard_grab_screen,
162             (unsigned long) si->keyboard_grab_window);
163   si->keyboard_grab_window = 0;
164 }
165
166
167 static void
168 ungrab_mouse(saver_info *si)
169 {
170   saver_preferences *p = &si->prefs;
171   XUngrabPointer(si->dpy, CurrentTime);
172   if (p->verbose_p)
173     fprintf(stderr, "%s: %d: ungrabbing mouse (was 0x%lx).\n",
174             blurb(), si->mouse_grab_screen,
175             (unsigned long) si->mouse_grab_window);
176   si->mouse_grab_window = 0;
177 }
178
179
180 /* Apparently there is this program called "rdesktop" which is a windows
181    terminal server client for Unix.  It would seem that this program holds
182    the keyboard GRABBED the whole time it has focus!  This is, of course,
183    completely idiotic: the whole point of grabbing is to get events when
184    you do *not* have focus, so grabbing *only when* you have focus is
185    completely redundant -- unless your goal is to make xscreensaver not
186    able to ever lock the screen when your program is running.
187
188    If xscreensaver blanks while rdesktop still has a keyboard grab, then
189    when we try to prompt for the password, we won't get the characters:
190    they'll be typed into rdesktop.
191
192    Perhaps rdesktop will release its keyboard grab if it loses focus?
193    What the hell, let's give it a try.  If we fail to grab the keyboard
194    four times in a row, we forcibly set focus to "None" and try four
195    more times.  (We don't touch focus unless we're already having a hard
196    time getting a grab.)
197  */
198 static void
199 nuke_focus (saver_info *si, int screen_no)
200 {
201   saver_preferences *p = &si->prefs;
202   Window focus = 0;
203   int rev = 0;
204
205   XGetInputFocus (si->dpy, &focus, &rev);
206
207   if (p->verbose_p)
208     {
209       char w[255], r[255];
210
211       if      (focus == PointerRoot) strcpy (w, "PointerRoot");
212       else if (focus == None)        strcpy (w, "None");
213       else    sprintf (w, "0x%lx", (unsigned long) focus);
214
215       if      (rev == RevertToParent)      strcpy (r, "RevertToParent");
216       else if (rev == RevertToPointerRoot) strcpy (r, "RevertToPointerRoot");
217       else if (rev == RevertToNone)        strcpy (r, "RevertToNone");
218       else    sprintf (r, "0x%x", rev);
219
220       fprintf (stderr, "%s: %d: removing focus from %s / %s.\n",
221                blurb(), screen_no, w, r);
222     }
223
224   XSetInputFocus (si->dpy, None, RevertToNone, CurrentTime);
225   XSync (si->dpy, False);
226 }
227
228
229 static Bool
230 grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor,
231                          int screen_no)
232 {
233   Status mstatus = 0, kstatus = 0;
234   int i;
235   int retries = 4;
236   Bool focus_fuckus = False;
237
238  AGAIN:
239
240   for (i = 0; i < retries; i++)
241     {
242       XSync (si->dpy, False);
243       kstatus = grab_kbd (si, window, screen_no);
244       if (kstatus == GrabSuccess)
245         break;
246
247       /* else, wait a second and try to grab again. */
248       sleep (1);
249     }
250
251   if (kstatus != GrabSuccess)
252     {
253       fprintf (stderr, "%s: couldn't grab keyboard!  (%s)\n",
254                blurb(), grab_string(kstatus));
255
256       if (! focus_fuckus)
257         {
258           focus_fuckus = True;
259           nuke_focus (si, screen_no);
260           goto AGAIN;
261         }
262     }
263
264   for (i = 0; i < retries; i++)
265     {
266       XSync (si->dpy, False);
267       mstatus = grab_mouse (si, window, cursor, screen_no);
268       if (mstatus == GrabSuccess)
269         break;
270
271       /* else, wait a second and try to grab again. */
272       sleep (1);
273     }
274
275   if (mstatus != GrabSuccess)
276     fprintf (stderr, "%s: couldn't grab pointer!  (%s)\n",
277              blurb(), grab_string(mstatus));
278
279
280   /* When should we allow blanking to proceed?  The current theory
281      is that a keyboard grab is manditory; a mouse grab is optional.
282
283      - If we don't have a keyboard grab, then we won't be able to
284        read a password to unlock, so the kbd grab is manditory.
285        (We can't conditionalize this on locked_p, because someone
286        might run "xscreensaver-command -lock" at any time.)
287
288      - If we don't have a mouse grab, then we might not see mouse
289        clicks as a signal to unblank -- but we will still see kbd
290        activity, so that's not a disaster.
291    */
292
293   if (kstatus != GrabSuccess)   /* Do not blank without a kbd grab.   */
294     return False;
295
296   return True;                  /* Grab is good, go ahead and blank.  */
297 }
298
299 static void
300 ungrab_keyboard_and_mouse (saver_info *si)
301 {
302   ungrab_mouse (si);
303   ungrab_kbd (si);
304 }
305
306
307 int
308 move_mouse_grab (saver_info *si, Window to, Cursor cursor, int to_screen_no)
309 {
310   Window old = si->mouse_grab_window;
311
312   if (old == 0)
313     return grab_mouse (si, to, cursor, to_screen_no);
314   else
315     {
316       saver_preferences *p = &si->prefs;
317       int status;
318
319       XSync (si->dpy, False);
320       XGrabServer (si->dpy);                    /* ############ DANGER! */
321       XSync (si->dpy, False);
322
323       if (p->verbose_p)
324         fprintf(stderr, "%s: grabbing server...\n", blurb());
325
326       ungrab_mouse (si);
327       status = grab_mouse (si, to, cursor, to_screen_no);
328
329       if (status != GrabSuccess)   /* Augh! */
330         {
331           sleep (1);               /* Note dramatic evil of sleeping
332                                       with server grabbed. */
333           XSync (si->dpy, False);
334           status = grab_mouse (si, to, cursor, to_screen_no);
335         }
336
337       if (status != GrabSuccess)   /* Augh!  Try to get the old one back... */
338         grab_mouse (si, old, cursor, to_screen_no);
339
340       XUngrabServer (si->dpy);
341       XSync (si->dpy, False);                   /* ###### (danger over) */
342
343       if (p->verbose_p)
344         fprintf(stderr, "%s: ungrabbing server.\n", blurb());
345
346       return status;
347     }
348 }
349
350
351 /* Prints an error message to stderr and returns True if there is another
352    xscreensaver running already.  Silently returns False otherwise. */
353 Bool
354 ensure_no_screensaver_running (Display *dpy, Screen *screen)
355 {
356   Bool status = 0;
357   int i;
358   Window root = RootWindowOfScreen (screen);
359   Window root2, parent, *kids;
360   unsigned int nkids;
361   XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler);
362
363   if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
364     abort ();
365   if (root != root2)
366     abort ();
367   if (parent)
368     abort ();
369   for (i = 0; i < nkids; i++)
370     {
371       Atom type;
372       int format;
373       unsigned long nitems, bytesafter;
374       unsigned char *version;
375
376       if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
377                               False, XA_STRING, &type, &format, &nitems,
378                               &bytesafter, &version)
379           == Success
380           && type != None)
381         {
382           unsigned char *id;
383           if (!XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
384                                    False, XA_STRING, &type, &format, &nitems,
385                                    &bytesafter, &id)
386               == Success
387               || type == None)
388             id = (unsigned char *) "???";
389
390           fprintf (stderr,
391       "%s: already running on display %s (window 0x%x)\n from process %s.\n",
392                    blurb(), DisplayString (dpy), (int) kids [i],
393                    (char *) id);
394           status = True;
395         }
396     }
397
398   if (kids) XFree ((char *) kids);
399   XSync (dpy, False);
400   XSetErrorHandler (old_handler);
401   return status;
402 }
403
404
405 \f
406 /* Virtual-root hackery */
407
408 #ifdef _VROOT_H_
409 ERROR!  You must not include vroot.h in this file.
410 #endif
411
412 static void
413 store_vroot_property (Display *dpy, Window win, Window value)
414 {
415 #if 0
416   if (p->verbose_p)
417     fprintf (stderr,
418              "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", blurb(), 
419              win,
420              (win == screensaver_window ? "ScreenSaver" :
421               (win == real_vroot ? "VRoot" :
422                (win == real_vroot_value ? "Vroot_value" : "???"))),
423              value,
424              (value == screensaver_window ? "ScreenSaver" :
425               (value == real_vroot ? "VRoot" :
426                (value == real_vroot_value ? "Vroot_value" : "???"))));
427 #endif
428   XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
429                    (unsigned char *) &value, 1);
430 }
431
432 static void
433 remove_vroot_property (Display *dpy, Window win)
434 {
435 #if 0
436   if (p->verbose_p)
437     fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", blurb(), win, 
438              (win == screensaver_window ? "ScreenSaver" :
439               (win == real_vroot ? "VRoot" :
440                (win == real_vroot_value ? "Vroot_value" : "???"))));
441 #endif
442   XDeleteProperty (dpy, win, XA_VROOT);
443 }
444
445
446 static Bool safe_XKillClient (Display *dpy, XID id);
447
448 #ifdef HAVE_XF86VMODE
449 static Bool safe_XF86VidModeGetViewPort (Display *, int, int *, int *);
450 #endif /* HAVE_XF86VMODE */
451
452
453 static void
454 kill_xsetroot_data_1 (Display *dpy, Window window,
455                       Atom prop, const char *atom_name,
456                       Bool verbose_p)
457 {
458   Atom type;
459   int format;
460   unsigned long nitems, bytesafter;
461   unsigned char *dataP = 0;
462
463   /* If the user has been using xv or xsetroot as a screensaver (to display
464      an image on the screensaver window, as a kind of slideshow) then the
465      pixmap and its associated color cells have been put in RetainPermanent
466      CloseDown mode.  Since we're not destroying the xscreensaver window,
467      but merely unmapping it, we need to free these resources or those
468      colormap cells will stay allocated while the screensaver is off.  (We
469      could just delete the screensaver window and recreate it later, but
470      that could cause other problems.)  This code does an atomic read-and-
471      delete of the _XSETROOT_ID property, and if it held a pixmap, then we
472      cause the RetainPermanent resources of the client which created it
473      (and which no longer exists) to be freed.
474
475      Update: it seems that Gnome and KDE do this same trick, but with the
476      properties "ESETROOT_PMAP_ID" and/or "_XROOTPMAP_ID" instead of
477      "_XSETROOT_ID".  So, we'll kill those too.
478    */
479   if (XGetWindowProperty (dpy, window, prop, 0, 1,
480                           True, AnyPropertyType, &type, &format, &nitems, 
481                           &bytesafter, &dataP)
482       == Success
483       && type != None)
484     {
485       Pixmap *pixP = (Pixmap *) dataP;
486       if (pixP && *pixP && type == XA_PIXMAP && format == 32 &&
487           nitems == 1 && bytesafter == 0)
488         {
489           if (verbose_p)
490             fprintf (stderr, "%s: destroying %s data (0x%lX).\n",
491                      blurb(), atom_name, *pixP);
492           safe_XKillClient (dpy, *pixP);
493         }
494       else
495         fprintf (stderr,
496                  "%s: deleted unrecognised %s property: \n"
497                  "\t%lu, %lu; type: %lu, format: %d, "
498                  "nitems: %lu, bytesafter %ld\n",
499                  blurb(), atom_name,
500                  (unsigned long) pixP, (pixP ? *pixP : 0), type,
501                  format, nitems, bytesafter);
502     }
503 }
504
505
506 static void
507 kill_xsetroot_data (Display *dpy, Window w, Bool verbose_p)
508 {
509   kill_xsetroot_data_1 (dpy, w, XA_XSETROOT_ID, "_XSETROOT_ID", verbose_p);
510   kill_xsetroot_data_1 (dpy, w, XA_ESETROOT_PMAP_ID, "ESETROOT_PMAP_ID",
511                         verbose_p);
512   kill_xsetroot_data_1 (dpy, w, XA_XROOTPMAP_ID, "_XROOTPMAP_ID", verbose_p);
513 }
514
515
516 static void
517 save_real_vroot (saver_screen_info *ssi)
518 {
519   saver_info *si = ssi->global;
520   Display *dpy = si->dpy;
521   Screen *screen = ssi->screen;
522   int i;
523   Window root = RootWindowOfScreen (screen);
524   Window root2, parent, *kids;
525   unsigned int nkids;
526   XErrorHandler old_handler;
527
528   /* It's possible that a window might be deleted between our call to
529      XQueryTree() and our call to XGetWindowProperty().  Don't die if
530      that happens (but just ignore that window, it's not the one we're
531      interested in anyway.)
532    */
533   XSync (dpy, False);
534   old_handler = XSetErrorHandler (BadWindow_ehandler);
535   XSync (dpy, False);
536
537   ssi->real_vroot = 0;
538   ssi->real_vroot_value = 0;
539   if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
540     abort ();
541   if (root != root2)
542     abort ();
543   if (parent)
544     abort ();
545   for (i = 0; i < nkids; i++)
546     {
547       Atom type;
548       int format;
549       unsigned long nitems, bytesafter;
550       unsigned char *dataP = 0;
551       Window *vrootP;
552       int j;
553
554       /* Skip this window if it is the xscreensaver window of any other
555          screen (this can happen in the Xinerama case.)
556        */
557       for (j = 0; j < si->nscreens; j++)
558         {
559           saver_screen_info *ssi2 = &si->screens[j];
560           if (kids[i] == ssi2->screensaver_window)
561             goto SKIP;
562         }
563
564       if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
565                               &type, &format, &nitems, &bytesafter,
566                               &dataP)
567           != Success)
568         continue;
569       if (! dataP)
570         continue;
571
572       vrootP = (Window *) dataP;
573       if (ssi->real_vroot)
574         {
575           if (*vrootP == ssi->screensaver_window) abort ();
576           fprintf (stderr,
577             "%s: more than one virtual root window found (0x%x and 0x%x).\n",
578                    blurb(), (int) ssi->real_vroot, (int) kids [i]);
579           exit (1);
580         }
581       ssi->real_vroot = kids [i];
582       ssi->real_vroot_value = *vrootP;
583     SKIP:
584       ;
585     }
586
587   XSync (dpy, False);
588   XSetErrorHandler (old_handler);
589   XSync (dpy, False);
590
591   if (ssi->real_vroot)
592     {
593       remove_vroot_property (si->dpy, ssi->real_vroot);
594       XSync (dpy, False);
595     }
596
597   XFree ((char *) kids);
598 }
599
600
601 static Bool
602 restore_real_vroot_1 (saver_screen_info *ssi)
603 {
604   saver_info *si = ssi->global;
605   saver_preferences *p = &si->prefs;
606   if (p->verbose_p && ssi->real_vroot)
607     fprintf (stderr,
608              "%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
609              blurb(), (unsigned long) ssi->real_vroot);
610   remove_vroot_property (si->dpy, ssi->screensaver_window);
611   if (ssi->real_vroot)
612     {
613       store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
614       ssi->real_vroot = 0;
615       ssi->real_vroot_value = 0;
616       /* make sure the property change gets there before this process
617          terminates!  We might be doing this because we have intercepted
618          SIGTERM or something. */
619       XSync (si->dpy, False);
620       return True;
621     }
622   return False;
623 }
624
625 Bool
626 restore_real_vroot (saver_info *si)
627 {
628   int i;
629   Bool did_any = False;
630   for (i = 0; i < si->nscreens; i++)
631     {
632       saver_screen_info *ssi = &si->screens[i];
633       if (restore_real_vroot_1 (ssi))
634         did_any = True;
635     }
636   return did_any;
637 }
638
639 \f
640 /* Signal hackery to ensure that the vroot doesn't get left in an 
641    inconsistent state
642  */
643
644 const char *
645 signal_name(int signal)
646 {
647   switch (signal) {
648   case SIGHUP:    return "SIGHUP";
649   case SIGINT:    return "SIGINT";
650   case SIGQUIT:   return "SIGQUIT";
651   case SIGILL:    return "SIGILL";
652   case SIGTRAP:   return "SIGTRAP";
653 #ifdef SIGABRT
654   case SIGABRT:   return "SIGABRT";
655 #endif
656   case SIGFPE:    return "SIGFPE";
657   case SIGKILL:   return "SIGKILL";
658   case SIGBUS:    return "SIGBUS";
659   case SIGSEGV:   return "SIGSEGV";
660   case SIGPIPE:   return "SIGPIPE";
661   case SIGALRM:   return "SIGALRM";
662   case SIGTERM:   return "SIGTERM";
663 #ifdef SIGSTOP
664   case SIGSTOP:   return "SIGSTOP";
665 #endif
666 #ifdef SIGCONT
667   case SIGCONT:   return "SIGCONT";
668 #endif
669 #ifdef SIGUSR1
670   case SIGUSR1:   return "SIGUSR1";
671 #endif
672 #ifdef SIGUSR2
673   case SIGUSR2:   return "SIGUSR2";
674 #endif
675 #ifdef SIGEMT
676   case SIGEMT:    return "SIGEMT";
677 #endif
678 #ifdef SIGSYS
679   case SIGSYS:    return "SIGSYS";
680 #endif
681 #ifdef SIGCHLD
682   case SIGCHLD:   return "SIGCHLD";
683 #endif
684 #ifdef SIGPWR
685   case SIGPWR:    return "SIGPWR";
686 #endif
687 #ifdef SIGWINCH
688   case SIGWINCH:  return "SIGWINCH";
689 #endif
690 #ifdef SIGURG
691   case SIGURG:    return "SIGURG";
692 #endif
693 #ifdef SIGIO
694   case SIGIO:     return "SIGIO";
695 #endif
696 #ifdef SIGVTALRM
697   case SIGVTALRM: return "SIGVTALRM";
698 #endif
699 #ifdef SIGXCPU
700   case SIGXCPU:   return "SIGXCPU";
701 #endif
702 #ifdef SIGXFSZ
703   case SIGXFSZ:   return "SIGXFSZ";
704 #endif
705 #ifdef SIGDANGER
706   case SIGDANGER: return "SIGDANGER";
707 #endif
708   default:
709     {
710       static char buf[50];
711       sprintf(buf, "signal %d\n", signal);
712       return buf;
713     }
714   }
715 }
716
717
718
719 static RETSIGTYPE
720 restore_real_vroot_handler (int sig)
721 {
722   saver_info *si = global_si_kludge;    /* I hate C so much... */
723
724   signal (sig, SIG_DFL);
725   if (restore_real_vroot (si))
726     fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n",
727              blurb(), signal_name(sig));
728   kill (getpid (), sig);
729 }
730
731 static void
732 catch_signal (saver_info *si, int sig, RETSIGTYPE (*handler) (int))
733 {
734 # ifdef HAVE_SIGACTION
735
736   struct sigaction a;
737   a.sa_handler = handler;
738   sigemptyset (&a.sa_mask);
739   a.sa_flags = 0;
740
741   /* On Linux 2.4.9 (at least) we need to tell the kernel to not mask delivery
742      of this signal from inside its handler, or else when we execvp() the
743      process again, it starts up with SIGHUP blocked, meaning that killing
744      it with -HUP only works *once*.  You'd think that execvp() would reset
745      all the signal masks, but it doesn't.
746    */
747 #  if defined(SA_NOMASK)
748   a.sa_flags |= SA_NOMASK;
749 #  elif defined(SA_NODEFER)
750   a.sa_flags |= SA_NODEFER;
751 #  endif
752
753   if (sigaction (sig, &a, 0) < 0)
754 # else  /* !HAVE_SIGACTION */
755   if (((long) signal (sig, handler)) == -1L)
756 # endif /* !HAVE_SIGACTION */
757     {
758       char buf [255];
759       sprintf (buf, "%s: couldn't catch %s", blurb(), signal_name(sig));
760       perror (buf);
761       saver_exit (si, 1, 0);
762     }
763 }
764
765 static RETSIGTYPE saver_sighup_handler (int sig);
766
767 void
768 handle_signals (saver_info *si)
769 {
770   catch_signal (si, SIGHUP, saver_sighup_handler);
771
772   catch_signal (si, SIGINT,  restore_real_vroot_handler);
773   catch_signal (si, SIGQUIT, restore_real_vroot_handler);
774   catch_signal (si, SIGILL,  restore_real_vroot_handler);
775   catch_signal (si, SIGTRAP, restore_real_vroot_handler);
776 #ifdef SIGIOT
777   catch_signal (si, SIGIOT,  restore_real_vroot_handler);
778 #endif
779   catch_signal (si, SIGABRT, restore_real_vroot_handler);
780 #ifdef SIGEMT
781   catch_signal (si, SIGEMT,  restore_real_vroot_handler);
782 #endif
783   catch_signal (si, SIGFPE,  restore_real_vroot_handler);
784   catch_signal (si, SIGBUS,  restore_real_vroot_handler);
785   catch_signal (si, SIGSEGV, restore_real_vroot_handler);
786 #ifdef SIGSYS
787   catch_signal (si, SIGSYS,  restore_real_vroot_handler);
788 #endif
789   catch_signal (si, SIGTERM, restore_real_vroot_handler);
790 #ifdef SIGXCPU
791   catch_signal (si, SIGXCPU, restore_real_vroot_handler);
792 #endif
793 #ifdef SIGXFSZ
794   catch_signal (si, SIGXFSZ, restore_real_vroot_handler);
795 #endif
796 #ifdef SIGDANGER
797   catch_signal (si, SIGDANGER, restore_real_vroot_handler);
798 #endif
799 }
800
801
802 static RETSIGTYPE
803 saver_sighup_handler (int sig)
804 {
805   saver_info *si = global_si_kludge;    /* I hate C so much... */
806
807   /* Re-establish SIGHUP handler */
808   catch_signal (si, SIGHUP, saver_sighup_handler);
809
810   fprintf (stderr, "%s: %s received: restarting...\n",
811            blurb(), signal_name(sig));
812
813   if (si->screen_blanked_p)
814     {
815       unblank_screen (si);
816       kill_screenhack (si);
817       XSync (si->dpy, False);
818     }
819
820   restart_process (si);   /* Does not return */
821   abort ();
822 }
823
824
825
826 void
827 saver_exit (saver_info *si, int status, const char *dump_core_reason)
828 {
829   saver_preferences *p = &si->prefs;
830   static Bool exiting = False;
831   Bool bugp;
832   Bool vrs;
833
834   if (exiting)
835     exit(status);
836
837   exiting = True;
838   
839   vrs = restore_real_vroot (si);
840   emergency_kill_subproc (si);
841   shutdown_stderr (si);
842
843   if (p->verbose_p && vrs)
844     fprintf (real_stderr, "%s: old vroot restored.\n", blurb());
845
846   fflush(real_stdout);
847
848 #ifdef VMS      /* on VMS, 1 is the "normal" exit code instead of 0. */
849   if (status == 0) status = 1;
850   else if (status == 1) status = -1;
851 #endif
852
853   bugp = !!dump_core_reason;
854
855   if (si->prefs.debug_p && !dump_core_reason)
856     dump_core_reason = "because of -debug";
857
858   if (dump_core_reason)
859     {
860       /* Note that the Linux man page for setuid() says If uid is
861          different from the old effective uid, the process will be
862          forbidden from leaving core dumps.
863       */
864       char cwd[4096]; /* should really be PATH_MAX, but who cares. */
865       cwd[0] = 0;
866       fprintf(real_stderr, "%s: dumping core (%s)\n", blurb(),
867               dump_core_reason);
868
869       if (bugp)
870         fprintf(real_stderr,
871                 "%s: see http://www.jwz.org/xscreensaver/bugs.html\n"
872                 "\t\t\tfor bug reporting information.\n\n",
873                 blurb());
874
875 # if defined(HAVE_GETCWD)
876       if (!getcwd (cwd, sizeof(cwd)))
877 # elif defined(HAVE_GETWD)
878       if (!getwd (cwd))
879 # endif
880         strcpy(cwd, "unknown.");
881
882       fprintf (real_stderr, "%s: current directory is %s\n", blurb(), cwd);
883       describe_uids (si, real_stderr);
884
885       /* Do this to drop a core file, so that we can get a stack trace. */
886       abort();
887     }
888
889   exit (status);
890 }
891
892 \f
893 /* Managing the actual screensaver window */
894
895 Bool
896 window_exists_p (Display *dpy, Window window)
897 {
898   XErrorHandler old_handler;
899   XWindowAttributes xgwa;
900   xgwa.screen = 0;
901   old_handler = XSetErrorHandler (BadWindow_ehandler);
902   XGetWindowAttributes (dpy, window, &xgwa);
903   XSync (dpy, False);
904   XSetErrorHandler (old_handler);
905   return (xgwa.screen != 0);
906 }
907
908 static void
909 store_saver_id (saver_screen_info *ssi)
910 {
911   XClassHint class_hints;
912   saver_info *si = ssi->global;
913   unsigned long pid = (unsigned long) getpid ();
914   char buf[20];
915   struct passwd *p = getpwuid (getuid ());
916   const char *name, *host;
917   char *id;
918
919   /* First store the name and class on the window.
920    */
921   class_hints.res_name = progname;
922   class_hints.res_class = progclass;
923   XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
924   XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
925
926   /* Then store the xscreensaver version number.
927    */
928   XChangeProperty (si->dpy, ssi->screensaver_window,
929                    XA_SCREENSAVER_VERSION,
930                    XA_STRING, 8, PropModeReplace,
931                    (unsigned char *) si->version,
932                    strlen (si->version));
933
934   /* Now store the XSCREENSAVER_ID property, that says what user and host
935      xscreensaver is running as.
936    */
937
938   if (p && p->pw_name && *p->pw_name)
939     name = p->pw_name;
940   else if (p)
941     {
942       sprintf (buf, "%lu", (unsigned long) p->pw_uid);
943       name = buf;
944     }
945   else
946     name = "???";
947
948 # if defined(HAVE_UNAME)
949   {
950     struct utsname uts;
951     if (uname (&uts) < 0)
952       host = "???";
953     else
954       host = uts.nodename;
955   }
956 # elif defined(VMS)
957   host = getenv("SYS$NODE");
958 # else  /* !HAVE_UNAME && !VMS */
959   host = "???";
960 # endif /* !HAVE_UNAME && !VMS */
961
962   id = (char *) malloc (strlen(name) + strlen(host) + 50);
963   sprintf (id, "%lu (%s@%s)", pid, name, host);
964
965   XChangeProperty (si->dpy, ssi->screensaver_window,
966                    XA_SCREENSAVER_ID, XA_STRING,
967                    8, PropModeReplace,
968                    (unsigned char *) id, strlen (id));
969   free (id);
970 }
971
972
973 void
974 store_saver_status (saver_info *si)
975 {
976   PROP32 *status;
977   int size = si->nscreens + 2;
978   int i;
979
980   status = (PROP32 *) calloc (size, sizeof(PROP32));
981
982   status[0] = (PROP32) (si->screen_blanked_p
983                         ? (si->locked_p ? XA_LOCK : XA_BLANK)
984                         : 0);
985   status[1] = (PROP32) si->blank_time;
986
987   for (i = 0; i < si->nscreens; i++)
988     {
989       saver_screen_info *ssi = &si->screens[i];
990       status [2 + i] = ssi->current_hack + 1;
991     }
992
993   XChangeProperty (si->dpy,
994                    RootWindow (si->dpy, 0),  /* always screen #0 */
995                    XA_SCREENSAVER_STATUS,
996                    XA_INTEGER, 32, PropModeReplace,
997                    (unsigned char *) status, size);
998   free (status);
999 }
1000
1001
1002
1003 /* Returns the area of the screen which the xscreensaver window should cover.
1004    Normally this is the whole screen, but if the X server's root window is
1005    actually larger than the monitor's displayable area, then we want to
1006    operate in the currently-visible portion of the desktop instead.
1007  */
1008 void
1009 get_screen_viewport (saver_screen_info *ssi,
1010                      int *x_ret, int *y_ret,
1011                      int *w_ret, int *h_ret,
1012                      int target_x, int target_y,
1013                      Bool verbose_p)
1014 {
1015   int w = WidthOfScreen (ssi->screen);
1016   int h = HeightOfScreen (ssi->screen);
1017
1018 # ifdef HAVE_XF86VMODE
1019   saver_info *si = ssi->global;
1020   saver_preferences *p = &si->prefs;
1021   int event, error;
1022   int dot;
1023   XF86VidModeModeLine ml;
1024   int x, y;
1025   Bool xinerama_p = si->xinerama_p;
1026
1027 #  ifndef HAVE_XINERAMA
1028   /* Even if we don't have the client-side Xinerama lib, check to see if
1029      the server supports Xinerama, so that we know to ignore the VidMode
1030      extension -- otherwise a server crash could result.  Yay. */
1031   xinerama_p = XQueryExtension (si->dpy, "XINERAMA", &error, &event, &error);
1032 #  endif /* !HAVE_XINERAMA */
1033
1034 #  ifdef HAVE_XINERAMA
1035   if (xinerama_p)
1036     {
1037       int mouse_p = (target_x != -1 && target_y != -1);
1038       int which = -1;
1039       int i;
1040
1041       /* If a mouse position wasn't passed in, assume we're talking about
1042          this screen. */
1043       if (!mouse_p)
1044         {
1045           target_x = ssi->x;
1046           target_y = ssi->y;
1047         }
1048
1049       /* Find the Xinerama rectangle that contains the mouse position. */
1050       for (i = 0; i < si->nscreens; i++)
1051         {
1052           if (target_x >= si->screens[i].x &&
1053               target_y >= si->screens[i].y &&
1054               target_x <  si->screens[i].x + si->screens[i].width &&
1055               target_y <  si->screens[i].y + si->screens[i].height)
1056             which = i;
1057         }
1058       if (which == -1) which = 0;  /* didn't find it?  Use the first. */
1059       *x_ret = si->screens[which].x;
1060       *y_ret = si->screens[which].y;
1061       *w_ret = si->screens[which].width;
1062       *h_ret = si->screens[which].height;
1063
1064       if (verbose_p)
1065         {
1066           fprintf (stderr, "%s: %d: xinerama vp: %dx%d+%d+%d",
1067                    blurb(), which,
1068                    si->screens[which].width, si->screens[which].height,
1069                    si->screens[which].x, si->screens[which].y);
1070           if (mouse_p)
1071             fprintf (stderr, "; mouse at %d,%d", target_x, target_y);
1072           fprintf (stderr, ".\n");
1073         }
1074
1075       return;
1076     }
1077 #  endif /* HAVE_XINERAMA */
1078
1079   if (!xinerama_p &&  /* Xinerama + VidMode = broken. */
1080       XF86VidModeQueryExtension (si->dpy, &event, &error) &&
1081       safe_XF86VidModeGetViewPort (si->dpy, ssi->number, &x, &y) &&
1082       XF86VidModeGetModeLine (si->dpy, ssi->number, &dot, &ml))
1083     {
1084       char msg[512];
1085       *x_ret = x;
1086       *y_ret = y;
1087       *w_ret = ml.hdisplay;
1088       *h_ret = ml.vdisplay;
1089
1090       if (*x_ret == 0 && *y_ret == 0 && *w_ret == w && *h_ret == h)
1091         /* There is no viewport -- the screen does not scroll. */
1092         return;
1093
1094
1095       /* Apparently some versions of XFree86 return nonsense here!
1096          I've had reports of 1024x768 viewports at -1936862040, -1953705044.
1097          So, sanity-check the values and give up if they are out of range.
1098        */
1099       if (*x_ret <  0 || *x_ret >= w ||
1100           *y_ret <  0 || *y_ret >= h ||
1101           *w_ret <= 0 || *w_ret >  w ||
1102           *h_ret <= 0 || *h_ret >  h)
1103         {
1104           static int warned_once = 0;
1105           if (!warned_once)
1106             {
1107               fprintf (stderr, "\n"
1108                   "%s: X SERVER BUG: %dx%d viewport at %d,%d is impossible.\n"
1109                   "%s: The XVidMode server extension is returning nonsense.\n"
1110                   "%s: Please report this bug to your X server vendor.\n\n",
1111                        blurb(), *w_ret, *h_ret, *x_ret, *y_ret,
1112                        blurb(), blurb());
1113               warned_once = 1;
1114             }
1115           *x_ret = 0;
1116           *y_ret = 0;
1117           *w_ret = w;
1118           *h_ret = h;
1119           return;
1120         }
1121
1122       sprintf (msg, "%s: %d: vp is %dx%d+%d+%d",
1123                blurb(), ssi->number,
1124                *w_ret, *h_ret, *x_ret, *y_ret);
1125
1126
1127       if (p->getviewport_full_of_lies_p)
1128         {
1129           /* XF86VidModeGetViewPort() tends to be full of lies on laptops
1130              that have a docking station or external monitor that runs in
1131              a different resolution than the laptop's screen:
1132
1133                  http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=81593
1134                  http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=208417
1135                  http://bugs.xfree86.org/show_bug.cgi?id=421
1136
1137              The XFree86 developers have closed the bug. As far as I can
1138              tell, their reason for this was, "this is an X server bug,
1139              but it's pretty hard to fix. Therefore, we are closing it."
1140
1141              So, now there's a preference item for those unfortunate users to
1142              tell us not to trust a word that XF86VidModeGetViewPort() says.
1143            */
1144           static int warned_once = 0;
1145           if (!warned_once && verbose_p)
1146             {
1147               warned_once = 1;
1148               fprintf (stderr,
1149                   "%s: %d: XF86VidModeGetViewPort() says vp is %dx%d+%d+%d;\n"
1150                   "%s: %d:     assuming that is a pack of lies;\n"
1151                   "%s: %d:     using %dx%d+0+0 instead.\n",
1152                        blurb(), ssi->number,
1153                        *w_ret, *h_ret, *x_ret, *y_ret,
1154                        blurb(), ssi->number,
1155                        blurb(), ssi->number, w, h);
1156             }
1157
1158           *x_ret = 0;
1159           *y_ret = 0;
1160           *w_ret = w;
1161           *h_ret = h;
1162           return;
1163         }
1164
1165
1166       /* Apparently, though the server stores the X position in increments of
1167          1 pixel, it will only make changes to the *display* in some other
1168          increment.  With XF86_SVGA on a Thinkpad, the display only updates
1169          in multiples of 8 pixels when in 8-bit mode, and in multiples of 4
1170          pixels in 16-bit mode.  I don't know what it does in 24- and 32-bit
1171          mode, because I don't have enough video memory to find out.
1172
1173          I consider it a bug that XF86VidModeGetViewPort() is telling me the
1174          server's *target* scroll position rather than the server's *actual*
1175          scroll position.  David Dawes agrees, and says they may fix this in
1176          XFree86 4.0, but it's notrivial.
1177
1178          He also confirms that this behavior is server-dependent, so the
1179          actual scroll position cannot be reliably determined by the client.
1180          So... that means the only solution is to provide a ``sandbox''
1181          around the blackout window -- we make the window be up to N pixels
1182          larger than the viewport on both the left and right sides.  That
1183          means some part of the outer edges of each hack might not be
1184          visible, but screw it.
1185
1186          I'm going to guess that 16 pixels is enough, and that the Y dimension
1187          doesn't have this problem.
1188
1189          The drawback of doing this, of course, is that some of the screenhacks
1190          will still look pretty stupid -- for example, "slidescreen" will cut
1191          off the left and right edges of the grid, etc.
1192       */
1193 #  define FUDGE 16
1194       if (x > 0 && x < w - ml.hdisplay)  /* not at left edge or right edge */
1195         {
1196           /* Round X position down to next lower multiple of FUDGE.
1197              Increase width by 2*FUDGE in case some server rounds up.
1198            */
1199           *x_ret = ((x - 1) / FUDGE) * FUDGE;
1200           *w_ret += (FUDGE * 2);
1201         }
1202 #  undef FUDGE
1203
1204       if (*x_ret != x ||
1205           *y_ret != y ||
1206           *w_ret != ml.hdisplay ||
1207           *h_ret != ml.vdisplay)
1208         sprintf (msg + strlen(msg), "; fudged to %dx%d+%d+%d",
1209                  *w_ret, *h_ret, *x_ret, *y_ret);
1210
1211       if (verbose_p)
1212         fprintf (stderr, "%s.\n", msg);
1213
1214       return;
1215     }
1216
1217 # endif /* HAVE_XF86VMODE */
1218
1219   *x_ret = 0;
1220   *y_ret = 0;
1221   *w_ret = w;
1222   *h_ret = h;
1223 }
1224
1225
1226 static Bool error_handler_hit_p = False;
1227
1228 static int
1229 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1230 {
1231   error_handler_hit_p = True;
1232   return 0;
1233 }
1234
1235
1236 /* Returns True if successful, False if an X error occurred.
1237    We need this because other programs might have done things to
1238    our window that will cause XChangeWindowAttributes() to fail:
1239    if that happens, we give up, destroy the window, and re-create
1240    it.
1241  */
1242 static Bool
1243 safe_XChangeWindowAttributes (Display *dpy, Window window,
1244                               unsigned long mask,
1245                               XSetWindowAttributes *attrs)
1246 {
1247   XErrorHandler old_handler;
1248   XSync (dpy, False);
1249   error_handler_hit_p = False;
1250   old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1251
1252   XChangeWindowAttributes (dpy, window, mask, attrs);
1253
1254   XSync (dpy, False);
1255   XSetErrorHandler (old_handler);
1256   XSync (dpy, False);
1257
1258   return (!error_handler_hit_p);
1259 }
1260
1261
1262 /* This might not be necessary, but just in case. */
1263 static Bool
1264 safe_XConfigureWindow (Display *dpy, Window window,
1265                        unsigned long mask, XWindowChanges *changes)
1266 {
1267   XErrorHandler old_handler;
1268   XSync (dpy, False);
1269   error_handler_hit_p = False;
1270   old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1271
1272   XConfigureWindow (dpy, window, mask, changes);
1273
1274   XSync (dpy, False);
1275   XSetErrorHandler (old_handler);
1276   XSync (dpy, False);
1277
1278   return (!error_handler_hit_p);
1279 }
1280
1281 /* This might not be necessary, but just in case. */
1282 static Bool
1283 safe_XDestroyWindow (Display *dpy, Window window)
1284 {
1285   XErrorHandler old_handler;
1286   XSync (dpy, False);
1287   error_handler_hit_p = False;
1288   old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1289
1290   XDestroyWindow (dpy, window);
1291
1292   XSync (dpy, False);
1293   XSetErrorHandler (old_handler);
1294   XSync (dpy, False);
1295
1296   return (!error_handler_hit_p);
1297 }
1298
1299
1300 static Bool
1301 safe_XKillClient (Display *dpy, XID id)
1302 {
1303   XErrorHandler old_handler;
1304   XSync (dpy, False);
1305   error_handler_hit_p = False;
1306   old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1307
1308   XKillClient (dpy, id);
1309
1310   XSync (dpy, False);
1311   XSetErrorHandler (old_handler);
1312   XSync (dpy, False);
1313
1314   return (!error_handler_hit_p);
1315 }
1316
1317
1318 #ifdef HAVE_XF86VMODE
1319 static Bool
1320 safe_XF86VidModeGetViewPort (Display *dpy, int screen, int *xP, int *yP)
1321 {
1322   Bool result;
1323   XErrorHandler old_handler;
1324   XSync (dpy, False);
1325   error_handler_hit_p = False;
1326   old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1327
1328   result = XF86VidModeGetViewPort (dpy, screen, xP, yP);
1329
1330   XSync (dpy, False);
1331   XSetErrorHandler (old_handler);
1332   XSync (dpy, False);
1333
1334   return (error_handler_hit_p
1335           ? False
1336           : result);
1337 }
1338
1339 /* There is no "safe_XF86VidModeGetModeLine" because it fails with an
1340    untrappable I/O error instead of an X error -- so one must call
1341    safe_XF86VidModeGetViewPort first, and assume that both have the
1342    same error condition.  Thank you XFree, may I have another.
1343  */
1344
1345 #endif /* HAVE_XF86VMODE */
1346
1347
1348 static void
1349 initialize_screensaver_window_1 (saver_screen_info *ssi)
1350 {
1351   saver_info *si = ssi->global;
1352   saver_preferences *p = &si->prefs;
1353   Bool install_cmap_p = ssi->install_cmap_p;   /* not p->install_cmap_p */
1354
1355   /* This resets the screensaver window as fully as possible, since there's
1356      no way of knowing what some random client may have done to us in the
1357      meantime.  We could just destroy and recreate the window, but that has
1358      its own set of problems...
1359    */
1360   XColor black;
1361   XSetWindowAttributes attrs;
1362   unsigned long attrmask;
1363   int x, y, width, height;
1364   static Bool printed_visual_info = False;  /* only print the message once. */
1365   Window horked_window = 0;
1366
1367   get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
1368                        (p->verbose_p && !si->screen_blanked_p));
1369
1370   black.red = black.green = black.blue = 0;
1371
1372   if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
1373     ssi->cmap = 0;
1374
1375   if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
1376     /* It's not the default visual, so we have no choice but to install. */
1377     install_cmap_p = True;
1378
1379   if (install_cmap_p)
1380     {
1381       if (! ssi->cmap)
1382         {
1383           ssi->cmap = XCreateColormap (si->dpy,
1384                                        RootWindowOfScreen (ssi->screen),
1385                                       ssi->current_visual, AllocNone);
1386           if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
1387           ssi->black_pixel = black.pixel;
1388         }
1389     }
1390   else
1391     {
1392       Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
1393       if (ssi->cmap)
1394         {
1395           XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
1396           if (ssi->cmap != ssi->demo_cmap &&
1397               ssi->cmap != def_cmap)
1398             XFreeColormap (si->dpy, ssi->cmap);
1399         }
1400       ssi->cmap = def_cmap;
1401       ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
1402     }
1403
1404   attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
1405               CWBackPixel | CWBackingPixel | CWBorderPixel);
1406   attrs.override_redirect = True;
1407
1408   /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
1409      actually be reading these events during normal operation; but we still
1410      need to see Button events for demo-mode to work properly.
1411    */
1412   attrs.event_mask = (KeyPressMask | KeyReleaseMask |
1413                       ButtonPressMask | ButtonReleaseMask |
1414                       PointerMotionMask);
1415
1416   attrs.backing_store = NotUseful;
1417   attrs.colormap = ssi->cmap;
1418   attrs.background_pixel = ssi->black_pixel;
1419   attrs.backing_pixel = ssi->black_pixel;
1420   attrs.border_pixel = ssi->black_pixel;
1421
1422   if (p->debug_p
1423 # ifdef QUAD_MODE
1424       && !p->quad_p
1425 # endif
1426       )
1427     width = width / 2;
1428
1429   if (!p->verbose_p || printed_visual_info)
1430     ;
1431   else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
1432     {
1433       fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
1434       describe_visual (stderr, ssi->screen, ssi->current_visual,
1435                        install_cmap_p);
1436     }
1437   else
1438     {
1439       fprintf (stderr, "%s: using visual:   ", blurb());
1440       describe_visual (stderr, ssi->screen, ssi->current_visual,
1441                        install_cmap_p);
1442       fprintf (stderr, "%s: default visual: ", blurb());
1443       describe_visual (stderr, ssi->screen,
1444                        DefaultVisualOfScreen (ssi->screen),
1445                        ssi->install_cmap_p);
1446     }
1447   printed_visual_info = True;
1448
1449 #ifdef HAVE_MIT_SAVER_EXTENSION
1450   if (si->using_mit_saver_extension)
1451     {
1452       XScreenSaverInfo *info;
1453       Window root = RootWindowOfScreen (ssi->screen);
1454
1455 #if 0
1456       /* This call sets the server screensaver timeouts to what we think
1457          they should be (based on the resources and args xscreensaver was
1458          started with.)  It's important that we do this to sync back up
1459          with the server - if we have turned on prematurely, as by an
1460          ACTIVATE ClientMessage, then the server may decide to activate
1461          the screensaver while it's already active.  That's ok for us,
1462          since we would know to ignore that ScreenSaverActivate event,
1463          but a side effect of this would be that the server would map its
1464          saver window (which we then hide again right away) meaning that
1465          the bits currently on the screen get blown away.  Ugly. */
1466
1467       /* #### Ok, that doesn't work - when we tell the server that the
1468          screensaver is "off" it sends us a Deactivate event, which is
1469          sensible... but causes the saver to never come on.  Hmm. */
1470       disable_builtin_screensaver (si, True);
1471 #endif /* 0 */
1472
1473 #if 0
1474       /* #### The MIT-SCREEN-SAVER extension gives us access to the
1475          window that the server itself uses for saving the screen.
1476          However, using this window in any way, in particular, calling
1477          XScreenSaverSetAttributes() as below, tends to make the X server
1478          crash.  So fuck it, let's try and get along without using it...
1479
1480          It's also inconvenient to use this window because it doesn't
1481          always exist (though the ID is constant.)  So to use this
1482          window, we'd have to reimplement the ACTIVATE ClientMessage to
1483          tell the *server* to tell *us* to turn on, to cause the window
1484          to get created at the right time.  Gag.  */
1485       XScreenSaverSetAttributes (si->dpy, root,
1486                                  0, 0, width, height, 0,
1487                                  current_depth, InputOutput, visual,
1488                                  attrmask, &attrs);
1489       XSync (si->dpy, False);
1490 #endif /* 0 */
1491
1492       info = XScreenSaverAllocInfo ();
1493       XScreenSaverQueryInfo (si->dpy, root, info);
1494       ssi->server_mit_saver_window = info->window;
1495       if (! ssi->server_mit_saver_window) abort ();
1496       XFree (info);
1497     }
1498 #endif /* HAVE_MIT_SAVER_EXTENSION */
1499
1500   if (ssi->screensaver_window)
1501     {
1502       XWindowChanges changes;
1503       unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1504       changes.x = x;
1505       changes.y = y;
1506       changes.width = width;
1507       changes.height = height;
1508       changes.border_width = 0;
1509
1510       if (! (safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1511                                   changesmask, &changes) &&
1512              safe_XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
1513                                            attrmask, &attrs)))
1514         {
1515           horked_window = ssi->screensaver_window;
1516           ssi->screensaver_window = 0;
1517         }
1518     }
1519
1520   if (!ssi->screensaver_window)
1521     {
1522       ssi->screensaver_window =
1523         XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen),
1524                        x, y, width, height,
1525                        0, ssi->current_depth, InputOutput,
1526                        ssi->current_visual, attrmask, &attrs);
1527
1528       reset_stderr (ssi);
1529
1530       if (horked_window)
1531         {
1532           fprintf (stderr,
1533             "%s: someone horked our saver window (0x%lx)!  Recreating it...\n",
1534                    blurb(), (unsigned long) horked_window);
1535           maybe_transfer_grabs (ssi, horked_window, ssi->screensaver_window,
1536                                 ssi->number);
1537           safe_XDestroyWindow (si->dpy, horked_window);
1538           horked_window = 0;
1539         }
1540
1541       if (p->verbose_p)
1542         fprintf (stderr, "%s: %d: saver window is 0x%lx.\n",
1543                  blurb(), ssi->number,
1544                  (unsigned long) ssi->screensaver_window);
1545     }
1546
1547   store_saver_id (ssi);       /* store window name and IDs */
1548
1549   if (!ssi->cursor)
1550     {
1551       Pixmap bit;
1552       bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
1553                                          "\000", 1, 1,
1554                                          BlackPixelOfScreen (ssi->screen),
1555                                          BlackPixelOfScreen (ssi->screen),
1556                                          1);
1557       ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
1558                                          0, 0);
1559       XFreePixmap (si->dpy, bit);
1560     }
1561
1562   XSetWindowBackground (si->dpy, ssi->screensaver_window, ssi->black_pixel);
1563
1564   if (si->demoing_p)
1565     XUndefineCursor (si->dpy, ssi->screensaver_window);
1566   else
1567     XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
1568 }
1569
1570 void
1571 initialize_screensaver_window (saver_info *si)
1572 {
1573   int i;
1574   for (i = 0; i < si->nscreens; i++)
1575     initialize_screensaver_window_1 (&si->screens[i]);
1576 }
1577
1578
1579 /* Called when the RANDR (Resize and Rotate) extension tells us that the
1580    size of the screen has changed while the screen was blanked.  If we
1581    don't do this, then the screen saver will no longer fully fill the
1582    screen, and some of the underlying desktop may be visible.
1583  */
1584 void
1585 resize_screensaver_window (saver_info *si)
1586 {
1587   saver_preferences *p = &si->prefs;
1588   int i;
1589
1590   /* First update the size info in the saver_screen_info structs.
1591    */
1592
1593 # ifdef HAVE_XINERAMA
1594   if (si->xinerama_p)
1595     {
1596       /* As of XFree86 4.3.0, the RANDR and XINERAMA extensions cannot coexist.
1597          However, maybe they will someday, so I'm guessing that the right thing
1598          to do in that case will be to re-query the Xinerama rectangles after
1599          a RANDR size change is received: presumably, if the resolution of one
1600          or more of the monitors has changed, then the Xinerama rectangle
1601          corresponding to that monitor will also have been updated.
1602        */
1603       int nscreens;
1604       XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
1605       if (nscreens != si->nscreens) abort();
1606       if (!xsi) abort();
1607       for (i = 0; i < si->nscreens; i++)
1608         {
1609           saver_screen_info *ssi = &si->screens[i];
1610           if (p->verbose_p &&
1611               (ssi->x      != xsi[i].x_org ||
1612                ssi->y      != xsi[i].y_org ||
1613                ssi->width  != xsi[i].width ||
1614                ssi->height != xsi[i].height))
1615             fprintf (stderr,
1616                    "%s: %d: resize xinerama from %dx%d+%d+%d to %dx%d+%d+%d\n",
1617                      blurb(), i,
1618                      ssi->width,   ssi->height,   ssi->x,       ssi->y,
1619                      xsi[i].width, xsi[i].height, xsi[i].x_org, xsi[i].y_org);
1620
1621           ssi->x      = xsi[i].x_org;
1622           ssi->y      = xsi[i].y_org;
1623           ssi->width  = xsi[i].width;
1624           ssi->height = xsi[i].height;
1625         }
1626       XFree (xsi);
1627     }
1628   else
1629 # endif /* HAVE_XINERAMA */
1630     {
1631       /* Not Xinerama -- get the real sizes of the root windows. */
1632       for (i = 0; i < si->nscreens; i++)
1633         {
1634           saver_screen_info *ssi = &si->screens[i];
1635           XWindowAttributes xgwa;
1636           XGetWindowAttributes (si->dpy, RootWindowOfScreen (ssi->screen),
1637                                 &xgwa);
1638
1639           if (p->verbose_p &&
1640               (ssi->x      != xgwa.x ||
1641                ssi->y      != xgwa.y ||
1642                ssi->width  != xgwa.width ||
1643                ssi->height != xgwa.height))
1644             fprintf (stderr,
1645                      "%s: %d: resize screen from %dx%d+%d+%d to %dx%d+%d+%d\n",
1646                      blurb(), i,
1647                      ssi->width, ssi->height, ssi->x, ssi->y,
1648                      xgwa.width, xgwa.height, xgwa.x, xgwa.y);
1649
1650           ssi->x      = xgwa.x;
1651           ssi->y      = xgwa.y;
1652           ssi->width  = xgwa.width;
1653           ssi->height = xgwa.height;
1654         }
1655     }
1656
1657   /* Next, ensure that the screensaver windows are the right size, taking
1658      into account both the new size of the screen in question's root window,
1659      and any viewport within that.
1660    */
1661
1662   for (i = 0; i < si->nscreens; i++)
1663     {
1664       saver_screen_info *ssi = &si->screens[i];
1665       XWindowAttributes xgwa;
1666       XWindowChanges changes;
1667       int x, y, width, height;
1668       unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
1669
1670       XGetWindowAttributes (si->dpy, ssi->screensaver_window, &xgwa);
1671       get_screen_viewport (ssi, &x, &y, &width, &height, -1, -1,
1672                            (p->verbose_p && !si->screen_blanked_p));
1673       if (xgwa.x == x &&
1674           xgwa.y == y &&
1675           xgwa.width  == width &&
1676           xgwa.height == height)
1677         continue;  /* no change! */
1678
1679       changes.x = x;
1680       changes.y = y;
1681       changes.width  = width;
1682       changes.height = height;
1683       changes.border_width = 0;
1684
1685       if (p->debug_p
1686 # ifdef QUAD_MODE
1687           && !p->quad_p
1688 # endif
1689           ) 
1690         changes.width = changes.width / 2;
1691
1692       if (p->verbose_p)
1693         fprintf (stderr,
1694                  "%s: %d: resize 0x%lx from %dx%d+%d+%d to %dx%d+%d+%d\n",
1695                  blurb(), i, (unsigned long) ssi->screensaver_window,
1696                  xgwa.width, xgwa.height, xgwa.x, xgwa.y,
1697                  width, height, x, y);
1698       if (! safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
1699                                    changesmask, &changes))
1700         {
1701           fprintf (stderr,
1702     "%s: %d: someone horked our saver window (0x%lx)!  Unable to resize it!\n",
1703                    blurb(), i, (unsigned long) ssi->screensaver_window);
1704         }
1705     }
1706 }
1707
1708
1709 void 
1710 raise_window (saver_info *si,
1711               Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
1712 {
1713   saver_preferences *p = &si->prefs;
1714   int i;
1715
1716   if (si->demoing_p)
1717     inhibit_fade = True;
1718
1719   if (si->emergency_lock_p)
1720     inhibit_fade = True;
1721
1722   if (!dont_clear)
1723     initialize_screensaver_window (si);
1724
1725   reset_watchdog_timer (si, True);
1726
1727   if (p->fade_p && si->fading_possible_p && !inhibit_fade)
1728     {
1729       Window *current_windows = (Window *)
1730         calloc(sizeof(Window), si->nscreens);
1731       Colormap *current_maps = (Colormap *)
1732         calloc(sizeof(Colormap), si->nscreens);
1733
1734       for (i = 0; i < si->nscreens; i++)
1735         {
1736           saver_screen_info *ssi = &si->screens[i];
1737           current_windows[i] = ssi->screensaver_window;
1738           current_maps[i] = (between_hacks_p
1739                              ? ssi->cmap
1740                              : DefaultColormapOfScreen (ssi->screen));
1741           /* Ensure that the default background of the window is really black,
1742              not a pixmap or something.  (This does not clear the window.) */
1743           XSetWindowBackground (si->dpy, ssi->screensaver_window,
1744                                 ssi->black_pixel);
1745         }
1746
1747       if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
1748
1749       XGrabServer (si->dpy);                    /* ############ DANGER! */
1750
1751       /* Clear the stderr layer on each screen.
1752        */
1753       if (!dont_clear)
1754         for (i = 0; i < si->nscreens; i++)
1755           {
1756             saver_screen_info *ssi = &si->screens[i];
1757             if (ssi->stderr_overlay_window)
1758               /* Do this before the fade, since the stderr cmap won't fade
1759                  even if we uninstall it (beats me...) */
1760               clear_stderr (ssi);
1761           }
1762
1763       /* Note!  The server is grabbed, and this will take several seconds
1764          to complete! */
1765       fade_screens (si->dpy, current_maps,
1766                     current_windows, si->nscreens,
1767                     p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
1768
1769       free(current_maps);
1770       free(current_windows);
1771       current_maps = 0;
1772       current_windows = 0;
1773
1774       if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
1775
1776 #ifdef HAVE_MIT_SAVER_EXTENSION
1777       for (i = 0; i < si->nscreens; i++)
1778         {
1779           saver_screen_info *ssi = &si->screens[i];
1780           if (ssi->server_mit_saver_window &&
1781               window_exists_p (si->dpy, ssi->server_mit_saver_window))
1782             XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1783         }
1784 #endif /* HAVE_MIT_SAVER_EXTENSION */
1785
1786       XUngrabServer (si->dpy);
1787       XSync (si->dpy, False);                   /* ###### (danger over) */
1788     }
1789   else
1790     {
1791       for (i = 0; i < si->nscreens; i++)
1792         {
1793           saver_screen_info *ssi = &si->screens[i];
1794           if (!dont_clear)
1795             XClearWindow (si->dpy, ssi->screensaver_window);
1796           if (!dont_clear || ssi->stderr_overlay_window)
1797             clear_stderr (ssi);
1798           XMapRaised (si->dpy, ssi->screensaver_window);
1799 #ifdef HAVE_MIT_SAVER_EXTENSION
1800           if (ssi->server_mit_saver_window &&
1801               window_exists_p (si->dpy, ssi->server_mit_saver_window))
1802             XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1803 #endif /* HAVE_MIT_SAVER_EXTENSION */
1804         }
1805     }
1806
1807   for (i = 0; i < si->nscreens; i++)
1808     {
1809       saver_screen_info *ssi = &si->screens[i];
1810       if (ssi->cmap)
1811         XInstallColormap (si->dpy, ssi->cmap);
1812     }
1813 }
1814
1815
1816 int
1817 mouse_screen (saver_info *si)
1818 {
1819   saver_preferences *p = &si->prefs;
1820   Window pointer_root, pointer_child;
1821   int root_x, root_y, win_x, win_y;
1822   unsigned int mask;
1823   int i;
1824
1825   if (si->nscreens == 1)
1826     return 0;
1827
1828   for (i = 0; i < si->nscreens; i++)
1829     {
1830       saver_screen_info *ssi = &si->screens[i];
1831       if (XQueryPointer (si->dpy, RootWindowOfScreen (ssi->screen),
1832                          &pointer_root, &pointer_child,
1833                          &root_x, &root_y, &win_x, &win_y, &mask) &&
1834           root_x >= ssi->x &&
1835           root_y >= ssi->y &&
1836           root_x <  ssi->x + ssi->width &&
1837           root_y <  ssi->y + ssi->height)
1838         {
1839           if (p->verbose_p)
1840             fprintf (stderr, "%s: mouse is on screen %d of %d\n",
1841                      blurb(), i, si->nscreens);
1842           return i;
1843         }
1844     }
1845
1846   /* couldn't figure out where the mouse is?  Oh well. */
1847   return 0;
1848 }
1849
1850
1851 Bool
1852 blank_screen (saver_info *si)
1853 {
1854   int i;
1855   Bool ok;
1856   Window w;
1857   int mscreen;
1858
1859   /* Note: we do our grabs on the root window, not on the screensaver window.
1860      If we grabbed on the saver window, then the demo mode and lock dialog
1861      boxes wouldn't get any events.
1862
1863      By "the root window", we mean "the root window that contains the mouse."
1864      We use to always grab the mouse on screen 0, but that has the effect of
1865      moving the mouse to screen 0 from whichever screen it was on, on
1866      multi-head systems.
1867    */
1868   mscreen = mouse_screen (si);
1869   w = RootWindowOfScreen(si->screens[mscreen].screen);
1870   ok = grab_keyboard_and_mouse (si, w,
1871                                 (si->demoing_p ? 0 : si->screens[0].cursor),
1872                                 mscreen);
1873
1874
1875 # if 0
1876   if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1877     /* If we're using a server extension, then failure to get a grab is
1878        not a big deal -- even without the grab, we will still be able
1879        to un-blank when there is user activity, since the server will
1880        tell us. */
1881     /* #### No, that's not true: if we don't have a keyboard grab,
1882             then we can't read passwords to unlock.
1883      */
1884     ok = True;
1885 # endif /* 0 */
1886
1887   if (!ok)
1888     return False;
1889
1890   for (i = 0; i < si->nscreens; i++)
1891     {
1892       saver_screen_info *ssi = &si->screens[i];
1893       if (ssi->real_screen_p)
1894         save_real_vroot (ssi);
1895       store_vroot_property (si->dpy,
1896                             ssi->screensaver_window,
1897                             ssi->screensaver_window);
1898
1899 #ifdef HAVE_XF86VMODE
1900       {
1901         int ev, er;
1902         if (!XF86VidModeQueryExtension (si->dpy, &ev, &er) ||
1903             !safe_XF86VidModeGetViewPort (si->dpy, i,
1904                                           &ssi->blank_vp_x,
1905                                           &ssi->blank_vp_y))
1906           ssi->blank_vp_x = ssi->blank_vp_y = -1;
1907       }
1908 #endif /* HAVE_XF86VMODE */
1909     }
1910
1911   raise_window (si, False, False, False);
1912
1913   si->screen_blanked_p = True;
1914   si->blank_time = time ((time_t) 0);
1915   si->last_wall_clock_time = 0;
1916
1917   store_saver_status (si);  /* store blank time */
1918
1919   return True;
1920 }
1921
1922
1923 void
1924 unblank_screen (saver_info *si)
1925 {
1926   saver_preferences *p = &si->prefs;
1927   Bool unfade_p = (si->fading_possible_p && p->unfade_p);
1928   int i;
1929
1930   monitor_power_on (si);
1931   reset_watchdog_timer (si, False);
1932
1933   if (si->demoing_p)
1934     unfade_p = False;
1935
1936   if (unfade_p)
1937     {
1938       Window *current_windows = (Window *)
1939         calloc(sizeof(Window), si->nscreens);
1940
1941       for (i = 0; i < si->nscreens; i++)
1942         {
1943           saver_screen_info *ssi = &si->screens[i];
1944           current_windows[i] = ssi->screensaver_window;
1945           /* Ensure that the default background of the window is really black,
1946              not a pixmap or something.  (This does not clear the window.) */
1947           XSetWindowBackground (si->dpy, ssi->screensaver_window,
1948                                 ssi->black_pixel);
1949         }
1950
1951       if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
1952
1953
1954       XSync (si->dpy, False);
1955       XGrabServer (si->dpy);                    /* ############ DANGER! */
1956       XSync (si->dpy, False);
1957
1958       /* Clear the stderr layer on each screen.
1959        */
1960       for (i = 0; i < si->nscreens; i++)
1961         {
1962           saver_screen_info *ssi = &si->screens[i];
1963           clear_stderr (ssi);
1964         }
1965
1966       XUngrabServer (si->dpy);
1967       XSync (si->dpy, False);                   /* ###### (danger over) */
1968
1969       fade_screens (si->dpy, 0,
1970                     current_windows, si->nscreens,
1971                     p->fade_seconds/1000, p->fade_ticks,
1972                     False, False);
1973
1974       free(current_windows);
1975       current_windows = 0;
1976
1977       if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
1978     }
1979   else
1980     {
1981       for (i = 0; i < si->nscreens; i++)
1982         {
1983           saver_screen_info *ssi = &si->screens[i];
1984           if (ssi->cmap)
1985             {
1986               Colormap c = DefaultColormapOfScreen (ssi->screen);
1987               /* avoid technicolor */
1988               XClearWindow (si->dpy, ssi->screensaver_window);
1989               if (c) XInstallColormap (si->dpy, c);
1990             }
1991           XUnmapWindow (si->dpy, ssi->screensaver_window);
1992         }
1993     }
1994
1995
1996   /* If the focus window does has a non-default colormap, then install
1997      that colormap as well.  (On SGIs, this will cause both the root map
1998      and the focus map to be installed simultaneously.  It'd be nice to
1999      pick up the other colormaps that had been installed, too; perhaps
2000      XListInstalledColormaps could be used for that?)
2001    */
2002   {
2003     Window focus = 0;
2004     int revert_to;
2005     XGetInputFocus (si->dpy, &focus, &revert_to);
2006     if (focus && focus != PointerRoot && focus != None)
2007       {
2008         XWindowAttributes xgwa;
2009         xgwa.colormap = 0;
2010         XGetWindowAttributes (si->dpy, focus, &xgwa);
2011         if (xgwa.colormap &&
2012             xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
2013           XInstallColormap (si->dpy, xgwa.colormap);
2014       }
2015   }
2016
2017
2018   for (i = 0; i < si->nscreens; i++)
2019     {
2020       saver_screen_info *ssi = &si->screens[i];
2021       kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
2022     }
2023
2024   store_saver_status (si);  /* store unblank time */
2025   ungrab_keyboard_and_mouse (si);
2026   restore_real_vroot (si);
2027
2028   /* Unmap the windows a second time, dammit -- just to avoid a race
2029      with the screen-grabbing hacks.  (I'm not sure if this is really
2030      necessary; I'm stabbing in the dark now.)
2031   */
2032   for (i = 0; i < si->nscreens; i++)
2033     XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
2034
2035   si->screen_blanked_p = False;
2036   si->blank_time = time ((time_t) 0);
2037   si->last_wall_clock_time = 0;
2038
2039   store_saver_status (si);  /* store unblank time */
2040 }
2041
2042
2043 /* Transfer any grabs from the old window to the new.
2044    Actually I think none of this is necessary, since we always
2045    hold our grabs on the root window, but I wrote this before
2046    re-discovering that...
2047  */
2048 static void
2049 maybe_transfer_grabs (saver_screen_info *ssi,
2050                       Window old_w, Window new_w,
2051                       int new_screen_no)
2052 {
2053   saver_info *si = ssi->global;
2054
2055   /* If the old window held our mouse grab, transfer the grab to the new
2056      window.  (Grab the server while so doing, to avoid a race condition.)
2057    */
2058   if (old_w == si->mouse_grab_window)
2059     {
2060       XGrabServer (si->dpy);            /* ############ DANGER! */
2061       ungrab_mouse (si);
2062       grab_mouse (si, ssi->screensaver_window,
2063                   (si->demoing_p ? 0 : ssi->cursor),
2064                   new_screen_no);
2065       XUngrabServer (si->dpy);
2066       XSync (si->dpy, False);           /* ###### (danger over) */
2067     }
2068
2069   /* If the old window held our keyboard grab, transfer the grab to the new
2070      window.  (Grab the server while so doing, to avoid a race condition.)
2071    */
2072   if (old_w == si->keyboard_grab_window)
2073     {
2074       XGrabServer (si->dpy);            /* ############ DANGER! */
2075       ungrab_kbd(si);
2076       grab_kbd(si, ssi->screensaver_window, ssi->number);
2077       XUngrabServer (si->dpy);
2078       XSync (si->dpy, False);           /* ###### (danger over) */
2079     }
2080 }
2081
2082
2083
2084 Bool
2085 select_visual (saver_screen_info *ssi, const char *visual_name)
2086 {
2087   saver_info *si = ssi->global;
2088   saver_preferences *p = &si->prefs;
2089   Bool install_cmap_p = p->install_cmap_p;
2090   Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
2091   Visual *new_v = 0;
2092   Bool got_it;
2093
2094   /* On some systems (most recently, MacOS X) OpenGL programs get confused
2095      when you kill one and re-start another on the same window.  So maybe
2096      it's best to just always destroy and recreate the xscreensaver window
2097      when changing hacks, instead of trying to reuse the old one?
2098    */
2099   Bool always_recreate_window_p = True;
2100
2101   if (visual_name && *visual_name)
2102     {
2103       if (!strcmp(visual_name, "default-i") ||
2104           !strcmp(visual_name, "Default-i") ||
2105           !strcmp(visual_name, "Default-I")
2106           )
2107         {
2108           visual_name = "default";
2109           install_cmap_p = True;
2110         }
2111       else if (!strcmp(visual_name, "default-n") ||
2112                !strcmp(visual_name, "Default-n") ||
2113                !strcmp(visual_name, "Default-N"))
2114         {
2115           visual_name = "default";
2116           install_cmap_p = False;
2117         }
2118       else if (!strcmp(visual_name, "gl") ||
2119                !strcmp(visual_name, "Gl") ||
2120                !strcmp(visual_name, "GL"))
2121         {
2122           new_v = ssi->best_gl_visual;
2123           if (!new_v && p->verbose_p)
2124             fprintf (stderr, "%s: no GL visuals.\n", progname);
2125         }
2126
2127       if (!new_v)
2128         new_v = get_visual (ssi->screen, visual_name, True, False);
2129     }
2130   else
2131     {
2132       new_v = ssi->default_visual;
2133     }
2134
2135   got_it = !!new_v;
2136
2137   if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
2138     /* It's not the default visual, so we have no choice but to install. */
2139     install_cmap_p = True;
2140
2141   ssi->install_cmap_p = install_cmap_p;
2142
2143   if (new_v &&
2144       (always_recreate_window_p ||
2145        (ssi->current_visual != new_v) ||
2146        (install_cmap_p != was_installed_p)))
2147     {
2148       Colormap old_c = ssi->cmap;
2149       Window old_w = ssi->screensaver_window;
2150
2151       if (p->verbose_p)
2152         {
2153           fprintf (stderr, "%s: %d: visual ", blurb(), ssi->number);
2154           describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
2155 #if 0
2156           fprintf (stderr, "%s:                  from ", blurb());
2157           describe_visual (stderr, ssi->screen, ssi->current_visual,
2158                            was_installed_p);
2159 #endif
2160         }
2161
2162       reset_stderr (ssi);
2163       ssi->current_visual = new_v;
2164       ssi->current_depth = visual_depth(ssi->screen, new_v);
2165       ssi->cmap = 0;
2166       ssi->screensaver_window = 0;
2167
2168       initialize_screensaver_window_1 (ssi);
2169
2170       /* stderr_overlay_window is a child of screensaver_window, so we need
2171          to destroy that as well (actually, we just need to invalidate and
2172          drop our pointers to it, but this will destroy it, which is ok so
2173          long as it happens before old_w itself is destroyed.) */
2174       reset_stderr (ssi);
2175
2176       raise_window (si, True, True, False);
2177       store_vroot_property (si->dpy,
2178                             ssi->screensaver_window, ssi->screensaver_window);
2179
2180       /* Transfer any grabs from the old window to the new. */
2181       maybe_transfer_grabs (ssi, old_w, ssi->screensaver_window, ssi->number);
2182
2183       /* Now we can destroy the old window without horking our grabs. */
2184       XDestroyWindow (si->dpy, old_w);
2185
2186       if (p->verbose_p)
2187         fprintf (stderr, "%s: %d: destroyed old saver window 0x%lx.\n",
2188                  blurb(), ssi->number, (unsigned long) old_w);
2189
2190       if (old_c &&
2191           old_c != DefaultColormapOfScreen (ssi->screen) &&
2192           old_c != ssi->demo_cmap)
2193         XFreeColormap (si->dpy, old_c);
2194     }
2195
2196   return got_it;
2197 }