/* 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
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 | \
grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor)
{
Status mstatus, kstatus;
- XSync (si->dpy, False);
+ int i;
+ int retries = 4;
- kstatus = grab_kbd (si, window);
- if (kstatus != GrabSuccess)
- { /* try again in a second */
- sleep (1);
+ for (i = 0; i < retries; i++)
+ {
+ XSync (si->dpy, False);
kstatus = grab_kbd (si, window);
- if (kstatus != GrabSuccess)
- fprintf (stderr, "%s: couldn't grab keyboard! (%s)\n",
- blurb(), grab_string(kstatus));
- }
+ if (kstatus == GrabSuccess)
+ break;
- mstatus = grab_mouse (si, window, cursor);
- if (mstatus != GrabSuccess)
- { /* try again in a second */
+ /* else, wait a second and try to grab again. */
sleep (1);
+ }
+
+ 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)
- fprintf (stderr, "%s: couldn't grab pointer! (%s)\n",
- blurb(), grab_string(mstatus));
+ if (mstatus == GrabSuccess)
+ break;
+
+ /* else, wait a second and try to grab again. */
+ sleep (1);
}
+ if (mstatus != GrabSuccess)
+ fprintf (stderr, "%s: couldn't grab pointer! (%s)\n",
+ blurb(), grab_string(mstatus));
+
return (kstatus == GrabSuccess ||
mstatus == GrabSuccess);
}
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);
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;
}
+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
#ifdef HAVE_XF86VMODE
saver_info *si = ssi->global;
int screen_no = screen_number (ssi->screen);
- int event, error;
+ int op, event, error;
int dot;
XF86VidModeModeLine ml;
int x, y;
- if (XF86VidModeQueryExtension (si->dpy, &event, &error) &&
+ /* 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))
{
/* 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);
}
+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)
{
unsigned long attrmask;
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));
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),
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);
}
-
- store_saver_id (ssi);
+ store_saver_id (ssi); /* store window name and IDs */
if (!ssi->cursor)
{
}
#endif /* HAVE_XF86VMODE */
}
- store_activate_time (si, si->screen_blanked_p);
+
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)
{
int i;
monitor_power_on (si);
-
- store_activate_time (si, True);
reset_watchdog_timer (si, False);
if (si->demoing_p)
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);
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)
{
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;
}
-#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);
+ new_v = ssi->best_gl_visual;
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);
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.
- 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->demoing_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. */
+ /* Transfer any grabs from the old window to the new. */
+ maybe_transfer_grabs (ssi, old_w, ssi->screensaver_window);
+ /* Now we can destroy the old window without horking our grabs. */
XDestroyWindow (si->dpy, old_w);
if (p->verbose_p)