/* windows.c --- turning the screen black; dealing with visuals, virtual roots.
- * xscreensaver, Copyright (c) 1991-1998 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1991-2001 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
# include "vms-gtod.h" /* for gettimeofday() */
#endif /* VMS */
-# ifdef HAVE_UNAME
-# include <sys/utsname.h> /* for uname() */
-# endif /* HAVE_UNAME */
+#ifndef VMS
+# include <pwd.h> /* for getpwuid() */
+#else /* VMS */
+# include "vms-pwd.h"
+#endif /* VMS */
+
+#ifdef HAVE_UNAME
+# include <sys/utsname.h> /* for uname() */
+#endif /* HAVE_UNAME */
#include <stdio.h>
#include <X11/Xproto.h> /* for CARD32 */
# include <X11/extensions/scrnsaver.h>
#endif /* HAVE_MIT_SAVER_EXTENSION */
-
-#ifdef HAVE_XHPDISABLERESET
-# include <X11/XHPlib.h>
-
- /* 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 <X11/extensions/xf86vmode.h>
+#endif /* HAVE_XF86VMODE */
/* This file doesn't need the Xt headers, so stub these types out... */
#include "fade.h"
-#ifdef HAVE_VT_LOCKSWITCH
-# include <fcntl.h>
-# include <sys/ioctl.h>
-# include <sys/vt.h>
- static void lock_vt (saver_info *si, Bool lock_p);
-#endif /* HAVE_VT_LOCKSWITCH */
-
-
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);
+static void maybe_transfer_grabs (saver_screen_info *ssi,
+ Window old_w, Window new_w);
#define ALL_POINTER_EVENTS \
(ButtonPressMask | ButtonReleaseMask | EnterWindowMask | \
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)
{
if (p->verbose_p)
fprintf(stderr, "%s: grabbing keyboard on 0x%x... %s.\n",
- blurb(), (unsigned long) w,
- (status == GrabSuccess ? "GrabSuccess" :
- status == AlreadyGrabbed ? "AlreadyGrabbed" :
- status == GrabInvalidTime ? "GrabInvalidTime" :
- status == GrabNotViewable ? "GrabNotViewable" :
- status == GrabFrozen ? "GrabFrozen" :
- "???"));
-
+ 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;
}
-void
+static Bool
grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor)
{
- Status status;
- XSync (si->dpy, False);
+ Status mstatus, kstatus;
+ int i;
+ int retries = 4;
+
+ for (i = 0; i < retries; i++)
+ {
+ XSync (si->dpy, False);
+ kstatus = grab_kbd (si, window);
+ if (kstatus == GrabSuccess)
+ break;
- status = grab_kbd (si, window);
- if (status != GrabSuccess)
- { /* try again in a second */
+ /* else, wait a second and try to grab again. */
sleep (1);
- status = grab_kbd (si, window);
- if (status != GrabSuccess)
- fprintf (stderr, "%s: couldn't grab keyboard! (%s)\n",
- blurb(), grab_string(status));
}
- status = grab_mouse (si, window, cursor);
- if (status != GrabSuccess)
- { /* try again in a second */
+ if (kstatus != GrabSuccess)
+ fprintf (stderr, "%s: couldn't grab keyboard! (%s)\n",
+ blurb(), grab_string(kstatus));
+
+ for (i = 0; i < retries; i++)
+ {
+ XSync (si->dpy, False);
+ mstatus = grab_mouse (si, window, cursor);
+ if (mstatus == GrabSuccess)
+ break;
+
+ /* else, wait a second and try to grab again. */
sleep (1);
- status = grab_mouse (si, window, cursor);
- if (status != GrabSuccess)
- fprintf (stderr, "%s: couldn't grab pointer! (%s)\n",
- blurb(), grab_string(status));
}
+
+ if (mstatus != GrabSuccess)
+ fprintf (stderr, "%s: couldn't grab pointer! (%s)\n",
+ blurb(), grab_string(mstatus));
+
+ return (kstatus == GrabSuccess ||
+ mstatus == GrabSuccess);
}
-void
+static void
ungrab_keyboard_and_mouse (saver_info *si)
{
ungrab_mouse (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
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;
ssi->real_vroot_value = *vrootP;
}
+ XSync (dpy, False);
+ XSetErrorHandler (old_handler);
+ XSync (dpy, False);
+
if (ssi->real_vroot)
{
handle_signals (si, True);
catch_signal (si, SIGQUIT, on_p);
catch_signal (si, SIGILL, on_p);
catch_signal (si, SIGTRAP, on_p);
+#ifdef SIGIOT
catch_signal (si, SIGIOT, on_p);
+#endif
catch_signal (si, SIGABRT, on_p);
#ifdef SIGEMT
catch_signal (si, SIGEMT, on_p);
vrs = restore_real_vroot_1 (si);
emergency_kill_subproc (si);
+ shutdown_stderr (si);
- if (vrs && (p->verbose_p || status != 0))
- 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());
+ if (p->verbose_p && vrs)
+ fprintf (real_stderr, "%s: old vroot restored.\n", blurb());
fflush(real_stdout);
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 Bool error_handler_hit_p = False;
+
+static int
+ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
+{
+ error_handler_hit_p = True;
+ return 0;
+}
+
+
+/* Returns True if successful, False if an X error occurred.
+ We need this because other programs might have done things to
+ our window that will cause XChangeWindowAttributes() to fail:
+ if that happens, we give up, destroy the window, and re-create
+ it.
+ */
+static Bool
+safe_XChangeWindowAttributes (Display *dpy, Window window,
+ unsigned long mask,
+ XSetWindowAttributes *attrs)
+{
+ XErrorHandler old_handler;
+ XSync (dpy, False);
+ error_handler_hit_p = False;
+ old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
+
+ XChangeWindowAttributes (dpy, window, mask, attrs);
+
+ XSync (dpy, False);
+ XSetErrorHandler (old_handler);
+ XSync (dpy, False);
+
+ return (!error_handler_hit_p);
+}
+
+
+/* This might not be necessary, but just in case. */
+static Bool
+safe_XConfigureWindow (Display *dpy, Window window,
+ unsigned long mask, XWindowChanges *changes)
+{
+ XErrorHandler old_handler;
+ XSync (dpy, False);
+ error_handler_hit_p = False;
+ old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
+
+ XConfigureWindow (dpy, window, mask, changes);
+
+ XSync (dpy, False);
+ XSetErrorHandler (old_handler);
+ XSync (dpy, False);
+
+ return (!error_handler_hit_p);
+}
+
+/* This might not be necessary, but just in case. */
+static Bool
+safe_XDestroyWindow (Display *dpy, Window window)
+{
+ XErrorHandler old_handler;
+ XSync (dpy, False);
+ error_handler_hit_p = False;
+ old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
+
+ XDestroyWindow (dpy, window);
+
+ XSync (dpy, False);
+ XSetErrorHandler (old_handler);
+ XSync (dpy, False);
+
+ return (!error_handler_hit_p);
+}
+
+
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 || p->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
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. */
+ Window horked_window = 0;
+
+ get_screen_viewport (ssi, &x, &y, &width, &height,
+ (p->verbose_p && !si->screen_blanked_p));
black.red = black.green = black.blue = 0;
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;
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);
{
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;
- XConfigureWindow (si->dpy, ssi->screensaver_window,
- changesmask, &changes);
- XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
- attrmask, &attrs);
+ if (! (safe_XConfigureWindow (si->dpy, ssi->screensaver_window,
+ changesmask, &changes) &&
+ safe_XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
+ attrmask, &attrs)))
+ {
+ horked_window = ssi->screensaver_window;
+ ssi->screensaver_window = 0;
+ }
}
- else
+
+ if (!ssi->screensaver_window)
{
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 (horked_window)
+ {
+ fprintf (stderr,
+ "%s: someone horked our saver window (0x%lx)! Recreating it...\n",
+ blurb(), (unsigned long) horked_window);
+ maybe_transfer_grabs (ssi, horked_window, ssi->screensaver_window);
+ safe_XDestroyWindow (si->dpy, horked_window);
+ horked_window = 0;
+ }
+
if (p->verbose_p)
fprintf (stderr, "%s: saver window is 0x%lx.\n",
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 ());
+ store_saver_id (ssi); /* store window name and IDs */
-# 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 */
-
- 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
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 && si->fading_possible_p && !inhibit_fade && !si->demo_mode_p)
+ if (p->fade_p && si->fading_possible_p && !inhibit_fade)
{
Window *current_windows = (Window *)
calloc(sizeof(Window), si->nscreens);
}
}
-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.
*/
- grab_keyboard_and_mouse (si,
- /*si->screens[0].screensaver_window,*/
- RootWindowOfScreen(si->screens[0].screen),
- (si->demo_mode_p ? 0 : si->screens[0].cursor));
+ 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++)
{
store_vroot_property (si->dpy,
ssi->screensaver_window,
ssi->screensaver_window);
- }
- store_activate_time (si, si->screen_blanked_p);
- raise_window (si, False, False, False);
-#ifdef HAVE_XHPDISABLERESET
- if (si->locked_p && !hp_locked_p)
- {
- XHPDisableReset (si->dpy); /* turn off C-Sh-Reset */
- hp_locked_p = True;
+#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 */
}
-#endif
-#ifdef HAVE_VT_LOCKSWITCH
- if (si->locked_p)
- lock_vt (si, True); /* turn off C-Alt-Fn */
-#endif
+ raise_window (si, False, False, False);
si->screen_blanked_p = True;
+ si->blank_time = time ((time_t) 0);
+ si->last_wall_clock_time = 0;
+
+ store_saver_status (si); /* store blank time */
+
+ 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->fading_possible_p && !si->demo_mode_p)
+ if (si->demoing_p)
+ unfade_p = False;
+
+ if (unfade_p)
{
Window *current_windows = (Window *)
calloc(sizeof(Window), si->nscreens);
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
-
-#ifdef HAVE_VT_LOCKSWITCH
- lock_vt (si, False); /* turn C-Alt-Fn back on */
-#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.)
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;
+
+ store_saver_status (si); /* store unblank time */
}
+/* Transfer any grabs from the old window to the new.
+ Actually I think none of this is necessary, since we always
+ hold our grabs on the root window, but I wrote this before
+ re-discovering that...
+ */
static void
-store_activate_time (saver_info *si, Bool use_last_p)
+maybe_transfer_grabs (saver_screen_info *ssi,
+ Window old_w, Window new_w)
{
- 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;
+ saver_info *si = ssi->global;
- for (i = 0; i < si->nscreens; i++)
+ /* If the old window held our mouse grab, transfer the grab to the new
+ window. (Grab the server while so doing, to avoid a race condition.)
+ */
+ if (old_w == si->mouse_grab_window)
{
- 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);
+ XGrabServer (si->dpy); /* ############ DANGER! */
+ ungrab_mouse (si);
+ grab_mouse (si, ssi->screensaver_window,
+ (si->demoing_p
+ ? 0
+ : ssi->cursor));
+ XUngrabServer (si->dpy);
+ XSync (si->dpy, False); /* ###### (danger over) */
+ }
+
+ /* If the old window held our keyboard grab, transfer the grab to the new
+ window. (Grab the server while so doing, to avoid a race condition.)
+ */
+ if (old_w == si->keyboard_grab_window)
+ {
+ XGrabServer (si->dpy); /* ############ DANGER! */
+ ungrab_kbd(si);
+ grab_kbd(si, ssi->screensaver_window);
+ XUngrabServer (si->dpy);
+ XSync (si->dpy, False); /* ###### (danger over) */
}
}
+
Bool
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);
+ else if (!strcmp(visual_name, "gl") ||
+ !strcmp(visual_name, "Gl") ||
+ !strcmp(visual_name, "GL"))
+ {
+ new_v = ssi->best_gl_visual;
+ if (!new_v && p->verbose_p)
+ fprintf (stderr, "%s: no GL visuals.\n", progname);
+ }
+
+ if (!new_v)
+ new_v = get_visual (ssi->screen, visual_name, True, False);
}
else
{
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;
raise_window (si, True, True, False);
store_vroot_property (si->dpy,
ssi->screensaver_window, ssi->screensaver_window);
- store_activate_time (si, True);
-
+ /* Transfer any grabs from the old window to the new. */
+ maybe_transfer_grabs (ssi, old_w, ssi->screensaver_window);
- /* Transfer the grabs from the old window to the new.
- Actually I think none of this is necessary, since we always
- hold our grabs on the root window, but I wrote this before
- re-discovering that...
- */
-
-
- /* If we're destroying the window that holds our mouse grab,
- transfer the grab to the new window. (Grab the server while
- so doing, to avoid a race condition.)
- */
- 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));
- XUngrabServer (si->dpy);
- XSync (si->dpy, False); /* ###### (danger over) */
- }
-
- /* If we're destroying the window that holds our keyboard grab,
- transfer the grab to the new window. (Grab the server while
- so doing, to avoid a race condition.)
- */
- if (old_w == si->keyboard_grab_window)
- {
- XGrabServer (si->dpy); /* ############ DANGER! */
- ungrab_kbd(si);
- grab_kbd(si, ssi->screensaver_window);
- XUngrabServer (si->dpy);
- XSync (si->dpy, False); /* ###### (danger over) */
- }
-
- /* Now we can destroy this window without horking our grabs. */
-
+ /* Now we can destroy the old window without horking our grabs. */
XDestroyWindow (si->dpy, old_w);
if (p->verbose_p)
return got_it;
}
-
-\f
-/* VT locking */
-
-#ifdef HAVE_VT_LOCKSWITCH
-static void
-lock_vt (saver_info *si, Bool lock_p)
-{
- saver_preferences *p = &si->prefs;
- static Bool locked_p = False;
- const char *dev_console = "/dev/console";
- int fd;
-
- if (lock_p == locked_p)
- return;
-
- if (lock_p && !p->lock_vt_p)
- return;
-
- fd = open (dev_console, O_RDWR);
- if (fd < 0)
- {
- char buf [255];
- sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
- (lock_p ? "lock" : "unlock"),
- dev_console);
-#if 0 /* #### doesn't work yet, so don't bother complaining */
- perror (buf);
-#endif
- return;
- }
-
- if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
- {
- locked_p = lock_p;
-
- if (p->verbose_p)
- fprintf (stderr, "%s: %s VTs\n", blurb(),
- (lock_p ? "locked" : "unlocked"));
- }
- else
- {
- char buf [255];
- sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
- (lock_p ? "lock" : "unlock"));
-#if 0 /* #### doesn't work yet, so don't bother complaining */
- perror (buf);
-#endif
- }
-
- close (fd);
-}
-#endif /* HAVE_VT_LOCKSWITCH */