diff -r 81a3d541d9a2 src/video/x11/SDL_x11modes.c --- a/src/video/x11/SDL_x11modes.c vie sep 28 14:42:47 2012 -0700 +++ b/src/video/x11/SDL_x11modes.c sáb sep 29 16:18:27 2012 -0300 @@ -25,7 +25,7 @@ #include "SDL_hints.h" #include "SDL_x11video.h" -/*#define X11MODES_DEBUG*/ +#define X11MODES_DEBUG static int get_visualinfo(Display * display, int screen, XVisualInfo * vinfo) @@ -684,49 +684,209 @@ int best_rate; XRRScreenSize *sizes; short *rates; + printf("XRANDR: %u\n", data->use_xrandr); - /* find the smallest resolution that is at least as big as the user requested */ - best = -1; - sizes = XRRConfigSizes(data->screen_config, &nsizes); - for (i = 0; i < nsizes; ++i) { - if (sizes[i].width < w || sizes[i].height < h) { - continue; +#if SDL_VIDEO_DRIVER_X11_XINERAMA + if (data->use_xrandr >= 102 && data->use_xinerama) { +#else + if (0) { +#endif + /* See http://cgit.freedesktop.org/xorg/app/xrandr/tree/xrandr.c for the rationale behind this */ + int screen, screencount; + int fb_width = 0, fb_height = 0; + int minWidth, minHeight, maxWidth, maxHeight; + XineramaScreenInfo * xinerama = NULL; + XRRScreenResources *res; + int _x, _y, _w, _h; + xinerama = XineramaQueryScreens(display, &screencount); + + if (!xinerama) { + SDL_SetError("Xinerama unexpectedly returned no screens"); + return; } - if (sizes[i].width == w && sizes[i].height == h) { - best = i; - break; + + /* Calculate, and then validate, the new screen size */ + for (screen = 0 ; screenxinerama_info.x_org && _y == data->xinerama_info.y_org) { + _w = w; + _h = h; + } + else { + /* If our change of resolution will affect other screens' offsets, adjust them accordingly */ + if (_x >= w+data->xinerama_info.x_org) _x += w-data->xinerama_info.width; + if (_y >= h+data->xinerama_info.y_org) _y += h-data->xinerama_info.height; + } + if ( fb_width < _x+_w) fb_width = _x+_w; + if ( fb_height < _y+_h) fb_height = _y+_h; } - if (best == -1 || - (sizes[i].width < sizes[best].width) || - (sizes[i].width == sizes[best].width - && sizes[i].height < sizes[best].height)) { - best = i; + + + + XRRGetScreenSizeRange (display, RootWindow(display, data->screen), &minWidth, &minHeight, &maxWidth, &maxHeight); + + if ( fb_width < minWidth || fb_width > maxWidth || fb_height < minHeight || fb_height > maxHeight) { + SDL_SetError("Desired screen size is out of bounds"); + XFree(xinerama); + return; } - } - if (best >= 0) { - best_rate = 0; - rates = XRRConfigRates(data->screen_config, best, &nrates); - for (i = 0; i < nrates; ++i) { - if (rates[i] == rate) { - best_rate = rate; + #ifdef X11MODES_DEBUG + fprintf(stderr, "XRANDR: set_best_resolution, new screen size is: w = %d, h = %d\n", fb_width, fb_height); + #endif + + if (fb_width > DisplayWidth (display, data->screen) || + fb_height > DisplayHeight (display, data->screen)) + { + /* Note by Gabriel: Here we should make the following call (as xrandr supposedly does), + * However! If you trace xrandr it actually doesn't seem to ever make this call, + * if you go from a bigger screen size to a smaller one, it just leaves the metamode set at the bigger size, + * and this metamode is always set at the maximum possible size you can reach... + * And to top it off, when you do force it to call XRRSetScreenSize with anything other than the maximum size, it fails! + * So, a mystery for those daring to investigate it, in the meantime...we just fail if the user wants a size that implies + * a screen size bigger than the current one + * Having called XGrabServer you should do... + + int fb_width_mm = fb_width * DisplayWidthMM(display, data->screen) / DisplayWidth (display, data->screen); + int fb_height_mm = fb_height * DisplayHeightMM(display, data->screen) / DisplayHeight (display, data->screen); + XRRSetScreenSize (display, RootWindow(display, data->screen), fb_width, fb_height, fb_width_mm, fb_height_mm); + + */ + SDL_SetError("Can not change screen size to be bigger"); + XFree(xinerama); + return; + } + res = XRRGetScreenResources (display, RootWindow(display, data->screen)); + if (res) { + XRROutputInfo *output_info = NULL; + XRRCrtcInfo *crtc = NULL; + XRRModeInfo *mode_info, *best_mode_info = NULL; + int mode_index = 0, output_mode_index = 0, output, crtn; + + for ( output = 0; output < res->noutput; output++) { + output_info = XRRGetOutputInfo (display, res, res->outputs[output]); + if (output_info && output_info->crtc) { + crtc = XRRGetCrtcInfo (display, res, output_info->crtc); + if (crtc) { + if (data->xinerama_info.x_org == crtc->x && data->xinerama_info.y_org == crtc->y) { + /* The CRT offset matches the Xinerama mode, let's hope it's the right one! */ + #ifdef X11MODES_DEBUG + fprintf(stderr, "XRANDR: set_best_resolution, matched Xinerama screen %d to CRT %d\n", + data->xinerama_info.screen_number, crtn, crtc->x, crtc->y); + #endif + /* Find out the best mode we can use */ + for (mode_index = 0; mode_index < res->nmode; mode_index++) + { + mode_info = &res->modes[mode_index]; + if (mode_info->width >= w && mode_info->height >= h) { + /* This may be a useful mode, check out if it belongs to the correct output */ + #ifdef X11MODES_DEBUG + fprintf(stderr, "Evaluating valid mode %d, w: %d, h: %d\n", mode_index, mode_info->width, mode_info->height); + #endif + for ( output_mode_index = 0; output_mode_index < output_info->nmode; output_mode_index++) { + if (output_info->modes[output_mode_index] == mode_info->id) break; + } + if (output_mode_index < output_info->nmode) { + #ifdef X11MODES_DEBUG + fprintf(stderr, "Mode belongs to the desired output %d w: %d, h: %d\n", mode_index, mode_info->width, mode_info->height); + #endif + /* We have a mode that belongs to the right output and that can contain the w,h required, see if it's smaller than the current one */ + if( !best_mode_info || + mode_info->width < best_mode_info->width || + (mode_info->width == best_mode_info->width && mode_info->height < best_mode_info->height) ) { + best_mode_info = mode_info; + } + } + #ifdef X11MODES_DEBUG + else { + fprintf(stderr, "Discarding mode because it does not belong to the desired output %d, w: %d, h: %d\n", mode_index, mode_info->width, mode_info->height); + } + #endif + } + } + + if (best_mode_info) { + #ifdef X11MODES_DEBUG + fprintf(stderr, "XRANDR: set_best_resolution, setting mode w = %d, h = %d on output: %d, CRT with offsets: %d,%d for Xinerama screen: %d\n", + best_mode_info->width, best_mode_info->height, output, crtc->x, crtc->y, data->xinerama_info.screen_number); + #endif + XGrabServer (display); + XRRSetCrtcConfig (display, res, output_info->crtc /*output_info->crtcs[crtn]*/, CurrentTime, + crtc->x, crtc->y, best_mode_info->id, crtc->rotation, + &res->outputs[output], 1); + /* TODO: Handle screen rotations, should we call XRRSetCrtcTransform if Xrandr >=1.3 ? */ + /* TODO: Handle refresh rate if such thing is possible when more than one monitor is involved */ + XUngrabServer (display); + break; + } + /* If we reach here, we have found the right screen but no valid best mode */ + SDL_SetError("The selected screen can't support a resolution of the size desired"); + break; + } + XRRFreeCrtcInfo(crtc); + crtc = NULL; + } + } + XRRFreeOutputInfo(output_info); + output_info = NULL; + } + + if (output_info) XRRFreeOutputInfo(output_info); + if (crtc) XRRFreeCrtcInfo(crtc); + XRRFreeScreenResources(res); + XFree(xinerama); + } + } else { + /* Use older xrandr functions that don't play along very nicely with multi monitors setups */ + /* find the smallest resolution that is at least as big as the user requested */ + best = -1; + sizes = XRRConfigSizes(data->screen_config, &nsizes); + for (i = 0; i < nsizes; ++i) { + if (sizes[i].width < w || sizes[i].height < h) { + continue; + } + if (sizes[i].width == w && sizes[i].height == h) { + best = i; break; } - if (!rate) { - /* Higher is better, right? */ - if (rates[i] > best_rate) { - best_rate = rates[i]; + if (best == -1 || + (sizes[i].width < sizes[best].width) || + (sizes[i].width == sizes[best].width + && sizes[i].height < sizes[best].height)) { + best = i; + } + } + + if (best >= 0) { + best_rate = 0; + rates = XRRConfigRates(data->screen_config, best, &nrates); + for (i = 0; i < nrates; ++i) { + if (rates[i] == rate) { + best_rate = rate; + break; } - } else { - if (SDL_abs(rates[i] - rate) < SDL_abs(best_rate - rate)) { - best_rate = rates[i]; + if (!rate) { + /* Higher is better, right? */ + if (rates[i] > best_rate) { + best_rate = rates[i]; + } + } else { + if (SDL_abs(rates[i] - rate) < SDL_abs(best_rate - rate)) { + best_rate = rates[i]; + } } } + XRRSetScreenConfigAndRate(display, data->screen_config, + RootWindow(display, data->screen), best, + data->saved_rotation, best_rate, + CurrentTime); } - XRRSetScreenConfigAndRate(display, data->screen_config, - RootWindow(display, data->screen), best, - data->saved_rotation, best_rate, - CurrentTime); } return; } diff -r 81a3d541d9a2 src/video/x11/SDL_x11sym.h --- a/src/video/x11/SDL_x11sym.h vie sep 28 14:42:47 2012 -0700 +++ b/src/video/x11/SDL_x11sym.h sáb sep 29 16:18:27 2012 -0300 @@ -237,6 +237,15 @@ SDL_X11_SYM(XRRScreenSize *,XRRConfigSizes,(XRRScreenConfiguration *config,int *nsizes),(config,nsizes),return) SDL_X11_SYM(Status,XRRSetScreenConfigAndRate,(Display *dpy,XRRScreenConfiguration *config,Drawable draw,int size_index,Rotation rotation,short rate,Time timestamp),(dpy,config,draw,size_index,rotation,rate,timestamp),return) SDL_X11_SYM(void,XRRFreeScreenConfigInfo,(XRRScreenConfiguration *config),(config),) +SDL_X11_SYM(void,XRRSetScreenSize,(Display *dpy, Window window,int width, int height,int mmWidth, int mmHeight),(dpy,window,width,height,mmWidth,mmHeight),) +SDL_X11_SYM(Status,XRRGetScreenSizeRange,(Display *dpy, Window window,int *minWidth, int *minHeight, int *maxWidth, int *maxHeight),(dpy,window,minWidth,minHeight,maxWidth,maxHeight),return) +SDL_X11_SYM(XRRScreenResources *,XRRGetScreenResources,(Display *dpy, Window window),(dpy, window),return) +SDL_X11_SYM(void,XRRFreeScreenResources,(XRRScreenResources *resources),(resources),) +SDL_X11_SYM(XRROutputInfo *,XRRGetOutputInfo,(Display *dpy, XRRScreenResources *resources, RROutput output),(dpy,resources,output),return) +SDL_X11_SYM(void,XRRFreeOutputInfo,(XRROutputInfo *outputInfo),(outputInfo),) +SDL_X11_SYM(XRRCrtcInfo *,XRRGetCrtcInfo,(Display *dpy, XRRScreenResources *resources, RRCrtc crtc),(dpy,resources,crtc),return) +SDL_X11_SYM(void,XRRFreeCrtcInfo,(XRRCrtcInfo *crtcInfo),(crtcInfo),) +SDL_X11_SYM(Status,XRRSetCrtcConfig,(Display *dpy, XRRScreenResources *resources, RRCrtc crtc, Time timestamp, int x, int y, RRMode mode, Rotation rotation, RROutput *outputs, int noutputs),(dpy,resources,crtc,timestamp,x,y,mode,rotation,outputs,noutputs),return) #endif /* MIT-SCREEN-SAVER support */