SDL_CreateWindow: No available displays


I believe there is a regression in libsdl 2.0.4 (ish), possibly due to the
recent changes to SDL_x11modes.

I’ve recently noticed steam (the game platform from Valve) does not want to
switch into “big picture mode” on my setup. It’s a Ubuntu Wily box but most
notably I only ever access it over remote desktop (specifically, chrome remote
desktop). As such, most of the time there is no display connected and X runs in
"headless" mode (no connected xrandr outputs).

Isolating the failure to ~minimal broken example:


int main(int argc, char **argv) {
SDL_Window *w;
// The SDL_CreateWindow call Steam client is attempting.
w = SDL_CreateWindow(
if (w == NULL) {
printf(“SDL_CreateWindow: %s\n”, SDL_GetError());
return 0;

This code fails with libsdl 2.0.4 (in this case with the upcoming Ubuntu
package, but I also tried with mercurial head):

$ LD_PRELOAD=libsdl2-2.0.4+dfsg1/build/.libs/ DISPLAY=:20 ./sdl
SDL_CreateWindow: No available displays

But works with libsdl 2.0.0 in Ubuntu Wily:

$ dpkg -l libsdl2-2.0-0
$ DISPLAY=:20 ./sdl

For reference, xrandr output:

$ DISPLAY=:20 xrandr
Screen 0: minimum 8 x 8, current 1366 x 768, maximum 32767 x 32767
DP1 disconnected (normal left inverted right x axis y axis)
Chrome Remote Desktop client resolution 0.00
HDMI1 disconnected (normal left inverted right x axis y axis)
HDMI2 disconnected (normal left inverted right x axis y axis)
VIRTUAL1 disconnected (normal left inverted right x axis y axis)

I have not yet taken a stab at fixing this, just reporting observations. I could
probably come up with a patch that makes this work locally but I’d really need
help with figuring out how to do this so as to not break other use cases - the
logic is not obvious to a bystander.

Currently it looks like all screens and outputs are tried twice - first to find
a working primary output if one exists and then to add all non-primary outputs.
Would it make sense to do something like add all the screens as the last pass?

Or is it cool to add a hack specifically for chrome remote desktop? Presumably
other people might be running similar configurations with vnc and the likes as
well so that does not sound optimal.



I tinkered a bit and managed to get steam kind of working in big picture mode
under gdb. It’s not working with SDL_WINDOW_FULLSCREEN so I needed to break
steam at SDL_CreateWindo and change the flags to just SDL_WINDOW_OPENGL which
seemed to work as expected (except for not being properly full screen).

A tiny test app that creates a screen and colors it red is also broken and
working for the same set of flags.

I’d appreciate pointers as to what needs and doesn’t need to be set up for a
SDL_VideoDisplay to work correctly (in particular for full screen). Or perhaps,
which code might care about XRandR output vs screen differences and need to
change for plain screens to work as SDL_VideoDisplays. And as a more distant
question, when should we and when shouldn’t we add screens as SDL_VideoDisplays.----
x11: also create displays based on plain screens

In case SDL is used on an X11 system with no connected displays (xrandr
outputs), SDL_CreateWindow will fail with error:

No available displays

Currently that makes SDL apps largely unusable on chrome remote desktop systems
(and possibly other remote desktops).

This change makes SDL also consider the more virtual “screens” themselves as
potentially usable displays, rather than requiring a physical “output” to be
available and connected.

diff -r 330f500d5815 -r cec47d7a4404 src/video/x11/SDL_x11modes.c
— a/src/video/x11/SDL_x11modes.c Wed Feb 17 15:14:20 2016 +0800
+++ b/src/video/x11/SDL_x11modes.c Wed Mar 02 00:57:27 2016 +0000
@@ -491,6 +491,41 @@

  •        // Add the screen itself as a display.
  •        if (res->nmode && !looking_for_primary) {
  •            SDL_DisplayData *displaydata;
  •            char display_name[128];
  •            SDL_DisplayMode mode;
  •            SDL_VideoDisplay display;
  •            displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
  •            if (!displaydata) {
  •                return SDL_OutOfMemory();
  •            }
  •            SDL_zero(mode);
  •            mode.w = res->modes[0].width;
  •            mode.h = res->modes[0].height;
  •            mode.format = pixelformat;
  •            displaydata->screen = screen;
  •            displaydata->visual = vinfo.visual;
  •            displaydata->depth = vinfo.depth;
  •            displaydata->hdpi = 75;
  •            displaydata->vdpi = 75;
  •            displaydata->ddpi = 75;
  •            displaydata->scanline_pad = scanline_pad;
  •            displaydata->use_xrandr = 1;
  •            SDL_zero(display);
  •            sprintf(display_name, "Screen %d", screen);
  •   = display_name;
  •            display.desktop_mode = mode;
  •            display.current_mode = mode;
  •            display.driverdata = displaydata;
  •            SDL_AddVideoDisplay(&display);
  •        }
  •        X11_XRRFreeScreenResources(res);