Browse Source

Add GLFW_TRANSPARENT attribute and documentation

This completes support for window framebuffer transparency on Windows,
macOS and X11.  Note that the hint/attribute may be renamed before
release to clarify its relationship to GLFW_OPACITY.

Fixes #197.
Closes #1079.
Related to #663.
Related to #715.
Related to #723.
Related to #1078.
Camilla Löwy 8 years ago
parent
commit
32e78aeb2e
22 changed files with 322 additions and 318 deletions
  1. 6 0
      README.md
  2. 5 0
      docs/compat.dox
  3. 7 0
      docs/news.dox
  4. 37 4
      docs/window.dox
  5. 1 2
      examples/gears.c
  6. 6 5
      include/GLFW/glfw3.h
  7. 10 8
      src/cocoa_window.m
  8. 3 0
      src/context.c
  9. 18 40
      src/egl_context.c
  10. 12 36
      src/glx_context.c
  11. 1 0
      src/internal.h
  12. 7 0
      src/mir_window.c
  13. 5 0
      src/null_window.c
  14. 5 117
      src/wgl_context.c
  15. 12 1
      src/win32_init.c
  16. 22 26
      src/win32_platform.h
  17. 84 2
      src/win32_window.c
  18. 2 1
      src/window.c
  19. 7 0
      src/wl_window.c
  20. 23 49
      src/x11_init.c
  21. 24 27
      src/x11_platform.h
  22. 25 0
      src/x11_window.c

+ 6 - 0
README.md

@@ -150,6 +150,8 @@ information on what to include when reporting a bug.
   functions for accessing X11 primary selection (#894,#1056)
   functions for accessing X11 primary selection (#894,#1056)
 - Added headless [OSMesa](http://mesa3d.org/osmesa.html) backend (#850)
 - Added headless [OSMesa](http://mesa3d.org/osmesa.html) backend (#850)
 - Added definition of `GLAPIENTRY` to public header
 - Added definition of `GLAPIENTRY` to public header
+- Added `GLFW_TRANSPARENT` window hint for enabling window framebuffer
+  transparency (#197,#663,#715,#723,#1078)
 - Added `GLFW_CENTER_CURSOR` window hint for controlling cursor centering
 - Added `GLFW_CENTER_CURSOR` window hint for controlling cursor centering
   (#749,#842)
   (#749,#842)
 - Added `GLFW_JOYSTICK_HAT_BUTTONS` init hint (#889)
 - Added `GLFW_JOYSTICK_HAT_BUTTONS` init hint (#889)
@@ -289,6 +291,7 @@ skills.
  - Yaron Cohen-Tal
  - Yaron Cohen-Tal
  - Omar Cornut
  - Omar Cornut
  - Andrew Corrigan
  - Andrew Corrigan
+ - Bailey Cosier
  - Noel Cower
  - Noel Cower
  - Jason Daly
  - Jason Daly
  - Jarrod Davis
  - Jarrod Davis
@@ -297,6 +300,7 @@ skills.
  - Michael Dickens
  - Michael Dickens
  - Роман Донченко
  - Роман Донченко
  - Mario Dorn
  - Mario Dorn
+ - Wolfgang Draxinger
  - Jonathan Dummer
  - Jonathan Dummer
  - Ralph Eastwood
  - Ralph Eastwood
  - Fredrik Ehnbom
  - Fredrik Ehnbom
@@ -322,6 +326,7 @@ skills.
  - Erik S. V. Jansson
  - Erik S. V. Jansson
  - Toni Jovanoski
  - Toni Jovanoski
  - Arseny Kapoulkine
  - Arseny Kapoulkine
+ - Cem Karan
  - Osman Keskin
  - Osman Keskin
  - Josh Kilmer
  - Josh Kilmer
  - Cameron King
  - Cameron King
@@ -363,6 +368,7 @@ skills.
  - Andri Pálsson
  - Andri Pálsson
  - Peoro
  - Peoro
  - Braden Pellett
  - Braden Pellett
+ - Christopher Pelloux
  - Arturo J. Pérez
  - Arturo J. Pérez
  - Anthony Pesch
  - Anthony Pesch
  - Orson Peters
  - Orson Peters

+ 5 - 0
docs/compat.dox

@@ -80,6 +80,11 @@ GLFW uses the XInput2 extension to provide raw, non-accelerated mouse motion
 when the cursor is disabled.  If the running X server does not support this
 when the cursor is disabled.  If the running X server does not support this
 extension, regular accelerated mouse motion will be used. 
 extension, regular accelerated mouse motion will be used. 
 
 
+GLFW uses both the XRender extension and the compositing manager to support
+transparent window framebuffers.  If the running X server does not support this
+extension or there is no running compositing manager, the `GLFW_TRANSPARENT`
+framebuffer hint will have no effect.
+
 
 
 @section compat_glx GLX extensions
 @section compat_glx GLX extensions
 
 

+ 7 - 0
docs/news.dox

@@ -85,6 +85,13 @@ be disabled with the @ref GLFW_JOYSTICK_HAT_BUTTONS init hint.
 @see @ref joystick_hat
 @see @ref joystick_hat
 
 
 
 
+@subsection news_33_transparent Support for transparent window framebuffer
+
+GLFW now supports the creation of windows with transparent framebuffers on
+systems with desktop compositing enabled with the @ref GLFW_TRANSPARENT window
+hint and attribute.  Any window decorations will still be opaque.
+
+
 @subsection news_33_centercursor Cursor centering window hint
 @subsection news_33_centercursor Cursor centering window hint
 
 
 GLFW now supports controlling whether the cursor is centered over newly created
 GLFW now supports controlling whether the cursor is centered over newly created

+ 37 - 4
docs/window.dox

@@ -225,6 +225,13 @@ __GLFW_CENTER_CURSOR__ specifies whether the cursor should be centered over
 newly created full screen windows.  Possible values are `GLFW_TRUE` and
 newly created full screen windows.  Possible values are `GLFW_TRUE` and
 `GLFW_FALSE`.  This hint is ignored for windowed mode windows.
 `GLFW_FALSE`.  This hint is ignored for windowed mode windows.
 
 
+@anchor GLFW_TRANSPARENT_hint
+__GLFW_TRANSPARENT__ specifies whether the window framebuffer will be
+transparent.  If enabled and supported by the system, the window framebuffer
+alpha channel will be used to combine the framebuffer with the background.  This
+does not affect window decorations.  Possible values are `GLFW_TRUE` and
+`GLFW_FALSE`.
+
 
 
 @subsubsection window_hints_fb Framebuffer related hints
 @subsubsection window_hints_fb Framebuffer related hints
 
 
@@ -287,10 +294,6 @@ __GLFW_DOUBLEBUFFER__ specifies whether the framebuffer should be double
 buffered.  You nearly always want to use double buffering.  This is a hard
 buffered.  You nearly always want to use double buffering.  This is a hard
 constraint.  Possible values are `GLFW_TRUE` and `GLFW_FALSE`.
 constraint.  Possible values are `GLFW_TRUE` and `GLFW_FALSE`.
 
 
-@anchor GLFW_TRANSPARENT_hint
-__GLFW_TRANSPARENT__ specifies whether the framebuffer will support transparency
-in the background. Possible values are `GLFW_TRUE` and `GLFW_FALSE`.
-
 
 
 @subsubsection window_hints_mtr Monitor related hints
 @subsubsection window_hints_mtr Monitor related hints
 
 
@@ -474,6 +477,7 @@ GLFW_AUTO_ICONIFY             | `GLFW_TRUE`                 | `GLFW_TRUE` or `GL
 GLFW_FLOATING                 | `GLFW_FALSE`                | `GLFW_TRUE` or `GLFW_FALSE`
 GLFW_FLOATING                 | `GLFW_FALSE`                | `GLFW_TRUE` or `GLFW_FALSE`
 GLFW_MAXIMIZED                | `GLFW_FALSE`                | `GLFW_TRUE` or `GLFW_FALSE`
 GLFW_MAXIMIZED                | `GLFW_FALSE`                | `GLFW_TRUE` or `GLFW_FALSE`
 GLFW_CENTER_CURSOR            | `GLFW_TRUE`                 | `GLFW_TRUE` or `GLFW_FALSE`
 GLFW_CENTER_CURSOR            | `GLFW_TRUE`                 | `GLFW_TRUE` or `GLFW_FALSE`
+GLFW_TRANSPARENT              | `GLFW_FALSE`                | `GLFW_TRUE` or `GLFW_FALSE`
 GLFW_RED_BITS                 | 8                           | 0 to `INT_MAX` or `GLFW_DONT_CARE`
 GLFW_RED_BITS                 | 8                           | 0 to `INT_MAX` or `GLFW_DONT_CARE`
 GLFW_GREEN_BITS               | 8                           | 0 to `INT_MAX` or `GLFW_DONT_CARE`
 GLFW_GREEN_BITS               | 8                           | 0 to `INT_MAX` or `GLFW_DONT_CARE`
 GLFW_BLUE_BITS                | 8                           | 0 to `INT_MAX` or `GLFW_DONT_CARE`
 GLFW_BLUE_BITS                | 8                           | 0 to `INT_MAX` or `GLFW_DONT_CARE`
@@ -1065,6 +1069,30 @@ window contents are saved off-screen, this callback might only be called when
 the window or framebuffer is resized.
 the window or framebuffer is resized.
 
 
 
 
+@subsection window_transparency Window transparency
+
+Window framebuffers can be made transparent on a per-pixel per-frame basis with
+the [GLFW_TRANSPARENT](@ref GLFW_TRANSPARENT_hint) window hint.
+
+@code
+glfwWindowHint(GLFW_TRANSPARENT, GLFW_TRUE);
+@endcode
+
+If supported by the system, the window framebuffer will be composited with the
+background using the framebuffer per-pixel alpha channel.  This requires desktop
+compositing to be enabled on the system.  It does not affect window decorations.
+
+You can check whether the window framebuffer was successfully made transparent
+with the [GLFW_TRANSPARENT](@ref GLFW_TRANSPARENT_attrib) window attribute.
+
+@code
+if (glfwGetWindowAttrib(window, GLFW_TRANSPARENT))
+{
+    // window framebuffer is currently transparent
+}
+@endcode
+
+
 @subsection window_attribs Window attributes
 @subsection window_attribs Window attributes
 
 
 Windows have a number of attributes that can be returned using @ref
 Windows have a number of attributes that can be returned using @ref
@@ -1134,6 +1162,11 @@ called topmost or always-on-top.  This can be set before creation with the
 [GLFW_FLOATING](@ref GLFW_FLOATING_hint) window hint or after with @ref
 [GLFW_FLOATING](@ref GLFW_FLOATING_hint) window hint or after with @ref
 glfwSetWindowAttrib.
 glfwSetWindowAttrib.
 
 
+@anchor GLFW_TRANSPARENT_attrib
+__GLFW_TRANSPARENT__ indicates whether the specified window has a transparent
+framebuffer, i.e. the window contents is composited with the background using
+the window framebuffer alpha channel.  See @ref window_transparency for details.
+
 
 
 @subsubsection window_attribs_ctx Context related attributes
 @subsubsection window_attribs_ctx Context related attributes
 
 

+ 1 - 2
examples/gears.c

@@ -172,7 +172,7 @@ static GLfloat angle = 0.f;
 /* OpenGL draw function & timing */
 /* OpenGL draw function & timing */
 static void draw(void)
 static void draw(void)
 {
 {
-  glClearColor(0., 0., 0., 0.);
+  glClearColor(0.0, 0.0, 0.0, 0.0);
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
 
   glPushMatrix();
   glPushMatrix();
@@ -312,7 +312,6 @@ int main(int argc, char *argv[])
     }
     }
 
 
     glfwWindowHint(GLFW_DEPTH_BITS, 16);
     glfwWindowHint(GLFW_DEPTH_BITS, 16);
-    glfwWindowHint(GLFW_ALPHA_BITS, 8);
     glfwWindowHint(GLFW_TRANSPARENT, GLFW_TRUE);
     glfwWindowHint(GLFW_TRANSPARENT, GLFW_TRUE);
 
 
     window = glfwCreateWindow( 300, 300, "Gears", NULL, NULL );
     window = glfwCreateWindow( 300, 300, "Gears", NULL, NULL );

+ 6 - 5
include/GLFW/glfw3.h

@@ -787,6 +787,12 @@ extern "C" {
  *  Cursor centering [window hint](@ref GLFW_CENTER_CURSOR_hint).
  *  Cursor centering [window hint](@ref GLFW_CENTER_CURSOR_hint).
  */
  */
 #define GLFW_CENTER_CURSOR          0x00020009
 #define GLFW_CENTER_CURSOR          0x00020009
+/*! @brief Window framebuffer transparency hint and attribute
+ *
+ *  Window framebuffer transparency [window hint](@ref GLFW_TRANSPARENT_hint)
+ *  and [window attribute](@ref GLFW_TRANSPARENT_attrib).
+ */
+#define GLFW_TRANSPARENT            0x0002000A
 
 
 /*! @brief Framebuffer bit depth hint.
 /*! @brief Framebuffer bit depth hint.
  *
  *
@@ -868,11 +874,6 @@ extern "C" {
  *  Framebuffer double buffering [hint](@ref GLFW_DOUBLEBUFFER).
  *  Framebuffer double buffering [hint](@ref GLFW_DOUBLEBUFFER).
  */
  */
 #define GLFW_DOUBLEBUFFER           0x00021010
 #define GLFW_DOUBLEBUFFER           0x00021010
-/*! @brief Framebuffer transparency hint.
- *
- *  Framebuffer transparency [hint](@ref GLFW_TRANSPARENT_hint).
- */
-#define GLFW_TRANSPARENT            0x00021011
 
 
 /*! @brief Context client API hint and attribute.
 /*! @brief Context client API hint and attribute.
  *
  *

+ 10 - 8
src/cocoa_window.m

@@ -413,11 +413,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
 
 
 - (BOOL)isOpaque
 - (BOOL)isOpaque
 {
 {
-    // Set to NO even if alphaMask is not used;
-    //   The NSView/GLFWContentView does not need to be opaque anyway,
-    //   and to avoid keeping track of alphaMask inside the NSView we
-    //   just return NO here instead.
-    return NO;
+    return [window->ns.object isOpaque];
 }
 }
 
 
 - (BOOL)canBecomeKeyView
 - (BOOL)canBecomeKeyView
@@ -1016,7 +1012,8 @@ static GLFWbool initializeAppKit(void)
 // Create the Cocoa window
 // Create the Cocoa window
 //
 //
 static GLFWbool createNativeWindow(_GLFWwindow* window,
 static GLFWbool createNativeWindow(_GLFWwindow* window,
-                                   const _GLFWwndconfig* wndconfig)
+                                   const _GLFWwndconfig* wndconfig,
+                                   const _GLFWfbconfig* fbconfig)
 {
 {
     window->ns.delegate = [[GLFWWindowDelegate alloc] initWithGlfwWindow:window];
     window->ns.delegate = [[GLFWWindowDelegate alloc] initWithGlfwWindow:window];
     if (window->ns.delegate == nil)
     if (window->ns.delegate == nil)
@@ -1085,7 +1082,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
     if (wndconfig->ns.retina)
     if (wndconfig->ns.retina)
         [window->ns.view setWantsBestResolutionOpenGLSurface:YES];
         [window->ns.view setWantsBestResolutionOpenGLSurface:YES];
 
 
-    if (_glfw.hints.framebuffer.transparent)
+    if (fbconfig->transparent)
     {
     {
         [window->ns.object setOpaque:NO];
         [window->ns.object setOpaque:NO];
         [window->ns.object setBackgroundColor:[NSColor clearColor]];
         [window->ns.object setBackgroundColor:[NSColor clearColor]];
@@ -1114,7 +1111,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
     if (!initializeAppKit())
     if (!initializeAppKit())
         return GLFW_FALSE;
         return GLFW_FALSE;
 
 
-    if (!createNativeWindow(window, wndconfig))
+    if (!createNativeWindow(window, wndconfig, fbconfig))
         return GLFW_FALSE;
         return GLFW_FALSE;
 
 
     if (ctxconfig->client != GLFW_NO_API)
     if (ctxconfig->client != GLFW_NO_API)
@@ -1453,6 +1450,11 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
     return [window->ns.object isZoomed];
     return [window->ns.object isZoomed];
 }
 }
 
 
+int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
+{
+    return ![window->ns.object isOpaque] && ![window->ns.view isOpaque];
+}
+
 void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
 void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
 {
 {
     [window->ns.object setStyleMask:getStyleMask(window)];
     [window->ns.object setStyleMask:getStyleMask(window)];

+ 3 - 0
src/context.c

@@ -208,6 +208,9 @@ const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired,
                 // not important to us here, so we count them as one
                 // not important to us here, so we count them as one
                 missing++;
                 missing++;
             }
             }
+
+            if (desired->transparent != current->transparent)
+                missing++;
         }
         }
 
 
         // These polynomials make many small channel size differences matter
         // These polynomials make many small channel size differences matter

+ 18 - 40
src/egl_context.c

@@ -87,21 +87,13 @@ static int getEGLConfigAttrib(EGLConfig config, int attrib)
 //
 //
 static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
 static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
                                 const _GLFWfbconfig* desired,
                                 const _GLFWfbconfig* desired,
-                                EGLConfig* result,
-                GLFWbool findTransparent)
+                                EGLConfig* result)
 {
 {
     EGLConfig* nativeConfigs;
     EGLConfig* nativeConfigs;
     _GLFWfbconfig* usableConfigs;
     _GLFWfbconfig* usableConfigs;
     const _GLFWfbconfig* closest;
     const _GLFWfbconfig* closest;
     int i, nativeCount, usableCount;
     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);
     eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount);
     if (!nativeCount)
     if (!nativeCount)
     {
     {
@@ -115,7 +107,6 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
     usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
     usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
     usableCount = 0;
     usableCount = 0;
 
 
-selectionloop:
     for (i = 0;  i < nativeCount;  i++)
     for (i = 0;  i < nativeCount;  i++)
     {
     {
         const EGLConfig n = nativeConfigs[i];
         const EGLConfig n = nativeConfigs[i];
@@ -130,31 +121,24 @@ selectionloop:
             continue;
             continue;
 
 
 #if defined(_GLFW_X11)
 #if defined(_GLFW_X11)
-        // Only consider EGLConfigs with associated Visuals
-    visualTemplate.visualid = getEGLConfigAttrib(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;
+        XVisualInfo vi = {0};
 
 
-            pictFormat = XRenderFindVisualFormat(_glfw.x11.display, visualinfo->visual);
-            if( !pictFormat ) {
-            XFree( visualinfo );
+        // Only consider EGLConfigs with associated Visuals
+        vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID);
+        if (!vi.visualid)
             continue;
             continue;
-        }
 
 
-            if( !pictFormat->direct.alphaMask ) {
-            XFree( visualinfo );
-            continue;
-        }
-        XFree( visualinfo );
+        if (desired->transparent)
+        {
+            int count;
+            XVisualInfo* vis = XGetVisualInfo(_glfw.x11.display,
+                                              VisualIDMask, &vi,
+                                              &count);
+            if (vis)
+            {
+                u->transparent = _glfwIsVisualTransparentX11(vis[0].visual);
+                XFree(vis);
+            }
         }
         }
 #endif // _GLFW_X11
 #endif // _GLFW_X11
 
 
@@ -191,12 +175,6 @@ selectionloop:
         u->handle = (uintptr_t) n;
         u->handle = (uintptr_t) n;
         usableCount++;
         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);
     closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
     if (closest)
     if (closest)
@@ -493,7 +471,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
     if (ctxconfig->share)
     if (ctxconfig->share)
         share = ctxconfig->share->context.egl.handle;
         share = ctxconfig->share->context.egl.handle;
 
 
-    if (!chooseEGLConfig(ctxconfig, fbconfig, &config, fbconfig->transparent))
+    if (!chooseEGLConfig(ctxconfig, fbconfig, &config))
     {
     {
         _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
         _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
                         "EGL: Failed to find a suitable EGLConfig");
                         "EGL: Failed to find a suitable EGLConfig");
@@ -738,7 +716,7 @@ GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
     EGLint visualID = 0, count = 0;
     EGLint visualID = 0, count = 0;
     const long vimask = VisualScreenMask | VisualIDMask;
     const long vimask = VisualScreenMask | VisualIDMask;
 
 
-    if (!chooseEGLConfig(ctxconfig, fbconfig, &native, fbconfig->transparent))
+    if (!chooseEGLConfig(ctxconfig, fbconfig, &native))
     {
     {
         _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
         _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
                         "EGL: Failed to find a suitable EGLConfig");
                         "EGL: Failed to find a suitable EGLConfig");

+ 12 - 36
src/glx_context.c

@@ -47,10 +47,8 @@ static int getGLXFBConfigAttrib(GLXFBConfig fbconfig, int attrib)
 
 
 // Return the GLXFBConfig most closely matching the specified hints
 // Return the GLXFBConfig most closely matching the specified hints
 //
 //
-static GLFWbool chooseGLXFBConfig(
-    const _GLFWfbconfig* desired,
-    GLXFBConfig* result,
-    GLFWbool findTransparent)
+static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired,
+                                  GLXFBConfig* result)
 {
 {
     GLXFBConfig* nativeConfigs;
     GLXFBConfig* nativeConfigs;
     _GLFWfbconfig* usableConfigs;
     _GLFWfbconfig* usableConfigs;
@@ -59,10 +57,6 @@ static GLFWbool chooseGLXFBConfig(
     const char* vendor;
     const char* vendor;
     GLFWbool trustWindowBit = GLFW_TRUE;
     GLFWbool trustWindowBit = GLFW_TRUE;
 
 
-    if ( !(_glfw.xrender.major || _glfw.xrender.minor) ) {
-        findTransparent = GLFW_FALSE;
-    }
-
     // HACK: This is a (hopefully temporary) workaround for Chromium
     // HACK: This is a (hopefully temporary) workaround for Chromium
     //       (VirtualBox GL) not setting the window bit on any GLXFBConfigs
     //       (VirtualBox GL) not setting the window bit on any GLXFBConfigs
     vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR);
     vendor = glXGetClientString(_glfw.x11.display, GLX_VENDOR);
@@ -80,7 +74,6 @@ static GLFWbool chooseGLXFBConfig(
     usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
     usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig));
     usableCount = 0;
     usableCount = 0;
 
 
-selectionloop:
     for (i = 0;  i < nativeCount;  i++)
     for (i = 0;  i < nativeCount;  i++)
     {
     {
         const GLXFBConfig n = nativeConfigs[i];
         const GLXFBConfig n = nativeConfigs[i];
@@ -97,25 +90,14 @@ selectionloop:
                 continue;
                 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 ) {
-            XFree( visualinfo );
-            continue;
-        }
-
-            if( !pictFormat->direct.alphaMask ) {
-            XFree( visualinfo );
-            continue;
-        }
-        XFree( visualinfo );
+        if (desired->transparent)
+        {
+            XVisualInfo* vi = glXGetVisualFromFBConfig(_glfw.x11.display, n);
+            if (vi)
+            {
+                u->transparent = _glfwIsVisualTransparentX11(vi->visual);
+                XFree(vi);
+            }
         }
         }
 
 
         u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE);
         u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE);
@@ -147,12 +129,6 @@ selectionloop:
         u->handle = (uintptr_t) n;
         u->handle = (uintptr_t) n;
         usableCount++;
         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);
     closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
     if (closest)
     if (closest)
@@ -477,7 +453,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
     if (ctxconfig->share)
     if (ctxconfig->share)
         share = ctxconfig->share->context.glx.handle;
         share = ctxconfig->share->context.glx.handle;
 
 
-    if (!chooseGLXFBConfig(fbconfig, &native, fbconfig->transparent))
+    if (!chooseGLXFBConfig(fbconfig, &native))
     {
     {
         _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
         _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
                         "GLX: Failed to find a suitable GLXFBConfig");
                         "GLX: Failed to find a suitable GLXFBConfig");
@@ -665,7 +641,7 @@ GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
     GLXFBConfig native;
     GLXFBConfig native;
     XVisualInfo* result;
     XVisualInfo* result;
 
 
-    if (!chooseGLXFBConfig(fbconfig, &native, fbconfig->transparent))
+    if (!chooseGLXFBConfig(fbconfig, &native))
     {
     {
         _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
         _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
                         "GLX: Failed to find a suitable GLXFBConfig");
                         "GLX: Failed to find a suitable GLXFBConfig");

+ 1 - 0
src/internal.h

@@ -682,6 +682,7 @@ int _glfwPlatformWindowFocused(_GLFWwindow* window);
 int _glfwPlatformWindowIconified(_GLFWwindow* window);
 int _glfwPlatformWindowIconified(_GLFWwindow* window);
 int _glfwPlatformWindowVisible(_GLFWwindow* window);
 int _glfwPlatformWindowVisible(_GLFWwindow* window);
 int _glfwPlatformWindowMaximized(_GLFWwindow* window);
 int _glfwPlatformWindowMaximized(_GLFWwindow* window);
+int _glfwPlatformFramebufferTransparent(_GLFWwindow* window);
 void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled);
 void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled);
 void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled);
 void _glfwPlatformSetWindowDecorated(_GLFWwindow* window, GLFWbool enabled);
 void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled);
 void _glfwPlatformSetWindowFloating(_GLFWwindow* window, GLFWbool enabled);

+ 7 - 0
src/mir_window.c

@@ -614,6 +614,13 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
     return mir_window_get_state(window->mir.window) == mir_window_state_maximized;
     return mir_window_get_state(window->mir.window) == mir_window_state_maximized;
 }
 }
 
 
+int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
+{
+    _glfwInputError(GLFW_PLATFORM_ERROR,
+                    "Mir: Unsupported function %s", __PRETTY_FUNCTION__);
+    return GLFW_FALSE;
+}
+
 void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
 void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
 {
 {
     _glfwInputError(GLFW_PLATFORM_ERROR,
     _glfwInputError(GLFW_PLATFORM_ERROR,

+ 5 - 0
src/null_window.c

@@ -156,6 +156,11 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
     return GLFW_FALSE;
     return GLFW_FALSE;
 }
 }
 
 
+int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
+{
+    return GLFW_FALSE;
+}
+
 void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
 void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
 {
 {
 }
 }

+ 5 - 117
src/wgl_context.c

@@ -83,20 +83,6 @@ static int choosePixelFormat(_GLFWwindow* window,
     {
     {
         const int n = i + 1;
         const int n = i + 1;
         _GLFWfbconfig* u = usableConfigs + usableCount;
         _GLFWfbconfig* u = usableConfigs + usableCount;
-        PIXELFORMATDESCRIPTOR pfd;
-
-        if (fbconfig->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)
         if (_glfw.wgl.ARB_pixel_format)
         {
         {
@@ -168,7 +154,9 @@ static int choosePixelFormat(_GLFWwindow* window,
         {
         {
             // Get pixel format attributes through legacy PFDs
             // Get pixel format attributes through legacy PFDs
 
 
-            if (!fbconfig->transparent && DescribePixelFormat(window->context.wgl.dc,
+            PIXELFORMATDESCRIPTOR pfd;
+
+            if (!DescribePixelFormat(window->context.wgl.dc,
                                      n,
                                      n,
                                      sizeof(PIXELFORMATDESCRIPTOR),
                                      sizeof(PIXELFORMATDESCRIPTOR),
                                      &pfd))
                                      &pfd))
@@ -215,14 +203,6 @@ static int choosePixelFormat(_GLFWwindow* window,
         u->handle = n;
         u->handle = n;
         usableCount++;
         usableCount++;
     }
     }
-    // Reiterate the selection loop without looking for transparency supporting
-    // formats if no matching pixelformat for a transparent window were found.
-    if (fbconfig->transparent && !usableCount) {
-        free(usableConfigs);
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-            "WGL: No pixel format found for transparent window. Ignoring transparency.");
-        return choosePixelFormat(window, ctxconfig, fbconfig);
-    }
 
 
     if (!usableCount)
     if (!usableCount)
     {
     {
@@ -249,21 +229,6 @@ static int choosePixelFormat(_GLFWwindow* window,
     return pixelFormat;
     return pixelFormat;
 }
 }
 
 
-// Returns whether desktop compositing is enabled
-//
-static GLFWbool isCompositionEnabled(void)
-{
-    if (_glfw.win32.dwmapi.instance)
-    {
-        BOOL enabled;
-
-        if (DwmIsCompositionEnabled(&enabled) == S_OK)
-            return enabled;
-    }
-
-    return FALSE;
-}
-
 static void makeContextCurrentWGL(_GLFWwindow* window)
 static void makeContextCurrentWGL(_GLFWwindow* window)
 {
 {
     if (window)
     if (window)
@@ -292,7 +257,7 @@ static void makeContextCurrentWGL(_GLFWwindow* window)
 static void swapBuffersWGL(_GLFWwindow* window)
 static void swapBuffersWGL(_GLFWwindow* window)
 {
 {
     // HACK: Use DwmFlush when desktop composition is enabled
     // HACK: Use DwmFlush when desktop composition is enabled
-    if (isCompositionEnabled() && !window->monitor)
+    if (_glfwIsCompositionEnabledWin32() && !window->monitor)
     {
     {
         int count = abs(window->context.wgl.interval);
         int count = abs(window->context.wgl.interval);
         while (count--)
         while (count--)
@@ -310,7 +275,7 @@ static void swapIntervalWGL(int interval)
 
 
     // HACK: Disable WGL swap interval when desktop composition is enabled to
     // HACK: Disable WGL swap interval when desktop composition is enabled to
     //       avoid interfering with DWM vsync
     //       avoid interfering with DWM vsync
-    if (isCompositionEnabled() && !window->monitor)
+    if (_glfwIsCompositionEnabledWin32() && !window->monitor)
         interval = 0;
         interval = 0;
 
 
     if (_glfw.wgl.EXT_swap_control)
     if (_glfw.wgl.EXT_swap_control)
@@ -504,75 +469,6 @@ void _glfwTerminateWGL(void)
     attribs[index++] = v; \
     attribs[index++] = v; \
 }
 }
 
 
-static GLFWbool setupTransparentWindow(_GLFWwindow* window)
-{
-    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;
-    HWND handle = window->win32.handle;
-
-    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 (window->decorated && 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
 // Create the OpenGL or OpenGL ES context
 //
 //
 GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
 GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
@@ -802,14 +698,6 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
         }
         }
     }
     }
 
 
-    if (fbconfig->transparent)
-    {
-        if (!setupTransparentWindow(window))
-            _glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
-                    "WGL: Failed to setup window as transparent as requested");
-
-    }
-
     window->context.makeCurrent = makeContextCurrentWGL;
     window->context.makeCurrent = makeContextCurrentWGL;
     window->context.swapBuffers = swapBuffersWGL;
     window->context.swapBuffers = swapBuffersWGL;
     window->context.swapInterval = swapIntervalWGL;
     window->context.swapInterval = swapIntervalWGL;

+ 12 - 1
src/win32_init.c

@@ -62,6 +62,17 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
 
 
 #endif // _GLFW_BUILD_DLL
 #endif // _GLFW_BUILD_DLL
 
 
+// HACK: Define versionhelpers.h functions manually as MinGW lacks the header
+BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp)
+{
+    OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, {0}, sp };
+    DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR;
+    ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
+    cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
+    cond = VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
+    return VerifyVersionInfoW(&osvi, mask, cond);
+}
+
 // Load necessary libraries (DLLs)
 // Load necessary libraries (DLLs)
 //
 //
 static GLFWbool loadLibraries(void)
 static GLFWbool loadLibraries(void)
@@ -131,7 +142,7 @@ static GLFWbool loadLibraries(void)
             GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled");
             GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled");
         _glfw.win32.dwmapi.Flush = (PFN_DwmFlush)
         _glfw.win32.dwmapi.Flush = (PFN_DwmFlush)
             GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush");
             GetProcAddress(_glfw.win32.dwmapi.instance, "DwmFlush");
-        _glfw.win32.dwmapi.DwmEnableBlurBehindWindow = (DWMENABLEBLURBEHINDWINDOW_T)
+        _glfw.win32.dwmapi.EnableBlurBehindWindow = (PFN_DwmEnableBlurBehindWindow)
             GetProcAddress(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow");
             GetProcAddress(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow");
     }
     }
 
 

+ 22 - 26
src/win32_platform.h

@@ -100,6 +100,9 @@
 #ifndef DISPLAY_DEVICE_ACTIVE
 #ifndef DISPLAY_DEVICE_ACTIVE
  #define DISPLAY_DEVICE_ACTIVE 0x00000001
  #define DISPLAY_DEVICE_ACTIVE 0x00000001
 #endif
 #endif
+#ifndef _WIN32_WINNT_WINBLUE
+ #define _WIN32_WINNT_WINBLUE 0x0602
+#endif
 
 
 #if WINVER < 0x0601
 #if WINVER < 0x0601
 typedef struct tagCHANGEFILTERSTRUCT
 typedef struct tagCHANGEFILTERSTRUCT
@@ -113,19 +116,9 @@ typedef struct tagCHANGEFILTERSTRUCT
 #endif
 #endif
 #endif /*Windows 7*/
 #endif /*Windows 7*/
 
 
-#ifndef DPI_ENUMS_DECLARED
-typedef enum PROCESS_DPI_AWARENESS
-{
-    PROCESS_DPI_UNAWARE = 0,
-    PROCESS_SYSTEM_DPI_AWARE = 1,
-    PROCESS_PER_MONITOR_DPI_AWARE = 2
-} PROCESS_DPI_AWARENESS;
-#endif /*DPI_ENUMS_DECLARED*/
-
-#if !defined(_DWMAPI_H_)
-#define DWM_BB_ENABLE                 0x00000001
-#define DWM_BB_BLURREGION             0x00000002
-
+#if WINVER < 0x0600
+#define DWM_BB_ENABLE 0x00000001
+#define DWM_BB_BLURREGION 0x00000002
 typedef struct
 typedef struct
 {
 {
     DWORD dwFlags;
     DWORD dwFlags;
@@ -133,19 +126,19 @@ typedef struct
     HRGN hRgnBlur;
     HRGN hRgnBlur;
     BOOL fTransitionOnMaximized;
     BOOL fTransitionOnMaximized;
 } DWM_BLURBEHIND;
 } DWM_BLURBEHIND;
-#endif
+#endif /*Windows Vista*/
 
 
-// HACK: Define versionhelpers.h functions manually as MinGW lacks the header
-FORCEINLINE BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp)
+#ifndef DPI_ENUMS_DECLARED
+typedef enum PROCESS_DPI_AWARENESS
 {
 {
-    OSVERSIONINFOEXW osvi = { sizeof(osvi), major, minor, 0, 0, {0}, sp };
-    DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR;
-    ULONGLONG cond = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL);
-    cond = VerSetConditionMask(cond, VER_MINORVERSION, VER_GREATER_EQUAL);
-    cond = VerSetConditionMask(cond, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
-    return VerifyVersionInfoW(&osvi, mask, cond);
-}
+    PROCESS_DPI_UNAWARE = 0,
+    PROCESS_SYSTEM_DPI_AWARE = 1,
+    PROCESS_PER_MONITOR_DPI_AWARE = 2
+} PROCESS_DPI_AWARENESS;
+#endif /*DPI_ENUMS_DECLARED*/
 
 
+// HACK: Define versionhelpers.h functions manually as MinGW lacks the header
+BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp);
 #define IsWindowsVistaOrGreater()                              \
 #define IsWindowsVistaOrGreater()                              \
     IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA),      \
     IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA),      \
                               LOBYTE(_WIN32_WINNT_VISTA), 0)
                               LOBYTE(_WIN32_WINNT_VISTA), 0)
@@ -216,10 +209,10 @@ typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,PCHANGEF
 // dwmapi.dll function pointer typedefs
 // dwmapi.dll function pointer typedefs
 typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*);
 typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*);
 typedef HRESULT (WINAPI * PFN_DwmFlush)(VOID);
 typedef HRESULT (WINAPI * PFN_DwmFlush)(VOID);
-typedef HRESULT(WINAPI * DWMENABLEBLURBEHINDWINDOW_T)(HWND, const DWM_BLURBEHIND*);
+typedef HRESULT(WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND,const DWM_BLURBEHIND*);
 #define DwmIsCompositionEnabled _glfw.win32.dwmapi.IsCompositionEnabled
 #define DwmIsCompositionEnabled _glfw.win32.dwmapi.IsCompositionEnabled
 #define DwmFlush _glfw.win32.dwmapi.Flush
 #define DwmFlush _glfw.win32.dwmapi.Flush
-#define _glfw_DwmEnableBlurBehindWindow _glfw.win32.dwmapi.DwmEnableBlurBehindWindow
+#define DwmEnableBlurBehindWindow _glfw.win32.dwmapi.EnableBlurBehindWindow
 
 
 // shcore.dll function pointer typedefs
 // shcore.dll function pointer typedefs
 typedef HRESULT (WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS);
 typedef HRESULT (WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS);
@@ -274,6 +267,8 @@ typedef struct _GLFWwindowWin32
     GLFWbool            frameAction;
     GLFWbool            frameAction;
     GLFWbool            iconified;
     GLFWbool            iconified;
     GLFWbool            maximized;
     GLFWbool            maximized;
+    // Whether to enable framebuffer transparency on DWM
+    GLFWbool            transparent;
 
 
     // The last received cursor position, regardless of source
     // The last received cursor position, regardless of source
     int                 lastCursorPosX, lastCursorPosY;
     int                 lastCursorPosX, lastCursorPosY;
@@ -325,7 +320,7 @@ typedef struct _GLFWlibraryWin32
         HINSTANCE                       instance;
         HINSTANCE                       instance;
         PFN_DwmIsCompositionEnabled     IsCompositionEnabled;
         PFN_DwmIsCompositionEnabled     IsCompositionEnabled;
         PFN_DwmFlush                    Flush;
         PFN_DwmFlush                    Flush;
-        DWMENABLEBLURBEHINDWINDOW_T DwmEnableBlurBehindWindow;
+        PFN_DwmEnableBlurBehindWindow   EnableBlurBehindWindow;
     } dwmapi;
     } dwmapi;
 
 
     struct {
     struct {
@@ -388,6 +383,7 @@ typedef struct _GLFWmutexWin32
 
 
 GLFWbool _glfwRegisterWindowClassWin32(void);
 GLFWbool _glfwRegisterWindowClassWin32(void);
 void _glfwUnregisterWindowClassWin32(void);
 void _glfwUnregisterWindowClassWin32(void);
+GLFWbool _glfwIsCompositionEnabledWin32(void);
 
 
 WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source);
 WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source);
 char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source);
 char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source);

+ 84 - 2
src/win32_window.c

@@ -306,6 +306,55 @@ static void updateWindowStyles(const _GLFWwindow* window)
                  SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER);
                  SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOZORDER);
 }
 }
 
 
+// Update window framebuffer transparency
+//
+static void updateFramebufferTransparency(const _GLFWwindow* window)
+{
+    if (!IsWindowsVistaOrGreater())
+        return;
+
+    if (_glfwIsCompositionEnabledWin32())
+    {
+        HRGN region = CreateRectRgn(0, 0, -1, -1);
+        DWM_BLURBEHIND bb = {0};
+        bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
+        bb.hRgnBlur = region;
+        bb.fEnable = TRUE;
+
+        if (SUCCEEDED(DwmEnableBlurBehindWindow(window->win32.handle, &bb)))
+        {
+            // Decorated windows 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, at least when used with blur behind window
+            //       plus negative region.
+            LONG style = GetWindowLongW(window->win32.handle, GWL_EXSTYLE);
+            style |= WS_EX_LAYERED;
+            SetWindowLongW(window->win32.handle, GWL_EXSTYLE, style);
+
+            // 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.
+            SetLayeredWindowAttributes(window->win32.handle,
+                                       RGB(0, 193, 48), 255, LWA_COLORKEY);
+        }
+
+        DeleteObject(region);
+    }
+    else
+    {
+        LONG style = GetWindowLongW(window->win32.handle, GWL_EXSTYLE);
+        style &= ~WS_EX_LAYERED;
+        SetWindowLongW(window->win32.handle, GWL_EXSTYLE, style);
+        RedrawWindow(window->win32.handle, NULL, NULL,
+                     RDW_ERASE | RDW_INVALIDATE | RDW_FRAME);
+    }
+}
+
 // Translates a GLFW standard cursor to a resource ID
 // Translates a GLFW standard cursor to a resource ID
 //
 //
 static LPWSTR translateCursorShape(int shape)
 static LPWSTR translateCursorShape(int shape)
@@ -916,6 +965,13 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
             return TRUE;
             return TRUE;
         }
         }
 
 
+        case WM_DWMCOMPOSITIONCHANGED:
+        {
+            if (window->win32.transparent)
+                updateFramebufferTransparency(window);
+            return 0;
+        }
+
         case WM_SETCURSOR:
         case WM_SETCURSOR:
         {
         {
             if (LOWORD(lParam) == HTCLIENT)
             if (LOWORD(lParam) == HTCLIENT)
@@ -981,7 +1037,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
 // Creates the GLFW window
 // Creates the GLFW window
 //
 //
 static int createNativeWindow(_GLFWwindow* window,
 static int createNativeWindow(_GLFWwindow* window,
-                              const _GLFWwndconfig* wndconfig)
+                              const _GLFWwndconfig* wndconfig,
+                              const _GLFWfbconfig* fbconfig)
 {
 {
     int xpos, ypos, fullWidth, fullHeight;
     int xpos, ypos, fullWidth, fullHeight;
     WCHAR* wideTitle;
     WCHAR* wideTitle;
@@ -1051,6 +1108,12 @@ static int createNativeWindow(_GLFWwindow* window,
 
 
     DragAcceptFiles(window->win32.handle, TRUE);
     DragAcceptFiles(window->win32.handle, TRUE);
 
 
+    if (fbconfig->transparent)
+    {
+        updateFramebufferTransparency(window);
+        window->win32.transparent = GLFW_TRUE;
+    }
+
     return GLFW_TRUE;
     return GLFW_TRUE;
 }
 }
 
 
@@ -1102,6 +1165,20 @@ void _glfwUnregisterWindowClassWin32(void)
     UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL));
     UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL));
 }
 }
 
 
+// Returns whether desktop compositing is enabled
+//
+GLFWbool _glfwIsCompositionEnabledWin32(void)
+{
+    if (IsWindowsVistaOrGreater())
+    {
+        BOOL enabled;
+        if (SUCCEEDED(DwmIsCompositionEnabled(&enabled)))
+            return enabled;
+    }
+
+    return FALSE;
+}
+
 
 
 //////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////
 //////                       GLFW platform API                      //////
 //////                       GLFW platform API                      //////
@@ -1112,7 +1189,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
                               const _GLFWctxconfig* ctxconfig,
                               const _GLFWctxconfig* ctxconfig,
                               const _GLFWfbconfig* fbconfig)
                               const _GLFWfbconfig* fbconfig)
 {
 {
-    if (!createNativeWindow(window, wndconfig))
+    if (!createNativeWindow(window, wndconfig, fbconfig))
         return GLFW_FALSE;
         return GLFW_FALSE;
 
 
     if (ctxconfig->client != GLFW_NO_API)
     if (ctxconfig->client != GLFW_NO_API)
@@ -1481,6 +1558,11 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
     return IsZoomed(window->win32.handle);
     return IsZoomed(window->win32.handle);
 }
 }
 
 
+int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
+{
+    return window->win32.transparent && _glfwIsCompositionEnabledWin32();
+}
+
 void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
 void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
 {
 {
     updateWindowStyles(window);
     updateWindowStyles(window);

+ 2 - 1
src/window.c

@@ -147,7 +147,6 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
     fbconfig  = _glfw.hints.framebuffer;
     fbconfig  = _glfw.hints.framebuffer;
     ctxconfig = _glfw.hints.context;
     ctxconfig = _glfw.hints.context;
     wndconfig = _glfw.hints.window;
     wndconfig = _glfw.hints.window;
-    fbconfig.transparent  = _glfw.hints.framebuffer.transparent ? GLFW_TRUE : GLFW_FALSE;
 
 
     wndconfig.width   = width;
     wndconfig.width   = width;
     wndconfig.height  = height;
     wndconfig.height  = height;
@@ -728,6 +727,8 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib)
             return _glfwPlatformWindowVisible(window);
             return _glfwPlatformWindowVisible(window);
         case GLFW_MAXIMIZED:
         case GLFW_MAXIMIZED:
             return _glfwPlatformWindowMaximized(window);
             return _glfwPlatformWindowMaximized(window);
+        case GLFW_TRANSPARENT:
+            return _glfwPlatformFramebufferTransparent(window);
         case GLFW_RESIZABLE:
         case GLFW_RESIZABLE:
             return window->resizable;
             return window->resizable;
         case GLFW_DECORATED:
         case GLFW_DECORATED:

+ 7 - 0
src/wl_window.c

@@ -654,6 +654,13 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
     return window->wl.maximized;
     return window->wl.maximized;
 }
 }
 
 
+int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
+{
+    _glfwInputError(GLFW_PLATFORM_ERROR,
+                    "Wayland: Framebuffer transparency attribute not implemented yet");
+    return GLFW_FALSE;
+}
+
 void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
 void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
 {
 {
     // TODO
     // TODO

+ 23 - 49
src/x11_init.c

@@ -651,6 +651,29 @@ static GLFWbool initExtensions(void)
             dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection");
             dlsym(_glfw.x11.x11xcb.handle, "XGetXCBConnection");
     }
     }
 
 
+    _glfw.x11.xrender.handle = dlopen("libXrender.so.1", RTLD_LAZY | RTLD_GLOBAL);
+    if (_glfw.x11.xrender.handle)
+    {
+        _glfw.x11.xrender.QueryExtension = (PFN_XRenderQueryExtension)
+            dlsym(_glfw.x11.xrender.handle, "XRenderQueryExtension");
+        _glfw.x11.xrender.QueryVersion = (PFN_XRenderQueryVersion)
+            dlsym(_glfw.x11.xrender.handle, "XRenderQueryVersion");
+        _glfw.x11.xrender.FindVisualFormat = (PFN_XRenderFindVisualFormat)
+            dlsym(_glfw.x11.xrender.handle, "XRenderFindVisualFormat");
+
+        if (XRenderQueryExtension(_glfw.x11.display,
+                                  &_glfw.x11.xrender.errorBase,
+                                  &_glfw.x11.xrender.eventBase))
+        {
+            if (XRenderQueryVersion(_glfw.x11.display,
+                                    &_glfw.x11.xrender.major,
+                                    &_glfw.x11.xrender.minor))
+            {
+                _glfw.x11.xrender.available = GLFW_TRUE;
+            }
+        }
+    }
+
     // Update the key code LUT
     // Update the key code LUT
     // FIXME: We should listen to XkbMapNotify events to track changes to
     // FIXME: We should listen to XkbMapNotify events to track changes to
     // the keyboard mapping.
     // the keyboard mapping.
@@ -717,55 +740,6 @@ static GLFWbool initExtensions(void)
     _glfw.x11.MOTIF_WM_HINTS =
     _glfw.x11.MOTIF_WM_HINTS =
         XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False);
         XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False);
 
 
-    int i;
-    const char* sonames_xrender[] =
-    {
-#if defined(__CYGWIN__)
-        "libXrender-1.so",
-#else
-        "libXrender.so.1",
-        "libXrender.so",
-#endif
-        NULL
-    };
-
-    // 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;
     return GLFW_TRUE;
 }
 }
 
 

+ 24 - 27
src/x11_platform.h

@@ -116,6 +116,13 @@ typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int);
 #define XIQueryVersion _glfw.x11.xi.QueryVersion
 #define XIQueryVersion _glfw.x11.xi.QueryVersion
 #define XISelectEvents _glfw.x11.xi.SelectEvents
 #define XISelectEvents _glfw.x11.xi.SelectEvents
 
 
+typedef Bool (* PFN_XRenderQueryExtension)(Display*,int*,int*);
+typedef Status (* PFN_XRenderQueryVersion)(Display*dpy,int*,int*);
+typedef XRenderPictFormat* (* PFN_XRenderFindVisualFormat)(Display*,Visual const*);
+#define XRenderQueryExtension _glfw.x11.xrender.QueryExtension
+#define XRenderQueryVersion _glfw.x11.xrender.QueryVersion
+#define XRenderFindVisualFormat _glfw.x11.xrender.FindVisualFormat
+
 typedef VkFlags VkXlibSurfaceCreateFlagsKHR;
 typedef VkFlags VkXlibSurfaceCreateFlagsKHR;
 typedef VkFlags VkXcbSurfaceCreateFlagsKHR;
 typedef VkFlags VkXcbSurfaceCreateFlagsKHR;
 
 
@@ -162,20 +169,10 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(Vk
 #define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.x11.display)
 #define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.x11.display)
 
 
 #define _GLFW_PLATFORM_WINDOW_STATE         _GLFWwindowX11  x11
 #define _GLFW_PLATFORM_WINDOW_STATE         _GLFWwindowX11  x11
-#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11 ; _GLFWlibraryXrender xrender
+#define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11
 #define _GLFW_PLATFORM_MONITOR_STATE        _GLFWmonitorX11 x11
 #define _GLFW_PLATFORM_MONITOR_STATE        _GLFWmonitorX11 x11
 #define _GLFW_PLATFORM_CURSOR_STATE         _GLFWcursorX11  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
 // X11-specific per-window data
 //
 //
@@ -189,6 +186,9 @@ typedef struct _GLFWwindowX11
     GLFWbool        iconified;
     GLFWbool        iconified;
     GLFWbool        maximized;
     GLFWbool        maximized;
 
 
+    // Whether the visual supports framebuffer transparency
+    GLFWbool        transparent;
+
     // Cached position and size used to filter out duplicate events
     // Cached position and size used to filter out duplicate events
     int             width, height;
     int             width, height;
     int             xpos, ypos;
     int             xpos, ypos;
@@ -383,23 +383,19 @@ typedef struct _GLFWlibraryX11
         PFN_XISelectEvents SelectEvents;
         PFN_XISelectEvents SelectEvents;
     } xi;
     } xi;
 
 
-} _GLFWlibraryX11;
-
-// Xrender-specific global data
-typedef struct _GLFWlibraryXrender
-{
-    int             major, minor;
-    int             eventBase;
-    int             errorBase;
-
-    // dlopen handle for libGL.so.1
-    void*           handle;
+    struct {
+        GLFWbool    available;
+        void*       handle;
+        int         major;
+        int         minor;
+        int         eventBase;
+        int         errorBase;
+        PFN_XRenderQueryExtension QueryExtension;
+        PFN_XRenderQueryVersion QueryVersion;
+        PFN_XRenderFindVisualFormat FindVisualFormat;
+    } xrender;
 
 
-    // Xrender functions (subset required for transparent window)
-    PFNXRENDERQUERYEXTENSIONPROC    QueryExtension;
-    PFNXRENDERQUERYVERSIONPROC      QueryVersion;
-    PFNXRENDERFINDVISUALFORMATPROC  FindVisualFormat;
-} _GLFWlibraryXrender;
+} _GLFWlibraryX11;
 
 
 // X11-specific per-monitor data
 // X11-specific per-monitor data
 //
 //
@@ -434,6 +430,7 @@ unsigned long _glfwGetWindowPropertyX11(Window window,
                                         Atom property,
                                         Atom property,
                                         Atom type,
                                         Atom type,
                                         unsigned char** value);
                                         unsigned char** value);
+GLFWbool _glfwIsVisualTransparentX11(Visual* visual);
 
 
 void _glfwGrabErrorHandlerX11(void);
 void _glfwGrabErrorHandlerX11(void);
 void _glfwReleaseErrorHandlerX11(void);
 void _glfwReleaseErrorHandlerX11(void);

+ 25 - 0
src/x11_window.c

@@ -364,6 +364,7 @@ static void updateWindowMode(_GLFWwindow* window)
         }
         }
 
 
         // Enable compositor bypass
         // Enable compositor bypass
+        if (!window->x11.transparent)
         {
         {
             const unsigned long value = 1;
             const unsigned long value = 1;
 
 
@@ -402,6 +403,7 @@ static void updateWindowMode(_GLFWwindow* window)
         }
         }
 
 
         // Disable compositor bypass
         // Disable compositor bypass
+        if (!window->x11.transparent)
         {
         {
             XDeleteProperty(_glfw.x11.display, window->x11.handle,
             XDeleteProperty(_glfw.x11.display, window->x11.handle,
                             _glfw.x11.NET_WM_BYPASS_COMPOSITOR);
                             _glfw.x11.NET_WM_BYPASS_COMPOSITOR);
@@ -577,6 +579,8 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
                                            visual,
                                            visual,
                                            AllocNone);
                                            AllocNone);
 
 
+    window->x11.transparent = _glfwIsVisualTransparentX11(visual);
+
     // Create the actual window
     // Create the actual window
     {
     {
         XSetWindowAttributes wa;
         XSetWindowAttributes wa;
@@ -1838,6 +1842,15 @@ unsigned long _glfwGetWindowPropertyX11(Window window,
     return itemCount;
     return itemCount;
 }
 }
 
 
+GLFWbool _glfwIsVisualTransparentX11(Visual* visual)
+{
+    if (!_glfw.x11.xrender.available)
+        return GLFW_FALSE;
+
+    XRenderPictFormat* pf = XRenderFindVisualFormat(_glfw.x11.display, visual);
+    return pf && pf->direct.alphaMask;
+}
+
 // Push contents of our selection to clipboard manager
 // Push contents of our selection to clipboard manager
 //
 //
 void _glfwPushSelectionToManagerX11(void)
 void _glfwPushSelectionToManagerX11(void)
@@ -2422,6 +2435,18 @@ int _glfwPlatformWindowMaximized(_GLFWwindow* window)
     return maximized;
     return maximized;
 }
 }
 
 
+int _glfwPlatformFramebufferTransparent(_GLFWwindow* window)
+{
+    if (!window->x11.transparent)
+        return GLFW_FALSE;
+
+    // Check whether a compositing manager is running
+    char name[32];
+    snprintf(name, sizeof(name), "_NET_WM_CM_S%u", _glfw.x11.screen);
+    const Atom selection = XInternAtom(_glfw.x11.display, name, False);
+    return XGetSelectionOwner(_glfw.x11.display, selection) != None;
+}
+
 void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
 void _glfwPlatformSetWindowResizable(_GLFWwindow* window, GLFWbool enabled)
 {
 {
     int width, height;
     int width, height;