1 /* screens.c --- dealing with RANDR, Xinerama, and VidMode Viewports.
2 * xscreensaver, Copyright (c) 1991-2008 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
13 /* There are a bunch of different mechanisms for multiple monitors
14 * available in X. XScreenSaver needs to care about this for two
15 * reasons: first, to ensure that all visible areas go black; and
16 * second, so that the windows of screen savers exactly fill the
17 * glass of each monitor (instead of one saver spanning multiple
18 * monitors, or a monitor displaying only a sub-rectangle of the
23 * This is the original way. Each monitor gets its own display
24 * number. :0.0 is the first one, :0.1 is the next, etc. The
25 * value of $DISPLAY determines which screen windows open on by
26 * default. A single app can open windows on multiple screens
27 * with the same display connection, but windows cannot be moved
28 * from one screen to another. The mouse can be moved from one
29 * screen to another, though. Screens may be different depths
30 * (e.g., one can be TrueColor and one can be PseudoColor.)
31 * Screens cannot be resized or moved without restarting X.
33 * Everyone hates this way of doing things because of the
34 * inability to move a window from one screen to another without
35 * restarting the application.
39 * There is a single giant root window that spans all the
40 * monitors. All monitors are the same depth, and windows can be
41 * moved around. Applications can learn which rectangles are
42 * actually visible on monitors by querying the Xinerama server
43 * extension. (If you don't do that, you end up with dialog
44 * boxes that try to appear in the middle of the screen actually
45 * spanning the gap between two monitors.)
47 * Xinerama doesn't work with DRI, which means that if you use
48 * it, you lose hardware acceleration on OpenGL programs. Also,
49 * screens can't be resized or moved without restarting X.
51 * 3) Vidmode Viewports:
53 * With this extension, the root window can be bigger than the
54 * monitor. Moving the mouse near the edges of the screen
55 * scrolls around, like a pan-and-scan movie. There can also be
56 * a hot key for changing the monitor's resolution (zooming
59 * Trying to combine this with Xinerama crashes the server, so
60 * you can only use this if you have only a single screen, or are
61 * in old-multi-screen mode.
63 * Also, half the time it doesn't work at all: it tends to lie
64 * about the size of the rectangle in use.
68 * The first version of the "Resize and Rotate" extension let you
69 * change the resolution of a screen on the fly. The root window
70 * would actually resize. However, it was also incompatible with
71 * Xinerama (did it crash, or just do nothing? I can't remember)
72 * so you needed to be in single-screen or old multi-screen mode.
73 * I believe RANDR could co-exist with Vidmode Viewports, but I'm
78 * Finally, RANDR added the functionality of Xinerama, plus some.
79 * Each X screen (in the sense of #1, "multi-screen") can have a
80 * number of sub-rectangles that are displayed on monitors, and
81 * each of those sub-rectangles can be displayed on more than one
82 * monitor. So it's possible (I think) to have a hybrid of
83 * multi-screen and Xinerama (e.g., to have two monitors running
84 * in one depth, and three monitors running in another?)
85 * Typically though, there will be a single X screen, with
86 * Xinerama-like division of that large root window onto multiple
87 * monitors. Also everything's dynamic: monitors can be added,
88 * removed, and resized at runtime.
90 * I believe that as of RANDR 1.2, the Xinerama extension still
91 * exists but only as a compatiblity layer: it's actually
92 * returning data from the RANDR extension.
94 * Though RANDR 1.2 allows the same image to be cloned onto more
95 * than one monitor, and also allows one monitor to show a
96 * subsection of something on another monitor (e.g., the
97 * rectangles can be enclosed or overlap). Since there's no way
98 * to put seperate savers on those duplicated-or-overlapping
99 * monitors, xscreensaver just ignores them (which allows them to
100 * display duplicates or overlaps).
102 * 5a) Nvidia fucks it up:
104 * Nvidia drivers as of Aug 2008 running in "TwinView" mode
105 * apparently report correct screen geometry via Xinerama, but
106 * report one giant screen via RANDR. The response from the
107 * nvidia developers is, "we don't support RANDR, use Xinerama
108 * instead." Which is a seriously lame answer. So, xscreensaver
109 * has to query *both* extensions, and make a guess as to which
112 * 5b) Also sometimes RANDR says stupid shit like, "You have one
113 * screen, and it has no available orientations or sizes."
121 #include <X11/Xlib.h>
124 # include <X11/extensions/Xrandr.h>
125 #endif /* HAVE_RANDR */
128 # include <X11/extensions/Xinerama.h>
129 #endif /* HAVE_XINERAMA */
131 #ifdef HAVE_XF86VMODE
132 # include <X11/extensions/xf86vmode.h>
133 #endif /* HAVE_XF86VMODE */
135 /* This file doesn't need the Xt headers, so stub these types out... */
137 #define XtAppContext void*
138 #define XrmDatabase void*
139 #define XtIntervalId void*
140 #define XtPointer void*
143 #include "xscreensaver.h"
147 typedef enum { S_SANE, S_ENCLOSED, S_DUPLICATE, S_OVERLAP,
148 S_OFFSCREEN, S_DISABLED } monitor_sanity;
150 /* 'typedef monitor' is in types.h */
155 int x, y, width, height;
156 monitor_sanity sanity; /* I'm not crazy you're the one who's crazy */
157 int enemy; /* which monitor it overlaps or duplicates */
158 char *err; /* msg to print at appropriate later time;
159 exists only on monitor #0. */
162 static Bool layouts_differ_p (monitor **a, monitor **b);
166 free_monitors (monitor **monitors)
168 monitor **m2 = monitors;
169 if (! monitors) return;
172 if ((*m2)->desc) free ((*m2)->desc);
173 if ((*m2)->err) free ((*m2)->err);
182 append (char *s1, const char *s2)
184 char *s = (char *) malloc ((s1 ? strlen(s1) : 0) +
185 (s2 ? strlen(s2) : 0) + 3);
187 if (s1) strcat (s, s1);
188 if (s1 && s2) strcat (s, "\n");
189 if (s2) strcat (s, s2);
198 xinerama_scan_monitors (Display *dpy, char **errP)
200 Screen *screen = DefaultScreenOfDisplay (dpy);
201 int event, error, nscreens, i;
202 XineramaScreenInfo *xsi;
205 if (! XineramaQueryExtension (dpy, &event, &error))
208 if (! XineramaIsActive (dpy))
211 xsi = XineramaQueryScreens (dpy, &nscreens);
214 monitors = (monitor **) calloc (nscreens + 1, sizeof(*monitors));
215 if (!monitors) return 0;
217 for (i = 0; i < nscreens; i++)
219 monitor *m = (monitor *) calloc (1, sizeof (monitor));
225 m->width = xsi[i].width;
226 m->height = xsi[i].height;
231 #endif /* HAVE_XINERAMA */
234 #ifdef HAVE_XF86VMODE
237 vidmode_scan_monitors (Display *dpy, char **errP)
239 int event, error, nscreens, i;
242 /* Note that XF86VidModeGetViewPort() tends to be full of lies on laptops
243 that have a docking station or external monitor that runs in a different
244 resolution than the laptop's screen:
246 http://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=81593
247 http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=208417
248 http://bugs.xfree86.org/show_bug.cgi?id=421
250 Presumably this is fixed by using RANDR instead of VidMode.
253 # ifdef HAVE_XINERAMA
254 /* Attempts to use the VidMode extension when the Xinerama extension is
255 active can result in a server crash! Yay! */
256 if (XQueryExtension (dpy, "XINERAMA", &error, &event, &error))
258 # endif /* !HAVE_XINERAMA */
260 if (! XF86VidModeQueryExtension (dpy, &event, &error))
263 nscreens = ScreenCount (dpy);
264 monitors = (monitor **) calloc (nscreens + 1, sizeof(*monitors));
265 if (!monitors) return 0;
267 for (i = 0; i < nscreens; i++)
269 monitor *m = (monitor *) calloc (1, sizeof (monitor));
270 XF86VidModeModeLine ml;
272 Screen *screen = ScreenOfDisplay (dpy, i);
278 if (! safe_XF86VidModeGetViewPort (dpy, i, &m->x, &m->y))
281 if (XF86VidModeGetModeLine (dpy, i, &dot, &ml))
283 m->width = ml.hdisplay;
284 m->height = ml.vdisplay;
287 /* On a system that has VidMode but does not have RANDR, and that has
288 "Option Rotate" set, WidthOfScreen/HeightOfScreen are the rotated
289 size, but XF86VidModeModeLine contains the unrotated size.
290 Maybe there's something in 'flags' that indicates this?
291 Or, we can just notice that the aspect ratios are inverted:
295 ((m->width > m->height) !=
296 (WidthOfScreen(screen) > HeightOfScreen(screen))))
299 m->width = m->height;
304 /* Apparently, though the server stores the X position in increments of
305 1 pixel, it will only make changes to the *display* in some other
306 increment. With XF86_SVGA on a Thinkpad, the display only updates
307 in multiples of 8 pixels when in 8-bit mode, and in multiples of 4
308 pixels in 16-bit mode. I don't know what it does in 24- and 32-bit
309 mode, because I don't have enough video memory to find out.
311 I consider it a bug that XF86VidModeGetViewPort() is telling me the
312 server's *target* scroll position rather than the server's *actual*
313 scroll position. David Dawes agrees, and says they may fix this in
314 XFree86 4.0, but it's nontrivial.
316 He also confirms that this behavior is server-dependent, so the
317 actual scroll position cannot be reliably determined by the client.
318 So... that means the only solution is to provide a ``sandbox''
319 around the blackout window -- we make the window be up to N pixels
320 larger than the viewport on both the left and right sides. That
321 means some part of the outer edges of each hack might not be
322 visible, but screw it.
324 I'm going to guess that 16 pixels is enough, and that the Y dimension
325 doesn't have this problem.
327 The drawback of doing this, of course, is that some of the screenhacks
328 will still look pretty stupid -- for example, "slidescreen" will cut
329 off the left and right edges of the grid, etc.
332 if (m->x > 0 && m->x < m->width - ml.hdisplay)
334 /* Not at left edge or right edge:
335 Round X position down to next lower multiple of FUDGE.
336 Increase width by 2*FUDGE in case some server rounds up.
338 m->x = ((m->x - 1) / FUDGE) * FUDGE;
339 m->width += (FUDGE * 2);
347 #endif /* HAVE_XF86VMODE */
353 randr_scan_monitors (Display *dpy, char **errP)
355 int event, error, major, minor, nscreens, i, j;
357 Bool new_randr_p = False;
359 if (! XRRQueryExtension (dpy, &event, &error))
362 if (! XRRQueryVersion (dpy, &major, &minor))
365 if (major <= 0) /* Protocol was still in flux back then -- fuck it. */
368 # ifdef HAVE_RANDR_12
369 new_randr_p = (major > 1 || (major == 1 && minor >= 2));
373 /* RANDR 1.0 -- no Xinerama-like virtual screens. */
374 nscreens = ScreenCount (dpy);
375 else /* RANDR 1.2 or newer -- built-in Xinerama */
377 # ifdef HAVE_RANDR_12
378 int xsc = ScreenCount (dpy);
380 /* Add up the virtual screens on each X screen. */
381 for (i = 0; i < xsc; i++)
383 XRRScreenResources *res =
384 XRRGetScreenResources (dpy, RootWindow (dpy, i));
385 nscreens += res->noutput;
386 XRRFreeScreenResources (res);
388 # endif /* HAVE_RANDR_12 */
393 *errP = append (*errP,
394 "WARNING: RANDR reported no screens! Ignoring it.");
398 monitors = (monitor **) calloc (nscreens + 1, sizeof(*monitors));
399 if (!monitors) return 0;
401 for (i = 0, j = 0; i < ScreenCount (dpy); i++)
403 Screen *screen = ScreenOfDisplay (dpy, i);
405 if (! new_randr_p) /* RANDR 1.0 */
407 XRRScreenConfiguration *rrc;
408 monitor *m = (monitor *) calloc (1, sizeof (monitor));
413 rrc = XRRGetScreenInfo (dpy, RootWindowOfScreen (screen));
418 XRRScreenSize *rrsizes;
421 size = XRRConfigCurrentConfiguration (rrc, &rot);
422 rrsizes = XRRConfigSizes (rrc, &nsizes);
424 if (nsizes <= 0) /* WTF? Shouldn't happen but does. */
426 m->width = DisplayWidth (dpy, i);
427 m->height = DisplayHeight (dpy, i);
429 else if (rot & (RR_Rotate_90|RR_Rotate_270))
431 m->width = rrsizes[size].height;
432 m->height = rrsizes[size].width;
436 m->width = rrsizes[size].width;
437 m->height = rrsizes[size].height;
440 /* don't free 'rrsizes' */
441 XRRFreeScreenConfigInfo (rrc);
444 else /* RANDR 1.2 or newer */
446 # ifdef HAVE_RANDR_12
448 XRRScreenResources *res =
449 XRRGetScreenResources (dpy, RootWindowOfScreen (screen));
450 for (k = 0; k < res->noutput; k++, j++)
452 monitor *m = (monitor *) calloc (1, sizeof (monitor));
453 XRROutputInfo *rroi = XRRGetOutputInfo (dpy, res,
455 RRCrtc crtc = (rroi->crtc ? rroi->crtc :
456 rroi->ncrtc ? rroi->crtcs[0] : 0);
457 XRRCrtcInfo *crtci = (crtc ? XRRGetCrtcInfo(dpy, res, crtc) : 0);
461 m->id = (i * 1000) + j;
462 m->desc = (rroi->name ? strdup (rroi->name) : 0);
466 /* Note: if the screen is rotated, XRRConfigSizes contains
467 the unrotated WxH, but XRRCrtcInfo contains rotated HxW.
471 m->width = crtci->width;
472 m->height = crtci->height;
475 if (rroi->connection == RR_Disconnected)
476 m->sanity = S_DISABLED;
477 /* #### do the same for RR_UnknownConnection? */
480 XRRFreeCrtcInfo (crtci);
481 XRRFreeOutputInfo (rroi);
483 XRRFreeScreenResources (res);
484 # endif /* HAVE_RANDR_12 */
488 /* Work around more fucking brain damage. */
494 if (monitors[i]->width != 0 && monitors[i]->height != 0)
500 *errP = append (*errP,
501 "WARNING: RANDR says all screens are 0x0! Ignoring it.");
502 free_monitors (monitors);
510 #endif /* HAVE_RANDR */
514 basic_scan_monitors (Display *dpy, char **errP)
516 int nscreens = ScreenCount (dpy);
518 monitor **monitors = (monitor **) calloc (nscreens + 1, sizeof(*monitors));
519 if (!monitors) return 0;
521 for (i = 0; i < nscreens; i++)
523 Screen *screen = ScreenOfDisplay (dpy, i);
524 monitor *m = (monitor *) calloc (1, sizeof (monitor));
530 m->width = WidthOfScreen (screen);
531 m->height = HeightOfScreen (screen);
537 #if defined(HAVE_RANDR) && defined(HAVE_XINERAMA)
539 /* From: Aaron Plattner <aplattner@nvidia.com>
540 Date: August 7, 2008 10:21:25 AM PDT
541 To: linux-bugs@nvidia.com
543 The NVIDIA X driver does not yet support RandR 1.2. The X server has
544 a compatibility layer in it that allows RandR 1.2 clients to talk to
545 RandR 1.1 drivers through an RandR 1.2 pseudo-output called "default".
546 This reports the total combined resolution of the TwinView display,
547 since it doesn't have any visibility into TwinView metamodes. There
548 is no way for the driver to prevent the server from turning on this
551 The intention is for X client applications to continue to use the
552 Xinerama extension to query the screen geometry. RandR 1.2 reports
553 its own Xinerama info for this purpose. I would recommend against
554 modifying xscreensaver to try to get this information from RandR.
557 randr_versus_xinerama_fight (Display *dpy, monitor **randr_monitors,
560 monitor **xinerama_monitors;
565 xinerama_monitors = xinerama_scan_monitors (dpy, errP);
566 if (!xinerama_monitors)
567 return randr_monitors;
569 if (! layouts_differ_p (randr_monitors, xinerama_monitors))
571 free_monitors (xinerama_monitors);
572 return randr_monitors;
574 else if ( randr_monitors[0] && !randr_monitors[1] && /* 1 monitor */
575 xinerama_monitors[0] && xinerama_monitors[1]) /* >1 monitor */
577 *errP = append (*errP,
578 "WARNING: RANDR reports 1 screen but Xinerama\n"
579 "\t\treports multiple. Believing Xinerama.");
580 free_monitors (randr_monitors);
581 return xinerama_monitors;
585 *errP = append (*errP,
586 "WARNING: RANDR and Xinerama report different\n"
587 "\t\tscreen layouts! Believing RANDR.");
588 free_monitors (xinerama_monitors);
589 return randr_monitors;
593 #endif /* HAVE_RANDR && HAVE_XINERAMA */
596 #ifdef DEBUG_MULTISCREEN
598 /* If DEBUG_MULTISCREEN is defined, then in "-debug" mode, xscreensaver
599 will pretend that it is changing the number of connected monitors
600 every few seconds, using the geometries in the following list,
601 for stress-testing purposes.
604 debug_scan_monitors (Display *dpy, char **errP)
606 static const char * const geoms[] = {
610 "800x600+0+22,800x600+800+22",
611 "800x600+0+22,800x600+800+22,800x600+300+622",
612 "800x600+0+22,800x600+800+22,800x600+0+622,800x600+800+622",
613 "640x480+0+22,640x480+640+22,640x480+0+502,640x480+640+502",
614 "640x480+240+22,640x480+0+502,640x480+640+502",
615 "640x480+0+200,640x480+640+200",
617 "320x200+0+22,320x200+320+22,320x200+640+22,320x200+960+22,320x200+0+222,320x200+320+222,320x200+640+222,320x200+960+222,320x200+0+422,320x200+320+422,320x200+640+422,320x200+960+422,320x200+0+622,320x200+320+622,320x200+640+622,320x200+960+622,320x200+0+822,320x200+320+822,320x200+640+822,320x200+960+822"
619 static int index = 0;
620 monitor **monitors = (monitor **) calloc (100, sizeof(*monitors));
622 Screen *screen = DefaultScreenOfDisplay (dpy);
624 char *s = strdup (geoms[index]);
625 char *token = strtok (s, ",");
628 monitor *m = calloc (1, sizeof (monitor));
632 if (4 != sscanf (token, "%dx%d+%d+%d%c",
633 &m->width, &m->height, &m->x, &m->y, &c))
637 monitors[nscreens++] = m;
638 token = strtok (0, ",");
642 index = (index+1) % countof(geoms);
646 #endif /* DEBUG_MULTISCREEN */
651 quadruple (monitor **monitors, Bool debug_p, char **errP)
655 while (monitors[count])
657 monitors2 = (monitor **) calloc (count * 4 + 1, sizeof(*monitors));
658 if (!monitors2) abort();
660 for (i = 0, j = 0; i < count; i++)
663 for (k = 0; k < 4; k++)
665 monitors2[j+k] = (monitor *) calloc (1, sizeof (monitor));
666 *monitors2[j+k] = *monitors[i];
667 monitors2[j+k]->width /= (debug_p ? 4 : 2);
668 monitors2[j+k]->height /= 2;
669 monitors2[j+k]->id = (monitors[i]->id * 4) + k;
670 monitors2[j+k]->name = (monitors[i]->name
671 ? strdup (monitors[i]->name) : 0);
673 monitors2[j+1]->x += monitors2[j]->width;
674 monitors2[j+2]->y += monitors2[j]->height;
675 monitors2[j+3]->x += monitors2[j]->width;
676 monitors2[j+3]->y += monitors2[j]->height;
680 free_monitors (monitors);
683 #endif /* QUAD_MODE */
687 scan_monitors (saver_info *si)
689 saver_preferences *p = &si->prefs;
690 monitor **monitors = 0;
693 # ifdef DEBUG_MULTISCREEN
694 if (! monitors) monitors = debug_scan_monitors (si->dpy, &err);
698 if (! p->getviewport_full_of_lies_p)
699 if (! monitors) monitors = randr_scan_monitors (si->dpy, &err);
701 # ifdef HAVE_XINERAMA
702 monitors = randr_versus_xinerama_fight (si->dpy, monitors, &err);
704 # endif /* HAVE_RANDR */
706 # ifdef HAVE_XF86VMODE
707 if (! monitors) monitors = vidmode_scan_monitors (si->dpy, &err);
710 # ifdef HAVE_XINERAMA
711 if (! monitors) monitors = xinerama_scan_monitors (si->dpy, &err);
714 if (! monitors) monitors = basic_scan_monitors (si->dpy, &err);
718 monitors = quadruple (monitors, p->debug_p, &err);
721 if (monitors && err) monitors[0]->err = err;
728 monitors_overlap_p (monitor *a, monitor *b)
730 /* Two rectangles overlap if the max of the tops is less than the
731 min of the bottoms and the max of the lefts is less than the min
736 # define MAX(A,B) ((A)>(B)?(A):(B))
737 # define MIN(A,B) ((A)<(B)?(A):(B))
739 int maxleft = MAX(a->x, b->x);
740 int maxtop = MAX(a->y, b->y);
741 int minright = MIN(a->x + a->width - 1, b->x + b->width);
742 int minbot = MIN(a->y + a->height - 1, b->y + b->height);
743 return (maxtop < minbot && maxleft < minright);
748 plausible_aspect_ratio_p (monitor **monitors)
750 /* Modern wide-screen monitors come in the following aspect ratios:
752 One monitor: If you tack a 640x480 monitor
753 onto the right, the ratio is:
755 852 x 480 --> 1.77 852+640 x 480 --> 3.11 "SD 480p"
756 1280 x 720 --> 1.78 1280+640 x 720 --> 2.67 "HD 720p"
757 1280 x 920 --> 1.39 1280+640 x 920 --> 2.09
758 1366 x 768 --> 1.78 1366+640 x 768 --> 2.61 "HD 768p"
759 1440 x 900 --> 1.60 1440+640 x 900 --> 2.31
760 1680 x 1050 --> 1.60 1680+640 x 1050 --> 2.21
761 1690 x 1050 --> 1.61 1690+640 x 1050 --> 2.22
762 1920 x 1080 --> 1.78 1920+640 x 1080 --> 2.37 "HD 1080p"
763 1920 x 1200 --> 1.60 1920+640 x 1200 --> 2.13
764 2560 x 1600 --> 1.60 2560+640 x 1600 --> 2.00
766 So that implies that if we ever see an aspect ratio >= 2.0,
767 we can be pretty sure that the X server is lying to us, and
768 that's actually two monitors, not one.
770 if (monitors[0] && !monitors[1] && /* exactly 1 monitor */
771 monitors[0]->height &&
772 monitors[0]->width / (double) monitors[0]->height >= 1.9)
779 /* Mark the ones that overlap, etc.
782 check_monitor_sanity (monitor **monitors)
786 while (monitors[count])
789 # define X1 monitors[i]->x
790 # define X2 monitors[j]->x
791 # define Y1 monitors[i]->y
792 # define Y2 monitors[j]->y
793 # define W1 monitors[i]->width
794 # define W2 monitors[j]->width
795 # define H1 monitors[i]->height
796 # define H2 monitors[j]->height
798 /* If a monitor is enclosed by any other monitor, that's insane.
800 for (i = 0; i < count; i++)
801 for (j = 0; j < count; j++)
803 monitors[i]->sanity == S_SANE &&
804 monitors[j]->sanity == S_SANE &&
805 monitors[i]->screen == monitors[j]->screen &&
808 (X2+W2) <= (X1+W1) &&
815 monitors[j]->sanity = S_DUPLICATE;
817 monitors[j]->sanity = S_ENCLOSED;
818 monitors[j]->enemy = i;
821 /* After checking for enclosure, check for other lossage against earlier
822 monitors. We do enclosure first so that we make sure to pick the
825 for (i = 0; i < count; i++)
826 for (j = 0; j < i; j++)
828 if (monitors[i]->sanity != S_SANE) continue; /* already marked */
829 if (monitors[j]->sanity != S_SANE) continue;
830 if (monitors[i]->screen != monitors[j]->screen) continue;
832 if (monitors_overlap_p (monitors[i], monitors[j]))
834 monitors[i]->sanity = S_OVERLAP;
835 monitors[i]->enemy = j;
839 /* Finally, make sure all monitors have sane positions and sizes.
840 Xinerama sometimes reports 1024x768 VPs at -1936862040, -1953705044.
842 for (i = 0; i < count; i++)
844 if (monitors[i]->sanity != S_SANE) continue; /* already marked */
845 if (X1 < 0 || Y1 < 0 ||
846 W1 <= 0 || H1 <= 0 ||
847 X1+W1 >= 0x7FFF || Y1+H1 >= 0x7FFF)
849 monitors[i]->sanity = S_OFFSCREEN;
850 monitors[i]->enemy = 0;
866 layouts_differ_p (monitor **a, monitor **b)
868 if (!a || !b) return True;
873 if ((*a)->screen != (*b)->screen ||
874 (*a)->x != (*b)->x ||
875 (*a)->y != (*b)->y ||
876 (*a)->width != (*b)->width ||
877 (*a)->height != (*b)->height)
890 describe_monitor_layout (saver_info *si)
892 monitor **monitors = si->monitor_layout;
896 int implausible_p = !plausible_aspect_ratio_p (monitors);
898 while (monitors[count])
900 if (monitors[count]->sanity == S_SANE)
907 if (monitors[0]->err) /* deferred error msg */
909 char *token = strtok (monitors[0]->err, "\n");
912 fprintf (stderr, "%s: %s\n", blurb(), token);
913 token = strtok (0, "\n");
915 free (monitors[0]->err);
916 monitors[0]->err = 0;
920 fprintf (stderr, "%s: no screens!\n", blurb());
924 fprintf (stderr, "%s: screens in use: %d\n", blurb(), good_count);
925 for (i = 0; i < count; i++)
927 monitor *m = monitors[i];
928 if (m->sanity != S_SANE) continue;
929 fprintf (stderr, "%s: %3d/%d: %dx%d+%d+%d",
930 blurb(), m->id, screen_number (m->screen),
931 m->width, m->height, m->x, m->y);
932 if (m->desc && *m->desc) fprintf (stderr, " (%s)", m->desc);
933 fprintf (stderr, "\n");
937 fprintf (stderr, "%s: rejected screens: %d\n", blurb(), bad_count);
938 for (i = 0; i < count; i++)
940 monitor *m = monitors[i];
941 monitor *e = monitors[m->enemy];
942 if (m->sanity == S_SANE) continue;
943 fprintf (stderr, "%s: %3d/%d: %dx%d+%d+%d",
944 blurb(), m->id, screen_number (m->screen),
945 m->width, m->height, m->x, m->y);
946 if (m->desc && *m->desc) fprintf (stderr, " (%s)", m->desc);
947 fprintf (stderr, " -- ");
950 case S_SANE: abort(); break;
952 fprintf (stderr, "enclosed by %d (%dx%d+%d+%d)\n",
953 e->id, e->width, e->height, e->x, e->y);
956 fprintf (stderr, "duplicate of %d\n", e->id);
959 fprintf (stderr, "overlaps %d (%dx%d+%d+%d)\n",
960 e->id, e->width, e->height, e->x, e->y);
963 fprintf (stderr, "off screen (%dx%d)\n",
964 WidthOfScreen (e->screen),
965 HeightOfScreen (e->screen));
968 fprintf (stderr, "output disabled\n");
976 "%s: WARNING: single screen aspect ratio is %dx%d = %.2f\n"
977 "%s: probable X server bug in Xinerama/RANDR!\n",
978 blurb(), monitors[0]->width, monitors[0]->height,
979 monitors[0]->width / (double) monitors[0]->height,
985 /* Synchronize the contents of si->ssi to the current state of the monitors.
986 Doesn't change anything if nothing has changed; otherwise, alters and
987 reuses existing saver_screen_info structs as much as possible.
988 Returns True if anything changed.
991 update_screen_layout (saver_info *si)
993 monitor **monitors = scan_monitors (si);
997 int seen_screens[100] = { 0, };
999 if (! layouts_differ_p (monitors, si->monitor_layout))
1001 free_monitors (monitors);
1005 free_monitors (si->monitor_layout);
1006 si->monitor_layout = monitors;
1007 check_monitor_sanity (si->monitor_layout);
1009 while (monitors[count])
1011 if (monitors[count]->sanity == S_SANE)
1016 if (si->ssi_count == 0)
1019 si->screens = (saver_screen_info *)
1020 calloc (sizeof(*si->screens), si->ssi_count);
1023 if (si->ssi_count <= good_count)
1025 si->ssi_count = good_count + 10;
1026 si->screens = (saver_screen_info *)
1027 realloc (si->screens, sizeof(*si->screens) * si->ssi_count);
1028 memset (si->screens + si->nscreens, 0,
1029 sizeof(*si->screens) * (si->ssi_count - si->nscreens));
1032 if (! si->screens) abort();
1034 si->nscreens = good_count;
1036 /* Regenerate the list of GL visuals as needed. */
1037 if (si->best_gl_visuals)
1038 free (si->best_gl_visuals);
1039 si->best_gl_visuals = 0;
1041 for (i = 0, j = 0; i < count; i++)
1043 monitor *m = monitors[i];
1044 saver_screen_info *ssi = &si->screens[j];
1045 Screen *old_screen = ssi->screen;
1047 if (monitors[i]->sanity != S_SANE) continue;
1052 sn = screen_number (m->screen);
1053 ssi->screen = m->screen;
1054 ssi->real_screen_number = sn;
1055 ssi->real_screen_p = (seen_screens[sn] == 0);
1058 ssi->default_visual =
1059 get_visual_resource (ssi->screen, "visualID", "VisualID", False);
1060 ssi->current_visual = ssi->default_visual;
1061 ssi->current_depth = visual_depth (ssi->screen, ssi->current_visual);
1063 /* If the screen changed (or if this is the first time) we need
1064 a new toplevel shell for this screen's depth.
1066 if (ssi->screen != old_screen)
1067 initialize_screen_root_widget (ssi);
1069 ssi->last_poll_mouse.root_x = -1;
1070 ssi->last_poll_mouse.root_y = -1;
1074 ssi->width = m->width;
1075 ssi->height = m->height;
1077 # ifndef DEBUG_MULTISCREEN
1079 saver_preferences *p = &si->prefs;
1092 si->default_screen = &si->screens[0];