aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pugl/detail/mac.m48
-rw-r--r--pugl/detail/win.c29
-rw-r--r--pugl/detail/x11.c19
-rw-r--r--pugl/detail/x11.h1
-rw-r--r--pugl/pugl.h29
-rw-r--r--test/test_utils.h8
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;
}