SDL  2.0
SDL_x11modes.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2016 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;
138  case 1:
139  if (BitmapBitOrder(display) == LSBFirst) {
141  } else {
143  }
144  break;
145  }
146  }
147 
149 }
150 
151 /* Global for the error handler */
152 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 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_XRRGetScreenResources(dpy, RootWindow(dpy, screen));
400  if (!res) {
401  continue;
402  }
403 
404  for (output = 0; output < res->noutput; output++) {
405  XRROutputInfo *output_info;
406  int display_x, display_y;
407  unsigned long display_mm_width, display_mm_height;
408  SDL_DisplayData *displaydata;
409  char display_name[128];
411  SDL_DisplayModeData *modedata;
412  SDL_VideoDisplay display;
413  RRMode modeID;
414  RRCrtc output_crtc;
415  XRRCrtcInfo *crtc;
416 
417  /* The primary output _should_ always be sorted first, but just in case... */
418  if ((looking_for_primary && (res->outputs[output] != primary)) ||
419  (!looking_for_primary && (screen == default_screen) && (res->outputs[output] == primary))) {
420  continue;
421  }
422 
423  output_info = X11_XRRGetOutputInfo(dpy, res, res->outputs[output]);
424  if (!output_info || !output_info->crtc || output_info->connection == RR_Disconnected) {
425  X11_XRRFreeOutputInfo(output_info);
426  continue;
427  }
428 
429  SDL_strlcpy(display_name, output_info->name, sizeof(display_name));
430  display_mm_width = output_info->mm_width;
431  display_mm_height = output_info->mm_height;
432  output_crtc = output_info->crtc;
433  X11_XRRFreeOutputInfo(output_info);
434 
435  crtc = X11_XRRGetCrtcInfo(dpy, res, output_crtc);
436  if (!crtc) {
437  continue;
438  }
439 
440  SDL_zero(mode);
441  modeID = crtc->mode;
442  mode.w = crtc->width;
443  mode.h = crtc->height;
444  mode.format = pixelformat;
445 
446  display_x = crtc->x;
447  display_y = crtc->y;
448 
449  X11_XRRFreeCrtcInfo(crtc);
450 
451  displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
452  if (!displaydata) {
453  return SDL_OutOfMemory();
454  }
455 
456  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
457  if (!modedata) {
458  SDL_free(displaydata);
459  return SDL_OutOfMemory();
460  }
461  modedata->xrandr_mode = modeID;
462  mode.driverdata = modedata;
463 
464  displaydata->screen = screen;
465  displaydata->visual = vinfo.visual;
466  displaydata->depth = vinfo.depth;
467  displaydata->hdpi = ((float) mode.w) * 25.4f / display_mm_width;
468  displaydata->vdpi = ((float) mode.h) * 25.4f / display_mm_height;
469  displaydata->ddpi = SDL_ComputeDiagonalDPI(mode.w, mode.h, ((float) display_mm_width) / 25.4f,((float) display_mm_height) / 25.4f);
470  displaydata->scanline_pad = scanline_pad;
471  displaydata->x = display_x;
472  displaydata->y = display_y;
473  displaydata->use_xrandr = 1;
474  displaydata->xrandr_output = res->outputs[output];
475 
476  SetXRandRModeInfo(dpy, res, output_crtc, modeID, &mode);
477  SetXRandRDisplayName(dpy, EDID, display_name, sizeof (display_name), res->outputs[output], display_mm_width, display_mm_height);
478 
479  SDL_zero(display);
480  if (*display_name) {
481  display.name = display_name;
482  }
483  display.desktop_mode = mode;
484  display.current_mode = mode;
485  display.driverdata = displaydata;
486  SDL_AddVideoDisplay(&display);
487  }
488 
489  X11_XRRFreeScreenResources(res);
490  }
491  }
492 
493  if (_this->num_displays == 0) {
494  return SDL_SetError("No available displays");
495  }
496 
497  return 0;
498 }
499 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
500 
501 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
502 static SDL_bool
503 CheckVidMode(Display * display, int *major, int *minor)
504 {
505  /* Default the extension not available */
506  *major = *minor = 0;
507 
508  /* Allow environment override */
510 #ifdef X11MODES_DEBUG
511  printf("XVidMode disabled due to hint\n");
512 #endif
513  return SDL_FALSE;
514  }
515 
516  if (!SDL_X11_HAVE_XVIDMODE) {
517 #ifdef X11MODES_DEBUG
518  printf("XVidMode support not available\n");
519 #endif
520  return SDL_FALSE;
521  }
522 
523  /* Query the extension version */
524  vm_error = -1;
525  if (!X11_XF86VidModeQueryExtension(display, &vm_event, &vm_error)
526  || !X11_XF86VidModeQueryVersion(display, major, minor)) {
527 #ifdef X11MODES_DEBUG
528  printf("XVidMode not active on the display\n");
529 #endif
530  return SDL_FALSE;
531  }
532 #ifdef X11MODES_DEBUG
533  printf("XVidMode available at version %d.%d!\n", *major, *minor);
534 #endif
535  return SDL_TRUE;
536 }
537 
538 static
539 Bool XF86VidModeGetModeInfo(Display * dpy, int scr,
540  XF86VidModeModeInfo* info)
541 {
542  Bool retval;
543  int dotclock;
544  XF86VidModeModeLine l;
545  SDL_zerop(info);
546  SDL_zero(l);
547  retval = X11_XF86VidModeGetModeLine(dpy, scr, &dotclock, &l);
548  info->dotclock = dotclock;
549  info->hdisplay = l.hdisplay;
550  info->hsyncstart = l.hsyncstart;
551  info->hsyncend = l.hsyncend;
552  info->htotal = l.htotal;
553  info->hskew = l.hskew;
554  info->vdisplay = l.vdisplay;
555  info->vsyncstart = l.vsyncstart;
556  info->vsyncend = l.vsyncend;
557  info->vtotal = l.vtotal;
558  info->flags = l.flags;
559  info->privsize = l.privsize;
560  info->private = l.private;
561  return retval;
562 }
563 
564 static int
565 CalculateXVidModeRefreshRate(const XF86VidModeModeInfo * info)
566 {
567  return (info->htotal
568  && info->vtotal) ? (1000 * info->dotclock / (info->htotal *
569  info->vtotal)) : 0;
570 }
571 
572 SDL_bool
573 SetXVidModeModeInfo(const XF86VidModeModeInfo *info, SDL_DisplayMode *mode)
574 {
575  mode->w = info->hdisplay;
576  mode->h = info->vdisplay;
577  mode->refresh_rate = CalculateXVidModeRefreshRate(info);
578  ((SDL_DisplayModeData*)mode->driverdata)->vm_mode = *info;
579  return SDL_TRUE;
580 }
581 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
582 
583 int
585 {
587  int snum, screen, screencount;
589  int xinerama_major, xinerama_minor;
590  int use_xinerama = 0;
591  XineramaScreenInfo *xinerama = NULL;
592 #endif
594  int xrandr_major, xrandr_minor;
595 #endif
597  int vm_major, vm_minor;
598  int use_vidmode = 0;
599 #endif
600 
601 /* XRandR is the One True Modern Way to do this on X11. If it's enabled and
602  available, don't even look at other ways of doing things. */
604  /* require at least XRandR v1.3 */
605  if (CheckXRandR(data->display, &xrandr_major, &xrandr_minor) &&
606  (xrandr_major >= 2 || (xrandr_major == 1 && xrandr_minor >= 3))) {
607  return X11_InitModes_XRandR(_this);
608  }
609 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
610 
611 /* !!! FIXME: eventually remove support for Xinerama and XVidMode (everything below here). */
612 
613  /* This is a workaround for some apps (UnrealEngine4, for example) until
614  we sort out the ramifications of removing XVidMode support outright.
615  This block should be removed with the XVidMode support. */
616  {
617  if (SDL_GetHintBoolean("SDL_VIDEO_X11_REQUIRE_XRANDR", SDL_FALSE)) {
618  #if SDL_VIDEO_DRIVER_X11_XRANDR
619  return SDL_SetError("XRandR support is required but not available");
620  #else
621  return SDL_SetError("XRandR support is required but not built into SDL!");
622  #endif
623  }
624  }
625 
626 #if SDL_VIDEO_DRIVER_X11_XINERAMA
627  /* Query Xinerama extention
628  * NOTE: This works with Nvidia Twinview correctly, but you need version 302.17 (released on June 2012)
629  * or newer of the Nvidia binary drivers
630  */
631  if (CheckXinerama(data->display, &xinerama_major, &xinerama_minor)) {
632  int (*handler) (Display *, XErrorEvent *);
633  X11_XSync(data->display, False);
634  handler = X11_XSetErrorHandler(X11_XineramaFailed);
635  xinerama = X11_XineramaQueryScreens(data->display, &screencount);
636  X11_XSync(data->display, False);
637  X11_XSetErrorHandler(handler);
638  if (xinerama_triggered_error) {
639  xinerama = 0;
640  }
641  if (xinerama) {
642  use_xinerama = xinerama_major * 100 + xinerama_minor;
643  }
644  }
645  if (!xinerama) {
646  screencount = ScreenCount(data->display);
647  }
648 #else
649  screencount = ScreenCount(data->display);
650 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
651 
652 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
653  if (CheckVidMode(data->display, &vm_major, &vm_minor)) {
654  use_vidmode = vm_major * 100 + vm_minor;
655  }
656 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
657 
658  for (snum = 0; snum < screencount; ++snum) {
659  XVisualInfo vinfo;
660  SDL_VideoDisplay display;
661  SDL_DisplayData *displaydata;
663  SDL_DisplayModeData *modedata;
664  XPixmapFormatValues *pixmapFormats;
665  char display_name[128];
666  int i, n;
667 
668  /* Re-order screens to always put default screen first */
669  if (snum == 0) {
670  screen = DefaultScreen(data->display);
671  } else if (snum == DefaultScreen(data->display)) {
672  screen = 0;
673  } else {
674  screen = snum;
675  }
676 
677 #if SDL_VIDEO_DRIVER_X11_XINERAMA
678  if (xinerama) {
679  if (get_visualinfo(data->display, 0, &vinfo) < 0) {
680  continue;
681  }
682  } else {
683  if (get_visualinfo(data->display, screen, &vinfo) < 0) {
684  continue;
685  }
686  }
687 #else
688  if (get_visualinfo(data->display, screen, &vinfo) < 0) {
689  continue;
690  }
691 #endif
692 
693  displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
694  if (!displaydata) {
695  continue;
696  }
697  display_name[0] = '\0';
698 
699  mode.format = X11_GetPixelFormatFromVisualInfo(data->display, &vinfo);
700  if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
701  /* We don't support palettized modes now */
702  SDL_free(displaydata);
703  continue;
704  }
705 #if SDL_VIDEO_DRIVER_X11_XINERAMA
706  if (xinerama) {
707  mode.w = xinerama[screen].width;
708  mode.h = xinerama[screen].height;
709  } else {
710  mode.w = DisplayWidth(data->display, screen);
711  mode.h = DisplayHeight(data->display, screen);
712  }
713 #else
714  mode.w = DisplayWidth(data->display, screen);
715  mode.h = DisplayHeight(data->display, screen);
716 #endif
717  mode.refresh_rate = 0;
718 
719  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
720  if (!modedata) {
721  SDL_free(displaydata);
722  continue;
723  }
724  mode.driverdata = modedata;
725 
726 #if SDL_VIDEO_DRIVER_X11_XINERAMA
727  /* Most of SDL's calls to X11 are unwaware of Xinerama, and to X11 standard calls, when Xinerama is active,
728  * there's only one screen available. So we force the screen number to zero and
729  * let Xinerama specific code handle specific functionality using displaydata->xinerama_info
730  */
731  if (use_xinerama) {
732  displaydata->screen = 0;
733  displaydata->use_xinerama = use_xinerama;
734  displaydata->xinerama_info = xinerama[screen];
735  displaydata->xinerama_screen = screen;
736  }
737  else displaydata->screen = screen;
738 #else
739  displaydata->screen = screen;
740 #endif
741  displaydata->visual = vinfo.visual;
742  displaydata->depth = vinfo.depth;
743 
744  // We use the displaydata screen index here so that this works
745  // for both the Xinerama case, where we get the overall DPI,
746  // and the regular X11 screen info case.
747  displaydata->hdpi = (float)DisplayWidth(data->display, displaydata->screen) * 25.4f /
748  DisplayWidthMM(data->display, displaydata->screen);
749  displaydata->vdpi = (float)DisplayHeight(data->display, displaydata->screen) * 25.4f /
750  DisplayHeightMM(data->display, displaydata->screen);
751  displaydata->ddpi = SDL_ComputeDiagonalDPI(DisplayWidth(data->display, displaydata->screen),
752  DisplayHeight(data->display, displaydata->screen),
753  (float)DisplayWidthMM(data->display, displaydata->screen) / 25.4f,
754  (float)DisplayHeightMM(data->display, displaydata->screen) / 25.4f);
755 
756  displaydata->scanline_pad = SDL_BYTESPERPIXEL(mode.format) * 8;
757  pixmapFormats = X11_XListPixmapFormats(data->display, &n);
758  if (pixmapFormats) {
759  for (i = 0; i < n; ++i) {
760  if (pixmapFormats[i].depth == displaydata->depth) {
761  displaydata->scanline_pad = pixmapFormats[i].scanline_pad;
762  break;
763  }
764  }
765  X11_XFree(pixmapFormats);
766  }
767 
768 #if SDL_VIDEO_DRIVER_X11_XINERAMA
769  if (use_xinerama) {
770  displaydata->x = xinerama[screen].x_org;
771  displaydata->y = xinerama[screen].y_org;
772  }
773  else
774 #endif
775  {
776  displaydata->x = 0;
777  displaydata->y = 0;
778  }
779 
780 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
781  if (!displaydata->use_xrandr &&
783  /* XVidMode only works on the screen at the origin */
784  (!displaydata->use_xinerama ||
785  (displaydata->x == 0 && displaydata->y == 0)) &&
786 #endif
787  use_vidmode) {
788  displaydata->use_vidmode = use_vidmode;
789  if (displaydata->use_xinerama) {
790  displaydata->vidmode_screen = 0;
791  } else {
792  displaydata->vidmode_screen = screen;
793  }
794  XF86VidModeGetModeInfo(data->display, displaydata->vidmode_screen, &modedata->vm_mode);
795  }
796 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
797 
798  SDL_zero(display);
799  if (*display_name) {
800  display.name = display_name;
801  }
802  display.desktop_mode = mode;
803  display.current_mode = mode;
804  display.driverdata = displaydata;
805  SDL_AddVideoDisplay(&display);
806  }
807 
808 #if SDL_VIDEO_DRIVER_X11_XINERAMA
809  if (xinerama) X11_XFree(xinerama);
810 #endif
811 
812  if (_this->num_displays == 0) {
813  return SDL_SetError("No available displays");
814  }
815  return 0;
816 }
817 
818 void
820 {
821  Display *display = ((SDL_VideoData *) _this->driverdata)->display;
822  SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
824  int nmodes;
825  XF86VidModeModeInfo ** modes;
826 #endif
827  int screen_w;
828  int screen_h;
829  SDL_DisplayMode mode;
830 
831  /* Unfortunately X11 requires the window to be created with the correct
832  * visual and depth ahead of time, but the SDL API allows you to create
833  * a window before setting the fullscreen display mode. This means that
834  * we have to use the same format for all windows and all display modes.
835  * (or support recreating the window with a new visual behind the scenes)
836  */
837  mode.format = sdl_display->current_mode.format;
838  mode.driverdata = NULL;
839 
840  screen_w = DisplayWidth(display, data->screen);
841  screen_h = DisplayHeight(display, data->screen);
842 
843 #if SDL_VIDEO_DRIVER_X11_XINERAMA
844  if (data->use_xinerama) {
845  if (data->use_vidmode && !data->xinerama_info.x_org && !data->xinerama_info.y_org &&
846  (screen_w > data->xinerama_info.width || screen_h > data->xinerama_info.height)) {
847  SDL_DisplayModeData *modedata;
848  /* Add the full (both screens combined) xinerama mode only on the display that starts at 0,0
849  * if we're using vidmode.
850  */
851  mode.w = screen_w;
852  mode.h = screen_h;
853  mode.refresh_rate = 0;
854  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
855  if (modedata) {
856  *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
857  }
858  mode.driverdata = modedata;
859  if (!SDL_AddDisplayMode(sdl_display, &mode)) {
860  SDL_free(modedata);
861  }
862  }
863  else if (!data->use_xrandr)
864  {
865  SDL_DisplayModeData *modedata;
866  /* Add the current mode of each monitor otherwise if we can't get them from xrandr */
867  mode.w = data->xinerama_info.width;
868  mode.h = data->xinerama_info.height;
869  mode.refresh_rate = 0;
870  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
871  if (modedata) {
872  *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
873  }
874  mode.driverdata = modedata;
875  if (!SDL_AddDisplayMode(sdl_display, &mode)) {
876  SDL_free(modedata);
877  }
878  }
879 
880  }
881 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
882 
883 #if SDL_VIDEO_DRIVER_X11_XRANDR
884  if (data->use_xrandr) {
885  XRRScreenResources *res;
886 
887  res = X11_XRRGetScreenResources (display, RootWindow(display, data->screen));
888  if (res) {
889  SDL_DisplayModeData *modedata;
890  XRROutputInfo *output_info;
891  int i;
892 
893  output_info = X11_XRRGetOutputInfo(display, res, data->xrandr_output);
894  if (output_info && output_info->connection != RR_Disconnected) {
895  for (i = 0; i < output_info->nmode; ++i) {
896  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
897  if (!modedata) {
898  continue;
899  }
900  mode.driverdata = modedata;
901 
902  if (!SetXRandRModeInfo(display, res, output_info->crtc, output_info->modes[i], &mode) ||
903  !SDL_AddDisplayMode(sdl_display, &mode)) {
904  SDL_free(modedata);
905  }
906  }
907  }
908  X11_XRRFreeOutputInfo(output_info);
909  X11_XRRFreeScreenResources(res);
910  }
911  return;
912  }
913 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
914 
915 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
916  if (data->use_vidmode &&
917  X11_XF86VidModeGetAllModeLines(display, data->vidmode_screen, &nmodes, &modes)) {
918  int i;
919  SDL_DisplayModeData *modedata;
920 
921 #ifdef X11MODES_DEBUG
922  printf("VidMode modes: (unsorted)\n");
923  for (i = 0; i < nmodes; ++i) {
924  printf("Mode %d: %d x %d @ %d, flags: 0x%x\n", i,
925  modes[i]->hdisplay, modes[i]->vdisplay,
926  CalculateXVidModeRefreshRate(modes[i]), modes[i]->flags);
927  }
928 #endif
929  for (i = 0; i < nmodes; ++i) {
930  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
931  if (!modedata) {
932  continue;
933  }
934  mode.driverdata = modedata;
935 
936  if (!SetXVidModeModeInfo(modes[i], &mode) || !SDL_AddDisplayMode(sdl_display, &mode)) {
937  SDL_free(modedata);
938  }
939  }
940  X11_XFree(modes);
941  return;
942  }
943 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
944 
945  if (!data->use_xrandr && !data->use_vidmode) {
946  SDL_DisplayModeData *modedata;
947  /* Add the desktop mode */
948  mode = sdl_display->desktop_mode;
949  modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
950  if (modedata) {
951  *modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
952  }
953  mode.driverdata = modedata;
954  if (!SDL_AddDisplayMode(sdl_display, &mode)) {
955  SDL_free(modedata);
956  }
957  }
958 }
959 
960 int
962 {
964  Display *display = viddata->display;
965  SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
967 
969 
970 #if SDL_VIDEO_DRIVER_X11_XRANDR
971  if (data->use_xrandr) {
972  XRRScreenResources *res;
973  XRROutputInfo *output_info;
974  XRRCrtcInfo *crtc;
975  Status status;
976 
977  res = X11_XRRGetScreenResources (display, RootWindow(display, data->screen));
978  if (!res) {
979  return SDL_SetError("Couldn't get XRandR screen resources");
980  }
981 
982  output_info = X11_XRRGetOutputInfo(display, res, data->xrandr_output);
983  if (!output_info || output_info->connection == RR_Disconnected) {
984  X11_XRRFreeScreenResources(res);
985  return SDL_SetError("Couldn't get XRandR output info");
986  }
987 
988  crtc = X11_XRRGetCrtcInfo(display, res, output_info->crtc);
989  if (!crtc) {
990  X11_XRRFreeOutputInfo(output_info);
991  X11_XRRFreeScreenResources(res);
992  return SDL_SetError("Couldn't get XRandR crtc info");
993  }
994 
995  status = X11_XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime,
996  crtc->x, crtc->y, modedata->xrandr_mode, crtc->rotation,
997  &data->xrandr_output, 1);
998 
999  X11_XRRFreeCrtcInfo(crtc);
1000  X11_XRRFreeOutputInfo(output_info);
1001  X11_XRRFreeScreenResources(res);
1002 
1003  if (status != Success) {
1004  return SDL_SetError("X11_XRRSetCrtcConfig failed");
1005  }
1006  }
1007 #endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
1008 
1009 #if SDL_VIDEO_DRIVER_X11_XVIDMODE
1010  if (data->use_vidmode) {
1011  X11_XF86VidModeSwitchToMode(display, data->vidmode_screen, &modedata->vm_mode);
1012  }
1013 #endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
1014 
1015  return 0;
1016 }
1017 
1018 void
1020 {
1021 }
1022 
1023 int
1025 {
1026  SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
1027 
1028  rect->x = data->x;
1029  rect->y = data->y;
1030  rect->w = sdl_display->current_mode.w;
1031  rect->h = sdl_display->current_mode.h;
1032 
1034  /* Get the real current bounds of the display */
1035  if (data->use_xinerama) {
1036  Display *display = ((SDL_VideoData *) _this->driverdata)->display;
1037  int screencount;
1038  XineramaScreenInfo *xinerama = X11_XineramaQueryScreens(display, &screencount);
1039  if (xinerama) {
1040  rect->x = xinerama[data->xinerama_screen].x_org;
1041  rect->y = xinerama[data->xinerama_screen].y_org;
1042  X11_XFree(xinerama);
1043  }
1044  }
1045 #endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
1046  return 0;
1047 }
1048 
1049 int
1050 X11_GetDisplayDPI(_THIS, SDL_VideoDisplay * sdl_display, float * ddpi, float * hdpi, float * vdpi)
1051 {
1052  SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
1053 
1054  if (ddpi) {
1055  *ddpi = data->ddpi;
1056  }
1057  if (hdpi) {
1058  *hdpi = data->hdpi;
1059  }
1060  if (vdpi) {
1061  *vdpi = data->vdpi;
1062  }
1063 
1064  return data->ddpi != 0.0f ? 0 : SDL_SetError("Couldn't get DPI");
1065 }
1066 
1067 int
1069 {
1071  Display *display = data->display;
1072  Atom _NET_WORKAREA;
1073  int status, real_format;
1074  int retval = -1;
1075  Atom real_type;
1076  unsigned long items_read = 0, items_left = 0;
1077  unsigned char *propdata = NULL;
1078 
1079  if (X11_GetDisplayBounds(_this, sdl_display, rect) < 0) {
1080  return -1;
1081  }
1082 
1083  _NET_WORKAREA = X11_XInternAtom(display, "_NET_WORKAREA", False);
1084  status = X11_XGetWindowProperty(display, DefaultRootWindow(display),
1085  _NET_WORKAREA, 0L, 4L, False, XA_CARDINAL,
1086  &real_type, &real_format, &items_read,
1087  &items_left, &propdata);
1088  if ((status == Success) && (items_read >= 4)) {
1089  const long *p = (long*) propdata;
1090  const SDL_Rect usable = { (int)p[0], (int)p[1], (int)p[2], (int)p[3] };
1091  retval = 0;
1092  if (!SDL_IntersectRect(rect, &usable, rect)) {
1093  SDL_zerop(rect);
1094  }
1095  }
1096 
1097  if (propdata) {
1098  X11_XFree(propdata);
1099  }
1100 
1101  return retval;
1102 }
1103 
1104 #endif /* SDL_VIDEO_DRIVER_X11 */
1105 
1106 /* 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
GLdouble n
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:308
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:81
SDL_bool X11_UseDirectColorVisuals(void)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
The structure that defines a display mode.
Definition: SDL_video.h:53
GLfloat f
#define SDL_BYTESPERPIXEL(X)
Definition: SDL_pixels.h:128
GLuint const GLchar * name
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:161
#define SDL_IntersectRect
#define SDL_zerop(x)
Definition: SDL_stdinc.h:362
int SDL_AddVideoDisplay(const SDL_VideoDisplay *display)
Definition: SDL_video.c:591
GLenum GLsizei len
GLuint res
#define SDL_GetHintBoolean
int X11_GetDisplayBounds(_THIS, SDL_VideoDisplay *sdl_display, SDL_Rect *rect)
static SDL_VideoDevice * _this
Definition: SDL_video.c:118
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:130
GLenum mode
#define SDL_strtol
#define SDL_zero(x)
Definition: SDL_stdinc.h:361
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:311
#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:143
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:130
SDL_DisplayMode desktop_mode
Definition: SDL_sysvideo.h:129
#define SDL_HINT_VIDEO_X11_XRANDR
A variable controlling whether the X11 XRandR extension should be used.
Definition: SDL_hints.h:186
GLint GLint GLsizei GLsizei GLsizei depth
Definition: SDL_opengl.h:1565
#define SDL_SetError
#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
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:728
#define SDL_snprintf
GLbitfield flags
#define SDL_VIDEO_DRIVER_X11_XINERAMA
Definition: SDL_config.h:305
Uint32 last_mode_change_deadline
Definition: SDL_x11video.h:127
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:164
int y
Definition: SDL_rect.h:66
float SDL_ComputeDiagonalDPI(int hpix, int vpix, float hinches, float vinches)
Definition: SDL_video.c:3783
#define SDL_HINT_VIDEO_X11_XINERAMA
A variable controlling whether the X11 Xinerama extension should be used.
Definition: SDL_hints.h:175
A rectangle, with the origin at the upper left.
Definition: SDL_rect.h:64