@@ -1,5 +1,5 @@ | |||
/* | |||
Copyright 2012 David Robillard <http://drobilla.net> | |||
Copyright 2012-2014 David Robillard <http://drobilla.net> | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
@@ -217,21 +217,54 @@ typedef void (*PuglScrollFunc)(PuglView* view, | |||
typedef void (*PuglSpecialFunc)(PuglView* view, bool press, PuglKey key); | |||
/** | |||
Create a new GL window. | |||
@param parent Parent window, or 0 for top level. | |||
@param title Window title, or NULL. | |||
@param width Window width in pixels. | |||
@param height Window height in pixels. | |||
@param resizable Whether window should be user resizable. | |||
@param visible Whether window should be initially visible. | |||
Create a Pugl context. | |||
To create a window, call the various puglInit* functions as necessary, then | |||
call puglCreateWindow(). | |||
@param pargc Pointer to argument count (unused, for GLUT compatibility). | |||
@param argv Arguments (unused, for GLUT compatibility). | |||
*/ | |||
PUGL_API PuglView* | |||
puglCreate(PuglNativeWindow parent, | |||
const char* title, | |||
int width, | |||
int height, | |||
bool resizable, | |||
bool visible); | |||
puglInit(int* pargc, char** argv); | |||
/** | |||
Set the parent window before creating a window (for embedding). | |||
*/ | |||
PUGL_API void | |||
puglInitWindowParent(PuglView* view, PuglNativeWindow parent); | |||
/** | |||
Set the window size before creating a window. | |||
*/ | |||
PUGL_API void | |||
puglInitWindowSize(PuglView* view, int width, int height); | |||
/** | |||
Enable or disable resizing before creating a window. | |||
*/ | |||
PUGL_API void | |||
puglInitResizable(PuglView* view, bool resizable); | |||
/** | |||
Create a window with the settings given by the various puglInit functions. | |||
@return 1 (pugl does not currently support multiple windows). | |||
*/ | |||
PUGL_API int | |||
puglCreateWindow(PuglView* view, const char* title); | |||
/** | |||
Show the current window. | |||
*/ | |||
PUGL_API void | |||
puglShowWindow(PuglView* view); | |||
/** | |||
Hide the current window. | |||
*/ | |||
PUGL_API void | |||
puglHideWindow(PuglView* view); | |||
/** | |||
Set the handle to be passed to all callbacks. | |||
@@ -39,8 +39,6 @@ | |||
# define PUGL_LOGF(fmt, ...) | |||
#endif | |||
void puglDefaultReshape(PuglView* view, int width, int height); | |||
typedef struct PuglInternalsImpl PuglInternals; | |||
struct PuglViewImpl { | |||
@@ -59,13 +57,59 @@ struct PuglViewImpl { | |||
PuglInternals* impl; | |||
PuglNativeWindow parent; | |||
int mods; | |||
bool mouse_in_view; | |||
bool ignoreKeyRepeat; | |||
bool redisplay; | |||
bool resizable; | |||
uint32_t event_timestamp_ms; | |||
}; | |||
PuglInternals* puglInitInternals(); | |||
void puglDefaultReshape(PuglView* view, int width, int height); | |||
PuglView* | |||
puglInit(int* pargc, char** argv) | |||
{ | |||
PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); | |||
if (!view) { | |||
return NULL; | |||
} | |||
PuglInternals* impl = puglInitInternals(); | |||
if (!impl) { | |||
return NULL; | |||
} | |||
view->impl = impl; | |||
view->width = 640; | |||
view->height = 480; | |||
return view; | |||
} | |||
void | |||
puglInitWindowSize(PuglView* view, int width, int height) | |||
{ | |||
view->width = width; | |||
view->height = height; | |||
} | |||
void | |||
puglInitWindowParent(PuglView* view, PuglNativeWindow parent) | |||
{ | |||
view->parent = parent; | |||
} | |||
void | |||
puglInitResizable(PuglView* view, bool resizable) | |||
{ | |||
view->resizable = true; | |||
} | |||
void | |||
puglSetHandle(PuglView* view, PuglHandle handle) | |||
{ | |||
@@ -61,12 +61,28 @@ DllMain(HINSTANCE hInst, DWORD, LPVOID) | |||
} // extern "C" | |||
PuglView* | |||
puglCreate(PuglNativeWindow parent, | |||
const char* title, | |||
int width, | |||
int height, | |||
bool resizable, | |||
bool visible) | |||
puglInit() | |||
{ | |||
PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); | |||
PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||
if (!view || !impl) { | |||
return NULL; | |||
} | |||
view->impl = impl; | |||
view->width = 640; | |||
view->height = 480; | |||
return view; | |||
} | |||
PuglView* | |||
puglCreateInternals(PuglNativeWindow parent, | |||
const char* title, | |||
int width, | |||
int height, | |||
bool resizable, | |||
bool visible) | |||
{ | |||
PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); | |||
PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||
@@ -160,7 +176,7 @@ puglDestroy(PuglView* view) | |||
free(view); | |||
} | |||
void | |||
static void | |||
puglReshape(PuglView* view, int width, int height) | |||
{ | |||
wglMakeCurrent(view->impl->hdc, view->impl->hglrc); | |||
@@ -175,7 +191,7 @@ puglReshape(PuglView* view, int width, int height) | |||
view->height = height; | |||
} | |||
void | |||
static void | |||
puglDisplay(PuglView* view) | |||
{ | |||
wglMakeCurrent(view->impl->hdc, view->impl->hglrc); | |||
@@ -65,23 +65,16 @@ static int attrListDbl[] = { | |||
None | |||
}; | |||
PuglView* | |||
puglCreate(PuglNativeWindow parent, | |||
const char* title, | |||
int width, | |||
int height, | |||
bool resizable, | |||
bool visible) | |||
PuglInternals* | |||
puglInitInternals() | |||
{ | |||
PuglView* view = (PuglView*)calloc(1, sizeof(PuglView)); | |||
PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||
if (!view || !impl) { | |||
return NULL; | |||
} | |||
return (PuglInternals*)calloc(1, sizeof(PuglInternals)); | |||
} | |||
view->impl = impl; | |||
view->width = width; | |||
view->height = height; | |||
int | |||
puglCreateWindow(PuglView* view, const char* title) | |||
{ | |||
PuglInternals* impl = view->impl; | |||
impl->display = XOpenDisplay(0); | |||
impl->screen = DefaultScreen(impl->display); | |||
@@ -102,8 +95,8 @@ puglCreate(PuglNativeWindow parent, | |||
impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); | |||
Window xParent = parent | |||
? (Window)parent | |||
Window xParent = view->parent | |||
? (Window)view->parent | |||
: RootWindow(impl->display, impl->screen); | |||
Colormap cmap = XCreateColormap( | |||
@@ -116,24 +109,24 @@ puglCreate(PuglNativeWindow parent, | |||
attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | |||
| ButtonPressMask | ButtonReleaseMask | |||
#ifdef XKEYFOCUSGRAB | |||
#ifdef PUGL_GRAB_FOCUS | |||
| EnterWindowMask | |||
#endif | |||
| PointerMotionMask | StructureNotifyMask; | |||
impl->win = XCreateWindow( | |||
impl->display, xParent, | |||
0, 0, (unsigned int)view->width, (unsigned int)view->height, 0, vi->depth, InputOutput, vi->visual, | |||
0, 0, view->width, view->height, 0, vi->depth, InputOutput, vi->visual, | |||
CWBorderPixel | CWColormap | CWEventMask, &attr); | |||
XSizeHints sizeHints; | |||
memset(&sizeHints, 0, sizeof(sizeHints)); | |||
if (!resizable) { | |||
if (!view->resizable) { | |||
sizeHints.flags = PMinSize|PMaxSize; | |||
sizeHints.min_width = width; | |||
sizeHints.min_height = height; | |||
sizeHints.max_width = width; | |||
sizeHints.max_height = height; | |||
sizeHints.min_width = view->width; | |||
sizeHints.min_height = view->height; | |||
sizeHints.max_width = view->width; | |||
sizeHints.max_height = view->height; | |||
XSetNormalHints(impl->display, impl->win, &sizeHints); | |||
} | |||
@@ -141,15 +134,11 @@ puglCreate(PuglNativeWindow parent, | |||
XStoreName(impl->display, impl->win, title); | |||
} | |||
if (!parent) { | |||
if (!view->parent) { | |||
Atom wmDelete = XInternAtom(impl->display, "WM_DELETE_WINDOW", True); | |||
XSetWMProtocols(impl->display, impl->win, &wmDelete, 1); | |||
} | |||
if (visible) { | |||
XMapRaised(impl->display, impl->win); | |||
} | |||
if (glXIsDirect(impl->display, impl->ctx)) { | |||
PUGL_LOG("DRI enabled (to disable, set LIBGL_ALWAYS_INDIRECT=1\n"); | |||
} else { | |||
@@ -158,7 +147,23 @@ puglCreate(PuglNativeWindow parent, | |||
XFree(vi); | |||
return view; | |||
return 0; | |||
} | |||
void | |||
puglShowWindow(PuglView* view) | |||
{ | |||
PuglInternals* impl = view->impl; | |||
XMapRaised(impl->display, impl->win); | |||
} | |||
void | |||
puglHideWindow(PuglView* view) | |||
{ | |||
PuglInternals* impl = view->impl; | |||
XUnmapWindow(impl->display, impl->win); | |||
} | |||
void | |||
@@ -245,9 +250,9 @@ keySymToSpecial(KeySym sym) | |||
} | |||
static void | |||
setModifiers(PuglView* view, unsigned xstate, unsigned long xtime) | |||
setModifiers(PuglView* view, unsigned xstate, unsigned xtime) | |||
{ | |||
view->event_timestamp_ms = (uint32_t)xtime; | |||
view->event_timestamp_ms = xtime; | |||
view->mods = 0; | |||
view->mods |= (xstate & ShiftMask) ? PUGL_MOD_SHIFT : 0; | |||
@@ -273,7 +278,7 @@ dispatchKey(PuglView* view, XEvent* event, bool press) | |||
if (special && view->specialFunc) { | |||
view->specialFunc(view, press, special); | |||
} else if (!special && view->keyboardFunc) { | |||
view->keyboardFunc(view, press, (uint32_t)str[0]); | |||
view->keyboardFunc(view, press, str[0]); | |||
} | |||
} | |||
@@ -330,7 +335,7 @@ puglProcessEvents(PuglView* view) | |||
if (view->mouseFunc && | |||
(event.xbutton.button < 4 || event.xbutton.button > 7)) { | |||
view->mouseFunc(view, | |||
(int)event.xbutton.button, event.type == ButtonPress, | |||
event.xbutton.button, event.type == ButtonPress, | |||
event.xbutton.x, event.xbutton.y); | |||
} | |||
break; | |||
@@ -354,15 +359,16 @@ puglProcessEvents(PuglView* view) | |||
dispatchKey(view, &event, false); | |||
break; | |||
case ClientMessage: { | |||
char* name = XGetAtomName(view->impl->display, event.xclient.message_type); | |||
if (!strcmp(name, "WM_PROTOCOLS")) { | |||
char* type = XGetAtomName(view->impl->display, | |||
event.xclient.message_type); | |||
if (!strcmp(type, "WM_PROTOCOLS")) { | |||
if (view->closeFunc) { | |||
view->closeFunc(view); | |||
} | |||
} | |||
XFree(name); | |||
} break; | |||
#ifdef XKEYFOCUSGRAB | |||
XFree(type); | |||
} break; | |||
#ifdef PUGL_GRAB_FOCUS | |||
case EnterNotify: | |||
XSetInputFocus(view->impl->display, | |||
view->impl->win, | |||
@@ -391,5 +397,5 @@ puglPostRedisplay(PuglView* view) | |||
PuglNativeWindow | |||
puglGetNativeWindow(PuglView* view) | |||
{ | |||
return (PuglNativeWindow)view->impl->win; | |||
return view->impl->win; | |||
} |