@@ -22,6 +22,10 @@ | |||||
#include "../Window.hpp" | #include "../Window.hpp" | ||||
#include "../../distrho/extra/d_string.hpp" | #include "../../distrho/extra/d_string.hpp" | ||||
#undef PUGL_HAVE_CAIRO | |||||
#undef PUGL_HAVE_GL | |||||
#define PUGL_HAVE_GL 1 | |||||
#include "pugl/pugl.h" | #include "pugl/pugl.h" | ||||
#if defined(DISTRHO_OS_WINDOWS) | #if defined(DISTRHO_OS_WINDOWS) | ||||
@@ -182,7 +186,8 @@ struct Window::PrivateData { | |||||
return; | return; | ||||
} | } | ||||
puglInitResizable(fView, fResizable); | |||||
puglInitContextType(fView, PUGL_GL); | |||||
puglInitUserResizable(fView, fResizable); | |||||
puglInitWindowSize(fView, static_cast<int>(fWidth), static_cast<int>(fHeight)); | puglInitWindowSize(fView, static_cast<int>(fWidth), static_cast<int>(fHeight)); | ||||
puglSetHandle(fView, this); | puglSetHandle(fView, this); | ||||
@@ -223,6 +228,7 @@ struct Window::PrivateData { | |||||
XChangeProperty(xDisplay, xWindow, _nwp, XA_CARDINAL, 32, PropModeReplace, (const uchar*)&pid, 1); | XChangeProperty(xDisplay, xWindow, _nwp, XA_CARDINAL, 32, PropModeReplace, (const uchar*)&pid, 1); | ||||
} | } | ||||
#endif | #endif | ||||
puglEnterContext(fView); | |||||
fApp.pData->windows.push_back(fSelf); | fApp.pData->windows.push_back(fSelf); | ||||
@@ -0,0 +1,121 @@ | |||||
/* | |||||
Copyright 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 | |||||
copyright notice and this permission notice appear in all copies. | |||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef PUGL_COMMON_H_INCLUDED | |||||
#define PUGL_COMMON_H_INCLUDED | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#endif | |||||
/** | |||||
@addtogroup pugl | |||||
@{ | |||||
*/ | |||||
/** | |||||
A Pugl view. | |||||
*/ | |||||
typedef struct PuglViewImpl PuglView; | |||||
/** | |||||
A native window handle. | |||||
On X11, this is a Window. | |||||
On OSX, this is an NSView*. | |||||
On Windows, this is a HWND. | |||||
*/ | |||||
typedef intptr_t PuglNativeWindow; | |||||
/** | |||||
Handle for opaque user data. | |||||
*/ | |||||
typedef void* PuglHandle; | |||||
/** | |||||
Return status code. | |||||
*/ | |||||
typedef enum { | |||||
PUGL_SUCCESS = 0 | |||||
} PuglStatus; | |||||
/** | |||||
Drawing context type. | |||||
*/ | |||||
typedef enum { | |||||
PUGL_GL, | |||||
PUGL_CAIRO | |||||
} PuglContextType; | |||||
/** | |||||
Convenience symbols for ASCII control characters. | |||||
*/ | |||||
typedef enum { | |||||
PUGL_CHAR_BACKSPACE = 0x08, | |||||
PUGL_CHAR_ESCAPE = 0x1B, | |||||
PUGL_CHAR_DELETE = 0x7F | |||||
} PuglChar; | |||||
/** | |||||
Keyboard modifier flags. | |||||
*/ | |||||
typedef enum { | |||||
PUGL_MOD_SHIFT = 1 << 0, /**< Shift key */ | |||||
PUGL_MOD_CTRL = 1 << 1, /**< Control key */ | |||||
PUGL_MOD_ALT = 1 << 2, /**< Alt/Option key */ | |||||
PUGL_MOD_SUPER = 1 << 3 /**< Mod4/Command/Windows key */ | |||||
} PuglMod; | |||||
/** | |||||
Special (non-Unicode) keyboard keys. | |||||
*/ | |||||
typedef enum { | |||||
PUGL_KEY_F1 = 1, | |||||
PUGL_KEY_F2, | |||||
PUGL_KEY_F3, | |||||
PUGL_KEY_F4, | |||||
PUGL_KEY_F5, | |||||
PUGL_KEY_F6, | |||||
PUGL_KEY_F7, | |||||
PUGL_KEY_F8, | |||||
PUGL_KEY_F9, | |||||
PUGL_KEY_F10, | |||||
PUGL_KEY_F11, | |||||
PUGL_KEY_F12, | |||||
PUGL_KEY_LEFT, | |||||
PUGL_KEY_UP, | |||||
PUGL_KEY_RIGHT, | |||||
PUGL_KEY_DOWN, | |||||
PUGL_KEY_PAGE_UP, | |||||
PUGL_KEY_PAGE_DOWN, | |||||
PUGL_KEY_HOME, | |||||
PUGL_KEY_END, | |||||
PUGL_KEY_INSERT, | |||||
PUGL_KEY_SHIFT, | |||||
PUGL_KEY_CTRL, | |||||
PUGL_KEY_ALT, | |||||
PUGL_KEY_SUPER | |||||
} PuglKey; | |||||
/** | |||||
@} | |||||
*/ | |||||
#ifdef __cplusplus | |||||
} /* extern "C" */ | |||||
#endif | |||||
#endif /* PUGL_COMMON_H_INCLUDED */ |
@@ -0,0 +1,41 @@ | |||||
/* | |||||
Copyright 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 | |||||
copyright notice and this permission notice appear in all copies. | |||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
#ifndef PUGL_EVENT_H_INCLUDED | |||||
#define PUGL_EVENT_H_INCLUDED | |||||
#ifdef __cplusplus | |||||
extern "C" { | |||||
#else | |||||
# include <stdbool.h> | |||||
#endif | |||||
#include "pugl/common.h" | |||||
/** | |||||
@addtogroup pugl | |||||
@{ | |||||
*/ | |||||
/** | |||||
@} | |||||
*/ | |||||
#ifdef __cplusplus | |||||
} /* extern "C" */ | |||||
#endif | |||||
#endif /* PUGL_EVENT_H_INCLUDED */ |
@@ -0,0 +1,32 @@ | |||||
/* | |||||
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 | |||||
copyright notice and this permission notice appear in all copies. | |||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
/** | |||||
@file gl.h Portable header wrapper for gl.h. | |||||
Unfortunately, GL includes vary across platforms so this header allows for | |||||
pure portable programs. | |||||
*/ | |||||
#ifdef __APPLE__ | |||||
# include "OpenGL/gl.h" | |||||
#else | |||||
# ifdef _WIN32 | |||||
# include <windows.h> /* Broken Windows GL headers require this */ | |||||
# endif | |||||
# include "GL/gl.h" | |||||
#endif | |||||
@@ -0,0 +1,32 @@ | |||||
/* | |||||
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 | |||||
copyright notice and this permission notice appear in all copies. | |||||
THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
*/ | |||||
/** | |||||
@file glu.h Portable header wrapper for glu.h. | |||||
Unfortunately, GL includes vary across platforms so this header allows for | |||||
pure portable programs. | |||||
*/ | |||||
#ifdef __APPLE__ | |||||
# include "OpenGL/glu.h" | |||||
#else | |||||
# ifdef _WIN32 | |||||
# include <windows.h> /* Broken Windows GL headers require this */ | |||||
# endif | |||||
# include "GL/glu.h" | |||||
#endif | |||||
@@ -23,19 +23,8 @@ | |||||
#include <stdint.h> | #include <stdint.h> | ||||
/* | |||||
This API is pure portable C and contains no platform specific elements, or | |||||
even a GL dependency. However, unfortunately GL includes vary across | |||||
platforms so they are included here to allow for pure portable programs. | |||||
*/ | |||||
#ifdef __APPLE__ | |||||
# include "OpenGL/gl.h" | |||||
#else | |||||
# ifdef _WIN32 | |||||
# include <windows.h> /* Broken Windows GL headers require this */ | |||||
# endif | |||||
# include "GL/gl.h" | |||||
#endif | |||||
#include "pugl/common.h" | |||||
#include "pugl/event.h" | |||||
#ifdef PUGL_SHARED | #ifdef PUGL_SHARED | ||||
# ifdef _WIN32 | # ifdef _WIN32 | ||||
@@ -70,82 +59,6 @@ extern "C" { | |||||
@{ | @{ | ||||
*/ | */ | ||||
/** | |||||
An OpenGL view. | |||||
*/ | |||||
typedef struct PuglViewImpl PuglView; | |||||
/** | |||||
A native window handle. | |||||
On X11, this is a Window. | |||||
On OSX, this is an NSView*. | |||||
On Windows, this is a HWND. | |||||
*/ | |||||
typedef intptr_t PuglNativeWindow; | |||||
/** | |||||
Return status code. | |||||
*/ | |||||
typedef enum { | |||||
PUGL_SUCCESS = 0 | |||||
} PuglStatus; | |||||
/** | |||||
Convenience symbols for ASCII control characters. | |||||
*/ | |||||
typedef enum { | |||||
PUGL_CHAR_BACKSPACE = 0x08, | |||||
PUGL_CHAR_ESCAPE = 0x1B, | |||||
PUGL_CHAR_DELETE = 0x7F | |||||
} PuglChar; | |||||
/** | |||||
Special (non-Unicode) keyboard keys. | |||||
*/ | |||||
typedef enum { | |||||
PUGL_KEY_F1 = 1, | |||||
PUGL_KEY_F2, | |||||
PUGL_KEY_F3, | |||||
PUGL_KEY_F4, | |||||
PUGL_KEY_F5, | |||||
PUGL_KEY_F6, | |||||
PUGL_KEY_F7, | |||||
PUGL_KEY_F8, | |||||
PUGL_KEY_F9, | |||||
PUGL_KEY_F10, | |||||
PUGL_KEY_F11, | |||||
PUGL_KEY_F12, | |||||
PUGL_KEY_LEFT, | |||||
PUGL_KEY_UP, | |||||
PUGL_KEY_RIGHT, | |||||
PUGL_KEY_DOWN, | |||||
PUGL_KEY_PAGE_UP, | |||||
PUGL_KEY_PAGE_DOWN, | |||||
PUGL_KEY_HOME, | |||||
PUGL_KEY_END, | |||||
PUGL_KEY_INSERT, | |||||
PUGL_KEY_SHIFT, | |||||
PUGL_KEY_CTRL, | |||||
PUGL_KEY_ALT, | |||||
PUGL_KEY_SUPER | |||||
} PuglKey; | |||||
/** | |||||
Keyboard modifier flags. | |||||
*/ | |||||
typedef enum { | |||||
PUGL_MOD_SHIFT = 1, /**< Shift key */ | |||||
PUGL_MOD_CTRL = 1 << 1, /**< Control key */ | |||||
PUGL_MOD_ALT = 1 << 2, /**< Alt/Option key */ | |||||
PUGL_MOD_SUPER = 1 << 3 /**< Mod4/Command/Windows key */ | |||||
} PuglMod; | |||||
/** | |||||
Handle for opaque user data. | |||||
*/ | |||||
typedef void* PuglHandle; | |||||
/** | /** | ||||
A function called when the window is closed. | A function called when the window is closed. | ||||
*/ | */ | ||||
@@ -227,6 +140,12 @@ typedef void (*PuglSpecialFunc)(PuglView* view, bool press, PuglKey key); | |||||
*/ | */ | ||||
typedef void (*PuglFileSelectedFunc)(PuglView* view, const char* filename); | typedef void (*PuglFileSelectedFunc)(PuglView* view, const char* filename); | ||||
/** | |||||
@name Initialization | |||||
Configuration functions which must be called before creating a window. | |||||
@{ | |||||
*/ | |||||
/** | /** | ||||
Create a Pugl context. | Create a Pugl context. | ||||
@@ -248,12 +167,43 @@ puglInitWindowParent(PuglView* view, PuglNativeWindow parent); | |||||
PUGL_API void | PUGL_API void | ||||
puglInitWindowSize(PuglView* view, int width, int height); | puglInitWindowSize(PuglView* view, int width, int height); | ||||
/** | |||||
Set the minimum window size before creating a window. | |||||
*/ | |||||
PUGL_API void | |||||
puglInitWindowMinSize(PuglView* view, int width, int height); | |||||
/** | /** | ||||
Enable or disable resizing before creating a window. | Enable or disable resizing before creating a window. | ||||
*/ | */ | ||||
PUGL_API void | PUGL_API void | ||||
puglInitUserResizable(PuglView* view, bool resizable); | puglInitUserResizable(PuglView* view, bool resizable); | ||||
/** | |||||
Set transient parent before creating a window. | |||||
On X11, parent_id must be a Window. | |||||
On OSX, parent_id must be an NSView*. | |||||
*/ | |||||
PUGL_API void | |||||
puglInitTransientFor(PuglView* view, uintptr_t parent); | |||||
/** | |||||
Set the context type before creating a window. | |||||
*/ | |||||
PUGL_API void | |||||
puglInitContextType(PuglView* view, PuglContextType type); | |||||
/** | |||||
@} | |||||
*/ | |||||
/** | |||||
@name Windows | |||||
Window management functions. | |||||
@{ | |||||
*/ | |||||
/** | /** | ||||
Create a window with the settings given by the various puglInit functions. | Create a window with the settings given by the various puglInit functions. | ||||
@@ -274,6 +224,16 @@ puglShowWindow(PuglView* view); | |||||
PUGL_API void | PUGL_API void | ||||
puglHideWindow(PuglView* view); | puglHideWindow(PuglView* view); | ||||
/** | |||||
Return the native window handle. | |||||
*/ | |||||
PUGL_API PuglNativeWindow | |||||
puglGetNativeWindow(PuglView* view); | |||||
/** | |||||
@} | |||||
*/ | |||||
/** | /** | ||||
Set the handle to be passed to all callbacks. | Set the handle to be passed to all callbacks. | ||||
@@ -292,6 +252,15 @@ puglSetHandle(PuglView* view, PuglHandle handle); | |||||
PUGL_API PuglHandle | PUGL_API PuglHandle | ||||
puglGetHandle(PuglView* view); | puglGetHandle(PuglView* view); | ||||
/** | |||||
Get the drawing context. | |||||
For PUGL_GL contexts, this is unused and returns NULL. | |||||
For PUGL_CAIRO contexts, this returns a pointer to a cairo_t. | |||||
*/ | |||||
PUGL_API void* | |||||
puglGetContext(PuglView* view); | |||||
/** | /** | ||||
Return the timestamp (if any) of the currently-processing event. | Return the timestamp (if any) of the currently-processing event. | ||||
*/ | */ | ||||
@@ -312,6 +281,12 @@ puglGetModifiers(PuglView* view); | |||||
PUGL_API void | PUGL_API void | ||||
puglIgnoreKeyRepeat(PuglView* view, bool ignore); | puglIgnoreKeyRepeat(PuglView* view, bool ignore); | ||||
/** | |||||
@name Event Callbacks | |||||
Functions to set event callbacks for handling user input. | |||||
@{ | |||||
*/ | |||||
/** | /** | ||||
Set the function to call when the window is closed. | Set the function to call when the window is closed. | ||||
*/ | */ | ||||
@@ -367,10 +342,14 @@ PUGL_API void | |||||
puglSetFileSelectedFunc(PuglView* view, PuglFileSelectedFunc fileSelectedFunc); | puglSetFileSelectedFunc(PuglView* view, PuglFileSelectedFunc fileSelectedFunc); | ||||
/** | /** | ||||
Return the native window handle. | |||||
@} | |||||
*/ | */ | ||||
PUGL_API PuglNativeWindow | |||||
puglGetNativeWindow(PuglView* view); | |||||
/** | |||||
Grab the input focus. | |||||
*/ | |||||
PUGL_API void | |||||
puglGrabFocus(PuglView* view); | |||||
/** | /** | ||||
Process all pending window events. | Process all pending window events. | ||||
@@ -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 | 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 | ||||
@@ -24,11 +24,14 @@ | |||||
If you are copying the pugl code into your source tree, the following | If you are copying the pugl code into your source tree, the following | ||||
symbols can be defined to tweak pugl behaviour: | symbols can be defined to tweak pugl behaviour: | ||||
PUGL_HAVE_CAIRO: Include Cairo support code. | |||||
PUGL_HAVE_GL: Include OpenGL support code. | |||||
PUGL_GRAB_FOCUS: Work around reparent keyboard issues by grabbing focus. | PUGL_GRAB_FOCUS: Work around reparent keyboard issues by grabbing focus. | ||||
PUGL_VERBOSE: Print GL information to console. | PUGL_VERBOSE: Print GL information to console. | ||||
*/ | */ | ||||
#include "pugl.h" | |||||
#include "pugl/pugl.h" | |||||
#include "pugl/event.h" | |||||
#ifdef PUGL_VERBOSE | #ifdef PUGL_VERBOSE | ||||
# include <stdio.h> | # include <stdio.h> | ||||
@@ -54,10 +57,15 @@ struct PuglViewImpl { | |||||
PuglFileSelectedFunc fileSelectedFunc; | PuglFileSelectedFunc fileSelectedFunc; | ||||
PuglInternals* impl; | PuglInternals* impl; | ||||
PuglNativeWindow parent; | PuglNativeWindow parent; | ||||
PuglContextType ctx_type; | |||||
uintptr_t transient_parent; | |||||
int width; | int width; | ||||
int height; | int height; | ||||
int min_width; | |||||
int min_height; | |||||
int mods; | int mods; | ||||
bool mouse_in_view; | bool mouse_in_view; | ||||
bool ignoreKeyRepeat; | bool ignoreKeyRepeat; | ||||
@@ -96,6 +104,13 @@ puglInitWindowSize(PuglView* view, int width, int height) | |||||
view->height = height; | view->height = height; | ||||
} | } | ||||
void | |||||
puglInitWindowMinSize(PuglView* view, int width, int height) | |||||
{ | |||||
view->min_width = width; | |||||
view->min_height = height; | |||||
} | |||||
void | void | ||||
puglInitWindowParent(PuglView* view, PuglNativeWindow parent) | puglInitWindowParent(PuglView* view, PuglNativeWindow parent) | ||||
{ | { | ||||
@@ -103,11 +118,23 @@ puglInitWindowParent(PuglView* view, PuglNativeWindow parent) | |||||
} | } | ||||
void | void | ||||
puglInitResizable(PuglView* view, bool resizable) | |||||
puglInitUserResizable(PuglView* view, bool resizable) | |||||
{ | { | ||||
view->resizable = resizable; | view->resizable = resizable; | ||||
} | } | ||||
void | |||||
puglInitTransientFor(PuglView* view, uintptr_t parent) | |||||
{ | |||||
view->transient_parent = parent; | |||||
} | |||||
void | |||||
puglInitContextType(PuglView* view, PuglContextType type) | |||||
{ | |||||
view->ctx_type = type; | |||||
} | |||||
void | void | ||||
puglSetHandle(PuglView* view, PuglHandle handle) | puglSetHandle(PuglView* view, PuglHandle handle) | ||||
{ | { | ||||
@@ -132,22 +159,6 @@ puglGetModifiers(PuglView* view) | |||||
return view->mods; | return view->mods; | ||||
} | } | ||||
static void | |||||
puglDefaultReshape(PuglView* view, int width, int height) | |||||
{ | |||||
glMatrixMode(GL_PROJECTION); | |||||
glLoadIdentity(); | |||||
glOrtho(0, width, height, 0, 0, 1); | |||||
glViewport(0, 0, width, height); | |||||
glMatrixMode(GL_MODELVIEW); | |||||
glLoadIdentity(); | |||||
return; | |||||
// unused | |||||
(void)view; | |||||
} | |||||
void | void | ||||
puglIgnoreKeyRepeat(PuglView* view, bool ignore) | puglIgnoreKeyRepeat(PuglView* view, bool ignore) | ||||
{ | { | ||||
@@ -207,3 +218,133 @@ puglSetFileSelectedFunc(PuglView* view, PuglFileSelectedFunc fileSelectedFunc) | |||||
{ | { | ||||
view->fileSelectedFunc = fileSelectedFunc; | view->fileSelectedFunc = fileSelectedFunc; | ||||
} | } | ||||
void | |||||
puglEnterContext(PuglView* view); | |||||
void | |||||
puglLeaveContext(PuglView* view, bool flush); | |||||
/** Return the code point for buf, or the replacement character on error. */ | |||||
static uint32_t | |||||
puglDecodeUTF8(const uint8_t* buf) | |||||
{ | |||||
#define FAIL_IF(cond) { if (cond) return 0xFFFD; } | |||||
/* http://en.wikipedia.org/wiki/UTF-8 */ | |||||
if (buf[0] < 0x80) { | |||||
return buf[0]; | |||||
} else if (buf[0] < 0xC2) { | |||||
return 0xFFFD; | |||||
} else if (buf[0] < 0xE0) { | |||||
FAIL_IF((buf[1] & 0xC0) != 0x80); | |||||
return (buf[0] << 6) + buf[1] - 0x3080; | |||||
} else if (buf[0] < 0xF0) { | |||||
FAIL_IF((buf[1] & 0xC0) != 0x80); | |||||
FAIL_IF(buf[0] == 0xE0 && buf[1] < 0xA0); | |||||
FAIL_IF((buf[2] & 0xC0) != 0x80); | |||||
return (buf[0] << 12) + (buf[1] << 6) + buf[2] - 0xE2080; | |||||
} else if (buf[0] < 0xF5) { | |||||
FAIL_IF((buf[1] & 0xC0) != 0x80); | |||||
FAIL_IF(buf[0] == 0xF0 && buf[1] < 0x90); | |||||
FAIL_IF(buf[0] == 0xF4 && buf[1] >= 0x90); | |||||
FAIL_IF((buf[2] & 0xC0) != 0x80); | |||||
FAIL_IF((buf[3] & 0xC0) != 0x80); | |||||
return ((buf[0] << 18) + | |||||
(buf[1] << 12) + | |||||
(buf[2] << 6) + | |||||
buf[3] - 0x3C82080); | |||||
} | |||||
return 0xFFFD; | |||||
} | |||||
static void | |||||
puglDefaultReshape(PuglView* view, int width, int height) | |||||
{ | |||||
glMatrixMode(GL_PROJECTION); | |||||
glLoadIdentity(); | |||||
glOrtho(0, width, height, 0, 0, 1); | |||||
glViewport(0, 0, width, height); | |||||
glMatrixMode(GL_MODELVIEW); | |||||
glLoadIdentity(); | |||||
return; | |||||
// unused | |||||
(void)view; | |||||
} | |||||
#if 0 | |||||
static void | |||||
puglDispatchEvent(PuglView* view, const PuglEvent* event) | |||||
{ | |||||
if (view->eventFunc) { | |||||
view->eventFunc(view, event); | |||||
} | |||||
switch (event->type) { | |||||
case PUGL_CONFIGURE: | |||||
puglEnterContext(view); | |||||
view->width = event->configure.width; | |||||
view->height = event->configure.height; | |||||
if (view->reshapeFunc) { | |||||
view->reshapeFunc(view, view->width, view->height); | |||||
} | |||||
puglLeaveContext(view, false); | |||||
break; | |||||
case PUGL_EXPOSE: | |||||
if (event->expose.count == 0) { | |||||
puglEnterContext(view); | |||||
if (view->displayFunc) { | |||||
view->displayFunc(view); | |||||
} | |||||
view->redisplay = false; | |||||
puglLeaveContext(view, true); | |||||
} | |||||
break; | |||||
case PUGL_MOTION_NOTIFY: | |||||
view->event_timestamp_ms = event->motion.time; | |||||
view->mods = event->motion.state; | |||||
if (view->motionFunc) { | |||||
view->motionFunc(view, event->motion.x, event->motion.y); | |||||
} | |||||
break; | |||||
case PUGL_SCROLL: | |||||
if (view->scrollFunc) { | |||||
view->scrollFunc(view, | |||||
event->scroll.x, event->scroll.y, | |||||
event->scroll.dx, event->scroll.dy); | |||||
} | |||||
break; | |||||
case PUGL_BUTTON_PRESS: | |||||
case PUGL_BUTTON_RELEASE: | |||||
view->event_timestamp_ms = event->button.time; | |||||
view->mods = event->button.state; | |||||
if (view->mouseFunc) { | |||||
view->mouseFunc(view, | |||||
event->button.button, | |||||
event->type == PUGL_BUTTON_PRESS, | |||||
event->button.x, | |||||
event->button.y); | |||||
} | |||||
break; | |||||
case PUGL_KEY_PRESS: | |||||
case PUGL_KEY_RELEASE: | |||||
view->event_timestamp_ms = event->key.time; | |||||
view->mods = event->key.state; | |||||
if (event->key.special && view->specialFunc) { | |||||
view->specialFunc(view, | |||||
event->type == PUGL_KEY_PRESS, | |||||
event->key.special); | |||||
} else if (event->key.character && view->keyboardFunc) { | |||||
view->keyboardFunc(view, | |||||
event->type == PUGL_KEY_PRESS, | |||||
event->key.character); | |||||
} | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
} | |||||
#endif |
@@ -1,7 +1,7 @@ | |||||
/* | /* | ||||
Copyright 2012-2014 David Robillard <http://drobilla.net> | Copyright 2012-2014 David Robillard <http://drobilla.net> | ||||
Copyright 2011-2012 Ben Loftis, Harrison Consoles | |||||
Copyright 2013 Robin Gareus <robin@gareus.org> | Copyright 2013 Robin Gareus <robin@gareus.org> | ||||
Copyright 2011-2012 Ben Loftis, Harrison Consoles | |||||
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 | ||||
@@ -24,13 +24,22 @@ | |||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <GL/gl.h> | |||||
#include <GL/glx.h> | |||||
#include <X11/Xatom.h> | #include <X11/Xatom.h> | ||||
#include <X11/Xlib.h> | #include <X11/Xlib.h> | ||||
#include <X11/Xutil.h> | |||||
#include <X11/keysym.h> | #include <X11/keysym.h> | ||||
#include "pugl_internal.h" | |||||
#ifdef PUGL_HAVE_GL | |||||
#include <GL/gl.h> | |||||
#include <GL/glx.h> | |||||
#endif | |||||
#ifdef PUGL_HAVE_CAIRO | |||||
#include <cairo/cairo.h> | |||||
#include <cairo/cairo-xlib.h> | |||||
#endif | |||||
#include "pugl/pugl_internal.h" | |||||
#define SOFD_HAVE_X11 | #define SOFD_HAVE_X11 | ||||
#include "../sofd/libsofd.h" | #include "../sofd/libsofd.h" | ||||
@@ -40,53 +49,16 @@ struct PuglInternalsImpl { | |||||
Display* display; | Display* display; | ||||
int screen; | int screen; | ||||
Window win; | Window win; | ||||
XIM xim; | |||||
XIC xic; | |||||
#ifdef PUGL_HAVE_CAIRO | |||||
cairo_t* cr; | |||||
cairo_surface_t* surface; | |||||
#endif | |||||
#ifdef PUGL_HAVE_GL | |||||
GLXContext ctx; | GLXContext ctx; | ||||
Bool doubleBuffered; | Bool doubleBuffered; | ||||
}; | |||||
/** | |||||
Attributes for single-buffered RGBA with at least | |||||
4 bits per color and a 16 bit depth buffer. | |||||
*/ | |||||
static int attrListSgl[] = { | |||||
GLX_RGBA, | |||||
GLX_RED_SIZE, 4, | |||||
GLX_GREEN_SIZE, 4, | |||||
GLX_BLUE_SIZE, 4, | |||||
GLX_DEPTH_SIZE, 16, | |||||
GLX_ARB_multisample, 1, | |||||
None | |||||
}; | |||||
/** | |||||
Attributes for double-buffered RGBA with at least | |||||
4 bits per color and a 16 bit depth buffer. | |||||
*/ | |||||
static int attrListDbl[] = { | |||||
GLX_RGBA, GLX_DOUBLEBUFFER, | |||||
GLX_RED_SIZE, 4, | |||||
GLX_GREEN_SIZE, 4, | |||||
GLX_BLUE_SIZE, 4, | |||||
GLX_DEPTH_SIZE, 16, | |||||
GLX_ARB_multisample, 1, | |||||
None | |||||
}; | |||||
/** | |||||
Attributes for double-buffered RGBA with multi-sampling | |||||
(antialiasing) | |||||
*/ | |||||
static int attrListDblMS[] = { | |||||
GLX_RGBA, | |||||
GLX_DOUBLEBUFFER , True, | |||||
GLX_RED_SIZE , 4, | |||||
GLX_GREEN_SIZE , 4, | |||||
GLX_BLUE_SIZE , 4, | |||||
GLX_ALPHA_SIZE , 4, | |||||
GLX_DEPTH_SIZE , 16, | |||||
GLX_SAMPLE_BUFFERS , 1, | |||||
GLX_SAMPLES , 4, | |||||
None | |||||
#endif | |||||
}; | }; | ||||
PuglInternals* | PuglInternals* | ||||
@@ -95,33 +67,186 @@ puglInitInternals(void) | |||||
return (PuglInternals*)calloc(1, sizeof(PuglInternals)); | return (PuglInternals*)calloc(1, sizeof(PuglInternals)); | ||||
} | } | ||||
static XVisualInfo* | |||||
getVisual(PuglView* view) | |||||
{ | |||||
PuglInternals* const impl = view->impl; | |||||
XVisualInfo* vi = NULL; | |||||
#ifdef PUGL_HAVE_GL | |||||
if (view->ctx_type == PUGL_GL) { | |||||
/** | |||||
Attributes for single-buffered RGBA with at least | |||||
4 bits per color and a 16 bit depth buffer. | |||||
*/ | |||||
int attrListSgl[] = { | |||||
GLX_RGBA, | |||||
GLX_RED_SIZE, 4, | |||||
GLX_GREEN_SIZE, 4, | |||||
GLX_BLUE_SIZE, 4, | |||||
GLX_DEPTH_SIZE, 16, | |||||
GLX_ARB_multisample, 1, | |||||
None | |||||
}; | |||||
/** | |||||
Attributes for double-buffered RGBA with at least | |||||
4 bits per color and a 16 bit depth buffer. | |||||
*/ | |||||
int attrListDbl[] = { | |||||
GLX_RGBA, | |||||
GLX_DOUBLEBUFFER, | |||||
GLX_RED_SIZE, 4, | |||||
GLX_GREEN_SIZE, 4, | |||||
GLX_BLUE_SIZE, 4, | |||||
GLX_DEPTH_SIZE, 16, | |||||
GLX_ARB_multisample, 1, | |||||
None | |||||
}; | |||||
/** | |||||
Attributes for double-buffered RGBA with multi-sampling | |||||
(antialiasing) | |||||
*/ | |||||
int attrListDblMS[] = { | |||||
GLX_RGBA, | |||||
GLX_DOUBLEBUFFER, | |||||
GLX_RED_SIZE, 4, | |||||
GLX_GREEN_SIZE, 4, | |||||
GLX_BLUE_SIZE, 4, | |||||
GLX_ALPHA_SIZE, 4, | |||||
GLX_DEPTH_SIZE, 16, | |||||
GLX_SAMPLE_BUFFERS, 1, | |||||
GLX_SAMPLES, 4, | |||||
None | |||||
}; | |||||
impl->doubleBuffered = True; | |||||
vi = glXChooseVisual(impl->display, impl->screen, attrListDblMS); | |||||
if (vi == NULL) { | |||||
vi = glXChooseVisual(impl->display, impl->screen, attrListDbl); | |||||
PUGL_LOG("multisampling (antialiasing) is not available\n"); | |||||
} | |||||
if (vi == NULL) { | |||||
vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); | |||||
impl->doubleBuffered = False; | |||||
PUGL_LOG("singlebuffered rendering will be used, no doublebuffering available\n"); | |||||
} | |||||
} | |||||
#endif | |||||
#ifdef PUGL_HAVE_CAIRO | |||||
if (view->ctx_type == PUGL_CAIRO) { | |||||
XVisualInfo pat; | |||||
int n; | |||||
pat.screen = impl->screen; | |||||
vi = XGetVisualInfo(impl->display, VisualScreenMask, &pat, &n); | |||||
} | |||||
#endif | |||||
return vi; | |||||
} | |||||
static bool | |||||
createContext(PuglView* view, XVisualInfo* vi) | |||||
{ | |||||
PuglInternals* const impl = view->impl; | |||||
#ifdef PUGL_HAVE_GL | |||||
if (view->ctx_type == PUGL_GL) { | |||||
impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); | |||||
return (impl->ctx != NULL); | |||||
} | |||||
#endif | |||||
#ifdef PUGL_HAVE_CAIRO | |||||
if (view->ctx_type == PUGL_CAIRO) { | |||||
impl->surface = cairo_xlib_surface_create( | |||||
impl->display, impl->win, vi->visual, view->width, view->height); | |||||
if (impl->surface == NULL) { | |||||
PUGL_LOG("failed to create cairo surface\n"); | |||||
return false; | |||||
} | |||||
impl->cr = cairo_create(impl->surface); | |||||
if (impl->cr == NULL) { | |||||
cairo_surface_destroy(impl->surface); | |||||
impl->surface = NULL; | |||||
PUGL_LOG("failed to create cairo context\n"); | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
#endif | |||||
return false; | |||||
} | |||||
static void | |||||
destroyContext(PuglView* view) | |||||
{ | |||||
PuglInternals* const impl = view->impl; | |||||
#ifdef PUGL_HAVE_GL | |||||
if (view->ctx_type == PUGL_GL) { | |||||
glXDestroyContext(impl->display, impl->ctx); | |||||
impl->ctx = NULL; | |||||
} | |||||
#endif | |||||
#ifdef PUGL_HAVE_CAIRO | |||||
if (view->ctx_type == PUGL_CAIRO) { | |||||
cairo_destroy(impl->cr); | |||||
impl->cr = NULL; | |||||
cairo_surface_destroy(impl->surface); | |||||
impl->surface = NULL; | |||||
} | |||||
#endif | |||||
} | |||||
void | |||||
puglEnterContext(PuglView* view) | |||||
{ | |||||
#ifdef PUGL_HAVE_GL | |||||
if (view->ctx_type == PUGL_GL) { | |||||
glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); | |||||
} | |||||
#endif | |||||
} | |||||
void | |||||
puglLeaveContext(PuglView* view, bool flush) | |||||
{ | |||||
#ifdef PUGL_HAVE_GL | |||||
if (view->ctx_type == PUGL_GL && flush) { | |||||
glFlush(); | |||||
if (view->impl->doubleBuffered) { | |||||
glXSwapBuffers(view->impl->display, view->impl->win); | |||||
} | |||||
} | |||||
#endif | |||||
} | |||||
int | int | ||||
puglCreateWindow(PuglView* view, const char* title) | puglCreateWindow(PuglView* view, const char* title) | ||||
{ | { | ||||
PuglInternals* impl = view->impl; | |||||
PuglInternals* const impl = view->impl; | |||||
impl->display = XOpenDisplay(NULL); | impl->display = XOpenDisplay(NULL); | ||||
impl->screen = DefaultScreen(impl->display); | impl->screen = DefaultScreen(impl->display); | ||||
impl->doubleBuffered = True; | |||||
XVisualInfo* vi = glXChooseVisual(impl->display, impl->screen, attrListDblMS); | |||||
XVisualInfo* const vi = getVisual(view); | |||||
if (!vi) { | if (!vi) { | ||||
vi = glXChooseVisual(impl->display, impl->screen, attrListDbl); | |||||
PUGL_LOG("multisampling (antialiasing) is not available\n"); | |||||
} | |||||
if (!vi) { | |||||
vi = glXChooseVisual(impl->display, impl->screen, attrListSgl); | |||||
impl->doubleBuffered = False; | |||||
PUGL_LOG("singlebuffered rendering will be used, no doublebuffering available\n"); | |||||
XCloseDisplay(impl->display); | |||||
impl->display = NULL; | |||||
return 1; | |||||
} | } | ||||
#ifdef PUGL_HAVE_GL | |||||
int glxMajor, glxMinor; | int glxMajor, glxMinor; | ||||
glXQueryVersion(impl->display, &glxMajor, &glxMinor); | glXQueryVersion(impl->display, &glxMajor, &glxMinor); | ||||
PUGL_LOGF("GLX Version %d.%d\n", glxMajor, glxMinor); | PUGL_LOGF("GLX Version %d.%d\n", glxMajor, glxMinor); | ||||
impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE); | |||||
#endif | |||||
Window xParent = view->parent | Window xParent = view->parent | ||||
? (Window)view->parent | ? (Window)view->parent | ||||
@@ -132,20 +257,29 @@ puglCreateWindow(PuglView* view, const char* title) | |||||
XSetWindowAttributes attr; | XSetWindowAttributes attr; | ||||
memset(&attr, 0, sizeof(XSetWindowAttributes)); | memset(&attr, 0, sizeof(XSetWindowAttributes)); | ||||
attr.colormap = cmap; | |||||
attr.border_pixel = 0; | |||||
attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | |||||
| ButtonPressMask | ButtonReleaseMask | |||||
#ifdef PUGL_GRAB_FOCUS | |||||
| EnterWindowMask | |||||
#endif | |||||
| PointerMotionMask | StructureNotifyMask; | |||||
attr.background_pixel = BlackPixel(impl->display, impl->screen); | |||||
attr.border_pixel = BlackPixel(impl->display, impl->screen); | |||||
attr.colormap = cmap; | |||||
attr.event_mask = (ExposureMask | StructureNotifyMask | | |||||
EnterWindowMask | LeaveWindowMask | | |||||
KeyPressMask | KeyReleaseMask | | |||||
ButtonPressMask | ButtonReleaseMask | | |||||
PointerMotionMask | FocusChangeMask); | |||||
impl->win = XCreateWindow( | impl->win = XCreateWindow( | ||||
impl->display, xParent, | impl->display, xParent, | ||||
0, 0, view->width, view->height, 0, vi->depth, InputOutput, vi->visual, | 0, 0, view->width, view->height, 0, vi->depth, InputOutput, vi->visual, | ||||
CWBorderPixel | CWColormap | CWEventMask, &attr); | |||||
CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &attr); | |||||
if (!createContext(view, vi)) { | |||||
XDestroyWindow(impl->display, impl->win); | |||||
impl->win = 0; | |||||
XCloseDisplay(impl->display); | |||||
impl->display = NULL; | |||||
return 1; | |||||
} | |||||
XSizeHints sizeHints; | XSizeHints sizeHints; | ||||
memset(&sizeHints, 0, sizeof(sizeHints)); | memset(&sizeHints, 0, sizeof(sizeHints)); | ||||
@@ -156,6 +290,11 @@ puglCreateWindow(PuglView* view, const char* title) | |||||
sizeHints.max_width = view->width; | sizeHints.max_width = view->width; | ||||
sizeHints.max_height = view->height; | sizeHints.max_height = view->height; | ||||
XSetNormalHints(impl->display, impl->win, &sizeHints); | XSetNormalHints(impl->display, impl->win, &sizeHints); | ||||
} else if (view->min_width > 0 && view->min_height > 0) { | |||||
sizeHints.flags = PMinSize; | |||||
sizeHints.min_width = view->min_width; | |||||
sizeHints.min_height = view->min_height; | |||||
XSetNormalHints(impl->display, impl->win, &sizeHints); | |||||
} | } | ||||
if (title) { | if (title) { | ||||
@@ -175,25 +314,19 @@ puglCreateWindow(PuglView* view, const char* title) | |||||
XFree(vi); | XFree(vi); | ||||
glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); | |||||
return 0; | |||||
return PUGL_SUCCESS; | |||||
} | } | ||||
void | void | ||||
puglShowWindow(PuglView* view) | puglShowWindow(PuglView* view) | ||||
{ | { | ||||
PuglInternals* impl = view->impl; | |||||
XMapRaised(impl->display, impl->win); | |||||
XMapRaised(view->impl->display, view->impl->win); | |||||
} | } | ||||
void | void | ||||
puglHideWindow(PuglView* view) | puglHideWindow(PuglView* view) | ||||
{ | { | ||||
PuglInternals* impl = view->impl; | |||||
XUnmapWindow(impl->display, impl->win); | |||||
XUnmapWindow(view->impl->display, view->impl->win); | |||||
} | } | ||||
void | void | ||||
@@ -205,7 +338,7 @@ puglDestroy(PuglView* view) | |||||
x_fib_close(view->impl->display); | x_fib_close(view->impl->display); | ||||
glXDestroyContext(view->impl->display, view->impl->ctx); | |||||
destroyContext(view); | |||||
XDestroyWindow(view->impl->display, view->impl->win); | XDestroyWindow(view->impl->display, view->impl->win); | ||||
XCloseDisplay(view->impl->display); | XCloseDisplay(view->impl->display); | ||||
free(view->impl); | free(view->impl); | ||||
@@ -462,3 +595,14 @@ puglGetNativeWindow(PuglView* view) | |||||
{ | { | ||||
return view->impl->win; | return view->impl->win; | ||||
} | } | ||||
void* | |||||
puglGetContext(PuglView* view) | |||||
{ | |||||
#ifdef PUGL_HAVE_CAIRO | |||||
if (view->ctx_type == PUGL_CAIRO) { | |||||
return view->impl->cr; | |||||
} | |||||
#endif | |||||
return NULL; | |||||
} |