@@ -20,10 +20,27 @@ | |||
Note this file contains function definitions, so it must be compiled into | |||
the final binary exactly once. Each platform specific implementation file | |||
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" | |||
#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; | |||
struct PuglViewImpl { | |||
@@ -24,14 +24,6 @@ | |||
#include "pugl_internal.h" | |||
void | |||
puglDisplay(PuglView* view) | |||
{ | |||
if (view->displayFunc) { | |||
view->displayFunc(view); | |||
} | |||
} | |||
@interface PuglWindow : NSWindow | |||
{ | |||
@public | |||
@@ -44,7 +36,6 @@ puglDisplay(PuglView* view) | |||
defer:(BOOL)flag; | |||
- (void) setPuglview:(PuglView*)view; | |||
- (BOOL) windowShouldClose:(id)sender; | |||
- (void) becomeKeyWindow:(id)sender; | |||
- (BOOL) canBecomeKeyWindow:(id)sender; | |||
@end | |||
@@ -59,8 +50,7 @@ puglDisplay(PuglView* view) | |||
styleMask:(NSClosableWindowMask | | |||
NSTitledWindowMask | | |||
NSResizableWindowMask) | |||
backing:NSBackingStoreBuffered | |||
defer:NO]; | |||
backing:NSBackingStoreBuffered defer:NO]; | |||
[result setAcceptsMouseMovedEvents:YES]; | |||
[result setLevel: CGShieldingWindowLevel() + 1]; | |||
@@ -81,19 +71,21 @@ puglDisplay(PuglView* view) | |||
return YES; | |||
} | |||
- (void)becomeKeyWindow:(id)sender | |||
{ | |||
printf("becomeKeyWindow\n"); | |||
} | |||
// this allows spacebar (for example) to start/stop the transport | |||
- (BOOL) canBecomeKeyWindow:(id)sender | |||
{ | |||
return YES; | |||
return NO; | |||
} | |||
@end | |||
void | |||
puglDisplay(PuglView* view) | |||
{ | |||
if (view->displayFunc) { | |||
view->displayFunc(view); | |||
} | |||
} | |||
@interface PuglOpenGLView : NSOpenGLView | |||
{ | |||
int colorBits; | |||
@@ -71,7 +71,7 @@ puglCreate(PuglNativeWindow parent, | |||
// Should class be a parameter? Does this make sense on other platforms? | |||
static int wc_count = 0; | |||
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.lpfnWndProc = wndProc; | |||
@@ -91,7 +91,6 @@ puglCreate(PuglNativeWindow parent, | |||
} | |||
// 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 }; | |||
AdjustWindowRectEx(&wr, winFlags, FALSE, WS_EX_TOPMOST); | |||
@@ -271,43 +270,45 @@ handleMessage(PuglView* view, UINT message, WPARAM wParam, LPARAM lParam) | |||
} | |||
break; | |||
case WM_LBUTTONDOWN: | |||
view->event_timestamp_ms = (GetMessageTime()); | |||
processMouseEvent(view, 1, true, lParam); | |||
break; | |||
case WM_MBUTTONDOWN: | |||
view->event_timestamp_ms = (GetMessageTime()); | |||
processMouseEvent(view, 2, true, lParam); | |||
break; | |||
case WM_RBUTTONDOWN: | |||
view->event_timestamp_ms = (GetMessageTime()); | |||
processMouseEvent(view, 3, true, lParam); | |||
break; | |||
case WM_LBUTTONUP: | |||
view->event_timestamp_ms = (GetMessageTime()); | |||
processMouseEvent(view, 1, false, lParam); | |||
break; | |||
case WM_MBUTTONUP: | |||
view->event_timestamp_ms = (GetMessageTime()); | |||
processMouseEvent(view, 2, false, lParam); | |||
break; | |||
case WM_RBUTTONUP: | |||
view->event_timestamp_ms = (GetMessageTime()); | |||
processMouseEvent(view, 3, false, lParam); | |||
break; | |||
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: | |||
if (view->scrollFunc) { | |||
view->event_timestamp_ms = GetMessageTime(); | |||
view->scrollFunc( | |||
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; | |||
case WM_KEYDOWN: | |||
view->event_timestamp_ms = (GetMessageTime()); | |||
if (view->ignoreKeyRepeat && (lParam & (1 << 30))) { | |||
break; | |||
} // else nobreak | |||
case WM_KEYUP: | |||
view->event_timestamp_ms = GetMessageTime(); | |||
if ((key = keySymToSpecial(wParam))) { | |||
if (view->specialFunc) { | |||
view->specialFunc(view, message == WM_KEYDOWN, key); | |||
@@ -338,6 +339,7 @@ puglProcessEvents(PuglView* view) | |||
handleMessage(view, msg.message, msg.wParam, msg.lParam); | |||
} | |||
if (view->redisplay) { | |||
InvalidateRect(view->impl->hwnd, NULL, FALSE); | |||
} | |||
@@ -1,7 +1,6 @@ | |||
/* | |||
Copyright 2012-2014 David Robillard <http://drobilla.net> | |||
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 | |||
purpose with or without fee is hereby granted, provided that the above | |||
@@ -32,16 +31,6 @@ | |||
#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 { | |||
Display* display; | |||
int screen; | |||
@@ -101,21 +90,15 @@ puglCreate(PuglNativeWindow parent, | |||
if (!vi) { | |||
vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); | |||
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 { | |||
impl->doubleBuffered = True; | |||
#ifdef VERBOSE_PUGL | |||
printf("puGL: doublebuffered rendering available\n"); | |||
#endif | |||
PUGL_LOG("Double buffered rendering enabled\n"); | |||
} | |||
int 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); | |||
@@ -163,34 +146,14 @@ puglCreate(PuglNativeWindow parent, | |||
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) { | |||
XMapRaised(impl->display, impl->win); | |||
} | |||
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 { | |||
#ifdef VERBOSE_PUGL | |||
printf("puGL: No DRI available\n"); | |||
#endif | |||
PUGL_LOG("No DRI available\n"); | |||
} | |||
XFree(vi); | |||
@@ -376,7 +339,7 @@ puglProcessEvents(PuglView* view) | |||
case KeyPress: | |||
setModifiers(view, event.xkey.state, event.xkey.time); | |||
dispatchKey(view, &event, true); | |||
break; | |||
break; | |||
case KeyRelease: | |||
setModifiers(view, event.xkey.state, event.xkey.time); | |||
if (view->ignoreKeyRepeat && | |||
@@ -391,7 +354,7 @@ puglProcessEvents(PuglView* view) | |||
} | |||
} | |||
dispatchKey(view, &event, false); | |||
break; | |||
break; | |||
case ClientMessage: | |||
if (!strcmp(XGetAtomName(view->impl->display, | |||
event.xclient.message_type), | |||
@@ -401,9 +364,12 @@ puglProcessEvents(PuglView* view) | |||
} | |||
} | |||
break; | |||
#ifdef XKEYFOCUSGRAB | |||
#ifdef PUGL_GRAB_FOCUS | |||
case EnterNotify: | |||
XSetInputFocus(view->impl->display, view->impl->win, RevertToPointerRoot, CurrentTime); | |||
XSetInputFocus(view->impl->display, | |||
view->impl->win, | |||
RevertToPointerRoot, | |||
CurrentTime); | |||
break; | |||
#endif | |||
default: | |||