From http://www.jwz.org/xscreensaver/xscreensaver-5.34.tar.gz
[xscreensaver] / driver / xscreensaver.c
index daacb41051e2361c05b8a9308163c08029bdfd82..45f0f0c48330afda7192a3b02fc6aee26100f965 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1991-2013 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1991-2015 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
  *   subwindows.  It is an incredible misdesign that one client can make
  *   another client malfunction in this way.
  *
+ *   But here's a new kink that started showing up in late 2014: GNOME programs
+ *   don't actually select for or receive KeyPress events! They do it behind
+ *   the scenes through some kind of Input Method magic, even when running in
+ *   an en_US locale.  However, in that case, those applications *do* seem to
+ *   update the _NET_WM_USER_TIME on their own windows every time they have
+ *   received a secret KeyPress, so we *also* monitor that property on every
+ *   window, and treat changes to it as identical to KeyPress.
+ *
  *   To detect mouse motion, we periodically wake up and poll the mouse
  *   position and button/modifier state, and notice when something has
  *   changed.  We make this check every five seconds by default, and since the
@@ -600,6 +608,16 @@ lock_initialization (saver_info *si, int *argc, char **argv)
         }
     }
 
+  /* Like MacOS, locking under Wayland's embedded X11 server does not work.
+     (X11 grabs don't work because the Wayland window manager lives at a
+     higher level than the X11 emulation layer.)
+   */
+  if (!si->locking_disabled_p && getenv ("WAYLAND_DISPLAY"))
+    {
+      si->locking_disabled_p = True;
+      si->nolock_reason = "Cannot lock securely under Wayland";
+    }
+
   if (si->prefs.debug_p)    /* But allow locking anyway in debug mode. */
     si->locking_disabled_p = False;
 
@@ -659,6 +677,7 @@ connect_to_server (saver_info *si, int *argc, char **argv)
   XA_XSETROOT_ID = XInternAtom (si->dpy, "_XSETROOT_ID", False);
   XA_ESETROOT_PMAP_ID = XInternAtom (si->dpy, "ESETROOT_PMAP_ID", False);
   XA_XROOTPMAP_ID = XInternAtom (si->dpy, "_XROOTPMAP_ID", False);
+  XA_NET_WM_USER_TIME = XInternAtom (si->dpy, "_NET_WM_USER_TIME", False);
   XA_ACTIVATE = XInternAtom (si->dpy, "ACTIVATE", False);
   XA_DEACTIVATE = XInternAtom (si->dpy, "DEACTIVATE", False);
   XA_RESTART = XInternAtom (si->dpy, "RESTART", False);
@@ -1138,6 +1157,7 @@ maybe_reload_init_file (saver_info *si)
       sync_server_dpms_settings (si->dpy,
                                  (p->dpms_enabled_p  &&
                                   p->mode != DONT_BLANK),
+                                 p->dpms_quickoff_p,
                                  p->dpms_standby / 1000,
                                  p->dpms_suspend / 1000,
                                  p->dpms_off / 1000,
@@ -1255,6 +1275,12 @@ main_loop (saver_info *si)
                   "%s: unable to grab keyboard or mouse!  Blanking aborted.\n",
                        blurb());
 
+              /* Since we were unable to blank, clearly we're not locked,
+                 but we might have been prematurely marked as locked by
+                 the LOCK ClientMessage. */
+              if (si->locked_p)
+                set_locked_p (si, False);
+
               schedule_wakeup_event (si, retry, p->debug_p);
               continue;
             }
@@ -1270,19 +1296,16 @@ main_loop (saver_info *si)
         for (i = 0; i < si->nscreens; i++)
           spawn_screenhack (&si->screens[i]);
 
-      /* If we are blanking only, optionally power down monitor right now.
-         To do this, we might need to temporarily re-enable DPMS first.
-       */
+      /* If we are blanking only, optionally power down monitor right now. */
       if (p->mode == BLANK_ONLY &&
           p->dpms_enabled_p && 
           p->dpms_quickoff_p)
         {
           sync_server_dpms_settings (si->dpy, True,
+                                     p->dpms_quickoff_p,
                                      p->dpms_standby / 1000,
                                      p->dpms_suspend / 1000,
-                                     (p->dpms_off
-                                      ? (p->dpms_off / 1000)
-                                      : 0xFFFF),
+                                     p->dpms_off / 1000,
                                      False);
           monitor_power_on (si, False);
         }
@@ -1528,7 +1551,7 @@ main (int argc, char **argv)
   if (p->verbose_p) analyze_display (si);
   initialize_server_extensions (si);
 
-  si->blank_time = time ((time_t) 0); /* must be before ..._window */
+  si->blank_time = time ((time_t *) 0); /* must be before ..._window */
   initialize_screensaver_window (si);
 
   select_events (si);
@@ -1538,6 +1561,7 @@ main (int argc, char **argv)
   sync_server_dpms_settings (si->dpy,
                              (p->dpms_enabled_p  &&
                               p->mode != DONT_BLANK),
+                             p->dpms_quickoff_p,
                              p->dpms_standby / 1000,
                              p->dpms_suspend / 1000,
                              p->dpms_off / 1000,
@@ -1802,29 +1826,47 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
     }
   else if (type == XA_DEACTIVATE)
     {
-      if (! until_idle_p)
-       {
-          if (si->throttled_p && p->verbose_p)
-            fprintf (stderr, "%s: unthrottled.\n", blurb());
-         si->throttled_p = False;
+# if 0
+      /* When -deactivate is received while locked, pop up the dialog box
+         instead of just ignoring it.  Some people depend on this behavior
+         to be able to unlock by using e.g. a fingerprint reader without
+         also having to click the mouse first.
+       */
+      if (si->locked_p) 
+        {
+          clientmessage_response(si, window, False,
+              "DEACTIVATE ClientMessage received while locked: ignored.",
+              "screen is locked.");
+        }
+      else
+# endif /* 0 */
+        {
+          if (! until_idle_p)
+            {
+              if (si->throttled_p && p->verbose_p)
+                fprintf (stderr, "%s: unthrottled.\n", blurb());
+              si->throttled_p = False;
 
-         clientmessage_response(si, window, False,
-                                "DEACTIVATE ClientMessage received.",
-                                "deactivating.");
-         if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
-           {
-             XForceScreenSaver (si->dpy, ScreenSaverReset);
-             return False;
-           }
-         else
-           {
-             return True;
-           }
-       }
-      clientmessage_response(si, window, False,
-     "ClientMessage DEACTIVATE received while inactive: resetting idle timer.",
-                            "not active: idle timer reset.");
-      reset_timers (si);
+              clientmessage_response(si, window, False,
+                                     "DEACTIVATE ClientMessage received.",
+                                     "deactivating.");
+              if (si->using_mit_saver_extension ||
+                  si->using_sgi_saver_extension)
+                {
+                  XForceScreenSaver (si->dpy, ScreenSaverReset);
+                  return False;
+                }
+              else
+                {
+                  return True;
+                }
+            }
+          clientmessage_response(si, window, False,
+                          "ClientMessage DEACTIVATE received while inactive: "
+                          "resetting idle timer.",
+                                 "not active: idle timer reset.");
+          reset_timers (si);
+        }
     }
   else if (type == XA_CYCLE)
     {
@@ -2027,7 +2069,16 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
                            : "locking.");
          sprintf (buf, "LOCK ClientMessage received; %s", response);
          clientmessage_response (si, window, False, buf, response);
+
+          /* Note that this leaves things in a slightly inconsistent state:
+             we are blanked but not locked.  And blanking might actually
+             fail if we can't get the grab. */
          set_locked_p (si, True);
+
+           /* Have to set the time or xscreensaver-command doesn't
+              report the LOCK state change. */
+           si->blank_time = time ((time_t *) 0);
+
          si->selection_mode = 0;
          si->demoing_p = False;
 
@@ -2313,11 +2364,13 @@ analyze_display (saver_info *si)
       vi_in.screen = ssi->real_screen_number;
       vi_out = XGetVisualInfo (si->dpy, VisualScreenMask, &vi_in, &out_count);
       if (!vi_out) continue;
-      for (j = 0; j < out_count; j++)
+      for (j = 0; j < out_count; j++) {
+       if (vi_out[j].depth >= 32) continue;
        if (vi_out[j].class == PseudoColor)
          colormapped_depths |= (1 << vi_out[j].depth);
        else
          non_mapped_depths  |= (1 << vi_out[j].depth);
+       }
       XFree ((char *) vi_out);
 
       if (colormapped_depths)