4

Looking at a Windows tooltips class hint window, i see that it draws its drop-shadow outside the hint window's actual rectangle.

Using SpyXX - i can get the tooltip's window rect, and class styles:

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

You'll notice that the drop shadow you see is physically outside the window that's being drawn. How can i draw a shadow outside around my window, while being outside my window?

Note: The shadow is not drawn using the standard CS_DROPSHADOW class style. i've confirmed this experimentally, and can also see the class style's for the window in SpyXX; it does not use CS_DROPSHADOW:

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

So how can i draw outside my window?

Note: Trying to draw on the desktop DC is out. From Greg Schechter's Redirecting GDI, DirectX, and WPF applications:

Drawing To and Reading From the Screen -- Baaaad!

Lastly, since we're on the redirection topic, one particularly dangerous practice is writing to the screen, either through the use of GetDC(NULL) and writing to that, or attempting to do XOR rubber-band lines, etc. There are two big reasons that writing to the screen is bad:

It's expensive... writing to the screen itself isn't expensive, but it is almost always accompanied by reading from the screen because one typically does read-modify-write operations like XOR when writing to the screen. Reading from the video memory surface is very expensive, requires synchronization with the DWM, and stalls the entire GPU pipe, as well as the DWM application pipe.
It's unpredictable... if you somehow manage to get to the actual primary and write to it, there can be no predictability as to how long what you wrote to the primary will remain on screen. Since the UCE doesn't know about it, it may get cleared in the next frame refresh, or it may persist for a very long time, depending on what else needs to be updated on the screen. (We really don't allow direct writing to the primary anyhow, for that very reason... if you try to access the DirectDraw primary, for instance, the DWM will turn off until the accessing application exits)

Armen Michaeli
  • 8,625
  • 8
  • 58
  • 95
Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • The simple answer is you can't draw outside your window. For the reasons given, this is a bad idea. this means that what you are seeing when there are drop shadows outside of window rects is not the raw desktop - but some kind of composited image. On Windows 6 the composited desktop is managed by dwm.exe - On windows XP I don't know - are you drawing your control(s) background with DrawThemeBackground? – Chris Becke Feb 10 '10 at 04:35

3 Answers3

5

You can't draw outside your window in the manner you describe.

If you right click your desktop then go to properties/appearance/effects and uncheck 'Show shadows under menus' ... you will no longer have the shadow.

Bottom line is that this is a product of the window manager not your program.

  • How is the `tooltips` common control drawing outside its window? Or what feature of Windows is it asking to make use of? – Ian Boyd Feb 09 '10 at 22:19
  • @Ian Boyd - I think you misunderstand. The control itself is not drawing outside its window. When the window manager is asked to paint windows with certain classes, like 'menu' or 'tooltips', it (the window manager) renders the dropshadow and then the window. It's built in to the default window manager under Windows. There are replacement window managers available. Some may be open source and reveal their secrets. However, none of the windows is "painting outside itself." –  Feb 09 '10 at 22:26
  • How is the tooltips common control asking the Windows window manager to render a drop shadow around its window? – Ian Boyd Feb 10 '10 at 02:26
  • The bottom line is, it can't be a trick of the window manager, because the window manager is not being given the necessary hints to tell it to draw the drop shadow. Which means that the tooltip control is explicitly calling some kind of window manager api to manually render a drop-shadow. what api is it? i am intrigued. – Chris Becke Feb 10 '10 at 05:02
  • 3
    The window manager simply adds the CS_DROPSHADOW style to the window. In your post above you haven't enumerated the Class Styles, only the Window Styles. Were you to actually enumerate the Class Styles on a tooltip window with the 'Show shadows under menus' option checked you would see the CS_DROPSHADOW class style. With the option unchecked you wouldn't see it. Class Style are different than window styles. Why not write a sample program to test it? I don't have the time for it atm. –  Feb 10 '10 at 14:40
  • The tooltip (probably) uses the CS_DROPSHADOW class style (i don't know how to get an hWnd's class styles) to add the drop-shadow. The reason the shadow matches the window's non-rectangular shape because the window has a region applied (GetWindowRgn confirms this). So the answer, "You can't draw outside your window" is the correct answer. +1 and accepted. – Ian Boyd Feb 10 '10 at 18:43
4

Q: How do you draw outside of one window? A: Draw inside another window!

First thing to note is that the tooltip class actually does use the CS_DROPSHADOW style - but note that this is a class style, not a window style, so you have to look at the Class tab in the Spy++ properties dialog to find it. You'll see that the tooltips_class32 windows does indeed have this - and a few others.

But that just leads to the next question - how does that work? Well, it seems that Windows implements this by creating a helper HWND to draw the shadow - presumably it's creating another popup window the same size and shape as the one it's shadowing, filling it with gray, placing it directly underneath the main window, and setting it as a WS_EX_LAYERED window so that the shadow can be transparent and fade out around the edges using alpha-blending. And there's nothing to stop you from using the same or similar techniques yourself if you want to add a different type of shadow effect to one of your own windows.

So, long story short: if you want to draw outside of your own window, create a helper transparent window in the general area that you want to draw on, and draw on that helper window instead.

--

Now, if you try to find one of these helper shadow windows in Spy++, you won't find much. Unlike the tooltip_class32 windows, which are long-lived and just hide/show themselves as needed, these shadow windows are a more elusive creature: they are only created for as long as needed, so you'd have to refresh Spy++ while there's a tooltip or popup menu or other window using the shadow present - and that's tricky, since most tooltips and menus will disappear as soon as you move the mouse to switch to Spy++. But it turns out that the tooltips on Spy++'s own toolbar will stick around: so start Spy++, hover over an item in the toolbar, and hit F5 to refresh the HWND tree while the tooltip and shadow are present. Now scroll down, and you should see the third and fourth visible HWNDs in the tree are the tooltip itself, and right after that, a SysShadow window. Unfortunately, since the tooltip and shadow have by now disappeared, if you attempt to get the properties dialog for that HWND, you'll get a get a blank property dialog with an 'Invalid Window' message. If you really want to poke around and see how that SysShadow works, what styles it itself uses and so on, you could create a target app with a long-lived popup that uses CS_DROPSHADOW that you can then explore in Spy++ at leisure.

(Finally, note that these shadows are a completely different thing than the shadows that you see when one app window is on top of another above another since Vista: this type of shadow is part of Aero Glass mode, and handled by the same Desktop Composition Manager that adds the glass titlebar effect, and it doesn't use or need helper windows to implement the shadows.)

BrendanMcK
  • 14,252
  • 45
  • 54
  • If it's of any interest to anyone, tooltip windows appear to have WS_CLIPCHILDREN, WS_CLIPSIBLINGS, WS_POPUP/WS_POPUPWINDOW, WS_VISIBLE set, and that's about it. Took this from intercepting events via SetWinEventHook in some code in visual studio, then just checking the styles on windows to what had been set on a tooltip window. – Martin B Oct 25 '21 at 12:20
1

I wouldn't be surprised if that shadow is intimately tied to the window manager itself; it is after all the window manager who decides what window gets to paint which parts of itself and when it can do it. I don't see it as rocket science to paint that shadow if control over all that is gained, which the window manager has.

Johann Gerell
  • 24,991
  • 10
  • 72
  • 122
  • i don't believe that the `tooltips` common control is painting the drop-shadow itself either. But then what feature of Windows is it making use of? – Ian Boyd Feb 09 '10 at 22:21