diff --git a/README.md b/README.md index 40e9544f4..e865115e7 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,8 @@ information on what to include when reporting a bug. functions for accessing X11 primary selection (#894,#1056) - Added headless [OSMesa](http://mesa3d.org/osmesa.html) backend (#850) - Added definition of `GLAPIENTRY` to public header +- Added `GLFW_TRANSPARENT` window hint for enabling framebuffer transparency + (#197,#663,#715,#723,#1078) - Added `GLFW_CENTER_CURSOR` window hint for controlling cursor centering (#749,#842) - Added `GLFW_JOYSTICK_HAT_BUTTONS` init hint (#889) @@ -288,6 +290,7 @@ skills. - Yaron Cohen-Tal - Omar Cornut - Andrew Corrigan + - Bailey Cosier - Noel Cower - Jason Daly - Jarrod Davis @@ -296,6 +299,7 @@ skills. - Michael Dickens - Роман Донченко - Mario Dorn + - Wolfgang Draxinger - Jonathan Dummer - Ralph Eastwood - Fredrik Ehnbom @@ -321,6 +325,7 @@ skills. - Erik S. V. Jansson - Toni Jovanoski - Arseny Kapoulkine + - Cem Karan - Osman Keskin - Josh Kilmer - Cameron King @@ -362,6 +367,7 @@ skills. - Andri Pálsson - Peoro - Braden Pellett + - Christopher Pelloux - Arturo J. Pérez - Anthony Pesch - Orson Peters diff --git a/docs/news.dox b/docs/news.dox index 042468f16..618ec4ee2 100644 --- a/docs/news.dox +++ b/docs/news.dox @@ -85,6 +85,12 @@ be disabled with the @ref GLFW_JOYSTICK_HAT_BUTTONS init hint. @see @ref joystick_hat +@subsection news_33_transparent Support for transparent windows + +GLFW now supports the creation of tranparent windows on platforms where this is +available with the [GLFW_TRANSPARENT](@ref GLFW_TRANSPARENT) window hint. + + @subsection news_33_centercursor Cursor centering window hint GLFW now supports controlling whether the cursor is centered over newly created diff --git a/docs/window.dox b/docs/window.dox index 17fa3002b..37debd6ee 100644 --- a/docs/window.dox +++ b/docs/window.dox @@ -287,7 +287,7 @@ __GLFW_DOUBLEBUFFER__ specifies whether the framebuffer should be double buffered. You nearly always want to use double buffering. This is a hard constraint. Possible values are `GLFW_TRUE` and `GLFW_FALSE`. -@anchor GLFW_TRANSPARENT_hint +@anchor GLFW_TRANSPARENT __GLFW_TRANSPARENT__ specifies whether the framebuffer will support transparency in the background. Possible values are `GLFW_TRUE` and `GLFW_FALSE`. @@ -490,6 +490,7 @@ GLFW_REFRESH_RATE | `GLFW_DONT_CARE` | 0 to `INT_MAX` or GLFW_STEREO | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_SRGB_CAPABLE | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_DOUBLEBUFFER | `GLFW_TRUE` | `GLFW_TRUE` or `GLFW_FALSE` +GLFW_TRANSPARENT | `GLFW_FALSE` | `GLFW_TRUE` or `GLFW_FALSE` GLFW_CLIENT_API | `GLFW_OPENGL_API` | `GLFW_OPENGL_API`, `GLFW_OPENGL_ES_API` or `GLFW_NO_API` GLFW_CONTEXT_CREATION_API | `GLFW_NATIVE_CONTEXT_API` | `GLFW_NATIVE_CONTEXT_API`, `GLFW_EGL_CONTEXT_API` or `GLFW_OSMESA_CONTEXT_API` GLFW_CONTEXT_VERSION_MAJOR | 1 | Any valid major version number of the chosen client API diff --git a/examples/gears.c b/examples/gears.c index f7526e05f..f14b300a7 100644 --- a/examples/gears.c +++ b/examples/gears.c @@ -172,7 +172,7 @@ static GLfloat angle = 0.f; /* OpenGL draw function & timing */ 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); glPushMatrix(); @@ -312,7 +312,6 @@ 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 ); diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 5e9eac6f2..dc993a353 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -870,7 +870,7 @@ extern "C" { #define GLFW_DOUBLEBUFFER 0x00021010 /*! @brief Framebuffer transparency hint. * - * Framebuffer transparency [hint](@ref GLFW_TRANSPARENT_hint). + * Framebuffer transparency [hint](@ref GLFW_TRANSPARENT). */ #define GLFW_TRANSPARENT 0x00021011 diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 5b2736b40..16e03ece6 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -413,11 +413,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 }; - (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 @@ -1016,7 +1012,8 @@ static GLFWbool initializeAppKit(void) // Create the Cocoa window // static GLFWbool createNativeWindow(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig) + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig) { window->ns.delegate = [[GLFWWindowDelegate alloc] initWithGlfwWindow:window]; if (window->ns.delegate == nil) @@ -1085,7 +1082,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, if (wndconfig->ns.retina) [window->ns.view setWantsBestResolutionOpenGLSurface:YES]; - if (_glfw.hints.framebuffer.transparent) + if (fbconfig->transparent) { [window->ns.object setOpaque:NO]; [window->ns.object setBackgroundColor:[NSColor clearColor]]; @@ -1114,7 +1111,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (!initializeAppKit()) return GLFW_FALSE; - if (!createNativeWindow(window, wndconfig)) + if (!createNativeWindow(window, wndconfig, fbconfig)) return GLFW_FALSE; if (ctxconfig->client != GLFW_NO_API) diff --git a/src/context.c b/src/context.c index 1a26356e1..3842f0a37 100644 --- a/src/context.c +++ b/src/context.c @@ -208,6 +208,9 @@ const _GLFWfbconfig* _glfwChooseFBConfig(const _GLFWfbconfig* desired, // not important to us here, so we count them as one missing++; } + + if (desired->transparent != current->transparent) + missing++; } // These polynomials make many small channel size differences matter diff --git a/src/egl_context.c b/src/egl_context.c index bba1efb7e..bf3130c64 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -87,21 +87,13 @@ static int getEGLConfigAttrib(EGLConfig config, int attrib) // static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* desired, - EGLConfig* result, - GLFWbool findTransparent) + EGLConfig* result) { 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) { @@ -115,7 +107,6 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; -selectionloop: for (i = 0; i < nativeCount; i++) { const EGLConfig n = nativeConfigs[i]; @@ -130,31 +121,32 @@ selectionloop: continue; #if defined(_GLFW_X11) + XVisualInfo vi = {0}; + // Only consider EGLConfigs with associated Visuals - visualTemplate.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID); - if (!visualTemplate.visualid) + vi.visualid = getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID); + if (!vi.visualid) continue; - if( findTransparent ) { - int n_vi; - XVisualInfo *visualinfo; - XRenderPictFormat *pictFormat; + if (desired->transparent) + { + if (_glfw.x11.xrender.available) + { + int count; + XVisualInfo* vis = XGetVisualInfo(_glfw.x11.display, + VisualIDMask, &vi, + &count); + if (vis) + { + XRenderPictFormat* pf = + XRenderFindVisualFormat(_glfw.x11.display, + vis[0].visual); + if (pf && pf->direct.alphaMask) + u->transparent = GLFW_TRUE; - 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 ); + XFree(vis); + } + } } #endif // _GLFW_X11 @@ -191,12 +183,6 @@ selectionloop: u->handle = (uintptr_t) 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) @@ -493,7 +479,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, if (ctxconfig->share) share = ctxconfig->share->context.egl.handle; - if (!chooseEGLConfig(ctxconfig, fbconfig, &config, fbconfig->transparent)) + if (!chooseEGLConfig(ctxconfig, fbconfig, &config)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Failed to find a suitable EGLConfig"); @@ -738,7 +724,7 @@ GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig, EGLint visualID = 0, count = 0; const long vimask = VisualScreenMask | VisualIDMask; - if (!chooseEGLConfig(ctxconfig, fbconfig, &native, fbconfig->transparent)) + if (!chooseEGLConfig(ctxconfig, fbconfig, &native)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Failed to find a suitable EGLConfig"); diff --git a/src/glx_context.c b/src/glx_context.c index 712e8c78e..48c0ac3a7 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -47,10 +47,8 @@ static int getGLXFBConfigAttrib(GLXFBConfig fbconfig, int attrib) // 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; _GLFWfbconfig* usableConfigs; @@ -59,10 +57,6 @@ static GLFWbool chooseGLXFBConfig( const char* vendor; GLFWbool trustWindowBit = GLFW_TRUE; - if ( !(_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); @@ -80,7 +74,6 @@ static GLFWbool chooseGLXFBConfig( usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; -selectionloop: for (i = 0; i < nativeCount; i++) { const GLXFBConfig n = nativeConfigs[i]; @@ -97,25 +90,21 @@ selectionloop: continue; } - if( findTransparent ) { - XVisualInfo *visualinfo; - XRenderPictFormat *pictFormat; + if (desired->transparent) + { + if (_glfw.x11.xrender.available) + { + XVisualInfo* vi = glXGetVisualFromFBConfig(_glfw.x11.display, n); + if (vi) + { + XRenderPictFormat* pf = + XRenderFindVisualFormat(_glfw.x11.display, vi->visual); + if (pf && pf->direct.alphaMask) + u->transparent = GLFW_TRUE; - 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 ); + XFree(vi); + } + } } u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE); @@ -147,12 +136,6 @@ selectionloop: u->handle = (uintptr_t) 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) @@ -477,7 +460,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, if (ctxconfig->share) share = ctxconfig->share->context.glx.handle; - if (!chooseGLXFBConfig(fbconfig, &native, fbconfig->transparent)) + if (!chooseGLXFBConfig(fbconfig, &native)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "GLX: Failed to find a suitable GLXFBConfig"); @@ -665,7 +648,7 @@ GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig, GLXFBConfig native; XVisualInfo* result; - if (!chooseGLXFBConfig(fbconfig, &native, fbconfig->transparent)) + if (!chooseGLXFBConfig(fbconfig, &native)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "GLX: Failed to find a suitable GLXFBConfig"); diff --git a/src/wgl_context.c b/src/wgl_context.c index 0834e0a89..ba5e816ae 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -215,14 +215,6 @@ static int choosePixelFormat(_GLFWwindow* window, u->handle = n; 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) { @@ -249,21 +241,6 @@ static int choosePixelFormat(_GLFWwindow* window, 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) { if (window) @@ -292,7 +269,7 @@ static void makeContextCurrentWGL(_GLFWwindow* window) static void swapBuffersWGL(_GLFWwindow* window) { // HACK: Use DwmFlush when desktop composition is enabled - if (isCompositionEnabled() && !window->monitor) + if (_glfwIsCompositionEnabledWin32() && !window->monitor) { int count = abs(window->context.wgl.interval); while (count--) @@ -310,7 +287,7 @@ static void swapIntervalWGL(int interval) // HACK: Disable WGL swap interval when desktop composition is enabled to // avoid interfering with DWM vsync - if (isCompositionEnabled() && !window->monitor) + if (_glfwIsCompositionEnabledWin32() && !window->monitor) interval = 0; if (_glfw.wgl.EXT_swap_control) @@ -504,75 +481,6 @@ void _glfwTerminateWGL(void) 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 // GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, @@ -802,14 +710,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.swapBuffers = swapBuffersWGL; window->context.swapInterval = swapIntervalWGL; diff --git a/src/win32_init.c b/src/win32_init.c index 619fcfb14..5d6920c44 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -131,7 +131,7 @@ static GLFWbool loadLibraries(void) GetProcAddress(_glfw.win32.dwmapi.instance, "DwmIsCompositionEnabled"); _glfw.win32.dwmapi.Flush = (PFN_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"); } diff --git a/src/win32_platform.h b/src/win32_platform.h index bfed50514..ad05421bd 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -113,6 +113,18 @@ typedef struct tagCHANGEFILTERSTRUCT #endif #endif /*Windows 7*/ +#if WINVER < 0x0600 +#define DWM_BB_ENABLE 0x00000001 +#define DWM_BB_BLURREGION 0x00000002 +typedef struct +{ + DWORD dwFlags; + BOOL fEnable; + HRGN hRgnBlur; + BOOL fTransitionOnMaximized; +} DWM_BLURBEHIND; +#endif /*Windows Vista*/ + #ifndef DPI_ENUMS_DECLARED typedef enum PROCESS_DPI_AWARENESS { @@ -122,19 +134,6 @@ typedef enum PROCESS_DPI_AWARENESS } PROCESS_DPI_AWARENESS; #endif /*DPI_ENUMS_DECLARED*/ -#if !defined(_DWMAPI_H_) -#define DWM_BB_ENABLE 0x00000001 -#define DWM_BB_BLURREGION 0x00000002 - -typedef struct -{ - DWORD dwFlags; - BOOL fEnable; - HRGN hRgnBlur; - BOOL fTransitionOnMaximized; -} DWM_BLURBEHIND; -#endif - // HACK: Define versionhelpers.h functions manually as MinGW lacks the header FORCEINLINE BOOL IsWindowsVersionOrGreater(WORD major, WORD minor, WORD sp) { @@ -216,10 +215,10 @@ typedef BOOL (WINAPI * PFN_ChangeWindowMessageFilterEx)(HWND,UINT,DWORD,PCHANGEF // dwmapi.dll function pointer typedefs typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*); 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 DwmFlush _glfw.win32.dwmapi.Flush -#define _glfw_DwmEnableBlurBehindWindow _glfw.win32.dwmapi.DwmEnableBlurBehindWindow +#define DwmEnableBlurBehindWindow _glfw.win32.dwmapi.EnableBlurBehindWindow // shcore.dll function pointer typedefs typedef HRESULT (WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); @@ -325,7 +324,7 @@ typedef struct _GLFWlibraryWin32 HINSTANCE instance; PFN_DwmIsCompositionEnabled IsCompositionEnabled; PFN_DwmFlush Flush; - DWMENABLEBLURBEHINDWINDOW_T DwmEnableBlurBehindWindow; + PFN_DwmEnableBlurBehindWindow EnableBlurBehindWindow; } dwmapi; struct { @@ -388,6 +387,7 @@ typedef struct _GLFWmutexWin32 GLFWbool _glfwRegisterWindowClassWin32(void); void _glfwUnregisterWindowClassWin32(void); +GLFWbool _glfwIsCompositionEnabledWin32(void); WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source); char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source); diff --git a/src/win32_window.c b/src/win32_window.c index 9ce9e4361..d52408eef 100644 --- a/src/win32_window.c +++ b/src/win32_window.c @@ -981,7 +981,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, // Creates the GLFW window // static int createNativeWindow(_GLFWwindow* window, - const _GLFWwndconfig* wndconfig) + const _GLFWwndconfig* wndconfig, + const _GLFWfbconfig* fbconfig) { int xpos, ypos, fullWidth, fullHeight; WCHAR* wideTitle; @@ -1051,6 +1052,41 @@ static int createNativeWindow(_GLFWwindow* window, DragAcceptFiles(window->win32.handle, TRUE); + if (fbconfig->transparent && + IsWindowsVistaOrGreater() && + _glfwIsCompositionEnabledWin32()) + { + DWM_BLURBEHIND bb = {0}; + bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION; + bb.hRgnBlur = CreateRectRgn(0, 0, -1, -1); + bb.fEnable = TRUE; + + if (SUCCEEDED(DwmEnableBlurBehindWindow(window->win32.handle, &bb))) + { + // Decorated windows on Windows 8 and later 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 and later, at least when used + // with DwmEnableBlurBehindWindow plus negative region. + if (wndconfig->decorated && IsWindows8OrGreater()) + { + 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); + } + } + } + return GLFW_TRUE; } @@ -1102,6 +1138,21 @@ void _glfwUnregisterWindowClassWin32(void) UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL)); } +// Returns whether desktop compositing is enabled +// +GLFWbool _glfwIsCompositionEnabledWin32(void) +{ + if (_glfw.win32.dwmapi.instance) + { + BOOL enabled; + + if (DwmIsCompositionEnabled(&enabled) == S_OK) + return enabled; + } + + return FALSE; +} + ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// @@ -1112,7 +1163,7 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) { - if (!createNativeWindow(window, wndconfig)) + if (!createNativeWindow(window, wndconfig, fbconfig)) return GLFW_FALSE; if (ctxconfig->client != GLFW_NO_API) diff --git a/src/x11_init.c b/src/x11_init.c index 195c8ce4f..526d9ca25 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -651,6 +651,29 @@ static GLFWbool initExtensions(void) 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 // FIXME: We should listen to XkbMapNotify events to track changes to // the keyboard mapping. @@ -717,55 +740,6 @@ static GLFWbool initExtensions(void) _glfw.x11.MOTIF_WM_HINTS = 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; } diff --git a/src/x11_platform.h b/src/x11_platform.h index 9890f7034..1d038d246 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -116,6 +116,13 @@ typedef int (* PFN_XISelectEvents)(Display*,Window,XIEventMask*,int); #define XIQueryVersion _glfw.x11.xi.QueryVersion #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 VkXcbSurfaceCreateFlagsKHR; @@ -162,20 +169,10 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(Vk #define _GLFW_EGL_NATIVE_DISPLAY ((EGLNativeDisplayType) _glfw.x11.display) #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_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 // @@ -383,24 +380,20 @@ typedef struct _GLFWlibraryX11 PFN_XISelectEvents SelectEvents; } xi; + struct { + GLFWbool available; + void* handle; + int major; + int minor; + int eventBase; + int errorBase; + PFN_XRenderQueryExtension QueryExtension; + PFN_XRenderQueryVersion QueryVersion; + PFN_XRenderFindVisualFormat FindVisualFormat; + } xrender; + } _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 // typedef struct _GLFWmonitorX11