SDL  2.0
SDL_x11modes.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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 #if SDL_VIDEO_DRIVER_X11_XINERAMA
152 static SDL_bool
153 CheckXinerama(Display * display, int *major, int *minor)
154 {
155  int event_base = 0;
156  int error_base = 0;
157 
158  /* Default the extension not available */
159  *major = *minor = 0;
160 
161  /* Allow environment override */
163 #ifdef X11MODES_DEBUG
164  printf("Xinerama disabled due to hint\n");
165 #endif
166  return SDL_FALSE;
167  }
168 
169  if (!SDL_X11_HAVE_XINERAMA) {
170 #ifdef X11MODES_DEBUG
171  printf("Xinerama support not available\n");
172 #endif
173  return SDL_FALSE;
174  }
175 
176  /* Query the extension version */
177  if (!X11_XineramaQueryExtension(display, &event_base, &error_base) ||
178  !X11_XineramaQueryVersion(display, major, minor) ||
179  !X11_XineramaIsActive(display)) {
180 #ifdef X11MODES_DEBUG
181  printf("Xinerama not active on the display\n");
182 #endif
183  return SDL_FALSE;
184  }
185 #ifdef X11MODES_DEBUG
186  printf("Xinerama available at version %d.%d!\n", *major, *minor);
187 #endif
188  return SDL_TRUE;
189 }
190 
191 /* !!! FIXME: remove this later. */
192 /* we have a weird bug where XineramaQueryScreens() throws an X error, so this
193  is here to help track it down (and not crash, too!). */
194 static SDL_bool xinerama_triggered_error = SDL_FALSE;
195 static int
196 X11_XineramaFailed(Display * d, XErrorEvent * e)
197 {
198  xinerama_triggered_error = SDL_TRUE;
199  fprintf(stderr, "XINERAMA X ERROR: type=%d serial=%lu err=%u req=%u minor=%u\n",
200  e->type, e->serial, (unsigned int) e->error_code,
201  (unsigned int) e->request_code, (unsigned int) e->minor_code);
202  fflush(stderr);
203  return 0;
204 }
205 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
206 
207 #if SDL_VIDEO_DRIVER_X11_XRANDR
208 static SDL_bool
209 CheckXRandR(Display * display, int *major, int *minor)
210 {
211  /* Default the extension not available */
212  *major = *minor = 0;
213 
214  /* Allow environment override */
215 #ifdef XRANDR_DISABLED_BY_DEFAULT
217 #ifdef X11MODES_DEBUG
218  printf("XRandR disabled by default due to window manager issues\n");
219 #endif
220  return SDL_FALSE;
221  }
222 #else
224 #ifdef X11MODES_DEBUG
225  printf("XRandR disabled due to hint\n");
226 #endif
227  return SDL_FALSE;
228  }
229 #endif /* XRANDR_ENABLED_BY_DEFAULT */
230 
231  if (!SDL_X11_HAVE_XRANDR) {
232 #ifdef X11MODES_DEBUG
233  printf("XRandR support not available\n");
234 #endif
235  return SDL_FALSE;
236  }
237 
238  /* Query the extension version */
239  *major = 1; *minor = 3; /* we want 1.3 */
240  if (!X11_XRRQueryVersion(display, major, minor)) {
241 #ifdef X11MODES_DEBUG
242  printf("XRandR not active on the display\n");
243 #endif
244  *major = *minor = 0;
245  return SDL_FALSE;
246  }
247 #ifdef X11MODES_DEBUG
248  printf("XRandR available at version %d.%d!\n", *major, *minor);
249 #endif
250  return SDL_TRUE;
251 }
252 
253 #define XRANDR_ROTATION_LEFT (1 << 1)
254 #define XRANDR_ROTATION_RIGHT (1 << 3)
255 
256 static int
257 CalculateXRandRRefreshRate(const XRRModeInfo *info)
258 {
259  return (info->hTotal && info->vTotal) ?
260  round(((double)info->dotClock / (double)(info->hTotal * info->vTotal))) : 0;
261 }
262 
263 static SDL_bool
264 SetXRandRModeInfo(Display *display, XRRScreenResources *res, RRCrtc crtc,
265  RRMode modeID, SDL_DisplayMode *mode)
266 {
267  int i;
268  for (i = 0; i < res->nmode; ++i) {
269  const XRRModeInfo *info = &res->modes[i];
270  if (info->id == modeID) {
271  XRRCrtcInfo *crtcinfo;
272  Rotation rotation = 0;
273 
274  crtcinfo = X11_XRRGetCrtcInfo(display, res, crtc);
275  if (crtcinfo) {
276  rotation = crtcinfo->rotation;
277  X11_XRRFreeCrtcInfo(crtcinfo);
278  }
279 
280  if (rotation & (XRANDR_ROTATION_LEFT|XRANDR_ROTATION_RIGHT)) {
281  mode->w = info->height;
282  mode->h = info->width;
283  } else {
284  mode->w = info->width;
285  mode->h = info->height;
286  }
287  mode->refresh_rate = CalculateXRandRRefreshRate(info);
288  ((SDL_DisplayModeData*)mode->driverdata)->xrandr_mode = modeID;
289 #ifdef X11MODES_DEBUG
290  printf("XRandR mode %d: %dx%d@%dHz\n", (int) modeID, mode->w, mode->h, mode->refresh_rate);
291 #endif
292  return SDL_TRUE;
293  }
294  }
295  return SDL_FALSE;
296 }
297 
298 static void
299 SetXRandRDisplayName(Display *dpy, Atom EDID, char *name, const size_t namelen, RROutput output, const unsigned long widthmm, const unsigned long heightmm)
300 {
301  /* See if we can get the EDID data for the real monitor name */
302  int inches;
303  int nprop;
304  Atom *props = X11_XRRListOutputProperties(dpy, output, &nprop);
305  int i;
306 
307  for (i = 0; i < nprop; ++i) {
308  unsigned char *prop;
309  int actual_format;
310  unsigned long nitems, bytes_after;
311  Atom actual_type;
312 
313  if (props[i] == EDID) {
314  if (X11_XRRGetOutputProperty(dpy, output, props[i], 0, 100, False,
315  False, AnyPropertyType, &actual_type,
316  &actual_format, &nitems, &bytes_after,
317  &prop) == Success) {
318  MonitorInfo *info = decode_edid(prop);
319  if (info) {
320 #ifdef X11MODES_DEBUG
321  printf("Found EDID data for %s\n", name);
322  dump_monitor_info(info);
323 #endif
324  SDL_strlcpy(name, info->dsc_product_name, namelen);
325  free(info);
326  }
327  X11_XFree(prop);
328  }
329  break;
330  }
331  }
332 
333  if (props) {
334  X11_XFree(props);
335  }
336 
337  inches = (int)((SDL_sqrtf(widthmm * widthmm + heightmm * heightmm) / 25.4f) + 0.5f);
338  if (*name && inches) {
339  const size_t len = SDL_strlen(name);
340  SDL_snprintf(&name[len], namelen-len, " %d\"", inches);
341  }
342 
343 #ifdef X11MODES_DEBUG
344  printf("Display name: %s\n", name);
345 #endif
346 }
347 
348 
349 static int
350 X11_InitModes_XRandR(_THIS)
351 {
353  Display *dpy = data->display;
354  const int screencount = ScreenCount(dpy);
355  const int default_screen = DefaultScreen(dpy);
356  RROutput primary = X11_XRRGetOutputPrimary(dpy, RootWindow(dpy, default_screen));
357  Atom EDID = X11_XInternAtom(dpy, "EDID", False);
358  XRRScreenResources *res = NULL;
359  Uint32 pixelformat;
360  XVisualInfo vinfo;
361  XPixmapFormatValues *pixmapformats;
362  int looking_for_primary;
363  int scanline_pad;
364  int output;
365  int screen, i, n;
366 
367  for (looking_for_primary = 1; looking_for_primary >= 0; looking_for_primary--) {
368  for (screen = 0; screen < screencount; screen++) {
369 
370  /* we want the primary output first, and then skipped later. */
371  if (looking_for_primary && (screen != default_screen)) {
372  continue;
373  }
374 
375  if (get_visualinfo(dpy, screen, &vinfo) < 0) {
376  continue; /* uh, skip this screen? */
377  }
378 
379  pixelformat = X11_GetPixelFormatFromVisualInfo(dpy, &vinfo);
380  if (SDL_ISPIXELFORMAT_INDEXED(pixelformat)) {
381  continue; /* Palettized video modes are no longer supported */
382  }
383 
384  scanline_pad = SDL_BYTESPERPIXEL(pixelformat) * 8;
385  pixmapformats = X11_XListPixmapFormats(dpy, &n);
386  if (pixmapformats) {
387  for (i = 0; i < n; ++i) {
388  if (pixmapformats[i].depth == vinfo.depth) {
389  scanline_pad = pixmapformats[i].scanline_pad;
390  break;
391  }
392  }
393  X11_XFree(pixmapformats);
394  }
395 
396  res = X11_XRRGetScreenResourcesCurrent(dpy, RootWindow(dpy, screen));
397  if (!res || res->noutput == 0) {
398  if (res) {
399  X11_XRRFreeScreenResources(res);
400  }
401 
402  res = X11_XRRGetScreenResources(dpy, RootWindow(dpy, screen));
403  if (!res) {
404  continue;
405  }
406  }
407 
408  for (output = 0; output < res->noutput; output++) {
409  XRROutputInfo *output_info;
410  int display_x, display_y;
411  unsigned long display_mm_width, display_mm_height;
412  SDL_DisplayData *displaydata;
413  char display_name[128];
415  SDL_DisplayModeData *modedata;
416  SDL_VideoDisplay display;
417  RRMode modeID;
418  RRCrtc output_crtc;
419  XRRCrtcInfo *crtc;
420 
421  /* The primary output _should_ always be sorted first, but just in case... */
422  if ((looking_for_primary && (res->outputs[output] != primary)) ||
423  (!looking_for_primary && (screen == default_screen) && (res->outputs[output] == primary))) {
424  continue;
425  }
426 
427  output_info = X11_XRRGetOutputInfo(dpy, res, res->outputs[output]);
428  if (!output_info || !output_info->crtc || output_info->connection == RR_Disconnected) {
429  X11_XRRFreeOutputInfo(output_info);
430  continue;
431  }
432 
433  SDL_strlcpy(display_name, output_info->name, sizeof(display_name));
434  display_mm_width = output_info->mm_width;
435  display_mm_height = output_info->mm_height;
436  output_crtc = output_info->crtc;
437  X11_XRRFreeOutputInfo(output_info);
438 
439  crtc = X11_XRRGetCrtcInfo(dpy, res, output_crtc);
440  if (!crtc) {
441  continue;
442  }
443 
444  SDL_zero(mode);
445  modeID = crtc->mode;
446  mode.w = crtc->width;
447  mode.h = crtc->height;
448  mode.format = pixelformat;
449 
450  display_x = crtc->x;
451  display_y = crtc->y;
452 
453  X11_XRRFreeCrtcInfo(crtc);
454 
455  displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
456  if (!displaydata) {
457  return SDL_OutOfMemory();
458  }
459 
460  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
461  if (!modedata) {
462  SDL_free(displaydata);
463  return SDL_OutOfMemory();
464  }
465  modedata->xrandr_mode = modeID;
466  mode.driverdata = modedata;
467 
468  displaydata->screen = screen;
469  displaydata->visual = vinfo.visual;
470  displaydata->depth = vinfo.depth;
471  displaydata->hdpi = display_mm_width ? (((float) mode.w) * 25.4f / display_mm_width) : 0.0f;
472  displaydata->vdpi = display_mm_height ? (((float) mode.h) * 25.4f / display_mm_height) : 0.0f;
473  displaydata->ddpi = SDL_ComputeDiagonalDPI(mode.w, mode.h, ((float) display_mm_width) / 25.4f,((float) display_mm_height) / 25.4f);
474  displaydata->scanline_pad = scanline_pad;
475  displaydata->x = display_x;
476  displaydata->y = display_y;
477  displaydata->use_xrandr = 1;
478  displaydata->xrandr_output = res->outputs[output];
479 
480  SetXRandRModeInfo(dpy, res, output_crtc, modeID, &mode);
481  SetXRandRDisplayName(dpy, EDID, display_name, sizeof (display_name), res->outputs[output], display_mm_width, display_mm_height);
482 
483  SDL_zero(display);
484  if (*display_name) {
485  display.name = display_name;
486  }
487  display.desktop_mode = mode;
488  display.current_mode = mode;
489  display.driverdata = displaydata;
490  SDL_AddVideoDisplay(&display);
491  }
492 
493  X11_XRRFreeScreenResources(res);
494  }
495  }
496 
497  if (_this->num_displays == 0) {
498  return SDL_SetError("No available displays");
499  }
500 
501  return 0;
502 }
503 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
504 
505 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
506 static SDL_bool
507 CheckVidMode(Display * display, int *major, int *minor)
508 {
509  int vm_event, vm_error = -1;
510  /* Default the extension not available */
511  *major = *minor = 0;
512 
513  /* Allow environment override */
515 #ifdef X11MODES_DEBUG
516  printf("XVidMode disabled due to hint\n");
517 #endif
518  return SDL_FALSE;
519  }
520 
521  if (!SDL_X11_HAVE_XVIDMODE) {
522 #ifdef X11MODES_DEBUG
523  printf("XVidMode support not available\n");
524 #endif
525  return SDL_FALSE;
526  }
527 
528  /* Query the extension version */
529  if (!X11_XF86VidModeQueryExtension(display, &vm_event, &vm_error)
530  || !X11_XF86VidModeQueryVersion(display, major, minor)) {
531 #ifdef X11MODES_DEBUG
532  printf("XVidMode not active on the display\n");
533 #endif
534  return SDL_FALSE;
535  }
536 #ifdef X11MODES_DEBUG
537  printf("XVidMode available at version %d.%d!\n", *major, *minor);
538 #endif
539  return SDL_TRUE;
540 }
541 
542 static
543 Bool XF86VidModeGetModeInfo(Display * dpy, int scr,
544  XF86VidModeModeInfo* info)
545 {
546  Bool retval;
547  int dotclock;
548  XF86VidModeModeLine l;
549  SDL_zerop(info);
550  SDL_zero(l);
551  retval = X11_XF86VidModeGetModeLine(dpy, scr, &dotclock, &l);
552  info->dotclock = dotclock;
553  info->hdisplay = l.hdisplay;
554  info->hsyncstart = l.hsyncstart;
555  info->hsyncend = l.hsyncend;
556  info->htotal = l.htotal;
557  info->hskew = l.hskew;
558  info->vdisplay = l.vdisplay;
559  info->vsyncstart = l.vsyncstart;
560  info->vsyncend = l.vsyncend;
561  info->vtotal = l.vtotal;
562  info->flags = l.flags;
563  info->privsize = l.privsize;
564  info->private = l.private;
565  return retval;
566 }
567 
568 static int
569 CalculateXVidModeRefreshRate(const XF86VidModeModeInfo * info)
570 {
571  return (info->htotal
572  && info->vtotal) ? (1000 * info->dotclock / (info->htotal *
573  info->vtotal)) : 0;
574 }
575 
576 static SDL_bool
577 SetXVidModeModeInfo(const XF86VidModeModeInfo *info, SDL_DisplayMode *mode)
578 {
579  mode->w = info->hdisplay;
580  mode->h = info->vdisplay;
581  mode->refresh_rate = CalculateXVidModeRefreshRate(info);
582  ((SDL_DisplayModeData*)mode->driverdata)->vm_mode = *info;
583  return SDL_TRUE;
584 }
585 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
586 
587 int
589 {
591  int snum, screen, screencount = 0;
593  int xinerama_major, xinerama_minor;
594  int use_xinerama = 0;
595  XineramaScreenInfo *xinerama = NULL;
596 #endif
598  int xrandr_major, xrandr_minor;
599 #endif
601  int vm_major, vm_minor;
602  int use_vidmode = 0;
603 #endif
604 
605 /* XRandR is the One True Modern Way to do this on X11. If it's enabled and
606  available, don't even look at other ways of doing things. */
608  /* require at least XRandR v1.3 */
609  if (CheckXRandR(data->display, &xrandr_major, &xrandr_minor) &&
610  (xrandr_major >= 2 || (xrandr_major == 1 && xrandr_minor >= 3))) {
611  if (X11_InitModes_XRandR(_this) == 0)
612  return 0;
613  }
614 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
615 
616 /* !!! FIXME: eventually remove support for Xinerama and XVidMode (everything below here). */
617 
618  /* This is a workaround for some apps (UnrealEngine4, for example) until
619  we sort out the ramifications of removing XVidMode support outright.
620  This block should be removed with the XVidMode support. */
621  {
622  if (SDL_GetHintBoolean("SDL_VIDEO_X11_REQUIRE_XRANDR", SDL_FALSE)) {
623  #if SDL_VIDEO_DRIVER_X11_XRANDR
624  return SDL_SetError("XRandR support is required but not available");
625  #else
626  return SDL_SetError("XRandR support is required but not built into SDL!");
627  #endif
628  }
629  }
630 
631 #if SDL_VIDEO_DRIVER_X11_XINERAMA
632  /* Query Xinerama extention
633  * NOTE: This works with Nvidia Twinview correctly, but you need version 302.17 (released on June 2012)
634  * or newer of the Nvidia binary drivers
635  */
636  if (CheckXinerama(data->display, &xinerama_major, &xinerama_minor)) {
637  int (*handler) (Display *, XErrorEvent *);
638  X11_XSync(data->display, False);
639  handler = X11_XSetErrorHandler(X11_XineramaFailed);
640  xinerama = X11_XineramaQueryScreens(data->display, &screencount);
641  X11_XSync(data->display, False);
642  X11_XSetErrorHandler(handler);
643  if (xinerama_triggered_error) {
644  xinerama = 0;
645  }
646  if (xinerama) {
647  use_xinerama = xinerama_major * 100 + xinerama_minor;
648  }
649  }
650  if (!xinerama) {
651  screencount = ScreenCount(data->display);
652  }
653 #else
654  screencount = ScreenCount(data->display);
655 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
656 
657 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
658  if (CheckVidMode(data->display, &vm_major, &vm_minor)) {
659  use_vidmode = vm_major * 100 + vm_minor;
660  }
661 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
662 
663  for (snum = 0; snum < screencount; ++snum) {
664  XVisualInfo vinfo;
665  SDL_VideoDisplay display;
666  SDL_DisplayData *displaydata;
668  SDL_DisplayModeData *modedata;
669  XPixmapFormatValues *pixmapFormats;
670  char display_name[128];
671  int i, n;
672 
673  /* Re-order screens to always put default screen first */
674  if (snum == 0) {
675  screen = DefaultScreen(data->display);
676  } else if (snum == DefaultScreen(data->display)) {
677  screen = 0;
678  } else {
679  screen = snum;
680  }
681 
682 #if SDL_VIDEO_DRIVER_X11_XINERAMA
683  if (xinerama) {
684  if (get_visualinfo(data->display, 0, &vinfo) < 0) {
685  continue;
686  }
687  } else {
688  if (get_visualinfo(data->display, screen, &vinfo) < 0) {
689  continue;
690  }
691  }
692 #else
693  if (get_visualinfo(data->display, screen, &vinfo) < 0) {
694  continue;
695  }
696 #endif
697 
698  displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
699  if (!displaydata) {
700  continue;
701  }
702  display_name[0] = '\0';
703 
704  mode.format = X11_GetPixelFormatFromVisualInfo(data->display, &vinfo);
705  if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
706  /* We don't support palettized modes now */
707  SDL_free(displaydata);
708  continue;
709  }
710 #if SDL_VIDEO_DRIVER_X11_XINERAMA
711  if (xinerama) {
712  mode.w = xinerama[screen].width;
713  mode.h = xinerama[screen].height;
714  } else {
715  mode.w = DisplayWidth(data->display, screen);
716  mode.h = DisplayHeight(data->display, screen);
717  }
718 #else
719  mode.w = DisplayWidth(data->display, screen);
720  mode.h = DisplayHeight(data->display, screen);
721 #endif
722  mode.refresh_rate = 0;
723 
724  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
725  if (!modedata) {
726  SDL_free(displaydata);
727  continue;
728  }
729  mode.driverdata = modedata;
730 
731 #if SDL_VIDEO_DRIVER_X11_XINERAMA
732  /* Most of SDL's calls to X11 are unwaware of Xinerama, and to X11 standard calls, when Xinerama is active,
733  * there's only one screen available. So we force the screen number to zero and
734  * let Xinerama specific code handle specific functionality using displaydata->xinerama_info
735  */
736  if (use_xinerama) {
737  displaydata->screen = 0;
738  displaydata->use_xinerama = use_xinerama;
739  displaydata->xinerama_info = xinerama[screen];
740  displaydata->xinerama_screen = screen;
741  }
742  else displaydata->screen = screen;
743 #else
744  displaydata->screen = screen;
745 #endif
746  displaydata->visual = vinfo.visual;
747  displaydata->depth = vinfo.depth;
748 
749  /* We use the displaydata screen index here so that this works
750  for both the Xinerama case, where we get the overall DPI,
751  and the regular X11 screen info case. */
752  displaydata->hdpi = (float)DisplayWidth(data->display, displaydata->screen) * 25.4f /
753  DisplayWidthMM(data->display, displaydata->screen);
754  displaydata->vdpi = (float)DisplayHeight(data->display, displaydata->screen) * 25.4f /
755  DisplayHeightMM(data->display, displaydata->screen);
756  displaydata->ddpi = SDL_ComputeDiagonalDPI(DisplayWidth(data->display, displaydata->screen),
757  DisplayHeight(data->display, displaydata->screen),
758  (float)DisplayWidthMM(data->display, displaydata->screen) / 25.4f,
759  (float)DisplayHeightMM(data->display, displaydata->screen) / 25.4f);
760 
761  displaydata->scanline_pad = SDL_BYTESPERPIXEL(mode.format) * 8;
762  pixmapFormats = X11_XListPixmapFormats(data->display, &n);
763  if (pixmapFormats) {
764  for (i = 0; i < n; ++i) {
765  if (pixmapFormats[i].depth == displaydata->depth) {
766  displaydata->scanline_pad = pixmapFormats[i].scanline_pad;
767  break;
768  }
769  }
770  X11_XFree(pixmapFormats);
771  }
772 
773 #if SDL_VIDEO_DRIVER_X11_XINERAMA
774  if (use_xinerama) {
775  displaydata->x = xinerama[screen].x_org;
776  displaydata->y = xinerama[screen].y_org;
777  }
778  else
779 #endif
780  {
781  displaydata->x = 0;
782  displaydata->y = 0;
783  }
784 
785 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
786  if (!displaydata->use_xrandr &&
788  /* XVidMode only works on the screen at the origin */
789  (!displaydata->use_xinerama ||
790  (displaydata->x == 0 && displaydata->y == 0)) &&
791 #endif
792  use_vidmode) {
793  displaydata->use_vidmode = use_vidmode;
794  if (displaydata->use_xinerama) {
795  displaydata->vidmode_screen = 0;
796  } else {
797  displaydata->vidmode_screen = screen;
798  }
799  XF86VidModeGetModeInfo(data->display, displaydata->vidmode_screen, &modedata->vm_mode);
800  }
801 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
802 
803  SDL_zero(display);
804  if (*display_name) {
805  display.name = display_name;
806  }
807  display.desktop_mode = mode;
808  display.current_mode = mode;
809  display.driverdata = displaydata;
810  SDL_AddVideoDisplay(&display);
811  }
812 
813 #if SDL_VIDEO_DRIVER_X11_XINERAMA
814  if (xinerama) X11_XFree(xinerama);
815 #endif
816 
817  if (_this->num_displays == 0) {
818  return SDL_SetError("No available displays");
819  }
820  return 0;
821 }
822 
823 void
825 {
826  Display *display = ((SDL_VideoData *) _this->driverdata)->display;
827  SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
829  int nmodes;
830  XF86VidModeModeInfo ** modes;
831 #endif
832  SDL_DisplayMode mode;
833 
834  /* Unfortunately X11 requires the window to be created with the correct
835  * visual and depth ahead of time, but the SDL API allows you to create
836  * a window before setting the fullscreen display mode. This means that
837  * we have to use the same format for all windows and all display modes.
838  * (or support recreating the window with a new visual behind the scenes)
839  */
840  mode.format = sdl_display->current_mode.format;
841  mode.driverdata = NULL;
842 
844  if (data->use_xinerama) {
845  int screen_w;
846  int screen_h;
847 
848  screen_w = DisplayWidth(display, data->screen);
849  screen_h = DisplayHeight(display, data->screen);
850 
851  if (data->use_vidmode && !data->xinerama_info.x_org && !data->xinerama_info.y_org &&
852  (screen_w > data->xinerama_info.width || screen_h > data->xinerama_info.height)) {
853  SDL_DisplayModeData *modedata;
854  /* Add the full (both screens combined) xinerama mode only on the display that starts at 0,0
855  * if we're using vidmode.
856  */
857  mode.w = screen_w;
858  mode.h = screen_h;
859  mode.refresh_rate = 0;
860  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
861  if (modedata) {
862  *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
863  }
864  mode.driverdata = modedata;
865  if (!SDL_AddDisplayMode(sdl_display, &mode)) {
866  SDL_free(modedata);
867  }
868  }
869  else if (!data->use_xrandr)
870  {
871  SDL_DisplayModeData *modedata;
872  /* Add the current mode of each monitor otherwise if we can't get them from xrandr */
873  mode.w = data->xinerama_info.width;
874  mode.h = data->xinerama_info.height;
875  mode.refresh_rate = 0;
876  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
877  if (modedata) {
878  *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
879  }
880  mode.driverdata = modedata;
881  if (!SDL_AddDisplayMode(sdl_display, &mode)) {
882  SDL_free(modedata);
883  }
884  }
885 
886  }
887 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
888 
889 #if SDL_VIDEO_DRIVER_X11_XRANDR
890  if (data->use_xrandr) {
891  XRRScreenResources *res;
892 
893  res = X11_XRRGetScreenResources (display, RootWindow(display, data->screen));
894  if (res) {
895  SDL_DisplayModeData *modedata;
896  XRROutputInfo *output_info;
897  int i;
898 
899  output_info = X11_XRRGetOutputInfo(display, res, data->xrandr_output);
900  if (output_info && output_info->connection != RR_Disconnected) {
901  for (i = 0; i < output_info->nmode; ++i) {
902  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
903  if (!modedata) {
904  continue;
905  }
906  mode.driverdata = modedata;
907 
908  if (!SetXRandRModeInfo(display, res, output_info->crtc, output_info->modes[i], &mode) ||
909  !SDL_AddDisplayMode(sdl_display, &mode)) {
910  SDL_free(modedata);
911  }
912  }
913  }
914  X11_XRRFreeOutputInfo(output_info);
915  X11_XRRFreeScreenResources(res);
916  }
917  return;
918  }
919 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
920 
921 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
922  if (data->use_vidmode &&
923  X11_XF86VidModeGetAllModeLines(display, data->vidmode_screen, &nmodes, &modes)) {
924  int i;
925  SDL_DisplayModeData *modedata;
926 
927 #ifdef X11MODES_DEBUG
928  printf("VidMode modes: (unsorted)\n");
929  for (i = 0; i < nmodes; ++i) {
930  printf("Mode %d: %d x %d @ %d, flags: 0x%x\n", i,
931  modes[i]->hdisplay, modes[i]->vdisplay,
932  CalculateXVidModeRefreshRate(modes[i]), modes[i]->flags);
933  }
934 #endif
935  for (i = 0; i < nmodes; ++i) {
936  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
937  if (!modedata) {
938  continue;
939  }
940  mode.driverdata = modedata;
941 
942  if (!SetXVidModeModeInfo(modes[i], &mode) || !SDL_AddDisplayMode(sdl_display, &mode)) {
943  SDL_free(modedata);
944  }
945  }
946  X11_XFree(modes);
947  return;
948  }
949 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
950 
951  if (!data->use_xrandr && !data->use_vidmode) {
952  SDL_DisplayModeData *modedata;
953  /* Add the desktop mode */
954  mode = sdl_display->desktop_mode;
955  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
956  if (modedata) {
957  *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
958  }
959  mode.driverdata = modedata;
960  if (!SDL_AddDisplayMode(sdl_display, &mode)) {
961  SDL_free(modedata);
962  }
963  }
964 }
965 
966 int
968 {
970  Display *display = viddata->display;
971  SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
973 
975 
976 #if SDL_VIDEO_DRIVER_X11_XRANDR
977  if (data->use_xrandr) {
978  XRRScreenResources *res;
979  XRROutputInfo *output_info;
980  XRRCrtcInfo *crtc;
981  Status status;
982 
983  res = X11_XRRGetScreenResources (display, RootWindow(display, data->screen));
984  if (!res) {
985  return SDL_SetError("Couldn't get XRandR screen resources");
986  }
987 
988  output_info = X11_XRRGetOutputInfo(display, res, data->xrandr_output);
989  if (!output_info || output_info->connection == RR_Disconnected) {
990  X11_XRRFreeScreenResources(res);
991  return SDL_SetError("Couldn't get XRandR output info");
992  }
993 
994  crtc = X11_XRRGetCrtcInfo(display, res, output_info->crtc);
995  if (!crtc) {
996  X11_XRRFreeOutputInfo(output_info);
997  X11_XRRFreeScreenResources(res);
998  return SDL_SetError("Couldn't get XRandR crtc info");
999  }
1000 
1001  status = X11_XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime,
1002  crtc->x, crtc->y, modedata->xrandr_mode, crtc->rotation,
1003  &data->xrandr_output, 1);
1004 
1005  X11_XRRFreeCrtcInfo(crtc);
1006  X11_XRRFreeOutputInfo(output_info);
1007  X11_XRRFreeScreenResources(res);
1008 
1009  if (status != Success) {
1010  return SDL_SetError("X11_XRRSetCrtcConfig failed");
1011  }
1012  }
1013 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
1014 
1015 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
1016  if (data->use_vidmode) {
1017  X11_XF86VidModeSwitchToMode(display, data->vidmode_screen, &modedata->vm_mode);
1018  }
1019 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
1020 
1021  return 0;
1022 }
1023 
1024 void
1026 {
1027 }
1028 
1029 int
1031 {
1032  SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
1033 
1034  rect->x = data->x;
1035  rect->y = data->y;
1036  rect->w = sdl_display->current_mode.w;
1037  rect->h = sdl_display->current_mode.h;
1038 
1040  /* Get the real current bounds of the display */
1041  if (data->use_xinerama) {
1042  Display *display = ((SDL_VideoData *) _this->driverdata)->display;
1043  int screencount;
1044  XineramaScreenInfo *xinerama = X11_XineramaQueryScreens(display, &screencount);
1045  if (xinerama) {
1046  rect->x = xinerama[data->xinerama_screen].x_org;
1047  rect->y = xinerama[data->xinerama_screen].y_org;
1048  X11_XFree(xinerama);
1049  }
1050  }
1051 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
1052  return 0;
1053 }
1054 
1055 int
1056 X11_GetDisplayDPI(_THIS, SDL_VideoDisplay * sdl_display, float * ddpi, float * hdpi, float * vdpi)
1057 {
1058  SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
1059 
1060  if (ddpi) {
1061  *ddpi = data->ddpi;
1062  }
1063  if (hdpi) {
1064  *hdpi = data->hdpi;
1065  }
1066  if (vdpi) {
1067  *vdpi = data->vdpi;
1068  }
1069 
1070  return data->ddpi != 0.0f ? 0 : SDL_SetError("Couldn't get DPI");
1071 }
1072 
1073 int
1075 {
1077  Display *display = data->display;
1078  Atom _NET_WORKAREA;
1079  int status, real_format;
1080  int retval = -1;
1081  Atom real_type;
1082  unsigned long items_read = 0, items_left = 0;
1083  unsigned char *propdata = NULL;
1084 
1085  if (X11_GetDisplayBounds(_this, sdl_display, rect) < 0) {
1086  return -1;
1087  }
1088 
1089  _NET_WORKAREA = X11_XInternAtom(display, "_NET_WORKAREA", False);
1090  status = X11_XGetWindowProperty(display, DefaultRootWindow(display),
1091  _NET_WORKAREA, 0L, 4L, False, XA_CARDINAL,
1092  &real_type, &real_format, &items_read,
1093  &items_left, &propdata);
1094  if ((status == Success) && (items_read >= 4)) {
1095  const long *p = (long*) propdata;
1096  const SDL_Rect usable = { (int)p[0], (int)p[1], (int)p[2], (int)p[3] };
1097  retval = 0;
1098  if (!SDL_IntersectRect(rect, &usable, rect)) {
1099  SDL_zerop(rect);
1100  }
1101  }
1102 
1103  if (propdata) {
1104  X11_XFree(propdata);
1105  }
1106 
1107  return retval;
1108 }
1109 
1110 #endif /* SDL_VIDEO_DRIVER_X11 */
1111 
1112 /* 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:343
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:84
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:417
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 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
#define SDL_free
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:416
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:346
#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:198
GLint GLint GLsizei GLsizei GLsizei depth
Definition: SDL_opengl.h:1572
#define SDL_SetError
GLbitfield flags
#define SDL_sqrtf
#define SDL_calloc
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:340
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:176
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:187
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:64