diff options
-rw-r--r-- | pugl/detail/mac.m | 48 | ||||
-rw-r--r-- | pugl/detail/win.c | 29 | ||||
-rw-r--r-- | pugl/detail/x11.c | 19 | ||||
-rw-r--r-- | pugl/detail/x11.h | 1 | ||||
-rw-r--r-- | pugl/pugl.h | 29 | ||||
-rw-r--r-- | test/test_utils.h | 8 |
6 files changed, 128 insertions, 6 deletions
diff --git a/pugl/detail/mac.m b/pugl/detail/mac.m index c083919..837d3cc 100644 --- a/pugl/detail/mac.m +++ b/pugl/detail/mac.m @@ -947,6 +947,32 @@ puglPollEvents(PuglWorld* world, const double timeout) return PUGL_SUCCESS; } +PuglStatus puglSendEvent(PuglView* view, const PuglEvent* event) +{ + if (event->type == PUGL_CLIENT) { + PuglWrapperView* wrapper = view->impl->wrapperView; + const NSWindow* window = [wrapper window]; + const NSRect rect = [wrapper frame]; + const NSPoint center = {NSMidX(rect), NSMidY(rect)}; + + NSEvent* nsevent = [NSEvent + otherEventWithType:NSApplicationDefined + location:center + modifierFlags:0 + timestamp:[[NSProcessInfo processInfo] systemUptime] + windowNumber:window.windowNumber + context:nil + subtype:PUGL_CLIENT + data1:event->client.data1 + data2:event->client.data2]; + + [view->world->impl->app postEvent:nsevent atStart:false]; + return PUGL_SUCCESS; + } + + return PUGL_UNSUPPORTED_TYPE; +} + #ifndef PUGL_DISABLE_DEPRECATED PuglStatus puglWaitForEvent(PuglView* view) @@ -955,6 +981,25 @@ puglWaitForEvent(PuglView* view) } #endif +static void +dispatchClientEvent(PuglWorld* world, NSEvent* ev) +{ + NSWindow* win = [ev window]; + NSPoint loc = [ev locationInWindow]; + for (size_t i = 0; i < world->numViews; ++i) { + PuglView* view = world->views[i]; + PuglWrapperView* wrapper = view->impl->wrapperView; + if ([wrapper window] == win && NSPointInRect(loc, [wrapper frame])) { + const PuglEventClient event = {PUGL_CLIENT, + 0, + [ev data1], + [ev data2]}; + + view->eventFunc(view, (const PuglEvent*)&event); + } + } +} + PUGL_API PuglStatus puglDispatchEvents(PuglWorld* world) { @@ -970,6 +1015,9 @@ puglDispatchEvents(PuglWorld* world) // Event is later, put it back for the next iteration and return [world->impl->app postEvent:ev atStart:true]; break; + } else if ([ev type] == NSApplicationDefined && + [ev subtype] == PUGL_CLIENT) { + dispatchClientEvent(world, ev); } [world->impl->app sendEvent: ev]; diff --git a/pugl/detail/win.c b/pugl/detail/win.c index 2e0cd96..bf60ddb 100644 --- a/pugl/detail/win.c +++ b/pugl/detail/win.c @@ -47,10 +47,11 @@ # define GWLP_USERDATA (-21) #endif -#define PUGL_LOCAL_CLOSE_MSG (WM_USER + 50) -#define PUGL_LOCAL_MARK_MSG (WM_USER + 51) -#define PUGL_RESIZE_TIMER_ID 9461 -#define PUGL_URGENT_TIMER_ID 9462 +#define PUGL_LOCAL_CLOSE_MSG (WM_USER + 50) +#define PUGL_LOCAL_MARK_MSG (WM_USER + 51) +#define PUGL_LOCAL_CLIENT_MSG (WM_USER + 52) +#define PUGL_RESIZE_TIMER_ID 9461 +#define PUGL_URGENT_TIMER_ID 9462 typedef BOOL (WINAPI *PFN_SetProcessDPIAware)(void); @@ -700,6 +701,11 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) break; case WM_SYSCHAR: return TRUE; + case PUGL_LOCAL_CLIENT_MSG: + event.client.type = PUGL_CLIENT; + event.client.data1 = (uintptr_t)wParam; + event.client.data2 = (uintptr_t)lParam; + break; case WM_QUIT: case PUGL_LOCAL_CLOSE_MSG: event.any.type = PUGL_CLOSE; @@ -738,6 +744,21 @@ puglRequestAttention(PuglView* view) return PUGL_SUCCESS; } +PuglStatus +puglSendEvent(PuglView* view, const PuglEvent* event) +{ + if (event->type == PUGL_CLIENT) { + PostMessage(view->impl->hwnd, + PUGL_LOCAL_CLIENT_MSG, + (WPARAM)event->client.data1, + (LPARAM)event->client.data2); + + return PUGL_SUCCESS; + } + + return PUGL_UNSUPPORTED_TYPE; +} + #ifndef PUGL_DISABLE_DEPRECATED PuglStatus puglWaitForEvent(PuglView* PUGL_UNUSED(view)) diff --git a/pugl/detail/x11.c b/pugl/detail/x11.c index 9c9fdfa..ae00f73 100644 --- a/pugl/detail/x11.c +++ b/pugl/detail/x11.c @@ -84,6 +84,7 @@ puglInitWorldInternals(void) impl->atoms.UTF8_STRING = XInternAtom(display, "UTF8_STRING", 0); impl->atoms.WM_PROTOCOLS = XInternAtom(display, "WM_PROTOCOLS", 0); impl->atoms.WM_DELETE_WINDOW = XInternAtom(display, "WM_DELETE_WINDOW", 0); + impl->atoms.PUGL_CLIENT_MSG = XInternAtom(display, "_PUGL_CLIENT_MSG", 0); impl->atoms.NET_WM_NAME = XInternAtom(display, "_NET_WM_NAME", 0); impl->atoms.NET_WM_STATE = XInternAtom(display, "_NET_WM_STATE", 0); impl->atoms.NET_WM_STATE_DEMANDS_ATTENTION = @@ -429,6 +430,10 @@ translateEvent(PuglView* view, XEvent xevent) if (protocol == atoms->WM_DELETE_WINDOW) { event.type = PUGL_CLOSE; } + } else if (xevent.xclient.message_type == atoms->PUGL_CLIENT_MSG) { + event.type = PUGL_CLIENT; + event.client.data1 = xevent.xclient.data.l[0]; + event.client.data2 = xevent.xclient.data.l[1]; } break; case VisibilityNotify: @@ -613,6 +618,18 @@ puglEventToX(PuglView* view, const PuglEvent* event) break; } + case PUGL_CLIENT: + xev.xclient.type = ClientMessage; + xev.xclient.serial = 0; + xev.xclient.send_event = True; + xev.xclient.display = view->impl->display; + xev.xclient.window = view->impl->win; + xev.xclient.message_type = view->world->impl->atoms.PUGL_CLIENT_MSG; + xev.xclient.format = 32; + xev.xclient.data.l[0] = event->client.data1; + xev.xclient.data.l[1] = event->client.data2; + break; + default: break; } @@ -620,7 +637,7 @@ puglEventToX(PuglView* view, const PuglEvent* event) return xev; } -static PuglStatus +PuglStatus puglSendEvent(PuglView* view, const PuglEvent* event) { XEvent xev = puglEventToX(view, event); diff --git a/pugl/detail/x11.h b/pugl/detail/x11.h index 220f3c8..fe8ce01 100644 --- a/pugl/detail/x11.h +++ b/pugl/detail/x11.h @@ -32,6 +32,7 @@ typedef struct { Atom UTF8_STRING; Atom WM_PROTOCOLS; Atom WM_DELETE_WINDOW; + Atom PUGL_CLIENT_MSG; Atom NET_WM_NAME; Atom NET_WM_STATE; Atom NET_WM_STATE_DEMANDS_ATTENTION; diff --git a/pugl/pugl.h b/pugl/pugl.h index 04f5343..53327c8 100644 --- a/pugl/pugl.h +++ b/pugl/pugl.h @@ -183,7 +183,8 @@ typedef enum { PUGL_MOTION_NOTIFY, ///< Pointer moved, a #PuglEventMotion PUGL_SCROLL, ///< Scrolled, a #PuglEventScroll PUGL_FOCUS_IN, ///< Keyboard focus entered view, a #PuglEventFocus - PUGL_FOCUS_OUT ///< Keyboard focus left view, a #PuglEventFocus + PUGL_FOCUS_OUT, ///< Keyboard focus left view, a #PuglEventFocus + PUGL_CLIENT ///< Custom client message, a #PuglEventClient } PuglEventType; /** @@ -389,6 +390,20 @@ typedef struct { } PuglEventFocus; /** + Custom client message event. + + This can be used to send a custom message to a view, which is delivered via + the window system and processed in the event loop as usual. Among other + things, this makes it possible to wake up the event loop for any reason. +*/ +typedef struct { + PuglEventType type; ///< PUGL_CLIENT + PuglEventFlags flags; ///< Bitwise OR of PuglEventFlag values + uintptr_t data1; ///< Client-specific data + uintptr_t data2; ///< Client-specific data +} PuglEventClient; + +/** View event. This is a union of all event types. The #type must be checked to determine @@ -411,6 +426,7 @@ typedef union { PuglEventMotion motion; ///< #PUGL_MOTION_NOTIFY PuglEventScroll scroll; ///< #PUGL_SCROLL PuglEventFocus focus; ///< #PUGL_FOCUS_IN, #PUGL_FOCUS_OUT + PuglEventClient client; ///< #PUGL_CLIENT } PuglEvent; /** @@ -984,6 +1000,17 @@ PUGL_API PuglStatus puglRequestAttention(PuglView* view); /** + Send an event to a view via the window system. + + If supported, the event will be delivered to the view via the event loop + like other events. Note that this function only works for certain event + types, and will return PUGL_UNSUPPORTED_TYPE for events that are not + supported. +*/ +PUGL_API PuglStatus +puglSendEvent(PuglView* view, const PuglEvent* event); + +/** @} */ diff --git a/test/test_utils.h b/test/test_utils.h index aca3376..7dc6e6e 100644 --- a/test/test_utils.h +++ b/test/test_utils.h @@ -14,8 +14,11 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#define __STDC_FORMAT_MACROS 1 + #include "pugl/pugl.h" +#include <inttypes.h> #include <stdarg.h> #include <stdbool.h> #include <stdint.h> @@ -118,6 +121,11 @@ printEvent(const PuglEvent* event, const char* prefix, const bool verbose) return PRINT("%sFocus out%s\n", prefix, event->focus.grab ? " (ungrab)" : ""); + case PUGL_CLIENT: + return PRINT("%sClient %" PRIXPTR " %" PRIXPTR "\n", + prefix, + event->client.data1, + event->client.data2); default: break; } |