@@ -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: | ||||