aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pugl/pugl_internal_types.h26
-rw-r--r--pugl/pugl_x11.c225
-rw-r--r--pugl/pugl_x11.h31
-rw-r--r--pugl/pugl_x11_cairo.c141
-rw-r--r--pugl/pugl_x11_cairo.h22
-rw-r--r--pugl/pugl_x11_gl.c145
-rw-r--r--pugl/pugl_x11_gl.h22
-rw-r--r--wscript5
8 files changed, 428 insertions, 189 deletions
diff --git a/pugl/pugl_internal_types.h b/pugl/pugl_internal_types.h
index a0f5b91..dce5429 100644
--- a/pugl/pugl_internal_types.h
+++ b/pugl/pugl_internal_types.h
@@ -55,5 +55,31 @@ struct PuglViewImpl {
bool visible;
};
+/** Opaque surface used by draw context. */
+typedef void PuglSurface;
+
+/** Drawing context interface. */
+typedef struct {
+ /** Get visual information from display and setup view as necessary. */
+ int (*configure)(PuglView*);
+
+ /** Create surface and drawing context. */
+ int (*create)(PuglView*);
+
+ /** Destroy surface and drawing context. */
+ int (*destroy)(PuglView*);
+
+ /** Enter drawing context. */
+ int (*enter)(PuglView*);
+
+ /** Leave drawing context, explicitly flushing if parameter is true. */
+ int (*leave)(PuglView*, bool);
+
+ /** Resize drawing context to the given width and height. */
+ int (*resize)(PuglView*, int, int);
+
+ /** Return the puglGetContext() handle for the application, if any. */
+ void* (*getHandle)(PuglView*);
+} PuglDrawContext;
#endif // PUGL_INTERNAL_TYPES_H
diff --git a/pugl/pugl_x11.c b/pugl/pugl_x11.c
index 5acd797..7a334e3 100644
--- a/pugl/pugl_x11.c
+++ b/pugl/pugl_x11.c
@@ -1,5 +1,5 @@
/*
- Copyright 2012-2016 David Robillard <http://drobilla.net>
+ Copyright 2012-2019 David Robillard <http://drobilla.net>
Copyright 2013 Robin Gareus <robin@gareus.org>
Copyright 2011-2012 Ben Loftis, Harrison Consoles
@@ -29,18 +29,17 @@
#include <X11/Xutil.h>
#include <X11/keysym.h>
+#include "pugl/pugl_internal.h"
+#include "pugl/pugl_x11.h"
+
#ifdef PUGL_HAVE_GL
-#include <GL/gl.h>
-#include <GL/glx.h>
+#include "pugl/pugl_x11_gl.h"
#endif
#ifdef PUGL_HAVE_CAIRO
-#include <cairo/cairo-xlib.h>
-#include <cairo/cairo.h>
+#include "pugl/pugl_x11_cairo.h"
#endif
-#include "pugl/pugl_internal.h"
-
#ifndef MIN
# define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
@@ -49,176 +48,22 @@
# define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
-#ifdef PUGL_HAVE_GL
-
-/** Attributes for double-buffered RGBA. */
-static int attrListDbl[] = {
- GLX_RGBA,
- GLX_DOUBLEBUFFER , True,
- GLX_RED_SIZE , 4,
- GLX_GREEN_SIZE , 4,
- GLX_BLUE_SIZE , 4,
- GLX_DEPTH_SIZE , 16,
- /* GLX_SAMPLE_BUFFERS , 1, */
- /* GLX_SAMPLES , 4, */
- None
-};
-
-/** Attributes for single-buffered RGBA. */
-static int attrListSgl[] = {
- GLX_RGBA,
- GLX_DOUBLEBUFFER , False,
- GLX_RED_SIZE , 4,
- GLX_GREEN_SIZE , 4,
- GLX_BLUE_SIZE , 4,
- GLX_DEPTH_SIZE , 16,
- /* GLX_SAMPLE_BUFFERS , 1, */
- /* GLX_SAMPLES , 4, */
- None
-};
-
-/** Null-terminated list of attributes in order of preference. */
-static int* attrLists[] = { attrListDbl, attrListSgl, NULL };
-
-#endif // PUGL_HAVE_GL
-
-struct PuglInternalsImpl {
- Display* display;
- int screen;
- Window win;
- XIM xim;
- XIC xic;
-#ifdef PUGL_HAVE_CAIRO
- cairo_surface_t* surface;
- cairo_t* cr;
-#endif
-#ifdef PUGL_HAVE_GL
- GLXContext ctx;
- int doubleBuffered;
-#endif
-};
-
PuglInternals*
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) {
- for (int* attr = *attrLists; !vi && *attr; ++attr) {
- vi = glXChooseVisual(impl->display, impl->screen, attr);
- }
- }
-#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;
-}
-
-#ifdef PUGL_HAVE_CAIRO
-static int
-createCairoContext(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
-
- if (impl->cr) {
- cairo_destroy(impl->cr);
- }
-
- impl->cr = cairo_create(impl->surface);
- return cairo_status(impl->cr);
-}
-#endif
-
-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);
- glXGetConfig(impl->display, vi, GLX_DOUBLEBUFFER, &impl->doubleBuffered);
- }
-#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);
- }
-#endif
-
-#ifdef PUGL_HAVE_CAIRO
- if (view->ctx_type & PUGL_CAIRO) {
- if (cairo_surface_status(impl->surface) != CAIRO_STATUS_SUCCESS) {
- fprintf(stderr, "error: failed to create cairo surface\n");
- return false;
- }
-
- if (createCairoContext(view) != CAIRO_STATUS_SUCCESS) {
- cairo_surface_destroy(impl->surface);
- fprintf(stderr, "error: failed to create cairo context\n");
- return false;
- }
- }
-#endif
-
- return true;
-}
-
-static void
-destroyContext(PuglView* view)
-{
-#ifdef PUGL_HAVE_GL
- if (view->ctx_type & PUGL_GL) {
- glXDestroyContext(view->impl->display, view->impl->ctx);
- }
-#endif
-#ifdef PUGL_HAVE_CAIRO
- if (view->ctx_type & PUGL_CAIRO) {
- cairo_destroy(view->impl->cr);
- cairo_surface_destroy(view->impl->surface);
- }
-#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
+ view->impl->ctx.enter(view);
}
void
puglLeaveContext(PuglView* view, bool flush)
{
-#ifdef PUGL_HAVE_GL
- if (flush && view->ctx_type & PUGL_GL) {
- glFlush();
- if (view->impl->doubleBuffered) {
- glXSwapBuffers(view->impl->display, view->impl->win);
- }
- }
-
- glXMakeCurrent(view->impl->display, None, NULL);
-#endif
+ view->impl->ctx.leave(view, flush);
}
int
@@ -229,17 +74,32 @@ puglCreateWindow(PuglView* view, const char* title)
impl->display = XOpenDisplay(0);
impl->screen = DefaultScreen(impl->display);
- XVisualInfo* const vi = getVisual(view);
- if (!vi) {
+ if (view->ctx_type == PUGL_GL) {
+#ifdef PUGL_HAVE_GL
+ impl->ctx = puglGetX11GlDrawContext();
+#endif
+ }
+ if (view->ctx_type == PUGL_CAIRO) {
+#ifdef PUGL_HAVE_CAIRO
+ impl->ctx = puglGetX11CairoDrawContext();
+#endif
+ }
+
+ if (!impl->ctx.configure) {
return 1;
}
+ impl->ctx.configure(view);
+ if (!impl->vi) {
+ return 2;
+ }
+
Window xParent = view->parent
? (Window)view->parent
: RootWindow(impl->display, impl->screen);
Colormap cmap = XCreateColormap(
- impl->display, xParent, vi->visual, AllocNone);
+ impl->display, xParent, impl->vi->visual, AllocNone);
XSetWindowAttributes attr;
memset(&attr, 0, sizeof(XSetWindowAttributes));
@@ -252,11 +112,11 @@ puglCreateWindow(PuglView* view, const char* title)
impl->win = XCreateWindow(
impl->display, xParent,
- 0, 0, view->width, view->height, 0, vi->depth, InputOutput, vi->visual,
- CWColormap | CWEventMask, &attr);
+ 0, 0, view->width, view->height, 0, impl->vi->depth, InputOutput,
+ impl->vi->visual, CWColormap | CWEventMask, &attr);
- if (!createContext(view, vi)) {
- return 2;
+ if (impl->ctx.create(view)) {
+ return 3;
}
XSizeHints sizeHints;
@@ -316,8 +176,6 @@ puglCreateWindow(PuglView* view, const char* title)
fprintf(stderr, "warning: XCreateIC failed\n");
}
- XFree(vi);
-
return 0;
}
@@ -339,9 +197,10 @@ void
puglDestroy(PuglView* view)
{
if (view) {
- destroyContext(view);
+ view->impl->ctx.destroy(view);
XDestroyWindow(view->impl->display, view->impl->win);
XCloseDisplay(view->impl->display);
+ XFree(view->impl->vi);
free(view->windowClass);
free(view->impl);
free(view);
@@ -633,15 +492,10 @@ puglProcessEvents(PuglView* view)
}
if (config_event.type) {
-#ifdef PUGL_HAVE_CAIRO
- if (view->ctx_type == PUGL_CAIRO) {
- // Resize surfaces/contexts before dispatching
- view->redisplay = true;
- cairo_xlib_surface_set_size(view->impl->surface,
- config_event.configure.width,
- config_event.configure.height);
- }
-#endif
+ // Resize drawing context before dispatching
+ view->impl->ctx.resize(view,
+ config_event.configure.width,
+ config_event.configure.height);
puglDispatchEvent(view, (const PuglEvent*)&config_event);
}
@@ -677,10 +531,5 @@ puglGetNativeWindow(PuglView* view)
void*
puglGetContext(PuglView* view)
{
-#ifdef PUGL_HAVE_CAIRO
- if (view->ctx_type & PUGL_CAIRO) {
- return view->impl->cr;
- }
-#endif
- return NULL;
+ return view->impl->ctx.getHandle(view);
}
diff --git a/pugl/pugl_x11.h b/pugl/pugl_x11.h
new file mode 100644
index 0000000..a8c8c02
--- /dev/null
+++ b/pugl/pugl_x11.h
@@ -0,0 +1,31 @@
+/*
+ Copyright 2012-2019 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.
+*/
+
+#include <X11/Xlib.h>
+
+#include "pugl/pugl.h"
+#include "pugl/pugl_internal_types.h"
+
+struct PuglInternalsImpl {
+ Display* display;
+ int screen;
+ XVisualInfo* vi;
+ Window win;
+ XIM xim;
+ XIC xic;
+ PuglDrawContext ctx;
+ PuglSurface* surface;
+};
diff --git a/pugl/pugl_x11_cairo.c b/pugl/pugl_x11_cairo.c
new file mode 100644
index 0000000..3614c4b
--- /dev/null
+++ b/pugl/pugl_x11_cairo.c
@@ -0,0 +1,141 @@
+/*
+ Copyright 2012-2019 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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <cairo/cairo-xlib.h>
+#include <cairo/cairo.h>
+
+#include <X11/Xutil.h>
+
+#include "pugl/pugl_internal_types.h"
+#include "pugl/pugl_x11.h"
+#include "pugl/pugl_x11_cairo.h"
+
+typedef struct {
+ cairo_surface_t* surface;
+ cairo_t* cr;
+} PuglX11CairoSurface;
+
+static int
+puglX11CairoConfigure(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+
+ XVisualInfo pat;
+ int n;
+ pat.screen = impl->screen;
+ impl->vi = XGetVisualInfo(impl->display, VisualScreenMask, &pat, &n);
+
+ return 0;
+}
+
+static int
+puglX11CairoCreate(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+ PuglX11CairoSurface* const surface =
+ (PuglX11CairoSurface*)calloc(1, sizeof(PuglX11CairoSurface));
+
+ impl->surface = surface;
+
+ if (view->ctx_type == PUGL_CAIRO) {
+ surface->surface = cairo_xlib_surface_create(
+ impl->display, impl->win, impl->vi->visual, view->width, view->height);
+ }
+
+ if (!surface->surface) {
+ return 1;
+ }
+
+ int st = cairo_surface_status(surface->surface);
+ if (st) {
+ fprintf(stderr, "error: failed to create cairo surface (%s)\n",
+ cairo_status_to_string(st));
+ } else if (!(surface->cr = cairo_create(surface->surface))) {
+ fprintf(stderr, "error: failed to create cairo context\n");
+ } else if ((st = cairo_status(surface->cr))) {
+ cairo_surface_destroy(surface->surface);
+ fprintf(stderr, "error: cairo context is invalid (%s)\n",
+ cairo_status_to_string(st));
+ }
+ return st;
+}
+
+static int
+puglX11CairoDestroy(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+ PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;
+
+ cairo_destroy(surface->cr);
+ cairo_surface_destroy(surface->surface);
+ free(surface);
+ impl->surface = NULL;
+ return 0;
+}
+
+static int
+puglX11CairoEnter(PuglView* view)
+{
+ return 0;
+}
+
+static int
+puglX11CairoLeave(PuglView* view, bool flush)
+{
+ return 0;
+}
+
+static int
+puglX11CairoResize(PuglView* view, int width, int height)
+{
+ PuglInternals* const impl = view->impl;
+ PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;
+
+ view->redisplay = true;
+
+ if (view->ctx_type == PUGL_CAIRO) {
+ cairo_xlib_surface_set_size(surface->surface, width, height);
+ }
+
+ return 0;
+}
+
+static void*
+puglX11CairoGetHandle(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+ PuglX11CairoSurface* const surface = (PuglX11CairoSurface*)impl->surface;
+
+ return surface->cr;
+}
+
+PuglDrawContext puglGetX11CairoDrawContext(void)
+{
+ static const PuglDrawContext puglX11CairoDrawContext = {
+ puglX11CairoConfigure,
+ puglX11CairoCreate,
+ puglX11CairoDestroy,
+ puglX11CairoEnter,
+ puglX11CairoLeave,
+ puglX11CairoResize,
+ puglX11CairoGetHandle
+ };
+
+ return puglX11CairoDrawContext;
+}
diff --git a/pugl/pugl_x11_cairo.h b/pugl/pugl_x11_cairo.h
new file mode 100644
index 0000000..ffad90b
--- /dev/null
+++ b/pugl/pugl_x11_cairo.h
@@ -0,0 +1,22 @@
+/*
+ Copyright 2012-2019 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_X11_CAIRO_H
+#define PUGL_X11_CAIRO_H
+
+PuglDrawContext puglGetX11CairoDrawContext(void);
+
+#endif // PUGL_X11_CAIRO_H
diff --git a/pugl/pugl_x11_gl.c b/pugl/pugl_x11_gl.c
new file mode 100644
index 0000000..809f4a3
--- /dev/null
+++ b/pugl/pugl_x11_gl.c
@@ -0,0 +1,145 @@
+/*
+ Copyright 2012-2019 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.
+*/
+
+#include <stdlib.h>
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+#include "pugl/pugl_x11.h"
+#include "pugl/pugl_x11_gl.h"
+#include "pugl/pugl_internal_types.h"
+
+typedef struct {
+ GLXContext ctx;
+ int doubleBuffered;
+} PuglX11GlSurface;
+
+static int
+puglX11GlConfigure(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+
+ /** Attributes for double-buffered RGBA. */
+ static int attrListDbl[] = { GLX_RGBA,
+ GLX_DOUBLEBUFFER, True,
+ GLX_RED_SIZE, 4,
+ GLX_GREEN_SIZE, 4,
+ GLX_BLUE_SIZE, 4,
+ GLX_DEPTH_SIZE, 16,
+ /* GLX_SAMPLE_BUFFERS , 1, */
+ /* GLX_SAMPLES , 4, */
+ None };
+
+ /** Attributes for single-buffered RGBA. */
+ static int attrListSgl[] = { GLX_RGBA,
+ GLX_DOUBLEBUFFER, False,
+ GLX_RED_SIZE, 4,
+ GLX_GREEN_SIZE, 4,
+ GLX_BLUE_SIZE, 4,
+ GLX_DEPTH_SIZE, 16,
+ /* GLX_SAMPLE_BUFFERS , 1, */
+ /* GLX_SAMPLES , 4, */
+ None };
+
+ /** Null-terminated list of attributes in order of preference. */
+ static int* attrLists[] = { attrListDbl, attrListSgl, NULL };
+
+ if (view->ctx_type & PUGL_GL) {
+ for (int* attr = *attrLists; !impl->vi && *attr; ++attr) {
+ impl->vi = glXChooseVisual(impl->display, impl->screen, attr);
+ }
+ }
+
+ return 0;
+}
+
+static int
+puglX11GlCreate(PuglView* view)
+{
+ PuglInternals* const impl = view->impl;
+
+ PuglX11GlSurface* surface = (PuglX11GlSurface*)calloc(1, sizeof(PuglX11GlSurface));
+
+ impl->surface = surface;
+ surface->ctx = glXCreateContext(impl->display, impl->vi, 0, GL_TRUE);
+ glXGetConfig(
+ impl->display, impl->vi, GLX_DOUBLEBUFFER, &surface->doubleBuffered);
+
+ return 0;
+}
+
+static int
+puglX11GlDestroy(PuglView* view)
+{
+ PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface;
+ glXDestroyContext(view->impl->display, surface->ctx);
+ free(surface);
+ view->impl->surface = NULL;
+ return 0;
+}
+
+static int
+puglX11GlEnter(PuglView* view)
+{
+ PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface;
+ glXMakeCurrent(view->impl->display, view->impl->win, surface->ctx);
+ return 0;
+}
+
+static int
+puglX11GlLeave(PuglView* view, bool flush)
+{
+ PuglX11GlSurface* surface = (PuglX11GlSurface*)view->impl->surface;
+
+ if (flush) {
+ glFlush();
+ }
+
+ glXMakeCurrent(view->impl->display, None, NULL);
+ if (surface->doubleBuffered) {
+ glXSwapBuffers(view->impl->display, view->impl->win);
+ }
+
+ return 0;
+}
+
+static int
+puglX11GlResize(PuglView* view, int width, int height)
+{
+ return 0;
+}
+
+static void*
+puglX11GlGetHandle(PuglView* view)
+{
+ return NULL;
+}
+
+PuglDrawContext puglGetX11GlDrawContext(void)
+{
+ static const PuglDrawContext puglX11GlDrawContext = {
+ puglX11GlConfigure,
+ puglX11GlCreate,
+ puglX11GlDestroy,
+ puglX11GlEnter,
+ puglX11GlLeave,
+ puglX11GlResize,
+ puglX11GlGetHandle
+ };
+
+ return puglX11GlDrawContext;
+}
diff --git a/pugl/pugl_x11_gl.h b/pugl/pugl_x11_gl.h
new file mode 100644
index 0000000..cba6473
--- /dev/null
+++ b/pugl/pugl_x11_gl.h
@@ -0,0 +1,22 @@
+/*
+ Copyright 2012-2019 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_X11_GL_H
+#define PUGL_X11_GL_H
+
+PuglDrawContext puglGetX11GlDrawContext(void);
+
+#endif // PUGL_X11_GL_H
diff --git a/wscript b/wscript
index 8d7f070..a61f73f 100644
--- a/wscript
+++ b/wscript
@@ -103,7 +103,10 @@ def build(bld):
lib_source = ['pugl/pugl_x11.c']
libs = ['X11']
if bld.is_defined('HAVE_GL'):
- libs += ['GL']
+ lib_source += ['pugl/pugl_x11_gl.c']
+ libs += ['GL']
+ if bld.is_defined('HAVE_CAIRO'):
+ lib_source += ['pugl/pugl_x11_cairo.c']
if bld.env['MSVC_COMPILER']:
libflags = []
else: