x11: If XRandR isn't available, add a generic display.

We can get _some_ of the info we need out of standard Xlib and report a
single display (which might actually be multiple physical displays mushed
into a single desktop). This is better than nothing, but you should really
just build with XRandR support and get a better X server.  :)
This commit is contained in:
Ryan C. Gordon 2022-04-26 23:14:44 -04:00
parent ccc70e644b
commit 05bd225a80
No known key found for this signature in database
GPG Key ID: FA148B892AB48044
1 changed files with 122 additions and 30 deletions

View File

@ -148,6 +148,30 @@ X11_GetPixelFormatFromVisualInfo(Display * display, XVisualInfo * vinfo)
return SDL_PIXELFORMAT_UNKNOWN; return SDL_PIXELFORMAT_UNKNOWN;
} }
static int
GetXftDPI(Display* dpy)
{
char* xdefault_resource;
int xft_dpi, err;
xdefault_resource = X11_XGetDefault(dpy, "Xft", "dpi");
if(!xdefault_resource) {
return 0;
}
/*
* It's possible for SDL_atoi to call SDL_strtol, if it fails due to a
* overflow or an underflow, it will return LONG_MAX or LONG_MIN and set
* errno to ERANGE. So we need to check for this so we dont get crazy dpi
* values
*/
xft_dpi = SDL_atoi(xdefault_resource);
err = errno;
return err == ERANGE ? 0 : xft_dpi;
}
#if SDL_VIDEO_DRIVER_X11_XRANDR #if SDL_VIDEO_DRIVER_X11_XRANDR
static SDL_bool static SDL_bool
CheckXRandR(Display * display, int *major, int *minor) CheckXRandR(Display * display, int *major, int *minor)
@ -289,30 +313,6 @@ SetXRandRDisplayName(Display *dpy, Atom EDID, char *name, const size_t namelen,
#endif #endif
} }
static int
GetXftDPI(Display* dpy)
{
char* xdefault_resource;
int xft_dpi, err;
xdefault_resource = X11_XGetDefault(dpy, "Xft", "dpi");
if(!xdefault_resource) {
return 0;
}
/*
* It's possible for SDL_atoi to call SDL_strtol, if it fails due to a
* overflow or an underflow, it will return LONG_MAX or LONG_MIN and set
* errno to ERANGE. So we need to check for this so we dont get crazy dpi
* values
*/
xft_dpi = SDL_atoi(xdefault_resource);
err = errno;
return err == ERANGE ? 0 : xft_dpi;
}
static int static int
X11_InitModes_XRandR(_THIS) X11_InitModes_XRandR(_THIS)
{ {
@ -478,16 +478,107 @@ X11_InitModes_XRandR(_THIS)
} }
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
/* This is used if there's no better functionality--like XRandR--to use.
It won't attempt to supply different display modes at all, but it can
enumerate the current displays and their current sizes. */
static int X11_InitModes_StdXlib(_THIS)
{
/* !!! FIXME: a lot of copy/paste from X11_InitModes_XRandR in this function. */
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
Display *dpy = data->display;
const int default_screen = DefaultScreen(dpy);
Screen *screen = ScreenOfDisplay(dpy, default_screen);
int display_mm_width, display_mm_height, xft_dpi, scanline_pad, n, i;
SDL_DisplayModeData *modedata;
SDL_DisplayData *displaydata;
SDL_DisplayMode mode;
XPixmapFormatValues *pixmapformats;
Uint32 pixelformat;
XVisualInfo vinfo;
SDL_VideoDisplay display;
/* note that generally even if you have a multiple physical monitors, ScreenCount(dpy) still only reports ONE screen. */
if (get_visualinfo(dpy, default_screen, &vinfo) < 0) {
return SDL_SetError("Failed to find an X11 visual for the primary display");
}
pixelformat = X11_GetPixelFormatFromVisualInfo(dpy, &vinfo);
if (SDL_ISPIXELFORMAT_INDEXED(pixelformat)) {
return SDL_SetError("Palettized video modes are no longer supported");
}
SDL_zero(mode);
mode.w = WidthOfScreen(screen);
mode.h = HeightOfScreen(screen);
mode.format = pixelformat;
mode.refresh_rate = 0; /* don't know it, sorry. */
displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
if (!displaydata) {
return SDL_OutOfMemory();
}
modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
if (!modedata) {
SDL_free(displaydata);
return SDL_OutOfMemory();
}
mode.driverdata = modedata;
display_mm_width = WidthMMOfScreen(screen);
display_mm_height = HeightMMOfScreen(screen);
displaydata->screen = default_screen;
displaydata->visual = vinfo.visual;
displaydata->depth = vinfo.depth;
displaydata->hdpi = display_mm_width ? (((float) mode.w) * 25.4f / display_mm_width) : 0.0f;
displaydata->vdpi = display_mm_height ? (((float) mode.h) * 25.4f / display_mm_height) : 0.0f;
displaydata->ddpi = SDL_ComputeDiagonalDPI(mode.w, mode.h, ((float) display_mm_width) / 25.4f,((float) display_mm_height) / 25.4f);
xft_dpi = GetXftDPI(dpy);
if(xft_dpi > 0) {
displaydata->hdpi = (float)xft_dpi;
displaydata->vdpi = (float)xft_dpi;
}
scanline_pad = SDL_BYTESPERPIXEL(pixelformat) * 8;
pixmapformats = X11_XListPixmapFormats(dpy, &n);
if (pixmapformats) {
for (i = 0; i < n; ++i) {
if (pixmapformats[i].depth == vinfo.depth) {
scanline_pad = pixmapformats[i].scanline_pad;
break;
}
}
X11_XFree(pixmapformats);
}
displaydata->scanline_pad = scanline_pad;
displaydata->x = 0;
displaydata->y = 0;
displaydata->use_xrandr = SDL_FALSE;
SDL_zero(display);
display.name = (char *) "Generic X11 Display"; /* this is just copied and thrown away, it's safe to cast to char* here. */
display.desktop_mode = mode;
display.current_mode = mode;
display.driverdata = displaydata;
SDL_AddVideoDisplay(&display, SDL_FALSE);
return 0;
}
int int
X11_InitModes(_THIS) X11_InitModes(_THIS)
{ {
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
/* XRandR is the One True Modern Way to do this on X11. If this /* XRandR is the One True Modern Way to do this on X11. If this
fails, we just won't report any display modes except the current fails, we just won't report any display modes except the current
desktop size. */ desktop size. */
#if SDL_VIDEO_DRIVER_X11_XRANDR #if SDL_VIDEO_DRIVER_X11_XRANDR
{ {
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
int xrandr_major, xrandr_minor; int xrandr_major, xrandr_minor;
/* require at least XRandR v1.3 */ /* require at least XRandR v1.3 */
if (CheckXRandR(data->display, &xrandr_major, &xrandr_minor) && if (CheckXRandR(data->display, &xrandr_major, &xrandr_minor) &&
@ -497,7 +588,8 @@ X11_InitModes(_THIS)
} }
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
return 0; /* still here? Just set up an extremely basic display. */
return X11_InitModes_StdXlib(_this);
} }
void void