From e406c2d7550c5c90542164bbcdfcaf95ad9ed64a Mon Sep 17 00:00:00 2001 From: Matthew King Date: Tue, 20 Jun 2023 21:22:38 +0100 Subject: [PATCH] Preliminary support for draw-only --- include/GLFW/glfw3.h | 58 +++++++++++++++++++++++++++++++++ include/GLFW/glfw3native.h | 16 +++++++++ src/input.c | 18 ++++++++++ src/internal.h | 6 ++++ src/window.c | 10 ++++++ src/x11_window.c | 67 ++++++++++++++++++++++++++++---------- 6 files changed, 157 insertions(+), 18 deletions(-) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 31b201ae..1a37a163 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -1031,6 +1031,14 @@ extern "C" { * [window hint](@ref GLFW_X11_CLASS_NAME_hint). */ #define GLFW_X11_INSTANCE_NAME 0x00024002 +/*! @brief X11 specific + * [window hint](@ref GLFW_HANDLE_DND_hint). + */ +#define GLFW_HANDLE_DND 0x00024003 +/*! @brief X11 specific but probably/possibly shouldn't be + * [window hint](@ref GLFW_HANDLE_KEYBOARD_hint). + */ +#define GLFW_HANDLE_KEYBOARD 0x00024004 /*! @} */ #define GLFW_NO_API 0 @@ -1641,6 +1649,26 @@ typedef void (* GLFWmonitorfun)(GLFWmonitor* monitor, int event); */ typedef void (* GLFWjoystickfun)(int jid, int event); +/*! @brief The function pointer type for unhandled event callbacks. + * + * This is the function pointer type for callbacks when GLFW has + * not handled an input event. + * unhandled event callback function has the following signature: + * @code + * void function_name(GLFWwindow* window, void *event) + * @endcode + * + * @param[in] window The window that received the event. + * @param[in] event The event. What it means is platform-dependent. + * + * @sa @ref glfwSetUnhandledCallback + * + * @since Added in version 3.9. + * + * @ingroup input + */ +typedef void (* GLFWunhandledfun)(GLFWwindow* window, void* event); + /*! @brief Video mode type. * * This describes a single video mode. @@ -4840,6 +4868,36 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun ca */ GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun callback); +/*! @brief Sets the unhandled event callback. + * + * This function sets the unhandled event callback of the specified + * window, which is called when an event is received from the windowing system + * which GLFW does not handle itself. + * + * @param[in] window The window whose callback to set. + * @param[in] callback The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @callback_signature + * @code + * void function_name(GLFWwindow* window, void *event) + * @endcode + * The meaning of the event variable is platform-dependent. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function must only be called from the main thread. + * + * @sa @ref cursor_enter + * + * @since Added in version 3.0. + * + * @ingroup input + */ +GLFWAPI GLFWunhandledfun glfwSetUnhandledCallback(GLFWwindow* window, GLFWunhandledfun callback); + /*! @brief Returns whether the specified joystick is present. * * This function returns whether the specified joystick is present. diff --git a/include/GLFW/glfw3native.h b/include/GLFW/glfw3native.h index 7be0227d..081a5b31 100644 --- a/include/GLFW/glfw3native.h +++ b/include/GLFW/glfw3native.h @@ -313,6 +313,22 @@ GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); */ GLFWAPI Display* glfwGetX11Display(void); +/*! @brief Returns the `Screen` used by GLFW. + * + * @return The `Screen` used by GLFW, or `-1` if an + * [error](@ref error_handling) occurred. + * + * @errors Possible errors include @ref GLFW_NOT_INITIALIZED. + * + * @thread_safety This function may be called from any thread. Access is not + * synchronized. + * + * @since Added in version 3.8.9. + * + * @ingroup native + */ +GLFWAPI int glfwGetX11Screen(void); + /*! @brief Returns the `RRCrtc` of the specified monitor. * * @return The `RRCrtc` of the specified monitor, or `None` if an diff --git a/src/input.c b/src/input.c index 7ea1222c..569bd417 100644 --- a/src/input.c +++ b/src/input.c @@ -245,6 +245,14 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string) ////// GLFW event API ////// ////////////////////////////////////////////////////////////////////////// +// Notifies shared code of an event that was not handled by GLFW +// +void _glfwInputUnhandledEvent(_GLFWwindow* window, void *event) +{ + if (window->callbacks.unhandled) + window->callbacks.unhandled((GLFWwindow*) window, event); +} + // Notifies shared code of a physical key event // void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods) @@ -849,6 +857,16 @@ GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle) _glfwPlatformSetCursor(window, cursor); } +GLFWAPI GLFWunhandledfun glfwSetUnhandledCallback(GLFWwindow* handle, GLFWunhandledfun cbfun) +{ + _GLFWwindow* window = (_GLFWwindow*) handle; + assert(window != NULL); + + _GLFW_REQUIRE_INIT_OR_RETURN(NULL); + _GLFW_SWAP_POINTERS(window->callbacks.unhandled, cbfun); + return cbfun; +} + GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun) { _GLFWwindow* window = (_GLFWwindow*) handle; diff --git a/src/internal.h b/src/internal.h index 7734caa3..3521b2a3 100644 --- a/src/internal.h +++ b/src/internal.h @@ -267,6 +267,8 @@ struct _GLFWwndconfig GLFWbool centerCursor; GLFWbool focusOnShow; GLFWbool scaleToMonitor; + GLFWbool handleDND; + GLFWbool handleKeyboard; struct { GLFWbool retina; char frameName[256]; @@ -393,6 +395,8 @@ struct _GLFWwindow // Virtual cursor position when cursor is disabled double virtualCursorPosX, virtualCursorPosY; GLFWbool rawMouseMotion; + GLFWbool handleDND; + GLFWbool handleKeyboard; _GLFWcontext context; @@ -414,6 +418,7 @@ struct _GLFWwindow GLFWcharfun character; GLFWcharmodsfun charmods; GLFWdropfun drop; + GLFWunhandledfun unhandled; } callbacks; // This is defined in the window API's platform.h @@ -716,6 +721,7 @@ void _glfwInputWindowDamage(_GLFWwindow* window); void _glfwInputWindowCloseRequest(_GLFWwindow* window); void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor); +void _glfwInputUnhandledEvent(_GLFWwindow* window, void* event); void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods); void _glfwInputChar(_GLFWwindow* window, diff --git a/src/window.c b/src/window.c index 5d80e436..a6bf3ea7 100644 --- a/src/window.c +++ b/src/window.c @@ -261,6 +261,10 @@ void glfwDefaultWindowHints(void) // The default is to use full Retina resolution framebuffers _glfw.hints.window.ns.retina = GLFW_TRUE; + + // Handle keyboard and drag-and-dtop in GLFW by default + _glfw.hints.window.handleDND = GLFW_TRUE; + _glfw.hints.window.handleKeyboard = GLFW_TRUE; } GLFWAPI void glfwWindowHint(int hint, int value) @@ -386,6 +390,12 @@ GLFWAPI void glfwWindowHint(int hint, int value) case GLFW_REFRESH_RATE: _glfw.hints.refreshRate = value; return; + case GLFW_HANDLE_DND: + _glfw.hints.window.handleDND = value ? GLFW_TRUE : GLFW_FALSE; + return; + case GLFW_HANDLE_KEYBOARD: + _glfw.hints.window.handleKeyboard = value ? GLFW_TRUE : GLFW_FALSE; + return; } _glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint 0x%08X", hint); diff --git a/src/x11_window.c b/src/x11_window.c index ddda48d7..56a77054 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -646,6 +646,9 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, _glfw.x11.context, (XPointer) window); + window->handleDND = wndconfig->handleDND; + window->handleKeyboard = wndconfig->handleKeyboard; + if (!wndconfig->decorated) _glfwPlatformSetWindowDecorated(window, GLFW_FALSE); @@ -759,6 +762,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, } // Announce support for Xdnd (drag and drop) + if (wndconfig->handleDND) { const Atom version = _GLFW_XDND_VERSION; XChangeProperty(_glfw.x11.display, window->x11.handle, @@ -768,7 +772,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, _glfwPlatformSetWindowTitle(window, wndconfig->title); - if (_glfw.x11.im) + if (wndconfig->handleKeyboard && _glfw.x11.im) { window->x11.ic = XCreateIC(_glfw.x11.im, XNInputStyle, @@ -780,7 +784,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, NULL); } - if (window->x11.ic) + if (wndconfig->handleKeyboard && window->x11.ic) { unsigned long filter = 0; if (XGetICValues(window->x11.ic, XNFilterEvents, &filter, NULL) == NULL) @@ -1163,13 +1167,19 @@ static void processEvent(XEvent *event) if (_glfw.x11.im) filtered = XFilterEvent(event, None); + _GLFWwindow* window = NULL; + XFindContext(_glfw.x11.display, + event->xany.window, + _glfw.x11.context, + (XPointer*) &window); + if (_glfw.x11.randr.available) { if (event->type == _glfw.x11.randr.eventBase + RRNotify) { XRRUpdateConfiguration(event); _glfwPollMonitorsX11(); - return; + goto unhandled_event; } } @@ -1183,7 +1193,7 @@ static void processEvent(XEvent *event) _glfw.x11.xkb.group = ((XkbEvent*) event)->state.group; } - return; + goto unhandled_event; } } @@ -1222,20 +1232,16 @@ static void processEvent(XEvent *event) XFreeEventData(_glfw.x11.display, &event->xcookie); } - return; + goto unhandled_event; } if (event->type == SelectionRequest) { handleSelectionRequest(event); - return; + goto unhandled_event; } - _GLFWwindow* window = NULL; - if (XFindContext(_glfw.x11.display, - event->xany.window, - _glfw.x11.context, - (XPointer*) &window) != 0) + if (!window) { // This is an event for a window that has already been destroyed return; @@ -1243,6 +1249,15 @@ static void processEvent(XEvent *event) switch (event->type) { +unhandled_event: + default: + { + if (!window) + return; + _glfwInputUnhandledEvent(window, (void *) event); + return; + } + case ReparentNotify: { window->x11.parent = event->xreparent.parent; @@ -1251,6 +1266,9 @@ static void processEvent(XEvent *event) case KeyPress: { + if (!window->handleKeyboard) + goto unhandled_event; + const int key = translateKey(keycode); const int mods = translateState(event->xkey.state); const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); @@ -1351,6 +1369,9 @@ static void processEvent(XEvent *event) case KeyRelease: { + if (!window->handleKeyboard) + goto unhandled_event; + const int key = translateKey(keycode); const int mods = translateState(event->xkey.state); @@ -1392,6 +1413,9 @@ static void processEvent(XEvent *event) case ButtonPress: { + if (!window->handleKeyboard) + goto unhandled_event; + const int mods = translateState(event->xbutton.state); if (event->xbutton.button == Button1) @@ -1578,13 +1602,11 @@ static void processEvent(XEvent *event) return; if (event->xclient.message_type == None) - return; + goto unhandled_event; if (event->xclient.message_type == _glfw.x11.WM_PROTOCOLS) { const Atom protocol = event->xclient.data.l[0]; - if (protocol == None) - return; if (protocol == _glfw.x11.WM_DELETE_WINDOW) { @@ -1592,6 +1614,7 @@ static void processEvent(XEvent *event) // example by the user pressing a 'close' window decoration // button _glfwInputWindowCloseRequest(window); + return; } else if (protocol == _glfw.x11.NET_WM_PING) { @@ -1605,9 +1628,14 @@ static void processEvent(XEvent *event) False, SubstructureNotifyMask | SubstructureRedirectMask, &reply); + return; } } - else if (event->xclient.message_type == _glfw.x11.XdndEnter) + + if (!window->handleDND) + goto unhandled_event; + + if (event->xclient.message_type == _glfw.x11.XdndEnter) { // A drag operation has entered the window unsigned long i, count; @@ -1859,9 +1887,6 @@ static void processEvent(XEvent *event) return; } - - case DestroyNotify: - return; } } @@ -3139,6 +3164,12 @@ GLFWAPI Display* glfwGetX11Display(void) return _glfw.x11.display; } +GLFWAPI int glfwGetX11Screen(void) +{ + _GLFW_REQUIRE_INIT_OR_RETURN(-1); + return _glfw.x11.screen; +} + GLFWAPI Window glfwGetX11Window(GLFWwindow* handle) { _GLFWwindow* window = (_GLFWwindow*) handle;