/*
 * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

Solaris uses the gtk unlock dialog program originally written by
Ximian & Wipro, in order to provide a dialog box that works with
the GNOME accessibility framework.   This was done as a fork of
the original xscreensaver because the maintainer would not allow
use of a toolkit in the lock dialog - he has since softened his
stance a bit, but this has not been presented to him to see if it
meets his requirements as spelled out at:
        http://www.jwz.org/xscreensaver/toolkits.html

This patch also contains a fixes for:

Sun bug 6541240
       Screen saver will lock user out of the system if they have no
       password set

Sun bug 5077993/GNOME Bug 147639:
        Gok cant automatically UI grab screensaver preferences
        http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=5077993
        http://bugzilla.gnome.org/show_bug.cgi?id=147639

Sun bug 5083155:
        Unable to unlock screen when running dual-head magnification
        http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=5083155

Sun bug 5059445:
        screen kb and screen reader support
        http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=5059445

Sun bug 5039878:
        "Password:" field should be focused / have flashing caret
        http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=5039878

Sun bug 6461887:
        GNOME screen lock does not prevent access to other applications
         via 'alt-tab'

Sun bug 6736157:
        [A11Y] Security problem when desktop a11y support is turned on.

Sun bug 6573182:
        after applying patch 120094-11 (or later), xscreensaver coredump
        http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=6573182
---
 config.h.in           |    3 +
 configure.in          |   23 +-
 driver/Makefile.in    |   59 +++-
 driver/auth.h         |    4 +
 driver/demo-Gtk.c     |   18 +
 driver/dialog-data.h  |  122 ++++++
 driver/lock-Gtk.c     |  956 ++++++++++++++++++++++++++++++++++++++++++++
 driver/lock.c         | 1069 ++++++++++++++++++++++++++++++++++++++++++++-----
 driver/passwd-pam.c   |  207 +++++++++-
 driver/passwd.c       |    1 +
 driver/setuid.c       |    5 +-
 driver/subprocs.c     |   35 ++-
 driver/timers.c       |  114 ++++++-
 driver/types.h        |   18 +
 driver/windows.c      |   21 +-
 driver/xscreensaver.c |  131 ++++++-
 driver/xscreensaver.h |    6 +
 17 files changed, 2654 insertions(+), 135 deletions(-)
 create mode 100644 driver/dialog-data.h
 create mode 100644 driver/lock-Gtk.c

diff --git xscreensaver-5.12/config.h.in xscreensaver-5.12/config.h.in
--- xscreensaver-5.12/config.h.in
+++ xscreensaver-5.12/config.h.in
@@ -405,6 +405,9 @@
    make use of this if it is available. */
 #undef HAVE_XPM
 
+/* Define this to build the external lock dialog */
+#undef HAVE_XSCREENSAVER_LOCK
+
 /* Define this if you have the X Shared Memory Extension. */
 #undef HAVE_XSHM_EXTENSION
 
diff --git xscreensaver-5.12/configure.in xscreensaver-5.12/configure.in
--- xscreensaver-5.12/configure.in
+++ xscreensaver-5.12/configure.in
@@ -2527,6 +2527,8 @@ if test "$with_gtk" = yes; then
   pkg_check_version        libglade-2.0  1.99.0
   pkg_check_version      gdk-pixbuf-2.0  2.0.0
   pkg_check_version gdk-pixbuf-xlib-2.0  2.0.0
+  pkg_check_version           gconf-2.0  2.6.1
+  pkg_check_version  libloginhelper-1.0  1.0
   have_gtk="$ok"
 
   if test "$have_gtk" = no; then
@@ -2542,6 +2544,9 @@ if test "$with_gtk" = yes; then
   fi
 
   if test "$have_gtk" = yes; then
+#--- Begin SUNW addition
+    AC_DEFINE(HAVE_XSCREENSAVER_LOCK,[],[Define this to build the external lock dialog])
+#--- End SUNW addition
     AC_CACHE_CHECK([for Gtk includes], ac_cv_gtk_config_cflags,
                    [ac_cv_gtk_config_cflags=`$pkg_config --cflags $pkgs`])
     AC_CACHE_CHECK([for Gtk libs], ac_cv_gtk_config_libs,
@@ -3626,6 +3631,16 @@ if test "$have_gtk" = yes; then
   ALL_DEMO_PROGRAMS="$PREFERRED_DEMO_PROGRAM $ALL_DEMO_PROGRAMS"
 fi
 
+#--- Begin SUNW addition
+PREFERRED_LOCK_PROGRAM=
+ALL_LOCK_PROGRAMS=
+LOCK_PROGRAM=
+if test "$have_gtk" = yes; then
+  PREFERRED_LOCK_PROGRAM=xscreensaver-lock-Gtk
+  ALL_LOCK_PROGRAMS="$PREFERRED_LOCK_PROGRAM $ALL_LOCK_PROGRAMS"
+  LOCK_PROGRAM=xscreensaver-lock
+fi
+#--- End SUNW addition
 
 if test "$have_kerberos" = yes; then
   PASSWD_SRCS="$PASSWD_SRCS \$(KERBEROS_SRCS)"
@@ -3765,6 +3780,11 @@ AC_SUBST(INCLUDES)
 
 AC_SUBST(PREFERRED_DEMO_PROGRAM)
 AC_SUBST(ALL_DEMO_PROGRAMS)
+#--- Begin SUNW addition
+AC_SUBST(PREFERRED_LOCK_PROGRAM)
+AC_SUBST(ALL_LOCK_PROGRAMS)
+AC_SUBST(LOCK_PROGRAM)
+#--- End SUNW addition
 AC_SUBST(SAVER_LIBS)
 AC_SUBST(MOTIF_LIBS)
 AC_SUBST(GTK_LIBS)
@@ -4244,7 +4264,8 @@ HACK_CONF_DIR=`echo "${HACK_CONF_DIR}" | sed 's@/$@@;s@//*@/@g'`
 
 
 # Sanity check the hackdir
-for bad_choice in xscreensaver xscreensaver-demo xscreensaver-command ; do
+# SUNW addition: added xscreensaver-lock to list on next line
+for bad_choice in xscreensaver xscreensaver-demo xscreensaver-command xscreensaver-lock ; do
   if test "${HACKDIR}" = "${bindir}/${bad_choice}" ; then
     echo ""
     AC_MSG_ERROR([\"--with-hackdir=${bindir}/${bad_choice}\" won't work.
diff --git xscreensaver-5.12/driver/Makefile.in xscreensaver-5.12/driver/Makefile.in
--- xscreensaver-5.12/driver/Makefile.in
+++ xscreensaver-5.12/driver/Makefile.in
@@ -29,6 +29,7 @@ GTK_APPDIR	= $(GTK_DATADIR)/applications
 GTK_ICONDIR	= $(GTK_DATADIR)/pixmaps
 GTK_GLADEDIR	= $(prefix)/lib/xscreensaver/config
 HACK_CONF_DIR	= @HACK_CONF_DIR@
+LOCK_DIR	= $(libexecdir)
 
 CC		= @CC@
 OBJCC		= @OBJCC@
@@ -42,6 +43,7 @@ SUBP_DEFS	= $(DEFS) -DHACK_PATH='"@HACKDIR@"' \
 GTK_DEFS	= $(DEFS) -DDEFAULT_ICONDIR='"$(GTK_GLADEDIR)"' \
 			-DBINDIR='"$(bindir)"'
 CONF_DEFS	= -DHACK_CONFIGURATION_PATH='"$(HACK_CONF_DIR)"'
+LOCK_DEFS	= $(DEFS) -DLOCKDIR=\"$(LOCK_DIR)\"
 
 LIBS		= @LIBS@
 INTL_LIBS	= @INTLLIBS@
@@ -100,6 +102,8 @@ GTK_SRCS	= demo-Gtk.c demo-Gtk-conf.c \
 		  demo-Gtk-widgets.c demo-Gtk-support.c
 GTK_EXTRA_OBJS  = demo-Gtk-widgets.o demo-Gtk-support.o
 GTK_OBJS	= demo-Gtk.o demo-Gtk-conf.o @GTK_EXTRA_OBJS@
+GTK_LOCK_SRCS	= lock-Gtk.c atoms.c remote.c
+GTK_LOCK_OBJS	= lock-Gtk.o atoms.o remote.o
 
 PWENT_SRCS	= passwd-pwent.c
 PWENT_OBJS	= passwd-pwent.o
@@ -219,8 +223,8 @@ GETIMG_LIBS	= $(LIBS) $(X_LIBS) $(XPM_LIBS) $(JPEG_LIBS) \
 		  $(X_PRE_LIBS) -lXt -lX11 $(XMU_LIBS) -lXext $(X_EXTRA_LIBS)
 
 EXES		= xscreensaver xscreensaver-command xscreensaver-demo \
-		  xscreensaver-getimage @EXES_OSX@
-EXES2		= @ALL_DEMO_PROGRAMS@
+		  xscreensaver-getimage @EXES_OSX@ @LOCK_PROGRAM@
+EXES2		= @ALL_DEMO_PROGRAMS@ @ALL_LOCK_PROGRAMS@
 EXES_OSX	= pdf2jpeg
 
 SCRIPTS_1	= xscreensaver-getimage-file xscreensaver-getimage-video \
@@ -250,7 +254,7 @@ VMSFILES	= compile_axp.com compile_decc.com link_axp.com link_decc.com \
 		  vms-getpwnam.c vms-pwd.h vms-hpwd.c vms-validate.c \
 		  vms_axp.opt vms_axp_12.opt vms_decc.opt vms_decc_12.opt
 
-TARFILES	= $(EXTRAS) $(VMSFILES) $(SAVER_SRCS_1) \
+TARFILES	= $(EXTRAS) $(VMSFILES) $(SAVER_SRCS_1) $(GTK_LOCK_SRCS) \
 		  $(MOTIF_SRCS) $(GTK_SRCS) $(PWENT_SRCS) $(PWHELPER_SRCS) \
 		  $(KERBEROS_SRCS) $(PAM_SRCS) $(LOCK_SRCS_1) $(DEMO_SRCS_1) \
 		  $(CMD_SRCS) $(GETIMG_SRCS_1) $(PDF2JPEG_SRCS) $(HDRS) \
@@ -263,7 +267,7 @@ all: $(EXES) $(EXES2)
 tests: $(TEST_EXES)
 
 install:   install-program   install-ad    install-scripts \
-	   install-gnome     install-man   install-xml install-pam
+	   install-gnome     install-man   install-xml
 uninstall: uninstall-program uninstall-ad  \
 	   uninstall-gnome   uninstall-man uninstall-xml  
 
@@ -275,6 +279,9 @@ install-program: $(EXES)
 	@if [ ! -d $(install_prefix)$(bindir) ]; then			\
 	  $(INSTALL_DIRS) $(install_prefix)$(bindir) ;			\
 	 fi
+	@if [ -n "@LOCK_PROGRAM@" -a ! -d $(install_prefix)$(LOCK_DIR) ]; then \
+	  $(INSTALL_DIRS) $(install_prefix)$(LOCK_DIR) ; 		\
+	 fi
 	@inst="$(INSTALL_PROGRAM)" ;					\
 	if [ @NEED_SETUID@ = yes ]; then				\
 	   me=`PATH="$$PATH:/usr/ucb" whoami` ;				\
@@ -303,6 +310,12 @@ install-program: $(EXES)
 	  echo $(INSTALL_PROGRAM) $$exe $(install_prefix)$(bindir)/$$exe ; \
 	       $(INSTALL_PROGRAM) $$exe $(install_prefix)$(bindir)/$$exe ; \
 	 done
+	@if [ -n "@LOCK_PROGRAM@" ]; then				     \
+	  echo $(INSTALL_PROGRAM) xscreensaver-lock \
+	    $(install_prefix)$(LOCK_DIR)/xscreensaver-lock ; \
+	   $(INSTALL_PROGRAM) xscreensaver-lock \
+	    $(install_prefix)$(LOCK_DIR)/xscreensaver-lock ; \
+	fi
 
 install-ad: XScreenSaver.ad
 	@if [ ! -d $(install_prefix)$(AD_DIR) ]; then			      \
@@ -738,7 +751,7 @@ $(SAVER_UTIL_OBJS):
 
 # How we build object files in this directory.
 .c.o:
-	$(CC) -c $(INCLUDES) $(DEFS) $(CFLAGS) $(X_CFLAGS) $<
+	$(CC) -c $(INCLUDES) $(DEFS) $(INTL_DEFS) $(CFLAGS) $(X_CFLAGS) $<
 
 .m.o:
 	$(OBJCC) -c $(INCLUDES) $(DEFS) $(CFLAGS) $(X_CFLAGS) $<
@@ -764,6 +777,16 @@ demo-Gtk-conf.o: demo-Gtk-conf.c
 	$(CC) -c $(INCLUDES) $(CONF_DEFS) $(GTK_DEFS) $(CFLAGS) $(X_CFLAGS) \
 	  $(srcdir)/demo-Gtk-conf.c
 
+# lock takes an extra -D option.
+lock.o:
+	$(CC) -c $(INCLUDES) $(LOCK_DEFS) $(CFLAGS) $(X_CFLAGS) \
+	  $(srcdir)/lock.c
+
+# lock-Gtk takes extra -D and -I options.
+lock-Gtk.o: lock-Gtk.c
+	$(CC) -c $(INCLUDES) -I$(ICON_SRC) $(GTK_DEFS) \
+	  $(CFLAGS) $(X_CFLAGS) $(INTL_DEFS) \
+	  $(srcdir)/lock-Gtk.c
 
 # How we build the default app-defaults file into the program.
 #
@@ -778,7 +801,8 @@ XScreenSaver_Xm_ad.h: XScreenSaver-Xm.ad
 # The executables linked in this directory.
 #
 xscreensaver: $(SAVER_OBJS)
-	$(CC) $(LDFLAGS) -o $@ $(SAVER_OBJS) $(SAVER_LIBS)
+	$(CC) $(LDFLAGS) -o $@ $(SAVER_OBJS) $(SAVER_LIBS) \
+	-lgconf-2 -lgobject-2.0
 
 xscreensaver-command: $(CMD_OBJS)
 	$(CC) $(LDFLAGS) -o $@ $(CMD_OBJS) $(CMD_LIBS)
@@ -794,6 +818,15 @@ xscreensaver-demo: @PREFERRED_DEMO_PROGRAM@
 	       cp -p @PREFERRED_DEMO_PROGRAM@@EXEEXT@ $@@EXEEXT@      ;	\
 	fi
 
+xscreensaver-lock: @PREFERRED_LOCK_PROGRAM@
+	$(INSTALL_PROGRAM) @PREFERRED_LOCK_PROGRAM@ $@
+
+xscreensaver-lock-Gtk: $(GTK_LOCK_OBJS)
+	$(CC) $(LDFLAGS) -o $@ $(GTK_LOCK_OBJS) $(LIBS) $(X_LIBS) \
+	$(GTK_LIBS) $(XML_LIBS) $(X_PRE_LIBS) -lXt -lX11 \
+	$(XDPMS_LIBS) -lXext \
+	$(X_EXTRA_LIBS)
+
 xscreensaver-demo-Xm: $(DEMO_OBJS) $(MOTIF_OBJS)
 	$(CC) $(LDFLAGS) -o $@ $(DEMO_OBJS) $(MOTIF_OBJS) $(LIBS) $(X_LIBS) \
 	$(MOTIF_LIBS) $(INTL_LIBS) $(X_PRE_LIBS) -lXt -lX11 \
@@ -817,7 +850,7 @@ pdf2jpeg: $(PDF2JPEG_OBJS)
 
 
 TEST_PASSWD_OBJS = test-passwd.o $(LOCK_OBJS_1) $(PASSWD_OBJS) \
-	 subprocs.o setuid.o splash.o prefs.o mlstring.o exec.o \
+	 subprocs.o setuid.o splash.o prefs.o mlstring.o \
 	$(SAVER_UTIL_OBJS)
 test-passwd.o: XScreenSaver_ad.h
 
@@ -907,8 +940,14 @@ dpms.o: $(srcdir)/types.h
 dpms.o: $(srcdir)/xscreensaver.h
 exec.o: ../config.h
 exec.o: $(srcdir)/exec.h
+lock-Gtk.o: $(srcdir)/atoms.h
+lock-Gtk.o: ../config.h
+lock-Gtk.o: $(srcdir)/remote.h
+lock-Gtk.o: $(UTILS_SRC)/xscreensaver-intl.h
 lock.o: $(srcdir)/auth.h
 lock.o: ../config.h
+lock.o: $(srcdir)/dialog-data.h
+lock.o: $(srcdir)/exec.h
 lock.o: $(srcdir)/mlstring.h
 lock.o: $(srcdir)/prefs.h
 lock.o: $(srcdir)/types.h
@@ -917,6 +956,8 @@ lock.o: $(srcdir)/xscreensaver.h
 mlstring.o: $(srcdir)/mlstring.h
 passwd.o: $(srcdir)/auth.h
 passwd.o: ../config.h
+passwd.o: $(srcdir)/dialog-data.h
+passwd.o: $(srcdir)/mlstring.h
 passwd.o: $(srcdir)/prefs.h
 passwd.o: $(srcdir)/types.h
 passwd.o: $(srcdir)/xscreensaver.h
@@ -984,6 +1025,8 @@ test-vp.o: ../config.h
 test-xdpms.o: ../config.h
 test-xinerama.o: ../config.h
 timers.o: ../config.h
+timers.o: $(srcdir)/dialog-data.h
+timers.o: $(srcdir)/mlstring.h
 timers.o: $(srcdir)/prefs.h
 timers.o: $(srcdir)/types.h
 timers.o: $(srcdir)/xscreensaver.h
@@ -1011,6 +1054,8 @@ xscreensaver-getimage.o: $(UTILS_SRC)/yarandom.h
 xscreensaver.o: XScreenSaver_ad.h
 xscreensaver.o: $(srcdir)/auth.h
 xscreensaver.o: ../config.h
+xscreensaver.o: $(srcdir)/dialog-data.h
+xscreensaver.o: $(srcdir)/mlstring.h
 xscreensaver.o: $(srcdir)/prefs.h
 xscreensaver.o: $(srcdir)/types.h
 xscreensaver.o: $(UTILS_SRC)/resources.h
diff --git xscreensaver-5.12/driver/auth.h xscreensaver-5.12/driver/auth.h
--- xscreensaver-5.12/driver/auth.h
+++ xscreensaver-5.12/driver/auth.h
@@ -51,4 +51,8 @@ xss_authenticate(saver_info *si, Bool verbose_p);
 void
 auth_finished_cb (saver_info *si);
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+extern int write_to_child (saver_info* si, const char* cmd, const char *msg);
+#endif
+
 #endif
diff --git xscreensaver-5.12/driver/demo-Gtk.c xscreensaver-5.12/driver/demo-Gtk.c
--- xscreensaver-5.12/driver/demo-Gtk.c
+++ xscreensaver-5.12/driver/demo-Gtk.c
@@ -98,6 +98,8 @@
 # define G_MODULE_EXPORT /**/
 #endif /* !HAVE_GTK2 */
 
+#include <gconf/gconf-client.h>
+
 #if defined(DEFAULT_ICONDIR) && !defined(GLADE_DIR)
 # define GLADE_DIR DEFAULT_ICONDIR
 #endif
@@ -5006,6 +5008,22 @@ main (int argc, char **argv)
   load_init_file (dpy, p);
   initialize_sort_map (s);
 
+  /* Bug 147639: Gok cant automatically UI grab screensaver preferences */
+  {
+    GConfClient *client = gconf_client_get_default ();
+
+#define KEY "/desktop/gnome/interface/accessibility"
+
+    /* check if accessibilty mode is enabled */
+    if (gconf_client_get_bool (client, KEY, NULL))
+      {
+	/* GTK Accessibility Module initialized */
+	const char *modulesptr = g_getenv ("GTK_MODULES");
+	if (!modulesptr || (modulesptr [0] == '\0'))
+	  putenv ("GTK_MODULES=gail:atk-bridge");
+      }
+  }
+
   /* Now that Xt has been initialized, and the resources have been read,
      we can set our `progname' variable to something more in line with
      reality.
diff --git xscreensaver-5.12/driver/dialog-data.h xscreensaver-5.12/driver/dialog-data.h
new file mode 100644
--- /dev/null
+++ xscreensaver-5.12/driver/dialog-data.h
@@ -0,0 +1,122 @@
+/* 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
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or
+ * implied warranty.
+ */
+
+#ifndef __DIALOG_DATA_H__
+#define __DIALOG_DATA_H__
+
+#include <stdio.h>
+#include "types.h"
+#include "mlstring.h"
+
+struct passwd_dialog_data {
+
+  saver_screen_info *prompt_screen;
+  int previous_mouse_x, previous_mouse_y;
+
+  char typed_passwd [80];
+
+  XtIntervalId timer;
+  int i_beam;
+
+  float ratio;
+  Position x, y;
+  Dimension width;
+  Dimension height;
+  Dimension border_width;
+
+  Bool echo_input;
+  Bool show_stars_p; /* "I regret that I have but one asterisk for my country."
+                        -- Nathan Hale, 1776. */
+
+  char *heading_label;
+  char *body_label;
+  char *user_label;
+  mlstring *info_label;
+  /* The entry field shall only be displayed if prompt_label is not NULL */
+  mlstring *prompt_label;
+  char *date_label;
+  char *passwd_string;
+  Bool passwd_changed_p; /* Whether the user entry field needs redrawing */
+  Bool caps_p;           /* Whether we saw a keypress with caps-lock on */
+  char *unlock_label;
+  char *login_label;
+  char *uname_label;
+
+  Bool show_uname_p;
+
+#ifndef HAVE_XSCREENSAVER_LOCK
+  XFontStruct *heading_font;
+  XFontStruct *body_font;
+  XFontStruct *label_font;
+  XFontStruct *passwd_font;
+  XFontStruct *date_font;
+  XFontStruct *button_font;
+  XFontStruct *uname_font;
+
+  Pixel foreground;
+  Pixel background;
+  Pixel passwd_foreground;
+  Pixel passwd_background;
+  Pixel thermo_foreground;
+  Pixel thermo_background;
+  Pixel shadow_top;
+  Pixel shadow_bottom;
+  Pixel button_foreground;
+  Pixel button_background;
+
+  Dimension preferred_logo_width, logo_width;
+  Dimension preferred_logo_height, logo_height;
+  Dimension thermo_width;
+  Dimension internal_border;
+  Dimension shadow_width;
+
+  Dimension passwd_field_x, passwd_field_y;
+  Dimension passwd_field_width, passwd_field_height;
+
+  Dimension unlock_button_x, unlock_button_y;
+  Dimension unlock_button_width, unlock_button_height;
+
+  Dimension login_button_x, login_button_y;
+  Dimension login_button_width, login_button_height;
+
+  Dimension thermo_field_x, thermo_field_y;
+  Dimension thermo_field_height;
+
+  Pixmap logo_pixmap;
+  Pixmap logo_clipmask;
+  int logo_npixels;
+  unsigned long *logo_pixels;
+#endif /* ! HAVE_XSCREENSAVER_LOCK */
+
+  Cursor passwd_cursor;
+  Bool unlock_button_down_p;
+  Bool login_button_down_p;
+  Bool login_button_p;
+  Bool login_button_enabled_p;
+  Bool button_state_changed_p; /* Refers to both buttons */
+
+  Pixmap save_under;
+  Pixmap user_entry_pixmap;
+
+#ifdef HAVE_XSCREENSAVER_LOCK
+  /* extern passwd dialog stuff */
+  XtInputId stdout_input_id;
+  int       stdin_fd;    /* child's stdin - parent writes to this */
+  int       stdout_fd;   /* child's stdout - parent reads from this */
+  FILE     *stdin_file;  /* child's stdin - parent writes to this */
+  FILE     *stdout_file; /* child's stdout - parent reads from this */
+  Bool      got_windowid;
+  Bool      got_passwd;
+#endif
+};
+
+#endif /* __DIALOG_DATA_H__ */
+
diff --git xscreensaver-5.12/driver/lock-Gtk.c xscreensaver-5.12/driver/lock-Gtk.c
new file mode 100644
--- /dev/null
+++ xscreensaver-5.12/driver/lock-Gtk.c
@@ -0,0 +1,956 @@
+/* lock-Gtk.c -- a GTK+ password dialog for xscreensaver
+ * xscreensaver, Copyright (c) 1993-1998 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
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation.  No representations are made about the suitability of this
+ * software for any purpose.  It is provided "as is" without express or
+ * implied warranty.
+ */
+
+/* GTK+ locking code written by Jacob Berkman  <jacob@ximian.com> for
+ *  Sun Microsystems.
+ *
+ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_GTK2 /* whole file */
+
+#include <xscreensaver-intl.h>
+
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+
+/* AT-enabled */
+#include <stdio.h>
+#include <ctype.h>
+#include <X11/Xos.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xutil.h>
+#include <X11/Xmu/WinUtil.h>
+
+#include <gconf/gconf-client.h>
+#include <libbonobo.h>
+#include <login-helper/Accessibility_LoginHelper.h>
+#include <atk/atkobject.h>
+
+#include "remote.h"
+#include "atoms.h"
+
+#if GTK_CHECK_VERSION(2,14,0)
+# define GET_WINDOW(w)          gtk_widget_get_window (w)
+#else
+# define GET_WINDOW(w)          ((w)->window)
+#endif
+
+static Atom XA_UNLOCK_RATIO;
+
+typedef struct {
+  GtkWidget *dialog;
+  GtkWidget *user_prompt_label;
+  GtkWidget *user_input_entry;
+  GtkWidget *progress;
+  GtkWidget *button;
+  GtkWidget *msg_label;
+  GtkWidget *pam_message_label;
+} PasswdDialog;
+
+/*Global info */
+#define MAXRAISEDWINS  2
+
+char *progname = 0;
+FILE *parent_file = NULL; /* child writes to parent on this */
+
+#define FD_TO_PARENT  9
+
+/* Send a command to the xscreensaver parent daemon
+   Arguments:
+    - msg - type of message - "input", "raise_wid", etc.
+    - data - data for message
+    - flush - whether to flush now or allow stdio to buffer
+   Message format sent to parent:
+    "msg\n" if no data, otherwise "msg=data\n"
+
+   Can be used to flush previously buffered messages by calling
+   with NULL msg & data, and TRUE for flush.
+ */
+static int
+write_to_parent (const char* msg, const char *data, gboolean flush)
+{
+  int len = 0;
+
+  /*
+  fprintf (stderr, "-->Child write_to_parent() string to send is: %s=%s\n",
+           msg, data ? data : "(null)");
+  fflush (stderr);
+  */
+
+  if (msg)
+    {
+      if (data)
+        len = fprintf (parent_file, "%s=%s\n", msg, data);
+      else
+        len = fprintf (parent_file, "%s\n", msg);
+    }
+
+  if (flush)
+    fflush (parent_file);
+
+  return len;
+}
+
+/* Send parent a message with a window id as the data */
+static void
+write_windowid (const char* msg, Window w)
+{
+  char s[16]; /* more than long enough to hold a 32-bit integer + '\0' */
+
+  snprintf(s, sizeof(s), "0x%lx", w);
+  write_to_parent(msg, s, FALSE);
+}
+
+static GtkWidget *
+load_unlock_logo_image (void)
+{
+  const char *logofile;
+  struct stat statbuf;
+
+  logofile = DEFAULT_ICONDIR "/unlock-logo.png";
+
+  if (stat (logofile, &statbuf) != 0)
+    {
+      logofile = DEFAULT_ICONDIR "/logo-180.gif"; /* fallback */
+    }
+
+  return gtk_image_new_from_file (logofile);
+}
+
+/* Create unlock dialog */
+static PasswdDialog *
+make_dialog (gboolean center_pos)
+{
+  GtkWidget *dialog;
+  AtkObject *atk_dialog;
+  GtkWidget *frame1, *frame2;
+  GtkWidget *vbox;
+  GtkWidget *hbox1, *hbox2;
+  GtkWidget *bbox;
+  GtkWidget *vbox2;
+  GtkWidget *entry;
+  AtkObject *atk_entry;
+  GtkWidget *title_label, *msg_label, *prompt_label,
+    *user_label, *date_label, *pam_msg_label;
+  AtkObject *atk_title_label, *atk_prompt_label;
+  GtkWidget *button;
+  GtkWidget *image;
+  GtkWidget *progress;
+  char *version;
+  char *user;
+  char *host;
+  char *s;
+  gchar *format_string_locale, *format_string_utf8;
+  PasswdDialog *pwd;
+
+  /* taken from lock.c */
+  char buf[256];
+  gchar *utf8_format;
+  time_t now = time (NULL);
+  struct tm* tm;
+
+  server_xscreensaver_version (GDK_DISPLAY (), &version, &user, &host);
+
+  if (!version)
+    {
+      fprintf (stderr, "%s: no xscreensaver running on display %s, exiting.\n",
+               progname, gdk_get_display ());
+      exit (1);
+    }
+
+  /* PUSH */
+  gtk_widget_push_colormap (gdk_rgb_get_cmap ());
+
+  pwd = g_new0 (PasswdDialog, 1);
+
+  dialog = gtk_window_new (GTK_WINDOW_POPUP);
+  pwd->dialog = dialog;
+
+  /*
+  ** bugid: 5077989(P2)Bug 147580: password input dialogue obscures GOK
+     gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
+     bugid: 5002244:  scr unlock dialog incompatible with MAG technique
+  ** 6182506: scr dialog is obscured by MAG window
+  */
+  if (center_pos)
+    gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ALWAYS);
+  else
+    gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
+
+  gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); /*mali99 irritating*/
+
+  /* AT-enabled dialog role = frame */
+  atk_dialog = gtk_widget_get_accessible (dialog);
+  atk_object_set_description (atk_dialog, _("screen unlock dialog"));
+
+  /* frame */
+  frame1 = g_object_new (GTK_TYPE_FRAME,
+                         "shadow", GTK_SHADOW_OUT,
+                         NULL);
+  gtk_container_add (GTK_CONTAINER (dialog), frame1);
+  /* AT role = panel */
+
+  /* vbox */
+  vbox = gtk_vbox_new (FALSE, 10);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
+  gtk_container_add (GTK_CONTAINER (frame1), vbox);
+  /* AT role= filler(default) */
+
+  /* hbox */
+  hbox1 = gtk_hbox_new (FALSE, 5);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox1,
+                      TRUE, TRUE, 0);
+
+  /* image frame */
+  frame2 = g_object_new (GTK_TYPE_FRAME,
+                         "shadow", GTK_SHADOW_ETCHED_IN,
+                         NULL);
+  gtk_box_pack_start (GTK_BOX (hbox1), frame2,
+                      TRUE, TRUE, 0);
+  /* AT role= filler(default) */
+
+  /* image */
+  image = load_unlock_logo_image ();
+  /* AT role = icon */
+  gtk_container_add (GTK_CONTAINER (frame2), image);
+
+  /* progress thingie */
+  progress = g_object_new (GTK_TYPE_PROGRESS_BAR,
+                           "orientation", GTK_PROGRESS_BOTTOM_TO_TOP,
+                           "fraction", 1.0,
+                           NULL);
+  gtk_box_pack_start (GTK_BOX (hbox1), progress,
+                      FALSE, FALSE, 0);
+  pwd->progress = progress;
+  atk_object_set_description (gtk_widget_get_accessible (progress),
+            _("Percent of time you have left to unlock the screen."));
+
+  /* text fields */
+  vbox2 = gtk_vbox_new (FALSE, 20);
+  gtk_box_pack_start (GTK_BOX (hbox1), vbox2,
+                      TRUE, TRUE, 0);
+  /* AT role =filler */
+
+  s = g_markup_printf_escaped ("<span size=\"xx-large\"><b>%s </b></span>",
+                               _("Screensaver"));
+  /* XScreenSaver foo label */
+  title_label = g_object_new (GTK_TYPE_LABEL,
+                              "use-markup", TRUE,
+                              "label", s,
+                              NULL);
+  g_free (s);
+  gtk_box_pack_start (GTK_BOX (vbox2), title_label,
+                      FALSE, FALSE, 0);
+  /* AT role = label prog name */
+  atk_title_label = gtk_widget_get_accessible (title_label);
+  atk_object_add_relationship (atk_title_label, ATK_RELATION_LABEL_FOR,
+                               atk_dialog);
+  atk_object_add_relationship (atk_dialog, ATK_RELATION_LABELLED_BY,
+                               atk_title_label);
+
+  /* This display is locked. */
+  msg_label = g_object_new (GTK_TYPE_LABEL,
+                            "use-markup", TRUE,
+                            "label", _("<b>This display is locked.</b>"),
+                            NULL);
+  pwd->msg_label = msg_label;
+  gtk_box_pack_start (GTK_BOX (vbox2), msg_label,
+                      FALSE, FALSE, 0);
+
+  /* User information */
+  s = g_strdup_printf (_("User: %s"), user ? user : "");
+  user_label = g_object_new (GTK_TYPE_LABEL,
+                             "label", s,
+                             "use_underline", TRUE,
+                             NULL);
+  g_free(s);
+  gtk_label_set_width_chars (GTK_LABEL (user_label), 35);
+  gtk_box_pack_start (GTK_BOX (vbox2), user_label, FALSE, FALSE, 0);
+
+  /* User input */
+  hbox2 = gtk_widget_new (GTK_TYPE_HBOX,
+                          "border_width", 5,
+                          "visible", TRUE,
+                          "homogeneous", FALSE,
+                          "spacing", 1,
+                          NULL);
+
+  /* PAM prompt */
+  prompt_label = g_object_new (GTK_TYPE_LABEL,
+                               /* blank space for prompt */
+                               "label", _("         "),
+                               "use_underline", TRUE,
+                               "use_markup", FALSE,
+                               "justify", GTK_JUSTIFY_CENTER,
+                               "wrap", FALSE,
+                               "selectable", FALSE,
+                               "xalign", 1.0,
+                               "xpad", 0,
+                               "ypad", 0,
+                               "visible", FALSE,
+                               NULL);
+  pwd->user_prompt_label = prompt_label;
+
+  entry = g_object_new (GTK_TYPE_ENTRY,
+                        "activates-default", TRUE,
+                        "visible", TRUE,
+                        "editable", TRUE,
+                        "visibility", FALSE,
+                        "can_focus", TRUE,
+                        NULL);
+  pwd->user_input_entry = entry;
+  /* gtk_widget_grab_focus (entry); */
+  atk_entry = gtk_widget_get_accessible (entry);
+  atk_object_set_role (atk_entry, ATK_ROLE_PASSWORD_TEXT);
+
+  /* AT role = label for input widget */
+  atk_prompt_label = gtk_widget_get_accessible (prompt_label);
+  atk_object_add_relationship (atk_prompt_label, ATK_RELATION_LABEL_FOR,
+                               atk_entry);
+  atk_object_add_relationship (atk_entry, ATK_RELATION_LABELLED_BY,
+                               atk_prompt_label);
+
+  gtk_box_pack_start (GTK_BOX (hbox2), prompt_label, FALSE, FALSE, 0);
+  gtk_box_pack_end (GTK_BOX (hbox2), entry, TRUE, TRUE, 0);
+  gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 0);
+
+  pam_msg_label = g_object_new (GTK_TYPE_LABEL,
+                                NULL);
+  pwd->pam_message_label = pam_msg_label;
+
+  gtk_box_pack_start (GTK_BOX (vbox2), pam_msg_label, FALSE, FALSE, 0);
+
+  /* date string */
+  tm = localtime (&now);
+  memset (buf, 0, sizeof (buf));
+  format_string_utf8 = _("%d-%b-%y (%a); %I:%M %p");
+  format_string_locale = g_locale_from_utf8 (format_string_utf8, -1,
+                                             NULL, NULL, NULL);
+  strftime (buf, sizeof (buf) - 1, format_string_locale, tm);
+  g_free (format_string_locale);
+
+  utf8_format = g_locale_to_utf8 (buf, -1, NULL, NULL, NULL);
+  s = g_markup_printf_escaped ("<small>%s</small>", utf8_format);
+  g_free (utf8_format);
+
+  date_label = g_object_new (GTK_TYPE_LABEL,
+                             "use-markup", TRUE,
+                             "label", s,
+                             NULL);
+  g_free (s);
+  gtk_box_pack_start (GTK_BOX (vbox2), date_label,
+                      FALSE, FALSE, 0);
+
+  /* button box */
+  bbox = g_object_new (GTK_TYPE_HBUTTON_BOX,
+                       "layout-style", GTK_BUTTONBOX_END,
+                       "spacing", 10,
+                       NULL);
+
+  /* Ok button */
+  button = gtk_button_new_from_stock (GTK_STOCK_OK);
+  pwd->button = button;
+
+  gtk_box_pack_end (GTK_BOX (bbox), button,
+                    FALSE, TRUE, 0);
+
+  free (user);
+  free (version);
+  free (host);
+
+  /* POP */
+  gtk_widget_pop_colormap ();
+
+  return pwd;
+}
+
+/* Callback for when user has finished entering input, even though
+   we don't display an "OK" button for them to click on */
+static void
+ok_clicked_cb (GtkWidget *button, PasswdDialog *pwd)
+{
+  const char *s;
+
+  g_object_set (pwd->msg_label, "label", _("<b>Checking...</b>"), NULL);
+
+  s = gtk_entry_get_text (GTK_ENTRY (pwd->user_input_entry));
+  write_to_parent ("input", s, TRUE);
+
+  /* Reset password field to blank, else passwd field shows old passwd *'s,
+     visible when passwd is expired, and pam is walking the user to change
+     old passwd.
+   */
+  gtk_editable_delete_text (GTK_EDITABLE (pwd->user_input_entry), 0, -1);
+  gtk_widget_hide (pwd->user_input_entry);
+  gtk_widget_hide (pwd->user_prompt_label);
+}
+
+static void
+connect_signals (PasswdDialog *pwd)
+{
+  g_signal_connect (pwd->button, "clicked",
+                    G_CALLBACK (ok_clicked_cb),
+                    pwd);
+
+  g_signal_connect (pwd->user_input_entry, "activate",
+                    G_CALLBACK (ok_clicked_cb),
+                    pwd);
+
+  g_signal_connect (pwd->dialog, "delete-event",
+                    G_CALLBACK (gtk_main_quit),
+                    NULL);
+}
+
+static GdkFilterReturn
+dialog_filter_func (GdkXEvent *xevent, GdkEvent *gevent, gpointer data)
+{
+  PasswdDialog *pwd = data;
+  XEvent *event = xevent;
+  gdouble ratio;
+
+  if ((event->xany.type != ClientMessage ||
+       event->xclient.message_type != XA_UNLOCK_RATIO))
+    return GDK_FILTER_CONTINUE;
+
+  ratio = event->xclient.data.l[0] / (gdouble)100.0;
+
+  /* CR 6176524 passwdTimeoutEnable for disabled user */
+  if (event->xclient.data.l[1] == 0)
+    g_object_set (pwd->progress, "fraction", ratio, NULL);
+
+  return GDK_FILTER_REMOVE;
+}
+
+static gboolean
+handle_input (GIOChannel *source, GIOCondition cond, gpointer data)
+{
+  PasswdDialog *pwd = data;
+  GIOStatus status;
+  char *str;
+  char *label;
+  char *hmsg = NULL;  /* This is the heading of lock dialog..shows status */
+
+  if (cond & G_IO_HUP) /* daemon crashed/exited/was killed */
+    gtk_main_quit ();
+
+  do
+    {
+      status = g_io_channel_read_line (source, &str, NULL, NULL, NULL);
+    }
+  while (status == G_IO_STATUS_AGAIN);
+
+/* debug only
+  if (status == G_IO_STATUS_ERROR)
+      g_message ("handle input() status_error %s\n",str);
+  if (status == G_IO_STATUS_EOF)
+      g_message ("handle input() status_eof %s\n",str);
+  if (status == G_IO_STATUS_NORMAL)
+      g_message ("handle input() status_normal %s\n",str);
+  Most likely, the returned error msg of g_io_channel_read_line(),
+  i.e str will not be translated into other locales ...
+*/
+
+  if (str)
+    {
+      /* strip trailing newline */
+      char *nl = strrchr(str, '\n');
+      if (nl)
+        *nl = 0;
+
+      /*
+      fprintf (stderr,">>>>>Child..in handle_input..string is:%s\n",str);
+      fflush (stderr);
+      */
+
+      /* Handle commands from parent daemon */
+
+      if (((strncmp (str, "ul_", 3)) == 0))
+        {
+          /* search for =, and if found, split into two strings there */
+          char *msgstr = strchr(str, '='); /* Data sent with command */
+          if (msgstr)
+            *msgstr++ = 0;
+
+          if ((strcmp (str, "ul_ok") == 0))
+            {
+              hmsg = _("Authentication Successful!");
+            }
+          else if ((strcmp (str, "ul_acct_ok") == 0))
+            {
+              hmsg = _("PAM Account Management Also Successful!");
+            }
+          else if ((strcmp (str, "ul_setcred_fail") == 0))
+            {
+              hmsg = _("Just a Warning PAM Set Credential Failed!");
+            }
+          else if ((strcmp (str, "ul_setcred_ok") == 0))
+            {
+              hmsg = _("PAM Set Credential Also Successful!");
+            }
+          else if ((strcmp (str, "ul_acct_fail") == 0))
+            {
+              hmsg = _("Your Password has expired.");
+            }
+          else if ((strcmp (str, "ul_fail") == 0))
+            {
+              hmsg = _("Sorry!");
+            }
+          else if ((strcmp (str, "ul_read") == 0))
+            {
+              hmsg = _("Waiting for user input!");
+            }
+          else if ((strcmp (str, "ul_time") == 0))
+            {
+              hmsg = _("Timed Out!");
+            }
+          else if ((strcmp (str, "ul_null") == 0))
+            {
+              hmsg = _("Still Checking!");
+            }
+          else if ((strcmp (str, "ul_cancel") == 0))
+            {
+              hmsg = _("Authentication Cancelled!");
+            }
+          else if ((strcmp (str, "ul_pamprompt") == 0))
+            {
+              gtk_label_set_text (GTK_LABEL (pwd->user_prompt_label), msgstr);
+              gtk_widget_show (pwd->user_prompt_label);
+              msgstr = NULL; /* clear message so we don't show it twice */
+            }
+          else if ((strcmp (str, "ul_prompt_echo") == 0))
+            {
+              if ((strcmp (msgstr, "true") == 0))
+                {
+                  gtk_entry_set_visibility
+                    (GTK_ENTRY (pwd->user_input_entry), TRUE);
+                }
+              else
+                {
+                  if ((strcmp (msgstr, "stars") == 0))
+                    /* reset to default display of "*" or bullet */
+                    gtk_entry_unset_invisible_char
+                      (GTK_ENTRY (pwd->user_input_entry));
+                  else
+                    /* set to no display */
+                    gtk_entry_set_invisible_char
+                       (GTK_ENTRY (pwd->user_input_entry), 0);
+
+                  gtk_entry_set_visibility
+                    (GTK_ENTRY (pwd->user_input_entry), FALSE);
+                }
+              msgstr = NULL; /* clear message so we don't show it to user */
+              /* Show the entry field */
+              gtk_widget_show (pwd->user_input_entry);
+              gtk_widget_grab_focus (pwd->user_input_entry);
+              gdk_display_sync
+		  (gtk_widget_get_display (pwd->user_input_entry));
+            }
+          else if ((strcmp (str, "ul_message") == 0))
+            {
+              hmsg = NULL; /* only show msg */
+            }
+          else
+            {
+              /* Should not be others, but if so just show it */
+              hmsg = str;
+            }
+
+          if (hmsg)
+            {
+              label = g_markup_printf_escaped ("<b>%s</b>", hmsg);
+              g_object_set (pwd->msg_label, "label", label, NULL);
+              g_free (label);
+            }
+
+          if (msgstr)
+            {
+              gtk_label_set_text (GTK_LABEL (pwd->pam_message_label), msgstr);
+            }
+        }
+      else if ((strcmp (str, "cmd_exit") == 0))
+        {
+          gtk_main_quit ();
+        }
+      else /* something came through that didn't start with ul_ */
+        {
+          gtk_label_set_text (GTK_LABEL (pwd->pam_message_label), str);
+        }
+
+      g_free (str);
+    }
+
+  return (status != G_IO_STATUS_EOF);
+}
+
+int
+main (int argc, char *argv[])
+{
+  GIOChannel *ioc;
+  PasswdDialog *pwd;
+  char *s;
+  char *real_progname = argv[0];
+  GConfClient *client;
+  const char *modulesptr = NULL;
+  int i;
+
+  gboolean  at_enable  = FALSE; /* accessibility mode enabled ? */
+  Bonobo_ServerInfoList *server_list = NULL;
+  CORBA_Environment ev;
+  Accessibility_LoginHelper helper;
+  Accessibility_LoginHelper *helper_list = NULL;
+  CORBA_boolean safe;
+  gboolean center_position = TRUE; /* center dialog on screen? */
+
+#ifdef ENABLE_NLS
+  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+  textdomain (GETTEXT_PACKAGE);
+
+#ifdef HAVE_GTK2
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#else /* ! HAVE_GTK2 */
+  if (!setlocale (LC_ALL, ""))
+    fprintf (stderr, "%s: locale not supported by C library\n", real_progname);
+#endif /* ! HAVE_GTK2 */
+#endif /* ENABLE_NLS */
+
+  s = strrchr (real_progname, '/');
+  if (s) real_progname = s+1;
+  progname = real_progname;
+
+  parent_file = fdopen(FD_TO_PARENT, "w");
+  if (!parent_file)
+    {
+      fprintf (stderr, "%s: can't communicate with parent, exiting.\n",
+               progname);
+      exit (1);
+    }
+
+  gtk_init (&argc, &argv);
+
+  /* Intern the atoms that xscreensaver_command() needs.
+   */
+  {
+    Display *dpy = gdk_x11_get_default_xdisplay();
+
+    const struct atom_request unlock_atoms[] =
+      {
+	{ &XA_UNLOCK_RATIO, "UNLOCK_RATIO" },
+	{ NULL, NULL } /* Must be last to terminate list */
+      };
+
+    const struct atom_request *atom_lists[3] = { NULL, NULL, NULL };
+    atom_lists[0] = remote_control_atoms;
+    atom_lists[1] = unlock_atoms;
+    request_atoms (dpy, atom_lists);
+  }
+
+  /* bugid 6346056(P1):
+     ATOK pallet sometimes appears in screensave/lock-screen mode
+  */
+  putenv ("GTK_IM_MODULE=gtk-im-context-simple");
+
+
+  /* accessibility mode enabled ? */
+  client = gconf_client_get_default ();
+  at_enable = gconf_client_get_bool (client,
+                                     "/desktop/gnome/interface/accessibility",
+                                     NULL);
+  if (at_enable)
+    {
+
+      /* GTK Accessibility Module initialized */
+      modulesptr = g_getenv ("GTK_MODULES");
+      if (!modulesptr || modulesptr [0] == '\0')
+        putenv ("GTK_MODULES=gail:atk-bridge");
+
+      CORBA_exception_init (&ev);
+      if (!bonobo_init (&argc, argv))
+        {
+          g_error ("Can't initialize Bonobo");
+        }
+
+      /* bonobo-activation query lists existing instances */
+      server_list = bonobo_activation_query (
+        "(repo_ids.has('IDL:Accessibility/LoginHelper:1.0')) AND _active",
+        NULL, &ev);
+
+      if (BONOBO_EX (&ev))
+        {
+          bonobo_debug_shutdown ();
+          g_error ("LoginHelper query failed : %s",
+                   bonobo_exception_get_text (&ev));
+          /* not reached (below) because g_error exits */
+          CORBA_exception_free (&ev);
+        }
+
+      /*
+       * 6182506: unlock dialog can be obscured by the magnifier window
+       * if it's always centered, so don't force that if any accessibility
+       * helpers are present
+       */
+      if (server_list && server_list->_length)
+        center_position = FALSE;
+    } /* accessibility enabled */
+
+  pwd = make_dialog (center_position);
+  connect_signals (pwd);
+
+  gtk_widget_show_all (pwd->dialog);
+  gtk_window_present (GTK_WINDOW (pwd->dialog));
+  gtk_widget_map (pwd->dialog);
+
+  gdk_display_sync (gtk_widget_get_display (pwd->dialog));
+
+  gdk_window_add_filter (GET_WINDOW (pwd->dialog), dialog_filter_func, pwd);
+  write_windowid ("dialog_win", GDK_WINDOW_XID (GET_WINDOW (pwd->dialog)));
+
+  if (server_list && server_list->_length)
+    {
+      /* debug only
+      g_message ("%d LoginHelpers are running.",
+                 server_list ? server_list->_length : 0);
+      */
+
+      helper_list = g_new0 (Accessibility_LoginHelper, server_list->_length);
+
+      /* for each instance... */
+      for (i = 0; i < server_list->_length; i++)
+        {
+          Bonobo_Unknown server;
+          Bonobo_ServerInfo info = server_list->_buffer[i];
+
+          server = bonobo_activation_activate_from_id (
+              info.iid, Bonobo_ACTIVATION_FLAG_EXISTING_ONLY, NULL, &ev);
+
+          if (BONOBO_EX (&ev))
+            {
+              g_warning ("Error activating server %d: %s", i,
+                         bonobo_exception_get_text (&ev));
+              CORBA_exception_free (&ev);
+              continue;
+            }
+          else if (server == CORBA_OBJECT_NIL)
+            {
+              g_warning ("Activated server %d is NIL!", i);
+              continue;
+            }
+
+          bonobo_activate ();
+
+          helper = Bonobo_Unknown_queryInterface
+            (server, "IDL:Accessibility/LoginHelper:1.0", &ev);
+
+          if (BONOBO_EX (&ev))
+            {
+              g_warning ("Error performing interface query: %s",
+                         bonobo_exception_get_text (&ev));
+              CORBA_exception_free (&ev);
+              continue;
+            }
+          else if (helper == CORBA_OBJECT_NIL)
+            {
+              g_warning ("Activated an object which advertised LoginHelper but does not implement it!");
+              continue;
+            }
+
+          helper_list[i] = helper;
+          bonobo_object_release_unref (server, &ev);
+
+          if (helper && !BONOBO_EX (&ev))
+            {
+              /* ask the helper to go into safe mode */
+              safe = Accessibility_LoginHelper_setSafe (helper, TRUE, &ev);
+              if (BONOBO_EX (&ev))
+                {
+                  g_warning ("setSafe(TRUE) failed: %s",
+                             bonobo_exception_get_text (&ev));
+                  CORBA_exception_free (&ev);
+                }
+
+              /* get the raise window list (if the program went into safe mode) */
+              if (safe)
+                {
+                  int j;
+                  gboolean needs_windows_raised = FALSE;
+                  Accessibility_LoginHelper_DeviceReqList *list;
+
+                  g_debug ("safe");
+
+                  /* does this helper need to have windows raised? */
+                  list = Accessibility_LoginHelper_getDeviceReqs (helper, &ev);
+
+                  if (BONOBO_EX (&ev))
+                    {
+                      g_warning ("Bonobo exception getting Device Requirements: %s",
+                                 bonobo_exception_get_text (&ev));
+                      CORBA_exception_free (&ev);
+                    }
+                  else
+                    {
+                      g_debug ("LoginHelper device requirements: ");
+                      if (list->_length == 0)
+                        g_debug (" - None.");
+
+                      for (j = 0; j < list->_length; j++)
+                        {
+                          switch (list->_buffer[j])
+                            {
+                            case Accessibility_LoginHelper_GUI_EVENTS:
+                              g_debug (" - Needs access to the GUI event subsystem (e.g. Xserver)");
+                              break;
+                            case Accessibility_LoginHelper_CORE_KEYBOARD:
+                              g_debug (" - Needs access to core keyboard device");
+                              write_to_parent("ungrab_keyboard", "true", FALSE);
+                              break;
+                            case Accessibility_LoginHelper_CORE_POINTER:
+                              g_debug (" - Needs access to core pointer device");
+                              write_to_parent("ungrab_pointer", "true", FALSE);
+                              break;
+                            case Accessibility_LoginHelper_EXT_INPUT:
+                              g_debug (" - Reads XInput extended input devices");
+                              break;
+                            case Accessibility_LoginHelper_POST_WINDOWS:
+                              g_debug (" - Posts windows");
+                              needs_windows_raised = TRUE;
+                              break;
+                            case Accessibility_LoginHelper_AUDIO_OUT:
+                              g_debug (" - Writes to audio device");
+                              break;
+                            case Accessibility_LoginHelper_AUDIO_IN:
+                              g_debug (" - Reads from audio device");
+                              break;
+                            case Accessibility_LoginHelper_LOCALHOST:
+                              g_debug (" - Needs LOCALHOST network connection");
+                              break;
+                            case Accessibility_LoginHelper_SERIAL_OUT:
+                              g_debug (" - Needs to write to one or more serial ports");
+                              break;
+                            default:
+                              break;
+                            }
+                        }
+                      CORBA_free (list);
+                    }
+
+                  if (needs_windows_raised)
+                    {
+                      Accessibility_LoginHelper_WindowList *windows
+                        = Accessibility_LoginHelper_getRaiseWindows
+                        (helper, &ev);
+
+                      if (BONOBO_EX (&ev))
+                        {
+                          g_warning ("getRaiseWindows failed: %s",
+                                     bonobo_exception_get_text (&ev));
+                          CORBA_exception_free (&ev);
+                        }
+
+                      g_debug ("%d windows need raising", windows->_length);
+                      for (j = 0; j < windows->_length; j++)
+                        {
+                          Window wid = windows->_buffer[j].winID;
+                          g_debug ("Window ID = 0x%lx", wid);
+                          if (wid)
+                            write_windowid ("raise_win", wid);
+                        }
+                    }
+                }
+              else
+                {
+                  g_warning ("LoginHelper %d did not go into safe mode", i);
+                }
+            }
+           else
+            {
+              if (BONOBO_EX (&ev))
+                {
+                  g_warning ("Error activating %s: %s",
+                             info.iid, bonobo_exception_get_text (&ev));
+                  CORBA_exception_free (&ev);
+                }
+              else
+                {
+                  g_warning ("no active instance of %s found", info.iid);
+                }
+            }
+        }
+    } /* accessibility helpers active */
+
+  /* Flush dialog window ids & any messages about login helpers to parent */
+  write_to_parent(NULL, NULL, TRUE);
+
+  gtk_widget_grab_focus (pwd->user_input_entry);
+
+  ioc = g_io_channel_unix_new (0);
+  g_io_add_watch (ioc, G_IO_IN | G_IO_HUP, handle_input, pwd);
+
+  gtk_main ();
+
+  /* Reset accessibility helpers back to non-safe mode now that we're done */
+  if (server_list)
+    {
+      for (i = 0; i < server_list->_length; i++)
+        {
+          helper = helper_list[i];
+          /* really no need to check the return value this time */
+          Accessibility_LoginHelper_setSafe (helper, FALSE, &ev);
+          if (BONOBO_EX (&ev))
+            {
+              g_warning ("setSafe(FALSE) failed: %s",
+                         bonobo_exception_get_text (&ev));
+              CORBA_exception_free (&ev);
+            }
+          CORBA_Object_release (helper, &ev);
+        }
+      CORBA_free (server_list);
+      bonobo_debug_shutdown ();
+    }
+
+  return 0;
+}
+#endif /* HAVE_GTK2 */
+
diff --git xscreensaver-5.12/driver/lock.c xscreensaver-5.12/driver/lock.c
--- xscreensaver-5.12/driver/lock.c
+++ xscreensaver-5.12/driver/lock.c
@@ -21,8 +21,13 @@
 #include <X11/Intrinsic.h>
 #include <X11/cursorfont.h>
 #include <X11/Xos.h>		/* for time() */
+#include <X11/Xatom.h>
 #include <time.h>
 #include <sys/time.h>
+#include <errno.h>
+#include <gconf/gconf-client.h>
+#include "exec.h"
+#include "dialog-data.h"
 #include "xscreensaver.h"
 #include "resources.h"
 #include "mlstring.h"
@@ -83,114 +88,631 @@ vms_passwd_valid_p(char *pw, Bool verbose_p)
 
 typedef struct info_dialog_data info_dialog_data;
 
-struct passwd_dialog_data {
-
-  saver_screen_info *prompt_screen;
-  int previous_mouse_x, previous_mouse_y;
-
-  char typed_passwd [80];
-  XtIntervalId timer;
-  int i_beam;
-
-  float ratio;
-  Position x, y;
-  Dimension width;
-  Dimension height;
-  Dimension border_width;
-
-  Bool echo_input;
-  Bool show_stars_p; /* "I regret that I have but one asterisk for my country."
-                        -- Nathan Hale, 1776. */
-
-  char *heading_label;
-  char *body_label;
-  char *user_label;
-  mlstring *info_label;
-  /* The entry field shall only be displayed if prompt_label is not NULL */
-  mlstring *prompt_label;
-  char *date_label;
-  char *passwd_string;
-  Bool passwd_changed_p; /* Whether the user entry field needs redrawing */
-  Bool caps_p;		 /* Whether we saw a keypress with caps-lock on */
-  char *unlock_label;
-  char *login_label;
-  char *uname_label;
-
-  Bool show_uname_p;
-
-  XFontStruct *heading_font;
-  XFontStruct *body_font;
-  XFontStruct *label_font;
-  XFontStruct *passwd_font;
-  XFontStruct *date_font;
-  XFontStruct *button_font;
-  XFontStruct *uname_font;
-
-  Pixel foreground;
-  Pixel background;
-  Pixel passwd_foreground;
-  Pixel passwd_background;
-  Pixel thermo_foreground;
-  Pixel thermo_background;
-  Pixel shadow_top;
-  Pixel shadow_bottom;
-  Pixel button_foreground;
-  Pixel button_background;
-
-  Dimension preferred_logo_width, logo_width;
-  Dimension preferred_logo_height, logo_height;
-  Dimension thermo_width;
-  Dimension internal_border;
-  Dimension shadow_width;
-
-  Dimension passwd_field_x, passwd_field_y;
-  Dimension passwd_field_width, passwd_field_height;
-
-  Dimension unlock_button_x, unlock_button_y;
-  Dimension unlock_button_width, unlock_button_height;
-
-  Dimension login_button_x, login_button_y;
-  Dimension login_button_width, login_button_height;
-
-  Dimension thermo_field_x, thermo_field_y;
-  Dimension thermo_field_height;
-
-  Pixmap logo_pixmap;
-  Pixmap logo_clipmask;
-  int logo_npixels;
-  unsigned long *logo_pixels;
-
-  Cursor passwd_cursor;
-  Bool unlock_button_down_p;
-  Bool login_button_down_p;
-  Bool login_button_p;
-  Bool login_button_enabled_p;
-  Bool button_state_changed_p; /* Refers to both buttons */
-
-  Pixmap save_under;
-  Pixmap user_entry_pixmap;
-};
+/* struct passwd_dialog_data moved to dialog-data.h */
 
+#ifndef HAVE_XSCREENSAVER_LOCK
 static void draw_passwd_window (saver_info *si);
+#endif
 static void update_passwd_window (saver_info *si, const char *printed_passwd,
 				  float ratio);
 static void destroy_passwd_window (saver_info *si);
+static int ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error);
 static void undo_vp_motion (saver_info *si);
+#ifndef HAVE_XSCREENSAVER_LOCK
 static void finished_typing_passwd (saver_info *si, passwd_dialog_data *pw);
+#endif
 static void cleanup_passwd_window (saver_info *si);
 static void restore_background (saver_info *si);
 
 extern void xss_authenticate(saver_info *si, Bool verbose_p);
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+
+#define WIN_ALLOC_INCREMENT 8	/* allocate entries in the window lists in
+                                   increments of 8 at a time for fewer
+                                   reallocs and less chance of malloc error
+                                   at the wrong time */
+#define EXTRA_RAISE_WIN_SLOTS 4 /* Need to leave four extra slots free in
+                                   raise_wins to allow calling XRestackWindows
+                                   when a window pops up without having to
+                                   realloc or copy to a new list.
+                                   These slots would be used by:
+                                   - passwd_dialog
+                                   - stderr_overlay_window
+                                   - xscreensaver virtual root
+                                   - an interloper popup we need to hide
+                                */
+
+extern Atom XA_UNLOCK_RATIO;
+
+Bool g_passwd_dialog_created = 0;
+
+GConfClient *client = NULL;
+
+static const char *switch_windows_gconf_key
+  = "/apps/metacity/global_keybindings/switch_windows";
+static char  *global_switch_key = NULL;
+
+static const char *main_menu_gconf_key
+  = "/apps/metacity/global_keybindings/panel_main_menu";
+static char  *global_menu_key = NULL;
+
+extern Bool safe_XDestroyWindow (Display *dpy, Window window);
+static Bool safe_XRestackWindows(Display *dpy, Window windows[], int nwindows);
+static Bool safe_XSendEvent(Display *dpy, Window w, Bool propagate,
+                            long event_mask, XEvent *event_send);
+static void passwd_animate_timer (XtPointer closure, XtIntervalId *id);
+extern void swallow_unlock_typeahead_events (saver_info *si, XEvent *e);
+
+
+static saver_screen_info *
+find_screen_for_window (saver_info *si, Window wid)
+{
+  saver_screen_info *ssi;
+  Screen *screen;
+  Window root, root_ret, parent_ret, *children = NULL;
+  unsigned int nchildren = 0;
+  int screen_no, status;
+
+  status = XQueryTree (si->dpy, wid, &root_ret, &parent_ret,
+                       &children, &nchildren);
+
+  if (status == 0) /* failed */
+    return NULL;
+
+  XFree(children);
+  children = NULL;
+
+  for (screen_no = 0; screen_no < si->nscreens; screen_no++)
+    {
+      ssi = &si->screens[screen_no];
+      screen = ssi->screen;
+      root   = RootWindowOfScreen (screen);
+
+      if (root == root_ret)
+        return ssi;
+    }
+
+  return NULL; /* Didn't match the root on any screen  we know of - PUNT! */
+}
+
+/*
+ 5083155 Unable to unlock screen when running dual-head MAG
+ adding dual or multiple heads for magnifier support
+
+ screen 0: loginhelp can pass the raisedWid of GOK or MAG or both
+           found: return its parent Wid (child of root)
+           not found:  0
+
+ other screen:        MAG only if the target screen no > 0 is selected
+           found:  restack on that screen
+               return 0
+           not-found : return 0
+
+ */
+
+static Window
+check_raisedWid (saver_info *si, Window wid)
+{
+  saver_screen_info *ssi;
+  Screen *screen;
+  Window root, root_ret, parent_ret, *children = NULL;
+  unsigned int nchildren = 0;
+  int screen_no, status;
+
+  status = XQueryTree (si->dpy, wid, &root_ret, &parent_ret,
+                       &children, &nchildren);
+
+  if (status == 0) /* failed */
+    return 0;
+
+  XFree(children);
+  children = NULL;
+
+  for (screen_no = 0; screen_no < si->nscreens; screen_no++)
+    {
+      ssi = &si->screens[screen_no];
+      screen = ssi->screen;
+      root   = RootWindowOfScreen (screen);
+
+      if (root == root_ret)
+        break;
+    }
+
+  if ( screen_no >= si->nscreens ) /* Didn't match the root on any screen */
+    return 0;                      /*  we know of - PUNT!                 */
+
+  /* Climb the tree until we find an ancestor that's a child of root */
+  while ( root_ret != parent_ret )
+    {
+      wid = parent_ret;
+
+      status = XQueryTree (si->dpy, wid, &root_ret, &parent_ret,
+                           &children, &nchildren);
+
+      if (status == 0) /* failed */
+        return 0;
+
+      XFree(children);
+      children = NULL;
+    }
+
+  if ( ssi != si->pw_data->prompt_screen )
+    {
+      /* found in other screen (not the one with the unlock dialog),
+         implies MAG target screen, invoke XRestackWindow() there
+      */
+      Window screen_win[2] = { wid, ssi->screensaver_window };
+      safe_XRestackWindows(si->dpy, screen_win, 2);
+      return 0;   /* no need to do the restack on prompt screen */
+    }
+
+  return wid;
+}
+
+/* Enforce window stacking order when a new window arrives.
+   Only allow raising windows the unlock dialog has told us to raise
+   (including itself).
+ */
+static void
+restack_my_windows (saver_info* si, saver_screen_info *ssi, Window newWin)
+{
+  int n = 0;
+  Window short_stack[EXTRA_RAISE_WIN_SLOTS];
+  Window *restack_list;
+  Bool allowed = False;
+
+  /* If window is on another screen than the unlock dialog,
+     or we have list of no windows to raise */
+  if ((si->raise_wins == NULL) || (ssi != si->pw_data->prompt_screen))
+    {
+      restack_list = short_stack;
+    }
+  else
+    {
+      restack_list = si->raise_wins;
+      for (n = 0; n < si->num_raise_wins; n++)
+        {
+          if (si->raise_wins[n] == newWin)
+            allowed = True;
+        }
+    }
+
+  if (si->passwd_dialog && (ssi == si->pw_data->prompt_screen))
+    {
+      restack_list[n++] = si->passwd_dialog;
+      if (si->passwd_dialog == newWin)
+        allowed = True;
+    }
+
+  if (ssi->stderr_overlay_window)
+    {
+      restack_list[n++] = ssi->stderr_overlay_window;
+      if (ssi->stderr_overlay_window == newWin)
+        allowed = True;
+    }
+
+  if (ssi->screensaver_window)
+    {
+      restack_list[n++] = ssi->screensaver_window;
+      if (ssi->screensaver_window == newWin)
+        allowed = True;
+    }
+
+  /* If it's not in the allowed list, it goes behind
+     the screensaver_window. */
+  if (newWin && !allowed)
+    restack_list[n++] = newWin;
+
+  if (n > 1)
+    safe_XRestackWindows (si->dpy, restack_list, n);
+}
+
+/* Send a command to the xscreensaver-lock child process
+   Arguments:
+    - msg - message to send, such as ul_ok
+    - data - additional data, such as string to display for this message,
+             if any, otherwise NULL
+   Message format sent to child:
+    "msg\n" if no data, otherwise "msg=data\n"
+ */
+int
+write_to_child (saver_info* si, const char* msg, const char *data)
+{
+  if (msg == NULL)
+    {
+      fprintf (stderr, "Invalid null message written to child\n");
+      return -1;
+    }
+
+  if (si->external_passwd && g_passwd_dialog_created &&
+      si->pw_data->stdin_fd != -1)
+    {
+      int len;
+
+      if (si->prefs.verbose_p)
+        {
+          fprintf (stderr,
+                   "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n"
+                   "HAVE_SCRSVR_LOCK writing to fd:%d message is:\n%s=%s\n"
+                   "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n",
+                   si->pw_data->stdin_fd, msg, data ? data : "(null)");
+        }
+
+      if (data)
+        len = fprintf (si->pw_data->stdin_file, "%s=%s\n", msg, data);
+      else
+        len = fprintf (si->pw_data->stdin_file, "%s\n", msg);
+
+      fflush (si->pw_data->stdin_file);
+      return len;
+    }
+
+  return (0); /* if we didn't write anything return 0 */
+}
+
+static int
+sane_dup2 (int fd1, int fd2)
+{
+  int ret;
+
+  do
+    {
+      ret = dup2 (fd1, fd2);
+    }
+  while (ret < 0 && errno == EINTR);
+
+  return ret;
+}
+
+static int
+close_and_invalidate (int *fd)
+{
+  int ret;
+
+  ret = close (*fd);
+  *fd = -1;
+
+  return ret;
+}
+
+void
+handle_passwd_input (XtPointer xtdata, int *fd, XtInputId *id)
+{
+  saver_info *si = (saver_info *)xtdata;
+  saver_preferences *p = &si->prefs;
+  char buffer[1024];
+  char *msg, *data;
+  passwd_dialog_data *pw = si->pw_data;
+
+  if (p->verbose_p)
+    fprintf (stderr, "passwd input handler() fd=%d\n", *fd);
+
+  msg = fgets (buffer, sizeof (buffer), pw->stdout_file);
+  if (!msg)  /* child closed pipe */
+    {
+      if (p->verbose_p)
+        {
+          fprintf (stderr, "done reading...\n");
+          fprintf (stderr, "removing input handler...\n");
+        }
+      XtRemoveInput (*id);
+      pw->stdout_input_id = 0;
+
+      if (p->verbose_p)
+        fprintf (stderr, "passwd input handler() returning...done reading\n");
+
+      return;
+    }
+
+  if (p->verbose_p)
+    fprintf (stderr, "Child sent message: %s\n", msg);
+
+  /* search for =, and if found, split msg & data into two strings there */
+  data = strchr(msg, '=');
+  if (data)
+    {
+      char *nl;
+
+      *data++ = 0;
+
+      /* strip trailing newline */
+      nl = strchr (data, '\n');
+      if (nl)
+        *nl = '\0';
+    }
+  else
+    {
+      /* All the messages we currently expect require data! */
+      if (p->verbose_p)
+        fprintf (stderr, "*** Invalid message: no data found, discarding\n");
+
+      return;
+    }
+
+  if ((strcmp(msg, "input") == 0)) /* User input */
+    {
+      si->unlock_state = ul_finished;
+      pw->got_passwd = TRUE;
+      pw->passwd_string = strdup (data);
+      memset (data, 0, strlen(data));
+    }
+  else if ((strcmp(msg, "ungrab_keyboard") == 0))
+    {
+      /* An accessibility helper needs to access the keyboard, so we have
+         to release our grab - unfortunately this risks other apps acting
+         on keys they shouldn't, so first we disable metacity keys that
+         could allow getting back to the locked session windows, and hope
+         we don't crash or die before restoring them later.
+
+         Other window managers are likely to be risky to use in this case.
+      */
+
+      if (client == NULL)
+        client = gconf_client_get_default();
+
+      if (global_switch_key == NULL)
+        {
+          global_switch_key =
+            gconf_client_get_string (client, switch_windows_gconf_key, NULL);
+
+          if (global_switch_key && strncmp (global_switch_key, "dis", 3))
+            gconf_client_set_string (client, switch_windows_gconf_key,
+                                     "disabled", NULL);
+        }
+
+      if (global_menu_key == NULL)
+        {
+          global_menu_key =
+            gconf_client_get_string (client, main_menu_gconf_key, NULL);
+
+          if (global_menu_key && strncmp(global_menu_key, "dis", 3))
+            gconf_client_set_string (client, main_menu_gconf_key,
+                                     "disabled", NULL);
+        }
+
+      XUngrabKeyboard (si->dpy, CurrentTime);
+      XFlush (si->dpy);
+    }
+  else if ((strcmp(msg, "ungrab_pointer") == 0))
+    {
+      /* An accessibility helper needs to access the mouse, so we have
+         to release our grab - this is simpler, since we don't worry about
+         mouse gestures that may get through, though maybe we should...
+      */
+
+      XUngrabPointer (si->dpy, CurrentTime);
+      XFlush (si->dpy);
+    }
+  else /* Get a window id of an interesting window from the child */
+    {
+      Window window = strtoul (data, NULL, 0);
+      int status;
+
+      if ((strcmp (msg, "dialog_win") == 0))
+        {
+          /* The unlock dialog itself */
+          si->passwd_dialog = window;
+          pw->got_windowid = True;
+
+          move_mouse_grab (si, si->passwd_dialog, pw->passwd_cursor,
+                           pw->prompt_screen->number);
+          undo_vp_motion (si);
+          passwd_animate_timer ((XtPointer) si, 0);
+
+          /* Flush queue of captured typeahead events */
+          if (si->typeahead_events && si->num_typeahead_events)
+            {
+              int i;
+
+              for (i = 0; i < si->num_typeahead_events; i++)
+                {
+                  si->typeahead_events[i].window = window;
+                  safe_XSendEvent (si->dpy, window, False, KeyPressMask,
+                                   (XEvent *) &si->typeahead_events[i]);
+                }
+              si->num_typeahead_events = 0;
+            }
+          XGrabKeyboard (si->dpy, window, True, GrabModeAsync, GrabModeAsync, CurrentTime);
+          XGrabPointer (si->dpy, window, True, 0, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
+          XFlush (si->dpy);
+          XSetInputFocus (si->dpy, window, RevertToPointerRoot, CurrentTime);
+          XSync (si->dpy, False);
+        }
+      else if ((strcmp (msg, "raise_win") == 0))
+        {
+          /* Accessibility helpers that need to be raised above the
+             full-screen blanking window hiding the user's desktop */
+          Window *newlist;
+          Window overwin;
+
+          if ( (si->num_raise_wins + EXTRA_RAISE_WIN_SLOTS)
+               >= si->max_raise_wins)
+            {
+              int raise_alloc = si->max_raise_wins + WIN_ALLOC_INCREMENT;
+
+              newlist = realloc(si->raise_wins, raise_alloc * sizeof(Window));
+              if (newlist == NULL)
+                return;
+
+              si->raise_wins = newlist;
+              si->max_raise_wins = raise_alloc;
+            }
+
+          overwin = check_raisedWid (si, window);
+          if (overwin)
+            {
+              XWindowAttributes attrs;
+              status = XGetWindowAttributes (si->dpy, overwin, &attrs);
+
+              if ( status && !attrs.override_redirect )
+                {
+                  unsigned long valuemask = CWOverrideRedirect;
+                  XSetWindowAttributes setwinattr;
+                  setwinattr.override_redirect = True;
+
+                  XChangeWindowAttributes (si->dpy, overwin,
+                                           valuemask, &setwinattr);
+
+                  if (si->num_override_wins >= si->max_override_wins)
+                    {
+                      int over_alloc
+                        = si->max_override_wins + WIN_ALLOC_INCREMENT;
+
+                      newlist = realloc(si->override_wins,
+                                        over_alloc * sizeof(Window));
+                      if (newlist == NULL)
+                        return;
+
+                      si->override_wins = newlist;
+                      si->max_override_wins = over_alloc;
+                    }
+
+                  si->override_wins[si->num_override_wins++] = overwin;
+                }
+              XMapSubwindows(si->dpy, overwin);
+              si->raise_wins[si->num_raise_wins++] = overwin;
+            }
+          else
+            si->raise_wins[si->num_raise_wins++] = window;
+        } /* "raise_win" */
+
+      restack_my_windows(si, si->pw_data->prompt_screen, 0);
+    }
+}
+
+/* returns successful fork/exec */
+Bool
+spawn_external_passwd_process (saver_info *si, passwd_dialog_data *pw)
+{
+  saver_preferences *p = &si->prefs;
+  pid_t forked;
+  const char *command = LOCKDIR "/xscreensaver-lock";
+  int stdin_pipe[2]  = { -1, -1 };
+  int stdout_pipe[2] = { -1, -1 };
+
+  si->passwd_pid = 0;
+  pw->stdin_fd = pw->stdout_fd = -1;
+  pw->got_windowid = False;
+
+  if (si->prefs.verbose_p)
+     fprintf(stderr, "-->spawn_external_passwd()\n");
+
+  if (si->passwd_pid > 0)
+    {
+      if (si->prefs.verbose_p)
+        fprintf (stderr,"pid %ld still exists.  Killing it with SIGKILL\n",
+                 si->passwd_pid);
+      kill_job (si, si->passwd_pid, SIGKILL);
+    }
+  si->passwd_pid = 0;
+
+  if (pipe (stdin_pipe) < 0)
+    {
+      perror ("pipe(stdin_pipe) failed!");
+      return False;
+    }
+
+  if (pipe (stdout_pipe) < 0)
+    {
+      perror ("pipe(stdout_pipe) failed!");
+      close_and_invalidate (&stdin_pipe[0]);
+      close_and_invalidate (&stdin_pipe[1]);
+      return False;
+    }
+  switch ((int) (forked = fork ()))
+    {
+    case -1:
+      fprintf (stderr, "%s: ", blurb ());
+      perror ("couldn't fork");
+
+      close_and_invalidate (&stdin_pipe[0]);
+      close_and_invalidate (&stdin_pipe[1]);
+      close_and_invalidate (&stdout_pipe[0]);
+      close_and_invalidate (&stdout_pipe[1]);
+
+      return False;
+
+    case 0:
+      close (ConnectionNumber (si->dpy)); /* close display fd */
+      /* limit_subproc_memory (p->inferior_memory_limit, p->verbose_p); */
+      /* hack_subproc_environment (ssi); */ /* FIX $DISPLAY */
+
+      /* Inside Child Process */
+      if (p->verbose_p)
+        fprintf (stderr, "%s: spawning \"%s\" in pid %lu.\n",
+                 blurb(), command, (unsigned long) getpid ());
+
+      close_and_invalidate (&stdin_pipe[1]);
+      close_and_invalidate (&stdout_pipe[0]);
+
+      sane_dup2 (stdin_pipe[0], 0);  /* Listen to Parent from here */
+      sane_dup2 (stdout_pipe[1], 9); /* Talk to Parent from here */
+
+      /* Make sure we have relinquished setuid privs or lock dialog gtk
+       * program will not run as libgtk is not setuid safe.
+       */
+      hack_uid (si);
+
+      exec_command (p->shell, command, 0);
+      /* print_path_error (command); */
+      fprintf (stderr, "%s: couldn't exec: %s\n",
+               blurb (), command);
+      abort ();
+
+    default:
+      /* In Parent */
+      make_job(forked, 0, command);
+      close_and_invalidate (&stdin_pipe[0]);
+      close_and_invalidate (&stdout_pipe[1]);
+
+      sane_dup2 (stdin_pipe[0], 0);  /* Listen to Child from here */
+      sane_dup2 (stdout_pipe[1], 13); /* Talk to Child from here */
+
+      pw->stdin_fd   = stdin_pipe[1];   /* Talk to child from here */
+      pw->stdout_fd  = stdout_pipe[0];  /* Listen to Child from here */
+      si->passwd_pid = forked;
+
+      /* Messages to child dialog are sent through this pipe/fd */
+      pw->stdin_file = fdopen (pw->stdin_fd, "w");
+      write_to_child (si, "Hello", NULL); /* Send a test message to Child */
+
+      /* Password from child dialog comes through this pipe/fd */
+      pw->stdout_file = fdopen (pw->stdout_fd, "r");
+
+      pw->stdout_input_id = XtAppAddInput (si->app, pw->stdout_fd,
+                                           (XtPointer) XtInputReadMask,
+                                           handle_passwd_input, si);
+
+      /* Set global flag to indicate that lock dialog is visible */
+      g_passwd_dialog_created = True;
+      return True;
+    }
+
+  /* shouldn't reach */
+  abort ();
+  return False;
+}
+#endif /* HAVE_XSCREENSAVER_LOCK */
+
 static int
 new_passwd_window (saver_info *si)
 {
   passwd_dialog_data *pw;
+#ifndef HAVE_XSCREENSAVER_LOCK
   Screen *screen;
   Colormap cmap;
   char *f;
+#endif
   saver_screen_info *ssi = &si->screens [mouse_screen (si)];
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+  /* si->pw_data is globally allocated and never freed when HAVE_XSS_LOCK */
+  pw = si->pw_data;
+  if (!spawn_external_passwd_process (si, pw))
+    return -1;
+  si->external_passwd = True;
+#else
   pw = (passwd_dialog_data *) calloc (1, sizeof(*pw));
   if (!pw)
     return -1;
@@ -199,17 +716,21 @@ new_passwd_window (saver_info *si)
    */
   pw->login_button_p = (si->prefs.new_login_command &&
                         *si->prefs.new_login_command);
+#endif
 
   pw->passwd_cursor = XCreateFontCursor (si->dpy, XC_top_left_arrow);
 
   pw->prompt_screen = ssi;
 
+#ifndef HAVE_XSCREENSAVER_LOCK
   screen = pw->prompt_screen->screen;
   cmap = DefaultColormapOfScreen (screen);
+#endif
 
   pw->show_stars_p = get_boolean_resource(si->dpy, "passwd.asterisks", 
 					  "Boolean");
   
+#ifndef HAVE_XSCREENSAVER_LOCK
   pw->heading_label = get_string_resource (si->dpy, "passwd.heading.label",
 					   "Dialog.Label.Label");
   pw->body_label = get_string_resource (si->dpy, "passwd.body.label",
@@ -358,6 +879,7 @@ new_passwd_window (saver_info *si)
   if (pw->shadow_width == 0) pw->shadow_width = 4;
   if (pw->thermo_width == 0) pw->thermo_width = pw->shadow_width;
 
+#endif /* ! HAVE_XSCREENSAVER_LOCK */
 
   /* We need to remember the mouse position and restore it afterward, or
      sometimes (perhaps only with Xinerama?) the mouse gets warped to
@@ -422,12 +944,16 @@ make_passwd_window (saver_info *si,
 		    const char *prompt,
 		    Bool echo)
 {
+#ifndef HAVE_XSCREENSAVER_LOCK
   XSetWindowAttributes attrs;
   unsigned long attrmask = 0;
+#endif
   passwd_dialog_data *pw;
+#ifndef HAVE_XSCREENSAVER_LOCK
   Screen *screen;
   Colormap cmap;
   Dimension max_string_width_px;
+#endif
   saver_screen_info *ssi = &si->screens [mouse_screen (si)];
 
   cleanup_passwd_window (si);
@@ -435,7 +961,12 @@ make_passwd_window (saver_info *si,
   if (! ssi)   /* WTF?  Trying to prompt while no screens connected? */
     return -1;
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+  /* si->pw_data is globally allocated and never freed when HAVE_XSS_LOCK */
+  if (!si->pw_data->got_windowid)
+#else
   if (!si->pw_data)
+#endif
     if (new_passwd_window (si) < 0)
       return -1;
 
@@ -450,6 +981,29 @@ make_passwd_window (saver_info *si,
              blurb(), pw->prompt_screen->number,
              info_msg ? info_msg : "");
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+  /* Wipe the old password, so we get prompted to enter new password. */
+  if (pw->passwd_string)
+    {
+      memset(pw->passwd_string, 0, strlen (pw->passwd_string));
+      free (pw->passwd_string);
+      pw->passwd_string = NULL;
+    }
+
+  if (info_msg)
+    write_to_child (si, "ul_message", info_msg);
+  if (prompt)
+    {
+      write_to_child (si, "ul_pamprompt", prompt);
+
+      if (echo)
+        write_to_child (si, "ul_prompt_echo", "true");
+      else if (pw->show_stars_p)
+        write_to_child (si, "ul_prompt_echo", "stars");
+      else
+        write_to_child (si, "ul_prompt_echo", "false");
+    }
+#else
   screen = pw->prompt_screen->screen;
   cmap = DefaultColormapOfScreen (screen);
 
@@ -687,11 +1241,13 @@ make_passwd_window (saver_info *si,
   if (cmap)
     XInstallColormap (si->dpy, cmap);
   draw_passwd_window (si);
+#endif /* ! HAVE_XSCREENSAVER_LOCK */
 
   return 0;
 }
 
 
+#ifndef HAVE_XSCREENSAVER_LOCK
 static void
 draw_passwd_window (saver_info *si)
 {
@@ -1035,17 +1591,48 @@ draw_button(Display *dpy,
   draw_shaded_rectangle(dpy, dialog, x, y, width, height,
 			shadow_width, shadow_light, shadow_dark);
 }
+#endif /* !HAVE_XSCREENSAVER_LOCK */
 
 static void
 update_passwd_window (saver_info *si, const char *printed_passwd, float ratio)
 {
   passwd_dialog_data *pw = si->pw_data;
+#ifndef HAVE_XSCREENSAVER_LOCK
   XGCValues gcv;
   GC gc1, gc2;
   int x, y;
   XRectangle rects[1];
+#endif
 
   pw->ratio = ratio;
+
+#ifdef HAVE_XSCREENSAVER_LOCK
+  /* Send countdown timer ratio to child lock dialog */
+  if (si->passwd_dialog)
+    {
+      XEvent event;
+
+      event.xany.type = ClientMessage;
+      event.xclient.display = si->dpy;
+      event.xclient.window = si->passwd_dialog;
+      event.xclient.message_type = XA_UNLOCK_RATIO;
+      event.xclient.format = 32;
+      memset (&event.xclient.data, 0, sizeof (event.xclient.data));
+      event.xclient.data.l[0] = (long)(pw->ratio * 100);
+      event.xclient.data.l[1] = 0;
+      event.xclient.data.l[2] = 0;
+
+      if (!safe_XSendEvent (si->dpy, si->passwd_dialog, False, 0L, &event))
+        fprintf (stderr, "%s: error sending ratio to lock dialog\n", blurb ());
+    }
+  else
+    {
+      if (si->prefs.verbose_p)
+        fprintf (stderr,
+          "-->update_passwd_window() lockdialog not created, returning!!\n");
+      return;
+    }
+#else
   gcv.foreground = pw->passwd_foreground;
   gcv.font = pw->passwd_font->fid;
   gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground|GCFont, &gcv);
@@ -1187,6 +1774,7 @@ update_passwd_window (saver_info *si, const char *printed_passwd, float ratio)
   XFreeGC (si->dpy, gc1);
   XFreeGC (si->dpy, gc2);
   XSync (si->dpy, False);
+#endif /* !HAVE_XSCREENSAVER_LOCK */
 }
 
 
@@ -1218,6 +1806,9 @@ cleanup_passwd_window (saver_info *si)
 {
   passwd_dialog_data *pw;
 
+  if (si->prefs.verbose_p)
+    fprintf (stderr, "cleanup_passwd_window\n");
+
   if (!(pw = si->pw_data))
     return;
 
@@ -1234,7 +1825,12 @@ cleanup_passwd_window (saver_info *si)
     }
 
   memset (pw->typed_passwd, 0, sizeof(pw->typed_passwd));
-  memset (pw->passwd_string, 0, strlen(pw->passwd_string));
+  if (pw->passwd_string)
+    {
+      memset (pw->passwd_string, 0, strlen(pw->passwd_string));
+      free (pw->passwd_string);
+      pw->passwd_string = NULL;
+    }
 
   if (pw->timer)
     {
@@ -1257,8 +1853,10 @@ destroy_passwd_window (saver_info *si)
   passwd_dialog_data *pw = si->pw_data;
   saver_screen_info *ssi = pw->prompt_screen;
   Colormap cmap = DefaultColormapOfScreen (ssi->screen);
+#ifndef HAVE_XSCREENSAVER_LOCK
   Pixel black = BlackPixelOfScreen (ssi->screen);
   Pixel white = WhitePixelOfScreen (ssi->screen);
+#endif
   XEvent event;
 
   cleanup_passwd_window (si);
@@ -1274,6 +1872,81 @@ destroy_passwd_window (saver_info *si)
       si->cached_passwd = NULL;
     }
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+  /* reset global flag to indicate passwd dialog is no longer there */
+  g_passwd_dialog_created = False;
+
+  if (si->external_passwd)
+    {
+      /* kill the child etc. */
+      write_to_child (si, "cmd_exit", NULL);
+
+      if (pw->stdin_file)
+        fclose (pw->stdin_file);
+      if (pw->stdin_fd != -1)
+        close_and_invalidate (&pw->stdin_fd);
+      if (pw->stdout_input_id)
+        XtRemoveInput (pw->stdout_input_id);
+      if (pw->stdout_file)
+        fclose (pw->stdout_file);
+      else if (pw->stdout_fd != -1)
+        close_and_invalidate (&pw->stdout_fd);
+
+      if (si->passwd_pid)
+        {
+          kill_job (si, si->passwd_pid, SIGTERM);
+          si->passwd_pid = 0;
+        }
+
+      free (si->raise_wins);
+      si->raise_wins = NULL;
+      si->num_raise_wins = 0;
+      si->max_raise_wins = 0;
+
+      if (si->override_wins)
+        {
+          int n;
+
+          unsigned long valuemask = CWOverrideRedirect;
+          XSetWindowAttributes setwinattr;
+          setwinattr.override_redirect = False;
+
+          for (n = 0; n < si->num_override_wins; n++)
+            {
+              XChangeWindowAttributes (si->dpy, si->override_wins[n],
+                                       valuemask, &setwinattr);
+            }
+          free(si->override_wins);
+          si->override_wins = NULL;
+        }
+      si->num_override_wins = 0;
+      si->max_override_wins = 0;
+
+      si->pw_data->got_windowid = False;
+      si->external_passwd = False;
+
+      /* restore any metacity keys we temporarily disabled */
+      if (client)
+        {
+          if (global_switch_key)
+            {
+              gconf_client_set_string (client, switch_windows_gconf_key,
+                                       global_switch_key, NULL);
+              g_free(global_switch_key);
+              global_switch_key = NULL;
+            }
+
+          if (global_menu_key)
+            {
+              gconf_client_set_string (client, main_menu_gconf_key,
+                                       global_menu_key, NULL);
+              g_free(global_menu_key);
+              global_menu_key = NULL;
+            }
+        }
+    }
+#endif /* HAVE_XSCREENSAVER_LOCK */
+
   move_mouse_grab (si, RootWindowOfScreen (ssi->screen),
                    ssi->cursor, ssi->number);
 
@@ -1308,7 +1981,14 @@ destroy_passwd_window (saver_info *si)
         fprintf (stderr, "%s: %d: destroying password dialog.\n",
                  blurb(), pw->prompt_screen->number);
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+      /* Ignore X error if window was already closed by the child,
+         and make sure any VisibilityNotify events are removed
+         from the event queue before we forget the window id. */
+      safe_XDestroyWindow (si->dpy, si->passwd_dialog);
+#else
       XDestroyWindow (si->dpy, si->passwd_dialog);
+#endif
       si->passwd_dialog = 0;
     }
   
@@ -1319,6 +1999,7 @@ destroy_passwd_window (saver_info *si)
       pw->save_under = 0;
     }
 
+#ifndef HAVE_XSCREENSAVER_LOCK
   if (pw->heading_label) free (pw->heading_label);
   if (pw->body_label)    free (pw->body_label);
   if (pw->user_label)    free (pw->user_label);
@@ -1369,6 +2050,7 @@ destroy_passwd_window (saver_info *si)
       pw->logo_pixels = 0;
       pw->logo_npixels = 0;
     }
+#endif /* ! HAVE_XSCREENSAVER_LOCK */
 
   if (pw->save_under)
     XFreePixmap (si->dpy, pw->save_under);
@@ -1376,9 +2058,12 @@ destroy_passwd_window (saver_info *si)
   if (cmap)
     XInstallColormap (si->dpy, cmap);
 
+#ifndef HAVE_XSCREENSAVER_LOCK
+  /* si->pw_data is globally allocated and never freed when HAVE_XSS_LOCK */
   memset (pw, 0, sizeof(*pw));
   free (pw);
   si->pw_data = 0;
+#endif
 }
 
 
@@ -1391,6 +2076,49 @@ ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
   return 0;
 }
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+/* Catch errors from XRestackWindows, since there's an inherent race
+   condition in which other clients can destroy windows between when
+   we get the notification event and when we send the RestackWindows
+   response to it. */
+static Bool
+safe_XRestackWindows(Display *dpy, Window windows[], int nwindows)
+{
+  XErrorHandler old_handler;
+  XSync (dpy, False);
+  error_handler_hit_p = False;
+  old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
+
+  XRestackWindows (dpy, windows, nwindows);
+
+  XSync (dpy, False);
+  XSetErrorHandler (old_handler);
+  XSync (dpy, False);
+
+  return (!error_handler_hit_p);
+}
+
+static Bool
+safe_XSendEvent(Display *dpy, Window w, Bool propagate,
+                long event_mask, XEvent *event_send)
+{
+  Status status;
+  XErrorHandler old_handler;
+  XSync (dpy, False);
+  error_handler_hit_p = False;
+  old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
+
+  status = XSendEvent (dpy, w, propagate, event_mask, event_send);
+
+  XSync (dpy, False);
+  XSetErrorHandler (old_handler);
+  XSync (dpy, False);
+
+  return (!error_handler_hit_p && status);
+}
+
+#endif
+
 
 #ifdef HAVE_XHPDISABLERESET
 /* This function enables and disables the C-Sh-Reset hot-key, which
@@ -1592,6 +2320,17 @@ passwd_animate_timer (XtPointer closure, XtIntervalId *id)
 
   if (!pw) return;
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+  /* We want to make sure dialog is up before we update countdown timer */
+  if (!si->passwd_dialog)
+    {
+      if (si->prefs.verbose_p)
+        fprintf (stderr,
+                 "-->passwd_animate_timer() returning..no dialog yet\n");
+      return;
+    }
+#endif
+
   pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick));
   if (pw->ratio < 0)
     {
@@ -1611,6 +2350,7 @@ passwd_animate_timer (XtPointer closure, XtIntervalId *id)
   idle_timer ((XtPointer) si, 0);
 }
 
+#ifndef HAVE_XSCREENSAVER_LOCK
 
 static XComposeStatus *compose_status;
 
@@ -1688,11 +2428,13 @@ finished_typing_passwd (saver_info *si, passwd_dialog_data *pw)
       update_passwd_window (si, "", pw->ratio);
     }
 }
+#endif /* !HAVE_XSCREENSAVER_LOCK */
 
 static void
 handle_passwd_key (saver_info *si, XKeyEvent *event)
 {
   passwd_dialog_data *pw = si->pw_data;
+#ifndef HAVE_XSCREENSAVER_LOCK
   int pw_size = sizeof (pw->typed_passwd) - 1;
   char *typed_passwd = pw->typed_passwd;
   char s[2];
@@ -1705,11 +2447,41 @@ handle_passwd_key (saver_info *si, XKeyEvent *event)
   s[1] = 0;
 
   pw->passwd_changed_p = True;
+#endif /* !HAVE_XSCREENSAVER_LOCK */
 
   /* Add 10% to the time remaining every time a key is pressed. */
   pw->ratio += 0.1;
   if (pw->ratio > 1) pw->ratio = 1;
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+  if (si->pw_data->got_windowid)
+    {
+      Bool status;
+
+      if (si->prefs.verbose_p)
+        fprintf (stderr, "event loop..gotwindowid..and keypress event...\n");
+
+      event->window = si->passwd_dialog;
+
+      status = safe_XSendEvent (si->dpy, si->passwd_dialog,
+                                False, KeyPressMask, (XEvent *) event);
+
+      if (si->prefs.verbose_p)
+        {
+          if (status)
+            fprintf (stderr, "sent key...\n");
+          else
+            fprintf (stderr, "error %d sending key...\n", status);
+        }
+      update_passwd_window (si, NULL, pw->ratio);
+    }
+  else
+    {
+      swallow_unlock_typeahead_events (si, (XEvent *) event);
+    }
+
+#else /* !HAVE_XSCREENSAVER_LOCK */
+
   switch (*s)
     {
     case '\010': case '\177':				/* Backspace */
@@ -1779,6 +2551,7 @@ handle_passwd_key (saver_info *si, XKeyEvent *event)
     {
       update_passwd_window (si, "", pw->ratio);
     }
+#endif /* !HAVE_XSCREENSAVER_LOCK */
 }
 
 
@@ -1801,7 +2574,9 @@ passwd_event_loop (saver_info *si)
 
   passwd_animate_timer ((XtPointer) si, 0);
 
-  while (si->unlock_state == ul_read)
+  si->pw_data->got_passwd = FALSE;
+
+  while (si->unlock_state == ul_read && si->pw_data->got_passwd == FALSE)
     {
       XtAppNextEvent (si->app, &event.x_event);
 
@@ -1842,12 +2617,17 @@ passwd_event_loop (saver_info *si)
 
       if (event.x_event.xany.window == si->passwd_dialog && 
           event.x_event.xany.type == Expose)
+#ifdef HAVE_XSCREENSAVER_LOCK
+	XtDispatchEvent (&event.x_event);
+#else
 	draw_passwd_window (si);
+#endif /* !HAVE_XSCREENSAVER_LOCK */
       else if (event.x_event.xany.type == KeyPress)
         {
           handle_passwd_key (si, &event.x_event.xkey);
           si->pw_data->caps_p = (event.x_event.xkey.state & LockMask);
         }
+#ifndef HAVE_XSCREENSAVER_LOCK
       else if (event.x_event.xany.type == ButtonPress || 
                event.x_event.xany.type == ButtonRelease)
 	{
@@ -1856,6 +2636,82 @@ passwd_event_loop (saver_info *si)
 	  if (si->pw_data->login_button_p)
 	    handle_login_button (si, &event.x_event);
 	}
+#endif /* !HAVE_XSCREENSAVER_LOCK */
+
+ /*
+  5077974 P1 "Bug 147583: Screen Lock unlocks because of GOK dwell movement in
+		core pointer mode"
+
+  ScreenLock did not unlock the screen, but WM's XRestackWindow() did.
+  Once WM/metacity fixes the problem, the code can be removed.
+  The problem:
+    repositioning the Wids in the wrong positions when
+    1. the window type is changed from NORMAL to DOCK or vice versa
+    2. the Wid is managed
+    within the X window stack with or without screen-lock in a mixed Wids
+  there are two temp. get-around solutions:
+    1. non-managed GOK or MAG Wid
+    or
+    2. screensaver picks up the WM's restacking task and fixes the prevous
+       restacking problem.
+       the cons: there is a flashing screen when corepointer is touching
+       GOK or MAG and mouse is moved in a fast way
+       when GOK or MAG window type is DOCK only.
+       and it is not a good temp. get-around solution.
+       This is the only choice if WM did not want to fix the problem now
+       and AT group did not want to use non-managed Wids.
+       Now, GOK only supports 2nd USB/mouse/Dwell, corepointer is supposed
+       not to be used, and GOK cannot disable it
+ */
+/*
+     bugid 6769901,6839026: popup windows appearing through xscreensaver
+*/
+      else if (((event.x_event.xany.type == UnmapNotify)
+             || (event.x_event.xany.type == MapNotify)
+             || (event.x_event.xany.type == VisibilityNotify)
+             || (event.x_event.xany.type == ConfigureNotify)
+             || (event.x_event.xany.type == PropertyNotify)
+             || (event.x_event.xany.type == CreateNotify)
+             || (event.x_event.xany.type == ReparentNotify))
+             && (si->passwd_dialog))
+        {
+          /* Find the handle of popup window
+           * Note: we can not get handle of popup window with
+           * event.xany.window, thats why we have switch cases.
+           */
+          Window wPopWin = 0;
+
+          switch(event.x_event.xany.type)
+            {
+            case ConfigureNotify:
+              wPopWin = event.x_event.xconfigure.window;
+              break;
+            case CreateNotify:
+              wPopWin = event.x_event.xcreatewindow.window;
+              break;
+            case VisibilityNotify:
+              wPopWin = event.x_event.xvisibility.window;
+              break;
+            default:
+              break;
+            }
+
+          if (wPopWin)
+            {
+              saver_screen_info *ssi = find_screen_for_window (si, wPopWin);
+
+              /* This if case is for safety, it prevent screensaver stuck in
+               * loop of ConfigureNotify
+               */
+              if ((wPopWin != si->passwd_dialog) && (ssi != NULL) &&
+                  (wPopWin != ssi->screensaver_window) &&
+                  (wPopWin != ssi->stderr_overlay_window))
+                {
+                  restack_my_windows(si, ssi, wPopWin);
+                }
+            }
+        }
+        /* the above new code for restacking under the condition */
       else
 	XtDispatchEvent (&event.x_event);
     }
@@ -1881,8 +2737,13 @@ passwd_event_loop (saver_info *si)
 
   if (msg)
     {
+#ifdef HAVE_XSCREENSAVER_LOCK
+      write_to_child (si, "ul_message", msg);
+      usleep (250000);  /* 1/4 second */
+#else
       si->pw_data->i_beam = 0;
       update_passwd_window (si, msg, 0.0);
+#endif
       XSync (si->dpy, False);
 
       /* Swallow all pending KeyPress/KeyRelease events. */
@@ -1898,6 +2759,10 @@ passwd_event_loop (saver_info *si)
 static void
 handle_typeahead (saver_info *si)
 {
+/* HAVE_XSCREENSAVER_LOCK: typeahead events are flushed to the external
+   dialog program in handle_passwd_input when we get the dialog_win notice
+   that it has created the window */
+#ifndef HAVE_XSCREENSAVER_LOCK
   passwd_dialog_data *pw = si->pw_data;
   int i;
   if (!si->unlock_typeahead)
@@ -1918,6 +2783,7 @@ handle_typeahead (saver_info *si)
 
   free (si->unlock_typeahead);
   si->unlock_typeahead = 0;
+#endif
 }
 
 
@@ -2023,9 +2889,11 @@ gui_auth_conv(int num_msg,
 	  free(prompt_trimmed);
       }
 
+#ifndef HAVE_XSCREENSAVER_LOCK
       compose_status = calloc (1, sizeof (*compose_status));
       if (!compose_status)
 	goto fail;
+#endif
 
       si->unlock_state = ul_read;
 
@@ -2035,7 +2903,14 @@ gui_auth_conv(int num_msg,
       if (si->unlock_state == ul_cancel)
 	goto fail;
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+      if ((si->unlock_state != ul_time) && si->pw_data->passwd_string)
+        responses[i].response = strdup (si->pw_data->passwd_string);
+      else
+        goto fail;
+#else
       responses[i].response = strdup(si->pw_data->typed_passwd);
+#endif
 
       /* Cache the first response to a PROMPT_NOECHO to save prompting for
        * each auth mechanism. */
@@ -2043,8 +2918,10 @@ gui_auth_conv(int num_msg,
 	  auth_msgs[i].type == AUTH_MSGTYPE_PROMPT_NOECHO)
 	si->cached_passwd = strdup(responses[i].response);
 
+#ifndef HAVE_XSCREENSAVER_LOCK
       free (compose_status);
       compose_status = 0;
+#endif
     }
 
   *resp = responses;
@@ -2052,8 +2929,10 @@ gui_auth_conv(int num_msg,
   return (si->unlock_state == ul_finished) ? 0 : -1;
 
 fail:
+#ifndef HAVE_XSCREENSAVER_LOCK
   if (compose_status)
     free (compose_status);
+#endif
 
   if (responses)
     {
@@ -2109,11 +2988,14 @@ auth_finished_cb (saver_info *si)
       if (XPending (si->dpy))
         {
           XNextEvent (si->dpy, &event);
+#ifndef HAVE_XSCREENSAVER_LOCK
           if (event.xany.window == si->passwd_dialog && 
               event.xany.type == Expose)
             draw_passwd_window (si);
-          else if (event.xany.type == ButtonPress || 
-                   event.xany.type == KeyPress)
+          else
+#endif
+            if (event.xany.type == ButtonPress ||
+                event.xany.type == KeyPress)
             break;
           XSync (si->dpy, False);
         }
diff --git xscreensaver-5.12/driver/passwd-pam.c xscreensaver-5.12/driver/passwd-pam.c
--- xscreensaver-5.12/driver/passwd-pam.c
+++ xscreensaver-5.12/driver/passwd-pam.c
@@ -39,10 +39,16 @@
 #ifndef NO_LOCKING  /* whole file */
 
 #include <stdlib.h>
+#include <xscreensaver-intl.h>
+
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif
 
+#ifdef __sun
+# include <deflt.h>
+#endif
+
 extern char *blurb(void);
 
 
@@ -58,6 +64,7 @@ extern char *blurb(void);
 
 #include <sys/stat.h>
 
+#include "dialog-data.h"
 #include "auth.h"
 
 extern sigset_t block_sigchld (void);
@@ -82,7 +89,10 @@ extern void unblock_sigchld (void);
 #endif
 
 static int pam_conversation (int nmsgs,
-                             const struct pam_message **msg,
+#ifndef __sun
+                             const
+#endif
+                             struct pam_message **msg,
                              struct pam_response **resp,
                              void *closure);
 
@@ -183,6 +193,11 @@ pam_try_unlock(saver_info *si, Bool verbose_p,
   struct pam_conv pc;
   sigset_t set;
   struct timespec timeout;
+  int pam_auth_status = 0;  /* Specific for pam_authenticate() status*/
+  int acct_rc, setcred_rc, chauth_rc;
+  int pam_flags = 0;
+
+  uid_t euid = geteuid();
 
   pc.conv = &pam_conversation;
   pc.appdata_ptr = (void *) si;
@@ -191,6 +206,23 @@ pam_try_unlock(saver_info *si, Bool verbose_p,
      `closure' argument to pc.conv always comes in as random garbage. */
   suns_pam_implementation_blows = (void *) si;
 
+#ifdef __sun
+  if (verbose_p)
+    fprintf (stderr, "Before uid=%d euid=%d \n\n", getuid(), geteuid());
+
+  if (seteuid (0) != 0)
+    {
+      if (verbose_p)
+        perror("Could not change euid to root, pam may not work!\n");
+    }
+
+  if (verbose_p)
+    {
+      fprintf (stderr, "After seteuid(0) uid=%d euid=%d \n\n",
+               getuid(), geteuid());
+      fprintf (stderr, "PAM is using SERVICE_NAME=\"%s\"\n\n", service);
+    }
+#endif
 
   /* Initialize PAM.
    */
@@ -201,11 +233,35 @@ pam_try_unlock(saver_info *si, Bool verbose_p,
              status, PAM_STRERROR (pamh, status));
   if (status != PAM_SUCCESS) goto DONE;
 
+#ifdef __sun
+  /* Check /etc/default/login to see if we should add
+     PAM_DISALLOW_NULL_AUTHTOK to pam_flags */
+  if (defopen("/etc/default/login") == 0) {
+    char *ptr;
+    int flags = defcntl(DC_GETFLAGS, 0);
+
+    TURNOFF(flags, DC_CASE);
+    (void) defcntl(DC_SETFLAGS, flags);
+    if ((ptr = defread("PASSREQ=")) != NULL &&
+        strcasecmp("YES", ptr) == 0)
+      {
+        pam_flags |= PAM_DISALLOW_NULL_AUTHTOK;
+      }
+
+    (void) defopen((char *)NULL); /* close current file */
+  }
+#endif
+
   /* #### We should set PAM_TTY to the display we're using, but we
      don't have that handy from here.  So set it to :0.0, which is a
      good guess (and has the bonus of counting as a "secure tty" as
      far as PAM is concerned...)
    */
+
+/* From the pam trace and log file, it is found out that the
+   Sun pam modules can drive itself.
+*/
+#ifndef __sun
   {
     char *tty = strdup (":0.0");
     status = pam_set_item (pamh, PAM_TTY, tty);
@@ -214,6 +270,7 @@ pam_try_unlock(saver_info *si, Bool verbose_p,
                blurb(), tty, status, PAM_STRERROR(pamh, status));
     free (tty);
   }
+#endif
 
   /* Try to authenticate as the current user.
      We must turn off our SIGCHLD handler for the duration of the call to
@@ -243,43 +300,101 @@ pam_try_unlock(saver_info *si, Bool verbose_p,
   timeout.tv_sec = 0;
   timeout.tv_nsec = 1;
   set = block_sigchld();
-  status = pam_authenticate (pamh, 0);
+  pam_auth_status = pam_authenticate (pamh, pam_flags);
 # ifdef HAVE_SIGTIMEDWAIT
   sigtimedwait (&set, NULL, &timeout);
   /* #### What is the portable thing to do if we don't have it? */
 # endif /* HAVE_SIGTIMEDWAIT */
   unblock_sigchld();
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+  /* Send status message to unlock dialog */
+  if (pam_auth_status == PAM_SUCCESS)
+    {
+      if (verbose_p)
+        write_to_child (si, "ul_ok", PAM_STRERROR (pamh, pam_auth_status));
+    }
+  else if (si->unlock_state != ul_cancel && si->unlock_state != ul_time)
+    {
+      write_to_child (si, "ul_fail", PAM_STRERROR (pamh, pam_auth_status));
+    }
+  if (verbose_p)
+    sleep (1);
+#endif
+
+  if (verbose_p)
+      fprintf (stderr, "after calling pam_authenticate state is: %s\n",
+               si->unlock_state == ul_success ? "ul_success" : "ul_fail");
+
   if (verbose_p)
     fprintf (stderr, "%s:   pam_authenticate (...) ==> %d (%s)\n",
-             blurb(), status, PAM_STRERROR(pamh, status));
+             blurb(), pam_auth_status, PAM_STRERROR(pamh, pam_auth_status));
 
-  if (status == PAM_SUCCESS)  /* Win! */
+  if (pam_auth_status == PAM_SUCCESS)  /* Win! */
     {
-      int status2;
+      /* perform PAM account validation procedures for login user only */
+      acct_rc   = pam_acct_mgmt(pamh, pam_flags);
 
-      /* We don't actually care if the account modules fail or succeed,
-       * but we need to run them anyway because certain pam modules
-       * depend on side effects of the account modules getting run.
-       */
-      status2 = pam_acct_mgmt (pamh, 0);
+      /******************************************************************
+           ignore other cases for the time being
+           PAM_USER_UNKNOWN, PAM_AUTH_ERR, PAM_ACCT_EXPIRED
+           (password mgn service module)
+           same as pam_setcred(), focus on auth. service module only
+       *****************************************************************/
 
       if (verbose_p)
         fprintf (stderr, "%s:   pam_acct_mgmt (...) ==> %d (%s)\n",
-                 blurb(), status2, PAM_STRERROR(pamh, status2));
+                 blurb(), acct_rc, PAM_STRERROR(pamh, acct_rc));
+
+#ifdef HAVE_XSCREENSAVER_LOCK
+      /* Send status message to unlock dialog ***/
+      if (acct_rc == PAM_SUCCESS)
+        {
+          if (verbose_p)
+            write_to_child (si, "ul_acct_ok", PAM_STRERROR(pamh, acct_rc));
+        }
+      else
+        write_to_child (si, "ul_acct_fail", PAM_STRERROR(pamh, acct_rc));
+      if (verbose_p)
+        sleep (1);
+#endif
 
       /* HPUX for some reason likes to make PAM defines different from
        * everyone else's. */
 #ifdef PAM_AUTHTOKEN_REQD
-      if (status2 == PAM_AUTHTOKEN_REQD)
+      if (acct_rc == PAM_AUTHTOKEN_REQD)
 #else
-      if (status2 == PAM_NEW_AUTHTOK_REQD)
+      if (acct_rc == PAM_NEW_AUTHTOK_REQD)
 #endif
         {
-          status2 = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
+          for (int i = 0; i < 3; i++)
+            {
+              chauth_rc  = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
+              if (chauth_rc == PAM_AUTHTOK_ERR ||
+                  chauth_rc  == PAM_TRY_AGAIN )
+                {
+                  i = 0;
+                  si->unlock_state = ul_read;
+                }
+              else break; /* get out of the loop */
+            }
+
           if (verbose_p)
             fprintf (stderr, "%s: pam_chauthtok (...) ==> %d (%s)\n",
-                     blurb(), status2, PAM_STRERROR(pamh, status2));
+                     blurb(), chauth_rc, PAM_STRERROR(pamh, chauth_rc));
+
+          if (chauth_rc != PAM_SUCCESS)
+            {
+              pam_auth_status = chauth_rc;
+              goto DONE;
+            }
+        }
+      else if (acct_rc != PAM_SUCCESS)
+        {
+          pam_auth_status = acct_rc;
+          write_to_child (si, "pw_acct_fail", PAM_STRERROR(pamh, acct_rc));
+          sleep (3);
+          goto DONE;
         }
 
       /* Each time we successfully authenticate, refresh credentials,
@@ -291,24 +406,57 @@ pam_try_unlock(saver_info *si, Bool verbose_p,
          says that the Linux PAM library ignores that one, and only refreshes
          credentials when using PAM_REINITIALIZE_CRED.
        */
-      status2 = pam_setcred (pamh, PAM_REINITIALIZE_CRED);
+      setcred_rc = pam_setcred (pamh, PAM_REINITIALIZE_CRED);
       if (verbose_p)
         fprintf (stderr, "%s:   pam_setcred (...) ==> %d (%s)\n",
-                 blurb(), status2, PAM_STRERROR(pamh, status2));
+                 blurb(), setcred_rc, PAM_STRERROR(pamh, setcred_rc));
+
+#ifdef HAVE_XSCREENSAVER_LOCK
+      /* Send status message to unlock dialog ***/
+      if (setcred_rc == PAM_SUCCESS)
+        {
+          if (verbose_p)
+            write_to_child (si, "ul_setcred_ok", PAM_STRERROR(pamh, setcred_rc));
+        }
+      else
+        write_to_child (si, "ul_setcred_fail", PAM_STRERROR(pamh, setcred_rc));
+      if (verbose_p)
+        sleep (1);
+#endif
     }
 
  DONE:
   if (pamh)
     {
-      int status2 = pam_end (pamh, status);
-      pamh = 0;
+      int status2 = pam_end (pamh, pam_auth_status);
+      pamh = NULL;
       if (verbose_p)
         fprintf (stderr, "%s: pam_end (...) ==> %d (%s)\n",
                  blurb(), status2,
                  (status2 == PAM_SUCCESS ? "Success" : "Failure"));
     }
 
-  if (status == PAM_SUCCESS)
+  if (seteuid (euid) != 0)
+    {
+      if (verbose_p)
+        perror("Error pam could not revert euid to user running as euid root,"
+               " locking may not work now\n");
+    }
+
+  if (verbose_p)
+    fprintf (stderr,
+             "<--end of pam_authenticate() returning ok_to_unblank = %d\n",
+             (int) ((pam_auth_status == PAM_SUCCESS) ? True : False));
+
+  if (si->pw_data->passwd_string)
+    {
+      memset(si->pw_data->passwd_string, 0,
+             strlen(si->pw_data->passwd_string));
+      free (si->pw_data->passwd_string);
+      si->pw_data->passwd_string = NULL;
+    }
+
+  if (pam_auth_status == PAM_SUCCESS)
     si->unlock_state = ul_success;	     /* yay */
   else if (si->unlock_state == ul_cancel ||
            si->unlock_state == ul_time)
@@ -334,6 +482,13 @@ pam_priv_init (int argc, char **argv, Bool verbose_p)
   const char file2[] = "/etc/pam.conf";
   struct stat st;
 
+#ifdef __sun
+  if (! verbose_p)      /* SUN addition: only print warnings in verbose mode */
+    {                   /* since they are rarely useful and mostly just      */
+      return True;      /* cause confusion when users see them.		     */
+    }
+#endif
+
 # ifndef S_ISDIR
 #  define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
 # endif
@@ -360,6 +515,8 @@ pam_priv_init (int argc, char **argv, Bool verbose_p)
                 break;
               }
           fclose (f);
+
+#ifndef __sun  /* disable the misleading message */
           if (!ok)
             {
               fprintf (stderr,
@@ -367,9 +524,11 @@ pam_priv_init (int argc, char **argv, Bool verbose_p)
                   "%s: password authentication via PAM is unlikely to work.\n",
                        blurb(), file2, PAM_SERVICE_NAME, blurb());
             }
+#endif
         }
       /* else warn about file2 existing but being unreadable? */
     }
+#ifndef __sun  /* disable the misleading message */
   else
     {
       fprintf (stderr,
@@ -377,15 +536,19 @@ pam_priv_init (int argc, char **argv, Bool verbose_p)
                "%s: password authentication via PAM is unlikely to work.\n",
                blurb(), file2, file, blurb());
     }
+#endif
 
   /* Return true anyway, just in case. */
   return True;
 }
 
 
-static int
+int
 pam_conversation (int nmsgs,
-		  const struct pam_message **msg,
+#ifndef __sun
+                  const
+#endif
+		  struct pam_message **msg,
 		  struct pam_response **resp,
 		  void *vsaver_info)
 {
diff --git xscreensaver-5.12/driver/passwd.c xscreensaver-5.12/driver/passwd.c
--- xscreensaver-5.12/driver/passwd.c
+++ xscreensaver-5.12/driver/passwd.c
@@ -35,6 +35,7 @@
 
 #include <X11/Intrinsic.h>
 
+#include "dialog-data.h"
 #include "xscreensaver.h"
 #include "auth.h"
 
diff --git xscreensaver-5.12/driver/setuid.c xscreensaver-5.12/driver/setuid.c
--- xscreensaver-5.12/driver/setuid.c
+++ xscreensaver-5.12/driver/setuid.c
@@ -145,7 +145,10 @@ set_ids_by_number (uid_t uid, gid_t gid, char **message_ret)
     gid_errno = errno ? errno : -1;
 
   errno = 0;
-  if (setuid (uid) != 0)
+/*mali  if (setuid (uid) != 0)**we need root privs back at pam_authenticate
+  this is causing to loose root priv for good, not good **/
+
+  if (seteuid (uid) != 0)
     uid_errno = errno ? errno : -1;
 
   if (uid_errno == 0 && gid_errno == 0 && sgs_errno == 0)
diff --git xscreensaver-5.12/driver/subprocs.c xscreensaver-5.12/driver/subprocs.c
--- xscreensaver-5.12/driver/subprocs.c
+++ xscreensaver-5.12/driver/subprocs.c
@@ -243,7 +243,11 @@ show_job_list (void)
 
 static void clean_job_list (void);
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+struct screenhack_job *
+#else
 static struct screenhack_job *
+#endif
 make_job (pid_t pid, int screen, const char *cmd)
 {
   struct screenhack_job *job = (struct screenhack_job *) malloc (sizeof(*job));
@@ -407,7 +411,11 @@ unblock_sigchld (void)
   block_sigchld_handler--;
 }
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+int
+#else
 static int
+#endif
 kill_job (saver_info *si, pid_t pid, int signal)
 {
   saver_preferences *p = &si->prefs;
@@ -590,9 +598,14 @@ describe_dead_child (saver_info *si, pid_t kid, int wait_status)
 	 mention them) if we've just killed the subprocess.  But mention them
 	 if they happen on their own.
        */
-      if (!job ||
-	  (exit_status != 0 &&
-	   (p->verbose_p || job->status != job_killed)))
+
+      if ((!job
+#ifdef HAVE_XSCREENSAVER_LOCK
+	   && kid != si->passwd_pid
+#endif /* HAVE_XSCREENSAVER_LOCK */
+	      ) ||
+	   (exit_status != 0 &&
+	    (p->verbose_p || (job && job->status != job_killed))))
         {
           /* Don't call fprintf() from signal handlers, as it might malloc.
 	  fprintf (stderr,
@@ -632,8 +645,12 @@ describe_dead_child (saver_info *si, pid_t kid, int wait_status)
   else if (WIFSIGNALED (wait_status))
     {
       if (p->verbose_p ||
-	  !job ||
-	  job->status != job_killed ||
+	  (!job
+#ifdef HAVE_XSCREENSAVER_LOCK
+	   && kid != si->passwd_pid
+#endif /* HAVE_XSCREENSAVER_LOCK */
+		  ) ||
+	  (job && job->status != job_killed) ||
 	  WTERMSIG (wait_status) != SIGTERM)
         {
           /* Don't call fprintf() from signal handlers, as it might malloc.
@@ -701,12 +718,20 @@ describe_dead_child (saver_info *si, pid_t kid, int wait_status)
   /* Clear out the pid so that screenhack_running_p() knows it's dead.
    */
   if (!job || job->status == job_dead)
+    {
     for (i = 0; i < si->nscreens; i++)
       {
 	saver_screen_info *ssi = &si->screens[i];
 	if (kid == ssi->pid)
 	  ssi->pid = 0;
       }
+#ifdef HAVE_XSCREENSAVER_LOCK
+      if (kid == si->passwd_pid)
+	{
+	  si->passwd_pid = 0;
+	}
+#endif
+    }
 }
 
 #else  /* VMS */
diff --git xscreensaver-5.12/driver/timers.c xscreensaver-5.12/driver/timers.c
--- xscreensaver-5.12/driver/timers.c
+++ xscreensaver-5.12/driver/timers.c
@@ -47,6 +47,8 @@
 #endif /* HAVE_RANDR */
 
 #include "xscreensaver.h"
+#include "types.h"
+#include "dialog-data.h"
 
 #undef ABS
 #define ABS(x)((x)<0?-(x):(x))
@@ -60,6 +62,11 @@ static Bool proc_interrupts_activity_p (saver_info *si);
 #endif /* HAVE_PROC_INTERRUPTS */
 
 static void check_for_clock_skew (saver_info *si);
+#ifdef HAVE_XSCREENSAVER_LOCK
+static void watchdog_timer (XtPointer closure, XtIntervalId *id);
+extern Bool g_passwd_dialog_created;
+extern Bool ok_to_unblank;
+#endif
 
 
 void
@@ -255,7 +262,11 @@ cycle_timer (XtPointer closure, XtIntervalId *id)
        crash.  So, restart the thing once an hour. */
     how_long = 1000 * 60 * 60;
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+  if (si->external_passwd)
+#else
   if (si->dbox_up_p)
+#endif
     {
       if (p->verbose_p)
 	fprintf (stderr, "%s: dialog box up; delaying hack change.\n",
@@ -308,7 +319,28 @@ activate_lock_timer (XtPointer closure, XtIntervalId *id)
 
   if (p->verbose_p)
     fprintf (stderr, "%s: timed out; activating lock.\n", blurb());
-  set_locked_p (si, True);
+
+  if (si->locked_p)
+    {
+      if (p->verbose_p)
+        fprintf (stderr,
+          "-->activate_lock_timer returning because screen already locked\n");
+      return;
+    }
+
+  /* Make sure screen is blanked before posting dialog box */
+  if (si->screen_blanked_p)
+    {
+      set_locked_p (si, True);
+      ok_to_unblank = unlock_p (si);
+      if (ok_to_unblank == True)
+        {
+          set_locked_p(si,False);
+          unblank_screen(si);
+        }
+    }
+  else /* blanking of screen failed reset lock flag */
+    set_locked_p (si, False);
 }
 
 
@@ -587,14 +619,30 @@ dispatch_event (saver_info *si, XEvent *event)
 }
 
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+void /* called from lock.c */
+#else
 static void
+#endif
 swallow_unlock_typeahead_events (saver_info *si, XEvent *e)
 {
   XEvent event;
   char buf [100];
   int i = 0;
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+  if (!si->typeahead_events)
+    {
+      /* Allocate enough space for 10 keys to be queued - if we get more
+         than that before the dialog is ready, it's most likely the user
+         left something sitting on the keyboard, and won't want them. */
+      si->typeahead_events = calloc(10, sizeof(XKeyEvent));
+      if (si->typeahead_events == NULL)
+        return;
+    }
+#else
   memset (buf, 0, sizeof(buf));
+#endif
 
   event = *e;
 
@@ -607,10 +655,12 @@ swallow_unlock_typeahead_events (saver_info *si, XEvent *e)
           if (size != 1) continue;
           switch (*s)
             {
+#ifndef HAVE_XSCREENSAVER_LOCK /* Let these be queued with the rest */
             case '\010': case '\177':			/* Backspace */
               if (i > 0) i--;
               break;
             case '\025': case '\030':			/* Erase line */
+#endif
             case '\012': case '\015':			/* Enter */
             case '\033':				/* ESC */
               i = 0;
@@ -620,7 +670,17 @@ swallow_unlock_typeahead_events (saver_info *si, XEvent *e)
                 break;  /* ignore space at beginning of line */
               /* else, fall through */
             default:
+#ifdef HAVE_XSCREENSAVER_LOCK
+              /* Queue events to replay once dialog is ready */
+              if (si->num_typeahead_events < 10)
+                memcpy (&si->typeahead_events[si->num_typeahead_events++],
+                        &event, sizeof(XKeyEvent));
+              else
+                XBell (si->dpy, 0);
+              i = 1; /* so that spaces are accepted after the beginning */
+#else
               buf [i++] = *s;
+#endif
               break;
             }
         }
@@ -628,6 +688,7 @@ swallow_unlock_typeahead_events (saver_info *si, XEvent *e)
     } while (i < sizeof(buf)-1 &&
              XCheckMaskEvent (si->dpy, KeyPressMask, &event));
 
+#ifndef HAVE_XSCREENSAVER_LOCK
   buf[i] = 0;
 
   if (si->unlock_typeahead)
@@ -642,6 +703,7 @@ swallow_unlock_typeahead_events (saver_info *si, XEvent *e)
     si->unlock_typeahead = 0;
 
   memset (buf, 0, sizeof(buf));
+#endif /* HAVE_XSCREENSAVER_LOCK */
 }
 
 
@@ -818,7 +880,10 @@ sleep_until_idle (saver_info *si, Bool until_idle_p)
 
       case ClientMessage:
 	if (handle_clientmessage (si, &event.x_event, until_idle_p))
-	  goto DONE;
+          {
+            si->emergency_lock_p = True;
+            goto DONE;
+          }
 	break;
 
       case CreateNotify:
@@ -831,6 +896,47 @@ sleep_until_idle (saver_info *si, Bool until_idle_p)
 	  }
 	break;
 
+      case VisibilityNotify:
+      {
+        int k;
+
+        if (p->debug_p)
+          {
+            fprintf (stderr,
+                     "************************************\n"
+                     "-->sleep_until_idle() event:VisibilityNotify\n"
+                     "\t Window of VisibilityNotify:%x\n"
+                     "\t until_idle_p=%d g_passwd_dialog_created=%d\n",
+                     event.x_event.xvisibility.window,
+                     until_idle_p, g_passwd_dialog_created);
+            fflush(stderr);
+          }
+
+        /* Don't raise root window when passwd dialog wants to come up */
+        if (g_passwd_dialog_created == 0 && !until_idle_p)
+          {
+            if (event.x_event.xvisibility.state != VisibilityUnobscured)
+              {
+                for (k = 0; k < si->nscreens; k++)
+                  {
+                    saver_screen_info *ssi = &si->screens[k];
+                    XClearWindow (si->dpy, ssi->screensaver_window);
+                    clear_stderr (ssi);
+                    XMapRaised (si->dpy, ssi->screensaver_window);
+                  }
+                if (p->debug_p)
+                  {
+                    fprintf (stderr,
+                             "A window is trying to popup.\n"
+                             "Raising saver root Window.\n"
+                             "************************************\n");
+                    fflush(stderr);
+                  }
+              }
+          }
+        break;
+      }
+
       case KeyPress:
       case ButtonPress:
       /* Ignore release events so that hitting ESC at the password dialog
@@ -1419,7 +1525,11 @@ watchdog_timer (XtPointer closure, XtIntervalId *id)
     {
       Bool running_p = screenhack_running_p (si);
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+      if (si->external_passwd)
+#else
       if (si->dbox_up_p)
+#endif
         {
           if (si->prefs.debug_p)
             fprintf (stderr, "%s: dialog box is up: not raising screen.\n",
diff --git xscreensaver-5.12/driver/types.h xscreensaver-5.12/driver/types.h
--- xscreensaver-5.12/driver/types.h
+++ xscreensaver-5.12/driver/types.h
@@ -248,12 +248,30 @@ struct saver_info {
 
   int unlock_failures;		/* Counts failed login attempts while the
 				   screen is locked. */
+#ifdef HAVE_XSCREENSAVER_LOCK
+  Window *raise_wins;		/* List of windows to raise above the	*/
+  int num_raise_wins;		/*  virtual root/hack display, such as	*/
+  int max_raise_wins;		/*  accessibility helpers		*/
+
+  Window *override_wins;        /* Windows we had to unset the          */
+  int num_override_wins;        /*  override_redirect attribute on and  */
+  int max_override_wins;        /*  need to restore it on after unlock. */
+
+
+  pid_t passwd_pid;             /* The pid of the password dialog child if we
+                                   are running an external process for it. */
+  Bool external_passwd;
+
+  XKeyEvent *typeahead_events;	/* Like unlock_typeahead, but as raw events */
+  int num_typeahead_events;
+#else
 
   char *unlock_typeahead;	/* If the screen is locked, and the user types
                                    a character, we assume that it is the first
                                    character of the password.  It's stored here
                                    for the password dialog to use to populate
                                    itself. */
+#endif /* HAVE_XSCREENSAVER_LOCK */
 
   char *user;			/* The user whose session is locked. */
   char *cached_passwd;		/* Cached password, used to avoid multiple
diff --git xscreensaver-5.12/driver/windows.c xscreensaver-5.12/driver/windows.c
--- xscreensaver-5.12/driver/windows.c
+++ xscreensaver-5.12/driver/windows.c
@@ -1081,8 +1081,12 @@ safe_XConfigureWindow (Display *dpy, Window window,
   return (!error_handler_hit_p);
 }
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+Bool
+#else
 /* This might not be necessary, but just in case. */
 static Bool
+#endif
 safe_XDestroyWindow (Display *dpy, Window window)
 {
   XErrorHandler old_handler;
@@ -1096,6 +1100,14 @@ safe_XDestroyWindow (Display *dpy, Window window)
   XSetErrorHandler (old_handler);
   XSync (dpy, False);
 
+  /* clear any queued VisibilityNotify events so we don't cause XErrors
+     later when we try to process them and find the windowid is invalid */
+  XEvent event;
+  while (XCheckWindowEvent(dpy, window, VisibilityChangeMask, &event))
+    {
+      /* discard event */ ;
+    }
+
   return (!error_handler_hit_p);
 }
 
@@ -1210,6 +1222,7 @@ initialize_screensaver_window_1 (saver_screen_info *ssi)
    */
   attrs.event_mask = (KeyPressMask | KeyReleaseMask |
 		      ButtonPressMask | ButtonReleaseMask |
+		      VisibilityChangeMask |
 		      PointerMotionMask);
 
   attrs.backing_store = NotUseful;
@@ -1481,6 +1494,9 @@ raise_window (saver_info *si,
   saver_preferences *p = &si->prefs;
   int i;
 
+  if (p->verbose_p)
+      fprintf(stderr,"-->raise_window()\n");
+
   if (si->demoing_p)
     inhibit_fade = True;
 
@@ -1695,6 +1711,9 @@ unblank_screen (saver_info *si)
   Bool unfade_p = (si->fading_possible_p && p->unfade_p);
   int i;
 
+  if (p->verbose_p)
+      fprintf(stderr,"-->unblank_screen()\n");
+
   monitor_power_on (si);
   reset_watchdog_timer (si, False);
 
@@ -1983,7 +2002,7 @@ select_visual (saver_screen_info *ssi, const char *visual_name)
       maybe_transfer_grabs (ssi, old_w, ssi->screensaver_window, ssi->number);
 
       /* Now we can destroy the old window without horking our grabs. */
-      XDestroyWindow (si->dpy, old_w);
+      safe_XDestroyWindow (si->dpy, old_w);
 
       if (p->verbose_p)
 	fprintf (stderr, "%s: %d: destroyed old saver window 0x%lx.\n",
diff --git xscreensaver-5.12/driver/xscreensaver.c xscreensaver-5.12/driver/xscreensaver.c
--- xscreensaver-5.12/driver/xscreensaver.c
+++ xscreensaver-5.12/driver/xscreensaver.c
@@ -156,6 +156,8 @@
 #include <X11/StringDefs.h>
 #include <X11/Shell.h>
 #include <X11/Xos.h>
+#include <gconf/gconf-client.h>
+#include <glib.h>
 #include <time.h>
 #include <sys/time.h>
 #include <netdb.h>	/* for gethostbyname() */
@@ -217,6 +219,7 @@
 #endif /* HAVE_RANDR */
 
 
+#include "dialog-data.h"
 #include "xscreensaver.h"
 #include "version.h"
 #include "yarandom.h"
@@ -228,11 +231,28 @@
 
 saver_info *global_si_kludge = 0;	/* I hate C so much... */
 
+/* Globals */
+Bool ok_to_unblank = False;
+
+#ifdef HAVE_XSCREENSAVER_LOCK
+/* Global storage for gtk passwd lock dialog
+ * we assign this to si->pw_data and this is needed
+ * to set user/passwd labels on gtk lock dialog by
+ * pam conv function.
+ */
+passwd_dialog_data mygtkpwd;
+passwd_dialog_data *ptr_mygtkpwd = &mygtkpwd;
+#endif
+
 char *progname = 0;
 char *progclass = 0;
 XrmDatabase db = 0;
 
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+Atom XA_UNLOCK_RATIO;
+#endif
+
 
 static XrmOptionDescRec options [] = {
 
@@ -630,6 +650,9 @@ connect_to_server (saver_info *si, int *argc, char **argv)
 	{ &XA_XSETROOT_ID, "_XSETROOT_ID" },
 	{ &XA_ESETROOT_PMAP_ID, "ESETROOT_PMAP_ID" },
 	{ &XA_XROOTPMAP_ID, "_XROOTPMAP_ID" },
+#ifdef HAVE_XSCREENSAVER_LOCK
+	{ &XA_UNLOCK_RATIO, "UNLOCK_RATIO" },
+#endif
 	{ NULL, NULL } /* Must be last to terminate list */
       };
     const struct atom_request *atom_lists[3] = { NULL, NULL, NULL };
@@ -1105,8 +1128,36 @@ static void
 main_loop (saver_info *si)
 {
   saver_preferences *p = &si->prefs;
-  Bool ok_to_unblank;
+  /* Bool ok_to_unblank; made this a global flag, gets set in timers.c */
   int i;
+  const char *modulesptr = NULL;
+
+/*
+** CR4784055(P1)locked-screen dialog is inaccessible to Gnopernicus
+** voice for each type-in char in the password field of
+** pop-up dialog
+*/
+
+  /* BUG #6573182
+  ** g_type_init should be done before calling gconf_client routines
+  ** so that xscreensaver does not dump core if gconf daemon is not running.
+  */
+  g_type_init ();
+
+  /*
+  ** 6395649 at-spi-registryd starts when screen is locked even
+  ** when accessible device support is off(SR)
+  ** per AT core gp suggestion
+  ** GTK_MODULES is set only if at support is enabled
+  */
+
+  if (gconf_client_get_bool(gconf_client_get_default(),
+			    "/desktop/gnome/interface/accessibility", NULL))
+    {
+      modulesptr = getenv ("GTK_MODULES");
+      if (!modulesptr || modulesptr [0] == '\0')
+	putenv ("GTK_MODULES=gail:atk-bridge");
+    }
 
   while (1)
     {
@@ -1137,6 +1188,17 @@ main_loop (saver_info *si)
             fprintf (stderr, "%s: idle with blanking disabled at %s.\n",
                      blurb(), timestring());
 
+          /* 6221109 Changing mode from disable to anything else,
+             doesn't lock screen.
+
+             This is Disable Screen Saver mode, in this mode we dont lock
+             screen, but si->locked_p is already set to True, since someone
+             tried to lock screen, reset it to False, else when we change
+             mode from disable and try to lock screen, xscreensaver thinks
+             screen is already locked and doesnt lock screen anymore.
+           */
+          set_locked_p (si, False);
+
           /* Go around the loop and wait for the next bout of idleness,
              or for the init file to change, or for a remote command to
              come in, or something.
@@ -1198,6 +1260,7 @@ main_loop (saver_info *si)
                        blurb());
 
               schedule_wakeup_event (si, retry, p->debug_p);
+              set_locked_p(si, False);
               continue;
             }
         }
@@ -1246,7 +1309,17 @@ main_loop (saver_info *si)
             p->lock_p &&                /* and locking is enabled */
             !si->locking_disabled_p &&  /* and locking is possible */
             lock_timeout == 0)          /* and locking is not timer-deferred */
-          set_locked_p (si, True);      /* then lock right now. */
+          {
+           if (p->debug_p)
+             fprintf(stderr, "going to lock screen B\n");
+           set_locked_p (si, True);      /* then lock right now. */
+           ok_to_unblank = unlock_p(si);
+           if (ok_to_unblank == True)
+             {
+               set_locked_p (si, False);
+               goto DONE;
+             }
+          }
 
         /* locked_p might be true already because of the above, or because of
            the LOCK ClientMessage.  But if not, and if we're supposed to lock
@@ -1261,10 +1334,7 @@ main_loop (saver_info *si)
       }
 #endif /* !NO_LOCKING */
 
-
-      ok_to_unblank = True;
       do {
-
         check_for_leaks ("blanked A");
 	sleep_until_idle (si, False);		/* until not idle */
         check_for_leaks ("blanked B");
@@ -1274,6 +1344,13 @@ main_loop (saver_info *si)
 #ifndef NO_LOCKING
         /* Maybe unlock the screen.
          */
+        if (si->demoing_p) goto DONE; /* in demoing mode and user wants out
+                                         unblank screen */
+
+        /* This is when blank timeout has happened but lock timeout hasnt
+           and user gets active.  Simply get him out of the blank screen. */
+        if (si->screen_blanked_p && !si->locked_p) goto DONE;
+
 	if (si->locked_p)
 	  {
 	    saver_screen_info *ssi = si->default_screen;
@@ -1285,7 +1362,20 @@ main_loop (saver_info *si)
               suspend_screenhack (&si->screens[i], True);	  /* suspend */
 	    XUndefineCursor (si->dpy, ssi->screensaver_window);
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+            /* Prevents lock dialog posting on non blanked screen */
+            if (!si->screen_blanked_p)  /* locked_p is true, so blank now */
+              blank_screen (si);
+            if (si->screen_blanked_p)   /* if blanking successful, call PAM */
+              {
+                set_locked_p (si, True);
+                ok_to_unblank = unlock_p(si);
+              }
+            else /* blanking failed, probably couldn't grab keyboard/mouse */
+              set_locked_p (si, False);
+#else
 	    ok_to_unblank = unlock_p (si);
+#endif
 
 	    si->dbox_up_p = False;
 	    XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
@@ -1310,6 +1400,7 @@ main_loop (saver_info *si)
 
 	} while (!ok_to_unblank);
 
+DONE:
 
       if (p->verbose_p)
 	fprintf (stderr, "%s: unblanking screen at %s.\n",
@@ -1375,7 +1466,19 @@ main (int argc, char **argv)
   textdomain (GETTEXT_PACKAGE);
 #endif /* ENABLE_NLS */
 
+#if defined(ENABLE_NLS) && defined(HAVE_XSCREENSAVER_LOCK)
+  /* Gtk unlock dialog needs to be sent UTF-8 text to display */
+  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+
   memset(si, 0, sizeof(*si));
+
+#ifdef HAVE_XSCREENSAVER_LOCK
+/* Initialize and point si to pw_data i.e. the lock dialog struct */
+  memset(ptr_mygtkpwd, 0, sizeof(*ptr_mygtkpwd));
+  si->pw_data = ptr_mygtkpwd;
+#endif
+
   global_si_kludge = si;	/* I hate C so much... */
 
   fix_fds();
@@ -1385,7 +1488,9 @@ main (int argc, char **argv)
 
   save_argv (argc, argv);
   set_version_string (si, &argc, argv);
+#ifndef HAVE_XSCREENSAVER_LOCK /* moved below for external lock */
   privileged_initialization (si, &argc, argv);
+#endif
   hack_environment (si);
 
   spasswd = getpwuid(getuid());
@@ -1408,6 +1513,10 @@ main (int argc, char **argv)
   print_banner (si);
 
   load_init_file(si->dpy, p); /* must be before initialize_per_screen_info() */
+#ifdef HAVE_XSCREENSAVER_LOCK
+  privileged_initialization (si, &argc, argv);
+#endif
+
   blurb_timestamp_p = p->timestamp_p;  /* kludge */
   initialize_per_screen_info (si, shell); /* also sets si->fading_possible_p */
 
@@ -1659,8 +1768,12 @@ handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
   Atom type = 0;
   Window window = event->xclient.window;
 
+  if (p->verbose_p)
+     fprintf(stderr, "handle_clientmessage\n");
+
   /* Preferences might affect our handling of client messages. */
   maybe_reload_init_file (si);
+  XSync (si->dpy, False);
 
   if (event->xclient.message_type != XA_SCREENSAVER ||
       event->xclient.format != 32)
@@ -1933,10 +2046,18 @@ 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);
+
+	  if (p->verbose_p)
+	    fprintf(stderr, "going to lock screen A\n");
+
 	  set_locked_p (si, True);
+	  si->emergency_lock_p = True;
 	  si->selection_mode = 0;
 	  si->demoing_p = False;
 
+	  return True; /* dont set lock_id to 0,
+                          causes to go in lock in main_loop above */
+
 	  if (si->lock_id)	/* we're doing it now, so lose the timeout */
 	    {
 	      XtRemoveTimeOut (si->lock_id);
diff --git xscreensaver-5.12/driver/xscreensaver.h xscreensaver-5.12/driver/xscreensaver.h
--- xscreensaver-5.12/driver/xscreensaver.h
+++ xscreensaver-5.12/driver/xscreensaver.h
@@ -164,6 +164,12 @@ extern Bool select_visual (saver_screen_info *ssi, const char *visual_name);
 extern void store_saver_status (saver_info *si);
 extern const char *signal_name (int signal);
 
+#ifdef HAVE_XSCREENSAVER_LOCK
+extern int kill_job (saver_info *si, pid_t pid, int signal);
+extern struct screenhack_job *make_job (pid_t pid, int screen,
+                                        const char *cmd);
+#endif
+
 /* =======================================================================
    subprocs diagnostics
    ======================================================================= */

