From a7cb0cb1506792d6893556bc976822e254a89106 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Mon, 9 Mar 2020 21:49:53 +0100 Subject: Add create, destroy, map, and unmap events These can be used to do things when a view is created or destroyed, in particular set up the GL context in a more controlled way. Map and unmap events are also added for when views are shown and hidden so application can react to this as well. Towards the deprecation of puglEnterContext() and puglLeaveContext(), which are prone to abuse. squash! Remove client event stuff --- pugl/detail/implementation.c | 5 +++++ pugl/detail/mac.m | 39 +++++++++++++++++++++++++++++++++++---- pugl/detail/win.c | 13 +++++++++++-- pugl/detail/x11.c | 15 ++++++--------- pugl/pugl.h | 10 +++++++++- test/test_utils.h | 8 ++++++++ 6 files changed, 74 insertions(+), 16 deletions(-) diff --git a/pugl/detail/implementation.c b/pugl/detail/implementation.c index e9e1ae9..5c3da62 100644 --- a/pugl/detail/implementation.c +++ b/pugl/detail/implementation.c @@ -159,6 +159,9 @@ puglNewView(PuglWorld* const world) void puglFreeView(PuglView* view) { + const PuglEvent destroyEvent = {{PUGL_DESTROY, 0}}; + puglDispatchEvent(view, &destroyEvent); + // Remove from world view list PuglWorld* world = view->world; for (size_t i = 0; i < world->numViews; ++i) { @@ -309,6 +312,8 @@ puglDispatchEvent(PuglView* view, const PuglEvent* event) switch (event->type) { case PUGL_NOTHING: break; + case PUGL_CREATE: + case PUGL_DESTROY: case PUGL_CONFIGURE: view->backend->enter(view, NULL); view->eventFunc(view, event); diff --git a/pugl/detail/mac.m b/pugl/detail/mac.m index da1ab35..c083919 100644 --- a/pugl/detail/mac.m +++ b/pugl/detail/mac.m @@ -98,6 +98,21 @@ updateViewRect(PuglView* view) return YES; } +- (void) setIsVisible:(BOOL)flag +{ + if (flag && !puglview->visible) { + const PuglEvent map = {{PUGL_MAP, 0}}; + puglview->eventFunc(puglview, &map); + } else if (!flag && puglview->visible) { + const PuglEvent unmap = {{PUGL_UNMAP, 0}}; + puglview->eventFunc(puglview, &unmap); + } + + puglview->visible = flag; + + [super setIsVisible:flag]; +} + @end @implementation PuglWrapperView @@ -817,15 +832,32 @@ puglCreateWindow(PuglView* view, const char* title) [impl->wrapperView updateTrackingAreas]; + const PuglEvent createEvent = {{PUGL_CREATE, 0}}; + puglDispatchEvent(view, &createEvent); + + const PuglEventConfigure ev = { + PUGL_CONFIGURE, + 0, + view->frame.x, + view->frame.y, + view->frame.width, + view->frame.height, + }; + + puglDispatchEvent(view, (const PuglEvent*)&ev); + return 0; } PuglStatus puglShowWindow(PuglView* view) { - [view->impl->window setIsVisible:YES]; - updateViewRect(view); - view->visible = true; + if (![view->impl->window isVisible]) { + [view->impl->window setIsVisible:YES]; + [view->impl->drawView setNeedsDisplay: YES]; + updateViewRect(view); + } + return PUGL_SUCCESS; } @@ -833,7 +865,6 @@ PuglStatus puglHideWindow(PuglView* view) { [view->impl->window setIsVisible:NO]; - view->visible = false; return PUGL_SUCCESS; } diff --git a/pugl/detail/win.c b/pugl/detail/win.c index b7f03a3..2e0cd96 100644 --- a/pugl/detail/win.c +++ b/pugl/detail/win.c @@ -193,6 +193,9 @@ puglCreateWindow(PuglView* view, const char* title) puglSetFrame(view, view->frame); SetWindowLongPtr(impl->hwnd, GWLP_USERDATA, (LONG_PTR)view); + const PuglEvent createEvent = {{PUGL_CREATE, 0}}; + view->eventFunc(view, &createEvent); + return PUGL_SUCCESS; } @@ -203,7 +206,6 @@ puglShowWindow(PuglView* view) ShowWindow(impl->hwnd, SW_SHOWNORMAL); SetFocus(impl->hwnd); - view->visible = true; return PUGL_SUCCESS; } @@ -213,7 +215,6 @@ puglHideWindow(PuglView* view) PuglInternals* impl = view->impl; ShowWindow(impl->hwnd, SW_HIDE); - view->visible = false; return PUGL_SUCCESS; } @@ -554,9 +555,17 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) case WM_SHOWWINDOW: if (wParam) { handleConfigure(view, &event); + puglDispatchEvent(view, &event); + event.type = PUGL_NOTHING; + RedrawWindow(view->impl->hwnd, NULL, NULL, RDW_INVALIDATE|RDW_ALLCHILDREN|RDW_INTERNALPAINT); } + + if ((bool)wParam != view->visible) { + view->visible = wParam; + event.any.type = wParam ? PUGL_MAP : PUGL_UNMAP; + } break; case WM_SIZE: handleConfigure(view, &event); diff --git a/pugl/detail/x11.c b/pugl/detail/x11.c index cc77f29..d3e4195 100644 --- a/pugl/detail/x11.c +++ b/pugl/detail/x11.c @@ -254,6 +254,9 @@ puglCreateWindow(PuglView* view, const char* title) fprintf(stderr, "warning: XCreateIC failed\n"); } + const PuglEvent createEvent = {{PUGL_CREATE, 0}}; + puglDispatchEvent(view, &createEvent); + return PUGL_SUCCESS; } @@ -425,17 +428,11 @@ translateEvent(PuglView* view, XEvent xevent) case VisibilityNotify: view->visible = xevent.xvisibility.state != VisibilityFullyObscured; break; - case MapNotify: { - XWindowAttributes attrs = {0}; - XGetWindowAttributes(view->impl->display, view->impl->win, &attrs); - event.type = PUGL_CONFIGURE; - event.configure.x = attrs.x; - event.configure.y = attrs.y; - event.configure.width = attrs.width; - event.configure.height = attrs.height; + case MapNotify: + event.type = PUGL_MAP; break; - } case UnmapNotify: + event.type = PUGL_UNMAP; view->visible = false; break; case ConfigureNotify: diff --git a/pugl/pugl.h b/pugl/pugl.h index d14c086..04f5343 100644 --- a/pugl/pugl.h +++ b/pugl/pugl.h @@ -168,7 +168,11 @@ typedef enum { PUGL_NOTHING, ///< No event PUGL_BUTTON_PRESS, ///< Mouse button pressed, a #PuglEventButton PUGL_BUTTON_RELEASE, ///< Mouse button released, a #PuglEventButton - PUGL_CONFIGURE, ///< View moved and/or resized, a #PuglEventConfigure + PUGL_CREATE, ///< View created, a #PuglEventAny + PUGL_DESTROY, ///< View destroyed, a #PuglEventAny + PUGL_MAP, ///< View made visible, a #PuglEventAny + PUGL_UNMAP, ///< View made invisible, a #PuglEventAny + PUGL_CONFIGURE, ///< View moved/resized, a #PuglEventConfigure PUGL_EXPOSE, ///< View must be drawn, a #PuglEventExpose PUGL_CLOSE, ///< View will be closed, a #PuglEventAny PUGL_KEY_PRESS, ///< Key pressed, a #PuglEventKey @@ -390,6 +394,10 @@ typedef struct { This is a union of all event types. The #type must be checked to determine which fields are safe to access. A pointer to PuglEvent can either be cast to the appropriate type, or the union members used. + + The graphics system may only be accessed when handling certain events. The + graphics context is active for #PUGL_CREATE, #PUGL_DESTROY, #PUGL_CONFIGURE, + and #PUGL_EXPOSE, but only enabled for drawing for #PUGL_EXPOSE. */ typedef union { PuglEventAny any; ///< Valid for all event types diff --git a/test/test_utils.h b/test/test_utils.h index 80d279b..aca3376 100644 --- a/test/test_utils.h +++ b/test/test_utils.h @@ -124,6 +124,14 @@ printEvent(const PuglEvent* event, const char* prefix, const bool verbose) if (verbose) { switch (event->type) { + case PUGL_CREATE: + return fprintf(stderr, "%sCreate\n", prefix); + case PUGL_DESTROY: + return fprintf(stderr, "%sDestroy\n", prefix); + case PUGL_MAP: + return fprintf(stderr, "%sMap\n", prefix); + case PUGL_UNMAP: + return fprintf(stderr, "%sUnmap\n", prefix); case PUGL_CONFIGURE: return PRINT("%sConfigure " PFMT " " PFMT "\n", prefix, -- cgit v1.2.1