Merge commit 'dec0d4ec4153bf9fc2b78ae6c2df45b6ea8dde7a' as 'external/sdl/SDL'

This commit is contained in:
2023-07-25 22:27:55 +02:00
1663 changed files with 627495 additions and 0 deletions

View File

@ -0,0 +1,278 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_X11
#include <limits.h> /* For INT_MAX */
#include "SDL_x11video.h"
#include "SDL_x11clipboard.h"
#include "../SDL_clipboard_c.h"
#include "../../events/SDL_events_c.h"
static const char *text_mime_types[] = {
"text/plain;charset=utf-8",
"text/plain",
"TEXT",
"UTF8_STRING",
"STRING"
};
/* Get any application owned window handle for clipboard association */
static Window GetWindow(SDL_VideoDevice *_this)
{
SDL_VideoData *data = _this->driverdata;
/* We create an unmapped window that exists just to manage the clipboard,
since X11 selection data is tied to a specific window and dies with it.
We create the window on demand, so apps that don't use the clipboard
don't have to keep an unnecessary resource around. */
if (data->clipboard_window == None) {
Display *dpy = data->display;
Window parent = RootWindow(dpy, DefaultScreen(dpy));
XSetWindowAttributes xattr;
data->clipboard_window = X11_XCreateWindow(dpy, parent, -10, -10, 1, 1, 0,
CopyFromParent, InputOnly,
CopyFromParent, 0, &xattr);
X11_XFlush(data->display);
}
return data->clipboard_window;
}
static int SetSelectionData(SDL_VideoDevice *_this, Atom selection, SDL_ClipboardDataCallback callback,
void *userdata, const char **mime_types, size_t mime_count, Uint32 sequence)
{
SDL_VideoData *videodata = _this->driverdata;
Display *display = videodata->display;
Window window;
SDLX11_ClipboardData *clipboard;
SDL_bool clipboard_owner = SDL_FALSE;
window = GetWindow(_this);
if (window == None) {
return SDL_SetError("Couldn't find a window to own the selection");
}
if (selection == XA_PRIMARY) {
clipboard = &videodata->primary_selection;
} else {
clipboard = &videodata->clipboard;
}
clipboard_owner = X11_XGetSelectionOwner(display, selection) == window;
/* If we are cancelling our own data we need to clean it up */
if (clipboard_owner && clipboard->sequence == 0) {
SDL_free(clipboard->userdata);
}
clipboard->callback = callback;
clipboard->userdata = userdata;
clipboard->mime_types = mime_types;
clipboard->mime_count = mime_count;
clipboard->sequence = sequence;
if (!clipboard_owner) {
X11_XSetSelectionOwner(display, selection, window, CurrentTime);
}
return 0;
}
static void *CloneDataBuffer(const void *buffer, size_t *len)
{
void *clone = NULL;
if (*len > 0 && buffer != NULL) {
clone = SDL_malloc((*len)+sizeof(Uint32));
if (clone == NULL) {
SDL_OutOfMemory();
} else {
SDL_memcpy(clone, buffer, *len);
SDL_memset((Uint8 *)clone + *len, 0, sizeof(Uint32));
}
}
return clone;
}
static void *GetSelectionData(SDL_VideoDevice *_this, Atom selection_type,
const char *mime_type, size_t *length)
{
SDL_VideoData *videodata = _this->driverdata;
Display *display = videodata->display;
Window window;
Window owner;
Atom selection;
Atom seln_type;
int seln_format;
unsigned long count;
unsigned long overflow;
Uint64 waitStart;
Uint64 waitElapsed;
SDLX11_ClipboardData *clipboard;
void *data = NULL;
unsigned char *src = NULL;
Atom XA_MIME = X11_XInternAtom(display, mime_type, False);
Atom XA_INCR = X11_XInternAtom(display, "INCR", False);
*length = 0;
/* Get the window that holds the selection */
window = GetWindow(_this);
owner = X11_XGetSelectionOwner(display, selection_type);
if (owner == None) {
/* This requires a fallback to ancient X10 cut-buffers. We will just skip those for now */
data = NULL;
} else if (owner == window) {
owner = DefaultRootWindow(display);
if (selection_type == XA_PRIMARY) {
clipboard = &videodata->primary_selection;
} else {
clipboard = &videodata->clipboard;
}
if (clipboard->callback) {
const void *clipboard_data = clipboard->callback(clipboard->userdata, mime_type, length);
data = CloneDataBuffer(clipboard_data, length);
}
} else {
/* Request that the selection owner copy the data to our window */
owner = window;
selection = X11_XInternAtom(display, "SDL_SELECTION", False);
X11_XConvertSelection(display, selection_type, XA_MIME, selection, owner,
CurrentTime);
/* When using synergy on Linux and when data has been put in the clipboard
on the remote (Windows anyway) machine then selection_waiting may never
be set to False. Time out after a while. */
waitStart = SDL_GetTicks();
videodata->selection_waiting = SDL_TRUE;
while (videodata->selection_waiting) {
SDL_PumpEvents();
waitElapsed = SDL_GetTicks() - waitStart;
/* Wait one second for a selection response. */
if (waitElapsed > 1000) {
videodata->selection_waiting = SDL_FALSE;
SDL_SetError("Selection timeout");
/* We need to set the selection text so that next time we won't
timeout, otherwise we will hang on every call to this function. */
SetSelectionData(_this, selection_type, SDL_ClipboardTextCallback, NULL,
text_mime_types, SDL_arraysize(text_mime_types), 0);
data = NULL;
*length = 0;
}
}
if (X11_XGetWindowProperty(display, owner, selection, 0, INT_MAX / 4, False,
XA_MIME, &seln_type, &seln_format, &count, &overflow, &src) == Success) {
if (seln_type == XA_MIME) {
*length = (size_t)count;
data = CloneDataBuffer(src, length);
} else if (seln_type == XA_INCR) {
/* FIXME: Need to implement the X11 INCR protocol */
/*SDL_Log("Need to implement the X11 INCR protocol");*/
}
X11_XFree(src);
}
}
return data;
}
const char **X11_GetTextMimeTypes(SDL_VideoDevice *_this, size_t *num_mime_types)
{
*num_mime_types = SDL_arraysize(text_mime_types);
return text_mime_types;
}
int X11_SetClipboardData(SDL_VideoDevice *_this)
{
SDL_VideoData *videodata = _this->driverdata;
Atom XA_CLIPBOARD = X11_XInternAtom(videodata->display, "CLIPBOARD", 0);
if (XA_CLIPBOARD == None) {
return SDL_SetError("Couldn't access X clipboard");
}
return SetSelectionData(_this, XA_CLIPBOARD, _this->clipboard_callback, _this->clipboard_userdata, (const char **)_this->clipboard_mime_types, _this->num_clipboard_mime_types, _this->clipboard_sequence);
}
void *X11_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *length)
{
SDL_VideoData *videodata = _this->driverdata;
Atom XA_CLIPBOARD = X11_XInternAtom(videodata->display, "CLIPBOARD", 0);
if (XA_CLIPBOARD == None) {
SDL_SetError("Couldn't access X clipboard");
*length = 0;
return NULL;
}
return GetSelectionData(_this, XA_CLIPBOARD, mime_type, length);
}
SDL_bool X11_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
{
size_t length;
void *data;
data = X11_GetClipboardData(_this, mime_type, &length);
if (data != NULL) {
SDL_free(data);
}
return length > 0;
}
int X11_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text)
{
return SetSelectionData(_this, XA_PRIMARY, SDL_ClipboardTextCallback, SDL_strdup(text), text_mime_types, SDL_arraysize(text_mime_types), 0);
}
char *X11_GetPrimarySelectionText(SDL_VideoDevice *_this)
{
size_t length;
char *text = GetSelectionData(_this, XA_PRIMARY, text_mime_types[0], &length);
if (!text) {
text = SDL_strdup("");
}
return text;
}
SDL_bool X11_HasPrimarySelectionText(SDL_VideoDevice *_this)
{
SDL_bool result = SDL_FALSE;
char *text = X11_GetPrimarySelectionText(_this);
if (text) {
if (text[0] != '\0') {
result = SDL_TRUE;
}
SDL_free(text);
}
return result;
}
void X11_QuitClipboard(SDL_VideoDevice *_this)
{
SDL_VideoData *data = _this->driverdata;
if (data->primary_selection.sequence == 0) {
SDL_free(data->primary_selection.userdata);
}
if (data->clipboard.sequence == 0) {
SDL_free(data->clipboard.userdata);
}
}
#endif /* SDL_VIDEO_DRIVER_X11 */

View File

@ -0,0 +1,45 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_x11clipboard_h_
#define SDL_x11clipboard_h_
#include <X11/Xlib.h>
typedef struct X11_ClipboardData {
SDL_ClipboardDataCallback callback;
void *userdata;
const char **mime_types;
size_t mime_count;
Uint32 sequence;
} SDLX11_ClipboardData;
extern const char **X11_GetTextMimeTypes(SDL_VideoDevice *_this, size_t *num_mime_types);
extern int X11_SetClipboardData(SDL_VideoDevice *_this);
extern void *X11_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *length);
extern SDL_bool X11_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type);
extern int X11_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text);
extern char *X11_GetPrimarySelectionText(SDL_VideoDevice *_this);
extern SDL_bool X11_HasPrimarySelectionText(SDL_VideoDevice *_this);
extern void X11_QuitClipboard(SDL_VideoDevice *_this);
#endif /* SDL_x11clipboard_h_ */

View File

@ -0,0 +1,201 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_X11
#define DEBUG_DYNAMIC_X11 0
#include "SDL_x11dyn.h"
#if DEBUG_DYNAMIC_X11
#include <stdio.h>
#endif
#ifdef SDL_VIDEO_DRIVER_X11_DYNAMIC
typedef struct
{
void *lib;
const char *libname;
} x11dynlib;
#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT
#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT NULL
#endif
#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR
#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR NULL
#endif
#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2
#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 NULL
#endif
#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XFIXES
#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XFIXES NULL
#endif
#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR
#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR NULL
#endif
#ifndef SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS
#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS NULL
#endif
static x11dynlib x11libs[] = {
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC },
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT },
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR },
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 },
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XFIXES },
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR },
{ NULL, SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS }
};
static void *X11_GetSym(const char *fnname, int *pHasModule)
{
int i;
void *fn = NULL;
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) {
*pHasModule = 0; /* kill this module. */
}
return fn;
}
#endif /* SDL_VIDEO_DRIVER_X11_DYNAMIC */
/* Define all the function pointers and wrappers... */
#define SDL_X11_SYM(rc, fn, params, args, ret) SDL_DYNX11FN_##fn X11_##fn = NULL;
#include "SDL_x11sym.h"
/* Annoying varargs entry point... */
#ifdef X_HAVE_UTF8_STRING
SDL_DYNX11FN_XCreateIC X11_XCreateIC = NULL;
SDL_DYNX11FN_XGetICValues X11_XGetICValues = 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 = 0;
#include "SDL_x11sym.h"
static int x11_load_refcount = 0;
void SDL_X11_UnloadSymbols(void)
{
/* Don't actually unload if more than one module is using the libs... */
if (x11_load_refcount > 0) {
if (--x11_load_refcount == 0) {
#ifdef SDL_VIDEO_DRIVER_X11_DYNAMIC
int i;
#endif
/* set all the function pointers to NULL. */
#define SDL_X11_MODULE(modname) SDL_X11_HAVE_##modname = 0;
#define SDL_X11_SYM(rc, fn, params, args, ret) X11_##fn = NULL;
#include "SDL_x11sym.h"
#ifdef X_HAVE_UTF8_STRING
X11_XCreateIC = NULL;
X11_XGetICValues = NULL;
#endif
#ifdef SDL_VIDEO_DRIVER_X11_DYNAMIC
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. */
/* deal with multiple modules (dga, x11, etc) needing these symbols... */
if (x11_load_refcount++ == 0) {
#ifdef SDL_VIDEO_DRIVER_X11_DYNAMIC
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) SDL_X11_HAVE_##modname = 1; /* default yes */
#include "SDL_x11sym.h"
#define SDL_X11_MODULE(modname) thismod = &SDL_X11_HAVE_##modname;
#define SDL_X11_SYM(a, fn, x, y, z) X11_##fn = (SDL_DYNX11FN_##fn)X11_GetSym(#fn, thismod);
#include "SDL_x11sym.h"
#ifdef X_HAVE_UTF8_STRING
X11_XCreateIC = (SDL_DYNX11FN_XCreateIC)
X11_GetSym("XCreateIC", &SDL_X11_HAVE_UTF8);
X11_XGetICValues = (SDL_DYNX11FN_XGetICValues)
X11_GetSym("XGetICValues", &SDL_X11_HAVE_UTF8);
#endif
if (SDL_X11_HAVE_BASEXLIB) {
/* all required symbols loaded. */
SDL_ClearError();
} else {
/* in case something got loaded... */
SDL_X11_UnloadSymbols();
rc = 0;
}
#else /* no dynamic X11 */
#define SDL_X11_MODULE(modname) SDL_X11_HAVE_##modname = 1; /* default yes */
#define SDL_X11_SYM(a, fn, x, y, z) X11_##fn = (SDL_DYNX11FN_##fn)fn;
#include "SDL_x11sym.h"
#ifdef X_HAVE_UTF8_STRING
X11_XCreateIC = XCreateIC;
X11_XGetICValues = XGetICValues;
#endif
#endif
}
return rc;
}
#endif /* SDL_VIDEO_DRIVER_X11 */

View File

@ -0,0 +1,106 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_x11dyn_h_
#define SDL_x11dyn_h_
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/Xresource.h>
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
#include <X11/XKBlib.h>
#endif
/* Apparently some X11 systems can't include this multiple times... */
#ifndef SDL_INCLUDED_XLIBINT_H
#define SDL_INCLUDED_XLIBINT_H 1
#include <X11/Xlibint.h>
#endif
#include <X11/Xproto.h>
#include <X11/extensions/Xext.h>
#ifndef NO_SHARED_MEMORY
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/extensions/XShm.h>
#endif
#ifdef SDL_VIDEO_DRIVER_X11_XCURSOR
#include <X11/Xcursor/Xcursor.h>
#endif
#ifdef SDL_VIDEO_DRIVER_X11_XDBE
#include <X11/extensions/Xdbe.h>
#endif
#if defined(SDL_VIDEO_DRIVER_X11_XINPUT2) || defined(SDL_VIDEO_DRIVER_X11_XFIXES)
#include <X11/extensions/XInput2.h>
#endif
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
#include <X11/extensions/Xfixes.h>
#endif
#ifdef SDL_VIDEO_DRIVER_X11_XRANDR
#include <X11/extensions/Xrandr.h>
#endif
#ifdef SDL_VIDEO_DRIVER_X11_XSCRNSAVER
#include <X11/extensions/scrnsaver.h>
#endif
#ifdef SDL_VIDEO_DRIVER_X11_XSHAPE
#include <X11/extensions/shape.h>
#endif
#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);
/* Declare all the function pointers and wrappers... */
#define SDL_X11_SYM(rc, fn, params, args, ret) \
typedef rc(*SDL_DYNX11FN_##fn) params; \
extern SDL_DYNX11FN_##fn X11_##fn;
#include "SDL_x11sym.h"
/* Annoying varargs entry point... */
#ifdef X_HAVE_UTF8_STRING
typedef XIC (*SDL_DYNX11FN_XCreateIC)(XIM, ...);
typedef char *(*SDL_DYNX11FN_XGetICValues)(XIC, ...);
extern SDL_DYNX11FN_XCreateIC X11_XCreateIC;
extern SDL_DYNX11FN_XGetICValues X11_XGetICValues;
#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;
#include "SDL_x11sym.h"
#ifdef __cplusplus
}
#endif
#endif /* !defined SDL_x11dyn_h_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_x11events_h_
#define SDL_x11events_h_
extern void X11_PumpEvents(SDL_VideoDevice *_this);
extern int X11_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS);
extern void X11_SendWakeupEvent(SDL_VideoDevice *_this, SDL_Window *window);
extern int X11_SuspendScreenSaver(SDL_VideoDevice *_this);
extern void X11_ReconcileKeyboardState(SDL_VideoDevice *_this);
extern void X11_GetBorderValues(SDL_WindowData *data);
#endif /* SDL_x11events_h_ */

View File

@ -0,0 +1,256 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_X11
#include "SDL_x11video.h"
#include "SDL_x11framebuffer.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;
}
return X_handler(d, e);
}
static SDL_bool have_mitshm(Display *dpy)
{
/* Only use shared memory on local X servers */
return X11_XShmQueryExtension(dpy) ? SDL_X11_HAVE_SHM : SDL_FALSE;
}
#endif /* !NO_SHARED_MEMORY */
int X11_CreateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, Uint32 *format,
void **pixels, int *pitch)
{
SDL_WindowData *data = window->driverdata;
Display *display = data->videodata->display;
XGCValues gcv;
XVisualInfo vinfo;
int w, h;
SDL_GetWindowSizeInPixels(window, &w, &h);
/* Free the old framebuffer surface */
X11_DestroyWindowFramebuffer(_this, window);
/* Create the graphics context for drawing */
gcv.graphics_exposures = False;
data->gc = X11_XCreateGC(display, data->xwindow, GCGraphicsExposures, &gcv);
if (!data->gc) {
return SDL_SetError("Couldn't create graphics context");
}
/* Find out the pixel format and depth */
if (X11_GetVisualInfoFromVisual(display, data->visual, &vinfo) < 0) {
return SDL_SetError("Couldn't get window visual information");
}
*format = X11_GetPixelFormatFromVisualInfo(display, &vinfo);
if (*format == SDL_PIXELFORMAT_UNKNOWN) {
return SDL_SetError("Unknown window pixel format");
}
/* Calculate pitch */
*pitch = (((w * SDL_BYTESPERPIXEL(*format)) + 3) & ~3);
/* Create the actual image */
#ifndef NO_SHARED_MEMORY
if (have_mitshm(display)) {
XShmSegmentInfo *shminfo = &data->shminfo;
shminfo->shmid = shmget(IPC_PRIVATE, (size_t)h * (*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 = X11_XSetErrorHandler(shm_errhandler);
X11_XShmAttach(display, shminfo);
X11_XSync(display, False);
X11_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) {
data->ximage = X11_XShmCreateImage(display, data->visual,
vinfo.depth, ZPixmap,
shminfo->shmaddr, shminfo,
w, h);
if (!data->ximage) {
X11_XShmDetach(display, shminfo);
X11_XSync(display, False);
shmdt(shminfo->shmaddr);
} else {
/* Done! */
data->ximage->byte_order = (SDL_BYTEORDER == SDL_BIG_ENDIAN) ? MSBFirst : LSBFirst;
data->use_mitshm = SDL_TRUE;
*pixels = shminfo->shmaddr;
return 0;
}
}
}
#endif /* not NO_SHARED_MEMORY */
*pixels = SDL_malloc((size_t)h * (*pitch));
if (*pixels == NULL) {
return SDL_OutOfMemory();
}
data->ximage = X11_XCreateImage(display, data->visual,
vinfo.depth, ZPixmap, 0, (char *)(*pixels),
w, h, 32, 0);
if (!data->ximage) {
SDL_free(*pixels);
return SDL_SetError("Couldn't create XImage");
}
data->ximage->byte_order = (SDL_BYTEORDER == SDL_BIG_ENDIAN) ? MSBFirst : LSBFirst;
return 0;
}
int X11_UpdateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, const SDL_Rect *rects,
int numrects)
{
SDL_WindowData *data = window->driverdata;
Display *display = data->videodata->display;
int i;
int x, y, w, h;
int window_w, window_h;
SDL_GetWindowSizeInPixels(window, &window_w, &window_h);
#ifndef NO_SHARED_MEMORY
if (data->use_mitshm) {
for (i = 0; i < numrects; ++i) {
x = rects[i].x;
y = rects[i].y;
w = rects[i].w;
h = rects[i].h;
if (w <= 0 || h <= 0 || (x + w) <= 0 || (y + h) <= 0) {
/* Clipped? */
continue;
}
if (x < 0) {
x += w;
w += rects[i].x;
}
if (y < 0) {
y += h;
h += rects[i].y;
}
if (x + w > window_w) {
w = window_w - x;
}
if (y + h > window_h) {
h = window_h - y;
}
X11_XShmPutImage(display, data->xwindow, data->gc, data->ximage,
x, y, x, y, w, h, False);
}
} else
#endif /* !NO_SHARED_MEMORY */
{
for (i = 0; i < numrects; ++i) {
x = rects[i].x;
y = rects[i].y;
w = rects[i].w;
h = rects[i].h;
if (w <= 0 || h <= 0 || (x + w) <= 0 || (y + h) <= 0) {
/* Clipped? */
continue;
}
if (x < 0) {
x += w;
w += rects[i].x;
}
if (y < 0) {
y += h;
h += rects[i].y;
}
if (x + w > window_w) {
w = window_w - x;
}
if (y + h > window_h) {
h = window_h - y;
}
X11_XPutImage(display, data->xwindow, data->gc, data->ximage,
x, y, x, y, w, h);
}
}
X11_XSync(display, False);
return 0;
}
void X11_DestroyWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
Display *display;
if (data == NULL) {
/* The window wasn't fully initialized */
return;
}
display = data->videodata->display;
if (data->ximage) {
XDestroyImage(data->ximage);
#ifndef NO_SHARED_MEMORY
if (data->use_mitshm) {
X11_XShmDetach(display, &data->shminfo);
X11_XSync(display, False);
shmdt(data->shminfo.shmaddr);
data->use_mitshm = SDL_FALSE;
}
#endif /* !NO_SHARED_MEMORY */
data->ximage = NULL;
}
if (data->gc) {
X11_XFreeGC(display, data->gc);
data->gc = NULL;
}
}
#endif /* SDL_VIDEO_DRIVER_X11 */

View File

@ -0,0 +1,34 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_x11framebuffer_h_
#define SDL_x11framebuffer_h_
#include "SDL_internal.h"
extern int X11_CreateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window,
Uint32 *format,
void **pixels, int *pitch);
extern int X11_UpdateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window,
const SDL_Rect *rects, int numrects);
extern void X11_DestroyWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window);
#endif /* SDL_x11framebuffer_h_ */

View File

@ -0,0 +1,498 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_X11
#include "SDL_x11video.h"
#include "../../events/SDL_keyboard_c.h"
#include "../../events/SDL_scancode_tables_c.h"
#include <X11/keysym.h>
#include <X11/XKBlib.h>
#include "../../events/imKStoUCS.h"
#include "../../events/SDL_keysym_to_scancode_c.h"
#ifdef X_HAVE_UTF8_STRING
#include <locale.h>
#endif
static SDL_ScancodeTable scancode_set[] = {
SDL_SCANCODE_TABLE_DARWIN,
SDL_SCANCODE_TABLE_XFREE86_1,
SDL_SCANCODE_TABLE_XFREE86_2,
SDL_SCANCODE_TABLE_XVNC,
};
static SDL_bool X11_ScancodeIsRemappable(SDL_Scancode scancode)
{
/*
* XKB remappings can assign different keysyms for these scancodes, but
* as these keys are in fixed positions, the scancodes themselves shouldn't
* be switched. Mark them as not being remappable.
*/
switch (scancode) {
case SDL_SCANCODE_ESCAPE:
case SDL_SCANCODE_CAPSLOCK:
case SDL_SCANCODE_NUMLOCKCLEAR:
case SDL_SCANCODE_LSHIFT:
case SDL_SCANCODE_RSHIFT:
case SDL_SCANCODE_LCTRL:
case SDL_SCANCODE_RCTRL:
case SDL_SCANCODE_LALT:
case SDL_SCANCODE_RALT:
case SDL_SCANCODE_LGUI:
case SDL_SCANCODE_RGUI:
return SDL_FALSE;
default:
return SDL_TRUE;
}
}
/* This function only correctly maps letters and numbers for keyboards in US QWERTY layout */
static SDL_Scancode X11_KeyCodeToSDLScancode(SDL_VideoDevice *_this, KeyCode keycode)
{
const KeySym keysym = X11_KeyCodeToSym(_this, keycode, 0);
if (keysym == NoSymbol) {
return SDL_SCANCODE_UNKNOWN;
}
return SDL_GetScancodeFromKeySym(keysym, keycode);
}
static Uint32 X11_KeyCodeToUcs4(SDL_VideoDevice *_this, KeyCode keycode, unsigned char group)
{
KeySym keysym = X11_KeyCodeToSym(_this, keycode, group);
if (keysym == NoSymbol) {
return 0;
}
return SDL_KeySymToUcs4(keysym);
}
KeySym
X11_KeyCodeToSym(SDL_VideoDevice *_this, KeyCode keycode, unsigned char group)
{
SDL_VideoData *data = _this->driverdata;
KeySym keysym;
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
if (data->xkb) {
int num_groups = XkbKeyNumGroups(data->xkb, keycode);
unsigned char info = XkbKeyGroupInfo(data->xkb, keycode);
if (num_groups && group >= num_groups) {
int action = XkbOutOfRangeGroupAction(info);
if (action == XkbRedirectIntoRange) {
group = XkbOutOfRangeGroupNumber(info);
if (group >= num_groups) {
group = 0;
}
} else if (action == XkbClampIntoRange) {
group = num_groups - 1;
} else {
group %= num_groups;
}
}
keysym = X11_XkbKeycodeToKeysym(data->display, keycode, group, 0);
} else {
keysym = X11_XKeycodeToKeysym(data->display, keycode, 0);
}
#else
keysym = X11_XKeycodeToKeysym(data->display, keycode, 0);
#endif
return keysym;
}
int X11_InitKeyboard(SDL_VideoDevice *_this)
{
SDL_VideoData *data = _this->driverdata;
int i = 0;
int j = 0;
int min_keycode, max_keycode;
struct
{
SDL_Scancode scancode;
KeySym keysym;
int value;
} fingerprint[] = {
{ SDL_SCANCODE_HOME, XK_Home, 0 },
{ SDL_SCANCODE_PAGEUP, XK_Prior, 0 },
{ SDL_SCANCODE_UP, XK_Up, 0 },
{ SDL_SCANCODE_LEFT, XK_Left, 0 },
{ SDL_SCANCODE_DELETE, XK_Delete, 0 },
{ SDL_SCANCODE_KP_ENTER, XK_KP_Enter, 0 },
};
int best_distance;
int best_index;
int distance;
Bool xkb_repeat = 0;
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
{
int xkb_major = XkbMajorVersion;
int xkb_minor = XkbMinorVersion;
if (X11_XkbQueryExtension(data->display, NULL, &data->xkb_event, NULL, &xkb_major, &xkb_minor)) {
data->xkb = X11_XkbGetMap(data->display, XkbAllClientInfoMask, XkbUseCoreKbd);
}
/* This will remove KeyRelease events for held keys */
X11_XkbSetDetectableAutoRepeat(data->display, True, &xkb_repeat);
}
#endif
/* Open a connection to the X input manager */
#ifdef X_HAVE_UTF8_STRING
if (SDL_X11_HAVE_UTF8) {
/* Set the locale, and call XSetLocaleModifiers before XOpenIM so that
Compose keys will work correctly. */
char *prev_locale = setlocale(LC_ALL, NULL);
char *prev_xmods = X11_XSetLocaleModifiers(NULL);
const char *new_xmods = "";
const char *env_xmods = SDL_getenv("XMODIFIERS");
SDL_bool has_dbus_ime_support = SDL_FALSE;
if (prev_locale) {
prev_locale = SDL_strdup(prev_locale);
}
if (prev_xmods) {
prev_xmods = SDL_strdup(prev_xmods);
}
/* IBus resends some key events that were filtered by XFilterEvents
when it is used via XIM which causes issues. Prevent this by forcing
@im=none if XMODIFIERS contains @im=ibus. IBus can still be used via
the DBus implementation, which also has support for pre-editing. */
if (env_xmods && SDL_strstr(env_xmods, "@im=ibus") != NULL) {
has_dbus_ime_support = SDL_TRUE;
}
if (env_xmods && SDL_strstr(env_xmods, "@im=fcitx") != NULL) {
has_dbus_ime_support = SDL_TRUE;
}
if (has_dbus_ime_support || !xkb_repeat) {
new_xmods = "@im=none";
}
(void)setlocale(LC_ALL, "");
X11_XSetLocaleModifiers(new_xmods);
data->im = X11_XOpenIM(data->display, NULL, NULL, NULL);
/* Reset the locale + X locale modifiers back to how they were,
locale first because the X locale modifiers depend on it. */
(void)setlocale(LC_ALL, prev_locale);
X11_XSetLocaleModifiers(prev_xmods);
if (prev_locale) {
SDL_free(prev_locale);
}
if (prev_xmods) {
SDL_free(prev_xmods);
}
}
#endif
/* Try to determine which scancodes are being used based on fingerprint */
best_distance = SDL_arraysize(fingerprint) + 1;
best_index = -1;
X11_XDisplayKeycodes(data->display, &min_keycode, &max_keycode);
for (i = 0; i < SDL_arraysize(fingerprint); ++i) {
fingerprint[i].value = X11_XKeysymToKeycode(data->display, fingerprint[i].keysym) - min_keycode;
}
for (i = 0; i < SDL_arraysize(scancode_set); ++i) {
int table_size;
const SDL_Scancode *table = SDL_GetScancodeTable(scancode_set[i], &table_size);
distance = 0;
for (j = 0; j < SDL_arraysize(fingerprint); ++j) {
if (fingerprint[j].value < 0 || fingerprint[j].value >= table_size) {
distance += 1;
} else if (table[fingerprint[j].value] != fingerprint[j].scancode) {
distance += 1;
}
}
if (distance < best_distance) {
best_distance = distance;
best_index = i;
}
}
if (best_index < 0 || best_distance > 2) {
/* This is likely to be SDL_SCANCODE_TABLE_XFREE86_2 with remapped keys, double check a rarely remapped value */
int fingerprint_value = X11_XKeysymToKeycode(data->display, 0x1008FF5B /* XF86Documents */) - min_keycode;
if (fingerprint_value == 235) {
for (i = 0; i < SDL_arraysize(scancode_set); ++i) {
if (scancode_set[i] == SDL_SCANCODE_TABLE_XFREE86_2) {
best_index = i;
best_distance = 0;
break;
}
}
}
}
if (best_index >= 0 && best_distance <= 2) {
SDL_Keycode default_keymap[SDL_NUM_SCANCODES];
int table_size;
const SDL_Scancode *table = SDL_GetScancodeTable(scancode_set[best_index], &table_size);
#ifdef DEBUG_KEYBOARD
SDL_Log("Using scancode set %d, min_keycode = %d, max_keycode = %d, table_size = %d\n", best_index, min_keycode, max_keycode, table_size);
#endif
/* This should never happen, but just in case... */
if (table_size > (SDL_arraysize(data->key_layout) - min_keycode)) {
table_size = (SDL_arraysize(data->key_layout) - min_keycode);
}
SDL_memcpy(&data->key_layout[min_keycode], table, sizeof(SDL_Scancode) * table_size);
/* Scancodes represent physical locations on the keyboard, unaffected by keyboard mapping.
However, there are a number of extended scancodes that have no standard location, so use
the X11 mapping for all non-character keys.
*/
SDL_GetDefaultKeymap(default_keymap);
for (i = min_keycode; i <= max_keycode; ++i) {
SDL_Scancode scancode = X11_KeyCodeToSDLScancode(_this, i);
#ifdef DEBUG_KEYBOARD
{
KeySym sym;
sym = X11_KeyCodeToSym(_this, (KeyCode)i, 0);
SDL_Log("code = %d, sym = 0x%X (%s) ", i - min_keycode,
(unsigned int)sym, sym == NoSymbol ? "NoSymbol" : X11_XKeysymToString(sym));
}
#endif
if (scancode == data->key_layout[i]) {
continue;
}
if (default_keymap[scancode] >= SDLK_SCANCODE_MASK && X11_ScancodeIsRemappable(scancode)) {
/* Not a character key and the scancode is safe to remap */
#ifdef DEBUG_KEYBOARD
SDL_Log("Changing scancode, was %d (%s), now %d (%s)\n", data->key_layout[i], SDL_GetScancodeName(data->key_layout[i]), scancode, SDL_GetScancodeName(scancode));
#endif
data->key_layout[i] = scancode;
}
}
} else {
#ifdef DEBUG_SCANCODES
SDL_Log("Keyboard layout unknown, please report the following to the SDL forums/mailing list (https://discourse.libsdl.org/):\n");
#endif
/* Determine key_layout - only works on US QWERTY layout */
for (i = min_keycode; i <= max_keycode; ++i) {
SDL_Scancode scancode = X11_KeyCodeToSDLScancode(_this, i);
#ifdef DEBUG_SCANCODES
{
KeySym sym;
sym = X11_KeyCodeToSym(_this, (KeyCode)i, 0);
SDL_Log("code = %d, sym = 0x%X (%s) ", i - min_keycode,
(unsigned int)sym, sym == NoSymbol ? "NoSymbol" : X11_XKeysymToString(sym));
}
if (scancode == SDL_SCANCODE_UNKNOWN) {
SDL_Log("scancode not found\n");
} else {
SDL_Log("scancode = %d (%s)\n", scancode, SDL_GetScancodeName(scancode));
}
#endif
data->key_layout[i] = scancode;
}
}
X11_UpdateKeymap(_this, SDL_FALSE);
SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
#ifdef SDL_USE_IME
SDL_IME_Init();
#endif
X11_ReconcileKeyboardState(_this);
return 0;
}
void X11_UpdateKeymap(SDL_VideoDevice *_this, SDL_bool send_event)
{
SDL_VideoData *data = _this->driverdata;
int i;
SDL_Scancode scancode;
SDL_Keycode keymap[SDL_NUM_SCANCODES];
unsigned char group = 0;
SDL_GetDefaultKeymap(keymap);
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
if (data->xkb) {
XkbStateRec state;
X11_XkbGetUpdatedMap(data->display, XkbAllClientInfoMask, data->xkb);
if (X11_XkbGetState(data->display, XkbUseCoreKbd, &state) == Success) {
group = state.group;
}
}
#endif
for (i = 0; i < SDL_arraysize(data->key_layout); i++) {
Uint32 key;
/* Make sure this is a valid scancode */
scancode = data->key_layout[i];
if (scancode == SDL_SCANCODE_UNKNOWN) {
continue;
}
/* See if there is a UCS keycode for this scancode */
key = X11_KeyCodeToUcs4(_this, (KeyCode)i, group);
if (key) {
keymap[scancode] = key;
} else {
SDL_Scancode keyScancode = X11_KeyCodeToSDLScancode(_this, (KeyCode)i);
switch (keyScancode) {
case SDL_SCANCODE_RETURN:
keymap[scancode] = SDLK_RETURN;
break;
case SDL_SCANCODE_ESCAPE:
keymap[scancode] = SDLK_ESCAPE;
break;
case SDL_SCANCODE_BACKSPACE:
keymap[scancode] = SDLK_BACKSPACE;
break;
case SDL_SCANCODE_TAB:
keymap[scancode] = SDLK_TAB;
break;
case SDL_SCANCODE_DELETE:
keymap[scancode] = SDLK_DELETE;
break;
default:
keymap[scancode] = SDL_SCANCODE_TO_KEYCODE(keyScancode);
break;
}
}
}
SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES, send_event);
}
void X11_QuitKeyboard(SDL_VideoDevice *_this)
{
SDL_VideoData *data = _this->driverdata;
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
if (data->xkb) {
X11_XkbFreeKeyboard(data->xkb, 0, True);
data->xkb = NULL;
}
#endif
#ifdef SDL_USE_IME
SDL_IME_Quit();
#endif
}
static void X11_ResetXIM(SDL_VideoDevice *_this)
{
#ifdef X_HAVE_UTF8_STRING
SDL_VideoData *videodata = _this->driverdata;
int i;
if (videodata && videodata->windowlist) {
for (i = 0; i < videodata->numwindows; ++i) {
SDL_WindowData *data = videodata->windowlist[i];
if (data && data->ic) {
/* Clear any partially entered dead keys */
char *contents = X11_Xutf8ResetIC(data->ic);
if (contents) {
X11_XFree(contents);
}
}
}
}
#endif
}
void X11_StartTextInput(SDL_VideoDevice *_this)
{
X11_ResetXIM(_this);
}
void X11_StopTextInput(SDL_VideoDevice *_this)
{
X11_ResetXIM(_this);
#ifdef SDL_USE_IME
SDL_IME_Reset();
#endif
}
int X11_SetTextInputRect(SDL_VideoDevice *_this, const SDL_Rect *rect)
{
#ifdef SDL_USE_IME
SDL_IME_UpdateTextRect(rect);
#endif
return 0;
}
SDL_bool X11_HasScreenKeyboardSupport(SDL_VideoDevice *_this)
{
SDL_VideoData *videodata = _this->driverdata;
return videodata->is_steam_deck;
}
void X11_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_VideoData *videodata = _this->driverdata;
if (videodata->is_steam_deck) {
/* For more documentation of the URL parameters, see:
* https://partner.steamgames.com/doc/api/ISteamUtils#ShowFloatingGamepadTextInput
*/
char deeplink[128];
(void)SDL_snprintf(deeplink, sizeof(deeplink),
"steam://open/keyboard?XPosition=0&YPosition=0&Width=0&Height=0&Mode=%d",
SDL_GetHintBoolean(SDL_HINT_RETURN_KEY_HIDES_IME, SDL_FALSE) ? 0 : 1);
SDL_OpenURL(deeplink);
videodata->steam_keyboard_open = SDL_TRUE;
}
}
void X11_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_VideoData *videodata = _this->driverdata;
if (videodata->is_steam_deck) {
SDL_OpenURL("steam://close/keyboard");
videodata->steam_keyboard_open = SDL_FALSE;
}
}
SDL_bool X11_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_VideoData *videodata = _this->driverdata;
return videodata->steam_keyboard_open;
}
#endif /* SDL_VIDEO_DRIVER_X11 */

View File

@ -0,0 +1,38 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_x11keyboard_h_
#define SDL_x11keyboard_h_
extern int X11_InitKeyboard(SDL_VideoDevice *_this);
extern void X11_UpdateKeymap(SDL_VideoDevice *_this, SDL_bool send_event);
extern void X11_QuitKeyboard(SDL_VideoDevice *_this);
extern void X11_StartTextInput(SDL_VideoDevice *_this);
extern void X11_StopTextInput(SDL_VideoDevice *_this);
extern int X11_SetTextInputRect(SDL_VideoDevice *_this, const SDL_Rect *rect);
extern SDL_bool X11_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
extern void X11_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
extern void X11_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
extern SDL_bool X11_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window);
extern KeySym X11_KeyCodeToSym(SDL_VideoDevice *_this, KeyCode, unsigned char group);
#endif /* SDL_x11keyboard_h_ */

View File

@ -0,0 +1,855 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_X11
#include "SDL_x11video.h"
#include "SDL_x11dyn.h"
#include "SDL_x11messagebox.h"
#include <X11/keysym.h>
#include <locale.h>
#define SDL_FORK_MESSAGEBOX 1
#define SDL_SET_LOCALE 1
#if SDL_FORK_MESSAGEBOX
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#endif
#define MAX_BUTTONS 8 /* Maximum number of buttons supported */
#define MIN_BUTTON_WIDTH 64 /* Minimum button width */
#define MIN_DIALOG_WIDTH 200 /* Minimum dialog width */
#define MIN_DIALOG_HEIGHT 100 /* Minimum dialog height */
static const char g_MessageBoxFontLatin1[] = "-*-*-medium-r-normal--0-120-*-*-p-0-iso8859-1";
static const char g_MessageBoxFont[] = "-*-*-medium-r-normal--*-120-*-*-*-*-*-*";
static const SDL_MessageBoxColor g_default_colors[SDL_MESSAGEBOX_COLOR_MAX] = {
{ 56, 54, 53 }, /* SDL_MESSAGEBOX_COLOR_BACKGROUND, */
{ 209, 207, 205 }, /* SDL_MESSAGEBOX_COLOR_TEXT, */
{ 140, 135, 129 }, /* SDL_MESSAGEBOX_COLOR_BUTTON_BORDER, */
{ 105, 102, 99 }, /* SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND, */
{ 205, 202, 53 }, /* SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED, */
};
#define SDL_MAKE_RGB(_r, _g, _b) (((Uint32)(_r) << 16) | \
((Uint32)(_g) << 8) | \
((Uint32)(_b)))
typedef struct SDL_MessageBoxButtonDataX11
{
int x, y; /* Text position */
int length; /* Text length */
int text_width; /* Text width */
SDL_Rect rect; /* Rectangle for entire button */
const SDL_MessageBoxButtonData *buttondata; /* Button data from caller */
} SDL_MessageBoxButtonDataX11;
typedef struct TextLineData
{
int width; /* Width of this text line */
int length; /* String length of this text line */
const char *text; /* Text for this line */
} TextLineData;
typedef struct SDL_MessageBoxDataX11
{
Display *display;
int screen;
Window window;
#ifdef SDL_VIDEO_DRIVER_X11_XDBE
XdbeBackBuffer buf;
SDL_bool xdbe; /* Whether Xdbe is present or not */
#endif
long event_mask;
Atom wm_protocols;
Atom wm_delete_message;
int dialog_width; /* Dialog box width. */
int dialog_height; /* Dialog box height. */
XFontSet font_set; /* for UTF-8 systems */
XFontStruct *font_struct; /* Latin1 (ASCII) fallback. */
int xtext, ytext; /* Text position to start drawing at. */
int numlines; /* Count of Text lines. */
int text_height; /* Height for text lines. */
TextLineData *linedata;
int *pbuttonid; /* Pointer to user return buttonid value. */
int button_press_index; /* Index into buttondata/buttonpos for button which is pressed (or -1). */
int mouse_over_index; /* Index into buttondata/buttonpos for button mouse is over (or -1). */
int numbuttons; /* Count of buttons. */
const SDL_MessageBoxButtonData *buttondata;
SDL_MessageBoxButtonDataX11 buttonpos[MAX_BUTTONS];
Uint32 color[SDL_MESSAGEBOX_COLOR_MAX];
const SDL_MessageBoxData *messageboxdata;
} SDL_MessageBoxDataX11;
/* Maximum helper for ints. */
static SDL_INLINE int IntMax(int a, int b)
{
return (a > b) ? a : b;
}
/* Return width and height for a string. */
static void GetTextWidthHeight(SDL_MessageBoxDataX11 *data, const char *str, int nbytes, int *pwidth, int *pheight)
{
if (SDL_X11_HAVE_UTF8) {
XRectangle overall_ink, overall_logical;
X11_Xutf8TextExtents(data->font_set, str, nbytes, &overall_ink, &overall_logical);
*pwidth = overall_logical.width;
*pheight = overall_logical.height;
} else {
XCharStruct text_structure;
int font_direction, font_ascent, font_descent;
X11_XTextExtents(data->font_struct, str, nbytes,
&font_direction, &font_ascent, &font_descent,
&text_structure);
*pwidth = text_structure.width;
*pheight = text_structure.ascent + text_structure.descent;
}
}
/* Return index of button if position x,y is contained therein. */
static int GetHitButtonIndex(SDL_MessageBoxDataX11 *data, int x, int y)
{
int i;
int numbuttons = data->numbuttons;
SDL_MessageBoxButtonDataX11 *buttonpos = data->buttonpos;
for (i = 0; i < numbuttons; i++) {
SDL_Rect *rect = &buttonpos[i].rect;
if ((x >= rect->x) &&
(x <= (rect->x + rect->w)) &&
(y >= rect->y) &&
(y <= (rect->y + rect->h))) {
return i;
}
}
return -1;
}
/* Initialize SDL_MessageBoxData structure and Display, etc. */
static int X11_MessageBoxInit(SDL_MessageBoxDataX11 *data, const SDL_MessageBoxData *messageboxdata, int *pbuttonid)
{
int i;
int numbuttons = messageboxdata->numbuttons;
const SDL_MessageBoxButtonData *buttondata = messageboxdata->buttons;
const SDL_MessageBoxColor *colorhints;
if (numbuttons > MAX_BUTTONS) {
return SDL_SetError("Too many buttons (%d max allowed)", MAX_BUTTONS);
}
data->dialog_width = MIN_DIALOG_WIDTH;
data->dialog_height = MIN_DIALOG_HEIGHT;
data->messageboxdata = messageboxdata;
data->buttondata = buttondata;
data->numbuttons = numbuttons;
data->pbuttonid = pbuttonid;
data->display = X11_XOpenDisplay(NULL);
if (!data->display) {
return SDL_SetError("Couldn't open X11 display");
}
if (SDL_X11_HAVE_UTF8) {
char **missing = NULL;
int num_missing = 0;
data->font_set = X11_XCreateFontSet(data->display, g_MessageBoxFont,
&missing, &num_missing, NULL);
if (missing != NULL) {
X11_XFreeStringList(missing);
}
if (data->font_set == NULL) {
return SDL_SetError("Couldn't load font %s", g_MessageBoxFont);
}
} else {
data->font_struct = X11_XLoadQueryFont(data->display, g_MessageBoxFontLatin1);
if (data->font_struct == NULL) {
return SDL_SetError("Couldn't load font %s", g_MessageBoxFontLatin1);
}
}
if (messageboxdata->colorScheme) {
colorhints = messageboxdata->colorScheme->colors;
} else {
colorhints = g_default_colors;
}
/* Convert our SDL_MessageBoxColor r,g,b values to packed RGB format. */
for (i = 0; i < SDL_MESSAGEBOX_COLOR_MAX; i++) {
data->color[i] = SDL_MAKE_RGB(colorhints[i].r, colorhints[i].g, colorhints[i].b);
}
return 0;
}
static int CountLinesOfText(const char *text)
{
int retval = 0;
while (text && *text) {
const char *lf = SDL_strchr(text, '\n');
retval++; /* even without an endline, this counts as a line. */
text = lf ? lf + 1 : NULL;
}
return retval;
}
/* Calculate and initialize text and button locations. */
static int X11_MessageBoxInitPositions(SDL_MessageBoxDataX11 *data)
{
int i;
int ybuttons;
int text_width_max = 0;
int button_text_height = 0;
int button_width = MIN_BUTTON_WIDTH;
const SDL_MessageBoxData *messageboxdata = data->messageboxdata;
/* Go over text and break linefeeds into separate lines. */
if (messageboxdata != NULL && messageboxdata->message[0]) {
const char *text = messageboxdata->message;
const int linecount = CountLinesOfText(text);
TextLineData *plinedata = (TextLineData *)SDL_malloc(sizeof(TextLineData) * linecount);
if (plinedata == NULL) {
return SDL_OutOfMemory();
}
data->linedata = plinedata;
data->numlines = linecount;
for (i = 0; i < linecount; i++, plinedata++) {
const char *lf = SDL_strchr(text, '\n');
const int length = lf ? (lf - text) : SDL_strlen(text);
int height;
plinedata->text = text;
GetTextWidthHeight(data, text, length, &plinedata->width, &height);
/* Text and widths are the largest we've ever seen. */
data->text_height = IntMax(data->text_height, height);
text_width_max = IntMax(text_width_max, plinedata->width);
plinedata->length = length;
if (lf && (lf > text) && (lf[-1] == '\r')) {
plinedata->length--;
}
text += length + 1;
/* Break if there are no more linefeeds. */
if (lf == NULL) {
break;
}
}
/* Bump up the text height slightly. */
data->text_height += 2;
}
/* Loop through all buttons and calculate the button widths and height. */
for (i = 0; i < data->numbuttons; i++) {
int height;
data->buttonpos[i].buttondata = &data->buttondata[i];
data->buttonpos[i].length = SDL_strlen(data->buttondata[i].text);
GetTextWidthHeight(data, data->buttondata[i].text, SDL_strlen(data->buttondata[i].text),
&data->buttonpos[i].text_width, &height);
button_width = IntMax(button_width, data->buttonpos[i].text_width);
button_text_height = IntMax(button_text_height, height);
}
if (data->numlines) {
/* x,y for this line of text. */
data->xtext = data->text_height;
data->ytext = data->text_height + data->text_height;
/* Bump button y down to bottom of text. */
ybuttons = 3 * data->ytext / 2 + (data->numlines - 1) * data->text_height;
/* Bump the dialog box width and height up if needed. */
data->dialog_width = IntMax(data->dialog_width, 2 * data->xtext + text_width_max);
data->dialog_height = IntMax(data->dialog_height, ybuttons);
} else {
/* Button y starts at height of button text. */
ybuttons = button_text_height;
}
if (data->numbuttons) {
int x, y;
int width_of_buttons;
int button_spacing = button_text_height;
int button_height = 2 * button_text_height;
/* Bump button width up a bit. */
button_width += button_text_height;
/* Get width of all buttons lined up. */
width_of_buttons = data->numbuttons * button_width + (data->numbuttons - 1) * button_spacing;
/* Bump up dialog width and height if buttons are wider than text. */
data->dialog_width = IntMax(data->dialog_width, width_of_buttons + 2 * button_spacing);
data->dialog_height = IntMax(data->dialog_height, ybuttons + 2 * button_height);
/* Location for first button. */
if (messageboxdata->flags & SDL_MESSAGEBOX_BUTTONS_RIGHT_TO_LEFT) {
x = data->dialog_width - (data->dialog_width - width_of_buttons) / 2 - (button_width + button_spacing);
} else {
x = (data->dialog_width - width_of_buttons) / 2;
}
y = ybuttons + (data->dialog_height - ybuttons - button_height) / 2;
for (i = 0; i < data->numbuttons; i++) {
/* Button coordinates. */
data->buttonpos[i].rect.x = x;
data->buttonpos[i].rect.y = y;
data->buttonpos[i].rect.w = button_width;
data->buttonpos[i].rect.h = button_height;
/* Button text coordinates. */
data->buttonpos[i].x = x + (button_width - data->buttonpos[i].text_width) / 2;
data->buttonpos[i].y = y + (button_height - button_text_height - 1) / 2 + button_text_height;
/* Scoot over for next button. */
if (messageboxdata->flags & SDL_MESSAGEBOX_BUTTONS_RIGHT_TO_LEFT) {
x -= button_width + button_spacing;
} else {
x += button_width + button_spacing;
}
}
}
return 0;
}
/* Free SDL_MessageBoxData data. */
static void X11_MessageBoxShutdown(SDL_MessageBoxDataX11 *data)
{
if (data->font_set != NULL) {
X11_XFreeFontSet(data->display, data->font_set);
data->font_set = NULL;
}
if (data->font_struct != NULL) {
X11_XFreeFont(data->display, data->font_struct);
data->font_struct = NULL;
}
#ifdef SDL_VIDEO_DRIVER_X11_XDBE
if (SDL_X11_HAVE_XDBE && data->xdbe) {
X11_XdbeDeallocateBackBufferName(data->display, data->buf);
}
#endif
if (data->display) {
if (data->window != None) {
X11_XWithdrawWindow(data->display, data->window, data->screen);
X11_XDestroyWindow(data->display, data->window);
data->window = None;
}
X11_XCloseDisplay(data->display);
data->display = NULL;
}
SDL_free(data->linedata);
}
/* Create and set up our X11 dialog box indow. */
static int X11_MessageBoxCreateWindow(SDL_MessageBoxDataX11 *data)
{
int x, y;
XSizeHints *sizehints;
XSetWindowAttributes wnd_attr;
Atom _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DIALOG;
Display *display = data->display;
SDL_WindowData *windowdata = NULL;
const SDL_MessageBoxData *messageboxdata = data->messageboxdata;
if (messageboxdata->window) {
SDL_DisplayData *displaydata = SDL_GetDisplayDriverDataForWindow(messageboxdata->window);
windowdata = messageboxdata->window->driverdata;
data->screen = displaydata->screen;
} else {
data->screen = DefaultScreen(display);
}
data->event_mask = ExposureMask |
ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask |
StructureNotifyMask | FocusChangeMask | PointerMotionMask;
wnd_attr.event_mask = data->event_mask;
data->window = X11_XCreateWindow(
display, RootWindow(display, data->screen),
0, 0,
data->dialog_width, data->dialog_height,
0, CopyFromParent, InputOutput, CopyFromParent,
CWEventMask, &wnd_attr);
if (data->window == None) {
return SDL_SetError("Couldn't create X window");
}
if (windowdata) {
Atom _NET_WM_STATE = X11_XInternAtom(display, "_NET_WM_STATE", False);
Atom stateatoms[16];
size_t statecount = 0;
/* Set some message-boxy window states when attached to a parent window... */
/* we skip the taskbar since this will pop to the front when the parent window is clicked in the taskbar, etc */
stateatoms[statecount++] = X11_XInternAtom(display, "_NET_WM_STATE_SKIP_TASKBAR", False);
stateatoms[statecount++] = X11_XInternAtom(display, "_NET_WM_STATE_SKIP_PAGER", False);
stateatoms[statecount++] = X11_XInternAtom(display, "_NET_WM_STATE_FOCUSED", False);
stateatoms[statecount++] = X11_XInternAtom(display, "_NET_WM_STATE_MODAL", False);
SDL_assert(statecount <= SDL_arraysize(stateatoms));
X11_XChangeProperty(display, data->window, _NET_WM_STATE, XA_ATOM, 32,
PropModeReplace, (unsigned char *)stateatoms, statecount);
/* http://tronche.com/gui/x/icccm/sec-4.html#WM_TRANSIENT_FOR */
X11_XSetTransientForHint(display, data->window, windowdata->xwindow);
}
SDL_X11_SetWindowTitle(display, data->window, (char *)messageboxdata->title);
/* Let the window manager know this is a dialog box */
_NET_WM_WINDOW_TYPE = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
_NET_WM_WINDOW_TYPE_DIALOG = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
X11_XChangeProperty(display, data->window, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
PropModeReplace,
(unsigned char *)&_NET_WM_WINDOW_TYPE_DIALOG, 1);
/* Allow the window to be deleted by the window manager */
data->wm_protocols = X11_XInternAtom(display, "WM_PROTOCOLS", False);
data->wm_delete_message = X11_XInternAtom(display, "WM_DELETE_WINDOW", False);
X11_XSetWMProtocols(display, data->window, &data->wm_delete_message, 1);
if (windowdata) {
XWindowAttributes attrib;
Window dummy;
X11_XGetWindowAttributes(display, windowdata->xwindow, &attrib);
x = attrib.x + (attrib.width - data->dialog_width) / 2;
y = attrib.y + (attrib.height - data->dialog_height) / 3;
X11_XTranslateCoordinates(display, windowdata->xwindow, RootWindow(display, data->screen), x, y, &x, &y, &dummy);
} else {
const SDL_VideoDevice *dev = SDL_GetVideoDevice();
if ((dev) && (dev->displays) && (dev->num_displays > 0)) {
const SDL_VideoDisplay *dpy = &dev->displays[0];
const SDL_DisplayData *dpydata = dpy->driverdata;
x = dpydata->x + ((dpy->current_mode->w - data->dialog_width) / 2);
y = dpydata->y + ((dpy->current_mode->h - data->dialog_height) / 3);
} else { /* oh well. This will misposition on a multi-head setup. Init first next time. */
x = (DisplayWidth(display, data->screen) - data->dialog_width) / 2;
y = (DisplayHeight(display, data->screen) - data->dialog_height) / 3;
}
}
X11_XMoveWindow(display, data->window, x, y);
sizehints = X11_XAllocSizeHints();
if (sizehints) {
sizehints->flags = USPosition | USSize | PMaxSize | PMinSize;
sizehints->x = x;
sizehints->y = y;
sizehints->width = data->dialog_width;
sizehints->height = data->dialog_height;
sizehints->min_width = sizehints->max_width = data->dialog_width;
sizehints->min_height = sizehints->max_height = data->dialog_height;
X11_XSetWMNormalHints(display, data->window, sizehints);
X11_XFree(sizehints);
}
X11_XMapRaised(display, data->window);
#ifdef SDL_VIDEO_DRIVER_X11_XDBE
/* Initialise a back buffer for double buffering */
if (SDL_X11_HAVE_XDBE) {
int xdbe_major, xdbe_minor;
if (X11_XdbeQueryExtension(display, &xdbe_major, &xdbe_minor) != 0) {
data->xdbe = SDL_TRUE;
data->buf = X11_XdbeAllocateBackBufferName(display, data->window, XdbeUndefined);
} else {
data->xdbe = SDL_FALSE;
}
}
#endif
return 0;
}
/* Draw our message box. */
static void X11_MessageBoxDraw(SDL_MessageBoxDataX11 *data, GC ctx)
{
int i;
Drawable window = data->window;
Display *display = data->display;
#ifdef SDL_VIDEO_DRIVER_X11_XDBE
if (SDL_X11_HAVE_XDBE && data->xdbe) {
window = data->buf;
X11_XdbeBeginIdiom(data->display);
}
#endif
X11_XSetForeground(display, ctx, data->color[SDL_MESSAGEBOX_COLOR_BACKGROUND]);
X11_XFillRectangle(display, window, ctx, 0, 0, data->dialog_width, data->dialog_height);
X11_XSetForeground(display, ctx, data->color[SDL_MESSAGEBOX_COLOR_TEXT]);
for (i = 0; i < data->numlines; i++) {
TextLineData *plinedata = &data->linedata[i];
if (SDL_X11_HAVE_UTF8) {
X11_Xutf8DrawString(display, window, data->font_set, ctx,
data->xtext, data->ytext + i * data->text_height,
plinedata->text, plinedata->length);
} else {
X11_XDrawString(display, window, ctx,
data->xtext, data->ytext + i * data->text_height,
plinedata->text, plinedata->length);
}
}
for (i = 0; i < data->numbuttons; i++) {
SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[i];
const SDL_MessageBoxButtonData *buttondata = buttondatax11->buttondata;
int border = (buttondata->flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT) ? 2 : 0;
int offset = ((data->mouse_over_index == i) && (data->button_press_index == data->mouse_over_index)) ? 1 : 0;
X11_XSetForeground(display, ctx, data->color[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND]);
X11_XFillRectangle(display, window, ctx,
buttondatax11->rect.x - border, buttondatax11->rect.y - border,
buttondatax11->rect.w + 2 * border, buttondatax11->rect.h + 2 * border);
X11_XSetForeground(display, ctx, data->color[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER]);
X11_XDrawRectangle(display, window, ctx,
buttondatax11->rect.x, buttondatax11->rect.y,
buttondatax11->rect.w, buttondatax11->rect.h);
X11_XSetForeground(display, ctx, (data->mouse_over_index == i) ? data->color[SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED] : data->color[SDL_MESSAGEBOX_COLOR_TEXT]);
if (SDL_X11_HAVE_UTF8) {
X11_Xutf8DrawString(display, window, data->font_set, ctx,
buttondatax11->x + offset,
buttondatax11->y + offset,
buttondata->text, buttondatax11->length);
} else {
X11_XDrawString(display, window, ctx,
buttondatax11->x + offset, buttondatax11->y + offset,
buttondata->text, buttondatax11->length);
}
}
#ifdef SDL_VIDEO_DRIVER_X11_XDBE
if (SDL_X11_HAVE_XDBE && data->xdbe) {
XdbeSwapInfo swap_info;
swap_info.swap_window = data->window;
swap_info.swap_action = XdbeUndefined;
X11_XdbeSwapBuffers(data->display, &swap_info, 1);
X11_XdbeEndIdiom(data->display);
}
#endif
}
/* NOLINTNEXTLINE(readability-non-const-parameter): cannot make XPointer a const pointer due to typedef */
static Bool X11_MessageBoxEventTest(Display *display, XEvent *event, XPointer arg)
{
const SDL_MessageBoxDataX11 *data = (const SDL_MessageBoxDataX11 *)arg;
return ((event->xany.display == data->display) && (event->xany.window == data->window)) ? True : False;
}
/* Loop and handle message box event messages until something kills it. */
static int X11_MessageBoxLoop(SDL_MessageBoxDataX11 *data)
{
GC ctx;
XGCValues ctx_vals;
SDL_bool close_dialog = SDL_FALSE;
SDL_bool has_focus = SDL_TRUE;
KeySym last_key_pressed = XK_VoidSymbol;
unsigned long gcflags = GCForeground | GCBackground;
SDL_zero(ctx_vals);
ctx_vals.foreground = data->color[SDL_MESSAGEBOX_COLOR_BACKGROUND];
ctx_vals.background = data->color[SDL_MESSAGEBOX_COLOR_BACKGROUND];
if (!SDL_X11_HAVE_UTF8) {
gcflags |= GCFont;
ctx_vals.font = data->font_struct->fid;
}
ctx = X11_XCreateGC(data->display, data->window, gcflags, &ctx_vals);
if (ctx == None) {
return SDL_SetError("Couldn't create graphics context");
}
data->button_press_index = -1; /* Reset what button is currently depressed. */
data->mouse_over_index = -1; /* Reset what button the mouse is over. */
while (!close_dialog) {
XEvent e;
SDL_bool draw = SDL_TRUE;
/* can't use XWindowEvent() because it can't handle ClientMessage events. */
/* can't use XNextEvent() because we only want events for this window. */
X11_XIfEvent(data->display, &e, X11_MessageBoxEventTest, (XPointer)data);
/* If X11_XFilterEvent returns True, then some input method has filtered the
event, and the client should discard the event. */
if ((e.type != Expose) && X11_XFilterEvent(&e, None)) {
continue;
}
switch (e.type) {
case Expose:
if (e.xexpose.count > 0) {
draw = SDL_FALSE;
}
break;
case FocusIn:
/* Got focus. */
has_focus = SDL_TRUE;
break;
case FocusOut:
/* lost focus. Reset button and mouse info. */
has_focus = SDL_FALSE;
data->button_press_index = -1;
data->mouse_over_index = -1;
break;
case MotionNotify:
if (has_focus) {
/* Mouse moved... */
const int previndex = data->mouse_over_index;
data->mouse_over_index = GetHitButtonIndex(data, e.xbutton.x, e.xbutton.y);
if (data->mouse_over_index == previndex) {
draw = SDL_FALSE;
}
}
break;
case ClientMessage:
if (e.xclient.message_type == data->wm_protocols &&
e.xclient.format == 32 &&
e.xclient.data.l[0] == data->wm_delete_message) {
close_dialog = SDL_TRUE;
}
break;
case KeyPress:
/* Store key press - we make sure in key release that we got both. */
last_key_pressed = X11_XLookupKeysym(&e.xkey, 0);
break;
case KeyRelease:
{
Uint32 mask = 0;
KeySym key = X11_XLookupKeysym(&e.xkey, 0);
/* If this is a key release for something we didn't get the key down for, then bail. */
if (key != last_key_pressed) {
break;
}
if (key == XK_Escape) {
mask = SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
} else if ((key == XK_Return) || (key == XK_KP_Enter)) {
mask = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
}
if (mask) {
int i;
/* Look for first button with this mask set, and return it if found. */
for (i = 0; i < data->numbuttons; i++) {
SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[i];
if (buttondatax11->buttondata->flags & mask) {
*data->pbuttonid = buttondatax11->buttondata->buttonid;
close_dialog = SDL_TRUE;
break;
}
}
}
break;
}
case ButtonPress:
data->button_press_index = -1;
if (e.xbutton.button == Button1) {
/* Find index of button they clicked on. */
data->button_press_index = GetHitButtonIndex(data, e.xbutton.x, e.xbutton.y);
}
break;
case ButtonRelease:
/* If button is released over the same button that was clicked down on, then return it. */
if ((e.xbutton.button == Button1) && (data->button_press_index >= 0)) {
int button = GetHitButtonIndex(data, e.xbutton.x, e.xbutton.y);
if (data->button_press_index == button) {
SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[button];
*data->pbuttonid = buttondatax11->buttondata->buttonid;
close_dialog = SDL_TRUE;
}
}
data->button_press_index = -1;
break;
}
if (draw) {
/* Draw our dialog box. */
X11_MessageBoxDraw(data, ctx);
}
}
X11_XFreeGC(data->display, ctx);
return 0;
}
static int X11_ShowMessageBoxImpl(const SDL_MessageBoxData *messageboxdata, int *buttonid)
{
int ret;
SDL_MessageBoxDataX11 data;
#if SDL_SET_LOCALE
char *origlocale;
#endif
SDL_zero(data);
if (!SDL_X11_LoadSymbols()) {
return -1;
}
#if SDL_SET_LOCALE
origlocale = setlocale(LC_ALL, NULL);
if (origlocale != NULL) {
origlocale = SDL_strdup(origlocale);
if (origlocale == NULL) {
return SDL_OutOfMemory();
}
(void)setlocale(LC_ALL, "");
}
#endif
/* This code could get called from multiple threads maybe? */
X11_XInitThreads();
/* Initialize the return buttonid value to -1 (for error or dialogbox closed). */
*buttonid = -1;
/* Init and display the message box. */
ret = X11_MessageBoxInit(&data, messageboxdata, buttonid);
if (ret != -1) {
ret = X11_MessageBoxInitPositions(&data);
if (ret != -1) {
ret = X11_MessageBoxCreateWindow(&data);
if (ret != -1) {
ret = X11_MessageBoxLoop(&data);
}
}
}
X11_MessageBoxShutdown(&data);
#if SDL_SET_LOCALE
if (origlocale) {
(void)setlocale(LC_ALL, origlocale);
SDL_free(origlocale);
}
#endif
return ret;
}
/* Display an x11 message box. */
int X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
{
#if SDL_FORK_MESSAGEBOX
/* Use a child process to protect against setlocale(). Annoying. */
pid_t pid;
int fds[2];
int status = 0;
if (pipe(fds) == -1) {
return X11_ShowMessageBoxImpl(messageboxdata, buttonid); /* oh well. */
}
pid = fork();
if (pid == -1) { /* failed */
close(fds[0]);
close(fds[1]);
return X11_ShowMessageBoxImpl(messageboxdata, buttonid); /* oh well. */
} else if (pid == 0) { /* we're the child */
int exitcode = 0;
close(fds[0]);
status = X11_ShowMessageBoxImpl(messageboxdata, buttonid);
if (write(fds[1], &status, sizeof(int)) != sizeof(int)) {
exitcode = 1;
} else if (write(fds[1], buttonid, sizeof(int)) != sizeof(int)) {
exitcode = 1;
}
close(fds[1]);
_exit(exitcode); /* don't run atexit() stuff, static destructors, etc. */
} else { /* we're the parent */
pid_t rc;
close(fds[1]);
do {
rc = waitpid(pid, &status, 0);
} while ((rc == -1) && (errno == EINTR));
SDL_assert(rc == pid); /* not sure what to do if this fails. */
if ((rc == -1) || (!WIFEXITED(status)) || (WEXITSTATUS(status) != 0)) {
status = SDL_SetError("msgbox child process failed");
} else if ((read(fds[0], &status, sizeof(int)) != sizeof(int)) ||
(read(fds[0], buttonid, sizeof(int)) != sizeof(int))) {
status = SDL_SetError("read from msgbox child process failed");
*buttonid = 0;
}
close(fds[0]);
return status;
}
#else
return X11_ShowMessageBoxImpl(messageboxdata, buttonid);
#endif
}
#endif /* SDL_VIDEO_DRIVER_X11 */

View File

@ -0,0 +1,31 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_x11messagebox_h_
#define SDL_x11messagebox_h_
#ifdef SDL_VIDEO_DRIVER_X11
extern int X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid);
#endif /* SDL_VIDEO_DRIVER_X11 */
#endif /* SDL_x11messagebox_h_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_x11modes_h_
#define SDL_x11modes_h_
struct SDL_DisplayData
{
int screen;
Visual *visual;
int depth;
int scanline_pad;
int x;
int y;
SDL_bool use_xrandr;
#ifdef SDL_VIDEO_DRIVER_X11_XRANDR
RROutput xrandr_output;
#endif
};
struct SDL_DisplayModeData
{
#ifdef SDL_VIDEO_DRIVER_X11_XRANDR
RRMode xrandr_mode;
#else
int unused; /* just so struct isn't empty. */
#endif
};
extern int X11_InitModes(SDL_VideoDevice *_this);
extern int X11_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display);
extern int X11_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
extern void X11_QuitModes(SDL_VideoDevice *_this);
/* Some utility functions for working with visuals */
extern int X11_GetVisualInfoFromVisual(Display *display, Visual *visual,
XVisualInfo *vinfo);
extern Uint32 X11_GetPixelFormatFromVisualInfo(Display *display,
XVisualInfo *vinfo);
extern int X11_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *sdl_display, SDL_Rect *rect);
extern int X11_GetDisplayUsableBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *sdl_display, SDL_Rect *rect);
#ifdef SDL_VIDEO_DRIVER_X11_XRANDR
extern void X11_HandleXRandREvent(SDL_VideoDevice *_this, const XEvent *xevent);
#endif
#endif /* SDL_x11modes_h_ */

View File

@ -0,0 +1,498 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_X11
#include <X11/cursorfont.h>
#include "SDL_x11video.h"
#include "SDL_x11mouse.h"
#include "SDL_x11xinput2.h"
#include "../../events/SDL_mouse_c.h"
/* FIXME: Find a better place to put this... */
static Cursor x11_empty_cursor = None;
static Display *GetDisplay(void)
{
return SDL_GetVideoDevice()->driverdata->display;
}
static Cursor X11_CreateEmptyCursor(void)
{
if (x11_empty_cursor == None) {
Display *display = GetDisplay();
char data[1];
XColor color;
Pixmap pixmap;
SDL_zeroa(data);
color.red = color.green = color.blue = 0;
pixmap = X11_XCreateBitmapFromData(display, DefaultRootWindow(display),
data, 1, 1);
if (pixmap) {
x11_empty_cursor = X11_XCreatePixmapCursor(display, pixmap, pixmap,
&color, &color, 0, 0);
X11_XFreePixmap(display, pixmap);
}
}
return x11_empty_cursor;
}
static void X11_DestroyEmptyCursor(void)
{
if (x11_empty_cursor != None) {
X11_XFreeCursor(GetDisplay(), x11_empty_cursor);
x11_empty_cursor = None;
}
}
static SDL_Cursor *X11_CreateDefaultCursor(void)
{
SDL_Cursor *cursor;
cursor = SDL_calloc(1, sizeof(*cursor));
if (cursor) {
/* None is used to indicate the default cursor */
cursor->driverdata = (void *)(uintptr_t)None;
} else {
SDL_OutOfMemory();
}
return cursor;
}
#ifdef SDL_VIDEO_DRIVER_X11_XCURSOR
static Cursor X11_CreateXCursorCursor(SDL_Surface *surface, int hot_x, int hot_y)
{
Display *display = GetDisplay();
Cursor cursor = None;
XcursorImage *image;
image = X11_XcursorImageCreate(surface->w, surface->h);
if (image == NULL) {
SDL_OutOfMemory();
return None;
}
image->xhot = hot_x;
image->yhot = hot_y;
image->delay = 0;
SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
SDL_assert(surface->pitch == surface->w * 4);
SDL_memcpy(image->pixels, surface->pixels, (size_t)surface->h * surface->pitch);
cursor = X11_XcursorImageLoadCursor(display, image);
X11_XcursorImageDestroy(image);
return cursor;
}
#endif /* SDL_VIDEO_DRIVER_X11_XCURSOR */
static Cursor X11_CreatePixmapCursor(SDL_Surface *surface, int hot_x, int hot_y)
{
Display *display = GetDisplay();
XColor fg, bg;
Cursor cursor = None;
Uint32 *ptr;
Uint8 *data_bits, *mask_bits;
Pixmap data_pixmap, mask_pixmap;
int x, y;
unsigned int rfg, gfg, bfg, rbg, gbg, bbg, fgBits, bgBits;
size_t width_bytes = ((surface->w + 7) & ~((size_t)7)) / 8;
data_bits = SDL_calloc(1, surface->h * width_bytes);
if (data_bits == NULL) {
SDL_OutOfMemory();
return None;
}
mask_bits = SDL_calloc(1, surface->h * width_bytes);
if (mask_bits == NULL) {
SDL_free(data_bits);
SDL_OutOfMemory();
return None;
}
/* Code below assumes ARGB pixel format */
SDL_assert(surface->format->format == SDL_PIXELFORMAT_ARGB8888);
rfg = gfg = bfg = rbg = gbg = bbg = fgBits = bgBits = 0;
for (y = 0; y < surface->h; ++y) {
ptr = (Uint32 *)((Uint8 *)surface->pixels + y * surface->pitch);
for (x = 0; x < surface->w; ++x) {
int alpha = (*ptr >> 24) & 0xff;
int red = (*ptr >> 16) & 0xff;
int green = (*ptr >> 8) & 0xff;
int blue = (*ptr >> 0) & 0xff;
if (alpha > 25) {
mask_bits[y * width_bytes + x / 8] |= (0x01 << (x % 8));
if ((red + green + blue) > 0x40) {
fgBits++;
rfg += red;
gfg += green;
bfg += blue;
data_bits[y * width_bytes + x / 8] |= (0x01 << (x % 8));
} else {
bgBits++;
rbg += red;
gbg += green;
bbg += blue;
}
}
++ptr;
}
}
if (fgBits) {
fg.red = rfg * 257 / fgBits;
fg.green = gfg * 257 / fgBits;
fg.blue = bfg * 257 / fgBits;
} else {
fg.red = fg.green = fg.blue = 0;
}
if (bgBits) {
bg.red = rbg * 257 / bgBits;
bg.green = gbg * 257 / bgBits;
bg.blue = bbg * 257 / bgBits;
} else {
bg.red = bg.green = bg.blue = 0;
}
data_pixmap = X11_XCreateBitmapFromData(display, DefaultRootWindow(display),
(char *)data_bits,
surface->w, surface->h);
mask_pixmap = X11_XCreateBitmapFromData(display, DefaultRootWindow(display),
(char *)mask_bits,
surface->w, surface->h);
cursor = X11_XCreatePixmapCursor(display, data_pixmap, mask_pixmap,
&fg, &bg, hot_x, hot_y);
X11_XFreePixmap(display, data_pixmap);
X11_XFreePixmap(display, mask_pixmap);
SDL_free(data_bits);
SDL_free(mask_bits);
return cursor;
}
static SDL_Cursor *X11_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
{
SDL_Cursor *cursor;
cursor = SDL_calloc(1, sizeof(*cursor));
if (cursor) {
Cursor x11_cursor = None;
#ifdef SDL_VIDEO_DRIVER_X11_XCURSOR
if (SDL_X11_HAVE_XCURSOR) {
x11_cursor = X11_CreateXCursorCursor(surface, hot_x, hot_y);
}
#endif
if (x11_cursor == None) {
x11_cursor = X11_CreatePixmapCursor(surface, hot_x, hot_y);
}
cursor->driverdata = (void *)(uintptr_t)x11_cursor;
} else {
SDL_OutOfMemory();
}
return cursor;
}
static SDL_Cursor *X11_CreateSystemCursor(SDL_SystemCursor id)
{
SDL_Cursor *cursor;
unsigned int shape;
switch (id) {
default:
SDL_assert(0);
return NULL;
/* X Font Cursors reference: */
/* http://tronche.com/gui/x/xlib/appendix/b/ */
case SDL_SYSTEM_CURSOR_ARROW:
shape = XC_left_ptr;
break;
case SDL_SYSTEM_CURSOR_IBEAM:
shape = XC_xterm;
break;
case SDL_SYSTEM_CURSOR_WAIT:
shape = XC_watch;
break;
case SDL_SYSTEM_CURSOR_CROSSHAIR:
shape = XC_tcross;
break;
case SDL_SYSTEM_CURSOR_WAITARROW:
shape = XC_watch;
break;
case SDL_SYSTEM_CURSOR_SIZENWSE:
shape = XC_top_left_corner;
break;
case SDL_SYSTEM_CURSOR_SIZENESW:
shape = XC_top_right_corner;
break;
case SDL_SYSTEM_CURSOR_SIZEWE:
shape = XC_sb_h_double_arrow;
break;
case SDL_SYSTEM_CURSOR_SIZENS:
shape = XC_sb_v_double_arrow;
break;
case SDL_SYSTEM_CURSOR_SIZEALL:
shape = XC_fleur;
break;
case SDL_SYSTEM_CURSOR_NO:
shape = XC_pirate;
break;
case SDL_SYSTEM_CURSOR_HAND:
shape = XC_hand2;
break;
}
cursor = SDL_calloc(1, sizeof(*cursor));
if (cursor) {
Cursor x11_cursor;
x11_cursor = X11_XCreateFontCursor(GetDisplay(), shape);
cursor->driverdata = (void *)(uintptr_t)x11_cursor;
} else {
SDL_OutOfMemory();
}
return cursor;
}
static void X11_FreeCursor(SDL_Cursor *cursor)
{
Cursor x11_cursor = (Cursor)cursor->driverdata;
if (x11_cursor != None) {
X11_XFreeCursor(GetDisplay(), x11_cursor);
}
SDL_free(cursor);
}
static int X11_ShowCursor(SDL_Cursor *cursor)
{
Cursor x11_cursor = 0;
if (cursor) {
x11_cursor = (Cursor)cursor->driverdata;
} else {
x11_cursor = X11_CreateEmptyCursor();
}
/* FIXME: Is there a better way than this? */
{
SDL_VideoDevice *video = SDL_GetVideoDevice();
Display *display = GetDisplay();
SDL_Window *window;
for (window = video->windows; window; window = window->next) {
SDL_WindowData *data = window->driverdata;
if (data) {
if (x11_cursor != None) {
X11_XDefineCursor(display, data->xwindow, x11_cursor);
} else {
X11_XUndefineCursor(display, data->xwindow);
}
}
}
X11_XFlush(display);
}
return 0;
}
static void X11_WarpMouseInternal(Window xwindow, float x, float y)
{
SDL_VideoData *videodata = SDL_GetVideoDevice()->driverdata;
Display *display = videodata->display;
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
int deviceid = 0;
/* It seems XIWarpPointer() doesn't work correctly on multi-head setups:
* https://developer.blender.org/rB165caafb99c6846e53d11c4e966990aaffc06cea
*/
if (ScreenCount(display) == 1) {
X11_XIGetClientPointer(display, None, &deviceid);
}
if (deviceid != 0) {
X11_XIWarpPointer(display, deviceid, None, xwindow, 0.0, 0.0, 0, 0, x, y);
} else
#endif
{
X11_XWarpPointer(display, None, xwindow, 0, 0, 0, 0, (int)x, (int)y);
}
X11_XSync(display, False);
videodata->global_mouse_changed = SDL_TRUE;
}
static int X11_WarpMouse(SDL_Window *window, float x, float y)
{
SDL_WindowData *data = window->driverdata;
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
/* If we have no barrier, we need to warp */
if (data->pointer_barrier_active == SDL_FALSE) {
X11_WarpMouseInternal(data->xwindow, x, y);
}
#else
X11_WarpMouseInternal(data->xwindow, x, y);
#endif
return 0;
}
static int X11_WarpMouseGlobal(float x, float y)
{
X11_WarpMouseInternal(DefaultRootWindow(GetDisplay()), x, y);
return 0;
}
static int X11_SetRelativeMouseMode(SDL_bool enabled)
{
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
if (X11_Xinput2IsInitialized()) {
return 0;
}
#endif
return SDL_Unsupported();
}
static int X11_CaptureMouse(SDL_Window *window)
{
Display *display = GetDisplay();
SDL_Window *mouse_focus = SDL_GetMouseFocus();
if (window) {
SDL_WindowData *data = window->driverdata;
const unsigned int mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask;
Window confined = (data->mouse_grabbed ? data->xwindow : None);
const int rc = X11_XGrabPointer(display, data->xwindow, False,
mask, GrabModeAsync, GrabModeAsync,
confined, None, CurrentTime);
if (rc != GrabSuccess) {
return SDL_SetError("X server refused mouse capture");
}
} else if (mouse_focus) {
SDL_UpdateWindowGrab(mouse_focus);
} else {
X11_XUngrabPointer(display, CurrentTime);
}
X11_XSync(display, False);
return 0;
}
static Uint32 X11_GetGlobalMouseState(float *x, float *y)
{
SDL_VideoData *videodata = SDL_GetVideoDevice()->driverdata;
SDL_DisplayID *displays;
Display *display = GetDisplay();
int i;
/* !!! FIXME: should we XSync() here first? */
#ifndef SDL_VIDEO_DRIVER_X11_XINPUT2
videodata->global_mouse_changed = SDL_TRUE;
#else
if (!SDL_X11_HAVE_XINPUT2)
videodata->global_mouse_changed = SDL_TRUE;
#endif
/* check if we have this cached since XInput last saw the mouse move. */
/* !!! FIXME: can we just calculate this from XInput's events? */
if (videodata->global_mouse_changed) {
displays = SDL_GetDisplays(NULL);
if (displays) {
for (i = 0; displays[i]; ++i) {
SDL_DisplayData *data = SDL_GetDisplayDriverData(displays[i]);
if (data != NULL) {
Window root, child;
int rootx, rooty, winx, winy;
unsigned int mask;
if (X11_XQueryPointer(display, RootWindow(display, data->screen), &root, &child, &rootx, &rooty, &winx, &winy, &mask)) {
XWindowAttributes root_attrs;
Uint32 buttons = 0;
buttons |= (mask & Button1Mask) ? SDL_BUTTON_LMASK : 0;
buttons |= (mask & Button2Mask) ? SDL_BUTTON_MMASK : 0;
buttons |= (mask & Button3Mask) ? SDL_BUTTON_RMASK : 0;
/* Use the SDL state for the extended buttons - it's better than nothing */
buttons |= (SDL_GetMouseState(NULL, NULL) & (SDL_BUTTON_X1MASK | SDL_BUTTON_X2MASK));
/* SDL_DisplayData->x,y point to screen origin, and adding them to mouse coordinates relative to root window doesn't do the right thing
* (observed on dual monitor setup with primary display being the rightmost one - mouse was offset to the right).
*
* Adding root position to root-relative coordinates seems to be a better way to get absolute position. */
X11_XGetWindowAttributes(display, root, &root_attrs);
videodata->global_mouse_position.x = root_attrs.x + rootx;
videodata->global_mouse_position.y = root_attrs.y + rooty;
videodata->global_mouse_buttons = buttons;
videodata->global_mouse_changed = SDL_FALSE;
break;
}
}
}
SDL_free(displays);
}
}
SDL_assert(!videodata->global_mouse_changed); /* The pointer wasn't on any X11 screen?! */
*x = (float)videodata->global_mouse_position.x;
*y = (float)videodata->global_mouse_position.y;
return videodata->global_mouse_buttons;
}
void X11_InitMouse(SDL_VideoDevice *_this)
{
SDL_Mouse *mouse = SDL_GetMouse();
mouse->CreateCursor = X11_CreateCursor;
mouse->CreateSystemCursor = X11_CreateSystemCursor;
mouse->ShowCursor = X11_ShowCursor;
mouse->FreeCursor = X11_FreeCursor;
mouse->WarpMouse = X11_WarpMouse;
mouse->WarpMouseGlobal = X11_WarpMouseGlobal;
mouse->SetRelativeMouseMode = X11_SetRelativeMouseMode;
mouse->CaptureMouse = X11_CaptureMouse;
mouse->GetGlobalMouseState = X11_GetGlobalMouseState;
SDL_SetDefaultCursor(X11_CreateDefaultCursor());
}
void X11_QuitMouse(SDL_VideoDevice *_this)
{
SDL_VideoData *data = _this->driverdata;
SDL_XInput2DeviceInfo *i;
SDL_XInput2DeviceInfo *next;
for (i = data->mouse_device_info; i != NULL; i = next) {
next = i->next;
SDL_free(i);
}
data->mouse_device_info = NULL;
X11_DestroyEmptyCursor();
}
#endif /* SDL_VIDEO_DRIVER_X11 */

View File

@ -0,0 +1,39 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_x11mouse_h_
#define SDL_x11mouse_h_
typedef struct SDL_XInput2DeviceInfo
{
int device_id;
SDL_bool relative[2];
double minval[2];
double maxval[2];
double prev_coords[2];
struct SDL_XInput2DeviceInfo *next;
} SDL_XInput2DeviceInfo;
extern void X11_InitMouse(SDL_VideoDevice *_this);
extern void X11_QuitMouse(SDL_VideoDevice *_this);
#endif /* SDL_x11mouse_h_ */

View File

@ -0,0 +1,990 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
Copyright (C) 2021 NVIDIA Corporation
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_X11
#include "SDL_x11video.h"
/* GLX implementation of SDL OpenGL support */
#ifdef SDL_VIDEO_OPENGL_GLX
#include "SDL_x11opengles.h"
#if defined(__IRIX__) || defined(__NetBSD__) || defined(__OpenBSD__)
/*
* IRIX doesn't have a GL library versioning system.
* NetBSD and OpenBSD have different GL library versions depending on how
* the library was installed.
*/
#define DEFAULT_OPENGL "libGL.so"
#elif defined(__MACOS__)
#define DEFAULT_OPENGL "/opt/X11/lib/libGL.1.dylib"
#else
#define DEFAULT_OPENGL "libGL.so.1"
#endif
#ifndef GLX_NONE_EXT
#define GLX_NONE_EXT 0x8000
#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
#ifndef GLX_EXT_visual_info
#define GLX_EXT_visual_info
#define GLX_X_VISUAL_TYPE_EXT 0x22
#define GLX_DIRECT_COLOR_EXT 0x8003
#endif
#ifndef GLX_ARB_create_context
#define GLX_ARB_create_context
#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
#define GLX_CONTEXT_FLAGS_ARB 0x2094
#define GLX_CONTEXT_DEBUG_BIT_ARB 0x0001
#define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002
/* Typedef for the GL 3.0 context creation function */
typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display *dpy,
GLXFBConfig config,
GLXContext
share_context,
Bool direct,
const int
*attrib_list);
#endif
#ifndef GLX_ARB_create_context_profile
#define GLX_ARB_create_context_profile
#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
#define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
#endif
#ifndef GLX_ARB_create_context_robustness
#define GLX_ARB_create_context_robustness
#define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
#define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
#define GLX_NO_RESET_NOTIFICATION_ARB 0x8261
#define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252
#endif
#ifndef GLX_EXT_create_context_es2_profile
#define GLX_EXT_create_context_es2_profile
#ifndef GLX_CONTEXT_ES2_PROFILE_BIT_EXT
#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000002
#endif
#endif
#ifndef GLX_ARB_framebuffer_sRGB
#define GLX_ARB_framebuffer_sRGB
#ifndef GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB
#define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20B2
#endif
#endif
#ifndef GLX_ARB_fbconfig_float
#define GLX_ARB_fbconfig_float
#ifndef GLX_RGBA_FLOAT_TYPE_ARB
#define GLX_RGBA_FLOAT_TYPE_ARB 0x20B9
#endif
#ifndef GLX_RGBA_FLOAT_BIT_ARB
#define GLX_RGBA_FLOAT_BIT_ARB 0x00000004
#endif
#endif
#ifndef GLX_ARB_create_context_no_error
#define GLX_ARB_create_context_no_error
#ifndef GLX_CONTEXT_OPENGL_NO_ERROR_ARB
#define GLX_CONTEXT_OPENGL_NO_ERROR_ARB 0x31B3
#endif
#endif
#ifndef GLX_EXT_swap_control
#define GLX_SWAP_INTERVAL_EXT 0x20F1
#define GLX_MAX_SWAP_INTERVAL_EXT 0x20F2
#endif
#ifndef GLX_EXT_swap_control_tear
#define GLX_LATE_SWAPS_TEAR_EXT 0x20F3
#endif
#ifndef GLX_ARB_context_flush_control
#define GLX_ARB_context_flush_control
#define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
#define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0x0000
#define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
#endif
#define OPENGL_REQUIRES_DLOPEN
#if defined(OPENGL_REQUIRES_DLOPEN) && defined(HAVE_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
static void X11_GL_InitExtensions(SDL_VideoDevice *_this);
int X11_GL_LoadLibrary(SDL_VideoDevice *_this, const char *path)
{
Display *display;
void *handle;
if (_this->gl_data) {
return SDL_SetError("OpenGL context already created");
}
/* Load the OpenGL library */
if (path == NULL) {
path = SDL_getenv("SDL_OPENGL_LIBRARY");
}
if (path == NULL) {
path = DEFAULT_OPENGL;
}
_this->gl_config.dll_handle = GL_LoadObject(path);
if (!_this->gl_config.dll_handle) {
#if defined(OPENGL_REQUIRES_DLOPEN) && defined(HAVE_DLOPEN)
SDL_SetError("Failed loading %s: %s", path, dlerror());
#endif
return -1;
}
SDL_strlcpy(_this->gl_config.driver_path, path,
SDL_arraysize(_this->gl_config.driver_path));
/* Allocate OpenGL memory */
_this->gl_data =
(struct SDL_GLDriverData *)SDL_calloc(1,
sizeof(struct
SDL_GLDriverData));
if (!_this->gl_data) {
return SDL_OutOfMemory();
}
/* Load function pointers */
handle = _this->gl_config.dll_handle;
_this->gl_data->glXQueryExtension =
(Bool(*)(Display *, int *, int *))
GL_LoadFunction(handle, "glXQueryExtension");
_this->gl_data->glXGetProcAddress =
(__GLXextFuncPtr (*)(const GLubyte *))
GL_LoadFunction(handle, "glXGetProcAddressARB");
_this->gl_data->glXChooseVisual =
(XVisualInfo * (*)(Display *, int, int *))
X11_GL_GetProcAddress(_this, "glXChooseVisual");
_this->gl_data->glXCreateContext =
(GLXContext(*)(Display *, XVisualInfo *, GLXContext, int))
X11_GL_GetProcAddress(_this, "glXCreateContext");
_this->gl_data->glXDestroyContext =
(void (*)(Display *, GLXContext))
X11_GL_GetProcAddress(_this, "glXDestroyContext");
_this->gl_data->glXMakeCurrent =
(int (*)(Display *, GLXDrawable, GLXContext))
X11_GL_GetProcAddress(_this, "glXMakeCurrent");
_this->gl_data->glXSwapBuffers =
(void (*)(Display *, GLXDrawable))
X11_GL_GetProcAddress(_this, "glXSwapBuffers");
_this->gl_data->glXQueryDrawable =
(void (*)(Display *, GLXDrawable, int, unsigned int *))
X11_GL_GetProcAddress(_this, "glXQueryDrawable");
if (!_this->gl_data->glXQueryExtension ||
!_this->gl_data->glXChooseVisual ||
!_this->gl_data->glXCreateContext ||
!_this->gl_data->glXDestroyContext ||
!_this->gl_data->glXMakeCurrent ||
!_this->gl_data->glXSwapBuffers) {
return SDL_SetError("Could not retrieve OpenGL functions");
}
display = _this->driverdata->display;
if (!_this->gl_data->glXQueryExtension(display, &_this->gl_data->errorBase, &_this->gl_data->eventBase)) {
return SDL_SetError("GLX is not supported");
}
/* Initialize extensions */
/* See lengthy comment about the inc/dec in
../windows/SDL_windowsopengl.c. */
++_this->gl_config.driver_loaded;
X11_GL_InitExtensions(_this);
--_this->gl_config.driver_loaded;
/* If we need a GL ES context and there's no
* GLX_EXT_create_context_es2_profile extension, switch over to X11_GLES functions
*/
if (((_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) ||
SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, SDL_FALSE)) &&
X11_GL_UseEGL(_this)) {
#ifdef SDL_VIDEO_OPENGL_EGL
X11_GL_UnloadLibrary(_this);
_this->GL_LoadLibrary = X11_GLES_LoadLibrary;
_this->GL_GetProcAddress = X11_GLES_GetProcAddress;
_this->GL_UnloadLibrary = X11_GLES_UnloadLibrary;
_this->GL_CreateContext = X11_GLES_CreateContext;
_this->GL_MakeCurrent = X11_GLES_MakeCurrent;
_this->GL_SetSwapInterval = X11_GLES_SetSwapInterval;
_this->GL_GetSwapInterval = X11_GLES_GetSwapInterval;
_this->GL_SwapWindow = X11_GLES_SwapWindow;
_this->GL_DeleteContext = X11_GLES_DeleteContext;
return X11_GLES_LoadLibrary(_this, NULL);
#else
return SDL_SetError("SDL not configured with EGL support");
#endif
}
return 0;
}
SDL_FunctionPointer X11_GL_GetProcAddress(SDL_VideoDevice *_this, const char *proc)
{
if (_this->gl_data->glXGetProcAddress) {
return _this->gl_data->glXGetProcAddress((const GLubyte *)proc);
}
return GL_LoadFunction(_this->gl_config.dll_handle, proc);
}
void X11_GL_UnloadLibrary(SDL_VideoDevice *_this)
{
/* Don't actually unload the library, since it may have registered
* X11 shutdown hooks, per the notes at:
* http://dri.sourceforge.net/doc/DRIuserguide.html
*/
#if 0
GL_UnloadObject(_this->gl_config.dll_handle);
_this->gl_config.dll_handle = NULL;
#endif
/* Free OpenGL memory */
SDL_free(_this->gl_data);
_this->gl_data = NULL;
}
static SDL_bool HasExtension(const char *extension, const char *extensions)
{
const char *start;
const char *where, *terminator;
if (!extensions) {
return SDL_FALSE;
}
/* Extension names should not have spaces. */
where = SDL_strchr(extension, ' ');
if (where || *extension == '\0') {
return SDL_FALSE;
}
/* 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 + SDL_strlen(extension);
if (where == start || *(where - 1) == ' ') {
if (*terminator == ' ' || *terminator == '\0') {
return SDL_TRUE;
}
}
start = terminator;
}
return SDL_FALSE;
}
static void X11_GL_InitExtensions(SDL_VideoDevice *_this)
{
Display *display = _this->driverdata->display;
const int screen = DefaultScreen(display);
XVisualInfo *vinfo = NULL;
Window w = 0;
GLXContext prev_ctx = 0;
GLXDrawable prev_drawable = 0;
GLXContext context = 0;
const char *(*glXQueryExtensionsStringFunc)(Display *, int);
const char *extensions;
vinfo = X11_GL_GetVisual(_this, display, screen, SDL_FALSE);
if (vinfo) {
GLXContext (*glXGetCurrentContextFunc)(void) =
(GLXContext(*)(void))
X11_GL_GetProcAddress(_this, "glXGetCurrentContext");
GLXDrawable (*glXGetCurrentDrawableFunc)(void) =
(GLXDrawable(*)(void))
X11_GL_GetProcAddress(_this, "glXGetCurrentDrawable");
if (glXGetCurrentContextFunc && glXGetCurrentDrawableFunc) {
XSetWindowAttributes xattr;
prev_ctx = glXGetCurrentContextFunc();
prev_drawable = glXGetCurrentDrawableFunc();
xattr.background_pixel = 0;
xattr.border_pixel = 0;
xattr.colormap =
X11_XCreateColormap(display, RootWindow(display, screen),
vinfo->visual, AllocNone);
w = X11_XCreateWindow(display, RootWindow(display, screen), 0, 0,
32, 32, 0, vinfo->depth, InputOutput, vinfo->visual,
(CWBackPixel | CWBorderPixel | CWColormap), &xattr);
context = _this->gl_data->glXCreateContext(display, vinfo,
NULL, True);
if (context) {
_this->gl_data->glXMakeCurrent(display, w, context);
}
}
X11_XFree(vinfo);
}
glXQueryExtensionsStringFunc =
(const char *(*)(Display *, int))X11_GL_GetProcAddress(_this,
"glXQueryExtensionsString");
if (glXQueryExtensionsStringFunc) {
extensions = glXQueryExtensionsStringFunc(display, screen);
} else {
extensions = NULL;
}
/* Check for GLX_EXT_swap_control(_tear) */
_this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_FALSE;
if (HasExtension("GLX_EXT_swap_control", extensions)) {
_this->gl_data->glXSwapIntervalEXT =
(void (*)(Display *, GLXDrawable, int))
X11_GL_GetProcAddress(_this, "glXSwapIntervalEXT");
if (HasExtension("GLX_EXT_swap_control_tear", extensions)) {
_this->gl_data->HAS_GLX_EXT_swap_control_tear = SDL_TRUE;
}
}
/* Check for GLX_MESA_swap_control */
if (HasExtension("GLX_MESA_swap_control", extensions)) {
_this->gl_data->glXSwapIntervalMESA =
(int (*)(int))X11_GL_GetProcAddress(_this, "glXSwapIntervalMESA");
_this->gl_data->glXGetSwapIntervalMESA =
(int (*)(void))X11_GL_GetProcAddress(_this,
"glXGetSwapIntervalMESA");
}
/* Check for GLX_SGI_swap_control */
if (HasExtension("GLX_SGI_swap_control", extensions)) {
_this->gl_data->glXSwapIntervalSGI =
(int (*)(int))X11_GL_GetProcAddress(_this, "glXSwapIntervalSGI");
}
/* Check for GLX_ARB_create_context */
if (HasExtension("GLX_ARB_create_context", extensions)) {
_this->gl_data->glXCreateContextAttribsARB =
(GLXContext(*)(Display *, GLXFBConfig, GLXContext, Bool, const int *))
X11_GL_GetProcAddress(_this, "glXCreateContextAttribsARB");
_this->gl_data->glXChooseFBConfig =
(GLXFBConfig * (*)(Display *, int, const int *, int *))
X11_GL_GetProcAddress(_this, "glXChooseFBConfig");
_this->gl_data->glXGetVisualFromFBConfig =
(XVisualInfo * (*)(Display *, GLXFBConfig))
X11_GL_GetProcAddress(_this, "glXGetVisualFromFBConfig");
}
/* Check for GLX_EXT_visual_rating */
if (HasExtension("GLX_EXT_visual_rating", extensions)) {
_this->gl_data->HAS_GLX_EXT_visual_rating = SDL_TRUE;
}
/* Check for GLX_EXT_visual_info */
if (HasExtension("GLX_EXT_visual_info", extensions)) {
_this->gl_data->HAS_GLX_EXT_visual_info = SDL_TRUE;
}
/* Check for GLX_EXT_create_context_es2_profile */
if (HasExtension("GLX_EXT_create_context_es2_profile", extensions)) {
/* this wants to call glGetString(), so it needs a context. */
/* !!! FIXME: it would be nice not to make a context here though! */
if (context) {
SDL_GL_DeduceMaxSupportedESProfile(
&_this->gl_data->es_profile_max_supported_version.major,
&_this->gl_data->es_profile_max_supported_version.minor);
}
}
/* Check for GLX_ARB_context_flush_control */
if (HasExtension("GLX_ARB_context_flush_control", extensions)) {
_this->gl_data->HAS_GLX_ARB_context_flush_control = SDL_TRUE;
}
/* Check for GLX_ARB_create_context_robustness */
if (HasExtension("GLX_ARB_create_context_robustness", extensions)) {
_this->gl_data->HAS_GLX_ARB_create_context_robustness = SDL_TRUE;
}
/* Check for GLX_ARB_create_context_no_error */
if (HasExtension("GLX_ARB_create_context_no_error", extensions)) {
_this->gl_data->HAS_GLX_ARB_create_context_no_error = SDL_TRUE;
}
if (context) {
_this->gl_data->glXMakeCurrent(display, None, NULL);
_this->gl_data->glXDestroyContext(display, context);
if (prev_ctx && prev_drawable) {
_this->gl_data->glXMakeCurrent(display, prev_drawable, prev_ctx);
}
}
if (w) {
X11_XDestroyWindow(display, w);
}
X11_PumpEvents(_this);
}
/* glXChooseVisual and glXChooseFBConfig have some small differences in
* the attribute encoding, it can be chosen with the for_FBConfig parameter.
* Some targets fail if you use GLX_X_VISUAL_TYPE_EXT/GLX_DIRECT_COLOR_EXT,
* so it gets specified last if used and is pointed to by *_pvistypeattr.
* In case of failure, if that pointer is not NULL, set that pointer to None
* and try again.
*/
static int X11_GL_GetAttributes(SDL_VideoDevice *_this, Display *display, int screen, int *attribs, int size, Bool for_FBConfig, int **_pvistypeattr, SDL_bool transparent)
{
int i = 0;
const int MAX_ATTRIBUTES = 64;
int *pvistypeattr = NULL;
/* assert buffer is large enough to hold all SDL attributes. */
SDL_assert(size >= MAX_ATTRIBUTES);
/* Setup our GLX attributes according to the gl_config. */
if (for_FBConfig) {
attribs[i++] = GLX_RENDER_TYPE;
if (_this->gl_config.floatbuffers) {
attribs[i++] = GLX_RGBA_FLOAT_BIT_ARB;
} else {
attribs[i++] = GLX_RGBA_BIT;
}
} else {
attribs[i++] = GLX_RGBA;
}
attribs[i++] = GLX_RED_SIZE;
attribs[i++] = _this->gl_config.red_size;
attribs[i++] = GLX_GREEN_SIZE;
attribs[i++] = _this->gl_config.green_size;
attribs[i++] = GLX_BLUE_SIZE;
attribs[i++] = _this->gl_config.blue_size;
if (_this->gl_config.alpha_size) {
attribs[i++] = GLX_ALPHA_SIZE;
attribs[i++] = _this->gl_config.alpha_size;
}
if (_this->gl_config.double_buffer) {
attribs[i++] = GLX_DOUBLEBUFFER;
if (for_FBConfig) {
attribs[i++] = True;
}
}
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 (for_FBConfig) {
attribs[i++] = True;
}
}
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.floatbuffers) {
attribs[i++] = GLX_RGBA_FLOAT_TYPE_ARB;
}
if (_this->gl_config.framebuffer_srgb_capable) {
attribs[i++] = GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB;
attribs[i++] = True; /* always needed, for_FBConfig or not! */
}
if (_this->gl_config.accelerated >= 0 &&
_this->gl_data->HAS_GLX_EXT_visual_rating) {
attribs[i++] = GLX_VISUAL_CAVEAT_EXT;
attribs[i++] = _this->gl_config.accelerated ? GLX_NONE_EXT : GLX_SLOW_VISUAL_EXT;
}
/* Un-wanted when we request a transparent buffer */
if (!transparent) {
/* If we're supposed to use DirectColor visuals, and we've got the
EXT_visual_info extension, then add GLX_X_VISUAL_TYPE_EXT. */
if (X11_UseDirectColorVisuals() && _this->gl_data->HAS_GLX_EXT_visual_info) {
pvistypeattr = &attribs[i];
attribs[i++] = GLX_X_VISUAL_TYPE_EXT;
attribs[i++] = GLX_DIRECT_COLOR_EXT;
}
}
attribs[i++] = None;
SDL_assert(i <= MAX_ATTRIBUTES);
if (_pvistypeattr) {
*_pvistypeattr = pvistypeattr;
}
return i;
}
XVisualInfo *X11_GL_GetVisual(SDL_VideoDevice *_this, Display *display, int screen, SDL_bool transparent)
{
/* 64 seems nice. */
int attribs[64];
XVisualInfo *vinfo = NULL;
int *pvistypeattr = NULL;
if (!_this->gl_data) {
/* The OpenGL library wasn't loaded, SDL_GetError() should have info */
return NULL;
}
if (_this->gl_data->glXChooseFBConfig &&
_this->gl_data->glXGetVisualFromFBConfig) {
GLXFBConfig *framebuffer_config = NULL;
int fbcount = 0;
X11_GL_GetAttributes(_this, display, screen, attribs, 64, SDL_TRUE, &pvistypeattr, transparent);
framebuffer_config = _this->gl_data->glXChooseFBConfig(display, screen, attribs, &fbcount);
if (!framebuffer_config && (pvistypeattr != NULL)) {
*pvistypeattr = None;
framebuffer_config = _this->gl_data->glXChooseFBConfig(display, screen, attribs, &fbcount);
}
if (transparent) {
/* Return the first transparent Visual */
int i;
for (i = 0; i < fbcount; i++) {
Uint32 format;
vinfo = _this->gl_data->glXGetVisualFromFBConfig(display, framebuffer_config[i]);
format = X11_GetPixelFormatFromVisualInfo(display, vinfo);
if (SDL_ISPIXELFORMAT_ALPHA(format)) { /* found! */
X11_XFree(framebuffer_config);
framebuffer_config = NULL;
break;
}
X11_XFree(vinfo);
vinfo = NULL;
}
}
if (framebuffer_config) {
vinfo = _this->gl_data->glXGetVisualFromFBConfig(display, framebuffer_config[0]);
}
X11_XFree(framebuffer_config);
}
if (!vinfo) {
X11_GL_GetAttributes(_this, display, screen, attribs, 64, SDL_FALSE, &pvistypeattr, transparent);
vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
if (!vinfo && (pvistypeattr != NULL)) {
*pvistypeattr = None;
vinfo = _this->gl_data->glXChooseVisual(display, screen, attribs);
}
}
if (!vinfo) {
SDL_SetError("Couldn't find matching GLX visual");
}
return vinfo;
}
static int (*handler)(Display *, XErrorEvent *) = NULL;
static const char *errorHandlerOperation = NULL;
static int errorBase = 0;
static int errorCode = 0;
static int X11_GL_ErrorHandler(Display *d, XErrorEvent *e)
{
char *x11_error = NULL;
char x11_error_locale[256];
errorCode = e->error_code;
if (X11_XGetErrorText(d, errorCode, x11_error_locale, sizeof(x11_error_locale)) == Success) {
x11_error = SDL_iconv_string("UTF-8", "", x11_error_locale, SDL_strlen(x11_error_locale) + 1);
}
if (x11_error) {
SDL_SetError("Could not %s: %s", errorHandlerOperation, x11_error);
SDL_free(x11_error);
} else {
SDL_SetError("Could not %s: %i (Base %i)", errorHandlerOperation, errorCode, errorBase);
}
return (0);
}
SDL_bool X11_GL_UseEGL(SDL_VideoDevice *_this)
{
SDL_assert(_this->gl_data != NULL);
if (SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, SDL_FALSE)) {
/* use of EGL has been requested, even for desktop GL */
return SDL_TRUE;
}
SDL_assert(_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES);
return (SDL_GetHintBoolean(SDL_HINT_OPENGL_ES_DRIVER, SDL_FALSE) || _this->gl_config.major_version == 1 /* No GLX extension for OpenGL ES 1.x profiles. */
|| _this->gl_config.major_version > _this->gl_data->es_profile_max_supported_version.major || (_this->gl_config.major_version == _this->gl_data->es_profile_max_supported_version.major && _this->gl_config.minor_version > _this->gl_data->es_profile_max_supported_version.minor));
}
SDL_GLContext X11_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
Display *display = data->videodata->display;
int screen = SDL_GetDisplayDriverDataForWindow(window)->screen;
XWindowAttributes xattr;
XVisualInfo v, *vinfo;
int n;
GLXContext context = NULL, share_context;
const int transparent = (window->flags & SDL_WINDOW_TRANSPARENT) ? SDL_TRUE : SDL_FALSE;
if (_this->gl_config.share_with_current_context) {
share_context = (GLXContext)SDL_GL_GetCurrentContext();
} else {
share_context = NULL;
}
/* We do this to create a clean separation between X and GLX errors. */
X11_XSync(display, False);
errorHandlerOperation = "create GL context";
errorBase = _this->gl_data->errorBase;
errorCode = Success;
handler = X11_XSetErrorHandler(X11_GL_ErrorHandler);
X11_XGetWindowAttributes(display, data->xwindow, &xattr);
v.screen = screen;
v.visualid = X11_XVisualIDFromVisual(xattr.visual);
vinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &v, &n);
if (vinfo) {
if (_this->gl_config.major_version < 3 &&
_this->gl_config.profile_mask == 0 &&
_this->gl_config.flags == 0 && !transparent) {
/* Create legacy context */
context =
_this->gl_data->glXCreateContext(display, vinfo, share_context, True);
} else {
/* max 14 attributes plus terminator */
int attribs[15] = {
GLX_CONTEXT_MAJOR_VERSION_ARB,
_this->gl_config.major_version,
GLX_CONTEXT_MINOR_VERSION_ARB,
_this->gl_config.minor_version,
0
};
int iattr = 4;
/* SDL profile bits match GLX profile bits */
if (_this->gl_config.profile_mask != 0) {
attribs[iattr++] = GLX_CONTEXT_PROFILE_MASK_ARB;
attribs[iattr++] = _this->gl_config.profile_mask;
}
/* SDL flags match GLX flags */
if (_this->gl_config.flags != 0) {
attribs[iattr++] = GLX_CONTEXT_FLAGS_ARB;
attribs[iattr++] = _this->gl_config.flags;
}
/* only set if glx extension is available and not the default setting */
if ((_this->gl_data->HAS_GLX_ARB_context_flush_control) && (_this->gl_config.release_behavior == 0)) {
attribs[iattr++] = GLX_CONTEXT_RELEASE_BEHAVIOR_ARB;
attribs[iattr++] =
_this->gl_config.release_behavior ? GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB : GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB;
}
/* only set if glx extension is available and not the default setting */
if ((_this->gl_data->HAS_GLX_ARB_create_context_robustness) && (_this->gl_config.reset_notification != 0)) {
attribs[iattr++] = GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB;
attribs[iattr++] =
_this->gl_config.reset_notification ? GLX_LOSE_CONTEXT_ON_RESET_ARB : GLX_NO_RESET_NOTIFICATION_ARB;
}
/* only set if glx extension is available and not the default setting */
if ((_this->gl_data->HAS_GLX_ARB_create_context_no_error) && (_this->gl_config.no_error != 0)) {
attribs[iattr++] = GLX_CONTEXT_OPENGL_NO_ERROR_ARB;
attribs[iattr++] = _this->gl_config.no_error;
}
attribs[iattr++] = 0;
/* Get a pointer to the context creation function for GL 3.0 */
if (!_this->gl_data->glXCreateContextAttribsARB) {
SDL_SetError("OpenGL 3.0 and later are not supported by this system");
} else {
int glxAttribs[64];
/* Create a GL 3.x context */
GLXFBConfig *framebuffer_config = NULL;
int fbcount = 0;
int *pvistypeattr = NULL;
X11_GL_GetAttributes(_this, display, screen, glxAttribs, 64, SDL_TRUE, &pvistypeattr, transparent);
if (_this->gl_data->glXChooseFBConfig) {
framebuffer_config = _this->gl_data->glXChooseFBConfig(display,
DefaultScreen(display), glxAttribs,
&fbcount);
if (!framebuffer_config && (pvistypeattr != NULL)) {
*pvistypeattr = None;
framebuffer_config = _this->gl_data->glXChooseFBConfig(display,
DefaultScreen(display), glxAttribs,
&fbcount);
}
if (framebuffer_config) {
context = _this->gl_data->glXCreateContextAttribsARB(display,
framebuffer_config[0],
share_context, True, attribs);
X11_XFree(framebuffer_config);
}
}
}
}
X11_XFree(vinfo);
}
X11_XSync(display, False);
X11_XSetErrorHandler(handler);
if (!context) {
if (errorCode == Success) {
SDL_SetError("Could not create GL context");
}
return NULL;
}
if (X11_GL_MakeCurrent(_this, window, context) < 0) {
X11_GL_DeleteContext(_this, context);
return NULL;
}
return context;
}
int X11_GL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context)
{
Display *display = _this->driverdata->display;
Window drawable =
(context ? window->driverdata->xwindow : None);
GLXContext glx_context = (GLXContext)context;
int rc;
if (!_this->gl_data) {
return SDL_SetError("OpenGL not initialized");
}
/* We do this to create a clean separation between X and GLX errors. */
X11_XSync(display, False);
errorHandlerOperation = "make GL context current";
errorBase = _this->gl_data->errorBase;
errorCode = Success;
handler = X11_XSetErrorHandler(X11_GL_ErrorHandler);
rc = _this->gl_data->glXMakeCurrent(display, drawable, glx_context);
X11_XSetErrorHandler(handler);
if (errorCode != Success) { /* uhoh, an X error was thrown! */
return -1; /* the error handler called SDL_SetError() already. */
} else if (!rc) { /* glXMakeCurrent() failed without throwing an X error */
return SDL_SetError("Unable to make GL context current");
}
return 0;
}
/*
0 is a valid argument to glXSwapInterval(MESA|EXT) and setting it to 0
will undo the effect of a previous call with a value that is greater
than zero (or at least that is what the docs say). OTOH, 0 is an invalid
argument to glXSwapIntervalSGI and it returns an error if you call it
with 0 as an argument.
*/
static int swapinterval = 0;
int X11_GL_SetSwapInterval(SDL_VideoDevice *_this, int interval)
{
int status = -1;
if ((interval < 0) && (!_this->gl_data->HAS_GLX_EXT_swap_control_tear)) {
return SDL_SetError("Negative swap interval unsupported in this GL");
} else if (_this->gl_data->glXSwapIntervalEXT) {
Display *display = _this->driverdata->display;
const SDL_WindowData *windowdata = SDL_GL_GetCurrentWindow()->driverdata;
Window drawable = windowdata->xwindow;
/*
* This is a workaround for a bug in NVIDIA drivers. Bug has been reported
* and will be fixed in a future release (probably 319.xx).
*
* There's a bug where glXSetSwapIntervalEXT ignores updates because
* it has the wrong value cached. To work around it, we just run a no-op
* update to the current value.
*/
int currentInterval = 0;
X11_GL_GetSwapInterval(_this, &currentInterval);
_this->gl_data->glXSwapIntervalEXT(display, drawable, currentInterval);
_this->gl_data->glXSwapIntervalEXT(display, drawable, interval);
status = 0;
swapinterval = interval;
} else if (_this->gl_data->glXSwapIntervalMESA) {
status = _this->gl_data->glXSwapIntervalMESA(interval);
if (status != 0) {
SDL_SetError("glXSwapIntervalMESA failed");
} else {
swapinterval = interval;
}
} else if (_this->gl_data->glXSwapIntervalSGI) {
status = _this->gl_data->glXSwapIntervalSGI(interval);
if (status != 0) {
SDL_SetError("glXSwapIntervalSGI failed");
} else {
swapinterval = interval;
}
} else {
return SDL_Unsupported();
}
return status;
}
int X11_GL_GetSwapInterval(SDL_VideoDevice *_this, int *interval)
{
if (_this->gl_data->glXSwapIntervalEXT) {
Display *display = _this->driverdata->display;
const SDL_WindowData *windowdata = SDL_GL_GetCurrentWindow()->driverdata;
Window drawable = windowdata->xwindow;
unsigned int allow_late_swap_tearing = 0;
unsigned int val = 0;
if (_this->gl_data->HAS_GLX_EXT_swap_control_tear) {
_this->gl_data->glXQueryDrawable(display, drawable,
GLX_LATE_SWAPS_TEAR_EXT,
&allow_late_swap_tearing);
}
_this->gl_data->glXQueryDrawable(display, drawable,
GLX_SWAP_INTERVAL_EXT, &val);
if ((allow_late_swap_tearing) && (val > 0)) {
*interval = -((int)val);
return 0;
}
*interval = (int)val;
return 0;
} else if (_this->gl_data->glXGetSwapIntervalMESA) {
int val = _this->gl_data->glXGetSwapIntervalMESA();
if (val == GLX_BAD_CONTEXT) {
return SDL_SetError("GLX_BAD_CONTEXT");
}
*interval = val;
return 0;
} else {
*interval = swapinterval;
return 0;
}
}
int X11_GL_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
Display *display = data->videodata->display;
_this->gl_data->glXSwapBuffers(display, data->xwindow);
return 0;
}
int X11_GL_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context)
{
Display *display = _this->driverdata->display;
GLXContext glx_context = (GLXContext)context;
if (!_this->gl_data) {
return 0;
}
_this->gl_data->glXDestroyContext(display, glx_context);
X11_XSync(display, False);
return 0;
}
#endif /* SDL_VIDEO_OPENGL_GLX */
#endif /* SDL_VIDEO_DRIVER_X11 */

View File

@ -0,0 +1,86 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_x11opengl_h_
#define SDL_x11opengl_h_
#ifdef SDL_VIDEO_OPENGL_GLX
#include <SDL3/SDL_opengl.h>
#include <GL/glx.h>
typedef void (*__GLXextFuncPtr)(void);
struct SDL_GLDriverData
{
int errorBase, eventBase;
SDL_bool HAS_GLX_EXT_visual_rating;
SDL_bool HAS_GLX_EXT_visual_info;
SDL_bool HAS_GLX_EXT_swap_control_tear;
SDL_bool HAS_GLX_ARB_context_flush_control;
SDL_bool HAS_GLX_ARB_create_context_robustness;
SDL_bool HAS_GLX_ARB_create_context_no_error;
/* Max version of OpenGL ES context that can be created if the
implementation supports GLX_EXT_create_context_es2_profile.
major = minor = 0 when unsupported.
*/
struct
{
int major;
int minor;
} es_profile_max_supported_version;
Bool (*glXQueryExtension)(Display *, int *, int *);
__GLXextFuncPtr (*glXGetProcAddress)(const GLubyte *);
XVisualInfo *(*glXChooseVisual)(Display *, int, int *);
GLXContext (*glXCreateContext)(Display *, XVisualInfo *, GLXContext, Bool);
GLXContext (*glXCreateContextAttribsARB)(Display *, GLXFBConfig, GLXContext, Bool, const int *);
GLXFBConfig *(*glXChooseFBConfig)(Display *, int, const int *, int *);
XVisualInfo *(*glXGetVisualFromFBConfig)(Display *, GLXFBConfig);
void (*glXDestroyContext)(Display *, GLXContext);
Bool (*glXMakeCurrent)(Display *, GLXDrawable, GLXContext);
void (*glXSwapBuffers)(Display *, GLXDrawable);
void (*glXQueryDrawable)(Display *, GLXDrawable, int, unsigned int *);
void (*glXSwapIntervalEXT)(Display *, GLXDrawable, int);
int (*glXSwapIntervalSGI)(int);
int (*glXSwapIntervalMESA)(int);
int (*glXGetSwapIntervalMESA)(void);
};
/* OpenGL functions */
extern int X11_GL_LoadLibrary(SDL_VideoDevice *_this, const char *path);
extern SDL_FunctionPointer X11_GL_GetProcAddress(SDL_VideoDevice *_this, const char *proc);
extern void X11_GL_UnloadLibrary(SDL_VideoDevice *_this);
extern SDL_bool X11_GL_UseEGL(SDL_VideoDevice *_this);
extern XVisualInfo *X11_GL_GetVisual(SDL_VideoDevice *_this, Display *display, int screen, SDL_bool transparent);
extern SDL_GLContext X11_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
extern int X11_GL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window,
SDL_GLContext context);
extern int X11_GL_SetSwapInterval(SDL_VideoDevice *_this, int interval);
extern int X11_GL_GetSwapInterval(SDL_VideoDevice *_this, int *interval);
extern int X11_GL_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern int X11_GL_DeleteContext(SDL_VideoDevice *_this, SDL_GLContext context);
#endif /* SDL_VIDEO_OPENGL_GLX */
#endif /* SDL_x11opengl_h_ */

View File

@ -0,0 +1,129 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_DRIVER_X11) && defined(SDL_VIDEO_OPENGL_EGL)
#include "SDL_x11video.h"
#include "SDL_x11opengles.h"
#include "SDL_x11opengl.h"
/* EGL implementation of SDL OpenGL support */
int X11_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path)
{
SDL_VideoData *data = _this->driverdata;
/* If the profile requested is not GL ES, switch over to X11_GL functions */
if ((_this->gl_config.profile_mask != SDL_GL_CONTEXT_PROFILE_ES) &&
!SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, SDL_FALSE)) {
#ifdef SDL_VIDEO_OPENGL_GLX
X11_GLES_UnloadLibrary(_this);
_this->GL_LoadLibrary = X11_GL_LoadLibrary;
_this->GL_GetProcAddress = X11_GL_GetProcAddress;
_this->GL_UnloadLibrary = X11_GL_UnloadLibrary;
_this->GL_CreateContext = X11_GL_CreateContext;
_this->GL_MakeCurrent = X11_GL_MakeCurrent;
_this->GL_SetSwapInterval = X11_GL_SetSwapInterval;
_this->GL_GetSwapInterval = X11_GL_GetSwapInterval;
_this->GL_SwapWindow = X11_GL_SwapWindow;
_this->GL_DeleteContext = X11_GL_DeleteContext;
return X11_GL_LoadLibrary(_this, path);
#else
return SDL_SetError("SDL not configured with OpenGL/GLX support");
#endif
}
return SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType)data->display, _this->gl_config.egl_platform);
}
XVisualInfo *X11_GLES_GetVisual(SDL_VideoDevice *_this, Display *display, int screen, SDL_bool transparent)
{
XVisualInfo *egl_visualinfo = NULL;
EGLint visual_id;
XVisualInfo vi_in;
int out_count;
if (!_this->egl_data) {
/* The EGL library wasn't loaded, SDL_GetError() should have info */
return NULL;
}
if (_this->egl_data->eglGetConfigAttrib(_this->egl_data->egl_display,
_this->egl_data->egl_config,
EGL_NATIVE_VISUAL_ID,
&visual_id) == EGL_FALSE ||
!visual_id) {
/* Use the default visual when all else fails */
vi_in.screen = screen;
egl_visualinfo = X11_XGetVisualInfo(display,
VisualScreenMask,
&vi_in, &out_count);
/* Return the first transparent Visual */
if (transparent) {
int i;
for (i = 0; i < out_count; i++) {
XVisualInfo *v = &egl_visualinfo[i];
Uint32 format = X11_GetPixelFormatFromVisualInfo(display, v);
if (SDL_ISPIXELFORMAT_ALPHA(format)) { /* found! */
/* re-request it to have a copy that can be X11_XFree'ed later */
vi_in.screen = screen;
vi_in.visualid = v->visualid;
X11_XFree(egl_visualinfo);
egl_visualinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &vi_in, &out_count);
return egl_visualinfo;
}
}
}
} else {
vi_in.screen = screen;
vi_in.visualid = visual_id;
egl_visualinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &vi_in, &out_count);
}
return egl_visualinfo;
}
SDL_GLContext X11_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_GLContext context;
SDL_WindowData *data = window->driverdata;
Display *display = data->videodata->display;
X11_XSync(display, False);
context = SDL_EGL_CreateContext(_this, data->egl_surface);
X11_XSync(display, False);
return context;
}
SDL_EGLSurface X11_GLES_GetEGLSurface(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
return data->egl_surface;
}
SDL_EGL_SwapWindow_impl(X11)
SDL_EGL_MakeCurrent_impl(X11)
#endif /* SDL_VIDEO_DRIVER_X11 && SDL_VIDEO_OPENGL_EGL */

View File

@ -0,0 +1,55 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_x11opengles_h_
#define SDL_x11opengles_h_
#ifdef SDL_VIDEO_OPENGL_EGL
#include "../SDL_sysvideo.h"
#include "../SDL_egl_c.h"
typedef struct SDL_PrivateGLESData
{
/* 1401 If the struct-declaration-list contains no named members, the behavior is undefined. */
/* warning: empty struct has size 0 in C, size 1 in C++ [-Wc++-compat] */
int dummy;
} SDL_PrivateGLESData;
/* OpenGLES functions */
#define X11_GLES_GetAttribute SDL_EGL_GetAttribute
#define X11_GLES_GetProcAddress SDL_EGL_GetProcAddressInternal
#define X11_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
#define X11_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
#define X11_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
#define X11_GLES_DeleteContext SDL_EGL_DeleteContext
extern int X11_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path);
extern XVisualInfo *X11_GLES_GetVisual(SDL_VideoDevice *_this, Display *display, int screen, SDL_bool transparent);
extern SDL_GLContext X11_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
extern int X11_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern int X11_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context);
extern SDL_EGLSurface X11_GLES_GetEGLSurface(SDL_VideoDevice *_this, SDL_Window *window);
#endif /* SDL_VIDEO_OPENGL_EGL */
#endif /* SDL_x11opengles_h_ */

View File

@ -0,0 +1,98 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_X11
#include "SDL_x11video.h"
#include "SDL_x11shape.h"
#include "SDL_x11window.h"
#include "../SDL_shape_internals.h"
SDL_WindowShaper *X11_CreateShaper(SDL_Window *window)
{
SDL_WindowShaper *result = NULL;
#ifdef SDL_VIDEO_DRIVER_X11_XSHAPE
SDL_ShapeData *data = NULL;
if (SDL_X11_HAVE_XSHAPE) { /* Make sure X server supports it. */
result = SDL_malloc(sizeof(SDL_WindowShaper));
if (result == NULL) {
SDL_OutOfMemory();
return NULL;
}
result->window = window;
result->mode.mode = ShapeModeDefault;
result->mode.parameters.binarizationCutoff = 1;
data = SDL_malloc(sizeof(SDL_ShapeData));
if (data == NULL) {
SDL_free(result);
SDL_OutOfMemory();
return NULL;
}
result->driverdata = data;
data->bitmapsize = 0;
data->bitmap = NULL;
window->shaper = result;
}
#endif
return result;
}
int X11_SetWindowShape(SDL_WindowShaper *shaper, SDL_Surface *shape, SDL_WindowShapeMode *shape_mode)
{
#ifdef SDL_VIDEO_DRIVER_X11_XSHAPE
SDL_ShapeData *data = NULL;
SDL_WindowData *windowdata = NULL;
Pixmap shapemask;
#endif
if (shaper == NULL || shape == NULL || shaper->driverdata == NULL) {
return -1;
}
#ifdef SDL_VIDEO_DRIVER_X11_XSHAPE
if (shape->format->Amask == 0 && SDL_SHAPEMODEALPHA(shape_mode->mode)) {
return -2;
}
if (shape->w != shaper->window->w || shape->h != shaper->window->h) {
return -3;
}
data = shaper->driverdata;
/* Assume that shaper->alphacutoff already has a value, because SDL_SetWindowShape() should have given it one. */
SDL_CalculateShapeBitmap(shaper->mode, shape, data->bitmap, 8);
windowdata = shaper->window->driverdata;
shapemask = X11_XCreateBitmapFromData(windowdata->videodata->display, windowdata->xwindow, data->bitmap, shaper->window->w, shaper->window->h);
X11_XShapeCombineMask(windowdata->videodata->display, windowdata->xwindow, ShapeBounding, 0, 0, shapemask, ShapeSet);
X11_XSync(windowdata->videodata->display, False);
X11_XFreePixmap(windowdata->videodata->display, shapemask);
#endif
return 0;
}
#endif /* SDL_VIDEO_DRIVER_X11 */

View File

@ -0,0 +1,37 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_x11shape_h_
#define SDL_x11shape_h_
#include "../SDL_sysvideo.h"
typedef struct
{
void *bitmap;
Uint32 bitmapsize;
} SDL_ShapeData;
extern SDL_WindowShaper *X11_CreateShaper(SDL_Window *window);
extern int X11_SetWindowShape(SDL_WindowShaper *shaper, SDL_Surface *shape, SDL_WindowShapeMode *shape_mode);
#endif /* SDL_x11shape_h_ */

View File

@ -0,0 +1,333 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/* *INDENT-OFF* */ /* clang-format off */
#ifndef SDL_X11_MODULE
#define SDL_X11_MODULE(modname)
#endif
#ifndef SDL_X11_SYM
#define SDL_X11_SYM(rc,fn,params,args,ret)
#endif
SDL_X11_MODULE(BASEXLIB)
SDL_X11_SYM(XSizeHints*,XAllocSizeHints,(void),(),return)
SDL_X11_SYM(XWMHints*,XAllocWMHints,(void),(),return)
SDL_X11_SYM(XClassHint*,XAllocClassHint,(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(Bool,XCheckIfEvent,(Display* a,XEvent *b,Bool (*c)(Display*,XEvent*,XPointer),XPointer d),(a,b,c,d),return)
SDL_X11_SYM(int,XClearWindow,(Display* a,Window b),(a,b),return)
SDL_X11_SYM(int,XCloseDisplay,(Display* a),(a),return)
SDL_X11_SYM(int,XConvertSelection,(Display* a,Atom b,Atom c,Atom d,Window e,Time f),(a,b,c,d,e,f),return)
SDL_X11_SYM(Pixmap,XCreateBitmapFromData,(Display *dpy,Drawable d,_Xconst char *data,unsigned int width,unsigned int height),(dpy,d,data,width,height),return)
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(Cursor,XCreateFontCursor,(Display* a,unsigned int b),(a,b),return)
SDL_X11_SYM(XFontSet,XCreateFontSet,(Display* a, _Xconst char* b, char*** c, int* d, char** e),(a,b,c,d,e),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(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(int,XDisplayKeycodes,(Display* a,int* b,int* c),(a,b,c),return)
SDL_X11_SYM(int,XDrawRectangle,(Display* a,Drawable b,GC c,int d,int e,unsigned int f,unsigned int g),(a,b,c,d,e,f,g),return)
SDL_X11_SYM(char*,XDisplayName,(_Xconst char* a),(a),return)
SDL_X11_SYM(int,XDrawString,(Display* a,Drawable b,GC c,int d,int e,_Xconst char* f,int g),(a,b,c,d,e,f,g),return)
SDL_X11_SYM(int,XEventsQueued,(Display* a,int b),(a,b),return)
SDL_X11_SYM(int,XFillRectangle,(Display* a,Drawable b,GC c,int d,int e,unsigned int f,unsigned int g),(a,b,c,d,e,f,g),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,XFreeCursor,(Display* a,Cursor b),(a,b),return)
SDL_X11_SYM(void,XFreeFontSet,(Display* a, XFontSet b),(a,b),)
SDL_X11_SYM(int,XFreeGC,(Display* a,GC b),(a,b),return)
SDL_X11_SYM(int,XFreeFont,(Display* a, XFontStruct* 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(void,XFreeStringList,(char** a),(a),)
SDL_X11_SYM(char*,XGetAtomName,(Display *a,Atom b),(a,b),return)
SDL_X11_SYM(int,XGetInputFocus,(Display *a,Window *b,int *c),(a,b,c),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(Window,XGetSelectionOwner,(Display* a,Atom b),(a,b),return)
SDL_X11_SYM(XVisualInfo*,XGetVisualInfo,(Display* a,long b,XVisualInfo* c,int* d),(a,b,c,d),return)
SDL_X11_SYM(Status,XGetWindowAttributes,(Display* a,Window b,XWindowAttributes* c),(a,b,c),return)
SDL_X11_SYM(int,XGetWindowProperty,(Display* a,Window b,Atom c,long d,long e,Bool f,Atom g,Atom* h,int* i,unsigned long* j,unsigned long *k,unsigned char **l),(a,b,c,d,e,f,g,h,i,j,k,l),return)
SDL_X11_SYM(XWMHints*,XGetWMHints,(Display* a,Window b),(a,b),return)
SDL_X11_SYM(Status,XGetWMNormalHints,(Display *a,Window b, XSizeHints *c, long *d),(a,b,c,d),return)
SDL_X11_SYM(int,XIfEvent,(Display* a,XEvent *b,Bool (*c)(Display*,XEvent*,XPointer),XPointer d),(a,b,c,d),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(int,XGrabServer,(Display* a),(a),return)
SDL_X11_SYM(Status,XIconifyWindow,(Display* a,Window b,int c),(a,b,c),return)
SDL_X11_SYM(KeyCode,XKeysymToKeycode,(Display* a,KeySym b),(a,b),return)
SDL_X11_SYM(char*,XKeysymToString,(KeySym a),(a),return)
SDL_X11_SYM(int,XInstallColormap,(Display* a,Colormap b),(a,b),return)
SDL_X11_SYM(Atom,XInternAtom,(Display* a,_Xconst char* b,Bool c),(a,b,c),return)
SDL_X11_SYM(XPixmapFormatValues*,XListPixmapFormats,(Display* a,int* b),(a,b),return)
SDL_X11_SYM(XFontStruct*,XLoadQueryFont,(Display* a,_Xconst char* b),(a,b),return)
SDL_X11_SYM(KeySym,XLookupKeysym,(XKeyEvent* 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(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,XMoveWindow,(Display* a,Window b,int c,int d),(a,b,c,d),return)
SDL_X11_SYM(Display*,XOpenDisplay,(_Xconst char* a),(a),return)
SDL_X11_SYM(Status,XInitThreads,(void),(),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,XQueryKeymap,(Display* a,char *b),(a,b),return)
SDL_X11_SYM(Bool,XQueryPointer,(Display* a,Window b,Window* c,Window* d,int* e,int* f,int* g,int* h,unsigned int* i),(a,b,c,d,e,f,g,h,i),return)
SDL_X11_SYM(int,XRaiseWindow,(Display* a,Window b),(a,b),return)
SDL_X11_SYM(int,XReparentWindow,(Display* a,Window b,Window c,int d,int e),(a,b,c,d,e),return)
SDL_X11_SYM(int,XResetScreenSaver,(Display* a),(a),return)
SDL_X11_SYM(int,XResizeWindow,(Display* a,Window b,unsigned int c,unsigned int d),(a,b,c,d),return)
SDL_X11_SYM(int,XScreenNumberOfScreen,(Screen* a),(a),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(XErrorHandler,XSetErrorHandler,(XErrorHandler a),(a),return)
SDL_X11_SYM(int,XSetForeground,(Display* a,GC b,unsigned long c),(a,b,c),return)
SDL_X11_SYM(XIOErrorHandler,XSetIOErrorHandler,(XIOErrorHandler a),(a),return)
SDL_X11_SYM(int,XSetInputFocus,(Display *a,Window b,int c,Time d),(a,b,c,d),return)
SDL_X11_SYM(int,XSetSelectionOwner,(Display* a,Atom b,Window c,Time d),(a,b,c,d),return)
SDL_X11_SYM(int,XSetTransientForHint,(Display* a,Window b,Window c),(a,b,c),return)
SDL_X11_SYM(void,XSetTextProperty,(Display* a,Window b,XTextProperty* c,Atom d),(a,b,c,d),)
SDL_X11_SYM(int,XSetWindowBackground,(Display* a,Window b,unsigned long c),(a,b,c),return)
SDL_X11_SYM(void,XSetWMHints,(Display* a,Window b,XWMHints* c),(a,b,c),)
SDL_X11_SYM(void,XSetWMNormalHints,(Display* a,Window b,XSizeHints* c),(a,b,c),)
SDL_X11_SYM(void,XSetWMProperties,(Display* a,Window b,XTextProperty* c,XTextProperty* d,char** e,int f,XSizeHints* g,XWMHints* h,XClassHint* i),(a,b,c,d,e,f,g,h,i),)
SDL_X11_SYM(Status,XSetWMProtocols,(Display* a,Window b,Atom* c,int d),(a,b,c,d),return)
SDL_X11_SYM(int,XStoreColors,(Display* a,Colormap b,XColor* c,int d),(a,b,c,d),return)
SDL_X11_SYM(int,XStoreName,(Display* a,Window b,_Xconst char* c),(a,b,c),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,XTextExtents,(XFontStruct* a,_Xconst char* b,int c,int* d,int* e,int* f,XCharStruct* g),(a,b,c,d,e,f,g),return)
SDL_X11_SYM(Bool,XTranslateCoordinates,(Display *a,Window b,Window c,int d,int e,int* f,int* g,Window* h),(a,b,c,d,e,f,g,h),return)
SDL_X11_SYM(int,XUndefineCursor,(Display* a,Window 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,XUngrabServer,(Display* a),(a),return)
SDL_X11_SYM(int,XUninstallColormap,(Display* a,Colormap b),(a,b),return)
SDL_X11_SYM(int,XUnloadFont,(Display* a,Font 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(int,XWindowEvent,(Display* a,Window b,long c,XEvent* d),(a,b,c,d),return)
SDL_X11_SYM(Status,XWithdrawWindow,(Display* a,Window b,int c),(a,b,c),return)
SDL_X11_SYM(VisualID,XVisualIDFromVisual,(Visual* a),(a),return)
SDL_X11_SYM(char*,XGetDefault,(Display* a,_Xconst char* b, _Xconst char* c),(a,b,c),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(void,XRefreshKeyboardMapping,(XMappingEvent *a),(a),)
SDL_X11_SYM(int,XQueryTree,(Display* a,Window b,Window* c,Window* d,Window** e,unsigned int* f),(a,b,c,d,e,f),return)
SDL_X11_SYM(Bool,XSupportsLocale,(void),(),return)
SDL_X11_SYM(Status,XmbTextListToTextProperty,(Display* a,char** b,int c,XICCEncodingStyle d,XTextProperty* e),(a,b,c,d,e),return)
SDL_X11_SYM(Region,XCreateRegion,(void),(),return)
SDL_X11_SYM(void,XDestroyRegion,(Region),(a),)
SDL_X11_SYM(void,XrmInitialize,(),(),)
SDL_X11_SYM(char*,XResourceManagerString,(Display *display),(display),)
SDL_X11_SYM(XrmDatabase,XrmGetStringDatabase,(char *data),(data),)
SDL_X11_SYM(void,XrmDestroyDatabase,(XrmDatabase db),(db),)
SDL_X11_SYM(Bool,XrmGetResource,(XrmDatabase db, char* str_name, char* str_class, char **str_type_return, XrmValue *),(db, str_name, str_class,str_type_return,value_return),)
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
SDL_X11_MODULE(XFIXES)
SDL_X11_SYM(PointerBarrier, XFixesCreatePointerBarrier, (Display* a, Window b, int c, int d, int e, int f, int g, int h, int *i),(a,b,c,d,e,f,g,h,i),return)
SDL_X11_SYM(void, XFixesDestroyPointerBarrier, (Display* a, PointerBarrier b), (a,b),)
SDL_X11_SYM(int, XIBarrierReleasePointer,(Display* a, int b, PointerBarrier c, BarrierEventID d), (a,b,c,d), return) /* this is actually Xinput2 */
SDL_X11_SYM(Status, XFixesQueryVersion,(Display* a, int* b, int* c), (a,b,c), return)
SDL_X11_SYM(Status, XFixesSelectSelectionInput, (Display* a, Window b, Atom c, unsigned long d), (a,b,c,d), return)
#endif
#ifdef SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
SDL_X11_SYM(Bool,XGetEventData,(Display* a,XGenericEventCookie* b),(a,b),return)
SDL_X11_SYM(void,XFreeEventData,(Display* a,XGenericEventCookie* b),(a,b),)
#endif
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
SDL_X11_SYM(Bool,XkbQueryExtension,(Display* a,int * b,int * c,int * d,int * e, int *f),(a,b,c,d,e,f),return)
#if NeedWidePrototypes
SDL_X11_SYM(KeySym,XkbKeycodeToKeysym,(Display* a,unsigned int b,int c,int d),(a,b,c,d),return)
#else
SDL_X11_SYM(KeySym,XkbKeycodeToKeysym,(Display* a,KeyCode b,int c,int d),(a,b,c,d),return)
#endif
SDL_X11_SYM(Status,XkbGetState,(Display* a,unsigned int b,XkbStatePtr c),(a,b,c),return)
SDL_X11_SYM(Status,XkbGetUpdatedMap,(Display* a,unsigned int b,XkbDescPtr c),(a,b,c),return)
SDL_X11_SYM(XkbDescPtr,XkbGetMap,(Display* a,unsigned int b,unsigned int c),(a,b,c),return)
SDL_X11_SYM(void,XkbFreeClientMap,(XkbDescPtr a,unsigned int b, Bool c),(a,b,c),)
SDL_X11_SYM(void,XkbFreeKeyboard,(XkbDescPtr a,unsigned int b, Bool c),(a,b,c),)
SDL_X11_SYM(Bool,XkbSetDetectableAutoRepeat,(Display* a, Bool b, Bool* c),(a,b,c),return)
#endif
#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(char*,XGetICValues,(XIC, ...),return) !!! ARGH! */
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)
SDL_X11_SYM(void,Xutf8DrawString,(Display *a, Drawable b, XFontSet c, GC d, int e, int f, _Xconst char *g, int h),(a,b,c,d,e,f,g,h),)
SDL_X11_SYM(int,Xutf8TextExtents,(XFontSet a, _Xconst char* b, int c, XRectangle* d, XRectangle* e),(a,b,c,d,e),return)
SDL_X11_SYM(char*,XSetLocaleModifiers,(const char *a),(a),return)
SDL_X11_SYM(char*,Xutf8ResetIC,(XIC 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(Pixmap,XShmCreatePixmap,(Display *a,Drawable b,char* c,XShmSegmentInfo* d, unsigned int e, unsigned int f, unsigned int g),(a,b,c,d,e,f,g),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 _Xconst 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.
*/
#ifdef __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
/* XCursor support */
#ifdef SDL_VIDEO_DRIVER_X11_XCURSOR
SDL_X11_MODULE(XCURSOR)
SDL_X11_SYM(XcursorImage*,XcursorImageCreate,(int a,int b),(a,b),return)
SDL_X11_SYM(void,XcursorImageDestroy,(XcursorImage *a),(a),)
SDL_X11_SYM(Cursor,XcursorImageLoadCursor,(Display *a,const XcursorImage *b),(a,b),return)
#endif
/* Xdbe support */
#ifdef SDL_VIDEO_DRIVER_X11_XDBE
SDL_X11_MODULE(XDBE)
SDL_X11_SYM(Status,XdbeQueryExtension,(Display *dpy,int *major_version_return,int *minor_version_return),(dpy,major_version_return,minor_version_return),return)
SDL_X11_SYM(XdbeBackBuffer,XdbeAllocateBackBufferName,(Display *dpy,Window window,XdbeSwapAction swap_action),(dpy,window,swap_action),return)
SDL_X11_SYM(Status,XdbeDeallocateBackBufferName,(Display *dpy,XdbeBackBuffer buffer),(dpy,buffer),return)
SDL_X11_SYM(Status,XdbeSwapBuffers,(Display *dpy,XdbeSwapInfo *swap_info,int num_windows),(dpy,swap_info,num_windows),return)
SDL_X11_SYM(Status,XdbeBeginIdiom,(Display *dpy),(dpy),return)
SDL_X11_SYM(Status,XdbeEndIdiom,(Display *dpy),(dpy),return)
SDL_X11_SYM(XdbeScreenVisualInfo*,XdbeGetVisualInfo,(Display *dpy,Drawable *screen_specifiers,int *num_screens),(dpy,screen_specifiers,num_screens),return)
SDL_X11_SYM(void,XdbeFreeVisualInfo,(XdbeScreenVisualInfo *visual_info),(visual_info),)
SDL_X11_SYM(XdbeBackBufferAttributes*,XdbeGetBackBufferAttributes,(Display *dpy,XdbeBackBuffer buffer),(dpy,buffer),return)
#endif
/* XInput2 support for multiple mice, tablets, etc. */
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
SDL_X11_MODULE(XINPUT2)
SDL_X11_SYM(XIDeviceInfo*,XIQueryDevice,(Display *a,int b,int *c),(a,b,c),return)
SDL_X11_SYM(void,XIFreeDeviceInfo,(XIDeviceInfo *a),(a),)
SDL_X11_SYM(int,XISelectEvents,(Display *a,Window b,XIEventMask *c,int d),(a,b,c,d),return)
SDL_X11_SYM(int,XIGrabTouchBegin,(Display *a,int b,Window c,int d,XIEventMask *e,int f,XIGrabModifiers *g),(a,b,c,d,e,f,g),return)
SDL_X11_SYM(int,XIUngrabTouchBegin, (Display *a,int b,Window c, int d,XIGrabModifiers *e),(a, b, c, d, e),return)
SDL_X11_SYM(Status,XIQueryVersion,(Display *a,int *b,int *c),(a,b,c),return)
SDL_X11_SYM(XIEventMask*,XIGetSelectedEvents,(Display *a,Window b,int *c),(a,b,c),return)
SDL_X11_SYM(Bool,XIGetClientPointer,(Display *a,Window b,int *c),(a,b,c),return)
SDL_X11_SYM(Bool,XIWarpPointer,(Display *a,int b,Window c,Window d,double e,double f,int g,int h,double i,double j),(a,b,c,d,e,f,g,h,i,j),return)
#endif
/* XRandR support */
#ifdef 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(Bool,XRRQueryExtension,(Display *dpy,int *event_base_return,int *error_base_return),(dpy,event_base_return,error_base_return),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(short,XRRConfigCurrentRate,(XRRScreenConfiguration *config),(config),return)
SDL_X11_SYM(short *,XRRConfigRates,(XRRScreenConfiguration *config,int sizeID,int *nrates),(config,sizeID,nrates),return)
SDL_X11_SYM(XRRScreenSize *,XRRConfigSizes,(XRRScreenConfiguration *config,int *nsizes),(config,nsizes),return)
SDL_X11_SYM(Status,XRRSetScreenConfigAndRate,(Display *dpy,XRRScreenConfiguration *config,Drawable draw,int size_index,Rotation rotation,short rate,Time timestamp),(dpy,config,draw,size_index,rotation,rate,timestamp),return)
SDL_X11_SYM(void,XRRFreeScreenConfigInfo,(XRRScreenConfiguration *config),(config),)
SDL_X11_SYM(void,XRRSetScreenSize,(Display *dpy, Window window,int width, int height,int mmWidth, int mmHeight),(dpy,window,width,height,mmWidth,mmHeight),)
SDL_X11_SYM(Status,XRRGetScreenSizeRange,(Display *dpy, Window window,int *minWidth, int *minHeight, int *maxWidth, int *maxHeight),(dpy,window,minWidth,minHeight,maxWidth,maxHeight),return)
SDL_X11_SYM(XRRScreenResources *,XRRGetScreenResources,(Display *dpy, Window window),(dpy, window),return)
SDL_X11_SYM(XRRScreenResources *,XRRGetScreenResourcesCurrent,(Display *dpy, Window window),(dpy, window),return)
SDL_X11_SYM(void,XRRFreeScreenResources,(XRRScreenResources *resources),(resources),)
SDL_X11_SYM(XRROutputInfo *,XRRGetOutputInfo,(Display *dpy, XRRScreenResources *resources, RROutput output),(dpy,resources,output),return)
SDL_X11_SYM(void,XRRFreeOutputInfo,(XRROutputInfo *outputInfo),(outputInfo),)
SDL_X11_SYM(XRRCrtcInfo *,XRRGetCrtcInfo,(Display *dpy, XRRScreenResources *resources, RRCrtc crtc),(dpy,resources,crtc),return)
SDL_X11_SYM(void,XRRFreeCrtcInfo,(XRRCrtcInfo *crtcInfo),(crtcInfo),)
SDL_X11_SYM(Status,XRRSetCrtcConfig,(Display *dpy, XRRScreenResources *resources, RRCrtc crtc, Time timestamp, int x, int y, RRMode mode, Rotation rotation, RROutput *outputs, int noutputs),(dpy,resources,crtc,timestamp,x,y,mode,rotation,outputs,noutputs),return)
SDL_X11_SYM(Atom*,XRRListOutputProperties,(Display *dpy, RROutput output, int *nprop),(dpy,output,nprop),return)
SDL_X11_SYM(XRRPropertyInfo*,XRRQueryOutputProperty,(Display *dpy,RROutput output, Atom property),(dpy,output,property),return)
SDL_X11_SYM(int,XRRGetOutputProperty,(Display *dpy,RROutput output, Atom property, long offset, long length, Bool _delete, Bool pending, Atom req_type, Atom *actual_type, int *actual_format, unsigned long *nitems, unsigned long *bytes_after, unsigned char **prop),(dpy,output,property,offset,length, _delete, pending, req_type, actual_type, actual_format, nitems, bytes_after, prop),return)
SDL_X11_SYM(RROutput,XRRGetOutputPrimary,(Display *dpy,Window window),(dpy,window),return)
SDL_X11_SYM(void,XRRSelectInput,(Display *dpy, Window window, int mask),(dpy,window,mask),)
SDL_X11_SYM(Status,XRRGetCrtcTransform,(Display *dpy,RRCrtc crtc,XRRCrtcTransformAttributes **attributes),(dpy,crtc,attributes),return)
#endif
/* MIT-SCREEN-SAVER support */
#ifdef SDL_VIDEO_DRIVER_X11_XSCRNSAVER
SDL_X11_MODULE(XSS)
SDL_X11_SYM(Bool,XScreenSaverQueryExtension,(Display *dpy,int *event_base,int *error_base),(dpy,event_base,error_base),return)
SDL_X11_SYM(Status,XScreenSaverQueryVersion,(Display *dpy,int *major_versionp,int *minor_versionp),(dpy,major_versionp,minor_versionp),return)
SDL_X11_SYM(void,XScreenSaverSuspend,(Display *dpy,Bool suspend),(dpy,suspend),return)
#endif
#ifdef SDL_VIDEO_DRIVER_X11_XSHAPE
SDL_X11_MODULE(XSHAPE)
SDL_X11_SYM(void,XShapeCombineMask,(Display *dpy,Window dest,int dest_kind,int x_off,int y_off,Pixmap src,int op),(dpy,dest,dest_kind,x_off,y_off,src,op),)
SDL_X11_SYM(void,XShapeCombineRegion,(Display *a,Window b,int c,int d,int e,Region f,int g),(a,b,c,d,e,f,g),)
#endif
#undef SDL_X11_MODULE
#undef SDL_X11_SYM
/* *INDENT-ON* */ /* clang-format on */

View File

@ -0,0 +1,46 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_X11
#include "SDL_x11video.h"
#include "SDL_x11touch.h"
#include "SDL_x11xinput2.h"
#include "../../events/SDL_touch_c.h"
void X11_InitTouch(SDL_VideoDevice *_this)
{
X11_InitXinput2Multitouch(_this);
}
void X11_QuitTouch(SDL_VideoDevice *_this)
{
SDL_QuitTouch();
}
void X11_ResetTouch(SDL_VideoDevice *_this)
{
X11_QuitTouch(_this);
X11_InitTouch(_this);
}
#endif /* SDL_VIDEO_DRIVER_X11 */

View File

@ -0,0 +1,30 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_x11touch_h_
#define SDL_x11touch_h_
extern void X11_InitTouch(SDL_VideoDevice *_this);
extern void X11_QuitTouch(SDL_VideoDevice *_this);
extern void X11_ResetTouch(SDL_VideoDevice *_this);
#endif /* SDL_x11touch_h_ */

View File

@ -0,0 +1,465 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_X11
#include <unistd.h> /* For getpid() and readlink() */
#include "../SDL_sysvideo.h"
#include "../SDL_pixels_c.h"
#include "../../core/linux/SDL_system_theme.h"
#include "SDL_x11video.h"
#include "SDL_x11framebuffer.h"
#include "SDL_x11shape.h"
#include "SDL_x11touch.h"
#include "SDL_x11xinput2.h"
#include "SDL_x11xfixes.h"
#ifdef SDL_VIDEO_OPENGL_EGL
#include "SDL_x11opengles.h"
#endif
#include "SDL_x11vulkan.h"
/* Initialization/Query functions */
static int X11_VideoInit(SDL_VideoDevice *_this);
static void X11_VideoQuit(SDL_VideoDevice *_this);
/* X11 driver bootstrap functions */
static int (*orig_x11_errhandler)(Display *, XErrorEvent *) = NULL;
static void X11_DeleteDevice(SDL_VideoDevice *device)
{
SDL_VideoData *data = device->driverdata;
if (device->vulkan_config.loader_handle) {
device->Vulkan_UnloadLibrary(device);
}
if (data->display) {
X11_XSetErrorHandler(orig_x11_errhandler);
X11_XCloseDisplay(data->display);
}
if (data->request_display) {
X11_XCloseDisplay(data->request_display);
}
SDL_free(data->windowlist);
if (device->wakeup_lock) {
SDL_DestroyMutex(device->wakeup_lock);
}
SDL_free(device->driverdata);
SDL_free(device);
SDL_X11_UnloadSymbols();
}
/* An error handler to reset the vidmode and then call the default handler. */
static SDL_bool safety_net_triggered = SDL_FALSE;
static int X11_SafetyNetErrHandler(Display *d, XErrorEvent *e)
{
SDL_VideoDevice *device = NULL;
/* if we trigger an error in our error handler, don't try again. */
if (!safety_net_triggered) {
safety_net_triggered = SDL_TRUE;
device = SDL_GetVideoDevice();
if (device != NULL) {
int i;
for (i = 0; i < device->num_displays; i++) {
SDL_VideoDisplay *display = &device->displays[i];
if (SDL_GetCurrentDisplayMode(display->id) != SDL_GetDesktopDisplayMode(display->id)) {
X11_SetDisplayMode(device, display, &display->desktop_mode);
}
}
}
}
if (orig_x11_errhandler != NULL) {
return orig_x11_errhandler(d, e); /* probably terminate. */
}
return 0;
}
static SDL_VideoDevice *X11_CreateDevice(void)
{
SDL_VideoDevice *device;
SDL_VideoData *data;
const char *display = NULL; /* Use the DISPLAY environment variable */
Display *x11_display = NULL;
if (!SDL_X11_LoadSymbols()) {
return NULL;
}
/* Need for threading gl calls. This is also required for the proprietary
nVidia driver to be threaded. */
X11_XInitThreads();
/* Open the display first to be sure that X11 is available */
x11_display = X11_XOpenDisplay(display);
if (x11_display == NULL) {
SDL_X11_UnloadSymbols();
return NULL;
}
/* Initialize all variables that we clean on shutdown */
device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
if (device == NULL) {
SDL_OutOfMemory();
return NULL;
}
data = (struct SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData));
if (data == NULL) {
SDL_free(device);
SDL_OutOfMemory();
return NULL;
}
device->driverdata = data;
data->global_mouse_changed = SDL_TRUE;
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
data->active_cursor_confined_window = NULL;
#endif /* SDL_VIDEO_DRIVER_X11_XFIXES */
data->display = x11_display;
data->request_display = X11_XOpenDisplay(display);
if (data->request_display == NULL) {
X11_XCloseDisplay(data->display);
SDL_free(device->driverdata);
SDL_free(device);
SDL_X11_UnloadSymbols();
return NULL;
}
device->wakeup_lock = SDL_CreateMutex();
#ifdef X11_DEBUG
X11_XSynchronize(data->display, True);
#endif
/* Hook up an X11 error handler to recover the desktop resolution. */
safety_net_triggered = SDL_FALSE;
orig_x11_errhandler = X11_XSetErrorHandler(X11_SafetyNetErrHandler);
/* Steam Deck will have an on-screen keyboard, so check their environment
* variable so we can make use of SDL_StartTextInput.
*/
data->is_steam_deck = SDL_GetHintBoolean("SteamDeck", SDL_FALSE);
/* Set the function pointers */
device->VideoInit = X11_VideoInit;
device->VideoQuit = X11_VideoQuit;
device->ResetTouch = X11_ResetTouch;
device->GetDisplayModes = X11_GetDisplayModes;
device->GetDisplayBounds = X11_GetDisplayBounds;
device->GetDisplayUsableBounds = X11_GetDisplayUsableBounds;
device->GetWindowICCProfile = X11_GetWindowICCProfile;
device->SetDisplayMode = X11_SetDisplayMode;
device->SuspendScreenSaver = X11_SuspendScreenSaver;
device->PumpEvents = X11_PumpEvents;
device->WaitEventTimeout = X11_WaitEventTimeout;
device->SendWakeupEvent = X11_SendWakeupEvent;
device->CreateSDLWindow = X11_CreateWindow;
device->CreateSDLWindowFrom = X11_CreateWindowFrom;
device->SetWindowTitle = X11_SetWindowTitle;
device->SetWindowIcon = X11_SetWindowIcon;
device->SetWindowPosition = X11_SetWindowPosition;
device->SetWindowSize = X11_SetWindowSize;
device->SetWindowMinimumSize = X11_SetWindowMinimumSize;
device->SetWindowMaximumSize = X11_SetWindowMaximumSize;
device->GetWindowBordersSize = X11_GetWindowBordersSize;
device->SetWindowOpacity = X11_SetWindowOpacity;
device->SetWindowModalFor = X11_SetWindowModalFor;
device->SetWindowInputFocus = X11_SetWindowInputFocus;
device->ShowWindow = X11_ShowWindow;
device->HideWindow = X11_HideWindow;
device->RaiseWindow = X11_RaiseWindow;
device->MaximizeWindow = X11_MaximizeWindow;
device->MinimizeWindow = X11_MinimizeWindow;
device->RestoreWindow = X11_RestoreWindow;
device->SetWindowBordered = X11_SetWindowBordered;
device->SetWindowResizable = X11_SetWindowResizable;
device->SetWindowAlwaysOnTop = X11_SetWindowAlwaysOnTop;
device->SetWindowFullscreen = X11_SetWindowFullscreen;
device->SetWindowMouseGrab = X11_SetWindowMouseGrab;
device->SetWindowKeyboardGrab = X11_SetWindowKeyboardGrab;
device->DestroyWindow = X11_DestroyWindow;
device->CreateWindowFramebuffer = X11_CreateWindowFramebuffer;
device->UpdateWindowFramebuffer = X11_UpdateWindowFramebuffer;
device->DestroyWindowFramebuffer = X11_DestroyWindowFramebuffer;
device->GetWindowWMInfo = X11_GetWindowWMInfo;
device->SetWindowHitTest = X11_SetWindowHitTest;
device->AcceptDragAndDrop = X11_AcceptDragAndDrop;
device->FlashWindow = X11_FlashWindow;
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
device->SetWindowMouseRect = X11_SetWindowMouseRect;
#endif /* SDL_VIDEO_DRIVER_X11_XFIXES */
device->shape_driver.CreateShaper = X11_CreateShaper;
device->shape_driver.SetWindowShape = X11_SetWindowShape;
#ifdef SDL_VIDEO_OPENGL_GLX
device->GL_LoadLibrary = X11_GL_LoadLibrary;
device->GL_GetProcAddress = X11_GL_GetProcAddress;
device->GL_UnloadLibrary = X11_GL_UnloadLibrary;
device->GL_CreateContext = X11_GL_CreateContext;
device->GL_MakeCurrent = X11_GL_MakeCurrent;
device->GL_SetSwapInterval = X11_GL_SetSwapInterval;
device->GL_GetSwapInterval = X11_GL_GetSwapInterval;
device->GL_SwapWindow = X11_GL_SwapWindow;
device->GL_DeleteContext = X11_GL_DeleteContext;
device->GL_GetEGLSurface = NULL;
#endif
#ifdef SDL_VIDEO_OPENGL_EGL
#ifdef SDL_VIDEO_OPENGL_GLX
if (SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, SDL_FALSE)) {
#endif
device->GL_LoadLibrary = X11_GLES_LoadLibrary;
device->GL_GetProcAddress = X11_GLES_GetProcAddress;
device->GL_UnloadLibrary = X11_GLES_UnloadLibrary;
device->GL_CreateContext = X11_GLES_CreateContext;
device->GL_MakeCurrent = X11_GLES_MakeCurrent;
device->GL_SetSwapInterval = X11_GLES_SetSwapInterval;
device->GL_GetSwapInterval = X11_GLES_GetSwapInterval;
device->GL_SwapWindow = X11_GLES_SwapWindow;
device->GL_DeleteContext = X11_GLES_DeleteContext;
device->GL_GetEGLSurface = X11_GLES_GetEGLSurface;
#ifdef SDL_VIDEO_OPENGL_GLX
}
#endif
#endif
device->GetTextMimeTypes = X11_GetTextMimeTypes;
device->SetClipboardData = X11_SetClipboardData;
device->GetClipboardData = X11_GetClipboardData;
device->HasClipboardData = X11_HasClipboardData;
device->SetPrimarySelectionText = X11_SetPrimarySelectionText;
device->GetPrimarySelectionText = X11_GetPrimarySelectionText;
device->HasPrimarySelectionText = X11_HasPrimarySelectionText;
device->StartTextInput = X11_StartTextInput;
device->StopTextInput = X11_StopTextInput;
device->SetTextInputRect = X11_SetTextInputRect;
device->HasScreenKeyboardSupport = X11_HasScreenKeyboardSupport;
device->ShowScreenKeyboard = X11_ShowScreenKeyboard;
device->HideScreenKeyboard = X11_HideScreenKeyboard;
device->IsScreenKeyboardShown = X11_IsScreenKeyboardShown;
device->free = X11_DeleteDevice;
#ifdef SDL_VIDEO_VULKAN
device->Vulkan_LoadLibrary = X11_Vulkan_LoadLibrary;
device->Vulkan_UnloadLibrary = X11_Vulkan_UnloadLibrary;
device->Vulkan_GetInstanceExtensions = X11_Vulkan_GetInstanceExtensions;
device->Vulkan_CreateSurface = X11_Vulkan_CreateSurface;
#endif
#ifdef SDL_USE_LIBDBUS
if (SDL_SystemTheme_Init())
device->system_theme = SDL_SystemTheme_Get();
#endif
device->quirk_flags = VIDEO_DEVICE_QUIRK_HAS_POPUP_WINDOW_SUPPORT;
return device;
}
VideoBootStrap X11_bootstrap = {
"x11", "SDL X11 video driver",
X11_CreateDevice
};
static int (*handler)(Display *, XErrorEvent *) = NULL;
static int X11_CheckWindowManagerErrorHandler(Display *d, XErrorEvent *e)
{
if (e->error_code == BadWindow) {
return 0;
} else {
return handler(d, e);
}
}
static void X11_CheckWindowManager(SDL_VideoDevice *_this)
{
SDL_VideoData *data = _this->driverdata;
Display *display = data->display;
Atom _NET_SUPPORTING_WM_CHECK;
int status, real_format;
Atom real_type;
unsigned long items_read = 0, items_left = 0;
unsigned char *propdata = NULL;
Window wm_window = 0;
#ifdef DEBUG_WINDOW_MANAGER
char *wm_name;
#endif
/* Set up a handler to gracefully catch errors */
X11_XSync(display, False);
handler = X11_XSetErrorHandler(X11_CheckWindowManagerErrorHandler);
_NET_SUPPORTING_WM_CHECK = X11_XInternAtom(display, "_NET_SUPPORTING_WM_CHECK", False);
status = X11_XGetWindowProperty(display, DefaultRootWindow(display), _NET_SUPPORTING_WM_CHECK, 0L, 1L, False, XA_WINDOW, &real_type, &real_format, &items_read, &items_left, &propdata);
if (status == Success) {
if (items_read) {
wm_window = ((Window *)propdata)[0];
}
if (propdata) {
X11_XFree(propdata);
propdata = NULL;
}
}
if (wm_window) {
status = X11_XGetWindowProperty(display, wm_window, _NET_SUPPORTING_WM_CHECK, 0L, 1L, False, XA_WINDOW, &real_type, &real_format, &items_read, &items_left, &propdata);
if (status != Success || !items_read || wm_window != ((Window *)propdata)[0]) {
wm_window = None;
}
if (status == Success && propdata) {
X11_XFree(propdata);
propdata = NULL;
}
}
/* Reset the error handler, we're done checking */
X11_XSync(display, False);
X11_XSetErrorHandler(handler);
if (!wm_window) {
#ifdef DEBUG_WINDOW_MANAGER
printf("Couldn't get _NET_SUPPORTING_WM_CHECK property\n");
#endif
return;
}
data->net_wm = SDL_TRUE;
#ifdef DEBUG_WINDOW_MANAGER
wm_name = X11_GetWindowTitle(_this, wm_window);
printf("Window manager: %s\n", wm_name);
SDL_free(wm_name);
#endif
}
int X11_VideoInit(SDL_VideoDevice *_this)
{
SDL_VideoData *data = _this->driverdata;
/* Get the process PID to be associated to the window */
data->pid = getpid();
/* I have no idea how random this actually is, or has to be. */
data->window_group = (XID)(((size_t)data->pid) ^ ((size_t)_this));
/* Look up some useful Atoms */
#define GET_ATOM(X) data->X = X11_XInternAtom(data->display, #X, False)
GET_ATOM(WM_PROTOCOLS);
GET_ATOM(WM_DELETE_WINDOW);
GET_ATOM(WM_TAKE_FOCUS);
GET_ATOM(WM_NAME);
GET_ATOM(_NET_WM_STATE);
GET_ATOM(_NET_WM_STATE_HIDDEN);
GET_ATOM(_NET_WM_STATE_FOCUSED);
GET_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
GET_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
GET_ATOM(_NET_WM_STATE_FULLSCREEN);
GET_ATOM(_NET_WM_STATE_ABOVE);
GET_ATOM(_NET_WM_STATE_SKIP_TASKBAR);
GET_ATOM(_NET_WM_STATE_SKIP_PAGER);
GET_ATOM(_NET_WM_ALLOWED_ACTIONS);
GET_ATOM(_NET_WM_ACTION_FULLSCREEN);
GET_ATOM(_NET_WM_NAME);
GET_ATOM(_NET_WM_ICON_NAME);
GET_ATOM(_NET_WM_ICON);
GET_ATOM(_NET_WM_PING);
GET_ATOM(_NET_WM_WINDOW_OPACITY);
GET_ATOM(_NET_WM_USER_TIME);
GET_ATOM(_NET_ACTIVE_WINDOW);
GET_ATOM(_NET_FRAME_EXTENTS);
GET_ATOM(_SDL_WAKEUP);
GET_ATOM(UTF8_STRING);
GET_ATOM(PRIMARY);
GET_ATOM(XdndEnter);
GET_ATOM(XdndPosition);
GET_ATOM(XdndStatus);
GET_ATOM(XdndTypeList);
GET_ATOM(XdndActionCopy);
GET_ATOM(XdndDrop);
GET_ATOM(XdndFinished);
GET_ATOM(XdndSelection);
GET_ATOM(XKLAVIER_STATE);
/* Detect the window manager */
X11_CheckWindowManager(_this);
if (X11_InitModes(_this) < 0) {
return -1;
}
X11_InitXinput2(_this);
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
X11_InitXfixes(_this);
#endif /* SDL_VIDEO_DRIVER_X11_XFIXES */
#ifndef X_HAVE_UTF8_STRING
#warning X server does not support UTF8_STRING, a feature introduced in 2000! This is likely to become a hard error in a future libSDL3.
#endif
if (X11_InitKeyboard(_this) != 0) {
return -1;
}
X11_InitMouse(_this);
X11_InitTouch(_this);
return 0;
}
void X11_VideoQuit(SDL_VideoDevice *_this)
{
SDL_VideoData *data = _this->driverdata;
if (data->clipboard_window) {
X11_XDestroyWindow(data->display, data->clipboard_window);
}
#ifdef X_HAVE_UTF8_STRING
if (data->im) {
X11_XCloseIM(data->im);
}
#endif
X11_QuitModes(_this);
X11_QuitKeyboard(_this);
X11_QuitMouse(_this);
X11_QuitTouch(_this);
X11_QuitClipboard(_this);
}
SDL_bool X11_UseDirectColorVisuals(void)
{
return SDL_getenv("SDL_VIDEO_X11_NODIRECTCOLOR") ? SDL_FALSE : SDL_TRUE;
}
#endif /* SDL_VIDEO_DRIVER_X11 */

View File

@ -0,0 +1,163 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_x11video_h_
#define SDL_x11video_h_
#include "../SDL_sysvideo.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/Xresource.h>
#ifdef SDL_VIDEO_DRIVER_X11_XCURSOR
#include <X11/Xcursor/Xcursor.h>
#endif
#ifdef SDL_VIDEO_DRIVER_X11_XDBE
#include <X11/extensions/Xdbe.h>
#endif
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
#include <X11/extensions/XInput2.h>
#endif
#ifdef SDL_VIDEO_DRIVER_X11_XRANDR
#include <X11/extensions/Xrandr.h>
#endif
#ifdef SDL_VIDEO_DRIVER_X11_XSCRNSAVER
#include <X11/extensions/scrnsaver.h>
#endif
#ifdef SDL_VIDEO_DRIVER_X11_XSHAPE
#include <X11/extensions/shape.h>
#endif
#include "../../core/linux/SDL_dbus.h"
#include "../../core/linux/SDL_ime.h"
#include "SDL_x11dyn.h"
#include "SDL_x11clipboard.h"
#include "SDL_x11events.h"
#include "SDL_x11keyboard.h"
#include "SDL_x11modes.h"
#include "SDL_x11mouse.h"
#include "SDL_x11opengl.h"
#include "SDL_x11window.h"
#include "SDL_x11vulkan.h"
/* Private display data */
struct SDL_VideoData
{
Display *display;
Display *request_display;
pid_t pid;
XIM im;
Uint64 screensaver_activity;
int numwindows;
SDL_WindowData **windowlist;
int windowlistlength;
XID window_group;
Window clipboard_window;
SDLX11_ClipboardData clipboard;
SDLX11_ClipboardData primary_selection;
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
SDL_Window *active_cursor_confined_window;
#endif /* SDL_VIDEO_DRIVER_X11_XFIXES */
/* This is true for ICCCM2.0-compliant window managers */
SDL_bool net_wm;
/* Useful atoms */
Atom WM_PROTOCOLS;
Atom WM_DELETE_WINDOW;
Atom WM_TAKE_FOCUS;
Atom WM_NAME;
Atom _NET_WM_STATE;
Atom _NET_WM_STATE_HIDDEN;
Atom _NET_WM_STATE_FOCUSED;
Atom _NET_WM_STATE_MAXIMIZED_VERT;
Atom _NET_WM_STATE_MAXIMIZED_HORZ;
Atom _NET_WM_STATE_FULLSCREEN;
Atom _NET_WM_STATE_ABOVE;
Atom _NET_WM_STATE_SKIP_TASKBAR;
Atom _NET_WM_STATE_SKIP_PAGER;
Atom _NET_WM_ALLOWED_ACTIONS;
Atom _NET_WM_ACTION_FULLSCREEN;
Atom _NET_WM_NAME;
Atom _NET_WM_ICON_NAME;
Atom _NET_WM_ICON;
Atom _NET_WM_PING;
Atom _NET_WM_WINDOW_OPACITY;
Atom _NET_WM_USER_TIME;
Atom _NET_ACTIVE_WINDOW;
Atom _NET_FRAME_EXTENTS;
Atom _SDL_WAKEUP;
Atom UTF8_STRING;
Atom PRIMARY;
Atom XdndEnter;
Atom XdndPosition;
Atom XdndStatus;
Atom XdndTypeList;
Atom XdndActionCopy;
Atom XdndDrop;
Atom XdndFinished;
Atom XdndSelection;
Atom XKLAVIER_STATE;
SDL_Scancode key_layout[256];
SDL_bool selection_waiting;
SDL_bool broken_pointer_grab; /* true if XGrabPointer seems unreliable. */
Uint64 last_mode_change_deadline;
SDL_bool global_mouse_changed;
SDL_Point global_mouse_position;
Uint32 global_mouse_buttons;
SDL_XInput2DeviceInfo *mouse_device_info;
int xrandr_event_base;
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
XkbDescPtr xkb;
#endif
int xkb_event;
KeyCode filter_code;
Time filter_time;
#ifdef SDL_VIDEO_VULKAN
/* Vulkan variables only valid if _this->vulkan_config.loader_handle is not NULL */
void *vulkan_xlib_xcb_library;
PFN_XGetXCBConnection vulkan_XGetXCBConnection;
#endif
/* Used to interact with the on-screen keyboard */
SDL_bool is_steam_deck;
SDL_bool steam_keyboard_open;
};
extern SDL_bool X11_UseDirectColorVisuals(void);
#endif /* SDL_x11video_h_ */

View File

@ -0,0 +1,233 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_X11)
#include "SDL_x11video.h"
#include "SDL_x11vulkan.h"
#include <X11/Xlib.h>
/*#include <xcb/xcb.h>*/
#ifdef __OpenBSD__
#define DEFAULT_VULKAN "libvulkan.so"
#else
#define DEFAULT_VULKAN "libvulkan.so.1"
#endif
/*
typedef uint32_t xcb_window_t;
typedef uint32_t xcb_visualid_t;
*/
int X11_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path)
{
SDL_VideoData *videoData = _this->driverdata;
VkExtensionProperties *extensions = NULL;
Uint32 extensionCount = 0;
SDL_bool hasSurfaceExtension = SDL_FALSE;
SDL_bool hasXlibSurfaceExtension = SDL_FALSE;
SDL_bool hasXCBSurfaceExtension = SDL_FALSE;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL;
Uint32 i;
if (_this->vulkan_config.loader_handle) {
return SDL_SetError("Vulkan already loaded");
}
/* Load the Vulkan loader library */
if (path == NULL) {
path = SDL_getenv("SDL_VULKAN_LIBRARY");
}
if (path == NULL) {
path = DEFAULT_VULKAN;
}
_this->vulkan_config.loader_handle = SDL_LoadObject(path);
if (!_this->vulkan_config.loader_handle) {
return -1;
}
SDL_strlcpy(_this->vulkan_config.loader_path, path, SDL_arraysize(_this->vulkan_config.loader_path));
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction(
_this->vulkan_config.loader_handle, "vkGetInstanceProcAddr");
if (!vkGetInstanceProcAddr) {
goto fail;
}
_this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr;
_this->vulkan_config.vkEnumerateInstanceExtensionProperties =
(void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)(
VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties");
if (!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) {
goto fail;
}
extensions = SDL_Vulkan_CreateInstanceExtensionsList(
(PFN_vkEnumerateInstanceExtensionProperties)
_this->vulkan_config.vkEnumerateInstanceExtensionProperties,
&extensionCount);
if (extensions == NULL) {
goto fail;
}
for (i = 0; i < extensionCount; i++) {
if (SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
hasSurfaceExtension = SDL_TRUE;
} else if (SDL_strcmp(VK_KHR_XCB_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
hasXCBSurfaceExtension = SDL_TRUE;
} else if (SDL_strcmp(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
hasXlibSurfaceExtension = SDL_TRUE;
}
}
SDL_free(extensions);
if (!hasSurfaceExtension) {
SDL_SetError("Installed Vulkan doesn't implement the " VK_KHR_SURFACE_EXTENSION_NAME " extension");
goto fail;
}
if (hasXlibSurfaceExtension) {
videoData->vulkan_xlib_xcb_library = NULL;
} else if (!hasXCBSurfaceExtension) {
SDL_SetError("Installed Vulkan doesn't implement either the " VK_KHR_XCB_SURFACE_EXTENSION_NAME "extension or the " VK_KHR_XLIB_SURFACE_EXTENSION_NAME " extension");
goto fail;
} else {
const char *libX11XCBLibraryName = SDL_getenv("SDL_X11_XCB_LIBRARY");
if (libX11XCBLibraryName == NULL) {
libX11XCBLibraryName = "libX11-xcb.so";
}
videoData->vulkan_xlib_xcb_library = SDL_LoadObject(libX11XCBLibraryName);
if (!videoData->vulkan_xlib_xcb_library) {
goto fail;
}
videoData->vulkan_XGetXCBConnection =
(PFN_XGetXCBConnection)SDL_LoadFunction(videoData->vulkan_xlib_xcb_library, "XGetXCBConnection");
if (!videoData->vulkan_XGetXCBConnection) {
SDL_UnloadObject(videoData->vulkan_xlib_xcb_library);
goto fail;
}
}
return 0;
fail:
SDL_UnloadObject(_this->vulkan_config.loader_handle);
_this->vulkan_config.loader_handle = NULL;
return -1;
}
void X11_Vulkan_UnloadLibrary(SDL_VideoDevice *_this)
{
SDL_VideoData *videoData = _this->driverdata;
if (_this->vulkan_config.loader_handle) {
if (videoData->vulkan_xlib_xcb_library) {
SDL_UnloadObject(videoData->vulkan_xlib_xcb_library);
}
SDL_UnloadObject(_this->vulkan_config.loader_handle);
_this->vulkan_config.loader_handle = NULL;
}
}
SDL_bool X11_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
unsigned *count,
const char **names)
{
SDL_VideoData *videoData = _this->driverdata;
if (!_this->vulkan_config.loader_handle) {
SDL_SetError("Vulkan is not loaded");
return SDL_FALSE;
}
if (videoData->vulkan_xlib_xcb_library) {
static const char *const extensionsForXCB[] = {
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_XCB_SURFACE_EXTENSION_NAME,
};
return SDL_Vulkan_GetInstanceExtensions_Helper(
count, names, SDL_arraysize(extensionsForXCB), extensionsForXCB);
} else {
static const char *const extensionsForXlib[] = {
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
};
return SDL_Vulkan_GetInstanceExtensions_Helper(
count, names, SDL_arraysize(extensionsForXlib), extensionsForXlib);
}
}
SDL_bool X11_Vulkan_CreateSurface(SDL_VideoDevice *_this,
SDL_Window *window,
VkInstance instance,
VkSurfaceKHR *surface)
{
SDL_VideoData *videoData = _this->driverdata;
SDL_WindowData *windowData = window->driverdata;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
if (!_this->vulkan_config.loader_handle) {
SDL_SetError("Vulkan is not loaded");
return SDL_FALSE;
}
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr;
if (videoData->vulkan_xlib_xcb_library) {
PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR =
(PFN_vkCreateXcbSurfaceKHR)vkGetInstanceProcAddr(instance,
"vkCreateXcbSurfaceKHR");
VkXcbSurfaceCreateInfoKHR createInfo;
VkResult result;
if (!vkCreateXcbSurfaceKHR) {
SDL_SetError(VK_KHR_XCB_SURFACE_EXTENSION_NAME
" extension is not enabled in the Vulkan instance.");
return SDL_FALSE;
}
SDL_zero(createInfo);
createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
createInfo.connection = videoData->vulkan_XGetXCBConnection(videoData->display);
if (!createInfo.connection) {
SDL_SetError("XGetXCBConnection failed");
return SDL_FALSE;
}
createInfo.window = (xcb_window_t)windowData->xwindow;
result = vkCreateXcbSurfaceKHR(instance, &createInfo,
NULL, surface);
if (result != VK_SUCCESS) {
SDL_SetError("vkCreateXcbSurfaceKHR failed: %s", SDL_Vulkan_GetResultString(result));
return SDL_FALSE;
}
return SDL_TRUE;
} else {
PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR =
(PFN_vkCreateXlibSurfaceKHR)vkGetInstanceProcAddr(instance,
"vkCreateXlibSurfaceKHR");
VkXlibSurfaceCreateInfoKHR createInfo;
VkResult result;
if (!vkCreateXlibSurfaceKHR) {
SDL_SetError(VK_KHR_XLIB_SURFACE_EXTENSION_NAME
" extension is not enabled in the Vulkan instance.");
return SDL_FALSE;
}
SDL_zero(createInfo);
createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
createInfo.dpy = videoData->display;
createInfo.window = (xcb_window_t)windowData->xwindow;
result = vkCreateXlibSurfaceKHR(instance, &createInfo,
NULL, surface);
if (result != VK_SUCCESS) {
SDL_SetError("vkCreateXlibSurfaceKHR failed: %s", SDL_Vulkan_GetResultString(result));
return SDL_FALSE;
}
return SDL_TRUE;
}
}
#endif

View File

@ -0,0 +1,45 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_x11vulkan_h_
#define SDL_x11vulkan_h_
#include "../SDL_vulkan_internal.h"
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_X11)
/*typedef struct xcb_connection_t xcb_connection_t;*/
typedef xcb_connection_t *(*PFN_XGetXCBConnection)(Display *dpy);
int X11_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path);
void X11_Vulkan_UnloadLibrary(SDL_VideoDevice *_this);
SDL_bool X11_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
unsigned *count,
const char **names);
SDL_bool X11_Vulkan_CreateSurface(SDL_VideoDevice *_this,
SDL_Window *window,
VkInstance instance,
VkSurfaceKHR *surface);
#endif
#endif /* SDL_x11vulkan_h_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,122 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_x11window_h_
#define SDL_x11window_h_
/* We need to queue the focus in/out changes because they may occur during
video mode changes and we can respond to them by triggering more mode
changes.
*/
#define PENDING_FOCUS_TIME 200
#ifdef SDL_VIDEO_OPENGL_EGL
#include <EGL/egl.h>
#endif
typedef enum
{
PENDING_FOCUS_NONE,
PENDING_FOCUS_IN,
PENDING_FOCUS_OUT
} PendingFocusEnum;
struct SDL_WindowData
{
SDL_Window *window;
Window xwindow;
Visual *visual;
Colormap colormap;
#ifndef NO_SHARED_MEMORY
/* MIT shared memory extension information */
SDL_bool use_mitshm;
XShmSegmentInfo shminfo;
#endif
XImage *ximage;
GC gc;
XIC ic;
SDL_bool created;
int border_left;
int border_right;
int border_top;
int border_bottom;
SDL_bool mouse_grabbed;
Uint64 last_focus_event_time;
PendingFocusEnum pending_focus;
Uint64 pending_focus_time;
XConfigureEvent last_xconfigure;
struct SDL_VideoData *videodata;
unsigned long user_time;
Atom xdnd_req;
Window xdnd_source;
SDL_bool flashing_window;
Uint64 flash_cancel_time;
SDL_Window *keyboard_focus;
#ifdef SDL_VIDEO_OPENGL_EGL
EGLSurface egl_surface;
#endif
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
SDL_bool pointer_barrier_active;
PointerBarrier barrier[4];
SDL_Rect barrier_rect;
#endif /* SDL_VIDEO_DRIVER_X11_XFIXES */
};
extern void X11_SetNetWMState(SDL_VideoDevice *_this, Window xwindow, Uint32 flags);
extern Uint32 X11_GetNetWMState(SDL_VideoDevice *_this, SDL_Window *window, Window xwindow);
extern int X11_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern int X11_CreateWindowFrom(SDL_VideoDevice *_this, SDL_Window *window, const void *data);
extern char *X11_GetWindowTitle(SDL_VideoDevice *_this, Window xwindow);
extern void X11_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
extern int X11_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *icon);
extern int X11_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window);
extern void X11_SetWindowMinimumSize(SDL_VideoDevice *_this, SDL_Window *window);
extern void X11_SetWindowMaximumSize(SDL_VideoDevice *_this, SDL_Window *window);
extern int X11_GetWindowBordersSize(SDL_VideoDevice *_this, SDL_Window *window, int *top, int *left, int *bottom, int *right);
extern int X11_SetWindowOpacity(SDL_VideoDevice *_this, SDL_Window *window, float opacity);
extern int X11_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window);
extern int X11_SetWindowInputFocus(SDL_VideoDevice *_this, SDL_Window *window);
extern void X11_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window);
extern void X11_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void X11_HideWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void X11_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void X11_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void X11_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void X11_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void X11_SetWindowBordered(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool bordered);
extern void X11_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool resizable);
extern void X11_SetWindowAlwaysOnTop(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool on_top);
extern void X11_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen);
extern void *X11_GetWindowICCProfile(SDL_VideoDevice *_this, SDL_Window *window, size_t *size);
extern void X11_SetWindowMouseGrab(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool grabbed);
extern void X11_SetWindowKeyboardGrab(SDL_VideoDevice *_this, SDL_Window *window, SDL_bool grabbed);
extern void X11_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern int X11_GetWindowWMInfo(SDL_VideoDevice *_this, SDL_Window *window, struct SDL_SysWMinfo *info);
extern int X11_SetWindowHitTest(SDL_Window *window, SDL_bool enabled);
extern void X11_AcceptDragAndDrop(SDL_Window *window, SDL_bool accept);
extern int X11_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
int SDL_X11_SetWindowTitle(Display *display, Window xwindow, char *title);
void X11_UpdateWindowPosition(SDL_Window *window);
#endif /* SDL_x11window_h_ */

View File

@ -0,0 +1,212 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_DRIVER_X11) && defined(SDL_VIDEO_DRIVER_X11_XFIXES)
#include "SDL_x11video.h"
#include "SDL_x11xfixes.h"
#include "../../events/SDL_mouse_c.h"
#include "../../events/SDL_touch_c.h"
static int xfixes_initialized = 0;
static int xfixes_selection_notify_event = 0;
static int query_xfixes_version(Display *display, int major, int minor)
{
/* We don't care if this fails, so long as it sets major/minor on it's way out the door. */
X11_XFixesQueryVersion(display, &major, &minor);
return (major * 1000) + minor;
}
static SDL_bool xfixes_version_atleast(const int version, const int wantmajor, const int wantminor)
{
return version >= ((wantmajor * 1000) + wantminor);
}
void X11_InitXfixes(SDL_VideoDevice *_this)
{
SDL_VideoData *data = _this->driverdata;
int version = 0;
int event, error;
int fixes_opcode;
Atom XA_CLIPBOARD = X11_XInternAtom(data->display, "CLIPBOARD", 0);
if (!SDL_X11_HAVE_XFIXES ||
!X11_XQueryExtension(data->display, "XFIXES", &fixes_opcode, &event, &error)) {
return;
}
/* Selection tracking is available in all versions of XFixes */
xfixes_selection_notify_event = event + XFixesSelectionNotify;
X11_XFixesSelectSelectionInput(data->display, DefaultRootWindow(data->display),
XA_CLIPBOARD, XFixesSetSelectionOwnerNotifyMask);
X11_XFixesSelectSelectionInput(data->display, DefaultRootWindow(data->display),
XA_PRIMARY, XFixesSetSelectionOwnerNotifyMask);
/* We need at least 5.0 for barriers. */
version = query_xfixes_version(data->display, 5, 0);
if (!xfixes_version_atleast(version, 5, 0)) {
return; /* X server does not support the version we want at all. */
}
xfixes_initialized = 1;
}
int X11_XfixesIsInitialized(void)
{
return xfixes_initialized;
}
int X11_GetXFixesSelectionNotifyEvent()
{
return xfixes_selection_notify_event;
}
void X11_SetWindowMouseRect(SDL_VideoDevice *_this, SDL_Window *window)
{
if (SDL_RectEmpty(&window->mouse_rect)) {
X11_ConfineCursorWithFlags(_this, window, NULL, 0);
} else {
if (window->flags & SDL_WINDOW_INPUT_FOCUS) {
X11_ConfineCursorWithFlags(_this, window, &window->mouse_rect, 0);
} else {
/* Save the state for when we get focus again */
SDL_WindowData *wdata = window->driverdata;
SDL_memcpy(&wdata->barrier_rect, &window->mouse_rect, sizeof(wdata->barrier_rect));
wdata->pointer_barrier_active = SDL_TRUE;
}
}
}
int X11_ConfineCursorWithFlags(SDL_VideoDevice *_this, SDL_Window *window, const SDL_Rect *rect, int flags)
{
/* Yaakuro: For some reason Xfixes when confining inside a rect where the
* edges exactly match, a rectangle the cursor 'slips' out of the barrier.
* To prevent that the lines for the barriers will span the whole screen.
*/
SDL_VideoData *data = _this->driverdata;
SDL_WindowData *wdata;
if (!X11_XfixesIsInitialized()) {
return SDL_Unsupported();
}
/* If there is already a set of barriers active, disable them. */
if (data->active_cursor_confined_window) {
X11_DestroyPointerBarrier(_this, data->active_cursor_confined_window);
}
SDL_assert(window != NULL);
wdata = window->driverdata;
/* If user did not specify an area to confine, destroy the barrier that was/is assigned to
* this window it was assigned */
if (rect) {
int x1, y1, x2, y2;
SDL_Rect bounds;
SDL_GetWindowPosition(window, &bounds.x, &bounds.y);
SDL_GetWindowSize(window, &bounds.w, &bounds.h);
/** Negative values are not allowed. Clip values relative to the specified window. */
x1 = bounds.x + SDL_max(rect->x, 0);
y1 = bounds.y + SDL_max(rect->y, 0);
x2 = SDL_min(bounds.x + rect->x + rect->w, bounds.x + bounds.w);
y2 = SDL_min(bounds.y + rect->y + rect->h, bounds.y + bounds.h);
if ((wdata->barrier_rect.x != rect->x) ||
(wdata->barrier_rect.y != rect->y) ||
(wdata->barrier_rect.w != rect->w) ||
(wdata->barrier_rect.h != rect->h)) {
wdata->barrier_rect = *rect;
}
/* Use the display bounds to ensure the barriers don't have corner gaps */
SDL_GetDisplayBounds(SDL_GetDisplayForWindow(window), &bounds);
/** Create the left barrier */
wdata->barrier[0] = X11_XFixesCreatePointerBarrier(data->display, wdata->xwindow,
x1, bounds.y,
x1, bounds.y + bounds.h,
BarrierPositiveX,
0, NULL);
/** Create the right barrier */
wdata->barrier[1] = X11_XFixesCreatePointerBarrier(data->display, wdata->xwindow,
x2, bounds.y,
x2, bounds.y + bounds.h,
BarrierNegativeX,
0, NULL);
/** Create the top barrier */
wdata->barrier[2] = X11_XFixesCreatePointerBarrier(data->display, wdata->xwindow,
bounds.x, y1,
bounds.x + bounds.w, y1,
BarrierPositiveY,
0, NULL);
/** Create the bottom barrier */
wdata->barrier[3] = X11_XFixesCreatePointerBarrier(data->display, wdata->xwindow,
bounds.x, y2,
bounds.x + bounds.w, y2,
BarrierNegativeY,
0, NULL);
X11_XFlush(data->display);
/* Lets remember current active confined window. */
data->active_cursor_confined_window = window;
/* User activated the confinement for this window. We use this later to reactivate
* the confinement if it got deactivated by FocusOut or UnmapNotify */
wdata->pointer_barrier_active = SDL_TRUE;
} else {
X11_DestroyPointerBarrier(_this, window);
/* Only set barrier inactive when user specified NULL and not handled by focus out. */
if (flags != X11_BARRIER_HANDLED_BY_EVENT) {
wdata->pointer_barrier_active = SDL_FALSE;
}
}
return 0;
}
void X11_DestroyPointerBarrier(SDL_VideoDevice *_this, SDL_Window *window)
{
int i;
SDL_VideoData *data = _this->driverdata;
if (window) {
SDL_WindowData *wdata = window->driverdata;
for (i = 0; i < 4; i++) {
if (wdata->barrier[i] > 0) {
X11_XFixesDestroyPointerBarrier(data->display, wdata->barrier[i]);
wdata->barrier[i] = 0;
}
}
X11_XFlush(data->display);
}
data->active_cursor_confined_window = NULL;
}
#endif /* SDL_VIDEO_DRIVER_X11 && SDL_VIDEO_DRIVER_X11_XFIXES */

View File

@ -0,0 +1,39 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_x11xfixes_h_
#define SDL_x11xfixes_h_
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
#define X11_BARRIER_HANDLED_BY_EVENT 1
extern void X11_InitXfixes(SDL_VideoDevice *_this);
extern int X11_XfixesIsInitialized(void);
extern void X11_SetWindowMouseRect(SDL_VideoDevice *_this, SDL_Window *window);
extern int X11_ConfineCursorWithFlags(SDL_VideoDevice *_this, SDL_Window *window, const SDL_Rect *rect, int flags);
extern void X11_DestroyPointerBarrier(SDL_VideoDevice *_this, SDL_Window *window);
extern int X11_GetXFixesSelectionNotifyEvent(void);
#endif /* SDL_VIDEO_DRIVER_X11_XFIXES */
#endif /* SDL_x11xfixes_h_ */

View File

@ -0,0 +1,521 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_X11
#include "SDL_x11video.h"
#include "SDL_x11xinput2.h"
#include "../../events/SDL_mouse_c.h"
#include "../../events/SDL_touch_c.h"
#define MAX_AXIS 16
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
static int xinput2_initialized = 0;
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
static int xinput2_multitouch_supported = 0;
#endif
/* Opcode returned X11_XQueryExtension
* It will be used in event processing
* to know that the event came from
* this extension */
static int xinput2_opcode;
static void parse_valuators(const double *input_values, const unsigned char *mask, int mask_len,
double *output_values, int output_values_len)
{
int i = 0, z = 0;
int top = mask_len * 8;
if (top > MAX_AXIS) {
top = MAX_AXIS;
}
SDL_memset(output_values, 0, output_values_len * sizeof(double));
for (; i < top && z < output_values_len; i++) {
if (XIMaskIsSet(mask, i)) {
const int value = (int)*input_values;
output_values[z] = value;
input_values++;
}
z++;
}
}
static int query_xinput2_version(Display *display, int major, int minor)
{
/* We don't care if this fails, so long as it sets major/minor on it's way out the door. */
X11_XIQueryVersion(display, &major, &minor);
return (major * 1000) + minor;
}
static SDL_bool xinput2_version_atleast(const int version, const int wantmajor, const int wantminor)
{
return version >= ((wantmajor * 1000) + wantminor);
}
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
static SDL_Window *xinput2_get_sdlwindow(SDL_VideoData *videodata, Window window)
{
int i;
for (i = 0; i < videodata->numwindows; i++) {
SDL_WindowData *d = videodata->windowlist[i];
if (d->xwindow == window) {
return d->window;
}
}
return NULL;
}
static void xinput2_normalize_touch_coordinates(SDL_Window *window, double in_x, double in_y, float *out_x, float *out_y)
{
if (window) {
if (window->w == 1) {
*out_x = 0.5f;
} else {
*out_x = in_x / (window->w - 1);
}
if (window->h == 1) {
*out_y = 0.5f;
} else {
*out_y = in_y / (window->h - 1);
}
} else {
// couldn't find the window...
*out_x = in_x;
*out_y = in_y;
}
}
#endif /* SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH */
#endif /* SDL_VIDEO_DRIVER_X11_XINPUT2 */
void X11_InitXinput2(SDL_VideoDevice *_this)
{
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
SDL_VideoData *data = _this->driverdata;
int version = 0;
XIEventMask eventmask;
unsigned char mask[4] = { 0, 0, 0, 0 };
int event, err;
/*
* Initialize XInput 2
* According to http://who-t.blogspot.com/2009/05/xi2-recipes-part-1.html its better
* to inform Xserver what version of Xinput we support.The server will store the version we support.
* "As XI2 progresses it becomes important that you use this call as the server may treat the client
* differently depending on the supported version".
*
* FIXME:event and err are not needed but if not passed X11_XQueryExtension returns SegmentationFault
*/
if (!SDL_X11_HAVE_XINPUT2 ||
!X11_XQueryExtension(data->display, "XInputExtension", &xinput2_opcode, &event, &err)) {
return; /* X server does not have XInput at all */
}
/* We need at least 2.2 for Multitouch, 2.0 otherwise. */
version = query_xinput2_version(data->display, 2, 2);
if (!xinput2_version_atleast(version, 2, 0)) {
return; /* X server does not support the version we want at all. */
}
xinput2_initialized = 1;
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH /* Multitouch needs XInput 2.2 */
xinput2_multitouch_supported = xinput2_version_atleast(version, 2, 2);
#endif
/* Enable raw motion events for this display */
eventmask.deviceid = XIAllMasterDevices;
eventmask.mask_len = sizeof(mask);
eventmask.mask = mask;
XISetMask(mask, XI_RawMotion);
XISetMask(mask, XI_RawButtonPress);
XISetMask(mask, XI_RawButtonRelease);
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
/* Enable raw touch events if supported */
if (X11_Xinput2IsMultitouchSupported()) {
XISetMask(mask, XI_RawTouchBegin);
XISetMask(mask, XI_RawTouchUpdate);
XISetMask(mask, XI_RawTouchEnd);
}
#endif
if (X11_XISelectEvents(data->display, DefaultRootWindow(data->display), &eventmask, 1) != Success) {
return;
}
SDL_zero(eventmask);
SDL_zeroa(mask);
eventmask.deviceid = XIAllDevices;
eventmask.mask_len = sizeof(mask);
eventmask.mask = mask;
XISetMask(mask, XI_HierarchyChanged);
if (X11_XISelectEvents(data->display, DefaultRootWindow(data->display), &eventmask, 1) != Success) {
return;
}
#endif
}
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
/* xi2 device went away? take it out of the list. */
static void xinput2_remove_device_info(SDL_VideoData *videodata, const int device_id)
{
SDL_XInput2DeviceInfo *prev = NULL;
SDL_XInput2DeviceInfo *devinfo;
for (devinfo = videodata->mouse_device_info; devinfo != NULL; devinfo = devinfo->next) {
if (devinfo->device_id == device_id) {
SDL_assert((devinfo == videodata->mouse_device_info) == (prev == NULL));
if (prev == NULL) {
videodata->mouse_device_info = devinfo->next;
} else {
prev->next = devinfo->next;
}
SDL_free(devinfo);
return;
}
prev = devinfo;
}
}
static SDL_XInput2DeviceInfo *xinput2_get_device_info(SDL_VideoData *videodata, const int device_id)
{
/* cache device info as we see new devices. */
SDL_XInput2DeviceInfo *prev = NULL;
SDL_XInput2DeviceInfo *devinfo;
XIDeviceInfo *xidevinfo;
int axis = 0;
int i;
for (devinfo = videodata->mouse_device_info; devinfo != NULL; devinfo = devinfo->next) {
if (devinfo->device_id == device_id) {
SDL_assert((devinfo == videodata->mouse_device_info) == (prev == NULL));
if (prev != NULL) { /* move this to the front of the list, assuming we'll get more from this one. */
prev->next = devinfo->next;
devinfo->next = videodata->mouse_device_info;
videodata->mouse_device_info = devinfo;
}
return devinfo;
}
prev = devinfo;
}
/* don't know about this device yet, query and cache it. */
devinfo = (SDL_XInput2DeviceInfo *)SDL_calloc(1, sizeof(SDL_XInput2DeviceInfo));
if (devinfo == NULL) {
SDL_OutOfMemory();
return NULL;
}
xidevinfo = X11_XIQueryDevice(videodata->display, device_id, &i);
if (xidevinfo == NULL) {
SDL_free(devinfo);
return NULL;
}
devinfo->device_id = device_id;
/* !!! FIXME: this is sort of hacky because we only care about the first two axes we see, but any given
!!! FIXME: axis could be relative or absolute, and they might not even be the X and Y axes!
!!! FIXME: But we go on, for now. Maybe we need a more robust mouse API in SDL3... */
for (i = 0; i < xidevinfo->num_classes; i++) {
const XIValuatorClassInfo *v = (const XIValuatorClassInfo *)xidevinfo->classes[i];
if (v->type == XIValuatorClass) {
devinfo->relative[axis] = (v->mode == XIModeRelative) ? SDL_TRUE : SDL_FALSE;
devinfo->minval[axis] = v->min;
devinfo->maxval[axis] = v->max;
if (++axis >= 2) {
break;
}
}
}
X11_XIFreeDeviceInfo(xidevinfo);
devinfo->next = videodata->mouse_device_info;
videodata->mouse_device_info = devinfo;
return devinfo;
}
#endif
int X11_HandleXinput2Event(SDL_VideoData *videodata, XGenericEventCookie *cookie)
{
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
if (cookie->extension != xinput2_opcode) {
return 0;
}
switch (cookie->evtype) {
case XI_RawMotion:
{
const XIRawEvent *rawev = (const XIRawEvent *)cookie->data;
SDL_Mouse *mouse = SDL_GetMouse();
SDL_XInput2DeviceInfo *devinfo;
double coords[2];
double processed_coords[2];
int i;
videodata->global_mouse_changed = SDL_TRUE;
if (!mouse->relative_mode || mouse->relative_mode_warp) {
return 0;
}
devinfo = xinput2_get_device_info(videodata, rawev->deviceid);
if (devinfo == NULL) {
return 0; /* oh well. */
}
parse_valuators(rawev->raw_values, rawev->valuators.mask,
rawev->valuators.mask_len, coords, 2);
for (i = 0; i < 2; i++) {
if (devinfo->relative[i]) {
processed_coords[i] = coords[i];
} else {
processed_coords[i] = devinfo->prev_coords[i] - coords[i]; /* convert absolute to relative */
}
}
SDL_SendMouseMotion(0, mouse->focus, mouse->mouseID, 1, (float)processed_coords[0], (float)processed_coords[1]);
devinfo->prev_coords[0] = coords[0];
devinfo->prev_coords[1] = coords[1];
return 1;
} break;
case XI_HierarchyChanged:
{
const XIHierarchyEvent *hierev = (const XIHierarchyEvent *)cookie->data;
int i;
for (i = 0; i < hierev->num_info; i++) {
if (hierev->info[i].flags & XISlaveRemoved) {
xinput2_remove_device_info(videodata, hierev->info[i].deviceid);
}
}
} break;
case XI_RawButtonPress:
case XI_RawButtonRelease:
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
case XI_RawTouchBegin:
case XI_RawTouchUpdate:
case XI_RawTouchEnd:
#endif
videodata->global_mouse_changed = SDL_TRUE;
break;
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
/* With multitouch, register to receive XI_Motion (which desctivates MotionNotify),
* so that we can distinguish real mouse motions from synthetic one. */
case XI_Motion:
{
const XIDeviceEvent *xev = (const XIDeviceEvent *)cookie->data;
int pointer_emulated = (xev->flags & XIPointerEmulated);
if (!pointer_emulated) {
SDL_Mouse *mouse = SDL_GetMouse();
if (!mouse->relative_mode || mouse->relative_mode_warp) {
SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
if (window) {
SDL_SendMouseMotion(0, window, 0, 0, (float)xev->event_x, (float)xev->event_y);
}
}
}
return 1;
} break;
case XI_TouchBegin:
{
const XIDeviceEvent *xev = (const XIDeviceEvent *)cookie->data;
float x, y;
SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
xinput2_normalize_touch_coordinates(window, xev->event_x, xev->event_y, &x, &y);
SDL_SendTouch(0, xev->sourceid, xev->detail, window, SDL_TRUE, x, y, 1.0);
return 1;
} break;
case XI_TouchEnd:
{
const XIDeviceEvent *xev = (const XIDeviceEvent *)cookie->data;
float x, y;
SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
xinput2_normalize_touch_coordinates(window, xev->event_x, xev->event_y, &x, &y);
SDL_SendTouch(0, xev->sourceid, xev->detail, window, SDL_FALSE, x, y, 1.0);
return 1;
} break;
case XI_TouchUpdate:
{
const XIDeviceEvent *xev = (const XIDeviceEvent *)cookie->data;
float x, y;
SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
xinput2_normalize_touch_coordinates(window, xev->event_x, xev->event_y, &x, &y);
SDL_SendTouchMotion(0, xev->sourceid, xev->detail, window, x, y, 1.0);
return 1;
} break;
#endif
}
#endif
return 0;
}
void X11_InitXinput2Multitouch(SDL_VideoDevice *_this)
{
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
SDL_VideoData *data = _this->driverdata;
XIDeviceInfo *info;
int ndevices, i, j;
if (!X11_Xinput2IsMultitouchSupported()) {
return;
}
info = X11_XIQueryDevice(data->display, XIAllDevices, &ndevices);
for (i = 0; i < ndevices; i++) {
XIDeviceInfo *dev = &info[i];
for (j = 0; j < dev->num_classes; j++) {
SDL_TouchID touchId;
SDL_TouchDeviceType touchType;
XIAnyClassInfo *class = dev->classes[j];
XITouchClassInfo *t = (XITouchClassInfo *)class;
/* Only touch devices */
if (class->type != XITouchClass) {
continue;
}
if (t->mode == XIDependentTouch) {
touchType = SDL_TOUCH_DEVICE_INDIRECT_RELATIVE;
} else { /* XIDirectTouch */
touchType = SDL_TOUCH_DEVICE_DIRECT;
}
touchId = t->sourceid;
SDL_AddTouch(touchId, touchType, dev->name);
}
}
X11_XIFreeDeviceInfo(info);
#endif
}
void X11_Xinput2SelectTouch(SDL_VideoDevice *_this, SDL_Window *window)
{
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
SDL_VideoData *data = NULL;
XIEventMask eventmask;
unsigned char mask[4] = { 0, 0, 0, 0 };
SDL_WindowData *window_data = NULL;
if (!X11_Xinput2IsMultitouchSupported()) {
return;
}
data = _this->driverdata;
window_data = window->driverdata;
eventmask.deviceid = XIAllMasterDevices;
eventmask.mask_len = sizeof(mask);
eventmask.mask = mask;
XISetMask(mask, XI_TouchBegin);
XISetMask(mask, XI_TouchUpdate);
XISetMask(mask, XI_TouchEnd);
XISetMask(mask, XI_Motion);
X11_XISelectEvents(data->display, window_data->xwindow, &eventmask, 1);
#endif
}
int X11_Xinput2IsInitialized(void)
{
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
return xinput2_initialized;
#else
return 0;
#endif
}
int X11_Xinput2IsMultitouchSupported(void)
{
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
return xinput2_initialized && xinput2_multitouch_supported;
#else
return 0;
#endif
}
void X11_Xinput2GrabTouch(SDL_VideoDevice *_this, SDL_Window *window)
{
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
SDL_WindowData *data = window->driverdata;
Display *display = data->videodata->display;
unsigned char mask[4] = { 0, 0, 0, 0 };
XIGrabModifiers mods;
XIEventMask eventmask;
if (!X11_Xinput2IsMultitouchSupported()) {
return;
}
mods.modifiers = XIAnyModifier;
mods.status = 0;
eventmask.deviceid = XIAllDevices;
eventmask.mask_len = sizeof(mask);
eventmask.mask = mask;
XISetMask(eventmask.mask, XI_TouchBegin);
XISetMask(eventmask.mask, XI_TouchUpdate);
XISetMask(eventmask.mask, XI_TouchEnd);
XISetMask(eventmask.mask, XI_Motion);
X11_XIGrabTouchBegin(display, XIAllDevices, data->xwindow, True, &eventmask, 1, &mods);
#endif
}
void X11_Xinput2UngrabTouch(SDL_VideoDevice *_this, SDL_Window *window)
{
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
SDL_WindowData *data = window->driverdata;
Display *display = data->videodata->display;
XIGrabModifiers mods;
if (!X11_Xinput2IsMultitouchSupported()) {
return;
}
mods.modifiers = XIAnyModifier;
mods.status = 0;
X11_XIUngrabTouchBegin(display, XIAllDevices, data->xwindow, 1, &mods);
#endif
}
#endif /* SDL_VIDEO_DRIVER_X11 */

View File

@ -0,0 +1,42 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_x11xinput2_h_
#define SDL_x11xinput2_h_
#ifndef SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
/* Define XGenericEventCookie as forward declaration when
*xinput2 is not available in order to compile */
struct XGenericEventCookie;
typedef struct XGenericEventCookie XGenericEventCookie;
#endif
extern void X11_InitXinput2(SDL_VideoDevice *_this);
extern void X11_InitXinput2Multitouch(SDL_VideoDevice *_this);
extern int X11_HandleXinput2Event(SDL_VideoData *videodata, XGenericEventCookie *cookie);
extern int X11_Xinput2IsInitialized(void);
extern int X11_Xinput2IsMultitouchSupported(void);
extern void X11_Xinput2SelectTouch(SDL_VideoDevice *_this, SDL_Window *window);
extern void X11_Xinput2GrabTouch(SDL_VideoDevice *_this, SDL_Window *window);
extern void X11_Xinput2UngrabTouch(SDL_VideoDevice *_this, SDL_Window *window);
#endif /* SDL_x11xinput2_h_ */

View File

@ -0,0 +1,753 @@
/*
* Copyright 2007 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* on the rights to use, copy, modify, merge, publish, distribute, sub
* license, and/or sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* Author: Soren Sandmann <sandmann@redhat.com> */
#include "SDL_internal.h"
#include "edid.h"
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdio.h>
#define TRUE 1
#define FALSE 0
static int
get_bit (int in, int bit)
{
return (in & (1 << bit)) >> bit;
}
static int
get_bits (int in, int begin, int end)
{
int mask = (1 << (end - begin + 1)) - 1;
return (in >> begin) & mask;
}
static int
decode_header (const uchar *edid)
{
if (SDL_memcmp (edid, "\x00\xff\xff\xff\xff\xff\xff\x00", 8) == 0)
return TRUE;
return FALSE;
}
static int
decode_vendor_and_product_identification (const uchar *edid, MonitorInfo *info)
{
int is_model_year;
/* Manufacturer Code */
info->manufacturer_code[0] = get_bits (edid[0x08], 2, 6);
info->manufacturer_code[1] = get_bits (edid[0x08], 0, 1) << 3;
info->manufacturer_code[1] |= get_bits (edid[0x09], 5, 7);
info->manufacturer_code[2] = get_bits (edid[0x09], 0, 4);
info->manufacturer_code[3] = '\0';
info->manufacturer_code[0] += 'A' - 1;
info->manufacturer_code[1] += 'A' - 1;
info->manufacturer_code[2] += 'A' - 1;
/* Product Code */
info->product_code = edid[0x0b] << 8 | edid[0x0a];
/* Serial Number */
info->serial_number =
edid[0x0c] | edid[0x0d] << 8 | edid[0x0e] << 16 | (Uint32)edid[0x0f] << 24;
/* Week and Year */
is_model_year = FALSE;
switch (edid[0x10])
{
case 0x00:
info->production_week = -1;
break;
case 0xff:
info->production_week = -1;
is_model_year = TRUE;
break;
default:
info->production_week = edid[0x10];
break;
}
if (is_model_year)
{
info->production_year = -1;
info->model_year = 1990 + edid[0x11];
}
else
{
info->production_year = 1990 + edid[0x11];
info->model_year = -1;
}
return TRUE;
}
static int
decode_edid_version (const uchar *edid, MonitorInfo *info)
{
info->major_version = edid[0x12];
info->minor_version = edid[0x13];
return TRUE;
}
static int
decode_display_parameters (const uchar *edid, MonitorInfo *info)
{
/* Digital vs Analog */
info->is_digital = get_bit (edid[0x14], 7);
if (info->is_digital)
{
int bits;
static const int bit_depth[8] =
{
-1, 6, 8, 10, 12, 14, 16, -1
};
static const Interface interfaces[6] =
{
UNDEFINED, DVI, HDMI_A, HDMI_B, MDDI, DISPLAY_PORT
};
bits = get_bits (edid[0x14], 4, 6);
info->ad.digital.bits_per_primary = bit_depth[bits];
bits = get_bits (edid[0x14], 0, 3);
if (bits <= 5)
info->ad.digital.interface = interfaces[bits];
else
info->ad.digital.interface = UNDEFINED;
}
else
{
int bits = get_bits (edid[0x14], 5, 6);
static const double levels[][3] =
{
{ 0.7, 0.3, 1.0 },
{ 0.714, 0.286, 1.0 },
{ 1.0, 0.4, 1.4 },
{ 0.7, 0.0, 0.7 },
};
info->ad.analog.video_signal_level = levels[bits][0];
info->ad.analog.sync_signal_level = levels[bits][1];
info->ad.analog.total_signal_level = levels[bits][2];
info->ad.analog.blank_to_black = get_bit (edid[0x14], 4);
info->ad.analog.separate_hv_sync = get_bit (edid[0x14], 3);
info->ad.analog.composite_sync_on_h = get_bit (edid[0x14], 2);
info->ad.analog.composite_sync_on_green = get_bit (edid[0x14], 1);
info->ad.analog.serration_on_vsync = get_bit (edid[0x14], 0);
}
/* Screen Size / Aspect Ratio */
if (edid[0x15] == 0 && edid[0x16] == 0)
{
info->width_mm = -1;
info->height_mm = -1;
info->aspect_ratio = -1.0;
}
else if (edid[0x16] == 0)
{
info->width_mm = -1;
info->height_mm = -1;
info->aspect_ratio = 100.0 / (edid[0x15] + 99);
}
else if (edid[0x15] == 0)
{
info->width_mm = -1;
info->height_mm = -1;
info->aspect_ratio = 100.0 / (edid[0x16] + 99);
info->aspect_ratio = 1/info->aspect_ratio; /* portrait */
}
else
{
info->width_mm = 10 * edid[0x15];
info->height_mm = 10 * edid[0x16];
}
/* Gamma */
if (edid[0x17] == 0xFF)
info->gamma = -1.0;
else
info->gamma = (edid[0x17] + 100.0) / 100.0;
/* Features */
info->standby = get_bit (edid[0x18], 7);
info->suspend = get_bit (edid[0x18], 6);
info->active_off = get_bit (edid[0x18], 5);
if (info->is_digital)
{
info->ad.digital.rgb444 = TRUE;
if (get_bit (edid[0x18], 3))
info->ad.digital.ycrcb444 = 1;
if (get_bit (edid[0x18], 4))
info->ad.digital.ycrcb422 = 1;
}
else
{
int bits = get_bits (edid[0x18], 3, 4);
ColorType color_type[4] =
{
MONOCHROME, RGB, OTHER_COLOR, UNDEFINED_COLOR
};
info->ad.analog.color_type = color_type[bits];
}
info->srgb_is_standard = get_bit (edid[0x18], 2);
/* In 1.3 this is called "has preferred timing" */
info->preferred_timing_includes_native = get_bit (edid[0x18], 1);
/* FIXME: In 1.3 this indicates whether the monitor accepts GTF */
info->continuous_frequency = get_bit (edid[0x18], 0);
return TRUE;
}
static double
decode_fraction (int high, int low)
{
double result = 0.0;
int i;
high = (high << 2) | low;
for (i = 0; i < 10; ++i)
result += get_bit (high, i) * SDL_pow (2, i - 10);
return result;
}
static int
decode_color_characteristics (const uchar *edid, MonitorInfo *info)
{
info->red_x = decode_fraction (edid[0x1b], get_bits (edid[0x19], 6, 7));
info->red_y = decode_fraction (edid[0x1c], get_bits (edid[0x19], 5, 4));
info->green_x = decode_fraction (edid[0x1d], get_bits (edid[0x19], 2, 3));
info->green_y = decode_fraction (edid[0x1e], get_bits (edid[0x19], 0, 1));
info->blue_x = decode_fraction (edid[0x1f], get_bits (edid[0x1a], 6, 7));
info->blue_y = decode_fraction (edid[0x20], get_bits (edid[0x1a], 4, 5));
info->white_x = decode_fraction (edid[0x21], get_bits (edid[0x1a], 2, 3));
info->white_y = decode_fraction (edid[0x22], get_bits (edid[0x1a], 0, 1));
return TRUE;
}
static int
decode_established_timings (const uchar *edid, MonitorInfo *info)
{
static const Timing established[][8] =
{
{
{ 800, 600, 60 },
{ 800, 600, 56 },
{ 640, 480, 75 },
{ 640, 480, 72 },
{ 640, 480, 67 },
{ 640, 480, 60 },
{ 720, 400, 88 },
{ 720, 400, 70 }
},
{
{ 1280, 1024, 75 },
{ 1024, 768, 75 },
{ 1024, 768, 70 },
{ 1024, 768, 60 },
{ 1024, 768, 87 },
{ 832, 624, 75 },
{ 800, 600, 75 },
{ 800, 600, 72 }
},
{
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 0, 0, 0 },
{ 1152, 870, 75 }
},
};
int i, j, idx;
idx = 0;
for (i = 0; i < 3; ++i)
{
for (j = 0; j < 8; ++j)
{
int byte = edid[0x23 + i];
if (get_bit (byte, j) && established[i][j].frequency != 0)
info->established[idx++] = established[i][j];
}
}
return TRUE;
}
static int
decode_standard_timings (const uchar *edid, MonitorInfo *info)
{
int i;
for (i = 0; i < 8; i++)
{
int first = edid[0x26 + 2 * i];
int second = edid[0x27 + 2 * i];
if (first != 0x01 && second != 0x01)
{
int w = 8 * (first + 31);
int h = 0;
switch (get_bits (second, 6, 7))
{
case 0x00: h = (w / 16) * 10; break;
case 0x01: h = (w / 4) * 3; break;
case 0x02: h = (w / 5) * 4; break;
case 0x03: h = (w / 16) * 9; break;
}
info->standard[i].width = w;
info->standard[i].height = h;
info->standard[i].frequency = get_bits (second, 0, 5) + 60;
}
}
return TRUE;
}
static void
decode_lf_string (const uchar *s, int n_chars, char *result)
{
int i;
for (i = 0; i < n_chars; ++i)
{
if (s[i] == 0x0a)
{
*result++ = '\0';
break;
}
else if (s[i] == 0x00)
{
/* Convert embedded 0's to spaces */
*result++ = ' ';
}
else
{
*result++ = s[i];
}
}
}
static void
decode_display_descriptor (const uchar *desc,
MonitorInfo *info)
{
switch (desc[0x03])
{
case 0xFC:
decode_lf_string (desc + 5, 13, info->dsc_product_name);
break;
case 0xFF:
decode_lf_string (desc + 5, 13, info->dsc_serial_number);
break;
case 0xFE:
decode_lf_string (desc + 5, 13, info->dsc_string);
break;
case 0xFD:
/* Range Limits */
break;
case 0xFB:
/* Color Point */
break;
case 0xFA:
/* Timing Identifications */
break;
case 0xF9:
/* Color Management */
break;
case 0xF8:
/* Timing Codes */
break;
case 0xF7:
/* Established Timings */
break;
case 0x10:
break;
}
}
static void
decode_detailed_timing (const uchar *timing,
DetailedTiming *detailed)
{
int bits;
StereoType stereo[] =
{
NO_STEREO, NO_STEREO, FIELD_RIGHT, FIELD_LEFT,
TWO_WAY_RIGHT_ON_EVEN, TWO_WAY_LEFT_ON_EVEN,
FOUR_WAY_INTERLEAVED, SIDE_BY_SIDE
};
detailed->pixel_clock = (timing[0x00] | timing[0x01] << 8) * 10000;
detailed->h_addr = timing[0x02] | ((timing[0x04] & 0xf0) << 4);
detailed->h_blank = timing[0x03] | ((timing[0x04] & 0x0f) << 8);
detailed->v_addr = timing[0x05] | ((timing[0x07] & 0xf0) << 4);
detailed->v_blank = timing[0x06] | ((timing[0x07] & 0x0f) << 8);
detailed->h_front_porch = timing[0x08] | get_bits (timing[0x0b], 6, 7) << 8;
detailed->h_sync = timing[0x09] | get_bits (timing[0x0b], 4, 5) << 8;
detailed->v_front_porch =
get_bits (timing[0x0a], 4, 7) | get_bits (timing[0x0b], 2, 3) << 4;
detailed->v_sync =
get_bits (timing[0x0a], 0, 3) | get_bits (timing[0x0b], 0, 1) << 4;
detailed->width_mm = timing[0x0c] | get_bits (timing[0x0e], 4, 7) << 8;
detailed->height_mm = timing[0x0d] | get_bits (timing[0x0e], 0, 3) << 8;
detailed->right_border = timing[0x0f];
detailed->top_border = timing[0x10];
detailed->interlaced = get_bit (timing[0x11], 7);
/* Stereo */
bits = get_bits (timing[0x11], 5, 6) << 1 | get_bit (timing[0x11], 0);
detailed->stereo = stereo[bits];
/* Sync */
bits = timing[0x11];
detailed->digital_sync = get_bit (bits, 4);
if (detailed->digital_sync)
{
detailed->ad.digital.composite = !get_bit (bits, 3);
if (detailed->ad.digital.composite)
{
detailed->ad.digital.serrations = get_bit (bits, 2);
detailed->ad.digital.negative_vsync = FALSE;
}
else
{
detailed->ad.digital.serrations = FALSE;
detailed->ad.digital.negative_vsync = !get_bit (bits, 2);
}
detailed->ad.digital.negative_hsync = !get_bit (bits, 0);
}
else
{
detailed->ad.analog.bipolar = get_bit (bits, 3);
detailed->ad.analog.serrations = get_bit (bits, 2);
detailed->ad.analog.sync_on_green = !get_bit (bits, 1);
}
}
static int
decode_descriptors (const uchar *edid, MonitorInfo *info)
{
int i;
int timing_idx;
timing_idx = 0;
for (i = 0; i < 4; ++i)
{
int index = 0x36 + i * 18;
if (edid[index + 0] == 0x00 && edid[index + 1] == 0x00)
{
decode_display_descriptor (edid + index, info);
}
else
{
decode_detailed_timing (
edid + index, &(info->detailed_timings[timing_idx++]));
}
}
info->n_detailed_timings = timing_idx;
return TRUE;
}
static void
decode_check_sum (const uchar *edid,
MonitorInfo *info)
{
int i;
uchar check = 0;
for (i = 0; i < 128; ++i)
check += edid[i];
info->checksum = check;
}
MonitorInfo *
decode_edid (const uchar *edid)
{
MonitorInfo *info = SDL_calloc (1, sizeof (MonitorInfo));
decode_check_sum (edid, info);
if (!decode_header (edid) ||
!decode_vendor_and_product_identification (edid, info) ||
!decode_edid_version (edid, info) ||
!decode_display_parameters (edid, info) ||
!decode_color_characteristics (edid, info) ||
!decode_established_timings (edid, info) ||
!decode_standard_timings (edid, info) ||
!decode_descriptors (edid, info)) {
SDL_free(info);
return NULL;
}
return info;
}
static const char *
yesno (int v)
{
return v? "yes" : "no";
}
void
dump_monitor_info (MonitorInfo *info)
{
int i;
printf ("Checksum: %d (%s)\n",
info->checksum, info->checksum? "incorrect" : "correct");
printf ("Manufacturer Code: %s\n", info->manufacturer_code);
printf ("Product Code: 0x%x\n", info->product_code);
printf ("Serial Number: %u\n", info->serial_number);
if (info->production_week != -1)
printf ("Production Week: %d\n", info->production_week);
else
printf ("Production Week: unspecified\n");
if (info->production_year != -1)
printf ("Production Year: %d\n", info->production_year);
else
printf ("Production Year: unspecified\n");
if (info->model_year != -1)
printf ("Model Year: %d\n", info->model_year);
else
printf ("Model Year: unspecified\n");
printf ("EDID revision: %d.%d\n", info->major_version, info->minor_version);
printf ("Display is %s\n", info->is_digital? "digital" : "analog");
if (info->is_digital)
{
const char *interface;
if (info->ad.digital.bits_per_primary != -1)
printf ("Bits Per Primary: %d\n", info->ad.digital.bits_per_primary);
else
printf ("Bits Per Primary: undefined\n");
switch (info->ad.digital.interface)
{
case DVI: interface = "DVI"; break;
case HDMI_A: interface = "HDMI-a"; break;
case HDMI_B: interface = "HDMI-b"; break;
case MDDI: interface = "MDDI"; break;
case DISPLAY_PORT: interface = "DisplayPort"; break;
case UNDEFINED: interface = "undefined"; break;
default: interface = "unknown"; break;
}
printf ("Interface: %s\n", interface);
printf ("RGB 4:4:4: %s\n", yesno (info->ad.digital.rgb444));
printf ("YCrCb 4:4:4: %s\n", yesno (info->ad.digital.ycrcb444));
printf ("YCrCb 4:2:2: %s\n", yesno (info->ad.digital.ycrcb422));
}
else
{
const char *s;
printf ("Video Signal Level: %f\n", info->ad.analog.video_signal_level);
printf ("Sync Signal Level: %f\n", info->ad.analog.sync_signal_level);
printf ("Total Signal Level: %f\n", info->ad.analog.total_signal_level);
printf ("Blank to Black: %s\n",
yesno (info->ad.analog.blank_to_black));
printf ("Separate HV Sync: %s\n",
yesno (info->ad.analog.separate_hv_sync));
printf ("Composite Sync on H: %s\n",
yesno (info->ad.analog.composite_sync_on_h));
printf ("Serration on VSync: %s\n",
yesno (info->ad.analog.serration_on_vsync));
switch (info->ad.analog.color_type)
{
case UNDEFINED_COLOR: s = "undefined"; break;
case MONOCHROME: s = "monochrome"; break;
case RGB: s = "rgb"; break;
case OTHER_COLOR: s = "other color"; break;
default: s = "unknown"; break;
}
printf ("Color: %s\n", s);
}
if (info->width_mm == -1)
printf ("Width: undefined\n");
else
printf ("Width: %d mm\n", info->width_mm);
if (info->height_mm == -1)
printf ("Height: undefined\n");
else
printf ("Height: %d mm\n", info->height_mm);
if (info->aspect_ratio > 0)
printf ("Aspect Ratio: %f\n", info->aspect_ratio);
else
printf ("Aspect Ratio: undefined\n");
if (info->gamma >= 0)
printf ("Gamma: %f\n", info->gamma);
else
printf ("Gamma: undefined\n");
printf ("Standby: %s\n", yesno (info->standby));
printf ("Suspend: %s\n", yesno (info->suspend));
printf ("Active Off: %s\n", yesno (info->active_off));
printf ("SRGB is Standard: %s\n", yesno (info->srgb_is_standard));
printf ("Preferred Timing Includes Native: %s\n",
yesno (info->preferred_timing_includes_native));
printf ("Continuous Frequency: %s\n", yesno (info->continuous_frequency));
printf ("Red X: %f\n", info->red_x);
printf ("Red Y: %f\n", info->red_y);
printf ("Green X: %f\n", info->green_x);
printf ("Green Y: %f\n", info->green_y);
printf ("Blue X: %f\n", info->blue_x);
printf ("Blue Y: %f\n", info->blue_y);
printf ("White X: %f\n", info->white_x);
printf ("White Y: %f\n", info->white_y);
printf ("Established Timings:\n");
for (i = 0; i < 24; ++i)
{
Timing *timing = &(info->established[i]);
if (timing->frequency == 0)
break;
printf (" %d x %d @ %d Hz\n",
timing->width, timing->height, timing->frequency);
}
printf ("Standard Timings:\n");
for (i = 0; i < 8; ++i)
{
Timing *timing = &(info->standard[i]);
if (timing->frequency == 0)
break;
printf (" %d x %d @ %d Hz\n",
timing->width, timing->height, timing->frequency);
}
for (i = 0; i < info->n_detailed_timings; ++i)
{
DetailedTiming *timing = &(info->detailed_timings[i]);
const char *s;
printf ("Timing%s: \n",
(i == 0 && info->preferred_timing_includes_native)?
" (Preferred)" : "");
printf (" Pixel Clock: %d\n", timing->pixel_clock);
printf (" H Addressable: %d\n", timing->h_addr);
printf (" H Blank: %d\n", timing->h_blank);
printf (" H Front Porch: %d\n", timing->h_front_porch);
printf (" H Sync: %d\n", timing->h_sync);
printf (" V Addressable: %d\n", timing->v_addr);
printf (" V Blank: %d\n", timing->v_blank);
printf (" V Front Porch: %d\n", timing->v_front_porch);
printf (" V Sync: %d\n", timing->v_sync);
printf (" Width: %d mm\n", timing->width_mm);
printf (" Height: %d mm\n", timing->height_mm);
printf (" Right Border: %d\n", timing->right_border);
printf (" Top Border: %d\n", timing->top_border);
switch (timing->stereo)
{
default:
case NO_STEREO: s = "No Stereo"; break;
case FIELD_RIGHT: s = "Field Sequential, Right on Sync"; break;
case FIELD_LEFT: s = "Field Sequential, Left on Sync"; break;
case TWO_WAY_RIGHT_ON_EVEN: s = "Two-way, Right on Even"; break;
case TWO_WAY_LEFT_ON_EVEN: s = "Two-way, Left on Even"; break;
case FOUR_WAY_INTERLEAVED: s = "Four-way Interleaved"; break;
case SIDE_BY_SIDE: s = "Side-by-Side"; break;
}
printf (" Stereo: %s\n", s);
if (timing->digital_sync)
{
printf (" Digital Sync:\n");
printf (" composite: %s\n", yesno (timing->ad.digital.composite));
printf (" serrations: %s\n", yesno (timing->ad.digital.serrations));
printf (" negative vsync: %s\n",
yesno (timing->ad.digital.negative_vsync));
printf (" negative hsync: %s\n",
yesno (timing->ad.digital.negative_hsync));
}
else
{
printf (" Analog Sync:\n");
printf (" bipolar: %s\n", yesno (timing->ad.analog.bipolar));
printf (" serrations: %s\n", yesno (timing->ad.analog.serrations));
printf (" sync on green: %s\n", yesno (
timing->ad.analog.sync_on_green));
}
}
printf ("Detailed Product information:\n");
printf (" Product Name: %s\n", info->dsc_product_name);
printf (" Serial Number: %s\n", info->dsc_serial_number);
printf (" Unspecified String: %s\n", info->dsc_string);
}

167
external/sdl/SDL/src/video/x11/edid.h vendored Normal file
View File

@ -0,0 +1,167 @@
typedef unsigned char uchar;
typedef struct MonitorInfo MonitorInfo;
typedef struct Timing Timing;
typedef struct DetailedTiming DetailedTiming;
typedef enum
{
UNDEFINED,
DVI,
HDMI_A,
HDMI_B,
MDDI,
DISPLAY_PORT
} Interface;
typedef enum
{
UNDEFINED_COLOR,
MONOCHROME,
RGB,
OTHER_COLOR
} ColorType;
typedef enum
{
NO_STEREO,
FIELD_RIGHT,
FIELD_LEFT,
TWO_WAY_RIGHT_ON_EVEN,
TWO_WAY_LEFT_ON_EVEN,
FOUR_WAY_INTERLEAVED,
SIDE_BY_SIDE
} StereoType;
struct Timing
{
int width;
int height;
int frequency;
};
struct DetailedTiming
{
int pixel_clock;
int h_addr;
int h_blank;
int h_sync;
int h_front_porch;
int v_addr;
int v_blank;
int v_sync;
int v_front_porch;
int width_mm;
int height_mm;
int right_border;
int top_border;
int interlaced;
StereoType stereo;
int digital_sync;
union
{
struct
{
int bipolar;
int serrations;
int sync_on_green;
} analog;
struct
{
int composite;
int serrations;
int negative_vsync;
int negative_hsync;
} digital;
} ad;
};
struct MonitorInfo
{
int checksum;
char manufacturer_code[4];
int product_code;
unsigned int serial_number;
int production_week; /* -1 if not specified */
int production_year; /* -1 if not specified */
int model_year; /* -1 if not specified */
int major_version;
int minor_version;
int is_digital;
union
{
struct
{
int bits_per_primary;
Interface interface;
int rgb444;
int ycrcb444;
int ycrcb422;
} digital;
struct
{
double video_signal_level;
double sync_signal_level;
double total_signal_level;
int blank_to_black;
int separate_hv_sync;
int composite_sync_on_h;
int composite_sync_on_green;
int serration_on_vsync;
ColorType color_type;
} analog;
} ad;
int width_mm; /* -1 if not specified */
int height_mm; /* -1 if not specified */
double aspect_ratio; /* -1.0 if not specififed */
double gamma; /* -1.0 if not specified */
int standby;
int suspend;
int active_off;
int srgb_is_standard;
int preferred_timing_includes_native;
int continuous_frequency;
double red_x;
double red_y;
double green_x;
double green_y;
double blue_x;
double blue_y;
double white_x;
double white_y;
Timing established[24]; /* Terminated by 0x0x0 */
Timing standard[8];
int n_detailed_timings;
DetailedTiming detailed_timings[4]; /* If monitor has a preferred
* mode, it is the first one
* (whether it has, is
* determined by the
* preferred_timing_includes
* bit.
*/
/* Optional product description */
char dsc_serial_number[14];
char dsc_product_name[14];
char dsc_string[14]; /* Unspecified ASCII data */
};
MonitorInfo *decode_edid(const uchar *data);
void dump_monitor_info(MonitorInfo *info);
char *make_display_name(const char *output_name,
const MonitorInfo *info);