From a06c00215abc85863200dac9bf82e269cc31d175 Mon Sep 17 00:00:00 2001 From: NarrikSynthfox <80410683+NarrikSynthfox@users.noreply.github.com> Date: Wed, 10 Apr 2024 11:22:59 -0400 Subject: [PATCH 1/2] Fixed issue with bad merge --- src/input.c | 129 ++-- src/x11_window.c | 1585 +++++++++++++++++++++------------------------- 2 files changed, 763 insertions(+), 951 deletions(-) diff --git a/src/input.c b/src/input.c index 6310b653..7c2a153a 100644 --- a/src/input.c +++ b/src/input.c @@ -653,93 +653,80 @@ GLFWAPI void glfwSetInputMode(GLFWwindow *handle, int mode, int value) switch (mode) { - case GLFW_CURSOR: - { - if (value != GLFW_CURSOR_NORMAL && - value != GLFW_CURSOR_HIDDEN && - value != GLFW_CURSOR_DISABLED && - value != GLFW_CURSOR_CAPTURED) + case GLFW_CURSOR: { - _glfwInputError(GLFW_INVALID_ENUM, - "Invalid cursor mode 0x%08X", - value); - return; - } - - if (window->cursorMode == value) - return; - - window->cursorMode = value; - - _glfw.platform.getCursorPos(window, - &window->virtualCursorPosX, - &window->virtualCursorPosY); - _glfw.platform.setCursorMode(window, value); - return; - } - - case GLFW_STICKY_KEYS: - { - value = value ? GLFW_TRUE : GLFW_FALSE; - if (window->stickyKeys == value) - return; - - if (!value) - { - int i; - - // Release all sticky keys - for (i = 0; i <= GLFW_KEY_LAST; i++) + if (value != GLFW_CURSOR_NORMAL && + value != GLFW_CURSOR_HIDDEN && + value != GLFW_CURSOR_DISABLED && + value != GLFW_CURSOR_CAPTURED) { - if (window->keys[i] == _GLFW_STICK) - window->keys[i] = GLFW_RELEASE; + _glfwInputError(GLFW_INVALID_ENUM, + "Invalid cursor mode 0x%08X", + value); + return; } + + if (window->cursorMode == value) + return; + + window->cursorMode = value; + + _glfw.platform.getCursorPos(window, + &window->virtualCursorPosX, + &window->virtualCursorPosY); + _glfw.platform.setCursorMode(window, value); + return; } - window->stickyKeys = value; - return; - } - - case GLFW_STICKY_MOUSE_BUTTONS: - { - value = value ? GLFW_TRUE : GLFW_FALSE; - if (window->stickyMouseButtons == value) - return; - - if (!value) + case GLFW_STICKY_KEYS: { - int i; + value = value ? GLFW_TRUE : GLFW_FALSE; + if (window->stickyKeys == value) + return; - // Release all sticky mouse buttons - for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) + if (!value) { - if (window->mouseButtons[i] == _GLFW_STICK) - window->mouseButtons[i] = GLFW_RELEASE; + int i; + + // Release all sticky keys + for (i = 0; i <= GLFW_KEY_LAST; i++) + { + if (window->keys[i] == _GLFW_STICK) + window->keys[i] = GLFW_RELEASE; + } } + + window->stickyKeys = value; + return; } - window->stickyMouseButtons = value; - return; - } - - case GLFW_LOCK_KEY_MODS: - { - window->lockKeyMods = value ? GLFW_TRUE : GLFW_FALSE; - return; - } - - case GLFW_RAW_MOUSE_MOTION: - { - if (!_glfw.platform.rawMouseMotionSupported()) + case GLFW_STICKY_MOUSE_BUTTONS: { - _glfwInputError(GLFW_PLATFORM_ERROR, - "Raw mouse motion is not supported on this system"); + value = value ? GLFW_TRUE : GLFW_FALSE; + if (window->stickyMouseButtons == value) + return; + + if (!value) + { + int i; + + // Release all sticky mouse buttons + for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) + { + if (window->mouseButtons[i] == _GLFW_STICK) + window->mouseButtons[i] = GLFW_RELEASE; + } + } + + window->stickyMouseButtons = value; return; } - value = value ? GLFW_TRUE : GLFW_FALSE; - if (window->rawMouseMotion == value) + case GLFW_LOCK_KEY_MODS: + { + window->lockKeyMods = value ? GLFW_TRUE : GLFW_FALSE; return; + } case GLFW_RAW_MOUSE_MOTION: { diff --git a/src/x11_window.c b/src/x11_window.c index df82d4c2..322349f0 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -42,17 +42,17 @@ #include // Action for EWMH client messages -#define _NET_WM_STATE_REMOVE 0 -#define _NET_WM_STATE_ADD 1 -#define _NET_WM_STATE_TOGGLE 2 +#define _NET_WM_STATE_REMOVE 0 +#define _NET_WM_STATE_ADD 1 +#define _NET_WM_STATE_TOGGLE 2 // Additional mouse button names for XButtonEvent -#define Button6 6 -#define Button7 7 +#define Button6 6 +#define Button7 7 // Motif WM hints flags -#define MWM_HINTS_DECORATIONS 2 -#define MWM_DECOR_ALL 1 +#define MWM_HINTS_DECORATIONS 2 +#define MWM_DECOR_ALL 1 #define _GLFW_XDND_VERSION 5 @@ -60,9 +60,9 @@ // This avoids blocking other threads via the per-display Xlib lock that also // covers GLX functions // -static GLFWbool waitForX11Event(double *timeout) +static GLFWbool waitForX11Event(double* timeout) { - struct pollfd fd = {ConnectionNumber(_glfw.x11.display), POLLIN}; + struct pollfd fd = { ConnectionNumber(_glfw.x11.display), POLLIN }; while (!XPending(_glfw.x11.display)) { @@ -77,7 +77,7 @@ static GLFWbool waitForX11Event(double *timeout) // This avoids blocking other threads via the per-display Xlib lock that also // covers GLX functions // -static GLFWbool waitForAnyEvent(double *timeout) +static GLFWbool waitForAnyEvent(double* timeout) { enum { XLIB_FD, PIPE_FD, INOTIFY_FD }; struct pollfd fds[] = @@ -136,7 +136,7 @@ static void drainEmptyEvents(void) // Waits until a VisibilityNotify event arrives for the specified window or the // timeout period elapses (ICCCM section 4.2.2) // -static GLFWbool waitForVisibilityNotify(_GLFWwindow *window) +static GLFWbool waitForVisibilityNotify(_GLFWwindow* window) { XEvent dummy; double timeout = 0.1; @@ -155,11 +155,10 @@ static GLFWbool waitForVisibilityNotify(_GLFWwindow *window) // Returns whether the window is iconified // -static int getWindowState(_GLFWwindow *window) +static int getWindowState(_GLFWwindow* window) { int result = WithdrawnState; - struct - { + struct { CARD32 state; Window icon; } *state = NULL; @@ -167,7 +166,7 @@ static int getWindowState(_GLFWwindow *window) if (_glfwGetWindowPropertyX11(window->x11.handle, _glfw.x11.WM_STATE, _glfw.x11.WM_STATE, - (unsigned char **)&state) >= 2) + (unsigned char**) &state) >= 2) { result = state->state; } @@ -180,7 +179,7 @@ static int getWindowState(_GLFWwindow *window) // Returns whether the event is a selection event // -static Bool isSelectionEvent(Display *display, XEvent *event, XPointer pointer) +static Bool isSelectionEvent(Display* display, XEvent* event, XPointer pointer) { if (event->xany.window != _glfw.x11.helperWindowHandle) return False; @@ -192,9 +191,9 @@ static Bool isSelectionEvent(Display *display, XEvent *event, XPointer pointer) // Returns whether it is a _NET_FRAME_EXTENTS event for the specified window // -static Bool isFrameExtentsEvent(Display *display, XEvent *event, XPointer pointer) +static Bool isFrameExtentsEvent(Display* display, XEvent* event, XPointer pointer) { - _GLFWwindow *window = (_GLFWwindow *)pointer; + _GLFWwindow* window = (_GLFWwindow*) pointer; return event->type == PropertyNotify && event->xproperty.state == PropertyNewValue && event->xproperty.window == window->x11.handle && @@ -203,9 +202,9 @@ static Bool isFrameExtentsEvent(Display *display, XEvent *event, XPointer pointe // Returns whether it is a property event for the specified selection transfer // -static Bool isSelPropNewValueNotify(Display *display, XEvent *event, XPointer pointer) +static Bool isSelPropNewValueNotify(Display* display, XEvent* event, XPointer pointer) { - XEvent *notification = (XEvent *)pointer; + XEvent* notification = (XEvent*) pointer; return event->type == PropertyNotify && event->xproperty.state == PropertyNewValue && event->xproperty.window == notification->xselection.requestor && @@ -247,10 +246,10 @@ static int translateKey(int scancode) // Sends an EWMH or ICCCM event to the window manager // -static void sendEventToWM(_GLFWwindow *window, Atom type, +static void sendEventToWM(_GLFWwindow* window, Atom type, long a, long b, long c, long d, long e) { - XEvent event = {ClientMessage}; + XEvent event = { ClientMessage }; event.xclient.window = window->x11.handle; event.xclient.format = 32; // Data is 32-bit longs event.xclient.message_type = type; @@ -268,9 +267,9 @@ static void sendEventToWM(_GLFWwindow *window, Atom type, // Updates the normal hints according to the window settings // -static void updateNormalHints(_GLFWwindow *window, int width, int height) +static void updateNormalHints(_GLFWwindow* window, int width, int height) { - XSizeHints *hints = XAllocSizeHints(); + XSizeHints* hints = XAllocSizeHints(); long supplied; XGetWMNormalHints(_glfw.x11.display, window->x11.handle, hints, &supplied); @@ -308,7 +307,7 @@ static void updateNormalHints(_GLFWwindow *window, int width, int height) else { hints->flags |= (PMinSize | PMaxSize); - hints->min_width = hints->max_width = width; + hints->min_width = hints->max_width = width; hints->min_height = hints->max_height = height; } } @@ -319,7 +318,7 @@ static void updateNormalHints(_GLFWwindow *window, int width, int height) // Updates the full screen status of the window // -static void updateWindowMode(_GLFWwindow *window) +static void updateWindowMode(_GLFWwindow* window) { if (window->monitor) { @@ -368,9 +367,9 @@ static void updateWindowMode(_GLFWwindow *window) { const unsigned long value = 1; - XChangeProperty(_glfw.x11.display, window->x11.handle, + XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_BYPASS_COMPOSITOR, XA_CARDINAL, 32, - PropModeReplace, (unsigned char *)&value, 1); + PropModeReplace, (unsigned char*) &value, 1); } } else @@ -414,17 +413,18 @@ static void updateWindowMode(_GLFWwindow *window) // Decode a Unicode code point from a UTF-8 stream // Based on cutef8 by Jeff Bezanson (Public Domain) // -static uint32_t decodeUTF8(const char **s) +static uint32_t decodeUTF8(const char** s) { uint32_t codepoint = 0, count = 0; static const uint32_t offsets[] = - { - 0x00000000u, 0x00003080u, 0x000e2080u, - 0x03c82080u, 0xfa082080u, 0x82082080u}; + { + 0x00000000u, 0x00003080u, 0x000e2080u, + 0x03c82080u, 0xfa082080u, 0x82082080u + }; do { - codepoint = (codepoint << 6) + (unsigned char)**s; + codepoint = (codepoint << 6) + (unsigned char) **s; (*s)++; count++; } while ((**s & 0xc0) == 0x80); @@ -435,18 +435,18 @@ static uint32_t decodeUTF8(const char **s) // Convert the specified Latin-1 string to UTF-8 // -static char *convertLatin1toUTF8(const char *source) +static char* convertLatin1toUTF8(const char* source) { size_t size = 1; - const char *sp; + const char* sp; - for (sp = source; *sp; sp++) + for (sp = source; *sp; sp++) size += (*sp & 0x80) ? 2 : 1; - char *target = _glfw_calloc(size, 1); - char *tp = target; + char* target = _glfw_calloc(size, 1); + char* tp = target; - for (sp = source; *sp; sp++) + for (sp = source; *sp; sp++) tp += _glfwEncodeUTF8(tp, *sp); return target; @@ -454,7 +454,7 @@ static char *convertLatin1toUTF8(const char *source) // Updates the cursor image according to its cursor mode // -static void updateCursorImage(_GLFWwindow *window) +static void updateCursorImage(_GLFWwindow* window) { if (window->cursorMode == GLFW_CURSOR_NORMAL || window->cursorMode == GLFW_CURSOR_CAPTURED) @@ -476,7 +476,7 @@ static void updateCursorImage(_GLFWwindow *window) // Grabs the cursor and confines it to the window // -static void captureCursor(_GLFWwindow *window) +static void captureCursor(_GLFWwindow* window) { XGrabPointer(_glfw.x11.display, window->x11.handle, True, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, @@ -495,10 +495,10 @@ static void releaseCursor(void) // Enable XI2 raw mouse motion events // -static void enableRawMouseMotion(_GLFWwindow *window) +static void enableRawMouseMotion(_GLFWwindow* window) { XIEventMask em; - unsigned char mask[XIMaskLen(XI_RawMotion)] = {0}; + unsigned char mask[XIMaskLen(XI_RawMotion)] = { 0 }; em.deviceid = XIAllMasterDevices; em.mask_len = sizeof(mask); @@ -510,10 +510,10 @@ static void enableRawMouseMotion(_GLFWwindow *window) // Disable XI2 raw mouse motion events // -static void disableRawMouseMotion(_GLFWwindow *window) +static void disableRawMouseMotion(_GLFWwindow* window) { XIEventMask em; - unsigned char mask[] = {0}; + unsigned char mask[] = { 0 }; em.deviceid = XIAllMasterDevices; em.mask_len = sizeof(mask); @@ -524,7 +524,7 @@ static void disableRawMouseMotion(_GLFWwindow *window) // Apply disabled cursor mode to a focused window // -static void disableCursor(_GLFWwindow *window) +static void disableCursor(_GLFWwindow* window) { if (window->rawMouseMotion) enableRawMouseMotion(window); @@ -540,7 +540,7 @@ static void disableCursor(_GLFWwindow *window) // Exit disabled cursor mode for the specified window // -static void enableCursor(_GLFWwindow *window) +static void enableCursor(_GLFWwindow* window) { if (window->rawMouseMotion) disableRawMouseMotion(window); @@ -557,15 +557,15 @@ static void enableCursor(_GLFWwindow *window) // static void inputContextDestroyCallback(XIC ic, XPointer clientData, XPointer callData) { - _GLFWwindow *window = (_GLFWwindow *)clientData; + _GLFWwindow* window = (_GLFWwindow*) clientData; window->x11.ic = NULL; } // Create the X11 window (and its colormap) // -static GLFWbool createNativeWindow(_GLFWwindow *window, - const _GLFWwndconfig *wndconfig, - Visual *visual, int depth) +static GLFWbool createNativeWindow(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + Visual* visual, int depth) { int width = wndconfig->width; int height = wndconfig->height; @@ -592,7 +592,7 @@ static GLFWbool createNativeWindow(_GLFWwindow *window, window->x11.transparent = _glfwIsVisualTransparentX11(visual); - XSetWindowAttributes wa = {0}; + XSetWindowAttributes wa = { 0 }; wa.colormap = window->x11.colormap; wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask | @@ -606,8 +606,8 @@ static GLFWbool createNativeWindow(_GLFWwindow *window, _glfw.x11.root, xpos, ypos, width, height, - 0, // Border width - depth, // Color depth + 0, // Border width + depth, // Color depth InputOutput, visual, CWBorderPixel | CWColormap | CWEventMask, @@ -625,7 +625,7 @@ static GLFWbool createNativeWindow(_GLFWwindow *window, XSaveContext(_glfw.x11.display, window->x11.handle, _glfw.x11.context, - (XPointer)window); + (XPointer) window); if (!wndconfig->decorated) _glfwSetWindowDecoratedX11(window, GLFW_FALSE); @@ -656,16 +656,17 @@ static GLFWbool createNativeWindow(_GLFWwindow *window, { XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_STATE, XA_ATOM, 32, - PropModeReplace, (unsigned char *)states, count); + PropModeReplace, (unsigned char*) states, count); } } // Declare the WM protocols supported by GLFW { Atom protocols[] = - { - _glfw.x11.WM_DELETE_WINDOW, - _glfw.x11.NET_WM_PING}; + { + _glfw.x11.WM_DELETE_WINDOW, + _glfw.x11.NET_WM_PING + }; XSetWMProtocols(_glfw.x11.display, window->x11.handle, protocols, sizeof(protocols) / sizeof(Atom)); @@ -675,23 +676,23 @@ static GLFWbool createNativeWindow(_GLFWwindow *window, { const long pid = getpid(); - XChangeProperty(_glfw.x11.display, window->x11.handle, + XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_PID, XA_CARDINAL, 32, PropModeReplace, - (unsigned char *)&pid, 1); + (unsigned char*) &pid, 1); } if (_glfw.x11.NET_WM_WINDOW_TYPE && _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL) { Atom type = _glfw.x11.NET_WM_WINDOW_TYPE_NORMAL; - XChangeProperty(_glfw.x11.display, window->x11.handle, + XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_WINDOW_TYPE, XA_ATOM, 32, - PropModeReplace, (unsigned char *)&type, 1); + PropModeReplace, (unsigned char*) &type, 1); } // Set ICCCM WM_HINTS property { - XWMHints *hints = XAllocWMHints(); + XWMHints* hints = XAllocWMHints(); if (!hints) { _glfwInputError(GLFW_OUT_OF_MEMORY, @@ -708,7 +709,7 @@ static GLFWbool createNativeWindow(_GLFWwindow *window, // Set ICCCM WM_NORMAL_HINTS property { - XSizeHints *hints = XAllocSizeHints(); + XSizeHints* hints = XAllocSizeHints(); if (!hints) { _glfwInputError(GLFW_OUT_OF_MEMORY, "X11: Failed to allocate size hints"); @@ -718,7 +719,7 @@ static GLFWbool createNativeWindow(_GLFWwindow *window, if (!wndconfig->resizable) { hints->flags |= (PMinSize | PMaxSize); - hints->min_width = hints->max_width = width; + hints->min_width = hints->max_width = width; hints->min_height = hints->max_height = height; } @@ -740,28 +741,28 @@ static GLFWbool createNativeWindow(_GLFWwindow *window, // Set ICCCM WM_CLASS property { - XClassHint *hint = XAllocClassHint(); + XClassHint* hint = XAllocClassHint(); if (strlen(wndconfig->x11.instanceName) && strlen(wndconfig->x11.className)) { - hint->res_name = (char *)wndconfig->x11.instanceName; - hint->res_class = (char *)wndconfig->x11.className; + hint->res_name = (char*) wndconfig->x11.instanceName; + hint->res_class = (char*) wndconfig->x11.className; } else { - const char *resourceName = getenv("RESOURCE_NAME"); + const char* resourceName = getenv("RESOURCE_NAME"); if (resourceName && strlen(resourceName)) - hint->res_name = (char *)resourceName; + hint->res_name = (char*) resourceName; else if (strlen(wndconfig->title)) - hint->res_name = (char *)wndconfig->title; + hint->res_name = (char*) wndconfig->title; else - hint->res_name = (char *)"glfw-application"; + hint->res_name = (char*) "glfw-application"; if (strlen(wndconfig->title)) - hint->res_class = (char *)wndconfig->title; + hint->res_class = (char*) wndconfig->title; else - hint->res_class = (char *)"GLFW-Application"; + hint->res_class = (char*) "GLFW-Application"; } XSetClassHint(_glfw.x11.display, window->x11.handle, hint); @@ -773,7 +774,7 @@ static GLFWbool createNativeWindow(_GLFWwindow *window, const Atom version = _GLFW_XDND_VERSION; XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.XdndAware, XA_ATOM, 32, - PropModeReplace, (unsigned char *)&version, 1); + PropModeReplace, (unsigned char*) &version, 1); } if (_glfw.x11.im) @@ -788,10 +789,10 @@ static GLFWbool createNativeWindow(_GLFWwindow *window, // Set the specified property to the selection converted to the requested target // -static Atom writeTargetToProperty(const XSelectionRequestEvent *request) +static Atom writeTargetToProperty(const XSelectionRequestEvent* request) { - char *selectionString = NULL; - const Atom formats[] = {_glfw.x11.UTF8_STRING, XA_STRING}; + char* selectionString = NULL; + const Atom formats[] = { _glfw.x11.UTF8_STRING, XA_STRING }; const int formatCount = sizeof(formats) / sizeof(formats[0]); if (request->selection == _glfw.x11.PRIMARY) @@ -810,10 +811,10 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent *request) { // The list of supported targets was requested - const Atom targets[] = {_glfw.x11.TARGETS, - _glfw.x11.MULTIPLE, - _glfw.x11.UTF8_STRING, - XA_STRING}; + const Atom targets[] = { _glfw.x11.TARGETS, + _glfw.x11.MULTIPLE, + _glfw.x11.UTF8_STRING, + XA_STRING }; XChangeProperty(_glfw.x11.display, request->requestor, @@ -821,7 +822,7 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent *request) XA_ATOM, 32, PropModeReplace, - (unsigned char *)targets, + (unsigned char*) targets, sizeof(targets) / sizeof(targets[0])); return request->property; @@ -831,18 +832,18 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent *request) { // Multiple conversions were requested - Atom *targets; + Atom* targets; const unsigned long count = _glfwGetWindowPropertyX11(request->requestor, request->property, _glfw.x11.ATOM_PAIR, - (unsigned char **)&targets); + (unsigned char**) &targets); - for (unsigned long i = 0; i < count; i += 2) + for (unsigned long i = 0; i < count; i += 2) { int j; - for (j = 0; j < formatCount; j++) + for (j = 0; j < formatCount; j++) { if (targets[i] == formats[j]) break; @@ -856,7 +857,7 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent *request) targets[i], 8, PropModeReplace, - (unsigned char *)selectionString, + (unsigned char *) selectionString, strlen(selectionString)); } else @@ -869,7 +870,7 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent *request) _glfw.x11.ATOM_PAIR, 32, PropModeReplace, - (unsigned char *)targets, + (unsigned char*) targets, count); XFree(targets); @@ -896,7 +897,7 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent *request) // Conversion to a data target was requested - for (int i = 0; i < formatCount; i++) + for (int i = 0; i < formatCount; i++) { if (request->target == formats[i]) { @@ -908,7 +909,7 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent *request) request->target, 8, PropModeReplace, - (unsigned char *)selectionString, + (unsigned char *) selectionString, strlen(selectionString)); return request->property; @@ -920,11 +921,11 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent *request) return None; } -static void handleSelectionRequest(XEvent *event) +static void handleSelectionRequest(XEvent* event) { - const XSelectionRequestEvent *request = &event->xselectionrequest; + const XSelectionRequestEvent* request = &event->xselectionrequest; - XEvent reply = {SelectionNotify}; + XEvent reply = { SelectionNotify }; reply.xselection.property = writeTargetToProperty(request); reply.xselection.display = request->display; reply.xselection.requestor = request->requestor; @@ -935,10 +936,10 @@ static void handleSelectionRequest(XEvent *event) XSendEvent(_glfw.x11.display, request->requestor, False, 0, &reply); } -static const char *getSelectionString(Atom selection) +static const char* getSelectionString(Atom selection) { - char **selectionString = NULL; - const Atom targets[] = {_glfw.x11.UTF8_STRING, XA_STRING}; + char** selectionString = NULL; + const Atom targets[] = { _glfw.x11.UTF8_STRING, XA_STRING }; const size_t targetCount = sizeof(targets) / sizeof(targets[0]); if (selection == _glfw.x11.PRIMARY) @@ -957,9 +958,9 @@ static const char *getSelectionString(Atom selection) _glfw_free(*selectionString); *selectionString = NULL; - for (size_t i = 0; i < targetCount; i++) + for (size_t i = 0; i < targetCount; i++) { - char *data; + char* data; Atom actualType; int actualFormat; unsigned long itemCount, bytesAfter; @@ -986,7 +987,7 @@ static const char *getSelectionString(Atom selection) XCheckIfEvent(_glfw.x11.display, &dummy, isSelPropNewValueNotify, - (XPointer)¬ification); + (XPointer) ¬ification); XGetWindowProperty(_glfw.x11.display, notification.xselection.requestor, @@ -999,19 +1000,19 @@ static const char *getSelectionString(Atom selection) &actualFormat, &itemCount, &bytesAfter, - (unsigned char **)&data); + (unsigned char**) &data); if (actualType == _glfw.x11.INCR) { size_t size = 1; - char *string = NULL; + char* string = NULL; for (;;) { while (!XCheckIfEvent(_glfw.x11.display, &dummy, isSelPropNewValueNotify, - (XPointer)¬ification)) + (XPointer) ¬ification)) { waitForX11Event(NULL); } @@ -1028,7 +1029,7 @@ static const char *getSelectionString(Atom selection) &actualFormat, &itemCount, &bytesAfter, - (unsigned char **)&data); + (unsigned char**) &data); if (itemCount) { @@ -1080,7 +1081,7 @@ static const char *getSelectionString(Atom selection) // Make the specified window and its video mode active on its monitor // -static void acquireMonitor(_GLFWwindow *window) +static void acquireMonitor(_GLFWwindow* window) { if (_glfw.x11.saver.count == 0) { @@ -1119,7 +1120,7 @@ static void acquireMonitor(_GLFWwindow *window) // Remove the window and restore the original video mode // -static void releaseMonitor(_GLFWwindow *window) +static void releaseMonitor(_GLFWwindow* window) { if (window->monitor->window != window) return; @@ -1167,10 +1168,10 @@ static void processEvent(XEvent *event) { if (event->type == _glfw.x11.xkb.eventBase + XkbEventCode) { - if (((XkbEvent *)event)->any.xkb_type == XkbStateNotify && - (((XkbEvent *)event)->state.changed & XkbGroupStateMask)) + if (((XkbEvent*) event)->any.xkb_type == XkbStateNotify && + (((XkbEvent*) event)->state.changed & XkbGroupStateMask)) { - _glfw.x11.xkb.group = ((XkbEvent *)event)->state.group; + _glfw.x11.xkb.group = ((XkbEvent*) event)->state.group; } return; @@ -1181,7 +1182,7 @@ static void processEvent(XEvent *event) { if (_glfw.x11.xi.available) { - _GLFWwindow *window = _glfw.x11.disabledCursorWindow; + _GLFWwindow* window = _glfw.x11.disabledCursorWindow; if (window && window->rawMouseMotion && @@ -1189,10 +1190,10 @@ static void processEvent(XEvent *event) XGetEventData(_glfw.x11.display, &event->xcookie) && event->xcookie.evtype == XI_RawMotion) { - XIRawEvent *re = event->xcookie.data; + XIRawEvent* re = event->xcookie.data; if (re->valuators.mask_len) { - const double *values = re->raw_values; + const double* values = re->raw_values; double xpos = window->virtualCursorPosX; double ypos = window->virtualCursorPosY; @@ -1221,11 +1222,11 @@ static void processEvent(XEvent *event) return; } - _GLFWwindow *window = NULL; + _GLFWwindow* window = NULL; if (XFindContext(_glfw.x11.display, event->xany.window, _glfw.x11.context, - (XPointer *)&window) != 0) + (XPointer*) &window) != 0) { // This is an event for a window that has already been destroyed return; @@ -1233,385 +1234,128 @@ static void processEvent(XEvent *event) switch (event->type) { - case ReparentNotify: - { - window->x11.parent = event->xreparent.parent; - return; - } - - case KeyPress: - { - const int key = translateKey(keycode); - const int mods = translateState(event->xkey.state); - const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); - - if (window->x11.ic) + case ReparentNotify: { - // HACK: Do not report the key press events duplicated by XIM - // Duplicate key releases are filtered out implicitly by - // the GLFW key repeat logic in _glfwInputKey - // A timestamp per key is used to handle simultaneous keys - // NOTE: Always allow the first event for each key through - // (the server never sends a timestamp of zero) - // NOTE: Timestamp difference is compared to handle wrap-around - Time diff = event->xkey.time - window->x11.keyPressTimes[keycode]; - if (diff == event->xkey.time || (diff > 0 && diff < ((Time)1 << 31))) + window->x11.parent = event->xreparent.parent; + return; + } + + case KeyPress: + { + const int key = translateKey(keycode); + const int mods = translateState(event->xkey.state); + const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); + + if (window->x11.ic) { - if (keycode) - _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); - - window->x11.keyPressTimes[keycode] = event->xkey.time; - } - - if (!filtered) - { - int count; - Status status; - char buffer[100]; - char *chars = buffer; - - count = Xutf8LookupString(window->x11.ic, - &event->xkey, - buffer, sizeof(buffer) - 1, - NULL, &status); - - if (status == XBufferOverflow) + // HACK: Do not report the key press events duplicated by XIM + // Duplicate key releases are filtered out implicitly by + // the GLFW key repeat logic in _glfwInputKey + // A timestamp per key is used to handle simultaneous keys + // NOTE: Always allow the first event for each key through + // (the server never sends a timestamp of zero) + // NOTE: Timestamp difference is compared to handle wrap-around + Time diff = event->xkey.time - window->x11.keyPressTimes[keycode]; + if (diff == event->xkey.time || (diff > 0 && diff < ((Time)1 << 31))) { - chars = _glfw_calloc(count + 1, 1); + if (keycode) + _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); + + window->x11.keyPressTimes[keycode] = event->xkey.time; + } + + if (!filtered) + { + int count; + Status status; + char buffer[100]; + char* chars = buffer; + count = Xutf8LookupString(window->x11.ic, &event->xkey, - chars, count, + buffer, sizeof(buffer) - 1, NULL, &status); - } - if (status == XLookupChars || status == XLookupBoth) - { - const char *c = chars; - chars[count] = '\0'; - while (c - chars < count) - _glfwInputChar(window, decodeUTF8(&c), mods, plain); - } - - if (chars != buffer) - _glfw_free(chars); - } - } - else - { - KeySym keysym; - XLookupString(&event->xkey, NULL, 0, &keysym, NULL); - - _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); - - const uint32_t codepoint = _glfwKeySym2Unicode(keysym); - if (codepoint != GLFW_INVALID_CODEPOINT) - _glfwInputChar(window, codepoint, mods, plain); - } - - return; - } - - case KeyRelease: - { - const int key = translateKey(keycode); - const int mods = translateState(event->xkey.state); - - if (!_glfw.x11.xkb.detectable) - { - // HACK: Key repeat events will arrive as KeyRelease/KeyPress - // pairs with similar or identical time stamps - // The key repeat logic in _glfwInputKey expects only key - // presses to repeat, so detect and discard release events - if (XEventsQueued(_glfw.x11.display, QueuedAfterReading)) - { - XEvent next; - XPeekEvent(_glfw.x11.display, &next); - - if (next.type == KeyPress && - next.xkey.window == event->xkey.window && - next.xkey.keycode == keycode) - { - // HACK: The time of repeat events sometimes doesn't - // match that of the press event, so add an - // epsilon - // Toshiyuki Takahashi can press a button - // 16 times per second so it's fairly safe to - // assume that no human is pressing the key 50 - // times per second (value is ms) - if ((next.xkey.time - event->xkey.time) < 20) + if (status == XBufferOverflow) { - // This is very likely a server-generated key repeat - // event, so ignore it - return; + chars = _glfw_calloc(count + 1, 1); + count = Xutf8LookupString(window->x11.ic, + &event->xkey, + chars, count, + NULL, &status); + } + + if (status == XLookupChars || status == XLookupBoth) + { + const char* c = chars; + chars[count] = '\0'; + while (c - chars < count) + _glfwInputChar(window, decodeUTF8(&c), mods, plain); + } + + if (chars != buffer) + _glfw_free(chars); + } + } + else + { + KeySym keysym; + XLookupString(&event->xkey, NULL, 0, &keysym, NULL); + + _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); + + const uint32_t codepoint = _glfwKeySym2Unicode(keysym); + if (codepoint != GLFW_INVALID_CODEPOINT) + _glfwInputChar(window, codepoint, mods, plain); + } + + return; + } + + case KeyRelease: + { + const int key = translateKey(keycode); + const int mods = translateState(event->xkey.state); + + if (!_glfw.x11.xkb.detectable) + { + // HACK: Key repeat events will arrive as KeyRelease/KeyPress + // pairs with similar or identical time stamps + // The key repeat logic in _glfwInputKey expects only key + // presses to repeat, so detect and discard release events + if (XEventsQueued(_glfw.x11.display, QueuedAfterReading)) + { + XEvent next; + XPeekEvent(_glfw.x11.display, &next); + + if (next.type == KeyPress && + next.xkey.window == event->xkey.window && + next.xkey.keycode == keycode) + { + // HACK: The time of repeat events sometimes doesn't + // match that of the press event, so add an + // epsilon + // Toshiyuki Takahashi can press a button + // 16 times per second so it's fairly safe to + // assume that no human is pressing the key 50 + // times per second (value is ms) + if ((next.xkey.time - event->xkey.time) < 20) + { + // This is very likely a server-generated key repeat + // event, so ignore it + return; + } } } } - } - _glfwInputKey(window, key, keycode, GLFW_RELEASE, mods); - return; - } - - case ButtonPress: - { - const int mods = translateState(event->xbutton.state); - - if (event->xbutton.button == Button1) - _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods); - else if (event->xbutton.button == Button2) - _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_MIDDLE, GLFW_PRESS, mods); - else if (event->xbutton.button == Button3) - _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, mods); - - // Modern X provides scroll events as mouse button presses - else if (event->xbutton.button == Button4) - _glfwInputScroll(window, 0.0, 1.0); - else if (event->xbutton.button == Button5) - _glfwInputScroll(window, 0.0, -1.0); - else if (event->xbutton.button == Button6) - _glfwInputScroll(window, 1.0, 0.0); - else if (event->xbutton.button == Button7) - _glfwInputScroll(window, -1.0, 0.0); - - else - { - // Additional buttons after 7 are treated as regular buttons - // We subtract 4 to fill the gap left by scroll input above - _glfwInputMouseClick(window, - event->xbutton.button - Button1 - 4, - GLFW_PRESS, - mods); - } - - return; - } - - case ButtonRelease: - { - const int mods = translateState(event->xbutton.state); - - if (event->xbutton.button == Button1) - { - _glfwInputMouseClick(window, - GLFW_MOUSE_BUTTON_LEFT, - GLFW_RELEASE, - mods); - } - else if (event->xbutton.button == Button2) - { - _glfwInputMouseClick(window, - GLFW_MOUSE_BUTTON_MIDDLE, - GLFW_RELEASE, - mods); - } - else if (event->xbutton.button == Button3) - { - _glfwInputMouseClick(window, - GLFW_MOUSE_BUTTON_RIGHT, - GLFW_RELEASE, - mods); - } - else if (event->xbutton.button > Button7) - { - // Additional buttons after 7 are treated as regular buttons - // We subtract 4 to fill the gap left by scroll input above - _glfwInputMouseClick(window, - event->xbutton.button - Button1 - 4, - GLFW_RELEASE, - mods); - } - - return; - } - - case EnterNotify: - { - // XEnterWindowEvent is XCrossingEvent - const int x = event->xcrossing.x; - const int y = event->xcrossing.y; - - // HACK: This is a workaround for WMs (KWM, Fluxbox) that otherwise - // ignore the defined cursor for hidden cursor mode - if (window->cursorMode == GLFW_CURSOR_HIDDEN) - updateCursorImage(window); - - _glfwInputCursorEnter(window, GLFW_TRUE); - _glfwInputCursorPos(window, x, y); - - window->x11.lastCursorPosX = x; - window->x11.lastCursorPosY = y; - return; - } - - case LeaveNotify: - { - _glfwInputCursorEnter(window, GLFW_FALSE); - return; - } - - case MotionNotify: - { - const int x = event->xmotion.x; - const int y = event->xmotion.y; - - if (x != window->x11.warpCursorPosX || - y != window->x11.warpCursorPosY) - { - // The cursor was moved by something other than GLFW - - if (window->cursorMode == GLFW_CURSOR_DISABLED) - { - if (_glfw.x11.disabledCursorWindow != window) - return; - if (window->rawMouseMotion) - return; - - const int dx = x - window->x11.lastCursorPosX; - const int dy = y - window->x11.lastCursorPosY; - - _glfwInputCursorPos(window, - window->virtualCursorPosX + dx, - window->virtualCursorPosY + dy); - } - else - _glfwInputCursorPos(window, x, y); - } - - window->x11.lastCursorPosX = x; - window->x11.lastCursorPosY = y; - return; - } - - case ConfigureNotify: - { - if (event->xconfigure.width != window->x11.width || - event->xconfigure.height != window->x11.height) - { - _glfwInputFramebufferSize(window, - event->xconfigure.width, - event->xconfigure.height); - - _glfwInputWindowSize(window, - event->xconfigure.width, - event->xconfigure.height); - - window->x11.width = event->xconfigure.width; - window->x11.height = event->xconfigure.height; - } - - int xpos = event->xconfigure.x; - int ypos = event->xconfigure.y; - - // NOTE: ConfigureNotify events from the server are in local - // coordinates, so if we are reparented we need to translate - // the position into root (screen) coordinates - if (!event->xany.send_event && window->x11.parent != _glfw.x11.root) - { - _glfwGrabErrorHandlerX11(); - - Window dummy; - XTranslateCoordinates(_glfw.x11.display, - window->x11.parent, - _glfw.x11.root, - xpos, ypos, - &xpos, &ypos, - &dummy); - - _glfwReleaseErrorHandlerX11(); - if (_glfw.x11.errorCode == BadWindow) - return; - } - - if (xpos != window->x11.xpos || ypos != window->x11.ypos) - { - _glfwInputWindowPos(window, xpos, ypos); - window->x11.xpos = xpos; - window->x11.ypos = ypos; - } - - return; - } - - case ClientMessage: - { - // Custom client message, probably from the window manager - - if (filtered) + _glfwInputKey(window, key, keycode, GLFW_RELEASE, mods); return; - - if (event->xclient.message_type == None) - return; - - 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) - { - // The window manager was asked to close the window, for - // example by the user pressing a 'close' window decoration - // button - _glfwInputWindowCloseRequest(window); - } - else if (protocol == _glfw.x11.NET_WM_PING) - { - // The window manager is pinging the application to ensure - // it's still responding to events - - XEvent reply = *event; - reply.xclient.window = _glfw.x11.root; - - XSendEvent(_glfw.x11.display, _glfw.x11.root, - False, - SubstructureNotifyMask | SubstructureRedirectMask, - &reply); - } } - else if (event->xclient.message_type == _glfw.x11.XdndEnter) + + case ButtonPress: { - // A drag operation has entered the window - unsigned long count; - Atom *formats = NULL; - const GLFWbool list = event->xclient.data.l[1] & 1; - - _glfw.x11.xdnd.source = event->xclient.data.l[0]; - _glfw.x11.xdnd.version = event->xclient.data.l[1] >> 24; - _glfw.x11.xdnd.format = None; - - if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION) - return; - - if (list) - { - count = _glfwGetWindowPropertyX11(_glfw.x11.xdnd.source, - _glfw.x11.XdndTypeList, - XA_ATOM, - (unsigned char **)&formats); - } - else - { - count = 3; - formats = (Atom *)event->xclient.data.l + 2; - } - - for (unsigned int i = 0; i < count; i++) - { - if (formats[i] == _glfw.x11.text_uri_list) - { - _glfw.x11.xdnd.format = _glfw.x11.text_uri_list; - break; - } - } - - if (list && formats) - XFree(formats); - } - else if (event->xclient.message_type == _glfw.x11.XdndDrop) - { - // The drag operation has finished by dropping on the window - Time time = CurrentTime; + const int mods = translateState(event->xbutton.state); if (event->xbutton.button == Button1) _glfwInputMouseClick(window, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods); @@ -1797,221 +1541,299 @@ static void processEvent(XEvent *event) if (filtered) return; - if (_glfw.x11.xdnd.format) - { - if (_glfw.x11.xdnd.version >= 1) - time = event->xclient.data.l[2]; - - // Request the chosen format from the source window - XConvertSelection(_glfw.x11.display, - _glfw.x11.XdndSelection, - _glfw.x11.xdnd.format, - _glfw.x11.XdndSelection, - window->x11.handle, - time); - } - else if (_glfw.x11.xdnd.version >= 2) - { - XEvent reply = {ClientMessage}; - reply.xclient.window = _glfw.x11.xdnd.source; - reply.xclient.message_type = _glfw.x11.XdndFinished; - reply.xclient.format = 32; - reply.xclient.data.l[0] = window->x11.handle; - reply.xclient.data.l[1] = 0; // The drag was rejected - reply.xclient.data.l[2] = None; - - XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, - False, NoEventMask, &reply); - XFlush(_glfw.x11.display); - } - } - else if (event->xclient.message_type == _glfw.x11.XdndPosition) - { - // The drag operation has moved over the window - const int xabs = (event->xclient.data.l[2] >> 16) & 0xffff; - const int yabs = (event->xclient.data.l[2]) & 0xffff; - Window dummy; - int xpos, ypos; - - if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION) + if (event->xclient.message_type == None) return; - XTranslateCoordinates(_glfw.x11.display, - _glfw.x11.root, - window->x11.handle, - xabs, yabs, - &xpos, &ypos, - &dummy); - - _glfwInputCursorPos(window, xpos, ypos); - - XEvent reply = {ClientMessage}; - reply.xclient.window = _glfw.x11.xdnd.source; - reply.xclient.message_type = _glfw.x11.XdndStatus; - reply.xclient.format = 32; - reply.xclient.data.l[0] = window->x11.handle; - reply.xclient.data.l[2] = 0; // Specify an empty rectangle - reply.xclient.data.l[3] = 0; - - if (_glfw.x11.xdnd.format) + if (event->xclient.message_type == _glfw.x11.WM_PROTOCOLS) { - // Reply that we are ready to copy the dragged data - reply.xclient.data.l[1] = 1; // Accept with no rectangle - if (_glfw.x11.xdnd.version >= 2) - reply.xclient.data.l[4] = _glfw.x11.XdndActionCopy; - } + const Atom protocol = event->xclient.data.l[0]; + if (protocol == None) + return; - XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, - False, NoEventMask, &reply); - XFlush(_glfw.x11.display); - } - - return; - } - - case SelectionNotify: - { - if (event->xselection.property == _glfw.x11.XdndSelection) - { - // The converted data from the drag operation has arrived - char *data; - const unsigned long result = - _glfwGetWindowPropertyX11(event->xselection.requestor, - event->xselection.property, - event->xselection.target, - (unsigned char **)&data); - - if (result) - { - int count; - char **paths = _glfwParseUriList(data, &count); - - _glfwInputDrop(window, count, (const char **)paths); - - for (int i = 0; i < count; i++) - _glfw_free(paths[i]); - _glfw_free(paths); - } - - if (data) - XFree(data); - - if (_glfw.x11.xdnd.version >= 2) - { - XEvent reply = {ClientMessage}; - reply.xclient.window = _glfw.x11.xdnd.source; - reply.xclient.message_type = _glfw.x11.XdndFinished; - reply.xclient.format = 32; - reply.xclient.data.l[0] = window->x11.handle; - reply.xclient.data.l[1] = result; - reply.xclient.data.l[2] = _glfw.x11.XdndActionCopy; - - XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, - False, NoEventMask, &reply); - XFlush(_glfw.x11.display); - } - } - - return; - } - - case FocusIn: - { - if (event->xfocus.mode == NotifyGrab || - event->xfocus.mode == NotifyUngrab) - { - // Ignore focus events from popup indicator windows, window menu - // key chords and window dragging - return; - } - - if (window->cursorMode == GLFW_CURSOR_DISABLED) - disableCursor(window); - else if (window->cursorMode == GLFW_CURSOR_CAPTURED) - captureCursor(window); - - if (window->x11.ic) - XSetICFocus(window->x11.ic); - - _glfwInputWindowFocus(window, GLFW_TRUE); - return; - } - - case FocusOut: - { - if (event->xfocus.mode == NotifyGrab || - event->xfocus.mode == NotifyUngrab) - { - // Ignore focus events from popup indicator windows, window menu - // key chords and window dragging - return; - } - - if (window->cursorMode == GLFW_CURSOR_DISABLED) - enableCursor(window); - else if (window->cursorMode == GLFW_CURSOR_CAPTURED) - releaseCursor(); - - if (window->x11.ic) - XUnsetICFocus(window->x11.ic); - - if (window->monitor && window->autoIconify) - _glfwIconifyWindowX11(window); - - _glfwInputWindowFocus(window, GLFW_FALSE); - return; - } - - case Expose: - { - _glfwInputWindowDamage(window); - return; - } - - case PropertyNotify: - { - if (event->xproperty.state != PropertyNewValue) - return; - - if (event->xproperty.atom == _glfw.x11.WM_STATE) - { - const int state = getWindowState(window); - if (state != IconicState && state != NormalState) - return; - - const GLFWbool iconified = (state == IconicState); - if (window->x11.iconified != iconified) - { - if (window->monitor) + if (protocol == _glfw.x11.WM_DELETE_WINDOW) { - if (iconified) - releaseMonitor(window); - else - acquireMonitor(window); + // The window manager was asked to close the window, for + // example by the user pressing a 'close' window decoration + // button + _glfwInputWindowCloseRequest(window); + } + else if (protocol == _glfw.x11.NET_WM_PING) + { + // The window manager is pinging the application to ensure + // it's still responding to events + + XEvent reply = *event; + reply.xclient.window = _glfw.x11.root; + + XSendEvent(_glfw.x11.display, _glfw.x11.root, + False, + SubstructureNotifyMask | SubstructureRedirectMask, + &reply); + } + } + else if (event->xclient.message_type == _glfw.x11.XdndEnter) + { + // A drag operation has entered the window + unsigned long count; + Atom* formats = NULL; + const GLFWbool list = event->xclient.data.l[1] & 1; + + _glfw.x11.xdnd.source = event->xclient.data.l[0]; + _glfw.x11.xdnd.version = event->xclient.data.l[1] >> 24; + _glfw.x11.xdnd.format = None; + + if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION) + return; + + if (list) + { + count = _glfwGetWindowPropertyX11(_glfw.x11.xdnd.source, + _glfw.x11.XdndTypeList, + XA_ATOM, + (unsigned char**) &formats); + } + else + { + count = 3; + formats = (Atom*) event->xclient.data.l + 2; } - window->x11.iconified = iconified; - _glfwInputWindowIconify(window, iconified); + for (unsigned int i = 0; i < count; i++) + { + if (formats[i] == _glfw.x11.text_uri_list) + { + _glfw.x11.xdnd.format = _glfw.x11.text_uri_list; + break; + } + } + + if (list && formats) + XFree(formats); } - } - else if (event->xproperty.atom == _glfw.x11.NET_WM_STATE) - { - const GLFWbool maximized = _glfwWindowMaximizedX11(window); - if (window->x11.maximized != maximized) + else if (event->xclient.message_type == _glfw.x11.XdndDrop) { - window->x11.maximized = maximized; - _glfwInputWindowMaximize(window, maximized); + // The drag operation has finished by dropping on the window + Time time = CurrentTime; + + if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION) + return; + + if (_glfw.x11.xdnd.format) + { + if (_glfw.x11.xdnd.version >= 1) + time = event->xclient.data.l[2]; + + // Request the chosen format from the source window + XConvertSelection(_glfw.x11.display, + _glfw.x11.XdndSelection, + _glfw.x11.xdnd.format, + _glfw.x11.XdndSelection, + window->x11.handle, + time); + } + else if (_glfw.x11.xdnd.version >= 2) + { + XEvent reply = { ClientMessage }; + reply.xclient.window = _glfw.x11.xdnd.source; + reply.xclient.message_type = _glfw.x11.XdndFinished; + reply.xclient.format = 32; + reply.xclient.data.l[0] = window->x11.handle; + reply.xclient.data.l[1] = 0; // The drag was rejected + reply.xclient.data.l[2] = None; + + XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, + False, NoEventMask, &reply); + XFlush(_glfw.x11.display); + } } + else if (event->xclient.message_type == _glfw.x11.XdndPosition) + { + // The drag operation has moved over the window + const int xabs = (event->xclient.data.l[2] >> 16) & 0xffff; + const int yabs = (event->xclient.data.l[2]) & 0xffff; + Window dummy; + int xpos, ypos; + + if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION) + return; + + XTranslateCoordinates(_glfw.x11.display, + _glfw.x11.root, + window->x11.handle, + xabs, yabs, + &xpos, &ypos, + &dummy); + + _glfwInputCursorPos(window, xpos, ypos); + + XEvent reply = { ClientMessage }; + reply.xclient.window = _glfw.x11.xdnd.source; + reply.xclient.message_type = _glfw.x11.XdndStatus; + reply.xclient.format = 32; + reply.xclient.data.l[0] = window->x11.handle; + reply.xclient.data.l[2] = 0; // Specify an empty rectangle + reply.xclient.data.l[3] = 0; + + if (_glfw.x11.xdnd.format) + { + // Reply that we are ready to copy the dragged data + reply.xclient.data.l[1] = 1; // Accept with no rectangle + if (_glfw.x11.xdnd.version >= 2) + reply.xclient.data.l[4] = _glfw.x11.XdndActionCopy; + } + + XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, + False, NoEventMask, &reply); + XFlush(_glfw.x11.display); + } + + return; } - return; - } + case SelectionNotify: + { + if (event->xselection.property == _glfw.x11.XdndSelection) + { + // The converted data from the drag operation has arrived + char* data; + const unsigned long result = + _glfwGetWindowPropertyX11(event->xselection.requestor, + event->xselection.property, + event->xselection.target, + (unsigned char**) &data); - case DestroyNotify: - return; + if (result) + { + int count; + char** paths = _glfwParseUriList(data, &count); + + _glfwInputDrop(window, count, (const char**) paths); + + for (int i = 0; i < count; i++) + _glfw_free(paths[i]); + _glfw_free(paths); + } + + if (data) + XFree(data); + + if (_glfw.x11.xdnd.version >= 2) + { + XEvent reply = { ClientMessage }; + reply.xclient.window = _glfw.x11.xdnd.source; + reply.xclient.message_type = _glfw.x11.XdndFinished; + reply.xclient.format = 32; + reply.xclient.data.l[0] = window->x11.handle; + reply.xclient.data.l[1] = result; + reply.xclient.data.l[2] = _glfw.x11.XdndActionCopy; + + XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source, + False, NoEventMask, &reply); + XFlush(_glfw.x11.display); + } + } + + return; + } + + case FocusIn: + { + if (event->xfocus.mode == NotifyGrab || + event->xfocus.mode == NotifyUngrab) + { + // Ignore focus events from popup indicator windows, window menu + // key chords and window dragging + return; + } + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + disableCursor(window); + else if (window->cursorMode == GLFW_CURSOR_CAPTURED) + captureCursor(window); + + if (window->x11.ic) + XSetICFocus(window->x11.ic); + + _glfwInputWindowFocus(window, GLFW_TRUE); + return; + } + + case FocusOut: + { + if (event->xfocus.mode == NotifyGrab || + event->xfocus.mode == NotifyUngrab) + { + // Ignore focus events from popup indicator windows, window menu + // key chords and window dragging + return; + } + + if (window->cursorMode == GLFW_CURSOR_DISABLED) + enableCursor(window); + else if (window->cursorMode == GLFW_CURSOR_CAPTURED) + releaseCursor(); + + if (window->x11.ic) + XUnsetICFocus(window->x11.ic); + + if (window->monitor && window->autoIconify) + _glfwIconifyWindowX11(window); + + _glfwInputWindowFocus(window, GLFW_FALSE); + return; + } + + case Expose: + { + _glfwInputWindowDamage(window); + return; + } + + case PropertyNotify: + { + if (event->xproperty.state != PropertyNewValue) + return; + + if (event->xproperty.atom == _glfw.x11.WM_STATE) + { + const int state = getWindowState(window); + if (state != IconicState && state != NormalState) + return; + + const GLFWbool iconified = (state == IconicState); + if (window->x11.iconified != iconified) + { + if (window->monitor) + { + if (iconified) + releaseMonitor(window); + else + acquireMonitor(window); + } + + window->x11.iconified = iconified; + _glfwInputWindowIconify(window, iconified); + } + } + else if (event->xproperty.atom == _glfw.x11.NET_WM_STATE) + { + const GLFWbool maximized = _glfwWindowMaximizedX11(window); + if (window->x11.maximized != maximized) + { + window->x11.maximized = maximized; + _glfwInputWindowMaximize(window, maximized); + } + } + + return; + } + + case DestroyNotify: + return; } } + ////////////////////////////////////////////////////////////////////////// ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// @@ -2022,7 +1844,7 @@ static void processEvent(XEvent *event) unsigned long _glfwGetWindowPropertyX11(Window window, Atom property, Atom type, - unsigned char **value) + unsigned char** value) { Atom actualType; int actualFormat; @@ -2044,12 +1866,12 @@ unsigned long _glfwGetWindowPropertyX11(Window window, return itemCount; } -GLFWbool _glfwIsVisualTransparentX11(Visual *visual) +GLFWbool _glfwIsVisualTransparentX11(Visual* visual) { if (!_glfw.x11.xrender.available) return GLFW_FALSE; - XRenderPictFormat *pf = XRenderFindVisualFormat(_glfw.x11.display, visual); + XRenderPictFormat* pf = XRenderFindVisualFormat(_glfw.x11.display, visual); return pf && pf->direct.alphaMask; } @@ -2072,24 +1894,24 @@ void _glfwPushSelectionToManagerX11(void) { switch (event.type) { - case SelectionRequest: - handleSelectionRequest(&event); - break; + case SelectionRequest: + handleSelectionRequest(&event); + break; - case SelectionNotify: - { - if (event.xselection.target == _glfw.x11.SAVE_TARGETS) + case SelectionNotify: { - // This means one of two things; either the selection - // was not owned, which means there is no clipboard - // manager, or the transfer to the clipboard manager has - // completed - // In either case, it means we are done here - return; - } + if (event.xselection.target == _glfw.x11.SAVE_TARGETS) + { + // This means one of two things; either the selection + // was not owned, which means there is no clipboard + // manager, or the transfer to the clipboard manager has + // completed + // In either case, it means we are done here + return; + } - break; - } + break; + } } } @@ -2097,11 +1919,11 @@ void _glfwPushSelectionToManagerX11(void) } } -void _glfwCreateInputContextX11(_GLFWwindow *window) +void _glfwCreateInputContextX11(_GLFWwindow* window) { XIMCallback callback; - callback.callback = (XIMProc)inputContextDestroyCallback; - callback.client_data = (XPointer)window; + callback.callback = (XIMProc) inputContextDestroyCallback; + callback.client_data = (XPointer) window; window->x11.ic = XCreateIC(_glfw.x11.im, XNInputStyle, @@ -2129,16 +1951,17 @@ void _glfwCreateInputContextX11(_GLFWwindow *window) } } + ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// -GLFWbool _glfwCreateWindowX11(_GLFWwindow *window, - const _GLFWwndconfig *wndconfig, - const _GLFWctxconfig *ctxconfig, - const _GLFWfbconfig *fbconfig) +GLFWbool _glfwCreateWindowX11(_GLFWwindow* window, + const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) { - Visual *visual = NULL; + Visual* visual = NULL; int depth; if (ctxconfig->client != GLFW_NO_API) @@ -2221,7 +2044,7 @@ GLFWbool _glfwCreateWindowX11(_GLFWwindow *window, return GLFW_TRUE; } -void _glfwDestroyWindowX11(_GLFWwindow *window) +void _glfwDestroyWindowX11(_GLFWwindow* window) { if (_glfw.x11.disabledCursorWindow == window) enableCursor(window); @@ -2243,19 +2066,19 @@ void _glfwDestroyWindowX11(_GLFWwindow *window) XDeleteContext(_glfw.x11.display, window->x11.handle, _glfw.x11.context); XUnmapWindow(_glfw.x11.display, window->x11.handle); XDestroyWindow(_glfw.x11.display, window->x11.handle); - window->x11.handle = (Window)0; + window->x11.handle = (Window) 0; } if (window->x11.colormap) { XFreeColormap(_glfw.x11.display, window->x11.colormap); - window->x11.colormap = (Colormap)0; + window->x11.colormap = (Colormap) 0; } XFlush(_glfw.x11.display); } -void _glfwSetWindowTitleX11(_GLFWwindow *window, const char *title) +void _glfwSetWindowTitleX11(_GLFWwindow* window, const char* title) { if (_glfw.x11.xlib.utf8) { @@ -2266,42 +2089,42 @@ void _glfwSetWindowTitleX11(_GLFWwindow *window, const char *title) NULL, NULL, NULL); } - XChangeProperty(_glfw.x11.display, window->x11.handle, + XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_NAME, _glfw.x11.UTF8_STRING, 8, PropModeReplace, - (unsigned char *)title, strlen(title)); + (unsigned char*) title, strlen(title)); - XChangeProperty(_glfw.x11.display, window->x11.handle, + XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_ICON_NAME, _glfw.x11.UTF8_STRING, 8, PropModeReplace, - (unsigned char *)title, strlen(title)); + (unsigned char*) title, strlen(title)); XFlush(_glfw.x11.display); } -void _glfwSetWindowIconX11(_GLFWwindow *window, int count, const GLFWimage *images) +void _glfwSetWindowIconX11(_GLFWwindow* window, int count, const GLFWimage* images) { if (count) { int longCount = 0; - for (int i = 0; i < count; i++) + for (int i = 0; i < count; i++) longCount += 2 + images[i].width * images[i].height; - unsigned long *icon = _glfw_calloc(longCount, sizeof(unsigned long)); - unsigned long *target = icon; + unsigned long* icon = _glfw_calloc(longCount, sizeof(unsigned long)); + unsigned long* target = icon; - for (int i = 0; i < count; i++) + for (int i = 0; i < count; i++) { *target++ = images[i].width; *target++ = images[i].height; - for (int j = 0; j < images[i].width * images[i].height; j++) + for (int j = 0; j < images[i].width * images[i].height; j++) { - *target++ = (((unsigned long)images[i].pixels[j * 4 + 0]) << 16) | - (((unsigned long)images[i].pixels[j * 4 + 1]) << 8) | - (((unsigned long)images[i].pixels[j * 4 + 2]) << 0) | - (((unsigned long)images[i].pixels[j * 4 + 3]) << 24); + *target++ = (((unsigned long) images[i].pixels[j * 4 + 0]) << 16) | + (((unsigned long) images[i].pixels[j * 4 + 1]) << 8) | + (((unsigned long) images[i].pixels[j * 4 + 2]) << 0) | + (((unsigned long) images[i].pixels[j * 4 + 3]) << 24); } } @@ -2315,7 +2138,7 @@ void _glfwSetWindowIconX11(_GLFWwindow *window, int count, const GLFWimage *imag _glfw.x11.NET_WM_ICON, XA_CARDINAL, 32, PropModeReplace, - (unsigned char *)icon, + (unsigned char*) icon, longCount); _glfw_free(icon); @@ -2329,7 +2152,7 @@ void _glfwSetWindowIconX11(_GLFWwindow *window, int count, const GLFWimage *imag XFlush(_glfw.x11.display); } -void _glfwGetWindowPosX11(_GLFWwindow *window, int *xpos, int *ypos) +void _glfwGetWindowPosX11(_GLFWwindow* window, int* xpos, int* ypos) { Window dummy; int x, y; @@ -2343,14 +2166,14 @@ void _glfwGetWindowPosX11(_GLFWwindow *window, int *xpos, int *ypos) *ypos = y; } -void _glfwSetWindowPosX11(_GLFWwindow *window, int xpos, int ypos) +void _glfwSetWindowPosX11(_GLFWwindow* window, int xpos, int ypos) { // HACK: Explicitly setting PPosition to any value causes some WMs, notably // Compiz and Metacity, to honor the position of unmapped windows if (!_glfwWindowVisibleX11(window)) { long supplied; - XSizeHints *hints = XAllocSizeHints(); + XSizeHints* hints = XAllocSizeHints(); if (XGetWMNormalHints(_glfw.x11.display, window->x11.handle, hints, &supplied)) { @@ -2367,7 +2190,7 @@ void _glfwSetWindowPosX11(_GLFWwindow *window, int xpos, int ypos) XFlush(_glfw.x11.display); } -void _glfwGetWindowSizeX11(_GLFWwindow *window, int *width, int *height) +void _glfwGetWindowSizeX11(_GLFWwindow* window, int* width, int* height) { XWindowAttributes attribs; XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &attribs); @@ -2378,7 +2201,7 @@ void _glfwGetWindowSizeX11(_GLFWwindow *window, int *width, int *height) *height = attribs.height; } -void _glfwSetWindowSizeX11(_GLFWwindow *window, int width, int height) +void _glfwSetWindowSizeX11(_GLFWwindow* window, int width, int height) { if (window->monitor) { @@ -2396,7 +2219,7 @@ void _glfwSetWindowSizeX11(_GLFWwindow *window, int width, int height) XFlush(_glfw.x11.display); } -void _glfwSetWindowSizeLimitsX11(_GLFWwindow *window, +void _glfwSetWindowSizeLimitsX11(_GLFWwindow* window, int minwidth, int minheight, int maxwidth, int maxheight) { @@ -2406,7 +2229,7 @@ void _glfwSetWindowSizeLimitsX11(_GLFWwindow *window, XFlush(_glfw.x11.display); } -void _glfwSetWindowAspectRatioX11(_GLFWwindow *window, int numer, int denom) +void _glfwSetWindowAspectRatioX11(_GLFWwindow* window, int numer, int denom) { int width, height; _glfwGetWindowSizeX11(window, &width, &height); @@ -2414,16 +2237,16 @@ void _glfwSetWindowAspectRatioX11(_GLFWwindow *window, int numer, int denom) XFlush(_glfw.x11.display); } -void _glfwGetFramebufferSizeX11(_GLFWwindow *window, int *width, int *height) +void _glfwGetFramebufferSizeX11(_GLFWwindow* window, int* width, int* height) { _glfwGetWindowSizeX11(window, width, height); } -void _glfwGetWindowFrameSizeX11(_GLFWwindow *window, - int *left, int *top, - int *right, int *bottom) +void _glfwGetWindowFrameSizeX11(_GLFWwindow* window, + int* left, int* top, + int* right, int* bottom) { - long *extents = NULL; + long* extents = NULL; if (window->monitor || !window->decorated) return; @@ -2450,7 +2273,7 @@ void _glfwGetWindowFrameSizeX11(_GLFWwindow *window, while (!XCheckIfEvent(_glfw.x11.display, &event, isFrameExtentsEvent, - (XPointer)window)) + (XPointer) window)) { if (!waitForX11Event(&timeout)) { @@ -2464,7 +2287,7 @@ void _glfwGetWindowFrameSizeX11(_GLFWwindow *window, if (_glfwGetWindowPropertyX11(window->x11.handle, _glfw.x11.NET_FRAME_EXTENTS, XA_CARDINAL, - (unsigned char **)&extents) == 4) + (unsigned char**) &extents) == 4) { if (left) *left = extents[0]; @@ -2480,7 +2303,7 @@ void _glfwGetWindowFrameSizeX11(_GLFWwindow *window, XFree(extents); } -void _glfwGetWindowContentScaleX11(_GLFWwindow *window, float *xscale, float *yscale) +void _glfwGetWindowContentScaleX11(_GLFWwindow* window, float* xscale, float* yscale) { if (xscale) *xscale = _glfw.x11.contentScaleX; @@ -2488,7 +2311,7 @@ void _glfwGetWindowContentScaleX11(_GLFWwindow *window, float *xscale, float *ys *yscale = _glfw.x11.contentScaleY; } -void _glfwIconifyWindowX11(_GLFWwindow *window) +void _glfwIconifyWindowX11(_GLFWwindow* window) { if (window->x11.overrideRedirect) { @@ -2503,7 +2326,7 @@ void _glfwIconifyWindowX11(_GLFWwindow *window) XFlush(_glfw.x11.display); } -void _glfwRestoreWindowX11(_GLFWwindow *window) +void _glfwRestoreWindowX11(_GLFWwindow* window) { if (window->x11.overrideRedirect) { @@ -2537,7 +2360,7 @@ void _glfwRestoreWindowX11(_GLFWwindow *window) XFlush(_glfw.x11.display); } -void _glfwMaximizeWindowX11(_GLFWwindow *window) +void _glfwMaximizeWindowX11(_GLFWwindow* window) { if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_MAXIMIZED_VERT || @@ -2549,33 +2372,34 @@ void _glfwMaximizeWindowX11(_GLFWwindow *window) if (_glfwWindowVisibleX11(window)) { sendEventToWM(window, - _glfw.x11.NET_WM_STATE, - _NET_WM_STATE_ADD, - _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, - _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ, - 1, 0); + _glfw.x11.NET_WM_STATE, + _NET_WM_STATE_ADD, + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ, + 1, 0); } else { - Atom *states = NULL; + Atom* states = NULL; unsigned long count = _glfwGetWindowPropertyX11(window->x11.handle, _glfw.x11.NET_WM_STATE, XA_ATOM, - (unsigned char **)&states); + (unsigned char**) &states); // NOTE: We don't check for failure as this property may not exist yet // and that's fine (and we'll create it implicitly with append) Atom missing[2] = - { - _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, - _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ}; + { + _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT, + _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ + }; unsigned long missingCount = 2; - for (unsigned long i = 0; i < count; i++) + for (unsigned long i = 0; i < count; i++) { - for (unsigned long j = 0; j < missingCount; j++) + for (unsigned long j = 0; j < missingCount; j++) { if (states[i] == missing[j]) { @@ -2594,14 +2418,14 @@ void _glfwMaximizeWindowX11(_GLFWwindow *window) XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_STATE, XA_ATOM, 32, PropModeAppend, - (unsigned char *)missing, + (unsigned char*) missing, missingCount); } XFlush(_glfw.x11.display); } -void _glfwShowWindowX11(_GLFWwindow *window) +void _glfwShowWindowX11(_GLFWwindow* window) { if (_glfwWindowVisibleX11(window)) return; @@ -2610,13 +2434,13 @@ void _glfwShowWindowX11(_GLFWwindow *window) waitForVisibilityNotify(window); } -void _glfwHideWindowX11(_GLFWwindow *window) +void _glfwHideWindowX11(_GLFWwindow* window) { XUnmapWindow(_glfw.x11.display, window->x11.handle); XFlush(_glfw.x11.display); } -void _glfwRequestWindowAttentionX11(_GLFWwindow *window) +void _glfwRequestWindowAttentionX11(_GLFWwindow* window) { if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_DEMANDS_ATTENTION) return; @@ -2628,7 +2452,7 @@ void _glfwRequestWindowAttentionX11(_GLFWwindow *window) 0, 1, 0); } -void _glfwFocusWindowX11(_GLFWwindow *window) +void _glfwFocusWindowX11(_GLFWwindow* window) { if (_glfw.x11.NET_ACTIVE_WINDOW) sendEventToWM(window, _glfw.x11.NET_ACTIVE_WINDOW, 1, 0, 0, 0, 0); @@ -2642,8 +2466,8 @@ void _glfwFocusWindowX11(_GLFWwindow *window) XFlush(_glfw.x11.display); } -void _glfwSetWindowMonitorX11(_GLFWwindow *window, - _GLFWmonitor *monitor, +void _glfwSetWindowMonitorX11(_GLFWwindow* window, + _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate) @@ -2699,7 +2523,7 @@ void _glfwSetWindowMonitorX11(_GLFWwindow *window, XFlush(_glfw.x11.display); } -GLFWbool _glfwWindowFocusedX11(_GLFWwindow *window) +GLFWbool _glfwWindowFocusedX11(_GLFWwindow* window) { Window focused; int state; @@ -2708,21 +2532,21 @@ GLFWbool _glfwWindowFocusedX11(_GLFWwindow *window) return window->x11.handle == focused; } -GLFWbool _glfwWindowIconifiedX11(_GLFWwindow *window) +GLFWbool _glfwWindowIconifiedX11(_GLFWwindow* window) { return getWindowState(window) == IconicState; } -GLFWbool _glfwWindowVisibleX11(_GLFWwindow *window) +GLFWbool _glfwWindowVisibleX11(_GLFWwindow* window) { XWindowAttributes wa; XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &wa); return wa.map_state == IsViewable; } -GLFWbool _glfwWindowMaximizedX11(_GLFWwindow *window) +GLFWbool _glfwWindowMaximizedX11(_GLFWwindow* window) { - Atom *states; + Atom* states; GLFWbool maximized = GLFW_FALSE; if (!_glfw.x11.NET_WM_STATE || @@ -2736,9 +2560,9 @@ GLFWbool _glfwWindowMaximizedX11(_GLFWwindow *window) _glfwGetWindowPropertyX11(window->x11.handle, _glfw.x11.NET_WM_STATE, XA_ATOM, - (unsigned char **)&states); + (unsigned char**) &states); - for (unsigned long i = 0; i < count; i++) + for (unsigned long i = 0; i < count; i++) { if (states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_VERT || states[i] == _glfw.x11.NET_WM_STATE_MAXIMIZED_HORZ) @@ -2754,7 +2578,7 @@ GLFWbool _glfwWindowMaximizedX11(_GLFWwindow *window) return maximized; } -GLFWbool _glfwWindowHoveredX11(_GLFWwindow *window) +GLFWbool _glfwWindowHoveredX11(_GLFWwindow* window) { Window w = _glfw.x11.root; while (w) @@ -2782,7 +2606,7 @@ GLFWbool _glfwWindowHoveredX11(_GLFWwindow *window) return GLFW_FALSE; } -GLFWbool _glfwFramebufferTransparentX11(_GLFWwindow *window) +GLFWbool _glfwFramebufferTransparentX11(_GLFWwindow* window) { if (!window->x11.transparent) return GLFW_FALSE; @@ -2790,14 +2614,14 @@ GLFWbool _glfwFramebufferTransparentX11(_GLFWwindow *window) return XGetSelectionOwner(_glfw.x11.display, _glfw.x11.NET_WM_CM_Sx) != None; } -void _glfwSetWindowResizableX11(_GLFWwindow *window, GLFWbool enabled) +void _glfwSetWindowResizableX11(_GLFWwindow* window, GLFWbool enabled) { int width, height; _glfwGetWindowSizeX11(window, &width, &height); updateNormalHints(window, width, height); } -void _glfwSetWindowDecoratedX11(_GLFWwindow *window, GLFWbool enabled) +void _glfwSetWindowDecoratedX11(_GLFWwindow* window, GLFWbool enabled) { struct { @@ -2815,11 +2639,11 @@ void _glfwSetWindowDecoratedX11(_GLFWwindow *window, GLFWbool enabled) _glfw.x11.MOTIF_WM_HINTS, _glfw.x11.MOTIF_WM_HINTS, 32, PropModeReplace, - (unsigned char *)&hints, + (unsigned char*) &hints, sizeof(hints) / sizeof(long)); } -void _glfwSetWindowFloatingX11(_GLFWwindow *window, GLFWbool enabled) +void _glfwSetWindowFloatingX11(_GLFWwindow* window, GLFWbool enabled) { if (!_glfw.x11.NET_WM_STATE || !_glfw.x11.NET_WM_STATE_ABOVE) return; @@ -2835,12 +2659,12 @@ void _glfwSetWindowFloatingX11(_GLFWwindow *window, GLFWbool enabled) } else { - Atom *states = NULL; + Atom* states = NULL; const unsigned long count = _glfwGetWindowPropertyX11(window->x11.handle, _glfw.x11.NET_WM_STATE, XA_ATOM, - (unsigned char **)&states); + (unsigned char**) &states); // NOTE: We don't check for failure as this property may not exist yet // and that's fine (and we'll create it implicitly with append) @@ -2849,7 +2673,7 @@ void _glfwSetWindowFloatingX11(_GLFWwindow *window, GLFWbool enabled) { unsigned long i; - for (i = 0; i < count; i++) + for (i = 0; i < count; i++) { if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE) break; @@ -2860,20 +2684,20 @@ void _glfwSetWindowFloatingX11(_GLFWwindow *window, GLFWbool enabled) XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_STATE, XA_ATOM, 32, PropModeAppend, - (unsigned char *)&_glfw.x11.NET_WM_STATE_ABOVE, + (unsigned char*) &_glfw.x11.NET_WM_STATE_ABOVE, 1); } } else if (states) { - for (unsigned long i = 0; i < count; i++) + for (unsigned long i = 0; i < count; i++) { if (states[i] == _glfw.x11.NET_WM_STATE_ABOVE) { states[i] = states[count - 1]; XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_STATE, XA_ATOM, 32, - PropModeReplace, (unsigned char *)states, count - 1); + PropModeReplace, (unsigned char*) states, count - 1); break; } } @@ -2886,7 +2710,7 @@ void _glfwSetWindowFloatingX11(_GLFWwindow *window, GLFWbool enabled) XFlush(_glfw.x11.display); } -void _glfwSetWindowMousePassthroughX11(_GLFWwindow *window, GLFWbool enabled) +void _glfwSetWindowMousePassthroughX11(_GLFWwindow* window, GLFWbool enabled) { if (!_glfw.x11.xshape.available) return; @@ -2905,20 +2729,20 @@ void _glfwSetWindowMousePassthroughX11(_GLFWwindow *window, GLFWbool enabled) } } -float _glfwGetWindowOpacityX11(_GLFWwindow *window) +float _glfwGetWindowOpacityX11(_GLFWwindow* window) { float opacity = 1.f; if (XGetSelectionOwner(_glfw.x11.display, _glfw.x11.NET_WM_CM_Sx)) { - CARD32 *value = NULL; + CARD32* value = NULL; if (_glfwGetWindowPropertyX11(window->x11.handle, _glfw.x11.NET_WM_WINDOW_OPACITY, XA_CARDINAL, - (unsigned char **)&value)) + (unsigned char**) &value)) { - opacity = (float)(*value / (double)0xffffffffu); + opacity = (float) (*value / (double) 0xffffffffu); } if (value) @@ -2928,12 +2752,12 @@ float _glfwGetWindowOpacityX11(_GLFWwindow *window) return opacity; } -void _glfwSetWindowOpacityX11(_GLFWwindow *window, float opacity) +void _glfwSetWindowOpacityX11(_GLFWwindow* window, float opacity) { - const CARD32 value = (CARD32)(0xffffffffu * (double)opacity); + const CARD32 value = (CARD32) (0xffffffffu * (double) opacity); XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.NET_WM_WINDOW_OPACITY, XA_CARDINAL, 32, - PropModeReplace, (unsigned char *)&value, 1); + PropModeReplace, (unsigned char*) &value, 1); } void _glfwSetRawMouseMotionX11(_GLFWwindow *window, GLFWbool enabled) @@ -2961,8 +2785,7 @@ void _glfwPollEventsX11(void) #if defined(GLFW_BUILD_LINUX_JOYSTICK) if (_glfw.joysticksInitialized) - _glfwPollAllJoysticks(); - _glfwDetectJoystickConnectionLinux(); + _glfwDetectJoystickConnectionLinux(); #endif XPending(_glfw.x11.display); @@ -2973,7 +2796,7 @@ void _glfwPollEventsX11(void) processEvent(&event); } - _GLFWwindow *window = _glfw.x11.disabledCursorWindow; + _GLFWwindow* window = _glfw.x11.disabledCursorWindow; if (window) { int width, height; @@ -3008,7 +2831,7 @@ void _glfwPostEmptyEventX11(void) writeEmptyEvent(); } -void _glfwGetCursorPosX11(_GLFWwindow *window, double *xpos, double *ypos) +void _glfwGetCursorPosX11(_GLFWwindow* window, double* xpos, double* ypos) { Window root, child; int rootX, rootY, childX, childY; @@ -3025,18 +2848,18 @@ void _glfwGetCursorPosX11(_GLFWwindow *window, double *xpos, double *ypos) *ypos = childY; } -void _glfwSetCursorPosX11(_GLFWwindow *window, double x, double y) +void _glfwSetCursorPosX11(_GLFWwindow* window, double x, double y) { // Store the new position so it can be recognized later - window->x11.warpCursorPosX = (int)x; - window->x11.warpCursorPosY = (int)y; + window->x11.warpCursorPosX = (int) x; + window->x11.warpCursorPosY = (int) y; XWarpPointer(_glfw.x11.display, None, window->x11.handle, - 0, 0, 0, 0, (int)x, (int)y); + 0,0,0,0, (int) x, (int) y); XFlush(_glfw.x11.display); } -void _glfwSetCursorModeX11(_GLFWwindow *window, int mode) +void _glfwSetCursorModeX11(_GLFWwindow* window, int mode) { if (_glfwWindowFocusedX11(window)) { @@ -3075,7 +2898,7 @@ void _glfwSetCursorModeX11(_GLFWwindow *window, int mode) XFlush(_glfw.x11.display); } -const char *_glfwGetScancodeNameX11(int scancode) +const char* _glfwGetScancodeNameX11(int scancode) { if (!_glfw.x11.xkb.available) return NULL; @@ -3112,8 +2935,8 @@ int _glfwGetKeyScancodeX11(int key) return _glfw.x11.scancodes[key]; } -GLFWbool _glfwCreateCursorX11(_GLFWcursor *cursor, - const GLFWimage *image, +GLFWbool _glfwCreateCursorX11(_GLFWcursor* cursor, + const GLFWimage* image, int xhot, int yhot) { cursor->x11.handle = _glfwCreateNativeCursorX11(image, xhot, yhot); @@ -3123,51 +2946,51 @@ GLFWbool _glfwCreateCursorX11(_GLFWcursor *cursor, return GLFW_TRUE; } -GLFWbool _glfwCreateStandardCursorX11(_GLFWcursor *cursor, int shape) +GLFWbool _glfwCreateStandardCursorX11(_GLFWcursor* cursor, int shape) { if (_glfw.x11.xcursor.handle) { - char *theme = XcursorGetTheme(_glfw.x11.display); + char* theme = XcursorGetTheme(_glfw.x11.display); if (theme) { const int size = XcursorGetDefaultSize(_glfw.x11.display); - const char *name = NULL; + const char* name = NULL; switch (shape) { - case GLFW_ARROW_CURSOR: - name = "default"; - break; - case GLFW_IBEAM_CURSOR: - name = "text"; - break; - case GLFW_CROSSHAIR_CURSOR: - name = "crosshair"; - break; - case GLFW_POINTING_HAND_CURSOR: - name = "pointer"; - break; - case GLFW_RESIZE_EW_CURSOR: - name = "ew-resize"; - break; - case GLFW_RESIZE_NS_CURSOR: - name = "ns-resize"; - break; - case GLFW_RESIZE_NWSE_CURSOR: - name = "nwse-resize"; - break; - case GLFW_RESIZE_NESW_CURSOR: - name = "nesw-resize"; - break; - case GLFW_RESIZE_ALL_CURSOR: - name = "all-scroll"; - break; - case GLFW_NOT_ALLOWED_CURSOR: - name = "not-allowed"; - break; + case GLFW_ARROW_CURSOR: + name = "default"; + break; + case GLFW_IBEAM_CURSOR: + name = "text"; + break; + case GLFW_CROSSHAIR_CURSOR: + name = "crosshair"; + break; + case GLFW_POINTING_HAND_CURSOR: + name = "pointer"; + break; + case GLFW_RESIZE_EW_CURSOR: + name = "ew-resize"; + break; + case GLFW_RESIZE_NS_CURSOR: + name = "ns-resize"; + break; + case GLFW_RESIZE_NWSE_CURSOR: + name = "nwse-resize"; + break; + case GLFW_RESIZE_NESW_CURSOR: + name = "nesw-resize"; + break; + case GLFW_RESIZE_ALL_CURSOR: + name = "all-scroll"; + break; + case GLFW_NOT_ALLOWED_CURSOR: + name = "not-allowed"; + break; } - XcursorImage *image = XcursorLibraryLoadImage(name, theme, size); + XcursorImage* image = XcursorLibraryLoadImage(name, theme, size); if (image) { cursor->x11.handle = XcursorImageLoadCursor(_glfw.x11.display, image); @@ -3182,31 +3005,31 @@ GLFWbool _glfwCreateStandardCursorX11(_GLFWcursor *cursor, int shape) switch (shape) { - case GLFW_ARROW_CURSOR: - native = XC_left_ptr; - break; - case GLFW_IBEAM_CURSOR: - native = XC_xterm; - break; - case GLFW_CROSSHAIR_CURSOR: - native = XC_crosshair; - break; - case GLFW_POINTING_HAND_CURSOR: - native = XC_hand2; - break; - case GLFW_RESIZE_EW_CURSOR: - native = XC_sb_h_double_arrow; - break; - case GLFW_RESIZE_NS_CURSOR: - native = XC_sb_v_double_arrow; - break; - case GLFW_RESIZE_ALL_CURSOR: - native = XC_fleur; - break; - default: - _glfwInputError(GLFW_CURSOR_UNAVAILABLE, - "X11: Standard cursor shape unavailable"); - return GLFW_FALSE; + case GLFW_ARROW_CURSOR: + native = XC_left_ptr; + break; + case GLFW_IBEAM_CURSOR: + native = XC_xterm; + break; + case GLFW_CROSSHAIR_CURSOR: + native = XC_crosshair; + break; + case GLFW_POINTING_HAND_CURSOR: + native = XC_hand2; + break; + case GLFW_RESIZE_EW_CURSOR: + native = XC_sb_h_double_arrow; + break; + case GLFW_RESIZE_NS_CURSOR: + native = XC_sb_v_double_arrow; + break; + case GLFW_RESIZE_ALL_CURSOR: + native = XC_fleur; + break; + default: + _glfwInputError(GLFW_CURSOR_UNAVAILABLE, + "X11: Standard cursor shape unavailable"); + return GLFW_FALSE; } cursor->x11.handle = XCreateFontCursor(_glfw.x11.display, native); @@ -3221,13 +3044,13 @@ GLFWbool _glfwCreateStandardCursorX11(_GLFWcursor *cursor, int shape) return GLFW_TRUE; } -void _glfwDestroyCursorX11(_GLFWcursor *cursor) +void _glfwDestroyCursorX11(_GLFWcursor* cursor) { if (cursor->x11.handle) XFreeCursor(_glfw.x11.display, cursor->x11.handle); } -void _glfwSetCursorX11(_GLFWwindow *window, _GLFWcursor *cursor) +void _glfwSetCursorX11(_GLFWwindow* window, _GLFWcursor* cursor) { if (window->cursorMode == GLFW_CURSOR_NORMAL || window->cursorMode == GLFW_CURSOR_CAPTURED) @@ -3237,9 +3060,9 @@ void _glfwSetCursorX11(_GLFWwindow *window, _GLFWcursor *cursor) } } -void _glfwSetClipboardStringX11(const char *string) +void _glfwSetClipboardStringX11(const char* string) { - char *copy = _glfw_strdup(string); + char* copy = _glfw_strdup(string); _glfw_free(_glfw.x11.clipboardString); _glfw.x11.clipboardString = copy; @@ -3256,12 +3079,12 @@ void _glfwSetClipboardStringX11(const char *string) } } -const char *_glfwGetClipboardStringX11(void) +const char* _glfwGetClipboardStringX11(void) { return getSelectionString(_glfw.x11.CLIPBOARD); } -EGLenum _glfwGetEGLPlatformX11(EGLint **attribs) +EGLenum _glfwGetEGLPlatformX11(EGLint** attribs) { if (_glfw.egl.ANGLE_platform_angle) { @@ -3302,15 +3125,15 @@ EGLNativeDisplayType _glfwGetEGLNativeDisplayX11(void) return _glfw.x11.display; } -EGLNativeWindowType _glfwGetEGLNativeWindowX11(_GLFWwindow *window) +EGLNativeWindowType _glfwGetEGLNativeWindowX11(_GLFWwindow* window) { if (_glfw.egl.platform) return &window->x11.handle; else - return (EGLNativeWindowType)window->x11.handle; + return (EGLNativeWindowType) window->x11.handle; } -void _glfwGetRequiredInstanceExtensionsX11(char **extensions) +void _glfwGetRequiredInstanceExtensionsX11(char** extensions) { if (!_glfw.vk.KHR_surface) return; @@ -3342,8 +3165,8 @@ GLFWbool _glfwGetPhysicalDevicePresentationSupportX11(VkInstance instance, { PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR vkGetPhysicalDeviceXcbPresentationSupportKHR = - (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR) - vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR"); + (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR) + vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR"); if (!vkGetPhysicalDeviceXcbPresentationSupportKHR) { _glfwInputError(GLFW_API_UNAVAILABLE, @@ -3351,7 +3174,7 @@ GLFWbool _glfwGetPhysicalDevicePresentationSupportX11(VkInstance instance, return GLFW_FALSE; } - xcb_connection_t *connection = XGetXCBConnection(_glfw.x11.display); + xcb_connection_t* connection = XGetXCBConnection(_glfw.x11.display); if (!connection) { _glfwInputError(GLFW_PLATFORM_ERROR, @@ -3368,8 +3191,8 @@ GLFWbool _glfwGetPhysicalDevicePresentationSupportX11(VkInstance instance, { PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR vkGetPhysicalDeviceXlibPresentationSupportKHR = - (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR) - vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); + (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR) + vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); if (!vkGetPhysicalDeviceXlibPresentationSupportKHR) { _glfwInputError(GLFW_API_UNAVAILABLE, @@ -3385,9 +3208,9 @@ GLFWbool _glfwGetPhysicalDevicePresentationSupportX11(VkInstance instance, } VkResult _glfwCreateWindowSurfaceX11(VkInstance instance, - _GLFWwindow *window, - const VkAllocationCallbacks *allocator, - VkSurfaceKHR *surface) + _GLFWwindow* window, + const VkAllocationCallbacks* allocator, + VkSurfaceKHR* surface) { if (_glfw.vk.KHR_xcb_surface && _glfw.x11.x11xcb.handle) { @@ -3395,7 +3218,7 @@ VkResult _glfwCreateWindowSurfaceX11(VkInstance instance, VkXcbSurfaceCreateInfoKHR sci; PFN_vkCreateXcbSurfaceKHR vkCreateXcbSurfaceKHR; - xcb_connection_t *connection = XGetXCBConnection(_glfw.x11.display); + xcb_connection_t* connection = XGetXCBConnection(_glfw.x11.display); if (!connection) { _glfwInputError(GLFW_PLATFORM_ERROR, @@ -3459,11 +3282,12 @@ VkResult _glfwCreateWindowSurfaceX11(VkInstance instance, } } + ////////////////////////////////////////////////////////////////////////// ////// GLFW native API ////// ////////////////////////////////////////////////////////////////////////// -GLFWAPI Display *glfwGetX11Display(void) +GLFWAPI Display* glfwGetX11Display(void) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); @@ -3476,7 +3300,7 @@ GLFWAPI Display *glfwGetX11Display(void) return _glfw.x11.display; } -GLFWAPI Window glfwGetX11Window(GLFWwindow *handle) +GLFWAPI Window glfwGetX11Window(GLFWwindow* handle) { _GLFW_REQUIRE_INIT_OR_RETURN(None); @@ -3492,7 +3316,7 @@ GLFWAPI Window glfwGetX11Window(GLFWwindow *handle) return window->x11.handle; } -GLFWAPI void glfwSetX11SelectionString(const char *string) +GLFWAPI void glfwSetX11SelectionString(const char* string) { assert(string != NULL); @@ -3520,7 +3344,7 @@ GLFWAPI void glfwSetX11SelectionString(const char *string) } } -GLFWAPI const char *glfwGetX11SelectionString(void) +GLFWAPI const char* glfwGetX11SelectionString(void) { _GLFW_REQUIRE_INIT_OR_RETURN(NULL); @@ -3534,3 +3358,4 @@ GLFWAPI const char *glfwGetX11SelectionString(void) } #endif // _GLFW_X11 + From 094db02c39f5e003d1932ee4eb6b27cbf29816a5 Mon Sep 17 00:00:00 2001 From: NarrikSynthfox <80410683+NarrikSynthfox@users.noreply.github.com> Date: Wed, 10 Apr 2024 13:08:34 -0400 Subject: [PATCH 2/2] Update docs, readme, news, and contributors --- CONTRIBUTORS.md | 3 ++ README.md | 2 +- docs/input.md | 79 +++++++++++++++++++++++++++++++++++++++++++++++++ docs/news.md | 15 ++++++++++ 4 files changed, 98 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 1371aedb..d3349217 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -294,6 +294,9 @@ video tutorials. - Jonas Ådahl - Lasse Öörni - Leonard König + - Beoran + - Enthuin + - Narrik Synthfox - All the unmentioned and anonymous contributors in the GLFW community, for bug reports, patches, feedback, testing and encouragement diff --git a/README.md b/README.md index 2718e45e..44f3fadd 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ information on what to include when reporting a bug. - [Null] Added EGL context creation on Mesa via `EGL_MESA_platform_surfaceless` - [EGL] Allowed native access on Wayland with `GLFW_CONTEXT_CREATION_API` set to `GLFW_NATIVE_CONTEXT_API` (#2518) - + - Added `GLFWgamepadstatefun`, `glfwSetGamepadStateCallback`, `GLFWjoystickbuttonfun`,`glfwSetJoystickButtonCallback`, `GLFWjoystickaxisfun`, `glfwSetJoystickAxisCallback`, `GLFWjoystickhatfun`, and `glfwSetJoystickHatCallback` for event-based joystick/gamepad input. ## Contact diff --git a/docs/input.md b/docs/input.md index 3ef1aebe..acfcfcdb 100644 --- a/docs/input.md +++ b/docs/input.md @@ -911,6 +911,85 @@ righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8, were recently added to SDL. The input modifiers `+`, `-` and `~` are supported and described above. +### Event-based joystick and gamepad input {#joystick_input_event} + +If you wish to be notified when a button on a joystick is pressed or released, set a joystick button callback. + +```c +glfwSetJoystickButtonCallback(joystick_button_callback); +``` + +The callback function receives the joystick id, the [joystick button](@ref joystick_button) that was pressed or released, and action. + +```c +void joystick_button_callback(int jid, int button, int action) +{ + if (button == 0 && action == GLFW_PRESS) + jump(); +} +``` + +The action is one of `GLFW_PRESS` or `GLFW_RELEASE` + +If you wish to be notified when an axis on a joystick is moved, set a joystick axis callback. + +```c +glfwSetJoystickAxisCallback(joystick_axis_callback); +``` + +The callback function receives the joystick id, [joystick axis](@ref joystick_axis) that was moved, and float value from -1.0 to 1.0 for the axis. + +```c +void joystick_axis_callback(int jid, int axis, float value) +{ + if (axis == 0){ + if(value == -1.0f) + move_left(); + else if(value == 1.0f) + move_right(); + } +} +``` + +If you wish to be notified when a hat on a joystick is moved, set a joystick hat callback. + +```c +glfwSetJoystickHatCallback(joystick_hat_callback); +``` + +The callback function receives the joystick id, hat, and the [hat states](@ref hat_state). + +```c +void joystick_hat_callback(int jid, int hat, int position) +{ + if(hat == 0 && position == GLFW_HAT_UP) + move_up(); +} +``` + +If you wish to be notified when the state of a gamepad is updated, set a gamepad state callback. This callback will occur every time any button, axis, or hat updates, so with this, you will have to handle checks for if a value is changed. + +```c +glfwSetGamepadStateCallback(gamepad_state_callback); +``` + +The callback function recieves the joystick id and the gamepad state. + +```c +bool jumpButtonHeld = false; + +gamepad_state_callback(int jid, GLFWgamepadstate state){ + if (state.buttons[GLFW_GAMEPAD_BUTTON_A] && !jumpButtonHeld) + { + input_jump(); + jumpButtonHeld = true; + } + else if (!state.buttons[GLFW_GAMEPAD_BUTTON_A] && jumpButtonHeld) + { + jumpButtonHeld = false; + } +} +``` ## Time input {#time} diff --git a/docs/news.md b/docs/news.md index 148d0871..cf02ac1d 100644 --- a/docs/news.md +++ b/docs/news.md @@ -14,6 +14,11 @@ values over 8. For compatibility with older versions, the @ref GLFW_UNLIMITED_MOUSE_BUTTONS input mode needs to be set to make use of this. +### Callback functions for gamepad state, joystick buttons, joystick axes, and joystick hat inputs {#joystick_input_callbacks} + +GLFW now has callback functions for [gamepad state](@ref glfwSetGamepadStateCallback), [joystick buttons](@ref glfwSetJoystickButtonCallback), [joystick axes](@ref glfwSetJoystickAxisCallback), and [joystick hats](@ref glfwSetJoystickHatCallback), allowing for +event-based inputs for joysticks and gamepads. + ## Caveats {#caveats} ## Deprecations {#deprecations} @@ -24,8 +29,18 @@ this. ### New functions {#new_functions} +- @ref glfwSetJoystickButtonCallback +- @ref glfwSetJoystickAxisCallback +- @ref glfwSetJoystickHatCallback +- @ref glfwSetGamepadStateCallback + ### New types {#new_types} +- @ref GLFWjoystickbuttonfun +- @ref GLFWjoystickaxisfun +- @ref GLFWjoystickhatfun +- @ref GLFWgamepadstatefun + ### New constants {#new_constants} - @ref GLFW_UNLIMITED_MOUSE_BUTTONS