http://www.jwz.org/xscreensaver/xscreensaver-5.12.tar.gz
[xscreensaver] / driver / lock.c
index e1d29dc92a958b31d8cbf3b6489e5997df8d012b..2886115d193e856a9c0ee346f54aaacfedeaa05d 100644 (file)
@@ -1,5 +1,5 @@
 /* lock.c --- handling the password dialog for locking-mode.
- * xscreensaver, Copyright (c) 1993-2007 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1993-2008 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
@@ -45,6 +45,9 @@
   static void xfree_lock_grab_smasher (saver_info *si, Bool lock_p);
 #endif /* HAVE_XF86MISCSETGRABKEYSSTATE */
 
+#ifdef HAVE_RANDR
+# include <X11/extensions/Xrandr.h>
+#endif /* HAVE_RANDR */
 
 #ifdef _VROOT_H_
 ERROR!  You must not include vroot.h in this file.
@@ -179,7 +182,7 @@ static void restore_background (saver_info *si);
 
 extern void xss_authenticate(saver_info *si, Bool verbose_p);
 
-static void
+static int
 new_passwd_window (saver_info *si)
 {
   passwd_dialog_data *pw;
@@ -190,7 +193,7 @@ new_passwd_window (saver_info *si)
 
   pw = (passwd_dialog_data *) calloc (1, sizeof(*pw));
   if (!pw)
-    return;
+    return -1;
 
   /* Display the button only if the "newLoginCommand" pref is non-null.
    */
@@ -406,13 +409,14 @@ new_passwd_window (saver_info *si)
   }
 
   si->pw_data = pw;
+  return 0;
 }
 
 
 /**
  * info_msg and prompt may be NULL.
  */
-static void
+static int
 make_passwd_window (saver_info *si,
                    const char *info_msg,
                    const char *prompt,
@@ -428,11 +432,15 @@ make_passwd_window (saver_info *si,
 
   cleanup_passwd_window (si);
 
+  if (! ssi)   /* WTF?  Trying to prompt while no screens connected? */
+    return -1;
+
   if (!si->pw_data)
-    new_passwd_window (si);
+    if (new_passwd_window (si) < 0)
+      return -1;
 
   if (!(pw = si->pw_data))
-    return;
+    return -1;
 
   pw->ratio = 1.0;
 
@@ -614,10 +622,11 @@ make_passwd_window (saver_info *si,
      actually be visible; this takes into account virtual viewports as
      well as Xinerama. */
   {
-    int x, y, w, h;
-    get_screen_viewport (pw->prompt_screen, &x, &y, &w, &h,
-                         pw->previous_mouse_x, pw->previous_mouse_y,
-                         si->prefs.verbose_p);
+    saver_screen_info *ssi = &si->screens [mouse_screen (si)];
+    int x = ssi->x;
+    int y = ssi->y;
+    int w = ssi->width;
+    int h = ssi->height;
     if (si->prefs.debug_p) w /= 2;
     pw->x = x + ((w + pw->width) / 2) - pw->width;
     pw->y = y + ((h + pw->height) / 2) - pw->height;
@@ -678,6 +687,8 @@ make_passwd_window (saver_info *si,
   if (cmap)
     XInstallColormap (si->dpy, cmap);
   draw_passwd_window (si);
+
+  return 0;
 }
 
 
@@ -1277,11 +1288,20 @@ destroy_passwd_window (saver_info *si)
   XWarpPointer (si->dpy, None, RootWindowOfScreen (ssi->screen),
                 0, 0, 0, 0,
                 pw->previous_mouse_x, pw->previous_mouse_y);
+  XSync (si->dpy, False);
 
   while (XCheckMaskEvent (si->dpy, PointerMotionMask, &event))
     if (p->verbose_p)
       fprintf (stderr, "%s: discarding MotionNotify event.\n", blurb());
 
+#ifdef HAVE_XINPUT
+  if (si->using_xinput_extension && si->xinput_DeviceMotionNotify)
+    while (XCheckTypedEvent (si->dpy, si->xinput_DeviceMotionNotify, &event))
+      if (p->verbose_p)
+       fprintf (stderr, "%s: discarding DeviceMotionNotify event.\n",
+                 blurb());
+#endif
+
   if (si->passwd_dialog)
     {
       if (si->prefs.verbose_p)
@@ -1418,8 +1438,12 @@ xfree_lock_grab_smasher (saver_info *si, Bool lock_p)
 {
   saver_preferences *p = &si->prefs;
   int status;
-
+  int event, error;
   XErrorHandler old_handler;
+
+  if (!XF86MiscQueryExtension(si->dpy, &event, &error))
+    return;
+
   XSync (si->dpy, False);
   error_handler_hit_p = False;
   old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
@@ -1463,6 +1487,7 @@ xfree_lock_mode_switch (saver_info *si, Bool lock_p)
   static Bool any_mode_locked_p = False;
   saver_preferences *p = &si->prefs;
   int screen;
+  int real_nscreens = ScreenCount (si->dpy);
   int event, error;
   Bool status;
   XErrorHandler old_handler;
@@ -1472,7 +1497,7 @@ xfree_lock_mode_switch (saver_info *si, Bool lock_p)
   if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
     return;
 
-  for (screen = 0; screen < (si->xinerama_p ? 1 : si->nscreens); screen++)
+  for (screen = 0; screen < real_nscreens; screen++)
     {
       XSync (si->dpy, False);
       old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
@@ -1509,12 +1534,13 @@ undo_vp_motion (saver_info *si)
 #ifdef HAVE_XF86VMODE
   saver_preferences *p = &si->prefs;
   int screen;
+  int real_nscreens = ScreenCount (si->dpy);
   int event, error;
 
   if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
     return;
 
-  for (screen = 0; screen < si->nscreens; screen++)
+  for (screen = 0; screen < real_nscreens; screen++)
     {
       saver_screen_info *ssi = &si->screens[screen];
       int x, y;
@@ -1761,30 +1787,77 @@ passwd_event_loop (saver_info *si)
 {
   saver_preferences *p = &si->prefs;
   char *msg = 0;
-  XEvent event;
+
+  /* We have to go through this union bullshit because gcc-4.4.0 has
+     stricter struct-aliasing rules.  Without this, the optimizer
+     can fuck things up.
+   */
+  union {
+    XEvent x_event;
+# ifdef HAVE_RANDR
+    XRRScreenChangeNotifyEvent xrr_event;
+# endif /* HAVE_RANDR */
+  } event;
 
   passwd_animate_timer ((XtPointer) si, 0);
 
   while (si->unlock_state == ul_read)
     {
-      XtAppNextEvent (si->app, &event);
-      if (event.xany.window == si->passwd_dialog && event.xany.type == Expose)
+      XtAppNextEvent (si->app, &event.x_event);
+
+#ifdef HAVE_RANDR
+      if (si->using_randr_extension &&
+          (event.x_event.type == 
+           (si->randr_event_number + RRScreenChangeNotify)))
+        {
+          /* The Resize and Rotate extension sends an event when the
+             size, rotation, or refresh rate of any screen has changed. */
+
+          if (p->verbose_p)
+            {
+              /* XRRRootToScreen is in Xrandr.h 1.4, 2001/06/07 */
+              int screen = XRRRootToScreen(si->dpy, event.xrr_event.window);
+                fprintf (stderr, "%s: %d: screen change event received\n",
+                         blurb(), screen);
+            }
+
+#ifdef RRScreenChangeNotifyMask
+          /* Inform Xlib that it's ok to update its data structures. */
+          XRRUpdateConfiguration(&event.x_event); /* Xrandr.h 1.9, 2002/09/29 */
+#endif /* RRScreenChangeNotifyMask */
+
+          /* Resize the existing xscreensaver windows and cached ssi data. */
+          if (update_screen_layout (si))
+            {
+              if (p->verbose_p)
+                {
+                  fprintf (stderr, "%s: new layout:\n", blurb());
+                  describe_monitor_layout (si);
+                }
+              resize_screensaver_window (si);
+            }
+        }
+      else
+#endif /* HAVE_RANDR */
+
+      if (event.x_event.xany.window == si->passwd_dialog && 
+          event.x_event.xany.type == Expose)
        draw_passwd_window (si);
-      else if (event.xany.type == KeyPress)
+      else if (event.x_event.xany.type == KeyPress)
         {
-          handle_passwd_key (si, &event.xkey);
-          si->pw_data->caps_p = (event.xkey.state & LockMask);
+          handle_passwd_key (si, &event.x_event.xkey);
+          si->pw_data->caps_p = (event.x_event.xkey.state & LockMask);
         }
-      else if (event.xany.type == ButtonPress || 
-               event.xany.type == ButtonRelease)
+      else if (event.x_event.xany.type == ButtonPress || 
+               event.x_event.xany.type == ButtonRelease)
        {
          si->pw_data->button_state_changed_p = True;
-         handle_unlock_button (si, &event);
+         handle_unlock_button (si, &event.x_event);
          if (si->pw_data->login_button_p)
-           handle_login_button (si, &event);
+           handle_login_button (si, &event.x_event);
        }
       else
-       XtDispatchEvent (&event);
+       XtDispatchEvent (&event.x_event);
     }
 
   switch (si->unlock_state)
@@ -1866,11 +1939,10 @@ remove_trailing_whitespace(const char *str)
   len = strlen(str);
 
   newstr = malloc(len + 1);
-  (void) strcpy(newstr, str);
-
   if (!newstr)
     return NULL;
 
+  (void) strcpy(newstr, str);
   chr = newstr + len;
   while (isspace(*--chr) && chr >= newstr)
     *chr = '\0';
@@ -1898,6 +1970,12 @@ gui_auth_conv(int num_msg,
   const char *info_msg, *prompt;
   struct auth_response *responses;
 
+  if (si->unlock_state == ul_cancel ||
+      si->unlock_state == ul_time)
+    /* If we've already cancelled or timed out in this PAM conversation,
+       don't prompt again even if PAM asks us to! */
+    return -1;
+
   if (!(responses = calloc(num_msg, sizeof(struct auth_response))))
     goto fail;
 
@@ -1932,9 +2010,11 @@ gui_auth_conv(int num_msg,
        info_msg_trimmed = remove_trailing_whitespace(info_msg);
        prompt_trimmed = remove_trailing_whitespace(prompt);
 
-       make_passwd_window(si, info_msg_trimmed, prompt_trimmed,
-                          auth_msgs[i].type == AUTH_MSGTYPE_PROMPT_ECHO
-                          ? True : False);
+       if (make_passwd_window(si, info_msg_trimmed, prompt_trimmed,
+                               auth_msgs[i].type == AUTH_MSGTYPE_PROMPT_ECHO
+                               ? True : False)
+            < 0)
+          goto fail;
 
        if (info_msg_trimmed)
          free(info_msg_trimmed);
@@ -2033,7 +2113,7 @@ auth_finished_cb (saver_info *si)
               event.xany.type == Expose)
             draw_passwd_window (si);
           else if (event.xany.type == ButtonPress || 
-                   event.xany.type == ButtonRelease)
+                   event.xany.type == KeyPress)
             break;
           XSync (si->dpy, False);
         }