Skip to content
This repository has been archived by the owner on Feb 11, 2021. It is now read-only.

Commit

Permalink
Fixes #1522, improved Xinerama / Twinview support
Browse files Browse the repository at this point in the history
  • Loading branch information
gabomdq committed Jun 19, 2012
1 parent 20419c5 commit d3be94a
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 63 deletions.
173 changes: 118 additions & 55 deletions src/video/x11/SDL_x11modes.c
Expand Up @@ -131,40 +131,97 @@ X11_GetPixelFormatFromVisualInfo(Display * display, XVisualInfo * vinfo)

return SDL_PIXELFORMAT_UNKNOWN;
}
#if SDL_VIDEO_DRIVER_X11_XINERAMA
static SDL_bool CheckXinerama(Display * display, int *major, int *minor);
#endif

int
X11_InitModes(_THIS)
{
SDL_VideoData *data = (SDL_VideoData *) _this->driverdata;
int screen;
int screen, screencount;

for (screen = 0; screen < ScreenCount(data->display); ++screen) {
#if SDL_VIDEO_DRIVER_X11_XINERAMA
int xinerama_major, xinerama_minor;
XineramaScreenInfo * xinerama = NULL;
/* 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) screencount = ScreenCount(data->display);
}
else {
screencount = ScreenCount(data->display);
}
#else
screencount = ScreenCount(data->display);
#endif

for (screen = 0; screen < screencount; ++screen) {
XVisualInfo vinfo;
SDL_VideoDisplay display;
SDL_DisplayData *displaydata;
SDL_DisplayMode mode;
XPixmapFormatValues *pixmapFormats;
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

mode.format = X11_GetPixelFormatFromVisualInfo(data->display, &vinfo);
if (SDL_ISPIXELFORMAT_INDEXED(mode.format)) {
/* We don't support palettized modes now */
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;
mode.driverdata = NULL;

displaydata = (SDL_DisplayData *) SDL_malloc(sizeof(*displaydata));
if (!displaydata) {
continue;
}
#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 (xinerama) {
displaydata->screen = 0;
displaydata->use_xinerama = xinerama_major * 100 + xinerama_minor;
displaydata->xinerama_info = xinerama[screen];
}
else displaydata->screen = screen;
#else
displaydata->screen = screen;
#endif
displaydata->visual = vinfo.visual;
displaydata->depth = vinfo.depth;

Expand All @@ -186,6 +243,11 @@ X11_InitModes(_THIS)
display.driverdata = displaydata;
SDL_AddVideoDisplay(&display);
}

#if SDL_VIDEO_DRIVER_X11_XINERAMA
if (xinerama) XFree(xinerama);
#endif

if (_this->num_displays == 0) {
SDL_SetError("No available displays");
return -1;
Expand Down Expand Up @@ -351,11 +413,6 @@ 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_XINERAMA
int xinerama_major, xinerama_minor;
int screens;
XineramaScreenInfo * xinerama;
#endif
#if SDL_VIDEO_DRIVER_X11_XRANDR
int xrandr_major, xrandr_minor;
int nsizes, nrates;
Expand All @@ -380,53 +437,27 @@ X11_GetDisplayModes(_THIS, SDL_VideoDisplay * sdl_display)
mode.format = sdl_display->current_mode.format;
mode.driverdata = NULL;

data->use_xinerama = 0;
data->use_xrandr = 0;
data->use_vidmode = 0;
screen_w = DisplayWidth(display, data->screen);
screen_h = DisplayHeight(display, data->screen);

#if SDL_VIDEO_DRIVER_X11_XINERAMA
/* Query Xinerama extention */
if (CheckXinerama(display, &xinerama_major, &xinerama_minor)) {
#ifdef X11MODES_DEBUG
printf("X11 detected Xinerama:\n");
#endif
xinerama = XineramaQueryScreens(display, &screens);
if (xinerama) {
int i;
for (i = 0; i < screens; i++) {
#ifdef X11MODES_DEBUG
printf("xinerama %d: %dx%d+%d+%d\n",
xinerama[i].screen_number,
xinerama[i].width, xinerama[i].height,
xinerama[i].x_org, xinerama[i].y_org);
#endif
if (xinerama[i].screen_number == data->screen) {
data->use_xinerama =
xinerama_major * 100 + xinerama_minor;
data->xinerama_info = xinerama[i];
}
}
XFree(xinerama);
}

if (data->use_xinerama) {
/* Add the full xinerama mode */
if (screen_w > data->xinerama_info.width ||
screen_h > data->xinerama_info.height) {
mode.w = screen_w;
mode.h = screen_h;
mode.refresh_rate = 0;
SDL_AddDisplayMode(sdl_display, &mode);
}

/* Add the head xinerama mode */
mode.w = data->xinerama_info.width;
mode.h = data->xinerama_info.height;
if (data->use_xinerama) {
/* Add the full (both screens combined) xinerama mode only on the display that starts at 0,0 */
if (!data->xinerama_info.x_org && !data->xinerama_info.y_org &&
(screen_w > data->xinerama_info.width || screen_h > data->xinerama_info.height)) {
mode.w = screen_w;
mode.h = screen_h;
mode.refresh_rate = 0;
SDL_AddDisplayMode(sdl_display, &mode);
}

/* Add the head xinerama mode */
mode.w = data->xinerama_info.width;
mode.h = data->xinerama_info.height;
mode.refresh_rate = 0;
SDL_AddDisplayMode(sdl_display, &mode);
}
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */

Expand Down Expand Up @@ -531,6 +562,15 @@ static void
get_real_resolution(Display * display, SDL_DisplayData * data, int *w, int *h,
int *rate)
{
#if SDL_VIDEO_DRIVER_X11_XINERAMA
if (data->use_xinerama) {
*w = data->xinerama_info.width;
*h = data->xinerama_info.height;
*rate = 0;
return;
}
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */

#if SDL_VIDEO_DRIVER_X11_XRANDR
if (data->use_xrandr) {
int nsizes;
Expand Down Expand Up @@ -570,15 +610,6 @@ get_real_resolution(Display * display, SDL_DisplayData * data, int *w, int *h,
}
#endif /* SDL_VIDEO_DRIVER_X11_XVIDMODE */

#if SDL_VIDEO_DRIVER_X11_XINERAMA
if (data->use_xinerama) {
*w = data->xinerama_info.width;
*h = data->xinerama_info.height;
*rate = 0;
return;
}
#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */

*w = DisplayWidth(display, data->screen);
*h = DisplayHeight(display, data->screen);
*rate = 0;
Expand All @@ -592,9 +623,17 @@ set_best_resolution(Display * display, SDL_DisplayData * data, int w, int h,

/* check current mode so we can avoid uneccessary mode changes */
get_real_resolution(display, data, &real_w, &real_h, &real_rate);

#if SDL_VIDEO_DRIVER_X11_XINERAMA
if (w == real_w && h == real_h && (data->use_xinerama || !rate || rate == real_rate)) {
return;
}
#else
if (w == real_w && h == real_h && (!rate || rate == real_rate)) {
return;
}
#endif

#if SDL_VIDEO_DRIVER_X11_XRANDR
if (data->use_xrandr) {
#ifdef X11MODES_DEBUG
Expand Down Expand Up @@ -719,6 +758,30 @@ X11_QuitModes(_THIS)
{
}

int
X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect)
{
SDL_DisplayData *data = (SDL_DisplayData *) sdl_display->driverdata;

#if SDL_VIDEO_DRIVER_X11_XINERAMA
if (data && data->use_xinerama) {
rect->x = data->xinerama_info.x_org;
rect->y = data->xinerama_info.y_org;
rect->w = data->xinerama_info.width;
rect->h = data->xinerama_info.height;
return 0;
}
#endif
if (_this->windows) {
rect->x = 0;
rect->y = 0;
rect->w = _this->windows->w;
rect->h = _this->windows->h;
return 0;
}
return -1;
}

#endif /* SDL_VIDEO_DRIVER_X11 */

/* vi: set ts=4 sw=4 expandtab: */
1 change: 1 addition & 0 deletions src/video/x11/SDL_x11modes.h
Expand Up @@ -63,6 +63,7 @@ extern int X11_GetVisualInfoFromVisual(Display * display, Visual * visual,
XVisualInfo * vinfo);
extern Uint32 X11_GetPixelFormatFromVisualInfo(Display * display,
XVisualInfo * vinfo);
extern int X11_GetDisplayBounds(_THIS, SDL_VideoDisplay * sdl_display, SDL_Rect * rect);

#endif /* _SDL_x11modes_h */

Expand Down
1 change: 1 addition & 0 deletions src/video/x11/SDL_x11video.c
Expand Up @@ -187,6 +187,7 @@ X11_CreateDevice(int devindex)
device->VideoInit = X11_VideoInit;
device->VideoQuit = X11_VideoQuit;
device->GetDisplayModes = X11_GetDisplayModes;
device->GetDisplayBounds = X11_GetDisplayBounds;
device->SetDisplayMode = X11_SetDisplayMode;
device->SuspendScreenSaver = X11_SuspendScreenSaver;
device->PumpEvents = X11_PumpEvents;
Expand Down
8 changes: 0 additions & 8 deletions src/video/x11/SDL_x11window.c
Expand Up @@ -269,14 +269,6 @@ X11_CreateWindow(_THIS, SDL_Window * window)
Atom wmstate_atoms[3];
Uint32 fevent = 0;

#if SDL_VIDEO_DRIVER_X11_XINERAMA
/* FIXME
if ( use_xinerama ) {
x = xinerama_info.x_org;
y = xinerama_info.y_org;
}
*/
#endif
#if SDL_VIDEO_OPENGL_GLX
if (window->flags & SDL_WINDOW_OPENGL) {
XVisualInfo *vinfo;
Expand Down

0 comments on commit d3be94a

Please sign in to comment.