mirror of
https://github.com/encounter/SDL.git
synced 2025-12-18 09:25:29 +00:00
Fixes #2022, do not resume on Android when surfaceChanged
If the app is in landscape mode and the user presses the power button, a pause is followed immediately by a surfaceChanged event because the lock screen is shown in portrait mode. This triggers a "false" resume. So, we just pause and resume following the onWindowFocusChanged events. Also, wait for SDL_APP_WILLENTERBACKGROUND and SDL_APP_DIDENTERBACKGROUND before blocking the event pump.
This commit is contained in:
888
src/video/x11/SDL_x11modes.c
Normal file
888
src/video/x11/SDL_x11modes.c
Normal file
@@ -0,0 +1,888 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#include "SDL_config.h"
|
||||
|
||||
#if SDL_VIDEO_DRIVER_X11
|
||||
|
||||
#include "SDL_hints.h"
|
||||
#include "SDL_x11video.h"
|
||||
#include "edid.h"
|
||||
|
||||
/*#define X11MODES_DEBUG*/
|
||||
|
||||
/* I'm becoming more and more convinced that the application should never
|
||||
* use XRandR, and it's the window manager's responsibility to track and
|
||||
* manage display modes for fullscreen windows. Right now XRandR is completely
|
||||
* broken with respect to window manager behavior on every window manager that
|
||||
* I can find. For example, on Unity 3D if you show a fullscreen window while
|
||||
* the resolution is changing (within ~250 ms) your window will retain the
|
||||
* fullscreen state hint but be decorated and windowed.
|
||||
*
|
||||
* However, many people swear by it, so let them swear at it. :)
|
||||
*/
|
||||
/*#define XRANDR_DISABLED_BY_DEFAULT*/
|
||||
|
||||
|
||||
static int
|
||||
get_visualinfo(Display * display, int screen, XVisualInfo * vinfo)
|
||||
{
|
||||
const char *visual_id = SDL_getenv("SDL_VIDEO_X11_VISUALID");
|
||||
int depth;
|
||||
|
||||
/* Look for an exact visual, if requested */
|
||||
if (visual_id) {
|
||||
XVisualInfo *vi, template;
|
||||
int nvis;
|
||||
|
||||
SDL_zero(template);
|
||||
template.visualid = SDL_strtol(visual_id, NULL, 0);
|
||||
vi = XGetVisualInfo(display, VisualIDMask, &template, &nvis);
|
||||
if (vi) {
|
||||
*vinfo = *vi;
|
||||
XFree(vi);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
depth = DefaultDepth(display, screen);
|
||||
if ((X11_UseDirectColorVisuals() &&
|
||||
XMatchVisualInfo(display, screen, depth, DirectColor, vinfo)) ||
|
||||
XMatchVisualInfo(display, screen, depth, TrueColor, vinfo) ||
|
||||
XMatchVisualInfo(display, screen, depth, PseudoColor, vinfo) ||
|
||||
XMatchVisualInfo(display, screen, depth, StaticColor, vinfo)) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
X11_GetVisualInfoFromVisual(Display * display, Visual * visual, XVisualInfo * vinfo)
|
||||
{
|
||||
XVisualInfo *vi;
|
||||
int nvis;
|
||||
|
||||
vinfo->visualid = XVisualIDFromVisual(visual);
|
||||
vi = XGetVisualInfo(display, VisualIDMask, vinfo, &nvis);
|
||||
if (vi) {
|
||||
*vinfo = *vi;
|
||||
XFree(vi);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Uint32
|
||||
X11_GetPixelFormatFromVisualInfo(Display * display, XVisualInfo * vinfo)
|
||||
{
|
||||
if (vinfo->class == DirectColor || vinfo->class == TrueColor) {
|
||||
int bpp;
|
||||
Uint32 Rmask, Gmask, Bmask, Amask;
|
||||
|
||||
Rmask = vinfo->visual->red_mask;
|
||||
Gmask = vinfo->visual->green_mask;
|
||||
Bmask = vinfo->visual->blue_mask;
|
||||
if (vinfo->depth == 32) {
|
||||
Amask = (0xFFFFFFFF & ~(Rmask | Gmask | Bmask));
|
||||
} else {
|
||||
Amask = 0;
|
||||
}
|
||||
|
||||
bpp = vinfo->depth;
|
||||
if (bpp == 24) {
|
||||
int i, n;
|
||||
XPixmapFormatValues *p = XListPixmapFormats(display, &n);
|
||||
if (p) {
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (p[i].depth == 24) {
|
||||
bpp = p[i].bits_per_pixel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
XFree(p);
|
||||
}
|
||||
}
|
||||
|
||||
return SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
|
||||
}
|
||||
|
||||
if (vinfo->class == PseudoColor || vinfo->class == StaticColor) {
|
||||
switch (vinfo->depth) {
|
||||
case 8:
|
||||
return SDL_PIXELTYPE_INDEX8;
|
||||
case 4:
|
||||
if (BitmapBitOrder(display) == LSBFirst) {
|
||||
return SDL_PIXELFORMAT_INDEX4LSB;
|
||||
} else {
|
||||
return SDL_PIXELFORMAT_INDEX4MSB;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (BitmapBitOrder(display) == LSBFirst) {
|
||||
return SDL_PIXELFORMAT_INDEX1LSB;
|
||||
} else {
|
||||
return SDL_PIXELFORMAT_INDEX1MSB;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return SDL_PIXELFORMAT_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Global for the error handler */
|
||||
int vm_event, vm_error = -1;
|
||||
|
||||
#if SDL_VIDEO_DRIVER_X11_XINERAMA
|
||||
static SDL_bool
|
||||
CheckXinerama(Display * display, int *major, int *minor)
|
||||
{
|
||||
int event_base = 0;
|
||||
int error_base = 0;
|
||||
const char *env;
|
||||
|
||||
/* Default the extension not available */
|
||||
*major = *minor = 0;
|
||||
|
||||
/* Allow environment override */
|
||||
env = SDL_GetHint(SDL_HINT_VIDEO_X11_XINERAMA);
|
||||
if (env && !SDL_atoi(env)) {
|
||||
#ifdef X11MODES_DEBUG
|
||||
printf("Xinerama disabled due to hint\n");
|
||||
#endif
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (!SDL_X11_HAVE_XINERAMA) {
|
||||
#ifdef X11MODES_DEBUG
|
||||
printf("Xinerama support not available\n");
|
||||
#endif
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Query the extension version */
|
||||
if (!XineramaQueryExtension(display, &event_base, &error_base) ||
|
||||
!XineramaQueryVersion(display, major, minor) ||
|
||||
!XineramaIsActive(display)) {
|
||||
#ifdef X11MODES_DEBUG
|
||||
printf("Xinerama not active on the display\n");
|
||||
#endif
|
||||
return SDL_FALSE;
|
||||
}
|
||||
#ifdef X11MODES_DEBUG
|
||||
printf("Xinerama available at version %d.%d!\n", *major, *minor);
|
||||
#endif
|
||||
return SDL_TRUE;
|
||||
}
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
|
||||
|
||||
#if SDL_VIDEO_DRIVER_X11_XRANDR
|
||||
static SDL_bool
|
||||
CheckXRandR(Display * display, int *major, int *minor)
|
||||
{
|
||||
const char *env;
|
||||
|
||||
/* Default the extension not available */
|
||||
*major = *minor = 0;
|
||||
|
||||
/* Allow environment override */
|
||||
env = SDL_GetHint(SDL_HINT_VIDEO_X11_XRANDR);
|
||||
#ifdef XRANDR_DISABLED_BY_DEFAULT
|
||||
if (!env || !SDL_atoi(env)) {
|
||||
#ifdef X11MODES_DEBUG
|
||||
printf("XRandR disabled by default due to window manager issues\n");
|
||||
#endif
|
||||
return SDL_FALSE;
|
||||
}
|
||||
#else
|
||||
if (env && !SDL_atoi(env)) {
|
||||
#ifdef X11MODES_DEBUG
|
||||
printf("XRandR disabled due to hint\n");
|
||||
#endif
|
||||
return SDL_FALSE;
|
||||
}
|
||||
#endif /* XRANDR_ENABLED_BY_DEFAULT */
|
||||
|
||||
if (!SDL_X11_HAVE_XRANDR) {
|
||||
#ifdef X11MODES_DEBUG
|
||||
printf("XRandR support not available\n");
|
||||
#endif
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Query the extension version */
|
||||
if (!XRRQueryVersion(display, major, minor)) {
|
||||
#ifdef X11MODES_DEBUG
|
||||
printf("XRandR not active on the display\n");
|
||||
#endif
|
||||
return SDL_FALSE;
|
||||
}
|
||||
#ifdef X11MODES_DEBUG
|
||||
printf("XRandR available at version %d.%d!\n", *major, *minor);
|
||||
#endif
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
#define XRANDR_ROTATION_LEFT (1 << 1)
|
||||
#define XRANDR_ROTATION_RIGHT (1 << 3)
|
||||
|
||||
static int
|
||||
CalculateXRandRRefreshRate(const XRRModeInfo *info)
|
||||
{
|
||||
return (info->hTotal
|
||||
&& info->vTotal) ? (info->dotClock / (info->hTotal * info->vTotal)) : 0;
|
||||
}
|
||||
|
||||
static SDL_bool
|
||||
SetXRandRModeInfo(Display *display, XRRScreenResources *res, XRROutputInfo *output_info,
|
||||
RRMode modeID, SDL_DisplayMode *mode)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < res->nmode; ++i) {
|
||||
if (res->modes[i].id == modeID) {
|
||||
XRRCrtcInfo *crtc;
|
||||
Rotation rotation = 0;
|
||||
const XRRModeInfo *info = &res->modes[i];
|
||||
|
||||
crtc = XRRGetCrtcInfo(display, res, output_info->crtc);
|
||||
if (crtc) {
|
||||
rotation = crtc->rotation;
|
||||
XRRFreeCrtcInfo(crtc);
|
||||
}
|
||||
|
||||
if (rotation & (XRANDR_ROTATION_LEFT|XRANDR_ROTATION_RIGHT)) {
|
||||
mode->w = info->height;
|
||||
mode->h = info->width;
|
||||
} else {
|
||||
mode->w = info->width;
|
||||
mode->h = info->height;
|
||||
}
|
||||
mode->refresh_rate = CalculateXRandRRefreshRate(info);
|
||||
((SDL_DisplayModeData*)mode->driverdata)->xrandr_mode = modeID;
|
||||
#ifdef X11MODES_DEBUG
|
||||
printf("XRandR mode %d: %dx%d@%dHz\n", (int) modeID, mode->w, mode->h, mode->refresh_rate);
|
||||
#endif
|
||||
return SDL_TRUE;
|
||||
}
|
||||
}
|
||||
return SDL_FALSE;
|
||||
}
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
|
||||
|
||||
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
|
||||
static SDL_bool
|
||||
CheckVidMode(Display * display, int *major, int *minor)
|
||||
{
|
||||
const char *env;
|
||||
|
||||
/* Default the extension not available */
|
||||
*major = *minor = 0;
|
||||
|
||||
/* Allow environment override */
|
||||
env = SDL_GetHint(SDL_HINT_VIDEO_X11_XVIDMODE);
|
||||
if (env && !SDL_atoi(env)) {
|
||||
#ifdef X11MODES_DEBUG
|
||||
printf("XVidMode disabled due to hint\n");
|
||||
#endif
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
if (!SDL_X11_HAVE_XVIDMODE) {
|
||||
#ifdef X11MODES_DEBUG
|
||||
printf("XVidMode support not available\n");
|
||||
#endif
|
||||
return SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Query the extension version */
|
||||
vm_error = -1;
|
||||
if (!XF86VidModeQueryExtension(display, &vm_event, &vm_error)
|
||||
|| !XF86VidModeQueryVersion(display, major, minor)) {
|
||||
#ifdef X11MODES_DEBUG
|
||||
printf("XVidMode not active on the display\n");
|
||||
#endif
|
||||
return SDL_FALSE;
|
||||
}
|
||||
#ifdef X11MODES_DEBUG
|
||||
printf("XVidMode available at version %d.%d!\n", *major, *minor);
|
||||
#endif
|
||||
return SDL_TRUE;
|
||||
}
|
||||
|
||||
static
|
||||
Bool XF86VidModeGetModeInfo(Display * dpy, int scr,
|
||||
XF86VidModeModeInfo* info)
|
||||
{
|
||||
Bool retval;
|
||||
int dotclock;
|
||||
XF86VidModeModeLine l;
|
||||
SDL_zerop(info);
|
||||
SDL_zero(l);
|
||||
retval = XF86VidModeGetModeLine(dpy, scr, &dotclock, &l);
|
||||
info->dotclock = dotclock;
|
||||
info->hdisplay = l.hdisplay;
|
||||
info->hsyncstart = l.hsyncstart;
|
||||
info->hsyncend = l.hsyncend;
|
||||
info->htotal = l.htotal;
|
||||
info->hskew = l.hskew;
|
||||
info->vdisplay = l.vdisplay;
|
||||
info->vsyncstart = l.vsyncstart;
|
||||
info->vsyncend = l.vsyncend;
|
||||
info->vtotal = l.vtotal;
|
||||
info->flags = l.flags;
|
||||
info->privsize = l.privsize;
|
||||
info->private = l.private;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
CalculateXVidModeRefreshRate(const XF86VidModeModeInfo * info)
|
||||
{
|
||||
return (info->htotal
|
||||
&& info->vtotal) ? (1000 * info->dotclock / (info->htotal *
|
||||
info->vtotal)) : 0;
|
||||
}
|
||||
|
||||
SDL_bool
|
||||
SetXVidModeModeInfo(const XF86VidModeModeInfo *info, SDL_DisplayMode *mode)
|
||||
{
|
||||
mode->w = info->hdisplay;
|
||||
mode->h = info->vdisplay;
|
||||
mode->refresh_rate = CalculateXVidModeRefreshRate(info);
|
||||
((SDL_DisplayModeData*)mode->driverdata)->vm_mode = *info;
|
||||
return SDL_TRUE;
|
||||
}
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
|
||||
|
||||
int
|
||||
X11_InitModes(_THIS)
|
||||
{
|
||||
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
|
||||
int screen, screencount;
|
||||
#if SDL_VIDEO_DRIVER_X11_XINERAMA
|
||||
int xinerama_major, xinerama_minor;
|
||||
int use_xinerama = 0;
|
||||
XineramaScreenInfo *xinerama = NULL;
|
||||
#endif
|
||||
#if SDL_VIDEO_DRIVER_X11_XRANDR
|
||||
int xrandr_major, xrandr_minor;
|
||||
int use_xrandr = 0;
|
||||
XRRScreenResources *res = NULL;
|
||||
#endif
|
||||
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
|
||||
int vm_major, vm_minor;
|
||||
int use_vidmode = 0;
|
||||
#endif
|
||||
|
||||
#if SDL_VIDEO_DRIVER_X11_XINERAMA
|
||||
/* Query Xinerama extention
|
||||
* NOTE: This works with Nvidia Twinview correctly, but you need version 302.17 (released on June 2012)
|
||||
* or newer of the Nvidia binary drivers
|
||||
*/
|
||||
if (CheckXinerama(data->display, &xinerama_major, &xinerama_minor)) {
|
||||
xinerama = XineramaQueryScreens(data->display, &screencount);
|
||||
if (xinerama) {
|
||||
use_xinerama = xinerama_major * 100 + xinerama_minor;
|
||||
}
|
||||
}
|
||||
if (!xinerama) {
|
||||
screencount = ScreenCount(data->display);
|
||||
}
|
||||
#else
|
||||
screencount = ScreenCount(data->display);
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
|
||||
|
||||
#if SDL_VIDEO_DRIVER_X11_XRANDR
|
||||
/* require at least XRandR v1.2 */
|
||||
if (CheckXRandR(data->display, &xrandr_major, &xrandr_minor) &&
|
||||
(xrandr_major >= 2 || (xrandr_major == 1 && xrandr_minor >= 2))) {
|
||||
use_xrandr = xrandr_major * 100 + xrandr_minor;
|
||||
}
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
|
||||
|
||||
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
|
||||
if (CheckVidMode(data->display, &vm_major, &vm_minor)) {
|
||||
use_vidmode = vm_major * 100 + vm_minor;
|
||||
}
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
|
||||
|
||||
for (screen = 0; screen < screencount; ++screen) {
|
||||
XVisualInfo vinfo;
|
||||
SDL_VideoDisplay display;
|
||||
SDL_DisplayData *displaydata;
|
||||
SDL_DisplayMode mode;
|
||||
SDL_DisplayModeData *modedata;
|
||||
XPixmapFormatValues *pixmapFormats;
|
||||
char display_name[128];
|
||||
int i, n;
|
||||
|
||||
#if SDL_VIDEO_DRIVER_X11_XINERAMA
|
||||
if (xinerama) {
|
||||
if (get_visualinfo(data->display, 0, &vinfo) < 0) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (get_visualinfo(data->display, screen, &vinfo) < 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (get_visualinfo(data->display, screen, &vinfo) < 0) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
displaydata = (SDL_DisplayData *) SDL_calloc(1, sizeof(*displaydata));
|
||||
if (!displaydata) {
|
||||
continue;
|
||||
}
|
||||
display_name[0] = '\0';
|
||||
|
||||
mode.format = X11_GetPixelFormatFromVisualInfo(data->display, &vinfo);
|
||||
if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
|
||||
/* We don't support palettized modes now */
|
||||
SDL_free(displaydata);
|
||||
continue;
|
||||
}
|
||||
#if SDL_VIDEO_DRIVER_X11_XINERAMA
|
||||
if (xinerama) {
|
||||
mode.w = xinerama[screen].width;
|
||||
mode.h = xinerama[screen].height;
|
||||
} else {
|
||||
mode.w = DisplayWidth(data->display, screen);
|
||||
mode.h = DisplayHeight(data->display, screen);
|
||||
}
|
||||
#else
|
||||
mode.w = DisplayWidth(data->display, screen);
|
||||
mode.h = DisplayHeight(data->display, screen);
|
||||
#endif
|
||||
mode.refresh_rate = 0;
|
||||
|
||||
modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
|
||||
if (!modedata) {
|
||||
SDL_free(displaydata);
|
||||
continue;
|
||||
}
|
||||
mode.driverdata = modedata;
|
||||
|
||||
#if SDL_VIDEO_DRIVER_X11_XINERAMA
|
||||
/* Most of SDL's calls to X11 are unwaware of Xinerama, and to X11 standard calls, when Xinerama is active,
|
||||
* there's only one screen available. So we force the screen number to zero and
|
||||
* let Xinerama specific code handle specific functionality using displaydata->xinerama_info
|
||||
*/
|
||||
if (use_xinerama) {
|
||||
displaydata->screen = 0;
|
||||
displaydata->use_xinerama = use_xinerama;
|
||||
displaydata->xinerama_info = xinerama[screen];
|
||||
displaydata->xinerama_screen = screen;
|
||||
}
|
||||
else displaydata->screen = screen;
|
||||
#else
|
||||
displaydata->screen = screen;
|
||||
#endif
|
||||
displaydata->visual = vinfo.visual;
|
||||
displaydata->depth = vinfo.depth;
|
||||
|
||||
displaydata->scanline_pad = SDL_BYTESPERPIXEL(mode.format) * 8;
|
||||
pixmapFormats = XListPixmapFormats(data->display, &n);
|
||||
if (pixmapFormats) {
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (pixmapFormats[i].depth == displaydata->depth) {
|
||||
displaydata->scanline_pad = pixmapFormats[i].scanline_pad;
|
||||
break;
|
||||
}
|
||||
}
|
||||
XFree(pixmapFormats);
|
||||
}
|
||||
|
||||
#if SDL_VIDEO_DRIVER_X11_XINERAMA
|
||||
if (use_xinerama) {
|
||||
displaydata->x = xinerama[screen].x_org;
|
||||
displaydata->y = xinerama[screen].y_org;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
displaydata->x = 0;
|
||||
displaydata->y = 0;
|
||||
}
|
||||
|
||||
#if SDL_VIDEO_DRIVER_X11_XRANDR
|
||||
if (use_xrandr) {
|
||||
res = XRRGetScreenResources(data->display, RootWindow(data->display, displaydata->screen));
|
||||
}
|
||||
if (res) {
|
||||
XRROutputInfo *output_info;
|
||||
XRRCrtcInfo *crtc;
|
||||
int output;
|
||||
Atom EDID = XInternAtom(data->display, "EDID", False);
|
||||
Atom *props;
|
||||
int nprop;
|
||||
unsigned long width_mm;
|
||||
unsigned long height_mm;
|
||||
int inches = 0;
|
||||
|
||||
for (output = 0; output < res->noutput; output++) {
|
||||
output_info = XRRGetOutputInfo(data->display, res, res->outputs[output]);
|
||||
if (!output_info || !output_info->crtc ||
|
||||
output_info->connection == RR_Disconnected) {
|
||||
XRRFreeOutputInfo(output_info);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Is this the output that corresponds to the current screen?
|
||||
We're checking the crtc position, but that may not be a valid test
|
||||
in all cases. Anybody want to give this some love?
|
||||
*/
|
||||
crtc = XRRGetCrtcInfo(data->display, res, output_info->crtc);
|
||||
if (!crtc || crtc->x != displaydata->x || crtc->y != displaydata->y) {
|
||||
XRRFreeOutputInfo(output_info);
|
||||
XRRFreeCrtcInfo(crtc);
|
||||
continue;
|
||||
}
|
||||
|
||||
displaydata->use_xrandr = use_xrandr;
|
||||
displaydata->xrandr_output = res->outputs[output];
|
||||
SetXRandRModeInfo(data->display, res, output_info, crtc->mode, &mode);
|
||||
|
||||
/* Get the name of this display */
|
||||
width_mm = output_info->mm_width;
|
||||
height_mm = output_info->mm_height;
|
||||
inches = (int)((sqrt(width_mm * width_mm +
|
||||
height_mm * height_mm) / 25.4f) + 0.5f);
|
||||
SDL_strlcpy(display_name, output_info->name, sizeof(display_name));
|
||||
|
||||
/* See if we can get the EDID data for the real monitor name */
|
||||
props = XRRListOutputProperties(data->display, res->outputs[output], &nprop);
|
||||
for (i = 0; i < nprop; ++i) {
|
||||
unsigned char *prop;
|
||||
int actual_format;
|
||||
unsigned long nitems, bytes_after;
|
||||
Atom actual_type;
|
||||
|
||||
if (props[i] == EDID) {
|
||||
if (XRRGetOutputProperty(data->display,
|
||||
res->outputs[output], props[i],
|
||||
0, 100, False, False,
|
||||
AnyPropertyType,
|
||||
&actual_type, &actual_format,
|
||||
&nitems, &bytes_after, &prop) == Success ) {
|
||||
MonitorInfo *info = decode_edid(prop);
|
||||
if (info) {
|
||||
#ifdef X11MODES_DEBUG
|
||||
printf("Found EDID data for %s\n", output_info->name);
|
||||
dump_monitor_info(info);
|
||||
#endif
|
||||
SDL_strlcpy(display_name, info->dsc_product_name, sizeof(display_name));
|
||||
free(info);
|
||||
}
|
||||
XFree(prop);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (props) {
|
||||
XFree(props);
|
||||
}
|
||||
|
||||
if (*display_name && inches) {
|
||||
size_t len = SDL_strlen(display_name);
|
||||
SDL_snprintf(&display_name[len], sizeof(display_name)-len, " %d\"", inches);
|
||||
}
|
||||
#ifdef X11MODES_DEBUG
|
||||
printf("Display name: %s\n", display_name);
|
||||
#endif
|
||||
|
||||
XRRFreeOutputInfo(output_info);
|
||||
XRRFreeCrtcInfo(crtc);
|
||||
break;
|
||||
}
|
||||
#ifdef X11MODES_DEBUG
|
||||
if (output == res->noutput) {
|
||||
printf("Couldn't find XRandR CRTC at %d,%d\n", displaydata->x, displaydata->y);
|
||||
}
|
||||
#endif
|
||||
XRRFreeScreenResources(res);
|
||||
}
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
|
||||
|
||||
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
|
||||
if (!displaydata->use_xrandr &&
|
||||
#if SDL_VIDEO_DRIVER_X11_XINERAMA
|
||||
/* XVidMode only works on the screen at the origin */
|
||||
(!displaydata->use_xinerama ||
|
||||
(displaydata->x == 0 && displaydata->y == 0)) &&
|
||||
#endif
|
||||
use_vidmode) {
|
||||
displaydata->use_vidmode = use_vidmode;
|
||||
if (displaydata->use_xinerama) {
|
||||
displaydata->vidmode_screen = 0;
|
||||
} else {
|
||||
displaydata->vidmode_screen = screen;
|
||||
}
|
||||
XF86VidModeGetModeInfo(data->display, displaydata->vidmode_screen, &modedata->vm_mode);
|
||||
}
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
|
||||
|
||||
SDL_zero(display);
|
||||
if (*display_name) {
|
||||
display.name = display_name;
|
||||
}
|
||||
display.desktop_mode = mode;
|
||||
display.current_mode = mode;
|
||||
display.driverdata = displaydata;
|
||||
SDL_AddVideoDisplay(&display);
|
||||
}
|
||||
|
||||
#if SDL_VIDEO_DRIVER_X11_XINERAMA
|
||||
if (xinerama) XFree(xinerama);
|
||||
#endif
|
||||
|
||||
if (_this->num_displays == 0) {
|
||||
return SDL_SetError("No available displays");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display)
|
||||
{
|
||||
Display *display = ((SDL_VideoData *) _this->driverdata)->display;
|
||||
SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
|
||||
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
|
||||
int nmodes;
|
||||
XF86VidModeModeInfo ** modes;
|
||||
#endif
|
||||
int screen_w;
|
||||
int screen_h;
|
||||
SDL_DisplayMode mode;
|
||||
SDL_DisplayModeData *modedata;
|
||||
|
||||
/* Unfortunately X11 requires the window to be created with the correct
|
||||
* visual and depth ahead of time, but the SDL API allows you to create
|
||||
* a window before setting the fullscreen display mode. This means that
|
||||
* we have to use the same format for all windows and all display modes.
|
||||
* (or support recreating the window with a new visual behind the scenes)
|
||||
*/
|
||||
mode.format = sdl_display->current_mode.format;
|
||||
mode.driverdata = NULL;
|
||||
|
||||
screen_w = DisplayWidth(display, data->screen);
|
||||
screen_h = DisplayHeight(display, data->screen);
|
||||
|
||||
#if SDL_VIDEO_DRIVER_X11_XINERAMA
|
||||
if (data->use_xinerama) {
|
||||
if (data->use_vidmode && !data->xinerama_info.x_org && !data->xinerama_info.y_org &&
|
||||
(screen_w > data->xinerama_info.width || screen_h > data->xinerama_info.height)) {
|
||||
/* Add the full (both screens combined) xinerama mode only on the display that starts at 0,0
|
||||
* if we're using vidmode.
|
||||
*/
|
||||
mode.w = screen_w;
|
||||
mode.h = screen_h;
|
||||
mode.refresh_rate = 0;
|
||||
modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
|
||||
if (modedata) {
|
||||
*modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
|
||||
}
|
||||
mode.driverdata = modedata;
|
||||
SDL_AddDisplayMode(sdl_display, &mode);
|
||||
}
|
||||
else if (!data->use_xrandr)
|
||||
{
|
||||
/* Add the current mode of each monitor otherwise if we can't get them from xrandr */
|
||||
mode.w = data->xinerama_info.width;
|
||||
mode.h = data->xinerama_info.height;
|
||||
mode.refresh_rate = 0;
|
||||
modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
|
||||
if (modedata) {
|
||||
*modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
|
||||
}
|
||||
mode.driverdata = modedata;
|
||||
SDL_AddDisplayMode(sdl_display, &mode);
|
||||
}
|
||||
|
||||
}
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
|
||||
|
||||
#if SDL_VIDEO_DRIVER_X11_XRANDR
|
||||
if (data->use_xrandr) {
|
||||
XRRScreenResources *res;
|
||||
|
||||
res = XRRGetScreenResources (display, RootWindow(display, data->screen));
|
||||
if (res) {
|
||||
SDL_DisplayModeData *modedata;
|
||||
XRROutputInfo *output_info;
|
||||
int i;
|
||||
|
||||
output_info = XRRGetOutputInfo(display, res, data->xrandr_output);
|
||||
if (output_info && output_info->connection != RR_Disconnected) {
|
||||
for (i = 0; i < output_info->nmode; ++i) {
|
||||
modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
|
||||
if (!modedata) {
|
||||
continue;
|
||||
}
|
||||
mode.driverdata = modedata;
|
||||
|
||||
if (SetXRandRModeInfo(display, res, output_info, output_info->modes[i], &mode)) {
|
||||
SDL_AddDisplayMode(sdl_display, &mode);
|
||||
} else {
|
||||
SDL_free(modedata);
|
||||
}
|
||||
}
|
||||
}
|
||||
XRRFreeOutputInfo(output_info);
|
||||
XRRFreeScreenResources(res);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
|
||||
|
||||
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
|
||||
if (data->use_vidmode &&
|
||||
XF86VidModeGetAllModeLines(display, data->vidmode_screen, &nmodes, &modes)) {
|
||||
int i;
|
||||
|
||||
#ifdef X11MODES_DEBUG
|
||||
printf("VidMode modes: (unsorted)\n");
|
||||
for (i = 0; i < nmodes; ++i) {
|
||||
printf("Mode %d: %d x %d @ %d, flags: 0x%x\n", i,
|
||||
modes[i]->hdisplay, modes[i]->vdisplay,
|
||||
CalculateXVidModeRefreshRate(modes[i]), modes[i]->flags);
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < nmodes; ++i) {
|
||||
modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
|
||||
if (!modedata) {
|
||||
continue;
|
||||
}
|
||||
mode.driverdata = modedata;
|
||||
|
||||
if (SetXVidModeModeInfo(modes[i], &mode)) {
|
||||
SDL_AddDisplayMode(sdl_display, &mode);
|
||||
} else {
|
||||
SDL_free(modedata);
|
||||
}
|
||||
}
|
||||
XFree(modes);
|
||||
return;
|
||||
}
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
|
||||
|
||||
if (!data->use_xrandr && !data->use_vidmode) {
|
||||
/* Add the desktop mode */
|
||||
mode = sdl_display->desktop_mode;
|
||||
modedata = (SDL_DisplayModeData *) SDL_calloc(1, sizeof(SDL_DisplayModeData));
|
||||
if (modedata) {
|
||||
*modedata = *(SDL_DisplayModeData *)sdl_display->desktop_mode.driverdata;
|
||||
}
|
||||
mode.driverdata = modedata;
|
||||
SDL_AddDisplayMode(sdl_display, &mode);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
X11_SetDisplayMode(_THIS, SDL_VideoDisplay * sdl_display, SDL_DisplayMode * mode)
|
||||
{
|
||||
Display *display = ((SDL_VideoData *) _this->driverdata)->display;
|
||||
SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
|
||||
SDL_DisplayModeData *modedata = (SDL_DisplayModeData *)mode->driverdata;
|
||||
|
||||
#if SDL_VIDEO_DRIVER_X11_XRANDR
|
||||
if (data->use_xrandr) {
|
||||
XRRScreenResources *res;
|
||||
XRROutputInfo *output_info;
|
||||
XRRCrtcInfo *crtc;
|
||||
Status status;
|
||||
|
||||
res = XRRGetScreenResources (display, RootWindow(display, data->screen));
|
||||
if (!res) {
|
||||
return SDL_SetError("Couldn't get XRandR screen resources");
|
||||
}
|
||||
|
||||
output_info = XRRGetOutputInfo(display, res, data->xrandr_output);
|
||||
if (!output_info || output_info->connection == RR_Disconnected) {
|
||||
XRRFreeScreenResources(res);
|
||||
return SDL_SetError("Couldn't get XRandR output info");
|
||||
}
|
||||
|
||||
crtc = XRRGetCrtcInfo(display, res, output_info->crtc);
|
||||
if (!crtc) {
|
||||
XRRFreeOutputInfo(output_info);
|
||||
XRRFreeScreenResources(res);
|
||||
return SDL_SetError("Couldn't get XRandR crtc info");
|
||||
}
|
||||
|
||||
status = XRRSetCrtcConfig (display, res, output_info->crtc, CurrentTime,
|
||||
crtc->x, crtc->y, modedata->xrandr_mode, crtc->rotation,
|
||||
&data->xrandr_output, 1);
|
||||
|
||||
XRRFreeCrtcInfo(crtc);
|
||||
XRRFreeOutputInfo(output_info);
|
||||
XRRFreeScreenResources(res);
|
||||
|
||||
if (status != Success) {
|
||||
return SDL_SetError("XRRSetCrtcConfig failed");
|
||||
}
|
||||
}
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */
|
||||
|
||||
#if SDL_VIDEO_DRIVER_X11_XVIDMODE
|
||||
if (data->use_vidmode) {
|
||||
XF86VidModeSwitchToMode(display, data->vidmode_screen, &modedata->vm_mode);
|
||||
}
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
X11_QuitModes(_THIS)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect)
|
||||
{
|
||||
SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;
|
||||
|
||||
rect->x = data->x;
|
||||
rect->y = data->y;
|
||||
rect->w = sdl_display->current_mode.w;
|
||||
rect->h = sdl_display->current_mode.h;
|
||||
|
||||
#if SDL_VIDEO_DRIVER_X11_XINERAMA
|
||||
/* Get the real current bounds of the display */
|
||||
if (data->use_xinerama) {
|
||||
Display *display = ((SDL_VideoData *) _this->driverdata)->display;
|
||||
int screencount;
|
||||
XineramaScreenInfo *xinerama = XineramaQueryScreens(display, &screencount);
|
||||
if (xinerama) {
|
||||
rect->x = xinerama[data->xinerama_screen].x_org;
|
||||
rect->y = xinerama[data->xinerama_screen].y_org;
|
||||
XFree(xinerama);
|
||||
}
|
||||
}
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_X11 */
|
||||
|
||||
/* vi: set ts=4 sw=4 expandtab: */
|
||||
Reference in New Issue
Block a user