X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=driver%2Fwindows.c;h=21eb6a39aac25a71b15d7aed591f5fdc2d2c78fd;hb=72c1f4c1dc6ab07fe121a327ff1c30bf51ef74c1;hp=1ec24e4e4af2fecdad427bf8f7900d172163edeb;hpb=0bd2eabab3e404c6769fe8f59b639275e960c415;p=xscreensaver diff --git a/driver/windows.c b/driver/windows.c index 1ec24e4e..21eb6a39 100644 --- a/driver/windows.c +++ b/driver/windows.c @@ -1,5 +1,5 @@ /* windows.c --- turning the screen black; dealing with visuals, virtual roots. - * xscreensaver, Copyright (c) 1991-1998 Jamie Zawinski + * xscreensaver, Copyright (c) 1991-1998 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -17,14 +17,17 @@ #ifdef VMS # include /* for getpid() */ # include "vms-gtod.h" /* for gettimeofday() */ -# if !defined(HAVE_UNAME) && (__VMS_VER >= 70000000) -# define HAVE_UNAME 1 -# endif /* !HAVE_UNAME */ #endif /* VMS */ -# ifdef HAVE_UNAME -# include /* for uname() */ -# endif /* HAVE_UNAME */ +#ifndef VMS +# include /* for getpwuid() */ +#else /* VMS */ +# include "vms-pwd.h" +#endif /* VMS */ + +#ifdef HAVE_UNAME +# include /* for uname() */ +#endif /* HAVE_UNAME */ #include #include /* for CARD32 */ @@ -38,16 +41,9 @@ # include #endif /* HAVE_MIT_SAVER_EXTENSION */ - -#ifdef HAVE_XHPDISABLERESET -# include - - /* Calls to XHPDisableReset and XHPEnableReset must be balanced, - or BadAccess errors occur. (Ok for this to be global, since it - affects the whole machine, not just the current screen.) */ - Bool hp_locked_p = False; - -#endif /* HAVE_XHPDISABLERESET */ +#ifdef HAVE_XF86VMODE +# include +#endif /* HAVE_XF86VMODE */ /* This file doesn't need the Xt headers, so stub these types out... */ @@ -62,18 +58,17 @@ #include "visual.h" #include "fade.h" + extern int kill (pid_t, int); /* signal() is in sys/signal.h... */ Atom XA_VROOT, XA_XSETROOT_ID; Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID; -Atom XA_SCREENSAVER_TIME; +Atom XA_SCREENSAVER_STATUS; extern saver_info *global_si_kludge; /* I hate C so much... */ -static void store_activate_time (saver_info *si, Bool use_last_p); - #define ALL_POINTER_EVENTS \ (ButtonPressMask | ButtonReleaseMask | EnterWindowMask | \ LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | \ @@ -81,6 +76,25 @@ static void store_activate_time (saver_info *si, Bool use_last_p); Button4MotionMask | Button5MotionMask | ButtonMotionMask) +static const char * +grab_string(int status) +{ + switch (status) + { + case GrabSuccess: return "GrabSuccess"; + case AlreadyGrabbed: return "AlreadyGrabbed"; + case GrabInvalidTime: return "GrabInvalidTime"; + case GrabNotViewable: return "GrabNotViewable"; + case GrabFrozen: return "GrabFrozen"; + default: + { + static char foo[255]; + sprintf(foo, "unknown status: %d", status); + return foo; + } + } +} + static int grab_kbd(saver_info *si, Window w) { @@ -93,53 +107,26 @@ grab_kbd(saver_info *si, Window w) if (status == GrabSuccess) si->keyboard_grab_window = w; - if (p->debug_p) - fprintf(stderr, "%s: XGrabKeyboard(... 0x%x ...) ==> %s\n", - progname, (unsigned long) w, - (status == GrabSuccess ? "GrabSuccess" : - status == AlreadyGrabbed ? "AlreadyGrabbed" : - status == GrabInvalidTime ? "GrabInvalidTime" : - status == GrabNotViewable ? "GrabNotViewable" : - status == GrabFrozen ? "GrabFrozen" : - "???")); - + if (p->verbose_p) + fprintf(stderr, "%s: grabbing keyboard on 0x%x... %s.\n", + blurb(), (unsigned long) w, grab_string(status)); return status; } -static const char * -grab_string(int status) -{ - switch (status) - { - case GrabSuccess: return "GrabSuccess"; break; - case AlreadyGrabbed: return "AlreadyGrabbed"; break; - case GrabInvalidTime: return "GrabInvalidTime"; break; - case GrabNotViewable: return "GrabNotViewable"; break; - case GrabFrozen: return "GrabFrozen"; break; - default: - { - static char foo[255]; - sprintf(foo, "unknown status: %d", status); - return foo; - } - } -} - static int grab_mouse (saver_info *si, Window w, Cursor cursor) { saver_preferences *p = &si->prefs; int status = XGrabPointer (si->dpy, w, True, ALL_POINTER_EVENTS, - GrabModeAsync, GrabModeAsync, None, + GrabModeAsync, GrabModeAsync, w, cursor, CurrentTime); if (status == GrabSuccess) si->mouse_grab_window = w; - if (p->debug_p) - fprintf(stderr, "%s: XGrabPointer(... 0x%x, 0x%x ...) ==> %s\n", - progname, (unsigned long) w, (unsigned long) cursor, - grab_string(status)); + if (p->verbose_p) + fprintf(stderr, "%s: grabbing mouse on 0x%x... %s.\n", + blurb(), (unsigned long) w, grab_string(status)); return status; } @@ -149,8 +136,8 @@ ungrab_kbd(saver_info *si) { saver_preferences *p = &si->prefs; XUngrabKeyboard(si->dpy, CurrentTime); - if (p->debug_p) - fprintf(stderr, "%s: XUngrabKeyboard (was 0x%x)\n", progname, + if (p->verbose_p) + fprintf(stderr, "%s: ungrabbing keyboard (was 0x%x).\n", blurb(), (unsigned long) si->keyboard_grab_window); si->keyboard_grab_window = 0; } @@ -161,41 +148,44 @@ ungrab_mouse(saver_info *si) { saver_preferences *p = &si->prefs; XUngrabPointer(si->dpy, CurrentTime); - if (p->debug_p) - fprintf(stderr, "%s: XUngrabPointer (was 0x%x)\n", progname, + if (p->verbose_p) + fprintf(stderr, "%s: ungrabbing mouse (was 0x%x).\n", blurb(), (unsigned long) si->mouse_grab_window); si->mouse_grab_window = 0; } -void +static Bool grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor) { - Status status; + Status mstatus, kstatus; XSync (si->dpy, False); - status = grab_kbd (si, window); - if (status != GrabSuccess) + kstatus = grab_kbd (si, window); + if (kstatus != GrabSuccess) { /* try again in a second */ sleep (1); - status = grab_kbd (si, window); - if (status != GrabSuccess) + kstatus = grab_kbd (si, window); + if (kstatus != GrabSuccess) fprintf (stderr, "%s: couldn't grab keyboard! (%s)\n", - progname, grab_string(status)); + blurb(), grab_string(kstatus)); } - status = grab_mouse (si, window, cursor); - if (status != GrabSuccess) + mstatus = grab_mouse (si, window, cursor); + if (mstatus != GrabSuccess) { /* try again in a second */ sleep (1); - status = grab_mouse (si, window, cursor); - if (status != GrabSuccess) + mstatus = grab_mouse (si, window, cursor); + if (mstatus != GrabSuccess) fprintf (stderr, "%s: couldn't grab pointer! (%s)\n", - progname, grab_string(status)); + blurb(), grab_string(mstatus)); } + + return (kstatus == GrabSuccess || + mstatus == GrabSuccess); } -void +static void ungrab_keyboard_and_mouse (saver_info *si) { ungrab_mouse (si); @@ -203,6 +193,50 @@ ungrab_keyboard_and_mouse (saver_info *si) } +int +move_mouse_grab (saver_info *si, Window to, Cursor cursor) +{ + Window old = si->mouse_grab_window; + + if (old == 0) + return grab_mouse (si, to, cursor); + else + { + saver_preferences *p = &si->prefs; + int status; + + XSync (si->dpy, False); + XGrabServer (si->dpy); /* ############ DANGER! */ + XSync (si->dpy, False); + + if (p->verbose_p) + fprintf(stderr, "%s: grabbing server...\n", blurb()); + + ungrab_mouse (si); + status = grab_mouse (si, to, cursor); + + if (status != GrabSuccess) /* Augh! */ + { + sleep (1); /* Note dramatic evil of sleeping + with server grabbed. */ + XSync (si->dpy, False); + status = grab_mouse (si, to, cursor); + } + + if (status != GrabSuccess) /* Augh! Try to get the old one back... */ + grab_mouse (si, to, cursor); + + XUngrabServer (si->dpy); + XSync (si->dpy, False); /* ###### (danger over) */ + + if (p->verbose_p) + fprintf(stderr, "%s: ungrabbing server.\n", blurb()); + + return status; + } +} + + /* Prints an error message to stderr and returns True if there is another xscreensaver running already. Silently returns False otherwise. */ Bool @@ -244,7 +278,7 @@ ensure_no_screensaver_running (Display *dpy, Screen *screen) fprintf (stderr, "%s: already running on display %s (window 0x%x)\n from process %s.\n", - progname, DisplayString (dpy), (int) kids [i], id); + blurb(), DisplayString (dpy), (int) kids [i], id); status = True; } } @@ -269,7 +303,7 @@ store_vroot_property (Display *dpy, Window win, Window value) #if 0 if (p->verbose_p) fprintf (stderr, - "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", progname, + "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", blurb(), win, (win == screensaver_window ? "ScreenSaver" : (win == real_vroot ? "VRoot" : @@ -288,7 +322,7 @@ remove_vroot_property (Display *dpy, Window win) { #if 0 if (p->verbose_p) - fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", progname, win, + fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", blurb(), win, (win == screensaver_window ? "ScreenSaver" : (win == real_vroot ? "VRoot" : (win == real_vroot_value ? "Vroot_value" : "???")))); @@ -327,14 +361,14 @@ kill_xsetroot_data (Display *dpy, Window window, Bool verbose_p) nitems == 1 && bytesafter == 0) { if (verbose_p) - printf ("%s: destroying xsetroot data (0x%lX).\n", - progname, *dataP); + fprintf (stderr, "%s: destroying xsetroot data (0x%lX).\n", + blurb(), *dataP); XKillClient (dpy, *dataP); } else fprintf (stderr, "%s: deleted unrecognised _XSETROOT_ID property: \n\ %lu, %lu; type: %lu, format: %d, nitems: %lu, bytesafter %ld\n", - progname, (unsigned long) dataP, (dataP ? *dataP : 0), type, + blurb(), (unsigned long) dataP, (dataP ? *dataP : 0), type, format, nitems, bytesafter); } } @@ -352,6 +386,16 @@ save_real_vroot (saver_screen_info *ssi) Window root = RootWindowOfScreen (screen); Window root2, parent, *kids; unsigned int nkids; + XErrorHandler old_handler; + + /* It's possible that a window might be deleted between our call to + XQueryTree() and our call to XGetWindowProperty(). Don't die if + that happens (but just ignore that window, it's not the one we're + interested in anyway.) + */ + XSync (dpy, False); + old_handler = XSetErrorHandler (BadWindow_ehandler); + XSync (dpy, False); ssi->real_vroot = 0; ssi->real_vroot_value = 0; @@ -380,13 +424,17 @@ save_real_vroot (saver_screen_info *ssi) if (*vrootP == ssi->screensaver_window) abort (); fprintf (stderr, "%s: more than one virtual root window found (0x%x and 0x%x).\n", - progname, (int) ssi->real_vroot, (int) kids [i]); + blurb(), (int) ssi->real_vroot, (int) kids [i]); exit (1); } ssi->real_vroot = kids [i]; ssi->real_vroot_value = *vrootP; } + XSync (dpy, False); + XSetErrorHandler (old_handler); + XSync (dpy, False); + if (ssi->real_vroot) { handle_signals (si, True); @@ -404,8 +452,9 @@ restore_real_vroot_2 (saver_screen_info *ssi) saver_info *si = ssi->global; saver_preferences *p = &si->prefs; if (p->verbose_p && ssi->real_vroot) - printf ("%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n", - progname, (unsigned long) ssi->real_vroot); + fprintf (stderr, + "%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n", + blurb(), (unsigned long) ssi->real_vroot); remove_vroot_property (si->dpy, ssi->screensaver_window); if (ssi->real_vroot) { @@ -530,7 +579,7 @@ restore_real_vroot_handler (int sig) signal (sig, SIG_DFL); if (restore_real_vroot_1 (si)) fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n", - progname, signal_name(sig)); + blurb(), signal_name(sig)); kill (getpid (), sig); } @@ -544,9 +593,9 @@ catch_signal (saver_info *si, int sig, Bool on_p) if (((long) signal (sig, restore_real_vroot_handler)) == -1L) { char buf [255]; - sprintf (buf, "%s: couldn't catch %s", progname, signal_name(sig)); + sprintf (buf, "%s: couldn't catch %s", blurb(), signal_name(sig)); perror (buf); - saver_exit (si, 1); + saver_exit (si, 1, 0); } } } @@ -555,8 +604,8 @@ static void handle_signals (saver_info *si, Bool on_p) { #if 0 - if (on_p) printf ("handling signals\n"); - else printf ("unhandling signals\n"); + if (on_p) fprintf (stderr, "handling signals\n"); + else fprintf (stderr, "unhandling signals\n"); #endif catch_signal (si, SIGHUP, on_p); @@ -588,10 +637,11 @@ handle_signals (saver_info *si, Bool on_p) } void -saver_exit (saver_info *si, int status) +saver_exit (saver_info *si, int status, const char *dump_core_reason) { saver_preferences *p = &si->prefs; static Bool exiting = False; + Bool bugp; Bool vrs; if (exiting) @@ -602,10 +652,13 @@ saver_exit (saver_info *si, int status) vrs = restore_real_vroot_1 (si); emergency_kill_subproc (si); - if (vrs && (p->verbose_p || status != 0)) - fprintf (real_stderr, "%s: vroot restored, exiting.\n", progname); - else if (p->verbose_p) - fprintf (real_stderr, "%s: no vroot to restore; exiting.\n", progname); + if (p->verbose_p) /* nobody cares about this */ + { + if (vrs) + fprintf (real_stderr, "%s: vroot restored, exiting.\n", blurb()); + else if (p->verbose_p) + fprintf (real_stderr, "%s: no vroot to restore; exiting.\n", blurb()); + } fflush(real_stdout); @@ -614,9 +667,38 @@ saver_exit (saver_info *si, int status) else if (status == 1) status = -1; #endif - if (si->prefs.debug_p) + bugp = !!dump_core_reason; + + if (si->prefs.debug_p && !dump_core_reason) + dump_core_reason = "because of -debug"; + + if (dump_core_reason) { - fprintf(real_stderr, "%s: dumping core (because of -debug)\n", progname); + /* Note that the Linux man page for setuid() says If uid is + different from the old effective uid, the process will be + forbidden from leaving core dumps. + */ + char cwd[4096]; /* should really be PATH_MAX, but who cares. */ + cwd[0] = 0; + fprintf(real_stderr, "%s: dumping core (%s)\n", blurb(), + dump_core_reason); + + if (bugp) + fprintf(real_stderr, + "%s: see http://www.jwz.org/xscreensaver/bugs.html\n" + "\t\tfor bug reporting information.\n\n", + blurb()); + +# if defined(HAVE_GETCWD) + if (!getcwd (cwd, sizeof(cwd))) +# elif defined(HAVE_GETWD) + if (!getwd (cwd)) +# endif + strcpy(cwd, "unknown."); + + fprintf (real_stderr, "%s: current directory is %s\n", blurb(), cwd); + describe_uids (si, real_stderr); + /* Do this to drop a core file, so that we can get a stack trace. */ abort(); } @@ -640,12 +722,240 @@ window_exists_p (Display *dpy, Window window) return (xgwa.screen != 0); } +static void +store_saver_id (saver_screen_info *ssi) +{ + XClassHint class_hints; + saver_info *si = ssi->global; + unsigned long pid = (unsigned long) getpid (); + char buf[20]; + struct passwd *p = getpwuid (getuid ()); + const char *name, *host; + char *id; + + /* First store the name and class on the window. + */ + class_hints.res_name = progname; + class_hints.res_class = progclass; + XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints); + XStoreName (si->dpy, ssi->screensaver_window, "screensaver"); + + /* Then store the xscreensaver version number. + */ + XChangeProperty (si->dpy, ssi->screensaver_window, + XA_SCREENSAVER_VERSION, + XA_STRING, 8, PropModeReplace, + (unsigned char *) si->version, + strlen (si->version)); + + /* Now store the XSCREENSAVER_ID property, that says what user and host + xscreensaver is running as. + */ + + if (p && p->pw_name && *p->pw_name) + name = p->pw_name; + else if (p) + { + sprintf (buf, "%lu", (unsigned long) p->pw_uid); + name = buf; + } + else + name = "???"; + +# if defined(HAVE_UNAME) + { + struct utsname uts; + if (uname (&uts) < 0) + host = "???"; + else + host = uts.nodename; + } +# elif defined(VMS) + host = getenv("SYS$NODE"); +# else /* !HAVE_UNAME && !VMS */ + host = "???"; +# endif /* !HAVE_UNAME && !VMS */ + + id = (char *) malloc (strlen(name) + strlen(host) + 50); + sprintf (id, "%lu (%s@%s)", pid, name, host); + + XChangeProperty (si->dpy, ssi->screensaver_window, + XA_SCREENSAVER_ID, XA_STRING, + 8, PropModeReplace, + (unsigned char *) id, strlen (id)); + free (id); +} + + +void +store_saver_status (saver_info *si) +{ + CARD32 *status; + int size = si->nscreens + 2; + int i; + + status = (CARD32 *) calloc (size, sizeof(CARD32)); + + status[0] = (CARD32) (si->screen_blanked_p + ? (si->locked_p ? XA_LOCK : XA_BLANK) + : 0); + status[1] = (CARD32) si->blank_time; + + for (i = 0; i < si->nscreens; i++) + { + saver_screen_info *ssi = &si->screens[i]; + status [2 + i] = ssi->current_hack + 1; + } + + XChangeProperty (si->dpy, + RootWindow (si->dpy, 0), /* always screen #0 */ + XA_SCREENSAVER_STATUS, + XA_INTEGER, 32, PropModeReplace, + (unsigned char *) status, size); +} + + + +/* Returns the area of the screen which the xscreensaver window should cover. + Normally this is the whole screen, but if the X server's root window is + actually larger than the monitor's displayable area, then we want to + operate in the currently-visible portion of the desktop instead. + */ +void +get_screen_viewport (saver_screen_info *ssi, + int *x_ret, int *y_ret, + int *w_ret, int *h_ret, + Bool verbose_p) +{ + int w = WidthOfScreen (ssi->screen); + int h = HeightOfScreen (ssi->screen); + +#ifdef HAVE_XF86VMODE + saver_info *si = ssi->global; + int screen_no = screen_number (ssi->screen); + int op, event, error; + int dot; + XF86VidModeModeLine ml; + int x, y; + + /* Check for Xinerama first, because the VidModeExtension is broken + when Xinerama is present. Wheee! + */ + + if (!XQueryExtension (si->dpy, "XINERAMA", &op, &event, &error) && + XF86VidModeQueryExtension (si->dpy, &event, &error) && + XF86VidModeGetModeLine (si->dpy, screen_no, &dot, &ml) && + XF86VidModeGetViewPort (si->dpy, screen_no, &x, &y)) + { + char msg[512]; + *x_ret = x; + *y_ret = y; + *w_ret = ml.hdisplay; + *h_ret = ml.vdisplay; + + if (*x_ret == 0 && *y_ret == 0 && *w_ret == w && *h_ret == h) + /* There is no viewport -- the screen does not scroll. */ + return; + + + /* Apparently some versions of XFree86 return nonsense here! + I've had reports of 1024x768 viewports at -1936862040, -1953705044. + So, sanity-check the values and give up if they are out of range. + */ + if (*x_ret < 0 || *x_ret >= w || + *y_ret < 0 || *y_ret >= h || + *w_ret <= 0 || *w_ret > w || + *h_ret <= 0 || *h_ret > h) + { + static int warned_once = 0; + if (!warned_once) + { + fprintf (stderr, "\n" + "%s: X SERVER BUG: %dx%d viewport at %d,%d is impossible.\n" + "%s: The XVidMode server extension is returning nonsense.\n" + "%s: Please report this bug to your X server vendor.\n\n", + blurb(), *w_ret, *h_ret, *x_ret, *y_ret, + blurb(), blurb()); + warned_once = 1; + } + *x_ret = 0; + *y_ret = 0; + *w_ret = w; + *h_ret = h; + return; + } + + + sprintf (msg, "%s: vp is %dx%d+%d+%d", + blurb(), *w_ret, *h_ret, *x_ret, *y_ret); + + + /* Apparently, though the server stores the X position in increments of + 1 pixel, it will only make changes to the *display* in some other + increment. With XF86_SVGA on a Thinkpad, the display only updates + in multiples of 8 pixels when in 8-bit mode, and in multiples of 4 + pixels in 16-bit mode. I don't know what it does in 24- and 32-bit + mode, because I don't have enough video memory to find out. + + I consider it a bug that XF86VidModeGetViewPort() is telling me the + server's *target* scroll position rather than the server's *actual* + scroll position. David Dawes agrees, and says they may fix this in + XFree86 4.0, but it's notrivial. + + He also confirms that this behavior is server-dependent, so the + actual scroll position cannot be reliably determined by the client. + So... that means the only solution is to provide a ``sandbox'' + around the blackout window -- we make the window be up to N pixels + larger than the viewport on both the left and right sides. That + means some part of the outer edges of each hack might not be + visible, but screw it. + + I'm going to guess that 16 pixels is enough, and that the Y dimension + doesn't have this problem. + + The drawback of doing this, of course, is that some of the screenhacks + will still look pretty stupid -- for example, "slidescreen" will cut + off the left and right edges of the grid, etc. + */ +# define FUDGE 16 + if (x > 0 && x < w - ml.hdisplay) /* not at left edge or right edge */ + { + /* Round X position down to next lower multiple of FUDGE. + Increase width by 2*FUDGE in case some server rounds up. + */ + *x_ret = ((x - 1) / FUDGE) * FUDGE; + *w_ret += (FUDGE * 2); + } +# undef FUDGE + + if (*x_ret != x || + *y_ret != y || + *w_ret != ml.hdisplay || + *h_ret != ml.vdisplay) + sprintf (msg + strlen(msg), "; fudged to %dx%d+%d+%d", + *w_ret, *h_ret, *x_ret, *y_ret); + + if (verbose_p) + fprintf (stderr, "%s.\n", msg); + + return; + } + +#endif /* HAVE_XF86VMODE */ + + *x_ret = 0; + *y_ret = 0; + *w_ret = w; + *h_ret = h; +} + + static void initialize_screensaver_window_1 (saver_screen_info *ssi) { saver_info *si = ssi->global; saver_preferences *p = &si->prefs; - Bool install_cmap_p = ssi->install_cmap_p; + Bool install_cmap_p = ssi->install_cmap_p; /* not p->install_cmap_p */ /* This resets the screensaver window as fully as possible, since there's no way of knowing what some random client may have done to us in the @@ -653,27 +963,29 @@ initialize_screensaver_window_1 (saver_screen_info *ssi) its own set of problems... */ XColor black; - XClassHint class_hints; XSetWindowAttributes attrs; unsigned long attrmask; - int width = WidthOfScreen (ssi->screen); - int height = HeightOfScreen (ssi->screen); - char id [2048]; + int x, y, width, height; static Bool printed_visual_info = False; /* only print the message once. */ + get_screen_viewport (ssi, &x, &y, &width, &height, + (p->verbose_p && !si->screen_blanked_p)); + black.red = black.green = black.blue = 0; if (ssi->cmap == DefaultColormapOfScreen (ssi->screen)) ssi->cmap = 0; if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen)) + /* It's not the default visual, so we have no choice but to install. */ install_cmap_p = True; if (install_cmap_p) { if (! ssi->cmap) { - ssi->cmap = XCreateColormap (si->dpy, RootWindowOfScreen (ssi->screen), + ssi->cmap = XCreateColormap (si->dpy, + RootWindowOfScreen (ssi->screen), ssi->current_visual, AllocNone); if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort (); ssi->black_pixel = black.pixel; @@ -717,21 +1029,24 @@ initialize_screensaver_window_1 (saver_screen_info *ssi) ; else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen)) { - fprintf (stderr, "%s: using default visual ", progname); - describe_visual (stderr, ssi->screen, ssi->current_visual); + fprintf (stderr, "%s: using default visual ", blurb()); + describe_visual (stderr, ssi->screen, ssi->current_visual, + install_cmap_p); } else { - fprintf (stderr, "%s: using visual: ", progname); - describe_visual (stderr, ssi->screen, ssi->current_visual); - fprintf (stderr, "%s: default visual: ", progname); + fprintf (stderr, "%s: using visual: ", blurb()); + describe_visual (stderr, ssi->screen, ssi->current_visual, + install_cmap_p); + fprintf (stderr, "%s: default visual: ", blurb()); describe_visual (stderr, ssi->screen, - DefaultVisualOfScreen (ssi->screen)); + DefaultVisualOfScreen (ssi->screen), + ssi->install_cmap_p); } printed_visual_info = True; #ifdef HAVE_MIT_SAVER_EXTENSION - if (p->use_mit_saver_extension) + if (si->using_mit_saver_extension) { XScreenSaverInfo *info; Window root = RootWindowOfScreen (ssi->screen); @@ -785,8 +1100,8 @@ initialize_screensaver_window_1 (saver_screen_info *ssi) { XWindowChanges changes; unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth; - changes.x = 0; - changes.y = 0; + changes.x = x; + changes.y = y; changes.width = width; changes.height = height; changes.border_width = 0; @@ -799,78 +1114,38 @@ initialize_screensaver_window_1 (saver_screen_info *ssi) else { ssi->screensaver_window = - XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen), 0, 0, - width, height, 0, ssi->current_depth, InputOutput, + XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen), + x, y, width, height, + 0, ssi->current_depth, InputOutput, ssi->current_visual, attrmask, &attrs); + reset_stderr (ssi); - store_activate_time(si, True); if (p->verbose_p) fprintf (stderr, "%s: saver window is 0x%lx.\n", - progname, (unsigned long) ssi->screensaver_window); + blurb(), (unsigned long) ssi->screensaver_window); } -#ifdef HAVE_MIT_SAVER_EXTENSION - if (!p->use_mit_saver_extension || - window_exists_p (si->dpy, ssi->screensaver_window)) - /* When using the MIT-SCREEN-SAVER extension, the window pointed to - by screensaver_window only exists while the saver is active. - So we must be careful to only try and manipulate it while it - exists... - (#### The above comment would be true if the MIT extension actually - worked, but it's not true today -- see `server_mit_saver_window'.) - */ -#endif /* HAVE_MIT_SAVER_EXTENSION */ - { - class_hints.res_name = progname; - class_hints.res_class = progclass; - XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints); - XStoreName (si->dpy, ssi->screensaver_window, "screensaver"); - XChangeProperty (si->dpy, ssi->screensaver_window, - XA_SCREENSAVER_VERSION, - XA_STRING, 8, PropModeReplace, - (unsigned char *) si->version, - strlen (si->version)); - - sprintf (id, "%lu on host ", (unsigned long) getpid ()); - -# if defined(HAVE_UNAME) - { - struct utsname uts; - if (uname (&uts) < 0) - strcat (id, "???"); - else - strcat (id, uts.nodename); - } -# elif defined(VMS) - strcat (id, getenv("SYS$NODE")); -# else /* !HAVE_UNAME && !VMS */ - strcat (id, "???"); -# endif /* !HAVE_UNAME && !VMS */ + store_saver_id (ssi); /* store window name and IDs */ - XChangeProperty (si->dpy, ssi->screensaver_window, - XA_SCREENSAVER_ID, XA_STRING, - 8, PropModeReplace, (unsigned char *) id, strlen (id)); + if (!ssi->cursor) + { + Pixmap bit; + bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window, + "\000", 1, 1, + BlackPixelOfScreen (ssi->screen), + BlackPixelOfScreen (ssi->screen), + 1); + ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black, + 0, 0); + XFreePixmap (si->dpy, bit); + } - if (!ssi->cursor) - { - Pixmap bit; - bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window, - "\000", 1, 1, - BlackPixelOfScreen (ssi->screen), - BlackPixelOfScreen (ssi->screen), - 1); - ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black, - 0, 0); - XFreePixmap (si->dpy, bit); - } + XSetWindowBackground (si->dpy, ssi->screensaver_window, ssi->black_pixel); - XSetWindowBackground (si->dpy, ssi->screensaver_window, - ssi->black_pixel); - if (si->demo_mode_p) - XUndefineCursor (si->dpy, ssi->screensaver_window); - else - XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor); - } + if (si->demoing_p) + XUndefineCursor (si->dpy, ssi->screensaver_window); + else + XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor); } void @@ -889,12 +1164,19 @@ raise_window (saver_info *si, saver_preferences *p = &si->prefs; int i; - initialize_screensaver_window (si); + if (si->demoing_p) + inhibit_fade = True; + + if (si->emergency_lock_p) + inhibit_fade = True; + + if (!dont_clear) + initialize_screensaver_window (si); + reset_watchdog_timer (si, True); - if (p->fade_p && !inhibit_fade && !si->demo_mode_p) + if (p->fade_p && si->fading_possible_p && !inhibit_fade) { - int grabbed = -1; Window *current_windows = (Window *) calloc(sizeof(Window), si->nscreens); Colormap *current_maps = (Colormap *) @@ -913,49 +1195,33 @@ raise_window (saver_info *si, ssi->black_pixel); } - if (p->verbose_p) fprintf (stderr, "%s: fading... ", progname); + if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb()); XGrabServer (si->dpy); /* ############ DANGER! */ /* Clear the stderr layer on each screen. - Grab the mouse on the first screen on which the mouse is grabbable - (if there are multiple heads, I think you might only be able to - grab the mouse on the screen that currently has the mouse? Anyway, - we only grab the mouse once, and don't try again after the grab - has succeeded.) We grab the mouse on the root window of the screen, - not on the screensaver window, since the screensaver window is not - yet mapped. */ - for (i = 0; i < si->nscreens; i++) - { - saver_screen_info *ssi = &si->screens[i]; - - /* grab and blacken mouse on the root window (saver not mapped yet) - */ - if (grabbed != GrabSuccess) - { - Window root = RootWindowOfScreen(ssi->screen); - grabbed = grab_mouse (si, root, - (si->demo_mode_p ? 0 : ssi->cursor)); - } - - if (!dont_clear || ssi->stderr_overlay_window) - /* Do this before the fade, since the stderr cmap won't fade - even if we uninstall it (beats me...) */ - clear_stderr (ssi); - } + if (!dont_clear) + for (i = 0; i < si->nscreens; i++) + { + saver_screen_info *ssi = &si->screens[i]; + if (ssi->stderr_overlay_window) + /* Do this before the fade, since the stderr cmap won't fade + even if we uninstall it (beats me...) */ + clear_stderr (ssi); + } /* Note! The server is grabbed, and this will take several seconds to complete! */ fade_screens (si->dpy, current_maps, current_windows, - p->fade_seconds, p->fade_ticks, True, !dont_clear); + p->fade_seconds/1000, p->fade_ticks, True, !dont_clear); free(current_maps); free(current_windows); current_maps = 0; current_windows = 0; - if (p->verbose_p) fprintf (stderr, "fading done.\n"); + if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb()); #ifdef HAVE_MIT_SAVER_EXTENSION for (i = 0; i < si->nscreens; i++) @@ -967,10 +1233,6 @@ raise_window (saver_info *si, } #endif /* HAVE_MIT_SAVER_EXTENSION */ - /* If we had successfully grabbed the mouse, let it go now. */ - if (grabbed == GrabSuccess) - ungrab_mouse (si); - XUngrabServer (si->dpy); XSync (si->dpy, False); /* ###### (danger over) */ } @@ -1000,10 +1262,34 @@ raise_window (saver_info *si, } } -void +Bool blank_screen (saver_info *si) { int i; + Bool ok; + + /* Note: we do our grabs on the root window, not on the screensaver window. + If we grabbed on the saver window, then the demo mode and lock dialog + boxes wouldn't get any events. + */ + ok = grab_keyboard_and_mouse (si, + /*si->screens[0].screensaver_window,*/ + RootWindowOfScreen(si->screens[0].screen), + (si->demoing_p + ? 0 + : si->screens[0].cursor)); + + + if (si->using_mit_saver_extension || si->using_sgi_saver_extension) + /* If we're using a server extension, then failure to get a grab is + not a big deal -- even without the grab, we will still be able + to un-blank when there is user activity, since the server will + tell us. */ + ok = True; + + if (!ok) + return False; + for (i = 0; i < si->nscreens; i++) { saver_screen_info *ssi = &si->screens[i]; @@ -1012,44 +1298,46 @@ blank_screen (saver_info *si) store_vroot_property (si->dpy, ssi->screensaver_window, ssi->screensaver_window); + +#ifdef HAVE_XF86VMODE + { + int ev, er; + if (!XF86VidModeQueryExtension (si->dpy, &ev, &er) || + !XF86VidModeGetViewPort (si->dpy, i, + &ssi->blank_vp_x, + &ssi->blank_vp_y)) + ssi->blank_vp_x = ssi->blank_vp_y = -1; + } +#endif /* HAVE_XF86VMODE */ } - store_activate_time (si, si->screen_blanked_p); + raise_window (si, False, False, False); - /* Note: we do our grabs on the root window, not on the screensaver window. - If we grabbed on the saver window, then the demo mode and lock dialog - boxes wouldn't get any events. - */ - grab_keyboard_and_mouse (si, - /*si->screens[0].screensaver_window,*/ - RootWindowOfScreen(si->screens[0].screen), - (si->demo_mode_p ? 0 : si->screens[0].cursor)); + si->screen_blanked_p = True; + si->blank_time = time ((time_t) 0); + si->last_wall_clock_time = 0; -#ifdef HAVE_XHPDISABLERESET - if (si->locked_p && !hp_locked_p) - { - XHPDisableReset (si->dpy); /* turn off C-Sh-Reset */ - hp_locked_p = True; - } -#endif + store_saver_status (si); /* store blank time */ - si->screen_blanked_p = True; + return True; } + void unblank_screen (saver_info *si) { saver_preferences *p = &si->prefs; + Bool unfade_p = (si->fading_possible_p && p->unfade_p); int i; monitor_power_on (si); - - store_activate_time (si, True); reset_watchdog_timer (si, False); - if (p->unfade_p && !si->demo_mode_p) + if (si->demoing_p) + unfade_p = False; + + if (unfade_p) { - int grabbed = -1; Window *current_windows = (Window *) calloc(sizeof(Window), si->nscreens); @@ -1063,7 +1351,7 @@ unblank_screen (saver_info *si) ssi->black_pixel); } - if (p->verbose_p) fprintf (stderr, "%s: unfading... ", progname); + if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb()); XSync (si->dpy, False); @@ -1071,18 +1359,10 @@ unblank_screen (saver_info *si) XSync (si->dpy, False); /* Clear the stderr layer on each screen. - Grab the mouse on the first screen on which the mouse is grabbable - (if there are multiple heads, I think you might only be able to - grab the mouse on the screen that currently has the mouse? Anyway, - we only grab the mouse once, and don't try again after the grab - has succeeded.) */ for (i = 0; i < si->nscreens; i++) { saver_screen_info *ssi = &si->screens[i]; - if (grabbed != GrabSuccess) - grabbed = grab_mouse (si, RootWindowOfScreen (ssi->screen), - 0); clear_stderr (ssi); } @@ -1091,17 +1371,13 @@ unblank_screen (saver_info *si) fade_screens (si->dpy, 0, current_windows, - p->fade_seconds, p->fade_ticks, + p->fade_seconds/1000, p->fade_ticks, False, False); free(current_windows); current_windows = 0; - if (p->verbose_p) fprintf (stderr, "unfading done.\n"); - - /* If we had successfully grabbed the mouse, let it go now. */ - if (grabbed == GrabSuccess) - ungrab_mouse (si); + if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb()); } else { @@ -1148,19 +1424,10 @@ unblank_screen (saver_info *si) kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p); } - store_activate_time(si, False); /* store unblank time */ - + store_saver_status (si); /* store unblank time */ ungrab_keyboard_and_mouse (si); restore_real_vroot (si); -#ifdef HAVE_XHPDISABLERESET - if (hp_locked_p) - { - XHPEnableReset (si->dpy); /* turn C-Sh-Reset back on */ - hp_locked_p = False; - } -#endif - /* Unmap the windows a second time, dammit -- just to avoid a race with the screen-grabbing hacks. (I'm not sure if this is really necessary; I'm stabbing in the dark now.) @@ -1169,26 +1436,10 @@ unblank_screen (saver_info *si) XUnmapWindow (si->dpy, si->screens[i].screensaver_window); si->screen_blanked_p = False; -} + si->blank_time = time ((time_t) 0); + si->last_wall_clock_time = 0; - -static void -store_activate_time (saver_info *si, Bool use_last_p) -{ - static time_t last_time = 0; - time_t now = ((use_last_p && last_time) ? last_time : time ((time_t) 0)); - CARD32 now32 = (CARD32) now; - int i; - last_time = now; - - for (i = 0; i < si->nscreens; i++) - { - saver_screen_info *ssi = &si->screens[i]; - if (!ssi->screensaver_window) continue; - XChangeProperty (si->dpy, ssi->screensaver_window, XA_SCREENSAVER_TIME, - XA_INTEGER, 32, PropModeReplace, - (unsigned char *) &now32, 1); - } + store_saver_status (si); /* store unblank time */ } @@ -1199,22 +1450,39 @@ select_visual (saver_screen_info *ssi, const char *visual_name) saver_preferences *p = &si->prefs; Bool install_cmap_p = p->install_cmap_p; Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen)); - Visual *new_v; + Visual *new_v = 0; Bool got_it; if (visual_name && *visual_name) { - if (!strcmp(visual_name, "default-i")) + if (!strcmp(visual_name, "default-i") || + !strcmp(visual_name, "Default-i") || + !strcmp(visual_name, "Default-I") + ) { visual_name = "default"; install_cmap_p = True; } - else if (!strcmp(visual_name, "default-n")) + else if (!strcmp(visual_name, "default-n") || + !strcmp(visual_name, "Default-n") || + !strcmp(visual_name, "Default-N")) { visual_name = "default"; install_cmap_p = False; } - new_v = get_visual (ssi->screen, visual_name, True, False); +#ifdef DAEMON_USE_GL + else if (!strcmp(visual_name, "gl") || + !strcmp(visual_name, "Gl") || + !strcmp(visual_name, "GL")) + { + new_v = get_gl_visual (ssi->screen); + if (!new_v && p->verbose_p) + fprintf (stderr, "%s: no GL visuals.\n", progname); + } +#endif /* DAEMON_USE_GL */ + + if (!new_v) + new_v = get_visual (ssi->screen, visual_name, True, False); } else { @@ -1224,6 +1492,7 @@ select_visual (saver_screen_info *ssi, const char *visual_name) got_it = !!new_v; if (new_v && new_v != DefaultVisualOfScreen(ssi->screen)) + /* It's not the default visual, so we have no choice but to install. */ install_cmap_p = True; ssi->install_cmap_p = install_cmap_p; @@ -1237,16 +1506,12 @@ select_visual (saver_screen_info *ssi, const char *visual_name) if (p->verbose_p) { + fprintf (stderr, "%s: switching to visual ", blurb()); + describe_visual (stderr, ssi->screen, new_v, install_cmap_p); #if 0 - fprintf (stderr, "%s: switching visuals\tfrom: ", progname); - describe_visual (stderr, ssi->screen, ssi->current_visual); - fprintf (stderr, "\t\t\t\tto: "); - describe_visual (stderr, ssi->screen, new_v); - fprintf (stderr, "\t\t\t\t install cmap: %s\n", - (install_cmap_p ? "yes" : "no")); -#else - fprintf (stderr, "%s: switching to visual ", progname); - describe_visual (stderr, ssi->screen, new_v); + fprintf (stderr, "%s: from ", blurb()); + describe_visual (stderr, ssi->screen, ssi->current_visual, + was_installed_p); #endif } @@ -1257,11 +1522,16 @@ select_visual (saver_screen_info *ssi, const char *visual_name) ssi->screensaver_window = 0; initialize_screensaver_window_1 (ssi); + + /* stderr_overlay_window is a child of screensaver_window, so we need + to destroy that as well (actually, we just need to invalidate and + drop our pointers to it, but this will destroy it, which is ok so + long as it happens before old_w itself is destroyed.) */ + reset_stderr (ssi); + raise_window (si, True, True, False); store_vroot_property (si->dpy, ssi->screensaver_window, ssi->screensaver_window); - store_activate_time (si, True); - /* Transfer the grabs from the old window to the new. @@ -1278,9 +1548,11 @@ select_visual (saver_screen_info *ssi, const char *visual_name) if (old_w == si->mouse_grab_window) { XGrabServer (si->dpy); /* ############ DANGER! */ - ungrab_mouse(si); - grab_mouse(si, ssi->screensaver_window, - (si->demo_mode_p ? 0 : ssi->cursor)); + ungrab_mouse (si); + grab_mouse (si, ssi->screensaver_window, + (si->demoing_p + ? 0 + : ssi->cursor)); XUngrabServer (si->dpy); XSync (si->dpy, False); /* ###### (danger over) */ } @@ -1304,7 +1576,7 @@ select_visual (saver_screen_info *ssi, const char *visual_name) if (p->verbose_p) fprintf (stderr, "%s: destroyed old saver window 0x%lx.\n", - progname, (unsigned long) old_w); + blurb(), (unsigned long) old_w); if (old_c && old_c != DefaultColormapOfScreen (ssi->screen) &&