Is there any way to remove the 1px border?
scp-r opened this issue · 13 comments
Unfortunately I have come to the conclusion that it's not possible to paint over1 remove the one pixel border on Windows 10, see issue #11 if you care for some more details.
However, if you don't require the soft shadow, you can just use the basic_borderless
window style (WS_POPUP
derived) instead of aero_borderless
, which does not come with such a border.
It should still work with the glass/"blur behind" effect:
- That's not quite accurate - you can paint over it (after moving it into the client area using
DwmExtendFrameIntoClientArea
and expanding the client area to the whole window inWM_NCCCALCSIZE
), but as you can see, painting over it with a transparent color will not hide it.
Yes! I've found a way to have both the shadow and get rid of 1px border on Window 10. Unfortunately, it relies on undocumented SetWindowCompositionAttribute
function. Here's the reference:
https://gist.github.com/riverar/fd6525579d6bbafc6e48
The AccentState has to be set to ACCENT_ENABLE_GRADIENT
.
This is a Window 10 only hack, so you also have to check the OS version in runtime. Also, the shadow is the same size as for the non-focused window, and it doesn't changes its size when focused/non-focused.
@melak47
However... I've just tested your sample in Windows 7 (modified wcx.hbrBackground
to make the background black), and the 1 px border is there as well. And it is just transparent, which looks weird. Am I missing something? I believed the issue was only with Windows 10.
@ZimM-LostPolygon the 1 px border you see is the result of calling DwmExtendFrameIntoClientArea
. It's there on both Windows 7 and Windows 10, but for some reason Windows 10 paints over it using your background brush, while Windows 7 will not.
You can paint over it yourself (e.g. using D2D, D3D, OGL, ...) -- but you have to use an opaque color -- @Jasper0819X wants to use some level of transparency for the blur behind effect to show, and that's why the border is showing through.
Here's an example of going from fully opaque to fully transparent (with blur behind enabled):
So as long as you can put something opaque in your client area you should be ok.
@melak47
Hm... I am painting on a window using D3D, but the transparent border is still there on Windows 7 as well. Do I have to draw with some special coordinates or something?
No special coordinates should be needed.
Do you clear the backbuffer with an opaque color (say RGBA (0,0,0,1))?
@ZimM-LostPolygon I just tried filling the window using D2D on Windows 7, and it works fine for me:
The code is here: https://github.com/melak47/BorderlessWindow/tree/d2d-fill if you want to compare.
No need to use SetWindowCompositionAttribute
.
@melak47
Ah, indeed, sorry. I was filling the window with RGBA(0,0,0,0). Making the color fully opaque fixed it on Windows 7.
My Windows 10 solution that uses the SetWindowCompositionAttribute
function avoids this problem completely, since DwmExtendFrameIntoClientArea
is not called at all. The only downside is that shadow is always the same shadow that is used for non-active windows. But for me this is better than the 1px border. Also, there shouldn't be any problems with controlling the opacity. Here's how it looks:
@melak47
SetWindowCompositionAttribute
trick is only for Windows 10. The AccentPolicy
and related APIs are only available there. The 1px border on Windows 10 is the accent border...
@ZimM-LostPolygon I can't quite reproduce your results. If I use ACCENT_ENABLE_GRADIENT
without DwmExtendFrameIntoClientArea
as you suggest, I get no aero shadow at all. (Also, now I can't use ACCENT_ENABLE_BLURBEHIND
anymore, so what opacity is there to control?)
Aren't you going to draw to the window, anyway? Why is clearing with an opaque color a problem? :)
Well, it is a problem, since in the end, I want to actually use the alpha channel for transparent effects :)
Here's a messy C# code snippet that I used for the screenshot:
WinApi.DwmApi.Undocumented.AccentPolicy accent = new WinApi.DwmApi.Undocumented.AccentPolicy();
accent.AccentState = WinApi.DwmApi.Undocumented.AccentState.ACCENT_ENABLE_BLURBEHIND;
accent.AccentState = WinApi.DwmApi.Undocumented.AccentState.ACCENT_ENABLE_GRADIENT;
//accent.AccentState = WinApi.DwmApi.Undocumented.AccentState.ACCENT_ENABLE_TRANSPARENTGRADIENT;
accent.AccentFlags = (WinApi.DwmApi.Undocumented.AccentFlags) (0x20 | 0x40 | 0x80 | 0x100);
// Uncomment next line to disable shadows
//accent.AccentFlags = 0;
accent.GradientColor = 0;
int accentStructSize = Marshal.SizeOf(accent);
IntPtr accentPtr = Marshal.AllocHGlobal(accentStructSize);
Marshal.StructureToPtr(accent, accentPtr, false);
WinApi.DwmApi.Undocumented.WindowCompositionAttributeData data = new WinApi.DwmApi.Undocumented.WindowCompositionAttributeData();
data.Attribute = WinApi.DwmApi.Undocumented.WindowCompositionAttribute.WCA_ACCENT_POLICY;
data.SizeOfData = accentStructSize;
data.Data = accentPtr;
WinApi.DwmApi.Undocumented.SetWindowCompositionAttribute(hWnd, ref data);
Marshal.FreeHGlobal(accentPtr);
As for the opaque color... Well, initially, I wanted a window with both blur-behind and shadows. Using SetWindowCompositionAttribute
with ACCENT_ENABLE_BLURBEHIND
, I can do that:
The gray 1px border you can notice here is actually part of the shadow, it is half-transparent, so it looks fine on all backgrounds. And the opacity control using SetLayeredWindowAttributes
works correctly, even without shadows:
So this is exactly what @Jasper0819X wanted.
If I don't want the blur-behind, but still want to have working transparency without the 1px accent color border, I can use ACCENT_ENABLE_TRANSPARENTGRADIENT
with AccentPolicy.GradientColor
set to 0x01000000
(0.39% of black, basically unnoticeable to a naked eye) and get this:
So basically... Using SetWindowCompositionAttribute
removes the need to paint over with an opaque color, opening some new possibilities on Windows 10.
Ah, those are the flags used to draw the borders on the start menu and the like.
enum AccentFlag {
DrawLeftBorder = 1 << 5,
DrawTopBorder = 1 << 6,
DrawRightBorder = 1 << 7,
DrawBottomBorder = 1 << 8,
DrawAllBorders = (DrawLeftBorder | DrawTopBorder | DrawRightBorder | DrawBottomBorder),
};
I've seen someone write about these before, but I hadn't found a good use for them, thanks.