diff options
Diffstat (limited to 'dgl/src/pugl/pugl_x11.c')
-rw-r--r-- | dgl/src/pugl/pugl_x11.c | 335 |
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; +} |