X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=driver%2Fscreens.c;h=0a7eade847183601e61ffe5fbc754c9023c25f2d;hb=f0261d8acab611f3433160e4f07367b870439739;hp=6516ade7f55cdcfb4a96c03ccf4f7c7dca121baa;hpb=c1b9b55ad8d59dc05ef55e316aebf5863e7dfa56;p=xscreensaver diff --git a/driver/screens.c b/driver/screens.c index 6516ade7..0a7eade8 100644 --- a/driver/screens.c +++ b/driver/screens.c @@ -99,7 +99,7 @@ * monitors, xscreensaver just ignores them (which allows them to * display duplicates or overlaps). * - * 5a) Nvidia fucks it up: + * 5a) Nvidia fucks it up: * * Nvidia drivers as of Aug 2008 running in "TwinView" mode * apparently report correct screen geometry via Xinerama, but @@ -108,6 +108,10 @@ * instead." Which is a seriously lame answer. So, xscreensaver * has to query *both* extensions, and make a guess as to which * is to be believed. + * + * 5b) Also sometimes RANDR says stupid shit like, "You have one + * screen, and it has no available orientations or sizes." + * */ #ifdef HAVE_CONFIG_H @@ -151,6 +155,8 @@ struct _monitor { int x, y, width, height; monitor_sanity sanity; /* I'm not crazy you're the one who's crazy */ int enemy; /* which monitor it overlaps or duplicates */ + char *err; /* msg to print at appropriate later time; + exists only on monitor #0. */ }; static Bool layouts_differ_p (monitor **a, monitor **b); @@ -164,6 +170,7 @@ free_monitors (monitor **monitors) while (*m2) { if ((*m2)->desc) free ((*m2)->desc); + if ((*m2)->err) free ((*m2)->err); free (*m2); m2++; } @@ -171,10 +178,24 @@ free_monitors (monitor **monitors) } +static char * +append (char *s1, const char *s2) +{ + char *s = (char *) malloc ((s1 ? strlen(s1) : 0) + + (s2 ? strlen(s2) : 0) + 3); + *s = 0; + if (s1) strcat (s, s1); + if (s1 && s2) strcat (s, "\n"); + if (s2) strcat (s, s2); + if (s1) free (s1); + return s; +} + + #ifdef HAVE_XINERAMA static monitor ** -xinerama_scan_monitors (Display *dpy) +xinerama_scan_monitors (Display *dpy, char **errP) { Screen *screen = DefaultScreenOfDisplay (dpy); int event, error, nscreens, i; @@ -213,7 +234,7 @@ xinerama_scan_monitors (Display *dpy) #ifdef HAVE_XF86VMODE static monitor ** -vidmode_scan_monitors (Display *dpy) +vidmode_scan_monitors (Display *dpy, char **errP) { int event, error, nscreens, i; monitor **monitors; @@ -312,7 +333,7 @@ vidmode_scan_monitors (Display *dpy) #ifdef HAVE_RANDR static monitor ** -randr_scan_monitors (Display *dpy) +randr_scan_monitors (Display *dpy, char **errP) { int event, error, major, minor, nscreens, i, j; monitor **monitors; @@ -350,6 +371,13 @@ randr_scan_monitors (Display *dpy) # endif /* HAVE_RANDR_12 */ } + if (nscreens <= 0) + { + *errP = append (*errP, + "WARNING: RANDR reported no screens! Ignoring it."); + return 0; + } + monitors = (monitor **) calloc (nscreens + 1, sizeof(*monitors)); if (!monitors) return 0; @@ -402,39 +430,37 @@ randr_scan_monitors (Display *dpy) int k; XRRScreenResources *res = XRRGetScreenResources (dpy, RootWindowOfScreen (screen)); - for (k = 0; k < res->noutput; k++) + for (k = 0; k < res->noutput; k++, j++) { monitor *m = (monitor *) calloc (1, sizeof (monitor)); XRROutputInfo *rroi = XRRGetOutputInfo (dpy, res, res->outputs[k]); - RRCrtc crtc = (rroi->crtc ? rroi->crtc : rroi->crtcs[0]); - XRRCrtcInfo *crtci = XRRGetCrtcInfo (dpy, res, crtc); + RRCrtc crtc = (rroi->crtc ? rroi->crtc : + rroi->ncrtc ? rroi->crtcs[0] : 0); + XRRCrtcInfo *crtci = (crtc ? XRRGetCrtcInfo(dpy, res, crtc) : 0); monitors[j] = m; m->screen = screen; m->id = (i * 1000) + j; m->desc = (rroi->name ? strdup (rroi->name) : 0); - m->x = crtci->x; - m->y = crtci->y; - if (crtci->rotation & (RR_Rotate_90|RR_Rotate_270)) - { - m->width = crtci->height; - m->height = crtci->width; - } - else + if (crtci) { + /* Note: if the screen is rotated, XRRConfigSizes contains + the unrotated WxH, but XRRCrtcInfo contains rotated HxW. + */ + m->x = crtci->x; + m->y = crtci->y; m->width = crtci->width; m->height = crtci->height; } - j++; - if (rroi->connection == RR_Disconnected) m->sanity = S_DISABLED; /* #### do the same for RR_UnknownConnection? */ - XRRFreeCrtcInfo (crtci); + if (crtci) + XRRFreeCrtcInfo (crtci); XRRFreeOutputInfo (rroi); } XRRFreeScreenResources (res); @@ -442,6 +468,25 @@ randr_scan_monitors (Display *dpy) } } + /* Work around more fucking brain damage. */ + { + int ok = 0; + int i = 0; + while (monitors[i]) + { + if (monitors[i]->width != 0 && monitors[i]->height != 0) + ok++; + i++; + } + if (! ok) + { + *errP = append (*errP, + "WARNING: RANDR says all screens are 0x0! Ignoring it."); + free_monitors (monitors); + monitors = 0; + } + } + return monitors; } @@ -449,7 +494,7 @@ randr_scan_monitors (Display *dpy) static monitor ** -basic_scan_monitors (Display *dpy) +basic_scan_monitors (Display *dpy, char **errP) { int nscreens = ScreenCount (dpy); int i; @@ -492,14 +537,15 @@ basic_scan_monitors (Display *dpy) modifying xscreensaver to try to get this information from RandR. */ static monitor ** -randr_versus_xinerama_fight (Display *dpy, monitor **randr_monitors) +randr_versus_xinerama_fight (Display *dpy, monitor **randr_monitors, + char **errP) { monitor **xinerama_monitors; if (!randr_monitors) return 0; - xinerama_monitors = xinerama_scan_monitors (dpy); + xinerama_monitors = xinerama_scan_monitors (dpy, errP); if (!xinerama_monitors) return randr_monitors; @@ -511,19 +557,17 @@ randr_versus_xinerama_fight (Display *dpy, monitor **randr_monitors) else if ( randr_monitors[0] && !randr_monitors[1] && /* 1 monitor */ xinerama_monitors[0] && xinerama_monitors[1]) /* >1 monitor */ { - fprintf (stderr, - "%s: WARNING: RANDR reports 1 screen but Xinerama\n" - "%s: reports multiple. Believing Xinerama.\n", - blurb(), blurb()); + *errP = append (*errP, + "WARNING: RANDR reports 1 screen but Xinerama\n" + "\t\treports multiple. Believing Xinerama."); free_monitors (randr_monitors); return xinerama_monitors; } else { - fprintf (stderr, - "%s: WARNING: RANDR and Xinerama report different\n" - "%s: screen layouts! Believing RANDR.\n", - blurb(), blurb()); + *errP = append (*errP, + "WARNING: RANDR and Xinerama report different\n" + "\t\tscreen layouts! Believing RANDR."); free_monitors (xinerama_monitors); return randr_monitors; } @@ -540,7 +584,7 @@ randr_versus_xinerama_fight (Display *dpy, monitor **randr_monitors) for stress-testing purposes. */ static monitor ** -debug_scan_monitors (Display *dpy) +debug_scan_monitors (Display *dpy, char **errP) { static const char * const geoms[] = { "1600x1028+0+22", @@ -587,7 +631,7 @@ debug_scan_monitors (Display *dpy) #ifdef QUAD_MODE static monitor ** -quadruple (monitor **monitors, Bool debug_p) +quadruple (monitor **monitors, Bool debug_p, char **errP) { int i, j, count = 0; monitor **monitors2; @@ -627,35 +671,38 @@ scan_monitors (saver_info *si) { saver_preferences *p = &si->prefs; monitor **monitors = 0; + char *err = 0; # ifdef DEBUG_MULTISCREEN - if (! monitors) monitors = debug_scan_monitors (si->dpy); + if (! monitors) monitors = debug_scan_monitors (si->dpy, &err); # endif # ifdef HAVE_RANDR if (! p->getviewport_full_of_lies_p) - if (! monitors) monitors = randr_scan_monitors (si->dpy); + if (! monitors) monitors = randr_scan_monitors (si->dpy, &err); # ifdef HAVE_XINERAMA - monitors = randr_versus_xinerama_fight (si->dpy, monitors); + monitors = randr_versus_xinerama_fight (si->dpy, monitors, &err); # endif # endif /* HAVE_RANDR */ # ifdef HAVE_XF86VMODE - if (! monitors) monitors = vidmode_scan_monitors (si->dpy); + if (! monitors) monitors = vidmode_scan_monitors (si->dpy, &err); # endif # ifdef HAVE_XINERAMA - if (! monitors) monitors = xinerama_scan_monitors (si->dpy); + if (! monitors) monitors = xinerama_scan_monitors (si->dpy, &err); # endif - if (! monitors) monitors = basic_scan_monitors (si->dpy); + if (! monitors) monitors = basic_scan_monitors (si->dpy, &err); # ifdef QUAD_MODE if (p->quad_p) - monitors = quadruple (monitors, p->debug_p); + monitors = quadruple (monitors, p->debug_p, &err); # endif + if (monitors && err) monitors[0]->err = err; + return monitors; } @@ -840,6 +887,18 @@ describe_monitor_layout (saver_info *si) count++; } + if (monitors[0]->err) /* deferred error msg */ + { + char *token = strtok (monitors[0]->err, "\n"); + while (token) + { + fprintf (stderr, "%s: %s\n", blurb(), token); + token = strtok (0, "\n"); + } + free (monitors[0]->err); + monitors[0]->err = 0; + } + if (count == 0) fprintf (stderr, "%s: no screens!\n", blurb()); else