0

I'm trying to do something like what Auslogics Disk Defrag does with its custom window:

Dark shadow

As can be seen, the blurred semi transparent shadow surrounding the window is much darker than the standard one, so the program must be drawing it by itself. The problem is, I can't find a way to paint anything transparent around a window.

In an answer to a similiar question, someone suggested creating a slightly bigger transparent window (using WS_EX_LAYERED + SetLayeredWindowAttributes()) behind the actual application window, and then do the translucent drawing on the transparent one. Not only does it sound like an ugly hack, it doesn't actually work. If, for example, one tries to draw a semi transparent black rectangle on a transparent window via GDI+, alpha blending is applied to the shape's color over the window background color (which would also be the transparency color) and then the shape is drawn with the calculated color, which obviously is not the window transparency, resulting in an opaque rectangle.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Mario D
  • 1
  • 2
  • Did you see this? https://stackoverflow.com/questions/43818022/borderless-window-with-drop-shadow – Jonathan Potter Jan 06 '21 at 22:09
  • Yes, I saw it, but it just explains how to create a borderless window while keeping the standard shadow that Windows creates. I already know how to do that and it's not what I'm trying to do. What I want to know is how I can draw my own translucent shadow (or any other shape) around a window. Or at least change the color/darkness of the standard one, but I don't think that's possible. – Mario D Jan 06 '21 at 22:57
  • The "ugly hack" is required to get this effect. GDI+ is an old horse that can't do this trick, you *must* buy into the kind of rendering that's supported by DirectWrite. Been around for well over a decade now, albeit feebly supported by GUI frameworks. WPF can do it. – Hans Passant Jan 06 '21 at 23:23
  • Yeah, I thought I might have to use something more sofisticated than GDI+. By the way, when I said ugly hack I was just referring to creating an extra window. I'd already assumed I'd have to create a window with transparency. I did try making my main window partially transparent (just a transparent frame around it), capturing the part of the screen surrounding it, alpha blending on it, and then blitting it over the window. It works, but of course, it flickers if I drag the window. I guess I'll try with DWM and Direct3D for compatibility with Vista/7. – Mario D Jan 07 '21 at 02:45

2 Answers2

0

The semi transparent shadow is actually done by Gaussian Blur of the black square.

You can use this effect to create glows and drop shadows and use the composite effect to apply the result to the original image. It is useful in photo processing for filters like highlights and shadows. You can use the output of this effect for input into lighting effects, like the Specular Lighting or Diffuse Lighting effects, because the alpha channel is blurred, too and lighting effects use the alpha channel to determine surface geometry as a height map.

This effect is used by the built-in Shadow effect.

Refer: Gaussian blur effect

Then remove the standard frame, the entire window is your client area, so you can draw shadow in the extended frame.

Refer: Drawing in the Extended Frame Window

Strive Sun
  • 5,988
  • 1
  • 9
  • 26
  • Actually I do know how to do Gaussan blur. I didn't know Direct2D had a function to do it,though, so it's good to know. Anyway, my problem is with drawing outside the whole window, not just outside the client area. I've used DWM to draw on the extended frame, but what I'm trying to do now is drawing transluscent things so that whatever is behind my shadow (the desktop icons, other windows, etc.) can still be seen through it, just like in the image I posted. Is that actually possible with DwmExtendFrameIntoClientArea? – Mario D Jan 12 '21 at 03:07
  • @MarioD I have not done such an effect. However, I consulted the relevant engineers and got a positive answer, DWM is the right direction. – Strive Sun Jan 12 '21 at 05:50
0

I think I've found a solution that works for me. I was hoping I wouldn't have to create an extra window just for the shadow, but every method I could find or think of would require me to draw all the controls by myself and/or somehow correct their alpha values.

So, I'm using a layered window with per pixel alpha. I paint over it with Direct2D, or, alternatively, I use some PNGs with transparency for the edges and corners of the shadow and copy them on a memory DC. Either way I simply recreate the shadow with the right dimensions when the window is resized, and call UpdateLayeredWindowIndirect. Both methods seem to be working well on Windows 7 and 10, and so far I haven't found any glitches.

Preventing it from showing on the taskbar was a bit tricky. All the ways I know have drawbacks. What worked best for me was making the layered window owned by the main one. At least that way it will only be visible on the desktop where the program is actually running, unlike other alternatives which would force it to show on every virtual desktop. Finally, because I disable that window, I interact with it by processing WM_SETCURSOR.

Mario D
  • 1
  • 2