diff options
author | David Robillard <d@drobilla.net> | 2019-07-22 18:49:09 +0200 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2019-09-03 08:34:38 +0200 |
commit | 816607027012de0205e144f3edd3fdcfd43db563 (patch) | |
tree | 6baafc16e21b6186c51d9ada7c97116b6a30811c | |
parent | f76954359229c25a6c9d29d6de3e75ab3a25f8dd (diff) |
Add functions to get and set view size and position
-rw-r--r-- | pugl/detail/implementation.c | 22 | ||||
-rw-r--r-- | pugl/detail/mac.h | 2 | ||||
-rw-r--r-- | pugl/detail/mac.m | 98 | ||||
-rw-r--r-- | pugl/detail/mac_cairo.m | 6 | ||||
-rw-r--r-- | pugl/detail/mac_gl.m | 14 | ||||
-rw-r--r-- | pugl/detail/types.h | 3 | ||||
-rw-r--r-- | pugl/detail/win.c | 46 | ||||
-rw-r--r-- | pugl/detail/win.h | 3 | ||||
-rw-r--r-- | pugl/detail/win_cairo.c | 13 | ||||
-rw-r--r-- | pugl/detail/x11.c | 46 | ||||
-rw-r--r-- | pugl/detail/x11_cairo.c | 4 | ||||
-rw-r--r-- | pugl/pugl.h | 31 | ||||
-rw-r--r-- | test/pugl_cairo_test.c | 13 | ||||
-rw-r--r-- | test/pugl_test.c | 4 |
14 files changed, 230 insertions, 75 deletions
diff --git a/pugl/detail/implementation.c b/pugl/detail/implementation.c index 6ec19c2..53af30b 100644 --- a/pugl/detail/implementation.c +++ b/pugl/detail/implementation.c @@ -89,9 +89,9 @@ puglNewView(PuglWorld* const world) return NULL; } - view->world = world; - view->width = 640; - view->height = 480; + view->world = world; + view->frame.width = 640; + view->frame.height = 480; puglSetDefaultHints(view->hints); @@ -138,8 +138,8 @@ puglInitWindowHint(PuglView* view, PuglWindowHint hint, int value) void puglInitWindowSize(PuglView* view, int width, int height) { - view->width = width; - view->height = height; + view->frame.width = width; + view->frame.height = height; } void @@ -218,8 +218,14 @@ puglGetVisible(PuglView* view) void puglGetSize(PuglView* view, int* width, int* height) { - *width = view->width; - *height = view->height; + *width = (int)view->frame.width; + *height = (int)view->frame.height; +} + +PuglRect +puglGetFrame(const PuglView* view) +{ + return view->frame; } void* @@ -293,8 +299,6 @@ puglDispatchEvent(PuglView* view, const PuglEvent* event) case PUGL_NOTHING: break; case PUGL_CONFIGURE: - view->width = (int)event->configure.width; - view->height = (int)event->configure.height; puglEnterContext(view, false); view->eventFunc(view, event); puglLeaveContext(view, false); diff --git a/pugl/detail/mac.h b/pugl/detail/mac.h index 1bd2bbc..0652733 100644 --- a/pugl/detail/mac.h +++ b/pugl/detail/mac.h @@ -33,10 +33,12 @@ NSMutableAttributedString* markedText; NSTimer* timer; NSTimer* urgentTimer; + bool reshaped; } - (void) dispatchConfigure:(NSRect)bounds; - (void) dispatchExpose:(NSRect)rect; +- (void) setReshaped; @end diff --git a/pugl/detail/mac.m b/pugl/detail/mac.m index 3fa700e..b7495f4 100644 --- a/pugl/detail/mac.m +++ b/pugl/detail/mac.m @@ -31,6 +31,31 @@ #include <stdlib.h> +static NSRect +rectToScreen(NSRect rect) +{ + const double screenHeight = [[NSScreen mainScreen] frame].size.height; + + rect.origin.y = screenHeight - rect.origin.y - rect.size.height; + return rect; +} + +static void +updateViewRect(PuglView* view) +{ + NSWindow* const window = view->impl->window; + if (window) { + const double screenHeight = [[NSScreen mainScreen] frame].size.height; + const NSRect frame = [window frame]; + const NSRect content = [window contentRectForFrameRect:frame]; + + view->frame.x = content.origin.x; + view->frame.y = screenHeight - content.origin.y - content.size.height; + view->frame.width = content.size.width; + view->frame.height = content.size.height; + } +} + @implementation PuglWindow - (id) initWithContentRect:(NSRect)contentRect @@ -52,7 +77,7 @@ - (void)setPuglview:(PuglView*)view { puglview = view; - [self setContentSize:NSMakeSize(view->width, view->height)]; + [self setContentSize:NSMakeSize(view->frame.width, view->frame.height)]; } - (BOOL) canBecomeKeyWindow @@ -79,6 +104,22 @@ - (void) dispatchExpose:(NSRect)rect { + if (reshaped) { + updateViewRect(puglview); + + const PuglEventConfigure ev = { + PUGL_CONFIGURE, + 0, + puglview->frame.x, + puglview->frame.y, + puglview->frame.width, + puglview->frame.height, + }; + + puglDispatchEvent(puglview, (const PuglEvent*)&ev); + reshaped = false; + } + const PuglEventExpose ev = { PUGL_EXPOSE, 0, @@ -102,18 +143,9 @@ return YES; } -- (void) dispatchConfigure:(NSRect)bounds +- (void) setReshaped { - const PuglEventConfigure ev = { - PUGL_CONFIGURE, - 0, - bounds.origin.x, - bounds.origin.y, - bounds.size.width, - bounds.size.height, - }; - - puglDispatchEvent(puglview, (const PuglEvent*)&ev); + reshaped = true; } static uint32_t @@ -608,6 +640,13 @@ handleCrossing(PuglWrapperView* view, NSEvent* event, const PuglEventType type) return YES; } +- (void) windowDidMove:(NSNotification*)notification +{ + (void)notification; + + updateViewRect(window->puglview); +} + - (void) windowDidBecomeKey:(NSNotification*)notification { (void)notification; @@ -684,7 +723,8 @@ puglCreateWindow(PuglView* view, const char* title) impl->wrapperView->puglview = view; impl->wrapperView->markedText = [[NSMutableAttributedString alloc] init]; [impl->wrapperView setAutoresizesSubviews:YES]; - [impl->wrapperView initWithFrame:NSMakeRect(0, 0, view->width, view->height)]; + [impl->wrapperView initWithFrame: + NSMakeRect(0, 0, view->frame.width, view->frame.height)]; [impl->wrapperView addConstraint: puglConstraint(impl->wrapperView, NSLayoutAttributeWidth, view->min_width)]; [impl->wrapperView addConstraint: @@ -712,7 +752,11 @@ puglCreateWindow(PuglView* view, const char* title) initWithBytes:title length:strlen(title) encoding:NSUTF8StringEncoding]; - NSRect frame = NSMakeRect(0, 0, view->min_width, view->min_height); + + const NSRect frame = rectToScreen( + NSMakeRect(view->frame.x, view->frame.y, + view->min_width, view->min_height)); + unsigned style = (NSClosableWindowMask | NSTitledWindowMask | NSMiniaturizableWindowMask ); @@ -757,6 +801,7 @@ void puglShowWindow(PuglView* view) { [view->impl->window setIsVisible:YES]; + updateViewRect(view); view->visible = true; } @@ -896,3 +941,28 @@ puglGetNativeWindow(PuglView* view) { return (PuglNativeWindow)view->impl->wrapperView; } + +PuglStatus +puglSetFrame(PuglView* view, const PuglRect frame) +{ + PuglInternals* const impl = view->impl; + + // Update view frame to exactly the requested frame in Pugl coordinates + view->frame = frame; + + const NSRect rect = NSMakeRect(frame.x, frame.y, frame.width, frame.height); + if (impl->window) { + // Resize window to fit new content rect + const NSRect windowFrame = [ + impl->window frameRectForContentRect:rectToScreen(rect)]; + + [impl->window setFrame:windowFrame display:NO]; + } + + // Resize views + const NSRect drawRect = NSMakeRect(0, 0, frame.width, frame.height); + [impl->wrapperView setFrame:(impl->window ? drawRect : rect)]; + [impl->drawView setFrame:drawRect]; + + return PUGL_SUCCESS; +} diff --git a/pugl/detail/mac_cairo.m b/pugl/detail/mac_cairo.m index ce03486..fcb4f07 100644 --- a/pugl/detail/mac_cairo.m +++ b/pugl/detail/mac_cairo.m @@ -50,7 +50,7 @@ PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; [super resizeWithOldSuperviewSize:oldSize]; - [wrapper dispatchConfigure:[self bounds]]; + [wrapper setReshaped]; } - (void) drawRect:(NSRect)rect @@ -74,7 +74,7 @@ puglMacCairoCreate(PuglView* view) PuglCairoView* drawView = [PuglCairoView alloc]; drawView->puglview = view; - [drawView initWithFrame:NSMakeRect(0, 0, view->width, view->height)]; + [drawView initWithFrame:NSMakeRect(0, 0, view->frame.width, view->frame.height)]; if (view->hints[PUGL_RESIZABLE]) { [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; } else { @@ -111,7 +111,7 @@ puglMacCairoEnter(PuglView* view, bool drawing) CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; drawView->surface = cairo_quartz_surface_create_for_cg_context( - context, view->width, view->height); + context, view->frame.width, view->frame.height); drawView->cr = cairo_create(drawView->surface); diff --git a/pugl/detail/mac_gl.m b/pugl/detail/mac_gl.m index 1392989..58d815d 100644 --- a/pugl/detail/mac_gl.m +++ b/pugl/detail/mac_gl.m @@ -82,15 +82,7 @@ typedef NSUInteger NSWindowStyleMask; PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; [super reshape]; - [wrapper dispatchConfigure:[self bounds]]; -} - -- (void) update -{ - PuglWrapperView* wrapper = (PuglWrapperView*)[self superview]; - - [super update]; - [wrapper dispatchConfigure:[self bounds]]; + [wrapper setReshaped]; } - (void) drawRect:(NSRect)rect @@ -112,9 +104,11 @@ puglMacGlCreate(PuglView* view) { PuglInternals* impl = view->impl; PuglOpenGLView* drawView = [PuglOpenGLView alloc]; + const NSRect rect = NSMakeRect( + 0, 0, view->frame.width, view->frame.height); drawView->puglview = view; - [drawView initWithFrame:NSMakeRect(0, 0, view->width, view->height)]; + [drawView initWithFrame:rect]; if (view->hints[PUGL_RESIZABLE]) { [drawView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; } else { diff --git a/pugl/detail/types.h b/pugl/detail/types.h index e279833..5254f01 100644 --- a/pugl/detail/types.h +++ b/pugl/detail/types.h @@ -56,8 +56,7 @@ struct PuglViewImpl { PuglNativeWindow parent; uintptr_t transient_parent; PuglHints hints; - int width; - int height; + PuglRect frame; int min_width; int min_height; int min_aspect_x; diff --git a/pugl/detail/win.c b/pugl/detail/win.c index 6cd34e3..65ae4ae 100644 --- a/pugl/detail/win.c +++ b/pugl/detail/win.c @@ -406,16 +406,20 @@ handleConfigure(PuglView* view, PuglEvent* event) { RECT rect; GetClientRect(view->impl->hwnd, &rect); - view->width = rect.right - rect.left; - view->height = rect.bottom - rect.top; + view->frame.x = rect.left; + view->frame.y = rect.top; + view->frame.width = rect.right - rect.left; + view->frame.height = rect.bottom - rect.top; event->configure.type = PUGL_CONFIGURE; - event->configure.x = rect.left; - event->configure.y = rect.top; - event->configure.width = view->width; - event->configure.height = view->height; - - view->backend->resize(view, view->width, view->height); + event->configure.x = view->frame.x; + event->configure.y = view->frame.y; + event->configure.width = view->frame.width; + event->configure.height = view->frame.height; + + view->backend->resize(view, + rect.right - rect.left, + rect.bottom - rect.top); return rect; } @@ -745,3 +749,29 @@ puglGetNativeWindow(PuglView* view) { return (PuglNativeWindow)view->impl->hwnd; } + +PuglStatus +puglSetFrame(PuglView* view, const PuglRect frame) +{ + view->frame = frame; + + if (view->impl->hwnd) { + RECT rect = { (long)frame.x, + (long)frame.y, + (long)frame.x + (long)frame.width, + (long)frame.y + (long)frame.height }; + + AdjustWindowRectEx(&rect, puglWinGetWindowFlags(view), + FALSE, + puglWinGetWindowExFlags(view)); + + if (!SetWindowPos(view->impl->hwnd, HWND_TOP, + rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + (SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOZORDER))) { + return PUGL_ERR_UNKNOWN; + } + } + + return PUGL_SUCCESS; +} diff --git a/pugl/detail/win.h b/pugl/detail/win.h index c051eb1..8d6ce12 100644 --- a/pugl/detail/win.h +++ b/pugl/detail/win.h @@ -95,7 +95,8 @@ puglWinCreateWindow(const PuglView* const view, const unsigned winExFlags = puglWinGetWindowExFlags(view); // Calculate total window size to accommodate requested view size - RECT wr = { 0, 0, view->width, view->height }; + RECT wr = { (long)view->frame.x, (long)view->frame.y, + (long)view->frame.width, (long)view->frame.height }; AdjustWindowRectEx(&wr, winFlags, FALSE, winExFlags); // Create window and get drawing context diff --git a/pugl/detail/win_cairo.c b/pugl/detail/win_cairo.c index 49175c1..cbca7e8 100644 --- a/pugl/detail/win_cairo.c +++ b/pugl/detail/win_cairo.c @@ -42,7 +42,7 @@ puglWinCairoCreateDrawContext(PuglView* view) surface->drawDc = CreateCompatibleDC(impl->hdc); surface->drawBitmap = CreateCompatibleBitmap( - impl->hdc, view->width, view->height); + impl->hdc, (int)view->frame.width, (int)view->frame.height); DeleteObject(SelectObject(surface->drawDc, surface->drawBitmap)); @@ -87,7 +87,7 @@ puglWinCairoConfigure(PuglView* view) return st; } - impl->pfd = puglWinGetPixelFormatDescriptor(&view->hints); + impl->pfd = puglWinGetPixelFormatDescriptor(view->hints); impl->pfId = ChoosePixelFormat(impl->hdc, &impl->pfd); if (!SetPixelFormat(impl->hdc, impl->pfId, &impl->pfd)) { @@ -150,7 +150,8 @@ puglWinCairoLeave(PuglView* view, bool drawing) cairo_restore(surface->cr); cairo_surface_flush(surface->surface); - BitBlt(impl->hdc, 0, 0, view->width, view->height, + BitBlt(impl->hdc, + 0, 0, (int)view->frame.width, (int)view->frame.height, surface->drawDc, 0, 0, SRCCOPY); PAINTSTRUCT ps; @@ -162,11 +163,9 @@ puglWinCairoLeave(PuglView* view, bool drawing) static int puglWinCairoResize(PuglView* view, - int width, - int height) + int PUGL_UNUSED(width), + int PUGL_UNUSED(height)) { - view->width = width; - view->height = height; int st = 0; if ((st = puglWinCairoDestroyDrawContext(view)) || (st = puglWinCairoCreateDrawContext(view))) { diff --git a/pugl/detail/x11.c b/pugl/detail/x11.c index b564225..e7b39f8 100644 --- a/pugl/detail/x11.c +++ b/pugl/detail/x11.c @@ -146,6 +146,8 @@ puglCreateWindow(PuglView* view, const char* title) PuglWorld* const world = view->world; PuglX11Atoms* const atoms = &view->world->impl->atoms; Display* const display = world->impl->display; + const int width = (int)view->frame.width; + const int height = (int)view->frame.height; impl->display = display; impl->screen = DefaultScreen(display); @@ -169,7 +171,8 @@ puglCreateWindow(PuglView* view, const char* title) const Window win = impl->win = XCreateWindow( display, xParent, - 0, 0, view->width, view->height, 0, impl->vi->depth, InputOutput, + (int)view->frame.x, (int)view->frame.y, width, height, + 0, impl->vi->depth, InputOutput, impl->vi->visual, CWColormap | CWEventMask, &attr); if (view->backend->create(view)) { @@ -179,10 +182,10 @@ puglCreateWindow(PuglView* view, const char* title) XSizeHints sizeHints = {0}; if (!view->hints[PUGL_RESIZABLE]) { sizeHints.flags = PMinSize|PMaxSize; - sizeHints.min_width = view->width; - sizeHints.min_height = view->height; - sizeHints.max_width = view->width; - sizeHints.max_height = view->height; + sizeHints.min_width = width; + sizeHints.min_height = height; + sizeHints.max_width = width; + sizeHints.max_height = height; } else { if (view->min_width || view->min_height) { sizeHints.flags = PMinSize; @@ -201,8 +204,9 @@ puglCreateWindow(PuglView* view, const char* title) if (title) { XStoreName(display, win, title); - XChangeProperty(display, win, atoms->NET_WM_NAME, atoms->UTF8_STRING, 8, - PropModeReplace, (const uint8_t*)title, strlen(title)); + XChangeProperty(display, win, atoms->NET_WM_NAME, + atoms->UTF8_STRING, 8, PropModeReplace, + (const uint8_t*)title, (int)strlen(title)); } if (!view->parent) { @@ -628,9 +632,14 @@ puglDispatchEvents(PuglWorld* world) puglEnterContext(view, mustExpose); if (configure->type) { - view->width = (int)configure->configure.width; - view->height = (int)configure->configure.height; - view->backend->resize(view, view->width, view->height); + view->frame.x = configure->configure.x; + view->frame.y = configure->configure.y; + view->frame.width = configure->configure.width; + view->frame.height = configure->configure.height; + + view->backend->resize(view, + (int)view->frame.width, + (int)view->frame.height); view->eventFunc(view, &view->impl->pendingConfigure); } @@ -667,7 +676,7 @@ puglPostRedisplay(PuglView* view) XExposeEvent ev = {Expose, 0, True, view->impl->display, view->impl->win, 0, 0, - view->width, view->height, + view->frame.width, view->frame.height, 0}; XSendEvent(view->impl->display, view->impl->win, False, 0, (XEvent*)&ev); @@ -678,3 +687,18 @@ puglGetNativeWindow(PuglView* view) { return (PuglNativeWindow)view->impl->win; } + +PuglStatus +puglSetFrame(PuglView* view, const PuglRect frame) +{ + view->frame = frame; + + if (view->impl->win && + XMoveResizeWindow(view->world->impl->display, view->impl->win, + (int)frame.x, (int)frame.y, + (int)frame.width, (int)frame.height)) { + return PUGL_ERR_UNKNOWN; + } + + return PUGL_SUCCESS; +} diff --git a/pugl/detail/x11_cairo.c b/pugl/detail/x11_cairo.c index d5e2ed7..550144a 100644 --- a/pugl/detail/x11_cairo.c +++ b/pugl/detail/x11_cairo.c @@ -55,8 +55,8 @@ static int puglX11CairoCreate(PuglView* view) { PuglInternals* const impl = view->impl; - const int width = view->width; - const int height = view->height; + const int width = (int)view->frame.width; + const int height = (int)view->frame.height; PuglX11CairoSurface surface = { 0 }; surface.back = cairo_xlib_surface_create( diff --git a/pugl/pugl.h b/pugl/pugl.h index 3639a96..1bd49bb 100644 --- a/pugl/pugl.h +++ b/pugl/pugl.h @@ -126,6 +126,19 @@ typedef enum { } PuglWindowHintValue; /** + A rectangle. + + This is used to describe things like view position and size. Pugl generally + uses coordinates where the top left corner is 0,0. +*/ +typedef struct { + double x; + double y; + double width; + double height; +} PuglRect; + +/** Keyboard modifier flags. */ typedef enum { @@ -539,8 +552,10 @@ puglInitWindowParent(PuglView* view, PuglNativeWindow parent); /** Set the window size before creating a window. + + @deprecated Use puglSetFrame(). */ -PUGL_API void +PUGL_API PUGL_DEPRECATED_BY("puglSetFrame") void puglInitWindowSize(PuglView* view, int width, int height); /** @@ -655,10 +670,22 @@ puglGetVisible(PuglView* view); /** Get the current size of the view. */ -PUGL_API void +PUGL_API PUGL_DEPRECATED_BY("puglGetFrame") void puglGetSize(PuglView* view, int* width, int* height); /** + Get the current position and size of the view. +*/ +PUGL_API PuglRect +puglGetFrame(const PuglView* view); + +/** + Set the current position and size of the view. +*/ +PUGL_API PuglStatus +puglSetFrame(PuglView* view, PuglRect frame); + +/** @name Context Functions for accessing the drawing context. @{ diff --git a/test/pugl_cairo_test.c b/test/pugl_cairo_test.c index 3ac2054..20a96e7 100644 --- a/test/pugl_cairo_test.c +++ b/test/pugl_cairo_test.c @@ -115,8 +115,9 @@ onDisplay(PuglView* view) cairo_t* cr = (cairo_t*)puglGetContext(view); // Draw background - int width, height; - puglGetSize(view, &width, &height); + const PuglRect frame = puglGetFrame(view); + const double width = frame.width; + const double height = frame.height; if (entered) { cairo_set_source_rgb(cr, 0.1, 0.1, 0.1); } else { @@ -126,8 +127,8 @@ onDisplay(PuglView* view) cairo_fill(cr); // Scale to view size - const double scaleX = (width - (512 / (double)width)) / 512.0; - const double scaleY = (height - (512 / (double)height)) / 512.0; + const double scaleX = (width - (512 / width)) / 512.0; + const double scaleY = (height - (512 / height)) / 512.0; cairo_scale(cr, scaleX, scaleY); // Draw button @@ -206,9 +207,11 @@ main(int argc, char** argv) world = puglNewWorld(); + const PuglRect frame = { 0, 0, 512, 512 }; + PuglView* view = puglNewView(world); puglInitWindowClass(view, "PuglCairoTest"); - puglInitWindowSize(view, 512, 512); + puglSetFrame(view, frame); puglInitWindowMinSize(view, 256, 256); puglInitWindowHint(view, PUGL_RESIZABLE, resizable); puglInitBackend(view, puglCairoBackend()); diff --git a/test/pugl_test.c b/test/pugl_test.c index d6207fe..ea849a6 100644 --- a/test/pugl_test.c +++ b/test/pugl_test.c @@ -181,9 +181,11 @@ main(int argc, char** argv) app.world = puglNewWorld(); + const PuglRect frame = { 0, 0, 512, 512 }; + PuglView* view = puglNewView(app.world); puglInitWindowClass(view, "PuglTest"); - puglInitWindowSize(view, 512, 512); + puglSetFrame(view, frame); puglInitWindowMinSize(view, 256, 256); puglInitWindowAspectRatio(view, 1, 1, 16, 9); puglInitBackend(view, puglGlBackend()); |