X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=driver%2Flock.c;h=277cfc3c21f27c67a0c15b63511a5bd32413097f;hb=a94197e76a5dea5cb60542840809d6c20d0abbf3;hp=6d498b199fdf835ff38172ca05c0a1ac33edfe3c;hpb=5832fe184606766fef23369159306c0a5799aeb0;p=xscreensaver diff --git a/driver/lock.c b/driver/lock.c index 6d498b19..277cfc3c 100644 --- a/driver/lock.c +++ b/driver/lock.c @@ -17,13 +17,15 @@ # include "config.h" #endif -#ifndef NO_LOCKING /* whole file */ - #include #include /* for time() */ +#include +#include #include "xscreensaver.h" #include "resources.h" +#ifndef NO_LOCKING /* (mostly) whole file */ + #ifdef HAVE_SYSLOG # include #endif /* HAVE_SYSLOG */ @@ -75,6 +77,9 @@ enum passwd_state { pw_read, pw_ok, pw_null, pw_fail, pw_cancel, pw_time }; struct passwd_dialog_data { + saver_screen_info *prompt_screen; + int previous_mouse_x, previous_mouse_y; + enum passwd_state state; char typed_passwd [80]; XtIntervalId timer; @@ -104,8 +109,8 @@ struct passwd_dialog_data { Pixel background; Pixel passwd_foreground; Pixel passwd_background; - Pixel logo_foreground; - Pixel logo_background; + Pixel thermo_foreground; + Pixel thermo_background; Pixel shadow_top; Pixel shadow_bottom; @@ -121,6 +126,10 @@ struct passwd_dialog_data { Dimension thermo_field_x, thermo_field_y; Dimension thermo_field_height; + Pixmap logo_pixmap; + int logo_npixels; + unsigned long *logo_pixels; + Pixmap save_under; }; @@ -137,11 +146,19 @@ make_passwd_window (saver_info *si) struct passwd *p = getpwuid (getuid ()); XSetWindowAttributes attrs; unsigned long attrmask = 0; - Screen *screen = si->default_screen->screen; passwd_dialog_data *pw = (passwd_dialog_data *) calloc (1, sizeof(*pw)); - Colormap cmap = DefaultColormapOfScreen (screen); + Screen *screen; + Colormap cmap; char *f; + pw->prompt_screen = &si->screens [mouse_screen (si)]; + if (si->prefs.verbose_p) + fprintf (stderr, "%s: %d: creating password dialog.\n", + blurb(), pw->prompt_screen->number); + + screen = pw->prompt_screen->screen; + cmap = DefaultColormapOfScreen (screen); + pw->ratio = 1.0; pw->heading_label = get_string_resource ("passwd.heading.label", @@ -170,7 +187,7 @@ make_passwd_window (saver_info *si) pw->heading_label = s; } - pw->user_string = (p->pw_name ? p->pw_name : "???"); + pw->user_string = (p && p->pw_name ? p->pw_name : "???"); pw->passwd_string = strdup(""); f = get_string_resource ("passwd.headingFont", "Dialog.Font"); @@ -218,12 +235,12 @@ make_passwd_window (saver_info *si) pw->passwd_background = get_pixel_resource ("passwd.text.background", "Dialog.Text.Background", si->dpy, cmap); - pw->logo_foreground = get_pixel_resource ("passwd.logo.foreground", - "Dialog.Logo.Foreground", - si->dpy, cmap); - pw->logo_background = get_pixel_resource ("passwd.logo.background", - "Dialog.Logo.Background", - si->dpy, cmap); + pw->thermo_foreground = get_pixel_resource ("passwd.thermometer.foreground", + "Dialog.Thermometer.Foreground", + si->dpy, cmap); + pw->thermo_background = get_pixel_resource ("passwd.thermometer.background", + "Dialog.Thermometer.Background", + si->dpy, cmap); pw->shadow_top = get_pixel_resource ("passwd.topShadowColor", "Dialog.Foreground", si->dpy, cmap); @@ -331,9 +348,40 @@ make_passwd_window (saver_info *si) attrmask |= CWOverrideRedirect; attrs.override_redirect = True; attrmask |= CWEventMask; attrs.event_mask = ExposureMask|KeyPressMask; + /* 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); + } + + /* 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. */ { int x, y, w, h; - get_screen_viewport (si->default_screen, &x, &y, &w, &h, False); + get_screen_viewport (pw->prompt_screen, &x, &y, &w, &h, + pw->previous_mouse_x, pw->previous_mouse_y, + si->prefs.verbose_p); 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; @@ -353,6 +401,10 @@ make_passwd_window (saver_info *si) attrmask, &attrs); XSetWindowBackground (si->dpy, si->passwd_dialog, pw->background); + pw->logo_pixmap = xscreensaver_logo (si->dpy, si->passwd_dialog, cmap, + pw->background, + &pw->logo_pixels, &pw->logo_npixels, + 0, True); /* Before mapping the window, save the bits that are underneath the rectangle the window will occlude. When we lower the window, we @@ -363,13 +415,13 @@ make_passwd_window (saver_info *si) XGCValues gcv; GC gc; pw->save_under = XCreatePixmap (si->dpy, - si->default_screen->screensaver_window, + pw->prompt_screen->screensaver_window, pw->width + (pw->border_width*2) + 1, pw->height + (pw->border_width*2) + 1, - si->default_screen->current_depth); + pw->prompt_screen->current_depth); gcv.function = GXcopy; gc = XCreateGC (si->dpy, pw->save_under, GCFunction, &gcv); - XCopyArea (si->dpy, si->default_screen->screensaver_window, + XCopyArea (si->dpy, pw->prompt_screen->screensaver_window, pw->save_under, gc, pw->x - pw->border_width, pw->y - pw->border_width, pw->width + (pw->border_width*2) + 1, @@ -381,11 +433,15 @@ make_passwd_window (saver_info *si) XMapRaised (si->dpy, si->passwd_dialog); XSync (si->dpy, False); - move_mouse_grab (si, si->passwd_dialog, si->screens[0].cursor); + move_mouse_grab (si, si->passwd_dialog, + pw->prompt_screen->cursor, + pw->prompt_screen->number); undo_vp_motion (si); si->pw_data = pw; + if (cmap) + XInstallColormap (si->dpy, cmap); draw_passwd_window (si); XSync (si->dpy, False); } @@ -536,38 +592,56 @@ draw_passwd_window (saver_info *si) } - /* the logo + /* The logo */ - XSetForeground (si->dpy, gc1, pw->logo_foreground); - XSetForeground (si->dpy, gc2, pw->logo_background); - - x1 = pw->shadow_width * 3; - y1 = pw->shadow_width * 3; - x2 = pw->logo_width - (pw->shadow_width * 6); - y2 = pw->logo_height - (pw->shadow_width * 6); + 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); - XFillRectangle (si->dpy, si->passwd_dialog, gc2, x1, y1, x2, y2); - skull (si->dpy, si->passwd_dialog, gc1, gc2, - x1 + pw->shadow_width, y1 + pw->shadow_width, - x2 - (pw->shadow_width * 2), y2 - (pw->shadow_width * 2)); + 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); + 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 * 3; - pw->thermo_field_height = pw->height - (pw->shadow_width * 6); + 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 * 2, - pw->shadow_width * 2, - pw->logo_width - (pw->shadow_width * 4), - pw->logo_height - (pw->shadow_width * 4), + 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); @@ -575,19 +649,19 @@ draw_passwd_window (saver_info *si) */ draw_shaded_rectangle (si->dpy, si->passwd_dialog, pw->logo_width, - pw->shadow_width * 2, + pw->shadow_width * 4, pw->thermo_width + (pw->shadow_width * 2), - pw->height - (pw->shadow_width * 4), + 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->logo_width + pw->shadow_width, - pw->shadow_width * 3, - pw->thermo_width - 1, - pw->height - (pw->shadow_width * 6) - 1); + pw->thermo_field_x, pw->thermo_field_y, + pw->thermo_width - 1, pw->thermo_field_height - 1); +#endif /* The shadow around the whole window */ @@ -664,7 +738,7 @@ update_passwd_window (saver_info *si, const char *printed_passwd, float ratio) /* the thermometer */ - y = pw->thermo_field_height * (1.0 - pw->ratio); + y = (pw->thermo_field_height - 2) * (1.0 - pw->ratio); if (y > 0) { XFillRectangle (si->dpy, si->passwd_dialog, gc2, @@ -672,7 +746,7 @@ update_passwd_window (saver_info *si, const char *printed_passwd, float ratio) pw->thermo_field_y + 1, pw->thermo_width-2, y); - XSetForeground (si->dpy, gc1, pw->logo_foreground); + 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, @@ -689,17 +763,33 @@ update_passwd_window (saver_info *si, const char *printed_passwd, float ratio) static void destroy_passwd_window (saver_info *si) { + saver_preferences *p = &si->prefs; passwd_dialog_data *pw = si->pw_data; - Screen *screen = si->default_screen->screen; - Colormap cmap = DefaultColormapOfScreen (screen); - Pixel black = BlackPixelOfScreen (screen); - Pixel white = WhitePixelOfScreen (screen); + saver_screen_info *ssi = pw->prompt_screen; + Colormap cmap = DefaultColormapOfScreen (ssi->screen); + Pixel black = BlackPixelOfScreen (ssi->screen); + Pixel white = WhitePixelOfScreen (ssi->screen); + XEvent event; if (pw->timer) XtRemoveTimeOut (pw->timer); - move_mouse_grab (si, RootWindowOfScreen(si->screens[0].screen), - si->screens[0].cursor); + move_mouse_grab (si, RootWindowOfScreen (ssi->screen), + ssi->cursor, ssi->number); + + 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()); if (si->passwd_dialog) { @@ -712,10 +802,9 @@ destroy_passwd_window (saver_info *si) XGCValues gcv; GC gc; gcv.function = GXcopy; - gc = XCreateGC (si->dpy, si->default_screen->screensaver_window, - GCFunction, &gcv); + gc = XCreateGC (si->dpy, ssi->screensaver_window, GCFunction, &gcv); XCopyArea (si->dpy, pw->save_under, - si->default_screen->screensaver_window, gc, + ssi->screensaver_window, gc, 0, 0, pw->width + (pw->border_width*2) + 1, pw->height + (pw->border_width*2) + 1, @@ -743,18 +832,28 @@ destroy_passwd_window (saver_info *si) 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->logo_foreground != black && pw->logo_foreground != white) - XFreeColors (si->dpy, cmap, &pw->logo_foreground, 1, 0L); - if (pw->logo_background != black && pw->logo_background != white) - XFreeColors (si->dpy, cmap, &pw->logo_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_npixels && pw->logo_pixels) + XFreeColors (si->dpy, cmap, pw->logo_pixels, pw->logo_npixels, 0L); + if (pw->logo_pixels) + free (pw->logo_pixels); + memset (pw, 0, sizeof(*pw)); free (pw); + if (cmap) + XInstallColormap (si->dpy, cmap); + si->pw_data = 0; } @@ -862,37 +961,40 @@ static Bool vp_got_error = False; static void xfree_lock_mode_switch (saver_info *si, Bool lock_p) { - static Bool mode_locked_p = False; + static Bool any_mode_locked_p = False; saver_preferences *p = &si->prefs; - int screen = 0; /* always screen 0 */ + int screen; int event, error; Bool status; XErrorHandler old_handler; - if (mode_locked_p == lock_p) + if (any_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")); + for (screen = 0; screen < si->nscreens; screen++) + { + 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) + 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")); + } } static int @@ -914,40 +1016,47 @@ 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; + int screen; + int event, error; - 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); + for (screen = 0; screen < si->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 */ } @@ -985,6 +1094,8 @@ passwd_animate_timer (XtPointer closure, XtIntervalId *id) } +static XComposeStatus *compose_status; + static void handle_passwd_key (saver_info *si, XKeyEvent *event) { @@ -995,7 +1106,7 @@ handle_passwd_key (saver_info *si, XKeyEvent *event) char s[2]; char *stars = 0; int i; - int size = XLookupString (event, s, 1, 0, 0); + int size = XLookupString (event, s, 1, 0, compose_status); if (size != 1) return; @@ -1164,12 +1275,34 @@ passwd_event_loop (saver_info *si) } +static void +handle_typeahead (saver_info *si) +{ + passwd_dialog_data *pw = si->pw_data; + int i; + if (!si->unlock_typeahead) + return; + + 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; + + 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; +} + + Bool unlock_p (saver_info *si) { saver_preferences *p = &si->prefs; - Screen *screen = si->default_screen->screen; - Colormap cmap = DefaultColormapOfScreen (screen); Bool status; raise_window (si, True, True, True); @@ -1181,15 +1314,17 @@ unlock_p (saver_info *si) destroy_passwd_window (si); make_passwd_window (si); - if (cmap) XInstallColormap (si->dpy, cmap); + compose_status = calloc (1, sizeof (*compose_status)); + + handle_typeahead (si); passwd_event_loop (si); status = (si->pw_data->state == pw_ok); destroy_passwd_window (si); - cmap = si->default_screen->cmap; - if (cmap) XInstallColormap (si->dpy, cmap); + free (compose_status); + compose_status = 0; return status; } @@ -1209,6 +1344,8 @@ set_locked_p (saver_info *si, Bool locked_p) #ifdef HAVE_XF86VMODE xfree_lock_mode_switch (si, locked_p); /* turn off/on C-Alt-Plus */ #endif + + store_saver_status (si); /* store locked-p */ }