mirror of
https://github.com/thunderbrewhq/thunderbrew
synced 2025-12-14 03:52:30 +00:00
chore(build): use SDL3
This commit is contained in:
parent
9d04a35d87
commit
b3c0734a9e
3286 changed files with 866354 additions and 554996 deletions
329
vendor/sdl-3.2.10/src/video/x11/SDL_x11clipboard.c
vendored
Normal file
329
vendor/sdl-3.2.10/src/video/x11/SDL_x11clipboard.c
vendored
Normal file
|
|
@ -0,0 +1,329 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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[] = {
|
||||
"UTF8_STRING",
|
||||
"text/plain;charset=utf-8",
|
||||
"text/plain",
|
||||
"TEXT",
|
||||
"STRING"
|
||||
};
|
||||
|
||||
// Get any application owned window handle for clipboard association
|
||||
Window GetWindow(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
|
||||
/* 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_XSelectInput(dpy, data->clipboard_window, PropertyChangeMask);
|
||||
X11_XFlush(data->display);
|
||||
}
|
||||
|
||||
return data->clipboard_window;
|
||||
}
|
||||
|
||||
static bool 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->internal;
|
||||
Display *display = videodata->display;
|
||||
Window window;
|
||||
SDLX11_ClipboardData *clipboard;
|
||||
bool clipboard_owner = 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 canceling 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;
|
||||
|
||||
X11_XSetSelectionOwner(display, selection, window, CurrentTime);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void *CloneDataBuffer(const void *buffer, const size_t len)
|
||||
{
|
||||
void *clone = NULL;
|
||||
if (len > 0 && buffer) {
|
||||
clone = SDL_malloc(len + sizeof(Uint32));
|
||||
if (clone) {
|
||||
SDL_memcpy(clone, buffer, len);
|
||||
SDL_memset((Uint8 *)clone + len, 0, sizeof(Uint32));
|
||||
}
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
/*
|
||||
* original_buffer is considered unusable after the function is called.
|
||||
*/
|
||||
static void *AppendDataBuffer(void *original_buffer, const size_t old_len, const void *buffer, const size_t buffer_len)
|
||||
{
|
||||
void *resized_buffer;
|
||||
|
||||
if (buffer_len > 0 && buffer) {
|
||||
resized_buffer = SDL_realloc(original_buffer, old_len + buffer_len + sizeof(Uint32));
|
||||
if (resized_buffer) {
|
||||
SDL_memcpy((Uint8 *)resized_buffer + old_len, buffer, buffer_len);
|
||||
SDL_memset((Uint8 *)resized_buffer + old_len + buffer_len, 0, sizeof(Uint32));
|
||||
}
|
||||
|
||||
return resized_buffer;
|
||||
} else {
|
||||
return original_buffer;
|
||||
}
|
||||
}
|
||||
|
||||
static bool WaitForSelection(SDL_VideoDevice *_this, Atom selection_type, bool *flag)
|
||||
{
|
||||
Uint64 waitStart;
|
||||
Uint64 waitElapsed;
|
||||
|
||||
waitStart = SDL_GetTicks();
|
||||
*flag = true;
|
||||
while (*flag) {
|
||||
SDL_PumpEvents();
|
||||
waitElapsed = SDL_GetTicks() - waitStart;
|
||||
// Wait one second for a selection response.
|
||||
if (waitElapsed > 1000) {
|
||||
*flag = 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);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void *GetSelectionData(SDL_VideoDevice *_this, Atom selection_type,
|
||||
const char *mime_type, size_t *length)
|
||||
{
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
Display *display = videodata->display;
|
||||
Window window;
|
||||
Window owner;
|
||||
Atom selection;
|
||||
Atom seln_type;
|
||||
int seln_format;
|
||||
unsigned long count;
|
||||
unsigned long overflow;
|
||||
|
||||
SDLX11_ClipboardData *clipboard;
|
||||
void *data = NULL;
|
||||
unsigned char *src = NULL;
|
||||
bool incr_success = false;
|
||||
Atom XA_MIME = X11_XInternAtom(display, mime_type, 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 = videodata->atoms.SDL_SELECTION;
|
||||
X11_XConvertSelection(display, selection_type, XA_MIME, selection, owner,
|
||||
CurrentTime);
|
||||
|
||||
if (WaitForSelection(_this, selection_type, &videodata->selection_waiting) == false) {
|
||||
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, count);
|
||||
} else if (seln_type == videodata->atoms.INCR) {
|
||||
while (1) {
|
||||
// Only delete the property after being done with the previous "chunk".
|
||||
X11_XDeleteProperty(display, owner, selection);
|
||||
X11_XFlush(display);
|
||||
|
||||
if (WaitForSelection(_this, selection_type, &videodata->selection_incr_waiting) == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
X11_XFree(src);
|
||||
if (X11_XGetWindowProperty(display, owner, selection, 0, INT_MAX / 4, False,
|
||||
XA_MIME, &seln_type, &seln_format, &count, &overflow, &src) != Success) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
incr_success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*length == 0) {
|
||||
*length = (size_t)count;
|
||||
data = CloneDataBuffer(src, count);
|
||||
} else {
|
||||
data = AppendDataBuffer(data, *length, src, count);
|
||||
*length += (size_t)count;
|
||||
}
|
||||
|
||||
if (data == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (incr_success == false) {
|
||||
SDL_free(data);
|
||||
data = 0;
|
||||
*length = 0;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
bool X11_SetClipboardData(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
return SetSelectionData(_this, videodata->atoms.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->internal;
|
||||
return GetSelectionData(_this, videodata->atoms.CLIPBOARD, mime_type, length);
|
||||
}
|
||||
|
||||
bool X11_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type)
|
||||
{
|
||||
size_t length;
|
||||
void *data;
|
||||
data = X11_GetClipboardData(_this, mime_type, &length);
|
||||
if (data) {
|
||||
SDL_free(data);
|
||||
}
|
||||
return length > 0;
|
||||
}
|
||||
|
||||
bool 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;
|
||||
}
|
||||
|
||||
bool X11_HasPrimarySelectionText(SDL_VideoDevice *_this)
|
||||
{
|
||||
bool result = false;
|
||||
char *text = X11_GetPrimarySelectionText(_this);
|
||||
if (text) {
|
||||
if (text[0] != '\0') {
|
||||
result = true;
|
||||
}
|
||||
SDL_free(text);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void X11_QuitClipboard(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
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
|
||||
46
vendor/sdl-3.2.10/src/video/x11/SDL_x11clipboard.h
vendored
Normal file
46
vendor/sdl-3.2.10/src/video/x11/SDL_x11clipboard.h
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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 bool X11_SetClipboardData(SDL_VideoDevice *_this);
|
||||
extern void *X11_GetClipboardData(SDL_VideoDevice *_this, const char *mime_type, size_t *length);
|
||||
extern bool X11_HasClipboardData(SDL_VideoDevice *_this, const char *mime_type);
|
||||
extern bool X11_SetPrimarySelectionText(SDL_VideoDevice *_this, const char *text);
|
||||
extern char *X11_GetPrimarySelectionText(SDL_VideoDevice *_this);
|
||||
extern bool X11_HasPrimarySelectionText(SDL_VideoDevice *_this);
|
||||
extern void X11_QuitClipboard(SDL_VideoDevice *_this);
|
||||
Window GetWindow(SDL_VideoDevice *_this);
|
||||
|
||||
#endif // SDL_x11clipboard_h_
|
||||
211
vendor/sdl-3.2.10/src/video/x11/SDL_x11dyn.c
vendored
Normal file
211
vendor/sdl-3.2.10/src/video/x11/SDL_x11dyn.c
vendored
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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
|
||||
{
|
||||
SDL_SharedObject *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_arraysize(x11libs); i++) {
|
||||
if (x11libs[i].lib) {
|
||||
fn = SDL_LoadFunction(x11libs[i].lib, fnname);
|
||||
if (fn) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG_DYNAMIC_X11
|
||||
if (fn)
|
||||
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) {
|
||||
*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;
|
||||
SDL_DYNX11FN_XSetICValues X11_XSetICValues = NULL;
|
||||
SDL_DYNX11FN_XVaCreateNestedList X11_XVaCreateNestedList = 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;
|
||||
X11_XSetICValues = NULL;
|
||||
X11_XVaCreateNestedList = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_DYNAMIC
|
||||
for (i = 0; i < SDL_arraysize(x11libs); i++) {
|
||||
if (x11libs[i].lib) {
|
||||
SDL_UnloadObject(x11libs[i].lib);
|
||||
x11libs[i].lib = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns non-zero if all needed symbols were loaded.
|
||||
bool SDL_X11_LoadSymbols(void)
|
||||
{
|
||||
bool result = true; // 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_arraysize(x11libs); i++) {
|
||||
if (x11libs[i].libname) {
|
||||
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);
|
||||
X11_XSetICValues = (SDL_DYNX11FN_XSetICValues)
|
||||
X11_GetSym("XSetICValues", &SDL_X11_HAVE_UTF8);
|
||||
X11_XVaCreateNestedList = (SDL_DYNX11FN_XVaCreateNestedList)
|
||||
X11_GetSym("XVaCreateNestedList", &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();
|
||||
result = false;
|
||||
}
|
||||
|
||||
#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;
|
||||
X11_XSetICValues = XSetICValues;
|
||||
X11_XVaCreateNestedList = XVaCreateNestedList;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_X11
|
||||
113
vendor/sdl-3.2.10/src/video/x11/SDL_x11dyn.h
vendored
Normal file
113
vendor/sdl-3.2.10/src/video/x11/SDL_x11dyn.h
vendored
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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_XKBLOOKUPKEYSYM
|
||||
#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_XSYNC
|
||||
#include <X11/extensions/sync.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 *);
|
||||
|
||||
extern bool SDL_X11_LoadSymbols(void);
|
||||
extern 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, ...);
|
||||
typedef char *(*SDL_DYNX11FN_XSetICValues)(XIC, ...);
|
||||
typedef XVaNestedList (*SDL_DYNX11FN_XVaCreateNestedList)(int, ...);
|
||||
extern SDL_DYNX11FN_XCreateIC X11_XCreateIC;
|
||||
extern SDL_DYNX11FN_XGetICValues X11_XGetICValues;
|
||||
extern SDL_DYNX11FN_XSetICValues X11_XSetICValues;
|
||||
extern SDL_DYNX11FN_XVaCreateNestedList X11_XVaCreateNestedList;
|
||||
#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_
|
||||
2206
vendor/sdl-3.2.10/src/video/x11/SDL_x11events.c
vendored
Normal file
2206
vendor/sdl-3.2.10/src/video/x11/SDL_x11events.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
40
vendor/sdl-3.2.10/src/video/x11/SDL_x11events.h
vendored
Normal file
40
vendor/sdl-3.2.10/src/video/x11/SDL_x11events.h
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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 bool X11_SuspendScreenSaver(SDL_VideoDevice *_this);
|
||||
extern void X11_ReconcileKeyboardState(SDL_VideoDevice *_this);
|
||||
extern void X11_GetBorderValues(SDL_WindowData *data);
|
||||
extern Uint64 X11_GetEventTimestamp(unsigned long time);
|
||||
extern void X11_HandleKeyEvent(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_KeyboardID keyboardID, XEvent *xevent);
|
||||
extern void X11_HandleButtonPress(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_MouseID mouseID, int button, float x, float y, unsigned long time);
|
||||
extern void X11_HandleButtonRelease(SDL_VideoDevice *_this, SDL_WindowData *windowdata, SDL_MouseID mouseID, int button, unsigned long time);
|
||||
extern SDL_WindowData *X11_FindWindow(SDL_VideoDevice *_this, Window window);
|
||||
extern bool X11_ProcessHitTest(SDL_VideoDevice *_this, SDL_WindowData *data, const float x, const float y, bool force_new_result);
|
||||
extern bool X11_TriggerHitTestAction(SDL_VideoDevice *_this, SDL_WindowData *data, const float x, const float y);
|
||||
|
||||
#endif // SDL_x11events_h_
|
||||
261
vendor/sdl-3.2.10/src/video/x11/SDL_x11framebuffer.c
vendored
Normal file
261
vendor/sdl-3.2.10/src/video/x11/SDL_x11framebuffer.c
vendored
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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"
|
||||
#include "SDL_x11xsync.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 bool have_mitshm(Display *dpy)
|
||||
{
|
||||
// Only use shared memory on local X servers
|
||||
return X11_XShmQueryExtension(dpy) ? SDL_X11_HAVE_SHM : false;
|
||||
}
|
||||
|
||||
#endif // !NO_SHARED_MEMORY
|
||||
|
||||
bool X11_CreateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, SDL_PixelFormat *format,
|
||||
void **pixels, int *pitch)
|
||||
{
|
||||
SDL_WindowData *data = window->internal;
|
||||
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)) {
|
||||
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 = true;
|
||||
*pixels = shminfo->shmaddr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // not NO_SHARED_MEMORY
|
||||
|
||||
*pixels = SDL_malloc((size_t)h * (*pitch));
|
||||
if (!*pixels) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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 true;
|
||||
}
|
||||
|
||||
bool X11_UpdateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, const SDL_Rect *rects,
|
||||
int numrects)
|
||||
{
|
||||
SDL_WindowData *data = window->internal;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
|
||||
X11_HandlePresent(data->window);
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */
|
||||
|
||||
X11_XSync(display, False);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void X11_DestroyWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_WindowData *data = window->internal;
|
||||
Display *display;
|
||||
|
||||
if (!data) {
|
||||
// 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 = false;
|
||||
}
|
||||
#endif // !NO_SHARED_MEMORY
|
||||
|
||||
data->ximage = NULL;
|
||||
}
|
||||
if (data->gc) {
|
||||
X11_XFreeGC(display, data->gc);
|
||||
data->gc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_X11
|
||||
34
vendor/sdl-3.2.10/src/video/x11/SDL_x11framebuffer.h
vendored
Normal file
34
vendor/sdl-3.2.10/src/video/x11/SDL_x11framebuffer.h
vendored
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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 bool X11_CreateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window,
|
||||
SDL_PixelFormat *format,
|
||||
void **pixels, int *pitch);
|
||||
extern bool 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_
|
||||
789
vendor/sdl-3.2.10/src/video/x11/SDL_x11keyboard.c
vendored
Normal file
789
vendor/sdl-3.2.10/src/video/x11/SDL_x11keyboard.c
vendored
Normal file
|
|
@ -0,0 +1,789 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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"
|
||||
#include "../../events/SDL_keysym_to_keycode_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 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 false;
|
||||
default:
|
||||
return 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, 0);
|
||||
|
||||
if (keysym == NoSymbol) {
|
||||
return SDL_SCANCODE_UNKNOWN;
|
||||
}
|
||||
|
||||
return SDL_GetScancodeFromKeySym(keysym, keycode);
|
||||
}
|
||||
|
||||
KeySym X11_KeyCodeToSym(SDL_VideoDevice *_this, KeyCode keycode, unsigned char group, unsigned int mod_mask)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
KeySym keysym;
|
||||
unsigned int mods_ret[16];
|
||||
|
||||
SDL_zero(mods_ret);
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
|
||||
if (data->xkb.desc_ptr) {
|
||||
int num_groups = XkbKeyNumGroups(data->xkb.desc_ptr, keycode);
|
||||
unsigned char info = XkbKeyGroupInfo(data->xkb.desc_ptr, 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;
|
||||
}
|
||||
}
|
||||
|
||||
if (X11_XkbLookupKeySym(data->display, keycode, XkbBuildCoreState(mod_mask, group), mods_ret, &keysym) == NoSymbol) {
|
||||
keysym = NoSymbol;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
// TODO: Handle groups and modifiers on the legacy path.
|
||||
keysym = X11_XKeycodeToKeysym(data->display, keycode, 0);
|
||||
}
|
||||
|
||||
return keysym;
|
||||
}
|
||||
|
||||
bool X11_InitKeyboard(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
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_XKBLOOKUPKEYSYM
|
||||
{
|
||||
int xkb_major = XkbMajorVersion;
|
||||
int xkb_minor = XkbMinorVersion;
|
||||
|
||||
if (X11_XkbQueryExtension(data->display, NULL, &data->xkb.event, NULL, &xkb_major, &xkb_minor)) {
|
||||
data->xkb.desc_ptr = 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);
|
||||
|
||||
if (prev_locale) {
|
||||
prev_locale = SDL_strdup(prev_locale);
|
||||
}
|
||||
|
||||
if (prev_xmods) {
|
||||
prev_xmods = SDL_strdup(prev_xmods);
|
||||
}
|
||||
|
||||
(void)setlocale(LC_ALL, "");
|
||||
X11_XSetLocaleModifiers("");
|
||||
|
||||
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) {
|
||||
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", 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.
|
||||
*/
|
||||
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 ((SDL_GetKeymapKeycode(NULL, scancode, SDL_KMOD_NONE) & (SDLK_SCANCODE_MASK | SDLK_EXTENDED_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)", 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/):");
|
||||
#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");
|
||||
} else {
|
||||
SDL_Log("scancode = %d (%s)", scancode, SDL_GetScancodeName(scancode));
|
||||
}
|
||||
#endif
|
||||
data->key_layout[i] = scancode;
|
||||
}
|
||||
}
|
||||
|
||||
X11_UpdateKeymap(_this, false);
|
||||
|
||||
SDL_SetScancodeName(SDL_SCANCODE_APPLICATION, "Menu");
|
||||
|
||||
X11_ReconcileKeyboardState(_this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned X11_GetNumLockModifierMask(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
Display *display = videodata->display;
|
||||
unsigned num_mask = 0;
|
||||
int i, j;
|
||||
XModifierKeymap *xmods;
|
||||
unsigned n;
|
||||
|
||||
xmods = X11_XGetModifierMapping(display);
|
||||
n = xmods->max_keypermod;
|
||||
for (i = 3; i < 8; i++) {
|
||||
for (j = 0; j < n; j++) {
|
||||
KeyCode kc = xmods->modifiermap[i * n + j];
|
||||
if (videodata->key_layout[kc] == SDL_SCANCODE_NUMLOCKCLEAR) {
|
||||
num_mask = 1 << i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
X11_XFreeModifiermap(xmods);
|
||||
|
||||
return num_mask;
|
||||
}
|
||||
|
||||
static unsigned X11_GetScrollLockModifierMask(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
Display *display = videodata->display;
|
||||
unsigned num_mask = 0;
|
||||
int i, j;
|
||||
XModifierKeymap *xmods;
|
||||
unsigned n;
|
||||
|
||||
xmods = X11_XGetModifierMapping(display);
|
||||
n = xmods->max_keypermod;
|
||||
for (i = 3; i < 8; i++) {
|
||||
for (j = 0; j < n; j++) {
|
||||
KeyCode kc = xmods->modifiermap[i * n + j];
|
||||
if (videodata->key_layout[kc] == SDL_SCANCODE_SCROLLLOCK) {
|
||||
num_mask = 1 << i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
X11_XFreeModifiermap(xmods);
|
||||
|
||||
return num_mask;
|
||||
}
|
||||
|
||||
void X11_UpdateKeymap(SDL_VideoDevice *_this, bool send_event)
|
||||
{
|
||||
struct Keymod_masks
|
||||
{
|
||||
SDL_Keymod sdl_mask;
|
||||
unsigned int xkb_mask;
|
||||
} const keymod_masks[] = {
|
||||
{ SDL_KMOD_NONE, 0 },
|
||||
{ SDL_KMOD_SHIFT, ShiftMask },
|
||||
{ SDL_KMOD_CAPS, LockMask },
|
||||
{ SDL_KMOD_SHIFT | SDL_KMOD_CAPS, ShiftMask | LockMask },
|
||||
{ SDL_KMOD_MODE, Mod5Mask },
|
||||
{ SDL_KMOD_MODE | SDL_KMOD_SHIFT, Mod5Mask | ShiftMask },
|
||||
{ SDL_KMOD_MODE | SDL_KMOD_CAPS, Mod5Mask | LockMask },
|
||||
{ SDL_KMOD_MODE | SDL_KMOD_SHIFT | SDL_KMOD_CAPS, Mod5Mask | ShiftMask | LockMask },
|
||||
{ SDL_KMOD_LEVEL5, Mod3Mask },
|
||||
{ SDL_KMOD_LEVEL5 | SDL_KMOD_SHIFT, Mod3Mask | ShiftMask },
|
||||
{ SDL_KMOD_LEVEL5 | SDL_KMOD_CAPS, Mod3Mask | LockMask },
|
||||
{ SDL_KMOD_LEVEL5 | SDL_KMOD_SHIFT | SDL_KMOD_CAPS, Mod3Mask | ShiftMask | LockMask },
|
||||
{ SDL_KMOD_LEVEL5 | SDL_KMOD_MODE, Mod5Mask | Mod3Mask },
|
||||
{ SDL_KMOD_LEVEL5 | SDL_KMOD_MODE | SDL_KMOD_SHIFT, Mod3Mask | Mod5Mask | ShiftMask },
|
||||
{ SDL_KMOD_LEVEL5 | SDL_KMOD_MODE | SDL_KMOD_CAPS, Mod3Mask | Mod5Mask | LockMask },
|
||||
{ SDL_KMOD_LEVEL5 | SDL_KMOD_MODE | SDL_KMOD_SHIFT | SDL_KMOD_CAPS, Mod3Mask | Mod5Mask | ShiftMask | LockMask }
|
||||
};
|
||||
|
||||
SDL_VideoData *data = _this->internal;
|
||||
SDL_Scancode scancode;
|
||||
SDL_Keymap *keymap = SDL_CreateKeymap();
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
|
||||
if (data->xkb.desc_ptr) {
|
||||
XkbStateRec state;
|
||||
X11_XkbGetUpdatedMap(data->display, XkbAllClientInfoMask, data->xkb.desc_ptr);
|
||||
|
||||
if (X11_XkbGetState(data->display, XkbUseCoreKbd, &state) == Success) {
|
||||
data->xkb.current_group = state.group;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int m = 0; m < SDL_arraysize(keymod_masks); ++m) {
|
||||
for (int i = 0; i < SDL_arraysize(data->key_layout); ++i) {
|
||||
// Make sure this is a valid scancode
|
||||
scancode = data->key_layout[i];
|
||||
if (scancode == SDL_SCANCODE_UNKNOWN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const KeySym keysym = X11_KeyCodeToSym(_this, i, data->xkb.current_group, keymod_masks[m].xkb_mask);
|
||||
|
||||
if (keysym != NoSymbol) {
|
||||
SDL_Keycode keycode = SDL_GetKeyCodeFromKeySym(keysym, i, keymod_masks[m].sdl_mask);
|
||||
|
||||
if (!keycode) {
|
||||
switch (scancode) {
|
||||
case SDL_SCANCODE_RETURN:
|
||||
keycode = SDLK_RETURN;
|
||||
break;
|
||||
case SDL_SCANCODE_ESCAPE:
|
||||
keycode = SDLK_ESCAPE;
|
||||
break;
|
||||
case SDL_SCANCODE_BACKSPACE:
|
||||
keycode = SDLK_BACKSPACE;
|
||||
break;
|
||||
case SDL_SCANCODE_DELETE:
|
||||
keycode = SDLK_DELETE;
|
||||
break;
|
||||
default:
|
||||
keycode = SDL_SCANCODE_TO_KEYCODE(scancode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_SetKeymapEntry(keymap, scancode, keymod_masks[m].sdl_mask, keycode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data->xkb.numlock_mask = X11_GetNumLockModifierMask(_this);
|
||||
data->xkb.scrolllock_mask = X11_GetScrollLockModifierMask(_this);
|
||||
SDL_SetKeymap(keymap, send_event);
|
||||
}
|
||||
|
||||
void X11_QuitKeyboard(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
|
||||
if (data->xkb.desc_ptr) {
|
||||
X11_XkbFreeKeyboard(data->xkb.desc_ptr, 0, True);
|
||||
data->xkb.desc_ptr = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void X11_ClearComposition(SDL_WindowData *data)
|
||||
{
|
||||
if (data->preedit_length > 0) {
|
||||
data->preedit_text[0] = '\0';
|
||||
data->preedit_length = 0;
|
||||
}
|
||||
|
||||
if (data->ime_needs_clear_composition) {
|
||||
SDL_SendEditingText("", 0, 0);
|
||||
data->ime_needs_clear_composition = false;
|
||||
}
|
||||
}
|
||||
|
||||
static void X11_SendEditingEvent(SDL_WindowData *data)
|
||||
{
|
||||
if (data->preedit_length == 0) {
|
||||
X11_ClearComposition(data);
|
||||
return;
|
||||
}
|
||||
|
||||
bool in_highlight = false;
|
||||
int start = -1, length = 0, i;
|
||||
for (i = 0; i < data->preedit_length; ++i) {
|
||||
if (data->preedit_feedback[i] & (XIMReverse | XIMHighlight)) {
|
||||
if (start < 0) {
|
||||
start = i;
|
||||
in_highlight = true;
|
||||
}
|
||||
} else if (in_highlight) {
|
||||
// Found the end of the highlight
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (in_highlight) {
|
||||
length = (i - start);
|
||||
} else {
|
||||
start = SDL_clamp(data->preedit_cursor, 0, data->preedit_length);
|
||||
}
|
||||
SDL_SendEditingText(data->preedit_text, start, length);
|
||||
|
||||
data->ime_needs_clear_composition = true;
|
||||
}
|
||||
|
||||
static int preedit_start_callback(XIC xic, XPointer client_data, XPointer call_data)
|
||||
{
|
||||
// No limit on preedit text length
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void preedit_done_callback(XIC xic, XPointer client_data, XPointer call_data)
|
||||
{
|
||||
}
|
||||
|
||||
static void preedit_draw_callback(XIC xic, XPointer client_data, XIMPreeditDrawCallbackStruct *call_data)
|
||||
{
|
||||
SDL_WindowData *data = (SDL_WindowData *)client_data;
|
||||
int chg_first = SDL_clamp(call_data->chg_first, 0, data->preedit_length);
|
||||
int chg_length = SDL_clamp(call_data->chg_length, 0, data->preedit_length - chg_first);
|
||||
|
||||
const char *start = data->preedit_text;
|
||||
if (chg_length > 0) {
|
||||
// Delete text in range
|
||||
for (int i = 0; start && *start && i < chg_first; ++i) {
|
||||
SDL_StepUTF8(&start, NULL);
|
||||
}
|
||||
|
||||
const char *end = start;
|
||||
for (int i = 0; end && *end && i < chg_length; ++i) {
|
||||
SDL_StepUTF8(&end, NULL);
|
||||
}
|
||||
|
||||
if (end > start) {
|
||||
SDL_memmove((char *)start, end, SDL_strlen(end) + 1);
|
||||
if ((chg_first + chg_length) > data->preedit_length) {
|
||||
SDL_memmove(&data->preedit_feedback[chg_first], &data->preedit_feedback[chg_first + chg_length], (data->preedit_length - chg_first - chg_length) * sizeof(*data->preedit_feedback));
|
||||
}
|
||||
}
|
||||
data->preedit_length -= chg_length;
|
||||
}
|
||||
|
||||
XIMText *text = call_data->text;
|
||||
if (text) {
|
||||
// Insert text in range
|
||||
SDL_assert(!text->encoding_is_wchar);
|
||||
|
||||
// The text length isn't calculated as directed by the spec, recalculate it now
|
||||
if (text->string.multi_byte) {
|
||||
text->length = SDL_utf8strlen(text->string.multi_byte);
|
||||
}
|
||||
|
||||
size_t string_size = SDL_strlen(text->string.multi_byte);
|
||||
size_t size = string_size + 1;
|
||||
if (data->preedit_text) {
|
||||
size += SDL_strlen(data->preedit_text);
|
||||
}
|
||||
char *preedit_text = (char *)SDL_malloc(size * sizeof(*preedit_text));
|
||||
if (preedit_text) {
|
||||
size_t pre_size = (start - data->preedit_text);
|
||||
size_t post_size = start ? SDL_strlen(start) : 0;
|
||||
if (pre_size > 0) {
|
||||
SDL_memcpy(&preedit_text[0], data->preedit_text, pre_size);
|
||||
}
|
||||
SDL_memcpy(&preedit_text[pre_size], text->string.multi_byte, string_size);
|
||||
if (post_size > 0) {
|
||||
SDL_memcpy(&preedit_text[pre_size + string_size], start, post_size);
|
||||
}
|
||||
preedit_text[size - 1] = '\0';
|
||||
}
|
||||
|
||||
size_t feedback_size = data->preedit_length + text->length;
|
||||
XIMFeedback *feedback = (XIMFeedback *)SDL_malloc(feedback_size * sizeof(*feedback));
|
||||
if (feedback) {
|
||||
size_t pre_size = (size_t)chg_first;
|
||||
size_t post_size = (size_t)data->preedit_length - pre_size;
|
||||
if (pre_size > 0) {
|
||||
SDL_memcpy(&feedback[0], data->preedit_feedback, pre_size * sizeof(*feedback));
|
||||
}
|
||||
SDL_memcpy(&feedback[pre_size], text->feedback, text->length * sizeof(*feedback));
|
||||
if (post_size > 0) {
|
||||
SDL_memcpy(&feedback[pre_size + text->length], &data->preedit_feedback[pre_size], post_size * sizeof(*feedback));
|
||||
}
|
||||
}
|
||||
|
||||
if (preedit_text && feedback) {
|
||||
SDL_free(data->preedit_text);
|
||||
data->preedit_text = preedit_text;
|
||||
|
||||
SDL_free(data->preedit_feedback);
|
||||
data->preedit_feedback = feedback;
|
||||
|
||||
data->preedit_length += text->length;
|
||||
} else {
|
||||
SDL_free(preedit_text);
|
||||
SDL_free(feedback);
|
||||
}
|
||||
}
|
||||
|
||||
data->preedit_cursor = call_data->caret;
|
||||
|
||||
#ifdef DEBUG_XIM
|
||||
if (call_data->chg_length > 0) {
|
||||
SDL_Log("Draw callback deleted %d characters at %d", call_data->chg_length, call_data->chg_first);
|
||||
}
|
||||
if (text) {
|
||||
SDL_Log("Draw callback inserted %s at %d, caret: %d", text->string.multi_byte, call_data->chg_first, call_data->caret);
|
||||
}
|
||||
SDL_Log("Pre-edit text: %s", data->preedit_text);
|
||||
#endif
|
||||
|
||||
X11_SendEditingEvent(data);
|
||||
}
|
||||
|
||||
static void preedit_caret_callback(XIC xic, XPointer client_data, XIMPreeditCaretCallbackStruct *call_data)
|
||||
{
|
||||
SDL_WindowData *data = (SDL_WindowData *)client_data;
|
||||
|
||||
switch (call_data->direction) {
|
||||
case XIMAbsolutePosition:
|
||||
if (call_data->position != data->preedit_cursor) {
|
||||
data->preedit_cursor = call_data->position;
|
||||
X11_SendEditingEvent(data);
|
||||
}
|
||||
break;
|
||||
case XIMDontChange:
|
||||
break;
|
||||
default:
|
||||
// Not currently supported
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void X11_CreateInputContext(SDL_WindowData *data)
|
||||
{
|
||||
#ifdef X_HAVE_UTF8_STRING
|
||||
SDL_VideoData *videodata = data->videodata;
|
||||
|
||||
if (SDL_X11_HAVE_UTF8 && videodata->im) {
|
||||
const char *hint = SDL_GetHint(SDL_HINT_IME_IMPLEMENTED_UI);
|
||||
if (hint && SDL_strstr(hint, "composition")) {
|
||||
XIMCallback draw_callback;
|
||||
draw_callback.client_data = (XPointer)data;
|
||||
draw_callback.callback = (XIMProc)preedit_draw_callback;
|
||||
|
||||
XIMCallback start_callback;
|
||||
start_callback.client_data = (XPointer)data;
|
||||
start_callback.callback = (XIMProc)preedit_start_callback;
|
||||
|
||||
XIMCallback done_callback;
|
||||
done_callback.client_data = (XPointer)data;
|
||||
done_callback.callback = (XIMProc)preedit_done_callback;
|
||||
|
||||
XIMCallback caret_callback;
|
||||
caret_callback.client_data = (XPointer)data;
|
||||
caret_callback.callback = (XIMProc)preedit_caret_callback;
|
||||
|
||||
XVaNestedList attr = X11_XVaCreateNestedList(0,
|
||||
XNPreeditStartCallback, &start_callback,
|
||||
XNPreeditDoneCallback, &done_callback,
|
||||
XNPreeditDrawCallback, &draw_callback,
|
||||
XNPreeditCaretCallback, &caret_callback,
|
||||
NULL);
|
||||
if (attr) {
|
||||
data->ic = X11_XCreateIC(videodata->im,
|
||||
XNInputStyle, XIMPreeditCallbacks | XIMStatusCallbacks,
|
||||
XNPreeditAttributes, attr,
|
||||
XNClientWindow, data->xwindow,
|
||||
NULL);
|
||||
X11_XFree(attr);
|
||||
}
|
||||
}
|
||||
if (!data->ic) {
|
||||
data->ic = X11_XCreateIC(videodata->im,
|
||||
XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
|
||||
XNClientWindow, data->xwindow,
|
||||
NULL);
|
||||
}
|
||||
data->xim_spot.x = -1;
|
||||
data->xim_spot.y = -1;
|
||||
}
|
||||
#endif // X_HAVE_UTF8_STRING
|
||||
}
|
||||
|
||||
static void X11_ResetXIM(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
#ifdef X_HAVE_UTF8_STRING
|
||||
SDL_WindowData *data = window->internal;
|
||||
|
||||
if (data && data->ic) {
|
||||
// Clear any partially entered dead keys
|
||||
char *contents = X11_Xutf8ResetIC(data->ic);
|
||||
if (contents) {
|
||||
X11_XFree(contents);
|
||||
}
|
||||
}
|
||||
#endif // X_HAVE_UTF8_STRING
|
||||
}
|
||||
|
||||
bool X11_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
|
||||
{
|
||||
X11_ResetXIM(_this, window);
|
||||
|
||||
return X11_UpdateTextInputArea(_this, window);
|
||||
}
|
||||
|
||||
bool X11_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
X11_ResetXIM(_this, window);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool X11_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
#ifdef X_HAVE_UTF8_STRING
|
||||
SDL_WindowData *data = window->internal;
|
||||
|
||||
if (data && data->ic) {
|
||||
XPoint spot;
|
||||
spot.x = window->text_input_rect.x + window->text_input_cursor;
|
||||
spot.y = window->text_input_rect.y + window->text_input_rect.h;
|
||||
if (spot.x != data->xim_spot.x || spot.y != data->xim_spot.y) {
|
||||
XVaNestedList attr = X11_XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);
|
||||
if (attr) {
|
||||
X11_XSetICValues(data->ic, XNPreeditAttributes, attr, NULL);
|
||||
X11_XFree(attr);
|
||||
}
|
||||
SDL_copyp(&data->xim_spot, &spot);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool X11_HasScreenKeyboardSupport(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
return videodata->is_steam_deck;
|
||||
}
|
||||
|
||||
void X11_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
|
||||
{
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
|
||||
if (videodata->is_steam_deck) {
|
||||
/* For more documentation of the URL parameters, see:
|
||||
* https://partner.steamgames.com/doc/api/ISteamUtils#ShowFloatingGamepadTextInput
|
||||
*/
|
||||
const int k_EFloatingGamepadTextInputModeModeSingleLine = 0; // Enter dismisses the keyboard
|
||||
const int k_EFloatingGamepadTextInputModeModeMultipleLines = 1; // User needs to explicitly dismiss the keyboard
|
||||
const int k_EFloatingGamepadTextInputModeModeEmail = 2; // Keyboard is displayed in a special mode that makes it easier to enter emails
|
||||
const int k_EFloatingGamepadTextInputModeModeNumeric = 3; // Numeric keypad is shown
|
||||
char deeplink[128];
|
||||
int mode;
|
||||
|
||||
switch (SDL_GetTextInputType(props)) {
|
||||
case SDL_TEXTINPUT_TYPE_TEXT_EMAIL:
|
||||
mode = k_EFloatingGamepadTextInputModeModeEmail;
|
||||
break;
|
||||
case SDL_TEXTINPUT_TYPE_NUMBER:
|
||||
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN:
|
||||
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE:
|
||||
mode = k_EFloatingGamepadTextInputModeModeNumeric;
|
||||
break;
|
||||
default:
|
||||
if (SDL_GetTextInputMultiline(props)) {
|
||||
mode = k_EFloatingGamepadTextInputModeModeMultipleLines;
|
||||
} else {
|
||||
mode = k_EFloatingGamepadTextInputModeModeSingleLine;
|
||||
}
|
||||
break;
|
||||
}
|
||||
(void)SDL_snprintf(deeplink, sizeof(deeplink),
|
||||
"steam://open/keyboard?XPosition=0&YPosition=0&Width=0&Height=0&Mode=%d",
|
||||
mode);
|
||||
SDL_OpenURL(deeplink);
|
||||
videodata->steam_keyboard_open = true;
|
||||
}
|
||||
}
|
||||
|
||||
void X11_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
|
||||
if (videodata->is_steam_deck) {
|
||||
SDL_OpenURL("steam://close/keyboard");
|
||||
videodata->steam_keyboard_open = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool X11_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
|
||||
return videodata->steam_keyboard_open;
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_X11
|
||||
40
vendor/sdl-3.2.10/src/video/x11/SDL_x11keyboard.h
vendored
Normal file
40
vendor/sdl-3.2.10/src/video/x11/SDL_x11keyboard.h
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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 bool X11_InitKeyboard(SDL_VideoDevice *_this);
|
||||
extern void X11_UpdateKeymap(SDL_VideoDevice *_this, bool send_event);
|
||||
extern void X11_QuitKeyboard(SDL_VideoDevice *_this);
|
||||
extern void X11_CreateInputContext(SDL_WindowData *data);
|
||||
extern void X11_ClearComposition(SDL_WindowData *data);
|
||||
extern bool X11_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
|
||||
extern bool X11_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool X11_UpdateTextInputArea(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool X11_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
|
||||
extern void X11_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
|
||||
extern void X11_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool X11_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern KeySym X11_KeyCodeToSym(SDL_VideoDevice *_this, KeyCode, unsigned char group, unsigned int mod_mask);
|
||||
|
||||
#endif // SDL_x11keyboard_h_
|
||||
887
vendor/sdl-3.2.10/src/video/x11/SDL_x11messagebox.c
vendored
Normal file
887
vendor/sdl-3.2.10/src/video/x11/SDL_x11messagebox.c
vendored
Normal file
|
|
@ -0,0 +1,887 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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-*-*-*-*-iso10646-1", // explicitly unicode (iso10646-1)
|
||||
"-*-*-medium-r-*--*-120-*-*-*-*-iso10646-1", // explicitly unicode (iso10646-1)
|
||||
"-misc-*-*-*-*--*-*-*-*-*-*-iso10646-1", // misc unicode (fix for some systems)
|
||||
"-*-*-*-*-*--*-*-*-*-*-*-iso10646-1", // just give me anything Unicode.
|
||||
"-*-*-medium-r-normal--*-120-*-*-*-*-iso8859-1", // explicitly latin1, in case low-ASCII works out.
|
||||
"-*-*-medium-r-*--*-120-*-*-*-*-iso8859-1", // explicitly latin1, in case low-ASCII works out.
|
||||
"-misc-*-*-*-*--*-*-*-*-*-*-iso8859-1", // misc latin1 (fix for some systems)
|
||||
"-*-*-*-*-*--*-*-*-*-*-*-iso8859-1", // just give me anything latin1.
|
||||
NULL
|
||||
};
|
||||
|
||||
static const SDL_MessageBoxColor g_default_colors[SDL_MESSAGEBOX_COLOR_COUNT] = {
|
||||
{ 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;
|
||||
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_COUNT];
|
||||
|
||||
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)
|
||||
{
|
||||
#ifdef X_HAVE_UTF8_STRING
|
||||
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
|
||||
#endif
|
||||
{
|
||||
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 bool 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");
|
||||
}
|
||||
|
||||
#ifdef X_HAVE_UTF8_STRING
|
||||
if (SDL_X11_HAVE_UTF8) {
|
||||
char **missing = NULL;
|
||||
int num_missing = 0;
|
||||
int i_font;
|
||||
for (i_font = 0; g_MessageBoxFont[i_font]; ++i_font) {
|
||||
data->font_set = X11_XCreateFontSet(data->display, g_MessageBoxFont[i_font],
|
||||
&missing, &num_missing, NULL);
|
||||
if (missing) {
|
||||
X11_XFreeStringList(missing);
|
||||
}
|
||||
if (data->font_set) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!data->font_set) {
|
||||
return SDL_SetError("Couldn't load x11 message box font");
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
data->font_struct = X11_XLoadQueryFont(data->display, g_MessageBoxFontLatin1);
|
||||
if (!data->font_struct) {
|
||||
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_COUNT; i++) {
|
||||
data->color[i] = SDL_MAKE_RGB(colorhints[i].r, colorhints[i].g, colorhints[i].b);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int CountLinesOfText(const char *text)
|
||||
{
|
||||
int result = 0;
|
||||
while (text && *text) {
|
||||
const char *lf = SDL_strchr(text, '\n');
|
||||
result++; // even without an endline, this counts as a line.
|
||||
text = lf ? lf + 1 : NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Calculate and initialize text and button locations.
|
||||
static bool 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 && messageboxdata->message[0]) {
|
||||
const char *text = messageboxdata->message;
|
||||
const int linecount = CountLinesOfText(text);
|
||||
TextLineData *plinedata = (TextLineData *)SDL_malloc(sizeof(TextLineData) * linecount);
|
||||
|
||||
if (!plinedata) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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) {
|
||||
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 true;
|
||||
}
|
||||
|
||||
// Free SDL_MessageBoxData data.
|
||||
static void X11_MessageBoxShutdown(SDL_MessageBoxDataX11 *data)
|
||||
{
|
||||
if (data->font_set) {
|
||||
X11_XFreeFontSet(data->display, data->font_set);
|
||||
data->font_set = NULL;
|
||||
}
|
||||
|
||||
if (data->font_struct) {
|
||||
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 bool 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->internal;
|
||||
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_delete_message = X11_XInternAtom(display, "WM_DELETE_WINDOW", False);
|
||||
X11_XSetWMProtocols(display, data->window, &data->wm_delete_message, 1);
|
||||
|
||||
data->wm_protocols = X11_XInternAtom(display, "WM_PROTOCOLS", False);
|
||||
|
||||
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->internal;
|
||||
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 = true;
|
||||
data->buf = X11_XdbeAllocateBackBufferName(display, data->window, XdbeUndefined);
|
||||
} else {
|
||||
data->xdbe = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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];
|
||||
|
||||
#ifdef X_HAVE_UTF8_STRING
|
||||
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
|
||||
#endif
|
||||
{
|
||||
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]);
|
||||
|
||||
#ifdef X_HAVE_UTF8_STRING
|
||||
if (SDL_X11_HAVE_UTF8) {
|
||||
X11_Xutf8DrawString(display, window, data->font_set, ctx,
|
||||
buttondatax11->x + offset,
|
||||
buttondatax11->y + offset,
|
||||
buttondata->text, buttondatax11->length);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
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 bool X11_MessageBoxLoop(SDL_MessageBoxDataX11 *data)
|
||||
{
|
||||
GC ctx;
|
||||
XGCValues ctx_vals;
|
||||
bool close_dialog = false;
|
||||
bool has_focus = true;
|
||||
KeySym last_key_pressed = XK_VoidSymbol;
|
||||
unsigned long gcflags = GCForeground | GCBackground;
|
||||
#ifdef X_HAVE_UTF8_STRING
|
||||
const int have_utf8 = SDL_X11_HAVE_UTF8;
|
||||
#else
|
||||
const int have_utf8 = 0;
|
||||
#endif
|
||||
|
||||
SDL_zero(ctx_vals);
|
||||
ctx_vals.foreground = data->color[SDL_MESSAGEBOX_COLOR_BACKGROUND];
|
||||
ctx_vals.background = data->color[SDL_MESSAGEBOX_COLOR_BACKGROUND];
|
||||
|
||||
if (!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;
|
||||
bool draw = 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 = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case FocusIn:
|
||||
// Got focus.
|
||||
has_focus = true;
|
||||
break;
|
||||
|
||||
case FocusOut:
|
||||
// lost focus. Reset button and mouse info.
|
||||
has_focus = 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 = 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 = 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 = 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 = true;
|
||||
}
|
||||
}
|
||||
data->button_press_index = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (draw) {
|
||||
// Draw our dialog box.
|
||||
X11_MessageBoxDraw(data, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
X11_XFreeGC(data->display, ctx);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool X11_ShowMessageBoxImpl(const SDL_MessageBoxData *messageboxdata, int *buttonID)
|
||||
{
|
||||
bool result = false;
|
||||
SDL_MessageBoxDataX11 data;
|
||||
#if SDL_SET_LOCALE
|
||||
char *origlocale;
|
||||
#endif
|
||||
|
||||
SDL_zero(data);
|
||||
|
||||
if (!SDL_X11_LoadSymbols()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if SDL_SET_LOCALE
|
||||
origlocale = setlocale(LC_ALL, NULL);
|
||||
if (origlocale) {
|
||||
origlocale = SDL_strdup(origlocale);
|
||||
if (!origlocale) {
|
||||
return false;
|
||||
}
|
||||
(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.
|
||||
if (X11_MessageBoxInit(&data, messageboxdata, buttonID) &&
|
||||
X11_MessageBoxInitPositions(&data) &&
|
||||
X11_MessageBoxCreateWindow(&data)) {
|
||||
result = X11_MessageBoxLoop(&data);
|
||||
}
|
||||
|
||||
X11_MessageBoxShutdown(&data);
|
||||
|
||||
#if SDL_SET_LOCALE
|
||||
if (origlocale) {
|
||||
(void)setlocale(LC_ALL, origlocale);
|
||||
SDL_free(origlocale);
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Display an x11 message box.
|
||||
bool 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;
|
||||
bool result = true;
|
||||
|
||||
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]);
|
||||
result = X11_ShowMessageBoxImpl(messageboxdata, buttonID);
|
||||
if (write(fds[1], &result, sizeof(result)) != sizeof(result)) {
|
||||
exitcode = 1;
|
||||
} else if (write(fds[1], buttonID, sizeof(*buttonID)) != sizeof(*buttonID)) {
|
||||
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)) {
|
||||
result = SDL_SetError("msgbox child process failed");
|
||||
} else if ((read(fds[0], &result, sizeof(result)) != sizeof(result)) ||
|
||||
(read(fds[0], buttonID, sizeof(*buttonID)) != sizeof(*buttonID))) {
|
||||
result = SDL_SetError("read from msgbox child process failed");
|
||||
*buttonID = 0;
|
||||
}
|
||||
close(fds[0]);
|
||||
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
return X11_ShowMessageBoxImpl(messageboxdata, buttonID);
|
||||
#endif
|
||||
}
|
||||
#endif // SDL_VIDEO_DRIVER_X11
|
||||
31
vendor/sdl-3.2.10/src/video/x11/SDL_x11messagebox.h
vendored
Normal file
31
vendor/sdl-3.2.10/src/video/x11/SDL_x11messagebox.h
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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 bool X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID);
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_X11
|
||||
|
||||
#endif // SDL_x11messagebox_h_
|
||||
1105
vendor/sdl-3.2.10/src/video/x11/SDL_x11modes.c
vendored
Normal file
1105
vendor/sdl-3.2.10/src/video/x11/SDL_x11modes.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
69
vendor/sdl-3.2.10/src/video/x11/SDL_x11modes.h
vendored
Normal file
69
vendor/sdl-3.2.10/src/video/x11/SDL_x11modes.h
vendored
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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;
|
||||
|
||||
Uint64 mode_switch_deadline_ns;
|
||||
|
||||
bool use_xrandr;
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XRANDR
|
||||
RROutput xrandr_output;
|
||||
char connector_name[16];
|
||||
#endif
|
||||
};
|
||||
|
||||
struct SDL_DisplayModeData
|
||||
{
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XRANDR
|
||||
RRMode xrandr_mode;
|
||||
#else
|
||||
int unused; // just so struct isn't empty.
|
||||
#endif
|
||||
};
|
||||
|
||||
extern bool X11_InitModes(SDL_VideoDevice *_this);
|
||||
extern bool X11_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display);
|
||||
extern bool 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 bool X11_GetVisualInfoFromVisual(Display *display, Visual *visual, XVisualInfo *vinfo);
|
||||
extern SDL_PixelFormat X11_GetPixelFormatFromVisualInfo(Display *display, XVisualInfo *vinfo);
|
||||
extern bool X11_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *sdl_display, SDL_Rect *rect);
|
||||
extern bool 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_
|
||||
552
vendor/sdl-3.2.10/src/video/x11/SDL_x11mouse.c
vendored
Normal file
552
vendor/sdl-3.2.10/src/video/x11/SDL_x11mouse.c
vendored
Normal file
|
|
@ -0,0 +1,552 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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 "../SDL_video_c.h"
|
||||
#include "../../events/SDL_mouse_c.h"
|
||||
|
||||
struct SDL_CursorData
|
||||
{
|
||||
Cursor cursor;
|
||||
};
|
||||
|
||||
// FIXME: Find a better place to put this...
|
||||
static Cursor x11_empty_cursor = None;
|
||||
static bool x11_cursor_visible = true;
|
||||
|
||||
static SDL_Cursor *sys_cursors[SDL_HITTEST_RESIZE_LEFT + 1];
|
||||
|
||||
static Display *GetDisplay(void)
|
||||
{
|
||||
return SDL_GetVideoDevice()->internal->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_CreateCursorAndData(Cursor x11_cursor)
|
||||
{
|
||||
SDL_Cursor *cursor = (SDL_Cursor *)SDL_calloc(1, sizeof(*cursor));
|
||||
if (cursor) {
|
||||
SDL_CursorData *data = (SDL_CursorData *)SDL_calloc(1, sizeof(*data));
|
||||
if (!data) {
|
||||
SDL_free(cursor);
|
||||
return NULL;
|
||||
}
|
||||
data->cursor = x11_cursor;
|
||||
cursor->internal = data;
|
||||
}
|
||||
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) {
|
||||
SDL_OutOfMemory();
|
||||
return None;
|
||||
}
|
||||
image->xhot = hot_x;
|
||||
image->yhot = hot_y;
|
||||
image->delay = 0;
|
||||
|
||||
SDL_assert(surface->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) {
|
||||
return None;
|
||||
}
|
||||
|
||||
mask_bits = SDL_calloc(1, surface->h * width_bytes);
|
||||
if (!mask_bits) {
|
||||
SDL_free(data_bits);
|
||||
return None;
|
||||
}
|
||||
|
||||
// Code below assumes ARGB pixel format
|
||||
SDL_assert(surface->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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
return X11_CreateCursorAndData(x11_cursor);
|
||||
}
|
||||
|
||||
static unsigned int GetLegacySystemCursorShape(SDL_SystemCursor id)
|
||||
{
|
||||
switch (id) {
|
||||
// X Font Cursors reference:
|
||||
// http://tronche.com/gui/x/xlib/appendix/b/
|
||||
case SDL_SYSTEM_CURSOR_DEFAULT: return XC_left_ptr;
|
||||
case SDL_SYSTEM_CURSOR_TEXT: return XC_xterm;
|
||||
case SDL_SYSTEM_CURSOR_WAIT: return XC_watch;
|
||||
case SDL_SYSTEM_CURSOR_CROSSHAIR: return XC_tcross;
|
||||
case SDL_SYSTEM_CURSOR_PROGRESS: return XC_watch;
|
||||
case SDL_SYSTEM_CURSOR_NWSE_RESIZE: return XC_top_left_corner;
|
||||
case SDL_SYSTEM_CURSOR_NESW_RESIZE: return XC_top_right_corner;
|
||||
case SDL_SYSTEM_CURSOR_EW_RESIZE: return XC_sb_h_double_arrow;
|
||||
case SDL_SYSTEM_CURSOR_NS_RESIZE: return XC_sb_v_double_arrow;
|
||||
case SDL_SYSTEM_CURSOR_MOVE: return XC_fleur;
|
||||
case SDL_SYSTEM_CURSOR_NOT_ALLOWED: return XC_pirate;
|
||||
case SDL_SYSTEM_CURSOR_POINTER: return XC_hand2;
|
||||
case SDL_SYSTEM_CURSOR_NW_RESIZE: return XC_top_left_corner;
|
||||
case SDL_SYSTEM_CURSOR_N_RESIZE: return XC_top_side;
|
||||
case SDL_SYSTEM_CURSOR_NE_RESIZE: return XC_top_right_corner;
|
||||
case SDL_SYSTEM_CURSOR_E_RESIZE: return XC_right_side;
|
||||
case SDL_SYSTEM_CURSOR_SE_RESIZE: return XC_bottom_right_corner;
|
||||
case SDL_SYSTEM_CURSOR_S_RESIZE: return XC_bottom_side;
|
||||
case SDL_SYSTEM_CURSOR_SW_RESIZE: return XC_bottom_left_corner;
|
||||
case SDL_SYSTEM_CURSOR_W_RESIZE: return XC_left_side;
|
||||
case SDL_SYSTEM_CURSOR_COUNT: break; // so the compiler might notice if an enum value is missing here.
|
||||
}
|
||||
|
||||
SDL_assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static SDL_Cursor *X11_CreateSystemCursor(SDL_SystemCursor id)
|
||||
{
|
||||
SDL_Cursor *cursor = NULL;
|
||||
Display *dpy = GetDisplay();
|
||||
Cursor x11_cursor = None;
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XCURSOR
|
||||
if (SDL_X11_HAVE_XCURSOR) {
|
||||
x11_cursor = X11_XcursorLibraryLoadCursor(dpy, SDL_GetCSSCursorName(id, NULL));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (x11_cursor == None) {
|
||||
x11_cursor = X11_XCreateFontCursor(dpy, GetLegacySystemCursorShape(id));
|
||||
}
|
||||
|
||||
if (x11_cursor != None) {
|
||||
cursor = X11_CreateCursorAndData(x11_cursor);
|
||||
}
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
static SDL_Cursor *X11_CreateDefaultCursor(void)
|
||||
{
|
||||
SDL_SystemCursor id = SDL_GetDefaultSystemCursor();
|
||||
return X11_CreateSystemCursor(id);
|
||||
}
|
||||
|
||||
static void X11_FreeCursor(SDL_Cursor *cursor)
|
||||
{
|
||||
Cursor x11_cursor = cursor->internal->cursor;
|
||||
|
||||
if (x11_cursor != None) {
|
||||
X11_XFreeCursor(GetDisplay(), x11_cursor);
|
||||
}
|
||||
SDL_free(cursor->internal);
|
||||
SDL_free(cursor);
|
||||
}
|
||||
|
||||
static bool X11_ShowCursor(SDL_Cursor *cursor)
|
||||
{
|
||||
Cursor x11_cursor = 0;
|
||||
|
||||
if (cursor) {
|
||||
x11_cursor = cursor->internal->cursor;
|
||||
} else {
|
||||
x11_cursor = X11_CreateEmptyCursor();
|
||||
}
|
||||
|
||||
// FIXME: Is there a better way than this?
|
||||
{
|
||||
SDL_VideoDevice *video = SDL_GetVideoDevice();
|
||||
Display *display = GetDisplay();
|
||||
SDL_Window *window;
|
||||
|
||||
x11_cursor_visible = !!cursor;
|
||||
|
||||
for (window = video->windows; window; window = window->next) {
|
||||
SDL_WindowData *data = window->internal;
|
||||
if (data) {
|
||||
if (x11_cursor != None) {
|
||||
X11_XDefineCursor(display, data->xwindow, x11_cursor);
|
||||
} else {
|
||||
X11_XUndefineCursor(display, data->xwindow);
|
||||
}
|
||||
}
|
||||
}
|
||||
X11_XFlush(display);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void X11_WarpMouseInternal(Window xwindow, float x, float y)
|
||||
{
|
||||
SDL_VideoData *videodata = SDL_GetVideoDevice()->internal;
|
||||
Display *display = videodata->display;
|
||||
bool warp_hack = false;
|
||||
|
||||
// XWayland will only warp the cursor if it is hidden, so this workaround is required.
|
||||
if (videodata->is_xwayland && x11_cursor_visible) {
|
||||
warp_hack = true;
|
||||
}
|
||||
|
||||
if (warp_hack) {
|
||||
X11_ShowCursor(NULL);
|
||||
}
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
|
||||
int deviceid = 0;
|
||||
if (X11_Xinput2IsInitialized()) {
|
||||
/* 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) {
|
||||
SDL_assert(SDL_X11_HAVE_XINPUT2);
|
||||
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);
|
||||
}
|
||||
|
||||
if (warp_hack) {
|
||||
X11_ShowCursor(SDL_GetCursor());
|
||||
}
|
||||
X11_XSync(display, False);
|
||||
videodata->global_mouse_changed = true;
|
||||
}
|
||||
|
||||
static bool X11_WarpMouse(SDL_Window *window, float x, float y)
|
||||
{
|
||||
SDL_WindowData *data = window->internal;
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
|
||||
// If we have no barrier, we need to warp
|
||||
if (data->pointer_barrier_active == false) {
|
||||
X11_WarpMouseInternal(data->xwindow, x, y);
|
||||
}
|
||||
#else
|
||||
X11_WarpMouseInternal(data->xwindow, x, y);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool X11_WarpMouseGlobal(float x, float y)
|
||||
{
|
||||
X11_WarpMouseInternal(DefaultRootWindow(GetDisplay()), x, y);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool X11_SetRelativeMouseMode(bool enabled)
|
||||
{
|
||||
if (!X11_Xinput2IsInitialized()) {
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool X11_CaptureMouse(SDL_Window *window)
|
||||
{
|
||||
Display *display = GetDisplay();
|
||||
SDL_Window *mouse_focus = SDL_GetMouseFocus();
|
||||
|
||||
if (window) {
|
||||
SDL_WindowData *data = window->internal;
|
||||
|
||||
/* If XInput2 is handling the pointer input, non-confinement grabs will always fail with 'AlreadyGrabbed',
|
||||
* since the pointer is being grabbed by XInput2.
|
||||
*/
|
||||
if (!data->xinput2_mouse_enabled || data->mouse_grabbed) {
|
||||
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");
|
||||
}
|
||||
|
||||
if (data->mouse_grabbed) {
|
||||
// XGrabPointer can warp the cursor when confining, so update the coordinates.
|
||||
data->videodata->global_mouse_changed = true;
|
||||
}
|
||||
}
|
||||
} else if (mouse_focus) {
|
||||
SDL_UpdateWindowGrab(mouse_focus);
|
||||
} else {
|
||||
X11_XUngrabPointer(display, CurrentTime);
|
||||
}
|
||||
|
||||
X11_XSync(display, False);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static SDL_MouseButtonFlags X11_GetGlobalMouseState(float *x, float *y)
|
||||
{
|
||||
SDL_VideoData *videodata = SDL_GetVideoDevice()->internal;
|
||||
SDL_DisplayID *displays;
|
||||
Display *display = GetDisplay();
|
||||
int i;
|
||||
|
||||
// !!! FIXME: should we XSync() here first?
|
||||
|
||||
if (!X11_Xinput2IsInitialized()) {
|
||||
videodata->global_mouse_changed = true;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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;
|
||||
SDL_MouseButtonFlags 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 = 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_HitTestResult r = SDL_HITTEST_NORMAL;
|
||||
while (r <= SDL_HITTEST_RESIZE_LEFT) {
|
||||
switch (r) {
|
||||
case SDL_HITTEST_NORMAL: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT); break;
|
||||
case SDL_HITTEST_DRAGGABLE: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT); break;
|
||||
case SDL_HITTEST_RESIZE_TOPLEFT: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_NW_RESIZE); break;
|
||||
case SDL_HITTEST_RESIZE_TOP: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_N_RESIZE); break;
|
||||
case SDL_HITTEST_RESIZE_TOPRIGHT: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_NE_RESIZE); break;
|
||||
case SDL_HITTEST_RESIZE_RIGHT: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_E_RESIZE); break;
|
||||
case SDL_HITTEST_RESIZE_BOTTOMRIGHT: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_SE_RESIZE); break;
|
||||
case SDL_HITTEST_RESIZE_BOTTOM: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_S_RESIZE); break;
|
||||
case SDL_HITTEST_RESIZE_BOTTOMLEFT: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_SW_RESIZE); break;
|
||||
case SDL_HITTEST_RESIZE_LEFT: sys_cursors[r] = X11_CreateSystemCursor(SDL_SYSTEM_CURSOR_W_RESIZE); break;
|
||||
}
|
||||
r++;
|
||||
}
|
||||
|
||||
SDL_SetDefaultCursor(X11_CreateDefaultCursor());
|
||||
}
|
||||
|
||||
void X11_QuitMouse(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
SDL_XInput2DeviceInfo *i;
|
||||
SDL_XInput2DeviceInfo *next;
|
||||
int j;
|
||||
|
||||
for (j = 0; j < SDL_arraysize(sys_cursors); j++) {
|
||||
X11_FreeCursor(sys_cursors[j]);
|
||||
sys_cursors[j] = NULL;
|
||||
}
|
||||
|
||||
for (i = data->mouse_device_info; i; i = next) {
|
||||
next = i->next;
|
||||
SDL_free(i);
|
||||
}
|
||||
data->mouse_device_info = NULL;
|
||||
|
||||
X11_DestroyEmptyCursor();
|
||||
}
|
||||
|
||||
void X11_SetHitTestCursor(SDL_HitTestResult rc)
|
||||
{
|
||||
if (rc == SDL_HITTEST_NORMAL || rc == SDL_HITTEST_DRAGGABLE) {
|
||||
SDL_SetCursor(NULL);
|
||||
} else {
|
||||
X11_ShowCursor(sys_cursors[rc]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_X11
|
||||
40
vendor/sdl-3.2.10/src/video/x11/SDL_x11mouse.h
vendored
Normal file
40
vendor/sdl-3.2.10/src/video/x11/SDL_x11mouse.h
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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;
|
||||
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);
|
||||
extern void X11_SetHitTestCursor(SDL_HitTestResult rc);
|
||||
|
||||
#endif // SDL_x11mouse_h_
|
||||
1116
vendor/sdl-3.2.10/src/video/x11/SDL_x11opengl.c
vendored
Normal file
1116
vendor/sdl-3.2.10/src/video/x11/SDL_x11opengl.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
96
vendor/sdl-3.2.10/src/video/x11/SDL_x11opengl.h
vendored
Normal file
96
vendor/sdl-3.2.10/src/video/x11/SDL_x11opengl.h
vendored
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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);
|
||||
|
||||
typedef enum SDL_GLSwapIntervalTearBehavior
|
||||
{
|
||||
SDL_SWAPINTERVALTEAR_UNTESTED,
|
||||
SDL_SWAPINTERVALTEAR_UNKNOWN,
|
||||
SDL_SWAPINTERVALTEAR_MESA,
|
||||
SDL_SWAPINTERVALTEAR_NVIDIA
|
||||
} SDL_GLSwapIntervalTearBehavior;
|
||||
|
||||
struct SDL_GLDriverData
|
||||
{
|
||||
int errorBase, eventBase;
|
||||
|
||||
bool HAS_GLX_EXT_visual_rating;
|
||||
bool HAS_GLX_EXT_visual_info;
|
||||
bool HAS_GLX_EXT_swap_control_tear;
|
||||
bool HAS_GLX_ARB_context_flush_control;
|
||||
bool HAS_GLX_ARB_create_context_robustness;
|
||||
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;
|
||||
|
||||
SDL_GLSwapIntervalTearBehavior swap_interval_tear_behavior;
|
||||
|
||||
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 bool 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 bool X11_GL_UseEGL(SDL_VideoDevice *_this);
|
||||
extern XVisualInfo *X11_GL_GetVisual(SDL_VideoDevice *_this, Display *display, int screen, bool transparent);
|
||||
extern SDL_GLContext X11_GL_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool X11_GL_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window,
|
||||
SDL_GLContext context);
|
||||
extern bool X11_GL_SetSwapInterval(SDL_VideoDevice *_this, int interval);
|
||||
extern bool X11_GL_GetSwapInterval(SDL_VideoDevice *_this, int *interval);
|
||||
extern bool X11_GL_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool X11_GL_DestroyContext(SDL_VideoDevice *_this, SDL_GLContext context);
|
||||
|
||||
#endif // SDL_VIDEO_OPENGL_GLX
|
||||
|
||||
#endif // SDL_x11opengl_h_
|
||||
152
vendor/sdl-3.2.10/src/video/x11/SDL_x11opengles.c
vendored
Normal file
152
vendor/sdl-3.2.10/src/video/x11/SDL_x11opengles.c
vendored
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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"
|
||||
#include "SDL_x11xsync.h"
|
||||
|
||||
// EGL implementation of SDL OpenGL support
|
||||
|
||||
bool X11_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
|
||||
// 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, 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_DestroyContext = X11_GL_DestroyContext;
|
||||
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, bool transparent)
|
||||
{
|
||||
|
||||
XVisualInfo *egl_visualinfo = NULL;
|
||||
EGLint visual_id = 0;
|
||||
XVisualInfo vi_in;
|
||||
int out_count = 0;
|
||||
|
||||
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 = 0;
|
||||
}
|
||||
if (visual_id != 0) {
|
||||
vi_in.screen = screen;
|
||||
vi_in.visualid = visual_id;
|
||||
egl_visualinfo = X11_XGetVisualInfo(display, VisualScreenMask | VisualIDMask, &vi_in, &out_count);
|
||||
if (transparent && egl_visualinfo) {
|
||||
Uint32 format = X11_GetPixelFormatFromVisualInfo(display, egl_visualinfo);
|
||||
if (!SDL_ISPIXELFORMAT_ALPHA(format)) {
|
||||
// not transparent!
|
||||
X11_XFree(egl_visualinfo);
|
||||
egl_visualinfo = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!egl_visualinfo) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return egl_visualinfo;
|
||||
}
|
||||
|
||||
SDL_GLContext X11_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_GLContext context;
|
||||
SDL_WindowData *data = window->internal;
|
||||
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->internal;
|
||||
return data->egl_surface;
|
||||
}
|
||||
|
||||
bool X11_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
const bool ret = SDL_EGL_SwapBuffers(_this, window->internal->egl_surface); \
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
|
||||
X11_HandlePresent(window);
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SDL_EGL_MakeCurrent_impl(X11)
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_X11 && SDL_VIDEO_OPENGL_EGL
|
||||
|
||||
55
vendor/sdl-3.2.10/src/video/x11/SDL_x11opengles.h
vendored
Normal file
55
vendor/sdl-3.2.10/src/video/x11/SDL_x11opengles.h
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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_DestroyContext SDL_EGL_DestroyContext
|
||||
|
||||
extern bool X11_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path);
|
||||
extern XVisualInfo *X11_GLES_GetVisual(SDL_VideoDevice *_this, Display *display, int screen, bool transparent);
|
||||
extern SDL_GLContext X11_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool X11_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool 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_
|
||||
437
vendor/sdl-3.2.10/src/video/x11/SDL_x11pen.c
vendored
Normal file
437
vendor/sdl-3.2.10/src/video/x11/SDL_x11pen.c
vendored
Normal file
|
|
@ -0,0 +1,437 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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"
|
||||
|
||||
#include "../../events/SDL_pen_c.h"
|
||||
#include "../SDL_sysvideo.h"
|
||||
#include "SDL_x11pen.h"
|
||||
#include "SDL_x11video.h"
|
||||
#include "SDL_x11xinput2.h"
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
|
||||
|
||||
// Does this device have a valuator for pressure sensitivity?
|
||||
static bool X11_XInput2DeviceIsPen(SDL_VideoDevice *_this, const XIDeviceInfo *dev)
|
||||
{
|
||||
const SDL_VideoData *data = _this->internal;
|
||||
for (int i = 0; i < dev->num_classes; i++) {
|
||||
const XIAnyClassInfo *classinfo = dev->classes[i];
|
||||
if (classinfo->type == XIValuatorClass) {
|
||||
const XIValuatorClassInfo *val_classinfo = (const XIValuatorClassInfo *)classinfo;
|
||||
if (val_classinfo->label == data->atoms.pen_atom_abs_pressure) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Heuristically determines if device is an eraser
|
||||
static bool X11_XInput2PenIsEraser(SDL_VideoDevice *_this, int deviceid, char *devicename)
|
||||
{
|
||||
#define PEN_ERASER_NAME_TAG "eraser" // String constant to identify erasers
|
||||
SDL_VideoData *data = _this->internal;
|
||||
|
||||
if (data->atoms.pen_atom_wacom_tool_type != None) {
|
||||
Atom type_return;
|
||||
int format_return;
|
||||
unsigned long num_items_return;
|
||||
unsigned long bytes_after_return;
|
||||
unsigned char *tooltype_name_info = NULL;
|
||||
|
||||
// Try Wacom-specific method
|
||||
if (Success == X11_XIGetProperty(data->display, deviceid,
|
||||
data->atoms.pen_atom_wacom_tool_type,
|
||||
0, 32, False,
|
||||
AnyPropertyType, &type_return, &format_return,
|
||||
&num_items_return, &bytes_after_return,
|
||||
&tooltype_name_info) &&
|
||||
tooltype_name_info != NULL && num_items_return > 0) {
|
||||
|
||||
bool result = false;
|
||||
char *tooltype_name = NULL;
|
||||
|
||||
if (type_return == XA_ATOM) {
|
||||
// Atom instead of string? Un-intern
|
||||
Atom atom = *((Atom *)tooltype_name_info);
|
||||
if (atom != None) {
|
||||
tooltype_name = X11_XGetAtomName(data->display, atom);
|
||||
}
|
||||
} else if (type_return == XA_STRING && format_return == 8) {
|
||||
tooltype_name = (char *)tooltype_name_info;
|
||||
}
|
||||
|
||||
if (tooltype_name) {
|
||||
if (SDL_strcasecmp(tooltype_name, PEN_ERASER_NAME_TAG) == 0) {
|
||||
result = true;
|
||||
}
|
||||
if (tooltype_name != (char *)tooltype_name_info) {
|
||||
X11_XFree(tooltype_name_info);
|
||||
}
|
||||
X11_XFree(tooltype_name);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Non-Wacom device?
|
||||
|
||||
/* We assume that a device is an eraser if its name contains the string "eraser".
|
||||
* Unfortunately there doesn't seem to be a clean way to distinguish these cases (as of 2022-03). */
|
||||
return (SDL_strcasestr(devicename, PEN_ERASER_NAME_TAG)) ? true : false;
|
||||
}
|
||||
|
||||
// Read out an integer property and store into a preallocated Sint32 array, extending 8 and 16 bit values suitably.
|
||||
// Returns number of Sint32s written (<= max_words), or 0 on error.
|
||||
static size_t X11_XInput2PenGetIntProperty(SDL_VideoDevice *_this, int deviceid, Atom property, Sint32 *dest, size_t max_words)
|
||||
{
|
||||
const SDL_VideoData *data = _this->internal;
|
||||
Atom type_return;
|
||||
int format_return;
|
||||
unsigned long num_items_return;
|
||||
unsigned long bytes_after_return;
|
||||
unsigned char *output;
|
||||
|
||||
if (property == None) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Success != X11_XIGetProperty(data->display, deviceid,
|
||||
property,
|
||||
0, max_words, False,
|
||||
XA_INTEGER, &type_return, &format_return,
|
||||
&num_items_return, &bytes_after_return,
|
||||
&output) ||
|
||||
num_items_return == 0 || output == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (type_return == XA_INTEGER) {
|
||||
int k;
|
||||
const int to_copy = SDL_min(max_words, num_items_return);
|
||||
|
||||
if (format_return == 8) {
|
||||
Sint8 *numdata = (Sint8 *)output;
|
||||
for (k = 0; k < to_copy; ++k) {
|
||||
dest[k] = numdata[k];
|
||||
}
|
||||
} else if (format_return == 16) {
|
||||
Sint16 *numdata = (Sint16 *)output;
|
||||
for (k = 0; k < to_copy; ++k) {
|
||||
dest[k] = numdata[k];
|
||||
}
|
||||
} else {
|
||||
SDL_memcpy(dest, output, sizeof(Sint32) * to_copy);
|
||||
}
|
||||
X11_XFree(output);
|
||||
return to_copy;
|
||||
}
|
||||
|
||||
return 0; // type mismatch
|
||||
}
|
||||
|
||||
// Identify Wacom devices (if true is returned) and extract their device type and serial IDs
|
||||
static bool X11_XInput2PenWacomDeviceID(SDL_VideoDevice *_this, int deviceid, Uint32 *wacom_devicetype_id, Uint32 *wacom_serial)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
Sint32 serial_id_buf[3];
|
||||
int result;
|
||||
|
||||
if ((result = X11_XInput2PenGetIntProperty(_this, deviceid, data->atoms.pen_atom_wacom_serial_ids, serial_id_buf, 3)) == 3) {
|
||||
*wacom_devicetype_id = serial_id_buf[2];
|
||||
*wacom_serial = serial_id_buf[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
*wacom_devicetype_id = *wacom_serial = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
typedef struct FindPenByDeviceIDData
|
||||
{
|
||||
int x11_deviceid;
|
||||
void *handle;
|
||||
} FindPenByDeviceIDData;
|
||||
|
||||
static bool FindPenByDeviceID(void *handle, void *userdata)
|
||||
{
|
||||
const X11_PenHandle *x11_handle = (const X11_PenHandle *) handle;
|
||||
FindPenByDeviceIDData *data = (FindPenByDeviceIDData *) userdata;
|
||||
if (x11_handle->x11_deviceid != data->x11_deviceid) {
|
||||
return false;
|
||||
}
|
||||
data->handle = handle;
|
||||
return true;
|
||||
}
|
||||
|
||||
X11_PenHandle *X11_FindPenByDeviceID(int deviceid)
|
||||
{
|
||||
FindPenByDeviceIDData data;
|
||||
data.x11_deviceid = deviceid;
|
||||
data.handle = NULL;
|
||||
SDL_FindPenByCallback(FindPenByDeviceID, &data);
|
||||
return (X11_PenHandle *) data.handle;
|
||||
}
|
||||
|
||||
static X11_PenHandle *X11_MaybeAddPen(SDL_VideoDevice *_this, const XIDeviceInfo *dev)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
SDL_PenCapabilityFlags capabilities = 0;
|
||||
X11_PenHandle *handle = NULL;
|
||||
|
||||
if ((dev->use != XISlavePointer && (dev->use != XIFloatingSlave)) || dev->enabled == 0 || !X11_XInput2DeviceIsPen(_this, dev)) {
|
||||
return NULL; // Only track physical devices that are enabled and look like pens
|
||||
} else if ((handle = X11_FindPenByDeviceID(dev->deviceid)) != 0) {
|
||||
return handle; // already have this pen, skip it.
|
||||
} else if ((handle = SDL_calloc(1, sizeof (*handle))) == NULL) {
|
||||
return NULL; // oh well.
|
||||
}
|
||||
|
||||
for (int i = 0; i < SDL_arraysize(handle->valuator_for_axis); i++) {
|
||||
handle->valuator_for_axis[i] = SDL_X11_PEN_AXIS_VALUATOR_MISSING; // until proven otherwise
|
||||
}
|
||||
|
||||
int total_buttons = 0;
|
||||
for (int i = 0; i < dev->num_classes; i++) {
|
||||
const XIAnyClassInfo *classinfo = dev->classes[i];
|
||||
if (classinfo->type == XIButtonClass) {
|
||||
const XIButtonClassInfo *button_classinfo = (const XIButtonClassInfo *)classinfo;
|
||||
total_buttons += button_classinfo->num_buttons;
|
||||
} else if (classinfo->type == XIValuatorClass) {
|
||||
const XIValuatorClassInfo *val_classinfo = (const XIValuatorClassInfo *)classinfo;
|
||||
const Sint8 valuator_nr = val_classinfo->number;
|
||||
const Atom vname = val_classinfo->label;
|
||||
const float min = (float)val_classinfo->min;
|
||||
const float max = (float)val_classinfo->max;
|
||||
bool use_this_axis = true;
|
||||
SDL_PenAxis axis = SDL_PEN_AXIS_COUNT;
|
||||
|
||||
// afaict, SDL_PEN_AXIS_DISTANCE is never reported by XInput2 (Wayland can offer it, though)
|
||||
if (vname == data->atoms.pen_atom_abs_pressure) {
|
||||
axis = SDL_PEN_AXIS_PRESSURE;
|
||||
} else if (vname == data->atoms.pen_atom_abs_tilt_x) {
|
||||
axis = SDL_PEN_AXIS_XTILT;
|
||||
} else if (vname == data->atoms.pen_atom_abs_tilt_y) {
|
||||
axis = SDL_PEN_AXIS_YTILT;
|
||||
} else {
|
||||
use_this_axis = false;
|
||||
}
|
||||
|
||||
// !!! FIXME: there are wacom-specific hacks for getting SDL_PEN_AXIS_(ROTATION|SLIDER) on some devices, but for simplicity, we're skipping all that for now.
|
||||
|
||||
if (use_this_axis) {
|
||||
capabilities |= SDL_GetPenCapabilityFromAxis(axis);
|
||||
handle->valuator_for_axis[axis] = valuator_nr;
|
||||
handle->axis_min[axis] = min;
|
||||
handle->axis_max[axis] = max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We have a pen if and only if the device measures pressure.
|
||||
// We checked this in X11_XInput2DeviceIsPen, so just assert it here.
|
||||
SDL_assert(capabilities & SDL_PEN_CAPABILITY_PRESSURE);
|
||||
|
||||
const bool is_eraser = X11_XInput2PenIsEraser(_this, dev->deviceid, dev->name);
|
||||
Uint32 wacom_devicetype_id = 0;
|
||||
Uint32 wacom_serial = 0;
|
||||
X11_XInput2PenWacomDeviceID(_this, dev->deviceid, &wacom_devicetype_id, &wacom_serial);
|
||||
|
||||
SDL_PenInfo peninfo;
|
||||
SDL_zero(peninfo);
|
||||
peninfo.capabilities = capabilities;
|
||||
peninfo.max_tilt = -1;
|
||||
peninfo.wacom_id = wacom_devicetype_id;
|
||||
peninfo.num_buttons = total_buttons;
|
||||
peninfo.subtype = is_eraser ? SDL_PEN_TYPE_ERASER : SDL_PEN_TYPE_PEN;
|
||||
if (is_eraser) {
|
||||
peninfo.capabilities |= SDL_PEN_CAPABILITY_ERASER;
|
||||
}
|
||||
|
||||
handle->is_eraser = is_eraser;
|
||||
handle->x11_deviceid = dev->deviceid;
|
||||
|
||||
handle->pen = SDL_AddPenDevice(0, dev->name, &peninfo, handle);
|
||||
if (!handle->pen) {
|
||||
SDL_free(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
X11_PenHandle *X11_MaybeAddPenByDeviceID(SDL_VideoDevice *_this, int deviceid)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
int num_device_info = 0;
|
||||
XIDeviceInfo *device_info = X11_XIQueryDevice(data->display, deviceid, &num_device_info);
|
||||
if (device_info) {
|
||||
SDL_assert(num_device_info == 1);
|
||||
X11_PenHandle *handle = X11_MaybeAddPen(_this, device_info);
|
||||
X11_XIFreeDeviceInfo(device_info);
|
||||
return handle;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void X11_RemovePenByDeviceID(int deviceid)
|
||||
{
|
||||
X11_PenHandle *handle = X11_FindPenByDeviceID(deviceid);
|
||||
if (handle) {
|
||||
SDL_RemovePenDevice(0, handle->pen);
|
||||
SDL_free(handle);
|
||||
}
|
||||
}
|
||||
|
||||
void X11_InitPen(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
|
||||
#define LOOKUP_PEN_ATOM(X) X11_XInternAtom(data->display, X, False)
|
||||
data->atoms.pen_atom_device_product_id = LOOKUP_PEN_ATOM("Device Product ID");
|
||||
data->atoms.pen_atom_wacom_serial_ids = LOOKUP_PEN_ATOM("Wacom Serial IDs");
|
||||
data->atoms.pen_atom_wacom_tool_type = LOOKUP_PEN_ATOM("Wacom Tool Type");
|
||||
data->atoms.pen_atom_abs_pressure = LOOKUP_PEN_ATOM("Abs Pressure");
|
||||
data->atoms.pen_atom_abs_tilt_x = LOOKUP_PEN_ATOM("Abs Tilt X");
|
||||
data->atoms.pen_atom_abs_tilt_y = LOOKUP_PEN_ATOM("Abs Tilt Y");
|
||||
#undef LOOKUP_PEN_ATOM
|
||||
|
||||
// Do an initial check on devices. After this, we'll add/remove individual pens when XI_HierarchyChanged events alert us.
|
||||
int num_device_info = 0;
|
||||
XIDeviceInfo *device_info = X11_XIQueryDevice(data->display, XIAllDevices, &num_device_info);
|
||||
if (device_info) {
|
||||
for (int i = 0; i < num_device_info; i++) {
|
||||
X11_MaybeAddPen(_this, &device_info[i]);
|
||||
}
|
||||
X11_XIFreeDeviceInfo(device_info);
|
||||
}
|
||||
}
|
||||
|
||||
static void X11_FreePenHandle(SDL_PenID instance_id, void *handle, void *userdata)
|
||||
{
|
||||
SDL_free(handle);
|
||||
}
|
||||
|
||||
void X11_QuitPen(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_RemoveAllPenDevices(X11_FreePenHandle, NULL);
|
||||
}
|
||||
|
||||
static void X11_XInput2NormalizePenAxes(const X11_PenHandle *pen, float *coords)
|
||||
{
|
||||
// Normalise axes
|
||||
for (int axis = 0; axis < SDL_PEN_AXIS_COUNT; ++axis) {
|
||||
const int valuator = pen->valuator_for_axis[axis];
|
||||
if (valuator == SDL_X11_PEN_AXIS_VALUATOR_MISSING) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float value = coords[axis];
|
||||
const float min = pen->axis_min[axis];
|
||||
const float max = pen->axis_max[axis];
|
||||
|
||||
if (axis == SDL_PEN_AXIS_SLIDER) {
|
||||
value += pen->slider_bias;
|
||||
}
|
||||
|
||||
// min ... 0 ... max
|
||||
if (min < 0.0) {
|
||||
// Normalise so that 0 remains 0.0
|
||||
if (value < 0) {
|
||||
value = value / (-min);
|
||||
} else {
|
||||
if (max == 0.0f) {
|
||||
value = 0.0f;
|
||||
} else {
|
||||
value = value / max;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 0 ... min ... max
|
||||
// including 0.0 = min
|
||||
if (max == 0.0f) {
|
||||
value = 0.0f;
|
||||
} else {
|
||||
value = (value - min) / max;
|
||||
}
|
||||
}
|
||||
|
||||
switch (axis) {
|
||||
case SDL_PEN_AXIS_XTILT:
|
||||
case SDL_PEN_AXIS_YTILT:
|
||||
//if (peninfo->info.max_tilt > 0.0f) {
|
||||
// value *= peninfo->info.max_tilt; // normalize to physical max
|
||||
//}
|
||||
break;
|
||||
|
||||
case SDL_PEN_AXIS_ROTATION:
|
||||
// normalised to -1..1, so let's convert to degrees
|
||||
value *= 180.0f;
|
||||
value += pen->rotation_bias;
|
||||
|
||||
// handle simple over/underflow
|
||||
if (value >= 180.0f) {
|
||||
value -= 360.0f;
|
||||
} else if (value < -180.0f) {
|
||||
value += 360.0f;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
coords[axis] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void X11_PenAxesFromValuators(const X11_PenHandle *pen,
|
||||
const double *input_values, const unsigned char *mask, int mask_len,
|
||||
float axis_values[SDL_PEN_AXIS_COUNT])
|
||||
{
|
||||
for (int i = 0; i < SDL_PEN_AXIS_COUNT; i++) {
|
||||
const int valuator = pen->valuator_for_axis[i];
|
||||
if ((valuator == SDL_X11_PEN_AXIS_VALUATOR_MISSING) || (valuator >= mask_len * 8) || !(XIMaskIsSet(mask, valuator))) {
|
||||
axis_values[i] = 0.0f;
|
||||
} else {
|
||||
axis_values[i] = (float)input_values[valuator];
|
||||
}
|
||||
}
|
||||
X11_XInput2NormalizePenAxes(pen, axis_values);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void X11_InitPen(SDL_VideoDevice *_this)
|
||||
{
|
||||
(void) _this;
|
||||
}
|
||||
|
||||
void X11_QuitPen(SDL_VideoDevice *_this)
|
||||
{
|
||||
(void) _this;
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_X11_XINPUT2
|
||||
|
||||
72
vendor/sdl-3.2.10/src/video/x11/SDL_x11pen.h
vendored
Normal file
72
vendor/sdl-3.2.10/src/video/x11/SDL_x11pen.h
vendored
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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_x11pen_h_
|
||||
#define SDL_x11pen_h_
|
||||
|
||||
// Pressure-sensitive pen support for X11.
|
||||
|
||||
#include "SDL_x11video.h"
|
||||
#include "../../events/SDL_pen_c.h"
|
||||
|
||||
// Prep pen support (never fails; pens simply won't be added if there's a problem).
|
||||
extern void X11_InitPen(SDL_VideoDevice *_this);
|
||||
|
||||
// Clean up pen support.
|
||||
extern void X11_QuitPen(SDL_VideoDevice *_this);
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
|
||||
|
||||
// Forward definition for SDL_x11video.h
|
||||
struct SDL_VideoData;
|
||||
|
||||
#define SDL_X11_PEN_AXIS_VALUATOR_MISSING -1
|
||||
|
||||
typedef struct X11_PenHandle
|
||||
{
|
||||
SDL_PenID pen;
|
||||
bool is_eraser;
|
||||
int x11_deviceid;
|
||||
int valuator_for_axis[SDL_PEN_AXIS_COUNT];
|
||||
float slider_bias; // shift value to add to PEN_AXIS_SLIDER (before normalisation)
|
||||
float rotation_bias; // rotation to add to PEN_AXIS_ROTATION (after normalisation)
|
||||
float axis_min[SDL_PEN_AXIS_COUNT];
|
||||
float axis_max[SDL_PEN_AXIS_COUNT];
|
||||
} X11_PenHandle;
|
||||
|
||||
// Converts XINPUT2 valuators into pen axis information, including normalisation.
|
||||
extern void X11_PenAxesFromValuators(const X11_PenHandle *pen,
|
||||
const double *input_values, const unsigned char *mask, int mask_len,
|
||||
float axis_values[SDL_PEN_AXIS_COUNT]);
|
||||
|
||||
// Add a pen (if this function's further checks validate it).
|
||||
extern X11_PenHandle *X11_MaybeAddPenByDeviceID(SDL_VideoDevice *_this, int deviceid);
|
||||
|
||||
// Remove a pen. It's okay if deviceid is bogus or not a pen, we'll check it.
|
||||
extern void X11_RemovePenByDeviceID(int deviceid);
|
||||
|
||||
// Map X11 device ID to pen ID.
|
||||
extern X11_PenHandle *X11_FindPenByDeviceID(int deviceid);
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_X11_XINPUT2
|
||||
|
||||
#endif // SDL_x11pen_h_
|
||||
129
vendor/sdl-3.2.10/src/video/x11/SDL_x11settings.c
vendored
Normal file
129
vendor/sdl-3.2.10/src/video/x11/SDL_x11settings.c
vendored
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright 2024 Igalia S.L.
|
||||
|
||||
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)
|
||||
|
||||
#include "SDL_x11video.h"
|
||||
#include "SDL_x11settings.h"
|
||||
|
||||
#define SDL_XSETTINGS_GDK_WINDOW_SCALING_FACTOR "Gdk/WindowScalingFactor"
|
||||
#define SDL_XSETTINGS_XFT_DPI "Xft/DPI"
|
||||
|
||||
static void X11_XsettingsNotify(const char *name, XSettingsAction action, XSettingsSetting *setting, void *data)
|
||||
{
|
||||
SDL_VideoDevice *_this = data;
|
||||
float scale_factor = 1.0;
|
||||
int i;
|
||||
|
||||
if (SDL_strcmp(name, SDL_XSETTINGS_GDK_WINDOW_SCALING_FACTOR) != 0 ||
|
||||
SDL_strcmp(name, SDL_XSETTINGS_XFT_DPI) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (setting->type != XSETTINGS_TYPE_INT) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case XSETTINGS_ACTION_NEW:
|
||||
SDL_FALLTHROUGH;
|
||||
case XSETTINGS_ACTION_CHANGED:
|
||||
scale_factor = setting->data.v_int;
|
||||
if (SDL_strcmp(name, SDL_XSETTINGS_XFT_DPI) == 0) {
|
||||
scale_factor = scale_factor / 1024.0f / 96.0f;
|
||||
}
|
||||
break;
|
||||
case XSETTINGS_ACTION_DELETED:
|
||||
scale_factor = 1.0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_this) {
|
||||
for (i = 0; i < _this->num_displays; ++i) {
|
||||
SDL_SetDisplayContentScale(_this->displays[i], scale_factor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void X11_InitXsettings(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
SDLX11_SettingsData *xsettings_data = &data->xsettings_data;
|
||||
|
||||
xsettings_data->xsettings = xsettings_client_new(data->display,
|
||||
DefaultScreen(data->display), X11_XsettingsNotify, NULL, _this);
|
||||
|
||||
}
|
||||
|
||||
void X11_QuitXsettings(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
SDLX11_SettingsData *xsettings_data = &data->xsettings_data;
|
||||
|
||||
if (xsettings_data->xsettings) {
|
||||
xsettings_client_destroy(xsettings_data->xsettings);
|
||||
xsettings_data->xsettings = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void X11_HandleXsettings(SDL_VideoDevice *_this, const XEvent *xevent)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
SDLX11_SettingsData *xsettings_data = &data->xsettings_data;
|
||||
|
||||
if (xsettings_data->xsettings) {
|
||||
if (!xsettings_client_process_event(xsettings_data->xsettings, xevent)) {
|
||||
xsettings_client_destroy(xsettings_data->xsettings);
|
||||
xsettings_data->xsettings = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int X11_GetXsettingsIntKey(SDL_VideoDevice *_this, const char *key, int fallback_value) {
|
||||
SDL_VideoData *data = _this->internal;
|
||||
SDLX11_SettingsData *xsettings_data = &data->xsettings_data;
|
||||
XSettingsSetting *setting = NULL;
|
||||
int res = fallback_value;
|
||||
|
||||
|
||||
if (xsettings_data->xsettings) {
|
||||
if (xsettings_client_get_setting(xsettings_data->xsettings, key, &setting) != XSETTINGS_SUCCESS) {
|
||||
goto no_key;
|
||||
}
|
||||
|
||||
if (setting->type != XSETTINGS_TYPE_INT) {
|
||||
goto no_key;
|
||||
}
|
||||
|
||||
res = setting->data.v_int;
|
||||
}
|
||||
|
||||
no_key:
|
||||
if (setting) {
|
||||
xsettings_setting_free(setting);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_X11
|
||||
39
vendor/sdl-3.2.10/src/video/x11/SDL_x11settings.h
vendored
Normal file
39
vendor/sdl-3.2.10/src/video/x11/SDL_x11settings.h
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright 2024 Igalia S.L.
|
||||
|
||||
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_x11settings_h_
|
||||
#define SDL_x11settings_h_
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include "xsettings-client.h"
|
||||
|
||||
typedef struct X11_SettingsData {
|
||||
XSettingsClient *xsettings;
|
||||
} SDLX11_SettingsData;
|
||||
|
||||
extern void X11_InitXsettings(SDL_VideoDevice *_this);
|
||||
extern void X11_QuitXsettings(SDL_VideoDevice *_this);
|
||||
extern void X11_HandleXsettings(SDL_VideoDevice *_this, const XEvent *xevent);
|
||||
extern int X11_GetXsettingsIntKey(SDL_VideoDevice *_this, const char *key, int fallback_value);
|
||||
|
||||
#endif // SDL_x11settings_h_
|
||||
111
vendor/sdl-3.2.10/src/video/x11/SDL_x11shape.c
vendored
Normal file
111
vendor/sdl-3.2.10/src/video/x11/SDL_x11shape.c
vendored
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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"
|
||||
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XSHAPE
|
||||
static Uint8 *GenerateShapeMask(SDL_Surface *shape)
|
||||
{
|
||||
int x, y;
|
||||
const size_t ppb = 8;
|
||||
const size_t bytes_per_scanline = (shape->w + (ppb - 1)) / ppb;
|
||||
const Uint8 *a;
|
||||
Uint8 *mask;
|
||||
Uint8 *mask_scanline;
|
||||
Uint8 mask_value;
|
||||
|
||||
mask = (Uint8 *)SDL_calloc(1, shape->h * bytes_per_scanline);
|
||||
if (mask) {
|
||||
for (y = 0; y < shape->h; y++) {
|
||||
a = (const Uint8 *)shape->pixels + y * shape->pitch;
|
||||
mask_scanline = mask + y * bytes_per_scanline;
|
||||
for (x = 0; x < shape->w; x++) {
|
||||
mask_value = (*a == SDL_ALPHA_TRANSPARENT) ? 0 : 1;
|
||||
mask_scanline[x / ppb] |= mask_value << (x % ppb);
|
||||
a += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
#endif // SDL_VIDEO_DRIVER_X11_XSHAPE
|
||||
|
||||
bool X11_UpdateWindowShape(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *shape)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XSHAPE
|
||||
SDL_WindowData *windowdata = window->internal;
|
||||
|
||||
// Generate a set of spans for the region
|
||||
if (shape) {
|
||||
SDL_Surface *stretched = NULL;
|
||||
Uint8 *mask;
|
||||
Pixmap pixmap;
|
||||
|
||||
if (shape->w != window->w || shape->h != window->h) {
|
||||
stretched = SDL_CreateSurface(window->w, window->h, SDL_PIXELFORMAT_ARGB32);
|
||||
if (!stretched) {
|
||||
return false;
|
||||
}
|
||||
if (!SDL_StretchSurface(shape, NULL, stretched, NULL, SDL_SCALEMODE_LINEAR)) {
|
||||
SDL_DestroySurface(stretched);
|
||||
return false;
|
||||
}
|
||||
shape = stretched;
|
||||
}
|
||||
|
||||
mask = GenerateShapeMask(shape);
|
||||
if (mask) {
|
||||
pixmap = X11_XCreateBitmapFromData(windowdata->videodata->display, windowdata->xwindow, (const char *)mask, shape->w, shape->h);
|
||||
X11_XShapeCombineMask(windowdata->videodata->display, windowdata->xwindow, ShapeInput, 0, 0, pixmap, ShapeSet);
|
||||
SDL_free(mask);
|
||||
|
||||
result = true;
|
||||
}
|
||||
|
||||
if (stretched) {
|
||||
SDL_DestroySurface(stretched);
|
||||
}
|
||||
} else {
|
||||
Region region = X11_XCreateRegion();
|
||||
XRectangle rect;
|
||||
|
||||
rect.x = 0;
|
||||
rect.y = 0;
|
||||
rect.width = window->w;
|
||||
rect.height = window->h;
|
||||
X11_XUnionRectWithRegion(&rect, region, region);
|
||||
X11_XShapeCombineRegion(windowdata->videodata->display, windowdata->xwindow, ShapeInput, 0, 0, region, ShapeSet);
|
||||
X11_XDestroyRegion(region);
|
||||
result = true;
|
||||
}
|
||||
#endif // SDL_VIDEO_DRIVER_X11_XSHAPE
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_X11
|
||||
28
vendor/sdl-3.2.10/src/video/x11/SDL_x11shape.h
vendored
Normal file
28
vendor/sdl-3.2.10/src/video/x11/SDL_x11shape.h
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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_
|
||||
|
||||
extern bool X11_UpdateWindowShape(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *shape);
|
||||
|
||||
#endif // SDL_x11shape_h_
|
||||
354
vendor/sdl-3.2.10/src/video/x11/SDL_x11sym.h
vendored
Normal file
354
vendor/sdl-3.2.10/src/video/x11/SDL_x11sym.h
vendored
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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[32]),(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(int,XUnionRectWithRegion,(XRectangle *a, Region b, Region c),(a,b,c), return)
|
||||
SDL_X11_SYM(void,XDestroyRegion,(Region),(a),)
|
||||
SDL_X11_SYM(void,XrmInitialize,(void),(),)
|
||||
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_XSYNC
|
||||
SDL_X11_MODULE(XSYNC)
|
||||
SDL_X11_SYM(Status, XSyncQueryExtension, (Display* a, int* b, int* c), (a, b, c), return)
|
||||
SDL_X11_SYM(Status, XSyncInitialize, (Display* a, int* b, int* c), (a, b, c), return)
|
||||
SDL_X11_SYM(XSyncCounter, XSyncCreateCounter, (Display* a, XSyncValue b), (a, b), return)
|
||||
SDL_X11_SYM(Status, XSyncDestroyCounter, (Display* a, XSyncCounter b), (a, b), return)
|
||||
SDL_X11_SYM(Status, XSyncSetCounter, (Display* a, XSyncCounter b, XSyncValue c), (a, b, c), 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_XKBLOOKUPKEYSYM
|
||||
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(Bool,XkbLookupKeySym,(Display* a, unsigned int b, unsigned int c, unsigned int* d, KeySym* e),(a,b,c,d,e),return)
|
||||
#else
|
||||
SDL_X11_SYM(Bool,XkbLookupKeySym,(Display* a, KeyCode b, unsigned int c, unsigned int* d, KeySym* e),(a,b,c,d,e),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
|
||||
|
||||
// XKeycodeToKeysym is a deprecated function
|
||||
#ifdef HAVE_GCC_DIAGNOSTIC_PRAGMA
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#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 HAVE_GCC_DIAGNOSTIC_PRAGMA
|
||||
#pragma GCC diagnostic pop
|
||||
#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(char*,XSetICValues,(XIC, ...),return) !!! ARGH! */
|
||||
/* SDL_X11_SYM(XVaNestedList,XVaCreateNestedList,(int, ...),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 SDL_PLATFORM_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)
|
||||
SDL_X11_SYM(Cursor,XcursorLibraryLoadCursor,(Display *a, const char *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)
|
||||
SDL_X11_SYM(Status,XIGetProperty,(Display *a,int 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)
|
||||
#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
|
||||
46
vendor/sdl-3.2.10/src/video/x11/SDL_x11touch.c
vendored
Normal file
46
vendor/sdl-3.2.10/src/video/x11/SDL_x11touch.c
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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
|
||||
30
vendor/sdl-3.2.10/src/video/x11/SDL_x11touch.h
vendored
Normal file
30
vendor/sdl-3.2.10/src/video/x11/SDL_x11touch.h
vendored
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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_
|
||||
505
vendor/sdl-3.2.10/src/video/x11/SDL_x11video.c
vendored
Normal file
505
vendor/sdl-3.2.10/src/video/x11/SDL_x11video.c
vendored
Normal file
|
|
@ -0,0 +1,505 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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 "../../core/linux/SDL_system_theme.h"
|
||||
#include "../../events/SDL_keyboard_c.h"
|
||||
#include "../../events/SDL_mouse_c.h"
|
||||
#include "../SDL_pixels_c.h"
|
||||
#include "../SDL_sysvideo.h"
|
||||
|
||||
#include "SDL_x11framebuffer.h"
|
||||
#include "SDL_x11pen.h"
|
||||
#include "SDL_x11touch.h"
|
||||
#include "SDL_x11video.h"
|
||||
#include "SDL_x11xfixes.h"
|
||||
#include "SDL_x11xinput2.h"
|
||||
#include "SDL_x11messagebox.h"
|
||||
#include "SDL_x11shape.h"
|
||||
#include "SDL_x11xsync.h"
|
||||
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
#include "SDL_x11opengles.h"
|
||||
#endif
|
||||
|
||||
// Initialization/Query functions
|
||||
static bool X11_VideoInit(SDL_VideoDevice *_this);
|
||||
static void X11_VideoQuit(SDL_VideoDevice *_this);
|
||||
|
||||
// X11 driver bootstrap functions
|
||||
|
||||
static void X11_DeleteDevice(SDL_VideoDevice *device)
|
||||
{
|
||||
SDL_VideoData *data = device->internal;
|
||||
if (device->vulkan_config.loader_handle) {
|
||||
device->Vulkan_UnloadLibrary(device);
|
||||
}
|
||||
if (data->display) {
|
||||
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->internal);
|
||||
SDL_free(device);
|
||||
|
||||
SDL_X11_UnloadSymbols();
|
||||
}
|
||||
|
||||
static bool X11_IsXWayland(Display *d)
|
||||
{
|
||||
int opcode, event, error;
|
||||
return X11_XQueryExtension(d, "XWAYLAND", &opcode, &event, &error) == True;
|
||||
}
|
||||
|
||||
static bool X11_CheckCurrentDesktop(const char *name)
|
||||
{
|
||||
SDL_Environment *env = SDL_GetEnvironment();
|
||||
|
||||
const char *desktopVar = SDL_GetEnvironmentVariable(env, "DESKTOP_SESSION");
|
||||
if (desktopVar && SDL_strcasecmp(desktopVar, name) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
desktopVar = SDL_GetEnvironmentVariable(env, "XDG_CURRENT_DESKTOP");
|
||||
if (desktopVar && SDL_strcasestr(desktopVar, name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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) {
|
||||
SDL_X11_UnloadSymbols();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Initialize all variables that we clean on shutdown
|
||||
device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
|
||||
if (!device) {
|
||||
return NULL;
|
||||
}
|
||||
data = (struct SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData));
|
||||
if (!data) {
|
||||
SDL_free(device);
|
||||
return NULL;
|
||||
}
|
||||
device->internal = data;
|
||||
|
||||
data->global_mouse_changed = 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) {
|
||||
X11_XCloseDisplay(data->display);
|
||||
SDL_free(device->internal);
|
||||
SDL_free(device);
|
||||
SDL_X11_UnloadSymbols();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
device->wakeup_lock = SDL_CreateMutex();
|
||||
|
||||
#ifdef X11_DEBUG
|
||||
X11_XSynchronize(data->display, True);
|
||||
#endif
|
||||
|
||||
/* 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", 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->SetWindowTitle = X11_SetWindowTitle;
|
||||
device->SetWindowIcon = X11_SetWindowIcon;
|
||||
device->SetWindowPosition = X11_SetWindowPosition;
|
||||
device->SetWindowSize = X11_SetWindowSize;
|
||||
device->SetWindowMinimumSize = X11_SetWindowMinimumSize;
|
||||
device->SetWindowMaximumSize = X11_SetWindowMaximumSize;
|
||||
device->SetWindowAspectRatio = X11_SetWindowAspectRatio;
|
||||
device->GetWindowBordersSize = X11_GetWindowBordersSize;
|
||||
device->SetWindowOpacity = X11_SetWindowOpacity;
|
||||
device->SetWindowParent = X11_SetWindowParent;
|
||||
device->SetWindowModal = X11_SetWindowModal;
|
||||
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->SetWindowHitTest = X11_SetWindowHitTest;
|
||||
device->AcceptDragAndDrop = X11_AcceptDragAndDrop;
|
||||
device->UpdateWindowShape = X11_UpdateWindowShape;
|
||||
device->FlashWindow = X11_FlashWindow;
|
||||
device->ShowWindowSystemMenu = X11_ShowWindowSystemMenu;
|
||||
device->SetWindowFocusable = X11_SetWindowFocusable;
|
||||
device->SyncWindow = X11_SyncWindow;
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
|
||||
device->SetWindowMouseRect = X11_SetWindowMouseRect;
|
||||
#endif // SDL_VIDEO_DRIVER_X11_XFIXES
|
||||
|
||||
#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_DestroyContext = X11_GL_DestroyContext;
|
||||
device->GL_GetEGLSurface = NULL;
|
||||
#endif
|
||||
#ifdef SDL_VIDEO_OPENGL_EGL
|
||||
#ifdef SDL_VIDEO_OPENGL_GLX
|
||||
if (SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, 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_DestroyContext = X11_GLES_DestroyContext;
|
||||
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->UpdateTextInputArea = X11_UpdateTextInputArea;
|
||||
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;
|
||||
device->Vulkan_DestroySurface = X11_Vulkan_DestroySurface;
|
||||
device->Vulkan_GetPresentationSupport = X11_Vulkan_GetPresentationSupport;
|
||||
#endif
|
||||
|
||||
#ifdef SDL_USE_LIBDBUS
|
||||
if (SDL_SystemTheme_Init())
|
||||
device->system_theme = SDL_SystemTheme_Get();
|
||||
#endif
|
||||
|
||||
device->device_caps = VIDEO_DEVICE_CAPS_HAS_POPUP_WINDOW_SUPPORT;
|
||||
|
||||
/* Openbox doesn't send the new window dimensions when entering fullscreen, so the events must be synthesized.
|
||||
* This is otherwise not wanted, as it can break fullscreen window positioning on multi-monitor configurations.
|
||||
*/
|
||||
if (!X11_CheckCurrentDesktop("openbox")) {
|
||||
device->device_caps |= VIDEO_DEVICE_CAPS_SENDS_DISPLAY_CHANGES;
|
||||
}
|
||||
|
||||
data->is_xwayland = X11_IsXWayland(x11_display);
|
||||
if (data->is_xwayland) {
|
||||
device->device_caps |= VIDEO_DEVICE_CAPS_MODE_SWITCHING_EMULATED |
|
||||
VIDEO_DEVICE_CAPS_DISABLE_MOUSE_WARP_ON_FULLSCREEN_TRANSITIONS;
|
||||
}
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
VideoBootStrap X11_bootstrap = {
|
||||
"x11", "SDL X11 video driver",
|
||||
X11_CreateDevice,
|
||||
X11_ShowMessageBox,
|
||||
false
|
||||
};
|
||||
|
||||
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->internal;
|
||||
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 = true;
|
||||
|
||||
#ifdef DEBUG_WINDOW_MANAGER
|
||||
wm_name = X11_GetWindowTitle(_this, wm_window);
|
||||
printf("Window manager: %s\n", wm_name);
|
||||
SDL_free(wm_name);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool X11_VideoInit(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
|
||||
// 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->atoms.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(WM_TRANSIENT_FOR);
|
||||
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_MOVERESIZE);
|
||||
GET_ATOM(_NET_WM_STATE_MODAL);
|
||||
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_SYNC_REQUEST);
|
||||
GET_ATOM(_NET_WM_SYNC_REQUEST_COUNTER);
|
||||
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(CLIPBOARD);
|
||||
GET_ATOM(INCR);
|
||||
GET_ATOM(SDL_SELECTION);
|
||||
GET_ATOM(TARGETS);
|
||||
GET_ATOM(SDL_FORMATS);
|
||||
GET_ATOM(XdndAware);
|
||||
GET_ATOM(XdndEnter);
|
||||
GET_ATOM(XdndLeave);
|
||||
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)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!X11_InitXinput2(_this)) {
|
||||
// Assume a mouse and keyboard are attached
|
||||
SDL_AddKeyboard(SDL_DEFAULT_KEYBOARD_ID, NULL, false);
|
||||
SDL_AddMouse(SDL_DEFAULT_MOUSE_ID, NULL, false);
|
||||
}
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
|
||||
X11_InitXfixes(_this);
|
||||
#endif // SDL_VIDEO_DRIVER_X11_XFIXES
|
||||
|
||||
X11_InitXsettings(_this);
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
|
||||
X11_InitXsync(_this);
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */
|
||||
|
||||
#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)) {
|
||||
return false;
|
||||
}
|
||||
X11_InitMouse(_this);
|
||||
|
||||
X11_InitTouch(_this);
|
||||
|
||||
X11_InitPen(_this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void X11_VideoQuit(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
|
||||
if (data->clipboard_window) {
|
||||
X11_XDestroyWindow(data->display, data->clipboard_window);
|
||||
}
|
||||
|
||||
if (data->xsettings_window) {
|
||||
X11_XDestroyWindow(data->display, data->xsettings_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_QuitPen(_this);
|
||||
X11_QuitClipboard(_this);
|
||||
X11_QuitXsettings(_this);
|
||||
}
|
||||
|
||||
bool X11_UseDirectColorVisuals(void)
|
||||
{
|
||||
if (SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_NODIRECTCOLOR, false)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_X11
|
||||
177
vendor/sdl-3.2.10/src/video/x11/SDL_x11video.h
vendored
Normal file
177
vendor/sdl-3.2.10/src/video/x11/SDL_x11video.h
vendored
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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 "../../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_x11settings.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
|
||||
Window xsettings_window;
|
||||
SDLX11_SettingsData xsettings_data;
|
||||
|
||||
// This is true for ICCCM2.0-compliant window managers
|
||||
bool net_wm;
|
||||
|
||||
// Useful atoms
|
||||
struct {
|
||||
Atom WM_PROTOCOLS;
|
||||
Atom WM_DELETE_WINDOW;
|
||||
Atom WM_TAKE_FOCUS;
|
||||
Atom WM_NAME;
|
||||
Atom WM_TRANSIENT_FOR;
|
||||
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_STATE_MODAL;
|
||||
Atom _NET_WM_MOVERESIZE;
|
||||
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_SYNC_REQUEST;
|
||||
Atom _NET_WM_SYNC_REQUEST_COUNTER;
|
||||
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 CLIPBOARD;
|
||||
Atom INCR;
|
||||
Atom SDL_SELECTION;
|
||||
Atom TARGETS;
|
||||
Atom SDL_FORMATS;
|
||||
Atom XdndAware;
|
||||
Atom XdndEnter;
|
||||
Atom XdndLeave;
|
||||
Atom XdndPosition;
|
||||
Atom XdndStatus;
|
||||
Atom XdndTypeList;
|
||||
Atom XdndActionCopy;
|
||||
Atom XdndDrop;
|
||||
Atom XdndFinished;
|
||||
Atom XdndSelection;
|
||||
Atom XKLAVIER_STATE;
|
||||
|
||||
// Pen atoms (these have names that don't map well to C symbols)
|
||||
Atom pen_atom_device_product_id;
|
||||
Atom pen_atom_abs_pressure;
|
||||
Atom pen_atom_abs_tilt_x;
|
||||
Atom pen_atom_abs_tilt_y;
|
||||
Atom pen_atom_wacom_serial_ids;
|
||||
Atom pen_atom_wacom_tool_type;
|
||||
} atoms;
|
||||
|
||||
SDL_Scancode key_layout[256];
|
||||
bool selection_waiting;
|
||||
bool selection_incr_waiting;
|
||||
|
||||
bool broken_pointer_grab; // true if XGrabPointer seems unreliable.
|
||||
|
||||
Uint64 last_mode_change_deadline;
|
||||
|
||||
bool global_mouse_changed;
|
||||
SDL_Point global_mouse_position;
|
||||
Uint32 global_mouse_buttons;
|
||||
|
||||
SDL_XInput2DeviceInfo *mouse_device_info;
|
||||
int xinput_master_pointer_device;
|
||||
bool xinput_hierarchy_changed;
|
||||
|
||||
int xrandr_event_base;
|
||||
struct
|
||||
{
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_HAS_XKBLOOKUPKEYSYM
|
||||
XkbDescPtr desc_ptr;
|
||||
#endif
|
||||
int event;
|
||||
unsigned int current_group;
|
||||
unsigned int xkb_modifiers;
|
||||
|
||||
SDL_Keymod sdl_modifiers;
|
||||
|
||||
Uint32 numlock_mask;
|
||||
Uint32 scrolllock_mask;
|
||||
} xkb;
|
||||
|
||||
KeyCode filter_code;
|
||||
Time filter_time;
|
||||
|
||||
#ifdef SDL_VIDEO_VULKAN
|
||||
// Vulkan variables only valid if _this->vulkan_config.loader_handle is not NULL
|
||||
SDL_SharedObject *vulkan_xlib_xcb_library;
|
||||
PFN_XGetXCBConnection vulkan_XGetXCBConnection;
|
||||
#endif
|
||||
|
||||
// Used to interact with the on-screen keyboard
|
||||
bool is_steam_deck;
|
||||
bool steam_keyboard_open;
|
||||
|
||||
bool is_xwayland;
|
||||
};
|
||||
|
||||
extern bool X11_UseDirectColorVisuals(void);
|
||||
|
||||
#endif // SDL_x11video_h_
|
||||
290
vendor/sdl-3.2.10/src/video/x11/SDL_x11vulkan.c
vendored
Normal file
290
vendor/sdl-3.2.10/src/video/x11/SDL_x11vulkan.c
vendored
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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_vulkan_internal.h"
|
||||
|
||||
#include "SDL_x11video.h"
|
||||
|
||||
#include "SDL_x11vulkan.h"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
// #include <xcb/xcb.h>
|
||||
|
||||
#ifdef SDL_PLATFORM_OPENBSD
|
||||
#define DEFAULT_VULKAN "libvulkan.so"
|
||||
#define DEFAULT_X11_XCB "libX11-xcb.so"
|
||||
#else
|
||||
#define DEFAULT_VULKAN "libvulkan.so.1"
|
||||
#define DEFAULT_X11_XCB "libX11-xcb.so.1"
|
||||
#endif
|
||||
|
||||
/*
|
||||
typedef uint32_t xcb_window_t;
|
||||
typedef uint32_t xcb_visualid_t;
|
||||
*/
|
||||
|
||||
bool X11_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path)
|
||||
{
|
||||
SDL_VideoData *videoData = _this->internal;
|
||||
VkExtensionProperties *extensions = NULL;
|
||||
Uint32 extensionCount = 0;
|
||||
bool hasSurfaceExtension = false;
|
||||
bool hasXlibSurfaceExtension = false;
|
||||
bool hasXCBSurfaceExtension = 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) {
|
||||
path = SDL_GetHint(SDL_HINT_VULKAN_LIBRARY);
|
||||
}
|
||||
if (!path) {
|
||||
path = DEFAULT_VULKAN;
|
||||
}
|
||||
_this->vulkan_config.loader_handle = SDL_LoadObject(path);
|
||||
if (!_this->vulkan_config.loader_handle) {
|
||||
return false;
|
||||
}
|
||||
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) {
|
||||
goto fail;
|
||||
}
|
||||
for (i = 0; i < extensionCount; i++) {
|
||||
if (SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
|
||||
hasSurfaceExtension = true;
|
||||
} else if (SDL_strcmp(VK_KHR_XCB_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
|
||||
hasXCBSurfaceExtension = true;
|
||||
} else if (SDL_strcmp(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
|
||||
hasXlibSurfaceExtension = 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_GetHint(SDL_HINT_X11_XCB_LIBRARY);
|
||||
if (!libX11XCBLibraryName || !*libX11XCBLibraryName) {
|
||||
libX11XCBLibraryName = DEFAULT_X11_XCB;
|
||||
}
|
||||
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 true;
|
||||
|
||||
fail:
|
||||
SDL_UnloadObject(_this->vulkan_config.loader_handle);
|
||||
_this->vulkan_config.loader_handle = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
void X11_Vulkan_UnloadLibrary(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *videoData = _this->internal;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
char const* const* X11_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
|
||||
Uint32 *count)
|
||||
{
|
||||
SDL_VideoData *videoData = _this->internal;
|
||||
if (videoData->vulkan_xlib_xcb_library) {
|
||||
static const char *const extensionsForXCB[] = {
|
||||
VK_KHR_SURFACE_EXTENSION_NAME,
|
||||
VK_KHR_XCB_SURFACE_EXTENSION_NAME,
|
||||
};
|
||||
if(count) {
|
||||
*count = SDL_arraysize(extensionsForXCB);
|
||||
}
|
||||
return extensionsForXCB;
|
||||
} else {
|
||||
static const char *const extensionsForXlib[] = {
|
||||
VK_KHR_SURFACE_EXTENSION_NAME,
|
||||
VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
|
||||
};
|
||||
if(count) {
|
||||
*count = SDL_arraysize(extensionsForXlib);
|
||||
}
|
||||
return extensionsForXlib;
|
||||
}
|
||||
}
|
||||
|
||||
bool X11_Vulkan_CreateSurface(SDL_VideoDevice *_this,
|
||||
SDL_Window *window,
|
||||
VkInstance instance,
|
||||
const struct VkAllocationCallbacks *allocator,
|
||||
VkSurfaceKHR *surface)
|
||||
{
|
||||
SDL_VideoData *videoData = _this->internal;
|
||||
SDL_WindowData *windowData = window->internal;
|
||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
|
||||
if (!_this->vulkan_config.loader_handle) {
|
||||
return SDL_SetError("Vulkan is not loaded");
|
||||
}
|
||||
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) {
|
||||
return SDL_SetError(VK_KHR_XCB_SURFACE_EXTENSION_NAME " extension is not enabled in the Vulkan instance.");
|
||||
}
|
||||
SDL_zero(createInfo);
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
|
||||
createInfo.connection = videoData->vulkan_XGetXCBConnection(videoData->display);
|
||||
if (!createInfo.connection) {
|
||||
return SDL_SetError("XGetXCBConnection failed");
|
||||
}
|
||||
createInfo.window = (xcb_window_t)windowData->xwindow;
|
||||
result = vkCreateXcbSurfaceKHR(instance, &createInfo, allocator, surface);
|
||||
if (result != VK_SUCCESS) {
|
||||
return SDL_SetError("vkCreateXcbSurfaceKHR failed: %s", SDL_Vulkan_GetResultString(result));
|
||||
}
|
||||
} else {
|
||||
PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR =
|
||||
(PFN_vkCreateXlibSurfaceKHR)vkGetInstanceProcAddr(instance,
|
||||
"vkCreateXlibSurfaceKHR");
|
||||
VkXlibSurfaceCreateInfoKHR createInfo;
|
||||
VkResult result;
|
||||
if (!vkCreateXlibSurfaceKHR) {
|
||||
return SDL_SetError(VK_KHR_XLIB_SURFACE_EXTENSION_NAME " extension is not enabled in the Vulkan instance.");
|
||||
}
|
||||
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, allocator, surface);
|
||||
if (result != VK_SUCCESS) {
|
||||
return SDL_SetError("vkCreateXlibSurfaceKHR failed: %s", SDL_Vulkan_GetResultString(result));
|
||||
}
|
||||
}
|
||||
|
||||
return true; // success!
|
||||
}
|
||||
|
||||
void X11_Vulkan_DestroySurface(SDL_VideoDevice *_this,
|
||||
VkInstance instance,
|
||||
VkSurfaceKHR surface,
|
||||
const struct VkAllocationCallbacks *allocator)
|
||||
{
|
||||
if (_this->vulkan_config.loader_handle) {
|
||||
SDL_Vulkan_DestroySurface_Internal(_this->vulkan_config.vkGetInstanceProcAddr, instance, surface, allocator);
|
||||
}
|
||||
}
|
||||
|
||||
bool X11_Vulkan_GetPresentationSupport(SDL_VideoDevice *_this,
|
||||
VkInstance instance,
|
||||
VkPhysicalDevice physicalDevice,
|
||||
Uint32 queueFamilyIndex)
|
||||
{
|
||||
SDL_VideoData *videoData = _this->internal;
|
||||
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
|
||||
const char *forced_visual_id;
|
||||
VisualID visualid;
|
||||
|
||||
if (!_this->vulkan_config.loader_handle) {
|
||||
return SDL_SetError("Vulkan is not loaded");
|
||||
}
|
||||
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr;
|
||||
|
||||
forced_visual_id = SDL_GetHint(SDL_HINT_VIDEO_X11_WINDOW_VISUALID);
|
||||
if (forced_visual_id) {
|
||||
visualid = SDL_strtol(forced_visual_id, NULL, 0);
|
||||
} else {
|
||||
visualid = X11_XVisualIDFromVisual(DefaultVisual(videoData->display, DefaultScreen(videoData->display)));
|
||||
}
|
||||
|
||||
if (videoData->vulkan_xlib_xcb_library) {
|
||||
PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR =
|
||||
(PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)vkGetInstanceProcAddr(
|
||||
instance,
|
||||
"vkGetPhysicalDeviceXcbPresentationSupportKHR");
|
||||
|
||||
if (!vkGetPhysicalDeviceXcbPresentationSupportKHR) {
|
||||
return SDL_SetError(VK_KHR_XCB_SURFACE_EXTENSION_NAME " extension is not enabled in the Vulkan instance.");
|
||||
}
|
||||
|
||||
return vkGetPhysicalDeviceXcbPresentationSupportKHR(physicalDevice,
|
||||
queueFamilyIndex,
|
||||
videoData->vulkan_XGetXCBConnection(videoData->display),
|
||||
visualid);
|
||||
} else {
|
||||
PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR =
|
||||
(PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR)vkGetInstanceProcAddr(
|
||||
instance,
|
||||
"vkGetPhysicalDeviceXlibPresentationSupportKHR");
|
||||
|
||||
if (!vkGetPhysicalDeviceXlibPresentationSupportKHR) {
|
||||
return SDL_SetError(VK_KHR_XLIB_SURFACE_EXTENSION_NAME " extension is not enabled in the Vulkan instance.");
|
||||
}
|
||||
|
||||
return vkGetPhysicalDeviceXlibPresentationSupportKHR(physicalDevice,
|
||||
queueFamilyIndex,
|
||||
videoData->display,
|
||||
visualid);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
52
vendor/sdl-3.2.10/src/video/x11/SDL_x11vulkan.h
vendored
Normal file
52
vendor/sdl-3.2.10/src/video/x11/SDL_x11vulkan.h
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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 <SDL3/SDL_vulkan.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);
|
||||
|
||||
extern bool X11_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path);
|
||||
extern void X11_Vulkan_UnloadLibrary(SDL_VideoDevice *_this);
|
||||
extern char const* const* X11_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count);
|
||||
extern bool X11_Vulkan_CreateSurface(SDL_VideoDevice *_this,
|
||||
SDL_Window *window,
|
||||
VkInstance instance,
|
||||
const struct VkAllocationCallbacks *allocator,
|
||||
VkSurfaceKHR *surface);
|
||||
extern void X11_Vulkan_DestroySurface(SDL_VideoDevice *_this,
|
||||
VkInstance instance,
|
||||
VkSurfaceKHR surface,
|
||||
const struct VkAllocationCallbacks *allocator);
|
||||
extern bool X11_Vulkan_GetPresentationSupport(SDL_VideoDevice *_this,
|
||||
VkInstance instance,
|
||||
VkPhysicalDevice physicalDevice,
|
||||
Uint32 queueFamilyIndex);
|
||||
|
||||
#endif
|
||||
|
||||
#endif // SDL_x11vulkan_h_
|
||||
2265
vendor/sdl-3.2.10/src/video/x11/SDL_x11window.c
vendored
Normal file
2265
vendor/sdl-3.2.10/src/video/x11/SDL_x11window.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
169
vendor/sdl-3.2.10/src/video/x11/SDL_x11window.h
vendored
Normal file
169
vendor/sdl-3.2.10/src/video/x11/SDL_x11window.h
vendored
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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
|
||||
bool use_mitshm;
|
||||
XShmSegmentInfo shminfo;
|
||||
#endif
|
||||
XImage *ximage;
|
||||
GC gc;
|
||||
XIC ic;
|
||||
bool created;
|
||||
int border_left;
|
||||
int border_right;
|
||||
int border_top;
|
||||
int border_bottom;
|
||||
bool xinput2_mouse_enabled;
|
||||
bool xinput2_keyboard_enabled;
|
||||
bool mouse_grabbed;
|
||||
Uint64 last_focus_event_time;
|
||||
PendingFocusEnum pending_focus;
|
||||
Uint64 pending_focus_time;
|
||||
bool pending_move;
|
||||
SDL_Point pending_move_point;
|
||||
XConfigureEvent last_xconfigure;
|
||||
struct SDL_VideoData *videodata;
|
||||
unsigned long user_time;
|
||||
Atom xdnd_req;
|
||||
Window xdnd_source;
|
||||
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
|
||||
bool pointer_barrier_active;
|
||||
PointerBarrier barrier[4];
|
||||
SDL_Rect barrier_rect;
|
||||
#endif // SDL_VIDEO_DRIVER_X11_XFIXES
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
|
||||
XSyncCounter resize_counter;
|
||||
XSyncValue resize_id;
|
||||
bool resize_in_progress;
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */
|
||||
|
||||
SDL_Rect expected;
|
||||
SDL_DisplayMode requested_fullscreen_mode;
|
||||
|
||||
enum
|
||||
{
|
||||
X11_PENDING_OP_NONE = 0x00,
|
||||
X11_PENDING_OP_RESTORE = 0x01,
|
||||
X11_PENDING_OP_MINIMIZE = 0x02,
|
||||
X11_PENDING_OP_MAXIMIZE = 0x04,
|
||||
X11_PENDING_OP_FULLSCREEN = 0x08,
|
||||
X11_PENDING_OP_MOVE = 0x10,
|
||||
X11_PENDING_OP_RESIZE = 0x20
|
||||
} pending_operation;
|
||||
|
||||
enum
|
||||
{
|
||||
X11_SIZE_MOVE_EVENTS_DISABLE = 0x01, // Events are completely disabled.
|
||||
X11_SIZE_MOVE_EVENTS_WAIT_FOR_BORDERS = 0x02, // Events are disabled until a _NET_FRAME_EXTENTS event arrives.
|
||||
} size_move_event_flags;
|
||||
|
||||
bool pending_size;
|
||||
bool pending_position;
|
||||
bool window_was_maximized;
|
||||
bool previous_borders_nonzero;
|
||||
bool toggle_borders;
|
||||
bool fullscreen_borders_forced_on;
|
||||
SDL_HitTestResult hit_test_result;
|
||||
|
||||
XPoint xim_spot;
|
||||
char *preedit_text;
|
||||
XIMFeedback *preedit_feedback;
|
||||
int preedit_length;
|
||||
int preedit_cursor;
|
||||
bool ime_needs_clear_composition;
|
||||
};
|
||||
|
||||
extern void X11_SetNetWMState(SDL_VideoDevice *_this, Window xwindow, SDL_WindowFlags flags);
|
||||
extern Uint32 X11_GetNetWMState(SDL_VideoDevice *_this, SDL_Window *window, Window xwindow);
|
||||
|
||||
extern bool X11_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props);
|
||||
extern char *X11_GetWindowTitle(SDL_VideoDevice *_this, Window xwindow);
|
||||
extern void X11_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool X11_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *icon);
|
||||
extern bool 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 void X11_SetWindowAspectRatio(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool X11_GetWindowBordersSize(SDL_VideoDevice *_this, SDL_Window *window, int *top, int *left, int *bottom, int *right);
|
||||
extern bool X11_SetWindowOpacity(SDL_VideoDevice *_this, SDL_Window *window, float opacity);
|
||||
extern bool X11_SetWindowParent(SDL_VideoDevice *_this, SDL_Window *window, SDL_Window *parent);
|
||||
extern bool X11_SetWindowModal(SDL_VideoDevice *_this, SDL_Window *window, bool modal);
|
||||
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, bool bordered);
|
||||
extern void X11_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, bool resizable);
|
||||
extern void X11_SetWindowAlwaysOnTop(SDL_VideoDevice *_this, SDL_Window *window, bool on_top);
|
||||
extern SDL_FullscreenResult X11_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_FullscreenOp fullscreen);
|
||||
extern void *X11_GetWindowICCProfile(SDL_VideoDevice *_this, SDL_Window *window, size_t *size);
|
||||
extern bool X11_SetWindowMouseGrab(SDL_VideoDevice *_this, SDL_Window *window, bool grabbed);
|
||||
extern bool X11_SetWindowKeyboardGrab(SDL_VideoDevice *_this, SDL_Window *window, bool grabbed);
|
||||
extern void X11_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool X11_SetWindowHitTest(SDL_Window *window, bool enabled);
|
||||
extern void X11_AcceptDragAndDrop(SDL_Window *window, bool accept);
|
||||
extern bool X11_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
|
||||
extern void X11_ShowWindowSystemMenu(SDL_Window *window, int x, int y);
|
||||
extern bool X11_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool X11_SetWindowFocusable(SDL_VideoDevice *_this, SDL_Window *window, bool focusable);
|
||||
|
||||
extern bool SDL_X11_SetWindowTitle(Display *display, Window xwindow, char *title);
|
||||
extern void X11_UpdateWindowPosition(SDL_Window *window, bool use_current_position);
|
||||
extern void X11_SetWindowMinMax(SDL_Window *window, bool use_current);
|
||||
|
||||
#endif // SDL_x11window_h_
|
||||
214
vendor/sdl-3.2.10/src/video/x11/SDL_x11xfixes.c
vendored
Normal file
214
vendor/sdl-3.2.10/src/video/x11/SDL_x11xfixes.c
vendored
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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 bool xfixes_initialized = true;
|
||||
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 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->internal;
|
||||
|
||||
int version = 0;
|
||||
int event, error;
|
||||
int fixes_opcode;
|
||||
|
||||
Atom XA_CLIPBOARD = data->atoms.CLIPBOARD;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool X11_XfixesIsInitialized(void)
|
||||
{
|
||||
return xfixes_initialized;
|
||||
}
|
||||
|
||||
int X11_GetXFixesSelectionNotifyEvent(void)
|
||||
{
|
||||
return xfixes_selection_notify_event;
|
||||
}
|
||||
|
||||
bool 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->internal;
|
||||
|
||||
SDL_memcpy(&wdata->barrier_rect, &window->mouse_rect, sizeof(wdata->barrier_rect));
|
||||
|
||||
wdata->pointer_barrier_active = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool 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->internal;
|
||||
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->internal;
|
||||
|
||||
/* 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 = 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 = false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void X11_DestroyPointerBarrier(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
int i;
|
||||
SDL_VideoData *data = _this->internal;
|
||||
if (window) {
|
||||
SDL_WindowData *wdata = window->internal;
|
||||
|
||||
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
|
||||
39
vendor/sdl-3.2.10/src/video/x11/SDL_x11xfixes.h
vendored
Normal file
39
vendor/sdl-3.2.10/src/video/x11/SDL_x11xfixes.h
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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 bool X11_XfixesIsInitialized(void);
|
||||
extern bool X11_SetWindowMouseRect(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern bool 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_
|
||||
829
vendor/sdl-3.2.10/src/video/x11/SDL_x11xinput2.c
vendored
Normal file
829
vendor/sdl-3.2.10/src/video/x11/SDL_x11xinput2.c
vendored
Normal file
|
|
@ -0,0 +1,829 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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_x11pen.h"
|
||||
#include "SDL_x11video.h"
|
||||
#include "SDL_x11xinput2.h"
|
||||
#include "../../events/SDL_events_c.h"
|
||||
#include "../../events/SDL_mouse_c.h"
|
||||
#include "../../events/SDL_pen_c.h"
|
||||
#include "../../events/SDL_touch_c.h"
|
||||
|
||||
#define MAX_AXIS 16
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
|
||||
static bool xinput2_initialized;
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
|
||||
static bool xinput2_multitouch_supported;
|
||||
#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 bool xinput2_version_atleast(const int version, const int wantmajor, const int wantminor)
|
||||
{
|
||||
return version >= ((wantmajor * 1000) + wantminor);
|
||||
}
|
||||
|
||||
static SDL_WindowData *xinput2_get_sdlwindowdata(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;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static SDL_Window *xinput2_get_sdlwindow(SDL_VideoData *videodata, Window window)
|
||||
{
|
||||
const SDL_WindowData *windowdata = xinput2_get_sdlwindowdata(videodata, window);
|
||||
return windowdata ? windowdata->window : NULL;
|
||||
}
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
|
||||
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 = (float)in_x / (window->w - 1);
|
||||
}
|
||||
if (window->h == 1) {
|
||||
*out_y = 0.5f;
|
||||
} else {
|
||||
*out_y = (float)in_y / (window->h - 1);
|
||||
}
|
||||
} else {
|
||||
// couldn't find the window...
|
||||
*out_x = (float)in_x;
|
||||
*out_y = (float)in_y;
|
||||
}
|
||||
}
|
||||
#endif // SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_X11_XINPUT2
|
||||
|
||||
bool X11_InitXinput2(SDL_VideoDevice *_this)
|
||||
{
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
|
||||
SDL_VideoData *data = _this->internal;
|
||||
|
||||
int version = 0;
|
||||
XIEventMask eventmask;
|
||||
unsigned char mask[4] = { 0, 0, 0, 0 };
|
||||
int event, err;
|
||||
|
||||
/* XInput2 is required for relative mouse mode, so you probably want to leave this enabled */
|
||||
if (!SDL_GetHintBoolean("SDL_VIDEO_X11_XINPUT2", true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 false; // 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 false; // X server does not support the version we want at all.
|
||||
}
|
||||
|
||||
xinput2_initialized = true;
|
||||
|
||||
#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
|
||||
SDL_zero(eventmask);
|
||||
SDL_zeroa(mask);
|
||||
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
|
||||
|
||||
X11_XISelectEvents(data->display, DefaultRootWindow(data->display), &eventmask, 1);
|
||||
|
||||
SDL_zero(eventmask);
|
||||
SDL_zeroa(mask);
|
||||
eventmask.deviceid = XIAllDevices;
|
||||
eventmask.mask_len = sizeof(mask);
|
||||
eventmask.mask = mask;
|
||||
|
||||
XISetMask(mask, XI_HierarchyChanged);
|
||||
X11_XISelectEvents(data->display, DefaultRootWindow(data->display), &eventmask, 1);
|
||||
|
||||
X11_Xinput2UpdateDevices(_this, true);
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#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; devinfo = devinfo->next) {
|
||||
if (devinfo->device_id == device_id) {
|
||||
SDL_assert((devinfo == videodata->mouse_device_info) == (prev == NULL));
|
||||
if (!prev) {
|
||||
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; devinfo = devinfo->next) {
|
||||
if (devinfo->device_id == device_id) {
|
||||
SDL_assert((devinfo == videodata->mouse_device_info) == (prev == NULL));
|
||||
if (prev) { // 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) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xidevinfo = X11_XIQueryDevice(videodata->display, device_id, &i);
|
||||
if (!xidevinfo) {
|
||||
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);
|
||||
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
|
||||
|
||||
void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie)
|
||||
{
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
|
||||
SDL_VideoData *videodata = _this->internal;
|
||||
|
||||
if (cookie->extension != xinput2_opcode) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (cookie->evtype) {
|
||||
case XI_HierarchyChanged:
|
||||
{
|
||||
const XIHierarchyEvent *hierev = (const XIHierarchyEvent *)cookie->data;
|
||||
int i;
|
||||
for (i = 0; i < hierev->num_info; i++) {
|
||||
// pen stuff...
|
||||
if ((hierev->info[i].flags & (XISlaveRemoved | XIDeviceDisabled)) != 0) {
|
||||
X11_RemovePenByDeviceID(hierev->info[i].deviceid); // it's okay if this thing isn't actually a pen, it'll handle it.
|
||||
} else if ((hierev->info[i].flags & (XISlaveAdded | XIDeviceEnabled)) != 0) {
|
||||
X11_MaybeAddPenByDeviceID(_this, hierev->info[i].deviceid); // this will do more checks to make sure this is valid.
|
||||
}
|
||||
|
||||
// not pen stuff...
|
||||
if (hierev->info[i].flags & XISlaveRemoved) {
|
||||
xinput2_remove_device_info(videodata, hierev->info[i].deviceid);
|
||||
}
|
||||
}
|
||||
videodata->xinput_hierarchy_changed = true;
|
||||
} break;
|
||||
|
||||
// !!! FIXME: the pen code used to rescan all devices here, but we can do this device-by-device with XI_HierarchyChanged. When do these events fire and why?
|
||||
//case XI_PropertyEvent:
|
||||
//case XI_DeviceChanged:
|
||||
|
||||
case XI_RawMotion:
|
||||
{
|
||||
const XIRawEvent *rawev = (const XIRawEvent *)cookie->data;
|
||||
const bool is_pen = X11_FindPenByDeviceID(rawev->sourceid) != NULL;
|
||||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
SDL_XInput2DeviceInfo *devinfo;
|
||||
double coords[2];
|
||||
double processed_coords[2];
|
||||
int i;
|
||||
Uint64 timestamp = X11_GetEventTimestamp(rawev->time);
|
||||
|
||||
videodata->global_mouse_changed = true;
|
||||
if (is_pen) {
|
||||
break; // Pens check for XI_Motion instead
|
||||
}
|
||||
|
||||
devinfo = xinput2_get_device_info(videodata, rawev->deviceid);
|
||||
if (!devinfo) {
|
||||
break; // 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
|
||||
}
|
||||
}
|
||||
|
||||
// Relative mouse motion is delivered to the window with keyboard focus
|
||||
if (mouse->relative_mode && SDL_GetKeyboardFocus()) {
|
||||
SDL_SendMouseMotion(timestamp, mouse->focus, (SDL_MouseID)rawev->sourceid, true, (float)processed_coords[0], (float)processed_coords[1]);
|
||||
}
|
||||
|
||||
devinfo->prev_coords[0] = coords[0];
|
||||
devinfo->prev_coords[1] = coords[1];
|
||||
} break;
|
||||
|
||||
case XI_KeyPress:
|
||||
case XI_KeyRelease:
|
||||
{
|
||||
const XIDeviceEvent *xev = (const XIDeviceEvent *)cookie->data;
|
||||
SDL_WindowData *windowdata = X11_FindWindow(_this, xev->event);
|
||||
XEvent xevent;
|
||||
|
||||
if (xev->deviceid != xev->sourceid) {
|
||||
// Discard events from "Master" devices to avoid duplicates.
|
||||
break;
|
||||
}
|
||||
|
||||
if (cookie->evtype == XI_KeyPress) {
|
||||
xevent.type = KeyPress;
|
||||
} else {
|
||||
xevent.type = KeyRelease;
|
||||
}
|
||||
xevent.xkey.serial = xev->serial;
|
||||
xevent.xkey.send_event = xev->send_event;
|
||||
xevent.xkey.display = xev->display;
|
||||
xevent.xkey.window = xev->event;
|
||||
xevent.xkey.root = xev->root;
|
||||
xevent.xkey.subwindow = xev->child;
|
||||
xevent.xkey.time = xev->time;
|
||||
xevent.xkey.x = (int)xev->event_x;
|
||||
xevent.xkey.y = (int)xev->event_y;
|
||||
xevent.xkey.x_root = (int)xev->root_x;
|
||||
xevent.xkey.y_root = (int)xev->root_y;
|
||||
xevent.xkey.state = xev->mods.effective;
|
||||
xevent.xkey.keycode = xev->detail;
|
||||
xevent.xkey.same_screen = 1;
|
||||
|
||||
X11_HandleKeyEvent(_this, windowdata, (SDL_KeyboardID)xev->sourceid, &xevent);
|
||||
} 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 = true;
|
||||
} break;
|
||||
|
||||
case XI_ButtonPress:
|
||||
case XI_ButtonRelease:
|
||||
{
|
||||
const XIDeviceEvent *xev = (const XIDeviceEvent *)cookie->data;
|
||||
X11_PenHandle *pen = X11_FindPenByDeviceID(xev->deviceid);
|
||||
const int button = xev->detail;
|
||||
const bool down = (cookie->evtype == XI_ButtonPress);
|
||||
|
||||
if (pen) {
|
||||
// Only report button event; if there was also pen movement / pressure changes, we expect an XI_Motion event first anyway.
|
||||
SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
|
||||
if (button == 1) { // button 1 is the pen tip
|
||||
SDL_SendPenTouch(0, pen->pen, window, pen->is_eraser, down);
|
||||
} else {
|
||||
SDL_SendPenButton(0, pen->pen, window, button - 1, down);
|
||||
}
|
||||
} else {
|
||||
// Otherwise assume a regular mouse
|
||||
SDL_WindowData *windowdata = xinput2_get_sdlwindowdata(videodata, xev->event);
|
||||
|
||||
if (xev->deviceid != xev->sourceid) {
|
||||
// Discard events from "Master" devices to avoid duplicates.
|
||||
break;
|
||||
}
|
||||
|
||||
if (down) {
|
||||
X11_HandleButtonPress(_this, windowdata, (SDL_MouseID)xev->sourceid, button,
|
||||
(float)xev->event_x, (float)xev->event_y, xev->time);
|
||||
} else {
|
||||
X11_HandleButtonRelease(_this, windowdata, (SDL_MouseID)xev->sourceid, button, xev->time);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
/* Register to receive XI_Motion (which deactivates MotionNotify), so that we can distinguish
|
||||
real mouse motions from synthetic ones, for multitouch and pen support. */
|
||||
case XI_Motion:
|
||||
{
|
||||
const XIDeviceEvent *xev = (const XIDeviceEvent *)cookie->data;
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
|
||||
bool pointer_emulated = ((xev->flags & XIPointerEmulated) != 0);
|
||||
#else
|
||||
bool pointer_emulated = false;
|
||||
#endif
|
||||
|
||||
videodata->global_mouse_changed = true;
|
||||
|
||||
X11_PenHandle *pen = X11_FindPenByDeviceID(xev->deviceid);
|
||||
if (pen) {
|
||||
if (xev->deviceid != xev->sourceid) {
|
||||
// Discard events from "Master" devices to avoid duplicates.
|
||||
break;
|
||||
}
|
||||
|
||||
SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
|
||||
SDL_SendPenMotion(0, pen->pen, window, (float) xev->event_x, (float) xev->event_y);
|
||||
|
||||
float axes[SDL_PEN_AXIS_COUNT];
|
||||
X11_PenAxesFromValuators(pen, xev->valuators.values, xev->valuators.mask, xev->valuators.mask_len, axes);
|
||||
|
||||
for (int i = 0; i < SDL_arraysize(axes); i++) {
|
||||
if (pen->valuator_for_axis[i] != SDL_X11_PEN_AXIS_VALUATOR_MISSING) {
|
||||
SDL_SendPenAxis(0, pen->pen, window, (SDL_PenAxis) i, axes[i]);
|
||||
}
|
||||
}
|
||||
} else if (!pointer_emulated && xev->deviceid == videodata->xinput_master_pointer_device) {
|
||||
// Use the master device for non-relative motion, as the slave devices can seemingly lag behind.
|
||||
SDL_Mouse *mouse = SDL_GetMouse();
|
||||
if (!mouse->relative_mode) {
|
||||
SDL_Window *window = xinput2_get_sdlwindow(videodata, xev->event);
|
||||
if (window) {
|
||||
X11_ProcessHitTest(_this, window->internal, (float)xev->event_x, (float)xev->event_y, false);
|
||||
SDL_SendMouseMotion(0, window, SDL_GLOBAL_MOUSE_ID, false, (float)xev->event_x, (float)xev->event_y);
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
|
||||
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_EVENT_FINGER_DOWN, x, y, 1.0);
|
||||
} 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_EVENT_FINGER_UP, x, y, 1.0);
|
||||
} 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);
|
||||
} break;
|
||||
#endif // SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
|
||||
}
|
||||
#endif // SDL_VIDEO_DRIVER_X11_XINPUT2
|
||||
}
|
||||
|
||||
void X11_InitXinput2Multitouch(SDL_VideoDevice *_this)
|
||||
{
|
||||
}
|
||||
|
||||
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->internal;
|
||||
window_data = window->internal;
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
bool X11_Xinput2IsInitialized(void)
|
||||
{
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
|
||||
return xinput2_initialized;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool X11_Xinput2SelectMouseAndKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_WindowData *windowdata = window->internal;
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
|
||||
const SDL_VideoData *data = _this->internal;
|
||||
|
||||
if (X11_Xinput2IsInitialized()) {
|
||||
XIEventMask eventmask;
|
||||
unsigned char mask[4] = { 0, 0, 0, 0 };
|
||||
|
||||
eventmask.mask_len = sizeof(mask);
|
||||
eventmask.mask = mask;
|
||||
eventmask.deviceid = XIAllDevices;
|
||||
|
||||
// This is not enabled by default because these events are only delivered to the window with mouse focus, not keyboard focus
|
||||
#ifdef USE_XINPUT2_KEYBOARD
|
||||
XISetMask(mask, XI_KeyPress);
|
||||
XISetMask(mask, XI_KeyRelease);
|
||||
windowdata->xinput2_keyboard_enabled = true;
|
||||
#endif
|
||||
|
||||
XISetMask(mask, XI_ButtonPress);
|
||||
XISetMask(mask, XI_ButtonRelease);
|
||||
XISetMask(mask, XI_Motion);
|
||||
windowdata->xinput2_mouse_enabled = true;
|
||||
|
||||
XISetMask(mask, XI_Enter);
|
||||
XISetMask(mask, XI_Leave);
|
||||
|
||||
// Hotplugging:
|
||||
XISetMask(mask, XI_DeviceChanged);
|
||||
XISetMask(mask, XI_HierarchyChanged);
|
||||
XISetMask(mask, XI_PropertyEvent); // E.g., when swapping tablet pens
|
||||
|
||||
if (X11_XISelectEvents(data->display, windowdata->xwindow, &eventmask, 1) != Success) {
|
||||
SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "Could not enable XInput2 event handling");
|
||||
windowdata->xinput2_keyboard_enabled = false;
|
||||
windowdata->xinput2_mouse_enabled = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (windowdata->xinput2_keyboard_enabled || windowdata->xinput2_mouse_enabled) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool X11_Xinput2IsMultitouchSupported(void)
|
||||
{
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
|
||||
return xinput2_initialized && xinput2_multitouch_supported;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void X11_Xinput2GrabTouch(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
|
||||
SDL_WindowData *data = window->internal;
|
||||
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->internal;
|
||||
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
|
||||
}
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
|
||||
|
||||
static void AddDeviceID(Uint32 deviceID, Uint32 **list, int *count)
|
||||
{
|
||||
int new_count = (*count + 1);
|
||||
Uint32 *new_list = (Uint32 *)SDL_realloc(*list, new_count * sizeof(*new_list));
|
||||
if (!new_list) {
|
||||
// Oh well, we'll drop this one
|
||||
return;
|
||||
}
|
||||
new_list[new_count - 1] = deviceID;
|
||||
|
||||
*count = new_count;
|
||||
*list = new_list;
|
||||
}
|
||||
|
||||
static bool HasDeviceID(Uint32 deviceID, const Uint32 *list, int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (deviceID == list[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void AddDeviceID64(Uint64 deviceID, Uint64 **list, int *count)
|
||||
{
|
||||
int new_count = (*count + 1);
|
||||
Uint64 *new_list = (Uint64 *)SDL_realloc(*list, new_count * sizeof(*new_list));
|
||||
if (!new_list) {
|
||||
// Oh well, we'll drop this one
|
||||
return;
|
||||
}
|
||||
new_list[new_count - 1] = deviceID;
|
||||
|
||||
*count = new_count;
|
||||
*list = new_list;
|
||||
}
|
||||
|
||||
static bool HasDeviceID64(Uint64 deviceID, const Uint64 *list, int count)
|
||||
{
|
||||
for (int i = 0; i < count; ++i) {
|
||||
if (deviceID == list[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_X11_XINPUT2
|
||||
|
||||
void X11_Xinput2UpdateDevices(SDL_VideoDevice *_this, bool initial_check)
|
||||
{
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2
|
||||
SDL_VideoData *data = _this->internal;
|
||||
XIDeviceInfo *info;
|
||||
int ndevices;
|
||||
int old_keyboard_count = 0;
|
||||
SDL_KeyboardID *old_keyboards = NULL;
|
||||
int new_keyboard_count = 0;
|
||||
SDL_KeyboardID *new_keyboards = NULL;
|
||||
int old_mouse_count = 0;
|
||||
SDL_MouseID *old_mice = NULL;
|
||||
int new_mouse_count = 0;
|
||||
SDL_MouseID *new_mice = NULL;
|
||||
int old_touch_count = 0;
|
||||
Uint64 *old_touch_devices = NULL;
|
||||
int new_touch_count = 0;
|
||||
Uint64 *new_touch_devices = NULL;
|
||||
bool send_event = !initial_check;
|
||||
|
||||
SDL_assert(X11_Xinput2IsInitialized());
|
||||
|
||||
info = X11_XIQueryDevice(data->display, XIAllDevices, &ndevices);
|
||||
|
||||
old_keyboards = SDL_GetKeyboards(&old_keyboard_count);
|
||||
old_mice = SDL_GetMice(&old_mouse_count);
|
||||
old_touch_devices = SDL_GetTouchDevices(&old_touch_count);
|
||||
|
||||
for (int i = 0; i < ndevices; i++) {
|
||||
XIDeviceInfo *dev = &info[i];
|
||||
|
||||
switch (dev->use) {
|
||||
case XIMasterKeyboard:
|
||||
case XISlaveKeyboard:
|
||||
{
|
||||
SDL_KeyboardID keyboardID = (SDL_KeyboardID)dev->deviceid;
|
||||
AddDeviceID(keyboardID, &new_keyboards, &new_keyboard_count);
|
||||
if (!HasDeviceID(keyboardID, old_keyboards, old_keyboard_count)) {
|
||||
SDL_AddKeyboard(keyboardID, dev->name, send_event);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case XIMasterPointer:
|
||||
data->xinput_master_pointer_device = dev->deviceid;
|
||||
SDL_FALLTHROUGH;
|
||||
case XISlavePointer:
|
||||
{
|
||||
SDL_MouseID mouseID = (SDL_MouseID)dev->deviceid;
|
||||
AddDeviceID(mouseID, &new_mice, &new_mouse_count);
|
||||
if (!HasDeviceID(mouseID, old_mice, old_mouse_count)) {
|
||||
SDL_AddMouse(mouseID, dev->name, send_event);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
|
||||
for (int j = 0; j < dev->num_classes; j++) {
|
||||
Uint64 touchID;
|
||||
SDL_TouchDeviceType touchType;
|
||||
XIAnyClassInfo *class = dev->classes[j];
|
||||
XITouchClassInfo *t = (XITouchClassInfo *)class;
|
||||
|
||||
// Only touch devices
|
||||
if (class->type != XITouchClass) {
|
||||
continue;
|
||||
}
|
||||
|
||||
touchID = (Uint64)t->sourceid;
|
||||
AddDeviceID64(touchID, &new_touch_devices, &new_touch_count);
|
||||
if (!HasDeviceID64(touchID, old_touch_devices, old_touch_count)) {
|
||||
if (t->mode == XIDependentTouch) {
|
||||
touchType = SDL_TOUCH_DEVICE_INDIRECT_RELATIVE;
|
||||
} else { // XIDirectTouch
|
||||
touchType = SDL_TOUCH_DEVICE_DIRECT;
|
||||
}
|
||||
SDL_AddTouch(touchID, touchType, dev->name);
|
||||
}
|
||||
}
|
||||
#endif // SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
|
||||
}
|
||||
|
||||
for (int i = old_keyboard_count; i--;) {
|
||||
if (!HasDeviceID(old_keyboards[i], new_keyboards, new_keyboard_count)) {
|
||||
SDL_RemoveKeyboard(old_keyboards[i], send_event);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = old_mouse_count; i--;) {
|
||||
if (!HasDeviceID(old_mice[i], new_mice, new_mouse_count)) {
|
||||
SDL_RemoveMouse(old_mice[i], send_event);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = old_touch_count; i--;) {
|
||||
if (!HasDeviceID64(old_touch_devices[i], new_touch_devices, new_touch_count)) {
|
||||
SDL_DelTouch(old_touch_devices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_free(old_keyboards);
|
||||
SDL_free(new_keyboards);
|
||||
SDL_free(old_mice);
|
||||
SDL_free(new_mice);
|
||||
SDL_free(old_touch_devices);
|
||||
SDL_free(new_touch_devices);
|
||||
|
||||
X11_XIFreeDeviceInfo(info);
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_X11_XINPUT2
|
||||
}
|
||||
|
||||
#endif // SDL_VIDEO_DRIVER_X11
|
||||
44
vendor/sdl-3.2.10/src/video/x11/SDL_x11xinput2.h
vendored
Normal file
44
vendor/sdl-3.2.10/src/video/x11/SDL_x11xinput2.h
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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 bool X11_InitXinput2(SDL_VideoDevice *_this);
|
||||
extern void X11_InitXinput2Multitouch(SDL_VideoDevice *_this);
|
||||
extern void X11_HandleXinput2Event(SDL_VideoDevice *_this, XGenericEventCookie *cookie);
|
||||
extern bool X11_Xinput2IsInitialized(void);
|
||||
extern bool 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);
|
||||
extern bool X11_Xinput2SelectMouseAndKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void X11_Xinput2UpdateDevices(SDL_VideoDevice *_this, bool initial_check);
|
||||
|
||||
#endif // SDL_x11xinput2_h_
|
||||
148
vendor/sdl-3.2.10/src/video/x11/SDL_x11xsync.c
vendored
Normal file
148
vendor/sdl-3.2.10/src/video/x11/SDL_x11xsync.c
vendored
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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_XSYNC)
|
||||
|
||||
#include "SDL_x11video.h"
|
||||
#include "SDL_x11xsync.h"
|
||||
|
||||
static int xsync_initialized = 0;
|
||||
|
||||
static int query_xsync_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_XSyncInitialize(display, &major, &minor);
|
||||
return (major * 1000) + minor;
|
||||
}
|
||||
|
||||
static bool xsync_version_atleast(const int version, const int wantmajor, const int wantminor)
|
||||
{
|
||||
return version >= ((wantmajor * 1000) + wantminor);
|
||||
}
|
||||
|
||||
void X11_InitXsync(SDL_VideoDevice *_this)
|
||||
{
|
||||
SDL_VideoData *data = _this->internal;
|
||||
|
||||
int version = 0;
|
||||
int event, error;
|
||||
int sync_opcode;
|
||||
|
||||
if (!SDL_X11_HAVE_XSYNC ||
|
||||
!X11_XQueryExtension(data->display, "SYNC", &sync_opcode, &event, &error)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* We need at least 5.0 for barriers. */
|
||||
version = query_xsync_version(data->display, 5, 0);
|
||||
if (!xsync_version_atleast(version, 3, 0)) {
|
||||
return; /* X server does not support the version we want at all. */
|
||||
}
|
||||
|
||||
xsync_initialized = 1;
|
||||
}
|
||||
|
||||
int X11_XsyncIsInitialized(void)
|
||||
{
|
||||
return xsync_initialized;
|
||||
}
|
||||
|
||||
int X11_InitResizeSync(SDL_Window *window)
|
||||
{
|
||||
SDL_assert(window != NULL);
|
||||
SDL_WindowData *data = window->internal;
|
||||
Display *display = data->videodata->display;
|
||||
Atom counter_prop = data->videodata->atoms._NET_WM_SYNC_REQUEST_COUNTER;
|
||||
XSyncCounter counter;
|
||||
CARD32 counter_id;
|
||||
|
||||
if (!X11_XsyncIsInitialized()){
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
counter = X11_XSyncCreateCounter(display, (XSyncValue){0, 0});
|
||||
data->resize_counter = counter;
|
||||
data->resize_id.lo = 0;
|
||||
data->resize_id.hi = 0;
|
||||
data->resize_in_progress = false;
|
||||
|
||||
if (counter == None){
|
||||
return SDL_Unsupported();
|
||||
}
|
||||
|
||||
counter_id = counter;
|
||||
X11_XChangeProperty(display, data->xwindow, counter_prop, XA_CARDINAL, 32,
|
||||
PropModeReplace, (unsigned char *)&counter_id, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void X11_TermResizeSync(SDL_Window *window)
|
||||
{
|
||||
SDL_WindowData *data = window->internal;
|
||||
Display *display = data->videodata->display;
|
||||
Atom counter_prop = data->videodata->atoms._NET_WM_SYNC_REQUEST_COUNTER;
|
||||
XSyncCounter counter = data->resize_counter;
|
||||
|
||||
X11_XDeleteProperty(display, data->xwindow, counter_prop);
|
||||
if (counter != None) {
|
||||
X11_XSyncDestroyCounter(display, counter);
|
||||
}
|
||||
}
|
||||
|
||||
void X11_HandleSyncRequest(SDL_Window *window, XClientMessageEvent *event)
|
||||
{
|
||||
SDL_WindowData *data = window->internal;
|
||||
|
||||
data->resize_id.lo = event->data.l[2];
|
||||
data->resize_id.hi = event->data.l[3];
|
||||
data->resize_in_progress = false;
|
||||
}
|
||||
|
||||
void X11_HandleConfigure(SDL_Window *window, XConfigureEvent *event)
|
||||
{
|
||||
SDL_WindowData *data = window->internal;
|
||||
|
||||
if (data->resize_id.lo || data->resize_id.hi) {
|
||||
data->resize_in_progress = true;
|
||||
}
|
||||
}
|
||||
|
||||
void X11_HandlePresent(SDL_Window *window)
|
||||
{
|
||||
SDL_WindowData *data = window->internal;
|
||||
Display *display = data->videodata->display;
|
||||
XSyncCounter counter = data->resize_counter;
|
||||
|
||||
if ((counter == None) || (!data->resize_in_progress)) {
|
||||
return;
|
||||
}
|
||||
|
||||
X11_XSyncSetCounter(display, counter, data->resize_id);
|
||||
|
||||
data->resize_id.lo = 0;
|
||||
data->resize_id.hi = 0;
|
||||
data->resize_in_progress = false;
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_X11 && SDL_VIDEO_DRIVER_X11_XSYNC */
|
||||
39
vendor/sdl-3.2.10/src/video/x11/SDL_x11xsync.h
vendored
Normal file
39
vendor/sdl-3.2.10/src/video/x11/SDL_x11xsync.h
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2025 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_x11xsync_h_
|
||||
#define SDL_x11xsync_h_
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
|
||||
|
||||
extern void X11_InitXsync(SDL_VideoDevice *_this);
|
||||
extern int X11_XsyncIsInitialized(void);
|
||||
int X11_InitResizeSync(SDL_Window *window);
|
||||
void X11_TermResizeSync(SDL_Window *window);
|
||||
void X11_HandleSyncRequest(SDL_Window *window, XClientMessageEvent *event);
|
||||
void X11_HandleConfigure(SDL_Window *window, XConfigureEvent *event);
|
||||
void X11_HandlePresent(SDL_Window *window);
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */
|
||||
|
||||
#endif /* SDL_x11xsync_h_ */
|
||||
753
vendor/sdl-3.2.10/src/video/x11/edid-parse.c
vendored
Normal file
753
vendor/sdl-3.2.10/src/video/x11/edid-parse.c
vendored
Normal 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);
|
||||
}
|
||||
|
||||
191
vendor/sdl-3.2.10/src/video/x11/edid.h
vendored
Normal file
191
vendor/sdl-3.2.10/src/video/x11/edid.h
vendored
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
* 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> */
|
||||
|
||||
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);
|
||||
859
vendor/sdl-3.2.10/src/video/x11/xsettings-client.c
vendored
Normal file
859
vendor/sdl-3.2.10/src/video/x11/xsettings-client.c
vendored
Normal file
|
|
@ -0,0 +1,859 @@
|
|||
/*
|
||||
* Copyright © 2001, 2007 Red Hat, Inc.
|
||||
* Copyright 2024 Igalia S.L.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of Red Hat not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. Red Hat makes no representations about the
|
||||
* suitability of this software for any purpose. It is provided "as is"
|
||||
* without express or implied warranty.
|
||||
*
|
||||
* RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
|
||||
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Owen Taylor, Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include "SDL_internal.h"
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11
|
||||
|
||||
#include "SDL_x11video.h"
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "xsettings-client.h"
|
||||
|
||||
struct _XSettingsClient
|
||||
{
|
||||
Display *display;
|
||||
int screen;
|
||||
XSettingsNotifyFunc notify;
|
||||
XSettingsWatchFunc watch;
|
||||
void *cb_data;
|
||||
|
||||
XSettingsGrabFunc grab;
|
||||
XSettingsGrabFunc ungrab;
|
||||
|
||||
Window manager_window;
|
||||
Atom manager_atom;
|
||||
Atom selection_atom;
|
||||
Atom xsettings_atom;
|
||||
|
||||
XSettingsList *settings;
|
||||
};
|
||||
|
||||
static void
|
||||
notify_changes (XSettingsClient *client,
|
||||
XSettingsList *old_list)
|
||||
{
|
||||
XSettingsList *old_iter = old_list;
|
||||
XSettingsList *new_iter = client->settings;
|
||||
|
||||
if (!client->notify)
|
||||
return;
|
||||
|
||||
while (old_iter || new_iter)
|
||||
{
|
||||
int cmp;
|
||||
|
||||
if (old_iter && new_iter)
|
||||
cmp = strcmp (old_iter->setting->name, new_iter->setting->name);
|
||||
else if (old_iter)
|
||||
cmp = -1;
|
||||
else
|
||||
cmp = 1;
|
||||
|
||||
if (cmp < 0)
|
||||
{
|
||||
client->notify (old_iter->setting->name,
|
||||
XSETTINGS_ACTION_DELETED,
|
||||
NULL,
|
||||
client->cb_data);
|
||||
}
|
||||
else if (cmp == 0)
|
||||
{
|
||||
if (!xsettings_setting_equal (old_iter->setting,
|
||||
new_iter->setting))
|
||||
client->notify (old_iter->setting->name,
|
||||
XSETTINGS_ACTION_CHANGED,
|
||||
new_iter->setting,
|
||||
client->cb_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
client->notify (new_iter->setting->name,
|
||||
XSETTINGS_ACTION_NEW,
|
||||
new_iter->setting,
|
||||
client->cb_data);
|
||||
}
|
||||
|
||||
if (old_iter)
|
||||
old_iter = old_iter->next;
|
||||
if (new_iter)
|
||||
new_iter = new_iter->next;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ignore_errors (Display *display, XErrorEvent *event)
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
static char local_byte_order = '\0';
|
||||
|
||||
#define BYTES_LEFT(buffer) ((buffer)->data + (buffer)->len - (buffer)->pos)
|
||||
|
||||
static XSettingsResult
|
||||
fetch_card16 (XSettingsBuffer *buffer,
|
||||
CARD16 *result)
|
||||
{
|
||||
CARD16 x;
|
||||
|
||||
if (BYTES_LEFT (buffer) < 2)
|
||||
return XSETTINGS_ACCESS;
|
||||
|
||||
x = *(CARD16 *)buffer->pos;
|
||||
buffer->pos += 2;
|
||||
|
||||
if (buffer->byte_order == local_byte_order)
|
||||
*result = x;
|
||||
else
|
||||
*result = (x << 8) | (x >> 8);
|
||||
|
||||
return XSETTINGS_SUCCESS;
|
||||
}
|
||||
|
||||
static XSettingsResult
|
||||
fetch_ushort (XSettingsBuffer *buffer,
|
||||
unsigned short *result)
|
||||
{
|
||||
CARD16 x;
|
||||
XSettingsResult r;
|
||||
|
||||
r = fetch_card16 (buffer, &x);
|
||||
if (r == XSETTINGS_SUCCESS)
|
||||
*result = x;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static XSettingsResult
|
||||
fetch_card32 (XSettingsBuffer *buffer,
|
||||
CARD32 *result)
|
||||
{
|
||||
CARD32 x;
|
||||
|
||||
if (BYTES_LEFT (buffer) < 4)
|
||||
return XSETTINGS_ACCESS;
|
||||
|
||||
x = *(CARD32 *)buffer->pos;
|
||||
buffer->pos += 4;
|
||||
|
||||
if (buffer->byte_order == local_byte_order)
|
||||
*result = x;
|
||||
else
|
||||
*result = (x << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | (x >> 24);
|
||||
|
||||
return XSETTINGS_SUCCESS;
|
||||
}
|
||||
|
||||
static XSettingsResult
|
||||
fetch_card8 (XSettingsBuffer *buffer,
|
||||
CARD8 *result)
|
||||
{
|
||||
if (BYTES_LEFT (buffer) < 1)
|
||||
return XSETTINGS_ACCESS;
|
||||
|
||||
*result = *(CARD8 *)buffer->pos;
|
||||
buffer->pos += 1;
|
||||
|
||||
return XSETTINGS_SUCCESS;
|
||||
}
|
||||
|
||||
#define XSETTINGS_PAD(n,m) ((n + m - 1) & (~(m-1)))
|
||||
|
||||
static XSettingsList *
|
||||
parse_settings (unsigned char *data,
|
||||
size_t len)
|
||||
{
|
||||
XSettingsBuffer buffer;
|
||||
XSettingsResult result = XSETTINGS_SUCCESS;
|
||||
XSettingsList *settings = NULL;
|
||||
CARD32 serial;
|
||||
CARD32 n_entries;
|
||||
CARD32 i;
|
||||
XSettingsSetting *setting = NULL;
|
||||
char buffer_byte_order = '\0';
|
||||
|
||||
local_byte_order = xsettings_byte_order ();
|
||||
|
||||
buffer.pos = buffer.data = data;
|
||||
buffer.len = len;
|
||||
buffer.byte_order = '\0';
|
||||
|
||||
result = fetch_card8 (&buffer, (unsigned char *) &buffer_byte_order);
|
||||
if (buffer_byte_order != MSBFirst &&
|
||||
buffer_byte_order != LSBFirst)
|
||||
{
|
||||
fprintf (stderr, "Invalid byte order in XSETTINGS property\n");
|
||||
result = XSETTINGS_FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
buffer.byte_order = buffer_byte_order;
|
||||
buffer.pos += 3;
|
||||
|
||||
result = fetch_card32 (&buffer, &serial);
|
||||
if (result != XSETTINGS_SUCCESS)
|
||||
goto out;
|
||||
|
||||
result = fetch_card32 (&buffer, &n_entries);
|
||||
if (result != XSETTINGS_SUCCESS)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < n_entries; i++)
|
||||
{
|
||||
CARD8 type;
|
||||
CARD16 name_len;
|
||||
CARD32 v_int;
|
||||
size_t pad_len;
|
||||
|
||||
result = fetch_card8 (&buffer, &type);
|
||||
if (result != XSETTINGS_SUCCESS)
|
||||
goto out;
|
||||
|
||||
buffer.pos += 1;
|
||||
|
||||
result = fetch_card16 (&buffer, &name_len);
|
||||
if (result != XSETTINGS_SUCCESS)
|
||||
goto out;
|
||||
|
||||
pad_len = XSETTINGS_PAD(name_len, 4);
|
||||
if (BYTES_LEFT (&buffer) < pad_len)
|
||||
{
|
||||
result = XSETTINGS_ACCESS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
setting = malloc (sizeof *setting);
|
||||
if (!setting)
|
||||
{
|
||||
result = XSETTINGS_NO_MEM;
|
||||
goto out;
|
||||
}
|
||||
setting->type = XSETTINGS_TYPE_INT; /* No allocated memory */
|
||||
|
||||
setting->name = malloc (name_len + 1);
|
||||
if (!setting->name)
|
||||
{
|
||||
result = XSETTINGS_NO_MEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy (setting->name, buffer.pos, name_len);
|
||||
setting->name[name_len] = '\0';
|
||||
buffer.pos += pad_len;
|
||||
|
||||
result = fetch_card32 (&buffer, &v_int);
|
||||
if (result != XSETTINGS_SUCCESS)
|
||||
goto out;
|
||||
setting->last_change_serial = v_int;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case XSETTINGS_TYPE_INT:
|
||||
result = fetch_card32 (&buffer, &v_int);
|
||||
if (result != XSETTINGS_SUCCESS)
|
||||
goto out;
|
||||
|
||||
setting->data.v_int = (INT32)v_int;
|
||||
break;
|
||||
case XSETTINGS_TYPE_STRING:
|
||||
result = fetch_card32 (&buffer, &v_int);
|
||||
if (result != XSETTINGS_SUCCESS)
|
||||
goto out;
|
||||
|
||||
pad_len = XSETTINGS_PAD (v_int, 4);
|
||||
if (v_int + 1 == 0 || /* Guard against wrap-around */
|
||||
BYTES_LEFT (&buffer) < pad_len)
|
||||
{
|
||||
result = XSETTINGS_ACCESS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
setting->data.v_string = malloc (v_int + 1);
|
||||
if (!setting->data.v_string)
|
||||
{
|
||||
result = XSETTINGS_NO_MEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy (setting->data.v_string, buffer.pos, v_int);
|
||||
setting->data.v_string[v_int] = '\0';
|
||||
buffer.pos += pad_len;
|
||||
|
||||
break;
|
||||
case XSETTINGS_TYPE_COLOR:
|
||||
result = fetch_ushort (&buffer, &setting->data.v_color.red);
|
||||
if (result != XSETTINGS_SUCCESS)
|
||||
goto out;
|
||||
result = fetch_ushort (&buffer, &setting->data.v_color.green);
|
||||
if (result != XSETTINGS_SUCCESS)
|
||||
goto out;
|
||||
result = fetch_ushort (&buffer, &setting->data.v_color.blue);
|
||||
if (result != XSETTINGS_SUCCESS)
|
||||
goto out;
|
||||
result = fetch_ushort (&buffer, &setting->data.v_color.alpha);
|
||||
if (result != XSETTINGS_SUCCESS)
|
||||
goto out;
|
||||
|
||||
break;
|
||||
default:
|
||||
/* Quietly ignore unknown types */
|
||||
break;
|
||||
}
|
||||
|
||||
setting->type = type;
|
||||
|
||||
result = xsettings_list_insert (&settings, setting);
|
||||
if (result != XSETTINGS_SUCCESS)
|
||||
goto out;
|
||||
|
||||
setting = NULL;
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
if (result != XSETTINGS_SUCCESS)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case XSETTINGS_NO_MEM:
|
||||
fprintf(stderr, "Out of memory reading XSETTINGS property\n");
|
||||
break;
|
||||
case XSETTINGS_ACCESS:
|
||||
fprintf(stderr, "Invalid XSETTINGS property (read off end)\n");
|
||||
break;
|
||||
case XSETTINGS_DUPLICATE_ENTRY:
|
||||
fprintf (stderr, "Duplicate XSETTINGS entry for '%s'\n", setting->name);
|
||||
SDL_FALLTHROUGH;
|
||||
case XSETTINGS_FAILED:
|
||||
SDL_FALLTHROUGH;
|
||||
case XSETTINGS_SUCCESS:
|
||||
SDL_FALLTHROUGH;
|
||||
case XSETTINGS_NO_ENTRY:
|
||||
break;
|
||||
}
|
||||
|
||||
if (setting)
|
||||
xsettings_setting_free (setting);
|
||||
|
||||
xsettings_list_free (settings);
|
||||
settings = NULL;
|
||||
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
static void
|
||||
read_settings (XSettingsClient *client)
|
||||
{
|
||||
Atom type;
|
||||
int format;
|
||||
unsigned long n_items;
|
||||
unsigned long bytes_after;
|
||||
unsigned char *data;
|
||||
int result;
|
||||
|
||||
int (*old_handler) (Display *, XErrorEvent *);
|
||||
|
||||
XSettingsList *old_list = client->settings;
|
||||
|
||||
client->settings = NULL;
|
||||
|
||||
if (client->manager_window)
|
||||
{
|
||||
old_handler = X11_XSetErrorHandler (ignore_errors);
|
||||
result = X11_XGetWindowProperty (client->display, client->manager_window,
|
||||
client->xsettings_atom, 0, LONG_MAX,
|
||||
False, client->xsettings_atom,
|
||||
&type, &format, &n_items, &bytes_after, &data);
|
||||
X11_XSetErrorHandler (old_handler);
|
||||
|
||||
if (result == Success && type != None)
|
||||
{
|
||||
if (type != client->xsettings_atom)
|
||||
{
|
||||
fprintf (stderr, "Invalid type for XSETTINGS property");
|
||||
}
|
||||
else if (format != 8)
|
||||
{
|
||||
fprintf (stderr, "Invalid format for XSETTINGS property %d", format);
|
||||
}
|
||||
else
|
||||
client->settings = parse_settings (data, n_items);
|
||||
|
||||
X11_XFree (data);
|
||||
}
|
||||
}
|
||||
|
||||
notify_changes (client, old_list);
|
||||
xsettings_list_free (old_list);
|
||||
}
|
||||
|
||||
static void
|
||||
add_events (Display *display,
|
||||
Window window,
|
||||
long mask)
|
||||
{
|
||||
XWindowAttributes attr;
|
||||
|
||||
X11_XGetWindowAttributes (display, window, &attr);
|
||||
X11_XSelectInput (display, window, attr.your_event_mask | mask);
|
||||
}
|
||||
|
||||
static void
|
||||
check_manager_window (XSettingsClient *client)
|
||||
{
|
||||
if (client->manager_window && client->watch)
|
||||
client->watch (client->manager_window, False, 0, client->cb_data);
|
||||
|
||||
if (client->grab)
|
||||
client->grab (client->display);
|
||||
else
|
||||
X11_XGrabServer (client->display);
|
||||
|
||||
client->manager_window = X11_XGetSelectionOwner (client->display,
|
||||
client->selection_atom);
|
||||
if (client->manager_window)
|
||||
X11_XSelectInput (client->display, client->manager_window,
|
||||
PropertyChangeMask | StructureNotifyMask);
|
||||
|
||||
if (client->ungrab)
|
||||
client->ungrab (client->display);
|
||||
else
|
||||
X11_XUngrabServer (client->display);
|
||||
|
||||
X11_XFlush (client->display);
|
||||
|
||||
if (client->manager_window && client->watch)
|
||||
{
|
||||
if (!client->watch (client->manager_window, True,
|
||||
PropertyChangeMask | StructureNotifyMask,
|
||||
client->cb_data))
|
||||
{
|
||||
/* Inability to watch the window probably means that it was destroyed
|
||||
* after we ungrabbed
|
||||
*/
|
||||
client->manager_window = None;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
read_settings (client);
|
||||
}
|
||||
|
||||
XSettingsClient *
|
||||
xsettings_client_new (Display *display,
|
||||
int screen,
|
||||
XSettingsNotifyFunc notify,
|
||||
XSettingsWatchFunc watch,
|
||||
void *cb_data)
|
||||
{
|
||||
return xsettings_client_new_with_grab_funcs (display, screen, notify, watch, cb_data,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
XSettingsClient *
|
||||
xsettings_client_new_with_grab_funcs (Display *display,
|
||||
int screen,
|
||||
XSettingsNotifyFunc notify,
|
||||
XSettingsWatchFunc watch,
|
||||
void *cb_data,
|
||||
XSettingsGrabFunc grab,
|
||||
XSettingsGrabFunc ungrab)
|
||||
{
|
||||
XSettingsClient *client;
|
||||
char buffer[256];
|
||||
char *atom_names[3];
|
||||
Atom atoms[3];
|
||||
|
||||
client = malloc (sizeof *client);
|
||||
if (!client)
|
||||
return NULL;
|
||||
|
||||
client->display = display;
|
||||
client->screen = screen;
|
||||
client->notify = notify;
|
||||
client->watch = watch;
|
||||
client->cb_data = cb_data;
|
||||
client->grab = grab;
|
||||
client->ungrab = ungrab;
|
||||
|
||||
client->manager_window = None;
|
||||
client->settings = NULL;
|
||||
|
||||
sprintf(buffer, "_XSETTINGS_S%d", screen);
|
||||
atom_names[0] = buffer;
|
||||
atom_names[1] = "_XSETTINGS_SETTINGS";
|
||||
atom_names[2] = "MANAGER";
|
||||
|
||||
#ifdef HAVE_XINTERNATOMS
|
||||
XInternAtoms (display, atom_names, 3, False, atoms);
|
||||
#else
|
||||
atoms[0] = X11_XInternAtom (display, atom_names[0], False);
|
||||
atoms[1] = X11_XInternAtom (display, atom_names[1], False);
|
||||
atoms[2] = X11_XInternAtom (display, atom_names[2], False);
|
||||
#endif
|
||||
|
||||
client->selection_atom = atoms[0];
|
||||
client->xsettings_atom = atoms[1];
|
||||
client->manager_atom = atoms[2];
|
||||
|
||||
/* Select on StructureNotify so we get MANAGER events
|
||||
*/
|
||||
add_events (display, RootWindow (display, screen), StructureNotifyMask);
|
||||
|
||||
if (client->watch)
|
||||
client->watch (RootWindow (display, screen), True, StructureNotifyMask,
|
||||
client->cb_data);
|
||||
|
||||
check_manager_window (client);
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
xsettings_client_set_grab_func (XSettingsClient *client,
|
||||
XSettingsGrabFunc grab)
|
||||
{
|
||||
client->grab = grab;
|
||||
}
|
||||
|
||||
void
|
||||
xsettings_client_set_ungrab_func (XSettingsClient *client,
|
||||
XSettingsGrabFunc ungrab)
|
||||
{
|
||||
client->ungrab = ungrab;
|
||||
}
|
||||
|
||||
void
|
||||
xsettings_client_destroy (XSettingsClient *client)
|
||||
{
|
||||
if (client->watch)
|
||||
client->watch (RootWindow (client->display, client->screen),
|
||||
False, 0, client->cb_data);
|
||||
if (client->manager_window && client->watch)
|
||||
client->watch (client->manager_window, False, 0, client->cb_data);
|
||||
|
||||
xsettings_list_free (client->settings);
|
||||
free (client);
|
||||
}
|
||||
|
||||
XSettingsResult
|
||||
xsettings_client_get_setting (XSettingsClient *client,
|
||||
const char *name,
|
||||
XSettingsSetting **setting)
|
||||
{
|
||||
XSettingsSetting *search = xsettings_list_lookup (client->settings, name);
|
||||
if (search)
|
||||
{
|
||||
*setting = xsettings_setting_copy (search);
|
||||
return *setting ? XSETTINGS_SUCCESS : XSETTINGS_NO_MEM;
|
||||
}
|
||||
else
|
||||
return XSETTINGS_NO_ENTRY;
|
||||
}
|
||||
|
||||
Bool
|
||||
xsettings_client_process_event (XSettingsClient *client,
|
||||
const XEvent *xev)
|
||||
{
|
||||
/* The checks here will not unlikely cause us to reread
|
||||
* the properties from the manager window a number of
|
||||
* times when the manager changes from A->B. But manager changes
|
||||
* are going to be pretty rare.
|
||||
*/
|
||||
if (xev->xany.window == RootWindow (client->display, client->screen))
|
||||
{
|
||||
if (xev->xany.type == ClientMessage &&
|
||||
xev->xclient.message_type == client->manager_atom &&
|
||||
xev->xclient.data.l[1] == client->selection_atom)
|
||||
{
|
||||
check_manager_window (client);
|
||||
return True;
|
||||
}
|
||||
}
|
||||
else if (xev->xany.window == client->manager_window)
|
||||
{
|
||||
if (xev->xany.type == DestroyNotify)
|
||||
{
|
||||
check_manager_window (client);
|
||||
return False;
|
||||
}
|
||||
else if (xev->xany.type == PropertyNotify)
|
||||
{
|
||||
read_settings (client);
|
||||
return True;
|
||||
}
|
||||
}
|
||||
|
||||
return False;
|
||||
}
|
||||
|
||||
XSettingsSetting *
|
||||
xsettings_setting_copy (XSettingsSetting *setting)
|
||||
{
|
||||
XSettingsSetting *result;
|
||||
size_t str_len;
|
||||
|
||||
result = malloc (sizeof *result);
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
||||
str_len = strlen (setting->name);
|
||||
result->name = malloc (str_len + 1);
|
||||
if (!result->name)
|
||||
goto err;
|
||||
|
||||
memcpy (result->name, setting->name, str_len + 1);
|
||||
|
||||
result->type = setting->type;
|
||||
|
||||
switch (setting->type)
|
||||
{
|
||||
case XSETTINGS_TYPE_INT:
|
||||
result->data.v_int = setting->data.v_int;
|
||||
break;
|
||||
case XSETTINGS_TYPE_COLOR:
|
||||
result->data.v_color = setting->data.v_color;
|
||||
break;
|
||||
case XSETTINGS_TYPE_STRING:
|
||||
str_len = strlen (setting->data.v_string);
|
||||
result->data.v_string = malloc (str_len + 1);
|
||||
if (!result->data.v_string)
|
||||
goto err;
|
||||
|
||||
memcpy (result->data.v_string, setting->data.v_string, str_len + 1);
|
||||
break;
|
||||
}
|
||||
|
||||
result->last_change_serial = setting->last_change_serial;
|
||||
|
||||
return result;
|
||||
|
||||
err:
|
||||
if (result->name)
|
||||
free (result->name);
|
||||
free (result);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
XSettingsList *
|
||||
xsettings_list_copy (XSettingsList *list)
|
||||
{
|
||||
XSettingsList *new = NULL;
|
||||
XSettingsList *old_iter = list;
|
||||
XSettingsList *new_iter = NULL;
|
||||
|
||||
while (old_iter)
|
||||
{
|
||||
XSettingsList *new_node;
|
||||
|
||||
new_node = malloc (sizeof *new_node);
|
||||
if (!new_node)
|
||||
goto error;
|
||||
|
||||
new_node->setting = xsettings_setting_copy (old_iter->setting);
|
||||
if (!new_node->setting)
|
||||
{
|
||||
free (new_node);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (new_iter)
|
||||
new_iter->next = new_node;
|
||||
else
|
||||
{
|
||||
new = new_node;
|
||||
new->next = NULL;
|
||||
}
|
||||
|
||||
|
||||
new_iter = new_node;
|
||||
|
||||
old_iter = old_iter->next;
|
||||
}
|
||||
|
||||
return new;
|
||||
|
||||
error:
|
||||
xsettings_list_free (new);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
xsettings_setting_equal (XSettingsSetting *setting_a,
|
||||
XSettingsSetting *setting_b)
|
||||
{
|
||||
if (setting_a->type != setting_b->type)
|
||||
return 0;
|
||||
|
||||
if (strcmp (setting_a->name, setting_b->name) != 0)
|
||||
return 0;
|
||||
|
||||
switch (setting_a->type)
|
||||
{
|
||||
case XSETTINGS_TYPE_INT:
|
||||
return setting_a->data.v_int == setting_b->data.v_int;
|
||||
case XSETTINGS_TYPE_COLOR:
|
||||
return (setting_a->data.v_color.red == setting_b->data.v_color.red &&
|
||||
setting_a->data.v_color.green == setting_b->data.v_color.green &&
|
||||
setting_a->data.v_color.blue == setting_b->data.v_color.blue &&
|
||||
setting_a->data.v_color.alpha == setting_b->data.v_color.alpha);
|
||||
case XSETTINGS_TYPE_STRING:
|
||||
return strcmp (setting_a->data.v_string, setting_b->data.v_string) == 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
xsettings_setting_free (XSettingsSetting *setting)
|
||||
{
|
||||
if (setting->type == XSETTINGS_TYPE_STRING)
|
||||
free (setting->data.v_string);
|
||||
|
||||
if (setting->name)
|
||||
free (setting->name);
|
||||
|
||||
free (setting);
|
||||
}
|
||||
|
||||
void
|
||||
xsettings_list_free (XSettingsList *list)
|
||||
{
|
||||
while (list)
|
||||
{
|
||||
XSettingsList *next = list->next;
|
||||
|
||||
xsettings_setting_free (list->setting);
|
||||
free (list);
|
||||
|
||||
list = next;
|
||||
}
|
||||
}
|
||||
|
||||
XSettingsResult
|
||||
xsettings_list_insert (XSettingsList **list,
|
||||
XSettingsSetting *setting)
|
||||
{
|
||||
XSettingsList *node;
|
||||
XSettingsList *iter;
|
||||
XSettingsList *last = NULL;
|
||||
|
||||
node = malloc (sizeof *node);
|
||||
if (!node)
|
||||
return XSETTINGS_NO_MEM;
|
||||
node->setting = setting;
|
||||
|
||||
iter = *list;
|
||||
while (iter)
|
||||
{
|
||||
int cmp = strcmp (setting->name, iter->setting->name);
|
||||
|
||||
if (cmp < 0)
|
||||
break;
|
||||
else if (cmp == 0)
|
||||
{
|
||||
free (node);
|
||||
return XSETTINGS_DUPLICATE_ENTRY;
|
||||
}
|
||||
|
||||
last = iter;
|
||||
iter = iter->next;
|
||||
}
|
||||
|
||||
if (last)
|
||||
last->next = node;
|
||||
else
|
||||
*list = node;
|
||||
|
||||
node->next = iter;
|
||||
|
||||
return XSETTINGS_SUCCESS;
|
||||
}
|
||||
|
||||
XSettingsResult
|
||||
xsettings_list_delete (XSettingsList **list,
|
||||
const char *name)
|
||||
{
|
||||
XSettingsList *iter;
|
||||
XSettingsList *last = NULL;
|
||||
|
||||
iter = *list;
|
||||
while (iter)
|
||||
{
|
||||
if (strcmp (name, iter->setting->name) == 0)
|
||||
{
|
||||
if (last)
|
||||
last->next = iter->next;
|
||||
else
|
||||
*list = iter->next;
|
||||
|
||||
xsettings_setting_free (iter->setting);
|
||||
free (iter);
|
||||
|
||||
return XSETTINGS_SUCCESS;
|
||||
}
|
||||
|
||||
last = iter;
|
||||
iter = iter->next;
|
||||
}
|
||||
|
||||
return XSETTINGS_FAILED;
|
||||
}
|
||||
|
||||
XSettingsSetting *
|
||||
xsettings_list_lookup (XSettingsList *list,
|
||||
const char *name)
|
||||
{
|
||||
XSettingsList *iter;
|
||||
|
||||
iter = list;
|
||||
while (iter)
|
||||
{
|
||||
if (strcmp (name, iter->setting->name) == 0)
|
||||
return iter->setting;
|
||||
|
||||
iter = iter->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char
|
||||
xsettings_byte_order (void)
|
||||
{
|
||||
CARD32 myint = 0x01020304;
|
||||
return (*(char *)&myint == 1) ? MSBFirst : LSBFirst;
|
||||
}
|
||||
|
||||
#endif /* SDL_VIDEO_DRIVER_X11 */
|
||||
153
vendor/sdl-3.2.10/src/video/x11/xsettings-client.h
vendored
Normal file
153
vendor/sdl-3.2.10/src/video/x11/xsettings-client.h
vendored
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Copyright © 2001, 2007 Red Hat, Inc.
|
||||
* Copyright 2024 Igalia S.L.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that
|
||||
* copyright notice and this permission notice appear in supporting
|
||||
* documentation, and that the name of Red Hat not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. Red Hat makes no representations about the
|
||||
* suitability of this software for any purpose. It is provided "as is"
|
||||
* without express or implied warranty.
|
||||
*
|
||||
* RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
|
||||
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Owen Taylor, Red Hat, Inc.
|
||||
*/
|
||||
#ifndef XSETTINGS_CLIENT_H
|
||||
#define XSETTINGS_CLIENT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
typedef struct _XSettingsBuffer XSettingsBuffer;
|
||||
typedef struct _XSettingsColor XSettingsColor;
|
||||
typedef struct _XSettingsList XSettingsList;
|
||||
typedef struct _XSettingsSetting XSettingsSetting;
|
||||
|
||||
/* Types of settings possible. Enum values correspond to
|
||||
* protocol values.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
XSETTINGS_TYPE_INT = 0,
|
||||
XSETTINGS_TYPE_STRING = 1,
|
||||
XSETTINGS_TYPE_COLOR = 2
|
||||
} XSettingsType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
XSETTINGS_SUCCESS,
|
||||
XSETTINGS_NO_MEM,
|
||||
XSETTINGS_ACCESS,
|
||||
XSETTINGS_FAILED,
|
||||
XSETTINGS_NO_ENTRY,
|
||||
XSETTINGS_DUPLICATE_ENTRY
|
||||
} XSettingsResult;
|
||||
|
||||
struct _XSettingsBuffer
|
||||
{
|
||||
char byte_order;
|
||||
size_t len;
|
||||
unsigned char *data;
|
||||
unsigned char *pos;
|
||||
};
|
||||
|
||||
struct _XSettingsColor
|
||||
{
|
||||
unsigned short red, green, blue, alpha;
|
||||
};
|
||||
|
||||
struct _XSettingsList
|
||||
{
|
||||
XSettingsSetting *setting;
|
||||
XSettingsList *next;
|
||||
};
|
||||
|
||||
struct _XSettingsSetting
|
||||
{
|
||||
char *name;
|
||||
XSettingsType type;
|
||||
|
||||
union {
|
||||
int v_int;
|
||||
char *v_string;
|
||||
XSettingsColor v_color;
|
||||
} data;
|
||||
|
||||
unsigned long last_change_serial;
|
||||
};
|
||||
|
||||
XSettingsSetting *xsettings_setting_copy (XSettingsSetting *setting);
|
||||
void xsettings_setting_free (XSettingsSetting *setting);
|
||||
int xsettings_setting_equal (XSettingsSetting *setting_a,
|
||||
XSettingsSetting *setting_b);
|
||||
|
||||
void xsettings_list_free (XSettingsList *list);
|
||||
XSettingsList *xsettings_list_copy (XSettingsList *list);
|
||||
XSettingsResult xsettings_list_insert (XSettingsList **list,
|
||||
XSettingsSetting *setting);
|
||||
XSettingsSetting *xsettings_list_lookup (XSettingsList *list,
|
||||
const char *name);
|
||||
XSettingsResult xsettings_list_delete (XSettingsList **list,
|
||||
const char *name);
|
||||
|
||||
char xsettings_byte_order (void);
|
||||
|
||||
#define XSETTINGS_PAD(n,m) ((n + m - 1) & (~(m-1)))
|
||||
|
||||
typedef struct _XSettingsClient XSettingsClient;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
XSETTINGS_ACTION_NEW,
|
||||
XSETTINGS_ACTION_CHANGED,
|
||||
XSETTINGS_ACTION_DELETED
|
||||
} XSettingsAction;
|
||||
|
||||
typedef void (*XSettingsNotifyFunc) (const char *name,
|
||||
XSettingsAction action,
|
||||
XSettingsSetting *setting,
|
||||
void *cb_data);
|
||||
typedef Bool (*XSettingsWatchFunc) (Window window,
|
||||
Bool is_start,
|
||||
long mask,
|
||||
void *cb_data);
|
||||
typedef void (*XSettingsGrabFunc) (Display *display);
|
||||
|
||||
XSettingsClient *xsettings_client_new (Display *display,
|
||||
int screen,
|
||||
XSettingsNotifyFunc notify,
|
||||
XSettingsWatchFunc watch,
|
||||
void *cb_data);
|
||||
XSettingsClient *xsettings_client_new_with_grab_funcs (Display *display,
|
||||
int screen,
|
||||
XSettingsNotifyFunc notify,
|
||||
XSettingsWatchFunc watch,
|
||||
void *cb_data,
|
||||
XSettingsGrabFunc grab,
|
||||
XSettingsGrabFunc ungrab);
|
||||
void xsettings_client_set_grab_func (XSettingsClient *client,
|
||||
XSettingsGrabFunc grab);
|
||||
void xsettings_client_set_ungrab_func (XSettingsClient *client,
|
||||
XSettingsGrabFunc ungrab);
|
||||
void xsettings_client_destroy (XSettingsClient *client);
|
||||
Bool xsettings_client_process_event (XSettingsClient *client,
|
||||
const XEvent *xev);
|
||||
XSettingsResult xsettings_client_get_setting (XSettingsClient *client,
|
||||
const char *name,
|
||||
XSettingsSetting **setting);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* XSETTINGS_CLIENT_H */
|
||||
Loading…
Add table
Add a link
Reference in a new issue