-
-/* 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,
- int target_x, int target_y,
- Bool verbose_p)
-{
- int w = WidthOfScreen (ssi->screen);
- int h = HeightOfScreen (ssi->screen);
-
-#ifdef HAVE_XF86VMODE
- saver_info *si = ssi->global;
- int event, error;
- int dot;
- XF86VidModeModeLine ml;
- int x, y;
- Bool xinerama_p;
- Bool placement_only_p = (target_x != -1 && target_y != -1);
-
-#ifdef HAVE_XINERAMA
- xinerama_p = (XineramaQueryExtension (si->dpy, &event, &error) &&
- XineramaIsActive (si->dpy));
-#else /* !HAVE_XINERAMA */
- /* Even if we don't have the client-side Xinerama lib, check to see if
- the server supports Xinerama, so that we know to ignore the VidMode
- extension -- otherwise a server crash could result. Yay. */
- xinerama_p = XQueryExtension (si->dpy, "XINERAMA", &error, &event, &error);
-
-#endif /* !HAVE_XINERAMA */
-
-#ifdef HAVE_XINERAMA
- if (xinerama_p && placement_only_p)
- {
- int nscreens = 0;
- XineramaScreenInfo *xsi = XineramaQueryScreens (si->dpy, &nscreens);
- if (xsi)
- {
- /* Find the screen that contains the mouse. */
- int which = -1;
- int i;
- for (i = 0; i < nscreens; i++)
- {
- if (target_x >= xsi[i].x_org &&
- target_y >= xsi[i].y_org &&
- target_x < xsi[i].x_org + xsi[i].width &&
- target_y < xsi[i].y_org + xsi[i].height)
- which = i;
- if (verbose_p)
- {
- fprintf (stderr, "%s: %d: xinerama vp: %dx%d+%d+%d",
- blurb(), i,
- xsi[which].width, xsi[which].height,
- xsi[i].x_org, xsi[i].y_org);
- if (which == i)
- fprintf (stderr, "; mouse at %d,%d",
- target_x, target_y);
- fprintf (stderr, ".\n");
- }
- }
- if (which == -1) which = 0; /* didn't find it? Use the first. */
- *x_ret = xsi[which].x_org;
- *y_ret = xsi[which].y_org;
- *w_ret = xsi[which].width;
- *h_ret = xsi[which].height;
- XFree (xsi);
- return;
- }
- }
-#endif /* HAVE_XINERAMA */
-
- if (!xinerama_p && /* Xinerama + VidMode = broken. */
- XF86VidModeQueryExtension (si->dpy, &event, &error) &&
- XF86VidModeGetModeLine (si->dpy, ssi->number, &dot, &ml) &&
- XF86VidModeGetViewPort (si->dpy, ssi->number, &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: %d: vp is %dx%d+%d+%d",
- blurb(), ssi->number,
- *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;
-}
-
-