-
-/* 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;
- saver_preferences *p = &si->prefs;
- int event, error;
- int dot;
- XF86VidModeModeLine ml;
- int x, y;
- Bool xinerama_p = si->xinerama_p;
-
-# ifndef 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)
- {
- int mouse_p = (target_x != -1 && target_y != -1);
- int which = -1;
- int i;
-
- /* If a mouse position wasn't passed in, assume we're talking about
- this screen. */
- if (!mouse_p)
- {
- target_x = ssi->x;
- target_y = ssi->y;
- which = ssi->number;
- }
-
- /* Find the Xinerama rectangle that contains the mouse position. */
- for (i = 0; i < si->nscreens; i++)
- {
- if (which == -1 &&
- target_x >= si->screens[i].x &&
- target_y >= si->screens[i].y &&
- target_x < si->screens[i].x + si->screens[i].width &&
- target_y < si->screens[i].y + si->screens[i].height)
- which = i;
- }
- if (which == -1) which = 0; /* didn't find it? Use the first. */
- *x_ret = si->screens[which].x;
- *y_ret = si->screens[which].y;
- *w_ret = si->screens[which].width;
- *h_ret = si->screens[which].height;
-
- if (verbose_p)
- {
- fprintf (stderr, "%s: %d: xinerama vp: %dx%d+%d+%d",
- blurb(), which,
- si->screens[which].width, si->screens[which].height,
- si->screens[which].x, si->screens[which].y);
- if (mouse_p)
- fprintf (stderr, "; mouse at %d,%d", target_x, target_y);
- fprintf (stderr, ".\n");
- }
-
- return;
- }
-# endif /* HAVE_XINERAMA */
-
- if (!xinerama_p && /* Xinerama + VidMode = broken. */
- XF86VidModeQueryExtension (si->dpy, &event, &error) &&
- safe_XF86VidModeGetViewPort (si->dpy, ssi->number, &x, &y) &&
- XF86VidModeGetModeLine (si->dpy, ssi->number, &dot, &ml))
- {
- 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);
-
-
- if (p->getviewport_full_of_lies_p)
- {
- /* XF86VidModeGetViewPort() tends to be full of lies on laptops
- that have a docking station or external monitor that runs in
- a different resolution than the laptop's screen:
-
- http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=81593
- http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=208417
- http://bugs.xfree86.org/show_bug.cgi?id=421
-
- The XFree86 developers have closed the bug. As far as I can
- tell, their reason for this was, "this is an X server bug,
- but it's pretty hard to fix. Therefore, we are closing it."
-
- So, now there's a preference item for those unfortunate users to
- tell us not to trust a word that XF86VidModeGetViewPort() says.
- */
- static int warned_once = 0;
- if (!warned_once && verbose_p)
- {
- warned_once = 1;
- fprintf (stderr,
- "%s: %d: XF86VidModeGetViewPort() says vp is %dx%d+%d+%d;\n"
- "%s: %d: assuming that is a pack of lies;\n"
- "%s: %d: using %dx%d+0+0 instead.\n",
- blurb(), ssi->number,
- *w_ret, *h_ret, *x_ret, *y_ret,
- blurb(), ssi->number,
- blurb(), ssi->number, w, h);
- }
-
- *x_ret = 0;
- *y_ret = 0;
- *w_ret = w;
- *h_ret = h;
- return;
- }
-
-
- /* 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;
-}
-
-