X11: support _NET_WM_SYNC_REQUEST

This commit is contained in:
numzero
2023-05-07 01:06:06 +03:00
committed by Ryan C. Gordon
parent d320d7143d
commit 123306b18c
16 changed files with 286 additions and 4 deletions

View File

@@ -310,7 +310,7 @@ set_option(SDL_RPATH "Use an rpath when linking SDL" ${SDL_RPATH_D
set_option(SDL_CLOCK_GETTIME "Use clock_gettime() instead of gettimeofday()" ${SDL_CLOCK_GETTIME_DEFAULT})
dep_option(SDL_X11 "Use X11 video driver" ${UNIX_SYS} "SDL_VIDEO" OFF)
dep_option(SDL_X11_SHARED "Dynamically load X11 support" ON "SDL_X11" OFF)
set(SDL_X11_OPTIONS Xcursor Xdbe XInput Xfixes Xrandr Xscrnsaver XShape)
set(SDL_X11_OPTIONS Xcursor Xdbe XInput Xfixes Xrandr Xscrnsaver XShape Xsync)
foreach(_SUB ${SDL_X11_OPTIONS})
string(TOUPPER "SDL_X11_${_SUB}" _OPT)
dep_option(${_OPT} "Enable ${_SUB} support" ON "SDL_X11" OFF)

View File

@@ -307,6 +307,7 @@ macro(CheckX11)
find_file(HAVE_XRANDR_H NAMES "X11/extensions/Xrandr.h" HINTS "${X11_INCLUDEDIR}")
find_file(HAVE_XFIXES_H_ NAMES "X11/extensions/Xfixes.h" HINTS "${X11_INCLUDEDIR}")
find_file(HAVE_XRENDER_H NAMES "X11/extensions/Xrender.h" HINTS "${X11_INCLUDEDIR}")
find_file(HAVE_XSYNC_H NAMES "X11/extensions/sync.h" HINTS "${X11_INCLUDEDIR}")
find_file(HAVE_XSS_H NAMES "X11/extensions/scrnsaver.h" HINTS "${X11_INCLUDEDIR}")
find_file(HAVE_XSHAPE_H NAMES "X11/extensions/shape.h" HINTS "${X11_INCLUDEDIR}")
find_file(HAVE_XDBE_H NAMES "X11/extensions/Xdbe.h" HINTS "${X11_INCLUDEDIR}")
@@ -445,6 +446,11 @@ macro(CheckX11)
set(HAVE_X11_XFIXES TRUE)
endif()
if(SDL_X11_XSYNC AND HAVE_XSYNC_H AND XEXT_LIB)
set(SDL_VIDEO_DRIVER_X11_XSYNC 1)
set(HAVE_X11_XSYNC TRUE)
endif()
if(SDL_X11_XRANDR AND HAVE_XRANDR_H AND XRANDR_LIB)
if(HAVE_X11_SHARED)
set(SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR "\"${XRANDR_LIB_SONAME}\"")

View File

@@ -424,6 +424,7 @@
#cmakedefine SDL_VIDEO_DRIVER_X11_XRANDR @SDL_VIDEO_DRIVER_X11_XRANDR@
#cmakedefine SDL_VIDEO_DRIVER_X11_XSCRNSAVER @SDL_VIDEO_DRIVER_X11_XSCRNSAVER@
#cmakedefine SDL_VIDEO_DRIVER_X11_XSHAPE @SDL_VIDEO_DRIVER_X11_XSHAPE@
#cmakedefine SDL_VIDEO_DRIVER_X11_XSYNC @SDL_VIDEO_DRIVER_X11_XSYNC@
#cmakedefine SDL_VIDEO_DRIVER_QNX @SDL_VIDEO_DRIVER_QNX@
#cmakedefine SDL_VIDEO_RENDER_D3D @SDL_VIDEO_RENDER_D3D@

View File

@@ -59,6 +59,9 @@
#ifdef SDL_VIDEO_DRIVER_X11_XFIXES
#include <X11/extensions/Xfixes.h>
#endif
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
#include <X11/extensions/sync.h>
#endif
#ifdef SDL_VIDEO_DRIVER_X11_XRANDR
#include <X11/extensions/Xrandr.h>
#endif

View File

@@ -35,6 +35,7 @@
#include "SDL_x11xfixes.h"
#include "SDL_x11settings.h"
#include "../SDL_clipboard_c.h"
#include "SDL_x11xsync.h"
#include "../../core/unix/SDL_poll.h"
#include "../../events/SDL_events_c.h"
#include "../../events/SDL_mouse_c.h"
@@ -1376,6 +1377,11 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
}
}
}
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
X11_HandleConfigure(data->window, &xevent->xconfigure);
#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */
if (xevent->xconfigure.width != data->last_xconfigure.width ||
xevent->xconfigure.height != data->last_xconfigure.height) {
if (!data->disable_size_position_events) {
@@ -1501,6 +1507,17 @@ static void X11_DispatchEvent(SDL_VideoDevice *_this, XEvent *xevent)
#endif
SDL_SendWindowEvent(data->window, SDL_EVENT_WINDOW_CLOSE_REQUESTED, 0, 0);
break;
} else if ((xevent->xclient.message_type == videodata->atoms.WM_PROTOCOLS) &&
(xevent->xclient.format == 32) &&
(xevent->xclient.data.l[0] == videodata->atoms._NET_WM_SYNC_REQUEST)) {
#ifdef DEBUG_XEVENTS
printf("window %p: _NET_WM_SYNC_REQUEST\n", data);
#endif
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
X11_HandleSyncRequest(data->window, &xevent->xclient);
#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */
break;
}
} break;

View File

@@ -24,6 +24,7 @@
#include "SDL_x11video.h"
#include "SDL_x11framebuffer.h"
#include "SDL_x11xsync.h"
#ifndef NO_SHARED_MEMORY
@@ -216,6 +217,10 @@ bool X11_UpdateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, con
}
}
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
X11_HandlePresent(data->window);
#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */
X11_XSync(display, False);
return true;

View File

@@ -459,10 +459,11 @@ static bool X11_MessageBoxCreateWindow(SDL_MessageBoxDataX11 *data)
(unsigned char *)&_NET_WM_WINDOW_TYPE_DIALOG, 1);
// Allow the window to be deleted by the window manager
data->wm_protocols = X11_XInternAtom(display, "WM_PROTOCOLS", False);
data->wm_delete_message = X11_XInternAtom(display, "WM_DELETE_WINDOW", False);
X11_XSetWMProtocols(display, data->window, &data->wm_delete_message, 1);
data->wm_protocols = X11_XInternAtom(display, "WM_PROTOCOLS", False);
if (windowdata) {
XWindowAttributes attrib;
Window dummy;

View File

@@ -24,6 +24,7 @@
#ifdef SDL_VIDEO_DRIVER_X11
#include "SDL_x11video.h"
#include "SDL_x11xsync.h"
// GLX implementation of SDL OpenGL support
@@ -1089,6 +1090,11 @@ bool X11_GL_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
Display *display = data->videodata->display;
_this->gl_data->glXSwapBuffers(display, data->xwindow);
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
X11_HandlePresent(data->window);
#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */
return true;
}

View File

@@ -25,6 +25,7 @@
#include "SDL_x11video.h"
#include "SDL_x11opengles.h"
#include "SDL_x11opengl.h"
#include "SDL_x11xsync.h"
// EGL implementation of SDL OpenGL support
@@ -134,7 +135,18 @@ SDL_EGLSurface X11_GLES_GetEGLSurface(SDL_VideoDevice *_this, SDL_Window *window
return data->egl_surface;
}
SDL_EGL_SwapWindow_impl(X11)
bool X11_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
const bool ret = SDL_EGL_SwapBuffers(_this, window->internal->egl_surface); \
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
X11_HandlePresent(window);
#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */
return ret;
}
SDL_EGL_MakeCurrent_impl(X11)
#endif // SDL_VIDEO_DRIVER_X11 && SDL_VIDEO_OPENGL_EGL

View File

@@ -173,6 +173,15 @@ SDL_X11_SYM(Status, XFixesQueryVersion,(Display* a, int* b, int* c), (a,b,c), re
SDL_X11_SYM(Status, XFixesSelectSelectionInput, (Display* a, Window b, Atom c, unsigned long d), (a,b,c,d), return)
#endif
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
SDL_X11_MODULE(XSYNC)
SDL_X11_SYM(Status, XSyncQueryExtension, (Display* a, int* b, int* c), (a, b, c), return)
SDL_X11_SYM(Status, XSyncInitialize, (Display* a, int* b, int* c), (a, b, c), return)
SDL_X11_SYM(XSyncCounter, XSyncCreateCounter, (Display* a, XSyncValue b), (a, b), return)
SDL_X11_SYM(Status, XSyncDestroyCounter, (Display* a, XSyncCounter b), (a, b), return)
SDL_X11_SYM(Status, XSyncSetCounter, (Display* a, XSyncCounter b, XSyncValue c), (a, b, c), return)
#endif
#ifdef SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
SDL_X11_SYM(Bool,XGetEventData,(Display* a,XGenericEventCookie* b),(a,b),return)
SDL_X11_SYM(void,XFreeEventData,(Display* a,XGenericEventCookie* b),(a,b),)

View File

@@ -38,6 +38,7 @@
#include "SDL_x11xinput2.h"
#include "SDL_x11messagebox.h"
#include "SDL_x11shape.h"
#include "SDL_x11xsync.h"
#ifdef SDL_VIDEO_OPENGL_EGL
#include "SDL_x11opengles.h"
@@ -377,6 +378,8 @@ static bool X11_VideoInit(SDL_VideoDevice *_this)
GET_ATOM(_NET_WM_ICON_NAME);
GET_ATOM(_NET_WM_ICON);
GET_ATOM(_NET_WM_PING);
GET_ATOM(_NET_WM_SYNC_REQUEST);
GET_ATOM(_NET_WM_SYNC_REQUEST_COUNTER);
GET_ATOM(_NET_WM_WINDOW_OPACITY);
GET_ATOM(_NET_WM_USER_TIME);
GET_ATOM(_NET_ACTIVE_WINDOW);
@@ -420,6 +423,10 @@ static bool X11_VideoInit(SDL_VideoDevice *_this)
X11_InitXsettings(_this);
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
X11_InitXsync(_this);
#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */
#ifndef X_HAVE_UTF8_STRING
#warning X server does not support UTF8_STRING, a feature introduced in 2000! This is likely to become a hard error in a future libSDL3.
#endif

View File

@@ -89,6 +89,8 @@ struct SDL_VideoData
Atom _NET_WM_ICON_NAME;
Atom _NET_WM_ICON;
Atom _NET_WM_PING;
Atom _NET_WM_SYNC_REQUEST;
Atom _NET_WM_SYNC_REQUEST_COUNTER;
Atom _NET_WM_WINDOW_OPACITY;
Atom _NET_WM_USER_TIME;
Atom _NET_ACTIVE_WINDOW;

View File

@@ -38,6 +38,8 @@
#include "SDL_x11opengles.h"
#endif
#include "SDL_x11xsync.h"
#define _NET_WM_STATE_REMOVE 0l
#define _NET_WM_STATE_ADD 1l
@@ -509,6 +511,7 @@ bool X11_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properties
}
const bool force_override_redirect = SDL_GetHintBoolean(SDL_HINT_X11_FORCE_OVERRIDE_REDIRECT, false);
const bool use_resize_sync = (window->flags & SDL_WINDOW_VULKAN); /* doesn't work well with Vulkan */
SDL_WindowData *windowdata;
Display *display = data->display;
int screen = displaydata->screen;
@@ -770,7 +773,7 @@ bool X11_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properties
}
{
Atom protocols[3];
Atom protocols[4];
int proto_count = 0;
protocols[proto_count++] = data->atoms.WM_DELETE_WINDOW; // Allow window to be deleted by the WM
@@ -781,6 +784,12 @@ bool X11_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properties
protocols[proto_count++] = data->atoms._NET_WM_PING; // Respond so WM knows we're alive
}
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
if (use_resize_sync) {
protocols[proto_count++] = data->atoms._NET_WM_SYNC_REQUEST; /* Respond after completing resize */
}
#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */
SDL_assert(proto_count <= sizeof(protocols) / sizeof(protocols[0]));
X11_XSetWMProtocols(display, w, protocols, proto_count);
@@ -801,6 +810,12 @@ bool X11_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Properties
windowdata->fullscreen_borders_forced_on = !!(window->pending_flags & SDL_WINDOW_FULLSCREEN) &&
!!(window->flags & SDL_WINDOW_BORDERLESS);
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
if (use_resize_sync) {
X11_InitResizeSync(window);
}
#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */
#if defined(SDL_VIDEO_OPENGL_ES) || defined(SDL_VIDEO_OPENGL_ES2) || defined(SDL_VIDEO_OPENGL_EGL)
if ((window->flags & SDL_WINDOW_OPENGL) &&
((_this->gl_config.profile_mask == SDL_GL_CONTEXT_PROFILE_ES) ||
@@ -1976,6 +1991,11 @@ void X11_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
X11_XDestroyIC(data->ic);
}
#endif
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
X11_TermResizeSync(window);
#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */
if (!(window->flags & SDL_WINDOW_EXTERNAL)) {
X11_XDestroyWindow(display, data->xwindow);
X11_XFlush(display);

View File

@@ -83,6 +83,12 @@ struct SDL_WindowData
PointerBarrier barrier[4];
SDL_Rect barrier_rect;
#endif // SDL_VIDEO_DRIVER_X11_XFIXES
#ifdef SDL_VIDEO_DRIVER_X11_XSYNC
XSyncCounter resize_counter;
XSyncValue resize_id;
bool resize_in_progress;
#endif /* SDL_VIDEO_DRIVER_X11_XSYNC */
SDL_Rect expected;
SDL_DisplayMode requested_fullscreen_mode;

View File

@@ -0,0 +1,148 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_DRIVER_X11) && defined(SDL_VIDEO_DRIVER_X11_XSYNC)
#include "SDL_x11video.h"
#include "SDL_x11xsync.h"
static int xsync_initialized = 0;
static int query_xsync_version(Display *display, int major, int minor)
{
/* We don't care if this fails, so long as it sets major/minor on it's way out the door. */
X11_XSyncInitialize(display, &major, &minor);
return (major * 1000) + minor;
}
static bool xsync_version_atleast(const int version, const int wantmajor, const int wantminor)
{
return version >= ((wantmajor * 1000) + wantminor);
}
void X11_InitXsync(SDL_VideoDevice *_this)
{
SDL_VideoData *data = (SDL_VideoData *) _this->internal;
int version = 0;
int event, error;
int sync_opcode;
if (!SDL_X11_HAVE_XSYNC ||
!X11_XQueryExtension(data->display, "SYNC", &sync_opcode, &event, &error)) {
return;
}
/* We need at least 5.0 for barriers. */
version = query_xsync_version(data->display, 5, 0);
if (!xsync_version_atleast(version, 3, 0)) {
return; /* X server does not support the version we want at all. */
}
xsync_initialized = 1;
}
int X11_XsyncIsInitialized(void)
{
return xsync_initialized;
}
int X11_InitResizeSync(SDL_Window *window)
{
SDL_assert(window != NULL);
SDL_WindowData *data = (SDL_WindowData *) window->internal;
Display *display = data->videodata->display;
Atom counter_prop = data->videodata->atoms._NET_WM_SYNC_REQUEST_COUNTER;
XSyncCounter counter;
CARD32 counter_id;
if (!X11_XsyncIsInitialized()){
return SDL_Unsupported();
}
counter = X11_XSyncCreateCounter(display, (XSyncValue){0, 0});
data->resize_counter = counter;
data->resize_id.lo = 0;
data->resize_id.hi = 0;
data->resize_in_progress = false;
if (counter == None){
return SDL_Unsupported();
}
counter_id = counter;
X11_XChangeProperty(display, data->xwindow, counter_prop, XA_CARDINAL, 32,
PropModeReplace, (unsigned char *)&counter_id, 1);
return 0;
}
void X11_TermResizeSync(SDL_Window *window)
{
SDL_WindowData *data = (SDL_WindowData *) window->internal;
Display *display = data->videodata->display;
Atom counter_prop = data->videodata->atoms._NET_WM_SYNC_REQUEST_COUNTER;
XSyncCounter counter = data->resize_counter;
X11_XDeleteProperty(display, data->xwindow, counter_prop);
if (counter != None) {
X11_XSyncDestroyCounter(display, counter);
}
}
void X11_HandleSyncRequest(SDL_Window *window, XClientMessageEvent *event)
{
SDL_WindowData *data = (SDL_WindowData *) window->internal;
data->resize_id.lo = event->data.l[2];
data->resize_id.hi = event->data.l[3];
data->resize_in_progress = false;
}
void X11_HandleConfigure(SDL_Window *window, XConfigureEvent *event)
{
SDL_WindowData *data = (SDL_WindowData *) window->internal;
if (data->resize_id.lo || data->resize_id.hi) {
data->resize_in_progress = true;
}
}
void X11_HandlePresent(SDL_Window *window)
{
SDL_WindowData *data = (SDL_WindowData *) window->internal;
Display *display = data->videodata->display;
XSyncCounter counter = data->resize_counter;
if ((counter == None) || (!data->resize_in_progress)) {
return;
}
X11_XSyncSetCounter(display, counter, data->resize_id);
data->resize_id.lo = 0;
data->resize_id.hi = 0;
data->resize_in_progress = false;
}
#endif /* SDL_VIDEO_DRIVER_X11 && SDL_VIDEO_DRIVER_X11_XSYNC */

View File

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