update sdl to release 2.0.22

This commit is contained in:
AzaezelX 2022-04-26 09:17:21 -05:00
parent 3f796d2a06
commit d4307ea413
135 changed files with 5746 additions and 1161 deletions

View file

@ -412,6 +412,12 @@ SDL_LoadBMP_RW(SDL_RWops * src, int freesrc)
goto done;
}
if (biBitCount >= 32) { /* we shift biClrUsed by this value later. */
SDL_SetError("Unsupported or incorrect biBitCount field");
was_error = SDL_TRUE;
goto done;
}
if (biClrUsed == 0) {
biClrUsed = 1 << biBitCount;
}

View file

@ -27,7 +27,6 @@
#endif
#if SDL_VIDEO_DRIVER_ANDROID
#include <android/native_window.h>
#include "../core/android/SDL_android.h"
#include "../video/android/SDL_androidvideo.h"
#endif
#if SDL_VIDEO_DRIVER_RPI
@ -99,7 +98,7 @@
#define DEFAULT_OGL_ES "libGLESv1_CM.so.1"
#endif /* SDL_VIDEO_DRIVER_RPI */
#if SDL_VIDEO_OPENGL
#if SDL_VIDEO_OPENGL && !SDL_VIDEO_VITA_PVR_OGL
#include "SDL_opengl.h"
#endif
@ -530,7 +529,7 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa
}
#endif
/* Try the implementation-specific eglGetDisplay even if eglGetPlatformDisplay fails */
if (_this->egl_data->egl_display == EGL_NO_DISPLAY) {
if ((_this->egl_data->egl_display == EGL_NO_DISPLAY) && (_this->egl_data->eglGetDisplay != NULL)) {
_this->egl_data->egl_display = _this->egl_data->eglGetDisplay(native_display);
}
if (_this->egl_data->egl_display == EGL_NO_DISPLAY) {
@ -1062,7 +1061,7 @@ SDL_EGL_CreateContext(_THIS, EGLSurface egl_surface)
if (SDL_GL_ExtensionSupported("GL_OES_surfaceless_context")) {
_this->gl_allow_no_surface = SDL_TRUE;
}
#if SDL_VIDEO_OPENGL
#if SDL_VIDEO_OPENGL && !defined(SDL_VIDEO_DRIVER_VITA)
} else {
/* Desktop OpenGL supports it by default from version 3.0 on. */
void (APIENTRY * glGetIntegervFunc) (GLenum pname, GLint * params);

View file

@ -28,6 +28,7 @@
#include "SDL_blit.h"
#include "SDL_pixels_c.h"
#include "SDL_RLEaccel_c.h"
#include "../SDL_list.h"
/* Lookup tables to expand partial bytes to the full 0..255 range */
@ -1024,12 +1025,6 @@ SDL_AllocBlitMap(void)
}
typedef struct SDL_ListNode
{
void *entry;
struct SDL_ListNode *next;
} SDL_ListNode;
void
SDL_InvalidateAllBlitMap(SDL_Surface *surface)
{
@ -1045,40 +1040,6 @@ SDL_InvalidateAllBlitMap(SDL_Surface *surface)
}
}
static void SDL_ListAdd(SDL_ListNode **head, void *ent);
static void SDL_ListRemove(SDL_ListNode **head, void *ent);
void
SDL_ListAdd(SDL_ListNode **head, void *ent)
{
SDL_ListNode *node = SDL_malloc(sizeof (*node));
if (node == NULL) {
SDL_OutOfMemory();
return;
}
node->entry = ent;
node->next = *head;
*head = node;
}
void
SDL_ListRemove(SDL_ListNode **head, void *ent)
{
SDL_ListNode **ptr = head;
while (*ptr) {
if ((*ptr)->entry == ent) {
SDL_ListNode *tmp = *ptr;
*ptr = (*ptr)->next;
SDL_free(tmp);
return;
}
ptr = &(*ptr)->next;
}
}
void
SDL_InvalidateMap(SDL_BlitMap * map)
{

View file

@ -345,6 +345,7 @@ struct SDL_VideoDevice
Uint32 next_object_id;
char *clipboard_text;
SDL_bool setting_display_mode;
SDL_bool disable_display_mode_switching;
/* * * */
/* Data used by the GL drivers */

View file

@ -61,12 +61,12 @@ static VideoBootStrap *bootstrap[] = {
#if SDL_VIDEO_DRIVER_COCOA
&COCOA_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_WAYLAND
&Wayland_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_X11
&X11_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_WAYLAND
&Wayland_bootstrap,
#endif
#if SDL_VIDEO_DRIVER_VIVANTE
&VIVANTE_bootstrap,
#endif
@ -261,6 +261,7 @@ SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window * window, Uint32 * fo
SDL_TEXTUREACCESS_STREAMING,
window->w, window->h);
if (!data->texture) {
/* codechecker_false_positive [Malloc] Static analyzer doesn't realize allocated `data` is saved to SDL_WINDOWTEXTUREDATA and not leaked here. */
return -1;
}
@ -424,7 +425,7 @@ SDL_VideoInit(const char *driver_name)
i = index = 0;
video = NULL;
if (driver_name == NULL) {
driver_name = SDL_getenv("SDL_VIDEODRIVER");
driver_name = SDL_GetHint(SDL_HINT_VIDEODRIVER);
}
if (driver_name != NULL && *driver_name != 0) {
const char *driver_attempt = driver_name;
@ -1184,6 +1185,7 @@ SDL_GetWindowDisplayMode(SDL_Window * window, SDL_DisplayMode * mode)
} else if (!SDL_GetClosestDisplayModeForDisplay(SDL_GetDisplayForWindow(window),
&fullscreen_mode,
&fullscreen_mode)) {
SDL_zerop(mode);
return SDL_SetError("Couldn't find display mode match");
}
@ -1337,14 +1339,17 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen)
resized = SDL_FALSE;
}
/* only do the mode change if we want exclusive fullscreen */
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) {
return -1;
}
} else {
if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) {
return -1;
/* Don't try to change the display mode if the driver doesn't want it. */
if (_this->disable_display_mode_switching == SDL_FALSE) {
/* only do the mode change if we want exclusive fullscreen */
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
if (SDL_SetDisplayModeForDisplay(display, &fullscreen_mode) < 0) {
return -1;
}
} else {
if (SDL_SetDisplayModeForDisplay(display, NULL) < 0) {
return -1;
}
}
}
@ -3055,7 +3060,8 @@ ShouldMinimizeOnFocusLoss(SDL_Window * window)
/* Real fullscreen windows should minimize on focus loss so the desktop video mode is restored */
hint = SDL_GetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS);
if (!hint || !*hint || SDL_strcasecmp(hint, "auto") == 0) {
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP ||
_this->disable_display_mode_switching == SDL_TRUE) {
return SDL_FALSE;
} else {
return SDL_TRUE;
@ -3919,6 +3925,10 @@ SDL_GL_MakeCurrent(SDL_Window * window, SDL_GLContext ctx)
{
int retval;
if (!_this) {
return SDL_UninitializedVideo();
}
if (window == SDL_GL_GetCurrentWindow() &&
ctx == SDL_GL_GetCurrentContext()) {
/* We're already current. */
@ -4262,12 +4272,12 @@ SDL_IsScreenKeyboardShown(SDL_Window *window)
#if SDL_VIDEO_DRIVER_UIKIT
#include "uikit/SDL_uikitmessagebox.h"
#endif
#if SDL_VIDEO_DRIVER_WAYLAND
#include "wayland/SDL_waylandmessagebox.h"
#endif
#if SDL_VIDEO_DRIVER_X11
#include "x11/SDL_x11messagebox.h"
#endif
#if SDL_VIDEO_DRIVER_WAYLAND
#include "wayland/SDL_waylandmessagebox.h"
#endif
#if SDL_VIDEO_DRIVER_HAIKU
#include "haiku/SDL_bmessagebox.h"
#endif
@ -4375,13 +4385,6 @@ SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
retval = 0;
}
#endif
#if SDL_VIDEO_DRIVER_WAYLAND
if (retval == -1 &&
SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WAYLAND) &&
Wayland_ShowMessageBox(messageboxdata, buttonid) == 0) {
retval = 0;
}
#endif
#if SDL_VIDEO_DRIVER_X11
if (retval == -1 &&
SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_X11) &&
@ -4389,6 +4392,13 @@ SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
retval = 0;
}
#endif
#if SDL_VIDEO_DRIVER_WAYLAND
if (retval == -1 &&
SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_WAYLAND) &&
Wayland_ShowMessageBox(messageboxdata, buttonid) == 0) {
retval = 0;
}
#endif
#if SDL_VIDEO_DRIVER_HAIKU
if (retval == -1 &&
SDL_MessageboxValidForDriver(messageboxdata, SDL_SYSWM_HAIKU) &&

View file

@ -122,6 +122,7 @@ Android_CreateDevice(int devindex)
device->SetWindowTitle = Android_SetWindowTitle;
device->SetWindowFullscreen = Android_SetWindowFullscreen;
device->MinimizeWindow = Android_MinimizeWindow;
device->SetWindowResizable = Android_SetWindowResizable;
device->DestroyWindow = Android_DestroyWindow;
device->GetWindowWMInfo = Android_GetWindowWMInfo;

View file

@ -167,6 +167,12 @@ Android_MinimizeWindow(_THIS, SDL_Window *window)
Android_JNI_MinizeWindow();
}
void Android_SetWindowResizable(_THIS, SDL_Window *window, SDL_bool resizable)
{
/* Set orientation */
Android_JNI_SetOrientation(window->w, window->h, window->flags & SDL_WINDOW_RESIZABLE, SDL_GetHint(SDL_HINT_ORIENTATIONS));
}
void
Android_DestroyWindow(_THIS, SDL_Window *window)
{

View file

@ -30,6 +30,7 @@ extern int Android_CreateWindow(_THIS, SDL_Window *window);
extern void Android_SetWindowTitle(_THIS, SDL_Window *window);
extern void Android_SetWindowFullscreen(_THIS, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen);
extern void Android_MinimizeWindow(_THIS, SDL_Window *window);
extern void Android_SetWindowResizable(_THIS, SDL_Window *window, SDL_bool resizable);
extern void Android_DestroyWindow(_THIS, SDL_Window *window);
extern SDL_bool Android_GetWindowWMInfo(_THIS, SDL_Window *window, struct SDL_SysWMinfo *info);

View file

@ -46,6 +46,7 @@
#include "SDL_nullvideo.h"
#include "SDL_nullevents_c.h"
#include "SDL_nullframebuffer_c.h"
#include "SDL_hints.h"
#define DUMMYVID_DRIVER_NAME "dummy"
@ -59,7 +60,7 @@ static void DUMMY_VideoQuit(_THIS);
static int
DUMMY_Available(void)
{
const char *envr = SDL_getenv("SDL_VIDEODRIVER");
const char *envr = SDL_GetHint(SDL_HINT_VIDEODRIVER);
if ((envr) && (SDL_strcmp(envr, DUMMYVID_DRIVER_NAME) == 0)) {
return (1);
}

View file

@ -26,6 +26,8 @@
#include "SDL_emscriptenframebuffer.h"
#include "SDL_hints.h"
#include <emscripten/threading.h>
int Emscripten_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * format, void ** pixels, int *pitch)
{
@ -57,18 +59,9 @@ int Emscripten_CreateWindowFramebuffer(_THIS, SDL_Window * window, Uint32 * form
return 0;
}
int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects)
static void
Emscripten_UpdateWindowFramebufferWorker(SDL_Surface* surface)
{
SDL_Surface *surface;
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
surface = data->surface;
if (!surface) {
return SDL_SetError("Couldn't find framebuffer surface for window");
}
/* Send the data to the display */
EM_ASM_INT({
var w = $0;
var h = $1;
@ -156,6 +149,29 @@ int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rec
SDL2.ctx.putImageData(SDL2.image, 0, 0);
return 0;
}, surface->w, surface->h, surface->pixels);
}
int Emscripten_UpdateWindowFramebuffer(_THIS, SDL_Window * window, const SDL_Rect * rects, int numrects)
{
SDL_Surface *surface;
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
surface = data->surface;
if (!surface) {
return SDL_SetError("Couldn't find framebuffer surface for window");
}
/* Send the data to the display */
if (emscripten_is_main_runtime_thread()) {
Emscripten_UpdateWindowFramebufferWorker(surface);
} else {
emscripten_sync_run_in_main_runtime_thread(
EM_FUNC_SIG_VI,
Emscripten_UpdateWindowFramebufferWorker,
(uint32_t)surface
);
}
if (emscripten_has_asyncify() && SDL_GetHintBoolean(SDL_HINT_EMSCRIPTEN_ASYNCIFY, SDL_TRUE)) {
/* give back control to browser for screen refresh */

View file

@ -24,6 +24,7 @@
#include <emscripten/emscripten.h>
#include <emscripten/html5.h>
#include <emscripten/threading.h>
#include "SDL_emscriptenmouse.h"
#include "SDL_emscriptenvideo.h"
@ -62,19 +63,10 @@ Emscripten_CreateDefaultCursor()
return Emscripten_CreateCursorFromString("default", SDL_FALSE);
}
static SDL_Cursor*
Emscripten_CreateCursor(SDL_Surface* surface, int hot_x, int hot_y)
static const char*
Emscripten_GetCursorUrl(int w, int h, int hot_x, int hot_y, void* pixels)
{
const char *cursor_url = NULL;
SDL_Surface *conv_surf;
conv_surf = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ABGR8888, 0);
if (!conv_surf) {
return NULL;
}
cursor_url = (const char *)EM_ASM_INT({
return (const char *)EM_ASM_INT({
var w = $0;
var h = $1;
var hot_x = $2;
@ -122,7 +114,40 @@ Emscripten_CreateCursor(SDL_Surface* surface, int hot_x, int hot_y)
stringToUTF8(url, urlBuf, url.length + 1);
return urlBuf;
}, surface->w, surface->h, hot_x, hot_y, conv_surf->pixels);
}, w, h, hot_x, hot_y, pixels);
}
static SDL_Cursor*
Emscripten_CreateCursor(SDL_Surface* surface, int hot_x, int hot_y)
{
const char *cursor_url = NULL;
SDL_Surface *conv_surf;
conv_surf = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ABGR8888, 0);
if (!conv_surf) {
return NULL;
}
if (emscripten_is_main_runtime_thread()) {
cursor_url = Emscripten_GetCursorUrl(
surface->w,
surface->h,
hot_x,
hot_y,
conv_surf->pixels
);
} else {
cursor_url = (const char *)emscripten_sync_run_in_main_runtime_thread(
EM_FUNC_SIG_IIIIIII,
Emscripten_GetCursorUrl,
surface->w,
surface->h,
hot_x,
hot_y,
conv_surf->pixels
);
}
SDL_FreeSurface(conv_surf);
@ -206,16 +231,15 @@ Emscripten_ShowCursor(SDL_Cursor* cursor)
curdata = (Emscripten_CursorData *) cursor->driverdata;
if(curdata->system_cursor) {
EM_ASM_INT({
MAIN_THREAD_EM_ASM({
if (Module['canvas']) {
Module['canvas'].style['cursor'] = UTF8ToString($0);
}
return 0;
}, curdata->system_cursor);
}
}
else {
EM_ASM(
MAIN_THREAD_EM_ASM(
if (Module['canvas']) {
Module['canvas'].style['cursor'] = 'none';
}

View file

@ -174,10 +174,10 @@ Emscripten_GetDisplayUsableBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect *
if (rect) {
rect->x = 0;
rect->y = 0;
rect->w = EM_ASM_INT_V({
rect->w = MAIN_THREAD_EM_ASM_INT({
return window.innerWidth;
});
rect->h = EM_ASM_INT_V({
rect->h = MAIN_THREAD_EM_ASM_INT({
return window.innerHeight;
});
}

View file

@ -186,8 +186,8 @@ UIKit_ShowMessageBoxAlertView(const SDL_MessageBoxData *messageboxdata, int *but
#endif /* __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 */
}
int
UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
static void
UIKit_ShowMessageBoxImpl(const SDL_MessageBoxData *messageboxdata, int *buttonid, int *returnValue)
{
BOOL success = NO;
@ -199,12 +199,26 @@ UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
}
if (!success) {
return SDL_SetError("Could not show message box.");
*returnValue = SDL_SetError("Could not show message box.");
} else {
*returnValue = 0;
}
return 0;
}
int
UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
{ @autoreleasepool
{
__block int returnValue = 0;
if ([NSThread isMainThread]) {
UIKit_ShowMessageBoxImpl(messageboxdata, buttonid, &returnValue);
} else {
dispatch_sync(dispatch_get_main_queue(), ^{ UIKit_ShowMessageBoxImpl(messageboxdata, buttonid, &returnValue); });
}
return returnValue;
}}
#endif /* SDL_VIDEO_DRIVER_UIKIT */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -31,7 +31,7 @@
#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))
#define DISPLAY_PIXEL_FORMAT SCE_DISPLAY_PIXELFORMAT_A8B8G8R8
void *vita_gpu_alloc(SceKernelMemBlockType type, unsigned int size, SceUID *uid)
void *vita_gpu_alloc(unsigned int type, unsigned int size, SceUID *uid)
{
void *mem;

View file

@ -20,11 +20,12 @@
*/
#include "../../SDL_internal.h"
#if SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR
#if SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR && SDL_VIDEO_VITA_PVR_OGL
#include <stdlib.h>
#include <string.h>
#include <psp2/kernel/modulemgr.h>
#include <gpu_es4/psp2_pvr_hint.h>
#include <gl4esinit.h>
#include "SDL_error.h"
#include "SDL_log.h"
@ -34,6 +35,16 @@
#define MAX_PATH 256 // vita limits are somehow wrong
/* Defaults */
int FB_WIDTH = 960;
int FB_HEIGHT = 544;
void getFBSize(int *width, int *height)
{
*width = FB_WIDTH;
*height = FB_HEIGHT;
}
int
VITA_GL_LoadLibrary(_THIS, const char *path)
{
@ -53,6 +64,9 @@ VITA_GL_LoadLibrary(_THIS, const char *path)
sceKernelLoadStartModule("vs0:sys/external/libfios2.suprx", 0, NULL, 0, NULL, NULL);
sceKernelLoadStartModule("vs0:sys/external/libc.suprx", 0, NULL, 0, NULL, NULL);
SDL_snprintf(target_path, MAX_PATH, "%s/%s", default_path, "libGL.suprx");
sceKernelLoadStartModule(target_path, 0, NULL, 0, NULL, NULL);
SDL_snprintf(target_path, MAX_PATH, "%s/%s", default_path, "libgpu_es4_ext.suprx");
sceKernelLoadStartModule(target_path, 0, NULL, 0, NULL, NULL);
@ -74,30 +88,45 @@ VITA_GL_LoadLibrary(_THIS, const char *path)
SDL_GLContext
VITA_GL_CreateContext(_THIS, SDL_Window * window)
{
return SDL_EGL_CreateContext(_this, ((SDL_WindowData *) window->driverdata)->egl_surface);
}
char gl_version[3];
SDL_GLContext context = NULL;
int temp_major = _this->gl_config.major_version;
int temp_minor = _this->gl_config.minor_version;
int temp_profile = _this->gl_config.profile_mask;
int
VITA_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
{
if (window && context) {
return SDL_EGL_MakeCurrent(_this, ((SDL_WindowData *) window->driverdata)->egl_surface, context);
} else {
return SDL_EGL_MakeCurrent(_this, NULL, NULL);
/* Set version to 2.0 and PROFILE to ES */
_this->gl_config.major_version = 2;
_this->gl_config.minor_version = 0;
_this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
context = SDL_EGL_CreateContext(_this, ((SDL_WindowData *) window->driverdata)->egl_surface);
if (context != NULL)
{
FB_WIDTH = window->w;
FB_HEIGHT = window->h;
set_getprocaddress((void *(*)(const char *))eglGetProcAddress);
set_getmainfbsize(getFBSize);
SDL_snprintf(gl_version, 3, "%d%d", temp_major, temp_minor);
gl4es_setenv("LIBGL_NOTEXRECT", "1", 1); /* Currently broken in driver */
gl4es_setenv("LIBGL_GL", gl_version, 1);
initialize_gl4es();
}
/* Restore gl_config */
_this->gl_config.major_version = temp_major;
_this->gl_config.minor_version = temp_minor;
_this->gl_config.profile_mask = temp_profile;
return context;
}
int
VITA_GL_SwapWindow(_THIS, SDL_Window * window)
void *
VITA_GL_GetProcAddress(_THIS, const char *proc)
{
SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
if (videodata->ime_active) {
sceImeUpdate();
}
return SDL_EGL_SwapBuffers(_this, ((SDL_WindowData *) window->driverdata)->egl_surface);
return gl4es_GetProcAddress(proc);
}
#endif /* SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -19,17 +19,16 @@
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_vitagl_c_h_
#define SDL_vitagl_c_h_
#ifndef SDL_vitagl_pvr_c_h_
#define SDL_vitagl_pvr_c_h_
#include "SDL_vitavideo.h"
extern int VITA_GL_MakeCurrent(_THIS,SDL_Window * window, SDL_GLContext context);
extern int VITA_GL_SwapWindow(_THIS, SDL_Window * window);
extern SDL_GLContext VITA_GL_CreateContext(_THIS, SDL_Window * window);
extern int VITA_GL_LoadLibrary(_THIS, const char *path);
extern void *VITA_GL_GetProcAddress(_THIS, const char *proc);
#endif /* SDL_vitagl_c_h_ */
#endif /* SDL_vitagl_pvr_c_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -27,7 +27,7 @@
#include "SDL_error.h"
#include "SDL_log.h"
#include "SDL_vitavideo.h"
#include "SDL_vitagl_c.h"
#include "SDL_vitagles_c.h"
/*****************************************************************************/
/* SDL OpenGL/OpenGL ES functions */
@ -45,7 +45,7 @@
} while (0)
void
VITA_GL_KeyboardCallback(ScePigletPreSwapData *data)
VITA_GLES_KeyboardCallback(ScePigletPreSwapData *data)
{
SceCommonDialogUpdateParam commonDialogParam;
SDL_zero(commonDialogParam);
@ -62,20 +62,20 @@ VITA_GL_KeyboardCallback(ScePigletPreSwapData *data)
}
int
VITA_GL_LoadLibrary(_THIS, const char *path)
VITA_GLES_LoadLibrary(_THIS, const char *path)
{
pibInit(PIB_SHACCCG | PIB_GET_PROC_ADDR_CORE);
return 0;
}
void *
VITA_GL_GetProcAddress(_THIS, const char *proc)
VITA_GLES_GetProcAddress(_THIS, const char *proc)
{
return eglGetProcAddress(proc);
}
void
VITA_GL_UnloadLibrary(_THIS)
VITA_GLES_UnloadLibrary(_THIS)
{
eglTerminate(_this->gl_data->display);
}
@ -84,7 +84,7 @@ static EGLint width = 960;
static EGLint height = 544;
SDL_GLContext
VITA_GL_CreateContext(_THIS, SDL_Window * window)
VITA_GLES_CreateContext(_THIS, SDL_Window * window)
{
SDL_WindowData *wdata = (SDL_WindowData *) window->driverdata;
@ -159,13 +159,13 @@ VITA_GL_CreateContext(_THIS, SDL_Window * window)
_this->gl_data->surface = surface;
preSwapCallback = (PFNEGLPIGLETVITASETPRESWAPCALLBACKSCEPROC) eglGetProcAddress("eglPigletVitaSetPreSwapCallbackSCE");
preSwapCallback(VITA_GL_KeyboardCallback);
preSwapCallback(VITA_GLES_KeyboardCallback);
return context;
}
int
VITA_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
VITA_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
{
if (!eglMakeCurrent(_this->gl_data->display, _this->gl_data->surface,
_this->gl_data->surface, _this->gl_data->context))
@ -176,7 +176,7 @@ VITA_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
}
int
VITA_GL_SetSwapInterval(_THIS, int interval)
VITA_GLES_SetSwapInterval(_THIS, int interval)
{
EGLBoolean status;
status = eglSwapInterval(_this->gl_data->display, interval);
@ -190,13 +190,13 @@ VITA_GL_SetSwapInterval(_THIS, int interval)
}
int
VITA_GL_GetSwapInterval(_THIS)
VITA_GLES_GetSwapInterval(_THIS)
{
return _this->gl_data->swapinterval;
}
int
VITA_GL_SwapWindow(_THIS, SDL_Window * window)
VITA_GLES_SwapWindow(_THIS, SDL_Window * window)
{
if (!eglSwapBuffers(_this->gl_data->display, _this->gl_data->surface)) {
return SDL_SetError("eglSwapBuffers() failed");
@ -205,7 +205,7 @@ VITA_GL_SwapWindow(_THIS, SDL_Window * window)
}
void
VITA_GL_DeleteContext(_THIS, SDL_GLContext context)
VITA_GLES_DeleteContext(_THIS, SDL_GLContext context)
{
SDL_VideoData *phdata = (SDL_VideoData *) _this->driverdata;
EGLBoolean status;

View file

@ -19,8 +19,8 @@
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_vitagl_c_h_
#define SDL_vitagl_c_h_
#ifndef SDL_vitagles_c_h_
#define SDL_vitagles_c_h_
#include <pib.h>
@ -39,19 +39,19 @@ typedef struct SDL_GLDriverData {
uint32_t swapinterval;
}SDL_GLDriverData;
extern void * VITA_GL_GetProcAddress(_THIS, const char *proc);
extern int VITA_GL_MakeCurrent(_THIS,SDL_Window * window, SDL_GLContext context);
extern void VITA_GL_SwapBuffers(_THIS);
extern void * VITA_GLES_GetProcAddress(_THIS, const char *proc);
extern int VITA_GLES_MakeCurrent(_THIS,SDL_Window * window, SDL_GLContext context);
extern void VITA_GLES_SwapBuffers(_THIS);
extern int VITA_GL_SwapWindow(_THIS, SDL_Window * window);
extern SDL_GLContext VITA_GL_CreateContext(_THIS, SDL_Window * window);
extern int VITA_GLES_SwapWindow(_THIS, SDL_Window * window);
extern SDL_GLContext VITA_GLES_CreateContext(_THIS, SDL_Window * window);
extern int VITA_GL_LoadLibrary(_THIS, const char *path);
extern void VITA_GL_UnloadLibrary(_THIS);
extern int VITA_GL_SetSwapInterval(_THIS, int interval);
extern int VITA_GL_GetSwapInterval(_THIS);
extern int VITA_GLES_LoadLibrary(_THIS, const char *path);
extern void VITA_GLES_UnloadLibrary(_THIS);
extern int VITA_GLES_SetSwapInterval(_THIS, int interval);
extern int VITA_GLES_GetSwapInterval(_THIS);
#endif /* SDL_vitagl_c_h_ */
#endif /* SDL_vitagles_c_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -0,0 +1,103 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 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 SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR
#include <stdlib.h>
#include <string.h>
#include <psp2/kernel/modulemgr.h>
#include <gpu_es4/psp2_pvr_hint.h>
#include "SDL_error.h"
#include "SDL_log.h"
#include "SDL_vitavideo.h"
#include "../SDL_egl_c.h"
#include "SDL_vitagles_pvr_c.h"
#define MAX_PATH 256 // vita limits are somehow wrong
int
VITA_GLES_LoadLibrary(_THIS, const char *path)
{
PVRSRV_PSP2_APPHINT hint;
char* override = SDL_getenv("VITA_MODULE_PATH");
char* skip_init = SDL_getenv("VITA_PVR_SKIP_INIT");
char* default_path = "app0:module";
char target_path[MAX_PATH];
if (skip_init == NULL) // we don't care about actual value
{
if (override != NULL)
{
default_path = override;
}
sceKernelLoadStartModule("vs0:sys/external/libfios2.suprx", 0, NULL, 0, NULL, NULL);
sceKernelLoadStartModule("vs0:sys/external/libc.suprx", 0, NULL, 0, NULL, NULL);
SDL_snprintf(target_path, MAX_PATH, "%s/%s", default_path, "libgpu_es4_ext.suprx");
sceKernelLoadStartModule(target_path, 0, NULL, 0, NULL, NULL);
SDL_snprintf(target_path, MAX_PATH, "%s/%s", default_path, "libIMGEGL.suprx");
sceKernelLoadStartModule(target_path, 0, NULL, 0, NULL, NULL);
PVRSRVInitializeAppHint(&hint);
SDL_snprintf(hint.szGLES1, MAX_PATH, "%s/%s", default_path, "libGLESv1_CM.suprx");
SDL_snprintf(hint.szGLES2, MAX_PATH, "%s/%s", default_path, "libGLESv2.suprx");
SDL_snprintf(hint.szWindowSystem, MAX_PATH, "%s/%s", default_path, "libpvrPSP2_WSEGL.suprx");
PVRSRVCreateVirtualAppHint(&hint);
}
return SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType) 0, 0);
}
SDL_GLContext
VITA_GLES_CreateContext(_THIS, SDL_Window * window)
{
return SDL_EGL_CreateContext(_this, ((SDL_WindowData *) window->driverdata)->egl_surface);
}
int
VITA_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context)
{
if (window && context) {
return SDL_EGL_MakeCurrent(_this, ((SDL_WindowData *) window->driverdata)->egl_surface, context);
} else {
return SDL_EGL_MakeCurrent(_this, NULL, NULL);
}
}
int
VITA_GLES_SwapWindow(_THIS, SDL_Window * window)
{
SDL_VideoData *videodata = (SDL_VideoData *)_this->driverdata;
if (videodata->ime_active) {
sceImeUpdate();
}
return SDL_EGL_SwapBuffers(_this, ((SDL_WindowData *) window->driverdata)->egl_surface);
}
#endif /* SDL_VIDEO_DRIVER_VITA && SDL_VIDEO_VITA_PVR */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -0,0 +1,35 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2022 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_vitagles_pvr_c_h_
#define SDL_vitagles_pvr_c_h_
#include "SDL_vitavideo.h"
extern int VITA_GLES_MakeCurrent(_THIS,SDL_Window * window, SDL_GLContext context);
extern int VITA_GLES_SwapWindow(_THIS, SDL_Window * window);
extern SDL_GLContext VITA_GLES_CreateContext(_THIS, SDL_Window * window);
extern int VITA_GLES_LoadLibrary(_THIS, const char *path);
#endif /* SDL_vitagles_pvr_c_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -41,15 +41,17 @@
#include "SDL_vitaframebuffer.h"
#if defined(SDL_VIDEO_VITA_PIB)
#include "SDL_vitagl_c.h"
#include "SDL_vitagles_c.h"
#elif defined(SDL_VIDEO_VITA_PVR)
#include "SDL_vitagles_pvr_c.h"
#if defined(SDL_VIDEO_VITA_PVR_OGL)
#include "SDL_vitagl_pvr_c.h"
#include "../SDL_egl_c.h"
#define VITA_GL_GetProcAddress SDL_EGL_GetProcAddress
#define VITA_GL_UnloadLibrary SDL_EGL_UnloadLibrary
#define VITA_GL_SetSwapInterval SDL_EGL_SetSwapInterval
#define VITA_GL_GetSwapInterval SDL_EGL_GetSwapInterval
#define VITA_GL_DeleteContext SDL_EGL_DeleteContext
#endif
#define VITA_GLES_GetProcAddress SDL_EGL_GetProcAddress
#define VITA_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
#define VITA_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
#define VITA_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
#define VITA_GLES_DeleteContext SDL_EGL_DeleteContext
#endif
SDL_Window *Vita_Window;
@ -140,15 +142,26 @@ VITA_Create()
*/
#if defined(SDL_VIDEO_VITA_PIB) || defined(SDL_VIDEO_VITA_PVR)
#if defined(SDL_VIDEO_VITA_PVR_OGL)
if(SDL_getenv("VITA_PVR_OGL") != NULL) {
device->GL_LoadLibrary = VITA_GL_LoadLibrary;
device->GL_GetProcAddress = VITA_GL_GetProcAddress;
device->GL_UnloadLibrary = VITA_GL_UnloadLibrary;
device->GL_CreateContext = VITA_GL_CreateContext;
device->GL_MakeCurrent = VITA_GL_MakeCurrent;
device->GL_SetSwapInterval = VITA_GL_SetSwapInterval;
device->GL_GetSwapInterval = VITA_GL_GetSwapInterval;
device->GL_SwapWindow = VITA_GL_SwapWindow;
device->GL_DeleteContext = VITA_GL_DeleteContext;
device->GL_GetProcAddress = VITA_GL_GetProcAddress;
} else {
#endif
device->GL_LoadLibrary = VITA_GLES_LoadLibrary;
device->GL_CreateContext = VITA_GLES_CreateContext;
device->GL_GetProcAddress = VITA_GLES_GetProcAddress;
#if defined(SDL_VIDEO_VITA_PVR_OGL)
}
#endif
device->GL_UnloadLibrary = VITA_GLES_UnloadLibrary;
device->GL_MakeCurrent = VITA_GLES_MakeCurrent;
device->GL_SetSwapInterval = VITA_GLES_SetSwapInterval;
device->GL_GetSwapInterval = VITA_GLES_GetSwapInterval;
device->GL_SwapWindow = VITA_GLES_SwapWindow;
device->GL_DeleteContext = VITA_GLES_DeleteContext;
#endif
device->HasScreenKeyboardSupport = VITA_HasScreenKeyboardSupport;
@ -245,6 +258,9 @@ VITA_CreateWindow(_THIS, SDL_Window * window)
SDL_WindowData *wdata;
#if defined(SDL_VIDEO_VITA_PVR)
Psp2NativeWindow win;
int temp_major = 2;
int temp_minor = 1;
int temp_profile = 0;
#endif
/* Allocate window internal data */
@ -282,11 +298,26 @@ VITA_CreateWindow(_THIS, SDL_Window * window)
win.windowSize = PSP2_WINDOW_960X544;
}
if ((window->flags & SDL_WINDOW_OPENGL) != 0) {
wdata->egl_surface = SDL_EGL_CreateSurface(_this, &win);
if(SDL_getenv("VITA_PVR_OGL") != NULL) {
/* Set version to 2.1 and PROFILE to ES */
temp_major = _this->gl_config.major_version;
temp_minor = _this->gl_config.minor_version;
temp_profile = _this->gl_config.profile_mask;
_this->gl_config.major_version = 2;
_this->gl_config.minor_version = 1;
_this->gl_config.profile_mask = SDL_GL_CONTEXT_PROFILE_ES;
}
wdata->egl_surface = SDL_EGL_CreateSurface(_this, &win);
if (wdata->egl_surface == EGL_NO_SURFACE) {
return SDL_SetError("Could not create GLES window surface");
}
if(SDL_getenv("VITA_PVR_OGL") != NULL) {
/* Revert */
_this->gl_config.major_version = temp_major;
_this->gl_config.minor_version = temp_minor;
_this->gl_config.profile_mask = temp_profile;
}
}
#endif

View file

@ -90,16 +90,23 @@ SDL_bool VITA_GetWindowWMInfo(_THIS, SDL_Window * window,
struct SDL_SysWMinfo *info);
#if SDL_VIDEO_DRIVER_VITA
#if defined(SDL_VIDEO_VITA_PVR_OGL)
/* OpenGL functions */
int VITA_GL_LoadLibrary(_THIS, const char *path);
void *VITA_GL_GetProcAddress(_THIS, const char *proc);
void VITA_GL_UnloadLibrary(_THIS);
SDL_GLContext VITA_GL_CreateContext(_THIS, SDL_Window * window);
int VITA_GL_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
int VITA_GL_SetSwapInterval(_THIS, int interval);
int VITA_GL_GetSwapInterval(_THIS);
int VITA_GL_SwapWindow(_THIS, SDL_Window * window);
void VITA_GL_DeleteContext(_THIS, SDL_GLContext context);
void *VITA_GL_GetProcAddress(_THIS, const char *proc);
#endif
/* OpenGLES functions */
int VITA_GLES_LoadLibrary(_THIS, const char *path);
void *VITA_GLES_GetProcAddress(_THIS, const char *proc);
void VITA_GLES_UnloadLibrary(_THIS);
SDL_GLContext VITA_GLES_CreateContext(_THIS, SDL_Window * window);
int VITA_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context);
int VITA_GLES_SetSwapInterval(_THIS, int interval);
int VITA_GLES_GetSwapInterval(_THIS);
int VITA_GLES_SwapWindow(_THIS, SDL_Window * window);
void VITA_GLES_DeleteContext(_THIS, SDL_GLContext context);
#endif
/* VITA on screen keyboard */

View file

@ -52,6 +52,14 @@ enum libdecor_window_state;
#include "xkbcommon/xkbcommon.h"
#include "xkbcommon/xkbcommon-compose.h"
/* Must be included before our #defines, see Bugzilla #4957 */
#include "wayland-client-core.h"
#define SDL_WAYLAND_CHECK_VERSION(x, y, z) \
(WAYLAND_VERSION_MAJOR > x || \
(WAYLAND_VERSION_MAJOR == x && WAYLAND_VERSION_MINOR > y) || \
(WAYLAND_VERSION_MAJOR == x && WAYLAND_VERSION_MINOR == y && WAYLAND_VERSION_MICRO >= z))
#ifdef __cplusplus
extern "C"
{
@ -71,9 +79,6 @@ void SDL_WAYLAND_UnloadSymbols(void);
}
#endif
/* Must be included before our #defines, see Bugzilla #4957 */
#include "wayland-client-core.h"
#ifdef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC
#if defined(_WAYLAND_CLIENT_H) || defined(WAYLAND_CLIENT_H)

View file

@ -40,6 +40,7 @@
#include "xdg-shell-client-protocol.h"
#include "keyboard-shortcuts-inhibit-unstable-v1-client-protocol.h"
#include "text-input-unstable-v3-client-protocol.h"
#include "tablet-unstable-v2-client-protocol.h"
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
@ -83,6 +84,7 @@ static const struct {
{ XKB_KEY_Super_R, SDLK_RGUI },
{ XKB_KEY_Hyper_L, SDLK_LGUI },
{ XKB_KEY_Hyper_R, SDLK_RGUI },
{ XKB_KEY_BackSpace, SDLK_BACKSPACE },
};
struct SDL_WaylandTouchPoint {
@ -387,8 +389,10 @@ pointer_handle_motion(void *data, struct wl_pointer *pointer,
input->sx_w = sx_w;
input->sy_w = sy_w;
if (input->pointer_focus) {
const int sx = wl_fixed_to_int(sx_w);
const int sy = wl_fixed_to_int(sy_w);
const float sx_f = (float)wl_fixed_to_double(sx_w);
const float sy_f = (float)wl_fixed_to_double(sy_w);
const int sx = (int)SDL_floorf(sx_f * window->pointer_scale_x);
const int sy = (int)SDL_floorf(sy_f * window->pointer_scale_y);
SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
}
}
@ -472,6 +476,9 @@ ProcessHitTest(struct SDL_WaylandInput *input, uint32_t serial)
const uint32_t *directions_libdecor = directions;
#endif
/* Hit tests shouldn't apply to xdg_popups, right? */
SDL_assert(!WINDOW_IS_XDG_POPUP(window));
switch (rc) {
case SDL_HITTEST_DRAGGABLE:
#ifdef HAVE_LIBDECOR_H
@ -715,8 +722,8 @@ touch_handler_down(void *data, struct wl_touch *touch, unsigned int serial,
int id, wl_fixed_t fx, wl_fixed_t fy)
{
SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface);
const double dblx = wl_fixed_to_double(fx);
const double dbly = wl_fixed_to_double(fy);
const double dblx = wl_fixed_to_double(fx) * window_data->pointer_scale_x;
const double dbly = wl_fixed_to_double(fy) * window_data->pointer_scale_y;
const float x = dblx / window_data->sdlwindow->w;
const float y = dbly / window_data->sdlwindow->h;
@ -748,8 +755,8 @@ touch_handler_motion(void *data, struct wl_touch *touch, unsigned int timestamp,
int id, wl_fixed_t fx, wl_fixed_t fy)
{
SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(touch_surface(id));
const double dblx = wl_fixed_to_double(fx);
const double dbly = wl_fixed_to_double(fy);
const double dblx = wl_fixed_to_double(fx) * window_data->pointer_scale_x;
const double dbly = wl_fixed_to_double(fy) * window_data->pointer_scale_y;
const float x = dblx / window_data->sdlwindow->w;
const float y = dbly / window_data->sdlwindow->h;
@ -815,6 +822,16 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
return;
}
#define GET_MOD_INDEX(mod) \
WAYLAND_xkb_keymap_mod_get_index(input->xkb.keymap, XKB_MOD_NAME_##mod)
input->xkb.idx_shift = 1 << GET_MOD_INDEX(SHIFT);
input->xkb.idx_ctrl = 1 << GET_MOD_INDEX(CTRL);
input->xkb.idx_alt = 1 << GET_MOD_INDEX(ALT);
input->xkb.idx_gui = 1 << GET_MOD_INDEX(LOGO);
input->xkb.idx_num = 1 << GET_MOD_INDEX(NUM);
input->xkb.idx_caps = 1 << GET_MOD_INDEX(CAPS);
#undef GET_MOD_INDEX
input->xkb.state = WAYLAND_xkb_state_new(input->xkb.keymap);
if (!input->xkb.state) {
fprintf(stderr, "failed to create XKB state\n");
@ -829,10 +846,14 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
*/
/* Look up the preferred locale, falling back to "C" as default */
if (!(locale = SDL_getenv("LC_ALL")))
if (!(locale = SDL_getenv("LC_CTYPE")))
if (!(locale = SDL_getenv("LANG")))
if (!(locale = SDL_getenv("LC_ALL"))) {
if (!(locale = SDL_getenv("LC_CTYPE"))) {
if (!(locale = SDL_getenv("LANG"))) {
locale = "C";
}
}
}
/* Set up XKB compose table */
input->xkb.compose_table = WAYLAND_xkb_compose_table_new_from_locale(input->display->xkb_context,
locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
@ -903,7 +924,7 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
}
static SDL_bool
keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key, SDL_bool *handled_by_ime)
keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key, Uint8 state, SDL_bool *handled_by_ime)
{
SDL_WindowData *window = input->keyboard_focus;
const xkb_keysym_t *syms;
@ -920,12 +941,16 @@ keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint
sym = syms[0];
#ifdef SDL_USE_IME
if (SDL_IME_ProcessKeyEvent(sym, key + 8)) {
if (SDL_IME_ProcessKeyEvent(sym, key + 8, state)) {
*handled_by_ime = SDL_TRUE;
return SDL_TRUE;
}
#endif
if (state == SDL_RELEASED) {
return SDL_FALSE;
}
if (input->xkb.compose_state && WAYLAND_xkb_compose_state_feed(input->xkb.compose_state, sym) == XKB_COMPOSE_FEED_ACCEPTED) {
switch(WAYLAND_xkb_compose_state_get_status(input->xkb.compose_state)) {
case XKB_COMPOSE_COMPOSING:
@ -959,7 +984,7 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
SDL_bool handled_by_ime = SDL_FALSE;
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
has_text = keyboard_input_get_text(text, input, key, &handled_by_ime);
has_text = keyboard_input_get_text(text, input, key, SDL_PRESSED, &handled_by_ime);
} else {
if (keyboard_repeat_is_set(&input->keyboard_repeat)) {
// Send any due key repeat events before stopping the repeat and generating the key up event
@ -969,6 +994,7 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
keyboard_repeat_handle(&input->keyboard_repeat, time - input->keyboard_repeat.wl_press_time);
keyboard_repeat_clear(&input->keyboard_repeat);
}
keyboard_input_get_text(text, input, key, SDL_RELEASED, &handled_by_ime);
}
if (!handled_by_ime && key < SDL_arraysize(xfree86_scancode_table2)) {
@ -1054,10 +1080,24 @@ keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
{
struct SDL_WaylandInput *input = data;
Wayland_Keymap keymap;
uint32_t modstate = (mods_depressed | mods_latched | mods_locked);
WAYLAND_xkb_state_update_mask(input->xkb.state, mods_depressed, mods_latched,
mods_locked, 0, 0, group);
SDL_ToggleModState(KMOD_SHIFT, modstate & input->xkb.idx_shift);
SDL_ToggleModState(KMOD_CTRL, modstate & input->xkb.idx_ctrl);
SDL_ToggleModState(KMOD_ALT, modstate & input->xkb.idx_alt);
SDL_ToggleModState(KMOD_GUI, modstate & input->xkb.idx_gui);
SDL_ToggleModState(KMOD_NUM, modstate & input->xkb.idx_num);
SDL_ToggleModState(KMOD_CAPS, modstate & input->xkb.idx_caps);
if (group == input->xkb.current_group) {
return;
}
/* The layout changed, remap and fire an event */
input->xkb.current_group = group;
keymap.layout = group;
SDL_GetDefaultKeymap(keymap.keymap);
WAYLAND_xkb_keymap_key_for_each(input->xkb.keymap,
@ -1646,6 +1686,363 @@ Wayland_add_text_input_manager(SDL_VideoData *d, uint32_t id, uint32_t version)
}
}
static void
tablet_tool_handle_type(void* data, struct zwp_tablet_tool_v2* tool, uint32_t type)
{
/* unimplemented */
}
static void
tablet_tool_handle_hardware_serial(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial_hi, uint32_t serial_lo)
{
/* unimplemented */
}
static void
tablet_tool_handle_hardware_id_wacom(void* data, struct zwp_tablet_tool_v2* tool, uint32_t id_hi, uint32_t id_lo)
{
/* unimplemented */
}
static void
tablet_tool_handle_capability(void* data, struct zwp_tablet_tool_v2* tool, uint32_t capability)
{
/* unimplemented */
}
static void
tablet_tool_handle_done(void* data, struct zwp_tablet_tool_v2* tool)
{
/* unimplemented */
}
static void
tablet_tool_handle_removed(void* data, struct zwp_tablet_tool_v2* tool)
{
/* unimplemented */
}
static void
tablet_tool_handle_proximity_in(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial, struct zwp_tablet_v2* tablet, struct wl_surface* surface)
{
struct SDL_WaylandTabletInput* input = data;
SDL_WindowData* window;
if (!surface) {
return;
}
if (!SDL_WAYLAND_own_surface(surface)) {
return;
}
window = (SDL_WindowData*)wl_surface_get_user_data(surface);
if (window) {
input->tool_focus = window;
input->tool_prox_serial = serial;
input->is_down = SDL_FALSE;
input->btn_stylus = SDL_FALSE;
input->btn_stylus2 = SDL_FALSE;
input->btn_stylus3 = SDL_FALSE;
SDL_SetMouseFocus(window->sdlwindow);
SDL_SetCursor(NULL);
}
}
static void
tablet_tool_handle_proximity_out(void* data, struct zwp_tablet_tool_v2* tool)
{
struct SDL_WaylandTabletInput* input = data;
if (input->tool_focus) {
SDL_SetMouseFocus(NULL);
input->tool_focus = NULL;
}
}
uint32_t
tablet_tool_btn_to_sdl_button(struct SDL_WaylandTabletInput* input)
{
unsigned int tool_btn = input->btn_stylus3 << 2 | input->btn_stylus2 << 1 | input->btn_stylus << 0;
switch (tool_btn) {
case 0b000:
return SDL_BUTTON_LEFT;
case 0b001:
return SDL_BUTTON_RIGHT;
case 0b010:
return SDL_BUTTON_MIDDLE;
case 0b100:
return SDL_BUTTON_X1;
default:
return SDL_BUTTON_LEFT;
}
}
static void
tablet_tool_handle_down(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial)
{
struct SDL_WaylandTabletInput* input = data;
SDL_WindowData* window = input->tool_focus;
input->is_down = SDL_TRUE;
if (!window) {
/* tablet_tool_handle_proximity_out gets called when moving over the libdecoration csd.
* that sets input->tool_focus (window) to NULL, but handle_{down,up} events are still
* received. To prevent SIGSEGV this returns when this is the case.
*/
return;
}
SDL_SendMouseButton(window->sdlwindow, 0, SDL_PRESSED, tablet_tool_btn_to_sdl_button(input));
}
static void
tablet_tool_handle_up(void* data, struct zwp_tablet_tool_v2* tool)
{
struct SDL_WaylandTabletInput* input = data;
SDL_WindowData* window = input->tool_focus;
input->is_down = SDL_FALSE;
if (!window) {
/* tablet_tool_handle_proximity_out gets called when moving over the libdecoration csd.
* that sets input->tool_focus (window) to NULL, but handle_{down,up} events are still
* received. To prevent SIGSEGV this returns when this is the case.
*/
return;
}
SDL_SendMouseButton(window->sdlwindow, 0, SDL_RELEASED, tablet_tool_btn_to_sdl_button(input));
}
static void
tablet_tool_handle_motion(void* data, struct zwp_tablet_tool_v2* tool, wl_fixed_t sx_w, wl_fixed_t sy_w)
{
struct SDL_WaylandTabletInput* input = data;
SDL_WindowData* window = input->tool_focus;
input->sx_w = sx_w;
input->sy_w = sy_w;
if (input->tool_focus) {
const float sx_f = (float)wl_fixed_to_double(sx_w);
const float sy_f = (float)wl_fixed_to_double(sy_w);
const int sx = (int)SDL_floorf(sx_f * window->pointer_scale_x);
const int sy = (int)SDL_floorf(sy_f * window->pointer_scale_y);
SDL_SendMouseMotion(window->sdlwindow, 0, 0, sx, sy);
}
}
static void
tablet_tool_handle_pressure(void* data, struct zwp_tablet_tool_v2* tool, uint32_t pressure)
{
/* unimplemented */
}
static void
tablet_tool_handle_distance(void* data, struct zwp_tablet_tool_v2* tool, uint32_t distance)
{
/* unimplemented */
}
static void
tablet_tool_handle_tilt(void* data, struct zwp_tablet_tool_v2* tool, wl_fixed_t xtilt, wl_fixed_t ytilt)
{
/* unimplemented */
}
static void
tablet_tool_handle_button(void* data, struct zwp_tablet_tool_v2* tool, uint32_t serial, uint32_t button, uint32_t state)
{
struct SDL_WaylandTabletInput* input = data;
if (input->is_down) {
tablet_tool_handle_up(data, tool);
input->is_down = SDL_TRUE;
}
switch (button) {
/* see %{_includedir}/linux/input-event-codes.h */
case 0x14b: /* BTN_STYLUS */
input->btn_stylus = state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED ? SDL_TRUE : SDL_FALSE;
break;
case 0x14c: /* BTN_STYLUS2 */
input->btn_stylus2 = state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED ? SDL_TRUE : SDL_FALSE;
break;
case 0x149: /* BTN_STYLUS3 */
input->btn_stylus3 = state == ZWP_TABLET_PAD_V2_BUTTON_STATE_PRESSED ? SDL_TRUE : SDL_FALSE;
break;
}
if (input->is_down) {
tablet_tool_handle_down(data, tool, serial);
}
}
static void
tablet_tool_handle_rotation(void* data, struct zwp_tablet_tool_v2* tool, wl_fixed_t degrees)
{
/* unimplemented */
}
static void
tablet_tool_handle_slider(void* data, struct zwp_tablet_tool_v2* tool, int32_t position)
{
/* unimplemented */
}
static void
tablet_tool_handle_wheel(void* data, struct zwp_tablet_tool_v2* tool, int32_t degrees, int32_t clicks)
{
/* unimplemented */
}
static void
tablet_tool_handle_frame(void* data, struct zwp_tablet_tool_v2* tool, uint32_t time)
{
/* unimplemented */
}
static const struct zwp_tablet_tool_v2_listener tablet_tool_listener = {
tablet_tool_handle_type,
tablet_tool_handle_hardware_serial,
tablet_tool_handle_hardware_id_wacom,
tablet_tool_handle_capability,
tablet_tool_handle_done,
tablet_tool_handle_removed,
tablet_tool_handle_proximity_in,
tablet_tool_handle_proximity_out,
tablet_tool_handle_down,
tablet_tool_handle_up,
tablet_tool_handle_motion,
tablet_tool_handle_pressure,
tablet_tool_handle_distance,
tablet_tool_handle_tilt,
tablet_tool_handle_rotation,
tablet_tool_handle_slider,
tablet_tool_handle_wheel,
tablet_tool_handle_button,
tablet_tool_handle_frame
};
struct SDL_WaylandTabletObjectListNode*
tablet_object_list_new_node(void* object)
{
struct SDL_WaylandTabletObjectListNode* node;
node = SDL_calloc(1, sizeof *node);
if (node == NULL) {
return NULL;
}
node->next = NULL;
node->object = object;
return node;
}
void tablet_object_list_append(struct SDL_WaylandTabletObjectListNode* head, void* object)
{
if (head->object == NULL) {
head->object = object;
return;
}
while (head->next) {
head = head->next;
}
head->next = tablet_object_list_new_node(object);
}
void tablet_object_list_destroy(struct SDL_WaylandTabletObjectListNode* head, void (*deleter)(void* object))
{
while (head) {
struct SDL_WaylandTabletObjectListNode* next = head->next;
if (head->object) {
(*deleter)(head->object);
}
SDL_free(head);
head = next;
}
}
static void
tablet_seat_handle_tablet_added(void* data, struct zwp_tablet_seat_v2* seat, struct zwp_tablet_v2* tablet)
{
struct SDL_WaylandTabletInput* input = data;
tablet_object_list_append(input->tablets, tablet);
}
static void
tablet_seat_handle_tool_added(void* data, struct zwp_tablet_seat_v2* seat, struct zwp_tablet_tool_v2* tool)
{
struct SDL_WaylandTabletInput* input = data;
zwp_tablet_tool_v2_add_listener(tool, &tablet_tool_listener, data);
zwp_tablet_tool_v2_set_user_data(tool, data);
tablet_object_list_append(input->tools, tool);
}
static void
tablet_seat_handle_pad_added(void* data, struct zwp_tablet_seat_v2* seat, struct zwp_tablet_pad_v2* pad)
{
struct SDL_WaylandTabletInput* input = data;
tablet_object_list_append(input->pads, pad);
}
static const struct zwp_tablet_seat_v2_listener tablet_seat_listener = {
tablet_seat_handle_tablet_added,
tablet_seat_handle_tool_added,
tablet_seat_handle_pad_added
};
void
Wayland_input_add_tablet(struct SDL_WaylandInput *input, struct SDL_WaylandTabletManager* tablet_manager)
{
struct SDL_WaylandTabletInput* tablet_input;
if (!tablet_manager || !input || !input->seat) {
return;
}
tablet_input = SDL_calloc(1, sizeof *tablet_input);
if (tablet_input == NULL) {
return;
}
input->tablet = tablet_input;
tablet_input->seat = (struct SDL_WaylandTabletSeat*)zwp_tablet_manager_v2_get_tablet_seat((struct zwp_tablet_manager_v2*)tablet_manager, input->seat);
tablet_input->tablets = tablet_object_list_new_node(NULL);
tablet_input->tools = tablet_object_list_new_node(NULL);
tablet_input->pads = tablet_object_list_new_node(NULL);
zwp_tablet_seat_v2_add_listener((struct zwp_tablet_seat_v2*)tablet_input->seat, &tablet_seat_listener, tablet_input);
}
#define TABLET_OBJECT_LIST_DELETER(fun) (void (*)(void*))fun
void
Wayland_input_destroy_tablet(struct SDL_WaylandInput* input)
{
tablet_object_list_destroy(input->tablet->pads, TABLET_OBJECT_LIST_DELETER(zwp_tablet_pad_v2_destroy));
tablet_object_list_destroy(input->tablet->tools, TABLET_OBJECT_LIST_DELETER(zwp_tablet_tool_v2_destroy));
tablet_object_list_destroy(input->tablet->tablets, TABLET_OBJECT_LIST_DELETER(zwp_tablet_v2_destroy));
zwp_tablet_seat_v2_destroy((struct zwp_tablet_seat_v2*)input->tablet->seat);
SDL_free(input->tablet);
input->tablet = NULL;
}
void
Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
{
@ -1659,6 +2056,7 @@ Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
input->seat = wl_registry_bind(d->registry, id, &wl_seat_interface, SDL_min(5, version));
input->sx_w = wl_fixed_from_int(0);
input->sy_w = wl_fixed_from_int(0);
input->xkb.current_group = ~0;
d->input = input;
if (d->data_device_manager != NULL) {
@ -1671,6 +2069,10 @@ Wayland_display_add_input(SDL_VideoData *d, uint32_t id, uint32_t version)
wl_seat_add_listener(input->seat, &seat_listener, input);
wl_seat_set_user_data(input->seat, input);
if (d->tablet_manager) {
Wayland_input_add_tablet(input, d->tablet_manager);
}
WAYLAND_wl_display_flush(d->display);
}
@ -1711,6 +2113,10 @@ void Wayland_display_destroy_input(SDL_VideoData *d)
wl_touch_destroy(input->touch);
}
if (input->tablet) {
Wayland_input_destroy_tablet(input);
}
if (input->seat)
wl_seat_destroy(input->seat);
@ -1951,12 +2357,19 @@ int Wayland_input_confine_pointer(struct SDL_WaylandInput *input, SDL_Window *wi
if (SDL_RectEmpty(&window->mouse_rect)) {
confine_rect = NULL;
} else {
SDL_Rect scaled_mouse_rect;
scaled_mouse_rect.x = (int)SDL_floorf((float)window->mouse_rect.x / w->pointer_scale_x);
scaled_mouse_rect.y = (int)SDL_floorf((float)window->mouse_rect.y / w->pointer_scale_y);
scaled_mouse_rect.w = (int)SDL_ceilf((float)window->mouse_rect.w / w->pointer_scale_x);
scaled_mouse_rect.h = (int)SDL_ceilf((float)window->mouse_rect.h / w->pointer_scale_y);
confine_rect = wl_compositor_create_region(d->compositor);
wl_region_add(confine_rect,
window->mouse_rect.x,
window->mouse_rect.y,
window->mouse_rect.w,
window->mouse_rect.h);
scaled_mouse_rect.x,
scaled_mouse_rect.y,
scaled_mouse_rect.w,
scaled_mouse_rect.h);
}
confined_pointer =

View file

@ -29,6 +29,34 @@
#include "SDL_waylanddatamanager.h"
#include "SDL_waylandkeyboard.h"
struct SDL_WaylandTabletSeat;
struct SDL_WaylandTabletObjectListNode {
void* object;
struct SDL_WaylandTabletObjectListNode* next;
};
struct SDL_WaylandTabletInput {
struct SDL_WaylandTabletSeat* seat;
struct SDL_WaylandTabletObjectListNode* tablets;
struct SDL_WaylandTabletObjectListNode* tools;
struct SDL_WaylandTabletObjectListNode* pads;
SDL_WindowData *tool_focus;
uint32_t tool_prox_serial;
/* Last motion location */
wl_fixed_t sx_w;
wl_fixed_t sy_w;
SDL_bool is_down;
SDL_bool btn_stylus;
SDL_bool btn_stylus2;
SDL_bool btn_stylus3;
};
typedef struct {
// repeat_rate in range of [1, 1000]
int32_t repeat_rate;
@ -68,6 +96,17 @@ struct SDL_WaylandInput {
struct xkb_state *state;
struct xkb_compose_table *compose_table;
struct xkb_compose_state *compose_state;
/* Keyboard layout "group" */
uint32_t current_group;
/* Modifier bitshift values */
uint32_t idx_shift;
uint32_t idx_ctrl;
uint32_t idx_alt;
uint32_t idx_gui;
uint32_t idx_num;
uint32_t idx_caps;
} xkb;
/* information about axis events on current frame */
@ -80,6 +119,8 @@ struct SDL_WaylandInput {
} pointer_curr_axis_info;
SDL_WaylandKeyboardRepeat keyboard_repeat;
struct SDL_WaylandTabletInput* tablet;
};
extern void Wayland_PumpEvents(_THIS);
@ -107,6 +148,9 @@ extern void Wayland_display_destroy_relative_pointer_manager(SDL_VideoData *d);
extern int Wayland_input_grab_keyboard(SDL_Window *window, struct SDL_WaylandInput *input);
extern int Wayland_input_ungrab_keyboard(SDL_Window *window);
extern void Wayland_input_add_tablet(struct SDL_WaylandInput *input, struct SDL_WaylandTabletManager* tablet_manager);
extern void Wayland_input_destroy_tablet(struct SDL_WaylandInput *input);
#endif /* SDL_waylandevents_h_ */
/* vi: set ts=4 sw=4 expandtab: */

View file

@ -205,11 +205,11 @@ Wayland_GLES_GetDrawableSize(_THIS, SDL_Window * window, int * w, int * h)
data = (SDL_WindowData *) window->driverdata;
if (w) {
*w = window->w * data->scale_factor;
*w = data->drawable_width;
}
if (h) {
*h = window->h * data->scale_factor;
*h = data->drawable_height;
}
}
}

View file

@ -72,21 +72,19 @@ SDL_WAYLAND_SYM(void, wl_list_remove, (struct wl_list *))
SDL_WAYLAND_SYM(int, wl_list_length, (const struct wl_list *))
SDL_WAYLAND_SYM(int, wl_list_empty, (const struct wl_list *))
SDL_WAYLAND_SYM(void, wl_list_insert_list, (struct wl_list *, struct wl_list *))
/* These functions are available in Wayland >= 1.4 */
SDL_WAYLAND_MODULE(WAYLAND_CLIENT_1_4)
SDL_WAYLAND_SYM(struct wl_proxy *, wl_proxy_marshal_constructor, (struct wl_proxy *, uint32_t opcode, const struct wl_interface *interface, ...))
SDL_WAYLAND_MODULE(WAYLAND_CLIENT_1_10)
SDL_WAYLAND_SYM(struct wl_proxy *, wl_proxy_marshal_constructor_versioned, (struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, ...))
SDL_WAYLAND_MODULE(WAYLAND_CLIENT_1_18)
SDL_WAYLAND_SYM(void, wl_proxy_set_tag, (struct wl_proxy *, const char * const *))
SDL_WAYLAND_SYM(const char * const *, wl_proxy_get_tag, (struct wl_proxy *))
SDL_WAYLAND_MODULE(WAYLAND_CLIENT_1_20)
#if SDL_WAYLAND_CHECK_VERSION(1, 20, 0)
/* wayland-scanner 1.20 generates code that will call these, so these are
* non-optional when we are compiling against Wayland 1.20. We don't
* explicitly call them ourselves, though, so if we are only compiling
* against Wayland 1.18, they're unnecessary. */
SDL_WAYLAND_SYM(struct wl_proxy*, wl_proxy_marshal_flags, (struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interfac, uint32_t version, uint32_t flags, ...))
SDL_WAYLAND_SYM(struct wl_proxy*, wl_proxy_marshal_array_flags, (struct wl_proxy *proxy, uint32_t opcode, const struct wl_interface *interface, uint32_t version, uint32_t flags, union wl_argument *args))
#endif
SDL_WAYLAND_INTERFACE(wl_seat_interface)
SDL_WAYLAND_INTERFACE(wl_surface_interface)
@ -149,6 +147,8 @@ SDL_WAYLAND_SYM(int, xkb_keymap_key_get_syms_by_level, (struct xkb_keymap *,
xkb_layout_index_t,
const xkb_keysym_t **) )
SDL_WAYLAND_SYM(uint32_t, xkb_keysym_to_utf32, (xkb_keysym_t) )
SDL_WAYLAND_SYM(uint32_t, xkb_keymap_mod_get_index, (struct xkb_keymap *,
const char *) )
#ifdef HAVE_LIBDECOR_H
SDL_WAYLAND_MODULE(WAYLAND_LIBDECOR)

View file

@ -52,6 +52,9 @@
#include "idle-inhibit-unstable-v1-client-protocol.h"
#include "xdg-activation-v1-client-protocol.h"
#include "text-input-unstable-v3-client-protocol.h"
#include "tablet-unstable-v2-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h"
#include "viewporter-client-protocol.h"
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
@ -59,6 +62,9 @@
#define WAYLANDVID_DRIVER_NAME "wayland"
static void
display_handle_done(void *data, struct wl_output *output);
/* Initialization/Query functions */
static int
Wayland_VideoInit(_THIS);
@ -133,32 +139,22 @@ static const char *SDL_WAYLAND_output_tag = "sdl-output";
void SDL_WAYLAND_register_surface(struct wl_surface *surface)
{
if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) {
wl_proxy_set_tag((struct wl_proxy *)surface, &SDL_WAYLAND_surface_tag);
}
wl_proxy_set_tag((struct wl_proxy *)surface, &SDL_WAYLAND_surface_tag);
}
void SDL_WAYLAND_register_output(struct wl_output *output)
{
if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) {
wl_proxy_set_tag((struct wl_proxy *)output, &SDL_WAYLAND_output_tag);
}
wl_proxy_set_tag((struct wl_proxy *)output, &SDL_WAYLAND_output_tag);
}
SDL_bool SDL_WAYLAND_own_surface(struct wl_surface *surface)
{
if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) {
return wl_proxy_get_tag((struct wl_proxy *) surface) == &SDL_WAYLAND_surface_tag;
}
return SDL_TRUE; /* For older clients we have to assume this is us... */
return wl_proxy_get_tag((struct wl_proxy *) surface) == &SDL_WAYLAND_surface_tag;
}
SDL_bool SDL_WAYLAND_own_output(struct wl_output *output)
{
if (SDL_WAYLAND_HAVE_WAYLAND_CLIENT_1_18) {
return wl_proxy_get_tag((struct wl_proxy *) output) == &SDL_WAYLAND_output_tag;
}
return SDL_TRUE; /* For older clients we have to assume this is us... */
return wl_proxy_get_tag((struct wl_proxy *) output) == &SDL_WAYLAND_output_tag;
}
static void
@ -283,6 +279,8 @@ Wayland_CreateDevice(int devindex)
device->free = Wayland_DeleteDevice;
device->disable_display_mode_switching = SDL_TRUE;
return device;
}
@ -291,6 +289,155 @@ VideoBootStrap Wayland_bootstrap = {
Wayland_CreateDevice
};
static void
xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output,
int32_t x, int32_t y)
{
SDL_WaylandOutputData* driverdata = data;
driverdata->x = x;
driverdata->y = y;
driverdata->has_logical_position = SDL_TRUE;
}
static void
xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output,
int32_t width, int32_t height)
{
SDL_WaylandOutputData* driverdata = data;
if (driverdata->width != 0 && driverdata->height != 0) {
/* FIXME: GNOME has a bug where the logical size does not account for
* scale, resulting in bogus viewport sizes.
*
* Until this is fixed, validate that _some_ kind of scaling is being
* done (we can't match exactly because fractional scaling can't be
* detected otherwise), then override if necessary.
* -flibit
*/
const float scale = (float) driverdata->width / (float) width;
if ((scale == 1.0f) && (driverdata->scale_factor != 1.0f)) {
SDL_LogWarn(
SDL_LOG_CATEGORY_VIDEO,
"xdg_output scale did not match, overriding with wl_output scale"
);
return;
}
}
driverdata->width = width;
driverdata->height = height;
driverdata->has_logical_size = SDL_TRUE;
}
static void
xdg_output_handle_done(void *data, struct zxdg_output_v1 *xdg_output)
{
SDL_WaylandOutputData* driverdata = data;
/*
* xdg-output.done events are deprecated and only apply below version 3 of the protocol.
* A wl-output.done event will be emitted in version 3 or higher.
*/
if (zxdg_output_v1_get_version(driverdata->xdg_output) < 3) {
display_handle_done(data, driverdata->output);
}
}
static void
xdg_output_handle_name(void *data, struct zxdg_output_v1 *xdg_output,
const char *name)
{
}
static void
xdg_output_handle_description(void *data, struct zxdg_output_v1 *xdg_output,
const char *description)
{
}
static const struct zxdg_output_v1_listener xdg_output_listener = {
xdg_output_handle_logical_position,
xdg_output_handle_logical_size,
xdg_output_handle_done,
xdg_output_handle_name,
xdg_output_handle_description,
};
static void
AddEmulatedModes(SDL_VideoDisplay *dpy, SDL_bool rot_90)
{
struct EmulatedMode
{
int w;
int h;
};
/* Resolution lists courtesy of XWayland */
const struct EmulatedMode mode_list[] = {
/* 16:9 (1.77) */
{ 7680, 4320 },
{ 6144, 3160 },
{ 5120, 2880 },
{ 4096, 2304 },
{ 3840, 2160 },
{ 3200, 1800 },
{ 2880, 1620 },
{ 2560, 1440 },
{ 2048, 1152 },
{ 1920, 1080 },
{ 1600, 900 },
{ 1368, 768 },
{ 1280, 720 },
{ 864, 486 },
/* 16:10 (1.6) */
{ 2560, 1600 },
{ 1920, 1200 },
{ 1680, 1050 },
{ 1440, 900 },
{ 1280, 800 },
/* 3:2 (1.5) */
{ 720, 480 },
/* 4:3 (1.33) */
{ 2048, 1536 },
{ 1920, 1440 },
{ 1600, 1200 },
{ 1440, 1080 },
{ 1400, 1050 },
{ 1280, 1024 },
{ 1280, 960 },
{ 1152, 864 },
{ 1024, 768 },
{ 800, 600 },
{ 640, 480 }
};
int i;
const int native_width = dpy->display_modes->w;
const int native_height = dpy->display_modes->h;
for (i = 0; i < SDL_arraysize(mode_list); ++i) {
/* Only add modes that are smaller than the native mode */
if ((mode_list[i].w < native_width && mode_list[i].h < native_height) ||
(mode_list[i].w < native_width && mode_list[i].h == native_height)) {
SDL_DisplayMode mode = *dpy->display_modes;
if (rot_90) {
mode.w = mode_list[i].h;
mode.h = mode_list[i].w;
} else {
mode.w = mode_list[i].w;
mode.h = mode_list[i].h;
}
SDL_AddDisplayMode(dpy, &mode);
}
}
}
static void
display_handle_geometry(void *data,
struct wl_output *output,
@ -307,7 +454,7 @@ display_handle_geometry(void *data,
SDL_VideoDisplay *display;
int i;
if (driverdata->done) {
if (driverdata->wl_output_done_count) {
/* Clear the wl_output ref so Reset doesn't free it */
display = SDL_GetDisplay(driverdata->index);
for (i = 0; i < display->num_display_modes; i += 1) {
@ -318,11 +465,14 @@ display_handle_geometry(void *data,
SDL_ResetDisplayModes(driverdata->index);
/* The display has officially started over. */
driverdata->done = SDL_FALSE;
driverdata->wl_output_done_count = 0;
}
driverdata->x = x;
driverdata->y = y;
/* Apply the change from wl-output only if xdg-output is not supported */
if (!driverdata->has_logical_position) {
driverdata->x = x;
driverdata->y = y;
}
driverdata->physical_width = physical_width;
driverdata->physical_height = physical_height;
if (driverdata->index == -1) {
@ -369,36 +519,21 @@ display_handle_mode(void *data,
int refresh)
{
SDL_WaylandOutputData* driverdata = data;
SDL_DisplayMode mode;
if (flags & WL_OUTPUT_MODE_CURRENT) {
/* Don't rotate this yet, handle_done will do it later */
driverdata->width = width;
driverdata->height = height;
driverdata->refresh = refresh;
}
driverdata->native_width = width;
driverdata->native_height = height;
/* Note that the width/height are NOT multiplied by scale_factor!
* This is intentional and is designed to get the unscaled modes, which is
* important for high-DPI games intending to use the display mode as the
* target drawable size. The scaled desktop mode will be added at the end
* when display_handle_done is called (see below).
*/
SDL_zero(mode);
mode.format = SDL_PIXELFORMAT_RGB888;
if (driverdata->transform & WL_OUTPUT_TRANSFORM_90) {
mode.w = height;
mode.h = width;
} else {
mode.w = width;
mode.h = height;
}
mode.refresh_rate = (int)SDL_round(refresh / 1000.0); /* mHz to Hz */
mode.driverdata = driverdata->output;
if (driverdata->index > -1) {
SDL_AddDisplayMode(SDL_GetDisplay(driverdata->index), &mode);
} else {
SDL_AddDisplayMode(&driverdata->placeholder, &mode);
/*
* Don't rotate this yet, wl-output coordinates are transformed in
* handle_done and xdg-output coordinates are pre-transformed.
*/
if (!driverdata->has_logical_size) {
driverdata->width = width;
driverdata->height = height;
}
driverdata->refresh = refresh;
}
}
@ -407,20 +542,73 @@ display_handle_done(void *data,
struct wl_output *output)
{
SDL_WaylandOutputData* driverdata = data;
SDL_DisplayMode mode;
SDL_VideoData* video = driverdata->videodata;
SDL_DisplayMode native_mode, desktop_mode;
SDL_VideoDisplay *dpy;
if (driverdata->done)
/*
* When using xdg-output, two wl-output.done events will be emitted:
* one at the completion of wl-display and one at the completion of xdg-output.
*
* All required events must be received before proceeding.
*/
const int event_await_count = 1 + (driverdata->xdg_output != NULL);
driverdata->wl_output_done_count = SDL_min(driverdata->wl_output_done_count + 1, event_await_count + 1);
if (driverdata->wl_output_done_count != event_await_count) {
return;
}
driverdata->done = SDL_TRUE;
/* The native display resolution */
SDL_zero(native_mode);
native_mode.format = SDL_PIXELFORMAT_RGB888;
SDL_zero(mode);
mode.format = SDL_PIXELFORMAT_RGB888;
if (driverdata->transform & WL_OUTPUT_TRANSFORM_90) {
mode.w = driverdata->height / driverdata->scale_factor;
mode.h = driverdata->width / driverdata->scale_factor;
native_mode.w = driverdata->native_height;
native_mode.h = driverdata->native_width;
} else {
native_mode.w = driverdata->native_width;
native_mode.h = driverdata->native_height;
}
native_mode.refresh_rate = (int)SDL_round(driverdata->refresh / 1000.0); /* mHz to Hz */
native_mode.driverdata = driverdata->output;
/* The scaled desktop mode */
SDL_zero(desktop_mode);
desktop_mode.format = SDL_PIXELFORMAT_RGB888;
/* Scale the desktop coordinates, if xdg-output isn't present */
if (!driverdata->has_logical_size) {
driverdata->width /= driverdata->scale_factor;
driverdata->height /= driverdata->scale_factor;
}
/* xdg-output dimensions are already transformed, so no need to rotate. */
if (driverdata->has_logical_size || !(driverdata->transform & WL_OUTPUT_TRANSFORM_90)) {
desktop_mode.w = driverdata->width;
desktop_mode.h = driverdata->height;
} else {
desktop_mode.w = driverdata->height;
desktop_mode.h = driverdata->width;
}
desktop_mode.refresh_rate = (int)SDL_round(driverdata->refresh / 1000.0); /* mHz to Hz */
desktop_mode.driverdata = driverdata->output;
/*
* The native display mode is only exposed separately from the desktop size if:
* the desktop is scaled and the wp_viewporter protocol is supported.
*/
if (driverdata->scale_factor > 1.0f && video->viewporter != NULL) {
if (driverdata->index > -1) {
SDL_AddDisplayMode(SDL_GetDisplay(driverdata->index), &native_mode);
} else {
SDL_AddDisplayMode(&driverdata->placeholder, &native_mode);
}
}
/* Calculate the display DPI */
if (driverdata->transform & WL_OUTPUT_TRANSFORM_90) {
driverdata->hdpi = driverdata->physical_height ?
(((float) driverdata->height) * 25.4f / driverdata->physical_height) :
0.0f;
@ -432,9 +620,6 @@ display_handle_done(void *data,
((float) driverdata->physical_height) / 25.4f,
((float) driverdata->physical_width) / 25.4f);
} else {
mode.w = driverdata->width / driverdata->scale_factor;
mode.h = driverdata->height / driverdata->scale_factor;
driverdata->hdpi = driverdata->physical_width ?
(((float) driverdata->width) * 25.4f / driverdata->physical_width) :
0.0f;
@ -446,8 +631,6 @@ display_handle_done(void *data,
((float) driverdata->physical_width) / 25.4f,
((float) driverdata->physical_height) / 25.4f);
}
mode.refresh_rate = (int)SDL_round(driverdata->refresh / 1000.0); /* mHz to Hz */
mode.driverdata = driverdata->output;
if (driverdata->index > -1) {
dpy = SDL_GetDisplay(driverdata->index);
@ -455,9 +638,14 @@ display_handle_done(void *data,
dpy = &driverdata->placeholder;
}
SDL_AddDisplayMode(dpy, &mode);
SDL_SetCurrentDisplayMode(dpy, &mode);
SDL_SetDesktopDisplayMode(dpy, &mode);
SDL_AddDisplayMode(dpy, &desktop_mode);
SDL_SetCurrentDisplayMode(dpy, &desktop_mode);
SDL_SetDesktopDisplayMode(dpy, &desktop_mode);
/* Add emulated modes if wp_viewporter is supported. */
if (video->viewporter) {
AddEmulatedModes(dpy, (driverdata->transform & WL_OUTPUT_TRANSFORM_90) != 0);
}
if (driverdata->index == -1) {
/* First time getting display info, create the VideoDisplay */
@ -504,11 +692,29 @@ Wayland_add_display(SDL_VideoData *d, uint32_t id)
data->videodata = d;
data->output = output;
data->registry_id = id;
data->scale_factor = 1.0;
data->scale_factor = 1.0f;
data->index = -1;
wl_output_add_listener(output, &output_listener, data);
SDL_WAYLAND_register_output(output);
/* Keep a list of outputs for deferred xdg-output initialization. */
if (d->output_list != NULL) {
SDL_WaylandOutputData *node = (SDL_WaylandOutputData*)d->output_list;
while (node->next != NULL) {
node = (SDL_WaylandOutputData*)node->next;
}
node->next = (struct SDL_WaylandOutputData*)data;
} else {
d->output_list = (struct SDL_WaylandOutputData*)data;
}
if (data->videodata->xdg_output_manager) {
data->xdg_output = zxdg_output_manager_v1_get_xdg_output(data->videodata->xdg_output_manager, output);
zxdg_output_v1_add_listener(data->xdg_output, &xdg_output_listener, data);
}
}
static void
@ -524,6 +730,9 @@ Wayland_free_display(uint32_t id)
data = (SDL_WaylandOutputData *) display->driverdata;
if (data->registry_id == id) {
SDL_DelVideoDisplay(i);
if (data->xdg_output) {
zxdg_output_v1_destroy(data->xdg_output);
}
wl_output_destroy(data->output);
SDL_free(data);
@ -540,6 +749,16 @@ Wayland_free_display(uint32_t id)
}
}
static void
Wayland_init_xdg_output(SDL_VideoData *d)
{
SDL_WaylandOutputData *node;
for (node = d->output_list; node != NULL; node = node->next) {
node->xdg_output = zxdg_output_manager_v1_get_xdg_output(node->videodata->xdg_output_manager, node->output);
zxdg_output_v1_add_listener(node->xdg_output, &xdg_output_listener, node);
}
}
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
static void
windowmanager_hints(void *data, struct qt_windowmanager *qt_windowmanager,
@ -600,7 +819,7 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
} else if (SDL_strcmp(interface, "wl_seat") == 0) {
Wayland_display_add_input(d, id, version);
} else if (SDL_strcmp(interface, "xdg_wm_base") == 0) {
d->shell.xdg = wl_registry_bind(d->registry, id, &xdg_wm_base_interface, 1);
d->shell.xdg = wl_registry_bind(d->registry, id, &xdg_wm_base_interface, SDL_min(version, 3));
xdg_wm_base_add_listener(d->shell.xdg, &shell_listener_xdg, NULL);
} else if (SDL_strcmp(interface, "wl_shm") == 0) {
d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
@ -620,6 +839,17 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
Wayland_add_data_device_manager(d, id, version);
} else if (SDL_strcmp(interface, "zxdg_decoration_manager_v1") == 0) {
d->decoration_manager = wl_registry_bind(d->registry, id, &zxdg_decoration_manager_v1_interface, 1);
} else if (SDL_strcmp(interface, "zwp_tablet_manager_v2") == 0) {
d->tablet_manager = wl_registry_bind(d->registry, id, &zwp_tablet_manager_v2_interface, 1);
if (d->input) {
Wayland_input_add_tablet(d->input, d->tablet_manager);
}
} else if (SDL_strcmp(interface, "zxdg_output_manager_v1") == 0) {
version = SDL_min(version, 3); /* Versions 1 through 3 are supported. */
d->xdg_output_manager = wl_registry_bind(d->registry, id, &zxdg_output_manager_v1_interface, version);
Wayland_init_xdg_output(d);
} else if (SDL_strcmp(interface, "wp_viewporter") == 0) {
d->viewporter = wl_registry_bind(d->registry, id, &wp_viewporter_interface, 1);
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
} else if (SDL_strcmp(interface, "qt_touch_extension") == 0) {
@ -646,6 +876,29 @@ static const struct wl_registry_listener registry_listener = {
display_handle_global,
display_remove_global
};
#ifdef HAVE_LIBDECOR_H
static SDL_bool should_use_libdecor(SDL_VideoData *data)
{
if (!SDL_WAYLAND_HAVE_WAYLAND_LIBDECOR) {
return SDL_FALSE;
}
if (!SDL_GetHintBoolean(SDL_HINT_VIDEO_WAYLAND_ALLOW_LIBDECOR, SDL_TRUE)) {
return SDL_FALSE;
}
if (SDL_GetHintBoolean(SDL_HINT_VIDEO_WAYLAND_PREFER_LIBDECOR, SDL_FALSE)) {
return SDL_TRUE;
}
if (data->decoration_manager) {
return SDL_FALSE;
}
return SDL_TRUE;
}
#endif
int
Wayland_VideoInit(_THIS)
@ -669,14 +922,8 @@ Wayland_VideoInit(_THIS)
#ifdef HAVE_LIBDECOR_H
/* Don't have server-side decorations? Try client-side instead. */
if (!data->decoration_manager && SDL_WAYLAND_HAVE_WAYLAND_LIBDECOR && SDL_GetHintBoolean(SDL_HINT_VIDEO_WAYLAND_ALLOW_LIBDECOR, SDL_TRUE)) {
if (should_use_libdecor(data)) {
data->shell.libdecor = libdecor_new(data->display, &libdecor_interface);
/* If libdecor works, we don't need xdg-shell anymore. */
if (data->shell.libdecor && data->shell.xdg) {
xdg_wm_base_destroy(data->shell.xdg);
data->shell.xdg = NULL;
}
}
#endif
@ -737,6 +984,10 @@ Wayland_VideoQuit(_THIS)
for (i = 0; i < _this->num_displays; ++i) {
SDL_VideoDisplay *display = &_this->displays[i];
if (((SDL_WaylandOutputData*)display->driverdata)->xdg_output) {
zxdg_output_v1_destroy(((SDL_WaylandOutputData*)display->driverdata)->xdg_output);
}
wl_output_destroy(((SDL_WaylandOutputData*)display->driverdata)->output);
SDL_free(display->driverdata);
display->driverdata = NULL;
@ -779,6 +1030,9 @@ Wayland_VideoQuit(_THIS)
Wayland_touch_destroy(data);
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
if (data->tablet_manager)
zwp_tablet_manager_v2_destroy((struct zwp_tablet_manager_v2*)data->tablet_manager);
if (data->data_device_manager)
wl_data_device_manager_destroy(data->data_device_manager);
@ -798,6 +1052,14 @@ Wayland_VideoQuit(_THIS)
}
#endif
if (data->xdg_output_manager) {
zxdg_output_manager_v1_destroy(data->xdg_output_manager);
}
if (data->viewporter) {
wp_viewporter_destroy(data->viewporter);
}
if (data->compositor)
wl_compositor_destroy(data->compositor);

View file

@ -34,6 +34,7 @@
struct xkb_context;
struct SDL_WaylandInput;
struct SDL_WaylandTabletManager;
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
struct SDL_WaylandTouch;
@ -46,6 +47,8 @@ typedef struct {
int size;
} SDL_WaylandCursorTheme;
typedef struct SDL_WaylandOutputData SDL_WaylandOutputData;
typedef struct {
SDL_bool initializing;
struct wl_display *display;
@ -70,6 +73,8 @@ typedef struct {
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager;
struct xdg_activation_v1 *activation_manager;
struct zwp_text_input_manager_v3 *text_input_manager;
struct zxdg_output_manager_v1 *xdg_output_manager;
struct wp_viewporter *viewporter;
EGLDisplay edpy;
EGLContext context;
@ -77,6 +82,8 @@ typedef struct {
struct xkb_context *xkb_context;
struct SDL_WaylandInput *input;
struct SDL_WaylandTabletManager *tablet_manager;
SDL_WaylandOutputData *output_list;
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
struct SDL_WaylandTouch *touch;
@ -89,19 +96,23 @@ typedef struct {
int relative_mouse_mode;
} SDL_VideoData;
typedef struct {
struct SDL_WaylandOutputData {
SDL_VideoData *videodata;
struct wl_output *output;
struct zxdg_output_v1 *xdg_output;
uint32_t registry_id;
float scale_factor;
int native_width, native_height;
int x, y, width, height, refresh, transform;
SDL_DisplayOrientation orientation;
int physical_width, physical_height;
float ddpi, hdpi, vdpi;
SDL_bool has_logical_position, has_logical_size;
int index;
SDL_VideoDisplay placeholder;
SDL_bool done;
} SDL_WaylandOutputData;
int wl_output_done_count;
SDL_WaylandOutputData *next;
};
/* Needed here to get wl_surface declaration, fixes GitHub#4594 */
#include "SDL_waylanddyn.h"

View file

@ -139,11 +139,11 @@ void Wayland_Vulkan_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h)
data = (SDL_WindowData *) window->driverdata;
if (w) {
*w = window->w * data->scale_factor;
*w = data->drawable_width;
}
if (h) {
*h = window->h * data->scale_factor;
*h = data->drawable_height;
}
}
}

View file

@ -25,22 +25,294 @@
#include "../SDL_sysvideo.h"
#include "../../events/SDL_windowevents_c.h"
#include "../../events/SDL_mouse_c.h"
#include "../SDL_egl_c.h"
#include "SDL_waylandevents_c.h"
#include "SDL_waylandwindow.h"
#include "SDL_waylandvideo.h"
#include "SDL_waylandtouch.h"
#include "SDL_hints.h"
#include "SDL_events.h"
#include "xdg-shell-client-protocol.h"
#include "xdg-decoration-unstable-v1-client-protocol.h"
#include "idle-inhibit-unstable-v1-client-protocol.h"
#include "xdg-activation-v1-client-protocol.h"
#include "viewporter-client-protocol.h"
#ifdef HAVE_LIBDECOR_H
#include <libdecor.h>
#endif
static void
GetFullScreenDimensions(SDL_Window *window, int *width, int *height, int *drawable_width, int *drawable_height)
{
SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata;
int fs_width, fs_height;
int buf_width, buf_height;
/*
* Fullscreen desktop mandates a desktop sized window, so that's what applications will get.
* If the application is DPI aware, it will need to handle the transformations between the
* differently sized window and backbuffer spaces on its own.
*/
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
fs_width = output->width;
fs_height = output->height;
/* If the application is DPI aware, we can expose the true backbuffer size */
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
buf_width = output->native_width;
buf_height = output->native_height;
} else {
buf_width = fs_width;
buf_height = fs_height;
}
} else {
/*
* If a mode was set, use it, otherwise use the native resolution
* for DPI aware apps and the desktop size for legacy apps.
*/
if (window->fullscreen_mode.w != 0 && window->fullscreen_mode.h != 0) {
fs_width = window->fullscreen_mode.w;
fs_height = window->fullscreen_mode.h;
} else if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
fs_width = output->native_width;
fs_height = output->native_height;
} else {
fs_width = output->width;
fs_height = output->height;
}
buf_width = fs_width;
buf_height = fs_height;
}
if (width) {
*width = fs_width;
}
if (height) {
*height = fs_height;
}
if (drawable_width) {
*drawable_width = buf_width;
}
if (drawable_height) {
*drawable_height = buf_height;
}
}
static inline SDL_bool
DesktopIsScaled(SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
return data->scale_factor != 1.0f;
}
static inline SDL_bool
DesktopIsFractionalScaled(SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata;
if ((output->native_width != (int)(output->width * data->scale_factor) ||
output->native_height != (int)(output->height * data->scale_factor))) {
return SDL_TRUE;
}
return SDL_FALSE;
}
static SDL_bool
NeedFullscreenViewport(SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
SDL_VideoData *video = data->waylandData;
SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata;
int fs_width, fs_height;
GetFullScreenDimensions(window, &fs_width, &fs_height, NULL, NULL);
/*
* Fullscreen needs a viewport:
* - If the desktop uses fractional scaling
* - Fullscreen desktop was not requested OR the window is DPI aware
*
* - The desktop uses non-fractional scaling
* - Fullscreen desktop was NOT requested
*
* - The desktop is not scaled
* - A non-native fullscreen mode was explicitly set by the client
*/
if (video->viewporter != NULL && (window->flags & SDL_WINDOW_FULLSCREEN)) {
if (DesktopIsFractionalScaled(window)) {
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP ||
(window->flags & SDL_WINDOW_ALLOW_HIGHDPI)) {
return SDL_TRUE;
}
} else if (DesktopIsScaled(window)) {
if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
return SDL_TRUE;
}
} else if (fs_width != output->native_width && fs_height != output->native_height) {
return SDL_TRUE;
}
}
return SDL_FALSE;
}
static inline SDL_bool
NeedWindowedViewport(SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
SDL_VideoData *video = data->waylandData;
return !(window->flags & SDL_WINDOW_FULLSCREEN) && (video->viewporter != NULL) &&
DesktopIsFractionalScaled(window) && (window->flags & SDL_WINDOW_ALLOW_HIGHDPI);
}
/* Never set a fullscreen window size larger than the desktop. */
SDL_FORCE_INLINE int
GetWindowWidth(SDL_Window *window)
{
return NeedFullscreenViewport(window) ? ((SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata)->width : window->w;
}
SDL_FORCE_INLINE int
GetWindowHeight(SDL_Window *window)
{
return NeedFullscreenViewport(window) ? ((SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata)->height : window->h;
}
static void
GetWindowBufferSize(SDL_Window *window, int *width, int *height)
{
SDL_WindowData *data = window->driverdata;
SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata;
int buf_width;
int buf_height;
if (NeedWindowedViewport(window)) {
const float frac_scale_x = (float)output->native_width / (float)output->width;
const float frac_scale_y = (float)output->native_height / (float)output->height;
buf_width = (int)SDL_lroundf(window->w * frac_scale_x);
buf_height = (int)SDL_lroundf(window->h * frac_scale_y);
} else { /* Windowed or fullscreen with no viewport */
buf_width = window->w * data->scale_factor;
buf_height = window->h * data->scale_factor;
}
if (width) {
*width = buf_width;
}
if (height) {
*height = buf_height;
}
}
static void
SetViewport(SDL_Window *window, int src_width, int src_height, int dst_width, int dst_height)
{
SDL_WindowData *wind = window->driverdata;
SDL_VideoData *video = wind->waylandData;
if (video->viewporter) {
if (wind->viewport == NULL) {
wind->viewport = wp_viewporter_get_viewport(video->viewporter, wind->surface);
}
wp_viewport_set_source(wind->viewport, wl_fixed_from_int(0), wl_fixed_from_int(0), wl_fixed_from_int(src_width), wl_fixed_from_int(src_height));
wp_viewport_set_destination(wind->viewport, dst_width, dst_height);
}
}
static void
UnsetViewport(SDL_Window *window)
{
SDL_WindowData *wind = window->driverdata;
if (wind->viewport) {
wp_viewport_destroy(wind->viewport);
wind->viewport = NULL;
}
}
static void
ConfigureViewport(SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
SDL_VideoData *viddata = data->waylandData;
SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata;
if (NeedFullscreenViewport(window)) {
int fs_width, fs_height;
int src_width, src_height;
GetFullScreenDimensions(window, &fs_width, &fs_height, &src_width, &src_height);
SetViewport(window, src_width, src_height, output->width, output->height);
data->damage_region.x = 0;
data->damage_region.y = 0;
data->damage_region.w = output->width;
data->damage_region.h = output->height;
data->pointer_scale_x = (float)fs_width / (float)output->width;
data->pointer_scale_y = (float)fs_height / (float)output->height;
} else {
if (NeedWindowedViewport(window)) {
int src_width, src_height;
GetWindowBufferSize(window, &src_width, &src_height);
SetViewport(window, src_width, src_height, window->w, window->h);
} else {
UnsetViewport(window);
}
SDL_zero(data->damage_region);
data->pointer_scale_x = 1.0f;
data->pointer_scale_y = 1.0f;
}
/*
* If mouse_rect is not empty, re-create the confinement region with the new scale value.
* If the pointer is locked to the general surface with unspecified coordinates, it will
* be confined to the viewport region, so no update is required.
*/
if (!SDL_RectEmpty(&window->mouse_rect)) {
Wayland_input_confine_pointer(viddata->input, window);
}
}
static void
SetDrawScale(SDL_Window *window)
{
SDL_WindowData *data = window->driverdata;
if (NeedFullscreenViewport(window)) {
int fs_width, fs_height;
GetFullScreenDimensions(window, &fs_width, &fs_height, &data->drawable_width, &data->drawable_height);
/* Set the buffer scale to 1 since a viewport will be used. */
wl_surface_set_buffer_scale(data->surface, 1);
} else {
GetWindowBufferSize(window, &data->drawable_width, &data->drawable_height);
if (NeedWindowedViewport(window)) {
/* Set the buffer scale to 1 since a viewport will be used. */
wl_surface_set_buffer_scale(data->surface, 1);
} else {
wl_surface_set_buffer_scale(data->surface, (int32_t)data->scale_factor);
}
}
}
static void
SetMinMaxDimensions(SDL_Window *window, SDL_bool commit)
{
@ -48,6 +320,15 @@ SetMinMaxDimensions(SDL_Window *window, SDL_bool commit)
SDL_VideoData *viddata = wind->waylandData;
int min_width, min_height, max_width, max_height;
/* Pop-ups don't get to change size */
if (WINDOW_IS_XDG_POPUP(window)) {
/* ... but we still want to commit, particularly for ShowWindow */
if (commit) {
wl_surface_commit(wind->surface);
}
return;
}
if (window->flags & SDL_WINDOW_FULLSCREEN) {
min_width = 0;
min_height = 0;
@ -66,7 +347,7 @@ SetMinMaxDimensions(SDL_Window *window, SDL_bool commit)
}
#ifdef HAVE_LIBDECOR_H
if (viddata->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(viddata, window)) {
if (wind->shell_surface.libdecor.frame == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
}
@ -100,13 +381,22 @@ SetFullscreen(SDL_Window *window, struct wl_output *output, SDL_bool commit)
SDL_WindowData *wind = window->driverdata;
SDL_VideoData *viddata = wind->waylandData;
/* Pop-ups don't get to be fullscreened */
if (WINDOW_IS_XDG_POPUP(window)) {
/* ... but we still want to commit, particularly for ShowWindow */
if (commit) {
wl_surface_commit(wind->surface);
}
return;
}
/* The desktop may try to enforce min/max sizes here, so turn them off for
* fullscreen and on (if applicable) for windowed
*/
SetMinMaxDimensions(window, SDL_FALSE);
#ifdef HAVE_LIBDECOR_H
if (viddata->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(viddata, window)) {
if (wind->shell_surface.libdecor.frame == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
}
@ -150,6 +440,11 @@ handle_surface_frame_done(void *data, struct wl_callback *cb, uint32_t time)
SDL_WindowData *wind = (SDL_WindowData *) data;
SDL_AtomicSet(&wind->swap_interval_ready, 1); /* mark window as ready to present again. */
if (!SDL_RectEmpty(&wind->damage_region)) {
wl_surface_damage(wind->surface, wind->damage_region.x, wind->damage_region.y,
wind->damage_region.w, wind->damage_region.h);
}
/* reset this callback to fire again once a new frame was presented and compositor wants the next one. */
wind->frame_callback = wl_surface_frame(wind->frame_surface_wrapper);
wl_callback_destroy(cb);
@ -303,9 +598,14 @@ handle_configure_xdg_toplevel(void *data,
* UPDATE: Nope, sure enough a compositor sends 0,0. This is a known bug:
* https://bugs.kde.org/show_bug.cgi?id=444962
*/
if (width != 0 && height != 0 && (window->w != width || window->h != height)) {
window->w = width;
window->h = height;
if (!NeedFullscreenViewport(window)) {
if (width != 0 && height != 0 && (window->w != width || window->h != height)) {
window->w = width;
window->h = height;
wind->needs_resize_event = SDL_TRUE;
}
} else {
GetFullScreenDimensions(window, &window->w, &window->h, NULL, NULL);
wind->needs_resize_event = SDL_TRUE;
}
@ -329,6 +629,60 @@ static const struct xdg_toplevel_listener toplevel_listener_xdg = {
handle_close_xdg_toplevel
};
static void
handle_configure_xdg_popup(void *data,
struct xdg_popup *xdg_popup,
int32_t x,
int32_t y,
int32_t width,
int32_t height)
{
/* No-op, we don't use x/y and width/height are fixed-size */
}
static void
handle_done_xdg_popup(void *data, struct xdg_popup *xdg_popup)
{
SDL_WindowData *window = (SDL_WindowData *)data;
SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
}
static void
handle_repositioned_xdg_popup(void *data,
struct xdg_popup *xdg_popup,
uint32_t token)
{
/* No-op, configure does all the work we care about */
}
static const struct xdg_popup_listener popup_listener_xdg = {
handle_configure_xdg_popup,
handle_done_xdg_popup,
handle_repositioned_xdg_popup
};
#define TOOLTIP_CURSOR_OFFSET 8 /* FIXME: Arbitrary, eyeballed from X tooltip */
static int
Wayland_PopupWatch(void *data, SDL_Event *event)
{
if (event->type == SDL_MOUSEMOTION) {
SDL_Window *window = (SDL_Window *) data;
SDL_WindowData *wind = window->driverdata;
/* Coordinates might be relative to the popup, which we don't want */
if (event->motion.windowID == wind->shell_surface.xdg.roleobj.popup.parentID) {
xdg_positioner_set_offset(wind->shell_surface.xdg.roleobj.popup.positioner,
event->motion.x + TOOLTIP_CURSOR_OFFSET,
event->motion.y + TOOLTIP_CURSOR_OFFSET);
xdg_popup_reposition(wind->shell_surface.xdg.roleobj.popup.popup,
wind->shell_surface.xdg.roleobj.popup.positioner,
0);
}
}
return 1;
}
#ifdef HAVE_LIBDECOR_H
static void
decoration_frame_configure(struct libdecor_frame *frame,
@ -399,17 +753,23 @@ decoration_frame_configure(struct libdecor_frame *frame,
* Always assume the configure is wrong.
*/
if (fullscreen) {
/* FIXME: We have been explicitly told to respect the fullscreen size
* parameters here, even though they are known to be wrong on GNOME at
* bare minimum. If this is wrong, don't blame us, we were explicitly
* told to do this.
*/
if (!libdecor_configuration_get_content_size(configuration, frame,
&width, &height)) {
width = window->w;
height = window->h;
if (!NeedFullscreenViewport(window)) {
/* FIXME: We have been explicitly told to respect the fullscreen size
* parameters here, even though they are known to be wrong on GNOME at
* bare minimum. If this is wrong, don't blame us, we were explicitly
* told to do this.
*/
if (!libdecor_configuration_get_content_size(configuration, frame,
&width, &height)) {
width = window->w;
height = window->h;
}
} else {
GetFullScreenDimensions(window, &width, &height, NULL, NULL);
}
wind->needs_resize_event = SDL_TRUE;
/* This part is good though. */
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
scale_factor = driverdata->scale_factor;
@ -445,7 +805,7 @@ decoration_frame_configure(struct libdecor_frame *frame,
wind->shell_surface.libdecor.initial_configure_seen = SDL_TRUE;
/* ... then commit the changes on the libdecor side. */
state = libdecor_state_new(width, height);
state = libdecor_state_new(GetWindowWidth(window), GetWindowHeight(window));
libdecor_frame_commit(frame, state, configuration);
libdecor_state_free(state);
@ -554,9 +914,28 @@ Wayland_move_window(SDL_Window *window,
int i, numdisplays = SDL_GetNumVideoDisplays();
for (i = 0; i < numdisplays; i += 1) {
if (SDL_GetDisplay(i)->driverdata == driverdata) {
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED,
SDL_WINDOWPOS_CENTERED_DISPLAY(i),
SDL_WINDOWPOS_CENTERED_DISPLAY(i));
/* We want to send a very very specific combination here:
*
* 1. A coordinate that tells the application what display we're on
* 2. Exactly (0, 0)
*
* Part 1 is useful information but is also really important for
* ensuring we end up on the right display for fullscreen, while
* part 2 is important because numerous applications use a specific
* combination of GetWindowPosition and GetGlobalMouseState, and of
* course neither are supported by Wayland. Since global mouse will
* fall back to just GetMouseState, we need the window position to
* be zero so the cursor math works without it going off in some
* random direction. See UE5 Editor for a notable example of this!
*
* This may be an issue some day if we're ever able to implement
* SDL_GetDisplayUsableBounds!
*
* -flibit
*/
SDL_Rect bounds;
SDL_GetDisplayBounds(i, &bounds);
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, bounds.x, bounds.y);
break;
}
}
@ -624,6 +1003,19 @@ static const struct wl_surface_listener surface_listener = {
handle_surface_leave
};
static void
Wayland_FillEmptyShellInfo(SDL_SysWMinfo * info, const Uint32 version)
{
info->info.wl.xdg_surface = NULL;
if (version >= SDL_VERSIONNUM(2, 0, 17)) {
info->info.wl.xdg_toplevel = NULL;
if (version >= SDL_VERSIONNUM(2, 0, 22)) {
info->info.wl.xdg_popup = NULL;
info->info.wl.xdg_positioner = NULL;
}
}
}
SDL_bool
Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
{
@ -656,23 +1048,40 @@ Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
info->info.wl.egl_window = data->egl_window;
#ifdef HAVE_LIBDECOR_H
if (viddata->shell.libdecor && data->shell_surface.libdecor.frame != NULL) {
info->info.wl.xdg_surface = libdecor_frame_get_xdg_surface(data->shell_surface.libdecor.frame);
if (version >= SDL_VERSIONNUM(2, 0, 17)) {
info->info.wl.xdg_toplevel = libdecor_frame_get_xdg_toplevel(data->shell_surface.libdecor.frame);
if (WINDOW_IS_LIBDECOR(viddata, window)) {
if (data->shell_surface.libdecor.frame != NULL) {
info->info.wl.xdg_surface = libdecor_frame_get_xdg_surface(data->shell_surface.libdecor.frame);
if (version >= SDL_VERSIONNUM(2, 0, 17)) {
info->info.wl.xdg_toplevel = libdecor_frame_get_xdg_toplevel(data->shell_surface.libdecor.frame);
if (version >= SDL_VERSIONNUM(2, 0, 22)) {
info->info.wl.xdg_popup = NULL;
info->info.wl.xdg_positioner = NULL;
}
}
} else {
/* Not mapped yet */
Wayland_FillEmptyShellInfo(info, version);
}
} else
#endif
if (viddata->shell.xdg && data->shell_surface.xdg.surface != NULL) {
info->info.wl.xdg_surface = data->shell_surface.xdg.surface;
if (version >= SDL_VERSIONNUM(2, 0, 17)) {
info->info.wl.xdg_toplevel = data->shell_surface.xdg.roleobj.toplevel;
SDL_bool popup = WINDOW_IS_XDG_POPUP(window);
info->info.wl.xdg_toplevel = popup ? NULL : data->shell_surface.xdg.roleobj.toplevel;
if (version >= SDL_VERSIONNUM(2, 0, 22)) {
if (popup) {
info->info.wl.xdg_popup = data->shell_surface.xdg.roleobj.popup.popup;
info->info.wl.xdg_positioner = data->shell_surface.xdg.roleobj.popup.positioner;
} else {
info->info.wl.xdg_popup = NULL;
info->info.wl.xdg_positioner = NULL;
}
}
}
} else {
info->info.wl.xdg_surface = NULL;
if (version >= SDL_VERSIONNUM(2, 0, 17)) {
info->info.wl.xdg_toplevel = NULL;
}
/* Either it's not mapped yet or we don't have a shell protocol */
Wayland_FillEmptyShellInfo(info, version);
}
}
@ -697,6 +1106,10 @@ Wayland_SetWindowModalFor(_THIS, SDL_Window *modal_window, SDL_Window *parent_wi
SDL_WindowData *modal_data = modal_window->driverdata;
SDL_WindowData *parent_data = parent_window->driverdata;
if (WINDOW_IS_XDG_POPUP(modal_window) || WINDOW_IS_XDG_POPUP(parent_window)) {
return SDL_SetError("Modal/Parent was a popup, not a toplevel");
}
#ifdef HAVE_LIBDECOR_H
if (viddata->shell.libdecor) {
if (modal_data->shell_surface.libdecor.frame == NULL) {
@ -731,9 +1144,26 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window)
SDL_VideoData *c = _this->driverdata;
SDL_WindowData *data = window->driverdata;
/* Create the shell surface and map the toplevel */
/* Detach any previous buffers before resetting everything, otherwise when
* calling this a second time you'll get an annoying protocol error!
*
* FIXME: This was originally moved to HideWindow, which _should_ make
* sense, but for whatever reason UE5's popups require that this actually
* be in both places at once? Possibly from renderers making commits? I can't
* fully remember if this location caused crashes or if I was fixing a pair
* of Hide/Show calls. In any case, UE gives us a pretty good test and having
* both detach calls passes. This bug may be relevant if I'm wrong:
*
* https://bugs.kde.org/show_bug.cgi?id=448856
*
* -flibit
*/
wl_surface_attach(data->surface, NULL, 0, 0);
wl_surface_commit(data->surface);
/* Create the shell surface and map the toplevel/popup */
#ifdef HAVE_LIBDECOR_H
if (c->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(c, window)) {
data->shell_surface.libdecor.frame = libdecor_decorate(c->shell.libdecor,
data->surface,
&libdecor_frame_interface,
@ -751,10 +1181,42 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window)
xdg_surface_set_user_data(data->shell_surface.xdg.surface, data);
xdg_surface_add_listener(data->shell_surface.xdg.surface, &shell_surface_listener_xdg, data);
/* !!! FIXME: add popup role */
data->shell_surface.xdg.roleobj.toplevel = xdg_surface_get_toplevel(data->shell_surface.xdg.surface);
xdg_toplevel_set_app_id(data->shell_surface.xdg.roleobj.toplevel, c->classname);
xdg_toplevel_add_listener(data->shell_surface.xdg.roleobj.toplevel, &toplevel_listener_xdg, data);
if (WINDOW_IS_XDG_POPUP(window)) {
SDL_Mouse *mouse = SDL_GetMouse();
SDL_Window *focused = SDL_GetMouseFocus();
SDL_WindowData *focuseddata = focused->driverdata;
/* This popup may be a child of another popup! */
data->shell_surface.xdg.roleobj.popup.parentID = SDL_GetWindowID(focused);
data->shell_surface.xdg.roleobj.popup.child = NULL;
if (WINDOW_IS_XDG_POPUP(focused)) {
SDL_assert(focuseddata->shell_surface.xdg.roleobj.popup.child == NULL);
focuseddata->shell_surface.xdg.roleobj.popup.child = window;
}
/* Set up the positioner for the popup */
data->shell_surface.xdg.roleobj.popup.positioner = xdg_wm_base_create_positioner(c->shell.xdg);
xdg_positioner_set_offset(data->shell_surface.xdg.roleobj.popup.positioner,
mouse->x + TOOLTIP_CURSOR_OFFSET,
mouse->y + TOOLTIP_CURSOR_OFFSET);
/* Assign the popup role */
data->shell_surface.xdg.roleobj.popup.popup = xdg_surface_get_popup(data->shell_surface.xdg.surface,
focuseddata->shell_surface.xdg.surface,
data->shell_surface.xdg.roleobj.popup.positioner);
xdg_popup_add_listener(data->shell_surface.xdg.roleobj.popup.popup, &popup_listener_xdg, data);
/* For tooltips, track mouse motion so it follows the cursor */
if (window->flags & SDL_WINDOW_TOOLTIP) {
if (xdg_popup_get_version(data->shell_surface.xdg.roleobj.popup.popup) >= 3) {
SDL_AddEventWatch(Wayland_PopupWatch, window);
}
}
} else {
data->shell_surface.xdg.roleobj.toplevel = xdg_surface_get_toplevel(data->shell_surface.xdg.surface);
xdg_toplevel_set_app_id(data->shell_surface.xdg.roleobj.toplevel, c->classname);
xdg_toplevel_add_listener(data->shell_surface.xdg.roleobj.toplevel, &toplevel_listener_xdg, data);
}
}
/* Restore state that was set prior to this call */
@ -770,7 +1232,7 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window)
* this surface will fail. This is a new rule for xdg_shell.
*/
#ifdef HAVE_LIBDECOR_H
if (c->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(c, window)) {
if (data->shell_surface.libdecor.frame) {
while (!data->shell_surface.libdecor.initial_configure_seen) {
WAYLAND_wl_display_flush(c->display);
@ -794,7 +1256,7 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window)
}
/* Create the window decorations */
if (data->shell_surface.xdg.roleobj.toplevel && c->decoration_manager) {
if (!WINDOW_IS_XDG_POPUP(window) && data->shell_surface.xdg.roleobj.toplevel && c->decoration_manager) {
data->server_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(c->decoration_manager, data->shell_surface.xdg.roleobj.toplevel);
}
} else {
@ -807,11 +1269,11 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window)
* them immediately afterward.
*/
#ifdef HAVE_LIBDECOR_H
if (c->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(c, window)) {
/* ... but don't call it redundantly for libdecor, the decorator
* may not interpret a redundant call nicely and cause weird stuff to happen
*/
if (window->flags & SDL_WINDOW_BORDERLESS) {
if (data->shell_surface.libdecor.frame && window->flags & SDL_WINDOW_BORDERLESS) {
Wayland_SetWindowBordered(_this, window, SDL_FALSE);
}
} else
@ -837,6 +1299,42 @@ void Wayland_ShowWindow(_THIS, SDL_Window *window)
}
}
static void
Wayland_ReleasePopup(_THIS, SDL_Window *popup)
{
SDL_WindowData *popupdata;
/* Basic sanity checks to weed out the weird popup closures */
if (popup == NULL || popup->magic != &_this->window_magic) {
return;
}
popupdata = popup->driverdata;
if (popupdata == NULL) {
return;
}
/* This may already be freed by a parent popup! */
if (popupdata->shell_surface.xdg.roleobj.popup.popup == NULL) {
return;
}
/* Release the child _first_, otherwise a protocol error triggers */
if (popupdata->shell_surface.xdg.roleobj.popup.child != NULL) {
Wayland_ReleasePopup(_this, popupdata->shell_surface.xdg.roleobj.popup.child);
popupdata->shell_surface.xdg.roleobj.popup.child = NULL;
}
if (popup->flags & SDL_WINDOW_TOOLTIP) {
if (xdg_popup_get_version(popupdata->shell_surface.xdg.roleobj.popup.popup) >= 3) {
SDL_DelEventWatch(Wayland_PopupWatch, popup);
}
}
xdg_popup_destroy(popupdata->shell_surface.xdg.roleobj.popup.popup);
xdg_positioner_destroy(popupdata->shell_surface.xdg.roleobj.popup.positioner);
popupdata->shell_surface.xdg.roleobj.popup.popup = NULL;
popupdata->shell_surface.xdg.roleobj.popup.positioner = NULL;
}
void Wayland_HideWindow(_THIS, SDL_Window *window)
{
SDL_VideoData *data = _this->driverdata;
@ -848,7 +1346,7 @@ void Wayland_HideWindow(_THIS, SDL_Window *window)
}
#ifdef HAVE_LIBDECOR_H
if (data->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(data, window)) {
if (wind->shell_surface.libdecor.frame) {
libdecor_frame_unref(wind->shell_surface.libdecor.frame);
wind->shell_surface.libdecor.frame = NULL;
@ -856,7 +1354,9 @@ void Wayland_HideWindow(_THIS, SDL_Window *window)
} else
#endif
if (data->shell.xdg) {
if (wind->shell_surface.xdg.roleobj.toplevel) {
if (WINDOW_IS_XDG_POPUP(window)) {
Wayland_ReleasePopup(_this, window);
} else if (wind->shell_surface.xdg.roleobj.toplevel) {
xdg_toplevel_destroy(wind->shell_surface.xdg.roleobj.toplevel);
wind->shell_surface.xdg.roleobj.toplevel = NULL;
}
@ -1073,13 +1573,17 @@ Wayland_RestoreWindow(_THIS, SDL_Window * window)
SDL_WindowData *wind = window->driverdata;
SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
if (WINDOW_IS_XDG_POPUP(window)) {
return;
}
/* Set this flag now even if we never actually maximized, eventually
* ShowWindow will take care of it along with the other window state.
*/
window->flags &= ~SDL_WINDOW_MAXIMIZED;
#ifdef HAVE_LIBDECOR_H
if (viddata->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(viddata, window)) {
if (wind->shell_surface.libdecor.frame == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
}
@ -1102,8 +1606,13 @@ Wayland_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
{
SDL_WindowData *wind = window->driverdata;
const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
if (WINDOW_IS_XDG_POPUP(window)) {
return;
}
#ifdef HAVE_LIBDECOR_H
if (viddata->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(viddata, window)) {
if (wind->shell_surface.libdecor.frame) {
libdecor_frame_set_visibility(wind->shell_surface.libdecor.frame, bordered);
}
@ -1122,7 +1631,7 @@ Wayland_SetWindowResizable(_THIS, SDL_Window * window, SDL_bool resizable)
SDL_VideoData *data = _this->driverdata;
const SDL_WindowData *wind = window->driverdata;
if (data->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(data, window)) {
if (wind->shell_surface.libdecor.frame == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
}
@ -1144,6 +1653,10 @@ Wayland_MaximizeWindow(_THIS, SDL_Window * window)
SDL_WindowData *wind = window->driverdata;
SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
if (WINDOW_IS_XDG_POPUP(window)) {
return;
}
if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
return;
}
@ -1154,7 +1667,7 @@ Wayland_MaximizeWindow(_THIS, SDL_Window * window)
window->flags |= SDL_WINDOW_MAXIMIZED;
#ifdef HAVE_LIBDECOR_H
if (viddata->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(viddata, window)) {
if (wind->shell_surface.libdecor.frame == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
}
@ -1177,8 +1690,12 @@ Wayland_MinimizeWindow(_THIS, SDL_Window * window)
SDL_WindowData *wind = window->driverdata;
SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
if (WINDOW_IS_XDG_POPUP(window)) {
return;
}
#ifdef HAVE_LIBDECOR_H
if (viddata->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(viddata, window)) {
if (wind->shell_surface.libdecor.frame == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
}
@ -1269,7 +1786,9 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window)
data->waylandData = c;
data->sdlwindow = window;
data->scale_factor = 1.0;
data->scale_factor = 1.0f;
data->pointer_scale_x = 1.0f;
data->pointer_scale_y = 1.0f;
if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) {
int i;
@ -1316,16 +1835,18 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window)
}
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
data->drawable_width = window->w * data->scale_factor;
data->drawable_height = window->h * data->scale_factor;
if (window->flags & SDL_WINDOW_OPENGL) {
data->egl_window = WAYLAND_wl_egl_window_create(data->surface,
window->w * data->scale_factor, window->h * data->scale_factor);
data->egl_window = WAYLAND_wl_egl_window_create(data->surface, data->drawable_width, data->drawable_height);
#if SDL_VIDEO_OPENGL_EGL
/* Create the GLES window surface */
data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->egl_window);
if (data->egl_surface == EGL_NO_SURFACE) {
return SDL_SetError("failed to create an EGL window surface");
return -1; /* SDL_EGL_CreateSurface should have set error */
}
#endif
}
@ -1375,12 +1896,13 @@ Wayland_HandleResize(SDL_Window *window, int width, int height, float scale)
data->needs_resize_event = SDL_FALSE;
}
wl_surface_set_buffer_scale(data->surface, data->scale_factor);
/* Configure the backbuffer size and scale factors */
SetDrawScale(window);
if (data->egl_window) {
WAYLAND_wl_egl_window_resize(data->egl_window,
window->w * data->scale_factor,
window->h * data->scale_factor,
data->drawable_width,
data->drawable_height,
0, 0);
}
@ -1394,9 +1916,18 @@ Wayland_HandleResize(SDL_Window *window, int width, int height, float scale)
* It doesn't fix the first frames after resize being glitched visually,
* but at least lets us not be terminated by the compositor.
* Can be removed once SDL's resize logic becomes compliant. */
if (viddata->shell.xdg && data->shell_surface.xdg.surface) {
xdg_surface_set_window_geometry(data->shell_surface.xdg.surface, 0, 0, window->w, window->h);
if (
#ifdef HAVE_LIBDECOR_H
!WINDOW_IS_LIBDECOR(viddata, window) &&
#endif
viddata->shell.xdg &&
data->shell_surface.xdg.surface) {
xdg_surface_set_window_geometry(data->shell_surface.xdg.surface, 0, 0,
GetWindowWidth(window), GetWindowHeight(window));
}
/* Update the viewport */
ConfigureViewport(window);
}
void
@ -1422,7 +1953,7 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window)
#ifdef HAVE_LIBDECOR_H
/* we must not resize the window while we have a static (non-floating) size */
if (data->shell.libdecor &&
if (WINDOW_IS_LIBDECOR(data, window) &&
wind->shell_surface.libdecor.frame &&
!libdecor_frame_is_floating(wind->shell_surface.libdecor.frame)) {
/* Commit the resize when we re-enter floating state */
@ -1431,18 +1962,18 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window)
}
#endif
wl_surface_set_buffer_scale(wind->surface, wind->scale_factor);
SetDrawScale(window);
if (wind->egl_window) {
WAYLAND_wl_egl_window_resize(wind->egl_window,
window->w * wind->scale_factor,
window->h * wind->scale_factor,
wind->drawable_width,
wind->drawable_height,
0, 0);
}
#ifdef HAVE_LIBDECOR_H
if (data->shell.libdecor && wind->shell_surface.libdecor.frame) {
state = libdecor_state_new(window->w, window->h);
if (WINDOW_IS_LIBDECOR(data, window) && wind->shell_surface.libdecor.frame) {
state = libdecor_state_new(GetWindowWidth(window), GetWindowHeight(window));
libdecor_frame_commit(wind->shell_surface.libdecor.frame, state, NULL);
libdecor_state_free(state);
}
@ -1458,8 +1989,14 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window)
wl_region_destroy(region);
/* Update the geometry which may have been set by a hack in Wayland_HandleResize */
if (data->shell.xdg && wind->shell_surface.xdg.surface) {
xdg_surface_set_window_geometry(wind->shell_surface.xdg.surface, 0, 0, window->w, window->h);
if (
#ifdef HAVE_LIBDECOR_H
!WINDOW_IS_LIBDECOR(data, window) &&
#endif
data->shell.xdg &&
wind->shell_surface.xdg.surface) {
xdg_surface_set_window_geometry(wind->shell_surface.xdg.surface, 0, 0,
GetWindowWidth(window), GetWindowHeight(window));
}
}
@ -1468,9 +2005,13 @@ void Wayland_SetWindowTitle(_THIS, SDL_Window * window)
SDL_WindowData *wind = window->driverdata;
SDL_VideoData *viddata = _this->driverdata;
if (WINDOW_IS_XDG_POPUP(window)) {
return;
}
if (window->title != NULL) {
#ifdef HAVE_LIBDECOR_H
if (viddata->shell.libdecor) {
if (WINDOW_IS_LIBDECOR(viddata, window)) {
if (wind->shell_surface.libdecor.frame == NULL) {
return; /* Can't do anything yet, wait for ShowWindow */
}
@ -1549,6 +2090,10 @@ void Wayland_DestroyWindow(_THIS, SDL_Window *window)
xdg_activation_token_v1_destroy(wind->activation_token);
}
if (wind->viewport) {
wp_viewport_destroy(wind->viewport);
}
SDL_free(wind->outputs);
if (wind->frame_callback) {

View file

@ -36,16 +36,27 @@ typedef struct {
struct xdg_surface *surface;
union {
struct xdg_toplevel *toplevel;
struct xdg_popup *popup;
struct {
struct xdg_popup *popup;
struct xdg_positioner *positioner;
Uint32 parentID;
SDL_Window *child;
} popup;
} roleobj;
SDL_bool initial_configure_seen;
} SDL_xdg_shell_surface;
#define WINDOW_IS_XDG_POPUP(window) \
(window->flags & (SDL_WINDOW_TOOLTIP | SDL_WINDOW_POPUP_MENU))
#ifdef HAVE_LIBDECOR_H
typedef struct {
struct libdecor_frame *frame;
SDL_bool initial_configure_seen;
} SDL_libdecor_surface;
#define WINDOW_IS_LIBDECOR(viddata, window) \
(viddata->shell.libdecor && !WINDOW_IS_XDG_POPUP(window))
#endif
typedef struct {
@ -72,6 +83,7 @@ typedef struct {
struct zwp_keyboard_shortcuts_inhibitor_v1 *key_inhibitor;
struct zwp_idle_inhibitor_v1 *idle_inhibitor;
struct xdg_activation_token_v1 *activation_token;
struct wp_viewport *viewport;
/* floating dimensions for restoring from maximized and fullscreen */
int floating_width, floating_height;
@ -86,6 +98,10 @@ typedef struct {
int num_outputs;
float scale_factor;
float pointer_scale_x;
float pointer_scale_y;
int drawable_width, drawable_height;
SDL_Rect damage_region;
SDL_bool needs_resize_event;
SDL_bool floating_resize_pending;
} SDL_WindowData;

View file

@ -378,14 +378,14 @@ WIN_CheckAsyncMouseRelease(SDL_WindowData *data)
}
static void
WIN_UpdateFocus(SDL_Window *window)
WIN_UpdateFocus(SDL_Window *window, SDL_bool expect_focus)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
HWND hwnd = data->hwnd;
SDL_bool had_focus = (SDL_GetKeyboardFocus() == window) ? SDL_TRUE : SDL_FALSE;
SDL_bool has_focus = (GetForegroundWindow() == hwnd) ? SDL_TRUE : SDL_FALSE;
if (had_focus == has_focus) {
if (had_focus == has_focus || has_focus != expect_focus) {
return;
}
@ -686,7 +686,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
/* Update the focus here, since it's possible to get WM_ACTIVATE and WM_SETFOCUS without
actually being the foreground window, but this appears to get called in all cases where
the global foreground window changes to and from this window. */
WIN_UpdateFocus(data->window);
WIN_UpdateFocus(data->window, !!wParam);
WIN_CheckICMProfileChanged(data->window);
}
break;
@ -694,16 +694,22 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_ACTIVATE:
{
/* Update the focus in case we changed focus to a child window and then away from the application */
WIN_UpdateFocus(data->window);
WIN_UpdateFocus(data->window, !!LOWORD(wParam));
}
break;
case WM_SETFOCUS:
{
/* Update the focus in case it's changing between top-level windows in the same application */
WIN_UpdateFocus(data->window, SDL_TRUE);
}
break;
case WM_KILLFOCUS:
case WM_ENTERIDLE:
{
/* Update the focus in case it's changing between top-level windows in the same application */
WIN_UpdateFocus(data->window);
WIN_UpdateFocus(data->window, SDL_FALSE);
}
break;

View file

@ -158,7 +158,7 @@ WIN_SetWindowPositionInternal(_THIS, SDL_Window * window, UINT flags)
int w, h;
/* Figure out what the window area will be */
if (SDL_ShouldAllowTopmost() && ((window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS) || (window->flags & SDL_WINDOW_ALWAYS_ON_TOP))) {
if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_ALWAYS_ON_TOP)) {
top = HWND_TOPMOST;
} else {
top = HWND_NOTOPMOST;
@ -734,7 +734,14 @@ WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display,
int x, y;
int w, h;
if (SDL_ShouldAllowTopmost() && ((window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS) || window->flags & SDL_WINDOW_ALWAYS_ON_TOP)) {
if (!fullscreen && (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_FULLSCREEN_DESKTOP)) != 0) {
/* Resizing the window on hide causes problems restoring it in Wine, and it's unnecessary.
* Also, Windows would preview the minimized window with the wrong size.
*/
return;
}
if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_ALWAYS_ON_TOP)) {
top = HWND_TOPMOST;
} else {
top = HWND_NOTOPMOST;

View file

@ -380,7 +380,7 @@ X11_GetScrollLockModifierMask(_THIS)
return num_mask;
}
static void
void
X11_ReconcileKeyboardState(_THIS)
{
SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
@ -408,7 +408,22 @@ X11_ReconcileKeyboardState(_THIS)
SDL_bool sdlKeyPressed = keyboardState[scancode] == SDL_PRESSED;
if (x11KeyPressed && !sdlKeyPressed) {
SDL_SendKeyboardKey(SDL_PRESSED, scancode);
/* Only update modifier state for keys that are pressed in another application */
switch (SDL_GetKeyFromScancode(scancode)) {
case SDLK_LCTRL:
case SDLK_RCTRL:
case SDLK_LSHIFT:
case SDLK_RSHIFT:
case SDLK_LALT:
case SDLK_RALT:
case SDLK_LGUI:
case SDLK_RGUI:
case SDLK_MODE:
SDL_SendKeyboardKey(SDL_PRESSED, scancode);
break;
default:
break;
}
} else if (!x11KeyPressed && sdlKeyPressed) {
SDL_SendKeyboardKey(SDL_RELEASED, scancode);
}
@ -718,7 +733,6 @@ static void
X11_DispatchEvent(_THIS, XEvent *xevent)
{
SDL_VideoData *videodata = (SDL_VideoData *) _this->driverdata;
XkbEvent* xkbEvent = (XkbEvent*) xevent;
Display *display;
SDL_WindowData *data;
int orig_event_type;
@ -805,11 +819,13 @@ X11_DispatchEvent(_THIS, XEvent *xevent)
if (!data) {
/* The window for KeymapNotify, etc events is 0 */
if (xevent->type == KeymapNotify) {
#ifdef DEBUG_XEVENTS
printf("window %p: KeymapNotify!\n", data);
#endif
if (SDL_GetKeyboardFocus() != NULL) {
X11_ReconcileKeyboardState(_this);
}
} else if (xevent->type == MappingNotify ||
(xevent->type == videodata->xkb_event && xkbEvent->any.xkb_type == XkbStateNotify)) {
} else if (xevent->type == MappingNotify) {
/* Has the keyboard layout changed? */
const int request = xevent->xmapping.request;
@ -996,8 +1012,9 @@ X11_DispatchEvent(_THIS, XEvent *xevent)
}
break;
/* Key press? */
case KeyPress:{
/* Key press/release? */
case KeyPress:
case KeyRelease: {
KeyCode keycode = xevent->xkey.keycode;
KeySym keysym = NoSymbol;
char text[SDL_TEXTINPUTEVENT_TEXT_SIZE];
@ -1005,7 +1022,7 @@ X11_DispatchEvent(_THIS, XEvent *xevent)
SDL_bool handled_by_ime = SDL_FALSE;
#ifdef DEBUG_XEVENTS
printf("window %p: KeyPress (X11 keycode = 0x%X)\n", data, xevent->xkey.keycode);
printf("window %p: %s (X11 keycode = 0x%X)\n", data, (xevent->type == KeyPress ? "KeyPress" : "KeyRelease"), xevent->xkey.keycode);
#endif
#if 1
if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN && keycode) {
@ -1021,7 +1038,7 @@ X11_DispatchEvent(_THIS, XEvent *xevent)
/* */
SDL_zeroa(text);
#ifdef X_HAVE_UTF8_STRING
if (data->ic) {
if (data->ic && xevent->type == KeyPress) {
X11_Xutf8LookupString(data->ic, &xevent->xkey, text, sizeof(text),
&keysym, &status);
} else {
@ -1033,35 +1050,30 @@ X11_DispatchEvent(_THIS, XEvent *xevent)
#ifdef SDL_USE_IME
if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){
handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode);
handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode, (xevent->type == KeyPress ? SDL_PRESSED : SDL_RELEASED));
}
#endif
if (!handled_by_ime) {
/* Don't send the key if it looks like a duplicate of a filtered key sent by an IME */
if (xevent->xkey.keycode != videodata->filter_code || xevent->xkey.time != videodata->filter_time) {
SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]);
}
if(*text) {
SDL_SendKeyboardText(text);
if (xevent->type == KeyPress) {
/* Don't send the key if it looks like a duplicate of a filtered key sent by an IME */
if (xevent->xkey.keycode != videodata->filter_code || xevent->xkey.time != videodata->filter_time) {
SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]);
}
if(*text) {
SDL_SendKeyboardText(text);
}
} else {
if (X11_KeyRepeat(display, xevent)) {
/* We're about to get a repeated key down, ignore the key up */
break;
}
SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]);
}
}
X11_UpdateUserTime(data, xevent->xkey.time);
}
break;
/* Key release? */
case KeyRelease:{
KeyCode keycode = xevent->xkey.keycode;
#ifdef DEBUG_XEVENTS
printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent->xkey.keycode);
#endif
if (X11_KeyRepeat(display, xevent)) {
/* We're about to get a repeated key down, ignore the key up */
break;
if (xevent->type == KeyPress) {
X11_UpdateUserTime(data, xevent->xkey.time);
}
SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]);
}
break;

View file

@ -27,6 +27,7 @@ extern void X11_PumpEvents(_THIS);
extern int X11_WaitEventTimeout(_THIS, int timeout);
extern void X11_SendWakeupEvent(_THIS, SDL_Window *window);
extern void X11_SuspendScreenSaver(_THIS);
extern void X11_ReconcileKeyboardState(_THIS);
#endif /* SDL_x11events_h_ */

View file

@ -409,6 +409,8 @@ X11_InitKeyboard(_THIS)
SDL_IME_Init();
#endif
X11_ReconcileKeyboardState(_this);
return 0;
}

View file

@ -830,10 +830,11 @@ X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
int exitcode = 0;
close(fds[0]);
status = X11_ShowMessageBoxImpl(messageboxdata, buttonid);
if (write(fds[1], &status, sizeof (int)) != sizeof (int))
if (write(fds[1], &status, sizeof (int)) != sizeof (int)) {
exitcode = 1;
else if (write(fds[1], buttonid, sizeof (int)) != sizeof (int))
} else if (write(fds[1], buttonid, sizeof (int)) != sizeof (int)) {
exitcode = 1;
}
close(fds[1]);
_exit(exitcode); /* don't run atexit() stuff, static destructors, etc. */
} else { /* we're the parent */
@ -846,13 +847,12 @@ X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
SDL_assert(rc == pid); /* not sure what to do if this fails. */
if ((rc == -1) || (!WIFEXITED(status)) || (WEXITSTATUS(status) != 0)) {
return SDL_SetError("msgbox child process failed");
status = SDL_SetError("msgbox child process failed");
} else if ( (read(fds[0], &status, sizeof (int)) != sizeof (int)) ||
(read(fds[0], buttonid, sizeof (int)) != sizeof (int)) ) {
status = SDL_SetError("read from msgbox child process failed");
*buttonid = 0;
}
if (read(fds[0], &status, sizeof (int)) != sizeof (int))
status = -1;
else if (read(fds[0], buttonid, sizeof (int)) != sizeof (int))
status = -1;
close(fds[0]);
return status;

View file

@ -1011,7 +1011,13 @@ static int (*PreXRRSetScreenSizeErrorHandler)(Display *, XErrorEvent *) = NULL;
static int
SDL_XRRSetScreenSizeErrHandler(Display *d, XErrorEvent *e)
{
return (e->error_code == BadMatch) ? 0 : PreXRRSetScreenSizeErrorHandler(d, e);
/* BadMatch: https://github.com/libsdl-org/SDL/issues/4561 */
/* BadValue: https://github.com/libsdl-org/SDL/issues/4840 */
if ((e->error_code == BadMatch) || (e->error_code == BadValue)) {
return 0;
}
return PreXRRSetScreenSizeErrorHandler(d, e);
}
int

View file

@ -247,11 +247,6 @@ X11_GL_LoadLibrary(_THIS, const char *path)
X11_GL_UseEGL(_this) ) {
#if SDL_VIDEO_OPENGL_EGL
X11_GL_UnloadLibrary(_this);
/* Better avoid conflicts! */
if (_this->gl_config.dll_handle != NULL ) {
GL_UnloadObject(_this->gl_config.dll_handle);
_this->gl_config.dll_handle = NULL;
}
_this->GL_LoadLibrary = X11_GLES_LoadLibrary;
_this->GL_GetProcAddress = X11_GLES_GetProcAddress;
_this->GL_UnloadLibrary = X11_GLES_UnloadLibrary;

View file

@ -185,7 +185,6 @@ SDL_X11_SYM(XkbDescPtr,XkbGetMap,(Display* a,unsigned int b,unsigned int c),(a,b
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)
SDL_X11_SYM(Bool,XkbSelectEvents,(Display* a, unsigned int b, unsigned int c, unsigned int d),(a,b,c,d),return)
#endif
#if NeedWidePrototypes

View file

@ -678,8 +678,6 @@ X11_CreateWindow(_THIS, SDL_Window * window)
/* For _ICC_PROFILE. */
X11_XSelectInput(display, RootWindow(display, screen), PropertyChangeMask);
X11_XkbSelectEvents(display, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask);
X11_XFlush(display);
return 0;
@ -782,11 +780,22 @@ X11_SetWindowIcon(_THIS, SDL_Window * window, SDL_Surface * icon)
X11_XFlush(display);
}
static SDL_bool caught_x11_error = SDL_FALSE;
static int
X11_CatchAnyError(Display * d, XErrorEvent * e)
{
/* this may happen during tumultuous times when we are polling anyhow,
so just note we had an error and return control. */
caught_x11_error = SDL_TRUE;
return 0;
}
void
X11_SetWindowPosition(_THIS, SDL_Window * window)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
Display *display = data->videodata->display;
int (*prev_handler) (Display *, XErrorEvent *) = NULL;
unsigned int childCount;
Window childReturn, root, parent;
Window* children;
@ -805,20 +814,27 @@ X11_SetWindowPosition(_THIS, SDL_Window * window)
/* Wait a brief time to see if the window manager decided to let this move happen.
If the window changes at all, even to an unexpected value, we break out. */
X11_XSync(display, False);
prev_handler = X11_XSetErrorHandler(X11_CatchAnyError);
timeout = SDL_GetTicks() + 100;
while (SDL_TRUE) {
int x, y;
caught_x11_error = SDL_FALSE;
X11_XSync(display, False);
X11_XGetWindowAttributes(display, data->xwindow, &attrs);
X11_XTranslateCoordinates(display, parent, DefaultRootWindow(display),
attrs.x, attrs.y, &x, &y, &childReturn);
if ((x != orig_x) || (y != orig_y)) {
window->x = x;
window->y = y;
break; /* window moved, time to go. */
} else if ((x == window->x) && (y == window->y)) {
break; /* we're at the place we wanted to be anyhow, drop out. */
if (!caught_x11_error) {
if ((x != orig_x) || (y != orig_y)) {
window->x = x;
window->y = y;
break; /* window moved, time to go. */
} else if ((x == window->x) && (y == window->y)) {
break; /* we're at the place we wanted to be anyhow, drop out. */
}
}
if (SDL_TICKS_PASSED(SDL_GetTicks(), timeout)) {
@ -827,6 +843,9 @@ X11_SetWindowPosition(_THIS, SDL_Window * window)
SDL_Delay(10);
}
X11_XSetErrorHandler(prev_handler);
caught_x11_error = SDL_FALSE;
}
void
@ -892,6 +911,7 @@ X11_SetWindowSize(_THIS, SDL_Window * window)
{
SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
Display *display = data->videodata->display;
int (*prev_handler) (Display *, XErrorEvent *) = NULL;
XWindowAttributes attrs;
int orig_w, orig_h;
Uint32 timeout;
@ -943,19 +963,25 @@ X11_SetWindowSize(_THIS, SDL_Window * window)
X11_XResizeWindow(display, data->xwindow, window->w, window->h);
}
X11_XSync(display, False);
prev_handler = X11_XSetErrorHandler(X11_CatchAnyError);
/* Wait a brief time to see if the window manager decided to let this resize happen.
If the window changes at all, even to an unexpected value, we break out. */
timeout = SDL_GetTicks() + 100;
while (SDL_TRUE) {
caught_x11_error = SDL_FALSE;
X11_XSync(display, False);
X11_XGetWindowAttributes(display, data->xwindow, &attrs);
if ((attrs.width != orig_w) || (attrs.height != orig_h)) {
window->w = attrs.width;
window->h = attrs.height;
break; /* window changed, time to go. */
} else if ((attrs.width == window->w) && (attrs.height == window->h)) {
break; /* we're at the place we wanted to be anyhow, drop out. */
if (!caught_x11_error) {
if ((attrs.width != orig_w) || (attrs.height != orig_h)) {
window->w = attrs.width;
window->h = attrs.height;
break; /* window changed, time to go. */
} else if ((attrs.width == window->w) && (attrs.height == window->h)) {
break; /* we're at the place we wanted to be anyhow, drop out. */
}
}
if (SDL_TICKS_PASSED(SDL_GetTicks(), timeout)) {
@ -964,6 +990,9 @@ X11_SetWindowSize(_THIS, SDL_Window * window)
SDL_Delay(10);
}
X11_XSetErrorHandler(prev_handler);
caught_x11_error = SDL_FALSE;
}
int
@ -1281,6 +1310,22 @@ X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _dis
if (X11_IsWindowMapped(_this, window)) {
XEvent e;
/* !!! FIXME: most of this waiting code is copy/pasted from elsewhere. */
int (*prev_handler) (Display *, XErrorEvent *) = NULL;
unsigned int childCount;
Window childReturn, root, parent;
Window* children;
XWindowAttributes attrs;
int orig_w, orig_h, orig_x, orig_y;
Uint64 timeout;
X11_XSync(display, False);
X11_XQueryTree(display, data->xwindow, &root, &parent, &children, &childCount);
X11_XGetWindowAttributes(display, data->xwindow, &attrs);
X11_XTranslateCoordinates(display, parent, DefaultRootWindow(display),
attrs.x, attrs.y, &orig_x, &orig_y, &childReturn);
orig_w = attrs.width;
orig_h = attrs.height;
if (!(window->flags & SDL_WINDOW_RESIZABLE)) {
/* Compiz refuses fullscreen toggle if we're not resizable, so update the hints so we
@ -1330,6 +1375,41 @@ X11_SetWindowFullscreenViaWM(_THIS, SDL_Window * window, SDL_VideoDisplay * _dis
X11_XSendEvent(display, RootWindow(display, displaydata->screen), 0,
SubstructureNotifyMask | SubstructureRedirectMask, &e);
}
/* Wait a brief time to see if the window manager decided to let this happen.
If the window changes at all, even to an unexpected value, we break out. */
X11_XSync(display, False);
prev_handler = X11_XSetErrorHandler(X11_CatchAnyError);
timeout = SDL_GetTicks64() + 100;
while (SDL_TRUE) {
int x, y;
caught_x11_error = SDL_FALSE;
X11_XSync(display, False);
X11_XGetWindowAttributes(display, data->xwindow, &attrs);
X11_XTranslateCoordinates(display, parent, DefaultRootWindow(display),
attrs.x, attrs.y, &x, &y, &childReturn);
if (!caught_x11_error) {
if ((x != orig_x) || (y != orig_y) || (attrs.width != orig_w) || (attrs.height != orig_h)) {
window->x = x;
window->y = y;
window->w = attrs.width;
window->h = attrs.height;
break; /* window moved, time to go. */
}
}
if (SDL_GetTicks64() >= timeout) {
break;
}
SDL_Delay(10);
}
X11_XSetErrorHandler(prev_handler);
caught_x11_error = SDL_FALSE;
} else {
Uint32 flags;

View file

@ -426,9 +426,17 @@ void SSE_FUNCTION_NAME(uint32_t width, uint32_t height,
const int fix_read_nv12 = 0;
#endif
#if YUV_FORMAT == YUV_FORMAT_422
/* Avoid invalid read on last line */
const int fix_read_422 = 1;
#else
const int fix_read_422 = 0;
#endif
if (width >= 32) {
uint32_t xpos, ypos;
for(ypos=0; ypos<(height-(uv_y_sample_interval-1)); ypos+=uv_y_sample_interval)
for(ypos=0; ypos<(height-(uv_y_sample_interval-1)) - fix_read_422; ypos+=uv_y_sample_interval)
{
const uint8_t *y_ptr1=Y+ypos*Y_stride,
*y_ptr2=Y+(ypos+1)*Y_stride,
@ -459,6 +467,15 @@ void SSE_FUNCTION_NAME(uint32_t width, uint32_t height,
}
}
if (fix_read_422) {
const uint8_t *y_ptr=Y+ypos*Y_stride,
*u_ptr=U+(ypos/uv_y_sample_interval)*UV_stride,
*v_ptr=V+(ypos/uv_y_sample_interval)*UV_stride;
uint8_t *rgb_ptr=RGB+ypos*RGB_stride;
STD_FUNCTION_NAME(width, 1, y_ptr, u_ptr, v_ptr, Y_stride, UV_stride, rgb_ptr, RGB_stride, yuv_type);
ypos += uv_y_sample_interval;
}
/* Catch the last line, if needed */
if (uv_y_sample_interval == 2 && ypos == (height-1))
{