diff --git a/.gitignore b/.gitignore index 584b7b136..de69337eb 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ MinSizeRel RelWithDebInfo *.xcodeproj .vs +*.VC.opendb # CMake files Makefile diff --git a/examples/gears.c b/examples/gears.c index a787baedf..669931b65 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(); @@ -297,7 +298,6 @@ static void init(void) glEnable(GL_NORMALIZE); } - /* program entry */ int main(int argc, char *argv[]) { @@ -311,6 +311,9 @@ 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_TRUE); window = glfwCreateWindow( 300, 300, "Gears", NULL, NULL ); if (!window) diff --git a/include/GLFW/glfw3.h b/include/GLFW/glfw3.h index 131f20795..b236d7d8f 100644 --- a/include/GLFW/glfw3.h +++ b/include/GLFW/glfw3.h @@ -788,6 +788,7 @@ extern "C" { */ #define GLFW_CENTER_CURSOR 0x00020009 + /*! @brief Framebuffer bit depth hint. * * Framebuffer bit depth [hint](@ref GLFW_RED_BITS). diff --git a/src/egl_context.c b/src/egl_context.c index 54257f25d..820407e97 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -87,13 +87,21 @@ static int getEGLConfigAttrib(EGLConfig config, int attrib) // static GLFWbool chooseEGLConfig(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) { @@ -107,6 +115,7 @@ 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]; @@ -124,6 +133,28 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, // Only consider EGLConfigs with associated Visuals if (!getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID)) 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->client == GLFW_OPENGL_ES_API) @@ -159,6 +190,12 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig, 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) @@ -455,7 +492,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, if (ctxconfig->share) share = ctxconfig->share->context.egl.handle; - if (!chooseEGLConfig(ctxconfig, fbconfig, &config)) + if (!chooseEGLConfig(ctxconfig, fbconfig, &config, fbconfig->alphaMask)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Failed to find a suitable EGLConfig"); @@ -689,7 +726,8 @@ GLFWbool _glfwCreateContextEGL(_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) { @@ -699,7 +737,8 @@ GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig, EGLint visualID = 0, count = 0; const long vimask = VisualScreenMask | VisualIDMask; - if (!chooseEGLConfig(ctxconfig, fbconfig, &native)) + + if (!chooseEGLConfig(ctxconfig, fbconfig, &native, wndconfig->alphaMask)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Failed to find a suitable EGLConfig"); diff --git a/src/egl_context.h b/src/egl_context.h index bfab5111f..aa339baac 100644 --- a/src/egl_context.h +++ b/src/egl_context.h @@ -211,7 +211,8 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig); #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 169b0f9e9..96e706d1a 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -47,7 +47,11 @@ static int getGLXFBConfigAttrib(GLXFBConfig fbconfig, int attrib) // Return the GLXFBConfig most closely matching the specified hints // -static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* result) +static GLFWbool chooseGLXFBConfig( + const _GLFWfbconfig* desired, + GLXFBConfig* result, + GLFWbool findTransparent) + { GLXFBConfig* nativeConfigs; _GLFWfbconfig* usableConfigs; @@ -55,8 +59,10 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* res int i, nativeCount, usableCount; const char* vendor; GLFWbool trustWindowBit = GLFW_TRUE; - XVisualInfo *visual; - XRenderPictFormat *pict_format; + + 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 @@ -75,7 +81,8 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* res usableConfigs = calloc(nativeCount, sizeof(_GLFWfbconfig)); usableCount = 0; - + +selectionloop: for (i = 0; i < nativeCount; i++) { const GLXFBConfig n = nativeConfigs[i]; @@ -92,13 +99,30 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* res continue; } - visual = glXGetVisualFromFBConfig(_glfw.x11.display, n); - pict_format = XRenderFindVisualFormat(_glfw.x11.display, visual->visual); - u->alphaMask = pict_format->direct.alphaMask > 0; + if( findTransparent ) { + XVisualInfo *visualinfo; + XRenderPictFormat *pictFormat; - u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE); - u->greenBits = getGLXFBConfigAttrib(n, GLX_GREEN_SIZE); - u->blueBits = getGLXFBConfigAttrib(n, GLX_BLUE_SIZE); + 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 ); + } + + u->redBits = getFBConfigAttrib(n, GLX_RED_SIZE); + u->greenBits = getFBConfigAttrib(n, GLX_GREEN_SIZE); + u->blueBits = getFBConfigAttrib(n, GLX_BLUE_SIZE); u->alphaBits = getGLXFBConfigAttrib(n, GLX_ALPHA_SIZE); u->depthBits = getGLXFBConfigAttrib(n, GLX_DEPTH_SIZE); @@ -125,6 +149,12 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* res 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) @@ -249,7 +279,7 @@ static void destroyContextGLX(_GLFWwindow* window) GLFWbool _glfwInitGLX(void) { int i; - const char* sonames[] = + const char* sonames_glx[] = { #if defined(_GLFW_GLX_LIBRARY) _GLFW_GLX_LIBRARY, @@ -265,9 +295,9 @@ GLFWbool _glfwInitGLX(void) if (_glfw.glx.handle) return GLFW_TRUE; - for (i = 0; sonames[i]; i++) + for (i = 0; sonames_glx[i]; i++) { - _glfw.glx.handle = dlopen(sonames[i], RTLD_LAZY | RTLD_GLOBAL); + _glfw.glx.handle = dlopen(sonames_glx[i], RTLD_LAZY | RTLD_GLOBAL); if (_glfw.glx.handle) break; } @@ -449,7 +479,8 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, if (ctxconfig->share) share = ctxconfig->share->context.glx.handle; - if (!chooseGLXFBConfig(fbconfig, &native)) + if (!chooseGLXFBConfig(fbconfig, &native, window->transparent)) + { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "GLX: Failed to find a suitable GLXFBConfig"); @@ -629,14 +660,15 @@ GLFWbool _glfwCreateContextGLX(_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 (!chooseGLXFBConfig(fbconfig, &native)) + if (!chooseGLXFBConfig(fbconfig, &native, wndconfig->transparent)) { _glfwInputError(GLFW_FORMAT_UNAVAILABLE, "GLX: Failed to find a suitable GLXFBConfig"); @@ -652,7 +684,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 30743c112..27635d42d 100644 --- a/src/glx_context.h +++ b/src/glx_context.h @@ -72,6 +72,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*); @@ -92,7 +93,6 @@ typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int); typedef int (*PFNGLXSWAPINTERVALSGIPROC)(int); typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLXContext,Bool,const int*); -// libGL.so function pointer typedefs #define glXGetFBConfigs _glfw.glx.GetFBConfigs #define glXGetFBConfigAttrib _glfw.glx.GetFBConfigAttrib #define glXGetClientString _glfw.glx.GetClientString @@ -168,14 +168,14 @@ typedef struct _GLFWlibraryGLX } _GLFWlibraryGLX; - GLFWbool _glfwInitGLX(void); void _glfwTerminateGLX(void); 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 1ee138378..35ffc8ece 100644 --- a/src/internal.h +++ b/src/internal.h @@ -299,6 +299,7 @@ struct _GLFWwndconfig GLFWbool resizable; GLFWbool visible; GLFWbool decorated; + GLFWbool transparent; GLFWbool focused; GLFWbool autoIconify; GLFWbool floating; @@ -404,6 +405,7 @@ struct _GLFWwindow // Window settings and state GLFWbool resizable; GLFWbool decorated; + GLFWbool transparent; GLFWbool autoIconify; GLFWbool floating; GLFWbool shouldClose; diff --git a/src/wgl_context.c b/src/wgl_context.c index b28d7255e..af7416d01 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -83,6 +83,20 @@ static int 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) { @@ -152,11 +166,9 @@ static int 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)) @@ -205,6 +217,15 @@ static int choosePixelFormat(_GLFWwindow* window, u->alphaMask = 1; 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); + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: No pixel format found for transparent window. Ignoring transparency."); + return choosePixelFormat(window, desired, result); + } if (!usableCount) { @@ -486,6 +507,101 @@ void _glfwTerminateWGL(void) attribs[index++] = v; \ } +// 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(_GLFWwindow* window) +{ + if (!isCompositionEnabled) { + _glfwInputError(GLFW_PLATFORM_ERROR, + "WGL: Composition needed for transparent window is disabled"); + } + if (!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 = 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 = GetWindowLongPtrW(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 (!SetWindowLongPtrW(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, @@ -666,8 +782,54 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, ctxconfig->major, ctxconfig->minor); } - } - else if (error == (0xc0070000 | ERROR_INVALID_PROFILE_ARB)) + } + else if (error == (0xc0070000 | ERROR_INVALID_PROFILE_ARB)) { + // TODO: _glfwInputError + } + } + } + + if (window->transparent) + { + if (!setupTransparentWindow(window)) + window->transparent = GLFW_FALSE; + } + + return GLFW_TRUE; +} + +#undef setWGLattrib + +// Destroy the OpenGL context +// +void _glfwDestroyContextWGL(_GLFWwindow* window) +{ + if (window->context.wgl.handle) + { + wglDeleteContext(window->context.wgl.handle); + window->context.wgl.handle = NULL; + } +} + +// Analyzes the specified context for possible recreation +// +int _glfwAnalyzeContextWGL(_GLFWwindow* window, + const _GLFWctxconfig* ctxconfig, + const _GLFWfbconfig* fbconfig) +{ + GLFWbool required = GLFW_FALSE; + + if (_glfw.wgl.extensionsLoaded) + return _GLFW_RECREATION_NOT_NEEDED; + + _glfwPlatformMakeContextCurrent(window); + loadExtensions(); + + if (ctxconfig->api == GLFW_OPENGL_API) + { + if (ctxconfig->forward) + { + if (!_glfw.wgl.ARB_create_context) { _glfwInputError(GLFW_VERSION_UNAVAILABLE, "WGL: Driver does not support the requested OpenGL profile"); diff --git a/src/win32_init.c b/src/win32_init.c index 5a287076c..16e7322af 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -128,6 +128,8 @@ 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.EnableBlurBehindWindow = (PFN_DwmEnableBlurBehindWindow) + 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 63aaa94dc..1943f879b 100644 --- a/src/win32_platform.h +++ b/src/win32_platform.h @@ -153,7 +153,22 @@ typedef enum PROCESS_DPI_AWARENESS // HACK: Define macros that some dinput.h variants don't #ifndef DIDFT_OPTIONAL - #define DIDFT_OPTIONAL 0x80000000 +#define DIDFT_OPTIONAL 0x80000000 +#endif + +#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; + BOOL fEnable; + HRGN hRgnBlur; + BOOL fTransitionOnMaximized; +} DWM_BLURBEHIND, *PDWM_BLURBEHIND; #endif // winmm.dll function pointer typedefs @@ -179,9 +194,13 @@ 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); + #define DwmIsCompositionEnabled _glfw.win32.dwmapi.IsCompositionEnabled #define DwmFlush _glfw.win32.dwmapi.Flush +typedef HRESULT(WINAPI * PFN_DwmEnableBlurBehindWindow)(HWND, const DWM_BLURBEHIND*); +#define DwmEnableBlurBehindWindow _glfw.win32.dwmapi.EnableBlurBehindWindow + // shcore.dll function pointer typedefs typedef HRESULT (WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); #define _glfw_SetProcessDpiAwareness _glfw.win32.shcore.SetProcessDpiAwareness @@ -286,6 +305,7 @@ typedef struct _GLFWlibraryWin32 HINSTANCE instance; PFN_DwmIsCompositionEnabled IsCompositionEnabled; PFN_DwmFlush Flush; + PFN_DwmEnableBlurBehindWindow EnableBlurBehindWindow; } dwmapi; struct { diff --git a/src/window.c b/src/window.c index de6fc568e..625e2523b 100644 --- a/src/window.c +++ b/src/window.c @@ -182,6 +182,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, window->monitor = (_GLFWmonitor*) monitor; window->resizable = wndconfig.resizable; window->decorated = wndconfig.decorated; + window->transparent = wndconfig.transparent; window->autoIconify = wndconfig.autoIconify; window->floating = wndconfig.floating; window->transparent = wndconfig.alphaMask; @@ -252,6 +253,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; @@ -735,6 +737,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_AUTO_ICONIFY: diff --git a/src/x11_init.c b/src/x11_init.c index c4e84474f..0597a9162 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -480,7 +480,7 @@ static GLFWbool initExtensions(void) } _glfw.x11.xi.handle = dlopen("libXi.so.6", RTLD_LAZY | RTLD_GLOBAL); - if (_glfw.x11.xi.handle) + if (_glfw.x11.xi.handle) { _glfw.x11.xi.QueryVersion = (PFN_XIQueryVersion) dlsym(_glfw.x11.xi.handle, "XIQueryVersion"); @@ -505,66 +505,72 @@ static GLFWbool initExtensions(void) } } - _glfw.x11.randr.handle = dlopen("libXrandr.so.2", RTLD_LAZY | RTLD_GLOBAL); - if (_glfw.x11.randr.handle) - { - _glfw.x11.randr.AllocGamma = (PFN_XRRAllocGamma) - dlsym(_glfw.x11.randr.handle, "XRRAllocGamma"); - _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma) - dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); - _glfw.x11.randr.FreeCrtcInfo = (PFN_XRRFreeCrtcInfo) - dlsym(_glfw.x11.randr.handle, "XRRFreeCrtcInfo"); - _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma) - dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); - _glfw.x11.randr.FreeOutputInfo = (PFN_XRRFreeOutputInfo) - dlsym(_glfw.x11.randr.handle, "XRRFreeOutputInfo"); - _glfw.x11.randr.FreeScreenResources = (PFN_XRRFreeScreenResources) - dlsym(_glfw.x11.randr.handle, "XRRFreeScreenResources"); - _glfw.x11.randr.GetCrtcGamma = (PFN_XRRGetCrtcGamma) - dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGamma"); - _glfw.x11.randr.GetCrtcGammaSize = (PFN_XRRGetCrtcGammaSize) - dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize"); - _glfw.x11.randr.GetCrtcInfo = (PFN_XRRGetCrtcInfo) - dlsym(_glfw.x11.randr.handle, "XRRGetCrtcInfo"); - _glfw.x11.randr.GetOutputInfo = (PFN_XRRGetOutputInfo) - dlsym(_glfw.x11.randr.handle, "XRRGetOutputInfo"); - _glfw.x11.randr.GetOutputPrimary = (PFN_XRRGetOutputPrimary) - dlsym(_glfw.x11.randr.handle, "XRRGetOutputPrimary"); - _glfw.x11.randr.GetScreenResourcesCurrent = (PFN_XRRGetScreenResourcesCurrent) - dlsym(_glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent"); - _glfw.x11.randr.QueryExtension = (PFN_XRRQueryExtension) - dlsym(_glfw.x11.randr.handle, "XRRQueryExtension"); - _glfw.x11.randr.QueryVersion = (PFN_XRRQueryVersion) - dlsym(_glfw.x11.randr.handle, "XRRQueryVersion"); - _glfw.x11.randr.SelectInput = (PFN_XRRSelectInput) - dlsym(_glfw.x11.randr.handle, "XRRSelectInput"); - _glfw.x11.randr.SetCrtcConfig = (PFN_XRRSetCrtcConfig) - dlsym(_glfw.x11.randr.handle, "XRRSetCrtcConfig"); - _glfw.x11.randr.SetCrtcGamma = (PFN_XRRSetCrtcGamma) - dlsym(_glfw.x11.randr.handle, "XRRSetCrtcGamma"); - _glfw.x11.randr.UpdateConfiguration = (PFN_XRRUpdateConfiguration) - dlsym(_glfw.x11.randr.handle, "XRRUpdateConfiguration"); + // Check for RandR extension + if (XRRQueryExtension(_glfw.x11.display, + &_glfw.x11.randr.eventBase, + &_glfw.x11.randr.errorBase)) { - if (XRRQueryExtension(_glfw.x11.display, - &_glfw.x11.randr.eventBase, - &_glfw.x11.randr.errorBase)) - { - if (XRRQueryVersion(_glfw.x11.display, - &_glfw.x11.randr.major, - &_glfw.x11.randr.minor)) - { - // The GLFW RandR path requires at least version 1.3 - if (_glfw.x11.randr.major > 1 || _glfw.x11.randr.minor >= 3) - _glfw.x11.randr.available = GLFW_TRUE; - } - else - { - _glfwInputError(GLFW_PLATFORM_ERROR, - "X11: Failed to query RandR version"); - } - } - } + _glfw.x11.randr.handle = dlopen("libXrandr.so.2", RTLD_LAZY | RTLD_GLOBAL); + + if (_glfw.x11.randr.handle) + { + _glfw.x11.randr.AllocGamma = (PFN_XRRAllocGamma) + dlsym(_glfw.x11.randr.handle, "XRRAllocGamma"); + _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma) + dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); + _glfw.x11.randr.FreeCrtcInfo = (PFN_XRRFreeCrtcInfo) + dlsym(_glfw.x11.randr.handle, "XRRFreeCrtcInfo"); + _glfw.x11.randr.FreeGamma = (PFN_XRRFreeGamma) + dlsym(_glfw.x11.randr.handle, "XRRFreeGamma"); + _glfw.x11.randr.FreeOutputInfo = (PFN_XRRFreeOutputInfo) + dlsym(_glfw.x11.randr.handle, "XRRFreeOutputInfo"); + _glfw.x11.randr.FreeScreenResources = (PFN_XRRFreeScreenResources) + dlsym(_glfw.x11.randr.handle, "XRRFreeScreenResources"); + _glfw.x11.randr.GetCrtcGamma = (PFN_XRRGetCrtcGamma) + dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGamma"); + _glfw.x11.randr.GetCrtcGammaSize = (PFN_XRRGetCrtcGammaSize) + dlsym(_glfw.x11.randr.handle, "XRRGetCrtcGammaSize"); + _glfw.x11.randr.GetCrtcInfo = (PFN_XRRGetCrtcInfo) + dlsym(_glfw.x11.randr.handle, "XRRGetCrtcInfo"); + _glfw.x11.randr.GetOutputInfo = (PFN_XRRGetOutputInfo) + dlsym(_glfw.x11.randr.handle, "XRRGetOutputInfo"); + _glfw.x11.randr.GetOutputPrimary = (PFN_XRRGetOutputPrimary) + dlsym(_glfw.x11.randr.handle, "XRRGetOutputPrimary"); + _glfw.x11.randr.GetScreenResourcesCurrent = (PFN_XRRGetScreenResourcesCurrent) + dlsym(_glfw.x11.randr.handle, "XRRGetScreenResourcesCurrent"); + _glfw.x11.randr.QueryExtension = (PFN_XRRQueryExtension) + dlsym(_glfw.x11.randr.handle, "XRRQueryExtension"); + _glfw.x11.randr.QueryVersion = (PFN_XRRQueryVersion) + dlsym(_glfw.x11.randr.handle, "XRRQueryVersion"); + _glfw.x11.randr.SelectInput = (PFN_XRRSelectInput) + dlsym(_glfw.x11.randr.handle, "XRRSelectInput"); + _glfw.x11.randr.SetCrtcConfig = (PFN_XRRSetCrtcConfig) + dlsym(_glfw.x11.randr.handle, "XRRSetCrtcConfig"); + _glfw.x11.randr.SetCrtcGamma = (PFN_XRRSetCrtcGamma) + dlsym(_glfw.x11.randr.handle, "XRRSetCrtcGamma"); + _glfw.x11.randr.UpdateConfiguration = (PFN_XRRUpdateConfiguration) + dlsym(_glfw.x11.randr.handle, "XRRUpdateConfiguration"); + if (XRRQueryExtension(_glfw.x11.display, + &_glfw.x11.randr.eventBase, + &_glfw.x11.randr.errorBase)) + { + if (XRRQueryVersion(_glfw.x11.display, + &_glfw.x11.randr.major, + &_glfw.x11.randr.minor)) + { + // The GLFW RandR path requires at least version 1.3 + if (_glfw.x11.randr.major > 1 || _glfw.x11.randr.minor >= 3) + _glfw.x11.randr.available = GLFW_TRUE; + } + else + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "X11: Failed to query RandR version"); + } + } + } + } if (_glfw.x11.randr.available) { XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, @@ -719,6 +725,76 @@ static GLFWbool initExtensions(void) _glfw.x11.MOTIF_WM_HINTS = XInternAtom(_glfw.x11.display, "_MOTIF_WM_HINTS", False); + + 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", + False); + _glfw.x11.WM_STATE = XInternAtom(_glfw.x11.display, "WM_STATE", False); + _glfw.x11.WM_DELETE_WINDOW = XInternAtom(_glfw.x11.display, + "WM_DELETE_WINDOW", + False); + _glfw.x11.MOTIF_WM_HINTS = XInternAtom(_glfw.x11.display, + "_MOTIF_WM_HINTS", + False); + +#if defined(_GLFW_HAS_XF86VM) + // Check for XF86VidMode extension + _glfw.x11.vidmode.available = + XF86VidModeQueryExtension(_glfw.x11.display, + &_glfw.x11.vidmode.eventBase, + &_glfw.x11.vidmode.errorBase); +#endif /*_GLFW_HAS_XF86VM*/ + + // 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. + int i; + 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 48d15bc92..c284932b7 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -162,10 +162,20 @@ 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 +#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 // @@ -374,6 +384,22 @@ 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 // typedef struct _GLFWmonitorX11 diff --git a/src/x11_window.c b/src/x11_window.c index aee89d402..cdc57e736 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -1828,8 +1828,14 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window, if (ctxconfig->client == GLFW_NO_API || ctxconfig->source == GLFW_OSMESA_CONTEXT_API) { - visual = DefaultVisual(_glfw.x11.display, _glfw.x11.screen); - depth = DefaultDepth(_glfw.x11.display, _glfw.x11.screen); + +#if defined(_GLFW_GLX) + if (!_glfwChooseVisualGLX(wndconfig, ctxconfig, fbconfig, &visual, &depth)) + return GLFW_FALSE; +#elif defined(_GLFW_EGL) + if (!_glfwChooseVisualEGL(wndconfig, ctxconfig, fbconfig, &visual, &depth)) + return GLFW_FALSE; +#endif } if (!createNativeWindow(window, wndconfig, visual, depth))