20

i've created a layered window by adding the the WS_EX_LAYERED extended style:

wndClass.ExStyle = wndClass.ExStyle | WS_EX_LAYERED;

Windows will use black as the chroma key color value. i'm going to leave a large border of black to make the problem obvious:

alt text


After the window is constructed, i tell it to use black as a chroma-key color:

SetLayeredWindowAttributes(hwnd, 0x00000000, 255, LWA_COLORKEY);

Now the popup layered window appears partially transparent:

alt text


The problem is the final step. i want to use CS_DROPSHADOW class style, available since Windows XP, to create a drop-shadow:

wndClass.Style = wndClass.Style | CS_DROPSHADOW;

The drop shadow appears, but the shadow surrounds the original rectangular window, and doesn't take into account the window's transparency provided by the layered window:

Does anyone know what magical option i've missed somewhere that will make the drop shadow honor the non-rectangular layered window?


Another example of where this issue appears is when you don't include the 6px padding/margin. The hint window as drawn by Windows® themes is non-rectangular. This leaves a small visible gap where the window is transparent, but the drop shadow does not appear:

alt text

Microsoft has managed to make it work, as you can see from this hint from Internet Explorer:

alt text


Looking closer at a Windows tooltips class hint window. Using SpyXX - i can get its window rect, and class styles:

SpyXX says:

Rectangle:     (440, 229)-(544, 249), 104x20
Restored Rect: (440, 229)-(544, 249), 104x20
Client Rect:   (0, 0)-(104, 20), 104x20

So everything points to the window itself being 104x20 pixels, with the drop shadow outside the window itself. (Which is consistent with CS_DROPSHADOW.)

Next i can look at the styles of the tooltips window class:

Windows Styles:     94000001

    WS_POPUP        80000000
    WS_VISIBLE      10000000
    WS_CLIPSIBLINGS  4000000
    TTS_ALWAYSTIP          1

Extended Styles:    00080088

    WS_EX_LAYERED      80000
    WS_EX_TOOLWIN         80
    WS_EX_TOPMOST          8

Interestingly, it doesn't use CS_SAVEBITS (0x800); which is useful for small, short-lived, windows.

Nor does it use CS_DROPSHADOW (0x20000). So now i wonder how is it drawing outside its own window?

Note: Transparent layered windows is documented as the preferred technique over regions.

Edit: Layered Windows have been around with Windows 2000. CS_DropShadow was added with XP.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • Please make your images suitable for a work environment. – Dave Jarvis Feb 08 '10 at 19:36
  • I work at a bank that sometimes gives live television interviews, so editing the images is much appreciated; otherwise I could've lost my job. –  Feb 08 '10 at 20:22
  • This is an old question, and it's probably a typo, but you wrote logical or ("||") where you should write bitwise or ("|"). – Jeff Dec 06 '11 at 02:41

3 Answers3

8

Transparent layered windows is documented as the preferred technique over regions.

However, CS_DROPSHADOW does pay attention to regions. If you crop or otherwise shape your window using a region, the drop-shadow will follow the new outline.

Fortunately, you can use regions with layered windows, and by combining the two get the effect you're looking for.

BTW: tooltips_class32 does use CS_DROPSHADOW - you won't see it in the window styles because it's a class style, not a window style.

Shog9
  • 156,901
  • 35
  • 231
  • 235
  • i *can* use regions with layered window? Since the two both cause transparency, but (as you say) only regions affect the window's true shape - is there any reason to use a layered window? (And if so, what? And if not, why does the tooltip use it?) – Ian Boyd Feb 10 '10 at 12:38
  • i will poke around with the window handle of a tooltip window, seeing if i can call the equivalent of `GetWindowRgn` and see if it has one. That should answer that part, although not why it's layered in the first place. – Ian Boyd Feb 10 '10 at 12:39
  • 1
    They can both be used to give a window a visible "shape", but they do very, very different things: the region effectively clips the window, excluding some areas completely while leaving what remains to be drawn normally; layered windows are still rectangular, but are drawn into an off-screen bitmap and composited (there's a hack in place to let you continue using the normal WM_PAINT drawing method, but the output is redirected). In addition to simple color-key transparency, layered windows allow for translucency and even per-pixel alpha values (if you handle drawing directly). – Shog9 Feb 10 '10 at 19:15
  • 1
    @Ian: As for tool windows, they're probably layered for performance. You noted the lack of `CS_SAVEBITS` - this style is unnecessary for layered windows, since Windows has to draw and preserve the windows underneath them in order to composite the layered window on top (this can actually hurt performance if a very *large* layered window is used, although that may no longer be as much of an issue if the DWM is compositing the entire desktop anyway). – Shog9 Feb 10 '10 at 19:19
2

Why don't you use LWA_ALPHA and build the shadow into the image?

Edit in reponse to your comment:

A) Doesn't stop you using an alpha channeled PNG for a shadow only. Blt the 2 images together and use as one single image.
B) Its not hard to generate a drop shadow. In the image you posted its black with 3 different alpha values.
C) But it doesn't work does it? ie Time to get creative.
D) Then don't try and get windows to do something it won't do for you.
E) Is entirely irrelevant. Layered windows handle that for you.

I strongly recommend you learn more about layered windows because they CAN help you to your goal.

Edit2: You have the bitmap. Its fairly easy to scan over the image and find which bits will be colour keyed (by identifying the black yourself) and hen modify that to have an alpha of 0 where everything else will have an alpha of 255 (Not: You may have to convert the image to a 32-bit image from a lower colour format, you can do this by creating a new DC and copying the image). This will give you the same effect with LWA_ALPHA as with LWA_COLORKEY. From there its fairly easy to identify the pixel at the edge, where the color changes to (R = 0, G = 0, B = 0, A = 0). You then change that first pixel to have a n alpha of 192, the one blow it to 128 and the one below to 64. You now have an alpha'd gradation below the image that will look like the shadow. You can adjust the alpha to get the effect you want.

Goz
  • 61,365
  • 24
  • 124
  • 204
  • a) i don't control the image; it comes from the current enabled visual theme b) i don't have an algorithm to generate a drop-shadow handy c) Windows already provides a mechanism to add a drop-shadow d) i'm trying to make it a visual clone of what Windows does. e) Sampling the pixels behind my window, in order to perform the alpha-blend, is not only potentially bad (because pixels can change), it is wrong - with the advent of desktop composition, and will cause things to run slow as the compositor generates me a picture of the desktop. – Ian Boyd Feb 08 '10 at 20:01
  • Why do you need to duplicate Windows' functionality instead of using what's already there? – Koro Feb 08 '10 at 22:33
  • Because it can't do what you want. – Goz Feb 08 '10 at 22:44
  • What image shall i use for the alpha-channeled PNG? i don't know the shape, or size, of the window after its transparency has been applied. And, yes (c) it doesn't work. Which is why i thought i'd ask a community of developers who might see what i've missed. – Ian Boyd Feb 09 '10 at 14:29
0

CS_DROPSHADOW only works with standard rectangular windows. WS_EX_LAYERED windows don't support everything. They are more of a low-level, self-service method to draw exactly what you want.

To get a drop shadow, you'll have to generate the drop-shadow yourself from the alpha channel in the image.

Adrian McCarthy
  • 45,555
  • 16
  • 123
  • 175
  • Any idea how Microsoft is managing to draw a drop-shadow outside a window? – Ian Boyd Feb 09 '10 at 21:26
  • +1, and Accepted answer. Turns out Microsoft is creating the properly sized drop shadow not with a layered window, but by using a region. A call to `GetWindowRgn` on the tooltips hWnd returns the rounded rectangle region. So CS_DropShadow doesn't support layered windows. – Ian Boyd Feb 10 '10 at 18:40