From 1a33796098696c40c3a490ad0cee97fc07f8cf77 Mon Sep 17 00:00:00 2001 From: Wolfgang Draxinger Date: Mon, 22 Feb 2016 18:08:15 +0100 Subject: [PATCH 01/11] Add support for transparent X11/GLX window --- examples/gears.c | 3 ++ include/GLFW/glfw3.h | 1 + src/glx_context.c | 98 ++++++++++++++++++++++++++++++++++++++++---- src/glx_context.h | 35 ++++++++++++++-- src/internal.h | 2 + src/window.c | 7 ++++ src/x11_window.c | 2 +- 7 files changed, 135 insertions(+), 13 deletions(-) diff --git a/examples/gears.c b/examples/gears.c index 29e63f58b..c5897dcca 100644 --- a/examples/gears.c +++ b/examples/gears.c @@ -172,6 +172,7 @@ static GLfloat angle = 0.f; /* OpenGL draw function & timing */ static void draw(void) { + glClearColor(0., 0., 0., 0.); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); @@ -311,6 +312,8 @@ int main(int argc, char *argv[]) } glfwWindowHint(GLFW_DEPTH_BITS, 16); + glfwWindowHint(GLFW_ALPHA_BITS, 8); + glfwWindowHint(GLFW_TRANSPARENT, GLFW_TRUE); window = glfwCreateWindow( 300, 300, "Gears", NULL, NULL ); if (!window) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 41e5f7d8c..2e6ed0c14 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -627,6 +627,7 @@ extern "C" { #define GLFW_AUTO_ICONIFY 0x00020006 #define GLFW_FLOATING 0x00020007 #define GLFW_MAXIMIZED 0x00020008 +#define GLFW_TRANSPARENT 0x00020009 #define GLFW_RED_BITS 0x00021001 #define GLFW_GREEN_BITS 0x00021002 diff --git a/src/glx_context.c b/src/glx_context.c index 22ec7e10a..b4b8b589f 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -47,7 +47,10 @@ static int getFBConfigAttrib(GLXFBConfig fbconfig, int attrib) // Return a list of available and usable framebuffer configs // -static GLFWbool chooseFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* result) +static GLFWbool chooseFBConfig( + const _GLFWfbconfig* desired, + GLXFBConfig* result, + GLFWbool findTransparent) { GLXFBConfig* nativeConfigs; _GLFWfbconfig* usableConfigs; @@ -56,6 +59,10 @@ static GLFWbool chooseFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* result const char* vendor; GLFWbool trustWindowBit = GLFW_TRUE; + if (findTransparent && !(_glfw.xrender.major || _glfw.xrender.minor)) { + findTransparent = GLFW_FALSE; + } + // HACK: This is a (hopefully temporary) workaround for Chromium // (VirtualBox GL) not setting the window bit on any GLXFBConfigs vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR); @@ -73,6 +80,7 @@ static GLFWbool chooseFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* result usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; +selectionloop: for (i = 0; i < nativeCount; i++) { const GLXFBConfig n = nativeConfigs[i]; @@ -89,6 +97,22 @@ static GLFWbool chooseFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* result continue; } + if( findTransparent ) { + XVisualInfo *visualinfo; + XRenderPictFormat *pictFormat; + + visualinfo = glXGetVisualFromFBConfig(_glfw.x11.display, n); + if (!visualinfo) + continue; + + pictFormat = XRenderFindVisualFormat(_glfw.x11.display, visualinfo->visual); + if( !pictFormat ) + continue; + + if( !pictFormat->direct.alphaMask ) + continue; + } + u->redBits = getFBConfigAttrib(n, GLX_RED_SIZE); u->greenBits = getFBConfigAttrib(n, GLX_GREEN_SIZE); u->blueBits = getFBConfigAttrib(n, GLX_BLUE_SIZE); @@ -118,6 +142,12 @@ static GLFWbool chooseFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* result u->glx = n; usableCount++; } + // reiterate the selection loop without looking for transparency supporting + // formats if no matchig FB configs for a transparent window were found. + if( findTransparent && !usableCount ) { + findTransparent = GLFW_FALSE; + goto selectionloop; + } closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); if (closest) @@ -152,7 +182,7 @@ static GLXContext createLegacyContext(_GLFWwindow* window, GLFWbool _glfwInitGLX(void) { int i; - const char* sonames[] = + const char* sonames_glx[] = { #if defined(__CYGWIN__) "libGL-1.so", @@ -163,14 +193,32 @@ GLFWbool _glfwInitGLX(void) NULL }; - - for (i = 0; sonames[i]; i++) + const char* sonames_xrender[] = { - _glfw.glx.handle = dlopen(sonames[i], RTLD_LAZY | RTLD_GLOBAL); +#if defined(__CYGWIN__) + "libXrender-1.so", +#else + "libXrender.so.1", + "libXrender.so", +#endif + NULL + }; + + + for (i = 0; sonames_glx[i]; i++) + { + _glfw.glx.handle = dlopen(sonames_glx[i], RTLD_LAZY | RTLD_GLOBAL); if (_glfw.glx.handle) break; } + for (i = 0; sonames_xrender[i]; i++) + { + _glfw.xrender.handle = dlopen(sonames_xrender[i], RTLD_LAZY | RTLD_GLOBAL); + if (_glfw.xrender.handle) + break; + } + if (!_glfw.glx.handle) { _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: Failed to load GLX"); @@ -230,6 +278,37 @@ GLFWbool _glfwInitGLX(void) return GLFW_FALSE; } + // Xrender support is optional and not a requirement for GLX + // to work. Xrender is required for selecting a FB config that + // supports a picture format with an alpha mask, which in turn + // is required for transparent windows. I Xrender is not supported + // the GLFW_TRANSPARENT window hint is ignored. + _glfw.xrender.errorBase = 0; + _glfw.xrender.eventBase = 0; + _glfw.xrender.major = 0; + _glfw.xrender.minor = 0; + if (_glfw.xrender.handle) do { + int errorBase, eventBase, major, minor; + _glfw.xrender.QueryExtension = + dlsym(_glfw.xrender.handle, "XRenderQueryExtension"); + _glfw.xrender.QueryVersion = + dlsym(_glfw.xrender.handle, "XRenderQueryVersion"); + _glfw.xrender.FindVisualFormat = + dlsym(_glfw.xrender.handle, "XRenderFindVisualFormat"); + + if ( !XRenderQueryExtension(_glfw.x11.display, &errorBase, &eventBase)) { + break; + } + if ( !XRenderQueryVersion(_glfw.x11.display, &major, &minor)) { + break; + } + + _glfw.xrender.errorBase = errorBase; + _glfw.xrender.eventBase = eventBase; + _glfw.xrender.major = major; + _glfw.xrender.minor = minor; + } while(0); + if (_glfwPlatformExtensionSupported("GLX_EXT_swap_control")) { _glfw.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) @@ -324,7 +403,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, if (ctxconfig->share) share = ctxconfig->share->context.glx.handle; - if (!chooseFBConfig(fbconfig, &native)) + if (!chooseFBConfig(fbconfig, &native, window->transparent)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "GLX: Failed to find a suitable GLXFBConfig"); @@ -507,14 +586,15 @@ void _glfwDestroyContextGLX(_GLFWwindow* window) // Returns the Visual and depth of the chosen GLXFBConfig // -GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig, +GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, Visual** visual, int* depth) { GLXFBConfig native; XVisualInfo* result; - if (!chooseFBConfig(fbconfig, &native)) + if (!chooseFBConfig(fbconfig, &native, wndconfig->transparent)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "GLX: Failed to find a suitable GLXFBConfig"); @@ -530,7 +610,7 @@ GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig, } *visual = result->visual; - *depth = result->depth; + *depth = result->depth; XFree(result); return GLFW_TRUE; diff --git a/src/glx_context.h b/src/glx_context.h index dc54c7973..81b7d1e6b 100644 --- a/src/glx_context.h +++ b/src/glx_context.h @@ -74,6 +74,7 @@ typedef struct __GLXFBConfig* GLXFBConfig; typedef struct __GLXcontext* GLXContext; typedef void (*__GLXextproc)(void); +// libGL.so function pointer typedefs typedef int (*PFNGLXGETFBCONFIGATTRIBPROC)(Display*,GLXFBConfig,int,int*); typedef const char* (*PFNGLXGETCLIENTSTRINGPROC)(Display*,int); typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display*,int*,int*); @@ -93,7 +94,7 @@ typedef XVisualInfo* (*PFNGLXGETVISUALFROMFBCONFIGPROC)(Display*,GLXFBConfig); typedef GLXWindow (*PFNGLXCREATEWINDOWPROC)(Display*,GLXFBConfig,Window,const int*); typedef void (*PFNGLXDESTROYWINDOWPROC)(Display*,GLXWindow); -// libGL.so function pointer typedefs +// libGL.so function identifier overlays #define glXGetFBConfigs _glfw.glx.GetFBConfigs #define glXGetFBConfigAttrib _glfw.glx.GetFBConfigAttrib #define glXGetClientString _glfw.glx.GetClientString @@ -108,9 +109,19 @@ typedef void (*PFNGLXDESTROYWINDOWPROC)(Display*,GLXWindow); #define glXCreateWindow _glfw.glx.CreateWindow #define glXDestroyWindow _glfw.glx.DestroyWindow +// libXrender.so function pointer typedefs +typedef Bool (*PFNXRENDERQUERYEXTENSIONPROC)(Display*,int*,int*); +typedef Status (*PFNXRENDERQUERYVERSIONPROC)(Display*dpy,int*,int*); +typedef XRenderPictFormat* (*PFNXRENDERFINDVISUALFORMATPROC)(Display*,Visual const *); + +// libXrender.so function identifier overlays +#define XRenderQueryExtension _glfw.xrender.QueryExtension +#define XRenderQueryVersion _glfw.xrender.QueryVersion +#define XRenderFindVisualFormat _glfw.xrender.FindVisualFormat + #define _GLFW_PLATFORM_FBCONFIG GLXFBConfig glx #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx -#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx ; _GLFWlibraryXrender xrender // GLX-specific per-context data @@ -170,6 +181,23 @@ typedef struct _GLFWlibraryGLX } _GLFWlibraryGLX; +// Xrender-specific global data +// +typedef struct _GLFWlibraryXrender +{ + int major, minor; + int eventBase; + int errorBase; + + // dlopen handle for libGL.so.1 + void* handle; + + // Xrender functions (subset required for transparent window) + PFNXRENDERQUERYEXTENSIONPROC QueryExtension; + PFNXRENDERQUERYVERSIONPROC QueryVersion; + PFNXRENDERFINDVISUALFORMATPROC FindVisualFormat; +} _GLFWlibraryXrender; + GLFWbool _glfwInitGLX(void); void _glfwTerminateGLX(void); @@ -177,7 +205,8 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); void _glfwDestroyContextGLX(_GLFWwindow* window); -GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig, +GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, Visual** visual, int* depth); diff --git a/src/internal.h b/src/internal.h index 358da2562..a11890366 100644 --- a/src/internal.h +++ b/src/internal.h @@ -252,6 +252,7 @@ struct _GLFWwndconfig GLFWbool resizable; GLFWbool visible; GLFWbool decorated; + GLFWbool transparent; GLFWbool focused; GLFWbool autoIconify; GLFWbool floating; @@ -341,6 +342,7 @@ struct _GLFWwindow // Window settings and state GLFWbool resizable; GLFWbool decorated; + GLFWbool transparent; GLFWbool autoIconify; GLFWbool floating; GLFWbool closed; diff --git a/src/window.c b/src/window.c index f051370e1..11b9b0add 100644 --- a/src/window.c +++ b/src/window.c @@ -178,6 +178,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, window->monitor = wndconfig.monitor; window->resizable = wndconfig.resizable; window->decorated = wndconfig.decorated; + window->transparent = wndconfig.transparent; window->autoIconify = wndconfig.autoIconify; window->floating = wndconfig.floating; window->cursorMode = GLFW_CURSOR_NORMAL; @@ -256,6 +257,7 @@ void glfwDefaultWindowHints(void) _glfw.hints.window.resizable = GLFW_TRUE; _glfw.hints.window.visible = GLFW_TRUE; _glfw.hints.window.decorated = GLFW_TRUE; + _glfw.hints.window.transparent = GLFW_FALSE; _glfw.hints.window.focused = GLFW_TRUE; _glfw.hints.window.autoIconify = GLFW_TRUE; @@ -330,6 +332,9 @@ GLFWAPI void glfwWindowHint(int hint, int value) case GLFW_DECORATED: _glfw.hints.window.decorated = value ? GLFW_TRUE : GLFW_FALSE; break; + case GLFW_TRANSPARENT: + _glfw.hints.window.transparent = value ? GLFW_TRUE : GLFW_FALSE; + break; case GLFW_FOCUSED: _glfw.hints.window.focused = value ? GLFW_TRUE : GLFW_FALSE; break; @@ -650,6 +655,8 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib) return window->resizable; case GLFW_DECORATED: return window->decorated; + case GLFW_TRANSPARENT: + return window->transparent; case GLFW_FLOATING: return window->floating; case GLFW_CLIENT_API: diff --git a/src/x11_window.c b/src/x11_window.c index 2f9130a74..a2b96a997 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1431,7 +1431,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, else { #if defined(_GLFW_GLX) - if (!_glfwChooseVisualGLX(ctxconfig, fbconfig, &visual, &depth)) + if (!_glfwChooseVisualGLX(wndconfig, ctxconfig, fbconfig, &visual, &depth)) return GLFW_FALSE; #elif defined(_GLFW_EGL) if (!_glfwChooseVisualEGL(ctxconfig, fbconfig, &visual, &depth)) From e9693a13fece33cb2042151e501cee83f29bdc00 Mon Sep 17 00:00:00 2001 From: Wolfgang Draxinger Date: Mon, 22 Feb 2016 18:55:30 +0100 Subject: [PATCH 02/11] Always reset transparency flag --- src/glx_context.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/glx_context.c b/src/glx_context.c index b4b8b589f..7d9cc0e1a 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -59,7 +59,7 @@ static GLFWbool chooseFBConfig( const char* vendor; GLFWbool trustWindowBit = GLFW_TRUE; - if (findTransparent && !(_glfw.xrender.major || _glfw.xrender.minor)) { + if ( !(_glfw.xrender.major || _glfw.xrender.minor) ) { findTransparent = GLFW_FALSE; } From 19c2a53dc0d42fdbeac74ef2d848e32f238c2634 Mon Sep 17 00:00:00 2001 From: Wolfgang Draxinger Date: Mon, 22 Feb 2016 19:42:21 +0100 Subject: [PATCH 03/11] Free visualinfo and picture format info structures Fixes a memory leak. --- src/glx_context.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/glx_context.c b/src/glx_context.c index 7d9cc0e1a..fedfc50d4 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -79,7 +79,9 @@ static GLFWbool chooseFBConfig( usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; - + + XVisualInfo *visualinfo = NULL; + XRenderPictFormat *pictFormat = NULL; selectionloop: for (i = 0; i < nativeCount; i++) { @@ -98,13 +100,21 @@ selectionloop: } if( findTransparent ) { - XVisualInfo *visualinfo; - XRenderPictFormat *pictFormat; + if( visualinfo ) { + XFree( visualinfo ); + visualinfo = NULL; + } + visualinfo = glXGetVisualFromFBConfig(_glfw.x11.display, n); if (!visualinfo) continue; + if( pictFormat ) { + XFree( pictFormat ); + pictFormat = NULL; + } + pictFormat = XRenderFindVisualFormat(_glfw.x11.display, visualinfo->visual); if( !pictFormat ) continue; @@ -141,6 +151,15 @@ selectionloop: u->glx = n; usableCount++; + + if( visualinfo ) { + XFree( visualinfo ); + visualinfo = NULL; + } + if( pictFormat ) { + XFree( pictFormat ); + pictFormat = NULL; + } } // reiterate the selection loop without looking for transparency supporting // formats if no matchig FB configs for a transparent window were found. From 9825849a09da830437bea787a5d2bd29089cbecd Mon Sep 17 00:00:00 2001 From: Wolfgang Draxinger Date: Mon, 22 Feb 2016 21:03:18 +0100 Subject: [PATCH 04/11] Add X11/EGL transparent window support Seems like Mesa EGL fbconfigs don't match with transparent picture formats. --- src/egl_context.c | 49 ++++++++++++++++++++++++--- src/egl_context.h | 3 +- src/glx_context.c | 83 ++++++---------------------------------------- src/glx_context.h | 30 +---------------- src/x11_init.c | 49 +++++++++++++++++++++++++++ src/x11_platform.h | 27 ++++++++++++++- src/x11_window.c | 2 +- 7 files changed, 133 insertions(+), 110 deletions(-) diff --git a/src/egl_context.c b/src/egl_context.c index 827ccbfd3..d3c35ef79 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -86,13 +86,21 @@ static int getConfigAttrib(EGLConfig config, int attrib) // static GLFWbool chooseFBConfigs(const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* desired, - EGLConfig* result) + EGLConfig* result, + GLFWbool findTransparent) { EGLConfig* nativeConfigs; _GLFWfbconfig* usableConfigs; const _GLFWfbconfig* closest; int i, nativeCount, usableCount; +#if defined(_GLFW_X11) + XVisualInfo visualTemplate = {0}; + if ( !(_glfw.xrender.major || _glfw.xrender.minor) ) { + findTransparent = GLFW_FALSE; + } +#endif // _GLFW_X11 + eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount); if (!nativeCount) { @@ -106,6 +114,7 @@ static GLFWbool chooseFBConfigs(const _GLFWctxconfig* ctxconfig, usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; +selectionloop: for (i = 0; i < nativeCount; i++) { const EGLConfig n = nativeConfigs[i]; @@ -121,8 +130,31 @@ static GLFWbool chooseFBConfigs(const _GLFWctxconfig* ctxconfig, #if defined(_GLFW_X11) // Only consider EGLConfigs with associated Visuals - if (!getConfigAttrib(n, EGL_NATIVE_VISUAL_ID)) + visualTemplate.visualid = getConfigAttrib(n, EGL_NATIVE_VISUAL_ID); + if (!visualTemplate.visualid) continue; + + if( findTransparent ) { + int n_vi; + XVisualInfo *visualinfo; + XRenderPictFormat *pictFormat; + + visualinfo = XGetVisualInfo(_glfw.x11.display, VisualIDMask, &visualTemplate, &n_vi); + if (!visualinfo) + continue; + + pictFormat = XRenderFindVisualFormat(_glfw.x11.display, visualinfo->visual); + if( !pictFormat ) { + XFree( visualinfo ); + continue; + } + + if( !pictFormat->direct.alphaMask ) { + XFree( visualinfo ); + continue; + } + XFree( visualinfo ); + } #endif // _GLFW_X11 if (ctxconfig->api == GLFW_OPENGL_ES_API) @@ -158,6 +190,12 @@ static GLFWbool chooseFBConfigs(const _GLFWctxconfig* ctxconfig, u->egl = n; usableCount++; } + // reiterate the selection loop without looking for transparency supporting + // formats if no matchig FB configs for a transparent window were found. + if( findTransparent && !usableCount ) { + findTransparent = GLFW_FALSE; + goto selectionloop; + } closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount); if (closest) @@ -297,7 +335,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, if (ctxconfig->share) share = ctxconfig->share->context.egl.handle; - if (!chooseFBConfigs(ctxconfig, fbconfig, &config)) + if (!chooseFBConfigs(ctxconfig, fbconfig, &config, window->transparent)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Failed to find a suitable EGLConfig"); @@ -535,7 +573,8 @@ void _glfwDestroyContextEGL(_GLFWwindow* window) // Returns the Visual and depth of the chosen EGLConfig // #if defined(_GLFW_X11) -GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig, +GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, Visual** visual, int* depth) { @@ -545,7 +584,7 @@ GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig, EGLint visualID = 0, count = 0; const long vimask = VisualScreenMask | VisualIDMask; - if (!chooseFBConfigs(ctxconfig, fbconfig, &native)) + if (!chooseFBConfigs(ctxconfig, fbconfig, &native, wndconfig->transparent)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Failed to find a suitable EGLConfig"); diff --git a/src/egl_context.h b/src/egl_context.h index 15d5a1258..b37263311 100644 --- a/src/egl_context.h +++ b/src/egl_context.h @@ -207,7 +207,8 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, const _GLFWfbconfig* fbconfig); void _glfwDestroyContextEGL(_GLFWwindow* window); #if defined(_GLFW_X11) -GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig, +GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig, + const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig, Visual** visual, int* depth); #endif /*_GLFW_X11*/ diff --git a/src/glx_context.c b/src/glx_context.c index fedfc50d4..ca225e244 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -80,8 +80,6 @@ static GLFWbool chooseFBConfig( usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; - XVisualInfo *visualinfo = NULL; - XRenderPictFormat *pictFormat = NULL; selectionloop: for (i = 0; i < nativeCount; i++) { @@ -100,27 +98,24 @@ selectionloop: } if( findTransparent ) { - - if( visualinfo ) { - XFree( visualinfo ); - visualinfo = NULL; - } + XVisualInfo *visualinfo; + XRenderPictFormat *pictFormat; visualinfo = glXGetVisualFromFBConfig(_glfw.x11.display, n); if (!visualinfo) continue; - if( pictFormat ) { - XFree( pictFormat ); - pictFormat = NULL; + pictFormat = XRenderFindVisualFormat(_glfw.x11.display, visualinfo->visual); + if( !pictFormat ) { + XFree( visualinfo ); + continue; } - pictFormat = XRenderFindVisualFormat(_glfw.x11.display, visualinfo->visual); - if( !pictFormat ) - continue; - - if( !pictFormat->direct.alphaMask ) + if( !pictFormat->direct.alphaMask ) { + XFree( visualinfo ); continue; + } + XFree( visualinfo ); } u->redBits = getFBConfigAttrib(n, GLX_RED_SIZE); @@ -151,15 +146,6 @@ selectionloop: u->glx = n; usableCount++; - - if( visualinfo ) { - XFree( visualinfo ); - visualinfo = NULL; - } - if( pictFormat ) { - XFree( pictFormat ); - pictFormat = NULL; - } } // reiterate the selection loop without looking for transparency supporting // formats if no matchig FB configs for a transparent window were found. @@ -212,17 +198,6 @@ GLFWbool _glfwInitGLX(void) NULL }; - const char* sonames_xrender[] = - { -#if defined(__CYGWIN__) - "libXrender-1.so", -#else - "libXrender.so.1", - "libXrender.so", -#endif - NULL - }; - for (i = 0; sonames_glx[i]; i++) { @@ -231,13 +206,6 @@ GLFWbool _glfwInitGLX(void) break; } - for (i = 0; sonames_xrender[i]; i++) - { - _glfw.xrender.handle = dlopen(sonames_xrender[i], RTLD_LAZY | RTLD_GLOBAL); - if (_glfw.xrender.handle) - break; - } - if (!_glfw.glx.handle) { _glfwInputError(GLFW_API_UNAVAILABLE, "GLX: Failed to load GLX"); @@ -297,37 +265,6 @@ GLFWbool _glfwInitGLX(void) return GLFW_FALSE; } - // Xrender support is optional and not a requirement for GLX - // to work. Xrender is required for selecting a FB config that - // supports a picture format with an alpha mask, which in turn - // is required for transparent windows. I Xrender is not supported - // the GLFW_TRANSPARENT window hint is ignored. - _glfw.xrender.errorBase = 0; - _glfw.xrender.eventBase = 0; - _glfw.xrender.major = 0; - _glfw.xrender.minor = 0; - if (_glfw.xrender.handle) do { - int errorBase, eventBase, major, minor; - _glfw.xrender.QueryExtension = - dlsym(_glfw.xrender.handle, "XRenderQueryExtension"); - _glfw.xrender.QueryVersion = - dlsym(_glfw.xrender.handle, "XRenderQueryVersion"); - _glfw.xrender.FindVisualFormat = - dlsym(_glfw.xrender.handle, "XRenderFindVisualFormat"); - - if ( !XRenderQueryExtension(_glfw.x11.display, &errorBase, &eventBase)) { - break; - } - if ( !XRenderQueryVersion(_glfw.x11.display, &major, &minor)) { - break; - } - - _glfw.xrender.errorBase = errorBase; - _glfw.xrender.eventBase = eventBase; - _glfw.xrender.major = major; - _glfw.xrender.minor = minor; - } while(0); - if (_glfwPlatformExtensionSupported("GLX_EXT_swap_control")) { _glfw.glx.SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) diff --git a/src/glx_context.h b/src/glx_context.h index 81b7d1e6b..cc3f22983 100644 --- a/src/glx_context.h +++ b/src/glx_context.h @@ -109,19 +109,9 @@ typedef void (*PFNGLXDESTROYWINDOWPROC)(Display*,GLXWindow); #define glXCreateWindow _glfw.glx.CreateWindow #define glXDestroyWindow _glfw.glx.DestroyWindow -// libXrender.so function pointer typedefs -typedef Bool (*PFNXRENDERQUERYEXTENSIONPROC)(Display*,int*,int*); -typedef Status (*PFNXRENDERQUERYVERSIONPROC)(Display*dpy,int*,int*); -typedef XRenderPictFormat* (*PFNXRENDERFINDVISUALFORMATPROC)(Display*,Visual const *); - -// libXrender.so function identifier overlays -#define XRenderQueryExtension _glfw.xrender.QueryExtension -#define XRenderQueryVersion _glfw.xrender.QueryVersion -#define XRenderFindVisualFormat _glfw.xrender.FindVisualFormat - #define _GLFW_PLATFORM_FBCONFIG GLXFBConfig glx #define _GLFW_PLATFORM_CONTEXT_STATE _GLFWcontextGLX glx -#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx ; _GLFWlibraryXrender xrender +#define _GLFW_PLATFORM_LIBRARY_CONTEXT_STATE _GLFWlibraryGLX glx // GLX-specific per-context data @@ -181,24 +171,6 @@ typedef struct _GLFWlibraryGLX } _GLFWlibraryGLX; -// Xrender-specific global data -// -typedef struct _GLFWlibraryXrender -{ - int major, minor; - int eventBase; - int errorBase; - - // dlopen handle for libGL.so.1 - void* handle; - - // Xrender functions (subset required for transparent window) - PFNXRENDERQUERYEXTENSIONPROC QueryExtension; - PFNXRENDERQUERYVERSIONPROC QueryVersion; - PFNXRENDERFINDVISUALFORMATPROC FindVisualFormat; -} _GLFWlibraryXrender; - - GLFWbool _glfwInitGLX(void); void _glfwTerminateGLX(void); GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, diff --git a/src/x11_init.c b/src/x11_init.c index e73bb1314..e04d98b1c 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -474,6 +474,18 @@ static void detectEWMH(void) // static GLFWbool initExtensions(void) { + int i; + const char* sonames_xrender[] = + { +#if defined(__CYGWIN__) + "libXrender-1.so", +#else + "libXrender.so.1", + "libXrender.so", +#endif + NULL + }; + // Find or create window manager atoms _glfw.x11.WM_PROTOCOLS = XInternAtom(_glfw.x11.display, "WM_PROTOCOLS", @@ -615,6 +627,43 @@ static GLFWbool initExtensions(void) _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", True); _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", True); + // Xrender support is optional and not a requirement for GLX/EGL + // to work. Xrender is required for selecting a FB config that + // supports a picture format with an alpha mask, which in turn + // is required for transparent windows. I Xrender is not supported + // the GLFW_TRANSPARENT window hint is ignored. + for (i = 0; sonames_xrender[i]; i++) + { + _glfw.xrender.handle = dlopen(sonames_xrender[i], RTLD_LAZY | RTLD_GLOBAL); + if (_glfw.xrender.handle) + break; + } + _glfw.xrender.errorBase = 0; + _glfw.xrender.eventBase = 0; + _glfw.xrender.major = 0; + _glfw.xrender.minor = 0; + if (_glfw.xrender.handle) do { + int errorBase, eventBase, major, minor; + _glfw.xrender.QueryExtension = + dlsym(_glfw.xrender.handle, "XRenderQueryExtension"); + _glfw.xrender.QueryVersion = + dlsym(_glfw.xrender.handle, "XRenderQueryVersion"); + _glfw.xrender.FindVisualFormat = + dlsym(_glfw.xrender.handle, "XRenderFindVisualFormat"); + + if ( !XRenderQueryExtension(_glfw.x11.display, &errorBase, &eventBase)) { + break; + } + if ( !XRenderQueryVersion(_glfw.x11.display, &major, &minor)) { + break; + } + + _glfw.xrender.errorBase = errorBase; + _glfw.xrender.eventBase = eventBase; + _glfw.xrender.major = major; + _glfw.xrender.minor = minor; + } while(0); + return GLFW_TRUE; } diff --git a/src/x11_platform.h b/src/x11_platform.h index 8d791f074..6a95ea263 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -103,10 +103,20 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(Vk #define _glfw_dlsym(handle, name) dlsym(handle, name) #define _GLFW_PLATFORM_WINDOW_STATE _GLFWwindowX11 x11 -#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11 +#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11 ; _GLFWlibraryXrender xrender #define _GLFW_PLATFORM_MONITOR_STATE _GLFWmonitorX11 x11 #define _GLFW_PLATFORM_CURSOR_STATE _GLFWcursorX11 x11 +// libXrender.so function pointer typedefs +typedef Bool (*PFNXRENDERQUERYEXTENSIONPROC)(Display*,int*,int*); +typedef Status (*PFNXRENDERQUERYVERSIONPROC)(Display*dpy,int*,int*); +typedef XRenderPictFormat* (*PFNXRENDERFINDVISUALFORMATPROC)(Display*,Visual const *); + +// libXrender.so function identifier overlays +#define XRenderQueryExtension _glfw.xrender.QueryExtension +#define XRenderQueryVersion _glfw.xrender.QueryVersion +#define XRenderFindVisualFormat _glfw.xrender.FindVisualFormat + // X11-specific per-window data // @@ -255,6 +265,21 @@ typedef struct _GLFWlibraryX11 } _GLFWlibraryX11; +// Xrender-specific global data +typedef struct _GLFWlibraryXrender +{ + int major, minor; + int eventBase; + int errorBase; + + // dlopen handle for libGL.so.1 + void* handle; + + // Xrender functions (subset required for transparent window) + PFNXRENDERQUERYEXTENSIONPROC QueryExtension; + PFNXRENDERQUERYVERSIONPROC QueryVersion; + PFNXRENDERFINDVISUALFORMATPROC FindVisualFormat; +} _GLFWlibraryXrender; // X11-specific per-monitor data // diff --git a/src/x11_window.c b/src/x11_window.c index a2b96a997..d85229328 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1434,7 +1434,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (!_glfwChooseVisualGLX(wndconfig, ctxconfig, fbconfig, &visual, &depth)) return GLFW_FALSE; #elif defined(_GLFW_EGL) - if (!_glfwChooseVisualEGL(ctxconfig, fbconfig, &visual, &depth)) + if (!_glfwChooseVisualEGL(wndconfig, ctxconfig, fbconfig, &visual, &depth)) return GLFW_FALSE; #endif } From 95b4c2c17f121181731587392b9d93a151b2dfe1 Mon Sep 17 00:00:00 2001 From: Christopher Pelloux Date: Tue, 23 Feb 2016 21:53:55 -0500 Subject: [PATCH 05/11] add to .gitignore a VS2015 file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c2450f75c..4d59cce85 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ Debug Release MinSizeRel RelWithDebInfo +*.VC.opendb # CMake files Makefile From 5796b966bf76716137c74a1eb07c75d7b3a9e9ed Mon Sep 17 00:00:00 2001 From: Christopher Pelloux Date: Tue, 23 Feb 2016 23:40:22 -0500 Subject: [PATCH 06/11] add transparent window support for Windows Vista and up --- examples/gears.c | 1 + src/win32_init.c | 2 ++ src/win32_platform.h | 12 ++++++++++++ src/win32_window.c | 13 +++++++++++++ 4 files changed, 28 insertions(+) diff --git a/examples/gears.c b/examples/gears.c index c5897dcca..7e3ca4391 100644 --- a/examples/gears.c +++ b/examples/gears.c @@ -314,6 +314,7 @@ int main(int argc, char *argv[]) glfwWindowHint(GLFW_DEPTH_BITS, 16); glfwWindowHint(GLFW_ALPHA_BITS, 8); glfwWindowHint(GLFW_TRANSPARENT, GLFW_TRUE); + glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); window = glfwCreateWindow( 300, 300, "Gears", NULL, NULL ); if (!window) diff --git a/src/win32_init.c b/src/win32_init.c index 57acdb3ae..8029999a1 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -97,6 +97,8 @@ static GLFWbool loadLibraries(void) GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled"); _glfw.win32.dwmapi.DwmFlush = (DWMFLUSH_T) GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush"); + _glfw.win32.dwmapi.DwmEnableBlurBehindWindow = (DWMENABLEBLURBEHINDWINDOW_T) + GetProcAddress(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow"); } _glfw.win32.shcore.instance = LoadLibraryA("shcore.dll"); diff --git a/src/win32_platform.h b/src/win32_platform.h index 47b4999a6..eabf40376 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -120,21 +120,32 @@ typedef enum PROCESS_DPI_AWARENESS } PROCESS_DPI_AWARENESS; #endif /*DPI_ENUMS_DECLARED*/ +typedef struct _DWM_BLURBEHIND +{ + DWORD dwFlags; + BOOL fEnable; + HRGN hRgnBlur; + BOOL fTransitionOnMaximized; +} DWM_BLURBEHIND, *PDWM_BLURBEHIND; + // winmm.dll function pointer typedefs typedef MMRESULT (WINAPI * JOYGETDEVCAPS_T)(UINT,LPJOYCAPS,UINT); typedef MMRESULT (WINAPI * JOYGETPOS_T)(UINT,LPJOYINFO); typedef MMRESULT (WINAPI * JOYGETPOSEX_T)(UINT,LPJOYINFOEX); typedef DWORD (WINAPI * TIMEGETTIME_T)(void); +typedef HRESULT(WINAPI * DWMENABLEBLURBEHINDWINDOW_T)(HWND, const DWM_BLURBEHIND*); #define _glfw_joyGetDevCaps _glfw.win32.winmm.joyGetDevCaps #define _glfw_joyGetPos _glfw.win32.winmm.joyGetPos #define _glfw_joyGetPosEx _glfw.win32.winmm.joyGetPosEx #define _glfw_timeGetTime _glfw.win32.winmm.timeGetTime +#define _glfw_DwmEnableBlurBehindWindow _glfw.win32.dwmapi.DwmEnableBlurBehindWindow // user32.dll function pointer typedefs typedef BOOL (WINAPI * SETPROCESSDPIAWARE_T)(void); typedef BOOL (WINAPI * CHANGEWINDOWMESSAGEFILTEREX_T)(HWND,UINT,DWORD,PCHANGEFILTERSTRUCT); #define _glfw_SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware #define _glfw_ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx +#define _glfw_DwmEnableBlurBehindWindow _glfw.win32.dwmapi.DwmEnableBlurBehindWindow // dwmapi.dll function pointer typedefs typedef HRESULT (WINAPI * DWMISCOMPOSITIONENABLED_T)(BOOL*); @@ -237,6 +248,7 @@ typedef struct _GLFWlibraryWin32 HINSTANCE instance; DWMISCOMPOSITIONENABLED_T DwmIsCompositionEnabled; DWMFLUSH_T DwmFlush; + DWMENABLEBLURBEHINDWINDOW_T DwmEnableBlurBehindWindow; } dwmapi; // shcore.dll diff --git a/src/win32_window.c b/src/win32_window.c index 5bbd04096..13375bdf3 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -732,6 +732,19 @@ static int createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) window->win32.numer = GLFW_DONT_CARE; window->win32.denom = GLFW_DONT_CARE; + // Accelerated transparent windows + // It currently doesn't support decorated windows. + // If decorated is required we just return an opaque window. + // Since DwmEnableBlurBehindWindow is supported since Vista, + // previous versions will simply get an opaque window. + if (!window->decorated && _glfw_DwmEnableBlurBehindWindow && window->transparent) { + DWM_BLURBEHIND bb = { 0 }; + bb.dwFlags = 3; // DWM_BB_ENABLE | DWM_BB_BLURREGION + bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1); // an invalid hRgnBlur makes the the window transparent + bb.fEnable = TRUE; + _glfw_DwmEnableBlurBehindWindow(window->win32.handle, &bb); + } + return GLFW_TRUE; } From 25313317f00578b3b2430a10a4d2cd3aa6b3c681 Mon Sep 17 00:00:00 2001 From: Christopher Pelloux Date: Tue, 1 Mar 2016 15:41:47 -0500 Subject: [PATCH 07/11] add filtering of pixelformat composition for win32 transparent window --- src/wgl_context.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/wgl_context.c b/src/wgl_context.c index afc85bab1..0c3ebfae2 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -133,6 +133,20 @@ static GLFWbool choosePixelFormat(_GLFWwindow* window, { const int n = i + 1; _GLFWfbconfig* u = usableConfigs + usableCount; + PIXELFORMATDESCRIPTOR pfd; + + if (window->transparent) { + if (!DescribePixelFormat(window->context.wgl.dc, + n, + sizeof(PIXELFORMATDESCRIPTOR), + &pfd)) + { + continue; + } + + if (!(pfd.dwFlags & PFD_SUPPORT_COMPOSITION)) + continue; + } if (_glfw.wgl.ARB_pixel_format) { @@ -188,11 +202,9 @@ static GLFWbool choosePixelFormat(_GLFWwindow* window, } else { - PIXELFORMATDESCRIPTOR pfd; - // Get pixel format attributes through legacy PFDs - if (!DescribePixelFormat(window->context.wgl.dc, + if (!window->transparent && !DescribePixelFormat(window->context.wgl.dc, n, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) @@ -239,6 +251,13 @@ static GLFWbool choosePixelFormat(_GLFWwindow* window, u->wgl = n; usableCount++; } + // Reiterate the selection loop without looking for transparency supporting + // formats if no matching pixelformat for a transparent window were found. + if (window->transparent && !usableCount) { + window->transparent = GLFW_FALSE; + free(usableConfigs); + return choosePixelFormat(window, desired, result); + } if (!usableCount) { From fe81dd989902313cc6f38d8088a0b80585f84188 Mon Sep 17 00:00:00 2001 From: Christopher Pelloux Date: Tue, 1 Mar 2016 17:00:55 -0500 Subject: [PATCH 08/11] fix: handle better DwmEnableBlurBehindWindow --- src/wgl_context.c | 22 ++++++++++++++++++++++ src/win32_platform.h | 12 +++++++++--- src/win32_window.c | 13 ------------- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/wgl_context.c b/src/wgl_context.c index 0c3ebfae2..9a1fbf423 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -493,6 +493,28 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, } } + if (window->transparent) { + if (!isCompositionEnabled || !_glfw_DwmEnableBlurBehindWindow) { + window->transparent = GLFW_FALSE; + } + else + { + HRESULT hr = S_OK; + + DWM_BLURBEHIND bb = { 0 }; + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1); // makes the window transparent + bb.fEnable = TRUE; + hr = _glfw_DwmEnableBlurBehindWindow(window->win32.handle, &bb); + + if (!SUCCEEDED(hr)) { + window->transparent = GLFW_FALSE; + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to enable blur behind window required for transparency"); + } + } + } + return GLFW_TRUE; } diff --git a/src/win32_platform.h b/src/win32_platform.h index eabf40376..643991a91 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -120,6 +120,12 @@ typedef enum PROCESS_DPI_AWARENESS } PROCESS_DPI_AWARENESS; #endif /*DPI_ENUMS_DECLARED*/ +#if !defined(_DWMAPI_H_) +// Blur behind data structures +#define DWM_BB_ENABLE 0x00000001 // fEnable has been specified +#define DWM_BB_BLURREGION 0x00000002 // hRgnBlur has been specified +#define DWM_BB_TRANSITIONONMAXIMIZED 0x00000004 // fTransitionOnMaximized has been specified + typedef struct _DWM_BLURBEHIND { DWORD dwFlags; @@ -127,31 +133,31 @@ typedef struct _DWM_BLURBEHIND HRGN hRgnBlur; BOOL fTransitionOnMaximized; } DWM_BLURBEHIND, *PDWM_BLURBEHIND; +#endif // winmm.dll function pointer typedefs typedef MMRESULT (WINAPI * JOYGETDEVCAPS_T)(UINT,LPJOYCAPS,UINT); typedef MMRESULT (WINAPI * JOYGETPOS_T)(UINT,LPJOYINFO); typedef MMRESULT (WINAPI * JOYGETPOSEX_T)(UINT,LPJOYINFOEX); typedef DWORD (WINAPI * TIMEGETTIME_T)(void); -typedef HRESULT(WINAPI * DWMENABLEBLURBEHINDWINDOW_T)(HWND, const DWM_BLURBEHIND*); #define _glfw_joyGetDevCaps _glfw.win32.winmm.joyGetDevCaps #define _glfw_joyGetPos _glfw.win32.winmm.joyGetPos #define _glfw_joyGetPosEx _glfw.win32.winmm.joyGetPosEx #define _glfw_timeGetTime _glfw.win32.winmm.timeGetTime -#define _glfw_DwmEnableBlurBehindWindow _glfw.win32.dwmapi.DwmEnableBlurBehindWindow // user32.dll function pointer typedefs typedef BOOL (WINAPI * SETPROCESSDPIAWARE_T)(void); typedef BOOL (WINAPI * CHANGEWINDOWMESSAGEFILTEREX_T)(HWND,UINT,DWORD,PCHANGEFILTERSTRUCT); #define _glfw_SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware #define _glfw_ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx -#define _glfw_DwmEnableBlurBehindWindow _glfw.win32.dwmapi.DwmEnableBlurBehindWindow // dwmapi.dll function pointer typedefs typedef HRESULT (WINAPI * DWMISCOMPOSITIONENABLED_T)(BOOL*); typedef HRESULT (WINAPI * DWMFLUSH_T)(VOID); +typedef HRESULT (WINAPI * DWMENABLEBLURBEHINDWINDOW_T)(HWND, const DWM_BLURBEHIND*); #define _glfw_DwmIsCompositionEnabled _glfw.win32.dwmapi.DwmIsCompositionEnabled #define _glfw_DwmFlush _glfw.win32.dwmapi.DwmFlush +#define _glfw_DwmEnableBlurBehindWindow _glfw.win32.dwmapi.DwmEnableBlurBehindWindow // shcore.dll function pointer typedefs typedef HRESULT (WINAPI * SETPROCESSDPIAWARENESS_T)(PROCESS_DPI_AWARENESS); diff --git a/src/win32_window.c b/src/win32_window.c index 13375bdf3..5bbd04096 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -732,19 +732,6 @@ static int createWindow(_GLFWwindow* window, const _GLFWwndconfig* wndconfig) window->win32.numer = GLFW_DONT_CARE; window->win32.denom = GLFW_DONT_CARE; - // Accelerated transparent windows - // It currently doesn't support decorated windows. - // If decorated is required we just return an opaque window. - // Since DwmEnableBlurBehindWindow is supported since Vista, - // previous versions will simply get an opaque window. - if (!window->decorated && _glfw_DwmEnableBlurBehindWindow && window->transparent) { - DWM_BLURBEHIND bb = { 0 }; - bb.dwFlags = 3; // DWM_BB_ENABLE | DWM_BB_BLURREGION - bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1); // an invalid hRgnBlur makes the the window transparent - bb.fEnable = TRUE; - _glfw_DwmEnableBlurBehindWindow(window->win32.handle, &bb); - } - return GLFW_TRUE; } From 4ccda807aaeb67f71857e1628132f685e4127c5f Mon Sep 17 00:00:00 2001 From: Christopher Pelloux Date: Thu, 3 Mar 2016 16:33:47 -0500 Subject: [PATCH 09/11] Fix win8+ transparent area not repainting --- examples/gears.c | 9 +++- src/wgl_context.c | 110 +++++++++++++++++++++++++++++++++++++++------- 2 files changed, 101 insertions(+), 18 deletions(-) diff --git a/examples/gears.c b/examples/gears.c index 7e3ca4391..1d64e72ca 100644 --- a/examples/gears.c +++ b/examples/gears.c @@ -298,10 +298,17 @@ static void init(void) glEnable(GL_NORMALIZE); } +GLFWerrorfun ErrorFun(int i, const char* str) { + char buf[255]; + sprintf(buf, "%d: %s", i, str); + MessageBoxA(0, buf, "Error", MB_ICONERROR | MB_OK); +} /* program entry */ int main(int argc, char *argv[]) { + glfwSetErrorCallback(ErrorFun); + GLFWwindow* window; int width, height; @@ -314,7 +321,7 @@ int main(int argc, char *argv[]) glfwWindowHint(GLFW_DEPTH_BITS, 16); glfwWindowHint(GLFW_ALPHA_BITS, 8); glfwWindowHint(GLFW_TRANSPARENT, GLFW_TRUE); - glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); + glfwWindowHint(GLFW_DECORATED, GLFW_TRUE); window = glfwCreateWindow( 300, 300, "Gears", NULL, NULL ); if (!window) diff --git a/src/wgl_context.c b/src/wgl_context.c index 9a1fbf423..ec7d952f5 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -256,6 +256,8 @@ static GLFWbool choosePixelFormat(_GLFWwindow* window, if (window->transparent && !usableCount) { window->transparent = GLFW_FALSE; free(usableConfigs); + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: No pixel format found for transparent window. Ignoring transparency."); return choosePixelFormat(window, desired, result); } @@ -344,6 +346,96 @@ void _glfwTerminateWGL(void) assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \ } +// Reliably check windows version as done in VersionHelpers.h +// needed for transparent window +static inline GLFWbool +isWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor) +{ + OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0,{ 0 }, 0, 0 }; + DWORDLONG const dwlConditionMask = VerSetConditionMask( + VerSetConditionMask( + VerSetConditionMask( + 0, VER_MAJORVERSION, VER_GREATER_EQUAL), + VER_MINORVERSION, VER_GREATER_EQUAL), + VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + + osvi.dwMajorVersion = wMajorVersion; + osvi.dwMinorVersion = wMinorVersion; + osvi.wServicePackMajor = wServicePackMajor; + + return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE; +} + +static GLFWbool isWindows8OrGreater() { + GLFWbool isWin8OrGreater = isWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0) ? GLFW_TRUE: GLFW_FALSE; + return isWin8OrGreater; +} + +static GLFWbool setupTransparentWindow(HWND handle, GLFWbool isDecorated) { + if (!isCompositionEnabled) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Composition needed for transparent window is disabled"); + } + if (!_glfw_DwmEnableBlurBehindWindow) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Unable to load DwmEnableBlurBehindWindow required for transparent window"); + return GLFW_FALSE; + } + + HRESULT hr = S_OK; + + DWM_BLURBEHIND bb = { 0 }; + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1); // makes the window transparent + bb.fEnable = TRUE; + hr = _glfw_DwmEnableBlurBehindWindow(handle, &bb); + + if (!SUCCEEDED(hr)) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to enable blur behind window required for transparent window"); + return GLFW_FALSE; + } + + // Decorated windows on Windows 8+ don't repaint the transparent background + // leaving a trail behind animations. + // Hack: making the window layered with a transparency color key seems to fix this. + // Normally, when specifying a transparency color key to be used when composing + // the layered window, all pixels painted by the window in this color will be transparent. + // That doesn't seem to be the case anymore on Windows 8+, at least when used with + // DwmEnableBlurBehindWindow + negative region. + if (isDecorated && isWindows8OrGreater()) { + long style = GetWindowLong(handle, GWL_EXSTYLE); + if (!style) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to retrieve extended styles. GetLastError: %d", + GetLastError()); + return GLFW_FALSE; + } + style |= WS_EX_LAYERED; + if (!SetWindowLongPtr(handle, GWL_EXSTYLE, style)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to add layered style. GetLastError: %d", + GetLastError()); + return GLFW_FALSE; + } + if (!SetLayeredWindowAttributes(handle, + // Using a color key not equal to black to fix the trailing issue. + // When set to black, something is making the hit test not resize with the + // window frame. + RGB(0, 193, 48), + 255, + LWA_COLORKEY)) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Failed to set layered window. GetLastError: %d", + GetLastError()); + return GLFW_FALSE; + } + } + return GLFW_TRUE; +} + // Create the OpenGL or OpenGL ES context // GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, @@ -494,25 +586,9 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, } if (window->transparent) { - if (!isCompositionEnabled || !_glfw_DwmEnableBlurBehindWindow) { + if (!setupTransparentWindow(window->win32.handle, window->decorated)) { window->transparent = GLFW_FALSE; } - else - { - HRESULT hr = S_OK; - - DWM_BLURBEHIND bb = { 0 }; - bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; - bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1); // makes the window transparent - bb.fEnable = TRUE; - hr = _glfw_DwmEnableBlurBehindWindow(window->win32.handle, &bb); - - if (!SUCCEEDED(hr)) { - window->transparent = GLFW_FALSE; - _glfwInputError(GLFW_PLATFORM_ERROR, - "WGL: Failed to enable blur behind window required for transparency"); - } - } } return GLFW_TRUE; From a0d82754d58ab1a3060ae325f2fd34bcc397ce64 Mon Sep 17 00:00:00 2001 From: Christopher Pelloux Date: Sat, 5 Mar 2016 10:00:12 -0500 Subject: [PATCH 10/11] cleanup --- examples/gears.c | 8 -------- src/wgl_context.c | 17 +++++++++++------ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/examples/gears.c b/examples/gears.c index 1d64e72ca..bc667ddea 100644 --- a/examples/gears.c +++ b/examples/gears.c @@ -298,17 +298,9 @@ static void init(void) glEnable(GL_NORMALIZE); } -GLFWerrorfun ErrorFun(int i, const char* str) { - char buf[255]; - sprintf(buf, "%d: %s", i, str); - MessageBoxA(0, buf, "Error", MB_ICONERROR | MB_OK); -} - /* program entry */ int main(int argc, char *argv[]) { - glfwSetErrorCallback(ErrorFun); - GLFWwindow* window; int width, height; diff --git a/src/wgl_context.c b/src/wgl_context.c index ec7d952f5..3a9a42b00 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -366,12 +366,14 @@ isWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServiceP return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE; } -static GLFWbool isWindows8OrGreater() { +static GLFWbool isWindows8OrGreater() +{ GLFWbool isWin8OrGreater = isWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0) ? GLFW_TRUE: GLFW_FALSE; return isWin8OrGreater; } -static GLFWbool setupTransparentWindow(HWND handle, GLFWbool isDecorated) { +static GLFWbool setupTransparentWindow(_GLFWwindow* window) +{ if (!isCompositionEnabled) { _glfwInputError(GLFW_PLATFORM_ERROR, "WGL: Composition needed for transparent window is disabled"); @@ -383,6 +385,7 @@ static GLFWbool setupTransparentWindow(HWND handle, GLFWbool isDecorated) { } HRESULT hr = S_OK; + HWND handle = window->win32.handle; DWM_BLURBEHIND bb = { 0 }; bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; @@ -403,7 +406,8 @@ static GLFWbool setupTransparentWindow(HWND handle, GLFWbool isDecorated) { // the layered window, all pixels painted by the window in this color will be transparent. // That doesn't seem to be the case anymore on Windows 8+, at least when used with // DwmEnableBlurBehindWindow + negative region. - if (isDecorated && isWindows8OrGreater()) { + if (window->decorated && isWindows8OrGreater()) + { long style = GetWindowLong(handle, GWL_EXSTYLE); if (!style) { _glfwInputError(GLFW_PLATFORM_ERROR, @@ -433,6 +437,7 @@ static GLFWbool setupTransparentWindow(HWND handle, GLFWbool isDecorated) { return GLFW_FALSE; } } + return GLFW_TRUE; } @@ -585,10 +590,10 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, } } - if (window->transparent) { - if (!setupTransparentWindow(window->win32.handle, window->decorated)) { + if (window->transparent) + { + if (!setupTransparentWindow(window)) window->transparent = GLFW_FALSE; - } } return GLFW_TRUE; From 43f116fa40d5147d66c6392e1eb5690c7497dd93 Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Mon, 7 Mar 2016 21:17:05 +0100 Subject: [PATCH 11/11] Cleanup --- src/wgl_context.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wgl_context.c b/src/wgl_context.c index 3a9a42b00..ccf951d99 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -408,7 +408,7 @@ static GLFWbool setupTransparentWindow(_GLFWwindow* window) // DwmEnableBlurBehindWindow + negative region. if (window->decorated && isWindows8OrGreater()) { - long style = GetWindowLong(handle, GWL_EXSTYLE); + long style = GetWindowLongPtrW(handle, GWL_EXSTYLE); if (!style) { _glfwInputError(GLFW_PLATFORM_ERROR, "WGL: Failed to retrieve extended styles. GetLastError: %d", @@ -416,7 +416,7 @@ static GLFWbool setupTransparentWindow(_GLFWwindow* window) return GLFW_FALSE; } style |= WS_EX_LAYERED; - if (!SetWindowLongPtr(handle, GWL_EXSTYLE, style)) + if (!SetWindowLongPtrW(handle, GWL_EXSTYLE, style)) { _glfwInputError(GLFW_PLATFORM_ERROR, "WGL: Failed to add layered style. GetLastError: %d",