summaryrefslogtreecommitdiff
path: root/dgl/src/pugl/pugl_x11.c
diff options
context:
space:
mode:
Diffstat (limited to 'dgl/src/pugl/pugl_x11.c')
-rw-r--r--dgl/src/pugl/pugl_x11.c335
1 files changed, 193 insertions, 142 deletions
diff --git a/dgl/src/pugl/pugl_x11.c b/dgl/src/pugl/pugl_x11.c
index d8b091bf..3f98a33e 100644
--- 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 2013 Robin Gareus <robin@gareus.org>
Copyright 2011-2012 Ben Loftis, Harrison Consoles
+ Copyright 2013,2015 Robin Gareus <robin@gareus.org>
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,15 +24,14 @@
#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 <GL/gl.h>
-#include <GL/glx.h>
-
-#include "pugl/pugl_internal.h"
+#include "pugl_internal.h"
#ifndef DGL_FILE_BROWSER_DISABLED
#define SOFD_HAVE_X11
@@ -40,108 +39,74 @@
#include "../sofd/libsofd.c"
#endif
+/* work around buggy re-parent & focus issues on some systems
+ * where no keyboard events are passed through even if the
+ * app has mouse-focus and all other events are working.
+ */
+//#define PUGL_GRAB_FOCUS
+
+/* show messages during initalization
+ */
+//#define PUGL_VERBOSE
+
struct PuglInternalsImpl {
Display* display;
int screen;
Window win;
- XIM xim;
- XIC xic;
GLXContext ctx;
Bool doubleBuffered;
};
-PuglInternals*
-puglInitInternals(void)
-{
- return (PuglInternals*)calloc(1, sizeof(PuglInternals));
-}
-
-static XVisualInfo*
-getVisual(PuglView* view)
-{
- PuglInternals* const impl = view->impl;
- XVisualInfo* vi = NULL;
-
- /**
- 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");
- }
-
- return vi;
-}
+/**
+ 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
+};
-static bool
-createContext(PuglView* view, XVisualInfo* vi)
-{
- PuglInternals* const impl = view->impl;
+/**
+ 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, True,
+ GLX_RED_SIZE, 4,
+ GLX_GREEN_SIZE, 4,
+ GLX_BLUE_SIZE, 4,
+ GLX_DEPTH_SIZE, 16,
+ GLX_ARB_multisample, 1,
+ None
+};
- impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE);
- return (impl->ctx != NULL);
-}
+/**
+ 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
+};
-static void
-destroyContext(PuglView* view)
+PuglInternals*
+puglInitInternals(void)
{
- PuglInternals* const impl = view->impl;
-
- glXDestroyContext(impl->display, impl->ctx);
- impl->ctx = NULL;
+ return (PuglInternals*)calloc(1, sizeof(PuglInternals));
}
void
@@ -165,21 +130,53 @@ puglLeaveContext(PuglView* view, bool flush)
int
puglCreateWindow(PuglView* view, const char* title)
{
- PuglInternals* const impl = view->impl;
+ PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals));
+ if (!impl) {
+ return 1;
+ }
+ view->impl = impl;
impl->display = XOpenDisplay(NULL);
- impl->screen = DefaultScreen(impl->display);
+ if (!impl->display) {
+ free(impl);
+ return 1;
+ }
+ impl->screen = DefaultScreen(impl->display);
+ impl->doubleBuffered = True;
+
+ XVisualInfo* vi = glXChooseVisual(impl->display, impl->screen, attrListDblMS);
+
+ if (!vi) {
+ vi = glXChooseVisual(impl->display, impl->screen, attrListDbl);
+#ifdef PUGL_VERBOSE
+ printf("puGL: multisampling (antialiasing) is not available\n");
+#endif
+ }
+
+ if (!vi) {
+ vi = glXChooseVisual(impl->display, impl->screen, attrListSgl);
+ impl->doubleBuffered = False;
+ }
- XVisualInfo* const vi = getVisual(view);
if (!vi) {
XCloseDisplay(impl->display);
- impl->display = NULL;
+ free(impl);
return 1;
}
+#ifdef PUGL_VERBOSE
int glxMajor, glxMinor;
glXQueryVersion(impl->display, &glxMajor, &glxMinor);
- PUGL_LOGF("GLX Version %d.%d\n", glxMajor, glxMinor);
+ printf("puGL: GLX-Version : %d.%d\n", glxMajor, glxMinor);
+#endif
+
+ impl->ctx = glXCreateContext(impl->display, vi, 0, GL_TRUE);
+
+ if (!impl->ctx) {
+ XCloseDisplay(impl->display);
+ free(impl);
+ return 1;
+ }
Window xParent = view->parent
? (Window)view->parent
@@ -204,62 +201,40 @@ puglCreateWindow(PuglView* view, const char* title)
0, 0, view->width, view->height, 0, vi->depth, InputOutput, vi->visual,
CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &attr);
- if (!createContext(view, vi)) {
- XDestroyWindow(impl->display, impl->win);
- impl->win = 0;
-
+ if (!impl->win) {
XCloseDisplay(impl->display);
- impl->display = NULL;
-
+ free(impl);
return 1;
}
- XSizeHints sizeHints;
- memset(&sizeHints, 0, sizeof(sizeHints));
- if (!view->resizable) {
- sizeHints.flags = PMinSize|PMaxSize;
- sizeHints.min_width = view->width;
- sizeHints.min_height = view->height;
- 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);
- }
+ puglUpdateGeometryConstraints(view, view->min_width, view->min_height, view->min_width != view->width);
+ XResizeWindow(view->impl->display, view->impl->win, view->width, view->height);
if (title) {
XStoreName(impl->display, impl->win, title);
}
- if (!view->parent) {
+ if (view->transient_parent > 0) {
+ XSetTransientForHint(impl->display, impl->win, (Window)view->transient_parent);
+ }
+
+ if (view->parent) {
+ XMapRaised(impl->display, impl->win);
+ } else {
Atom wmDelete = XInternAtom(impl->display, "WM_DELETE_WINDOW", True);
XSetWMProtocols(impl->display, impl->win, &wmDelete, 1);
}
+#ifdef PUGL_VERBOSE
if (glXIsDirect(impl->display, impl->ctx)) {
- PUGL_LOG("DRI enabled (to disable, set LIBGL_ALWAYS_INDIRECT=1\n");
+ printf("puGL: DRI enabled (to disable, set LIBGL_ALWAYS_INDIRECT=1\n");
} else {
- PUGL_LOG("No DRI available\n");
+ printf("puGL: No DRI available\n");
}
+#endif
XFree(vi);
-
- return PUGL_SUCCESS;
-}
-
-void
-puglShowWindow(PuglView* view)
-{
- XMapRaised(view->impl->display, view->impl->win);
-}
-
-void
-puglHideWindow(PuglView* view)
-{
- XUnmapWindow(view->impl->display, view->impl->win);
+ return 0;
}
void
@@ -268,18 +243,29 @@ puglDestroy(PuglView* view)
if (!view) {
return;
}
-
#ifndef DGL_FILE_BROWSER_DISABLED
x_fib_close(view->impl->display);
#endif
- destroyContext(view);
+ glXDestroyContext(view->impl->display, view->impl->ctx);
XDestroyWindow(view->impl->display, view->impl->win);
XCloseDisplay(view->impl->display);
free(view->impl);
free(view);
}
+void
+puglShowWindow(PuglView* view)
+{
+ XMapRaised(view->impl->display, view->impl->win);
+}
+
+void
+puglHideWindow(PuglView* view)
+{
+ XUnmapWindow(view->impl->display, view->impl->win);
+}
+
static void
puglReshape(PuglView* view, int width, int height)
{
@@ -288,7 +274,7 @@ puglReshape(PuglView* view, int width, int height)
if (view->reshapeFunc) {
view->reshapeFunc(view, width, height);
} else {
- puglDefaultReshape(view, width, height);
+ puglDefaultReshape(width, height);
}
puglLeaveContext(view, false);
@@ -303,7 +289,6 @@ puglDisplay(PuglView* view)
puglEnterContext(view);
view->redisplay = false;
-
if (view->displayFunc) {
view->displayFunc(view);
}
@@ -311,6 +296,36 @@ puglDisplay(PuglView* view)
puglLeaveContext(view, true);
}
+static void
+puglResize(PuglView* view)
+{
+ int set_hints = 1;
+ view->pending_resize = false;
+ if (!view->resizeFunc) { return; }
+ /* ask the plugin about the new size */
+ view->resizeFunc(view, &view->width, &view->height, &set_hints);
+
+ if (set_hints) {
+ XSizeHints sizeHints;
+ memset(&sizeHints, 0, sizeof(sizeHints));
+ sizeHints.flags = PMinSize|PMaxSize;
+ sizeHints.min_width = view->width;
+ sizeHints.min_height = view->height;
+ sizeHints.max_width = view->user_resizable ? 4096 : view->width;
+ sizeHints.max_height = view->user_resizable ? 4096 : view->height;
+ XSetWMNormalHints(view->impl->display, view->impl->win, &sizeHints);
+ }
+ XResizeWindow(view->impl->display, view->impl->win, view->width, view->height);
+ XFlush(view->impl->display);
+
+#ifdef PUGL_VERBOSE
+ printf("puGL: window resize (%dx%d)\n", view->width, view->height);
+#endif
+
+ /* and call Reshape in glX context */
+ puglReshape(view, view->width, view->height);
+}
+
static PuglKey
keySymToSpecial(KeySym sym)
{
@@ -439,6 +454,11 @@ puglProcessEvents(PuglView* view)
}
switch (event.type) {
+ case UnmapNotify:
+ if (view->motionFunc) {
+ view->motionFunc(view, -1, -1);
+ }
+ break;
case MapNotify:
puglReshape(view, view->width, view->height);
break;
@@ -530,6 +550,10 @@ puglProcessEvents(PuglView* view)
}
}
+ if (view->pending_resize) {
+ puglResize(view);
+ }
+
if (view->redisplay) {
puglDisplay(view);
}
@@ -543,8 +567,35 @@ puglPostRedisplay(PuglView* view)
view->redisplay = true;
}
+void
+puglPostResize(PuglView* view)
+{
+ view->pending_resize = true;
+}
+
PuglNativeWindow
puglGetNativeWindow(PuglView* view)
{
return view->impl->win;
}
+
+int
+puglUpdateGeometryConstraints(PuglView* view, int min_width, int min_height, bool aspect)
+{
+ XSizeHints sizeHints;
+ memset(&sizeHints, 0, sizeof(sizeHints));
+ sizeHints.flags = PMinSize|PMaxSize;
+ sizeHints.min_width = min_width;
+ sizeHints.min_height = min_height;
+ sizeHints.max_width = view->user_resizable ? 4096 : min_width;
+ sizeHints.max_height = view->user_resizable ? 4096 : min_height;
+ if (aspect) {
+ sizeHints.flags |= PAspect;
+ sizeHints.min_aspect.x = min_width;
+ sizeHints.min_aspect.y = min_height;
+ sizeHints.max_aspect.x = min_width;
+ sizeHints.max_aspect.y = min_height;
+ }
+ XSetWMNormalHints(view->impl->display, view->impl->win, &sizeHints);
+ return 0;
+}