SDL  2.0
SDL_x11modes.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22 
23 #if SDL_VIDEO_DRIVER_X11
24 
25 #include "SDL_hints.h"
26 #include "SDL_x11video.h"
27 #include "SDL_timer.h"
28 #include "edid.h"
29 
30 /* #define X11MODES_DEBUG */
31 
32 /* I'm becoming more and more convinced that the application should never
33  * use XRandR, and it's the window manager's responsibility to track and
34  * manage display modes for fullscreen windows. Right now XRandR is completely
35  * broken with respect to window manager behavior on every window manager that
36  * I can find. For example, on Unity 3D if you show a fullscreen window while
37  * the resolution is changing (within ~250 ms) your window will retain the
38  * fullscreen state hint but be decorated and windowed.
39  *
40  * However, many people swear by it, so let them swear at it. :)
41 */
42 /* #define XRANDR_DISABLED_BY_DEFAULT */
43 
44 
45 static int
46 get_visualinfo(Display * display, int screen, XVisualInfo * vinfo)
47 {
48  const char *visual_id = SDL_getenv("SDL_VIDEO_X11_VISUALID");
49  int depth;
50 
51  /* Look for an exact visual, if requested */
52  if (visual_id) {
53  XVisualInfo *vi, template;
54  int nvis;
55 
56  SDL_zero(template);
57  template.visualid = SDL_strtol(visual_id, NULL, 0);
58  vi = X11_XGetVisualInfo(display, VisualIDMask, &template, &nvis);
59  if (vi) {
60  *vinfo = *vi;
61  X11_XFree(vi);
62  return 0;
63  }
64  }
65 
66  depth = DefaultDepth(display, screen);
68  X11_XMatchVisualInfo(display, screen, depth, DirectColor, vinfo)) ||
69  X11_XMatchVisualInfo(display, screen, depth, TrueColor, vinfo) ||
70  X11_XMatchVisualInfo(display, screen, depth, PseudoColor, vinfo) ||
71  X11_XMatchVisualInfo(display, screen, depth, StaticColor, vinfo)) {
72  return 0;
73  }
74  return -1;
75 }
76 
77 int
78 X11_GetVisualInfoFromVisual(Display * display, Visual * visual, XVisualInfo * vinfo)
79 {
80  XVisualInfo *vi;
81  int nvis;
82 
83  vinfo->visualid = X11_XVisualIDFromVisual(visual);
84  vi = X11_XGetVisualInfo(display, VisualIDMask, vinfo, &nvis);
85  if (vi) {
86  *vinfo = *vi;
87  X11_XFree(vi);
88  return 0;
89  }
90  return -1;
91 }
92 
93 Uint32
94 X11_GetPixelFormatFromVisualInfo(Display * display, XVisualInfo * vinfo)
95 {
96  if (vinfo->class == DirectColor || vinfo->class == TrueColor) {
97  int bpp;
98  Uint32 Rmask, Gmask, Bmask, Amask;
99 
100  Rmask = vinfo->visual->red_mask;
101  Gmask = vinfo->visual->green_mask;
102  Bmask = vinfo->visual->blue_mask;
103  if (vinfo->depth == 32) {
104  Amask = (0xFFFFFFFF & ~(Rmask | Gmask | Bmask));
105  } else {
106  Amask = 0;
107  }
108 
109  bpp = vinfo->depth;
110  if (bpp == 24) {
111  int i, n;
112  XPixmapFormatValues *p = X11_XListPixmapFormats(display, &n);
113  if (p) {
114  for (i = 0; i < n; ++i) {
115  if (p[i].depth == 24) {
116  bpp = p[i].bits_per_pixel;
117  break;
118  }
119  }
120  X11_XFree(p);
121  }
122  }
123 
124  return SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
125  }
126 
127  if (vinfo->class == PseudoColor || vinfo->class == StaticColor) {
128  switch (vinfo->depth) {
129  case 8:
130  return SDL_PIXELTYPE_INDEX8;
131  case 4:
132  if (BitmapBitOrder(display) == LSBFirst) {
134  } else {
136  }
137  /* break; -Wunreachable-code-break */
138  case 1:
139  if (BitmapBitOrder(display) == LSBFirst) {
141  } else {
143  }
144  /* break; -Wunreachable-code-break */
145  }
146  }
147 
149 }
150 
151 /* Global for the error handler */
152 static int vm_event, vm_error = -1;
153 
154 #if SDL_VIDEO_DRIVER_X11_XINERAMA
155 static SDL_bool
156 CheckXinerama(Display * display, int *major, int *minor)
157 {
158  int event_base = 0;
159  int error_base = 0;
160 
161  /* Default the extension not available */
162  *major = *minor = 0;
163 
164  /* Allow environment override */
166 #ifdef X11MODES_DEBUG
167  printf("Xinerama disabled due to hint\n");
168 #endif
169  return SDL_FALSE;
170  }
171 
172  if (!SDL_X11_HAVE_XINERAMA) {
173 #ifdef X11MODES_DEBUG
174  printf("Xinerama support not available\n");
175 #endif
176  return SDL_FALSE;
177  }
178 
179  /* Query the extension version */
180  if (!X11_XineramaQueryExtension(display, &event_base, &error_base) ||
181  !X11_XineramaQueryVersion(display, major, minor) ||
182  !X11_XineramaIsActive(display)) {
183 #ifdef X11MODES_DEBUG
184  printf("Xinerama not active on the display\n");
185 #endif
186  return SDL_FALSE;
187  }
188 #ifdef X11MODES_DEBUG
189  printf("Xinerama available at version %d.%d!\n", *major, *minor);
190 #endif
191  return SDL_TRUE;
192 }
193 
194 /* !!! FIXME: remove this later. */
195 /* we have a weird bug where XineramaQueryScreens() throws an X error, so this
196  is here to help track it down (and not crash, too!). */
197 static SDL_bool xinerama_triggered_error = SDL_FALSE;
198 static int
199 X11_XineramaFailed(Display * d, XErrorEvent * e)
200 {
201  xinerama_triggered_error = SDL_TRUE;
202  fprintf(stderr, "XINERAMA X ERROR: type=%d serial=%lu err=%u req=%u minor=%u\n",
203  e->type, e->serial, (unsigned int) e->error_code,
204  (unsigned int) e->request_code, (unsigned int) e->minor_code);
205  fflush(stderr);
206  return 0;
207 }
208 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
209 
210 #if SDL_VIDEO_DRIVER_X11_XRANDR
211 static SDL_bool
212 CheckXRandR(Display * display, int *major, int *minor)
213 {
214  /* Default the extension not available */
215  *major = *minor = 0;
216 
217  /* Allow environment override */
218 #ifdef XRANDR_DISABLED_BY_DEFAULT
220 #ifdef X11MODES_DEBUG
221  printf("XRandR disabled by default due to window manager issues\n");
222 #endif
223  return SDL_FALSE;
224  }
225 #else
227 #ifdef X11MODES_DEBUG
228  printf("XRandR disabled due to hint\n");
229 #endif
230  return SDL_FALSE;
231  }
232 #endif /* XRANDR_ENABLED_BY_DEFAULT */
233 
234  if (!SDL_X11_HAVE_XRANDR) {
235 #ifdef X11MODES_DEBUG
236  printf("XRandR support not available\n");
237 #endif
238  return SDL_FALSE;
239  }
240 
241  /* Query the extension version */
242  *major = 1; *minor = 3; /* we want 1.3 */
243  if (!X11_XRRQueryVersion(display, major, minor)) {
244 #ifdef X11MODES_DEBUG
245  printf("XRandR not active on the display\n");
246 #endif
247  *major = *minor = 0;
248  return SDL_FALSE;
249  }
250 #ifdef X11MODES_DEBUG
251  printf("XRandR available at version %d.%d!\n", *major, *minor);
252 #endif
253  return SDL_TRUE;
254 }
255 
256 #define XRANDR_ROTATION_LEFT (1 << 1)
257 #define XRANDR_ROTATION_RIGHT (1 << 3)
258 
259 static int
260 CalculateXRandRRefreshRate(const XRRModeInfo *info)
261 {
262  return (info->hTotal && info->vTotal) ?
263  round(((double)info->dotClock / (double)(info->hTotal * info->vTotal))) : 0;
264 }
265 
266 static SDL_bool
267 SetXRandRModeInfo(Display *display, XRRScreenResources *res, RRCrtc crtc,
268  RRMode modeID, SDL_DisplayMode *mode)
269 {
270  int i;
271  for (i = 0; i < res->nmode; ++i) {
272  const XRRModeInfo *info = &res->modes[i];
273  if (info->id == modeID) {
274  XRRCrtcInfo *crtcinfo;
275  Rotation rotation = 0;
276 
277  crtcinfo = X11_XRRGetCrtcInfo(display, res, crtc);
278  if (crtcinfo) {
279  rotation = crtcinfo->rotation;
280  X11_XRRFreeCrtcInfo(crtcinfo);
281  }
282 
283  if (rotation & (XRANDR_ROTATION_LEFT|XRANDR_ROTATION_RIGHT)) {
284  mode->w = info->height;
285  mode->h = info->width;
286  } else {
287  mode->w = info->width;
288  mode->h = info->height;
289  }
290  mode->refresh_rate = CalculateXRandRRefreshRate(info);
291  ((SDL_DisplayModeData*)mode->driverdata)->xrandr_mode = modeID;
292 #ifdef X11MODES_DEBUG
293  printf("XRandR mode %d: %dx%d@%dHz\n", (int) modeID, mode->w, mode->h, mode->refresh_rate);
294 #endif
295  return SDL_TRUE;
296  }
297  }
298  return SDL_FALSE;
299 }
300 
301 static void
302 SetXRandRDisplayName(Display *dpy, Atom EDID, char *name, const size_t namelen, RROutput output, const unsigned long widthmm, const unsigned long heightmm)
303 {
304  /* See if we can get the EDID data for the real monitor name */
305  int inches;
306  int nprop;
307  Atom *props = X11_XRRListOutputProperties(dpy, output, &nprop);
308  int i;
309 
310  for (i = 0; i < nprop; ++i) {
311  unsigned char *prop;
312  int actual_format;
313  unsigned long nitems, bytes_after;
314  Atom actual_type;
315 
316  if (props[i] == EDID) {
317  if (X11_XRRGetOutputProperty(dpy, output, props[i], 0, 100, False,
318  False, AnyPropertyType, &actual_type,
319  &actual_format, &nitems, &bytes_after,
320  &prop) == Success) {
321  MonitorInfo *info = decode_edid(prop);
322  if (info) {
323 #ifdef X11MODES_DEBUG
324  printf("Found EDID data for %s\n", name);
325  dump_monitor_info(info);
326 #endif
327  SDL_strlcpy(name, info->dsc_product_name, namelen);
328  free(info);
329  }
330  X11_XFree(prop);
331  }
332  break;
333  }
334  }
335 
336  if (props) {
337  X11_XFree(props);
338  }
339 
340  inches = (int)((SDL_sqrtf(widthmm * widthmm + heightmm * heightmm) / 25.4f) + 0.5f);
341  if (*name && inches) {
342  const size_t len = SDL_strlen(name);
343  SDL_snprintf(&name[len], namelen-len, " %d\"", inches);
344  }
345 
346 #ifdef X11MODES_DEBUG
347  printf("Display name: %s\n", name);
348 #endif
349 }
350 
351 
352 static int
353 X11_InitModes_XRandR(_THIS)
354 {
356  Display *dpy = data->display;
357  const int screencount = ScreenCount(dpy);
358  const int default_screen = DefaultScreen(dpy);
359  RROutput primary = X11_XRRGetOutputPrimary(dpy, RootWindow(dpy, default_screen));
360  Atom EDID = X11_XInternAtom(dpy, "EDID", False);
361  XRRScreenResources *res = NULL;
362  Uint32 pixelformat;
363  XVisualInfo vinfo;
364  XPixmapFormatValues *pixmapformats;
365  int looking_for_primary;
366  int scanline_pad;
367  int output;
368  int screen, i, n;
369 
370  for (looking_for_primary = 1; looking_for_primary >= 0; looking_for_primary--) {
371  for (screen = 0; screen < screencount; screen++) {
372 
373  /* we want the primary output first, and then skipped later. */
374  if (looking_for_primary && (screen != default_screen)) {
375  continue;
376  }
377 
378  if (get_visualinfo(dpy, screen, &vinfo) < 0) {
379  continue; /* uh, skip this screen? */
380  }
381 
382  pixelformat = X11_GetPixelFormatFromVisualInfo(dpy, &vinfo);
383  if (SDL_ISPIXELFORMAT_INDEXED(pixelformat)) {
384  continue; /* Palettized video modes are no longer supported */
385  }
386 
387  scanline_pad = SDL_BYTESPERPIXEL(pixelformat) * 8;
388  pixmapformats = X11_XListPixmapFormats(dpy, &n);
389  if (pixmapformats) {
390  for (i = 0; i < n; ++i) {
391  if (pixmapformats[i].depth == vinfo.depth) {
392  scanline_pad = pixmapformats[i].scanline_pad;
393  break;
394  }
395  }
396  X11_XFree(pixmapformats);
397  }
398 
399  res = X11_XRRGetScreenResourcesCurrent(dpy, RootWindow(dpy, screen));
400  if (!res || res->noutput == 0) {
401  if (res) {
402  X11_XRRFreeScreenResources(res);
403  }
404 
405  res = X11_XRRGetScreenResources(dpy, RootWindow(dpy, screen));
406  if (!res) {
407  continue;
408  }
409  }
410 
411  for (output = 0; output < res->noutput; output++) {
412  XRROutputInfo *output_info;
413  int display_x, display_y;
414  unsigned long display_mm_width, display_mm_height;
415  SDL_DisplayData *displaydata;
416  char display_name[128];
418  SDL_DisplayModeData *modedata;
419  SDL_VideoDisplay display;
420  RRMode modeID;
421  RRCrtc output_crtc;
422  XRRCrtcInfo *crtc;
423 
424  /* The primary output _should_ always be sorted first, but just in case... */
425  if ((looking_for_primary && (res->outputs[output] != primary)) ||
426  (!looking_for_primary && (screen == default_screen) && (res->outputs[output] == primary))) {
427  continue;
428  }
429 
430  output_info = X11_XRRGetOutputInfo(dpy, res, res->outputs[output]);
431  if (!output_info || !output_info->crtc || output_info->connection == RR_Disconnected) {
432  X11_XRRFreeOutputInfo(output_info);
433  continue;
434  }
435 
436  SDL_strlcpy(display_name, output_info->name, sizeof(display_name));
437  display_mm_width = output_info->mm_width;
438  display_mm_height = output_info->mm_height;
439  output_crtc = output_info->crtc;
440  X11_XRRFreeOutputInfo(output_info);
441 
442  crtc = X11_XRRGetCrtcInfo(dpy, res, output_crtc);
443  if (!crtc) {
444  continue;
445  }
446 
447  SDL_zero(mode);
448  modeID = crtc->mode;
449  mode.w = crtc->width;
450  mode.h = crtc->height;
451  mode.format = pixelformat;
452 
453  display_x = crtc->x;
454  display_y = crtc->y;
455 
456  X11_XRRFreeCrtcInfo(crtc);
457 
458  displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
459  if (!displaydata) {
460  return SDL_OutOfMemory();
461  }
462 
463  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
464  if (!modedata) {
465  SDL_free(displaydata);
466  return SDL_OutOfMemory();
467  }
468  modedata->xrandr_mode = modeID;
469  mode.driverdata = modedata;
470 
471  displaydata->screen = screen;
472  displaydata->visual = vinfo.visual;
473  displaydata->depth = vinfo.depth;
474  displaydata->hdpi = display_mm_width ? (((float) mode.w) * 25.4f / display_mm_width) : 0.0f;
475  displaydata->vdpi = display_mm_height ? (((float) mode.h) * 25.4f / display_mm_height) : 0.0f;
476  displaydata->ddpi = SDL_ComputeDiagonalDPI(mode.w, mode.h, ((float) display_mm_width) / 25.4f,((float) display_mm_height) / 25.4f);
477  displaydata->scanline_pad = scanline_pad;
478  displaydata->x = display_x;
479  displaydata->y = display_y;
480  displaydata->use_xrandr = 1;
481  displaydata->xrandr_output = res->outputs[output];
482 
483  SetXRandRModeInfo(dpy, res, output_crtc, modeID, &mode);
484  SetXRandRDisplayName(dpy, EDID, display_name, sizeof (display_name), res->outputs[output], display_mm_width, display_mm_height);
485 
486  SDL_zero(display);
487  if (*display_name) {
488  display.name = display_name;
489  }
490  display.desktop_mode = mode;
491  display.current_mode = mode;
492  display.driverdata = displaydata;
493  SDL_AddVideoDisplay(&display);
494  }
495 
496  X11_XRRFreeScreenResources(res);
497  }
498  }
499 
500  if (_this->num_displays == 0) {
501  return SDL_SetError("No available displays");
502  }
503 
504  return 0;
505 }
506 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
507 
508 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
509 static SDL_bool
510 CheckVidMode(Display * display, int *major, int *minor)
511 {
512  /* Default the extension not available */
513  *major = *minor = 0;
514 
515  /* Allow environment override */
517 #ifdef X11MODES_DEBUG
518  printf("XVidMode disabled due to hint\n");
519 #endif
520  return SDL_FALSE;
521  }
522 
523  if (!SDL_X11_HAVE_XVIDMODE) {
524 #ifdef X11MODES_DEBUG
525  printf("XVidMode support not available\n");
526 #endif
527  return SDL_FALSE;
528  }
529 
530  /* Query the extension version */
531  vm_error = -1;
532  if (!X11_XF86VidModeQueryExtension(display, &vm_event, &vm_error)
533  || !X11_XF86VidModeQueryVersion(display, major, minor)) {
534 #ifdef X11MODES_DEBUG
535  printf("XVidMode not active on the display\n");
536 #endif
537  return SDL_FALSE;
538  }
539 #ifdef X11MODES_DEBUG
540  printf("XVidMode available at version %d.%d!\n", *major, *minor);
541 #endif
542  return SDL_TRUE;
543 }
544 
545 static
546 Bool XF86VidModeGetModeInfo(Display * dpy, int scr,
547  XF86VidModeModeInfo* info)
548 {
549  Bool retval;
550  int dotclock;
551  XF86VidModeModeLine l;
552  SDL_zerop(info);
553  SDL_zero(l);
554  retval = X11_XF86VidModeGetModeLine(dpy, scr, &dotclock, &l);
555  info->dotclock = dotclock;
556  info->hdisplay = l.hdisplay;
557  info->hsyncstart = l.hsyncstart;
558  info->hsyncend = l.hsyncend;
559  info->htotal = l.htotal;
560  info->hskew = l.hskew;
561  info->vdisplay = l.vdisplay;
562  info->vsyncstart = l.vsyncstart;
563  info->vsyncend = l.vsyncend;
564  info->vtotal = l.vtotal;
565  info->flags = l.flags;
566  info->privsize = l.privsize;
567  info->private = l.private;
568  return retval;
569 }
570 
571 static int
572 CalculateXVidModeRefreshRate(const XF86VidModeModeInfo * info)
573 {
574  return (info->htotal
575  && info->vtotal) ? (1000 * info->dotclock / (info->htotal *
576  info->vtotal)) : 0;
577 }
578 
579 static SDL_bool
580 SetXVidModeModeInfo(const XF86VidModeModeInfo *info, SDL_DisplayMode *mode)
581 {
582  mode->w = info->hdisplay;
583  mode->h = info->vdisplay;
584  mode->refresh_rate = CalculateXVidModeRefreshRate(info);
585  ((SDL_DisplayModeData*)mode->driverdata)->vm_mode = *info;
586  return SDL_TRUE;
587 }
588 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
589 
590 int
592 {
594  int snum, screen, screencount = 0;
596  int xinerama_major, xinerama_minor;
597  int use_xinerama = 0;
598  XineramaScreenInfo *xinerama = NULL;
599 #endif
601  int xrandr_major, xrandr_minor;
602 #endif
604  int vm_major, vm_minor;
605  int use_vidmode = 0;
606 #endif
607 
608 /* XRandR is the One True Modern Way to do this on X11. If it's enabled and
609  available, don't even look at other ways of doing things. */
611  /* require at least XRandR v1.3 */
612  if (CheckXRandR(data->display, &xrandr_major, &xrandr_minor) &&
613  (xrandr_major >= 2 || (xrandr_major == 1 && xrandr_minor >= 3))) {
614  if (X11_InitModes_XRandR(_this) == 0)
615  return 0;
616  }
617 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
618 
619 /* !!! FIXME: eventually remove support for Xinerama and XVidMode (everything below here). */
620 
621  /* This is a workaround for some apps (UnrealEngine4, for example) until
622  we sort out the ramifications of removing XVidMode support outright.
623  This block should be removed with the XVidMode support. */
624  {
625  if (SDL_GetHintBoolean("SDL_VIDEO_X11_REQUIRE_XRANDR", SDL_FALSE)) {
626  #if SDL_VIDEO_DRIVER_X11_XRANDR
627  return SDL_SetError("XRandR support is required but not available");
628  #else
629  return SDL_SetError("XRandR support is required but not built into SDL!");
630  #endif
631  }
632  }
633 
634 #if SDL_VIDEO_DRIVER_X11_XINERAMA
635  /* Query Xinerama extention
636  * NOTE: This works with Nvidia Twinview correctly, but you need version 302.17 (released on June 2012)
637  * or newer of the Nvidia binary drivers
638  */
639  if (CheckXinerama(data->display, &xinerama_major, &xinerama_minor)) {
640  int (*handler) (Display *, XErrorEvent *);
641  X11_XSync(data->display, False);
642  handler = X11_XSetErrorHandler(X11_XineramaFailed);
643  xinerama = X11_XineramaQueryScreens(data->display, &screencount);
644  X11_XSync(data->display, False);
645  X11_XSetErrorHandler(handler);
646  if (xinerama_triggered_error) {
647  xinerama = 0;
648  }
649  if (xinerama) {
650  use_xinerama = xinerama_major * 100 + xinerama_minor;
651  }
652  }
653  if (!xinerama) {
654  screencount = ScreenCount(data->display);
655  }
656 #else
657  screencount = ScreenCount(data->display);
658 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
659 
660 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
661  if (CheckVidMode(data->display, &vm_major, &vm_minor)) {
662  use_vidmode = vm_major * 100 + vm_minor;
663  }
664 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
665 
666  for (snum = 0; snum < screencount; ++snum) {
667  XVisualInfo vinfo;
668  SDL_VideoDisplay display;
669  SDL_DisplayData *displaydata;
671  SDL_DisplayModeData *modedata;
672  XPixmapFormatValues *pixmapFormats;
673  char display_name[128];
674  int i, n;
675 
676  /* Re-order screens to always put default screen first */
677  if (snum == 0) {
678  screen = DefaultScreen(data->display);
679  } else if (snum == DefaultScreen(data->display)) {
680  screen = 0;
681  } else {
682  screen = snum;
683  }
684 
685 #if SDL_VIDEO_DRIVER_X11_XINERAMA
686  if (xinerama) {
687  if (get_visualinfo(data->display, 0, &vinfo) < 0) {
688  continue;
689  }
690  } else {
691  if (get_visualinfo(data->display, screen, &vinfo) < 0) {
692  continue;
693  }
694  }
695 #else
696  if (get_visualinfo(data->display, screen, &vinfo) < 0) {
697  continue;
698  }
699 #endif
700 
701  displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
702  if (!displaydata) {
703  continue;
704  }
705  display_name[0] = '\0';
706 
707  mode.format = X11_GetPixelFormatFromVisualInfo(data->display, &vinfo);
708  if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
709  /* We don't support palettized modes now */
710  SDL_free(displaydata);
711  continue;
712  }
713 #if SDL_VIDEO_DRIVER_X11_XINERAMA
714  if (xinerama) {
715  mode.w = xinerama[screen].width;
716  mode.h = xinerama[screen].height;
717  } else {
718  mode.w = DisplayWidth(data->display, screen);
719  mode.h = DisplayHeight(data->display, screen);
720  }
721 #else
722  mode.w = DisplayWidth(data->display, screen);
723  mode.h = DisplayHeight(data->display, screen);
724 #endif
725  mode.refresh_rate = 0;
726 
727  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
728  if (!modedata) {
729  SDL_free(displaydata);
730  continue;
731  }
732  mode.driverdata = modedata;
733 
734 #if SDL_VIDEO_DRIVER_X11_XINERAMA
735  /* Most of SDL's calls to X11 are unwaware of Xinerama, and to X11 standard calls, when Xinerama is active,
736  * there's only one screen available. So we force the screen number to zero and
737  * let Xinerama specific code handle specific functionality using displaydata->xinerama_info
738  */
739  if (use_xinerama) {
740  displaydata->screen = 0;
741  displaydata->use_xinerama = use_xinerama;
742  displaydata->xinerama_info = xinerama[screen];
743  displaydata->xinerama_screen = screen;
744  }
745  else displaydata->screen = screen;
746 #else
747  displaydata->screen = screen;
748 #endif
749  displaydata->visual = vinfo.visual;
750  displaydata->depth = vinfo.depth;
751 
752  /* We use the displaydata screen index here so that this works
753  for both the Xinerama case, where we get the overall DPI,
754  and the regular X11 screen info case. */
755  displaydata->hdpi = (float)DisplayWidth(data->display, displaydata->screen) * 25.4f /
756  DisplayWidthMM(data->display, displaydata->screen);
757  displaydata->vdpi = (float)DisplayHeight(data->display, displaydata->screen) * 25.4f /
758  DisplayHeightMM(data->display, displaydata->screen);
759  displaydata->ddpi = SDL_ComputeDiagonalDPI(DisplayWidth(data->display, displaydata->screen),
760  DisplayHeight(data->display, displaydata->screen),
761  (float)DisplayWidthMM(data->display, displaydata->screen) / 25.4f,
762  (float)DisplayHeightMM(data->display, displaydata->screen) / 25.4f);
763 
764  displaydata->scanline_pad = SDL_BYTESPERPIXEL(mode.format) * 8;
765  pixmapFormats = X11_XListPixmapFormats(data->display, &n);
766  if (pixmapFormats) {
767  for (i = 0; i < n; ++i) {
768  if (pixmapFormats[i].depth == displaydata->depth) {
769  displaydata->scanline_pad = pixmapFormats[i].scanline_pad;
770  break;
771  }
772  }
773  X11_XFree(pixmapFormats);
774  }
775 
776 #if SDL_VIDEO_DRIVER_X11_XINERAMA
777  if (use_xinerama) {
778  displaydata->x = xinerama[screen].x_org;
779  displaydata->y = xinerama[screen].y_org;
780  }
781  else
782 #endif
783  {
784  displaydata->x = 0;
785  displaydata->y = 0;
786  }
787 
788 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
789  if (!displaydata->use_xrandr &&
791  /* XVidMode only works on the screen at the origin */
792  (!displaydata->use_xinerama ||
793  (displaydata->x == 0 && displaydata->y == 0)) &&
794 #endif
795  use_vidmode) {
796  displaydata->use_vidmode = use_vidmode;
797  if (displaydata->use_xinerama) {
798  displaydata->vidmode_screen = 0;
799  } else {
800  displaydata->vidmode_screen = screen;
801  }
802  XF86VidModeGetModeInfo(data->display, displaydata->vidmode_screen, &modedata->vm_mode);
803  }
804 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
805 
806  SDL_zero(display);
807  if (*display_name) {
808  display.name = display_name;
809  }
810  display.desktop_mode = mode;
811  display.current_mode = mode;
812  display.driverdata = displaydata;
813  SDL_AddVideoDisplay(&display);
814  }
815 
816 #if SDL_VIDEO_DRIVER_X11_XINERAMA
817  if (xinerama) X11_XFree(xinerama);
818 #endif
819 
820  if (_this->num_displays == 0) {
821  return SDL_SetError("No available displays");
822  }
823  return 0;
824 }
825 
826 void
828 {
829  Display *display = ((SDL_VideoData *) _this->driverdata)->display;
830  SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
832  int nmodes;
833  XF86VidModeModeInfo ** modes;
834 #endif
835  SDL_DisplayMode mode;
836 
837  /* Unfortunately X11 requires the window to be created with the correct
838  * visual and depth ahead of time, but the SDL API allows you to create
839  * a window before setting the fullscreen display mode. This means that
840  * we have to use the same format for all windows and all display modes.
841  * (or support recreating the window with a new visual behind the scenes)
842  */
843  mode.format = sdl_display->current_mode.format;
844  mode.driverdata = NULL;
845 
847  if (data->use_xinerama) {
848  int screen_w;
849  int screen_h;
850 
851  screen_w = DisplayWidth(display, data->screen);
852  screen_h = DisplayHeight(display, data->screen);
853 
854  if (data->use_vidmode && !data->xinerama_info.x_org && !data->xinerama_info.y_org &&
855  (screen_w > data->xinerama_info.width || screen_h > data->xinerama_info.height)) {
856  SDL_DisplayModeData *modedata;
857  /* Add the full (both screens combined) xinerama mode only on the display that starts at 0,0
858  * if we're using vidmode.
859  */
860  mode.w = screen_w;
861  mode.h = screen_h;
862  mode.refresh_rate = 0;
863  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
864  if (modedata) {
865  *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
866  }
867  mode.driverdata = modedata;
868  if (!SDL_AddDisplayMode(sdl_display, &mode)) {
869  SDL_free(modedata);
870  }
871  }
872  else if (!data->use_xrandr)
873  {
874  SDL_DisplayModeData *modedata;
875  /* Add the current mode of each monitor otherwise if we can't get them from xrandr */
876  mode.w = data->xinerama_info.width;
877  mode.h = data->xinerama_info.height;
878  mode.refresh_rate = 0;
879  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
880  if (modedata) {
881  *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
882  }
883  mode.driverdata = modedata;
884  if (!SDL_AddDisplayMode(sdl_display, &mode)) {
885  SDL_free(modedata);
886  }
887  }
888 
889  }
890 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
891 
892 #if SDL_VIDEO_DRIVER_X11_XRANDR
893  if (data->use_xrandr) {
894  XRRScreenResources *res;
895 
896  res = X11_XRRGetScreenResources (display, RootWindow(display, data->screen));
897  if (res) {
898  SDL_DisplayModeData *modedata;
899  XRROutputInfo *output_info;
900  int i;
901 
902  output_info = X11_XRRGetOutputInfo(display, res, data->xrandr_output);
903  if (output_info && output_info->connection != RR_Disconnected) {
904  for (i = 0; i < output_info->nmode; ++i) {
905  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
906  if (!modedata) {
907  continue;
908  }
909  mode.driverdata = modedata;
910 
911  if (!SetXRandRModeInfo(display, res, output_info->crtc, output_info->modes[i], &mode) ||
912  !SDL_AddDisplayMode(sdl_display, &mode)) {
913  SDL_free(modedata);
914  }
915  }
916  }
917  X11_XRRFreeOutputInfo(output_info);
918  X11_XRRFreeScreenResources(res);
919  }
920  return;
921  }
922 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
923 
924 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
925  if (data->use_vidmode &&
926  X11_XF86VidModeGetAllModeLines(display, data->vidmode_screen, &nmodes, &modes)) {
927  int i;
928  SDL_DisplayModeData *modedata;
929 
930 #ifdef X11MODES_DEBUG
931  printf("VidMode modes: (unsorted)\n");
932  for (i = 0; i < nmodes; ++i) {
933  printf("Mode %d: %d x %d @ %d, flags: 0x%x\n", i,
934  modes[i]->hdisplay, modes[i]->vdisplay,
935  CalculateXVidModeRefreshRate(modes[i]), modes[i]->flags);
936  }
937 #endif
938  for (i = 0; i < nmodes; ++i) {
939  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
940  if (!modedata) {
941  continue;
942  }
943  mode.driverdata = modedata;
944 
945  if (!SetXVidModeModeInfo(modes[i], &mode) || !SDL_AddDisplayMode(sdl_display, &mode)) {
946  SDL_free(modedata);
947  }
948  }
949  X11_XFree(modes);
950  return;
951  }
952 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
953 
954  if (!data->use_xrandr && !data->use_vidmode) {
955  SDL_DisplayModeData *modedata;
956  /* Add the desktop mode */
957  mode = sdl_display->desktop_mode;
958  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
959  if (modedata) {
960  *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
961  }
962  mode.driverdata = modedata;
963  if (!SDL_AddDisplayMode(sdl_display, &mode)) {
964  SDL_free(modedata);
965  }
966  }
967 }
968 
969 int
971 {
973  Display *display = viddata->display;
974  SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
976 
978 
979 #if SDL_VIDEO_DRIVER_X11_XRANDR
980  if (data->use_xrandr) {
981  XRRScreenResources *res;
982  XRROutputInfo *output_info;
983  XRRCrtcInfo *crtc;
984  Status status;
985 
986  res = X11_XRRGetScreenResources (display, RootWindow(display, data->screen));
987  if (!res) {
988  return SDL_SetError("Couldn't get XRandR screen resources");
989  }
990 
991  output_info = X11_XRRGetOutputInfo(display, res, data->xrandr_output);
992  if (!output_info || output_info->connection == RR_Disconnected) {
993  X11_XRRFreeScreenResources(res);
994  return SDL_SetError("Couldn't get XRandR output info");
995  }
996 
997  crtc = X11_XRRGetCrtcInfo(display, res, output_info->crtc);
998  if (!crtc) {
999  X11_XRRFreeOutputInfo(output_info);
1000  X11_XRRFreeScreenResources(res);
1001  return SDL_SetError("Couldn't get XRandR crtc info");
1002  }
1003 
1004  status = X11_XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime,
1005  crtc->x, crtc->y, modedata->xrandr_mode, crtc->rotation,
1006  &data->xrandr_output, 1);
1007 
1008  X11_XRRFreeCrtcInfo(crtc);
1009  X11_XRRFreeOutputInfo(output_info);
1010  X11_XRRFreeScreenResources(res);
1011 
1012  if (status != Success) {
1013  return SDL_SetError("X11_XRRSetCrtcConfig failed");
1014  }
1015  }
1016 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
1017 
1018 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
1019  if (data->use_vidmode) {
1020  X11_XF86VidModeSwitchToMode(display, data->vidmode_screen, &modedata->vm_mode);
1021  }
1022 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
1023 
1024  return 0;
1025 }
1026 
1027 void
1029 {
1030 }
1031 
1032 int
1034 {
1035  SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
1036 
1037  rect->x = data->x;
1038  rect->y = data->y;
1039  rect->w = sdl_display->current_mode.w;
1040  rect->h = sdl_display->current_mode.h;
1041 
1043  /* Get the real current bounds of the display */
1044  if (data->use_xinerama) {
1045  Display *display = ((SDL_VideoData *) _this->driverdata)->display;
1046  int screencount;
1047  XineramaScreenInfo *xinerama = X11_XineramaQueryScreens(display, &screencount);
1048  if (xinerama) {
1049  rect->x = xinerama[data->xinerama_screen].x_org;
1050  rect->y = xinerama[data->xinerama_screen].y_org;
1051  X11_XFree(xinerama);
1052  }
1053  }
1054 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
1055  return 0;
1056 }
1057 
1058 int
1059 X11_GetDisplayDPI(_THIS, SDL_VideoDisplay * sdl_display, float * ddpi, float * hdpi, float * vdpi)
1060 {
1061  SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
1062 
1063  if (ddpi) {
1064  *ddpi = data->ddpi;
1065  }
1066  if (hdpi) {
1067  *hdpi = data->hdpi;
1068  }
1069  if (vdpi) {
1070  *vdpi = data->vdpi;
1071  }
1072 
1073  return data->ddpi != 0.0f ? 0 : SDL_SetError("Couldn't get DPI");
1074 }
1075 
1076 int
1078 {
1080  Display *display = data->display;
1081  Atom _NET_WORKAREA;
1082  int status, real_format;
1083  int retval = -1;
1084  Atom real_type;
1085  unsigned long items_read = 0, items_left = 0;
1086  unsigned char *propdata = NULL;
1087 
1088  if (X11_GetDisplayBounds(_this, sdl_display, rect) < 0) {
1089  return -1;
1090  }
1091 
1092  _NET_WORKAREA = X11_XInternAtom(display, "_NET_WORKAREA", False);
1093  status = X11_XGetWindowProperty(display, DefaultRootWindow(display),
1094  _NET_WORKAREA, 0L, 4L, False, XA_CARDINAL,
1095  &real_type, &real_format, &items_read,
1096  &items_left, &propdata);
1097  if ((status == Success) && (items_read >= 4)) {
1098  const long *p = (long*) propdata;
1099  const SDL_Rect usable = { (int)p[0], (int)p[1], (int)p[2], (int)p[3] };
1100  retval = 0;
1101  if (!SDL_IntersectRect(rect, &usable, rect)) {
1102  SDL_zerop(rect);
1103  }
1104  }
1105 
1106  if (propdata) {
1107  X11_XFree(propdata);
1108  }
1109 
1110  return retval;
1111 }
1112 
1113 #endif /* SDL_VIDEO_DRIVER_X11 */
1114 
1115 /* vi: set ts=4 sw=4 expandtab: */
Uint32 X11_GetPixelFormatFromVisualInfo(Display *display, XVisualInfo *vinfo)
char dsc_product_name[14]
Definition: edid.h:160
#define SDL_strlcpy
GLint namelen
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 Uint32 * e
MonitorInfo * decode_edid(const uchar *edid)
Definition: edid-parse.c:523
int X11_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
#define SDL_ISPIXELFORMAT_INDEXED(format)
Definition: SDL_pixels.h:134
#define SDL_VIDEO_DRIVER_X11_XRANDR
Definition: SDL_config.h:327
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display dpy)
Definition: SDL_x11sym.h:44
SDL_Rect rect
Definition: testrelative.c:27
struct wl_display * display
#define SDL_MasksToPixelFormatEnum
GLfloat GLfloat p
SDL_EventEntry * free
Definition: SDL_events.c:83
SDL_bool X11_UseDirectColorVisuals(void)
The structure that defines a display mode.
Definition: SDL_video.h:53
GLfloat f
#define SDL_BYTESPERPIXEL(X)
Definition: SDL_pixels.h:128
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
uint32_t Uint32
Definition: SDL_stdinc.h:181
#define SDL_IntersectRect
#define SDL_zerop(x)
Definition: SDL_stdinc.h:386
int SDL_AddVideoDisplay(const SDL_VideoDisplay *display)
Definition: SDL_video.c:606
GLenum GLsizei len
GLuint const GLchar * name
GLuint res
#define SDL_GetHintBoolean
int X11_GetDisplayBounds(_THIS, SDL_VideoDisplay *sdl_display, SDL_Rect *rect)
static SDL_VideoDevice * _this
Definition: SDL_video.c:121
void dump_monitor_info(MonitorInfo *info)
Definition: edid-parse.c:551
SDL_bool retval
void * SDL_calloc(size_t nmemb, size_t size)
void X11_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 ** d
int X11_InitModes(_THIS)
#define _THIS
void SDL_free(void *mem)
void * driverdata
Definition: SDL_video.h:59
int X11_GetDisplayDPI(_THIS, SDL_VideoDisplay *sdl_display, float *ddpi, float *hdpi, float *vdpi)
SDL_DisplayMode current_mode
Definition: SDL_sysvideo.h:132
GLenum mode
#define SDL_strtol
#define SDL_zero(x)
Definition: SDL_stdinc.h:385
Visual * visual
Definition: SDL_x11modes.h:29
int x
Definition: SDL_rect.h:66
int w
Definition: SDL_rect.h:67
#define SDL_VIDEO_DRIVER_X11_XVIDMODE
Definition: SDL_config.h:330
#define SDL_getenv
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:164
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:139
SDL_DisplayMode desktop_mode
Definition: SDL_sysvideo.h:131
#define SDL_HINT_VIDEO_X11_XRANDR
A variable controlling whether the X11 XRandR extension should be used.
Definition: SDL_hints.h:197
GLint GLint GLsizei GLsizei GLsizei depth
Definition: SDL_opengl.h:1572
#define SDL_SetError
GLbitfield flags
#define SDL_sqrtf
void X11_QuitModes(_THIS)
#define SDL_strlen
int h
Definition: SDL_rect.h:67
#define PENDING_FOCUS_TIME
Definition: SDL_x11window.h:30
GLdouble n
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:743
#define SDL_snprintf
#define SDL_VIDEO_DRIVER_X11_XINERAMA
Definition: SDL_config.h:324
Uint32 last_mode_change_deadline
Definition: SDL_x11video.h:131
Uint32 format
Definition: SDL_video.h:55
int X11_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay *sdl_display, SDL_Rect *rect)
GLenum GLuint GLsizei const GLenum * props
int X11_GetVisualInfoFromVisual(Display *display, Visual *visual, XVisualInfo *vinfo)
SDL_Renderer * screen
#define SDL_HINT_VIDEO_X11_XVIDMODE
A variable controlling whether the X11 VidMode extension should be used.
Definition: SDL_hints.h:175
int y
Definition: SDL_rect.h:66
float SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches)
Definition: SDL_video.c:3911
#define SDL_HINT_VIDEO_X11_XINERAMA
A variable controlling whether the X11 Xinerama extension should be used.
Definition: SDL_hints.h:186
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:64