http://ftp.x.org/contrib/applications/xscreensaver-2.17.tar.gz
[xscreensaver] / driver / windows.c
index 7dabe9f11e12352c432df5d260d54f6799fe2cef..37702a10ab30513adb58c7a8065d126304fac100 100644 (file)
@@ -1,5 +1,5 @@
 /* windows.c --- turning the screen black; dealing with visuals, virtual roots.
- * xscreensaver, Copyright (c) 1991-1997 Jamie Zawinski <jwz@netscape.com>
+ * xscreensaver, Copyright (c) 1991-1998 Jamie Zawinski <jwz@netscape.com>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -80,33 +80,69 @@ static void store_activate_time (saver_info *si, Bool use_last_p);
         Button1MotionMask | Button2MotionMask | Button3MotionMask | \
         Button4MotionMask | Button5MotionMask | ButtonMotionMask)
 
-/* I don't really understand Sync vs Async, but these seem to work... */
-#define grab_kbd(dpy,win) \
-  XGrabKeyboard ((dpy), (win), True, GrabModeSync, GrabModeAsync, CurrentTime)
-#define grab_mouse(dpy,win,cursor) \
-  XGrabPointer ((dpy), (win), True, ALL_POINTER_EVENTS, \
-               GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime)
+
+static int
+grab_kbd(saver_info *si, Window w)
+{
+  saver_preferences *p = &si->prefs;
+  int status = XGrabKeyboard (si->dpy, w, True,
+                             /* I don't really understand Sync vs Async,
+                                but these seem to work... */
+                             GrabModeSync, GrabModeAsync,
+                             CurrentTime);
+  if (p->debug_p)
+    fprintf(real_stderr, "%s: XGrabKeyboard(... 0x%x ...) ==> %s\n",
+           progname, (unsigned long) w,
+           (status == GrabSuccess ? "GrabSuccess" :
+            status == AlreadyGrabbed ? "AlreadyGrabbed" :
+            status == GrabInvalidTime ? "GrabInvalidTime" :
+            status == GrabNotViewable ? "GrabNotViewable" :
+            status == GrabFrozen ? "GrabFrozen" :
+            "???"));
+
+  return status;
+}
+
+static int
+grab_mouse (saver_info *si, Window w, Cursor cursor)
+{
+  saver_preferences *p = &si->prefs;
+  int status = XGrabPointer (si->dpy, w, True, ALL_POINTER_EVENTS,
+                            GrabModeAsync, GrabModeAsync, None,
+                            cursor, CurrentTime);
+  if (p->debug_p)
+    fprintf(real_stderr, "%s: XGrabPointer(... 0x%x, 0x%x ...) ==> %s\n",
+           progname, (unsigned long) w, (unsigned long) cursor,
+           (status == GrabSuccess ? "GrabSuccess" :
+            status == AlreadyGrabbed ? "AlreadyGrabbed" :
+            status == GrabInvalidTime ? "GrabInvalidTime" :
+            status == GrabNotViewable ? "GrabNotViewable" :
+            status == GrabFrozen ? "GrabFrozen" :
+            "???"));
+  return status;
+}
+
 
 void
-grab_keyboard_and_mouse (Display *dpy, Window window, Cursor cursor)
+grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor)
 {
   Status status;
-  XSync (dpy, False);
+  XSync (si->dpy, False);
 
-  status = grab_kbd (dpy, window);
+  status = grab_kbd (si, window);
   if (status != GrabSuccess)
     {  /* try again in a second */
       sleep (1);
-      status = grab_kbd (dpy, window);
+      status = grab_kbd (si, window);
       if (status != GrabSuccess)
        fprintf (stderr, "%s: couldn't grab keyboard!  (%d)\n",
                 progname, status);
     }
-  status = grab_mouse (dpy, window, cursor);
+  status = grab_mouse (si, window, cursor);
   if (status != GrabSuccess)
     {  /* try again in a second */
       sleep (1);
-      status = grab_mouse (dpy, window, cursor);
+      status = grab_mouse (si, window, cursor);
       if (status != GrabSuccess)
        fprintf (stderr, "%s: couldn't grab pointer!  (%d)\n",
                 progname, status);
@@ -114,10 +150,15 @@ grab_keyboard_and_mouse (Display *dpy, Window window, Cursor cursor)
 }
 
 void
-ungrab_keyboard_and_mouse (Display *dpy)
+ungrab_keyboard_and_mouse (saver_info *si)
 {
-  XUngrabPointer (dpy, CurrentTime);
-  XUngrabKeyboard (dpy, CurrentTime);
+  saver_preferences *p = &si->prefs;
+
+  XUngrabPointer (si->dpy, CurrentTime);
+  XUngrabKeyboard (si->dpy, CurrentTime);
+
+  if (p->debug_p)
+    fprintf(real_stderr, "%s: XungrabPointer / XUngrabKeyboard\n", progname);
 }
 
 
@@ -528,11 +569,12 @@ saver_exit (saver_info *si, int status)
   else if (status == 1) status = -1;
 #endif
 
-#ifdef DEBUG
   if (si->prefs.debug_p)
-    /* Do this to drop a core file, so that we can get a stack trace. */
-    abort();
-#endif
+    {
+      fprintf(real_stderr, "%s: dumping core (because of -debug)\n", progname);
+      /* Do this to drop a core file, so that we can get a stack trace. */
+      abort();
+    }
 
   exit (status);
 }
@@ -558,6 +600,7 @@ initialize_screensaver_window_1 (saver_screen_info *ssi)
 {
   saver_info *si = ssi->global;
   saver_preferences *p = &si->prefs;
+  Bool install_cmap_p = ssi->install_cmap_p;
 
   /* This resets the screensaver window as fully as possible, since there's
      no way of knowing what some random client may have done to us in the
@@ -578,8 +621,10 @@ initialize_screensaver_window_1 (saver_screen_info *ssi)
   if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
     ssi->cmap = 0;
 
-  if (p->install_cmap_p ||
-      ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
+  if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
+    install_cmap_p = True;
+
+  if (install_cmap_p)
     {
       if (! ssi->cmap)
        {
@@ -591,31 +636,18 @@ initialize_screensaver_window_1 (saver_screen_info *ssi)
     }
   else
     {
+      Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
       if (ssi->cmap)
        {
          XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
-         if (ssi->cmap != ssi->demo_cmap)
+         if (ssi->cmap != ssi->demo_cmap &&
+             ssi->cmap != def_cmap)
            XFreeColormap (si->dpy, ssi->cmap);
        }
-      ssi->cmap = DefaultColormapOfScreen (ssi->screen);
+      ssi->cmap = def_cmap;
       ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
     }
 
-#if 0
-  if (cmap2)
-    {
-      XFreeColormap (si->dpy, cmap2);
-      cmap2 = 0;
-    }
-
-  if (p->fade_p)
-    {
-      cmap2 = copy_colormap (si->screen, ssi->current_visual, ssi->cmap, 0);
-      if (! cmap2)
-       p->fade_p = p->unfade_p = 0;
-    }
-#endif
-
   attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
              CWBackPixel | CWBackingPixel | CWBorderPixel);
   attrs.override_redirect = True;
@@ -634,9 +666,7 @@ initialize_screensaver_window_1 (saver_screen_info *ssi)
   attrs.backing_pixel = ssi->black_pixel;
   attrs.border_pixel = ssi->black_pixel;
 
-#ifdef DEBUG
   if (p->debug_p) width = width / 2;
-#endif /* DEBUG */
 
   if (!p->verbose_p || printed_visual_info)
     ;
@@ -820,15 +850,22 @@ raise_window (saver_info *si,
   if (p->fade_p && !inhibit_fade && !si->demo_mode_p)
     {
       int grabbed = -1;
+      Window *current_windows = (Window *)
+       calloc(sizeof(Window), si->nscreens);
       Colormap *current_maps = (Colormap *)
        calloc(sizeof(Colormap), si->nscreens);
 
       for (i = 0; i < si->nscreens; i++)
        {
          saver_screen_info *ssi = &si->screens[i];
+         current_windows[i] = ssi->screensaver_window;
          current_maps[i] = (between_hacks_p
                             ? ssi->cmap
                             : DefaultColormapOfScreen (ssi->screen));
+         /* Ensure that the default background of the window is really black,
+            not a pixmap or something.  (This does not clear the window.) */
+         XSetWindowBackground (si->dpy, ssi->screensaver_window,
+                               ssi->black_pixel);
        }
 
       if (p->verbose_p) fprintf (stderr, "%s: fading... ", progname);
@@ -842,7 +879,7 @@ raise_window (saver_info *si,
          /* grab and blacken mouse on the root window (saver not mapped yet)
           */
          if (grabbed != GrabSuccess)
-           grabbed = grab_mouse (si->dpy, ssi->screensaver_window,
+           grabbed = grab_mouse (si, ssi->screensaver_window,
                                  (si->demo_mode_p ? 0 : ssi->cursor));
 
          if (!dont_clear || ssi->stderr_overlay_window)
@@ -851,29 +888,24 @@ raise_window (saver_info *si,
            clear_stderr (ssi);
        }
 
-      fade_screens (si->dpy, current_maps, p->fade_seconds, p->fade_ticks,
-                   True);
+      fade_screens (si->dpy, current_maps, current_windows,
+                   p->fade_seconds, p->fade_ticks, True, !dont_clear);
+      free(current_maps);
+      free(current_windows);
+      current_maps = 0;
+      current_windows = 0;
 
       if (p->verbose_p) fprintf (stderr, "fading done.\n");
 
+#ifdef HAVE_MIT_SAVER_EXTENSION
       for (i = 0; i < si->nscreens; i++)
        {
          saver_screen_info *ssi = &si->screens[i];
-         if (!dont_clear)
-           XClearWindow (si->dpy, ssi->screensaver_window);
-         XMapRaised (si->dpy, ssi->screensaver_window);
-
-#ifdef HAVE_MIT_SAVER_EXTENSION
          if (ssi->server_mit_saver_window &&
              window_exists_p (si->dpy, ssi->server_mit_saver_window))
            XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
-#endif /* HAVE_MIT_SAVER_EXTENSION */
-
-         /* Once the saver window is up, restore the colormap.
-            (The "black" pixels of the two colormaps are compatible.) */
-         if (ssi->cmap)
-           XInstallColormap (si->dpy, ssi->cmap);
        }
+#endif /* HAVE_MIT_SAVER_EXTENSION */
 
       if (grabbed == GrabSuccess)
        XUngrabPointer (si->dpy, CurrentTime);
@@ -918,10 +950,10 @@ blank_screen (saver_info *si)
                            ssi->screensaver_window,
                            ssi->screensaver_window);
     }
-  store_activate_time (si, True);
+  store_activate_time (si, si->screen_blanked_p);
   raise_window (si, False, False, False);
   /* #### */
-  grab_keyboard_and_mouse (si->dpy, si->screens[0].screensaver_window,
+  grab_keyboard_and_mouse (si, si->screens[0].screensaver_window,
                           (si->demo_mode_p ? 0 : si->screens[0].cursor));
 #ifdef HAVE_XHPDISABLERESET
   if (si->locked_p && !hp_locked_p)
@@ -938,7 +970,7 @@ void
 unblank_screen (saver_info *si)
 {
   saver_preferences *p = &si->prefs;
-  int i, j;
+  int i;
 
   store_activate_time (si, True);
   reset_watchdog_timer (si, False);
@@ -946,45 +978,45 @@ unblank_screen (saver_info *si)
   if (p->unfade_p && !si->demo_mode_p)
     {
       int grabbed = -1;
-      int extra_cmaps = 4;
-      int ncmaps = si->nscreens * (extra_cmaps + 1);
-      Colormap *cmaps = (Colormap *) calloc(sizeof(Colormap), ncmaps);
+      Window *current_windows = (Window *)
+       calloc(sizeof(Window), si->nscreens);
+
+      for (i = 0; i < si->nscreens; i++)
+       {
+         saver_screen_info *ssi = &si->screens[i];
+         current_windows[i] = ssi->screensaver_window;
+         /* Ensure that the default background of the window is really black,
+            not a pixmap or something.  (This does not clear the window.) */
+         XSetWindowBackground (si->dpy, ssi->screensaver_window,
+                               ssi->black_pixel);
+       }
 
       if (p->verbose_p) fprintf (stderr, "%s: unfading... ", progname);
 
-      /* Fake out SGI's multi-colormap hardware; see utils/fade.c
-        for an explanation. */
-      for (i = 0; i < ncmaps; i += (extra_cmaps + 1))
-       for (j = 0; j < (extra_cmaps + 1); j++)
-         {
-           cmaps[i+j] = XCreateColormap (si->dpy,
-                                         RootWindow (si->dpy, i),
-                                         DefaultVisual(si->dpy, i),
-                                         AllocAll);
-           if (cmaps[i+j])
-             {
-               blacken_colormap (ScreenOfDisplay(si->dpy, i), cmaps[i+j]);
-               XInstallColormap (si->dpy, cmaps[i+j]);
-             }
-         }
 
-      XGrabServer (si->dpy);
+      XSync (si->dpy, False);
+      XGrabServer (si->dpy);                   /* ############ DANGER! */
+      XSync (si->dpy, False);
+
       for (i = 0; i < si->nscreens; i++)
        {
          saver_screen_info *ssi = &si->screens[i];
          if (grabbed != GrabSuccess)
-           grabbed = grab_mouse (si->dpy, RootWindowOfScreen (ssi->screen),
+           grabbed = grab_mouse (si, RootWindowOfScreen (ssi->screen),
                                  0);
-         XUnmapWindow (si->dpy, ssi->screensaver_window);
          clear_stderr (ssi);
        }
+
       XUngrabServer (si->dpy);
+      XSync (si->dpy, False);                  /* ###### (danger over) */
+
 
-      fade_screens (si->dpy, 0, p->fade_seconds, p->fade_ticks, False);
+      fade_screens (si->dpy, 0, current_windows,
+                   p->fade_seconds, p->fade_ticks,
+                   False, False);
 
-      for (i = 0; i < ncmaps; i++)
-       if (cmaps[i]) XFreeColormap (si->dpy, cmaps[i]);
-      free (cmaps);
+      free(current_windows);
+      current_windows = 0;
 
       if (p->verbose_p) fprintf (stderr, "unfading done.\n");
       if (grabbed == GrabSuccess)
@@ -1035,7 +1067,9 @@ unblank_screen (saver_info *si)
       kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
     }
 
-  ungrab_keyboard_and_mouse (si->dpy);
+  store_activate_time(si, False);  /* store unblank time */
+
+  ungrab_keyboard_and_mouse (si);
   restore_real_vroot (si);
 
 #ifdef HAVE_XHPDISABLERESET
@@ -1046,6 +1080,13 @@ unblank_screen (saver_info *si)
     }
 #endif
 
+  /* Unmap the windows a second time, dammit -- just to avoid a race
+     with the screen-grabbing hacks.  (I'm not sure if this is really
+     necessary; I'm stabbing in the dark now.)
+  */
+  for (i = 0; i < si->nscreens; i++)
+    XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
+
   si->screen_blanked_p = False;
 }
 
@@ -1075,17 +1116,40 @@ select_visual (saver_screen_info *ssi, const char *visual_name)
 {
   saver_info *si = ssi->global;
   saver_preferences *p = &si->prefs;
+  Bool install_cmap_p = p->install_cmap_p;
+  Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
   Visual *new_v;
   Bool got_it;
 
   if (visual_name && *visual_name)
-    new_v = get_visual (ssi->screen, visual_name, True, False);
+    {
+      if (!strcmp(visual_name, "default-i"))
+       {
+         visual_name = "default";
+         install_cmap_p = True;
+       }
+      else if (!strcmp(visual_name, "default-n"))
+       {
+         visual_name = "default";
+         install_cmap_p = False;
+       }
+      new_v = get_visual (ssi->screen, visual_name, True, False);
+    }
   else
-    new_v = ssi->default_visual;
+    {
+      new_v = ssi->default_visual;
+    }
 
   got_it = !!new_v;
 
-  if (new_v && ssi->current_visual != new_v)
+  if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
+    install_cmap_p = True;
+
+  ssi->install_cmap_p = install_cmap_p;
+
+  if (new_v &&
+      ((ssi->current_visual != new_v) ||
+       (install_cmap_p != was_installed_p)))
     {
       Colormap old_c = ssi->cmap;
       Window old_w = ssi->screensaver_window;
@@ -1097,6 +1161,8 @@ select_visual (saver_screen_info *ssi, const char *visual_name)
          describe_visual (stderr, ssi->screen, ssi->current_visual);
          fprintf (stderr, "\t\t\t\tto:   ");
          describe_visual (stderr, ssi->screen, new_v);
+         fprintf (stderr, "\t\t\t\t install cmap:   %s\n",
+                  (install_cmap_p ? "yes" : "no"));
 #else
          fprintf (stderr, "%s: switching to visual ", progname);
          describe_visual (stderr, ssi->screen, new_v);
@@ -1113,7 +1179,7 @@ select_visual (saver_screen_info *ssi, const char *visual_name)
       raise_window (si, True, True, False);
       store_vroot_property (si->dpy,
                            ssi->screensaver_window, ssi->screensaver_window);
-      store_activate_time (si, False);
+      store_activate_time (si, True);
 
       XDestroyWindow (si->dpy, old_w);
       if (old_c &&