From a855d6202536ff28e5aae4f22a0f31d8f5b325d0 Mon Sep 17 00:00:00 2001 From: Franklin Wei Date: Sat, 21 Jan 2017 15:18:31 -0500 Subject: Port of Duke Nukem 3D This ports Fabien Sanglard's Chocolate Duke to run on a version of SDL for Rockbox. Change-Id: I8f2c4c78af19de10c1633ed7bb7a997b43256dd9 --- apps/plugins/sdl/src/video/x11/SDL_x11dga.c | 90 ++ apps/plugins/sdl/src/video/x11/SDL_x11dga_c.h | 33 + apps/plugins/sdl/src/video/x11/SDL_x11dyn.c | 222 +++ apps/plugins/sdl/src/video/x11/SDL_x11dyn.h | 93 ++ apps/plugins/sdl/src/video/x11/SDL_x11events.c | 1414 +++++++++++++++++++ apps/plugins/sdl/src/video/x11/SDL_x11events_c.h | 34 + apps/plugins/sdl/src/video/x11/SDL_x11gamma.c | 142 ++ apps/plugins/sdl/src/video/x11/SDL_x11gamma_c.h | 32 + apps/plugins/sdl/src/video/x11/SDL_x11gl.c | 577 ++++++++ apps/plugins/sdl/src/video/x11/SDL_x11gl_c.h | 99 ++ apps/plugins/sdl/src/video/x11/SDL_x11image.c | 316 +++++ apps/plugins/sdl/src/video/x11/SDL_x11image_c.h | 38 + apps/plugins/sdl/src/video/x11/SDL_x11modes.c | 1143 ++++++++++++++++ apps/plugins/sdl/src/video/x11/SDL_x11modes_c.h | 43 + apps/plugins/sdl/src/video/x11/SDL_x11mouse.c | 288 ++++ apps/plugins/sdl/src/video/x11/SDL_x11mouse_c.h | 33 + apps/plugins/sdl/src/video/x11/SDL_x11sym.h | 201 +++ apps/plugins/sdl/src/video/x11/SDL_x11video.c | 1571 ++++++++++++++++++++++ apps/plugins/sdl/src/video/x11/SDL_x11video.h | 214 +++ apps/plugins/sdl/src/video/x11/SDL_x11wm.c | 434 ++++++ apps/plugins/sdl/src/video/x11/SDL_x11wm_c.h | 34 + apps/plugins/sdl/src/video/x11/SDL_x11yuv.c | 538 ++++++++ apps/plugins/sdl/src/video/x11/SDL_x11yuv_c.h | 41 + 23 files changed, 7630 insertions(+) create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11dga.c create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11dga_c.h create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11dyn.c create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11dyn.h create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11events.c create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11events_c.h create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11gamma.c create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11gamma_c.h create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11gl.c create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11gl_c.h create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11image.c create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11image_c.h create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11modes.c create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11modes_c.h create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11mouse.c create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11mouse_c.h create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11sym.h create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11video.c create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11video.h create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11wm.c create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11wm_c.h create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11yuv.c create mode 100644 apps/plugins/sdl/src/video/x11/SDL_x11yuv_c.h (limited to 'apps/plugins/sdl/src/video/x11') diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11dga.c b/apps/plugins/sdl/src/video/x11/SDL_x11dga.c new file mode 100644 index 0000000000..e1c0c2e8cd --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11dga.c @@ -0,0 +1,90 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* This is currently only used to enable DGA mouse. + There is a completely separate DGA driver that is fullscreen-only. +*/ + +#include "SDL_video.h" +#include "../SDL_cursor_c.h" +#include "SDL_x11dga_c.h" + +/* Global for the error handler */ +int dga_event, dga_error = -1; + +void X11_EnableDGAMouse(_THIS) +{ +#if SDL_VIDEO_DRIVER_X11_DGAMOUSE + static int use_dgamouse = -1; + + /* Check configuration to see if we should use DGA mouse */ + if ( use_dgamouse < 0 ) { + int dga_major, dga_minor; + int dga_flags; + const char *env_use_dgamouse; + + use_dgamouse = 1; + env_use_dgamouse = SDL_getenv("SDL_VIDEO_X11_DGAMOUSE"); + if ( env_use_dgamouse ) { + use_dgamouse = SDL_atoi(env_use_dgamouse); + } + /* Check for buggy X servers */ + if ( use_dgamouse && BUGGY_XFREE86(==, 4000) ) { + use_dgamouse = 0; + } + if ( !use_dgamouse || !local_X11 || + !SDL_NAME(XF86DGAQueryExtension)(SDL_Display, &dga_event, &dga_error) || + !SDL_NAME(XF86DGAQueryVersion)(SDL_Display, &dga_major, &dga_minor) || + !SDL_NAME(XF86DGAQueryDirectVideo)(SDL_Display, SDL_Screen, &dga_flags) || + !(dga_flags & XF86DGADirectPresent) ) { + use_dgamouse = 0; + } + } + + if ( use_dgamouse && !(using_dga & DGA_MOUSE) ) { + if ( SDL_NAME(XF86DGADirectVideo)(SDL_Display, SDL_Screen, XF86DGADirectMouse) ) { + using_dga |= DGA_MOUSE; + } + } +#endif /* SDL_VIDEO_DRIVER_X11_DGAMOUSE */ +} + +/* Argh. Glide resets DGA mouse mode when it makes the context current! */ +void X11_CheckDGAMouse(_THIS) +{ +#if SDL_VIDEO_DRIVER_X11_DGAMOUSE + if ( using_dga & DGA_MOUSE ) { + SDL_NAME(XF86DGADirectVideo)(SDL_Display,SDL_Screen,XF86DGADirectMouse); + } +#endif +} + +void X11_DisableDGAMouse(_THIS) +{ +#if SDL_VIDEO_DRIVER_X11_DGAMOUSE + if ( using_dga & DGA_MOUSE ) { + SDL_NAME(XF86DGADirectVideo)(SDL_Display, SDL_Screen, 0); + using_dga &= ~DGA_MOUSE; + } +#endif /* SDL_VIDEO_DRIVER_X11_DGAMOUSE */ +} diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11dga_c.h b/apps/plugins/sdl/src/video/x11/SDL_x11dga_c.h new file mode 100644 index 0000000000..a57511c893 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11dga_c.h @@ -0,0 +1,33 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#include "SDL_x11video.h" + +/* Different DGA access states */ +#define DGA_GRAPHICS 0x01 +#define DGA_KEYBOARD 0x02 +#define DGA_MOUSE 0x04 + +extern void X11_EnableDGAMouse(_THIS); +extern void X11_CheckDGAMouse(_THIS); +extern void X11_DisableDGAMouse(_THIS); diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11dyn.c b/apps/plugins/sdl/src/video/x11/SDL_x11dyn.c new file mode 100644 index 0000000000..7058addfa8 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11dyn.c @@ -0,0 +1,222 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#define DEBUG_DYNAMIC_X11 0 + +#include "SDL_x11dyn.h" + +#if DEBUG_DYNAMIC_X11 +#include +#endif + +#ifdef SDL_VIDEO_DRIVER_X11_DYNAMIC + +#include "SDL_name.h" +#include "SDL_loadso.h" + +typedef struct +{ + void *lib; + const char *libname; +} x11dynlib; + +#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC +#define SDL_VIDEO_DRIVER_X11_DYNAMIC NULL +#endif +#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT +#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT NULL +#endif +#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XRENDER +#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XRENDER NULL +#endif +#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR +#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR NULL +#endif + +static x11dynlib x11libs[] = +{ + { NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC }, + { NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT }, + { NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XRENDER }, + { NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR }, +}; + +static void *X11_GetSym(const char *fnname, int *rc) +{ + void *fn = NULL; + int i; + for (i = 0; i < SDL_TABLESIZE(x11libs); i++) { + if (x11libs[i].lib != NULL) + { + fn = SDL_LoadFunction(x11libs[i].lib, fnname); + if (fn != NULL) + break; + } + } + + #if DEBUG_DYNAMIC_X11 + if (fn != NULL) + printf("X11: Found '%s' in %s (%p)\n", fnname, x11libs[i].libname, *fn); + else + printf("X11: Symbol '%s' NOT FOUND!\n", fnname); + #endif + + if (fn == NULL) + *rc = 0; /* kill this module. */ + + return fn; +} + + +/* Define all the function pointers and wrappers... */ +#define SDL_X11_MODULE(modname) +#define SDL_X11_SYM(rc,fn,params,args,ret) \ + static rc (*p##fn) params = NULL; \ + rc fn params { ret p##fn args ; } +#include "SDL_x11sym.h" +#undef SDL_X11_MODULE +#undef SDL_X11_SYM +#endif /* SDL_VIDEO_DRIVER_X11_DYNAMIC */ + +/* Annoying varargs entry point... */ +#ifdef X_HAVE_UTF8_STRING +XIC (*pXCreateIC)(XIM,...) = NULL; +char *(*pXGetICValues)(XIC, ...) = NULL; +#endif + +/* These SDL_X11_HAVE_* flags are here whether you have dynamic X11 or not. */ +#define SDL_X11_MODULE(modname) int SDL_X11_HAVE_##modname = 1; +#define SDL_X11_SYM(rc,fn,params,args,ret) +#include "SDL_x11sym.h" +#undef SDL_X11_MODULE +#undef SDL_X11_SYM + + +static void *SDL_XGetRequest_workaround(Display* dpy, CARD8 type, size_t len) +{ + xReq *req; + WORD64ALIGN + if (dpy->bufptr + len > dpy->bufmax) + _XFlush(dpy); + dpy->last_req = dpy->bufptr; + req = (xReq*)dpy->bufptr; + req->reqType = type; + req->length = len / 4; + dpy->bufptr += len; + dpy->request++; + return req; +} + +static int x11_load_refcount = 0; + +void SDL_X11_UnloadSymbols(void) +{ + #ifdef SDL_VIDEO_DRIVER_X11_DYNAMIC + /* Don't actually unload if more than one module is using the libs... */ + if (x11_load_refcount > 0) { + if (--x11_load_refcount == 0) { + int i; + + /* set all the function pointers to NULL. */ + #define SDL_X11_MODULE(modname) SDL_X11_HAVE_##modname = 1; + #define SDL_X11_SYM(rc,fn,params,args,ret) p##fn = NULL; + #include "SDL_x11sym.h" + #undef SDL_X11_MODULE + #undef SDL_X11_SYM + + #ifdef X_HAVE_UTF8_STRING + pXCreateIC = NULL; + pXGetICValues = NULL; + #endif + + for (i = 0; i < SDL_TABLESIZE(x11libs); i++) { + if (x11libs[i].lib != NULL) { + SDL_UnloadObject(x11libs[i].lib); + x11libs[i].lib = NULL; + } + } + } + } + #endif +} + +/* returns non-zero if all needed symbols were loaded. */ +int SDL_X11_LoadSymbols(void) +{ + int rc = 1; /* always succeed if not using Dynamic X11 stuff. */ + + #ifdef SDL_VIDEO_DRIVER_X11_DYNAMIC + /* deal with multiple modules (dga, x11, etc) needing these symbols... */ + if (x11_load_refcount++ == 0) { + int i; + int *thismod = NULL; + for (i = 0; i < SDL_TABLESIZE(x11libs); i++) { + if (x11libs[i].libname != NULL) { + x11libs[i].lib = SDL_LoadObject(x11libs[i].libname); + } + } + #define SDL_X11_MODULE(modname) thismod = &SDL_X11_HAVE_##modname; + #define SDL_X11_SYM(rc,fn,params,args,ret) \ + p##fn = (rc(*)params) X11_GetSym(#fn, thismod); + #include "SDL_x11sym.h" + #undef SDL_X11_MODULE + #undef SDL_X11_SYM + + #ifdef X_HAVE_UTF8_STRING + pXCreateIC = (XIC(*)(XIM,...)) X11_GetSym("XCreateIC", + &SDL_X11_HAVE_UTF8); + pXGetICValues = (char * (*)(XIC,...)) X11_GetSym("XGetICValues", + &SDL_X11_HAVE_UTF8); + #endif + + /* + * In case we're built with newer Xlib headers, we need to make sure + * that _XGetRequest() is available, even on older systems. + * Otherwise, various Xlib macros we use will call a NULL pointer. + */ + if (!SDL_X11_HAVE_XGETREQUEST) { + p_XGetRequest = SDL_XGetRequest_workaround; + } + + if (SDL_X11_HAVE_BASEXLIB) { /* all required symbols loaded. */ + SDL_ClearError(); + } else { + SDL_X11_UnloadSymbols(); /* in case something got loaded... */ + rc = 0; + } + } + #else + #if DEBUG_DYNAMIC_X11 + printf("X11: No dynamic X11 support in this build of SDL.\n"); + #endif + #ifdef X_HAVE_UTF8_STRING + pXCreateIC = XCreateIC; + pXGetICValues = XGetICValues; + #endif + #endif + + return rc; +} + +/* end of SDL_x11dyn.c ... */ + diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11dyn.h b/apps/plugins/sdl/src/video/x11/SDL_x11dyn.h new file mode 100644 index 0000000000..c2ff82a727 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11dyn.h @@ -0,0 +1,93 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifndef _SDL_x11dyn_h +#define _SDL_x11dyn_h + +#include +#include +#include + +/* Apparently some X11 systems can't include this multiple times... */ +#ifndef SDL_INCLUDED_XLIBINT_H +#define SDL_INCLUDED_XLIBINT_H 1 +#include +#endif + +#include + +#include "../Xext/extensions/Xext.h" +#include "../Xext/extensions/extutil.h" + +#ifndef NO_SHARED_MEMORY +#include +#include +#include +#endif + +#if SDL_VIDEO_DRIVER_X11_XRANDR +#include +#endif + +/* + * When using the "dynamic X11" functionality, we duplicate all the Xlib + * symbols that would be referenced by SDL inside of SDL itself. + * These duplicated symbols just serve as passthroughs to the functions + * in Xlib, that was dynamically loaded. + * + * This allows us to use Xlib as-is when linking against it directly, but + * also handles all the strange cases where there was code in the Xlib + * headers that may or may not exist or vary on a given platform. + */ +#ifdef __cplusplus +extern "C" { +#endif + +/* evil function signatures... */ +typedef Bool (*SDL_X11_XESetWireToEventRetType)(Display*,XEvent*,xEvent*); +typedef int (*SDL_X11_XSynchronizeRetType)(Display*); +typedef Status (*SDL_X11_XESetEventToWireRetType)(Display*,XEvent*,xEvent*); + +int SDL_X11_LoadSymbols(void); +void SDL_X11_UnloadSymbols(void); + +/* That's really annoying...make this a function pointer no matter what. */ +#ifdef X_HAVE_UTF8_STRING +extern XIC (*pXCreateIC)(XIM,...); +extern char *(*pXGetICValues)(XIC, ...); +#endif + +/* These SDL_X11_HAVE_* flags are here whether you have dynamic X11 or not. */ +#define SDL_X11_MODULE(modname) extern int SDL_X11_HAVE_##modname; +#define SDL_X11_SYM(rc,fn,params,args,ret) +#include "SDL_x11sym.h" +#undef SDL_X11_MODULE +#undef SDL_X11_SYM + + +#ifdef __cplusplus +} +#endif + +#endif /* !defined _SDL_x11dyn_h */ + diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11events.c b/apps/plugins/sdl/src/video/x11/SDL_x11events.c new file mode 100644 index 0000000000..559a001486 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11events.c @@ -0,0 +1,1414 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* Handle the event stream, converting X11 events into SDL events */ + +#include +#include +#include +#include +#ifdef __SVR4 +#include +#endif +#include +#include +#include + +#include "SDL_timer.h" +#include "SDL_syswm.h" +#include "../SDL_sysvideo.h" +#include "../../events/SDL_sysevents.h" +#include "../../events/SDL_events_c.h" +#include "SDL_x11video.h" +#include "SDL_x11dga_c.h" +#include "SDL_x11modes_c.h" +#include "SDL_x11image_c.h" +#include "SDL_x11gamma_c.h" +#include "SDL_x11wm_c.h" +#include "SDL_x11mouse_c.h" +#include "SDL_x11events_c.h" + + +/* Define this if you want to debug X11 events */ +/*#define DEBUG_XEVENTS*/ + +/* The translation tables from an X11 keysym to a SDL keysym */ +static SDLKey ODD_keymap[256]; +static SDLKey MISC_keymap[256]; +SDLKey X11_TranslateKeycode(Display *display, KeyCode kc); + +/* + Pending resize target for ConfigureNotify (so outdated events don't + cause inappropriate resize events) +*/ +int X11_PendingConfigureNotifyWidth = -1; +int X11_PendingConfigureNotifyHeight = -1; + +#ifdef X_HAVE_UTF8_STRING +Uint32 Utf8ToUcs4(const Uint8 *utf8) +{ + Uint32 c; + int i = 1; + int noOctets = 0; + int firstOctetMask = 0; + unsigned char firstOctet = utf8[0]; + if (firstOctet < 0x80) { + /* + Characters in the range: + 00000000 to 01111111 (ASCII Range) + are stored in one octet: + 0xxxxxxx (The same as its ASCII representation) + The least 6 significant bits of the first octet is the most 6 significant nonzero bits + of the UCS4 representation. + */ + noOctets = 1; + firstOctetMask = 0x7F; /* 0(1111111) - The most significant bit is ignored */ + } else if ((firstOctet & 0xE0) /* get the most 3 significant bits by AND'ing with 11100000 */ + == 0xC0 ) { /* see if those 3 bits are 110. If so, the char is in this range */ + /* + Characters in the range: + 00000000 10000000 to 00000111 11111111 + are stored in two octets: + 110xxxxx 10xxxxxx + The least 5 significant bits of the first octet is the most 5 significant nonzero bits + of the UCS4 representation. + */ + noOctets = 2; + firstOctetMask = 0x1F; /* 000(11111) - The most 3 significant bits are ignored */ + } else if ((firstOctet & 0xF0) /* get the most 4 significant bits by AND'ing with 11110000 */ + == 0xE0) { /* see if those 4 bits are 1110. If so, the char is in this range */ + /* + Characters in the range: + 00001000 00000000 to 11111111 11111111 + are stored in three octets: + 1110xxxx 10xxxxxx 10xxxxxx + The least 4 significant bits of the first octet is the most 4 significant nonzero bits + of the UCS4 representation. + */ + noOctets = 3; + firstOctetMask = 0x0F; /* 0000(1111) - The most 4 significant bits are ignored */ + } else if ((firstOctet & 0xF8) /* get the most 5 significant bits by AND'ing with 11111000 */ + == 0xF0) { /* see if those 5 bits are 11110. If so, the char is in this range */ + /* + Characters in the range: + 00000001 00000000 00000000 to 00011111 11111111 11111111 + are stored in four octets: + 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + The least 3 significant bits of the first octet is the most 3 significant nonzero bits + of the UCS4 representation. + */ + noOctets = 4; + firstOctetMask = 0x07; /* 11110(111) - The most 5 significant bits are ignored */ + } else if ((firstOctet & 0xFC) /* get the most 6 significant bits by AND'ing with 11111100 */ + == 0xF8) { /* see if those 6 bits are 111110. If so, the char is in this range */ + /* + Characters in the range: + 00000000 00100000 00000000 00000000 to + 00000011 11111111 11111111 11111111 + are stored in five octets: + 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + The least 2 significant bits of the first octet is the most 2 significant nonzero bits + of the UCS4 representation. + */ + noOctets = 5; + firstOctetMask = 0x03; /* 111110(11) - The most 6 significant bits are ignored */ + } else if ((firstOctet & 0xFE) /* get the most 7 significant bits by AND'ing with 11111110 */ + == 0xFC) { /* see if those 7 bits are 1111110. If so, the char is in this range */ + /* + Characters in the range: + 00000100 00000000 00000000 00000000 to + 01111111 11111111 11111111 11111111 + are stored in six octets: + 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + The least significant bit of the first octet is the most significant nonzero bit + of the UCS4 representation. + */ + noOctets = 6; + firstOctetMask = 0x01; /* 1111110(1) - The most 7 significant bits are ignored */ + } else + return 0; /* The given chunk is not a valid UTF-8 encoded Unicode character */ + + /* + The least noOctets significant bits of the first octet is the most 2 significant nonzero bits + of the UCS4 representation. + The first 6 bits of the UCS4 representation is the least 8-noOctets-1 significant bits of + firstOctet if the character is not ASCII. If so, it's the least 7 significant bits of firstOctet. + This done by AND'ing firstOctet with its mask to trim the bits used for identifying the + number of continuing octets (if any) and leave only the free bits (the x's) + Sample: + 1-octet: 0xxxxxxx & 01111111 = 0xxxxxxx + 2-octets: 110xxxxx & 00011111 = 000xxxxx + */ + c = firstOctet & firstOctetMask; + + /* Now, start filling c.ucs4 with the bits from the continuing octets from utf8. */ + for (i = 1; i < noOctets; i++) { + /* A valid continuing octet is of the form 10xxxxxx */ + if ((utf8[i] & 0xC0) /* get the most 2 significant bits by AND'ing with 11000000 */ + != 0x80) /* see if those 2 bits are 10. If not, the is a malformed sequence. */ + /*The given chunk is a partial sequence at the end of a string that could + begin a valid character */ + return 0; + + /* Make room for the next 6-bits */ + c <<= 6; + + /* + Take only the least 6 significance bits of the current octet (utf8[i]) and fill the created room + of c.ucs4 with them. + This done by AND'ing utf8[i] with 00111111 and the OR'ing the result with c.ucs4. + */ + c |= utf8[i] & 0x3F; + } + return c; +} + +/* Given a UTF-8 encoded string pointed to by utf8 of length length in + bytes, returns the corresponding UTF-16 encoded string in the + buffer pointed to by utf16. The maximum number of UTF-16 encoding + units (i.e., Unit16s) allowed in the buffer is specified in + utf16_max_length. The return value is the number of UTF-16 + encoding units placed in the output buffer pointed to by utf16. + + In case of an error, -1 is returned, leaving some unusable partial + results in the output buffer. + + The caller must estimate the size of utf16 buffer by itself before + calling this function. Insufficient output buffer is considered as + an error, and once an error occured, this function doesn't give any + clue how large the result will be. + + The error cases include following: + + - Invalid byte sequences were in the input UTF-8 bytes. The caller + has no way to know what point in the input buffer was the + errornous byte. + + - The input contained a character (a valid UTF-8 byte sequence) + whose scalar value exceeded the range that UTF-16 can represent + (i.e., characters whose Unicode scalar value above 0x110000). + + - The output buffer has no enough space to hold entire utf16 data. + + Please note: + + - '\0'-termination is not assumed both on the input UTF-8 string + and on the output UTF-16 string; any legal zero byte in the input + UTF-8 string will be converted to a 16-bit zero in output. As a + side effect, the last UTF-16 encoding unit stored in the output + buffer will have a non-zero value if the input UTF-8 was not + '\0'-terminated. + + - UTF-8 aliases are *not* considered as an error. They are + converted to UTF-16. For example, 0xC0 0xA0, 0xE0 0x80 0xA0, + and 0xF0 0x80 0x80 0xA0 are all mapped to a single UTF-16 + encoding unit 0x0020. + + - Three byte UTF-8 sequences whose value corresponds to a surrogate + code or other reserved scalar value are not considered as an + error either. They may cause an invalid UTF-16 data (e.g., those + containing unpaired surrogates). + +*/ + +static int Utf8ToUtf16(const Uint8 *utf8, const int utf8_length, Uint16 *utf16, const int utf16_max_length) { + + /* p moves over the output buffer. max_ptr points to the next to the last slot of the buffer. */ + Uint16 *p = utf16; + Uint16 const *const max_ptr = utf16 + utf16_max_length; + + /* end_of_input points to the last byte of input as opposed to the next to the last byte. */ + Uint8 const *const end_of_input = utf8 + utf8_length - 1; + + while (utf8 <= end_of_input) { + Uint8 const c = *utf8; + if (p >= max_ptr) { + /* No more output space. */ + return -1; + } + if (c < 0x80) { + /* One byte ASCII. */ + *p++ = c; + utf8 += 1; + } else if (c < 0xC0) { + /* Follower byte without preceeding leader bytes. */ + return -1; + } else if (c < 0xE0) { + /* Two byte sequence. We need one follower byte. */ + if (end_of_input - utf8 < 1 || (((utf8[1] ^ 0x80)) & 0xC0)) { + return -1; + } + *p++ = (Uint16)(0xCF80 + (c << 6) + utf8[1]); + utf8 += 2; + } else if (c < 0xF0) { + /* Three byte sequence. We need two follower byte. */ + if (end_of_input - utf8 < 2 || (((utf8[1] ^ 0x80) | (utf8[2] ^ 0x80)) & 0xC0)) { + return -1; + } + *p++ = (Uint16)(0xDF80 + (c << 12) + (utf8[1] << 6) + utf8[2]); + utf8 += 3; + } else if (c < 0xF8) { + int plane; + /* Four byte sequence. We need three follower bytes. */ + if (end_of_input - utf8 < 3 || (((utf8[1] ^ 0x80) | (utf8[2] ^0x80) | (utf8[3] ^ 0x80)) & 0xC0)) { + return -1; + } + plane = (-0xC8 + (c << 2) + (utf8[1] >> 4)); + if (plane == 0) { + /* This four byte sequence is an alias that + corresponds to a Unicode scalar value in BMP. + It fits in an UTF-16 encoding unit. */ + *p++ = (Uint16)(0xDF80 + (utf8[1] << 12) + (utf8[2] << 6) + utf8[3]); + } else if (plane <= 16) { + /* This is a legal four byte sequence that corresponds to a surrogate pair. */ + if (p + 1 >= max_ptr) { + /* No enough space on the output buffer for the pair. */ + return -1; + } + *p++ = (Uint16)(0xE5B8 + (c << 8) + (utf8[1] << 2) + (utf8[2] >> 4)); + *p++ = (Uint16)(0xDB80 + ((utf8[2] & 0x0F) << 6) + utf8[3]); + } else { + /* This four byte sequence is out of UTF-16 code space. */ + return -1; + } + utf8 += 4; + } else { + /* Longer sequence or unused byte. */ + return -1; + } + } + return p - utf16; +} + +#endif + +/* Check to see if this is a repeated key. + (idea shamelessly lifted from GII -- thanks guys! :) + */ +static int X11_KeyRepeat(Display *display, XEvent *event) +{ + XEvent peekevent; + int repeated; + + repeated = 0; + if ( XPending(display) ) { + XPeekEvent(display, &peekevent); + if ( (peekevent.type == KeyPress) && + (peekevent.xkey.keycode == event->xkey.keycode) && + ((peekevent.xkey.time-event->xkey.time) < 2) ) { + repeated = 1; + XNextEvent(display, &peekevent); + } + } + return(repeated); +} + +/* Note: The X server buffers and accumulates mouse motion events, so + the motion event generated by the warp may not appear exactly as we + expect it to. We work around this (and improve performance) by only + warping the pointer when it reaches the edge, and then wait for it. +*/ +#define MOUSE_FUDGE_FACTOR 8 + +static __inline__ int X11_WarpedMotion(_THIS, XEvent *xevent) +{ + int w, h, i; + int deltax, deltay; + int posted; + + w = SDL_VideoSurface->w; + h = SDL_VideoSurface->h; + deltax = xevent->xmotion.x - mouse_last.x; + deltay = xevent->xmotion.y - mouse_last.y; +#ifdef DEBUG_MOTION + printf("Warped mouse motion: %d,%d\n", deltax, deltay); +#endif + mouse_last.x = xevent->xmotion.x; + mouse_last.y = xevent->xmotion.y; + posted = SDL_PrivateMouseMotion(0, 1, deltax, deltay); + + if ( (xevent->xmotion.x < MOUSE_FUDGE_FACTOR) || + (xevent->xmotion.x > (w-MOUSE_FUDGE_FACTOR)) || + (xevent->xmotion.y < MOUSE_FUDGE_FACTOR) || + (xevent->xmotion.y > (h-MOUSE_FUDGE_FACTOR)) ) { + /* Get the events that have accumulated */ + while ( XCheckTypedEvent(SDL_Display, MotionNotify, xevent) ) { + deltax = xevent->xmotion.x - mouse_last.x; + deltay = xevent->xmotion.y - mouse_last.y; +#ifdef DEBUG_MOTION + printf("Extra mouse motion: %d,%d\n", deltax, deltay); +#endif + mouse_last.x = xevent->xmotion.x; + mouse_last.y = xevent->xmotion.y; + posted += SDL_PrivateMouseMotion(0, 1, deltax, deltay); + } + mouse_last.x = w/2; + mouse_last.y = h/2; + XWarpPointer(SDL_Display, None, SDL_Window, 0, 0, 0, 0, + mouse_last.x, mouse_last.y); + for ( i=0; i<10; ++i ) { + XMaskEvent(SDL_Display, PointerMotionMask, xevent); + if ( (xevent->xmotion.x > + (mouse_last.x-MOUSE_FUDGE_FACTOR)) && + (xevent->xmotion.x < + (mouse_last.x+MOUSE_FUDGE_FACTOR)) && + (xevent->xmotion.y > + (mouse_last.y-MOUSE_FUDGE_FACTOR)) && + (xevent->xmotion.y < + (mouse_last.y+MOUSE_FUDGE_FACTOR)) ) { + break; + } +#ifdef DEBUG_XEVENTS + printf("Lost mouse motion: %d,%d\n", xevent->xmotion.x, xevent->xmotion.y); +#endif + } +#ifdef DEBUG_XEVENTS + if ( i == 10 ) { + printf("Warning: didn't detect mouse warp motion\n"); + } +#endif + } + return(posted); +} + +static int X11_DispatchEvent(_THIS) +{ + int posted; + XEvent xevent; + + SDL_memset(&xevent, '\0', sizeof (XEvent)); /* valgrind fix. --ryan. */ + XNextEvent(SDL_Display, &xevent); + + /* Discard KeyRelease and KeyPress events generated by auto-repeat. + We need to do it before passing event to XFilterEvent. Otherwise, + KeyRelease aware IMs are confused... */ + if ( xevent.type == KeyRelease + && X11_KeyRepeat(SDL_Display, &xevent) ) { + return 0; + } + +#ifdef X_HAVE_UTF8_STRING + /* If we are translating with IM, we need to pass all events + to XFilterEvent, and discard those filtered events immediately. */ + if ( SDL_TranslateUNICODE + && SDL_IM != NULL + && XFilterEvent(&xevent, None) ) { + return 0; + } +#endif + + posted = 0; + switch (xevent.type) { + + /* Gaining mouse coverage? */ + case EnterNotify: { +#ifdef DEBUG_XEVENTS +printf("EnterNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y); +if ( xevent.xcrossing.mode == NotifyGrab ) +printf("Mode: NotifyGrab\n"); +if ( xevent.xcrossing.mode == NotifyUngrab ) +printf("Mode: NotifyUngrab\n"); +#endif + if ( this->input_grab == SDL_GRAB_OFF ) { + posted = SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS); + } + posted = SDL_PrivateMouseMotion(0, 0, + xevent.xcrossing.x, + xevent.xcrossing.y); + } + break; + + /* Losing mouse coverage? */ + case LeaveNotify: { +#ifdef DEBUG_XEVENTS +printf("LeaveNotify! (%d,%d)\n", xevent.xcrossing.x, xevent.xcrossing.y); +if ( xevent.xcrossing.mode == NotifyGrab ) +printf("Mode: NotifyGrab\n"); +if ( xevent.xcrossing.mode == NotifyUngrab ) +printf("Mode: NotifyUngrab\n"); +#endif + if ( (xevent.xcrossing.mode != NotifyGrab) && + (xevent.xcrossing.mode != NotifyUngrab) && + (xevent.xcrossing.detail != NotifyInferior) ) { + if ( this->input_grab == SDL_GRAB_OFF ) { + posted = SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS); + } else { + posted = SDL_PrivateMouseMotion(0, 0, + xevent.xcrossing.x, + xevent.xcrossing.y); + } + } + } + break; + + /* Gaining input focus? */ + case FocusIn: { +#ifdef DEBUG_XEVENTS +printf("FocusIn!\n"); +#endif + posted = SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS); + +#ifdef X_HAVE_UTF8_STRING + if ( SDL_IC != NULL ) { + XSetICFocus(SDL_IC); + } +#endif + /* Queue entry into fullscreen mode */ + switch_waiting = 0x01 | SDL_FULLSCREEN; + switch_time = SDL_GetTicks() + 1500; + } + break; + + /* Losing input focus? */ + case FocusOut: { +#ifdef DEBUG_XEVENTS +printf("FocusOut!\n"); +#endif + posted = SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS); + +#ifdef X_HAVE_UTF8_STRING + if ( SDL_IC != NULL ) { + XUnsetICFocus(SDL_IC); + } +#endif + /* Queue leaving fullscreen mode */ + switch_waiting = 0x01; + switch_time = SDL_GetTicks() + 200; + } + break; + +#ifdef X_HAVE_UTF8_STRING + /* Some IM requires MappingNotify to be passed to + XRefreshKeyboardMapping by the app. */ + case MappingNotify: { + XRefreshKeyboardMapping(&xevent.xmapping); + } + break; +#endif /* X_HAVE_UTF8_STRING */ + + /* Generated upon EnterWindow and FocusIn */ + case KeymapNotify: { +#ifdef DEBUG_XEVENTS +printf("KeymapNotify!\n"); +#endif + X11_SetKeyboardState(SDL_Display, xevent.xkeymap.key_vector); + } + break; + + /* Mouse motion? */ + case MotionNotify: { + if ( SDL_VideoSurface ) { + if ( mouse_relative ) { + if ( using_dga & DGA_MOUSE ) { +#ifdef DEBUG_MOTION + printf("DGA motion: %d,%d\n", xevent.xmotion.x_root, xevent.xmotion.y_root); +#endif + posted = SDL_PrivateMouseMotion(0, 1, + xevent.xmotion.x_root, + xevent.xmotion.y_root); + } else { + posted = X11_WarpedMotion(this,&xevent); + } + } else { +#ifdef DEBUG_MOTION + printf("X11 motion: %d,%d\n", xevent.xmotion.x, xevent.xmotion.y); +#endif + posted = SDL_PrivateMouseMotion(0, 0, + xevent.xmotion.x, + xevent.xmotion.y); + } + } + } + break; + + /* Mouse button press? */ + case ButtonPress: { + posted = SDL_PrivateMouseButton(SDL_PRESSED, + xevent.xbutton.button, 0, 0); + } + break; + + /* Mouse button release? */ + case ButtonRelease: { + posted = SDL_PrivateMouseButton(SDL_RELEASED, + xevent.xbutton.button, 0, 0); + } + break; + + /* Key press? */ + case KeyPress: { + SDL_keysym keysym; + KeyCode keycode = xevent.xkey.keycode; + +#ifdef DEBUG_XEVENTS +printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode); +#endif + /* If we're not doing translation, we're done! */ + if ( !SDL_TranslateUNICODE ) { + /* Get the translated SDL virtual keysym and put it on the queue.*/ + keysym.scancode = keycode; + keysym.sym = X11_TranslateKeycode(SDL_Display, keycode); + keysym.mod = KMOD_NONE; + keysym.unicode = 0; + posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym); + break; + } + + /* Look up the translated value for the key event */ +#ifdef X_HAVE_UTF8_STRING + if ( SDL_IC != NULL ) { + Status status; + KeySym xkeysym; + int i; + /* A UTF-8 character can be at most 6 bytes */ + /* ... It's true, but Xutf8LookupString can + return more than one characters. Moreover, + the spec. put no upper bound, so we should + be ready for longer strings. */ + char keybuf[32]; + char *keydata = keybuf; + int count; + Uint16 utf16buf[32]; + Uint16 *utf16data = utf16buf; + int utf16size; + int utf16length; + + count = Xutf8LookupString(SDL_IC, &xevent.xkey, keydata, sizeof(keybuf), &xkeysym, &status); + if (XBufferOverflow == status) { + /* The IM has just generated somewhat long + string. We need a longer buffer in this + case. */ + keydata = SDL_malloc(count); + if ( keydata == NULL ) { + SDL_OutOfMemory(); + break; + } + count = Xutf8LookupString(SDL_IC, &xevent.xkey, keydata, count, &xkeysym, &status); + } + + switch (status) { + + case XBufferOverflow: { + /* Oops! We have allocated the bytes as + requested by Xutf8LookupString, so the + length of the buffer must be + sufficient. This case should never + happen! */ + SDL_SetError("Xutf8LookupString indicated a double buffer overflow!"); + break; + } + + case XLookupChars: + case XLookupBoth: { + if (0 == count) { + break; + } + + /* We got a converted string from IM. Make + sure to deliver all characters to the + application as SDL events. Note that + an SDL event can only carry one UTF-16 + encoding unit, and a surrogate pair is + delivered as two SDL events. I guess + this behaviour is probably _imported_ + from Windows or MacOS. To do so, we need + to convert the UTF-8 data into UTF-16 + data (not UCS4/UTF-32!). We need an + estimate of the number of UTF-16 encoding + units here. The worst case is pure ASCII + string. Assume so. */ + /* In 1.3 SDL may have a text event instead, that + carries the whole UTF-8 string with it. */ + utf16size = count * sizeof(Uint16); + if (utf16size > sizeof(utf16buf)) { + utf16data = (Uint16 *) SDL_malloc(utf16size); + if (utf16data == NULL) { + SDL_OutOfMemory(); + break; + } + } + utf16length = Utf8ToUtf16((Uint8 *)keydata, count, utf16data, utf16size); + if (utf16length < 0) { + /* The keydata contained an invalid byte + sequence. It should be a bug of the IM + or Xlib... */ + SDL_SetError("Oops! Xutf8LookupString returned an invalid UTF-8 sequence!"); + break; + } + + /* Deliver all UTF-16 encoding units. At + this moment, SDL event queue has a + fixed size (128 events), and an SDL + event can hold just one UTF-16 encoding + unit. So, if we receive more than 128 + UTF-16 encoding units from a commit, + exceeded characters will be lost. */ + for (i = 0; i < utf16length - 1; i++) { + keysym.scancode = 0; + keysym.sym = SDLK_UNKNOWN; + keysym.mod = KMOD_NONE; + keysym.unicode = utf16data[i]; + posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym); + } + /* The keysym for the last character carries the + scancode and symbol that corresponds to the X11 + keycode. */ + if (utf16length > 0) { + keysym.scancode = keycode; + keysym.sym = (keycode ? X11_TranslateKeycode(SDL_Display, keycode) : 0); + keysym.mod = KMOD_NONE; + keysym.unicode = utf16data[utf16length - 1]; + posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym); + } + break; + } + + case XLookupKeySym: { + /* I'm not sure whether it is possible that + a zero keycode makes XLookupKeySym + status. What I'm sure is that a + combination of a zero scan code and a non + zero sym makes SDL_PrivateKeyboard + strange state... So, just discard it. + If this doesn't work, I'm receiving bug + reports, and I can know under what + condition this case happens. */ + if (keycode) { + keysym.scancode = keycode; + keysym.sym = X11_TranslateKeycode(SDL_Display, keycode); + keysym.mod = KMOD_NONE; + keysym.unicode = 0; + posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym); + } + break; + } + + case XLookupNone: { + /* IM has eaten the event. */ + break; + } + + default: + /* An unknown status from Xutf8LookupString. */ + SDL_SetError("Oops! Xutf8LookupStringreturned an unknown status"); + } + + /* Release dynamic buffers if allocated. */ + if (keydata != NULL && keybuf != keydata) { + SDL_free(keydata); + } + if (utf16data != NULL && utf16buf != utf16data) { + SDL_free(utf16data); + } + } + else +#endif + { + static XComposeStatus state; + char keybuf[32]; + + keysym.scancode = keycode; + keysym.sym = X11_TranslateKeycode(SDL_Display, keycode); + keysym.mod = KMOD_NONE; + keysym.unicode = 0; + if ( XLookupString(&xevent.xkey, + keybuf, sizeof(keybuf), + NULL, &state) ) { + /* + * FIXME: XLookupString() may yield more than one + * character, so we need a mechanism to allow for + * this (perhaps null keypress events with a + * unicode value) + */ + keysym.unicode = (Uint8)keybuf[0]; + } + + posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym); + } + } + break; + + /* Key release? */ + case KeyRelease: { + SDL_keysym keysym; + KeyCode keycode = xevent.xkey.keycode; + + if (keycode == 0) { + /* There should be no KeyRelease for keycode == 0, + since it is a notification from IM but a real + keystroke. */ + /* We need to emit some diagnostic message here. */ + break; + } + +#ifdef DEBUG_XEVENTS +printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode); +#endif + + /* Get the translated SDL virtual keysym */ + keysym.scancode = keycode; + keysym.sym = X11_TranslateKeycode(SDL_Display, keycode); + keysym.mod = KMOD_NONE; + keysym.unicode = 0; + + posted = SDL_PrivateKeyboard(SDL_RELEASED, &keysym); + } + break; + + /* Have we been iconified? */ + case UnmapNotify: { +#ifdef DEBUG_XEVENTS +printf("UnmapNotify!\n"); +#endif + /* If we're active, make ourselves inactive */ + if ( SDL_GetAppState() & SDL_APPACTIVE ) { + /* Swap out the gamma before we go inactive */ + X11_SwapVidModeGamma(this); + + /* Send an internal deactivate event */ + posted = SDL_PrivateAppActive(0, + SDL_APPACTIVE|SDL_APPINPUTFOCUS); + } + } + break; + + /* Have we been restored? */ + case MapNotify: { +#ifdef DEBUG_XEVENTS +printf("MapNotify!\n"); +#endif + /* If we're not active, make ourselves active */ + if ( !(SDL_GetAppState() & SDL_APPACTIVE) ) { + /* Send an internal activate event */ + posted = SDL_PrivateAppActive(1, SDL_APPACTIVE); + + /* Now that we're active, swap the gamma back */ + X11_SwapVidModeGamma(this); + } + + if ( SDL_VideoSurface && + (SDL_VideoSurface->flags & SDL_FULLSCREEN) ) { + X11_EnterFullScreen(this); + } else { + X11_GrabInputNoLock(this, this->input_grab); + } + X11_CheckMouseModeNoLock(this); + + if ( SDL_VideoSurface ) { + X11_RefreshDisplay(this); + } + } + break; + + /* Have we been resized or moved? */ + case ConfigureNotify: { +#ifdef DEBUG_XEVENTS +printf("ConfigureNotify! (resize: %dx%d)\n", xevent.xconfigure.width, xevent.xconfigure.height); +#endif + if ((X11_PendingConfigureNotifyWidth != -1) && + (X11_PendingConfigureNotifyHeight != -1)) { + if ((xevent.xconfigure.width != X11_PendingConfigureNotifyWidth) && + (xevent.xconfigure.height != X11_PendingConfigureNotifyHeight)) { + /* Event is from before the resize, so ignore. */ + break; + } + X11_PendingConfigureNotifyWidth = -1; + X11_PendingConfigureNotifyHeight = -1; + } + if ( SDL_VideoSurface ) { + if ((xevent.xconfigure.width != SDL_VideoSurface->w) || + (xevent.xconfigure.height != SDL_VideoSurface->h)) { + /* FIXME: Find a better fix for the bug with KDE 1.2 */ + if ( ! ((xevent.xconfigure.width == 32) && + (xevent.xconfigure.height == 32)) ) { + SDL_PrivateResize(xevent.xconfigure.width, + xevent.xconfigure.height); + } + } else { + /* OpenGL windows need to know about the change */ + if ( SDL_VideoSurface->flags & SDL_OPENGL ) { + SDL_PrivateExpose(); + } + } + } + } + break; + + /* Have we been requested to quit (or another client message?) */ + case ClientMessage: { + if ( (xevent.xclient.format == 32) && + (xevent.xclient.data.l[0] == WM_DELETE_WINDOW) ) + { + posted = SDL_PrivateQuit(); + } else + if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) { + SDL_SysWMmsg wmmsg; + + SDL_VERSION(&wmmsg.version); + wmmsg.subsystem = SDL_SYSWM_X11; + wmmsg.event.xevent = xevent; + posted = SDL_PrivateSysWMEvent(&wmmsg); + } + } + break; + + /* Do we need to refresh ourselves? */ + case Expose: { +#ifdef DEBUG_XEVENTS +printf("Expose (count = %d)\n", xevent.xexpose.count); +#endif + if ( SDL_VideoSurface && (xevent.xexpose.count == 0) ) { + X11_RefreshDisplay(this); + } + } + break; + + default: { +#ifdef DEBUG_XEVENTS +printf("Unhandled event %d\n", xevent.type); +#endif + /* Only post the event if we're watching for it */ + if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) { + SDL_SysWMmsg wmmsg; + + SDL_VERSION(&wmmsg.version); + wmmsg.subsystem = SDL_SYSWM_X11; + wmmsg.event.xevent = xevent; + posted = SDL_PrivateSysWMEvent(&wmmsg); + } + } + break; + } + return(posted); +} + +/* Ack! XPending() actually performs a blocking read if no events available */ +int X11_Pending(Display *display) +{ + /* Flush the display connection and look to see if events are queued */ + XFlush(display); + if ( XEventsQueued(display, QueuedAlready) ) { + return(1); + } + + /* More drastic measures are required -- see if X is ready to talk */ + { + static struct timeval zero_time; /* static == 0 */ + int x11_fd; + fd_set fdset; + + x11_fd = ConnectionNumber(display); + FD_ZERO(&fdset); + FD_SET(x11_fd, &fdset); + if ( select(x11_fd+1, &fdset, NULL, NULL, &zero_time) == 1 ) { + return(XPending(display)); + } + } + + /* Oh well, nothing is ready .. */ + return(0); +} + +void X11_PumpEvents(_THIS) +{ + int pending; + + /* Update activity every five seconds to prevent screensaver. --ryan. */ + if (!allow_screensaver) { + static Uint32 screensaverTicks; + Uint32 nowTicks = SDL_GetTicks(); + if ((nowTicks - screensaverTicks) > 5000) { + XResetScreenSaver(SDL_Display); + screensaverTicks = nowTicks; + } + } + + /* Keep processing pending events */ + pending = 0; + while ( X11_Pending(SDL_Display) ) { + X11_DispatchEvent(this); + ++pending; + } + if ( switch_waiting ) { + Uint32 now; + + now = SDL_GetTicks(); + if ( pending || !SDL_VideoSurface ) { + /* Try again later... */ + if ( switch_waiting & SDL_FULLSCREEN ) { + switch_time = now + 1500; + } else { + switch_time = now + 200; + } + } else if ( (int)(switch_time-now) <= 0 ) { + Uint32 go_fullscreen; + + go_fullscreen = switch_waiting & SDL_FULLSCREEN; + switch_waiting = 0; + if ( SDL_VideoSurface->flags & SDL_FULLSCREEN ) { + if ( go_fullscreen ) { + X11_EnterFullScreen(this); + } else { + X11_LeaveFullScreen(this); + } + } + /* Handle focus in/out when grabbed */ + if ( go_fullscreen ) { + X11_GrabInputNoLock(this, this->input_grab); + } else { + X11_GrabInputNoLock(this, SDL_GRAB_OFF); + } + X11_CheckMouseModeNoLock(this); + } + } +} + +void X11_InitKeymap(void) +{ + int i; + + /* Odd keys used in international keyboards */ + for ( i=0; i 0x%.4x\n", kc, xsym); +#endif + key = SDLK_UNKNOWN; + if ( xsym ) { + switch (xsym>>8) { + case 0x1005FF: +#ifdef SunXK_F36 + if ( xsym == SunXK_F36 ) + key = SDLK_F11; +#endif +#ifdef SunXK_F37 + if ( xsym == SunXK_F37 ) + key = SDLK_F12; +#endif + break; + case 0x00: /* Latin 1 */ + key = (SDLKey)(xsym & 0xFF); + break; + case 0x01: /* Latin 2 */ + case 0x02: /* Latin 3 */ + case 0x03: /* Latin 4 */ + case 0x04: /* Katakana */ + case 0x05: /* Arabic */ + case 0x06: /* Cyrillic */ + case 0x07: /* Greek */ + case 0x08: /* Technical */ + case 0x0A: /* Publishing */ + case 0x0C: /* Hebrew */ + case 0x0D: /* Thai */ + /* These are wrong, but it's better than nothing */ + key = (SDLKey)(xsym & 0xFF); + break; + case 0xFE: + key = ODD_keymap[xsym&0xFF]; + break; + case 0xFF: + key = MISC_keymap[xsym&0xFF]; + break; + default: + /* + fprintf(stderr, "X11: Unhandled xsym, sym = 0x%04x\n", + (unsigned int)xsym); + */ + break; + } + } else { + /* X11 doesn't know how to translate the key! */ + switch (kc) { + /* Caution: + These keycodes are from the Microsoft Keyboard + */ + case 115: + key = SDLK_LSUPER; + break; + case 116: + key = SDLK_RSUPER; + break; + case 117: + key = SDLK_MENU; + break; + default: + /* + * no point in an error message; happens for + * several keys when we get a keymap notify + */ + break; + } + } + return key; +} + +/* X11 modifier masks for various keys */ +static unsigned meta_l_mask, meta_r_mask, alt_l_mask, alt_r_mask; +static unsigned num_mask, mode_switch_mask; + +static void get_modifier_masks(Display *display) +{ + static unsigned got_masks; + int i, j; + XModifierKeymap *xmods; + unsigned n; + + if(got_masks) + return; + + xmods = XGetModifierMapping(display); + n = xmods->max_keypermod; + for(i = 3; i < 8; i++) { + for(j = 0; j < n; j++) { + KeyCode kc = xmods->modifiermap[i * n + j]; + KeySym ks = XKeycodeToKeysym(display, kc, 0); + unsigned mask = 1 << i; + switch(ks) { + case XK_Num_Lock: + num_mask = mask; break; + case XK_Alt_L: + alt_l_mask = mask; break; + case XK_Alt_R: + alt_r_mask = mask; break; + case XK_Meta_L: + meta_l_mask = mask; break; + case XK_Meta_R: + meta_r_mask = mask; break; + case XK_Mode_switch: + mode_switch_mask = mask; break; + } + } + } + XFreeModifiermap(xmods); + got_masks = 1; +} + + +/* + * This function is semi-official; it is not officially exported and should + * not be considered part of the SDL API, but may be used by client code + * that *really* needs it (including legacy code). + * It is slow, though, and should be avoided if possible. + * + * Note that it isn't completely accurate either; in particular, multi-key + * sequences (dead accents, compose key sequences) will not work since the + * state has been irrevocably lost. + */ +Uint16 X11_KeyToUnicode(SDLKey keysym, SDLMod modifiers) +{ + struct SDL_VideoDevice *this = current_video; + char keybuf[32]; + int i; + KeySym xsym = 0; + XKeyEvent xkey; + Uint16 unicode; + + if ( !this || !SDL_Display ) { + return 0; + } + + SDL_memset(&xkey, 0, sizeof(xkey)); + xkey.display = SDL_Display; + + xsym = keysym; /* last resort if not found */ + for (i = 0; i < 256; ++i) { + if ( MISC_keymap[i] == keysym ) { + xsym = 0xFF00 | i; + break; + } else if ( ODD_keymap[i] == keysym ) { + xsym = 0xFE00 | i; + break; + } + } + + xkey.keycode = XKeysymToKeycode(xkey.display, xsym); + + get_modifier_masks(SDL_Display); + if(modifiers & KMOD_SHIFT) + xkey.state |= ShiftMask; + if(modifiers & KMOD_CAPS) + xkey.state |= LockMask; + if(modifiers & KMOD_CTRL) + xkey.state |= ControlMask; + if(modifiers & KMOD_MODE) + xkey.state |= mode_switch_mask; + if(modifiers & KMOD_LALT) + xkey.state |= alt_l_mask; + if(modifiers & KMOD_RALT) + xkey.state |= alt_r_mask; + if(modifiers & KMOD_LMETA) + xkey.state |= meta_l_mask; + if(modifiers & KMOD_RMETA) + xkey.state |= meta_r_mask; + if(modifiers & KMOD_NUM) + xkey.state |= num_mask; + + unicode = 0; + if ( XLookupString(&xkey, keybuf, sizeof(keybuf), NULL, NULL) ) + unicode = (unsigned char)keybuf[0]; + return(unicode); +} + + +/* + * Called when focus is regained, to read the keyboard state and generate + * synthetic keypress/release events. + * key_vec is a bit vector of keycodes (256 bits) + */ +void X11_SetKeyboardState(Display *display, const char *key_vec) +{ + char keys_return[32]; + int i; + Uint8 *kstate = SDL_GetKeyState(NULL); + SDLMod modstate; + Window junk_window; + int x, y; + unsigned int mask; + + /* The first time the window is mapped, we initialize key state */ + if ( ! key_vec ) { + XQueryKeymap(display, keys_return); + key_vec = keys_return; + } + + /* Get the keyboard modifier state */ + modstate = 0; + get_modifier_masks(display); + if ( XQueryPointer(display, DefaultRootWindow(display), + &junk_window, &junk_window, &x, &y, &x, &y, &mask) ) { + if ( mask & LockMask ) { + modstate |= KMOD_CAPS; + } + if ( mask & mode_switch_mask ) { + modstate |= KMOD_MODE; + } + if ( mask & num_mask ) { + modstate |= KMOD_NUM; + } + } + + /* Zero the new keyboard state and generate it */ + SDL_memset(kstate, 0, SDLK_LAST); + /* + * An obvious optimisation is to check entire longwords at a time in + * both loops, but we can't be sure the arrays are aligned so it's not + * worth the extra complexity + */ + for ( i = 0; i < 32; i++ ) { + int j; + if ( !key_vec[i] ) + continue; + for ( j = 0; j < 8; j++ ) { + if ( key_vec[i] & (1 << j) ) { + SDLKey key; + KeyCode kc = (i << 3 | j); + key = X11_TranslateKeycode(display, kc); + if ( key == SDLK_UNKNOWN ) { + continue; + } + kstate[key] = SDL_PRESSED; + switch (key) { + case SDLK_LSHIFT: + modstate |= KMOD_LSHIFT; + break; + case SDLK_RSHIFT: + modstate |= KMOD_RSHIFT; + break; + case SDLK_LCTRL: + modstate |= KMOD_LCTRL; + break; + case SDLK_RCTRL: + modstate |= KMOD_RCTRL; + break; + case SDLK_LALT: + modstate |= KMOD_LALT; + break; + case SDLK_RALT: + modstate |= KMOD_RALT; + break; + case SDLK_LMETA: + modstate |= KMOD_LMETA; + break; + case SDLK_RMETA: + modstate |= KMOD_RMETA; + break; + default: + break; + } + } + } + } + + /* Hack - set toggle key state */ + if ( modstate & KMOD_CAPS ) { + kstate[SDLK_CAPSLOCK] = SDL_PRESSED; + } else { + kstate[SDLK_CAPSLOCK] = SDL_RELEASED; + } + if ( modstate & KMOD_NUM ) { + kstate[SDLK_NUMLOCK] = SDL_PRESSED; + } else { + kstate[SDLK_NUMLOCK] = SDL_RELEASED; + } + + /* Set the final modifier state */ + SDL_SetModState(modstate); +} + +void X11_InitOSKeymap(_THIS) +{ + X11_InitKeymap(); +} + diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11events_c.h b/apps/plugins/sdl/src/video/x11/SDL_x11events_c.h new file mode 100644 index 0000000000..fe26d9c263 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11events_c.h @@ -0,0 +1,34 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#include "SDL_x11video.h" + +/* Functions to be exported */ +extern void X11_InitOSKeymap(_THIS); +extern void X11_PumpEvents(_THIS); +extern void X11_SetKeyboardState(Display *display, const char *key_vec); + +/* Variables to be exported */ +extern int X11_PendingConfigureNotifyWidth; +extern int X11_PendingConfigureNotifyHeight; + diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11gamma.c b/apps/plugins/sdl/src/video/x11/SDL_x11gamma.c new file mode 100644 index 0000000000..c6afbda11c --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11gamma.c @@ -0,0 +1,142 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#include "SDL.h" +#include "SDL_events.h" +#include "../../events/SDL_events_c.h" +#include "SDL_x11video.h" + +/* From the X server sources... */ +#define MAX_GAMMA 10.0 +#define MIN_GAMMA (1.0/MAX_GAMMA) + +static int X11_SetGammaNoLock(_THIS, float red, float green, float blue) +{ +#if SDL_VIDEO_DRIVER_X11_VIDMODE + if (use_vidmode >= 200) { + SDL_NAME(XF86VidModeGamma) gamma; + Bool succeeded; + + /* Clamp the gamma values */ + if ( red < MIN_GAMMA ) { + gamma.red = MIN_GAMMA; + } else + if ( red > MAX_GAMMA ) { + gamma.red = MAX_GAMMA; + } else { + gamma.red = red; + } + if ( green < MIN_GAMMA ) { + gamma.green = MIN_GAMMA; + } else + if ( green > MAX_GAMMA ) { + gamma.green = MAX_GAMMA; + } else { + gamma.green = green; + } + if ( blue < MIN_GAMMA ) { + gamma.blue = MIN_GAMMA; + } else + if ( blue > MAX_GAMMA ) { + gamma.blue = MAX_GAMMA; + } else { + gamma.blue = blue; + } + if ( SDL_GetAppState() & SDL_APPACTIVE ) { + succeeded = SDL_NAME(XF86VidModeSetGamma)(SDL_Display, SDL_Screen, &gamma); + XSync(SDL_Display, False); + } else { + gamma_saved[0] = gamma.red; + gamma_saved[1] = gamma.green; + gamma_saved[2] = gamma.blue; + succeeded = True; + } + if ( succeeded ) { + ++gamma_changed; + } + return succeeded ? 0 : -1; + } +#endif + SDL_SetError("Gamma correction not supported"); + return -1; +} +int X11_SetVidModeGamma(_THIS, float red, float green, float blue) +{ + int result; + + SDL_Lock_EventThread(); + result = X11_SetGammaNoLock(this, red, green, blue); + SDL_Unlock_EventThread(); + + return(result); +} + +static int X11_GetGammaNoLock(_THIS, float *red, float *green, float *blue) +{ +#if SDL_VIDEO_DRIVER_X11_VIDMODE + if (use_vidmode >= 200) { + SDL_NAME(XF86VidModeGamma) gamma; + if (SDL_NAME(XF86VidModeGetGamma)(SDL_Display, SDL_Screen, &gamma)) { + *red = gamma.red; + *green = gamma.green; + *blue = gamma.blue; + return 0; + } + return -1; + } +#endif + return -1; +} +int X11_GetVidModeGamma(_THIS, float *red, float *green, float *blue) +{ + int result; + + SDL_Lock_EventThread(); + result = X11_GetGammaNoLock(this, red, green, blue); + SDL_Unlock_EventThread(); + + return(result); +} + +void X11_SaveVidModeGamma(_THIS) +{ + /* Try to save the current gamma, otherwise disable gamma control */ + if ( X11_GetGammaNoLock(this, + &gamma_saved[0], &gamma_saved[1], &gamma_saved[2]) < 0 ) { + this->SetGamma = 0; + this->GetGamma = 0; + } + gamma_changed = 0; +} +void X11_SwapVidModeGamma(_THIS) +{ + float new_gamma[3]; + + if ( gamma_changed ) { + new_gamma[0] = gamma_saved[0]; + new_gamma[1] = gamma_saved[1]; + new_gamma[2] = gamma_saved[2]; + X11_GetGammaNoLock(this, &gamma_saved[0], &gamma_saved[1], &gamma_saved[2]); + X11_SetGammaNoLock(this, new_gamma[0], new_gamma[1], new_gamma[2]); + } +} diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11gamma_c.h b/apps/plugins/sdl/src/video/x11/SDL_x11gamma_c.h new file mode 100644 index 0000000000..c46350fd22 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11gamma_c.h @@ -0,0 +1,32 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifndef _SDL_x11gamma_h +#define _SDL_x11gamma_h + +extern int X11_SetVidModeGamma(_THIS, float red, float green, float blue); +extern int X11_GetVidModeGamma(_THIS, float *red, float *green, float *blue); +extern void X11_SaveVidModeGamma(_THIS); +extern void X11_SwapVidModeGamma(_THIS); + +#endif diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11gl.c b/apps/plugins/sdl/src/video/x11/SDL_x11gl.c new file mode 100644 index 0000000000..aa5297b674 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11gl.c @@ -0,0 +1,577 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#include "SDL_x11video.h" +#include "../../events/SDL_events_c.h" +#include "SDL_x11dga_c.h" +#include "SDL_x11gl_c.h" + +#if defined(__IRIX__) +/* IRIX doesn't have a GL library versioning system */ +#define DEFAULT_OPENGL "libGL.so" +#elif defined(__MACOSX__) +#define DEFAULT_OPENGL "/usr/X11R6/lib/libGL.1.dylib" +#elif defined(__QNXNTO__) +#define DEFAULT_OPENGL "libGL.so.3" +#elif defined(__OpenBSD__) +#define DEFAULT_OPENGL "libGL.so.4.0" +#else +#define DEFAULT_OPENGL "libGL.so.1" +#endif + +#ifndef GLX_ARB_multisample +#define GLX_ARB_multisample +#define GLX_SAMPLE_BUFFERS_ARB 100000 +#define GLX_SAMPLES_ARB 100001 +#endif + +/* GLX_EXT_visual_rating stuff that might not be in the system headers... */ +#ifndef GLX_VISUAL_CAVEAT_EXT +#define GLX_VISUAL_CAVEAT_EXT 0x20 +#endif +#ifndef GLX_NONE_EXT +#define GLX_NONE_EXT 0x8000 +#endif +#ifndef GLX_SLOW_VISUAL_EXT +#define GLX_SLOW_VISUAL_EXT 0x8001 +#endif +#ifndef GLX_NON_CONFORMANT_VISUAL_EXT +#define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D +#endif + + +#if SDL_VIDEO_OPENGL_GLX +static int glXExtensionSupported(_THIS, const char *extension) +{ + const char *extensions; + const char *start; + const char *where, *terminator; + + /* Extension names should not have spaces. */ + where = SDL_strchr(extension, ' '); + if ( where || *extension == '\0' ) { + return 0; + } + + extensions = this->gl_data->glXQueryExtensionsString(GFX_Display,SDL_Screen); + /* It takes a bit of care to be fool-proof about parsing the + * OpenGL extensions string. Don't be fooled by sub-strings, etc. + */ + + /* http://bugs.debian.org/537487 */ + if (extensions == NULL) { + return 0; + } + + start = extensions; + + for (;;) { + where = SDL_strstr(start, extension); + if (!where) break; + + terminator = where + strlen(extension); + if (where == start || *(where - 1) == ' ') + if (*terminator == ' ' || *terminator == '\0') return 1; + + start = terminator; + } + return 0; +} +#endif /* SDL_VIDEO_OPENGL_GLX */ + +XVisualInfo *X11_GL_GetVisual(_THIS) +{ +#if SDL_VIDEO_OPENGL_GLX + /* 64 seems nice. */ + int attribs[64]; + int i; + + /* load the gl driver from a default path */ + if ( ! this->gl_config.driver_loaded ) { + /* no driver has been loaded, use default (ourselves) */ + if ( X11_GL_LoadLibrary(this, NULL) < 0 ) { + return NULL; + } + } + + /* See if we already have a window which we must use */ + if ( SDL_windowid ) { + XWindowAttributes a; + XVisualInfo vi_in; + int out_count; + + XGetWindowAttributes(SDL_Display, SDL_Window, &a); + vi_in.screen = SDL_Screen; + vi_in.visualid = XVisualIDFromVisual(a.visual); + glx_visualinfo = XGetVisualInfo(SDL_Display, + VisualScreenMask|VisualIDMask, &vi_in, &out_count); + return glx_visualinfo; + } + + /* Setup our GLX attributes according to the gl_config. */ + i = 0; + attribs[i++] = GLX_RGBA; + attribs[i++] = GLX_RED_SIZE; + attribs[i++] = this->gl_config.red_size; + attribs[i++] = GLX_GREEN_SIZE; + attribs[i++] = this->gl_config.green_size; + attribs[i++] = GLX_BLUE_SIZE; + attribs[i++] = this->gl_config.blue_size; + + if( this->gl_config.alpha_size ) { + attribs[i++] = GLX_ALPHA_SIZE; + attribs[i++] = this->gl_config.alpha_size; + } + + if( this->gl_config.double_buffer ) { + attribs[i++] = GLX_DOUBLEBUFFER; + } + + attribs[i++] = GLX_DEPTH_SIZE; + attribs[i++] = this->gl_config.depth_size; + + if( this->gl_config.stencil_size ) { + attribs[i++] = GLX_STENCIL_SIZE; + attribs[i++] = this->gl_config.stencil_size; + } + + if( this->gl_config.accum_red_size ) { + attribs[i++] = GLX_ACCUM_RED_SIZE; + attribs[i++] = this->gl_config.accum_red_size; + } + + if( this->gl_config.accum_green_size ) { + attribs[i++] = GLX_ACCUM_GREEN_SIZE; + attribs[i++] = this->gl_config.accum_green_size; + } + + if( this->gl_config.accum_blue_size ) { + attribs[i++] = GLX_ACCUM_BLUE_SIZE; + attribs[i++] = this->gl_config.accum_blue_size; + } + + if( this->gl_config.accum_alpha_size ) { + attribs[i++] = GLX_ACCUM_ALPHA_SIZE; + attribs[i++] = this->gl_config.accum_alpha_size; + } + + if( this->gl_config.stereo ) { + attribs[i++] = GLX_STEREO; + } + + if( this->gl_config.multisamplebuffers ) { + attribs[i++] = GLX_SAMPLE_BUFFERS_ARB; + attribs[i++] = this->gl_config.multisamplebuffers; + } + + if( this->gl_config.multisamplesamples ) { + attribs[i++] = GLX_SAMPLES_ARB; + attribs[i++] = this->gl_config.multisamplesamples; + } + + if( this->gl_config.accelerated >= 0 && + glXExtensionSupported(this, "GLX_EXT_visual_rating") ) { + attribs[i++] = GLX_VISUAL_CAVEAT_EXT; + attribs[i++] = GLX_NONE_EXT; + } + +#ifdef GLX_DIRECT_COLOR /* Try for a DirectColor visual for gamma support */ + if ( !SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ) { + attribs[i++] = GLX_X_VISUAL_TYPE; + attribs[i++] = GLX_DIRECT_COLOR; + } +#endif + attribs[i++] = None; + + glx_visualinfo = this->gl_data->glXChooseVisual(GFX_Display, + SDL_Screen, attribs); +#ifdef GLX_DIRECT_COLOR + if( !glx_visualinfo && !SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ) { /* No DirectColor visual? Try again.. */ + attribs[i-3] = None; + glx_visualinfo = this->gl_data->glXChooseVisual(GFX_Display, + SDL_Screen, attribs); + } +#endif + if( !glx_visualinfo ) { + SDL_SetError( "Couldn't find matching GLX visual"); + return NULL; + } +/* + printf("Found GLX visual 0x%x\n", glx_visualinfo->visualid); +*/ + return glx_visualinfo; +#else + SDL_SetError("X11 driver not configured with OpenGL"); + return NULL; +#endif +} + +int X11_GL_CreateWindow(_THIS, int w, int h) +{ + int retval; +#if SDL_VIDEO_OPENGL_GLX + XSetWindowAttributes attributes; + unsigned long mask; + unsigned long black; + + black = (glx_visualinfo->visual == DefaultVisual(SDL_Display, + SDL_Screen)) + ? BlackPixel(SDL_Display, SDL_Screen) : 0; + attributes.background_pixel = black; + attributes.border_pixel = black; + attributes.colormap = SDL_XColorMap; + mask = CWBackPixel | CWBorderPixel | CWColormap; + + SDL_Window = XCreateWindow(SDL_Display, WMwindow, + 0, 0, w, h, 0, glx_visualinfo->depth, + InputOutput, glx_visualinfo->visual, + mask, &attributes); + if ( !SDL_Window ) { + SDL_SetError("Could not create window"); + return -1; + } + retval = 0; +#else + SDL_SetError("X11 driver not configured with OpenGL"); + retval = -1; +#endif + return(retval); +} + +int X11_GL_CreateContext(_THIS) +{ + int retval; +#if SDL_VIDEO_OPENGL_GLX + + /* We do this to create a clean separation between X and GLX errors. */ + XSync( SDL_Display, False ); + glx_context = this->gl_data->glXCreateContext(GFX_Display, + glx_visualinfo, NULL, True); + XSync( GFX_Display, False ); + + if ( glx_context == NULL ) { + SDL_SetError("Could not create GL context"); + return(-1); + } + if ( X11_GL_MakeCurrent(this) < 0 ) { + return(-1); + } + gl_active = 1; + + if ( !glXExtensionSupported(this, "GLX_SGI_swap_control") ) { + this->gl_data->glXSwapIntervalSGI = NULL; + } + if ( !glXExtensionSupported(this, "GLX_MESA_swap_control") ) { + this->gl_data->glXSwapIntervalMESA = NULL; + } + if ( !glXExtensionSupported(this, "GLX_EXT_swap_control") ) { + this->gl_data->glXSwapIntervalEXT = NULL; + } + + if ( this->gl_config.swap_control >= 0 ) { + int rc = -1; + if ( this->gl_data->glXSwapIntervalEXT ) { + rc = this->gl_data->glXSwapIntervalEXT(GFX_Display, SDL_Window, + this->gl_config.swap_control); + } else if ( this->gl_data->glXSwapIntervalMESA ) { + rc = this->gl_data->glXSwapIntervalMESA(this->gl_config.swap_control); + } else if ( this->gl_data->glXSwapIntervalSGI ) { + rc = this->gl_data->glXSwapIntervalSGI(this->gl_config.swap_control); + } + if (rc == 0) { + this->gl_data->swap_interval = this->gl_config.swap_control; + } + } +#else + SDL_SetError("X11 driver not configured with OpenGL"); +#endif + if ( gl_active ) { + retval = 0; + } else { + retval = -1; + } + return(retval); +} + +void X11_GL_Shutdown(_THIS) +{ +#if SDL_VIDEO_OPENGL_GLX + /* Clean up OpenGL */ + if( glx_context ) { + this->gl_data->glXMakeCurrent(GFX_Display, None, NULL); + + if (glx_context != NULL) + this->gl_data->glXDestroyContext(GFX_Display, glx_context); + + glx_context = NULL; + } + gl_active = 0; +#endif /* SDL_VIDEO_OPENGL_GLX */ +} + +#if SDL_VIDEO_OPENGL_GLX + +/* Make the current context active */ +int X11_GL_MakeCurrent(_THIS) +{ + int retval; + + retval = 0; + if ( ! this->gl_data->glXMakeCurrent(GFX_Display, + SDL_Window, glx_context) ) { + SDL_SetError("Unable to make GL context current"); + retval = -1; + } + XSync( GFX_Display, False ); + + /* More Voodoo X server workarounds... Grr... */ + SDL_Lock_EventThread(); + X11_CheckDGAMouse(this); + SDL_Unlock_EventThread(); + + return(retval); +} + +/* Get attribute data from glX. */ +int X11_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value) +{ + int retval = -1; + int unsupported = 0; + int glx_attrib = None; + + switch( attrib ) { + case SDL_GL_RED_SIZE: + glx_attrib = GLX_RED_SIZE; + break; + case SDL_GL_GREEN_SIZE: + glx_attrib = GLX_GREEN_SIZE; + break; + case SDL_GL_BLUE_SIZE: + glx_attrib = GLX_BLUE_SIZE; + break; + case SDL_GL_ALPHA_SIZE: + glx_attrib = GLX_ALPHA_SIZE; + break; + case SDL_GL_DOUBLEBUFFER: + glx_attrib = GLX_DOUBLEBUFFER; + break; + case SDL_GL_BUFFER_SIZE: + glx_attrib = GLX_BUFFER_SIZE; + break; + case SDL_GL_DEPTH_SIZE: + glx_attrib = GLX_DEPTH_SIZE; + break; + case SDL_GL_STENCIL_SIZE: + glx_attrib = GLX_STENCIL_SIZE; + break; + case SDL_GL_ACCUM_RED_SIZE: + glx_attrib = GLX_ACCUM_RED_SIZE; + break; + case SDL_GL_ACCUM_GREEN_SIZE: + glx_attrib = GLX_ACCUM_GREEN_SIZE; + break; + case SDL_GL_ACCUM_BLUE_SIZE: + glx_attrib = GLX_ACCUM_BLUE_SIZE; + break; + case SDL_GL_ACCUM_ALPHA_SIZE: + glx_attrib = GLX_ACCUM_ALPHA_SIZE; + break; + case SDL_GL_STEREO: + glx_attrib = GLX_STEREO; + break; + case SDL_GL_MULTISAMPLEBUFFERS: + glx_attrib = GLX_SAMPLE_BUFFERS_ARB; + break; + case SDL_GL_MULTISAMPLESAMPLES: + glx_attrib = GLX_SAMPLES_ARB; + break; + case SDL_GL_ACCELERATED_VISUAL: + if ( glXExtensionSupported(this, "GLX_EXT_visual_rating") ) { + glx_attrib = GLX_VISUAL_CAVEAT_EXT; + retval = this->gl_data->glXGetConfig(GFX_Display, glx_visualinfo, glx_attrib, value); + if ( *value == GLX_SLOW_VISUAL_EXT ) { + *value = SDL_FALSE; + } else { + *value = SDL_TRUE; + } + return retval; + } else { + unsupported = 1; + } + break; + case SDL_GL_SWAP_CONTROL: + if ( ( this->gl_data->glXSwapIntervalEXT ) || + ( this->gl_data->glXSwapIntervalMESA ) || + ( this->gl_data->glXSwapIntervalSGI ) ) { + *value = this->gl_data->swap_interval; + return 0; + } else { + unsupported = 1; + } + break; + default: + unsupported = 1; + break; + } + + if (unsupported) { + SDL_SetError("OpenGL attribute is unsupported on this system"); + } else { + retval = this->gl_data->glXGetConfig(GFX_Display, glx_visualinfo, glx_attrib, value); + } + return retval; +} + +void X11_GL_SwapBuffers(_THIS) +{ + this->gl_data->glXSwapBuffers(GFX_Display, SDL_Window); +} + +#endif /* SDL_VIDEO_OPENGL_GLX */ + +#define OPENGL_REQUIRS_DLOPEN +#if defined(OPENGL_REQUIRS_DLOPEN) && defined(SDL_LOADSO_DLOPEN) +#include +#define GL_LoadObject(X) dlopen(X, (RTLD_NOW|RTLD_GLOBAL)) +#define GL_LoadFunction dlsym +#define GL_UnloadObject dlclose +#else +#define GL_LoadObject SDL_LoadObject +#define GL_LoadFunction SDL_LoadFunction +#define GL_UnloadObject SDL_UnloadObject +#endif + +void X11_GL_UnloadLibrary(_THIS) +{ +#if SDL_VIDEO_OPENGL_GLX + if ( this->gl_config.driver_loaded ) { + + GL_UnloadObject(this->gl_config.dll_handle); + + this->gl_data->glXGetProcAddress = NULL; + this->gl_data->glXChooseVisual = NULL; + this->gl_data->glXCreateContext = NULL; + this->gl_data->glXDestroyContext = NULL; + this->gl_data->glXMakeCurrent = NULL; + this->gl_data->glXSwapBuffers = NULL; + this->gl_data->glXSwapIntervalSGI = NULL; + this->gl_data->glXSwapIntervalMESA = NULL; + this->gl_data->glXSwapIntervalEXT = NULL; + + this->gl_config.dll_handle = NULL; + this->gl_config.driver_loaded = 0; + } +#endif +} + +#if SDL_VIDEO_OPENGL_GLX + +/* Passing a NULL path means load pointers from the application */ +int X11_GL_LoadLibrary(_THIS, const char* path) +{ + void* handle = NULL; + + if ( gl_active ) { + SDL_SetError("OpenGL context already created"); + return -1; + } + + if ( path == NULL ) { + path = SDL_getenv("SDL_VIDEO_GL_DRIVER"); + if ( path == NULL ) { + path = DEFAULT_OPENGL; + } + } + + handle = GL_LoadObject(path); + if ( handle == NULL ) { +#if defined(OPENGL_REQUIRS_DLOPEN) && defined(SDL_LOADSO_DLOPEN) + SDL_SetError("Failed loading %s", path); +#else + /* SDL_LoadObject() will call SDL_SetError() for us. */ +#endif + return -1; + } + + /* Unload the old driver and reset the pointers */ + X11_GL_UnloadLibrary(this); + + /* Save the handle for X11_GL_GetProcAddress() */ + this->gl_config.dll_handle = handle; + + /* Load new function pointers */ + this->gl_data->glXGetProcAddress = + (void *(*)(const GLubyte *)) GL_LoadFunction(handle, "glXGetProcAddressARB"); + this->gl_data->glXChooseVisual = + (XVisualInfo *(*)(Display *, int, int *)) X11_GL_GetProcAddress(this, "glXChooseVisual"); + this->gl_data->glXCreateContext = + (GLXContext (*)(Display *, XVisualInfo *, GLXContext, int)) X11_GL_GetProcAddress(this, "glXCreateContext"); + this->gl_data->glXDestroyContext = + (void (*)(Display *, GLXContext)) X11_GL_GetProcAddress(this, "glXDestroyContext"); + this->gl_data->glXMakeCurrent = + (int (*)(Display *, GLXDrawable, GLXContext)) X11_GL_GetProcAddress(this, "glXMakeCurrent"); + this->gl_data->glXSwapBuffers = + (void (*)(Display *, GLXDrawable)) X11_GL_GetProcAddress(this, "glXSwapBuffers"); + this->gl_data->glXGetConfig = + (int (*)(Display *, XVisualInfo *, int, int *)) X11_GL_GetProcAddress(this, "glXGetConfig"); + this->gl_data->glXQueryExtensionsString = + (const char *(*)(Display *, int)) X11_GL_GetProcAddress(this, "glXQueryExtensionsString"); + this->gl_data->glXSwapIntervalSGI = + (int (*)(int)) X11_GL_GetProcAddress(this, "glXSwapIntervalSGI"); + this->gl_data->glXSwapIntervalMESA = + (GLint (*)(unsigned)) X11_GL_GetProcAddress(this, "glXSwapIntervalMESA"); + this->gl_data->glXSwapIntervalEXT = + (int (*)(Display*,GLXDrawable,int)) X11_GL_GetProcAddress(this, "glXSwapIntervalEXT"); + + if ( (this->gl_data->glXChooseVisual == NULL) || + (this->gl_data->glXCreateContext == NULL) || + (this->gl_data->glXDestroyContext == NULL) || + (this->gl_data->glXMakeCurrent == NULL) || + (this->gl_data->glXSwapBuffers == NULL) || + (this->gl_data->glXGetConfig == NULL) || + (this->gl_data->glXQueryExtensionsString == NULL)) { + GL_UnloadObject(this->gl_config.dll_handle); + this->gl_config.dll_handle = NULL; + SDL_SetError("Could not retrieve OpenGL functions"); + return -1; + } + + this->gl_config.driver_loaded = 1; + if ( path ) { + SDL_strlcpy(this->gl_config.driver_path, path, + SDL_arraysize(this->gl_config.driver_path)); + } else { + *this->gl_config.driver_path = '\0'; + } + return 0; +} + +void *X11_GL_GetProcAddress(_THIS, const char* proc) +{ + if ( this->gl_data->glXGetProcAddress ) { + return this->gl_data->glXGetProcAddress((const GLubyte *)proc); + } + return GL_LoadFunction(this->gl_config.dll_handle, proc); +} + +#endif /* SDL_VIDEO_OPENGL_GLX */ diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11gl_c.h b/apps/plugins/sdl/src/video/x11/SDL_x11gl_c.h new file mode 100644 index 0000000000..b4822cb3c0 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11gl_c.h @@ -0,0 +1,99 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#if SDL_VIDEO_OPENGL_GLX +#include +#include "SDL_loadso.h" +#endif + +#include "../SDL_sysvideo.h" + +struct SDL_PrivateGLData { + int gl_active; /* to stop switching drivers while we have a valid context */ + +#if SDL_VIDEO_OPENGL_GLX + GLXContext glx_context; /* Current GL context */ + XVisualInfo* glx_visualinfo; /* XVisualInfo* returned by glXChooseVisual */ + + void * (*glXGetProcAddress)(const GLubyte *procName); + + XVisualInfo* (*glXChooseVisual) + ( Display* dpy, + int screen, + int* attribList ); + + GLXContext (*glXCreateContext) + ( Display* dpy, + XVisualInfo* vis, + GLXContext shareList, + Bool direct ); + + void (*glXDestroyContext) + ( Display* dpy, + GLXContext ctx ); + + Bool (*glXMakeCurrent) + ( Display* dpy, + GLXDrawable drawable, + GLXContext ctx ); + + void (*glXSwapBuffers) + ( Display* dpy, + GLXDrawable drawable ); + + int (*glXGetConfig) + ( Display* dpy, + XVisualInfo* visual_info, + int attrib, + int* value ); + + const char *(*glXQueryExtensionsString) + ( Display* dpy, + int screen ); + + int (*glXSwapIntervalSGI) ( int interval ); + GLint (*glXSwapIntervalMESA) ( unsigned interval ); + int (*glXSwapIntervalEXT)( Display *dpy, GLXDrawable drw, int interval); + int swap_interval; +#endif /* SDL_VIDEO_OPENGL_GLX */ +}; + +/* Old variable names */ +#define gl_active (this->gl_data->gl_active) +#define glx_context (this->gl_data->glx_context) +#define glx_visualinfo (this->gl_data->glx_visualinfo) + +/* OpenGL functions */ +extern XVisualInfo *X11_GL_GetVisual(_THIS); +extern int X11_GL_CreateWindow(_THIS, int w, int h); +extern int X11_GL_CreateContext(_THIS); +extern void X11_GL_Shutdown(_THIS); +#if SDL_VIDEO_OPENGL_GLX +extern int X11_GL_MakeCurrent(_THIS); +extern int X11_GL_GetAttribute(_THIS, SDL_GLattr attrib, int* value); +extern void X11_GL_SwapBuffers(_THIS); +extern int X11_GL_LoadLibrary(_THIS, const char* path); +extern void *X11_GL_GetProcAddress(_THIS, const char* proc); +#endif +extern void X11_GL_UnloadLibrary(_THIS); + diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11image.c b/apps/plugins/sdl/src/video/x11/SDL_x11image.c new file mode 100644 index 0000000000..464bc37ba7 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11image.c @@ -0,0 +1,316 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#include +#include + +#include "SDL_endian.h" +#include "../../events/SDL_events_c.h" +#include "SDL_x11image_c.h" + +#ifndef NO_SHARED_MEMORY + +/* Shared memory error handler routine */ +static int shm_error; +static int (*X_handler)(Display *, XErrorEvent *) = NULL; +static int shm_errhandler(Display *d, XErrorEvent *e) +{ + if ( e->error_code == BadAccess ) { + shm_error = True; + return(0); + } else + return(X_handler(d,e)); +} + +static void try_mitshm(_THIS, SDL_Surface *screen) +{ + /* Dynamic X11 may not have SHM entry points on this box. */ + if ((use_mitshm) && (!SDL_X11_HAVE_SHM)) + use_mitshm = 0; + + if(!use_mitshm) + return; + shminfo.shmid = shmget(IPC_PRIVATE, screen->h*screen->pitch, + IPC_CREAT | 0777); + if ( shminfo.shmid >= 0 ) { + shminfo.shmaddr = (char *)shmat(shminfo.shmid, 0, 0); + shminfo.readOnly = False; + if ( shminfo.shmaddr != (char *)-1 ) { + shm_error = False; + X_handler = XSetErrorHandler(shm_errhandler); + XShmAttach(SDL_Display, &shminfo); + XSync(SDL_Display, True); + XSetErrorHandler(X_handler); + if ( shm_error ) + shmdt(shminfo.shmaddr); + } else { + shm_error = True; + } + shmctl(shminfo.shmid, IPC_RMID, NULL); + } else { + shm_error = True; + } + if ( shm_error ) + use_mitshm = 0; + if ( use_mitshm ) + screen->pixels = shminfo.shmaddr; +} +#endif /* ! NO_SHARED_MEMORY */ + +/* Various screen update functions available */ +static void X11_NormalUpdate(_THIS, int numrects, SDL_Rect *rects); +static void X11_MITSHMUpdate(_THIS, int numrects, SDL_Rect *rects); + +int X11_SetupImage(_THIS, SDL_Surface *screen) +{ +#ifndef NO_SHARED_MEMORY + try_mitshm(this, screen); + if(use_mitshm) { + SDL_Ximage = XShmCreateImage(SDL_Display, SDL_Visual, + this->hidden->depth, ZPixmap, + shminfo.shmaddr, &shminfo, + screen->w, screen->h); + if(!SDL_Ximage) { + XShmDetach(SDL_Display, &shminfo); + XSync(SDL_Display, False); + shmdt(shminfo.shmaddr); + screen->pixels = NULL; + goto error; + } + this->UpdateRects = X11_MITSHMUpdate; + } + if(!use_mitshm) +#endif /* not NO_SHARED_MEMORY */ + { + screen->pixels = SDL_malloc(screen->h*screen->pitch); + if ( screen->pixels == NULL ) { + SDL_OutOfMemory(); + return -1; + } + SDL_Ximage = XCreateImage(SDL_Display, SDL_Visual, + this->hidden->depth, ZPixmap, 0, + (char *)screen->pixels, + screen->w, screen->h, + 32, 0); + if ( SDL_Ximage == NULL ) + goto error; + /* XPutImage will convert byte sex automatically */ + SDL_Ximage->byte_order = (SDL_BYTEORDER == SDL_BIG_ENDIAN) + ? MSBFirst : LSBFirst; + this->UpdateRects = X11_NormalUpdate; + } + screen->pitch = SDL_Ximage->bytes_per_line; + return(0); + +error: + SDL_SetError("Couldn't create XImage"); + return 1; +} + +void X11_DestroyImage(_THIS, SDL_Surface *screen) +{ + if ( SDL_Ximage ) { + XDestroyImage(SDL_Ximage); +#ifndef NO_SHARED_MEMORY + if ( use_mitshm ) { + XShmDetach(SDL_Display, &shminfo); + XSync(SDL_Display, False); + shmdt(shminfo.shmaddr); + } +#endif /* ! NO_SHARED_MEMORY */ + SDL_Ximage = NULL; + } + if ( screen ) { + screen->pixels = NULL; + } +} + +/* Determine the number of CPUs in the system */ +static int num_CPU(void) +{ + static int num_cpus = 0; + + if(!num_cpus) { +#if defined(__LINUX__) + char line[BUFSIZ]; + FILE *pstat = fopen("/proc/stat", "r"); + if ( pstat ) { + while ( fgets(line, sizeof(line), pstat) ) { + if (SDL_memcmp(line, "cpu", 3) == 0 && line[3] != ' ') { + ++num_cpus; + } + } + fclose(pstat); + } +#elif defined(__IRIX__) + num_cpus = sysconf(_SC_NPROC_ONLN); +#elif defined(_SC_NPROCESSORS_ONLN) + /* number of processors online (SVR4.0MP compliant machines) */ + num_cpus = sysconf(_SC_NPROCESSORS_ONLN); +#elif defined(_SC_NPROCESSORS_CONF) + /* number of processors configured (SVR4.0MP compliant machines) */ + num_cpus = sysconf(_SC_NPROCESSORS_CONF); +#endif + if ( num_cpus <= 0 ) { + num_cpus = 1; + } + } + return num_cpus; +} + +int X11_ResizeImage(_THIS, SDL_Surface *screen, Uint32 flags) +{ + int retval; + + X11_DestroyImage(this, screen); + if ( flags & SDL_OPENGL ) { /* No image when using GL */ + retval = 0; + } else { + retval = X11_SetupImage(this, screen); + /* We support asynchronous blitting on the display */ + if ( flags & SDL_ASYNCBLIT ) { + /* This is actually slower on single-CPU systems, + probably because of CPU contention between the + X server and the application. + Note: Is this still true with XFree86 4.0? + */ + if ( num_CPU() > 1 ) { + screen->flags |= SDL_ASYNCBLIT; + } + } + } + return(retval); +} + +/* We don't actually allow hardware surfaces other than the main one */ +int X11_AllocHWSurface(_THIS, SDL_Surface *surface) +{ + return(-1); +} +void X11_FreeHWSurface(_THIS, SDL_Surface *surface) +{ + return; +} + +int X11_LockHWSurface(_THIS, SDL_Surface *surface) +{ + if ( (surface == SDL_VideoSurface) && blit_queued ) { + XSync(GFX_Display, False); + blit_queued = 0; + } + return(0); +} +void X11_UnlockHWSurface(_THIS, SDL_Surface *surface) +{ + return; +} + +int X11_FlipHWSurface(_THIS, SDL_Surface *surface) +{ + return(0); +} + +static void X11_NormalUpdate(_THIS, int numrects, SDL_Rect *rects) +{ + int i; + + for (i = 0; i < numrects; ++i) { + if ( rects[i].w == 0 || rects[i].h == 0 ) { /* Clipped? */ + continue; + } + XPutImage(GFX_Display, SDL_Window, SDL_GC, SDL_Ximage, + rects[i].x, rects[i].y, + rects[i].x, rects[i].y, rects[i].w, rects[i].h); + } + if ( SDL_VideoSurface->flags & SDL_ASYNCBLIT ) { + XFlush(GFX_Display); + blit_queued = 1; + } else { + XSync(GFX_Display, False); + } +} + +static void X11_MITSHMUpdate(_THIS, int numrects, SDL_Rect *rects) +{ +#ifndef NO_SHARED_MEMORY + int i; + + for ( i=0; iflags & SDL_ASYNCBLIT ) { + XFlush(GFX_Display); + blit_queued = 1; + } else { + XSync(GFX_Display, False); + } +#endif /* ! NO_SHARED_MEMORY */ +} + +/* There's a problem with the automatic refreshing of the display. + Even though the XVideo code uses the GFX_Display to update the + video memory, it appears that updating the window asynchronously + from a different thread will cause "blackouts" of the window. + This is a sort of a hacked workaround for the problem. +*/ +static int enable_autorefresh = 1; + +void X11_DisableAutoRefresh(_THIS) +{ + --enable_autorefresh; +} + +void X11_EnableAutoRefresh(_THIS) +{ + ++enable_autorefresh; +} + +void X11_RefreshDisplay(_THIS) +{ + /* Don't refresh a display that doesn't have an image (like GL) + Instead, post an expose event so the application can refresh. + */ + if ( ! SDL_Ximage || (enable_autorefresh <= 0) ) { + SDL_PrivateExpose(); + return; + } +#ifndef NO_SHARED_MEMORY + if ( this->UpdateRects == X11_MITSHMUpdate ) { + XShmPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage, + 0, 0, 0, 0, this->screen->w, this->screen->h, + False); + } else +#endif /* ! NO_SHARED_MEMORY */ + { + XPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage, + 0, 0, 0, 0, this->screen->w, this->screen->h); + } + XSync(SDL_Display, False); +} + diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11image_c.h b/apps/plugins/sdl/src/video/x11/SDL_x11image_c.h new file mode 100644 index 0000000000..2de15717ba --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11image_c.h @@ -0,0 +1,38 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#include "SDL_x11video.h" + +extern int X11_SetupImage(_THIS, SDL_Surface *screen); +extern void X11_DestroyImage(_THIS, SDL_Surface *screen); +extern int X11_ResizeImage(_THIS, SDL_Surface *screen, Uint32 flags); + +extern int X11_AllocHWSurface(_THIS, SDL_Surface *surface); +extern void X11_FreeHWSurface(_THIS, SDL_Surface *surface); +extern int X11_LockHWSurface(_THIS, SDL_Surface *surface); +extern void X11_UnlockHWSurface(_THIS, SDL_Surface *surface); +extern int X11_FlipHWSurface(_THIS, SDL_Surface *surface); + +extern void X11_DisableAutoRefresh(_THIS); +extern void X11_EnableAutoRefresh(_THIS); +extern void X11_RefreshDisplay(_THIS); diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11modes.c b/apps/plugins/sdl/src/video/x11/SDL_x11modes.c new file mode 100644 index 0000000000..c232e6aa36 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11modes.c @@ -0,0 +1,1143 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* Utilities for getting and setting the X display mode */ + +#include + +#include "SDL_timer.h" +#include "SDL_events.h" +#include "../../events/SDL_events_c.h" +#include "SDL_x11video.h" +#include "SDL_x11wm_c.h" +#include "SDL_x11modes_c.h" +#include "SDL_x11image_c.h" + +/*#define X11MODES_DEBUG*/ + +#define MAX(a, b) (a > b ? a : b) + +#if SDL_VIDEO_DRIVER_X11_XRANDR +static int cmpmodelist(const void *va, const void *vb) +{ + const SDL_Rect *a = *(const SDL_Rect **)va; + const SDL_Rect *b = *(const SDL_Rect **)vb; + if ( a->w == b->w ) + return b->h - a->h; + else + return b->w - a->w; +} +#endif + +#if SDL_VIDEO_DRIVER_X11_VIDMODE +Bool SDL_NAME(XF86VidModeGetModeInfo)(Display *dpy, int scr, SDL_NAME(XF86VidModeModeInfo) *info) +{ + Bool retval; + int dotclock; + SDL_NAME(XF86VidModeModeLine) l; + SDL_memset(&l, 0, sizeof(l)); + retval = SDL_NAME(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; +} +#endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */ + +#if SDL_VIDEO_DRIVER_X11_VIDMODE +static void save_mode(_THIS) +{ + SDL_memset(&saved_mode, 0, sizeof(saved_mode)); + SDL_NAME(XF86VidModeGetModeInfo)(SDL_Display,SDL_Screen,&saved_mode); + SDL_NAME(XF86VidModeGetViewPort)(SDL_Display,SDL_Screen,&saved_view.x,&saved_view.y); +} +#endif + +#if SDL_VIDEO_DRIVER_X11_VIDMODE +static void restore_mode(_THIS) +{ + SDL_NAME(XF86VidModeModeLine) mode; + int unused; + + if ( SDL_NAME(XF86VidModeGetModeLine)(SDL_Display, SDL_Screen, &unused, &mode) ) { + if ( (saved_mode.hdisplay != mode.hdisplay) || + (saved_mode.vdisplay != mode.vdisplay) ) { + SDL_NAME(XF86VidModeSwitchToMode)(SDL_Display, SDL_Screen, &saved_mode); + } + } + if ( (saved_view.x != 0) || (saved_view.y != 0) ) { + SDL_NAME(XF86VidModeSetViewPort)(SDL_Display, SDL_Screen, saved_view.x, saved_view.y); + } +} +#endif + +#if SDL_VIDEO_DRIVER_X11_VIDMODE +static int cmpmodes(const void *va, const void *vb) +{ + const SDL_NAME(XF86VidModeModeInfo) *a = *(const SDL_NAME(XF86VidModeModeInfo)**)va; + const SDL_NAME(XF86VidModeModeInfo) *b = *(const SDL_NAME(XF86VidModeModeInfo)**)vb; + if ( a->hdisplay == b->hdisplay ) + return b->vdisplay - a->vdisplay; + else + return b->hdisplay - a->hdisplay; +} +#endif + +static void get_real_resolution(_THIS, int* w, int* h); + +static void set_best_resolution(_THIS, int width, int height) +{ +#if SDL_VIDEO_DRIVER_X11_VIDMODE + if ( use_vidmode ) { + SDL_NAME(XF86VidModeModeLine) mode; + SDL_NAME(XF86VidModeModeInfo) **modes; + int i; + int nmodes; + int best = -1; + + if ( SDL_NAME(XF86VidModeGetModeLine)(SDL_Display, SDL_Screen, &i, &mode) && + SDL_NAME(XF86VidModeGetAllModeLines)(SDL_Display,SDL_Screen,&nmodes,&modes) ) { + for ( i = 0; i < nmodes ; i++ ) { + if ( (modes[i]->hdisplay == width) && + (modes[i]->vdisplay == height) ) { + best = i; + break; + } + if ( modes[i]->hdisplay >= width && + modes[i]->vdisplay >= height ) { + if ( best < 0 || + (modes[i]->hdisplay < modes[best]->hdisplay && + modes[i]->vdisplay <= modes[best]->vdisplay) || + (modes[i]->vdisplay < modes[best]->vdisplay && + modes[i]->hdisplay <= modes[best]->hdisplay) ) { + best = i; + } + } + } + if ( best >= 0 && + ((modes[best]->hdisplay != mode.hdisplay) || + (modes[best]->vdisplay != mode.vdisplay)) ) { +#ifdef X11MODES_DEBUG + printf("Best Mode %d: %d x %d @ %d\n", best, + modes[best]->hdisplay, modes[best]->vdisplay, + (modes[best]->htotal && modes[best]->vtotal) ? (1000 * modes[best]->dotclock / (modes[best]->htotal * modes[best]->vtotal)) : 0 ); +#endif + SDL_NAME(XF86VidModeSwitchToMode)(SDL_Display, SDL_Screen, modes[best]); + } + XFree(modes); + } + } +#endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */ + + /* XiG */ +#if SDL_VIDEO_DRIVER_X11_XME + if ( use_xme && SDL_modelist ) { + int i; + +#ifdef X11MODES_DEBUG + fprintf(stderr, "XME: set_best_resolution(): w = %d, h = %d\n", + width, height); +#endif + for ( i=0; SDL_modelist[i]; ++i ) { + if ( (SDL_modelist[i]->w >= width) && + (SDL_modelist[i]->h >= height) ) { + break; + } + } + + if ( SDL_modelist[i] ) { /* found one, lets try it */ + int w, h; + + /* check current mode so we can avoid uneccessary mode changes */ + get_real_resolution(this, &w, &h); + + if ( (SDL_modelist[i]->w != w) || (SDL_modelist[i]->h != h) ) { +#ifdef X11MODES_DEBUG + fprintf(stderr, "XME: set_best_resolution: " + "XiGMiscChangeResolution: %d %d\n", + SDL_modelist[i]->w, SDL_modelist[i]->h); +#endif + XiGMiscChangeResolution(SDL_Display, + SDL_Screen, + 0, /* view */ + SDL_modelist[i]->w, + SDL_modelist[i]->h, + 0); + XSync(SDL_Display, False); + } + } + } +#endif /* SDL_VIDEO_DRIVER_X11_XME */ + +#if SDL_VIDEO_DRIVER_X11_XRANDR + if ( use_xrandr && SDL_modelist ) { +#ifdef X11MODES_DEBUG + fprintf(stderr, "XRANDR: set_best_resolution(): w = %d, h = %d\n", + width, height); +#endif + int i, nsizes; + XRRScreenSize *sizes; + + /* find the smallest resolution that is at least as big as the user requested */ + sizes = XRRConfigSizes(screen_config, &nsizes); + for ( i = (nsizes-1); i >= 0; i-- ) { + if ( (SDL_modelist[i]->w >= width) && + (SDL_modelist[i]->h >= height) ) { + break; + } + } + + if ( i >= 0 && SDL_modelist[i] ) { /* found one, lets try it */ + int w, h; + + /* check current mode so we can avoid uneccessary mode changes */ + get_real_resolution(this, &w, &h); + + if ( (SDL_modelist[i]->w != w) || (SDL_modelist[i]->h != h) ) { + int size_id; + +#ifdef X11MODES_DEBUG + fprintf(stderr, "XRANDR: set_best_resolution: " + "XXRSetScreenConfig: %d %d\n", + SDL_modelist[i]->w, SDL_modelist[i]->h); +#endif + + /* find the matching size entry index */ + for ( size_id = 0; size_id < nsizes; ++size_id ) { + if ( (sizes[size_id].width == SDL_modelist[i]->w) && + (sizes[size_id].height == SDL_modelist[i]->h) ) + break; + } + + XRRSetScreenConfig(SDL_Display, screen_config, SDL_Root, + size_id, saved_rotation, CurrentTime); + } + } + } +#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ +} + +static void get_real_resolution(_THIS, int* w, int* h) +{ +#if SDL_VIDEO_DRIVER_X11_XME + if ( use_xme ) { + int ractive; + XiGMiscResolutionInfo *modelist; + + XiGMiscQueryResolutions(SDL_Display, SDL_Screen, + 0, /* view */ + &ractive, &modelist); + *w = modelist[ractive].width; + *h = modelist[ractive].height; +#ifdef X11MODES_DEBUG + fprintf(stderr, "XME: get_real_resolution: w = %d h = %d\n", *w, *h); +#endif + XFree(modelist); + return; + } +#endif /* SDL_VIDEO_DRIVER_X11_XME */ + +#if SDL_VIDEO_DRIVER_X11_VIDMODE + if ( use_vidmode ) { + SDL_NAME(XF86VidModeModeLine) mode; + int unused; + + if ( SDL_NAME(XF86VidModeGetModeLine)(SDL_Display, SDL_Screen, &unused, &mode) ) { + *w = mode.hdisplay; + *h = mode.vdisplay; + return; + } + } +#endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */ + +#if SDL_VIDEO_DRIVER_X11_XRANDR + if ( use_xrandr ) { + int nsizes; + XRRScreenSize* sizes; + + sizes = XRRConfigSizes(screen_config, &nsizes); + if ( nsizes > 0 ) { + int cur_size; + Rotation cur_rotation; + + cur_size = XRRConfigCurrentConfiguration(screen_config, &cur_rotation); + if ( cur_size >= 0 && cur_size < nsizes ) { + *w = sizes[cur_size].width; + *h = sizes[cur_size].height; + } +#ifdef X11MODES_DEBUG + fprintf(stderr, "XRANDR: get_real_resolution: w = %d h = %d\n", *w, *h); +#endif + return; + } + } +#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ + +#if SDL_VIDEO_DRIVER_X11_XINERAMA + if ( use_xinerama ) { + *w = xinerama_info.width; + *h = xinerama_info.height; + return; + } +#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ + + *w = DisplayWidth(SDL_Display, SDL_Screen); + *h = DisplayHeight(SDL_Display, SDL_Screen); +} + +/* Called after mapping a window - waits until the window is mapped */ +void X11_WaitMapped(_THIS, Window win) +{ + XEvent event; + do { + XMaskEvent(SDL_Display, StructureNotifyMask, &event); + } while ( (event.type != MapNotify) || (event.xmap.event != win) ); +} + +/* Called after unmapping a window - waits until the window is unmapped */ +void X11_WaitUnmapped(_THIS, Window win) +{ + XEvent event; + do { + XMaskEvent(SDL_Display, StructureNotifyMask, &event); + } while ( (event.type != UnmapNotify) || (event.xunmap.event != win) ); +} + +static void move_cursor_to(_THIS, int x, int y) +{ + XWarpPointer(SDL_Display, None, SDL_Root, 0, 0, 0, 0, x, y); +} + +static int add_default_visual(_THIS) +{ + int i; + int n = this->hidden->nvisuals; + for (i=0; ihidden->visuals[i].visual == DefaultVisual(SDL_Display, SDL_Screen)) return n; + } + this->hidden->visuals[n].depth = DefaultDepth(SDL_Display, SDL_Screen);; + this->hidden->visuals[n].visual = DefaultVisual(SDL_Display, SDL_Screen);; + this->hidden->nvisuals++; + return(this->hidden->nvisuals); +} +static int add_visual(_THIS, int depth, int class) +{ + XVisualInfo vi; + if(XMatchVisualInfo(SDL_Display, SDL_Screen, depth, class, &vi)) { + int n = this->hidden->nvisuals; + this->hidden->visuals[n].depth = vi.depth; + this->hidden->visuals[n].visual = vi.visual; + this->hidden->nvisuals++; + } + return(this->hidden->nvisuals); +} +static int add_visual_byid(_THIS, const char *visual_id) +{ + XVisualInfo *vi, template; + int nvis; + + if ( visual_id ) { + SDL_memset(&template, 0, (sizeof template)); + template.visualid = SDL_strtol(visual_id, NULL, 0); + vi = XGetVisualInfo(SDL_Display, VisualIDMask, &template, &nvis); + if ( vi ) { + int n = this->hidden->nvisuals; + this->hidden->visuals[n].depth = vi->depth; + this->hidden->visuals[n].visual = vi->visual; + this->hidden->nvisuals++; + XFree(vi); + } + } + return(this->hidden->nvisuals); +} + +/* Global for the error handler */ +int vm_event, vm_error = -1; + +#if SDL_VIDEO_DRIVER_X11_XINERAMA +static int CheckXinerama(_THIS, int *major, int *minor) +{ + const char *env; + + /* Default the extension not available */ + *major = *minor = 0; + + /* Allow environment override */ + env = getenv("SDL_VIDEO_X11_XINERAMA"); + if ( env && !SDL_atoi(env) ) { + return 0; + } + + /* Query the extension version */ + if ( !SDL_NAME(XineramaQueryExtension)(SDL_Display, major, minor) || + !SDL_NAME(XineramaIsActive)(SDL_Display) ) { + return 0; + } + return 1; +} +#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ + +#if SDL_VIDEO_DRIVER_X11_XRANDR +static int CheckXRandR(_THIS, int *major, int *minor) +{ + const char *env; + + /* Default the extension not available */ + *major = *minor = 0; + + /* Allow environment override */ + env = getenv("SDL_VIDEO_X11_XRANDR"); + if ( env && !SDL_atoi(env) ) { + return 0; + } + + /* This defaults off now, due to KDE window maximize problems */ + if ( !env ) { + return 0; + } + + if ( !SDL_X11_HAVE_XRANDR ) { + return 0; + } + + /* Query the extension version */ + if ( !XRRQueryVersion(SDL_Display, major, minor) ) { + return 0; + } + return 1; +} +#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ + +#if SDL_VIDEO_DRIVER_X11_VIDMODE +static int CheckVidMode(_THIS, int *major, int *minor) +{ + const char *env; + + /* Default the extension not available */ + *major = *minor = 0; + + /* Allow environment override */ + env = getenv("SDL_VIDEO_X11_VIDMODE"); + if ( env && !SDL_atoi(env) ) { + return 0; + } + + /* Metro-X 4.3.0 and earlier has a broken implementation of + XF86VidModeGetAllModeLines() - it hangs the client. + */ + if ( SDL_strcmp(ServerVendor(SDL_Display), "Metro Link Incorporated") == 0 ) { + FILE *metro_fp; + + metro_fp = fopen("/usr/X11R6/lib/X11/Metro/.version", "r"); + if ( metro_fp != NULL ) { + int major, minor, patch, version, scannum; + major = 0; minor = 0; patch = 0; + scannum = fscanf(metro_fp, "%d.%d.%d", &major, &minor, &patch); + fclose(metro_fp); + if ( (scannum < 0) || (scannum > 3) ) { + return 0; /* we need _something_ useful from fscanf(). */ + } + version = major*100+minor*10+patch; + if ( version < 431 ) { + return 0; + } + } + } + + /* Query the extension version */ + vm_error = -1; + if ( !SDL_NAME(XF86VidModeQueryExtension)(SDL_Display, &vm_event, &vm_error) || + !SDL_NAME(XF86VidModeQueryVersion)(SDL_Display, major, minor) ) { + return 0; + } + return 1; +} +#endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */ + +#if SDL_VIDEO_DRIVER_X11_XME +static int CheckXME(_THIS, int *major, int *minor) +{ + const char *env; + + /* Default the extension not available */ + *major = *minor = 0; + + /* Allow environment override */ + env = getenv("SDL_VIDEO_X11_VIDMODE"); + if ( env && !SDL_atoi(env) ) { + return 0; + } + + /* Query the extension version */ + if ( !XiGMiscQueryVersion(SDL_Display, major, minor) ) { + return 0; + } + return 1; +} +#endif /* SDL_VIDEO_DRIVER_X11_XME */ + +int X11_GetVideoModes(_THIS) +{ +#if SDL_VIDEO_DRIVER_X11_XINERAMA + int xinerama_major, xinerama_minor; +#endif +#if SDL_VIDEO_DRIVER_X11_XRANDR + int xrandr_major, xrandr_minor; + int nsizes; + XRRScreenSize *sizes; +#endif +#if SDL_VIDEO_DRIVER_X11_VIDMODE + int vm_major, vm_minor; + int nmodes; + SDL_NAME(XF86VidModeModeInfo) **modes; +#endif +#if SDL_VIDEO_DRIVER_X11_XME + int xme_major, xme_minor; + int ractive, nummodes; + XiGMiscResolutionInfo *modelist; +#endif + int i, n; + int screen_w; + int screen_h; + + use_xinerama = 0; + use_xrandr = 0; + use_vidmode = 0; + use_xme = 0; + screen_w = DisplayWidth(SDL_Display, SDL_Screen); + screen_h = DisplayHeight(SDL_Display, SDL_Screen); + +#if SDL_VIDEO_DRIVER_X11_XINERAMA + /* Query Xinerama extention */ + if ( CheckXinerama(this, &xinerama_major, &xinerama_minor) ) { + /* Find out which screen is the desired one */ + int desired = -1; + int screens; + int w, h; + SDL_NAME(XineramaScreenInfo) *xinerama; + + const char *variable = SDL_getenv("SDL_VIDEO_FULLSCREEN_DISPLAY"); + if ( !variable ) { + variable = SDL_getenv("SDL_VIDEO_FULLSCREEN_HEAD"); + } + if ( variable ) { + desired = SDL_atoi(variable); + } +#ifdef X11MODES_DEBUG + printf("X11 detected Xinerama:\n"); +#endif + xinerama = SDL_NAME(XineramaQueryScreens)(SDL_Display, &screens); + 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 == desired ) { + use_xinerama = 1; + xinerama_info = xinerama[i]; + } + } + XFree(xinerama); + + if ( use_xinerama ) { + SDL_modelist = (SDL_Rect **)SDL_malloc(3*sizeof(SDL_Rect *)); + if ( !SDL_modelist ) { + SDL_OutOfMemory(); + return -1; + } + + /* Add the full xinerama mode */ + n = 0; + w = xinerama_info.width; + h = xinerama_info.height; + if ( screen_w > w || screen_h > h) { + SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect)); + if ( SDL_modelist[n] ) { + SDL_modelist[n]->x = 0; + SDL_modelist[n]->y = 0; + SDL_modelist[n]->w = screen_w; + SDL_modelist[n]->h = screen_h; + ++n; + } + } + + /* Add the head xinerama mode */ + SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect)); + if ( SDL_modelist[n] ) { + SDL_modelist[n]->x = 0; + SDL_modelist[n]->y = 0; + SDL_modelist[n]->w = w; + SDL_modelist[n]->h = h; + ++n; + } + SDL_modelist[n] = NULL; + } + } +#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ + +#if SDL_VIDEO_DRIVER_X11_XRANDR + /* XRandR */ + /* require at least XRandR v1.0 (arbitrary) */ + if ( CheckXRandR(this, &xrandr_major, &xrandr_minor) && (xrandr_major >= 1) ) + { +#ifdef X11MODES_DEBUG + fprintf(stderr, "XRANDR: XRRQueryVersion: V%d.%d\n", + xrandr_major, xrandr_minor); +#endif + + /* save the screen configuration since we must reference it + each time we toggle modes. + */ + screen_config = XRRGetScreenInfo(SDL_Display, SDL_Root); + + /* retrieve the list of resolution */ + sizes = XRRConfigSizes(screen_config, &nsizes); + if (nsizes > 0) { + if ( SDL_modelist ) { + for ( i = 0; SDL_modelist[i]; ++i ) { + SDL_free(SDL_modelist[i]); + } + SDL_free(SDL_modelist); + } + SDL_modelist = (SDL_Rect **)malloc((nsizes+1)*sizeof(SDL_Rect *)); + if ( !SDL_modelist ) { + SDL_OutOfMemory(); + return -1; + } + for ( i=0; i < nsizes; i++ ) { + if ((SDL_modelist[i] = + (SDL_Rect *)malloc(sizeof(SDL_Rect))) == NULL) + break; +#ifdef X11MODES_DEBUG + fprintf(stderr, "XRANDR: mode = %4d, w = %4d, h = %4d\n", + i, sizes[i].width, sizes[i].height); +#endif + + SDL_modelist[i]->x = 0; + SDL_modelist[i]->y = 0; + SDL_modelist[i]->w = sizes[i].width; + SDL_modelist[i]->h = sizes[i].height; + + } + /* sort the mode list descending as SDL expects */ + SDL_qsort(SDL_modelist, nsizes, sizeof *SDL_modelist, cmpmodelist); + SDL_modelist[i] = NULL; /* terminator */ + + use_xrandr = xrandr_major * 100 + xrandr_minor; + saved_size_id = XRRConfigCurrentConfiguration(screen_config, &saved_rotation); + } + } +#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ + +#if SDL_VIDEO_DRIVER_X11_VIDMODE + /* XVidMode */ + if ( !use_xrandr && +#if SDL_VIDEO_DRIVER_X11_XINERAMA + (!use_xinerama || xinerama_info.screen_number == -1) && +#endif + CheckVidMode(this, &vm_major, &vm_minor) && + SDL_NAME(XF86VidModeGetAllModeLines)(SDL_Display, SDL_Screen,&nmodes,&modes) ) + { +#ifdef X11MODES_DEBUG + printf("VidMode modes: (unsorted)\n"); + for ( i = 0; i < nmodes; ++i ) { + printf("Mode %d: %d x %d @ %d\n", i, + modes[i]->hdisplay, modes[i]->vdisplay, + (modes[i]->htotal && modes[i]->vtotal) ? (1000 * modes[i]->dotclock / (modes[i]->htotal * modes[i]->vtotal)) : 0 ); + } +#endif + if ( SDL_modelist ) { + for ( i = 0; SDL_modelist[i]; ++i ) { + SDL_free(SDL_modelist[i]); + } + SDL_free(SDL_modelist); + } + SDL_modelist = (SDL_Rect **)SDL_malloc((nmodes+2)*sizeof(SDL_Rect *)); + if ( !SDL_modelist ) { + SDL_OutOfMemory(); + return -1; + } + SDL_qsort(modes, nmodes, sizeof *modes, cmpmodes); + n = 0; + for ( i=0; i 0 && + modes[i]->hdisplay == modes[i-1]->hdisplay && + modes[i]->vdisplay == modes[i-1]->vdisplay ) { + continue; + } + + /* Check to see if we should add the screen size (Xinerama) */ + w = modes[i]->hdisplay; + h = modes[i]->vdisplay; + if ( (screen_w * screen_h) >= (w * h) ) { + if ( (screen_w != w) || (screen_h != h) ) { + SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect)); + if ( SDL_modelist[n] ) { + SDL_modelist[n]->x = 0; + SDL_modelist[n]->y = 0; + SDL_modelist[n]->w = screen_w; + SDL_modelist[n]->h = screen_h; + ++n; + } + } + screen_w = 0; + screen_h = 0; + } + + /* Add the size from the video mode list */ + SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect)); + if ( SDL_modelist[n] == NULL ) { + break; + } + SDL_modelist[n]->x = 0; + SDL_modelist[n]->y = 0; + SDL_modelist[n]->w = w; + SDL_modelist[n]->h = h; + ++n; + } + SDL_modelist[n] = NULL; + XFree(modes); + + use_vidmode = vm_major * 100 + vm_minor; + save_mode(this); + } +#endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */ + +#if SDL_VIDEO_DRIVER_X11_XME + /* XiG */ + modelist = NULL; + /* first lets make sure we have the extension, and it's at least v2.0 */ + if ( CheckXME(this, &xme_major, &xme_minor) && xme_major >= 2 && + (nummodes = XiGMiscQueryResolutions(SDL_Display, SDL_Screen, + 0, /* view */ + &ractive, &modelist)) > 1 ) + { /* then we actually have some */ + int j; + + /* We get the list already sorted in descending order. + We'll copy it in reverse order so SDL is happy */ +#ifdef X11MODES_DEBUG + fprintf(stderr, "XME: nummodes = %d, active mode = %d\n", + nummodes, ractive); +#endif + if ( SDL_modelist ) { + for ( i = 0; SDL_modelist[i]; ++i ) { + SDL_free(SDL_modelist[i]); + } + SDL_free(SDL_modelist); + } + SDL_modelist = (SDL_Rect **)SDL_malloc((nummodes+1)*sizeof(SDL_Rect *)); + if ( !SDL_modelist ) { + SDL_OutOfMemory(); + return -1; + } + for ( i=0, j=nummodes-1; j>=0; i++, j-- ) { + if ((SDL_modelist[i] = + (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect))) == NULL) + break; +#ifdef X11MODES_DEBUG + fprintf(stderr, "XME: mode = %4d, w = %4d, h = %4d\n", + i, modelist[i].width, modelist[i].height); +#endif + + SDL_modelist[i]->x = 0; + SDL_modelist[i]->y = 0; + SDL_modelist[i]->w = modelist[j].width; + SDL_modelist[i]->h = modelist[j].height; + + } + SDL_modelist[i] = NULL; /* terminator */ + + use_xme = xme_major * 100 + xme_minor; + saved_res = modelist[ractive]; /* save the current resolution */ + } + if ( modelist ) { + XFree(modelist); + } +#endif /* SDL_VIDEO_DRIVER_X11_XME */ + + { + /* It's interesting to note that if we allow 32 bit depths, + we get a visual with an alpha mask on composite servers. + static int depth_list[] = { 32, 24, 16, 15, 8 }; + */ + static int depth_list[] = { 24, 16, 15, 8 }; + int j, np; + int use_directcolor = 1; + XPixmapFormatValues *pf; + + /* Search for the visuals in deepest-first order, so that the first + will be the richest one */ + if ( SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ) { + use_directcolor = 0; + } + this->hidden->nvisuals = 0; + if ( ! add_visual_byid(this, SDL_getenv("SDL_VIDEO_X11_VISUALID")) ) { + for ( i=0; i 8 ) { + if ( use_directcolor ) { + add_visual(this, depth_list[i], DirectColor); + } + add_visual(this, depth_list[i], TrueColor); + } else { + add_visual(this, depth_list[i], PseudoColor); + add_visual(this, depth_list[i], StaticColor); + } + } + add_default_visual(this); + } + if ( this->hidden->nvisuals == 0 ) { + SDL_SetError("Found no sufficiently capable X11 visuals"); + return -1; + } + + /* look up the pixel quantum for each depth */ + pf = XListPixmapFormats(SDL_Display, &np); + for(i = 0; i < this->hidden->nvisuals; i++) { + int d = this->hidden->visuals[i].depth; + for(j = 0; j < np; j++) + if(pf[j].depth == d) + break; + this->hidden->visuals[i].bpp = j < np ? pf[j].bits_per_pixel : d; + } + + XFree(pf); + } + + if ( SDL_modelist == NULL ) { + SDL_modelist = (SDL_Rect **)SDL_malloc((1+1)*sizeof(SDL_Rect *)); + if ( !SDL_modelist ) { + SDL_OutOfMemory(); + return -1; + } + n = 0; + SDL_modelist[n] = (SDL_Rect *)SDL_malloc(sizeof(SDL_Rect)); + if ( SDL_modelist[n] ) { + SDL_modelist[n]->x = 0; + SDL_modelist[n]->y = 0; + SDL_modelist[n]->w = screen_w; + SDL_modelist[n]->h = screen_h; + ++n; + } + SDL_modelist[n] = NULL; + } + +#ifdef X11MODES_DEBUG + if ( use_xinerama ) { + printf("Xinerama is enabled\n"); + } + + if ( use_xrandr ) { + printf("XRandR is enabled\n"); + } + + if ( use_vidmode ) { + printf("VidMode is enabled\n"); + } + + if ( use_xme ) { + printf("Xi Graphics XME fullscreen is enabled\n"); + } + + if ( SDL_modelist ) { + printf("X11 video mode list:\n"); + for ( i=0; SDL_modelist[i]; ++i ) { + printf("\t%dx%d\n", SDL_modelist[i]->w, SDL_modelist[i]->h); + } + } +#endif /* X11MODES_DEBUG */ + + return 0; +} + +int X11_SupportedVisual(_THIS, SDL_PixelFormat *format) +{ + int i; + for(i = 0; i < this->hidden->nvisuals; i++) + if(this->hidden->visuals[i].bpp == format->BitsPerPixel) + return 1; + return 0; +} + +SDL_Rect **X11_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags) +{ + if ( X11_SupportedVisual(this, format) ) { + if ( flags & SDL_FULLSCREEN ) { + return(SDL_modelist); + } else { + return((SDL_Rect **)-1); + } + } else { + return((SDL_Rect **)0); + } +} + +void X11_FreeVideoModes(_THIS) +{ + int i; + + if ( SDL_modelist ) { + for ( i=0; SDL_modelist[i]; ++i ) { + SDL_free(SDL_modelist[i]); + } + SDL_free(SDL_modelist); + SDL_modelist = NULL; + } + +#if SDL_VIDEO_DRIVER_X11_XRANDR + /* Free the Xrandr screen configuration */ + if ( screen_config ) { + XRRFreeScreenConfigInfo(screen_config); + screen_config = NULL; + } +#endif /* SDL_VIDEO_DRIVER_X11_XRANDR */ +} + +int X11_ResizeFullScreen(_THIS) +{ + int x = 0, y = 0; + int real_w, real_h; + int screen_w; + int screen_h; + + screen_w = DisplayWidth(SDL_Display, SDL_Screen); + screen_h = DisplayHeight(SDL_Display, SDL_Screen); + +#if SDL_VIDEO_DRIVER_X11_XINERAMA + if ( use_xinerama && + window_w <= xinerama_info.width && + window_h <= xinerama_info.height ) { + x = xinerama_info.x_org; + y = xinerama_info.y_org; + } +#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ + + if ( currently_fullscreen ) { + /* Switch resolution and cover it with the FSwindow */ + move_cursor_to(this, x, y); + set_best_resolution(this, window_w, window_h); + move_cursor_to(this, x, y); + get_real_resolution(this, &real_w, &real_h); + if ( window_w > real_w ) { + real_w = MAX(real_w, screen_w); + } + if ( window_h > real_h ) { + real_h = MAX(real_h, screen_h); + } + XMoveResizeWindow(SDL_Display, FSwindow, x, y, real_w, real_h); + move_cursor_to(this, real_w/2, real_h/2); + + /* Center and reparent the drawing window */ + x = (real_w - window_w)/2; + y = (real_h - window_h)/2; + XReparentWindow(SDL_Display, SDL_Window, FSwindow, x, y); + /* FIXME: move the mouse to the old relative location */ + XSync(SDL_Display, True); /* Flush spurious mode change events */ + } + return(1); +} + +void X11_QueueEnterFullScreen(_THIS) +{ + switch_waiting = 0x01 | SDL_FULLSCREEN; + switch_time = SDL_GetTicks() + 1500; +#if 0 /* This causes a BadMatch error if the window is iconified (not needed) */ + XSetInputFocus(SDL_Display, WMwindow, RevertToNone, CurrentTime); +#endif +} + +int X11_EnterFullScreen(_THIS) +{ + int okay; +#if 0 + Window tmpwin, *windows; + int i, nwindows; +#endif + int x = 0, y = 0; + int real_w, real_h; + int screen_w; + int screen_h; + + okay = 1; + if ( currently_fullscreen ) { + return(okay); + } + + /* Ungrab the input so that we can move the mouse around */ + X11_GrabInputNoLock(this, SDL_GRAB_OFF); + +#if SDL_VIDEO_DRIVER_X11_XINERAMA + if ( use_xinerama && + window_w <= xinerama_info.width && + window_h <= xinerama_info.height ) { + x = xinerama_info.x_org; + y = xinerama_info.y_org; + } +#endif /* SDL_VIDEO_DRIVER_X11_XINERAMA */ + + /* Map the fullscreen window to blank the screen */ + screen_w = DisplayWidth(SDL_Display, SDL_Screen); + screen_h = DisplayHeight(SDL_Display, SDL_Screen); + get_real_resolution(this, &real_w, &real_h); + real_w = MAX(window_w, MAX(real_w, screen_w)); + real_h = MAX(window_h, MAX(real_h, screen_h)); + XMoveResizeWindow(SDL_Display, FSwindow, + x, y, real_w, real_h); + XMapRaised(SDL_Display, FSwindow); + X11_WaitMapped(this, FSwindow); + +#if 0 /* This seems to break WindowMaker in focus-follows-mouse mode */ + /* Make sure we got to the top of the window stack */ + if ( XQueryTree(SDL_Display, SDL_Root, &tmpwin, &tmpwin, + &windows, &nwindows) && windows ) { + /* If not, try to put us there - if fail... oh well */ + if ( windows[nwindows-1] != FSwindow ) { + tmpwin = windows[nwindows-1]; + for ( i=0; iinput_grab | SDL_GRAB_FULLSCREEN); + } + + /* We may need to refresh the screen at this point (no backing store) + We also don't get an event, which is why we explicitly refresh. */ + if ( this->screen ) { + if ( this->screen->flags & SDL_OPENGL ) { + SDL_PrivateExpose(); + } else { + X11_RefreshDisplay(this); + } + } + + return(okay); +} + +int X11_LeaveFullScreen(_THIS) +{ + if ( currently_fullscreen ) { + XReparentWindow(SDL_Display, SDL_Window, WMwindow, 0, 0); +#if SDL_VIDEO_DRIVER_X11_VIDMODE + if ( use_vidmode ) { + restore_mode(this); + SDL_NAME(XF86VidModeLockModeSwitch)(SDL_Display, SDL_Screen, False); + } +#endif + +#if SDL_VIDEO_DRIVER_X11_XME + if ( use_xme ) { + int rw, rh; + + /* check current mode so we can avoid uneccessary mode changes */ + get_real_resolution(this, &rw, &rh); + + if (rw != saved_res.width || rh != saved_res.height) { + XiGMiscChangeResolution(SDL_Display, + SDL_Screen, + 0, /* view */ + saved_res.width, + saved_res.height, + 0); + XSync(SDL_Display, False); + } + } +#endif + +#if SDL_VIDEO_DRIVER_X11_XRANDR + if ( use_xrandr ) { + XRRSetScreenConfig(SDL_Display, screen_config, SDL_Root, + saved_size_id, saved_rotation, CurrentTime); + } +#endif + + XUnmapWindow(SDL_Display, FSwindow); + X11_WaitUnmapped(this, FSwindow); + XSync(SDL_Display, True); /* Flush spurious mode change events */ + currently_fullscreen = 0; + } + /* If we get popped out of fullscreen mode for some reason, input_grab + will still have the SDL_GRAB_FULLSCREEN flag set, since this is only + temporary. In this case, release the grab unless the input has been + explicitly grabbed. + */ + X11_GrabInputNoLock(this, this->input_grab & ~SDL_GRAB_FULLSCREEN); + + /* We may need to refresh the screen at this point (no backing store) + We also don't get an event, which is why we explicitly refresh. */ + if ( this->screen ) { + if ( this->screen->flags & SDL_OPENGL ) { + SDL_PrivateExpose(); + } else { + X11_RefreshDisplay(this); + } + } + + return(0); +} diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11modes_c.h b/apps/plugins/sdl/src/video/x11/SDL_x11modes_c.h new file mode 100644 index 0000000000..f7780bf213 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11modes_c.h @@ -0,0 +1,43 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* Utilities for getting and setting the X display mode */ + +#include "SDL_x11video.h" + +/* Define this if you want to grab the keyboard in fullscreen mode. + If you do not define this, SDL will return from SDL_SetVideoMode() + immediately, but will not actually go fullscreen until the window + manager is idle. +*/ +#define GRAB_FULLSCREEN + +extern int X11_GetVideoModes(_THIS); +extern SDL_Rect **X11_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags); +extern void X11_FreeVideoModes(_THIS); +extern int X11_ResizeFullScreen(_THIS); +extern void X11_WaitMapped(_THIS, Window win); +extern void X11_WaitUnmapped(_THIS, Window win); +extern void X11_QueueEnterFullScreen(_THIS); +extern int X11_EnterFullScreen(_THIS); +extern int X11_LeaveFullScreen(_THIS); diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11mouse.c b/apps/plugins/sdl/src/video/x11/SDL_x11mouse.c new file mode 100644 index 0000000000..16ad739195 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11mouse.c @@ -0,0 +1,288 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#include +#include + +#include "SDL_mouse.h" +#include "../../events/SDL_events_c.h" +#include "../SDL_cursor_c.h" +#include "SDL_x11dga_c.h" +#include "SDL_x11mouse_c.h" + + +/* The implementation dependent data for the window manager cursor */ +struct WMcursor { + Cursor x_cursor; +}; + + +void X11_FreeWMCursor(_THIS, WMcursor *cursor) +{ + if ( SDL_Display != NULL ) { + SDL_Lock_EventThread(); + XFreeCursor(SDL_Display, cursor->x_cursor); + XSync(SDL_Display, False); + SDL_Unlock_EventThread(); + } + SDL_free(cursor); +} + +WMcursor *X11_CreateWMCursor(_THIS, + Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y) +{ + WMcursor *cursor; + XGCValues GCvalues; + GC GCcursor; + XImage *data_image, *mask_image; + Pixmap data_pixmap, mask_pixmap; + int clen, i; + char *x_data, *x_mask; + static XColor black = { 0, 0, 0, 0 }; + static XColor white = { 0xffff, 0xffff, 0xffff, 0xffff }; + + /* Allocate the cursor memory */ + cursor = (WMcursor *)SDL_malloc(sizeof(WMcursor)); + if ( cursor == NULL ) { + SDL_OutOfMemory(); + return(NULL); + } + + /* Mix the mask and the data */ + clen = (w/8)*h; + x_data = (char *)SDL_malloc(clen); + if ( x_data == NULL ) { + SDL_free(cursor); + SDL_OutOfMemory(); + return(NULL); + } + x_mask = (char *)SDL_malloc(clen); + if ( x_mask == NULL ) { + SDL_free(cursor); + SDL_free(x_data); + SDL_OutOfMemory(); + return(NULL); + } + for ( i=0; ibyte_order = MSBFirst; + data_image->bitmap_bit_order = MSBFirst; + data_pixmap = XCreatePixmap(SDL_Display, SDL_Root, w, h, 1); + + /* Create the data mask */ + mask_image = XCreateImage(SDL_Display, + DefaultVisual(SDL_Display, SDL_Screen), + 1, XYBitmap, 0, x_mask, w, h, 8, w/8); + mask_image->byte_order = MSBFirst; + mask_image->bitmap_bit_order = MSBFirst; + mask_pixmap = XCreatePixmap(SDL_Display, SDL_Root, w, h, 1); + + /* Create the graphics context */ + GCvalues.function = GXcopy; + GCvalues.foreground = ~0; + GCvalues.background = 0; + GCvalues.plane_mask = AllPlanes; + GCcursor = XCreateGC(SDL_Display, data_pixmap, + (GCFunction|GCForeground|GCBackground|GCPlaneMask), + &GCvalues); + + /* Blit the images to the pixmaps */ + XPutImage(SDL_Display, data_pixmap, GCcursor, data_image, + 0, 0, 0, 0, w, h); + XPutImage(SDL_Display, mask_pixmap, GCcursor, mask_image, + 0, 0, 0, 0, w, h); + XFreeGC(SDL_Display, GCcursor); + /* These free the x_data and x_mask memory pointers */ + XDestroyImage(data_image); + XDestroyImage(mask_image); + + /* Create the cursor */ + cursor->x_cursor = XCreatePixmapCursor(SDL_Display, data_pixmap, + mask_pixmap, &black, &white, hot_x, hot_y); + XFreePixmap(SDL_Display, data_pixmap); + XFreePixmap(SDL_Display, mask_pixmap); + + /* Release the event thread */ + XSync(SDL_Display, False); + SDL_Unlock_EventThread(); + + return(cursor); +} + +int X11_ShowWMCursor(_THIS, WMcursor *cursor) +{ + /* Don't do anything if the display is gone */ + if ( SDL_Display == NULL ) { + return(0); + } + + /* Set the X11 cursor cursor, or blank if cursor is NULL */ + if ( SDL_Window ) { + SDL_Lock_EventThread(); + if ( cursor == NULL ) { + if ( SDL_BlankCursor != NULL ) { + XDefineCursor(SDL_Display, SDL_Window, + SDL_BlankCursor->x_cursor); + } + } else { + XDefineCursor(SDL_Display, SDL_Window, cursor->x_cursor); + } + XSync(SDL_Display, False); + SDL_Unlock_EventThread(); + } + return(1); +} + +void X11_WarpWMCursor(_THIS, Uint16 x, Uint16 y) +{ + if ( using_dga & DGA_MOUSE ) { + SDL_PrivateMouseMotion(0, 0, x, y); + } else if ( mouse_relative) { + /* RJR: March 28, 2000 + leave physical cursor at center of screen if + mouse hidden and grabbed */ + SDL_PrivateMouseMotion(0, 0, x, y); + } else { + SDL_Lock_EventThread(); + XWarpPointer(SDL_Display, None, SDL_Window, 0, 0, 0, 0, x, y); + XSync(SDL_Display, False); + SDL_Unlock_EventThread(); + } +} + +/* Sets the mouse acceleration from a string of the form: + 2/1/0 + The first number is the numerator, followed by the acceleration + denumenator and threshold. +*/ +static void SetMouseAccel(_THIS, const char *accel_param) +{ + int i; + size_t len; + int accel_value[3]; + char *mouse_param, *mouse_param_buf, *pin; + + len = SDL_strlen(accel_param)+1; + mouse_param_buf = SDL_stack_alloc(char, len); + if ( ! mouse_param_buf ) { + return; + } + SDL_strlcpy(mouse_param_buf, accel_param, len); + mouse_param = mouse_param_buf; + + for ( i=0; (i < 3) && mouse_param; ++i ) { + pin = SDL_strchr(mouse_param, '/'); + if ( pin ) { + *pin = '\0'; + } + accel_value[i] = atoi(mouse_param); + if ( pin ) { + mouse_param = pin+1; + } else { + mouse_param = NULL; + } + } + if ( i == 3 ) { + XChangePointerControl(SDL_Display, True, True, + accel_value[0], accel_value[1], accel_value[2]); + } + SDL_stack_free(mouse_param_buf); +} + +/* Check to see if we need to enter or leave mouse relative mode */ +void X11_CheckMouseModeNoLock(_THIS) +{ + const Uint8 full_focus = (SDL_APPACTIVE|SDL_APPINPUTFOCUS|SDL_APPMOUSEFOCUS); + char *env_override; + int enable_relative = 1; + + /* This happens when quiting after an xio error */ + if ( SDL_Display == NULL ) + return; + + /* Allow the user to override the relative mouse mode. + They almost never want to do this, as it seriously affects + applications that rely on continuous relative mouse motion. + */ + env_override = SDL_getenv("SDL_MOUSE_RELATIVE"); + if ( env_override ) { + enable_relative = atoi(env_override); + } + + /* If the mouse is hidden and input is grabbed, we use relative mode */ + if ( enable_relative && + !(SDL_cursorstate & CURSOR_VISIBLE) && + (this->input_grab != SDL_GRAB_OFF) && + (SDL_GetAppState() & full_focus) == full_focus ) { + if ( ! mouse_relative ) { + X11_EnableDGAMouse(this); + if ( ! (using_dga & DGA_MOUSE) ) { + char *xmouse_accel; + + SDL_GetMouseState(&mouse_last.x, &mouse_last.y); + /* Use as raw mouse mickeys as possible */ + XGetPointerControl(SDL_Display, + &mouse_accel.numerator, + &mouse_accel.denominator, + &mouse_accel.threshold); + xmouse_accel=SDL_getenv("SDL_VIDEO_X11_MOUSEACCEL"); + if ( xmouse_accel ) { + SetMouseAccel(this, xmouse_accel); + } + } + mouse_relative = 1; + } + } else { + if ( mouse_relative ) { + if ( using_dga & DGA_MOUSE ) { + X11_DisableDGAMouse(this); + } else { + XChangePointerControl(SDL_Display, True, True, + mouse_accel.numerator, + mouse_accel.denominator, + mouse_accel.threshold); + } + mouse_relative = 0; + } + } +} +void X11_CheckMouseMode(_THIS) +{ + SDL_Lock_EventThread(); + X11_CheckMouseModeNoLock(this); + SDL_Unlock_EventThread(); +} diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11mouse_c.h b/apps/plugins/sdl/src/video/x11/SDL_x11mouse_c.h new file mode 100644 index 0000000000..03d97d86f6 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11mouse_c.h @@ -0,0 +1,33 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#include "SDL_x11video.h" + +/* Functions to be exported */ +extern void X11_FreeWMCursor(_THIS, WMcursor *cursor); +extern WMcursor *X11_CreateWMCursor(_THIS, + Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y); +extern int X11_ShowWMCursor(_THIS, WMcursor *cursor); +extern void X11_WarpWMCursor(_THIS, Uint16 x, Uint16 y); +extern void X11_CheckMouseModeNoLock(_THIS); +extern void X11_CheckMouseMode(_THIS); diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11sym.h b/apps/plugins/sdl/src/video/x11/SDL_x11sym.h new file mode 100644 index 0000000000..4875b989c9 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11sym.h @@ -0,0 +1,201 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@libsdl.org +*/ + +SDL_X11_MODULE(BASEXLIB) +SDL_X11_SYM(XClassHint*,XAllocClassHint,(void),(),return) +SDL_X11_SYM(Status,XAllocColor,(Display* a,Colormap b,XColor* c),(a,b,c),return) +SDL_X11_SYM(XSizeHints*,XAllocSizeHints,(void),(),return) +SDL_X11_SYM(XWMHints*,XAllocWMHints,(void),(),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(int,XChangeWindowAttributes,(Display* a,Window b,unsigned long c,XSetWindowAttributes* d),(a,b,c,d),return) +SDL_X11_SYM(Bool,XCheckTypedEvent,(Display* a,int b,XEvent* c),(a,b,c),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(Colormap,XCreateColormap,(Display* a,Window b,Visual* c,int d),(a,b,c,d),return) +SDL_X11_SYM(Cursor,XCreatePixmapCursor,(Display* a,Pixmap b,Pixmap c,XColor* d,XColor* e,unsigned int f,unsigned int g),(a,b,c,d,e,f,g),return) +SDL_X11_SYM(GC,XCreateGC,(Display* a,Drawable b,unsigned long c,XGCValues* d),(a,b,c,d),return) +SDL_X11_SYM(XImage*,XCreateImage,(Display* a,Visual* b,unsigned int c,int d,int e,char* f,unsigned int g,unsigned int h,int i,int j),(a,b,c,d,e,f,g,h,i,j),return) +SDL_X11_SYM(Pixmap,XCreatePixmap,(Display* a,Drawable b,unsigned int c,unsigned int d,unsigned int e),(a,b,c,d,e),return) +SDL_X11_SYM(Pixmap,XCreatePixmapFromBitmapData,(Display* a,Drawable b,char* c,unsigned int d,unsigned int e,unsigned long f,unsigned long g,unsigned int h),(a,b,c,d,e,f,g,h),return) +SDL_X11_SYM(Window,XCreateSimpleWindow,(Display* a,Window b,int c,int d,unsigned int e,unsigned int f,unsigned int g,unsigned long h,unsigned long i),(a,b,c,d,e,f,g,h,i),return) +SDL_X11_SYM(Window,XCreateWindow,(Display* a,Window b,int c,int d,unsigned int e,unsigned int f,unsigned int g,int h,unsigned int i,Visual* j,unsigned long k,XSetWindowAttributes* l),(a,b,c,d,e,f,g,h,i,j,k,l),return) +SDL_X11_SYM(int,XDefineCursor,(Display* a,Window b,Cursor c),(a,b,c),return) +SDL_X11_SYM(int,XDeleteProperty,(Display* a,Window b,Atom c),(a,b,c),return) +SDL_X11_SYM(int,XDestroyWindow,(Display* a,Window b),(a,b),return) +SDL_X11_SYM(char*,XDisplayName,(_Xconst char* a),(a),return) +SDL_X11_SYM(int,XEventsQueued,(Display* a,int b),(a,b),return) +SDL_X11_SYM(Bool,XFilterEvent,(XEvent *event, Window w),(event,w),return) +SDL_X11_SYM(int,XFlush,(Display* a),(a),return) +SDL_X11_SYM(int,XFree,(void*a),(a),return) +SDL_X11_SYM(int,XFreeColormap,(Display* a,Colormap b),(a,b),return) +SDL_X11_SYM(int,XFreeColors,(Display* a,Colormap b,unsigned long* c,int d,unsigned long e),(a,b,c,d,e),return) +SDL_X11_SYM(int,XFreeCursor,(Display* a,Cursor b),(a,b),return) +SDL_X11_SYM(int,XFreeGC,(Display* a,GC b),(a,b),return) +SDL_X11_SYM(int,XFreeModifiermap,(XModifierKeymap* a),(a),return) +SDL_X11_SYM(int,XFreePixmap,(Display* a,Pixmap b),(a,b),return) +SDL_X11_SYM(int,XGetErrorDatabaseText,(Display* a,_Xconst char* b,_Xconst char* c,_Xconst char* d,char* e,int f),(a,b,c,d,e,f),return) +SDL_X11_SYM(XModifierKeymap*,XGetModifierMapping,(Display* a),(a),return) +SDL_X11_SYM(int,XGetPointerControl,(Display* a,int* b,int* c,int* d),(a,b,c,d),return) +SDL_X11_SYM(XVisualInfo*,XGetVisualInfo,(Display* a,long b,XVisualInfo* c,int* d),(a,b,c,d),return) +SDL_X11_SYM(XWMHints*,XGetWMHints,(Display* a,Window b),(a,b),return) +SDL_X11_SYM(Status,XGetWindowAttributes,(Display* a,Window b,XWindowAttributes* c),(a,b,c),return) +SDL_X11_SYM(int,XGrabKeyboard,(Display* a,Window b,Bool c,int d,int e,Time f),(a,b,c,d,e,f),return) +SDL_X11_SYM(int,XGrabPointer,(Display* a,Window b,Bool c,unsigned int d,int e,int f,Window g,Cursor h,Time i),(a,b,c,d,e,f,g,h,i),return) +SDL_X11_SYM(Status,XIconifyWindow,(Display* a,Window b,int c),(a,b,c),return) +SDL_X11_SYM(int,XInstallColormap,(Display* a,Colormap b),(a,b),return) +SDL_X11_SYM(KeyCode,XKeysymToKeycode,(Display* a,KeySym 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(int,XLookupString,(XKeyEvent* a,char* b,int c,KeySym* d,XComposeStatus* e),(a,b,c,d,e),return) +SDL_X11_SYM(int,XMapRaised,(Display* a,Window b),(a,b),return) +SDL_X11_SYM(int,XMapWindow,(Display* a,Window b),(a,b),return) +SDL_X11_SYM(int,XMaskEvent,(Display* a,long b,XEvent* c),(a,b,c),return) +SDL_X11_SYM(Status,XMatchVisualInfo,(Display* a,int b,int c,int d,XVisualInfo* e),(a,b,c,d,e),return) +SDL_X11_SYM(int,XMissingExtension,(Display* a,_Xconst char* b),(a,b),return) +SDL_X11_SYM(int,XMoveResizeWindow,(Display* a,Window b,int c,int d,unsigned int e,unsigned int f),(a,b,c,d,e,f),return) +SDL_X11_SYM(int,XMoveWindow,(Display* a,Window b,int c,int d),(a,b,c,d),return) +SDL_X11_SYM(int,XNextEvent,(Display* a,XEvent* b),(a,b),return) +SDL_X11_SYM(Display*,XOpenDisplay,(_Xconst char* a),(a),return) +SDL_X11_SYM(int,XPeekEvent,(Display* a,XEvent* b),(a,b),return) +SDL_X11_SYM(int,XPending,(Display* a),(a),return) +SDL_X11_SYM(int,XPutImage,(Display* a,Drawable b,GC c,XImage* d,int e,int f,int g,int h,unsigned int i,unsigned int j),(a,b,c,d,e,f,g,h,i,j),return) +SDL_X11_SYM(int,XQueryColors,(Display* a,Colormap b,XColor* c,int d),(a,b,c,d),return) +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) +SDL_X11_SYM(Status,XSendEvent,(Display* a,Window b,Bool c,long d,XEvent* e),(a,b,c,d,e),return) +SDL_X11_SYM(int,XSetClassHint,(Display* a,Window b,XClassHint* c),(a,b,c),return) +SDL_X11_SYM(XErrorHandler,XSetErrorHandler,(XErrorHandler a),(a),return) +SDL_X11_SYM(XIOErrorHandler,XSetIOErrorHandler,(XIOErrorHandler a),(a),return) +SDL_X11_SYM(int,XSetTransientForHint,(Display* a,Window b,Window c),(a,b,c),return) +SDL_X11_SYM(int,XSetWMHints,(Display* a,Window b,XWMHints* 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(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) +SDL_X11_SYM(int,XSetWindowBackground,(Display* a,Window b,unsigned long c),(a,b,c),return) +SDL_X11_SYM(int,XSetWindowBackgroundPixmap,(Display* a,Window b,Pixmap c),(a,b,c),return) +SDL_X11_SYM(int,XSetWindowColormap,(Display* a,Window b,Colormap c),(a,b,c),return) +SDL_X11_SYM(int,XStoreColors,(Display* a,Colormap b,XColor* c,int d),(a,b,c,d),return) +SDL_X11_SYM(Status,XStringListToTextProperty,(char** a,int b,XTextProperty* c),(a,b,c),return) +SDL_X11_SYM(int,XSync,(Display* a,Bool b),(a,b),return) +SDL_X11_SYM(int,XUngrabKeyboard,(Display* a,Time b),(a,b),return) +SDL_X11_SYM(int,XUngrabPointer,(Display* a,Time b),(a,b),return) +SDL_X11_SYM(int,XUnmapWindow,(Display* a,Window b),(a,b),return) +SDL_X11_SYM(int,XWarpPointer,(Display* a,Window b,Window c,int d,int e,unsigned int f,unsigned int g,int h, int i),(a,b,c,d,e,f,g,h,i),return) +SDL_X11_SYM(VisualID,XVisualIDFromVisual,(Visual* a),(a),return) +SDL_X11_SYM(XExtDisplayInfo*,XextAddDisplay,(XExtensionInfo* a,Display* b,char* c,XExtensionHooks* d,int e,XPointer f),(a,b,c,d,e,f),return) +SDL_X11_SYM(XExtensionInfo*,XextCreateExtension,(void),(),return) +SDL_X11_SYM(void,XextDestroyExtension,(XExtensionInfo* a),(a),) +SDL_X11_SYM(XExtDisplayInfo*,XextFindDisplay,(XExtensionInfo* a,Display* b),(a,b),return) +SDL_X11_SYM(int,XextRemoveDisplay,(XExtensionInfo* a,Display* b),(a,b),return) +SDL_X11_SYM(Bool,XQueryExtension,(Display* a,_Xconst char* b,int* c,int* d,int* e),(a,b,c,d,e),return) +SDL_X11_SYM(char *,XDisplayString,(Display* a),(a),return) +SDL_X11_SYM(int,XGetErrorText,(Display* a,int b,char* c,int d),(a,b,c,d),return) +SDL_X11_SYM(void,_XEatData,(Display* a,unsigned long b),(a,b),) +SDL_X11_SYM(void,_XFlush,(Display* a),(a),) +SDL_X11_SYM(void,_XFlushGCCache,(Display* a,GC b),(a,b),) +SDL_X11_SYM(int,_XRead,(Display* a,char* b,long c),(a,b,c),return) +SDL_X11_SYM(void,_XReadPad,(Display* a,char* b,long c),(a,b,c),) +SDL_X11_SYM(void,_XSend,(Display* a,_Xconst char* b,long c),(a,b,c),) +SDL_X11_SYM(Status,_XReply,(Display* a,xReply* b,int c,Bool d),(a,b,c,d),return) +SDL_X11_SYM(unsigned long,_XSetLastRequestRead,(Display* a,xGenericReply* b),(a,b),return) +SDL_X11_SYM(SDL_X11_XSynchronizeRetType,XSynchronize,(Display* a,Bool b),(a,b),return) +SDL_X11_SYM(SDL_X11_XESetWireToEventRetType,XESetWireToEvent,(Display* a,int b,SDL_X11_XESetWireToEventRetType c),(a,b,c),return) +SDL_X11_SYM(SDL_X11_XESetEventToWireRetType,XESetEventToWire,(Display* a,int b,SDL_X11_XESetEventToWireRetType c),(a,b,c),return) +SDL_X11_SYM(XExtensionErrorHandler,XSetExtensionErrorHandler,(XExtensionErrorHandler a),(a),return) + +#if NeedWidePrototypes +SDL_X11_SYM(KeySym,XKeycodeToKeysym,(Display* a,unsigned int b,int c),(a,b,c),return) +#else +SDL_X11_SYM(KeySym,XKeycodeToKeysym,(Display* a,KeyCode b,int c),(a,b,c),return) +#endif + +#ifdef X_HAVE_UTF8_STRING +SDL_X11_MODULE(UTF8) +SDL_X11_SYM(int,Xutf8TextListToTextProperty,(Display* a,char** b,int c,XICCEncodingStyle d,XTextProperty* e),(a,b,c,d,e),return) +SDL_X11_SYM(int,Xutf8LookupString,(XIC a,XKeyPressedEvent* b,char* c,int d,KeySym* e,Status* f),(a,b,c,d,e,f),return) +/*SDL_X11_SYM(XIC,XCreateIC,(XIM, ...),return) !!! ARGH! */ +SDL_X11_SYM(void,XDestroyIC,(XIC a),(a),) +SDL_X11_SYM(void,XSetICFocus,(XIC a),(a),) +SDL_X11_SYM(void,XUnsetICFocus,(XIC a),(a),) +/*SDL_X11_SYM(char*,XGetICValues,(XIC a, ...),return)*/ +SDL_X11_SYM(XIM,XOpenIM,(Display* a,struct _XrmHashBucketRec* b,char* c,char* d),(a,b,c,d),return) +SDL_X11_SYM(Status,XCloseIM,(XIM a),(a),return) +SDL_X11_SYM(char*,XSetLocaleModifiers,(_Xconst char* a),(a),return) +SDL_X11_SYM(int,XRefreshKeyboardMapping,(XMappingEvent* a),(a),return) +SDL_X11_SYM(Display*,XDisplayOfIM,(XIM a),(a),return) +#endif + +#ifndef NO_SHARED_MEMORY +SDL_X11_MODULE(SHM) +SDL_X11_SYM(Status,XShmAttach,(Display* a,XShmSegmentInfo* b),(a,b),return) +SDL_X11_SYM(Status,XShmDetach,(Display* a,XShmSegmentInfo* b),(a,b),return) +SDL_X11_SYM(Status,XShmPutImage,(Display* a,Drawable b,GC c,XImage* d,int e,int f,int g,int h,unsigned int i,unsigned int j,Bool k),(a,b,c,d,e,f,g,h,i,j,k),return) +SDL_X11_SYM(XImage*,XShmCreateImage,(Display* a,Visual* b,unsigned int c,int d,char* e,XShmSegmentInfo* f,unsigned int g,unsigned int h),(a,b,c,d,e,f,g,h),return) +SDL_X11_SYM(Bool,XShmQueryExtension,(Display* a),(a),return) +#endif + +/* + * Not required...these only exist in code in headers on some 64-bit platforms, + * and are removed via macros elsewhere, so it's safe for them to be missing. + */ +#ifdef LONG64 +SDL_X11_MODULE(IO_32BIT) +SDL_X11_SYM(int,_XData32,(Display *dpy,register long *data,unsigned len),(dpy,data,len),return) +SDL_X11_SYM(void,_XRead32,(Display *dpy,register long *data,long len),(dpy,data,len),) +#endif + +/* + * libX11 1.4.99.1 added _XGetRequest, and macros use it behind the scenes. + */ +SDL_X11_MODULE(XGETREQUEST) +SDL_X11_SYM(void *,_XGetRequest,(Display* a,CARD8 b,size_t c),(a,b,c),return) + +/* + * These only show up on some variants of Unix. + */ +#if defined(__osf__) +SDL_X11_MODULE(OSF_ENTRY_POINTS) +SDL_X11_SYM(void,_SmtBufferOverflow,(Display *dpy,register smtDisplayPtr p),(dpy,p),) +SDL_X11_SYM(void,_SmtIpError,(Display *dpy,register smtDisplayPtr p, int i),(dpy,p,i),) +SDL_X11_SYM(int,ipAllocateData,(ChannelPtr a, IPCard b, IPDataPtr * c),(a,b,c),return) +SDL_X11_SYM(int,ipUnallocateAndSendData,(ChannelPtr a, IPCard b),(a,b),return) +#endif + +/* Xrandr support. */ +#if SDL_VIDEO_DRIVER_X11_XRANDR +SDL_X11_MODULE(XRANDR) +SDL_X11_SYM(Status,XRRQueryVersion,(Display *dpy,int *major_versionp,int *minor_versionp),(dpy,major_versionp,minor_versionp),return) +SDL_X11_SYM(XRRScreenConfiguration *,XRRGetScreenInfo,(Display *dpy,Drawable draw),(dpy,draw),return) +SDL_X11_SYM(SizeID,XRRConfigCurrentConfiguration,(XRRScreenConfiguration *config,Rotation *rotation),(config,rotation),return) +SDL_X11_SYM(XRRScreenSize *,XRRConfigSizes,(XRRScreenConfiguration *config, int *nsizes),(config,nsizes),return) +SDL_X11_SYM(Status,XRRSetScreenConfig,(Display *dpy, XRRScreenConfiguration *config, Drawable draw, int size_index, Rotation rotation, Time timestamp),(dpy,config,draw,size_index,rotation,timestamp),return) +SDL_X11_SYM(void,XRRFreeScreenConfigInfo,(XRRScreenConfiguration *config),(config),) +#endif + +/* end of SDL_x11sym.h ... */ + diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11video.c b/apps/plugins/sdl/src/video/x11/SDL_x11video.c new file mode 100644 index 0000000000..f7d80732c0 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11video.c @@ -0,0 +1,1571 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* X11 based SDL video driver implementation. + Note: This implementation does not currently need X11 thread locking, + since the event thread uses a separate X connection and any + additional locking necessary is handled internally. However, + if full locking is neccessary, take a look at XInitThreads(). +*/ + +#include +#include +#ifdef MTRR_SUPPORT +#include +#include +#endif + +#include "SDL_endian.h" +#include "SDL_timer.h" +#include "SDL_thread.h" +#include "SDL_video.h" +#include "SDL_mouse.h" +#include "../SDL_sysvideo.h" +#include "../SDL_pixels_c.h" +#include "../../events/SDL_events_c.h" +#include "SDL_x11video.h" +#include "SDL_x11wm_c.h" +#include "SDL_x11mouse_c.h" +#include "SDL_x11events_c.h" +#include "SDL_x11modes_c.h" +#include "SDL_x11image_c.h" +#include "SDL_x11yuv_c.h" +#include "SDL_x11gl_c.h" +#include "SDL_x11gamma_c.h" +#include "../blank_cursor.h" + +#ifdef X_HAVE_UTF8_STRING +#include +#endif + +/* Initialization/Query functions */ +static int X11_VideoInit(_THIS, SDL_PixelFormat *vformat); +static SDL_Surface *X11_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags); +static int X11_ToggleFullScreen(_THIS, int on); +static void X11_UpdateMouse(_THIS); +static int X11_SetColors(_THIS, int firstcolor, int ncolors, + SDL_Color *colors); +static int X11_SetGammaRamp(_THIS, Uint16 *ramp); +static void X11_VideoQuit(_THIS); + + +/* X11 driver bootstrap functions */ + +static int X11_Available(void) +{ + Display *display = NULL; + if ( SDL_X11_LoadSymbols() ) { + display = XOpenDisplay(NULL); + if ( display != NULL ) { + XCloseDisplay(display); + } + SDL_X11_UnloadSymbols(); + } + return(display != NULL); +} + +static void X11_DeleteDevice(SDL_VideoDevice *device) +{ + if ( device ) { + if ( device->hidden ) { + SDL_free(device->hidden); + } + if ( device->gl_data ) { + SDL_free(device->gl_data); + } + SDL_free(device); + SDL_X11_UnloadSymbols(); + } +} + +static SDL_VideoDevice *X11_CreateDevice(int devindex) +{ + SDL_VideoDevice *device = NULL; + + if ( SDL_X11_LoadSymbols() ) { + /* Initialize all variables that we clean on shutdown */ + device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice)); + if ( device ) { + SDL_memset(device, 0, (sizeof *device)); + device->hidden = (struct SDL_PrivateVideoData *) + SDL_malloc((sizeof *device->hidden)); + device->gl_data = (struct SDL_PrivateGLData *) + SDL_malloc((sizeof *device->gl_data)); + } + if ( (device == NULL) || (device->hidden == NULL) || + (device->gl_data == NULL) ) { + SDL_OutOfMemory(); + X11_DeleteDevice(device); /* calls SDL_X11_UnloadSymbols(). */ + return(0); + } + SDL_memset(device->hidden, 0, (sizeof *device->hidden)); + SDL_memset(device->gl_data, 0, (sizeof *device->gl_data)); + +#if SDL_VIDEO_OPENGL_GLX + device->gl_data->swap_interval = -1; +#endif + + /* Set the driver flags */ + device->handles_any_size = 1; + + /* Set the function pointers */ + device->VideoInit = X11_VideoInit; + device->ListModes = X11_ListModes; + device->SetVideoMode = X11_SetVideoMode; + device->ToggleFullScreen = X11_ToggleFullScreen; + device->UpdateMouse = X11_UpdateMouse; +#if SDL_VIDEO_DRIVER_X11_XV + device->CreateYUVOverlay = X11_CreateYUVOverlay; +#endif + device->SetColors = X11_SetColors; + device->UpdateRects = NULL; + device->VideoQuit = X11_VideoQuit; + device->AllocHWSurface = X11_AllocHWSurface; + device->CheckHWBlit = NULL; + device->FillHWRect = NULL; + device->SetHWColorKey = NULL; + device->SetHWAlpha = NULL; + device->LockHWSurface = X11_LockHWSurface; + device->UnlockHWSurface = X11_UnlockHWSurface; + device->FlipHWSurface = X11_FlipHWSurface; + device->FreeHWSurface = X11_FreeHWSurface; + device->SetGamma = X11_SetVidModeGamma; + device->GetGamma = X11_GetVidModeGamma; + device->SetGammaRamp = X11_SetGammaRamp; + device->GetGammaRamp = NULL; +#if SDL_VIDEO_OPENGL_GLX + device->GL_LoadLibrary = X11_GL_LoadLibrary; + device->GL_GetProcAddress = X11_GL_GetProcAddress; + device->GL_GetAttribute = X11_GL_GetAttribute; + device->GL_MakeCurrent = X11_GL_MakeCurrent; + device->GL_SwapBuffers = X11_GL_SwapBuffers; +#endif + device->SetCaption = X11_SetCaption; + device->SetIcon = X11_SetIcon; + device->IconifyWindow = X11_IconifyWindow; + device->GrabInput = X11_GrabInput; + device->GetWMInfo = X11_GetWMInfo; + device->FreeWMCursor = X11_FreeWMCursor; + device->CreateWMCursor = X11_CreateWMCursor; + device->ShowWMCursor = X11_ShowWMCursor; + device->WarpWMCursor = X11_WarpWMCursor; + device->CheckMouseMode = X11_CheckMouseMode; + device->InitOSKeymap = X11_InitOSKeymap; + device->PumpEvents = X11_PumpEvents; + + device->free = X11_DeleteDevice; + } + + return device; +} + +VideoBootStrap X11_bootstrap = { + "x11", "X Window System", + X11_Available, X11_CreateDevice +}; + +/* Normal X11 error handler routine */ +static int (*X_handler)(Display *, XErrorEvent *) = NULL; +static int x_errhandler(Display *d, XErrorEvent *e) +{ +#if SDL_VIDEO_DRIVER_X11_VIDMODE + extern int vm_error; +#endif +#if SDL_VIDEO_DRIVER_X11_DGAMOUSE + extern int dga_error; +#endif + +#if SDL_VIDEO_DRIVER_X11_VIDMODE + /* VidMode errors are non-fatal. :) */ + /* Are the errors offset by one from the error base? + e.g. the error base is 143, the code is 148, and the + actual error is XF86VidModeExtensionDisabled (4) ? + */ + if ( (vm_error >= 0) && + (((e->error_code == BadRequest)&&(e->request_code == vm_error)) || + ((e->error_code > vm_error) && + (e->error_code <= (vm_error+XF86VidModeNumberErrors)))) ) { +#ifdef X11_DEBUG +{ char errmsg[1024]; + XGetErrorText(d, e->error_code, errmsg, sizeof(errmsg)); +printf("VidMode error: %s\n", errmsg); +} +#endif + return(0); + } +#endif /* SDL_VIDEO_DRIVER_X11_VIDMODE */ + +#if SDL_VIDEO_DRIVER_X11_DGAMOUSE + /* DGA errors can be non-fatal. :) */ + if ( (dga_error >= 0) && + ((e->error_code > dga_error) && + (e->error_code <= (dga_error+XF86DGANumberErrors))) ) { +#ifdef X11_DEBUG +{ char errmsg[1024]; + XGetErrorText(d, e->error_code, errmsg, sizeof(errmsg)); +printf("DGA error: %s\n", errmsg); +} +#endif + return(0); + } +#endif /* SDL_VIDEO_DRIVER_X11_DGAMOUSE */ + + return(X_handler(d,e)); +} + +/* X11 I/O error handler routine */ +static int (*XIO_handler)(Display *) = NULL; +static int xio_errhandler(Display *d) +{ + /* Ack! Lost X11 connection! */ + + /* We will crash if we try to clean up our display */ + if ( SDL_VideoSurface && current_video->hidden->Ximage ) { + SDL_VideoSurface->pixels = NULL; + } + current_video->hidden->X11_Display = NULL; + + /* Continue with the standard X11 error handler */ + return(XIO_handler(d)); +} + +static int (*Xext_handler)(Display *, _Xconst char *, _Xconst char *) = NULL; +static int xext_errhandler(Display *d, _Xconst char *ext, _Xconst char *reason) +{ +#ifdef X11_DEBUG + printf("Xext error inside SDL (may be harmless):\n"); + printf(" Extension \"%s\" %s on display \"%s\".\n", + ext, reason, XDisplayString(d)); +#endif + + if (SDL_strcmp(reason, "missing") == 0) { + /* + * Since the query itself, elsewhere, can handle a missing extension + * and the default behaviour in Xlib is to write to stderr, which + * generates unnecessary bug reports, we just ignore these. + */ + return 0; + } + + /* Everything else goes to the default handler... */ + return Xext_handler(d, ext, reason); +} + +/* Find out what class name we should use */ +static char *get_classname(char *classname, int maxlen) +{ + char *spot; +#if defined(__LINUX__) || defined(__FREEBSD__) + char procfile[1024]; + char linkfile[1024]; + int linksize; +#endif + + /* First allow environment variable override */ + spot = SDL_getenv("SDL_VIDEO_X11_WMCLASS"); + if ( spot ) { + SDL_strlcpy(classname, spot, maxlen); + return classname; + } + + /* Next look at the application's executable name */ +#if defined(__LINUX__) || defined(__FREEBSD__) +#if defined(__LINUX__) + SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/exe", getpid()); +#elif defined(__FREEBSD__) + SDL_snprintf(procfile, SDL_arraysize(procfile), "/proc/%d/file", getpid()); +#else +#error Where can we find the executable name? +#endif + linksize = readlink(procfile, linkfile, sizeof(linkfile)-1); + if ( linksize > 0 ) { + linkfile[linksize] = '\0'; + spot = SDL_strrchr(linkfile, '/'); + if ( spot ) { + SDL_strlcpy(classname, spot+1, maxlen); + } else { + SDL_strlcpy(classname, linkfile, maxlen); + } + return classname; + } +#endif /* __LINUX__ */ + + /* Finally use the default we've used forever */ + SDL_strlcpy(classname, "SDL_App", maxlen); + return classname; +} + +/* Create auxiliary (toplevel) windows with the current visual */ +static void create_aux_windows(_THIS) +{ + int x = 0, y = 0; + char classname[1024]; + XSetWindowAttributes xattr; + XWMHints *hints; + unsigned long app_event_mask; + int def_vis = (SDL_Visual == DefaultVisual(SDL_Display, SDL_Screen)); + + /* Look up some useful Atoms */ + WM_DELETE_WINDOW = XInternAtom(SDL_Display, "WM_DELETE_WINDOW", False); + + /* Don't create any extra windows if we are being managed */ + if ( SDL_windowid ) { + FSwindow = 0; + WMwindow = SDL_strtol(SDL_windowid, NULL, 0); + return; + } + + if(FSwindow) + XDestroyWindow(SDL_Display, FSwindow); + +#if SDL_VIDEO_DRIVER_X11_XINERAMA + if ( use_xinerama ) { + x = xinerama_info.x_org; + y = xinerama_info.y_org; + } +#endif + xattr.override_redirect = True; + xattr.background_pixel = def_vis ? BlackPixel(SDL_Display, SDL_Screen) : 0; + xattr.border_pixel = 0; + xattr.colormap = SDL_XColorMap; + + FSwindow = XCreateWindow(SDL_Display, SDL_Root, + x, y, 32, 32, 0, + this->hidden->depth, InputOutput, SDL_Visual, + CWOverrideRedirect | CWBackPixel | CWBorderPixel + | CWColormap, + &xattr); + + XSelectInput(SDL_Display, FSwindow, StructureNotifyMask); + + /* Tell KDE to keep the fullscreen window on top */ + { + XEvent ev; + long mask; + + SDL_memset(&ev, 0, sizeof(ev)); + ev.xclient.type = ClientMessage; + ev.xclient.window = SDL_Root; + ev.xclient.message_type = XInternAtom(SDL_Display, + "KWM_KEEP_ON_TOP", False); + ev.xclient.format = 32; + ev.xclient.data.l[0] = FSwindow; + ev.xclient.data.l[1] = CurrentTime; + mask = SubstructureRedirectMask; + XSendEvent(SDL_Display, SDL_Root, False, mask, &ev); + } + + hints = NULL; + if(WMwindow) { + /* All window attributes must survive the recreation */ + hints = XGetWMHints(SDL_Display, WMwindow); + XDestroyWindow(SDL_Display, WMwindow); + } + + /* Create the window for windowed management */ + /* (reusing the xattr structure above) */ + WMwindow = XCreateWindow(SDL_Display, SDL_Root, + x, y, 32, 32, 0, + this->hidden->depth, InputOutput, SDL_Visual, + CWBackPixel | CWBorderPixel | CWColormap, + &xattr); + + /* Set the input hints so we get keyboard input */ + if(!hints) { + hints = XAllocWMHints(); + hints->input = True; + hints->flags = InputHint; + } + XSetWMHints(SDL_Display, WMwindow, hints); + XFree(hints); + X11_SetCaptionNoLock(this, this->wm_title, this->wm_icon); + + app_event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask + | PropertyChangeMask | StructureNotifyMask | KeymapStateMask; + XSelectInput(SDL_Display, WMwindow, app_event_mask); + + /* Set the class hints so we can get an icon (AfterStep) */ + get_classname(classname, sizeof(classname)); + { + XClassHint *classhints; + classhints = XAllocClassHint(); + if(classhints != NULL) { + classhints->res_name = classname; + classhints->res_class = classname; + XSetClassHint(SDL_Display, WMwindow, classhints); + XFree(classhints); + } + } + + { + pid_t pid = getpid(); + char hostname[256]; + + if (pid > 0 && gethostname(hostname, sizeof(hostname)) > -1) { + Atom _NET_WM_PID = XInternAtom(SDL_Display, "_NET_WM_PID", False); + Atom WM_CLIENT_MACHINE = XInternAtom(SDL_Display, "WM_CLIENT_MACHINE", False); + + hostname[sizeof(hostname)-1] = '\0'; + XChangeProperty(SDL_Display, WMwindow, _NET_WM_PID, XA_CARDINAL, 32, + PropModeReplace, (unsigned char *)&pid, 1); + XChangeProperty(SDL_Display, WMwindow, WM_CLIENT_MACHINE, XA_STRING, 8, + PropModeReplace, (unsigned char *)hostname, SDL_strlen(hostname)); + } + } + + /* Setup the communication with the IM server */ + /* create_aux_windows may be called several times against the same + Display. We should reuse the SDL_IM if one has been opened for + the Display, so we should not simply reset SDL_IM here. */ + + #ifdef X_HAVE_UTF8_STRING + if (SDL_X11_HAVE_UTF8) { + /* Discard obsolete resources if any. */ + if (SDL_IM != NULL && SDL_Display != XDisplayOfIM(SDL_IM)) { + /* Just a double check. I don't think this + code is ever executed. */ + SDL_SetError("display has changed while an IM is kept"); + if (SDL_IC) { + XUnsetICFocus(SDL_IC); + XDestroyIC(SDL_IC); + SDL_IC = NULL; + } + XCloseIM(SDL_IM); + SDL_IM = NULL; + } + + /* Open an input method. */ + if (SDL_IM == NULL) { + char *old_locale = NULL, *old_modifiers = NULL; + const char *p; + size_t n; + /* I'm not comfortable to do locale setup + here. However, we need C library locale + (and xlib modifiers) to be set based on the + user's preference to use XIM, and many + existing game programs doesn't take care of + users' locale preferences, so someone other + than the game program should do it. + Moreover, ones say that some game programs + heavily rely on the C locale behaviour, + e.g., strcol()'s, and we can't change the C + library locale. Given the situation, I + couldn't find better place to do the + job... */ + + /* Save the current (application program's) + locale settings. */ + p = setlocale(LC_ALL, NULL); + if ( p ) { + n = SDL_strlen(p)+1; + old_locale = SDL_stack_alloc(char, n); + if ( old_locale ) { + SDL_strlcpy(old_locale, p, n); + } + } + p = XSetLocaleModifiers(NULL); + if ( p ) { + n = SDL_strlen(p)+1; + old_modifiers = SDL_stack_alloc(char, n); + if ( old_modifiers ) { + SDL_strlcpy(old_modifiers, p, n); + } + } + + /* Fetch the user's preferences and open the + input method with them. */ + setlocale(LC_ALL, ""); + XSetLocaleModifiers(""); + SDL_IM = XOpenIM(SDL_Display, NULL, classname, classname); + + /* Restore the application's locale settings + so that we don't break the application's + expected behaviour. */ + if ( old_locale ) { + /* We need to restore the C library + locale first, since the + interpretation of the X modifier + may depend on it. */ + setlocale(LC_ALL, old_locale); + SDL_stack_free(old_locale); + } + if ( old_modifiers ) { + XSetLocaleModifiers(old_modifiers); + SDL_stack_free(old_modifiers); + } + } + + /* Create a new input context for the new window just created. */ + if (SDL_IM == NULL) { + SDL_SetError("no input method could be opened"); + } else { + if (SDL_IC != NULL) { + /* Discard the old IC before creating new one. */ + XUnsetICFocus(SDL_IC); + XDestroyIC(SDL_IC); + } + /* Theoretically we should check the current IM supports + PreeditNothing+StatusNothing style (i.e., root window method) + before creating the IC. However, it is the bottom line method, + and we supports any other options. If the IM didn't support + root window method, the following call fails, and SDL falls + back to pre-XIM keyboard handling. */ + SDL_IC = pXCreateIC(SDL_IM, + XNClientWindow, WMwindow, + XNFocusWindow, WMwindow, + XNInputStyle, XIMPreeditNothing | XIMStatusNothing, + XNResourceName, classname, + XNResourceClass, classname, + NULL); + + if (SDL_IC == NULL) { + SDL_SetError("no input context could be created"); + XCloseIM(SDL_IM); + SDL_IM = NULL; + } else { + /* We need to receive X events that an IM wants and to pass + them to the IM through XFilterEvent. The set of events may + vary depending on the IM implementation and the options + specified through various routes. Although unlikely, the + xlib specification allows IM to change the event requirement + with its own circumstances, it is safe to call SelectInput + whenever we re-create an IC. */ + unsigned long mask = 0; + char *ret = pXGetICValues(SDL_IC, XNFilterEvents, &mask, NULL); + if (ret != NULL) { + XUnsetICFocus(SDL_IC); + XDestroyIC(SDL_IC); + SDL_IC = NULL; + SDL_SetError("no input context could be created"); + XCloseIM(SDL_IM); + SDL_IM = NULL; + } else { + XSelectInput(SDL_Display, WMwindow, app_event_mask | mask); + XSetICFocus(SDL_IC); + } + } + } + } + #endif + + /* Allow the window to be deleted by the window manager */ + XSetWMProtocols(SDL_Display, WMwindow, &WM_DELETE_WINDOW, 1); +} + +static int X11_VideoInit(_THIS, SDL_PixelFormat *vformat) +{ + const char *env; + char *display; + int i; + + /* Open the X11 display */ + display = NULL; /* Get it from DISPLAY environment variable */ + + if ( (SDL_strncmp(XDisplayName(display), ":", 1) == 0) || + (SDL_strncmp(XDisplayName(display), "unix:", 5) == 0) ) { + local_X11 = 1; + } else { + local_X11 = 0; + } + SDL_Display = XOpenDisplay(display); +#if defined(__osf__) && defined(SDL_VIDEO_DRIVER_X11_DYNAMIC) + /* On Tru64 if linking without -lX11, it fails and you get following message. + * Xlib: connection to ":0.0" refused by server + * Xlib: XDM authorization key matches an existing client! + * + * It succeeds if retrying 1 second later + * or if running xhost +localhost on shell. + * + */ + if ( SDL_Display == NULL ) { + SDL_Delay(1000); + SDL_Display = XOpenDisplay(display); + } +#endif + if ( SDL_Display == NULL ) { + SDL_SetError("Couldn't open X11 display"); + return(-1); + } +#ifdef X11_DEBUG + XSynchronize(SDL_Display, True); +#endif + + /* Create an alternate X display for graphics updates -- allows us + to do graphics updates in a separate thread from event handling. + Thread-safe X11 doesn't seem to exist. + */ + GFX_Display = XOpenDisplay(display); + if ( GFX_Display == NULL ) { + XCloseDisplay(SDL_Display); + SDL_Display = NULL; + SDL_SetError("Couldn't open X11 display"); + return(-1); + } + + /* Set the normal X error handler */ + X_handler = XSetErrorHandler(x_errhandler); + + /* Set the error handler if we lose the X display */ + XIO_handler = XSetIOErrorHandler(xio_errhandler); + + /* Set the X extension error handler */ + Xext_handler = XSetExtensionErrorHandler(xext_errhandler); + + /* use default screen (from $DISPLAY) */ + SDL_Screen = DefaultScreen(SDL_Display); + +#ifndef NO_SHARED_MEMORY + /* Check for MIT shared memory extension */ + use_mitshm = 0; + if ( local_X11 ) { + use_mitshm = XShmQueryExtension(SDL_Display); + } +#endif /* NO_SHARED_MEMORY */ + + /* Get the available video modes */ + if(X11_GetVideoModes(this) < 0) { + XCloseDisplay(GFX_Display); + GFX_Display = NULL; + XCloseDisplay(SDL_Display); + SDL_Display = NULL; + return -1; + } + + /* Determine the current screen size */ + this->info.current_w = DisplayWidth(SDL_Display, SDL_Screen); + this->info.current_h = DisplayHeight(SDL_Display, SDL_Screen); + + /* Determine the default screen depth: + Use the default visual (or at least one with the same depth) */ + SDL_DisplayColormap = DefaultColormap(SDL_Display, SDL_Screen); + for(i = 0; i < this->hidden->nvisuals; i++) + if(this->hidden->visuals[i].depth == DefaultDepth(SDL_Display, + SDL_Screen)) + break; + if(i == this->hidden->nvisuals) { + /* default visual was useless, take the deepest one instead */ + i = 0; + } + SDL_Visual = this->hidden->visuals[i].visual; + if ( SDL_Visual == DefaultVisual(SDL_Display, SDL_Screen) ) { + SDL_XColorMap = SDL_DisplayColormap; + } else { + SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root, + SDL_Visual, AllocNone); + } + this->hidden->depth = this->hidden->visuals[i].depth; + vformat->BitsPerPixel = this->hidden->visuals[i].bpp; + if ( vformat->BitsPerPixel > 8 ) { + vformat->Rmask = SDL_Visual->red_mask; + vformat->Gmask = SDL_Visual->green_mask; + vformat->Bmask = SDL_Visual->blue_mask; + } + if ( this->hidden->depth == 32 ) { + vformat->Amask = (0xFFFFFFFF & ~(vformat->Rmask|vformat->Gmask|vformat->Bmask)); + } + X11_SaveVidModeGamma(this); + + /* Allow environment override of screensaver disable. */ + env = SDL_getenv("SDL_VIDEO_ALLOW_SCREENSAVER"); + if ( env ) { + allow_screensaver = SDL_atoi(env); + } else { +#ifdef SDL_VIDEO_DISABLE_SCREENSAVER + allow_screensaver = 0; +#else + allow_screensaver = 1; +#endif + } + + /* See if we have been passed a window to use */ + SDL_windowid = SDL_getenv("SDL_WINDOWID"); + + /* Create the fullscreen and managed windows */ + create_aux_windows(this); + + /* Create the blank cursor */ + SDL_BlankCursor = this->CreateWMCursor(this, blank_cdata, blank_cmask, + BLANK_CWIDTH, BLANK_CHEIGHT, + BLANK_CHOTX, BLANK_CHOTY); + + /* Fill in some window manager capabilities */ + this->info.wm_available = 1; + + /* We're done! */ + XFlush(SDL_Display); + return(0); +} + +static void X11_DestroyWindow(_THIS, SDL_Surface *screen) +{ + /* Clean up OpenGL */ + if ( screen ) { + screen->flags &= ~(SDL_OPENGL|SDL_OPENGLBLIT); + } + X11_GL_Shutdown(this); + + if ( ! SDL_windowid ) { + /* Hide the managed window */ + if ( WMwindow ) { + XUnmapWindow(SDL_Display, WMwindow); + } + if ( screen && (screen->flags & SDL_FULLSCREEN) ) { + screen->flags &= ~SDL_FULLSCREEN; + X11_LeaveFullScreen(this); + } + + /* Destroy the output window */ + if ( SDL_Window ) { + XDestroyWindow(SDL_Display, SDL_Window); + } + + /* Free the colormap entries */ + if ( SDL_XPixels ) { + int numcolors; + unsigned long pixel; + numcolors = SDL_Visual->map_entries; + for ( pixel=0; pixel 0 ) { + XFreeColors(GFX_Display, + SDL_DisplayColormap,&pixel,1,0); + --SDL_XPixels[pixel]; + } + } + SDL_free(SDL_XPixels); + SDL_XPixels = NULL; + } + + /* Free the graphics context */ + if ( SDL_GC ) { + XFreeGC(SDL_Display, SDL_GC); + SDL_GC = 0; + } + } +} + +static SDL_bool X11_WindowPosition(_THIS, int *x, int *y, int w, int h) +{ + const char *window = SDL_getenv("SDL_VIDEO_WINDOW_POS"); + const char *center = SDL_getenv("SDL_VIDEO_CENTERED"); + if ( window ) { + if ( SDL_sscanf(window, "%d,%d", x, y) == 2 ) { + return SDL_TRUE; + } + if ( SDL_strcmp(window, "center") == 0 ) { + center = window; + } + } + if ( center ) { + *x = (DisplayWidth(SDL_Display, SDL_Screen) - w)/2; + *y = (DisplayHeight(SDL_Display, SDL_Screen) - h)/2; + return SDL_TRUE; + } + return SDL_FALSE; +} + +static void X11_SetSizeHints(_THIS, int w, int h, Uint32 flags) +{ + XSizeHints *hints; + + hints = XAllocSizeHints(); + if ( hints ) { + if (!(flags & SDL_RESIZABLE)) { + hints->min_width = hints->max_width = w; + hints->min_height = hints->max_height = h; + hints->flags = PMaxSize | PMinSize; + } + if ( flags & SDL_FULLSCREEN ) { + hints->x = 0; + hints->y = 0; + hints->flags |= USPosition; + } else + /* Center it, if desired */ + if ( X11_WindowPosition(this, &hints->x, &hints->y, w, h) ) { + hints->flags |= USPosition; + + /* Hints must be set before moving the window, otherwise an + unwanted ConfigureNotify event will be issued */ + XSetWMNormalHints(SDL_Display, WMwindow, hints); + + XMoveWindow(SDL_Display, WMwindow, hints->x, hints->y); + + /* Flush the resize event so we don't catch it later */ + XSync(SDL_Display, True); + } + XSetWMNormalHints(SDL_Display, WMwindow, hints); + XFree(hints); + } + + /* Respect the window caption style */ + if ( flags & SDL_NOFRAME ) { + SDL_bool set; + Atom WM_HINTS; + + /* We haven't modified the window manager hints yet */ + set = SDL_FALSE; + + /* First try to set MWM hints */ + WM_HINTS = XInternAtom(SDL_Display, "_MOTIF_WM_HINTS", True); + if ( WM_HINTS != None ) { + /* Hints used by Motif compliant window managers */ + struct { + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long input_mode; + unsigned long status; + } MWMHints = { (1L << 1), 0, 0, 0, 0 }; + + XChangeProperty(SDL_Display, WMwindow, + WM_HINTS, WM_HINTS, 32, + PropModeReplace, + (unsigned char *)&MWMHints, + sizeof(MWMHints)/sizeof(long)); + set = SDL_TRUE; + } + /* Now try to set KWM hints */ + WM_HINTS = XInternAtom(SDL_Display, "KWM_WIN_DECORATION", True); + if ( WM_HINTS != None ) { + long KWMHints = 0; + + XChangeProperty(SDL_Display, WMwindow, + WM_HINTS, WM_HINTS, 32, + PropModeReplace, + (unsigned char *)&KWMHints, + sizeof(KWMHints)/sizeof(long)); + set = SDL_TRUE; + } + /* Now try to set GNOME hints */ + WM_HINTS = XInternAtom(SDL_Display, "_WIN_HINTS", True); + if ( WM_HINTS != None ) { + long GNOMEHints = 0; + + XChangeProperty(SDL_Display, WMwindow, + WM_HINTS, WM_HINTS, 32, + PropModeReplace, + (unsigned char *)&GNOMEHints, + sizeof(GNOMEHints)/sizeof(long)); + set = SDL_TRUE; + } + /* Finally set the transient hints if necessary */ + if ( ! set ) { + XSetTransientForHint(SDL_Display, WMwindow, SDL_Root); + } + } else { + SDL_bool set; + Atom WM_HINTS; + + /* We haven't modified the window manager hints yet */ + set = SDL_FALSE; + + /* First try to unset MWM hints */ + WM_HINTS = XInternAtom(SDL_Display, "_MOTIF_WM_HINTS", True); + if ( WM_HINTS != None ) { + XDeleteProperty(SDL_Display, WMwindow, WM_HINTS); + set = SDL_TRUE; + } + /* Now try to unset KWM hints */ + WM_HINTS = XInternAtom(SDL_Display, "KWM_WIN_DECORATION", True); + if ( WM_HINTS != None ) { + XDeleteProperty(SDL_Display, WMwindow, WM_HINTS); + set = SDL_TRUE; + } + /* Now try to unset GNOME hints */ + WM_HINTS = XInternAtom(SDL_Display, "_WIN_HINTS", True); + if ( WM_HINTS != None ) { + XDeleteProperty(SDL_Display, WMwindow, WM_HINTS); + set = SDL_TRUE; + } + /* Finally unset the transient hints if necessary */ + if ( ! set ) { + XDeleteProperty(SDL_Display, WMwindow, XA_WM_TRANSIENT_FOR); + } + } +} + +static int X11_CreateWindow(_THIS, SDL_Surface *screen, + int w, int h, int bpp, Uint32 flags) +{ + int i, depth; + Visual *vis; + int vis_change; + Uint32 Amask; + + /* If a window is already present, destroy it and start fresh */ + if ( SDL_Window ) { + X11_DestroyWindow(this, screen); + switch_waiting = 0; /* Prevent jump back to now-meaningless state. */ + } + + /* See if we have been given a window id */ + if ( SDL_windowid ) { + SDL_Window = SDL_strtol(SDL_windowid, NULL, 0); + } else { + SDL_Window = 0; + } + + /* find out which visual we are going to use */ + if ( flags & SDL_OPENGL ) { + XVisualInfo *vi; + + vi = X11_GL_GetVisual(this); + if( !vi ) { + return -1; + } + vis = vi->visual; + depth = vi->depth; + } else if ( SDL_windowid ) { + XWindowAttributes a; + + XGetWindowAttributes(SDL_Display, SDL_Window, &a); + vis = a.visual; + depth = a.depth; + } else { + for ( i = 0; i < this->hidden->nvisuals; i++ ) { + if ( this->hidden->visuals[i].bpp == bpp ) + break; + } + if ( i == this->hidden->nvisuals ) { + SDL_SetError("No matching visual for requested depth"); + return -1; /* should never happen */ + } + vis = this->hidden->visuals[i].visual; + depth = this->hidden->visuals[i].depth; + } +#ifdef X11_DEBUG + printf("Choosing %s visual at %d bpp - %d colormap entries\n", vis->class == PseudoColor ? "PseudoColor" : (vis->class == TrueColor ? "TrueColor" : (vis->class == DirectColor ? "DirectColor" : "Unknown")), depth, vis->map_entries); +#endif + vis_change = (vis != SDL_Visual); + SDL_Visual = vis; + this->hidden->depth = depth; + + /* Allocate the new pixel format for this video mode */ + if ( this->hidden->depth == 32 ) { + Amask = (0xFFFFFFFF & ~(vis->red_mask|vis->green_mask|vis->blue_mask)); + } else { + Amask = 0; + } + if ( ! SDL_ReallocFormat(screen, bpp, + vis->red_mask, vis->green_mask, vis->blue_mask, Amask) ) { + return -1; + } + + /* Create the appropriate colormap */ + if ( SDL_XColorMap != SDL_DisplayColormap ) { + XFreeColormap(SDL_Display, SDL_XColorMap); + } + if ( SDL_Visual->class == PseudoColor ) { + int ncolors; + + /* Allocate the pixel flags */ + ncolors = SDL_Visual->map_entries; + SDL_XPixels = SDL_malloc(ncolors * sizeof(int)); + if(SDL_XPixels == NULL) { + SDL_OutOfMemory(); + return -1; + } + SDL_memset(SDL_XPixels, 0, ncolors * sizeof(*SDL_XPixels)); + + /* always allocate a private colormap on non-default visuals */ + if ( SDL_Visual != DefaultVisual(SDL_Display, SDL_Screen) ) { + flags |= SDL_HWPALETTE; + } + if ( flags & SDL_HWPALETTE ) { + screen->flags |= SDL_HWPALETTE; + SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root, + SDL_Visual, AllocAll); + } else { + SDL_XColorMap = SDL_DisplayColormap; + } + } else if ( SDL_Visual->class == DirectColor ) { + + /* Create a colormap which we can manipulate for gamma */ + SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root, + SDL_Visual, AllocAll); + XSync(SDL_Display, False); + + /* Initialize the colormap to the identity mapping */ + SDL_GetGammaRamp(0, 0, 0); + this->screen = screen; + X11_SetGammaRamp(this, this->gamma); + this->screen = NULL; + } else { + /* Create a read-only colormap for our window */ + SDL_XColorMap = XCreateColormap(SDL_Display, SDL_Root, + SDL_Visual, AllocNone); + } + + /* Recreate the auxiliary windows, if needed (required for GL) */ + if ( vis_change ) + create_aux_windows(this); + + if(screen->flags & SDL_HWPALETTE) { + /* Since the full-screen window might have got a nonzero background + colour (0 is white on some displays), we should reset the + background to 0 here since that is what the user expects + with a private colormap */ + XSetWindowBackground(SDL_Display, FSwindow, 0); + XClearWindow(SDL_Display, FSwindow); + } + + /* resize the (possibly new) window manager window */ + if( !SDL_windowid ) { + X11_SetSizeHints(this, w, h, flags); + window_w = w; + window_h = h; + XResizeWindow(SDL_Display, WMwindow, w, h); + } + + /* Create (or use) the X11 display window */ + if ( !SDL_windowid ) { + if ( flags & SDL_OPENGL ) { + if ( X11_GL_CreateWindow(this, w, h) < 0 ) { + return(-1); + } + } else { + XSetWindowAttributes swa; + + swa.background_pixel = 0; + swa.border_pixel = 0; + swa.colormap = SDL_XColorMap; + SDL_Window = XCreateWindow(SDL_Display, WMwindow, + 0, 0, w, h, 0, depth, + InputOutput, SDL_Visual, + CWBackPixel | CWBorderPixel + | CWColormap, &swa); + } + /* Only manage our input if we own the window */ + XSelectInput(SDL_Display, SDL_Window, + ( EnterWindowMask | LeaveWindowMask + | ButtonPressMask | ButtonReleaseMask + | PointerMotionMask | ExposureMask )); + } + /* Create the graphics context here, once we have a window */ + if ( flags & SDL_OPENGL ) { + if ( X11_GL_CreateContext(this) < 0 ) { + return(-1); + } else { + screen->flags |= SDL_OPENGL; + } + } else { + XGCValues gcv; + + gcv.graphics_exposures = False; + SDL_GC = XCreateGC(SDL_Display, SDL_Window, + GCGraphicsExposures, &gcv); + if ( ! SDL_GC ) { + SDL_SetError("Couldn't create graphics context"); + return(-1); + } + } + + /* Set our colormaps when not setting a GL mode */ + if ( ! (flags & SDL_OPENGL) ) { + XSetWindowColormap(SDL_Display, SDL_Window, SDL_XColorMap); + if( !SDL_windowid ) { + XSetWindowColormap(SDL_Display, FSwindow, SDL_XColorMap); + XSetWindowColormap(SDL_Display, WMwindow, SDL_XColorMap); + } + } + +#if 0 /* This is an experiment - are the graphics faster now? - nope. */ + if ( SDL_getenv("SDL_VIDEO_X11_BACKINGSTORE") ) +#endif + /* Cache the window in the server, when possible */ + { + Screen *xscreen; + XSetWindowAttributes a; + + xscreen = ScreenOfDisplay(SDL_Display, SDL_Screen); + a.backing_store = DoesBackingStore(xscreen); + if ( a.backing_store != NotUseful ) { + XChangeWindowAttributes(SDL_Display, SDL_Window, + CWBackingStore, &a); + } + } + + /* Map them both and go fullscreen, if requested */ + if ( ! SDL_windowid ) { + XMapWindow(SDL_Display, SDL_Window); + XMapWindow(SDL_Display, WMwindow); + X11_WaitMapped(this, WMwindow); + if ( flags & SDL_FULLSCREEN ) { + screen->flags |= SDL_FULLSCREEN; + X11_EnterFullScreen(this); + } else { + screen->flags &= ~SDL_FULLSCREEN; + } + } + + return(0); +} + +static int X11_ResizeWindow(_THIS, + SDL_Surface *screen, int w, int h, Uint32 flags) +{ + if ( ! SDL_windowid ) { + /* Resize the window manager window */ + X11_SetSizeHints(this, w, h, flags); + window_w = w; + window_h = h; + XResizeWindow(SDL_Display, WMwindow, w, h); + + /* Resize the fullscreen and display windows */ + if ( flags & SDL_FULLSCREEN ) { + if ( screen->flags & SDL_FULLSCREEN ) { + X11_ResizeFullScreen(this); + } else { + screen->flags |= SDL_FULLSCREEN; + X11_EnterFullScreen(this); + } + } else { + if ( screen->flags & SDL_FULLSCREEN ) { + screen->flags &= ~SDL_FULLSCREEN; + X11_LeaveFullScreen(this); + } + } + XResizeWindow(SDL_Display, SDL_Window, w, h); + } + return(0); +} + +SDL_Surface *X11_SetVideoMode(_THIS, SDL_Surface *current, + int width, int height, int bpp, Uint32 flags) +{ + Uint32 saved_flags; + + /* Lock the event thread, in multi-threading environments */ + SDL_Lock_EventThread(); + + /* Check the combination of flags we were passed */ + if ( flags & SDL_FULLSCREEN ) { + /* Clear fullscreen flag if not supported */ + if ( SDL_windowid ) { + flags &= ~SDL_FULLSCREEN; + } + } + + /* Flush any delayed updates */ + XSync(GFX_Display, False); + + /* Set up the X11 window */ + saved_flags = current->flags; + if ( (SDL_Window) && ((saved_flags&SDL_OPENGL) == (flags&SDL_OPENGL)) + && (bpp == current->format->BitsPerPixel) + && ((saved_flags&SDL_NOFRAME) == (flags&SDL_NOFRAME)) ) { + if (X11_ResizeWindow(this, current, width, height, flags) < 0) { + current = NULL; + goto done; + } + X11_PendingConfigureNotifyWidth = width; + X11_PendingConfigureNotifyHeight = height; + } else { + if (X11_CreateWindow(this,current,width,height,bpp,flags) < 0) { + current = NULL; + goto done; + } + } + + /* Update the internal keyboard state */ + X11_SetKeyboardState(SDL_Display, NULL); + + /* When the window is first mapped, ignore non-modifier keys */ + if ( !current->w && !current->h ) { + Uint8 *keys = SDL_GetKeyState(NULL); + int i; + for ( i = 0; i < SDLK_LAST; ++i ) { + switch (i) { + case SDLK_NUMLOCK: + case SDLK_CAPSLOCK: + case SDLK_LCTRL: + case SDLK_RCTRL: + case SDLK_LSHIFT: + case SDLK_RSHIFT: + case SDLK_LALT: + case SDLK_RALT: + case SDLK_LMETA: + case SDLK_RMETA: + case SDLK_MODE: + break; + default: + keys[i] = SDL_RELEASED; + break; + } + } + } + + /* Set up the new mode framebuffer */ + if ( ((current->w != width) || (current->h != height)) || + ((saved_flags&SDL_OPENGL) != (flags&SDL_OPENGL)) ) { + current->w = width; + current->h = height; + current->pitch = SDL_CalculatePitch(current); + if (X11_ResizeImage(this, current, flags) < 0) { + current = NULL; + goto done; + } + } + + /* Clear these flags and set them only if they are in the new set. */ + current->flags &= ~(SDL_RESIZABLE|SDL_NOFRAME); + current->flags |= (flags&(SDL_RESIZABLE|SDL_NOFRAME)); + + done: + /* Release the event thread */ + XSync(SDL_Display, False); + SDL_Unlock_EventThread(); + + /* We're done! */ + return(current); +} + +static int X11_ToggleFullScreen(_THIS, int on) +{ + Uint32 event_thread; + + /* Don't switch if we don't own the window */ + if ( SDL_windowid ) { + return(0); + } + + /* Don't lock if we are the event thread */ + event_thread = SDL_EventThreadID(); + if ( event_thread && (SDL_ThreadID() == event_thread) ) { + event_thread = 0; + } + if ( event_thread ) { + SDL_Lock_EventThread(); + } + if ( on ) { + this->screen->flags |= SDL_FULLSCREEN; + X11_EnterFullScreen(this); + } else { + this->screen->flags &= ~SDL_FULLSCREEN; + X11_LeaveFullScreen(this); + } + X11_RefreshDisplay(this); + if ( event_thread ) { + SDL_Unlock_EventThread(); + } + SDL_ResetKeyboard(); + return(1); +} + +/* Update the current mouse state and position */ +static void X11_UpdateMouse(_THIS) +{ + Window u1; int u2; + Window current_win; + int x, y; + unsigned int mask; + + /* Lock the event thread, in multi-threading environments */ + SDL_Lock_EventThread(); + if ( XQueryPointer(SDL_Display, SDL_Window, &u1, ¤t_win, + &u2, &u2, &x, &y, &mask) ) { + if ( (x >= 0) && (x < SDL_VideoSurface->w) && + (y >= 0) && (y < SDL_VideoSurface->h) ) { + SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS); + SDL_PrivateMouseMotion(0, 0, x, y); + } else { + SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS); + } + } + SDL_Unlock_EventThread(); +} + +/* simple colour distance metric. Supposed to be better than a plain + Euclidian distance anyway. */ +#define COLOUR_FACTOR 3 +#define LIGHT_FACTOR 1 +#define COLOUR_DIST(r1, g1, b1, r2, g2, b2) \ + (COLOUR_FACTOR * (abs(r1 - r2) + abs(g1 - g2) + abs(b1 - b2)) \ + + LIGHT_FACTOR * abs(r1 + g1 + b1 - (r2 + g2 + b2))) + +static void allocate_nearest(_THIS, SDL_Color *colors, + SDL_Color *want, int nwant) +{ + /* + * There is no way to know which ones to choose from, so we retrieve + * the entire colormap and try the nearest possible, until we find one + * that is shared. + */ + XColor all[256]; + int i; + for(i = 0; i < 256; i++) + all[i].pixel = i; + /* + * XQueryColors sets the flags in the XColor struct, so we use + * that to keep track of which colours are available + */ + XQueryColors(GFX_Display, SDL_XColorMap, all, 256); + + for(i = 0; i < nwant; i++) { + XColor *c; + int j; + int best = 0; + int mindist = 0x7fffffff; + int ri = want[i].r; + int gi = want[i].g; + int bi = want[i].b; + for(j = 0; j < 256; j++) { + int rj, gj, bj, d2; + if(!all[j].flags) + continue; /* unavailable colour cell */ + rj = all[j].red >> 8; + gj = all[j].green >> 8; + bj = all[j].blue >> 8; + d2 = COLOUR_DIST(ri, gi, bi, rj, gj, bj); + if(d2 < mindist) { + mindist = d2; + best = j; + } + } + if(SDL_XPixels[best]) + continue; /* already allocated, waste no more time */ + c = all + best; + if(XAllocColor(GFX_Display, SDL_XColorMap, c)) { + /* got it */ + colors[c->pixel].r = c->red >> 8; + colors[c->pixel].g = c->green >> 8; + colors[c->pixel].b = c->blue >> 8; + ++SDL_XPixels[c->pixel]; + } else { + /* + * The colour couldn't be allocated, probably being + * owned as a r/w cell by another client. Flag it as + * unavailable and try again. The termination of the + * loop is guaranteed since at least black and white + * are always there. + */ + c->flags = 0; + i--; + } + } +} + +int X11_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors) +{ + int nrej = 0; + + /* Check to make sure we have a colormap allocated */ + if ( SDL_XPixels == NULL ) { + return(0); + } + if ( (this->screen->flags & SDL_HWPALETTE) == SDL_HWPALETTE ) { + /* private writable colormap: just set the colours we need */ + XColor *xcmap; + int i; + xcmap = SDL_stack_alloc(XColor, ncolors); + if(xcmap == NULL) + return 0; + for ( i=0; iscreen->format->palette->ncolors; + colors = this->screen->format->palette->colors; + freelist = SDL_stack_alloc(unsigned long, nc); + /* make sure multiple allocations of the same cell are freed */ + for(i = 0; i < ncolors; i++) { + int pixel = firstcolor + i; + while(SDL_XPixels[pixel]) { + freelist[nfree++] = pixel; + --SDL_XPixels[pixel]; + } + } + XFreeColors(GFX_Display, SDL_XColorMap, freelist, nfree, 0); + SDL_stack_free(freelist); + + want = SDL_stack_alloc(SDL_Color, ncolors); + reject = SDL_stack_alloc(SDL_Color, ncolors); + SDL_memcpy(want, colors + firstcolor, ncolors * sizeof(SDL_Color)); + /* make sure the user isn't fooled by her own wishes + (black is safe, always available in the default colormap) */ + SDL_memset(colors + firstcolor, 0, ncolors * sizeof(SDL_Color)); + + /* now try to allocate the colours */ + for(i = 0; i < ncolors; i++) { + XColor col; + col.red = want[i].r << 8; + col.green = want[i].g << 8; + col.blue = want[i].b << 8; + col.flags = DoRed | DoGreen | DoBlue; + if(XAllocColor(GFX_Display, SDL_XColorMap, &col)) { + /* We got the colour, or at least the nearest + the hardware could get. */ + colors[col.pixel].r = col.red >> 8; + colors[col.pixel].g = col.green >> 8; + colors[col.pixel].b = col.blue >> 8; + ++SDL_XPixels[col.pixel]; + } else { + /* + * no more free cells, add it to the list + * of rejected colours + */ + reject[nrej++] = want[i]; + } + } + if(nrej) + allocate_nearest(this, colors, reject, nrej); + SDL_stack_free(reject); + SDL_stack_free(want); + } + return nrej == 0; +} + +int X11_SetGammaRamp(_THIS, Uint16 *ramp) +{ + int i, ncolors; + XColor xcmap[256]; + + /* See if actually setting the gamma is supported */ + if ( SDL_Visual->class != DirectColor ) { + SDL_SetError("Gamma correction not supported on this visual"); + return(-1); + } + + /* Calculate the appropriate palette for the given gamma ramp */ + ncolors = SDL_Visual->map_entries; + for ( i=0; iscreen->format, c, c, c); + xcmap[i].red = ramp[0*256+c]; + xcmap[i].green = ramp[1*256+c]; + xcmap[i].blue = ramp[2*256+c]; + xcmap[i].flags = (DoRed|DoGreen|DoBlue); + } + XStoreColors(GFX_Display, SDL_XColorMap, xcmap, ncolors); + XSync(GFX_Display, False); + return(0); +} + +/* Note: If we are terminated, this could be called in the middle of + another SDL video routine -- notably UpdateRects. +*/ +void X11_VideoQuit(_THIS) +{ + /* Shutdown everything that's still up */ + /* The event thread should be done, so we can touch SDL_Display */ + if ( SDL_Display != NULL ) { + /* Flush any delayed updates */ + XSync(GFX_Display, False); + + /* Close the connection with the IM server */ + #ifdef X_HAVE_UTF8_STRING + if (SDL_IC != NULL) { + XUnsetICFocus(SDL_IC); + XDestroyIC(SDL_IC); + SDL_IC = NULL; + } + if (SDL_IM != NULL) { + XCloseIM(SDL_IM); + SDL_IM = NULL; + } + #endif + + /* Start shutting down the windows */ + X11_DestroyImage(this, this->screen); + X11_DestroyWindow(this, this->screen); + X11_FreeVideoModes(this); + if ( SDL_XColorMap != SDL_DisplayColormap ) { + XFreeColormap(SDL_Display, SDL_XColorMap); + } + if ( SDL_iconcolors ) { + unsigned long pixel; + Colormap dcmap = DefaultColormap(SDL_Display, + SDL_Screen); + for(pixel = 0; pixel < 256; ++pixel) { + while(SDL_iconcolors[pixel] > 0) { + XFreeColors(GFX_Display, + dcmap, &pixel, 1, 0); + --SDL_iconcolors[pixel]; + } + } + SDL_free(SDL_iconcolors); + SDL_iconcolors = NULL; + } + + /* Restore gamma settings if they've changed */ + if ( SDL_GetAppState() & SDL_APPACTIVE ) { + X11_SwapVidModeGamma(this); + } + + /* Free that blank cursor */ + if ( SDL_BlankCursor != NULL ) { + this->FreeWMCursor(this, SDL_BlankCursor); + SDL_BlankCursor = NULL; + } + + /* Close the X11 graphics connection */ + if ( GFX_Display != NULL ) { + XCloseDisplay(GFX_Display); + GFX_Display = NULL; + } + + /* Close the X11 display connection */ + XCloseDisplay(SDL_Display); + SDL_Display = NULL; + + /* Reset the X11 error handlers */ + if ( XIO_handler ) { + XSetIOErrorHandler(XIO_handler); + } + if ( X_handler ) { + XSetErrorHandler(X_handler); + } + + /* Unload GL library after X11 shuts down */ + X11_GL_UnloadLibrary(this); + } + if ( this->screen && (this->screen->flags & SDL_HWSURFACE) ) { + /* Direct screen access, no memory buffer */ + this->screen->pixels = NULL; + } + +#if SDL_VIDEO_DRIVER_X11_XME + XiGMiscDestroy(); +#endif +} + diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11video.h b/apps/plugins/sdl/src/video/x11/SDL_x11video.h new file mode 100644 index 0000000000..f347560d6d --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11video.h @@ -0,0 +1,214 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifndef _SDL_x11video_h +#define _SDL_x11video_h + +#include +#include +#include + +#include "SDL_mouse.h" +#include "../SDL_sysvideo.h" + +#if SDL_VIDEO_DRIVER_X11_DGAMOUSE +#include "../Xext/extensions/xf86dga.h" +#endif +#if SDL_VIDEO_DRIVER_X11_XINERAMA +#include "../Xext/extensions/Xinerama.h" +#endif +#if SDL_VIDEO_DRIVER_X11_XRANDR +#include +#endif +#if SDL_VIDEO_DRIVER_X11_VIDMODE +#include "../Xext/extensions/xf86vmode.h" +#endif +#if SDL_VIDEO_DRIVER_X11_XME +#include "../Xext/extensions/xme.h" +#endif + +#include "SDL_x11dyn.h" + +/* Hidden "this" pointer for the video functions */ +#define _THIS SDL_VideoDevice *this + +/* Private display data */ +struct SDL_PrivateVideoData { + int local_X11; /* Flag: true if local display */ + Display *X11_Display; /* Used for events and window management */ + Display *GFX_Display; /* Used for graphics and colormap stuff */ + Visual *SDL_Visual; /* The visual used by our window */ + Window WMwindow; /* Input window, managed by window manager */ + Window FSwindow; /* Fullscreen window, completely unmanaged */ + Window SDL_Window; /* Shared by both displays (no X security?) */ + Atom WM_DELETE_WINDOW; /* "close-window" protocol atom */ + WMcursor *BlankCursor; /* The invisible cursor */ + XIM X11_IM; /* Used to communicate with the input method (IM) server */ + XIC X11_IC; /* Used for retaining the state, properties, and semantics of communication with the input method (IM) server */ + + char *SDL_windowid; /* Flag: true if we have been passed a window */ + + /* Direct Graphics Access extension information */ + int using_dga; + +#ifndef NO_SHARED_MEMORY + /* MIT shared memory extension information */ + int use_mitshm; + XShmSegmentInfo shminfo; +#endif + + /* The variables used for displaying graphics */ + XImage *Ximage; /* The X image for our window */ + GC gc; /* The graphic context for drawing */ + + /* The current width and height of the fullscreen mode */ + int window_w; + int window_h; + + /* Support for internal mouse warping */ + struct { + int x; + int y; + } mouse_last; + struct { + int numerator; + int denominator; + int threshold; + } mouse_accel; + int mouse_relative; + + /* The current list of available video modes */ + SDL_Rect **modelist; + + /* available visuals of interest to us, sorted deepest first */ + struct { + Visual *visual; + int depth; /* number of significant bits/pixel */ + int bpp; /* pixel quantum in bits */ + } visuals[2*5]; /* at most 2 entries for 8, 15, 16, 24, 32 */ + int nvisuals; + + Visual *vis; /* current visual in use */ + int depth; /* current visual depth (not bpp) */ + + /* Variables used by the X11 video mode code */ +#if SDL_VIDEO_DRIVER_X11_XINERAMA + SDL_NAME(XineramaScreenInfo) xinerama_info; +#endif +#if SDL_VIDEO_DRIVER_X11_XRANDR + XRRScreenConfiguration* screen_config; + int saved_size_id; + Rotation saved_rotation; +#endif +#if SDL_VIDEO_DRIVER_X11_VIDMODE + SDL_NAME(XF86VidModeModeInfo) saved_mode; + struct { + int x, y; + } saved_view; +#endif +#if SDL_VIDEO_DRIVER_X11_XME /* XiG XME fullscreen */ + XiGMiscResolutionInfo saved_res; +#endif + + int use_xinerama; + int use_xrandr; + int use_vidmode; + int use_xme; + int currently_fullscreen; + + /* Automatic mode switching support (entering/leaving fullscreen) */ + Uint32 switch_waiting; + Uint32 switch_time; + + /* Prevent too many XSync() calls */ + int blit_queued; + + /* Colormap handling */ + Colormap DisplayColormap; /* The default display colormap */ + Colormap XColorMap; /* The current window colormap */ + int *XPixels; /* pixels value allocation counts */ + float gamma_saved[3]; /* Saved gamma values for VidMode gamma */ + int gamma_changed; /* flag: has VidMode gamma been modified? */ + + short *iconcolors; /* List of colors used by the icon */ + + /* Screensaver settings */ + int allow_screensaver; +}; + +/* Old variable names */ +#define local_X11 (this->hidden->local_X11) +#define SDL_Display (this->hidden->X11_Display) +#define GFX_Display (this->hidden->GFX_Display) +#define SDL_Screen DefaultScreen(this->hidden->X11_Display) +#define SDL_Visual (this->hidden->vis) +#define SDL_Root RootWindow(SDL_Display, SDL_Screen) +#define WMwindow (this->hidden->WMwindow) +#define FSwindow (this->hidden->FSwindow) +#define SDL_Window (this->hidden->SDL_Window) +#define WM_DELETE_WINDOW (this->hidden->WM_DELETE_WINDOW) +#define SDL_BlankCursor (this->hidden->BlankCursor) +#define SDL_IM (this->hidden->X11_IM) +#define SDL_IC (this->hidden->X11_IC) +#define SDL_windowid (this->hidden->SDL_windowid) +#define using_dga (this->hidden->using_dga) +#define use_mitshm (this->hidden->use_mitshm) +#define shminfo (this->hidden->shminfo) +#define SDL_Ximage (this->hidden->Ximage) +#define SDL_GC (this->hidden->gc) +#define window_w (this->hidden->window_w) +#define window_h (this->hidden->window_h) +#define mouse_last (this->hidden->mouse_last) +#define mouse_accel (this->hidden->mouse_accel) +#define mouse_relative (this->hidden->mouse_relative) +#define SDL_modelist (this->hidden->modelist) +#define xinerama_info (this->hidden->xinerama_info) +#define saved_mode (this->hidden->saved_mode) +#define saved_view (this->hidden->saved_view) +#define saved_res (this->hidden->saved_res) +#define screen_config (this->hidden->screen_config) +#define saved_size_id (this->hidden->saved_size_id) +#define saved_rotation (this->hidden->saved_rotation) +#define use_xinerama (this->hidden->use_xinerama) +#define use_vidmode (this->hidden->use_vidmode) +#define use_xrandr (this->hidden->use_xrandr) +#define use_xme (this->hidden->use_xme) +#define currently_fullscreen (this->hidden->currently_fullscreen) +#define switch_waiting (this->hidden->switch_waiting) +#define switch_time (this->hidden->switch_time) +#define blit_queued (this->hidden->blit_queued) +#define SDL_DisplayColormap (this->hidden->DisplayColormap) +#define SDL_PrivateColormap (this->hidden->PrivateColormap) +#define SDL_XColorMap (this->hidden->XColorMap) +#define SDL_XPixels (this->hidden->XPixels) +#define gamma_saved (this->hidden->gamma_saved) +#define gamma_changed (this->hidden->gamma_changed) +#define SDL_iconcolors (this->hidden->iconcolors) +#define allow_screensaver (this->hidden->allow_screensaver) + +/* Some versions of XFree86 have bugs - detect if this is one of them */ +#define BUGGY_XFREE86(condition, buggy_version) \ +((SDL_strcmp(ServerVendor(SDL_Display), "The XFree86 Project, Inc") == 0) && \ + (VendorRelease(SDL_Display) condition buggy_version)) + +#endif /* _SDL_x11video_h */ diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11wm.c b/apps/plugins/sdl/src/video/x11/SDL_x11wm.c new file mode 100644 index 0000000000..14c816b942 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11wm.c @@ -0,0 +1,434 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#include +#include + +#include "SDL_version.h" +#include "SDL_timer.h" +#include "SDL_video.h" +#include "SDL_syswm.h" +#include "../SDL_pixels_c.h" +#include "../../events/SDL_events_c.h" +#include "SDL_x11modes_c.h" +#include "SDL_x11wm_c.h" + +static Uint8 reverse_byte(Uint8 x) +{ + x = (x & 0xaa) >> 1 | (x & 0x55) << 1; + x = (x & 0xcc) >> 2 | (x & 0x33) << 2; + x = (x & 0xf0) >> 4 | (x & 0x0f) << 4; + return x; +} + +void X11_SetIcon(_THIS, SDL_Surface *icon, Uint8 *mask) +{ + SDL_Surface *sicon; + XWMHints *wmhints; + XImage *icon_image; + Pixmap icon_pixmap; + Pixmap mask_pixmap; + Window icon_window = None; + GC gc; + XGCValues GCvalues; + int i, dbpp; + SDL_Rect bounds; + Uint8 *LSBmask; + Visual *dvis; + char *p; + int masksize; + + SDL_Lock_EventThread(); + + /* The icon must use the default visual, depth and colormap of the + screen, so it might need a conversion */ + dvis = DefaultVisual(SDL_Display, SDL_Screen); + dbpp = DefaultDepth(SDL_Display, SDL_Screen); + for(i = 0; i < this->hidden->nvisuals; i++) { + if(this->hidden->visuals[i].visual == dvis) { + dbpp = this->hidden->visuals[i].bpp; + break; + } + } + + /* The Visual struct is supposed to be opaque but we cheat a little */ + sicon = SDL_CreateRGBSurface(SDL_SWSURFACE, icon->w, icon->h, + dbpp, + dvis->red_mask, dvis->green_mask, + dvis->blue_mask, 0); + if ( sicon == NULL ) + goto done; + + if(dbpp == 8) { + /* Default visual is 8bit; we need to allocate colours from + the default colormap */ + SDL_Color want[256], got[256]; + int nwant; + Colormap dcmap; + int missing; + dcmap = DefaultColormap(SDL_Display, SDL_Screen); + if(icon->format->palette) { + /* The icon has a palette as well - we just have to + find those colours */ + nwant = icon->format->palette->ncolors; + SDL_memcpy(want, icon->format->palette->colors, + nwant * sizeof want[0]); + } else { + /* try the standard 6x6x6 cube for lack of better + ideas */ + int r, g, b, i; + for(r = i = 0; r < 256; r += 0x33) + for(g = 0; g < 256; g += 0x33) + for(b = 0; b < 256; b += 0x33, i++) { + want[i].r = r; + want[i].g = g; + want[i].b = b; + } + nwant = 216; + } + if(SDL_iconcolors) { + /* free already allocated colours first */ + unsigned long freelist[512]; + int nfree = 0; + for(i = 0; i < 256; i++) { + while(SDL_iconcolors[i]) { + freelist[nfree++] = i; + SDL_iconcolors[i]--; + } + } + XFreeColors(GFX_Display, dcmap, freelist, nfree, 0); + } + if(!SDL_iconcolors) + SDL_iconcolors = SDL_malloc(256 * sizeof *SDL_iconcolors); + SDL_memset(SDL_iconcolors, 0, 256 * sizeof *SDL_iconcolors); + + /* try to allocate the colours */ + SDL_memset(got, 0, sizeof got); + missing = 0; + for(i = 0; i < nwant; i++) { + XColor c; + c.red = want[i].r << 8; + c.green = want[i].g << 8; + c.blue = want[i].b << 8; + c.flags = DoRed | DoGreen | DoBlue; + if(XAllocColor(GFX_Display, dcmap, &c)) { + /* got the colour */ + SDL_iconcolors[c.pixel]++; + got[c.pixel] = want[i]; + } else { + missing = 1; + } + } + if(missing) { + /* Some colours were apparently missing, so we just + allocate all the rest as well */ + XColor cols[256]; + for(i = 0; i < 256; i++) + cols[i].pixel = i; + XQueryColors(GFX_Display, dcmap, cols, 256); + for(i = 0; i < 256; i++) { + got[i].r = cols[i].red >> 8; + got[i].g = cols[i].green >> 8; + got[i].b = cols[i].blue >> 8; + if(!SDL_iconcolors[i]) { + if(XAllocColor(GFX_Display, dcmap, + cols + i)) { + SDL_iconcolors[i] = 1; + } else { + /* index not available */ + got[i].r = 0; + got[i].g = 0; + got[i].b = 0; + } + } + } + } + + SDL_SetColors(sicon, got, 0, 256); + } + + bounds.x = 0; + bounds.y = 0; + bounds.w = icon->w; + bounds.h = icon->h; + if ( SDL_LowerBlit(icon, &bounds, sicon, &bounds) < 0 ) + goto done; + + /* We need the mask as given, except in LSBfirst format instead of + MSBfirst. Reverse the bits in each byte. */ + masksize = ((sicon->w + 7) >> 3) * sicon->h; + LSBmask = SDL_malloc(masksize); + if ( LSBmask == NULL ) { + goto done; + } + SDL_memset(LSBmask, 0, masksize); + for(i = 0; i < masksize; i++) + LSBmask[i] = reverse_byte(mask[i]); + mask_pixmap = XCreatePixmapFromBitmapData(SDL_Display, WMwindow, + (char *)LSBmask, + sicon->w, sicon->h, + 1L, 0L, 1); + + /* Transfer the image to an X11 pixmap */ + icon_image = XCreateImage(SDL_Display, + DefaultVisual(SDL_Display, SDL_Screen), + DefaultDepth(SDL_Display, SDL_Screen), + ZPixmap, 0, sicon->pixels, + sicon->w, sicon->h, + 32, 0); + icon_image->byte_order = (SDL_BYTEORDER == SDL_BIG_ENDIAN) + ? MSBFirst : LSBFirst; + icon_pixmap = XCreatePixmap(SDL_Display, SDL_Root, sicon->w, sicon->h, + DefaultDepth(SDL_Display, SDL_Screen)); + gc = XCreateGC(SDL_Display, icon_pixmap, 0, &GCvalues); + XPutImage(SDL_Display, icon_pixmap, gc, icon_image, + 0, 0, 0, 0, sicon->w, sicon->h); + XFreeGC(SDL_Display, gc); + XDestroyImage(icon_image); + SDL_free(LSBmask); + sicon->pixels = NULL; + + /* Some buggy window managers (some versions of Enlightenment, it + seems) need an icon window *and* icon pixmap to work properly, while + it screws up others. The default is only to use a pixmap. */ + p = SDL_getenv("SDL_VIDEO_X11_ICONWIN"); + if(p && *p) { + icon_window = XCreateSimpleWindow(SDL_Display, SDL_Root, + 0, 0, sicon->w, sicon->h, 0, + CopyFromParent, + CopyFromParent); + XSetWindowBackgroundPixmap(SDL_Display, icon_window, + icon_pixmap); + XClearWindow(SDL_Display, icon_window); + } + + /* Set the window icon to the icon pixmap (and icon window) */ + wmhints = XAllocWMHints(); + wmhints->flags = (IconPixmapHint | IconMaskHint | InputHint); + wmhints->icon_pixmap = icon_pixmap; + wmhints->icon_mask = mask_pixmap; + wmhints->input = True; + if(icon_window != None) { + wmhints->flags |= IconWindowHint; + wmhints->icon_window = icon_window; + } + XSetWMHints(SDL_Display, WMwindow, wmhints); + XFree(wmhints); + XSync(SDL_Display, False); + + done: + SDL_Unlock_EventThread(); + SDL_FreeSurface(sicon); +} + +void X11_SetCaptionNoLock(_THIS, const char *title, const char *icon) +{ + XTextProperty titleprop, iconprop; + Status status; + +#ifdef X_HAVE_UTF8_STRING + Atom _NET_WM_NAME = 0; + Atom _NET_WM_ICON_NAME = 0; + + /* Look up some useful Atoms */ + if (SDL_X11_HAVE_UTF8) { + _NET_WM_NAME = XInternAtom(SDL_Display, "_NET_WM_NAME", False); + _NET_WM_ICON_NAME = XInternAtom(SDL_Display, "_NET_WM_ICON_NAME", False); + } +#endif + + if ( title != NULL ) { + char *title_locale = SDL_iconv_utf8_locale(title); + if ( !title_locale ) { + SDL_OutOfMemory(); + return; + } + status = XStringListToTextProperty(&title_locale, 1, &titleprop); + SDL_free(title_locale); + if ( status ) { + XSetTextProperty(SDL_Display, WMwindow, &titleprop, XA_WM_NAME); + XFree(titleprop.value); + } +#ifdef X_HAVE_UTF8_STRING + if (SDL_X11_HAVE_UTF8) { + status = Xutf8TextListToTextProperty(SDL_Display, + (char **)&title, 1, XUTF8StringStyle, &titleprop); + if ( status == Success ) { + XSetTextProperty(SDL_Display, WMwindow, &titleprop, _NET_WM_NAME); + XFree(titleprop.value); + } + } +#endif + } + if ( icon != NULL ) { + char *icon_locale = SDL_iconv_utf8_locale(icon); + if ( !icon_locale ) { + SDL_OutOfMemory(); + return; + } + status = XStringListToTextProperty(&icon_locale, 1, &iconprop); + SDL_free(icon_locale); + if ( status ) { + XSetTextProperty(SDL_Display, WMwindow, &iconprop, XA_WM_ICON_NAME); + XFree(iconprop.value); + } +#ifdef X_HAVE_UTF8_STRING + if (SDL_X11_HAVE_UTF8) { + status = Xutf8TextListToTextProperty(SDL_Display, + (char **)&icon, 1, XUTF8StringStyle, &iconprop); + if ( status == Success ) { + XSetTextProperty(SDL_Display, WMwindow, &iconprop, _NET_WM_ICON_NAME); + XFree(iconprop.value); + } + } +#endif + } + XSync(SDL_Display, False); +} + +void X11_SetCaption(_THIS, const char *title, const char *icon) +{ + SDL_Lock_EventThread(); + X11_SetCaptionNoLock(this, title, icon); + SDL_Unlock_EventThread(); +} + +/* Iconify the window */ +int X11_IconifyWindow(_THIS) +{ + int result; + + SDL_Lock_EventThread(); + result = XIconifyWindow(SDL_Display, WMwindow, SDL_Screen); + XSync(SDL_Display, False); + SDL_Unlock_EventThread(); + return(result); +} + +SDL_GrabMode X11_GrabInputNoLock(_THIS, SDL_GrabMode mode) +{ + int result; + + if ( this->screen == NULL || SDL_Display == NULL ) { + return(SDL_GRAB_OFF); + } + if ( ! SDL_Window ) { + return(mode); /* Will be set later on mode switch */ + } + if ( mode == SDL_GRAB_OFF ) { + XUngrabPointer(SDL_Display, CurrentTime); + XUngrabKeyboard(SDL_Display, CurrentTime); + } else { + if ( this->screen->flags & SDL_FULLSCREEN ) { + /* Unbind the mouse from the fullscreen window */ + XUngrabPointer(SDL_Display, CurrentTime); + } + /* Try to grab the mouse */ +#if 0 /* We'll wait here until we actually grab, otherwise behavior undefined */ + for ( numtries = 0; numtries < 10; ++numtries ) { +#else + for ( ; ; ) { +#endif + result = XGrabPointer(SDL_Display, SDL_Window, True, 0, + GrabModeAsync, GrabModeAsync, + SDL_Window, None, CurrentTime); + if ( result == GrabSuccess ) { + break; + } + SDL_Delay(100); + } + if ( result != GrabSuccess ) { + /* Uh, oh, what do we do here? */ ; + } + /* Now grab the keyboard */ + XGrabKeyboard(SDL_Display, WMwindow, True, + GrabModeAsync, GrabModeAsync, CurrentTime); + + /* Raise the window if we grab the mouse */ + if ( !(this->screen->flags & SDL_FULLSCREEN) ) + XRaiseWindow(SDL_Display, WMwindow); + + /* Make sure we register input focus */ + SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS); + /* Since we grabbed the pointer, we have mouse focus, too. */ + SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS); + } + XSync(SDL_Display, False); + + return(mode); +} + +SDL_GrabMode X11_GrabInput(_THIS, SDL_GrabMode mode) +{ + SDL_Lock_EventThread(); + mode = X11_GrabInputNoLock(this, mode); + SDL_Unlock_EventThread(); + + return(mode); +} + +/* If 'info' is the right version, this function fills it and returns 1. + Otherwise, in case of a version mismatch, it returns -1. +*/ +static void lock_display(void) +{ + SDL_Lock_EventThread(); +} +static void unlock_display(void) +{ + /* Make sure any X11 transactions are completed */ + SDL_VideoDevice *this = current_video; + XSync(SDL_Display, False); + SDL_Unlock_EventThread(); +} + +#include +int X11_GetWMInfo(_THIS, SDL_SysWMinfo *info) +{ + if ( info->version.major <= SDL_MAJOR_VERSION ) { + info->subsystem = SDL_SYSWM_X11; + info->info.x11.display = SDL_Display; + info->info.x11.window = SDL_Window; + if ( SDL_VERSIONNUM(info->version.major, + info->version.minor, + info->version.patch) >= 1002 ) { + info->info.x11.fswindow = FSwindow; + info->info.x11.wmwindow = WMwindow; + } + + + if ( SDL_VERSIONNUM(info->version.major, + info->version.minor, + info->version.patch) >= 1212 ) { + info->info.x11.gfxdisplay = GFX_Display; + } + + info->info.x11.lock_func = lock_display; + info->info.x11.unlock_func = unlock_display; + return(1); + } else { + SDL_SetError("Application not compiled with SDL %d.%d\n", + SDL_MAJOR_VERSION, SDL_MINOR_VERSION); + return(-1); + } +} diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11wm_c.h b/apps/plugins/sdl/src/video/x11/SDL_x11wm_c.h new file mode 100644 index 0000000000..f85477bba1 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11wm_c.h @@ -0,0 +1,34 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#include "SDL_x11video.h" + +/* Functions to be exported */ +extern void X11_SetCaptionNoLock(_THIS, const char *title, const char *icon); +extern void X11_SetCaption(_THIS, const char *title, const char *icon); +extern void X11_SetIcon(_THIS, SDL_Surface *icon, Uint8 *mask); +extern int X11_IconifyWindow(_THIS); +extern SDL_GrabMode X11_GrabInputNoLock(_THIS, SDL_GrabMode mode); +extern SDL_GrabMode X11_GrabInput(_THIS, SDL_GrabMode mode); +extern int X11_GetWMInfo(_THIS, SDL_SysWMinfo *info); + diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11yuv.c b/apps/plugins/sdl/src/video/x11/SDL_x11yuv.c new file mode 100644 index 0000000000..62698dfd9b --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11yuv.c @@ -0,0 +1,538 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* This is the XFree86 Xv extension implementation of YUV video overlays */ + +#if SDL_VIDEO_DRIVER_X11_XV + +#include +#ifndef NO_SHARED_MEMORY +#include +#include +#include +#endif +#include "../Xext/extensions/Xvlib.h" + +#include "SDL_x11yuv_c.h" +#include "../SDL_yuvfuncs.h" + +#define XFREE86_REFRESH_HACK +#ifdef XFREE86_REFRESH_HACK +#include "SDL_x11image_c.h" +#endif + +/* Workaround when pitch != width */ +#define PITCH_WORKAROUND + +/* Workaround intel i810 video overlay waiting with failing until the + first Xv[Shm]PutImage call */ +#define INTEL_XV_BADALLOC_WORKAROUND + +/* Fix for the NVidia GeForce 2 - use the last available adaptor */ +/*#define USE_LAST_ADAPTOR*/ /* Apparently the NVidia drivers are fixed */ + +/* The functions used to manipulate software video overlays */ +static struct private_yuvhwfuncs x11_yuvfuncs = { + X11_LockYUVOverlay, + X11_UnlockYUVOverlay, + X11_DisplayYUVOverlay, + X11_FreeYUVOverlay +}; + +struct private_yuvhwdata { + int port; +#ifndef NO_SHARED_MEMORY + int yuv_use_mitshm; + XShmSegmentInfo yuvshm; +#endif + SDL_NAME(XvImage) *image; +}; + + +static int (*X_handler)(Display *, XErrorEvent *) = NULL; + +#ifndef NO_SHARED_MEMORY +/* Shared memory error handler routine */ +static int shm_error; +static int shm_errhandler(Display *d, XErrorEvent *e) +{ + if ( e->error_code == BadAccess ) { + shm_error = True; + return(0); + } else + return(X_handler(d,e)); +} +#endif /* !NO_SHARED_MEMORY */ + +static int xv_error; +static int xv_errhandler(Display *d, XErrorEvent *e) +{ + if ( e->error_code == BadMatch ) { + xv_error = True; + return(0); + } else + return(X_handler(d,e)); +} + +#ifdef INTEL_XV_BADALLOC_WORKAROUND +static int intel_errhandler(Display *d, XErrorEvent *e) +{ + if ( e->error_code == BadAlloc ) { + xv_error = True; + return(0); + } else + return(X_handler(d,e)); +} + +static void X11_ClearYUVOverlay(SDL_Overlay *overlay) +{ + int x,y; + + switch (overlay->format) + { + case SDL_YV12_OVERLAY: + case SDL_IYUV_OVERLAY: + for (y = 0; y < overlay->h; y++) + memset(overlay->pixels[0] + y * overlay->pitches[0], + 0, overlay->w); + + for (y = 0; y < (overlay->h / 2); y++) + { + memset(overlay->pixels[1] + y * overlay->pitches[1], + -128, overlay->w / 2); + memset(overlay->pixels[2] + y * overlay->pitches[2], + -128, overlay->w / 2); + } + break; + case SDL_YUY2_OVERLAY: + case SDL_YVYU_OVERLAY: + for (y = 0; y < overlay->h; y++) + { + for (x = 0; x < overlay->w; x += 2) + { + Uint8 *pixel_pair = overlay->pixels[0] + + y * overlay->pitches[0] + x * 2; + pixel_pair[0] = 0; + pixel_pair[1] = -128; + pixel_pair[2] = 0; + pixel_pair[3] = -128; + } + } + break; + case SDL_UYVY_OVERLAY: + for (y = 0; y < overlay->h; y++) + { + for (x = 0; x < overlay->w; x += 2) + { + Uint8 *pixel_pair = overlay->pixels[0] + + y * overlay->pitches[0] + x * 2; + pixel_pair[0] = -128; + pixel_pair[1] = 0; + pixel_pair[2] = -128; + pixel_pair[3] = 0; + } + } + break; + } +} +#endif + +SDL_Overlay *X11_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface *display) +{ + SDL_Overlay *overlay; + struct private_yuvhwdata *hwdata; + int xv_port; + unsigned int i, j, k; + unsigned int adaptors; + SDL_NAME(XvAdaptorInfo) *ainfo; + int bpp; +#ifndef NO_SHARED_MEMORY + XShmSegmentInfo *yuvshm; +#endif +#ifdef INTEL_XV_BADALLOC_WORKAROUND + int intel_adapter = False; +#endif + + /* Look for the XVideo extension with a valid port for this format */ + xv_port = -1; + if ( (Success == SDL_NAME(XvQueryExtension)(GFX_Display, &j, &j, &j, &j, &j)) && + (Success == SDL_NAME(XvQueryAdaptors)(GFX_Display, + RootWindow(GFX_Display, SDL_Screen), + &adaptors, &ainfo)) ) { +#ifdef USE_LAST_ADAPTOR + for ( i=0; i < adaptors; ++i ) +#else + for ( i=0; (i < adaptors) && (xv_port == -1); ++i ) +#endif /* USE_LAST_ADAPTOR */ + { + /* Check to see if the visual can be used */ + if ( BUGGY_XFREE86(<=, 4001) ) { + int visual_ok = 0; + for ( j=0; jvisualid ) { + visual_ok = 1; + break; + } + } + if ( ! visual_ok ) { + continue; + } + } +#ifdef INTEL_XV_BADALLOC_WORKAROUND + if ( !strcmp(ainfo[i].name, "Intel(R) Video Overla")) + intel_adapter = True; + else + intel_adapter = False; +#endif + if ( (ainfo[i].type & XvInputMask) && + (ainfo[i].type & XvImageMask) ) { + int num_formats; + SDL_NAME(XvImageFormatValues) *formats; + formats = SDL_NAME(XvListImageFormats)(GFX_Display, + ainfo[i].base_id, &num_formats); +#ifdef USE_LAST_ADAPTOR + for ( j=0; j < num_formats; ++j ) +#else + for ( j=0; (j < num_formats) && (xv_port == -1); ++j ) +#endif /* USE_LAST_ADAPTOR */ + { + if ( (Uint32)formats[j].id == format ) { + for ( k=0; k < ainfo[i].num_ports; ++k ) { + if ( Success == SDL_NAME(XvGrabPort)(GFX_Display, ainfo[i].base_id+k, CurrentTime) ) { + xv_port = ainfo[i].base_id+k; + break; + } + } + } + } + if ( formats ) { + XFree(formats); + } + } + } + SDL_NAME(XvFreeAdaptorInfo)(ainfo); + } + + /* Precalculate the bpp for the pitch workaround below */ + switch (format) { + /* Add any other cases we need to support... */ + case SDL_YUY2_OVERLAY: + case SDL_UYVY_OVERLAY: + case SDL_YVYU_OVERLAY: + bpp = 2; + break; + default: + bpp = 1; + break; + } + +#if 0 + /* + * !!! FIXME: + * "Here are some diffs for X11 and yuv. Note that the last part 2nd + * diff should probably be a new call to XvQueryAdaptorFree with ainfo + * and the number of adaptors, instead of the loop through like I did." + * + * ACHTUNG: This is broken! It looks like XvFreeAdaptorInfo does this + * for you, so we end up with a double-free. I need to look at this + * more closely... --ryan. + */ + for ( i=0; i < adaptors; ++i ) { + if (ainfo[i].name != NULL) Xfree(ainfo[i].name); + if (ainfo[i].formats != NULL) Xfree(ainfo[i].formats); + } + Xfree(ainfo); +#endif + + if ( xv_port == -1 ) { + SDL_SetError("No available video ports for requested format"); + return(NULL); + } + + /* Enable auto-painting of the overlay colorkey */ + { + static const char *attr[] = { "XV_AUTOPAINT_COLORKEY", "XV_AUTOPAINT_COLOURKEY" }; + unsigned int i; + + SDL_NAME(XvSelectPortNotify)(GFX_Display, xv_port, True); + X_handler = XSetErrorHandler(xv_errhandler); + for ( i=0; i < sizeof(attr)/(sizeof attr[0]); ++i ) { + Atom a; + + xv_error = False; + a = XInternAtom(GFX_Display, attr[i], True); + if ( a != None ) { + SDL_NAME(XvSetPortAttribute)(GFX_Display, xv_port, a, 1); + XSync(GFX_Display, True); + if ( ! xv_error ) { + break; + } + } + } + XSetErrorHandler(X_handler); + SDL_NAME(XvSelectPortNotify)(GFX_Display, xv_port, False); + } + + /* Create the overlay structure */ + overlay = (SDL_Overlay *)SDL_malloc(sizeof *overlay); + if ( overlay == NULL ) { + SDL_NAME(XvUngrabPort)(GFX_Display, xv_port, CurrentTime); + SDL_OutOfMemory(); + return(NULL); + } + SDL_memset(overlay, 0, (sizeof *overlay)); + + /* Fill in the basic members */ + overlay->format = format; + overlay->w = width; + overlay->h = height; + + /* Set up the YUV surface function structure */ + overlay->hwfuncs = &x11_yuvfuncs; + overlay->hw_overlay = 1; + + /* Create the pixel data and lookup tables */ + hwdata = (struct private_yuvhwdata *)SDL_malloc(sizeof *hwdata); + overlay->hwdata = hwdata; + if ( hwdata == NULL ) { + SDL_NAME(XvUngrabPort)(GFX_Display, xv_port, CurrentTime); + SDL_OutOfMemory(); + SDL_FreeYUVOverlay(overlay); + return(NULL); + } + hwdata->port = xv_port; +#ifndef NO_SHARED_MEMORY + yuvshm = &hwdata->yuvshm; + SDL_memset(yuvshm, 0, sizeof(*yuvshm)); + hwdata->image = SDL_NAME(XvShmCreateImage)(GFX_Display, xv_port, format, + 0, width, height, yuvshm); +#ifdef PITCH_WORKAROUND + if ( hwdata->image != NULL && hwdata->image->pitches[0] != (width*bpp) ) { + /* Ajust overlay width according to pitch */ + width = hwdata->image->pitches[0] / bpp; + XFree(hwdata->image); + hwdata->image = SDL_NAME(XvShmCreateImage)(GFX_Display, xv_port, format, + 0, width, height, yuvshm); + } +#endif /* PITCH_WORKAROUND */ + hwdata->yuv_use_mitshm = (hwdata->image != NULL); + if ( hwdata->yuv_use_mitshm ) { + yuvshm->shmid = shmget(IPC_PRIVATE, hwdata->image->data_size, + IPC_CREAT | 0777); + if ( yuvshm->shmid >= 0 ) { + yuvshm->shmaddr = (char *)shmat(yuvshm->shmid, 0, 0); + yuvshm->readOnly = False; + if ( yuvshm->shmaddr != (char *)-1 ) { + shm_error = False; + X_handler = XSetErrorHandler(shm_errhandler); + XShmAttach(GFX_Display, yuvshm); + XSync(GFX_Display, True); + XSetErrorHandler(X_handler); + if ( shm_error ) + shmdt(yuvshm->shmaddr); + } else { + shm_error = True; + } + shmctl(yuvshm->shmid, IPC_RMID, NULL); + } else { + shm_error = True; + } + if ( shm_error ) { + XFree(hwdata->image); + hwdata->yuv_use_mitshm = 0; + } else { + hwdata->image->data = yuvshm->shmaddr; + } + } + if ( !hwdata->yuv_use_mitshm ) +#endif /* NO_SHARED_MEMORY */ + { + hwdata->image = SDL_NAME(XvCreateImage)(GFX_Display, xv_port, format, + 0, width, height); + +#ifdef PITCH_WORKAROUND + if ( hwdata->image != NULL && hwdata->image->pitches[0] != (width*bpp) ) { + /* Ajust overlay width according to pitch */ + XFree(hwdata->image); + width = hwdata->image->pitches[0] / bpp; + hwdata->image = SDL_NAME(XvCreateImage)(GFX_Display, xv_port, format, + 0, width, height); + } +#endif /* PITCH_WORKAROUND */ + if ( hwdata->image == NULL ) { + SDL_SetError("Couldn't create XVideo image"); + SDL_FreeYUVOverlay(overlay); + return(NULL); + } + hwdata->image->data = SDL_malloc(hwdata->image->data_size); + if ( hwdata->image->data == NULL ) { + SDL_OutOfMemory(); + SDL_FreeYUVOverlay(overlay); + return(NULL); + } + } + + /* Find the pitch and offset values for the overlay */ + overlay->planes = hwdata->image->num_planes; + overlay->pitches = (Uint16 *)SDL_malloc(overlay->planes * sizeof(Uint16)); + overlay->pixels = (Uint8 **)SDL_malloc(overlay->planes * sizeof(Uint8 *)); + if ( !overlay->pitches || !overlay->pixels ) { + SDL_OutOfMemory(); + SDL_FreeYUVOverlay(overlay); + return(NULL); + } + for ( i=0; iplanes; ++i ) { + overlay->pitches[i] = hwdata->image->pitches[i]; + overlay->pixels[i] = (Uint8 *)hwdata->image->data + + hwdata->image->offsets[i]; + } + +#ifdef XFREE86_REFRESH_HACK + /* Work around an XFree86 X server bug (?) + We can't perform normal updates in windows that have video + being output to them. See SDL_x11image.c for more details. + */ + X11_DisableAutoRefresh(this); +#endif + +#ifdef INTEL_XV_BADALLOC_WORKAROUND + /* HACK, GRRR sometimes (i810) creating the overlay succeeds, but the + first call to XvShm[Put]Image to a mapped window fails with: + "BadAlloc (insufficient resources for operation)". This happens with + certain formats when the XvImage is too large to the i810's liking. + + We work around this by doing a test XvShm[Put]Image with a black + Xv image, this may cause some flashing, so only do this check if we + are running on an intel Xv-adapter. */ + if (intel_adapter) + { + xv_error = False; + X_handler = XSetErrorHandler(intel_errhandler); + + X11_ClearYUVOverlay(overlay); + + /* We set the destination height and width to 1 pixel to avoid + putting a large black rectangle over the screen, thus + strongly reducing possible flashing. */ +#ifndef NO_SHARED_MEMORY + if ( hwdata->yuv_use_mitshm ) { + SDL_NAME(XvShmPutImage)(GFX_Display, hwdata->port, + SDL_Window, SDL_GC, + hwdata->image, + 0, 0, overlay->w, overlay->h, + 0, 0, 1, 1, False); + } + else +#endif + { + SDL_NAME(XvPutImage)(GFX_Display, hwdata->port, + SDL_Window, SDL_GC, + hwdata->image, + 0, 0, overlay->w, overlay->h, + 0, 0, 1, 1); + } + XSync(GFX_Display, False); + XSetErrorHandler(X_handler); + + if (xv_error) + { + X11_FreeYUVOverlay(this, overlay); + return NULL; + } + /* Repair the (1 pixel worth of) damage we've just done */ + X11_RefreshDisplay(this); + } +#endif + + /* We're all done.. */ + return(overlay); +} + +int X11_LockYUVOverlay(_THIS, SDL_Overlay *overlay) +{ + return(0); +} + +void X11_UnlockYUVOverlay(_THIS, SDL_Overlay *overlay) +{ + return; +} + +int X11_DisplayYUVOverlay(_THIS, SDL_Overlay *overlay, SDL_Rect *src, SDL_Rect *dst) +{ + struct private_yuvhwdata *hwdata; + + hwdata = overlay->hwdata; + +#ifndef NO_SHARED_MEMORY + if ( hwdata->yuv_use_mitshm ) { + SDL_NAME(XvShmPutImage)(GFX_Display, hwdata->port, SDL_Window, SDL_GC, + hwdata->image, + src->x, src->y, src->w, src->h, + dst->x, dst->y, dst->w, dst->h, False); + } + else +#endif + { + SDL_NAME(XvPutImage)(GFX_Display, hwdata->port, SDL_Window, SDL_GC, + hwdata->image, + src->x, src->y, src->w, src->h, + dst->x, dst->y, dst->w, dst->h); + } + XSync(GFX_Display, False); + return(0); +} + +void X11_FreeYUVOverlay(_THIS, SDL_Overlay *overlay) +{ + struct private_yuvhwdata *hwdata; + + hwdata = overlay->hwdata; + if ( hwdata ) { + SDL_NAME(XvUngrabPort)(GFX_Display, hwdata->port, CurrentTime); +#ifndef NO_SHARED_MEMORY + if ( hwdata->yuv_use_mitshm ) { + XShmDetach(GFX_Display, &hwdata->yuvshm); + shmdt(hwdata->yuvshm.shmaddr); + } +#endif + if ( hwdata->image ) { + XFree(hwdata->image); + } + SDL_free(hwdata); + } + if ( overlay->pitches ) { + SDL_free(overlay->pitches); + overlay->pitches = NULL; + } + if ( overlay->pixels ) { + SDL_free(overlay->pixels); + overlay->pixels = NULL; + } +#ifdef XFREE86_REFRESH_HACK + X11_EnableAutoRefresh(this); +#endif +} + +#endif /* SDL_VIDEO_DRIVER_X11_XV */ diff --git a/apps/plugins/sdl/src/video/x11/SDL_x11yuv_c.h b/apps/plugins/sdl/src/video/x11/SDL_x11yuv_c.h new file mode 100644 index 0000000000..d297683c24 --- /dev/null +++ b/apps/plugins/sdl/src/video/x11/SDL_x11yuv_c.h @@ -0,0 +1,41 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* This is the XFree86 Xv extension implementation of YUV video overlays */ + +#include "SDL_video.h" +#include "SDL_x11video.h" + +#if SDL_VIDEO_DRIVER_X11_XV + +extern SDL_Overlay *X11_CreateYUVOverlay(_THIS, int width, int height, Uint32 format, SDL_Surface *display); + +extern int X11_LockYUVOverlay(_THIS, SDL_Overlay *overlay); + +extern void X11_UnlockYUVOverlay(_THIS, SDL_Overlay *overlay); + +extern int X11_DisplayYUVOverlay(_THIS, SDL_Overlay *overlay, SDL_Rect *src, SDL_Rect *dst); + +extern void X11_FreeYUVOverlay(_THIS, SDL_Overlay *overlay); + +#endif /* SDL_VIDEO_DRIVER_X11_XV */ -- cgit v1.2.3