Merge remote-tracking branch 'glfw/transparent-window' into cosier/transparent_windows

This commit is contained in:
Bailey Cosier 2017-09-16 23:40:42 +07:00
commit 6d4708f78a
15 changed files with 469 additions and 94 deletions

1
.gitignore vendored
View File

@ -15,6 +15,7 @@ MinSizeRel
RelWithDebInfo RelWithDebInfo
*.xcodeproj *.xcodeproj
.vs .vs
*.VC.opendb
# CMake files # CMake files
Makefile Makefile

View File

@ -172,6 +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.);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix(); glPushMatrix();
@ -297,7 +298,6 @@ static void init(void)
glEnable(GL_NORMALIZE); glEnable(GL_NORMALIZE);
} }
/* program entry */ /* program entry */
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
@ -311,6 +311,9 @@ 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_DECORATED, GLFW_TRUE);
window = glfwCreateWindow( 300, 300, "Gears", NULL, NULL ); window = glfwCreateWindow( 300, 300, "Gears", NULL, NULL );
if (!window) if (!window)

View File

@ -788,6 +788,7 @@ extern "C" {
*/ */
#define GLFW_CENTER_CURSOR 0x00020009 #define GLFW_CENTER_CURSOR 0x00020009
/*! @brief Framebuffer bit depth hint. /*! @brief Framebuffer bit depth hint.
* *
* Framebuffer bit depth [hint](@ref GLFW_RED_BITS). * Framebuffer bit depth [hint](@ref GLFW_RED_BITS).

View File

@ -87,13 +87,21 @@ 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) EGLConfig* result,
GLFWbool findTransparent)
{ {
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)
{ {
@ -107,6 +115,7 @@ 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];
@ -124,6 +133,28 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
// Only consider EGLConfigs with associated Visuals // Only consider EGLConfigs with associated Visuals
if (!getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID)) if (!getEGLConfigAttrib(n, EGL_NATIVE_VISUAL_ID))
continue; 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 #endif // _GLFW_X11
if (ctxconfig->client == GLFW_OPENGL_ES_API) if (ctxconfig->client == GLFW_OPENGL_ES_API)
@ -159,6 +190,12 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
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)
@ -455,7 +492,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)) if (!chooseEGLConfig(ctxconfig, fbconfig, &config, fbconfig->alphaMask))
{ {
_glfwInputError(GLFW_FORMAT_UNAVAILABLE, _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"EGL: Failed to find a suitable EGLConfig"); "EGL: Failed to find a suitable EGLConfig");
@ -689,7 +726,8 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
// Returns the Visual and depth of the chosen EGLConfig // Returns the Visual and depth of the chosen EGLConfig
// //
#if defined(_GLFW_X11) #if defined(_GLFW_X11)
GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig, GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig, const _GLFWfbconfig* fbconfig,
Visual** visual, int* depth) Visual** visual, int* depth)
{ {
@ -699,7 +737,8 @@ GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig,
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))
if (!chooseEGLConfig(ctxconfig, fbconfig, &native, wndconfig->alphaMask))
{ {
_glfwInputError(GLFW_FORMAT_UNAVAILABLE, _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"EGL: Failed to find a suitable EGLConfig"); "EGL: Failed to find a suitable EGLConfig");

View File

@ -211,7 +211,8 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig, const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig); const _GLFWfbconfig* fbconfig);
#if defined(_GLFW_X11) #if defined(_GLFW_X11)
GLFWbool _glfwChooseVisualEGL(const _GLFWctxconfig* ctxconfig, GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig, const _GLFWfbconfig* fbconfig,
Visual** visual, int* depth); Visual** visual, int* depth);
#endif /*_GLFW_X11*/ #endif /*_GLFW_X11*/

View File

@ -47,7 +47,11 @@ 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) static GLFWbool chooseGLXFBConfig(
const _GLFWfbconfig* desired,
GLXFBConfig* result,
GLFWbool findTransparent)
{ {
GLXFBConfig* nativeConfigs; GLXFBConfig* nativeConfigs;
_GLFWfbconfig* usableConfigs; _GLFWfbconfig* usableConfigs;
@ -55,8 +59,10 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* res
int i, nativeCount, usableCount; int i, nativeCount, usableCount;
const char* vendor; const char* vendor;
GLFWbool trustWindowBit = GLFW_TRUE; 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 // 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
@ -76,6 +82,7 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* res
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];
@ -92,13 +99,30 @@ static GLFWbool chooseGLXFBConfig(const _GLFWfbconfig* desired, GLXFBConfig* res
continue; continue;
} }
visual = glXGetVisualFromFBConfig(_glfw.x11.display, n); if( findTransparent ) {
pict_format = XRenderFindVisualFormat(_glfw.x11.display, visual->visual); XVisualInfo *visualinfo;
u->alphaMask = pict_format->direct.alphaMask > 0; XRenderPictFormat *pictFormat;
u->redBits = getGLXFBConfigAttrib(n, GLX_RED_SIZE); visualinfo = glXGetVisualFromFBConfig(_glfw.x11.display, n);
u->greenBits = getGLXFBConfigAttrib(n, GLX_GREEN_SIZE); if (!visualinfo)
u->blueBits = getGLXFBConfigAttrib(n, GLX_BLUE_SIZE); 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->alphaBits = getGLXFBConfigAttrib(n, GLX_ALPHA_SIZE);
u->depthBits = getGLXFBConfigAttrib(n, GLX_DEPTH_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; 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)
@ -249,7 +279,7 @@ static void destroyContextGLX(_GLFWwindow* window)
GLFWbool _glfwInitGLX(void) GLFWbool _glfwInitGLX(void)
{ {
int i; int i;
const char* sonames[] = const char* sonames_glx[] =
{ {
#if defined(_GLFW_GLX_LIBRARY) #if defined(_GLFW_GLX_LIBRARY)
_GLFW_GLX_LIBRARY, _GLFW_GLX_LIBRARY,
@ -265,9 +295,9 @@ GLFWbool _glfwInitGLX(void)
if (_glfw.glx.handle) if (_glfw.glx.handle)
return GLFW_TRUE; 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) if (_glfw.glx.handle)
break; break;
} }
@ -449,7 +479,8 @@ 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)) if (!chooseGLXFBConfig(fbconfig, &native, window->transparent))
{ {
_glfwInputError(GLFW_FORMAT_UNAVAILABLE, _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"GLX: Failed to find a suitable GLXFBConfig"); "GLX: Failed to find a suitable GLXFBConfig");
@ -629,14 +660,15 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
// Returns the Visual and depth of the chosen GLXFBConfig // 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, const _GLFWfbconfig* fbconfig,
Visual** visual, int* depth) Visual** visual, int* depth)
{ {
GLXFBConfig native; GLXFBConfig native;
XVisualInfo* result; XVisualInfo* result;
if (!chooseGLXFBConfig(fbconfig, &native)) if (!chooseGLXFBConfig(fbconfig, &native, wndconfig->transparent))
{ {
_glfwInputError(GLFW_FORMAT_UNAVAILABLE, _glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"GLX: Failed to find a suitable GLXFBConfig"); "GLX: Failed to find a suitable GLXFBConfig");

View File

@ -72,6 +72,7 @@ typedef struct __GLXFBConfig* GLXFBConfig;
typedef struct __GLXcontext* GLXContext; typedef struct __GLXcontext* GLXContext;
typedef void (*__GLXextproc)(void); typedef void (*__GLXextproc)(void);
// libGL.so function pointer typedefs
typedef int (*PFNGLXGETFBCONFIGATTRIBPROC)(Display*,GLXFBConfig,int,int*); typedef int (*PFNGLXGETFBCONFIGATTRIBPROC)(Display*,GLXFBConfig,int,int*);
typedef const char* (*PFNGLXGETCLIENTSTRINGPROC)(Display*,int); typedef const char* (*PFNGLXGETCLIENTSTRINGPROC)(Display*,int);
typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display*,int*,int*); typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display*,int*,int*);
@ -92,7 +93,6 @@ typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int);
typedef int (*PFNGLXSWAPINTERVALSGIPROC)(int); typedef int (*PFNGLXSWAPINTERVALSGIPROC)(int);
typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLXContext,Bool,const int*); typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLXContext,Bool,const int*);
// libGL.so function pointer typedefs
#define glXGetFBConfigs _glfw.glx.GetFBConfigs #define glXGetFBConfigs _glfw.glx.GetFBConfigs
#define glXGetFBConfigAttrib _glfw.glx.GetFBConfigAttrib #define glXGetFBConfigAttrib _glfw.glx.GetFBConfigAttrib
#define glXGetClientString _glfw.glx.GetClientString #define glXGetClientString _glfw.glx.GetClientString
@ -168,14 +168,14 @@ typedef struct _GLFWlibraryGLX
} _GLFWlibraryGLX; } _GLFWlibraryGLX;
GLFWbool _glfwInitGLX(void); GLFWbool _glfwInitGLX(void);
void _glfwTerminateGLX(void); void _glfwTerminateGLX(void);
GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig, const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig); const _GLFWfbconfig* fbconfig);
void _glfwDestroyContextGLX(_GLFWwindow* window); void _glfwDestroyContextGLX(_GLFWwindow* window);
GLFWbool _glfwChooseVisualGLX(const _GLFWctxconfig* ctxconfig, GLFWbool _glfwChooseVisualGLX(const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig, const _GLFWfbconfig* fbconfig,
Visual** visual, int* depth); Visual** visual, int* depth);

View File

@ -299,6 +299,7 @@ struct _GLFWwndconfig
GLFWbool resizable; GLFWbool resizable;
GLFWbool visible; GLFWbool visible;
GLFWbool decorated; GLFWbool decorated;
GLFWbool transparent;
GLFWbool focused; GLFWbool focused;
GLFWbool autoIconify; GLFWbool autoIconify;
GLFWbool floating; GLFWbool floating;
@ -404,6 +405,7 @@ struct _GLFWwindow
// Window settings and state // Window settings and state
GLFWbool resizable; GLFWbool resizable;
GLFWbool decorated; GLFWbool decorated;
GLFWbool transparent;
GLFWbool autoIconify; GLFWbool autoIconify;
GLFWbool floating; GLFWbool floating;
GLFWbool shouldClose; GLFWbool shouldClose;

View File

@ -83,6 +83,20 @@ 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 (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) if (_glfw.wgl.ARB_pixel_format)
{ {
@ -152,11 +166,9 @@ static int choosePixelFormat(_GLFWwindow* window,
} }
else else
{ {
PIXELFORMATDESCRIPTOR pfd;
// Get pixel format attributes through legacy PFDs // Get pixel format attributes through legacy PFDs
if (!DescribePixelFormat(window->context.wgl.dc, if (!window->transparent && !DescribePixelFormat(window->context.wgl.dc,
n, n,
sizeof(PIXELFORMATDESCRIPTOR), sizeof(PIXELFORMATDESCRIPTOR),
&pfd)) &pfd))
@ -205,6 +217,15 @@ static int choosePixelFormat(_GLFWwindow* window,
u->alphaMask = 1; u->alphaMask = 1;
usableCount++; 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) if (!usableCount)
{ {
@ -486,6 +507,101 @@ void _glfwTerminateWGL(void)
attribs[index++] = v; \ 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 // Create the OpenGL or OpenGL ES context
// //
GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
@ -667,7 +783,53 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
ctxconfig->minor); 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, _glfwInputError(GLFW_VERSION_UNAVAILABLE,
"WGL: Driver does not support the requested OpenGL profile"); "WGL: Driver does not support the requested OpenGL profile");

View File

@ -128,6 +128,8 @@ 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.EnableBlurBehindWindow = (PFN_DwmEnableBlurBehindWindow)
GetProcAddress(_glfw.win32.dwmapi.instance, "DwmEnableBlurBehindWindow");
} }
_glfw.win32.shcore.instance = LoadLibraryA("shcore.dll"); _glfw.win32.shcore.instance = LoadLibraryA("shcore.dll");

View File

@ -153,7 +153,22 @@ typedef enum PROCESS_DPI_AWARENESS
// HACK: Define macros that some dinput.h variants don't // HACK: Define macros that some dinput.h variants don't
#ifndef DIDFT_OPTIONAL #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 #endif
// winmm.dll function pointer typedefs // winmm.dll function pointer typedefs
@ -179,9 +194,13 @@ 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);
#define DwmIsCompositionEnabled _glfw.win32.dwmapi.IsCompositionEnabled #define DwmIsCompositionEnabled _glfw.win32.dwmapi.IsCompositionEnabled
#define DwmFlush _glfw.win32.dwmapi.Flush #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 // shcore.dll function pointer typedefs
typedef HRESULT (WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); typedef HRESULT (WINAPI * PFN_SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS);
#define _glfw_SetProcessDpiAwareness _glfw.win32.shcore.SetProcessDpiAwareness #define _glfw_SetProcessDpiAwareness _glfw.win32.shcore.SetProcessDpiAwareness
@ -286,6 +305,7 @@ typedef struct _GLFWlibraryWin32
HINSTANCE instance; HINSTANCE instance;
PFN_DwmIsCompositionEnabled IsCompositionEnabled; PFN_DwmIsCompositionEnabled IsCompositionEnabled;
PFN_DwmFlush Flush; PFN_DwmFlush Flush;
PFN_DwmEnableBlurBehindWindow EnableBlurBehindWindow;
} dwmapi; } dwmapi;
struct { struct {

View File

@ -182,6 +182,7 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
window->monitor = (_GLFWmonitor*) monitor; window->monitor = (_GLFWmonitor*) monitor;
window->resizable = wndconfig.resizable; window->resizable = wndconfig.resizable;
window->decorated = wndconfig.decorated; window->decorated = wndconfig.decorated;
window->transparent = wndconfig.transparent;
window->autoIconify = wndconfig.autoIconify; window->autoIconify = wndconfig.autoIconify;
window->floating = wndconfig.floating; window->floating = wndconfig.floating;
window->transparent = wndconfig.alphaMask; window->transparent = wndconfig.alphaMask;
@ -252,6 +253,7 @@ void glfwDefaultWindowHints(void)
_glfw.hints.window.resizable = GLFW_TRUE; _glfw.hints.window.resizable = GLFW_TRUE;
_glfw.hints.window.visible = GLFW_TRUE; _glfw.hints.window.visible = GLFW_TRUE;
_glfw.hints.window.decorated = GLFW_TRUE; _glfw.hints.window.decorated = GLFW_TRUE;
_glfw.hints.window.transparent = GLFW_FALSE;
_glfw.hints.window.focused = GLFW_TRUE; _glfw.hints.window.focused = GLFW_TRUE;
_glfw.hints.window.autoIconify = GLFW_TRUE; _glfw.hints.window.autoIconify = GLFW_TRUE;
@ -735,6 +737,8 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib)
return window->resizable; return window->resizable;
case GLFW_DECORATED: case GLFW_DECORATED:
return window->decorated; return window->decorated;
case GLFW_TRANSPARENT:
return window->transparent;
case GLFW_FLOATING: case GLFW_FLOATING:
return window->floating; return window->floating;
case GLFW_AUTO_ICONIFY: case GLFW_AUTO_ICONIFY:

View File

@ -505,7 +505,13 @@ static GLFWbool initExtensions(void)
} }
} }
// Check for RandR extension
if (XRRQueryExtension(_glfw.x11.display,
&_glfw.x11.randr.eventBase,
&_glfw.x11.randr.errorBase)) {
_glfw.x11.randr.handle = dlopen("libXrandr.so.2", RTLD_LAZY | RTLD_GLOBAL); _glfw.x11.randr.handle = dlopen("libXrandr.so.2", RTLD_LAZY | RTLD_GLOBAL);
if (_glfw.x11.randr.handle) if (_glfw.x11.randr.handle)
{ {
_glfw.x11.randr.AllocGamma = (PFN_XRRAllocGamma) _glfw.x11.randr.AllocGamma = (PFN_XRRAllocGamma)
@ -564,7 +570,7 @@ static GLFWbool initExtensions(void)
} }
} }
} }
}
if (_glfw.x11.randr.available) if (_glfw.x11.randr.available)
{ {
XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display, XRRScreenResources* sr = XRRGetScreenResourcesCurrent(_glfw.x11.display,
@ -719,6 +725,76 @@ 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);
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; return GLFW_TRUE;
} }

View File

@ -162,10 +162,20 @@ 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 #define _GLFW_PLATFORM_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11 ; _GLFWlibraryXrender xrender
#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
// //
@ -374,6 +384,22 @@ typedef struct _GLFWlibraryX11
} _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 // X11-specific per-monitor data
// //
typedef struct _GLFWmonitorX11 typedef struct _GLFWmonitorX11

View File

@ -1828,8 +1828,14 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
if (ctxconfig->client == GLFW_NO_API || if (ctxconfig->client == GLFW_NO_API ||
ctxconfig->source == GLFW_OSMESA_CONTEXT_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)) if (!createNativeWindow(window, wndconfig, visual, depth))