Commit 532023bd authored by Sam Lantinga's avatar Sam Lantinga

Starting fresh with the X11 driver

--HG--
extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%401994
parent fe52e82b
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2004 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 <stdio.h>
#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)
{
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. */
}
/* 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;
#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 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;
#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(a,fn,x,y,z) X11_GetSym(#fn,thismod,(void**)&p##fn);
#include "SDL_x11sym.h"
#undef SDL_X11_MODULE
#undef SDL_X11_SYM
#ifdef X_HAVE_UTF8_STRING
X11_GetSym("XCreateIC", &SDL_X11_HAVE_UTF8, (void **) &pXCreateIC);
#endif
if (!SDL_X11_HAVE_BASEXLIB) { /* some required symbol didn't load. */
SDL_X11_UnloadSymbols(); /* in case something got loaded... */
rc = 0;
}
}
#else
#ifdef X_HAVE_UTF8_STRING
pXCreateIC = XCreateIC;
#endif
#endif
return rc;
}
/* end of SDL_x11dyn.c ... */
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2004 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 <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/Xlibint.h>
#include <X11/Xproto.h>
#include "../Xext/extensions/Xext.h"
#include "../Xext/extensions/extutil.h"
#ifndef NO_SHARED_MEMORY
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>
#endif
#if SDL_VIDEO_DRIVER_X11_XRANDR
#include <X11/extensions/Xrandr.h>
#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, ...);
#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 */
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 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 <setjmp.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#ifdef __SVR4
#include <X11/Sunkeysym.h>
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#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);
#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;
}
#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);
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 ((xevent.xcrossing.mode != NotifyGrab) &&
(xevent.xcrossing.mode != NotifyUngrab)) {
if (SDL_CurrentWindow.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 (SDL_CurrentWindow.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;
/* 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:
{
static SDL_keysym saved_keysym;
SDL_keysym keysym;
KeyCode keycode = xevent.xkey.keycode;
#ifdef DEBUG_XEVENTS
printf("KeyPress (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
#endif
/* Get the translated SDL virtual keysym */
if (keycode) {
keysym.scancode = keycode;
keysym.sym = X11_TranslateKeycode(SDL_Display, keycode);
keysym.mod = KMOD_NONE;
keysym.unicode = 0;
} else {
keysym = saved_keysym;
}
/* If we're not doing translation, we're done! */
if (!SDL_TranslateUNICODE) {
posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
break;
}
if (XFilterEvent(&xevent, None)) {
if (xevent.xkey.keycode) {
posted = SDL_PrivateKeyboard(SDL_PRESSED, &keysym);
} else {
/* Save event to be associated with IM text
In 1.3 we'll have a text event instead.. */
saved_keysym = keysym;
}
break;
}
/* Look up the translated value for the key event */
#ifdef X_HAVE_UTF8_STRING
if (SDL_IC != NULL) {
static Status state;
/* A UTF-8 character can be at most 6 bytes */
char keybuf[6];
if (Xutf8LookupString(SDL_IC, &xevent.xkey,
keybuf, sizeof(keybuf), NULL, &state)) {
keysym.unicode = Utf8ToUcs4((Uint8 *) keybuf);
}
} else
#endif
{
static XComposeStatus state;
char keybuf[32];
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;
#ifdef DEBUG_XEVENTS
printf("KeyRelease (X11 keycode = 0x%X)\n", xevent.xkey.keycode);
#endif
/* Check to see if this is a repeated key */
if (X11_KeyRepeat(SDL_Display, &xevent)) {
break;
}
/* 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, SDL_CurrentWindow.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 (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_INTERNALOPENGL) {
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;
/* 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, SDL_CurrentWindow.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 < SDL_arraysize(ODD_keymap); ++i)
ODD_keymap[i] = SDLK_UNKNOWN;
/* Some of these might be mappable to an existing SDLK_ code */
ODD_keymap[XK_dead_grave & 0xFF] = SDLK_COMPOSE;
ODD_keymap[XK_dead_acute & 0xFF] = SDLK_COMPOSE;
ODD_keymap[XK_dead_tilde & 0xFF] = SDLK_COMPOSE;
ODD_keymap[XK_dead_macron & 0xFF] = SDLK_COMPOSE;
ODD_keymap[XK_dead_breve & 0xFF] = SDLK_COMPOSE;
ODD_keymap[XK_dead_abovedot & 0xFF] = SDLK_COMPOSE;
ODD_keymap[XK_dead_diaeresis & 0xFF] = SDLK_COMPOSE;
ODD_keymap[XK_dead_abovering & 0xFF] = SDLK_COMPOSE;
ODD_keymap[XK_dead_doubleacute & 0xFF] = SDLK_COMPOSE;
ODD_keymap[XK_dead_caron & 0xFF] = SDLK_COMPOSE;
ODD_keymap[XK_dead_cedilla & 0xFF] = SDLK_COMPOSE;
ODD_keymap[XK_dead_ogonek & 0xFF] = SDLK_COMPOSE;
ODD_keymap[XK_dead_iota & 0xFF] = SDLK_COMPOSE;
ODD_keymap[XK_dead_voiced_sound & 0xFF] = SDLK_COMPOSE;
ODD_keymap[XK_dead_semivoiced_sound & 0xFF] = SDLK_COMPOSE;
ODD_keymap[XK_dead_belowdot & 0xFF] = SDLK_COMPOSE;
#ifdef XK_dead_hook
ODD_keymap[XK_dead_hook & 0xFF] = SDLK_COMPOSE;
#endif
#ifdef XK_dead_horn
ODD_keymap[XK_dead_horn & 0xFF] = SDLK_COMPOSE;
#endif
#ifdef XK_dead_circumflex
/* These X keysyms have 0xFE as the high byte */
ODD_keymap[XK_dead_circumflex & 0xFF] = SDLK_CARET;
#endif
#ifdef XK_ISO_Level3_Shift
ODD_keymap[XK_ISO_Level3_Shift & 0xFF] = SDLK_MODE; /* "Alt Gr" key */
#endif
/* Map the miscellaneous keys */
for (i = 0; i < SDL_arraysize(MISC_keymap); ++i)
MISC_keymap[i] = SDLK_UNKNOWN;
/* These X keysyms have 0xFF as the high byte */
MISC_keymap[XK_BackSpace & 0xFF] = SDLK_BACKSPACE;
MISC_keymap[XK_Tab & 0xFF] = SDLK_TAB;
MISC_keymap[XK_Clear & 0xFF] = SDLK_CLEAR;
MISC_keymap[XK_Return & 0xFF] = SDLK_RETURN;
MISC_keymap[XK_Pause & 0xFF] = SDLK_PAUSE;
MISC_keymap[XK_Escape & 0xFF] = SDLK_ESCAPE;
MISC_keymap[XK_Delete & 0xFF] = SDLK_DELETE;
MISC_keymap[XK_KP_0 & 0xFF] = SDLK_KP0; /* Keypad 0-9 */
MISC_keymap[XK_KP_1 & 0xFF] = SDLK_KP1;
MISC_keymap[XK_KP_2 & 0xFF] = SDLK_KP2;
MISC_keymap[XK_KP_3 & 0xFF] = SDLK_KP3;
MISC_keymap[XK_KP_4 & 0xFF] = SDLK_KP4;
MISC_keymap[XK_KP_5 & 0xFF] = SDLK_KP5;
MISC_keymap[XK_KP_6 & 0xFF] = SDLK_KP6;
MISC_keymap[XK_KP_7 & 0xFF] = SDLK_KP7;
MISC_keymap[XK_KP_8 & 0xFF] = SDLK_KP8;
MISC_keymap[XK_KP_9 & 0xFF] = SDLK_KP9;
MISC_keymap[XK_KP_Insert & 0xFF] = SDLK_KP0;
MISC_keymap[XK_KP_End & 0xFF] = SDLK_KP1;
MISC_keymap[XK_KP_Down & 0xFF] = SDLK_KP2;
MISC_keymap[XK_KP_Page_Down & 0xFF] = SDLK_KP3;
MISC_keymap[XK_KP_Left & 0xFF] = SDLK_KP4;
MISC_keymap[XK_KP_Begin & 0xFF] = SDLK_KP5;
MISC_keymap[XK_KP_Right & 0xFF] = SDLK_KP6;
MISC_keymap[XK_KP_Home & 0xFF] = SDLK_KP7;
MISC_keymap[XK_KP_Up & 0xFF] = SDLK_KP8;
MISC_keymap[XK_KP_Page_Up & 0xFF] = SDLK_KP9;
MISC_keymap[XK_KP_Delete & 0xFF] = SDLK_KP_PERIOD;
MISC_keymap[XK_KP_Decimal & 0xFF] = SDLK_KP_PERIOD;
MISC_keymap[XK_KP_Divide & 0xFF] = SDLK_KP_DIVIDE;
MISC_keymap[XK_KP_Multiply & 0xFF] = SDLK_KP_MULTIPLY;
MISC_keymap[XK_KP_Subtract & 0xFF] = SDLK_KP_MINUS;
MISC_keymap[XK_KP_Add & 0xFF] = SDLK_KP_PLUS;
MISC_keymap[XK_KP_Enter & 0xFF] = SDLK_KP_ENTER;
MISC_keymap[XK_KP_Equal & 0xFF] = SDLK_KP_EQUALS;
MISC_keymap[XK_Up & 0xFF] = SDLK_UP;
MISC_keymap[XK_Down & 0xFF] = SDLK_DOWN;
MISC_keymap[XK_Right & 0xFF] = SDLK_RIGHT;
MISC_keymap[XK_Left & 0xFF] = SDLK_LEFT;
MISC_keymap[XK_Insert & 0xFF] = SDLK_INSERT;
MISC_keymap[XK_Home & 0xFF] = SDLK_HOME;
MISC_keymap[XK_End & 0xFF] = SDLK_END;
MISC_keymap[XK_Page_Up & 0xFF] = SDLK_PAGEUP;
MISC_keymap[XK_Page_Down & 0xFF] = SDLK_PAGEDOWN;
MISC_keymap[XK_F1 & 0xFF] = SDLK_F1;
MISC_keymap[XK_F2 & 0xFF] = SDLK_F2;
MISC_keymap[XK_F3 & 0xFF] = SDLK_F3;
MISC_keymap[XK_F4 & 0xFF] = SDLK_F4;
MISC_keymap[XK_F5 & 0xFF] = SDLK_F5;
MISC_keymap[XK_F6 & 0xFF] = SDLK_F6;
MISC_keymap[XK_F7 & 0xFF] = SDLK_F7;
MISC_keymap[XK_F8 & 0xFF] = SDLK_F8;
MISC_keymap[XK_F9 & 0xFF] = SDLK_F9;
MISC_keymap[XK_F10 & 0xFF] = SDLK_F10;
MISC_keymap[XK_F11 & 0xFF] = SDLK_F11;
MISC_keymap[XK_F12 & 0xFF] = SDLK_F12;
MISC_keymap[XK_F13 & 0xFF] = SDLK_F13;
MISC_keymap[XK_F14 & 0xFF] = SDLK_F14;
MISC_keymap[XK_F15 & 0xFF] = SDLK_F15;
MISC_keymap[XK_Num_Lock & 0xFF] = SDLK_NUMLOCK;
MISC_keymap[XK_Caps_Lock & 0xFF] = SDLK_CAPSLOCK;
MISC_keymap[XK_Scroll_Lock & 0xFF] = SDLK_SCROLLOCK;
MISC_keymap[XK_Shift_R & 0xFF] = SDLK_RSHIFT;
MISC_keymap[XK_Shift_L & 0xFF] = SDLK_LSHIFT;
MISC_keymap[XK_Control_R & 0xFF] = SDLK_RCTRL;
MISC_keymap[XK_Control_L & 0xFF] = SDLK_LCTRL;
MISC_keymap[XK_Alt_R & 0xFF] = SDLK_RALT;
MISC_keymap[XK_Alt_L & 0xFF] = SDLK_LALT;
MISC_keymap[XK_Meta_R & 0xFF] = SDLK_RMETA;
MISC_keymap[XK_Meta_L & 0xFF] = SDLK_LMETA;
MISC_keymap[XK_Super_L & 0xFF] = SDLK_LSUPER; /* Left "Windows" */
MISC_keymap[XK_Super_R & 0xFF] = SDLK_RSUPER; /* Right "Windows */
MISC_keymap[XK_Mode_switch & 0xFF] = SDLK_MODE; /* "Alt Gr" key */
MISC_keymap[XK_Multi_key & 0xFF] = SDLK_COMPOSE; /* Multi-key compose */
MISC_keymap[XK_Help & 0xFF] = SDLK_HELP;
MISC_keymap[XK_Print & 0xFF] = SDLK_PRINT;
MISC_keymap[XK_Sys_Req & 0xFF] = SDLK_SYSREQ;
MISC_keymap[XK_Break & 0xFF] = SDLK_BREAK;
MISC_keymap[XK_Menu & 0xFF] = SDLK_MENU;
MISC_keymap[XK_Hyper_R & 0xFF] = SDLK_MENU; /* Windows "Menu" key */
}
/* Get the translated SDL virtual keysym */
SDLKey
X11_TranslateKeycode(Display * display, KeyCode kc)
{
KeySym xsym;
SDLKey key;
xsym = XKeycodeToKeysym(display, kc, 0);
#ifdef DEBUG_KEYS
fprintf(stderr, "Translating key code %d -> 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)
{
SDL_VideoDevice *_this = SDL_GetVideoDevice();
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();
}
void
X11_SaveScreenSaver(Display * display, int *saved_timeout, BOOL * dpms)
{
int timeout, interval, prefer_blank, allow_exp;
XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
*saved_timeout = timeout;
#if SDL_VIDEO_DRIVER_X11_DPMS
if (SDL_X11_HAVE_DPMS) {
int dummy;
if (DPMSQueryExtension(display, &dummy, &dummy)) {
CARD16 state;
DPMSInfo(display, &state, dpms);
}
}
#else
*dpms = 0;
#endif /* SDL_VIDEO_DRIVER_X11_DPMS */
}
void
X11_DisableScreenSaver(Display * display)
{
int timeout, interval, prefer_blank, allow_exp;
XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
timeout = 0;
XSetScreenSaver(display, timeout, interval, prefer_blank, allow_exp);
#if SDL_VIDEO_DRIVER_X11_DPMS
if (SDL_X11_HAVE_DPMS) {
int dummy;
if (DPMSQueryExtension(display, &dummy, &dummy)) {
DPMSDisable(display);
}
}
#endif /* SDL_VIDEO_DRIVER_X11_DPMS */
}
void
X11_RestoreScreenSaver(Display * display, int saved_timeout, BOOL dpms)
{
int timeout, interval, prefer_blank, allow_exp;
XGetScreenSaver(display, &timeout, &interval, &prefer_blank, &allow_exp);
timeout = saved_timeout;
XSetScreenSaver(display, timeout, interval, prefer_blank, allow_exp);
#if SDL_VIDEO_DRIVER_X11_DPMS
if (SDL_X11_HAVE_DPMS) {
int dummy;
if (DPMSQueryExtension(display, &dummy, &dummy)) {
if (dpms) {
DPMSEnable(display);
}
}
}
#endif /* SDL_VIDEO_DRIVER_X11_DPMS */
}
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 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);
extern void X11_SaveScreenSaver(Display * display, int *saved_timeout,
BOOL * dpms);
extern void X11_DisableScreenSaver(Display * display);
extern void X11_RestoreScreenSaver(Display * display, int saved_timeout,
BOOL dpms);
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 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]);
}
}
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 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
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 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"
#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
#ifndef GLX_EXT_visual_rating
#define GLX_EXT_visual_rating
#define GLX_VISUAL_CAVEAT_EXT 0x20
#define GLX_NONE_EXT 0x8000
#define GLX_SLOW_VISUAL_EXT 0x8001
#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.
*/
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.buffer_size) {
attribs[i++] = GLX_BUFFER_SIZE;
attribs[i++] = this->gl_config.buffer_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, "SGI_swap_control")) {
this->gl_data->glXSwapIntervalSGI = NULL;
}
if (!glXExtensionSupported(this, "GLX_MESA_swap_control")) {
this->gl_data->glXSwapIntervalMESA = NULL;
this->gl_data->glXGetSwapIntervalMESA = NULL;
}
if (this->gl_config.swap_control >= 0) {
if (this->gl_data->glXSwapIntervalMESA) {
this->gl_data->glXSwapIntervalMESA(this->gl_config.swap_control);
} else if (this->gl_data->glXSwapIntervalSGI) {
this->gl_data->glXSwapIntervalSGI(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;
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 {
return (-1);
}
break;
case SDL_GL_SWAP_CONTROL:
if (this->gl_data->glXGetSwapIntervalMESA) {
*value = this->gl_data->glXGetSwapIntervalMESA();
return (0);
} else {
return (-1);
}
break;
default:
return (-1);
}
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 <dlfcn.h>
#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->glXGetSwapIntervalMESA = 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) {
/* SDL_LoadObject() will call SDL_SetError() for us. */
return -1;
}
/* Unload the old driver and reset the pointers */
X11_GL_UnloadLibrary(this);
/* Load new function pointers */
this->gl_data->glXGetProcAddress =
(void *(*)(const GLubyte *)) GL_LoadFunction(handle,
"glXGetProcAddressARB");
this->gl_data->glXChooseVisual =
(XVisualInfo * (*)(Display *, int, int *)) GL_LoadFunction(handle,
"glXChooseVisual");
this->gl_data->glXCreateContext =
(GLXContext(*)(Display *, XVisualInfo *, GLXContext, int))
GL_LoadFunction(handle, "glXCreateContext");
this->gl_data->glXDestroyContext =
(void (*)(Display *, GLXContext)) GL_LoadFunction(handle,
"glXDestroyContext");
this->gl_data->glXMakeCurrent =
(int (*)(Display *, GLXDrawable, GLXContext)) GL_LoadFunction(handle,
"glXMakeCurrent");
this->gl_data->glXSwapBuffers =
(void (*)(Display *, GLXDrawable)) GL_LoadFunction(handle,
"glXSwapBuffers");
this->gl_data->glXGetConfig =
(int (*)(Display *, XVisualInfo *, int, int *))
GL_LoadFunction(handle, "glXGetConfig");
this->gl_data->glXQueryExtensionsString =
(const char *(*)(Display *, int)) GL_LoadFunction(handle,
"glXQueryExtensionsString");
this->gl_data->glXSwapIntervalSGI =
(int (*)(int)) GL_LoadFunction(handle, "glXSwapIntervalSGI");
this->gl_data->glXSwapIntervalMESA =
(GLint(*)(unsigned)) GL_LoadFunction(handle, "glXSwapIntervalMESA");
this->gl_data->glXGetSwapIntervalMESA =
(GLint(*)(void)) GL_LoadFunction(handle, "glXGetSwapIntervalMESA");
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)) {
SDL_SetError("Could not retrieve OpenGL functions");
return -1;
}
this->gl_config.dll_handle = handle;
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)
{
void *handle;
handle = this->gl_config.dll_handle;
if (this->gl_data->glXGetProcAddress) {
return this->gl_data->glXGetProcAddress((const GLubyte *) proc);
}
return GL_LoadFunction(handle, proc);
}
#endif /* SDL_VIDEO_OPENGL_GLX */
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 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 <GL/glx.h>
#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);
GLint(*glXGetSwapIntervalMESA) (void);
#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);
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 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 <stdio.h>
#include <unistd.h>
#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 */
{
int bpp;
screen->pixels = SDL_malloc(screen->h * screen->pitch);
if (screen->pixels == NULL) {
SDL_OutOfMemory();
return -1;
}
bpp = screen->format->BytesPerPixel;
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_INTERNALOPENGL) { /* 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; i < numrects; ++i) {
if (rects[i].w == 0 || rects[i].h == 0) { /* Clipped? */
continue;
}
XShmPutImage(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, False);
}
if (SDL_VideoSurface->flags & 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, SDL_CurrentWindow.offset_x,
SDL_CurrentWindow.offset_y,
SDL_CurrentDisplay.current_mode.w,
SDL_CurrentDisplay.current_mode.h, False);
} else
#endif /* ! NO_SHARED_MEMORY */
{
XPutImage(SDL_Display, SDL_Window, SDL_GC, SDL_Ximage,
0, 0, SDL_CurrentWindow.offset_x,
SDL_CurrentWindow.offset_y,
SDL_CurrentDisplay.current_mode.w,
SDL_CurrentDisplay.current_mode.h);
}
XSync(SDL_Display, False);
}
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 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);
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 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 <stdio.h>
#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_VIDMODE
int
vidmode_refreshrate(SDL_NAME(XF86VidModeModeInfo) * mode)
{
return (mode->htotal
&& mode->vtotal) ? (1000 * mode->dotclock / (mode->htotal *
mode->vtotal)) : 0;
}
#endif
#if SDL_VIDEO_DRIVER_X11_VIDMODE
Bool SDL_NAME(XF86VidModeGetModeInfo) (Display * dpy, int scr,
SDL_NAME(XF86VidModeModeInfo) * info)
{
SDL_NAME(XF86VidModeModeLine) * l =
(SDL_NAME(XF86VidModeModeLine) *) ((char *) info +
sizeof info->dotclock);
return SDL_NAME(XF86VidModeGetModeLine) (dpy, scr,
(int *) &info->dotclock, l);
}
#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
static void get_real_resolution(_THIS, int *w, int *h);
static void
set_best_resolution(_THIS, int width, int height)
{
SDL_DisplayMode mode;
mode.format = 0;
mode.w = width;
mode.h = height;
mode.refresh_rate = 0;
SDL_GetClosestDisplayMode(&mode, &mode, SDL_FULLSCREEN);
#if SDL_VIDEO_DRIVER_X11_VIDMODE
if (use_vidmode) {
SDL_NAME(XF86VidModeModeLine) vmode;
SDL_NAME(XF86VidModeModeInfo) vinfo;
SDL_NAME(XF86VidModeModeInfo) ** modes;
int i, dotclock;
int nmodes;
int best = -1;
if (SDL_NAME(XF86VidModeGetModeLine)
(SDL_Display, SDL_Screen, &dotclock, &vmode)
&& SDL_NAME(XF86VidModeGetAllModeLines) (SDL_Display,
SDL_Screen, &nmodes,
&modes)) {
vinfo.dotclock = dotclock;
SDL_memcpy(&vinfo.hdisplay, &vmode, sizeof(vmode));
for (i = 0; i < nmodes; i++) {
if ((modes[i]->hdisplay == mode.w) &&
(modes[i]->vdisplay == mode.h) &&
(vidmode_refreshrate(modes[i]) == mode.refresh_rate)) {
best = i;
break;
}
}
if (best >= 0 &&
((modes[best]->hdisplay != vmode.hdisplay) ||
(modes[best]->vdisplay != vmode.vdisplay) ||
(vidmode_refreshrate(modes[best]) !=
vidmode_refreshrate(&vinfo)))) {
#ifdef X11MODES_DEBUG
printf("Best Mode %d: %d x %d @ %d\n", best,
modes[best]->hdisplay, modes[best]->vdisplay,
vidmode_refreshrate(modes[best]));
#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) {
int i;
int w, h;
/* check current mode so we can avoid uneccessary mode changes */
get_real_resolution(this, &w, &h);
if ((mode.w != w) || (mode.h != h)) {
#ifdef X11MODES_DEBUG
fprintf(stderr, "XME: set_best_resolution: "
"XiGMiscChangeResolution: %d %d\n", mode.w, mode.h);
#endif
XiGMiscChangeResolution(SDL_Display, SDL_Screen, 0, /* view */
mode.w, mode.h, 0);
XSync(SDL_Display, False);
}
}
#endif /* SDL_VIDEO_DRIVER_X11_XME */
#if SDL_VIDEO_DRIVER_X11_XRANDR
if (use_xrandr) {
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 ((mode.w >= width) && (mode.h >= height)) {
break;
}
}
if (i >= 0) { /* 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 ((mode.w != w) || (mode.h != h)) {
int size_id;
#ifdef X11MODES_DEBUG
fprintf(stderr, "XRANDR: set_best_resolution: "
"XXRSetScreenConfig: %d %d\n", mode.w, mode.h);
#endif
/* find the matching size entry index */
for (size_id = 0; size_id < nsizes; ++size_id) {
if ((sizes[size_id].width == mode.w) &&
(sizes[size_id].height == mode.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[this->current_display].width;
*h = xinerama[this->current_display].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_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);
}
int
X11_GetVisuals(_THIS)
{
/* 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 i, 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 < SDL_arraysize(depth_list); ++i) {
if (depth_list[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);
}
}
}
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);
return 0;
}
/* 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;
major = 0;
minor = 0;
patch = 0;
fscanf(metro_fp, "%d.%d.%d", &major, &minor, &patch);
fclose(metro_fp);
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;
int nrates;
short *rates;
#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;
int screen_w;
int screen_h;
SDL_DisplayMode mode;
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);
mode.format = this->displays[this->current_display].desktop_mode.format;
mode.w = screen_w;
mode.h = screen_h;
mode.refresh_rate = 0;
SDL_AddDisplayMode(0, &mode);
#if SDL_VIDEO_DRIVER_X11_XINERAMA
/* Query Xinerama extention */
if (CheckXinerama(this, &xinerama_major, &xinerama_minor)) {
int screens;
#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 != 0) {
SDL_AddVideoDisplay(&mode);
}
mode.w = xinerama[i].width;
mode.h = xinerama[i].height;
SDL_AddDisplayMode(xinerama[i].screen_number, &mode);
}
use_xinerama = 1;
}
#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) {
for (i = 0; i < nsizes; i++) {
mode.w = sizes[i].width;
mode.h = sizes[i].height;
rates = XRRConfigRates(screen_config, i, &nrates);
if (nrates == 0) {
mode.refresh_rate = 0;
SDL_AddDisplayMode(0, &mode);
} else {
int j;
for (j = 0; j < nrates; ++j) {
mode.refresh_rate = rates[j];
SDL_AddDisplayMode(0, &mode);
}
}
}
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 &&
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,
vidmode_refreshrate(modes[i]));
}
#endif
for (i = 0; i < nmodes; ++i) {
mode.w = modes[i]->hdisplay;
mode.h = modes[i]->vdisplay;
mode.refresh_rate = vidmode_refreshrate(modes[i]);
SDL_AddDisplayMode(0, &mode);
}
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 */
/* 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
mode.refresh_rate = 0;
for (i = 0; i < nummodes; ++i) {
#ifdef X11MODES_DEBUG
fprintf(stderr, "XME: mode = %4d, w = %4d, h = %4d\n",
i, modelist[i].width, modelist[i].height);
#endif
mode.w = modelist[i].width;
mode.h = modelist[i].height;
SDL_AddDisplayMode(0, &mode);
}
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 */
#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");
}
#endif /* X11MODES_DEBUG */
return 0;
}
void
X11_FreeVideoModes(_THIS)
{
#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[this->current_display].width &&
window_h <= xinerama[this->current_display].height) {
x = xinerama[this->current_display].x_org;
y = xinerama[this->current_display].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[this->current_display].width &&
window_h <= xinerama[this->current_display].height) {
x = xinerama[this->current_display].x_org;
y = xinerama[this->current_display].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);
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);
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; i < nwindows; ++i) {
if (windows[i] == FSwindow) {
SDL_memcpy(&windows[i], &windows[i + 1],
(nwindows - i - 1) * sizeof(windows[i]));
break;
}
}
windows[nwindows - 1] = FSwindow;
XRestackWindows(SDL_Display, windows, nwindows);
XSync(SDL_Display, False);
}
XFree(windows);
}
#else
XRaiseWindow(SDL_Display, FSwindow);
#endif
#if SDL_VIDEO_DRIVER_X11_VIDMODE
/* Save the current video mode */
if (use_vidmode) {
SDL_NAME(XF86VidModeLockModeSwitch) (SDL_Display, SDL_Screen, True);
}
#endif
currently_fullscreen = 1;
/* Set the new resolution */
okay = X11_ResizeFullScreen(this);
if (!okay) {
X11_LeaveFullScreen(this);
}
/* Set the colormap */
if (SDL_XColorMap) {
XInstallColormap(SDL_Display, SDL_XColorMap);
}
if (okay) {
X11_GrabInputNoLock(this,
SDL_CurrentWindow.
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 (SDL_VideoSurface) {
if (SDL_VideoSurface->flags & SDL_INTERNALOPENGL) {
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,
SDL_CurrentWindow.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 (SDL_VideoSurface) {
if (SDL_VideoSurface->flags & SDL_INTERNALOPENGL) {
SDL_PrivateExpose();
} else {
X11_RefreshDisplay(this);
}
}
return (0);
}
Uint32
X11_VisualToFormat(const Visual * visual, int depth, int bpp)
{
Uint32 Rmask = visual->red_mask;
Uint32 Gmask = visual->green_mask;
Uint32 Bmask = visual->blue_mask;
Uint32 Amask;
if (depth == 32) {
Amask = (0xFFFFFFFF & ~(Rmask | Gmask | Bmask));
} else {
Amask = 0;
}
return (SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask));
}
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 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_GetVisuals(_THIS);
extern int X11_GetVideoModes(_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);
extern Uint32 X11_VisualToFormat(const Visual * visual, int depth, int bpp);
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 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 <X11/Xlib.h>
#include <X11/Xutil.h>
#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; i < clen; ++i) {
/* The mask is OR'd with the data to turn inverted color
pixels black since inverted color cursors aren't supported
under X11.
*/
x_mask[i] = data[i] | mask[i];
x_data[i] = data[i];
}
/* Prevent the event thread from running while we use the X server */
SDL_Lock_EventThread();
/* Create the data image */
data_image = XCreateImage(SDL_Display,
DefaultVisual(SDL_Display, SDL_Screen),
1, XYBitmap, 0, x_data, w, h, 8, w / 8);
data_image->byte_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 (mouse_param_buf) {
XChangePointerControl(SDL_Display, True, True,
accel_value[0], accel_value[1], accel_value[2]);
SDL_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;
/* 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) &&
(SDL_CurrentWindow.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();
}
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 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);
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2004 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(int, XGetScreenSaver,
(Display * a, int *b, int *c, int *d, int *e), (a, b, c, d, e),
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, 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, XSetScreenSaver,
(Display * a, int b,
int c, int d, int e),
(a, b, c, d, e), 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(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)
#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
/*
* 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(short *, XRRConfigRates,
(XRRScreenConfiguration * config, int sizeID, int *nrates),
(config, sizeID, nrates), 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
/* DPMS support */
#if SDL_VIDEO_DRIVER_X11_DPMS
SDL_X11_MODULE(DPMS)
SDL_X11_SYM(Status, DPMSQueryExtension,
(Display * dpy, int *major_versionp, int *minor_versionp), (dpy,
major_versionp,
minor_versionp),
return)
SDL_X11_SYM(Status, DPMSInfo, (Display * dpy, CARD16 * state, BOOL * onoff),
(dpy, state, onoff), return)
SDL_X11_SYM(Status, DPMSEnable, (Display * dpy), (dpy), return)
SDL_X11_SYM(Status, DPMSDisable, (Display * dpy), (dpy), return)
#endif
/* end of SDL_x11sym.h ... */
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 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 <unistd.h>
#include <sys/ioctl.h>
#ifdef MTRR_SUPPORT
#include <asm/mtrr.h>
#include <sys/fcntl.h>
#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"
/* Initialization/Query functions */
static int X11_VideoInit(_THIS);
static SDL_Surface *X11_SetVideoMode(_THIS, SDL_Surface * current,
const SDL_DisplayMode * mode,
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));
/* Set the driver flags */
device->handles_any_size = 1;
/* Set the function pointers */
device->VideoInit = X11_VideoInit;
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 (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;
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[this->current_display].x_org;
y = xinerama[this->current_display].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, SDL_CurrentWindow.wm_title,
SDL_CurrentWindow.wm_icon);
XSelectInput(SDL_Display, WMwindow,
FocusChangeMask | KeyPressMask | KeyReleaseMask
| PropertyChangeMask | StructureNotifyMask |
KeymapStateMask);
/* 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);
}
}
/* Setup the communication with the IM server */
SDL_IM = NULL;
SDL_IC = NULL;
#ifdef X_HAVE_UTF8_STRING
if (SDL_X11_HAVE_UTF8) {
SDL_IM = XOpenIM(SDL_Display, NULL, classname, classname);
if (SDL_IM == NULL) {
SDL_SetError("no input method could be opened");
} else {
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;
}
}
}
#endif
/* Allow the window to be deleted by the window manager */
XSetWMProtocols(SDL_Display, WMwindow, &WM_DELETE_WINDOW, 1);
}
static int
X11_VideoInit(_THIS)
{
char *display;
int i;
SDL_DisplayMode desktop_mode;
/* 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) {
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 visuals */
if (X11_GetVisuals(this) < 0)
return -1;
/* Determine the default screen mode:
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);
}
desktop_mode.format =
X11_VisualToFormat(this->hidden->visuals[i].visual,
this->hidden->visuals[i].depth,
this->hidden->visuals[i].bpp);
desktop_mode.w = DisplayWidth(SDL_Display, SDL_Screen);
desktop_mode.h = DisplayHeight(SDL_Display, SDL_Screen);
desktop_mode.refresh_rate = 0;
SDL_AddVideoDisplay(&desktop_mode);
/* Get the available video modes */
if (X11_GetVideoModes(this) < 0)
return -1;
X11_SaveVidModeGamma(this);
/* Save DPMS and screensaver settings */
X11_SaveScreenSaver(SDL_Display, &screensaver_timeout, &dpms_enabled);
X11_DisableScreenSaver(SDL_Display);
/* 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_INTERNALOPENGL;
}
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 < numcolors; ++pixel) {
while (SDL_XPixels[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 = 32;
hints->min_height = 32;
hints->max_height = 4096;
hints->max_width = 4096;
} else {
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;
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) {
/* NOTE: Does this work? */
XSetTransientForHint(SDL_Display, WMwindow, None);
}
}
}
static int
X11_CreateWindow(_THIS, SDL_Surface * screen,
const SDL_DisplayMode * mode, Uint32 flags)
{
int i, depth;
Visual *vis;
int vis_change;
int bpp;
Uint32 Rmask, Gmask, Bmask, Amask;
SDL_PixelFormatEnumToMasks(mode->format, &bpp, &Rmask, &Gmask, &Bmask,
&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_INTERNALOPENGL) {
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 &&
this->hidden->visuals[i].visual->red_mask == Rmask &&
this->hidden->visuals[i].visual->green_mask == Gmask &&
this->hidden->visuals[i].visual->blue_mask == Bmask)
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 (!SDL_ReallocFormat(screen, bpp, Rmask, Gmask, Bmask, 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);
SDL_VideoSurface = screen;
X11_SetGammaRamp(this, SDL_CurrentWindow.gamma);
SDL_VideoSurface = 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, mode->w, mode->h, flags);
window_w = mode->w;
window_h = mode->h;
XResizeWindow(SDL_Display, WMwindow, mode->w, mode->h);
}
/* Create (or use) the X11 display window */
if (!SDL_windowid) {
if (flags & SDL_INTERNALOPENGL) {
if (X11_GL_CreateWindow(this, mode->w, mode->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, mode->w, mode->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_INTERNALOPENGL) {
if (X11_GL_CreateContext(this) < 0) {
return (-1);
} else {
screen->flags |= SDL_INTERNALOPENGL;
}
} 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_INTERNALOPENGL)) {
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);
}
}
/* Update the internal keyboard state */
X11_SetKeyboardState(SDL_Display, NULL);
/* When the window is first mapped, ignore non-modifier keys */
{
Uint8 *keys = SDL_GetKeyState(NULL);
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;
}
}
}
/* 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,
const SDL_DisplayMode * mode, 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_INTERNALOPENGL) ==
(flags & SDL_INTERNALOPENGL))
&& (mode->format == SDL_CurrentDisplay.current_mode.format)
&& ((saved_flags & SDL_NOFRAME) == (flags & SDL_NOFRAME))) {
if (X11_ResizeWindow(this, current, mode->w, mode->h, flags) < 0) {
current = NULL;
goto done;
}
} else {
if (X11_CreateWindow(this, current, mode, flags) < 0) {
current = NULL;
goto done;
}
}
/* Set up the new mode framebuffer */
if (((current->w != mode->w) || (current->h != mode->h)) ||
((saved_flags & SDL_INTERNALOPENGL) != (flags & SDL_INTERNALOPENGL)))
{
current->w = mode->w;
current->h = mode->h;
current->pitch = SDL_CalculatePitch(current);
X11_ResizeImage(this, current, flags);
}
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) {
SDL_VideoSurface->flags |= SDL_FULLSCREEN;
X11_EnterFullScreen(this);
} else {
SDL_VideoSurface->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, &current_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 ((SDL_VideoSurface->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; i < ncolors; ++i) {
xcmap[i].pixel = i + firstcolor;
xcmap[i].red = (colors[i].r << 8) | colors[i].r;
xcmap[i].green = (colors[i].g << 8) | colors[i].g;
xcmap[i].blue = (colors[i].b << 8) | colors[i].b;
xcmap[i].flags = (DoRed | DoGreen | DoBlue);
}
XStoreColors(GFX_Display, SDL_XColorMap, xcmap, ncolors);
XSync(GFX_Display, False);
SDL_stack_free(xcmap);
} else {
/*
* Shared colormap: We only allocate read-only cells, which
* increases the likelyhood of colour sharing with other
* clients. The pixel values will almost certainly be
* different from the requested ones, so the user has to
* walk the colormap and see which index got what colour.
*
* We can work directly with the logical palette since it
* has already been set when we get here.
*/
SDL_Color *want, *reject;
unsigned long *freelist;
int i;
int nfree = 0;
int nc = SDL_VideoSurface->format->palette->ncolors;
colors = SDL_VideoSurface->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; i < ncolors; ++i) {
Uint8 c = (256 * i / ncolors);
xcmap[i].pixel = SDL_MapRGB(SDL_VideoSurface->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) {
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, SDL_VideoSurface);
X11_DestroyWindow(this, SDL_VideoSurface);
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;
}
if (xinerama) {
XFree(xinerama);
}
/* Restore gamma settings if they've changed */
if (SDL_GetAppState() & SDL_APPACTIVE) {
X11_SwapVidModeGamma(this);
}
/* Restore DPMS and screensaver settings */
X11_RestoreScreenSaver(SDL_Display, screensaver_timeout,
dpms_enabled);
/* 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 (SDL_VideoSurface && (SDL_VideoSurface->flags & SDL_HWSURFACE)) {
/* Direct screen access, no memory buffer */
SDL_VideoSurface->pixels = NULL;
}
}
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 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 <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#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 <X11/extensions/Xrandr.h>
#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
#if SDL_VIDEO_DRIVER_X11_DPMS
#include <X11/extensions/dpms.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;
/* 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;
#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 screensaver_timeout;
BOOL dpms_enabled;
};
/* 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 (this->hidden->xinerama)
#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 screensaver_timeout (this->hidden->screensaver_timeout)
#define dpms_enabled (this->hidden->dpms_enabled)
/* 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 */
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 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 <X11/Xlib.h>
#include <X11/Xutil.h>
#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);
wmhints->icon_pixmap = icon_pixmap;
wmhints->icon_mask = mask_pixmap;
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;
Atom _NET_WM_ICON_NAME;
/* 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_latin1 = SDL_iconv_utf8_latin1((char *) title);
if (!title_latin1) {
SDL_OutOfMemory();
return;
}
status = XStringListToTextProperty(&title_latin1, 1, &titleprop);
SDL_free(title_latin1);
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_latin1 = SDL_iconv_utf8_latin1((char *) icon);
if (!icon_latin1) {
SDL_OutOfMemory();
return;
}
status = XStringListToTextProperty(&icon_latin1, 1, &iconprop);
SDL_free(icon_latin1);
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 (SDL_VideoSurface == 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 (SDL_VideoSurface->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 (!(SDL_VideoSurface->flags & SDL_FULLSCREEN))
XRaiseWindow(SDL_Display, WMwindow);
/* Make sure we register input focus */
SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS);
}
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();
}
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;
}
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);
}
}
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 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);
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 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 <X11/Xlib.h>
#ifndef NO_SHARED_MEMORY
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>
#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
/* Fix for the NVidia GeForce 2 - use the last available adaptor */
#if 0 /* Apparently the NVidia drivers are fixed */
#define USE_LAST_ADAPTOR
#endif
/* 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));
}
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
/* 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; j < ainfo[i].num_formats; ++j) {
if (ainfo[i].formats[j].visual_id == SDL_Visual->visualid) {
visual_ok = 1;
break;
}
}
if (!visual_ok) {
continue;
}
}
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 */
XFree(hwdata->image);
width = hwdata->image->pitches[0] / bpp;
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; i < overlay->planes; ++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
/* 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 */
/* vi: set ts=4 sw=4 expandtab: */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 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 */
/* vi: set ts=4 sw=4 expandtab: */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment