/* 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
extern saver_info *global_si_kludge; /* I hate C so much... */
+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);
}
+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);
+
+ 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);
}
+/* 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
+maybe_transfer_grabs (saver_screen_info *ssi,
+ Window old_w, Window new_w)
+{
+ saver_info *si = ssi->global;
+
+ /* 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)
+ {
+ 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)
{
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);
store_vroot_property (si->dpy,
ssi->screensaver_window, ssi->screensaver_window);
+ /* 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->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. */
-
+ /* Now we can destroy the old window without horking our grabs. */
XDestroyWindow (si->dpy, old_w);
if (p->verbose_p)