diff options
author | Simon Rettberg | 2024-09-06 14:42:37 +0200 |
---|---|---|
committer | Simon Rettberg | 2024-09-06 14:42:37 +0200 |
commit | badef32037f52f79abc1f1440b786cd71afdf270 (patch) | |
tree | 412b792d4cab4a7a110db82fcf74fe8a1ac55ec1 /driver/lock.c | |
parent | Delete pre-6.00 files (diff) | |
download | xscreensaver-master.tar.gz xscreensaver-master.tar.xz xscreensaver-master.zip |
Diffstat (limited to 'driver/lock.c')
-rw-r--r-- | driver/lock.c | 2276 |
1 files changed, 0 insertions, 2276 deletions
diff --git a/driver/lock.c b/driver/lock.c deleted file mode 100644 index d36481e..0000000 --- a/driver/lock.c +++ /dev/null @@ -1,2276 +0,0 @@ -/* lock.c --- handling the password dialog for locking-mode. - * xscreensaver, Copyright (c) 1993-2018 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. - */ - -/* Athena locking code contributed by Jon A. Christopher <jac8782@tamu.edu> */ -/* Copyright 1997, with the same permissions as above. */ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <ctype.h> -#include <X11/Intrinsic.h> -#include <X11/cursorfont.h> -#include <X11/Xos.h> /* for time() */ -#include <time.h> -#include <sys/time.h> -#include "xscreensaver.h" -#include "resources.h" -#include "mlstring.h" -#include "auth.h" - -#ifndef NO_LOCKING /* (mostly) whole file */ - -#ifdef HAVE_XHPDISABLERESET -# include <X11/XHPlib.h> - static void hp_lock_reset (saver_info *si, Bool lock_p); -#endif /* HAVE_XHPDISABLERESET */ - -#ifdef HAVE_XF86VMODE -# include <X11/extensions/xf86vmode.h> - static void xfree_lock_mode_switch (saver_info *si, Bool lock_p); -#endif /* HAVE_XF86VMODE */ - -#ifdef HAVE_XF86MISCSETGRABKEYSSTATE -# include <X11/extensions/xf86misc.h> - static void xfree_lock_grab_smasher (saver_info *si, Bool lock_p); -#endif /* HAVE_XF86MISCSETGRABKEYSSTATE */ - -#ifdef HAVE_RANDR -# include <X11/extensions/Xrandr.h> -#endif /* HAVE_RANDR */ - -#ifdef _VROOT_H_ -ERROR! You must not include vroot.h in this file. -#endif - -#ifdef HAVE_UNAME -# include <sys/utsname.h> /* for hostname info */ -#endif /* HAVE_UNAME */ -#include <ctype.h> - -#ifndef VMS -# include <pwd.h> -#else /* VMS */ - -extern char *getenv(const char *name); -extern int validate_user(char *name, char *password); - -static Bool -vms_passwd_valid_p(char *pw, Bool verbose_p) -{ - return (validate_user (getenv("USER"), typed_passwd) == 1); -} -# undef passwd_valid_p -# define passwd_valid_p vms_passwd_valid_p - -#endif /* VMS */ - -#define SAMPLE_INPUT "MMMMMMMMMMMM" - - -#undef MAX -#define MAX(a,b) ((a)>(b)?(a):(b)) - -typedef struct info_dialog_data info_dialog_data; - - -#define MAX_BYTES_PER_CHAR 8 /* UTF-8 uses no more than 3, I think */ -#define MAX_PASSWD_CHARS 128 /* Longest possible passphrase */ - -struct passwd_dialog_data { - - saver_screen_info *prompt_screen; - int previous_mouse_x, previous_mouse_y; - - /* "Characters" in the password may be a variable number of bytes long. - typed_passwd contains the raw bytes. - typed_passwd_char_size indicates the size in bytes of each character, - so that we can make backspace work. - */ - char typed_passwd [MAX_PASSWD_CHARS * MAX_BYTES_PER_CHAR]; - char typed_passwd_char_size [MAX_PASSWD_CHARS]; - - 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 border; - 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; -}; - -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); -static void finished_typing_passwd (saver_info *si, passwd_dialog_data *pw); -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); - -static int -new_passwd_window (saver_info *si) -{ - passwd_dialog_data *pw; - Screen *screen; - Colormap cmap; - saver_screen_info *ssi = &si->screens [mouse_screen (si)]; - - pw = (passwd_dialog_data *) calloc (1, sizeof(*pw)); - if (!pw) - return -1; - - /* Display the button only if the "newLoginCommand" pref is non-null. - */ - pw->login_button_p = (si->prefs.new_login_command && - *si->prefs.new_login_command); - - pw->passwd_cursor = XCreateFontCursor (si->dpy, XC_top_left_arrow); - - pw->prompt_screen = ssi; - - screen = pw->prompt_screen->screen; - cmap = DefaultColormapOfScreen (screen); - - pw->show_stars_p = get_boolean_resource(si->dpy, "passwd.asterisks", - "Boolean"); - - 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", - "Dialog.Label.Label"); - pw->user_label = get_string_resource (si->dpy, "passwd.user.label", - "Dialog.Label.Label"); - pw->unlock_label = get_string_resource (si->dpy, "passwd.unlock.label", - "Dialog.Button.Label"); - pw->login_label = get_string_resource (si->dpy, "passwd.login.label", - "Dialog.Button.Label"); - - pw->date_label = get_string_resource (si->dpy, "dateFormat", "DateFormat"); - - if (!pw->heading_label) - pw->heading_label = strdup("ERROR: RESOURCES NOT INSTALLED CORRECTLY"); - if (!pw->body_label) - pw->body_label = strdup("ERROR: RESOURCES NOT INSTALLED CORRECTLY"); - if (!pw->user_label) pw->user_label = strdup("ERROR"); - if (!pw->date_label) pw->date_label = strdup("ERROR"); - if (!pw->unlock_label) pw->unlock_label = strdup("ERROR (UNLOCK)"); - if (!pw->login_label) pw->login_label = strdup ("ERROR (LOGIN)") ; - - /* Put the version number in the label. */ - { - char *s = (char *) malloc (strlen(pw->heading_label) + 20); - sprintf(s, pw->heading_label, si->version); - free (pw->heading_label); - pw->heading_label = s; - } - - /* Get hostname info */ - pw->uname_label = strdup(""); /* Initialy, write nothing */ - -# ifdef HAVE_UNAME - { - struct utsname uts; - - if (uname (&uts) == 0) - { -#if 0 /* Get the full hostname */ - { - char *s; - if ((s = strchr(uts.nodename, '.'))) - *s = 0; - } -#endif - char *s = strdup (uts.nodename); - free (pw->uname_label); - pw->uname_label = s; - } - } -# endif - - pw->passwd_string = strdup(""); - - pw->heading_font = - splash_load_font (si->dpy, "passwd.headingFont", "Dialog.Font"); - pw->button_font = - splash_load_font (si->dpy, "passwd.buttonFont", "Dialog.Font"); - pw->body_font = - splash_load_font (si->dpy, "passwd.bodyFont", "Dialog.Font"); - pw->label_font = - splash_load_font (si->dpy, "passwd.labelFont", "Dialog.Font"); - pw->passwd_font = - splash_load_font (si->dpy, "passwd.passwdFont", "Dialog.Font"); - pw->date_font = - splash_load_font (si->dpy, "passwd.dateFont", "Dialog.Font"); - pw->uname_font = - splash_load_font (si->dpy, "passwd.unameFont", "Dialog.Font"); - - pw->show_uname_p = get_boolean_resource(si->dpy, "passwd.uname", "Boolean"); - - pw->foreground = get_pixel_resource (si->dpy, cmap, - "passwd.foreground", - "Dialog.Foreground" ); - pw->background = get_pixel_resource (si->dpy, cmap, - "passwd.background", - "Dialog.Background" ); - pw->border = get_pixel_resource (si->dpy, cmap, - "passwd.borderColor", - "Dialog.borderColor"); - - if (pw->foreground == pw->background) - { - /* Make sure the error messages show up. */ - pw->foreground = BlackPixelOfScreen (screen); - pw->background = WhitePixelOfScreen (screen); - } - - pw->passwd_foreground = get_pixel_resource (si->dpy, cmap, - "passwd.text.foreground", - "Dialog.Text.Foreground" ); - pw->passwd_background = get_pixel_resource (si->dpy, cmap, - "passwd.text.background", - "Dialog.Text.Background" ); - pw->button_foreground = get_pixel_resource (si->dpy, cmap, - "splash.Button.foreground", - "Dialog.Button.Foreground" ); - pw->button_background = get_pixel_resource (si->dpy, cmap, - "splash.Button.background", - "Dialog.Button.Background" ); - pw->thermo_foreground = get_pixel_resource (si->dpy, cmap, - "passwd.thermometer.foreground", - "Dialog.Thermometer.Foreground"); - pw->thermo_background = get_pixel_resource ( si->dpy, cmap, - "passwd.thermometer.background", - "Dialog.Thermometer.Background"); - pw->shadow_top = get_pixel_resource ( si->dpy, cmap, - "passwd.topShadowColor", - "Dialog.Foreground" ); - pw->shadow_bottom = get_pixel_resource (si->dpy, cmap, - "passwd.bottomShadowColor", - "Dialog.Background" ); - - pw->preferred_logo_width = get_integer_resource (si->dpy, - "passwd.logo.width", - "Dialog.Logo.Width"); - pw->preferred_logo_height = get_integer_resource (si->dpy, - "passwd.logo.height", - "Dialog.Logo.Height"); - pw->thermo_width = get_integer_resource (si->dpy, "passwd.thermometer.width", - "Dialog.Thermometer.Width"); - pw->internal_border = get_integer_resource (si->dpy, - "passwd.internalBorderWidth", - "Dialog.InternalBorderWidth"); - pw->shadow_width = get_integer_resource (si->dpy, "passwd.shadowThickness", - "Dialog.ShadowThickness"); - - if (pw->preferred_logo_width == 0) pw->preferred_logo_width = 150; - if (pw->preferred_logo_height == 0) pw->preferred_logo_height = 150; - if (pw->internal_border == 0) pw->internal_border = 15; - if (pw->shadow_width == 0) pw->shadow_width = 4; - if (pw->thermo_width == 0) pw->thermo_width = pw->shadow_width; - - - /* We need to remember the mouse position and restore it afterward, or - sometimes (perhaps only with Xinerama?) the mouse gets warped to - inside the bounds of the lock dialog window. - */ - { - Window pointer_root, pointer_child; - int root_x, root_y, win_x, win_y; - unsigned int mask; - pw->previous_mouse_x = 0; - pw->previous_mouse_y = 0; - if (XQueryPointer (si->dpy, RootWindowOfScreen (pw->prompt_screen->screen), - &pointer_root, &pointer_child, - &root_x, &root_y, &win_x, &win_y, &mask)) - { - pw->previous_mouse_x = root_x; - pw->previous_mouse_y = root_y; - if (si->prefs.verbose_p) - fprintf (stderr, "%s: %d: mouse is at %d,%d.\n", - blurb(), pw->prompt_screen->number, - pw->previous_mouse_x, pw->previous_mouse_y); - } - else if (si->prefs.verbose_p) - fprintf (stderr, "%s: %d: unable to determine mouse position?\n", - blurb(), pw->prompt_screen->number); - } - - /* Before mapping the window, save a pixmap of the current screen. - 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, - pw->prompt_screen->screensaver_window, - pw->prompt_screen->width, - pw->prompt_screen->height, - pw->prompt_screen->current_depth); - gcv.function = GXcopy; - gc = XCreateGC (si->dpy, pw->save_under, GCFunction, &gcv); - XCopyArea (si->dpy, pw->prompt_screen->screensaver_window, - pw->save_under, gc, - 0, 0, - pw->prompt_screen->width, pw->prompt_screen->height, - 0, 0); - XFreeGC (si->dpy, gc); - } - - si->pw_data = pw; - return 0; -} - - -Bool debug_passwd_window_p = False; /* used only by test-passwd.c */ - - -/** - * info_msg and prompt may be NULL. - */ -static int -make_passwd_window (saver_info *si, - const char *info_msg, - const char *prompt, - Bool echo) -{ - XSetWindowAttributes attrs; - unsigned long attrmask = 0; - passwd_dialog_data *pw; - Screen *screen; - Colormap cmap; - Dimension max_string_width_px; - saver_screen_info *ssi = &si->screens [mouse_screen (si)]; - - cleanup_passwd_window (si); - - if (! ssi) /* WTF? Trying to prompt while no screens connected? */ - return -1; - - if (!si->pw_data) - if (new_passwd_window (si) < 0) - return -1; - - if (!(pw = si->pw_data)) - return -1; - - pw->ratio = 1.0; - - pw->prompt_screen = ssi; - if (si->prefs.verbose_p) - fprintf (stderr, "%s: %d: creating password dialog (\"%s\")\n", - blurb(), pw->prompt_screen->number, - info_msg ? info_msg : ""); - - screen = pw->prompt_screen->screen; - cmap = DefaultColormapOfScreen (screen); - - pw->echo_input = echo; - - max_string_width_px = ssi->width - - pw->shadow_width * 4 - - pw->border_width * 2 - - pw->thermo_width - - pw->preferred_logo_width - - pw->internal_border * 2; - /* As the string wraps it makes the window taller which makes the logo wider - * which leaves less room for the text which makes the string wrap. Uh-oh, a - * loop. By wrapping at a bit less than the available width, there's some - * room for the dialog to grow without going off the edge of the screen. */ - max_string_width_px *= 0.75; - - if (!info_msg && senesculent_p()) - info_msg = ("\n" - "This version of XScreenSaver\n" - "is very old! Please upgrade!\n"); - - pw->info_label = mlstring_new(info_msg ? info_msg : pw->body_label, - pw->label_font, max_string_width_px); - - { - int direction, ascent, descent; - XCharStruct overall; - - pw->width = 0; - pw->height = 0; - - /* Measure the heading_label. */ - XTextExtents (pw->heading_font, - pw->heading_label, strlen(pw->heading_label), - &direction, &ascent, &descent, &overall); - if (overall.width > pw->width) pw->width = overall.width; - pw->height += ascent + descent; - - /* Measure the uname_label. */ - if ((strlen(pw->uname_label)) && pw->show_uname_p) - { - XTextExtents (pw->uname_font, - pw->uname_label, strlen(pw->uname_label), - &direction, &ascent, &descent, &overall); - if (overall.width > pw->width) pw->width = overall.width; - pw->height += ascent + descent; - } - - { - Dimension w2 = 0, w3 = 0, button_w = 0; - Dimension h2 = 0, h3 = 0, button_h = 0; - const char *passwd_string = SAMPLE_INPUT; - - /* Measure the user_label. */ - XTextExtents (pw->label_font, - pw->user_label, strlen(pw->user_label), - &direction, &ascent, &descent, &overall); - if (overall.width > w2) w2 = overall.width; - h2 += ascent + descent; - - /* Measure the info_label. */ - if (pw->info_label->overall_width > pw->width) - pw->width = pw->info_label->overall_width; - h2 += pw->info_label->overall_height; - - /* Measure the user string. */ - XTextExtents (pw->passwd_font, - si->user, strlen(si->user), - &direction, &ascent, &descent, &overall); - overall.width += (pw->shadow_width * 4); - ascent += (pw->shadow_width * 4); - if (overall.width > w3) w3 = overall.width; - h3 += ascent + descent; - - /* Measure the (dummy) passwd_string. */ - if (prompt) - { - XTextExtents (pw->passwd_font, - passwd_string, strlen(passwd_string), - &direction, &ascent, &descent, &overall); - overall.width += (pw->shadow_width * 4); - ascent += (pw->shadow_width * 4); - if (overall.width > w3) w3 = overall.width; - h3 += ascent + descent; - - /* Measure the prompt_label. */ - max_string_width_px -= w3; - pw->prompt_label = mlstring_new (prompt, pw->label_font, - max_string_width_px); - - if (pw->prompt_label->overall_width > w2) - w2 = pw->prompt_label->overall_width; - - h2 += pw->prompt_label->overall_height; - - w2 = w2 + w3 + (pw->shadow_width * 2); - h2 = MAX (h2, h3); - } - - /* The "Unlock" button. */ - XTextExtents (pw->label_font, - pw->unlock_label, strlen(pw->unlock_label), - &direction, &ascent, &descent, &overall); - button_w = overall.width; - button_h = ascent + descent; - - /* Add some horizontal padding inside the button. */ - button_w += ascent; - - button_w += ((ascent + descent) / 2) + (pw->shadow_width * 2); - button_h += ((ascent + descent) / 2) + (pw->shadow_width * 2); - - pw->unlock_button_width = button_w; - pw->unlock_button_height = button_h; - - w2 = MAX (w2, button_w); - h2 += button_h * 1.5; - - /* The "New Login" button */ - pw->login_button_width = 0; - pw->login_button_height = 0; - - if (pw->login_button_p) - { - pw->login_button_enabled_p = True; - - /* Measure the "New Login" button */ - XTextExtents (pw->button_font, pw->login_label, - strlen (pw->login_label), - &direction, &ascent, &descent, &overall); - button_w = overall.width; - button_h = ascent + descent; - - /* Add some horizontal padding inside the buttons. */ - button_w += ascent; - - button_w += ((ascent + descent) / 2) + (pw->shadow_width * 2); - button_h += ((ascent + descent) / 2) + (pw->shadow_width * 2); - - pw->login_button_width = button_w; - pw->login_button_height = button_h; - - if (button_h > pw->unlock_button_height) - h2 += (button_h * 1.5 - pw->unlock_button_height * 1.5); - - /* Use (2 * shadow_width) spacing between the buttons. Another - (2 * shadow_width) is required to account for button shadows. */ - w2 = MAX (w2, - button_w + pw->unlock_button_width + - (pw->shadow_width * 4)); - } - - if (w2 > pw->width) pw->width = w2; - pw->height += h2; - } - - pw->width += (pw->internal_border * 2); - pw->height += (pw->internal_border * 4); - - pw->width += pw->thermo_width + (pw->shadow_width * 3); - - if (pw->preferred_logo_height > pw->height) - pw->height = pw->logo_height = pw->preferred_logo_height; - else if (pw->height > pw->preferred_logo_height) - pw->logo_height = pw->height; - - pw->logo_width = pw->logo_height; - - pw->width += pw->logo_width; - } - - attrmask |= CWOverrideRedirect; attrs.override_redirect = True; - - if (debug_passwd_window_p) - attrs.override_redirect = False; /* kludge for test-passwd.c */ - - attrmask |= CWEventMask; - attrs.event_mask = (ExposureMask | KeyPressMask | - ButtonPressMask | ButtonReleaseMask); - - /* Figure out where on the desktop to place the window so that it will - actually be visible; this takes into account virtual viewports as - well as Xinerama. */ - { - saver_screen_info *ssi = &si->screens [mouse_screen (si)]; - int x = ssi->x; - int y = ssi->y; - int w = ssi->width; - int h = ssi->height; - if (si->prefs.debug_p) w /= 2; - pw->x = x + ((w + pw->width) / 2) - pw->width; - pw->y = y + ((h + pw->height) / 2) - pw->height; - if (pw->x < x) pw->x = x; - if (pw->y < y) pw->y = y; - } - - pw->border_width = get_integer_resource (si->dpy, "passwd.borderWidth", - "Dialog.BorderWidth"); - - /* Only create the window the first time around */ - if (!si->passwd_dialog) - { - si->passwd_dialog = - XCreateWindow (si->dpy, - RootWindowOfScreen(screen), - 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); - XSetWindowBorder (si->dpy, si->passwd_dialog, pw->border); - - /* We use the default visual, not ssi->visual, so that the logo pixmap's - visual matches that of the si->passwd_dialog window. */ - pw->logo_pixmap = xscreensaver_logo (ssi->screen, - /* ssi->current_visual, */ - DefaultVisualOfScreen(screen), - si->passwd_dialog, cmap, - pw->background, - &pw->logo_pixels, &pw->logo_npixels, - &pw->logo_clipmask, True); - } - else /* On successive prompts, just resize the window */ - { - XWindowChanges wc; - unsigned int mask = CWX | CWY | CWWidth | CWHeight; - - wc.x = pw->x; - wc.y = pw->y; - wc.width = pw->width; - wc.height = pw->height; - - XConfigureWindow (si->dpy, si->passwd_dialog, mask, &wc); - } - - restore_background(si); - - XMapRaised (si->dpy, si->passwd_dialog); - XSync (si->dpy, False); - - move_mouse_grab (si, si->passwd_dialog, - pw->passwd_cursor, - pw->prompt_screen->number); - undo_vp_motion (si); - - si->pw_data = pw; - - if (cmap) - XInstallColormap (si->dpy, cmap); - draw_passwd_window (si); - - return 0; -} - - -static void -draw_passwd_window (saver_info *si) -{ - passwd_dialog_data *pw = si->pw_data; - XGCValues gcv; - GC gc1, gc2; - int spacing, height; - int x1, x2, x3, y1, y2; - int sw; - int tb_height; - - /* Force redraw */ - pw->passwd_changed_p = True; - pw->button_state_changed_p = True; - - /* This height is the height of all the elements, not to be confused with - * the overall window height which is pw->height. It is used to compute - * the amount of spacing (padding) between elements. */ - height = (pw->heading_font->ascent + pw->heading_font->descent + - pw->info_label->overall_height + - MAX (((pw->label_font->ascent + pw->label_font->descent) + - (pw->prompt_label ? pw->prompt_label->overall_height : 0)), - ((pw->passwd_font->ascent + pw->passwd_font->descent) + - (pw->shadow_width * 2)) * (pw->prompt_label ? 2 : 1)) + - pw->date_font->ascent + pw->date_font->descent); - - if ((strlen(pw->uname_label)) && pw->show_uname_p) - height += (pw->uname_font->ascent + pw->uname_font->descent); - - height += ((pw->button_font->ascent + pw->button_font->descent) * 2 + - 2 * pw->shadow_width); - - spacing = ((pw->height - 2 * pw->shadow_width - - pw->internal_border - height) - / 10); - - if (spacing < 0) spacing = 0; - - gcv.foreground = pw->foreground; - gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv); - gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv); - x1 = pw->logo_width + pw->thermo_width + (pw->shadow_width * 3); - x3 = pw->width - (pw->shadow_width * 2); - y1 = (pw->shadow_width * 2) + spacing + spacing; - - /* top heading - */ - XSetFont (si->dpy, gc1, pw->heading_font->fid); - sw = string_width (pw->heading_font, pw->heading_label); - x2 = (x1 + ((x3 - x1 - sw) / 2)); - y1 += spacing + pw->heading_font->ascent + pw->heading_font->descent; - XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1, - pw->heading_label, strlen(pw->heading_label)); - - /* uname below top heading - */ - if ((strlen(pw->uname_label)) && pw->show_uname_p) - { - XSetFont (si->dpy, gc1, pw->uname_font->fid); - y1 += spacing + pw->uname_font->ascent + pw->uname_font->descent; - sw = string_width (pw->uname_font, pw->uname_label); - x2 = (x1 + ((x3 - x1 - sw) / 2)); - XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1, - pw->uname_label, strlen(pw->uname_label)); - } - - /* the info_label (below uname) - */ - x2 = (x1 + ((x3 - x1 - pw->info_label->overall_width) / 2)); - y1 += spacing + pw->info_label->font_height / 2; - mlstring_draw(si->dpy, si->passwd_dialog, gc1, pw->info_label, - x2, y1); - y1 += pw->info_label->overall_height; - - - tb_height = (pw->passwd_font->ascent + pw->passwd_font->descent + - (pw->shadow_width * 4)); - - /* the "User:" prompt - */ - y2 = y1; - XSetForeground (si->dpy, gc1, pw->foreground); - XSetFont (si->dpy, gc1, pw->label_font->fid); - y1 += (spacing + tb_height + pw->shadow_width); - x2 = (x1 + pw->internal_border + - MAX(string_width (pw->label_font, pw->user_label), - pw->prompt_label ? pw->prompt_label->overall_width : 0)); - XDrawString (si->dpy, si->passwd_dialog, gc1, - x2 - string_width (pw->label_font, pw->user_label), - y1 - pw->passwd_font->descent, - pw->user_label, strlen(pw->user_label)); - - /* the prompt_label prompt - */ - if (pw->prompt_label) - { - y1 += tb_height - pw->label_font->ascent + pw->shadow_width; - mlstring_draw(si->dpy, si->passwd_dialog, gc1, pw->prompt_label, - x2 - pw->prompt_label->overall_width, y1); - } - - /* the "user name" text field - */ - y1 = y2; - XSetForeground (si->dpy, gc1, pw->passwd_foreground); - XSetForeground (si->dpy, gc2, pw->passwd_background); - XSetFont (si->dpy, gc1, pw->passwd_font->fid); - y1 += (spacing + tb_height); - x2 += (pw->shadow_width * 4); - - pw->passwd_field_width = x3 - x2 - pw->internal_border; - pw->passwd_field_height = (pw->passwd_font->ascent + - pw->passwd_font->descent + - pw->shadow_width); - - XFillRectangle (si->dpy, si->passwd_dialog, gc2, - x2 - pw->shadow_width, - y1 - (pw->passwd_font->ascent + pw->passwd_font->descent), - pw->passwd_field_width, pw->passwd_field_height); - XDrawString (si->dpy, si->passwd_dialog, gc1, - x2, - y1 - pw->passwd_font->descent, - si->user, strlen(si->user)); - - /* the password/prompt text field - */ - if (pw->prompt_label) - { - y1 += (spacing + pw->prompt_label->overall_height + pw->shadow_width*2); - - pw->passwd_field_x = x2 - pw->shadow_width; - pw->passwd_field_y = y1 - (pw->passwd_font->ascent + - pw->passwd_font->descent); - } - - /* The shadow around the text fields - */ - y1 = y2; - y1 += (spacing + (pw->shadow_width * 3)); - x1 = x2 - (pw->shadow_width * 2); - x2 = pw->passwd_field_width + (pw->shadow_width * 2); - y2 = pw->passwd_field_height + (pw->shadow_width * 2); - - draw_shaded_rectangle (si->dpy, si->passwd_dialog, - x1, y1, x2, y2, - pw->shadow_width, - pw->shadow_bottom, pw->shadow_top); - - if (pw->prompt_label) - { - y1 += (spacing + pw->prompt_label->overall_height + pw->shadow_width*2); - draw_shaded_rectangle (si->dpy, si->passwd_dialog, - x1, y1, x2, y2, - pw->shadow_width, - pw->shadow_bottom, pw->shadow_top); - } - - - /* The date, below the text fields - */ - { - char buf[100]; - time_t now = time ((time_t *) 0); - struct tm *tm = localtime (&now); - memset (buf, 0, sizeof(buf)); - strftime (buf, sizeof(buf)-1, pw->date_label, tm); - - XSetForeground (si->dpy, gc1, pw->foreground); - XSetFont (si->dpy, gc1, pw->date_font->fid); - y1 += pw->shadow_width; - y1 += (spacing + tb_height); - y1 += spacing/2; - sw = string_width (pw->date_font, buf); - x2 = x1 + x2 - sw; - XDrawString (si->dpy, si->passwd_dialog, gc1, x2, y1, buf, strlen(buf)); - } - - /* Set up the GCs for the "New Login" and "Unlock" buttons. - */ - XSetForeground(si->dpy, gc1, pw->button_foreground); - XSetForeground(si->dpy, gc2, pw->button_background); - XSetFont(si->dpy, gc1, pw->button_font->fid); - - /* The "Unlock" button */ - x2 = pw->width - pw->internal_border - (pw->shadow_width * 2); - - /* right aligned button */ - x1 = x2 - pw->unlock_button_width; - - /* Add half the difference between y1 and the internal edge. - * It actually looks better if the internal border is ignored. */ - y1 += ((pw->height - MAX (pw->unlock_button_height, pw->login_button_height) - - spacing - y1) - / 2); - - pw->unlock_button_x = x1; - pw->unlock_button_y = y1; - - /* The "New Login" button - */ - if (pw->login_button_p) - { - /* Using the same GC as for the Unlock button */ - - sw = string_width (pw->button_font, pw->login_label); - - /* left aligned button */ - x1 = (pw->logo_width + pw->thermo_width + (pw->shadow_width * 3) + - pw->internal_border); - - pw->login_button_x = x1; - pw->login_button_y = y1; - } - - /* The logo - */ - x1 = pw->shadow_width * 6; - y1 = pw->shadow_width * 6; - x2 = pw->logo_width - (pw->shadow_width * 12); - y2 = pw->logo_height - (pw->shadow_width * 12); - - if (pw->logo_pixmap) - { - Window root; - int x, y; - unsigned int w, h, bw, d; - XGetGeometry (si->dpy, pw->logo_pixmap, &root, &x, &y, &w, &h, &bw, &d); - XSetForeground (si->dpy, gc1, pw->foreground); - XSetBackground (si->dpy, gc1, pw->background); - XSetClipMask (si->dpy, gc1, pw->logo_clipmask); - XSetClipOrigin (si->dpy, gc1, - x1 + ((x2 - (int)w) / 2), - y1 + ((y2 - (int)h) / 2)); - if (d == 1) - XCopyPlane (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1, - 0, 0, w, h, - x1 + ((x2 - (int)w) / 2), - y1 + ((y2 - (int)h) / 2), - 1); - else - XCopyArea (si->dpy, pw->logo_pixmap, si->passwd_dialog, gc1, - 0, 0, w, h, - x1 + ((x2 - (int)w) / 2), - y1 + ((y2 - (int)h) / 2)); - } - - /* The thermometer - */ - XSetForeground (si->dpy, gc1, pw->thermo_foreground); - XSetForeground (si->dpy, gc2, pw->thermo_background); - - pw->thermo_field_x = pw->logo_width + pw->shadow_width; - pw->thermo_field_y = pw->shadow_width * 5; - pw->thermo_field_height = pw->height - (pw->shadow_width * 10); - -#if 0 - /* Solid border inside the logo box. */ - XSetForeground (si->dpy, gc1, pw->foreground); - XDrawRectangle (si->dpy, si->passwd_dialog, gc1, x1, y1, x2-1, y2-1); -#endif - - /* The shadow around the logo - */ - draw_shaded_rectangle (si->dpy, si->passwd_dialog, - pw->shadow_width * 4, - pw->shadow_width * 4, - pw->logo_width - (pw->shadow_width * 8), - pw->logo_height - (pw->shadow_width * 8), - pw->shadow_width, - pw->shadow_bottom, pw->shadow_top); - - /* The shadow around the thermometer - */ - draw_shaded_rectangle (si->dpy, si->passwd_dialog, - pw->logo_width, - pw->shadow_width * 4, - pw->thermo_width + (pw->shadow_width * 2), - pw->height - (pw->shadow_width * 8), - pw->shadow_width, - pw->shadow_bottom, pw->shadow_top); - -#if 1 - /* Solid border inside the thermometer. */ - XSetForeground (si->dpy, gc1, pw->foreground); - XDrawRectangle (si->dpy, si->passwd_dialog, gc1, - pw->thermo_field_x, pw->thermo_field_y, - pw->thermo_width - 1, pw->thermo_field_height - 1); -#endif - - /* The shadow around the whole window - */ - draw_shaded_rectangle (si->dpy, si->passwd_dialog, - 0, 0, pw->width, pw->height, pw->shadow_width, - pw->shadow_top, pw->shadow_bottom); - - XFreeGC (si->dpy, gc1); - XFreeGC (si->dpy, gc2); - - update_passwd_window (si, pw->passwd_string, pw->ratio); -} - -static void -draw_button(Display *dpy, - Drawable dialog, - XFontStruct *font, - unsigned long foreground, unsigned long background, - char *label, - int x, int y, - int width, int height, - int shadow_width, - Pixel shadow_light, Pixel shadow_dark, - Bool button_down) -{ - XGCValues gcv; - GC gc1, gc2; - int sw; - int label_x, label_y; - - gcv.foreground = foreground; - gcv.font = font->fid; - gc1 = XCreateGC(dpy, dialog, GCForeground|GCFont, &gcv); - gcv.foreground = background; - gc2 = XCreateGC(dpy, dialog, GCForeground, &gcv); - - XFillRectangle(dpy, dialog, gc2, - x, y, width, height); - - sw = string_width(font, label); - - label_x = x + ((width - sw) / 2); - label_y = (y + (height - (font->ascent + font->descent)) / 2 + font->ascent); - - if (button_down) - { - label_x += 2; - label_y += 2; - } - - XDrawString(dpy, dialog, gc1, label_x, label_y, label, strlen(label)); - - XFreeGC(dpy, gc1); - XFreeGC(dpy, gc2); - - draw_shaded_rectangle(dpy, dialog, x, y, width, height, - shadow_width, shadow_light, shadow_dark); -} - -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; - gcv.font = pw->passwd_font->fid; - gc1 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground|GCFont, &gcv); - gcv.foreground = pw->passwd_background; - gc2 = XCreateGC (si->dpy, si->passwd_dialog, GCForeground, &gcv); - - if (printed_passwd) - { - char *s = strdup (printed_passwd); - if (pw->passwd_string) free (pw->passwd_string); - pw->passwd_string = s; - } - - if (pw->prompt_label) - { - - /* 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; - - /* The user entry (password) field is double buffered. - * This avoids flickering, particularly in synchronous mode. */ - - if (pw->passwd_changed_p) - { - pw->passwd_changed_p = False; - - if (pw->user_entry_pixmap) - { - XFreePixmap(si->dpy, pw->user_entry_pixmap); - pw->user_entry_pixmap = 0; - } - - pw->user_entry_pixmap = - XCreatePixmap (si->dpy, si->passwd_dialog, - rects[0].width, rects[0].height, - DefaultDepthOfScreen (pw->prompt_screen->screen)); - - XFillRectangle (si->dpy, pw->user_entry_pixmap, gc2, - 0, 0, rects[0].width, rects[0].height); - - XDrawString (si->dpy, pw->user_entry_pixmap, gc1, - pw->shadow_width, - pw->passwd_font->ascent, - pw->passwd_string, strlen(pw->passwd_string)); - - /* Ensure the new pixmap gets copied to the window */ - pw->i_beam = 0; - - } - - /* The I-beam - */ - if (pw->i_beam == 0) - { - /* Make the I-beam disappear */ - XCopyArea(si->dpy, pw->user_entry_pixmap, si->passwd_dialog, gc2, - 0, 0, rects[0].width, rects[0].height, - rects[0].x, rects[0].y); - } - else if (pw->i_beam == 1) - { - /* Make the I-beam appear */ - x = (rects[0].x + pw->shadow_width + - string_width (pw->passwd_font, pw->passwd_string)); - 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 + - pw->passwd_font->descent-1); - } - - pw->i_beam = (pw->i_beam + 1) % 4; - - } - - /* the thermometer - */ - y = (pw->thermo_field_height - 2) * (1.0 - pw->ratio); - if (y > 0) - { - XSetForeground (si->dpy, gc1, pw->thermo_background); - XFillRectangle (si->dpy, si->passwd_dialog, gc1, - pw->thermo_field_x + 1, - pw->thermo_field_y + 1, - pw->thermo_width-2, - y); - XSetForeground (si->dpy, gc1, pw->thermo_foreground); - XFillRectangle (si->dpy, si->passwd_dialog, gc1, - pw->thermo_field_x + 1, - pw->thermo_field_y + 1 + y, - pw->thermo_width-2, - MAX (0, pw->thermo_field_height - y - 2)); - } - - if (pw->button_state_changed_p) - { - pw->button_state_changed_p = False; - - /* The "Unlock" button - */ - draw_button(si->dpy, si->passwd_dialog, pw->button_font, - pw->button_foreground, pw->button_background, - pw->unlock_label, - pw->unlock_button_x, pw->unlock_button_y, - pw->unlock_button_width, pw->unlock_button_height, - pw->shadow_width, - (pw->unlock_button_down_p ? pw->shadow_bottom : - pw->shadow_top), - (pw->unlock_button_down_p ? pw->shadow_top : - pw->shadow_bottom), - pw->unlock_button_down_p); - - /* The "New Login" button - */ - if (pw->login_button_p) - { - draw_button(si->dpy, si->passwd_dialog, pw->button_font, - (pw->login_button_enabled_p - ? pw->passwd_foreground - : pw->shadow_bottom), - pw->button_background, - pw->login_label, - pw->login_button_x, pw->login_button_y, - pw->login_button_width, pw->login_button_height, - pw->shadow_width, - (pw->login_button_down_p - ? pw->shadow_bottom - : pw->shadow_top), - (pw->login_button_down_p - ? pw->shadow_top - : pw->shadow_bottom), - pw->login_button_down_p); - } - } - - XFreeGC (si->dpy, gc1); - XFreeGC (si->dpy, gc2); - XSync (si->dpy, False); -} - - -void -restore_background (saver_info *si) -{ - passwd_dialog_data *pw = si->pw_data; - saver_screen_info *ssi = pw->prompt_screen; - XGCValues gcv; - GC gc; - - gcv.function = GXcopy; - - gc = XCreateGC (si->dpy, ssi->screensaver_window, GCFunction, &gcv); - - XCopyArea (si->dpy, pw->save_under, - ssi->screensaver_window, gc, - 0, 0, - ssi->width, ssi->height, - 0, 0); - - XFreeGC (si->dpy, gc); -} - - -/* Frees anything created by make_passwd_window */ -static void -cleanup_passwd_window (saver_info *si) -{ - passwd_dialog_data *pw; - - if (!(pw = si->pw_data)) - return; - - if (pw->info_label) - { - mlstring_free(pw->info_label); - pw->info_label = 0; - } - - if (pw->prompt_label) - { - mlstring_free(pw->prompt_label); - pw->prompt_label = 0; - } - - memset (pw->typed_passwd, 0, sizeof(pw->typed_passwd)); - memset (pw->typed_passwd_char_size, 0, sizeof(pw->typed_passwd_char_size)); - memset (pw->passwd_string, 0, strlen(pw->passwd_string)); - - if (pw->timer) - { - XtRemoveTimeOut (pw->timer); - pw->timer = 0; - } - - if (pw->user_entry_pixmap) - { - XFreePixmap(si->dpy, pw->user_entry_pixmap); - pw->user_entry_pixmap = 0; - } -} - - -static void -destroy_passwd_window (saver_info *si) -{ - saver_preferences *p = &si->prefs; - passwd_dialog_data *pw = si->pw_data; - saver_screen_info *ssi = pw->prompt_screen; - Colormap cmap = DefaultColormapOfScreen (ssi->screen); - Pixel black = BlackPixelOfScreen (ssi->screen); - Pixel white = WhitePixelOfScreen (ssi->screen); - XEvent event; - - cleanup_passwd_window (si); - - if (si->cached_passwd) - { - char *wipe = si->cached_passwd; - - while (*wipe) - *wipe++ = '\0'; - - free(si->cached_passwd); - si->cached_passwd = NULL; - } - - move_mouse_grab (si, RootWindowOfScreen (ssi->screen), - ssi->cursor, ssi->number); - - if (pw->passwd_cursor) - XFreeCursor (si->dpy, pw->passwd_cursor); - - if (p->verbose_p) - fprintf (stderr, "%s: %d: moving mouse back to %d,%d.\n", - blurb(), ssi->number, - pw->previous_mouse_x, pw->previous_mouse_y); - - XWarpPointer (si->dpy, None, RootWindowOfScreen (ssi->screen), - 0, 0, 0, 0, - pw->previous_mouse_x, pw->previous_mouse_y); - XSync (si->dpy, False); - - while (XCheckMaskEvent (si->dpy, PointerMotionMask, &event)) - if (p->verbose_p) - fprintf (stderr, "%s: discarding MotionNotify event.\n", blurb()); - -#ifdef HAVE_XINPUT - if (si->using_xinput_extension && si->xinput_DeviceMotionNotify) - while (XCheckTypedEvent (si->dpy, si->xinput_DeviceMotionNotify, &event)) - if (p->verbose_p) - fprintf (stderr, "%s: discarding DeviceMotionNotify event.\n", - blurb()); -#endif - - if (si->passwd_dialog) - { - if (si->prefs.verbose_p) - fprintf (stderr, "%s: %d: destroying password dialog.\n", - blurb(), pw->prompt_screen->number); - - XDestroyWindow (si->dpy, si->passwd_dialog); - si->passwd_dialog = 0; - } - - if (pw->save_under) - { - restore_background(si); - XFreePixmap (si->dpy, pw->save_under); - pw->save_under = 0; - } - - if (pw->heading_label) free (pw->heading_label); - if (pw->body_label) free (pw->body_label); - if (pw->user_label) free (pw->user_label); - if (pw->date_label) free (pw->date_label); - if (pw->login_label) free (pw->login_label); - if (pw->unlock_label) free (pw->unlock_label); - if (pw->passwd_string) free (pw->passwd_string); - if (pw->uname_label) free (pw->uname_label); - - if (pw->heading_font) XFreeFont (si->dpy, pw->heading_font); - if (pw->body_font) XFreeFont (si->dpy, pw->body_font); - if (pw->label_font) XFreeFont (si->dpy, pw->label_font); - if (pw->passwd_font) XFreeFont (si->dpy, pw->passwd_font); - if (pw->date_font) XFreeFont (si->dpy, pw->date_font); - if (pw->button_font) XFreeFont (si->dpy, pw->button_font); - if (pw->uname_font) XFreeFont (si->dpy, pw->uname_font); - - if (pw->foreground != black && pw->foreground != white) - XFreeColors (si->dpy, cmap, &pw->foreground, 1, 0L); - if (pw->background != black && pw->background != white) - XFreeColors (si->dpy, cmap, &pw->background, 1, 0L); - if (!(pw->button_foreground == black || pw->button_foreground == white)) - XFreeColors (si->dpy, cmap, &pw->button_foreground, 1, 0L); - if (!(pw->button_background == black || pw->button_background == white)) - XFreeColors (si->dpy, cmap, &pw->button_background, 1, 0L); - if (pw->passwd_foreground != black && pw->passwd_foreground != white) - XFreeColors (si->dpy, cmap, &pw->passwd_foreground, 1, 0L); - if (pw->passwd_background != black && pw->passwd_background != white) - XFreeColors (si->dpy, cmap, &pw->passwd_background, 1, 0L); - if (pw->thermo_foreground != black && pw->thermo_foreground != white) - XFreeColors (si->dpy, cmap, &pw->thermo_foreground, 1, 0L); - if (pw->thermo_background != black && pw->thermo_background != white) - XFreeColors (si->dpy, cmap, &pw->thermo_background, 1, 0L); - if (pw->shadow_top != black && pw->shadow_top != white) - XFreeColors (si->dpy, cmap, &pw->shadow_top, 1, 0L); - if (pw->shadow_bottom != black && pw->shadow_bottom != white) - XFreeColors (si->dpy, cmap, &pw->shadow_bottom, 1, 0L); - - if (pw->logo_pixmap) - XFreePixmap (si->dpy, pw->logo_pixmap); - if (pw-> logo_clipmask) - XFreePixmap (si->dpy, pw->logo_clipmask); - if (pw->logo_pixels) - { - if (pw->logo_npixels) - XFreeColors (si->dpy, cmap, pw->logo_pixels, pw->logo_npixels, 0L); - free (pw->logo_pixels); - pw->logo_pixels = 0; - pw->logo_npixels = 0; - } - - if (pw->save_under) - XFreePixmap (si->dpy, pw->save_under); - - if (cmap) - XInstallColormap (si->dpy, cmap); - - memset (pw, 0, sizeof(*pw)); - free (pw); - si->pw_data = 0; - - si->unlock_dismiss_time = time((time_t *) 0); -} - - -#if defined(HAVE_XF86MISCSETGRABKEYSSTATE) || defined(HAVE_XF86VMODE) - -static Bool error_handler_hit_p = False; - -static int -ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error) -{ - error_handler_hit_p = True; - return 0; -} - -#endif /* HAVE_XF86MISCSETGRABKEYSSTATE || HAVE_XF86VMODE */ - - -#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 */ - - -#ifdef HAVE_XF86MISCSETGRABKEYSSTATE - -/* This function enables and disables the Ctrl-Alt-KP_star and - Ctrl-Alt-KP_slash hot-keys, which (in XFree86 4.2) break any - grabs and/or kill the grabbing client. That would effectively - unlock the screen, so we don't like that. - - The Ctrl-Alt-KP_star and Ctrl-Alt-KP_slash hot-keys only exist - if AllowDeactivateGrabs and/or AllowClosedownGrabs are turned on - in XF86Config. I believe they are disabled by default. - - This does not affect any other keys (specifically Ctrl-Alt-BS or - Ctrl-Alt-F1) but I wish it did. Maybe it will someday. - */ -static void -xfree_lock_grab_smasher (saver_info *si, Bool lock_p) -{ - saver_preferences *p = &si->prefs; - int status; - int event, error; - XErrorHandler old_handler; - - if (!XF86MiscQueryExtension(si->dpy, &event, &error)) - return; - - XSync (si->dpy, False); - error_handler_hit_p = False; - old_handler = XSetErrorHandler (ignore_all_errors_ehandler); - XSync (si->dpy, False); - status = XF86MiscSetGrabKeysState (si->dpy, !lock_p); - XSync (si->dpy, False); - if (error_handler_hit_p) status = 666; - - if (!lock_p && status == MiscExtGrabStateAlready) - status = MiscExtGrabStateSuccess; /* shut up, consider this success */ - - if (p->verbose_p && status != MiscExtGrabStateSuccess) - fprintf (stderr, "%s: error: XF86MiscSetGrabKeysState(%d) returned %s\n", - blurb(), !lock_p, - (status == MiscExtGrabStateSuccess ? "MiscExtGrabStateSuccess" : - status == MiscExtGrabStateLocked ? "MiscExtGrabStateLocked" : - status == MiscExtGrabStateAlready ? "MiscExtGrabStateAlready" : - status == 666 ? "an X error" : - "unknown value")); - - XSync (si->dpy, False); - XSetErrorHandler (old_handler); - XSync (si->dpy, False); -} -#endif /* HAVE_XF86MISCSETGRABKEYSSTATE */ - - - -/* 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 void -xfree_lock_mode_switch (saver_info *si, Bool lock_p) -{ - static Bool any_mode_locked_p = False; - saver_preferences *p = &si->prefs; - int screen; - int real_nscreens = ScreenCount (si->dpy); - int event, error; - Bool status; - XErrorHandler old_handler; - - if (any_mode_locked_p == lock_p) - return; - if (!XF86VidModeQueryExtension (si->dpy, &event, &error)) - return; - - for (screen = 0; screen < real_nscreens; screen++) - { - XSync (si->dpy, False); - old_handler = XSetErrorHandler (ignore_all_errors_ehandler); - error_handler_hit_p = False; - status = XF86VidModeLockModeSwitch (si->dpy, screen, lock_p); - XSync (si->dpy, False); - XSetErrorHandler (old_handler); - if (error_handler_hit_p) status = False; - - if (status) - any_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: %d: unable to %s mode switching!\n", - blurb(), screen, (lock_p ? "lock" : "unlock")); - else if (p->verbose_p) - fprintf (stderr, "%s: %d: %s mode switching.\n", - blurb(), screen, (lock_p ? "locked" : "unlocked")); - } -} -#endif /* HAVE_XF86VMODE */ - - -/* 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; - int real_nscreens = ScreenCount (si->dpy); - int event, error; - - if (!XF86VidModeQueryExtension (si->dpy, &event, &error)) - return; - - for (screen = 0; screen < real_nscreens; screen++) - { - saver_screen_info *ssi = &si->screens[screen]; - int x, y; - Bool status; - - if (ssi->blank_vp_x == -1 && ssi->blank_vp_y == -1) - break; - if (!XF86VidModeGetViewPort (si->dpy, screen, &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: %d: unable to move vp from (%d,%d) back to (%d,%d)!\n", - blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y); - else if (p->verbose_p) - fprintf (stderr, - "%s: %d: vp moved to (%d,%d); moved it back to (%d,%d).\n", - blurb(), screen, x, y, ssi->blank_vp_x, ssi->blank_vp_y); - } -#endif /* HAVE_XF86VMODE */ -} - - - -/* Interactions - */ - -static void -passwd_animate_timer (XtPointer closure, XtIntervalId *id) -{ - saver_info *si = (saver_info *) closure; - int tick = 166; - passwd_dialog_data *pw = si->pw_data; - - if (!pw) return; - - pw->ratio -= (1.0 / ((double) si->prefs.passwd_timeout / (double) tick)); - if (pw->ratio < 0) - { - pw->ratio = 0; - if (si->unlock_state == ul_read) - si->unlock_state = ul_time; - } - - update_passwd_window (si, 0, pw->ratio); - - if (si->unlock_state == ul_read) - pw->timer = XtAppAddTimeOut (si->app, tick, passwd_animate_timer, - (XtPointer) si); - else - pw->timer = 0; - - idle_timer ((XtPointer) si, 0); -} - - -static XComposeStatus *compose_status; - -static void -handle_login_button (saver_info *si, XEvent *event) -{ - saver_preferences *p = &si->prefs; - Bool mouse_in_box = False; - Bool hit_p = False; - passwd_dialog_data *pw = si->pw_data; - saver_screen_info *ssi = pw->prompt_screen; - - if (! pw->login_button_enabled_p) - return; - - mouse_in_box = - (event->xbutton.x >= pw->login_button_x && - event->xbutton.x <= pw->login_button_x + pw->login_button_width && - event->xbutton.y >= pw->login_button_y && - event->xbutton.y <= pw->login_button_y + pw->login_button_height); - - if (ButtonRelease == event->xany.type && - pw->login_button_down_p && - mouse_in_box) - { - /* Only allow them to press the button once: don't want to - accidentally launch a dozen gdm choosers if the machine - is being slow. - */ - hit_p = True; - pw->login_button_enabled_p = False; - } - - pw->login_button_down_p = (mouse_in_box && - ButtonRelease != event->xany.type); - - update_passwd_window (si, 0, pw->ratio); - - if (hit_p) - fork_and_exec (ssi, p->new_login_command); -} - - -static void -handle_unlock_button (saver_info *si, XEvent *event) -{ - Bool mouse_in_box = False; - passwd_dialog_data *pw = si->pw_data; - - mouse_in_box = - (event->xbutton.x >= pw->unlock_button_x && - event->xbutton.x <= pw->unlock_button_x + pw->unlock_button_width && - event->xbutton.y >= pw->unlock_button_y && - event->xbutton.y <= pw->unlock_button_y + pw->unlock_button_height); - - if (ButtonRelease == event->xany.type && - pw->unlock_button_down_p && - mouse_in_box) - finished_typing_passwd (si, pw); - - pw->unlock_button_down_p = (mouse_in_box && - ButtonRelease != event->xany.type); -} - - -static void -finished_typing_passwd (saver_info *si, passwd_dialog_data *pw) -{ - if (si->unlock_state == ul_read) - { - update_passwd_window (si, "Checking...", pw->ratio); - XSync (si->dpy, False); - - si->unlock_state = ul_finished; - update_passwd_window (si, "", pw->ratio); - } -} - -static void -handle_passwd_key (saver_info *si, XKeyEvent *event) -{ - passwd_dialog_data *pw = si->pw_data; - unsigned char decoded [MAX_BYTES_PER_CHAR * 10]; /* leave some slack */ - KeySym keysym = 0; - - /* XLookupString may return more than one character via XRebindKeysym; - and on some systems it returns multi-byte UTF-8 characters (contrary - to its documentation, which says it returns only Latin1.) - - It seems to only do so, however, if setlocale() has been called. - See the code inside ENABLE_NLS in xscreensaver.c. - */ - int decoded_size = XLookupString (event, (char *)decoded, sizeof(decoded), - &keysym, compose_status); - -#if 0 - { - const char *ks = XKeysymToString (keysym); - int i; - fprintf(stderr, "## %-12s\t=> %d\t", (ks ? ks : "(null)"), decoded_size); - for (i = 0; i < decoded_size; i++) - fprintf(stderr, "%c", decoded[i]); - fprintf(stderr, "\t"); - for (i = 0; i < decoded_size; i++) - fprintf(stderr, "\\%03o", ((unsigned char *)decoded)[i]); - fprintf(stderr, "\n"); - } -#endif - - if (decoded_size > MAX_BYTES_PER_CHAR) - { - /* The multi-byte character returned is too large. */ - XBell (si->dpy, 0); - return; - } - - decoded[decoded_size] = 0; - pw->passwd_changed_p = True; - - /* Add 10% to the time remaining every time a key is pressed. */ - pw->ratio += 0.1; - if (pw->ratio > 1) pw->ratio = 1; - - if (decoded_size == 1) /* Handle single-char commands */ - { - switch (*decoded) - { - case '\010': case '\177': /* Backspace */ - { - /* kludgey way to get the number of "logical" characters. */ - int nchars = strlen (pw->typed_passwd_char_size); - int nbytes = strlen (pw->typed_passwd); - if (nbytes <= 0) - XBell (si->dpy, 0); - else - { - int i; - for (i = pw->typed_passwd_char_size[nchars-1]; i >= 0; i--) - { - if (nbytes < 0) abort(); - pw->typed_passwd[nbytes--] = 0; - } - pw->typed_passwd_char_size[nchars-1] = 0; - } - } - break; - - case '\012': case '\015': /* Enter */ - finished_typing_passwd (si, pw); - break; - - case '\033': /* Escape */ - si->unlock_state = ul_cancel; - break; - - case '\025': case '\030': /* Erase line */ - memset (pw->typed_passwd, 0, sizeof (pw->typed_passwd)); - memset (pw->typed_passwd_char_size, 0, - sizeof (pw->typed_passwd_char_size)); - break; - - default: - if (*decoded < ' ' && *decoded != '\t') /* Other ctrl char */ - XBell (si->dpy, 0); - else - goto SELF_INSERT; - break; - } - } - else - { - int nbytes, nchars; - SELF_INSERT: - nbytes = strlen (pw->typed_passwd); - nchars = strlen (pw->typed_passwd_char_size); - if (nchars + 1 >= sizeof (pw->typed_passwd_char_size)-1 || - nbytes + decoded_size >= sizeof (pw->typed_passwd)-1) /* overflow */ - XBell (si->dpy, 0); - else - { - pw->typed_passwd_char_size[nchars] = decoded_size; - pw->typed_passwd_char_size[nchars+1] = 0; - memcpy (pw->typed_passwd + nbytes, decoded, decoded_size); - pw->typed_passwd[nbytes + decoded_size] = 0; - } - } - - if (pw->echo_input) - { - /* If the input is wider than the text box, only show the last portion, - to simulate a horizontally-scrolling text field. */ - int chars_in_pwfield = (pw->passwd_field_width / - pw->passwd_font->max_bounds.width); - const char *output = pw->typed_passwd; - if (strlen(output) > chars_in_pwfield) - output += (strlen(output) - chars_in_pwfield); - update_passwd_window (si, output, pw->ratio); - } - else if (pw->show_stars_p) - { - int nchars = strlen (pw->typed_passwd_char_size); - char *stars = 0; - stars = (char *) malloc(nchars + 1); - memset (stars, '*', nchars); - stars[nchars] = 0; - update_passwd_window (si, stars, pw->ratio); - free (stars); - } - else - { - update_passwd_window (si, "", pw->ratio); - } -} - - -static void -passwd_event_loop (saver_info *si) -{ - saver_preferences *p = &si->prefs; - char *msg = 0; - - /* We have to go through this union bullshit because gcc-4.4.0 has - stricter struct-aliasing rules. Without this, the optimizer - can fuck things up. - */ - union { - XEvent x_event; -# ifdef HAVE_RANDR - XRRScreenChangeNotifyEvent xrr_event; -# endif /* HAVE_RANDR */ - } event; - - passwd_animate_timer ((XtPointer) si, 0); - reset_watchdog_timer (si, False); /* Disable watchdog while dialog up */ - - while (si->unlock_state == ul_read) - { - XtAppNextEvent (si->app, &event.x_event); - -#ifdef HAVE_RANDR - if (si->using_randr_extension && - (event.x_event.type == - (si->randr_event_number + RRScreenChangeNotify))) - { - /* The Resize and Rotate extension sends an event when the - size, rotation, or refresh rate of any screen has changed. */ - - if (p->verbose_p) - { - /* XRRRootToScreen is in Xrandr.h 1.4, 2001/06/07 */ - int screen = XRRRootToScreen(si->dpy, event.xrr_event.window); - fprintf (stderr, "%s: %d: screen change event received\n", - blurb(), screen); - } - -#ifdef RRScreenChangeNotifyMask - /* Inform Xlib that it's ok to update its data structures. */ - XRRUpdateConfiguration(&event.x_event); /* Xrandr.h 1.9, 2002/09/29*/ -#endif /* RRScreenChangeNotifyMask */ - - /* Resize the existing xscreensaver windows and cached ssi data. */ - if (update_screen_layout (si)) - { - if (p->verbose_p) - { - fprintf (stderr, "%s: new layout:\n", blurb()); - describe_monitor_layout (si); - } - resize_screensaver_window (si); - } - } - else -#endif /* HAVE_RANDR */ - - if (event.x_event.xany.window == si->passwd_dialog && - event.x_event.xany.type == Expose) - draw_passwd_window (si); - else if (event.x_event.xany.type == KeyPress) - { - handle_passwd_key (si, &event.x_event.xkey); - si->pw_data->caps_p = (event.x_event.xkey.state & LockMask); - } - else if (event.x_event.xany.type == ButtonPress || - event.x_event.xany.type == ButtonRelease) - { - si->pw_data->button_state_changed_p = True; - handle_unlock_button (si, &event.x_event); - if (si->pw_data->login_button_p) - handle_login_button (si, &event.x_event); - } - else - XtDispatchEvent (&event.x_event); - } - - switch (si->unlock_state) - { - case ul_cancel: msg = ""; break; - case ul_time: msg = "Timed out!"; break; - case ul_finished: msg = "Checking..."; break; - default: msg = 0; break; - } - - if (p->verbose_p) - switch (si->unlock_state) { - case ul_cancel: - fprintf (stderr, "%s: input cancelled.\n", blurb()); break; - case ul_time: - fprintf (stderr, "%s: input timed out.\n", blurb()); break; - case ul_finished: - fprintf (stderr, "%s: input finished.\n", blurb()); break; - default: break; - } - - if (msg) - { - si->pw_data->i_beam = 0; - update_passwd_window (si, msg, 0.0); - XSync (si->dpy, False); - - /* Swallow all pending KeyPress/KeyRelease events. */ - { - XEvent e; - while (XCheckMaskEvent (si->dpy, KeyPressMask|KeyReleaseMask, &e)) - ; - } - } - - reset_watchdog_timer (si, True); /* Re-enable watchdog */ -} - - -static void -handle_typeahead (saver_info *si) -{ - passwd_dialog_data *pw = si->pw_data; - int i; - if (!si->unlock_typeahead) - return; - - pw->passwd_changed_p = True; - - i = strlen (si->unlock_typeahead); - if (i >= sizeof(pw->typed_passwd) - 1) - i = sizeof(pw->typed_passwd) - 1; - - memcpy (pw->typed_passwd, si->unlock_typeahead, i); - pw->typed_passwd [i] = 0; - { - int j; - char *c = pw->typed_passwd_char_size; - for (j = 0; j < i; j++) - *c++ = 1; - *c = 0; - } - - memset (si->unlock_typeahead, '*', strlen(si->unlock_typeahead)); - si->unlock_typeahead[i] = 0; - update_passwd_window (si, si->unlock_typeahead, pw->ratio); - - free (si->unlock_typeahead); - si->unlock_typeahead = 0; -} - - -/** - * Returns a copy of the input string with trailing whitespace removed. - * Whitespace is anything considered so by isspace(). - * It is safe to call this with NULL, in which case NULL will be returned. - * The returned string (if not NULL) should be freed by the caller with free(). - */ -static char * -remove_trailing_whitespace(const char *str) -{ - size_t len; - char *newstr, *chr; - - if (!str) - return NULL; - - len = strlen(str); - - newstr = malloc(len + 1); - if (!newstr) - return NULL; - - (void) strcpy(newstr, str); - chr = newstr + len; - while (isspace(*--chr) && chr >= newstr) - *chr = '\0'; - - return newstr; -} - - -/* - * The authentication conversation function. - * Like a PAM conversation function, this accepts multiple messages in a single - * round. It then splits them into individual messages for display on the - * passwd dialog. A message sequence of info or error followed by a prompt will - * be reduced into a single dialog window. - * - * Returns 0 on success or -1 if some problem occurred (cancelled, OOM, etc.) - */ -int -gui_auth_conv(int num_msg, - const struct auth_message auth_msgs[], - struct auth_response **resp, - saver_info *si) -{ - int i; - const char *info_msg, *prompt; - struct auth_response *responses; - - if (si->unlock_state == ul_cancel || - si->unlock_state == ul_time) - /* If we've already cancelled or timed out in this PAM conversation, - don't prompt again even if PAM asks us to! */ - return -1; - - if (!(responses = calloc(num_msg, sizeof(struct auth_response)))) - goto fail; - - for (i = 0; i < num_msg; ++i) - { - info_msg = prompt = NULL; - - /* See if there is a following message that can be shown at the same - * time */ - if (auth_msgs[i].type == AUTH_MSGTYPE_INFO - && i+1 < num_msg - && ( auth_msgs[i+1].type == AUTH_MSGTYPE_PROMPT_NOECHO - || auth_msgs[i+1].type == AUTH_MSGTYPE_PROMPT_ECHO) - ) - { - info_msg = auth_msgs[i].msg; - prompt = auth_msgs[++i].msg; - } - else - { - if ( auth_msgs[i].type == AUTH_MSGTYPE_INFO - || auth_msgs[i].type == AUTH_MSGTYPE_ERROR) - info_msg = auth_msgs[i].msg; - else - prompt = auth_msgs[i].msg; - } - - { - char *info_msg_trimmed, *prompt_trimmed; - - /* Trailing whitespace looks bad in a GUI */ - info_msg_trimmed = remove_trailing_whitespace(info_msg); - prompt_trimmed = remove_trailing_whitespace(prompt); - - if (make_passwd_window(si, info_msg_trimmed, prompt_trimmed, - auth_msgs[i].type == AUTH_MSGTYPE_PROMPT_ECHO - ? True : False) - < 0) - goto fail; - - if (info_msg_trimmed) - free(info_msg_trimmed); - - if (prompt_trimmed) - free(prompt_trimmed); - } - - compose_status = calloc (1, sizeof (*compose_status)); - if (!compose_status) - goto fail; - - si->unlock_state = ul_read; - - handle_typeahead (si); - passwd_event_loop (si); - - if (si->unlock_state == ul_cancel) - goto fail; - - responses[i].response = strdup(si->pw_data->typed_passwd); - - /* Cache the first response to a PROMPT_NOECHO to save prompting for - * each auth mechanism. */ - if (si->cached_passwd == NULL && - auth_msgs[i].type == AUTH_MSGTYPE_PROMPT_NOECHO) - si->cached_passwd = strdup(responses[i].response); - - free (compose_status); - compose_status = 0; - } - - *resp = responses; - - return (si->unlock_state == ul_finished) ? 0 : -1; - -fail: - if (compose_status) - free (compose_status); - compose_status = 0; - - if (responses) - { - for (i = 0; i < num_msg; ++i) - if (responses[i].response) - free (responses[i].response); - free (responses); - } - - return -1; -} - - -void -auth_finished_cb (saver_info *si) -{ - char buf[1024]; - const char *s; - - /* If we have something to say, put the dialog back up for a few seconds - to display it. Otherwise, don't bother. - */ - - if (si->unlock_state == ul_fail && /* failed with caps lock on */ - si->pw_data && si->pw_data->caps_p) - s = "Authentication failed (Caps Lock?)"; - else if (si->unlock_state == ul_fail) /* failed without caps lock */ - s = "Authentication failed!"; - else if (si->unlock_state == ul_success && /* good, but report failures */ - si->unlock_failures > 0) - { - if (si->unlock_failures == 1) - s = "There has been\n1 failed login attempt."; - else - { - sprintf (buf, "There have been\n%d failed login attempts.", - si->unlock_failures); - s = buf; - } - si->unlock_failures = 0; - - /* ignore failures if they all were too recent */ - if (time((time_t *) 0) - si->unlock_failure_time - < si->prefs.auth_warning_slack) - goto END; - } - else /* good, with no failures, */ - goto END; /* or timeout, or cancel. */ - - make_passwd_window (si, s, NULL, True); - XSync (si->dpy, False); - - { - int secs = 4; - time_t start = time ((time_t *) 0); - XEvent event; - while (time ((time_t *) 0) < start + secs) - if (XPending (si->dpy)) - { - XNextEvent (si->dpy, &event); - 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) - break; - XSync (si->dpy, False); - } - else - usleep (250000); /* 1/4 second */ - } - - END: - if (si->pw_data) - destroy_passwd_window (si); -} - - -Bool -unlock_p (saver_info *si) -{ - saver_preferences *p = &si->prefs; - time_t now = time ((time_t *) 0); - - if (!si->unlock_cb) - { - fprintf(stderr, "%s: Error: no unlock function specified!\n", blurb()); - return False; - } - - raise_window (si, True, True, True); - - /* If your cat is sitting on the return key, don't thrash the window. - Only one failed/cancelled unlock per 2 seconds. - */ - if (si->unlock_dismiss_time >= now - 1) - { - if (p->verbose_p) - fprintf (stderr, "%s: unlock: thrashing: RET held down?\n", blurb()); - XSync (si->dpy, False); -# undef sleep - sleep (2); /* This is less than ideal, but fine */ - } - - xss_authenticate(si, p->verbose_p); - - return (si->unlock_state == ul_success); -} - - -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_XF86VMODE - xfree_lock_mode_switch (si, locked_p); /* turn off/on C-Alt-Plus */ -#endif -#ifdef HAVE_XF86MISCSETGRABKEYSSTATE - xfree_lock_grab_smasher (si, locked_p); /* turn off/on C-Alt-KP-*,/ */ -#endif - - store_saver_status (si); /* store locked-p */ -} - - -#else /* NO_LOCKING -- whole file */ - -void -set_locked_p (saver_info *si, Bool locked_p) -{ - if (locked_p) abort(); -} - -#endif /* !NO_LOCKING */ |