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

Commit

Permalink
X11: Attempt to go fullscreen the way SDL 1.2 did it.
Browse files Browse the repository at this point in the history
Ideally this code is never used, but as a legacy fallback, it could be useful.
  • Loading branch information
icculus committed Sep 27, 2012
1 parent 8db67d8 commit a51ee16
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 25 deletions.
5 changes: 5 additions & 0 deletions src/video/x11/SDL_x11sym.h
Expand Up @@ -30,6 +30,7 @@ SDL_X11_SYM(int,XAutoRepeatOff,(Display* a),(a),return)
SDL_X11_SYM(int,XChangePointerControl,(Display* a,Bool b,Bool c,int d,int e,int f),(a,b,c,d,e,f),return)
SDL_X11_SYM(int,XChangeProperty,(Display* a,Window b,Atom c,Atom d,int e,int f,_Xconst unsigned char* g,int h),(a,b,c,d,e,f,g,h),return)
SDL_X11_SYM(Bool,XCheckIfEvent,(Display* a,XEvent *b,Bool (*c)(Display*,XEvent*,XPointer),XPointer d),(a,b,c,d),return)
SDL_X11_SYM(int,XClearWindow,(Display* a,Window b),(a,b),return)
SDL_X11_SYM(int,XCloseDisplay,(Display* a),(a),return)
SDL_X11_SYM(int,XConvertSelection,(Display* a,Atom b,Atom c,Atom d,Window e,Time f),(a,b,c,d,e,f),return)
SDL_X11_SYM(Pixmap,XCreateBitmapFromData,(Display *dpy,Drawable d,_Xconst char *data,unsigned int width,unsigned int height),(dpy,d,data,width,height),return)
Expand Down Expand Up @@ -69,6 +70,7 @@ SDL_X11_SYM(int,XGrabServer,(Display* a),(a),return)
SDL_X11_SYM(Status,XIconifyWindow,(Display* a,Window b,int c),(a,b,c),return)
SDL_X11_SYM(KeyCode,XKeysymToKeycode,(Display* a,KeySym b),(a,b),return)
SDL_X11_SYM(char*,XKeysymToString,(KeySym a),(a),return)
SDL_X11_SYM(int,XInstallColormap,(Display* a,Colormap b),(a,b),return)
SDL_X11_SYM(Atom,XInternAtom,(Display* a,_Xconst char* b,Bool c),(a,b,c),return)
SDL_X11_SYM(XPixmapFormatValues*,XListPixmapFormats,(Display* a,int* b),(a,b),return)
SDL_X11_SYM(KeySym,XLookupKeysym,(XKeyEvent* a,int b),(a,b),return)
Expand All @@ -85,6 +87,7 @@ SDL_X11_SYM(int,XPutImage,(Display* a,Drawable b,GC c,XImage* d,int e,int f,int
SDL_X11_SYM(int,XQueryKeymap,(Display* a,char *b),(a,b),return)
SDL_X11_SYM(Bool,XQueryPointer,(Display* a,Window b,Window* c,Window* d,int* e,int* f,int* g,int* h,unsigned int* i),(a,b,c,d,e,f,g,h,i),return)
SDL_X11_SYM(int,XRaiseWindow,(Display* a,Window b),(a,b),return)
SDL_X11_SYM(int,XReparentWindow,(Display* a,Window b,Window c,int d,int e),(a,b,c,d,e),return)
SDL_X11_SYM(int,XResetScreenSaver,(Display* a),(a),return)
SDL_X11_SYM(int,XResizeWindow,(Display* a,Window b,unsigned int c,unsigned int d),(a,b,c,d),return)
SDL_X11_SYM(int,XSelectInput,(Display* a,Window b,long c),(a,b,c),return)
Expand All @@ -95,6 +98,7 @@ SDL_X11_SYM(int,XSetInputFocus,(Display *a,Window b,int c,Time d),(a,b,c,d),retu
SDL_X11_SYM(int,XSetSelectionOwner,(Display* a,Atom b,Window c,Time d),(a,b,c,d),return)
SDL_X11_SYM(int,XSetTransientForHint,(Display* a,Window b,Window c),(a,b,c),return)
SDL_X11_SYM(void,XSetTextProperty,(Display* a,Window b,XTextProperty* c,Atom d),(a,b,c,d),)
SDL_X11_SYM(int,XSetWindowBackground,(Display* a,Window b,unsigned long c),(a,b,c),return)
SDL_X11_SYM(void,XSetWMProperties,(Display* a,Window b,XTextProperty* c,XTextProperty* d,char** e,int f,XSizeHints* g,XWMHints* h,XClassHint* i),(a,b,c,d,e,f,g,h,i),)
SDL_X11_SYM(void,XSetWMNormalHints,(Display* a,Window b,XSizeHints* c),(a,b,c),)
SDL_X11_SYM(Status,XSetWMProtocols,(Display* a,Window b,Atom* c,int d),(a,b,c,d),return)
Expand Down Expand Up @@ -256,6 +260,7 @@ SDL_X11_SYM(Bool,XF86VidModeGetViewPort,(Display *a,int b,int *c,int *d),(a,b,c,
SDL_X11_SYM(Bool,XF86VidModeQueryExtension,(Display *a,int *b,int *c),(a,b,c),return)
SDL_X11_SYM(Bool,XF86VidModeQueryVersion,(Display *a,int *b,int *c),(a,b,c),return)
SDL_X11_SYM(Bool,XF86VidModeSwitchToMode,(Display *a,int b,XF86VidModeModeInfo *c),(a,b,c),return)
SDL_X11_SYM(Bool,XF86VidModeLockModeSwitch,(Display *a,int b,int c),(a,b,c),return)
#endif

/* *INDENT-ON* */
Expand Down
237 changes: 212 additions & 25 deletions src/video/x11/SDL_x11window.c
Expand Up @@ -38,22 +38,38 @@

#include "SDL_timer.h"
#include "SDL_syswm.h"
#include "SDL_assert.h"

#define _NET_WM_STATE_REMOVE 0l
#define _NET_WM_STATE_ADD 1l
#define _NET_WM_STATE_TOGGLE 2l

static SDL_bool
X11_IsWindowOldFullscreen(_THIS, SDL_Window * window)
static Bool isMapNotify(Display *dpy, XEvent *ev, XPointer win)
{
SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
return ev->type == MapNotify && ev->xmap.window == *((Window*)win);
}
static Bool isUnmapNotify(Display *dpy, XEvent *ev, XPointer win)
{
return ev->type == UnmapNotify && ev->xunmap.window == *((Window*)win);
}
static Bool isConfigureNotify(Display *dpy, XEvent *ev, XPointer win)
{
return ev->type == ConfigureNotify && ev->xunmap.window == *((Window*)win);
}
static Bool isFocusOut(Display *dpy, XEvent *ev, XPointer win)
{
return ev->type == FocusOut && ev->xunmap.window == *((Window*)win);
}
static Bool isFocusIn(Display *dpy, XEvent *ev, XPointer win)
{
return ev->type == FocusIn && ev->xunmap.window == *((Window*)win);
}

/* ICCCM2.0-compliant window managers can handle fullscreen windows */
if ((window->flags & SDL_WINDOW_FULLSCREEN) && !videodata->net_wm) {
return SDL_TRUE;
} else {
return SDL_FALSE;
}
static SDL_bool
X11_IsWindowLegacyFullscreen(_THIS, SDL_Window * window)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
return (data->fswindow != 0);
}

static SDL_bool
Expand Down Expand Up @@ -724,19 +740,6 @@ X11_SetWindowSize(_THIS, SDL_Window * window)
XFlush(display);
}

static Bool isMapNotify(Display *dpy, XEvent *ev, XPointer win)
{
return ev->type == MapNotify && ev->xmap.window == *((Window*)win);
}
static Bool isUnmapNotify(Display *dpy, XEvent *ev, XPointer win)
{
return ev->type == UnmapNotify && ev->xunmap.window == *((Window*)win);
}
static Bool isConfigureNotify(Display *dpy, XEvent *ev, XPointer win)
{
return ev->type == ConfigureNotify && ev->xunmap.window == *((Window*)win);
}

void
X11_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
{
Expand Down Expand Up @@ -907,8 +910,9 @@ isActionAllowed(SDL_WindowData *data, Atom action)
return ret;
}

void
X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
/* This asks the Window Manager to handle fullscreen for us. Most don't do it right, though. */
static void
X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
Expand Down Expand Up @@ -977,6 +981,189 @@ X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display,
XFlush(display);
}

static __inline__ int
maxint(const int a, const int b)
{
return (a > b ? a : b);
}


/* This handles fullscreen itself, outside the Window Manager. */
static void
X11_BeginWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
Visual *visual = data->visual;
Display *display = data->videodata->display;
const int screen = displaydata->screen;
Window root = RootWindow(display, screen);
const int def_vis = (visual == DefaultVisual(display, screen));
const int w = maxint(window->w, _display->current_mode.w);
const int h = maxint(window->h, _display->current_mode.h);
unsigned long xattrmask = 0;
XSetWindowAttributes xattr;
XEvent ev;
int x = 0;
int y = 0;

if ( data->fswindow ) {
return; /* already fullscreen, I hope. */
}

/* Ungrab the input so that we can move the mouse around */
XUngrabPointer(display, CurrentTime);

#if SDL_VIDEO_DRIVER_X11_XINERAMA
/* !!! FIXME: there was some Xinerama code in 1.2 here to set x,y to the origin of a specific screen. */
#endif

SDL_zero(xattr);
xattr.override_redirect = True;
xattrmask |= CWOverrideRedirect;
xattr.background_pixel = def_vis ? BlackPixel(display, screen) : 0;
xattrmask |= CWBackPixel;
xattr.border_pixel = 0;
xattrmask |= CWBorderPixel;
xattr.colormap = data->colormap;
xattrmask |= CWColormap;

data->fswindow = XCreateWindow(display, root, x, y, w, h, 0,
displaydata->depth, InputOutput,
visual, xattrmask, &xattr);

XSelectInput(display, data->fswindow, StructureNotifyMask);

XSetWindowBackground(display, data->fswindow, 0);
XClearWindow(display, data->fswindow);

XMapRaised(display, data->fswindow);

/* Wait to be mapped, filter Unmap event out if it arrives. */
XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->fswindow);
XCheckIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);

#if SDL_VIDEO_DRIVER_X11_XVIDMODE
if ( displaydata->use_vidmode ) {
XF86VidModeLockModeSwitch(display, screen, True);
}
#endif

XInstallColormap(display, data->colormap);

SetWindowBordered(display, displaydata->screen, data->xwindow, SDL_FALSE);
XFlush(display);
//XIfEvent(display, &ev, &isConfigureNotify, (XPointer)&data->xwindow);

/* Center actual window within our cover-the-screen window. */
x += (w - window->w) / 2;
y += (h - window->h) / 2;
XReparentWindow(display, data->xwindow, data->fswindow, x, y);
XRaiseWindow(display, data->xwindow);

/* Make sure the fswindow is in view by warping mouse to the corner */
XWarpPointer(display, None, root, 0, 0, 0, 0, 0, 0);
XFlush(display);

/* Center mouse in the window. */
x += (window->w / 2);
y += (window->h / 2);
XWarpPointer(display, None, root, 0, 0, 0, 0, x, y);

/* Wait to be mapped, filter Unmap event out if it arrives. */
XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);

/* Wait to be visible, or XSetInputFocus() triggers an X error. */
while (SDL_TRUE) {
XWindowAttributes attr;
XSync(display, False);
XGetWindowAttributes(display, data->xwindow, &attr);
if (attr.map_state == IsViewable)
break;
}

XSetInputFocus(display, data->xwindow, RevertToParent, CurrentTime);
window->flags |= SDL_WINDOW_INPUT_FOCUS;
SDL_SetKeyboardFocus(data->window);

X11_SetWindowGrab(_this, window);

XSync(display, False);
}

static void
X11_EndWindowFullscreenLegacy(_THIS, SDL_Window * window, SDL_VideoDisplay * _display)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
Display *display = data->videodata->display;
const int screen = displaydata->screen;
Window root = RootWindow(display, screen);
XEvent ev;

if (!data->fswindow)
return; /* already not fullscreen, I hope. */

XReparentWindow(display, data->xwindow, root, window->x, window->y);

#if SDL_VIDEO_DRIVER_X11_VIDMODE
if ( displaydata->use_vidmode ) {
XF86VidModeLockModeSwitch(display, screen, False);
}
#endif

XUnmapWindow(display, data->fswindow);
/* Wait to be unmapped. */
XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->fswindow);
XDestroyWindow(display, data->fswindow);
data->fswindow = 0;

/* catch these events so we know the window is back in business. */
XIfEvent(display, &ev, &isUnmapNotify, (XPointer)&data->xwindow);
XIfEvent(display, &ev, &isMapNotify, (XPointer)&data->xwindow);

XSync(display, True); /* Flush spurious mode change events */

X11_SetWindowGrab(_this, window);

SetWindowBordered(display, screen, data->xwindow,
(window->flags & SDL_WINDOW_BORDERLESS) == 0);

XFlush(display);
}


void
X11_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * _display, SDL_bool fullscreen)
{
/* !!! FIXME: SDL_Hint? */
SDL_bool legacy = SDL_FALSE;
const char *env = SDL_getenv("SDL_VIDEO_X11_LEGACY_FULLSCREEN");
if (env) {
legacy = SDL_atoi(env);
} else {
SDL_DisplayData *displaydata = (SDL_DisplayData *) _display->driverdata;
if ( displaydata->use_vidmode ) {
legacy = SDL_TRUE; /* the new stuff only works with XRandR. */
} else {
/* !!! FIXME: look at the window manager name, and blacklist certain ones? */
/* http://stackoverflow.com/questions/758648/find-the-name-of-the-x-window-manager */
legacy = SDL_FALSE; /* try the new way. */
}
}

if (legacy) {
if (fullscreen) {
X11_BeginWindowFullscreenLegacy(_this, window, _display);
} else {
X11_EndWindowFullscreenLegacy(_this, window, _display);
}
} else {
X11_SetWindowFullscreenViaWM(_this, window, _display, fullscreen);
}
}


int
X11_SetWindowGammaRamp(_THIS, SDL_Window * window, const Uint16 * ramp)
{
Expand Down Expand Up @@ -1054,7 +1241,7 @@ X11_SetWindowGrab(_THIS, SDL_Window * window)
SDL_bool oldstyle_fullscreen;

/* ICCCM2.0-compliant window managers can handle fullscreen windows */
oldstyle_fullscreen = X11_IsWindowOldFullscreen(_this, window);
oldstyle_fullscreen = X11_IsWindowLegacyFullscreen(_this, window);

if (((window->flags & SDL_WINDOW_INPUT_GRABBED) || oldstyle_fullscreen)
&& (window->flags & SDL_WINDOW_INPUT_FOCUS)) {
Expand Down
1 change: 1 addition & 0 deletions src/video/x11/SDL_x11window.h
Expand Up @@ -27,6 +27,7 @@ typedef struct
{
SDL_Window *window;
Window xwindow;
Window fswindow; /* used if we can't have the WM handle fullscreen. */
Visual *visual;
Colormap colormap;
#ifndef NO_SHARED_MEMORY
Expand Down

0 comments on commit a51ee16

Please sign in to comment.