diff --git a/dgl/src/Window.cpp b/dgl/src/Window.cpp index 43279c3a..876b2a84 100644 --- a/dgl/src/Window.cpp +++ b/dgl/src/Window.cpp @@ -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(fWidth), static_cast(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); diff --git a/dgl/src/pugl/common.h b/dgl/src/pugl/common.h new file mode 100644 index 00000000..afda61e0 --- /dev/null +++ b/dgl/src/pugl/common.h @@ -0,0 +1,121 @@ +/* + Copyright 2014 David Robillard + + 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 */ diff --git a/dgl/src/pugl/event.h b/dgl/src/pugl/event.h new file mode 100644 index 00000000..7314e48a --- /dev/null +++ b/dgl/src/pugl/event.h @@ -0,0 +1,41 @@ +/* + Copyright 2014 David Robillard + + 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 +#endif + +#include "pugl/common.h" + +/** + @addtogroup pugl + @{ +*/ + +/** + @} +*/ + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* PUGL_EVENT_H_INCLUDED */ diff --git a/dgl/src/pugl/gl.h b/dgl/src/pugl/gl.h new file mode 100644 index 00000000..9a6aeefe --- /dev/null +++ b/dgl/src/pugl/gl.h @@ -0,0 +1,32 @@ +/* + Copyright 2012-2014 David Robillard + + 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 /* Broken Windows GL headers require this */ +# endif +# include "GL/gl.h" +#endif + diff --git a/dgl/src/pugl/glu.h b/dgl/src/pugl/glu.h new file mode 100644 index 00000000..4be79c70 --- /dev/null +++ b/dgl/src/pugl/glu.h @@ -0,0 +1,32 @@ +/* + Copyright 2012-2014 David Robillard + + 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 /* Broken Windows GL headers require this */ +# endif +# include "GL/glu.h" +#endif + diff --git a/dgl/src/pugl/pugl.h b/dgl/src/pugl/pugl.h index 7cd8b842..3ee1c43d 100644 --- a/dgl/src/pugl/pugl.h +++ b/dgl/src/pugl/pugl.h @@ -23,19 +23,8 @@ #include -/* - 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 /* 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. diff --git a/dgl/src/pugl/pugl_internal.h b/dgl/src/pugl/pugl_internal.h index 7301091a..eb2df381 100644 --- a/dgl/src/pugl/pugl_internal.h +++ b/dgl/src/pugl/pugl_internal.h @@ -1,5 +1,5 @@ /* - Copyright 2012 David Robillard + Copyright 2012-2014 David Robillard 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 @@ -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 diff --git a/dgl/src/pugl/pugl_x11.c b/dgl/src/pugl/pugl_x11.c index d1f68ea4..9926b6df 100644 --- a/dgl/src/pugl/pugl_x11.c +++ b/dgl/src/pugl/pugl_x11.c @@ -1,7 +1,7 @@ /* Copyright 2012-2014 David Robillard - Copyright 2011-2012 Ben Loftis, Harrison Consoles Copyright 2013 Robin Gareus + 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 #include -#include -#include #include #include +#include #include -#include "pugl_internal.h" +#ifdef PUGL_HAVE_GL +#include +#include +#endif + +#ifdef PUGL_HAVE_CAIRO +#include +#include +#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; +}