Transparent and non-rectangular windows


I get a lot of questions about how to do transparent top-level windows in Avalon, or nonrectangular windows, or layered windows, or other variations on the same theme.  The short answer is you can do most of these things, but it’s really a Win32 feature rather than an Avalon feature, and you’ll do it using Win32 APIs.  And some of this stuff works better on Longhorn, or at least will once we finish Longhorn.  But the complete answer is quite a bit more involved…


First thing to know is that the only thing the window manager understands is a good old-fashioned Win32 HWND.  So every Avalon Window object is an hwnd.  And it has to play by the rules that hwnds play by – inside that hwnd, Avalon can do all sorts of crazy stuff, but when it comes to other hwnds on the desktop, Avalon has to play by Win32 rules.


In Win32, you can get a non-rectangular window two different ways.  One is by using an region (HRGN) to describe the shape of the window.  The other is to use layered windows (WS_EX_LAYERED), which allow you designate a certain color as being the “transparency key”, and Win32 will make any pixels of that color be completely transparent.  So if you want a circular window, paint everything outside your circle with the transparency key color.


Layered windows also allow you to make the entire window translucent (semi-transparent) by specifying an alpha value to apply to every pixel in the window.  (Win32 even supports per-pixel alpha, but this is very difficult to use in practical programs because in this mode you’ll need to draw any child hwnd yourself)


Avalon supports HRGN just fine in all its variations, we don’t provide any managed API for doing this but you can always use PInvoke and HwndSource and do it yourself.  (Why not?  Mostly as future proofing– we don’t want to bake HRGN and its limitations into the Avalon API, because one day we want to teach the window manager to go beyond hwnds and HRGNs)


Layered windows, on the other hand, come with some limitations, because Avalon is unlike your typical hwnd and uses DirectX rather than GDI to render.  And here’s where it really gets complicated.



  • Avalon doesn’t hardware accelerate layered windows, all rendering is done in software.  We’re working on getting hardware acceleration for Longhorn, we’ll have to see what’s possible on earlier platforms.
  • We currently have a number of timing issues – if you resize or move the window at the wrong time, you can get into the situation where the application stops painting itself.  You can also get rendering turds outside of the window, where the window used to be (these can be fixed by getting the background window to repaint, but not by moving the layered window over the turd).  We’re working on fixing these issues, not clear we’ll be able to fix it completely for XP due to limitations in Win32, but we should be able to do it for Windows Server 2003 SP1 and Longhorn.
  • We don’t really support transparency color keys or plan to, because Avalon can’t guarantee we render the exact color you asked for, particularly when hardware accelerated.  There’s cases, for example, where we render 0x0000001 instead of 0x000000 – human eye sees both as black, but Win32 sees them very differently. 
  • We don’t currently support per-pixel alpha, if you try today you get black instead of transparent.  We’re looking into this, right now it’s not clear which platforms we’ll be able to get it for.
  • Layered windows on top of DirectX surfaces flicker when the DirectX application renders (basically, gdi hides the layered window, then lets DirectX draw, then puts the layered window back).  This is actually true of non-Avalon layered windows as well as Avalon layered windows, this will be fixed in Longhorn when using the Desktop Window Manager (DWM), but there’s no way to fix in previous operating systems.
  • Per-window alpha works fine.

So to recap, in English:



  • Non-rectangular regions can be done by using Win32 APIs, either HRGNs or layered windows.  HRGNs work completely, layered windows we’re trying to make work completely on Longhorn, layered windows will work with limitations on earlier platforms.
  • Per-window alpha (transparency) works fine, again using Win32 APIs.
  • Per-pixel alpha (transparency) doesn’t really work today, stay tuned for further developments.

As always, I’d appreciate your feedback so we can make sure we prioritize things appropriately.  And if you can figure out how to explain this one better, please let me know — this was a very long answer to a short question!


Comments (21)

  1. mihailik says:

    Excellent posting!

    Nick, but what about tooltips and menus?

    They both have nice shadows that cannot be drawn without per-pixel alpha. Priveous Avalon CTPs had ugly black borders around menus and tooltips. Same as you said in your posting.

    But in Beta 1 RC menus and tooltips are nice, with per-pixel alpha shadows. How is it done? And, may be, this technics can be expanded to support full-window per-pixel alpha?

  2. Ryan Dawson says:

    Nick-

    I think the ability to modify the Window Chrome is huge.

    So, if you could take care of the nasty details involved in per-pixel alpha and WS_EX_LAYERED, that would be awesome.

    Although Avalon plays in the Windows (a.k.a. Handles) world, it doesn’t mean it has to have the same programming model.

  3. hm says:

    Would not it be possible to cheat a bit, let gdi do its thing then grab a bitmap of the gdi output, and place it in the DirectX and let hardware do the alpha-blending against the avalon window? Well as long as the alpha works in Longhorn I am happy!

  4. Nick, you seem to be under playing the per-pixel alpha:

    "Win32 even supports per-pixel alpha, but this is very difficult to use in practical programs because in this mode you’ll need to draw any child hwnd yourself"

    Perhaps I missed something, but I thought Avalon was drawing everything inside the Window – doesn’t it use a ‘one big HWND’ approach? So in principal, the way per-pixel alpha works isn’t necessarily a problem.

    Or was this bit under the category of "Stuff you need to know to work with this in classic Win32 code"?

    I’m left a little unsatisfied because I’ve used per-pixel alpha in Win32 apps and have been very happy with the results, and I still don’t feel my understanding of why Avalon can’t use it that goes any deeper than "It just can’t". Unless I missed it, I don’t see any explanation of why – you just say "We don’t currently support per-pixel alpha".

    Also, I still don’t really understand *why* Avalon doesn’t hardware accelerate layered windows. I thought DirectX would let you render into an off-screen surface, so how come you can’t do that and then transfer that surface onto the layered window?

  5. Lucas Menge says:

    I find this to be pretty frustrating, specially since the whole breaking free of the rectanglular window paradigm was a big thing for me. I’ve developed a piece of software that used Direct3D to render images and that updated a layered window with them (it is an annoying process…) and was expecting Avalon to make it all easier (and faster – PLEASE), but it seems as though it won’t. This brings a huge frown to my face.

    Any chance we’ll see the the "liberation" in Longhorn?

  6. Sean Gerety says:

    Nick,

    Does not the HGRN model above just clip the rectangle window?

    And does the rectangular window problem a result of the functional categories of XAML? Currently, if I understand it correctly a control is third in the Avalon food chain.

    ( Root element-> Panel element -> control element )

    I’d like to see an 3D object able to live without the chrome.

  7. Sean Gerety says:

    Nick Kramer on Avalon

  8. There’s been some internal discussion about transparent and/or non-rectangular windows recently, and…


  9. There’s been some internal discussion about transparent and/or non-rectangular windows recently, and…


  10. There’s been some internal discussion about transparent and/or non-rectangular windows recently, and…

  11. Couple notes about where this series is going:

    part 1 was an introduction to the topic

    part 2 is…

  12. So that concludes my series about hwnd interop, which is really a draft of the hwnd interop white…

  13. Alex Cohn says:

    Hi, have you ever seen an attempt to put side-by side a region window with an per-pixel aplha window? My idea was to make the latter (a thin stripe on the right-bottom) adjacent to the fully oblique region window to provide a 3D shadow effect.

  14. nkramer says:

    That can work, and for many people in scenarios it’s worth pursuing.  The one complication you may run into is moving the two windows together — traditionally in Win32, it’s difficult to move two adjacent hwnds simultaneously in a way that doesn’t have some kind of flashing at the boundary between them.  (eg, the system repaints after the first hwnd is moved to before the second one…)

  15. Alex Cohn says:

    Yes, I thought about this. The trick is, at least in my case, while the window is being moved, it does not change – therefore, I can capture the opaque "region" window  using PrintWindow(), hide it, and extend the layered one to the "full size".

  16. Alex Cohn says:

    I have found (but not tested yet) another approach: using POPUP child windows for the layered window: cf. http://web.mac.com/seattleamadio/iWeb/OoeyGUI/Blog/8834809A-FC89-4534-8B7F-55306752131B.html

  17. nkramer says:

    Hmm, neat trick, that could work!

  18. nkramer says:

    (I was referring to merging the layered windows, but the pop-up approaches also viable — I keep meeting to write about that but I still haven’t finished the complete sample)

  19. rabidrobot says:

    Tim said:

    "We don’t currently support per-pixel alpha, if you try today you get black instead of transparent.  We’re looking into this, right now it’s not clear which platforms we’ll be able to get it for."

    Is this still the latest information, and could you be more specific as to what exactly you are referring to?  We can make per-pixel alpha transparent (2D) images and place them in the HwndSource now.  But I am seeing black where I expect transparency when I try to capture layered windows to a bitmap using CopyPixelOperation.CaptureBlt.  Is it possible that fixes have been made in some areas but not all?  CopyPixelOperation is .NET2.0, not Avalon, so…  ?

    (I am using WindowsXP, if that is a concern)

    Tim also said:

    "HRGNs work completely"

    Is there any more information on how to use these available?  Can the region path be defined by a XAML path?  Or will it require creating a bitmap, then rectangulating the bitmap to get a region path?  Any pointers in this area would be very welcome.

  20. rabidrobot says:

    I’m sorry, I used "Tim" where I meant "Nick".  My apologies.