GNOME Bugzilla – Bug 727316
W32: GDK does not support per-pixel alpha-blended windows
Last modified: 2015-04-29 21:14:48 UTC
Because of this, drawing shadows around windows with CSDs does not work (windows end up with a thick black border instead of a shadow).
Created attachment 273252 [details] [review] Adds RGBA support to W32 GDK backend This patch is broken. Pixman will crash the process if GTK asks for padding of box-shadow for a GtkWindow, which is what happens when you do things like this: .window-frame { box-shadow: 0 2px 7px 3px alpha(black, 0.8); } Removing the cairo_win32_surface_create_with_alpha part of the patch (using normal cairo_win32_surface_create) removes the crash, but color/alpha interpretation gets really weird (most noticeable on popup menu items).
Created attachment 273253 [details] [review] Adds cairo_win32_surface_create_with_alpha() function to cairo
A backtrace of a pixman crash looks along these lines (pixman specifically compiled without SSE and MMX for debugging purposes, hence fast_composite_src_memcpy):
+ Trace 233412
Line 1178 is: memcpy (dst, src, n_bytes); The access violation comes from the attempt to access values in src. In one particular crash i've had n_bytes=3912, but src[x] gives access violation for x > 1891.
Crash also goes away if i increase window frame margins considerably. This works: .window-frame { box-shadow: 0px 2px 7px 0px alpha(black, 0.8); margin: 18px; } This doesn't: .window-frame { box-shadow: 0px 2px 7px 0px alpha(black, 0.8); margin: 17px; } Since margins influences the size of window frame border, input-wise (i.e. it defines, among other things, the size of the area where window can be gripped for resizing), simply increasing it is not a valid workaround, AFAIC.
Created attachment 273262 [details] How shadows look This image is an incentive: this is what you can get with ARGB windows - sexy shadows for CSD windows (you can also get true widget transparency, but that is not very useful, while shadows are pretty much a necessity for CSD). Also note the size of the image. It was taken by a simple Alt+PrintScreen, i.e. this is the size of the actual native W32 window. It's so big because margins is 18.
Poked around a bit. It looks like by default cairo decides to use pixman for graphics manipulations, instead of W32 API. And pixman somehow fails to notice that it is going to blit over the edge of a surface, which leads to a crash. Forcing cairo to use W32 API doesn't work - i get the same weird alpha problems that i've had originally.
Review of attachment 273252 [details] [review]: See comments. ::: gdk/win32/gdkwindow-win32.c @@ +705,3 @@ + + if (dwmEnableBlurBehindWindow) + { wrong indentation here. you are missing 2 spaces @@ +712,3 @@ + hRgn = CreateRectRgn (0, 0, -1, -1); + if (hRgn != NULL) + { same here
Created attachment 273664 [details] [review] W32: RGBA GDK backend (requires a patched version cairo)
Created attachment 273681 [details] [review] Misc cairo changes to make it accept RGBA formats These may or may not have any effect on GTK. I have no idea.
Created attachment 273682 [details] [review] A patch from cairo bug 53121, fixes crashes This patch, on the other hand, is critical to fixing crashes with RGBA windows. Taken from https://bugs.freedesktop.org/show_bug.cgi?id=53121
Created attachment 273683 [details] [review] W32: Add a basic set of CSD styles Adds CSD styles. Goes along with RGBA windows (without it you can't see any improvements). I'd very much like to make a better-looking style for the titlebar, and maybe for window border, and definitely for the titlebar buttons, but this will suffice for now.
Another thing is to make sure it doesn't go ugly when (A) no 32-bit color is set in the system, (B) DWM does not support composition (or composition is disabled). Right now, as i'm VNCing to my desktop, composition gets nuked, and window shadows once again look like thick black borders around CSDed windows. Is there a switch in GTK that enables/disables RGBA on the fly depending on the circumstances?
Well. I've always wondered why GTK CSD windows have resize-grip-areas outside of the window, where shadow is. gtkwindow.c comments cleared that up - this is intentional. Basically, GTK maintains an extra outside-of-the-window shape region that is used both for drawing a shadow and for resizing. This, by itself, is un-windowsly (normally, Windows windows have a window frame that can be gripped to resize the window; shadow is completely decorative and non-interactable, and doesn't count as part of the window as far as WM is concetned), but i'll let that slide. The really bad consequence of this is that when desktop composition is disabled, that area outside of the window remains in use, and gtk paints it over with its default black cairo color (it's supposed to be transparent, but no composition means no transparency). Removing that region in response to a loss of composition ability is not an option, since it also prevents windows from being re-sized, because the same region is used for re-sizing. So, yeah... One way to tackle this is to draw *something* in that region when transparency is not available. This will be ugly-ish, but not as ugly as a thick black box around a window. The other way is to create a new GTK thingy - "is-composition-available" (or somesuch), and report availability of composition to GTK that way. If unavailable, GTK will be able to do something (such as forcing a window to not to use CSD). I've tried doing this purely in GDK, it doesn't work (when GTK tells GDK to remove decorations, it expects the whole window to be fair game; having GDK preserve WS_BORDER style on the window has no useful effect, as GTK just draws over it).
(In reply to comment #13) > The other way is to create a new GTK thingy - "is-composition-available" (or > somesuch), and report availability of composition to GTK that way. If > unavailable, GTK will be able to do something (such as forcing a window to not > to use CSD). See gdk_screen_is_composited(). We actally check it when deciding whether to use CSD or not. I don't think we deal well with runtime changes at the moment, though.
(In reply to comment #14) > (In reply to comment #13) > > > The other way is to create a new GTK thingy - "is-composition-available" (or > > somesuch), and report availability of composition to GTK that way. If > > unavailable, GTK will be able to do something (such as forcing a window to not > > to use CSD). > > See gdk_screen_is_composited(). We actally check it when deciding whether to > use CSD or not. I don't think we deal well with runtime changes at the moment, > though. gdk_win32_screen_is_composited() is already implemented by W32 GDK backend. It returns FALSE. This somehow does not prevent CSDs from being used. OK, let's suppose that we will somehow fix the decision to use/not use CSDs depending on composition availability. This will make sure *new* windows will be decorated when composition is disabled. Lack of options for existing windows is kind of bad though. For example, both VNC and RDP (ssvnc client, UltraVNC server; xfreerdp client, stock MS RDP server) connections don't have composition, and managing a desktop with those will switch composition off. This isn't the first time, i see things like that, by the way. Changing W32 themes doesn't work either (-gtk-win32-theme-part() breaks on W32 theme changes). Will GTK get support for runtime adjustments eventually? If not, then these will just go into "known bugs category".
After looking at gtkwindow.c i now know why gdk_win32_screen_is_composited() has no effect. That is fixable, i'm working on a patch. What is more interesting to me is the ability to switch client decorations on and off for already realized windows. I'll poke the code a bit more.
Created attachment 273962 [details] [review] W32: Implement composition check for GDK Also move DWM function grabbing and make those functions available to all of GDK-Win32.
Attachment 273962 [details] implements composition check in GDK and makes sure GTK actually makes use of the gdk_screen_is_composited() function. This rolls W32 back to the state described in bug 726592: when desktop composition is not enabled, newly-created windows will not have shadows. Which means that they have no size grip (except for the optional corner grip), their rounded corners look ugly (because background is still rectangular), they blend into background because they lack shadows. And this only applies to new windows. Existing windows will just get thick black border around them, where shadow used to be.
Review of attachment 273962 [details] [review]: Here a first review. ::: gdk/win32/gdkscreen-win32.c @@ +178,3 @@ +} + + remove uneeded empty line @@ +189,3 @@ + /* Composition is always enabled in W8 */ + if (major >= 6 && minor >= 2) + { no need for {} in single line block @@ +192,3 @@ + return TRUE; + } + if (dwmIsCompositionEnabled && (S_OK == dwmIsCompositionEnabled (&b))) leave one empty line between different ifs @@ +193,3 @@ + } + if (dwmIsCompositionEnabled && (S_OK == dwmIsCompositionEnabled (&b))) + { same here
Created attachment 273963 [details] [review] W32: Implement composition check for GDK (v2) Also move DWM function grabbing and make those functions available to all of GDK-Win32. v2: Fixed code style
So, about the bug 726592 problem for non-composited windows, i see two ways of fixing this: (A) a non-composited version of the CSD (no shadows, just a solid/image border) (B) Somehow coerce GDK into enabling WM's own border for non-composited windows that are set to use CSDs. This looks in no way perfect, but at least it fits (or supposed to fit) half-way into native theme, and gives user something to resize the window with. WS_SIZEBOX style looks mighty decent on a dummy test W32 app that i've made; I've had some success in replicating this to GDK, but the result doesn't look the way i expected it to, and there's a problem in differentiating appwindows from popups and tooltips. Interesting fact: even with composition disabled, native W32 tooltips still have rounded corners and a shadow; MS probably uses 100%-layered windows for this; GDK could use that as well, but the drawing model is completely different, and it will have to be switched on and off depending on whether CSDs are enabled or disabled.
And the final nitpick is that rounded window corners should be eliminated for toplevels when there's no composition. Because it inherently requires transparent windows. Not sure how to do that; expose non-composited state to CSS (and have a separate style for non-composited windows), or do it in code? What about themes that draw titlebar background/border from images? Only css that invokes an image in the first place knows whether it has rounded corners or not. Also, another fact: GTK tooltips (with background drawn by -gtk-win32-theme-part) also retain their rounded corners when composition is disabled (although the corners are visibly not as smooth as when composition is enabled; also, top-right and bottom-right corners may initially appear to be black, until mouse is moved a bit).
IRC conversations with GTK+ devs (namely - Company) left me with this statement: GKT+-3.x is aimed at desktops that support composition. If they don't, it's ok for GTK+-3.x to look ugly. Which led to a question: just how often is composition off on Windows? Some people (including myself) readily pointed out that VNCing and RDPing into W7 desktop switches composition off. After googling a bit and doing some tests i've found that only RDP servers in server editions of W7 (and W2008) support desktop composition (and even then you need to actively enable it via policy or by editing the registry). With VNC things are a bit better: UltraVNC does not disable composition in W7, unless mirror driver is being used. W8, on the other hand, has desktop composition enabled all the time, and my tests confirm that neither VNC nor RDP connecting to a W8 desktop have any effect on composition (but then, W8 has neither window shadows nor transparent window frames, so the difference is difficult to see; taskbar is transparent though). So, apart from the problem with non-server versions of Windows and RDP, composition on W7 is pretty much a given, and on W8 is guaranteed. To that end i take back the requirement for GTK+ to do anything on composition on/off switching.
Created attachment 274579 [details] [review] W32: Implement composition check for GDK Also move DWM function grabbing and make those functions available to all of GDK-Win32. v2: Fixed code style v3: Added a missing part of the patch (where stuff from attachment 273664 [details] [review] is partially removed)
Review of attachment 274579 [details] [review]: this patch look to me, but it depends on making rgba actually work (ie the other patches in this bug), since the docs say: * Returns whether windows with an RGBA visual can reasonably * be expected to have their alpha channel drawn correctly on * the screen.
Review of attachment 273683 [details] [review]: ok
A small correction for comment 23: RDPing into a W8 desktop (non-server OS) does not disable desktop composition, but it does induce some kind of mode switch that breaks the rendering of existing GDK windows the same way disabling composition does. So there is some room for W32-GDK improvement. Anyway, things are now blocked on cairo being fixed, and that is not going very well: cairo devs point out that existing workaround is, in fact, a workaround, not a fix, but at the same time i can't fix cairo myself properly, and cairo doesn't seem to have a living-and-breathing w32 maintainer either.
Might it be possible to revert the previous behaviour for Windows until this is fixed?
With cairo 1.14.0 things improved somewhat: the bug that caused it to crash with transparent windows *seems* to be fixed (i've done limited testing so far; can't be sure until i do a clean rebuild). It still needs patches for RGBA windows to be enabled (i.e. the cairo_win32_surface_create_with_alpha() at the very least, or its equivalent), but these should be much less controversial than the patch from https://bugs.freedesktop.org/show_bug.cgi?id=53121 .
Hi, Just wondering, since we also want to check for whether we have composition for the GdkScreen when we do OpenGL, can we try to get the composition stuff into GDK-Win32, and make that as a prerequisite of this instead? I will open another bug for this[1], or we can re-use parts of LRN's work for this, depending on whether it is preferable that way. With blessings, thank you! [1]: Bug 741849
Created attachment 301594 [details] [review] Enable RGBA windows on W32 \o/ cairo devs finally accepted my patch - http://cgit.freedesktop.org/cairo/commit/?id=16898ba11b4d6e9e2e64bb2d02d0fb5adbe266e2 This new patch combines rgba window creation, composition check, dwm stuff and the no-transparency-for-childwindows fixup. Also obsoleting old cairo patches that no longer apply.
Yay! Great to hear this!
Review of attachment 301594 [details] [review]: See comments. ::: gdk/win32/gdkscreen-win32.c @@ +199,3 @@ + BOOL enabled; +#endif + DWORD sysver, major, minor; I think fan added a method in glib for the version stuff, since afaik GetVersion is deprecated? ::: gdk/win32/gdkwindow-win32.c @@ +706,3 @@ + */ +#ifdef HAVE_W32_DWM + if (suitable_for_alpha && \ why the \? that is not needed @@ +3390,3 @@ return NULL; + impl->cairo_surface = just put it in one line
Review of attachment 301594 [details] [review]: Hi, The function in GLib to check the version stuff is g_win32_check_windows_version(), which also handles post Windows 8.1 fine, since GetVersion()/GetVersionEx() is deprecated by Microsoft. I think, as I mentioned in bug 741849, I think it's time that we just start to forget about having the code run on Windows XP, as AFAIK we are dropping XP support in this dev cycle, and Emmanuele is getting GSK in, which depends on his graphene library, which does not run on XP. With blessings.
Created attachment 301766 [details] [review] Enable RGBA windows on W32 Rebased on top of patches from bug 741849 Requires Vista and newer (same as bug 741849). Requires cairo-1.14.4 (or 1.14.3 past 2015-04-14). I found no way to make this requirement variable and require 1.14.4 only on W32.
Review of attachment 301766 [details] [review]: Patch looks good to me. See the nitpick. If fan or mclasen give the ack I'd say go for it. ::: gdk/win32/gdkwindow-win32.c @@ +716,3 @@ + { + g_warning ("%s: %s failed: %" G_GINT32_MODIFIER "x", + G_STRLOC, "DwmEnableBlurBehindWindow", (guint32) call_result); align this and no need for the {} in single calls
Review of attachment 301766 [details] [review]: ::: gdk/win32/gdkscreen-win32.c @@ +238,3 @@ screen_class->get_monitor_workarea = gdk_win32_screen_get_monitor_geometry; screen_class->get_system_visual = _gdk_win32_screen_get_system_visual; + screen_class->get_rgba_visual = _gdk_win32_screen_get_system_visual; I'm not sure this is quite right. I think you want two different visuals. One with alpha and one without. That way you know if the app explicitly chose alpha or not.
Created attachment 301812 [details] RGBA Window in Action on Windows Hi LRN, I checked the build in both x64 (the css basics with the text in red (2008) and purple (2013)) and x86 (the css basics with the text in brown), going into checking how things go. Generally I think things look good (especially if the css basic image is like what you intended it to be). Thanks very much for venturing into this, and this also gets the GtkGLArea support on Windows more feature-complete. With blessings.
Created attachment 301835 [details] [review] Enable RGBA windows on W32 * Added a separate rgba visual. * Fixed an assertion that checks for visuals to pass with the rgba visual * Modified the configure cairo check. Now it again checks for 1.14.0, but then goes on to make a special followup check on W32, looking for cairo_win32_surface_create_with_format() and failing if it's absent.
Created attachment 301842 [details] [review] Enable RGBA windows on W32 *Fixed nitpicks
Created attachment 302176 [details] [review] Enable RGBA windows on W32 * Create surfaces with cairo_win32_surface_create_with_format * Provide an rgba visual that can be distinguished from the system visual * Make rgba visual the best available visual * Check for composition support before enabling CSDs * Enable alpha-transparency for all windows that we control * Check for appropriate cairo capabilities at configure time (W32 - 1.14.3 newer than 2015-04-14; others - 1.14.0) Requires Vista and newer.
Review of attachment 302176 [details] [review]: ::: gdk/win32/gdkwindow-win32.c @@ +3378,3 @@ return NULL; + impl->cairo_surface = cairo_win32_surface_create_with_format (hdc, CAIRO_FORMAT_ARGB32); I think this should be RGB24 if the visual is not the rgba visual, no? ::: gtk/gtkwindow.c @@ +3981,3 @@ + if (!gdk_screen_is_composited (screen)) + return FALSE; Is the screen ever composited on win32?
(In reply to Alexander Larsson from comment #42) > Review of attachment 302176 [details] [review] [review]: > > ::: gdk/win32/gdkwindow-win32.c > @@ +3378,3 @@ > return NULL; > > + impl->cairo_surface = cairo_win32_surface_create_with_format (hdc, > CAIRO_FORMAT_ARGB32); > > I think this should be RGB24 if the visual is not the rgba visual, no? Depends on what cairo thinks ARGB32 is. If it's just an A channel attached to RGB channels, we have nothing to worry about. GDI will just ignore or garble the A channel and use RGB. If it's some kind of pre-multiplied alpha, then parts that cairo thought were to be transparent are going to be just...pale... Yep, looked it up - cairo uses pre-multiplied alpha. Nice. OK, i'll look into it. > > ::: gtk/gtkwindow.c > @@ +3981,3 @@ > > + if (!gdk_screen_is_composited (screen)) > + return FALSE; > > Is the screen ever composited on win32? Yes. Wait, you haven't read the comments on this bug or bug 741849 ?
Problem: alpha window (from testgtk) has b0rked contents on 8.1 (but looks OK on 7). However, forcing alpha window to use CSDs magically solves the problem. Still investigating the cause. Some good news: i think i can make transparent windows become transparent again after composition was disabled and re-enabled for some reason. This requires handling WM_DWMCOMPOSITIONCHANGED message by re-enabling blurbehind for a window.
Some person on stackoverflow says that blurbehind does not, in fact, blur anything anymore in 8, and that the only way to draw transparent windows the "usual" way now is to properly use layered windows. Great. I also found a weird blogpost[1] about drawing windows without using a redirection surface. AFAIU, this is 100% DirectX-based. I'll try to dig the layered windows angle a bit more. [1] https://msdn.microsoft.com/en-us/magazine/dn745861.aspx
thanks for the continued investigation!
Hi, (In reply to LRN from comment #46) > Some person on stackoverflow says that blurbehind does not, in fact, blur > anything anymore in 8, I think the reason behind this is that Aero Glass has been removed on Windows 8, plus this functionality is not available on the Starter and Home Basic Editions of Windows Vista/7.[a] > and that the only way to draw transparent windows the > "usual" way now is to properly use layered windows. Great. > I also found a weird blogpost[1] about drawing windows without using a > redirection surface. AFAIU, this is 100% DirectX-based. > > I'll try to dig the layered windows angle a bit more. Perhaps, I think for now, is to get this item in with a TODO note indicating that this need to be further investigated for Windows 8.x, which would mean another bug for that. I'm not sure how many people use Vista (or 7) Starter or Home Basic with GTK+-3.x, but most likely tackling Windows 8.x will also tackle the more entry-level editions of Windows. [a]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa969537%28v=vs.85%29.aspx With blessings, thanks!
Hi LRN, Would this code project page help you for Windows 8+? http://www.codeproject.com/Articles/705243/HUD-window-bit-DWM-composition With blessings!
(In reply to Fan, Chun-wei from comment #49) > Would this code project page help you for Windows 8+? > > http://www.codeproject.com/Articles/705243/HUD-window-bit-DWM-composition > Codeproject programs should be handled with care, as they are non-free (CPOL license). I don't know whether that applies to the source code only or to the contents of the associated blogpost as well. (In reply to Fan, Chun-wei from comment #48) > Hi, > > (In reply to LRN from comment #46) > > Some person on stackoverflow says that blurbehind does not, in fact, blur > > anything anymore in 8, > > I think the reason behind this is that Aero Glass has been removed on > Windows 8, plus this functionality is not available on the Starter and Home > Basic Editions of Windows Vista/7.[a] Could be. However, Windows 8 still does support transparent windows (taskbar is transparent in Windows 8, for example). Maybe they just use a different rendering mechanism... Also, CSDed GTK windows are rendered just fine on Windows 8, only the gtktest alphawindow (which is the first and the one only of its kind that i've ever seen - a GTK window that has WM decorations *and* transparent contents) has problems. I still haven't figured why. My attempts to reproduce this in a simple non-GTK testcase were unsuccessful. > > > and that the only way to draw transparent windows the > > "usual" way now is to properly use layered windows. Great. > > I also found a weird blogpost[1] about drawing windows without using a > > redirection surface. AFAIU, this is 100% DirectX-based. > > > > I'll try to dig the layered windows angle a bit more. > > Perhaps, I think for now, is to get this item in with a TODO note indicating > that this need to be further investigated for Windows 8.x, which would mean > another bug for that. I'm not sure how many people use Vista (or 7) Starter > or Home Basic with GTK+-3.x, but most likely tackling Windows 8.x will also > tackle the more entry-level editions of Windows. > I'd say we need to figure out just how many GTK apps do transparent client area with WM decorations. If gtktest alphawindow is the only one, then fixing this is not a priority, and we can just put this into a list of known bugs for now. Change of the rendering process (from WM_PAINT to UpdateLayeredWindow) is long overdue, but can be done in a new bug. Bug 272316 is for "fix transparency with the tools at hand", not the "rewrite gdk-w32 rendering system".
LRN: gtk devs. Question: how many apps actually use transparent contents (where desktop or other windows can be seen through)? LRN: Followup: how many of these apps do that without also enabling CSD? mclasen: LRN: only gnome-terminal, with a downstream patch LRN: mclasen, in that case we'll push bug 727316 as-is (well, i have an unrelated followup, but that doesn't matter) and make the remaining W8 problems into a KnownBug nacho: LRN, so for 8+ csd will not work? LRN: nacho, CSD will work, transparent windows without CSD won't nacho: ah! ok nacho: I guess that's fine mclasen: LRN: sounds good to me
Hello LRN, (In reply to LRN from comment #51) > nacho: I guess that's fine > mclasen: LRN: sounds good to me Sounds good to me as well-especially that not so many people use Windows 8+, relatively speaking. With blessings. p.s. The CodeProject part, it was more on the blog for future references (I don't think CPOL would hit that part that much, though). Sorry for my not-too-clear wording.
Created attachment 302526 [details] [review] gdk: Handle W32 composition changes This change allows alpha-blended windows to suffer through composition being disabled and come out of it in one piece.
Fanc, please do a final review of everything. If everything's all right, i'll push the code changes. Attachment 273683 [details] will probably remain unpushed, since it's kind of half-baked, and also old. I don't do much for the Windows theme anymore, given that Adwaita is the default, so improving it is not on my TODO list.
Review of attachment 302526 [details] [review]: Hi LRN, I think we are good to go for these 2 patches (that is, attachments 302176 and 302526), but I'd guess that it would be best if we squash them as 302526 depends on 302176, if it's ok to you. With blessings, thank you!
Hi LRN, ...oh, and can you please also change the #define WINVER 0x0500 to #define WINVER 0x0600 in gdkprivate-win32.h so that we can be sure that everything can be found from the Windows headers, such as WM_DWMCOMPOSITIONCHANGED, as they require _WIN32_WINNT to be at least 0x0600 so that they can be found during the build. For attachment 302526 [details] [review] (as you squash them), I think there are some trailing white spaces in there, so please also get rid of them. With blessings, thank you!
Attachment 302176 [details] pushed as d44921a - Enable RGBA windows on W32 Attachment 302526 [details] squashed into it