| @@ -22,6 +22,10 @@ | |||
| #include "../Window.hpp" | |||
| #include "../../distrho/extra/d_string.hpp" | |||
| #undef PUGL_HAVE_CAIRO | |||
| #undef PUGL_HAVE_GL | |||
| #define PUGL_HAVE_GL 1 | |||
| #include "pugl/pugl.h" | |||
| #if defined(DISTRHO_OS_WINDOWS) | |||
| @@ -182,7 +186,8 @@ struct Window::PrivateData { | |||
| return; | |||
| } | |||
| puglInitResizable(fView, fResizable); | |||
| puglInitContextType(fView, PUGL_GL); | |||
| puglInitUserResizable(fView, fResizable); | |||
| puglInitWindowSize(fView, static_cast<int>(fWidth), static_cast<int>(fHeight)); | |||
| puglSetHandle(fView, this); | |||
| @@ -223,6 +228,7 @@ struct Window::PrivateData { | |||
| XChangeProperty(xDisplay, xWindow, _nwp, XA_CARDINAL, 32, PropModeReplace, (const uchar*)&pid, 1); | |||
| } | |||
| #endif | |||
| puglEnterContext(fView); | |||
| 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> | |||
| /* | |||
| 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 _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. | |||
| */ | |||
| @@ -227,6 +140,12 @@ typedef void (*PuglSpecialFunc)(PuglView* view, bool press, PuglKey key); | |||
| */ | |||
| typedef void (*PuglFileSelectedFunc)(PuglView* view, const char* filename); | |||
| /** | |||
| @name Initialization | |||
| Configuration functions which must be called before creating a window. | |||
| @{ | |||
| */ | |||
| /** | |||
| Create a Pugl context. | |||
| @@ -248,12 +167,43 @@ puglInitWindowParent(PuglView* view, PuglNativeWindow parent); | |||
| PUGL_API void | |||
| 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. | |||
| */ | |||
| PUGL_API void | |||
| 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. | |||
| @@ -274,6 +224,16 @@ puglShowWindow(PuglView* view); | |||
| PUGL_API void | |||
| puglHideWindow(PuglView* view); | |||
| /** | |||
| Return the native window handle. | |||
| */ | |||
| PUGL_API PuglNativeWindow | |||
| puglGetNativeWindow(PuglView* view); | |||
| /** | |||
| @} | |||
| */ | |||
| /** | |||
| Set the handle to be passed to all callbacks. | |||
| @@ -292,6 +252,15 @@ puglSetHandle(PuglView* view, PuglHandle handle); | |||
| PUGL_API PuglHandle | |||
| 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. | |||
| */ | |||
| @@ -312,6 +281,12 @@ puglGetModifiers(PuglView* view); | |||
| PUGL_API void | |||
| 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. | |||
| */ | |||
| @@ -367,10 +342,14 @@ PUGL_API void | |||
| 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. | |||
| @@ -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 | |||
| @@ -24,11 +24,14 @@ | |||
| If you are copying the pugl code into your source tree, the following | |||
| 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_VERBOSE: Print GL information to console. | |||
| */ | |||
| #include "pugl.h" | |||
| #include "pugl/pugl.h" | |||
| #include "pugl/event.h" | |||
| #ifdef PUGL_VERBOSE | |||
| # include <stdio.h> | |||
| @@ -54,10 +57,15 @@ struct PuglViewImpl { | |||
| PuglFileSelectedFunc fileSelectedFunc; | |||
| PuglInternals* impl; | |||
| PuglNativeWindow parent; | |||
| PuglContextType ctx_type; | |||
| uintptr_t transient_parent; | |||
| int width; | |||
| int height; | |||
| int min_width; | |||
| int min_height; | |||
| int mods; | |||
| bool mouse_in_view; | |||
| bool ignoreKeyRepeat; | |||
| @@ -96,6 +104,13 @@ puglInitWindowSize(PuglView* view, int width, int height) | |||
| view->height = height; | |||
| } | |||
| void | |||
| puglInitWindowMinSize(PuglView* view, int width, int height) | |||
| { | |||
| view->min_width = width; | |||
| view->min_height = height; | |||
| } | |||
| void | |||
| puglInitWindowParent(PuglView* view, PuglNativeWindow parent) | |||
| { | |||
| @@ -103,11 +118,23 @@ puglInitWindowParent(PuglView* view, PuglNativeWindow parent) | |||
| } | |||
| void | |||
| puglInitResizable(PuglView* view, bool resizable) | |||
| puglInitUserResizable(PuglView* view, bool 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 | |||
| puglSetHandle(PuglView* view, PuglHandle handle) | |||
| { | |||
| @@ -132,22 +159,6 @@ puglGetModifiers(PuglView* view) | |||
| 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 | |||
| puglIgnoreKeyRepeat(PuglView* view, bool ignore) | |||
| { | |||
| @@ -207,3 +218,133 @@ puglSetFileSelectedFunc(PuglView* view, PuglFileSelectedFunc 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 2011-2012 Ben Loftis, Harrison Consoles | |||
| 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 | |||
| purpose with or without fee is hereby granted, provided that the above | |||
| @@ -24,13 +24,22 @@ | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <GL/gl.h> | |||
| #include <GL/glx.h> | |||
| #include <X11/Xatom.h> | |||
| #include <X11/Xlib.h> | |||
| #include <X11/Xutil.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 | |||
| #include "../sofd/libsofd.h" | |||
| @@ -40,53 +49,16 @@ struct PuglInternalsImpl { | |||
| Display* display; | |||
| int screen; | |||
| Window win; | |||
| XIM xim; | |||
| XIC xic; | |||
| #ifdef PUGL_HAVE_CAIRO | |||
| cairo_t* cr; | |||
| cairo_surface_t* surface; | |||
| #endif | |||
| #ifdef PUGL_HAVE_GL | |||
| GLXContext ctx; | |||
| 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* | |||
| @@ -95,33 +67,186 @@ puglInitInternals(void) | |||
| 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 | |||
| puglCreateWindow(PuglView* view, const char* title) | |||
| { | |||
| PuglInternals* impl = view->impl; | |||
| PuglInternals* const impl = view->impl; | |||
| impl->display = XOpenDisplay(NULL); | |||
| impl->screen = DefaultScreen(impl->display); | |||
| impl->doubleBuffered = True; | |||
| XVisualInfo* vi = glXChooseVisual(impl->display, impl->screen, attrListDblMS); | |||
| XVisualInfo* const vi = getVisual(view); | |||
| 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; | |||
| glXQueryVersion(impl->display, &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)view->parent | |||
| @@ -132,20 +257,29 @@ puglCreateWindow(PuglView* view, const char* title) | |||
| XSetWindowAttributes attr; | |||
| 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->display, xParent, | |||
| 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; | |||
| memset(&sizeHints, 0, sizeof(sizeHints)); | |||
| @@ -156,6 +290,11 @@ puglCreateWindow(PuglView* view, const char* title) | |||
| sizeHints.max_width = view->width; | |||
| sizeHints.max_height = view->height; | |||
| 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) { | |||
| @@ -175,25 +314,19 @@ puglCreateWindow(PuglView* view, const char* title) | |||
| XFree(vi); | |||
| glXMakeCurrent(view->impl->display, view->impl->win, view->impl->ctx); | |||
| return 0; | |||
| return PUGL_SUCCESS; | |||
| } | |||
| void | |||
| puglShowWindow(PuglView* view) | |||
| { | |||
| PuglInternals* impl = view->impl; | |||
| XMapRaised(impl->display, impl->win); | |||
| XMapRaised(view->impl->display, view->impl->win); | |||
| } | |||
| void | |||
| puglHideWindow(PuglView* view) | |||
| { | |||
| PuglInternals* impl = view->impl; | |||
| XUnmapWindow(impl->display, impl->win); | |||
| XUnmapWindow(view->impl->display, view->impl->win); | |||
| } | |||
| void | |||
| @@ -205,7 +338,7 @@ puglDestroy(PuglView* view) | |||
| x_fib_close(view->impl->display); | |||
| glXDestroyContext(view->impl->display, view->impl->ctx); | |||
| destroyContext(view); | |||
| XDestroyWindow(view->impl->display, view->impl->win); | |||
| XCloseDisplay(view->impl->display); | |||
| free(view->impl); | |||
| @@ -462,3 +595,14 @@ puglGetNativeWindow(PuglView* view) | |||
| { | |||
| 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; | |||
| } | |||