commit d9b8366a0d9ff74a379866538190f6153d5294dc
parent 28822a20701a75444b755463daeb82e640e1ceea
Author: falkTX <falktx@gmail.com>
Date: Sat, 18 Apr 2015 16:24:58 +0200
Start updating to latest pugl, again
Diffstat:
8 files changed, 691 insertions(+), 195 deletions(-)
diff --git 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<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);
diff --git a/dgl/src/pugl/common.h b/dgl/src/pugl/common.h
@@ -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 */
diff --git a/dgl/src/pugl/event.h b/dgl/src/pugl/event.h
@@ -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 */
diff --git a/dgl/src/pugl/gl.h b/dgl/src/pugl/gl.h
@@ -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
+
diff --git a/dgl/src/pugl/glu.h b/dgl/src/pugl/glu.h
@@ -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
+
diff --git a/dgl/src/pugl/pugl.h b/dgl/src/pugl/pugl.h
@@ -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
@@ -71,82 +60,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.
*/
typedef void (*PuglCloseFunc)(PuglView* view);
@@ -228,6 +141,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.
To create a window, call the various puglInit* functions as necessary, then
@@ -249,12 +168,43 @@ 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.
@return 1 (pugl does not currently support multiple windows).
@@ -275,6 +225,16 @@ 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.
This is generally a pointer to a struct which contains all necessary state.
@@ -293,6 +253,15 @@ 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.
*/
PUGL_API uint32_t
@@ -313,6 +282,12 @@ 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.
*/
PUGL_API void
@@ -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
@@ -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;
@@ -97,18 +105,37 @@ puglInitWindowSize(PuglView* view, int width, int height)
}
void
+puglInitWindowMinSize(PuglView* view, int width, int height)
+{
+ view->min_width = width;
+ view->min_height = height;
+}
+
+void
puglInitWindowParent(PuglView* view, PuglNativeWindow parent)
{
view->parent = 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)
{
view->handle = 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
@@ -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;
+}