+/* Go through the list of Xinerama screen descriptions, and mark the
+ ones that appear to be insane, so that we don't use them.
+ */
+static void
+check_xinerama_sanity (int count, Bool verbose_p, XineramaScreenInfo *xsi)
+{
+ static Bool printed_p = False;
+ int i, j;
+ char err[1024];
+ *err = 0;
+
+# define X1 xsi[i].x_org
+# define X2 xsi[j].x_org
+# define Y1 xsi[i].y_org
+# define Y2 xsi[j].y_org
+# define W1 xsi[i].width
+# define W2 xsi[j].width
+# define H1 xsi[i].height
+# define H2 xsi[j].height
+
+# define WHINE() do { \
+ if (verbose_p) { \
+ if (! printed_p) { \
+ fprintf (stderr, "%s: compensating for Xinerama braindamage:\n", \
+ blurb()); \
+ printed_p = True; \
+ } \
+ fprintf (stderr, "%s: %d: %s\n", blurb(), xsi[i].screen_number,err); \
+ } \
+ xsi[i].screen_number = -1; \
+ } while(0)
+
+ /* If a screen is enclosed by any other screen, that's insane.
+ */
+ for (i = 0; i < count; i++)
+ for (j = 0; j < count; j++)
+ if (i != j &&
+ xsi[i].screen_number >= 0 &&
+ xsi[j].screen_number >= 0 &&
+ X1 >= X2 && Y1 >= Y2 && (X1+W1) <= (X2+W2) && (X1+H1) <= (X2+H2))
+ {
+ sprintf (err, "%dx%d+%d+%d enclosed by %dx%d+%d+%d",
+ W1, H1, X1, Y1,
+ W2, H2, X2, Y2);
+ WHINE();
+ continue;
+ }
+
+ /* After checking for enclosure, check for other lossage against earlier
+ screens. We do enclosure first so that we make sure to pick the
+ larger one.
+ */
+ for (i = 0; i < count; i++)
+ for (j = 0; j < i; j++)
+ {
+ if (xsi[i].screen_number < 0) continue; /* already marked */
+
+ *err = 0;
+ if (X1 == X2 && Y1 == Y2 && W1 == W2 && H1 == H2)
+ sprintf (err, "%dx%d+%d+%d duplicated", W1, H1, X1, Y1);
+
+ else if (screens_overlap_p (&xsi[i], &xsi[j]))
+ sprintf (err, "%dx%d+%d+%d overlaps %dx%d+%d+%d",
+ W1, H1, X1, Y1,
+ W2, H2, X2, Y2);
+
+ if (*err) WHINE();
+ }
+
+# undef X1
+# undef X2
+# undef Y1
+# undef Y2
+# undef W1
+# undef W2
+# undef H1
+# undef H2
+}
+
+#endif /* HAVE_XINERAMA */
+
+
+
+/* Examine all of the display's screens, and populate the `saver_screen_info'
+ structures. Make sure this is called after hack_environment() sets $PATH.
+ */
+static void
+initialize_per_screen_info (saver_info *si, Widget toplevel_shell)
+{
+ Bool found_any_writable_cells = False;
+ int i;
+
+# ifdef HAVE_XINERAMA
+ {
+ int event, error;
+ si->xinerama_p = (XineramaQueryExtension (si->dpy, &event, &error) &&
+ XineramaIsActive (si->dpy));
+ }
+
+ if (si->xinerama_p && ScreenCount (si->dpy) != 1)
+ {
+ si->xinerama_p = False;
+ if (si->prefs.verbose_p)
+ fprintf (stderr,
+ "%s: Xinerama AND %d screens? Disabling Xinerama support!\n",
+ blurb(), ScreenCount(si->dpy));
+ }
+
+ if (si->xinerama_p)
+ {
+ int nscreens = 0;
+ XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
+ if (!xsi)
+ si->xinerama_p = False;
+ else
+ {
+ int j = 0;
+ si->screens = (saver_screen_info *)
+ calloc(sizeof(saver_screen_info), nscreens);
+ check_xinerama_sanity (nscreens, si->prefs.verbose_p, xsi);
+ for (i = 0; i < nscreens; i++)
+ {
+ if (xsi[i].screen_number < 0) /* deemed insane */
+ continue;
+ si->screens[j].x = xsi[i].x_org;
+ si->screens[j].y = xsi[i].y_org;
+ si->screens[j].width = xsi[i].width;
+ si->screens[j].height = xsi[i].height;
+ j++;
+ }
+ si->nscreens = j;
+ XFree (xsi);
+ }
+ si->default_screen = &si->screens[0];
+ si->default_screen->real_screen_p = True;
+ }
+# endif /* !HAVE_XINERAMA */
+
+ if (!si->xinerama_p)
+ {
+ si->nscreens = ScreenCount(si->dpy);
+ si->screens = (saver_screen_info *)
+ calloc(sizeof(saver_screen_info), si->nscreens);
+ si->default_screen = &si->screens[DefaultScreen(si->dpy)];
+
+ for (i = 0; i < si->nscreens; i++)
+ {
+ saver_screen_info *ssi = &si->screens[i];
+ ssi->width = DisplayWidth (si->dpy, i);
+ ssi->height = DisplayHeight (si->dpy, i);
+ ssi->real_screen_p = True;
+ ssi->real_screen_number = i;
+ }
+ }
+
+
+# ifdef QUAD_MODE
+ /* In "quad mode", we use the Xinerama code to pretend that there are 4
+ screens for every physical screen, and run four times as many hacks...
+ */
+ if (si->prefs.quad_p)
+ {
+ int ns2 = si->nscreens * 4;
+ saver_screen_info *ssi2 = (saver_screen_info *)
+ calloc(sizeof(saver_screen_info), ns2);
+
+ for (i = 0; i < si->nscreens; i++)
+ {
+ saver_screen_info *old = &si->screens[i];
+
+ if (si->prefs.debug_p) old->width = old->width / 2;
+
+ ssi2[i*4 ] = *old;
+ ssi2[i*4+1] = *old;
+ ssi2[i*4+2] = *old;
+ ssi2[i*4+3] = *old;
+
+ ssi2[i*4 ].width /= 2;
+ ssi2[i*4 ].height /= 2;
+
+ ssi2[i*4+1].x += ssi2[i*4 ].width;
+ ssi2[i*4+1].width -= ssi2[i*4 ].width;
+ ssi2[i*4+1].height /= 2;
+
+ ssi2[i*4+2].y += ssi2[i*4 ].height;
+ ssi2[i*4+2].width /= 2;
+ ssi2[i*4+2].height -= ssi2[i*4 ].height;
+
+ ssi2[i*4+3].x += ssi2[i*4+2].width;
+ ssi2[i*4+3].y += ssi2[i*4+2].height;
+ ssi2[i*4+3].width -= ssi2[i*4+2].width;
+ ssi2[i*4+3].height -= ssi2[i*4+2].height;
+
+ ssi2[i*4+1].real_screen_p = False;
+ ssi2[i*4+2].real_screen_p = False;
+ ssi2[i*4+3].real_screen_p = False;
+ }
+
+ si->nscreens = ns2;
+ free (si->screens);
+ si->screens = ssi2;
+ si->default_screen = &si->screens[DefaultScreen(si->dpy) * 4];
+ si->xinerama_p = True;
+ }
+# endif /* QUAD_MODE */
+
+ /* finish initializing the screens.
+ */
+ for (i = 0; i < si->nscreens; i++)
+ {
+ saver_screen_info *ssi = &si->screens[i];
+ ssi->global = si;
+
+ ssi->number = i;
+ ssi->screen = ScreenOfDisplay (si->dpy, ssi->real_screen_number);
+ ssi->poll_mouse_last_root_x = -1;
+ ssi->poll_mouse_last_root_y = -1;
+
+ if (!si->xinerama_p)
+ {
+ ssi->width = WidthOfScreen (ssi->screen);
+ ssi->height = HeightOfScreen (ssi->screen);
+ }
+
+ /* Note: we can't use the resource ".visual" because Xt is SO FUCKED. */
+ ssi->default_visual =
+ get_visual_resource (ssi->screen, "visualID", "VisualID", False);
+
+ ssi->current_visual = ssi->default_visual;
+ ssi->current_depth = visual_depth (ssi->screen, ssi->current_visual);
+
+ /* Execute a subprocess to find the GL visual. */
+ ssi->best_gl_visual = get_best_gl_visual (ssi);
+
+ if (ssi == si->default_screen)
+ /* Since this is the default screen, use the one already created. */
+ ssi->toplevel_shell = toplevel_shell;
+ else
+ /* Otherwise, each screen must have its own unmapped root widget. */
+ ssi->toplevel_shell =
+ XtVaAppCreateShell (progname, progclass, applicationShellWidgetClass,
+ si->dpy,
+ XtNscreen, ssi->screen,
+ XtNvisual, ssi->current_visual,
+ XtNdepth, visual_depth (ssi->screen,
+ ssi->current_visual),
+ NULL);
+
+ if (! found_any_writable_cells)
+ {
+ /* Check to see whether fading is ever possible -- if any of the
+ screens on the display has a PseudoColor visual, then fading can
+ work (on at least some screens.) If no screen has a PseudoColor
+ visual, then don't bother ever trying to fade, because it will
+ just cause a delay without causing any visible effect.
+ */
+ if (has_writable_cells (ssi->screen, ssi->current_visual) ||
+ get_visual (ssi->screen, "PseudoColor", True, False) ||
+ get_visual (ssi->screen, "GrayScale", True, False))
+ found_any_writable_cells = True;