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