| @@ -20,10 +20,27 @@ | |||||
| Note this file contains function definitions, so it must be compiled into | Note this file contains function definitions, so it must be compiled into | ||||
| the final binary exactly once. Each platform specific implementation file | the final binary exactly once. Each platform specific implementation file | ||||
| including it once should achieve this. | including it once should achieve this. | ||||
| If you are copying the pugl code into your source tree, the following | |||||
| symbols can be defined to tweak pugl behaviour: | |||||
| PUGL_GRAB_FOCUS: Work around reparent keyboard issues by grabbing focus. | |||||
| PUGL_VERBOSE: Print GL information to console. | |||||
| */ | */ | ||||
| #include "pugl.h" | #include "pugl.h" | ||||
| #ifdef PUGL_VERBOSE | |||||
| # include <stdio.h> | |||||
| # define PUGL_LOG(str) fprintf(stderr, "pugl: " str) | |||||
| # define PUGL_LOGF(fmt, ...) fprintf(stderr, "pugl: " fmt, __VA_ARGS__) | |||||
| #else | |||||
| # define PUGL_LOG(str) | |||||
| # define PUGL_LOGF(fmt, ...) | |||||
| #endif | |||||
| void puglDefaultReshape(PuglView* view, int width, int height); | |||||
| typedef struct PuglInternalsImpl PuglInternals; | typedef struct PuglInternalsImpl PuglInternals; | ||||
| struct PuglViewImpl { | struct PuglViewImpl { | ||||
| @@ -24,14 +24,6 @@ | |||||
| #include "pugl_internal.h" | #include "pugl_internal.h" | ||||
| void | |||||
| puglDisplay(PuglView* view) | |||||
| { | |||||
| if (view->displayFunc) { | |||||
| view->displayFunc(view); | |||||
| } | |||||
| } | |||||
| @interface PuglWindow : NSWindow | @interface PuglWindow : NSWindow | ||||
| { | { | ||||
| @public | @public | ||||
| @@ -44,7 +36,6 @@ puglDisplay(PuglView* view) | |||||
| defer:(BOOL)flag; | defer:(BOOL)flag; | ||||
| - (void) setPuglview:(PuglView*)view; | - (void) setPuglview:(PuglView*)view; | ||||
| - (BOOL) windowShouldClose:(id)sender; | - (BOOL) windowShouldClose:(id)sender; | ||||
| - (void) becomeKeyWindow:(id)sender; | |||||
| - (BOOL) canBecomeKeyWindow:(id)sender; | - (BOOL) canBecomeKeyWindow:(id)sender; | ||||
| @end | @end | ||||
| @@ -59,8 +50,7 @@ puglDisplay(PuglView* view) | |||||
| styleMask:(NSClosableWindowMask | | styleMask:(NSClosableWindowMask | | ||||
| NSTitledWindowMask | | NSTitledWindowMask | | ||||
| NSResizableWindowMask) | NSResizableWindowMask) | ||||
| backing:NSBackingStoreBuffered | |||||
| defer:NO]; | |||||
| backing:NSBackingStoreBuffered defer:NO]; | |||||
| [result setAcceptsMouseMovedEvents:YES]; | [result setAcceptsMouseMovedEvents:YES]; | ||||
| [result setLevel: CGShieldingWindowLevel() + 1]; | [result setLevel: CGShieldingWindowLevel() + 1]; | ||||
| @@ -81,19 +71,21 @@ puglDisplay(PuglView* view) | |||||
| return YES; | return YES; | ||||
| } | } | ||||
| - (void)becomeKeyWindow:(id)sender | |||||
| { | |||||
| printf("becomeKeyWindow\n"); | |||||
| } | |||||
| // this allows spacebar (for example) to start/stop the transport | |||||
| - (BOOL) canBecomeKeyWindow:(id)sender | - (BOOL) canBecomeKeyWindow:(id)sender | ||||
| { | { | ||||
| return YES; | |||||
| return NO; | |||||
| } | } | ||||
| @end | @end | ||||
| void | |||||
| puglDisplay(PuglView* view) | |||||
| { | |||||
| if (view->displayFunc) { | |||||
| view->displayFunc(view); | |||||
| } | |||||
| } | |||||
| @interface PuglOpenGLView : NSOpenGLView | @interface PuglOpenGLView : NSOpenGLView | ||||
| { | { | ||||
| int colorBits; | int colorBits; | ||||
| @@ -71,7 +71,7 @@ puglCreate(PuglNativeWindow parent, | |||||
| // Should class be a parameter? Does this make sense on other platforms? | // Should class be a parameter? Does this make sense on other platforms? | ||||
| static int wc_count = 0; | static int wc_count = 0; | ||||
| char classNameBuf[256]; | char classNameBuf[256]; | ||||
| sprintf(classNameBuf, "%s_%d\n", title, wc_count++); | |||||
| _snprintf(classNameBuf, sizeof(classNameBuf), "%s_%d\n", title, wc_count++); | |||||
| impl->wc.style = CS_OWNDC; | impl->wc.style = CS_OWNDC; | ||||
| impl->wc.lpfnWndProc = wndProc; | impl->wc.lpfnWndProc = wndProc; | ||||
| @@ -91,7 +91,6 @@ puglCreate(PuglNativeWindow parent, | |||||
| } | } | ||||
| // Adjust the overall window size to accomodate our requested client size | // Adjust the overall window size to accomodate our requested client size | ||||
| // If there's any doubt that Windows is laughably outdated, here's the proof | |||||
| RECT wr = { 0, 0, width, height }; | RECT wr = { 0, 0, width, height }; | ||||
| AdjustWindowRectEx(&wr, winFlags, FALSE, WS_EX_TOPMOST); | AdjustWindowRectEx(&wr, winFlags, FALSE, WS_EX_TOPMOST); | ||||
| @@ -271,43 +270,45 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) | |||||
| } | } | ||||
| break; | break; | ||||
| case WM_LBUTTONDOWN: | case WM_LBUTTONDOWN: | ||||
| view->event_timestamp_ms = (GetMessageTime()); | |||||
| processMouseEvent(view, 1, true, lParam); | processMouseEvent(view, 1, true, lParam); | ||||
| break; | break; | ||||
| case WM_MBUTTONDOWN: | case WM_MBUTTONDOWN: | ||||
| view->event_timestamp_ms = (GetMessageTime()); | |||||
| processMouseEvent(view, 2, true, lParam); | processMouseEvent(view, 2, true, lParam); | ||||
| break; | break; | ||||
| case WM_RBUTTONDOWN: | case WM_RBUTTONDOWN: | ||||
| view->event_timestamp_ms = (GetMessageTime()); | |||||
| processMouseEvent(view, 3, true, lParam); | processMouseEvent(view, 3, true, lParam); | ||||
| break; | break; | ||||
| case WM_LBUTTONUP: | case WM_LBUTTONUP: | ||||
| view->event_timestamp_ms = (GetMessageTime()); | |||||
| processMouseEvent(view, 1, false, lParam); | processMouseEvent(view, 1, false, lParam); | ||||
| break; | break; | ||||
| case WM_MBUTTONUP: | case WM_MBUTTONUP: | ||||
| view->event_timestamp_ms = (GetMessageTime()); | |||||
| processMouseEvent(view, 2, false, lParam); | processMouseEvent(view, 2, false, lParam); | ||||
| break; | break; | ||||
| case WM_RBUTTONUP: | case WM_RBUTTONUP: | ||||
| view->event_timestamp_ms = (GetMessageTime()); | |||||
| processMouseEvent(view, 3, false, lParam); | processMouseEvent(view, 3, false, lParam); | ||||
| break; | break; | ||||
| case WM_MOUSEWHEEL: | case WM_MOUSEWHEEL: | ||||
| if (view->scrollFunc) { | |||||
| view->event_timestamp_ms = GetMessageTime(); | |||||
| view->scrollFunc( | |||||
| view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), | |||||
| 0.0f, (int16_t)HIWORD(wParam) / (float)WHEEL_DELTA); | |||||
| } | |||||
| break; | |||||
| case WM_MOUSEHWHEEL: | case WM_MOUSEHWHEEL: | ||||
| if (view->scrollFunc) { | if (view->scrollFunc) { | ||||
| view->event_timestamp_ms = GetMessageTime(); | |||||
| view->scrollFunc( | view->scrollFunc( | ||||
| view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), | view, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), | ||||
| (int16_t)HIWORD(wParam) / (float)WHEEL_DELTA, 0); | |||||
| (int16_t)HIWORD(wParam) / float(WHEEL_DELTA), 0.0f); | |||||
| } | } | ||||
| break; | break; | ||||
| case WM_KEYDOWN: | case WM_KEYDOWN: | ||||
| view->event_timestamp_ms = (GetMessageTime()); | |||||
| if (view->ignoreKeyRepeat && (lParam & (1 << 30))) { | if (view->ignoreKeyRepeat && (lParam & (1 << 30))) { | ||||
| break; | break; | ||||
| } // else nobreak | } // else nobreak | ||||
| case WM_KEYUP: | case WM_KEYUP: | ||||
| view->event_timestamp_ms = GetMessageTime(); | |||||
| if ((key = keySymToSpecial(wParam))) { | if ((key = keySymToSpecial(wParam))) { | ||||
| if (view->specialFunc) { | if (view->specialFunc) { | ||||
| view->specialFunc(view, message == WM_KEYDOWN, key); | view->specialFunc(view, message == WM_KEYDOWN, key); | ||||
| @@ -338,6 +339,7 @@ puglProcessEvents(PuglView* view) | |||||
| handleMessage(view, msg.message, msg.wParam, msg.lParam); | handleMessage(view, msg.message, msg.wParam, msg.lParam); | ||||
| } | } | ||||
| if (view->redisplay) { | if (view->redisplay) { | ||||
| InvalidateRect(view->impl->hwnd, NULL, FALSE); | InvalidateRect(view->impl->hwnd, NULL, FALSE); | ||||
| } | } | ||||
| @@ -1,7 +1,6 @@ | |||||
| /* | /* | ||||
| Copyright 2012-2014 David Robillard <http://drobilla.net> | Copyright 2012-2014 David Robillard <http://drobilla.net> | ||||
| Copyright 2011-2012 Ben Loftis, Harrison Consoles | Copyright 2011-2012 Ben Loftis, Harrison Consoles | ||||
| Copyright 2013 Robin Gareus <robin@gareus.org> | |||||
| Permission to use, copy, modify, and/or distribute this software for any | Permission to use, copy, modify, and/or distribute this software for any | ||||
| purpose with or without fee is hereby granted, provided that the above | purpose with or without fee is hereby granted, provided that the above | ||||
| @@ -32,16 +31,6 @@ | |||||
| #include "pugl_internal.h" | #include "pugl_internal.h" | ||||
| /* work around buggy re-parent & focus issues on some systems | |||||
| * where no keyboard events are passed through even if the | |||||
| * app has mouse-focus and all other events are working. | |||||
| */ | |||||
| //#define XKEYFOCUSGRAB | |||||
| /* show messages during initalization | |||||
| */ | |||||
| //#define VERBOSE_PUGL | |||||
| struct PuglInternalsImpl { | struct PuglInternalsImpl { | ||||
| Display* display; | Display* display; | ||||
| int screen; | int screen; | ||||
| @@ -101,21 +90,15 @@ puglCreate(PuglNativeWindow parent, | |||||
| if (!vi) { | if (!vi) { | ||||
| vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); | vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); | ||||
| impl->doubleBuffered = False; | impl->doubleBuffered = False; | ||||
| #ifdef VERBOSE_PUGL | |||||
| printf("puGL: singlebuffered rendering will be used, no doublebuffering available\n"); | |||||
| #endif | |||||
| PUGL_LOG("No double buffering available\n"); | |||||
| } else { | } else { | ||||
| impl->doubleBuffered = True; | impl->doubleBuffered = True; | ||||
| #ifdef VERBOSE_PUGL | |||||
| printf("puGL: doublebuffered rendering available\n"); | |||||
| #endif | |||||
| PUGL_LOG("Double buffered rendering enabled\n"); | |||||
| } | } | ||||
| int glxMajor, glxMinor; | int glxMajor, glxMinor; | ||||
| glXQueryVersion(impl->display, &glxMajor, &glxMinor); | glXQueryVersion(impl->display, &glxMajor, &glxMinor); | ||||
| #ifdef VERBOSE_PUGL | |||||
| printf("puGL: GLX-Version %d.%d\n", glxMajor, glxMinor); | |||||
| #endif | |||||
| PUGL_LOGF("GLX Version %d.%d\n", glxMajor, glxMinor); | |||||
| impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); | impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); | ||||
| @@ -163,34 +146,14 @@ puglCreate(PuglNativeWindow parent, | |||||
| XSetWMProtocols(impl->display, impl->win, &wmDelete, 1); | XSetWMProtocols(impl->display, impl->win, &wmDelete, 1); | ||||
| } | } | ||||
| #if 0 | |||||
| if (true) { // stay on top | |||||
| Atom type = XInternAtom(impl->display, "_NET_WM_STATE_ABOVE", False); | |||||
| XChangeProperty(impl->display, | |||||
| impl->win, | |||||
| XInternAtom(impl->display, "_NET_WM_STATE", False), | |||||
| XInternAtom(impl->display, "ATOM", False), | |||||
| 32, | |||||
| PropModeReplace, | |||||
| (unsigned char *)&type, | |||||
| 1 | |||||
| ); | |||||
| } | |||||
| #endif | |||||
| if (visible) { | if (visible) { | ||||
| XMapRaised(impl->display, impl->win); | XMapRaised(impl->display, impl->win); | ||||
| } | } | ||||
| if (glXIsDirect(impl->display, impl->ctx)) { | if (glXIsDirect(impl->display, impl->ctx)) { | ||||
| #ifdef VERBOSE_PUGL | |||||
| printf("puGL: DRI enabled\n"); | |||||
| printf("If you have drawing issues, try setting LIBGL_ALWAYS_INDIRECT=1 in your environment.\n" ); | |||||
| #endif | |||||
| PUGL_LOG("DRI enabled (to disable, set LIBGL_ALWAYS_INDIRECT=1\n"); | |||||
| } else { | } else { | ||||
| #ifdef VERBOSE_PUGL | |||||
| printf("puGL: No DRI available\n"); | |||||
| #endif | |||||
| PUGL_LOG("No DRI available\n"); | |||||
| } | } | ||||
| XFree(vi); | XFree(vi); | ||||
| @@ -376,7 +339,7 @@ puglProcessEvents(PuglView* view) | |||||
| case KeyPress: | case KeyPress: | ||||
| setModifiers(view, event.xkey.state, event.xkey.time); | setModifiers(view, event.xkey.state, event.xkey.time); | ||||
| dispatchKey(view, &event, true); | dispatchKey(view, &event, true); | ||||
| break; | |||||
| break; | |||||
| case KeyRelease: | case KeyRelease: | ||||
| setModifiers(view, event.xkey.state, event.xkey.time); | setModifiers(view, event.xkey.state, event.xkey.time); | ||||
| if (view->ignoreKeyRepeat && | if (view->ignoreKeyRepeat && | ||||
| @@ -391,7 +354,7 @@ puglProcessEvents(PuglView* view) | |||||
| } | } | ||||
| } | } | ||||
| dispatchKey(view, &event, false); | dispatchKey(view, &event, false); | ||||
| break; | |||||
| break; | |||||
| case ClientMessage: | case ClientMessage: | ||||
| if (!strcmp(XGetAtomName(view->impl->display, | if (!strcmp(XGetAtomName(view->impl->display, | ||||
| event.xclient.message_type), | event.xclient.message_type), | ||||
| @@ -401,9 +364,12 @@ puglProcessEvents(PuglView* view) | |||||
| } | } | ||||
| } | } | ||||
| break; | break; | ||||
| #ifdef XKEYFOCUSGRAB | |||||
| #ifdef PUGL_GRAB_FOCUS | |||||
| case EnterNotify: | case EnterNotify: | ||||
| XSetInputFocus(view->impl->display, view->impl->win, RevertToPointerRoot, CurrentTime); | |||||
| XSetInputFocus(view->impl->display, | |||||
| view->impl->win, | |||||
| RevertToPointerRoot, | |||||
| CurrentTime); | |||||
| break; | break; | ||||
| #endif | #endif | ||||
| default: | default: | ||||