# include <syslog.h>
#endif /* HAVE_SYSLOG */
+#ifdef HAVE_XHPDISABLERESET
+# include <X11/XHPlib.h>
+ static void hp_lock_reset (saver_info *si, Bool lock_p);
+#endif /* HAVE_XHPDISABLERESET */
+
+#ifdef HAVE_VT_LOCKSWITCH
+# include <fcntl.h>
+# include <sys/ioctl.h>
+# include <sys/vt.h>
+ static void linux_lock_vt_switch (saver_info *si, Bool lock_p);
+#endif /* HAVE_VT_LOCKSWITCH */
+
+#ifdef HAVE_XF86VMODE
+# include <X11/extensions/xf86vmode.h>
+ static void xfree_lock_mode_switch (saver_info *si, Bool lock_p);
+#endif /* HAVE_XF86VMODE */
+
+
#ifdef _VROOT_H_
ERROR! You must not include vroot.h in this file.
#endif
extern int validate_user(char *name, char *password);
static Bool
-vms_passwd_valid_p(char *pw)
+vms_passwd_valid_p(char *pw, Bool verbose_p)
{
return (validate_user (getenv("USER"), typed_passwd) == 1);
}
int i_beam;
float ratio;
+ Position x, y;
Dimension width;
Dimension height;
+ Dimension border_width;
char *heading_label;
char *body_label;
Dimension thermo_field_x, thermo_field_y;
Dimension thermo_field_height;
+
+ Pixmap save_under;
};
+static void draw_passwd_window (saver_info *si);
+static void update_passwd_window (saver_info *si, const char *printed_passwd,
+ float ratio);
+static void destroy_passwd_window (saver_info *si);
+static void undo_vp_motion (saver_info *si);
-void
+
+static void
make_passwd_window (saver_info *si)
{
struct passwd *p = getpwuid (getuid ());
- int x, y, bw;
XSetWindowAttributes attrs;
unsigned long attrmask = 0;
Screen *screen = si->default_screen->screen;
attrmask |= CWEventMask; attrs.event_mask = ExposureMask|KeyPressMask;
{
- Dimension w = WidthOfScreen(screen);
- Dimension h = HeightOfScreen(screen);
+ int x, y, w, h;
+ get_screen_viewport (si->default_screen, &x, &y, &w, &h, False);
if (si->prefs.debug_p) w /= 2;
- x = ((w + pw->width) / 2) - pw->width;
- y = ((h + pw->height) / 2) - pw->height;
- if (x < 0) x = 0;
- if (y < 0) y = 0;
+ pw->x = x + ((w + pw->width) / 2) - pw->width;
+ pw->y = y + ((h + pw->height) / 2) - pw->height;
+ if (pw->x < x) pw->x = x;
+ if (pw->y < y) pw->y = y;
}
- bw = get_integer_resource ("passwd.borderWidth", "Dialog.BorderWidth");
+ pw->border_width = get_integer_resource ("passwd.borderWidth",
+ "Dialog.BorderWidth");
si->passwd_dialog =
XCreateWindow (si->dpy,
RootWindowOfScreen(screen),
- x, y, pw->width, pw->height, bw,
+ pw->x, pw->y, pw->width, pw->height, pw->border_width,
DefaultDepthOfScreen (screen), InputOutput,
DefaultVisualOfScreen(screen),
attrmask, &attrs);
XSetWindowBackground (si->dpy, si->passwd_dialog, pw->background);
+
+ /* Before mapping the window, save the bits that are underneath the
+ rectangle the window will occlude. When we lower the window, we
+ restore these bits. This works, because the running screenhack
+ has already been sent SIGSTOP, so we know nothing else is drawing
+ right now! */
+ {
+ XGCValues gcv;
+ GC gc;
+ pw->save_under = XCreatePixmap (si->dpy,
+ si->default_screen->screensaver_window,
+ pw->width + (pw->border_width*2) + 1,
+ pw->height + (pw->border_width*2) + 1,
+ si->default_screen->current_depth);
+ gcv.function = GXcopy;
+ gc = XCreateGC (si->dpy, pw->save_under, GCFunction, &gcv);
+ XCopyArea (si->dpy, si->default_screen->screensaver_window,
+ pw->save_under, gc,
+ pw->x - pw->border_width, pw->y - pw->border_width,
+ pw->width + (pw->border_width*2) + 1,
+ pw->height + (pw->border_width*2) + 1,
+ 0, 0);
+ XFreeGC (si->dpy, gc);
+ }
+
XMapRaised (si->dpy, si->passwd_dialog);
XSync (si->dpy, False);
+ move_mouse_grab (si, si->passwd_dialog, si->screens[0].cursor);
+ undo_vp_motion (si);
+
si->pw_data = pw;
draw_passwd_window (si);
}
-void
+static void
draw_passwd_window (saver_info *si)
{
passwd_dialog_data *pw = si->pw_data;
}
-void
+static void
update_passwd_window (saver_info *si, const char *printed_passwd, float ratio)
{
passwd_dialog_data *pw = si->pw_data;
XGCValues gcv;
GC gc1, gc2;
int x, y;
+ XRectangle rects[1];
pw->ratio = ratio;
gcv.foreground = pw->passwd_foreground;
/* the "password" text field
*/
+ rects[0].x = pw->passwd_field_x;
+ rects[0].y = pw->passwd_field_y;
+ rects[0].width = pw->passwd_field_width;
+ rects[0].height = pw->passwd_field_height;
+
XFillRectangle (si->dpy, si->passwd_dialog, gc2,
- pw->passwd_field_x, pw->passwd_field_y,
- pw->passwd_field_width, pw->passwd_field_height);
+ rects[0].x, rects[0].y, rects[0].width, rects[0].height);
+
+ XSetClipRectangles (si->dpy, gc1, 0, 0, rects, 1, Unsorted);
+
XDrawString (si->dpy, si->passwd_dialog, gc1,
- pw->passwd_field_x + pw->shadow_width,
- pw->passwd_field_y + (pw->passwd_font->ascent +
- pw->passwd_font->descent),
- pw->passwd_string, strlen(pw->passwd_string));
+ rects[0].x + pw->shadow_width,
+ rects[0].y + (pw->passwd_font->ascent +
+ pw->passwd_font->descent),
+ pw->passwd_string, strlen(pw->passwd_string));
+
+ XSetClipMask (si->dpy, gc1, None);
/* The I-beam
*/
if (pw->i_beam != 0)
{
- x = (pw->passwd_field_x + pw->shadow_width +
+ x = (rects[0].x + pw->shadow_width +
string_width (pw->passwd_font, pw->passwd_string));
- y = pw->passwd_field_y + pw->shadow_width;
+ y = rects[0].y + pw->shadow_width;
+
+ if (x > rects[0].x + rects[0].width - 1)
+ x = rects[0].x + rects[0].width - 1;
XDrawLine (si->dpy, si->passwd_dialog, gc1,
x, y, x, y + pw->passwd_font->ascent);
}
}
-void
+static void
destroy_passwd_window (saver_info *si)
{
passwd_dialog_data *pw = si->pw_data;
if (pw->timer)
XtRemoveTimeOut (pw->timer);
+ move_mouse_grab (si, RootWindowOfScreen(si->screens[0].screen),
+ si->screens[0].cursor);
+
if (si->passwd_dialog)
{
XDestroyWindow (si->dpy, si->passwd_dialog);
si->passwd_dialog = 0;
}
+ if (pw->save_under)
+ {
+ XGCValues gcv;
+ GC gc;
+ gcv.function = GXcopy;
+ gc = XCreateGC (si->dpy, si->default_screen->screensaver_window,
+ GCFunction, &gcv);
+ XCopyArea (si->dpy, pw->save_under,
+ si->default_screen->screensaver_window, gc,
+ 0, 0,
+ pw->width + (pw->border_width*2) + 1,
+ pw->height + (pw->border_width*2) + 1,
+ pw->x - pw->border_width, pw->y - pw->border_width);
+ XFreePixmap (si->dpy, pw->save_under);
+ pw->save_under = 0;
+ XFreeGC (si->dpy, gc);
+ }
+
if (pw->heading_label) free (pw->heading_label);
if (pw->body_label) free (pw->body_label);
if (pw->user_label) free (pw->user_label);
si->pw_data = 0;
}
+
+#ifdef HAVE_XHPDISABLERESET
+/* This function enables and disables the C-Sh-Reset hot-key, which
+ normally resets the X server (logging out the logged-in user.)
+ We don't want random people to be able to do that while the
+ screen is locked.
+ */
+static void
+hp_lock_reset (saver_info *si, Bool lock_p)
+{
+ static Bool hp_locked_p = False;
+
+ /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
+ or BadAccess errors occur. (It's ok for this to be global,
+ since it affects the whole machine, not just the current screen.)
+ */
+ if (hp_locked_p == lock_p)
+ return;
+
+ if (lock_p)
+ XHPDisableReset (si->dpy);
+ else
+ XHPEnableReset (si->dpy);
+ hp_locked_p = lock_p;
+}
+#endif /* HAVE_XHPDISABLERESET */
+
+
+\f
+/* This function enables and disables the C-Sh-F1 ... F12 hot-keys,
+ which, on Linux systems, switches to another virtual console.
+ We'd like the whole screen/keyboard to be locked, not just one
+ virtual console, so this function disables that while the X
+ screen is locked.
+
+ Unfortunately, this doesn't work -- this ioctl only works when
+ called by root, and we have disavowed our privileges long ago.
+ */
+#ifdef HAVE_VT_LOCKSWITCH
+static void
+linux_lock_vt_switch (saver_info *si, Bool lock_p)
+{
+ saver_preferences *p = &si->prefs;
+ static Bool vt_locked_p = False;
+ const char *dev_console = "/dev/console";
+ int fd;
+
+ if (lock_p == vt_locked_p)
+ return;
+
+ if (lock_p && !p->lock_vt_p)
+ return;
+
+ fd = open (dev_console, O_RDWR);
+ if (fd < 0)
+ {
+ char buf [255];
+ sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
+ (lock_p ? "lock" : "unlock"),
+ dev_console);
+#if 1 /* #### doesn't work yet, so don't bother complaining */
+ perror (buf);
+#endif
+ return;
+ }
+
+ if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
+ {
+ vt_locked_p = lock_p;
+
+ if (p->verbose_p)
+ fprintf (stderr, "%s: %s VTs\n", blurb(),
+ (lock_p ? "locked" : "unlocked"));
+ }
+ else
+ {
+ char buf [255];
+ sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
+ (lock_p ? "lock" : "unlock"));
+#if 0 /* #### doesn't work yet, so don't bother complaining */
+ perror (buf);
+#endif
+ }
+
+ close (fd);
+}
+#endif /* HAVE_VT_LOCKSWITCH */
+
+\f
+/* This function enables and disables the C-Alt-Plus and C-Alt-Minus
+ hot-keys, which normally change the resolution of the X server.
+ We don't want people to be able to switch the server resolution
+ while the screen is locked, because if they switch to a higher
+ resolution, it could cause part of the underlying desktop to become
+ exposed.
+ */
+#ifdef HAVE_XF86VMODE
+
+static int ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error);
+static Bool vp_got_error = False;
+
+static void
+xfree_lock_mode_switch (saver_info *si, Bool lock_p)
+{
+ static Bool mode_locked_p = False;
+ saver_preferences *p = &si->prefs;
+ int screen = 0; /* always screen 0 */
+ int event, error;
+ Bool status;
+ XErrorHandler old_handler;
+
+ if (mode_locked_p == lock_p)
+ return;
+ if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
+ return;
+
+ XSync (si->dpy, False);
+ old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
+ status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p);
+ XSync (si->dpy, False);
+ XSetErrorHandler (old_handler);
+ if (vp_got_error) status = False;
+
+ if (status)
+ mode_locked_p = lock_p;
+
+ if (!status && (p->verbose_p || !lock_p))
+ /* Only print this when verbose, or when we locked but can't unlock.
+ I tried printing this message whenever it comes up, but
+ mode-locking always fails if DontZoom is set in XF86Config. */
+ fprintf (stderr, "%s: unable to %s mode switching!\n",
+ blurb(), (lock_p ? "lock" : "unlock"));
+ else if (p->verbose_p)
+ fprintf (stderr, "%s: %s mode switching.\n",
+ blurb(), (lock_p ? "locked" : "unlocked"));
+}
+
+static int
+ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
+{
+ vp_got_error = True;
+ return 0;
+}
+
+#endif /* HAVE_XF86VMODE */
+
+\f
+/* If the viewport has been scrolled since the screen was blanked,
+ then scroll it back to where it belongs. This function only exists
+ to patch over a very brief race condition.
+ */
+static void
+undo_vp_motion (saver_info *si)
+{
+#ifdef HAVE_XF86VMODE
+ saver_preferences *p = &si->prefs;
+ int screen = 0; /* always screen 0 */
+ saver_screen_info *ssi = &si->screens[screen];
+ int event, error, x, y;
+ Bool status;
+
+ if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1)
+ return;
+ if (!XF86VidModeQueryExtension (si->dpy, &event, &error))
+ return;
+ if (!XF86VidModeGetViewPort (si->dpy, 0, &x, &y))
+ return;
+ if (ssi->blank_vp_x == x && ssi->blank_vp_y == y)
+ return;
+
+ /* We're going to move the viewport. The mouse has just been grabbed on
+ (and constrained to, thus warped to) the password window, so it is no
+ longer near the edge of the screen. However, wait a bit anyway, just
+ to make sure the server drains its last motion event, so that the
+ screen doesn't continue to scroll after we've reset the viewport.
+ */
+ XSync (si->dpy, False);
+ usleep (250000); /* 1/4 second */
+ XSync (si->dpy, False);
+
+ status = XF86VidModeSetViewPort (si->dpy, screen,
+ ssi->blank_vp_x, ssi->blank_vp_y);
+
+ if (!status)
+ fprintf (stderr, "%s: unable to move vp from (%d,%d) back to (%d,%d)!\n",
+ blurb(), x, y, ssi->blank_vp_x, ssi->blank_vp_y);
+ else if (p->verbose_p)
+ fprintf (stderr, "%s: vp moved to (%d,%d); moved it back to (%d,%d).\n",
+ blurb(), x, y, ssi->blank_vp_x, ssi->blank_vp_y);
+
+#endif /* HAVE_XF86VMODE */
+}
+
+
\f
/* Interactions
*/
static void
handle_passwd_key (saver_info *si, XKeyEvent *event)
{
+ saver_preferences *p = &si->prefs;
passwd_dialog_data *pw = si->pw_data;
int pw_size = sizeof (pw->typed_passwd) - 1;
char *typed_passwd = pw->typed_passwd;
case '\012': case '\015': /* Enter */
if (pw->state != pw_read)
; /* already done? */
- else if (passwd_valid_p (typed_passwd))
- pw->state = pw_ok;
else if (typed_passwd[0] == 0)
pw->state = pw_null;
else
- pw->state = pw_fail;
+ {
+ update_passwd_window (si, "Checking...", pw->ratio);
+ XSync (si->dpy, False);
+ if (passwd_valid_p (typed_passwd, p->verbose_p))
+ pw->state = pw_ok;
+ else
+ pw->state = pw_fail;
+ update_passwd_window (si, "", pw->ratio);
+ }
break;
default:
}
#endif /* HAVE_SYSLOG */
+ if (si->pw_data->state == pw_fail)
+ XBell (si->dpy, False);
+
if (si->pw_data->state == pw_ok && si->unlock_failures != 0)
{
if (si->unlock_failures == 1)
{
si->pw_data->i_beam = 0;
update_passwd_window (si, msg, 0.0);
- XBell (si->dpy, False);
XSync (si->dpy, False);
sleep (1);
Colormap cmap = DefaultColormapOfScreen (screen);
Bool status;
+ raise_window (si, True, True, True);
+
if (p->verbose_p)
fprintf (stderr, "%s: prompting for password.\n", blurb());
return status;
}
-#endif /* !NO_LOCKING -- whole file */
+
+void
+set_locked_p (saver_info *si, Bool locked_p)
+{
+ si->locked_p = locked_p;
+
+#ifdef HAVE_XHPDISABLERESET
+ hp_lock_reset (si, locked_p); /* turn off/on C-Sh-Reset */
+#endif
+#ifdef HAVE_VT_LOCKSWITCH
+ linux_lock_vt_switch (si, locked_p); /* turn off/on C-Alt-F1 */
+#endif
+#ifdef HAVE_XF86VMODE
+ xfree_lock_mode_switch (si, locked_p); /* turn off/on C-Alt-Plus */
+#endif
+}
+
+
+#else /* NO_LOCKING -- whole file */
+
+void
+set_locked_p (saver_info *si, Bool locked_p)
+{
+ if (locked_p) abort();
+}
+
+#endif /* !NO_LOCKING */