views:

619

answers:

3

What color must i paint in the client area in order to make glass appear?

i've extended the frame of my form into the client area using:

DwmExtendFrameIntoClientArea(self.Handle, margins);

i cannot find any official documentation from Microsoft on what color and/or alpha the DWM will look for to replace with glass. The documentation on DwmExtendFrameInClientArea doesn't even mention that a custom color is required. There's only hearsay and myth that a special color is even required.

The closest i can find is a topic on MSDN:

Custom Window Frame Using DWM

For the extended frames to be visible, the regions underlying each of the extended frame's sides must have pixel data that has an alpha value of 0.

Update: And a blog post:

Windows Vista for Developers – Part 3 – The Desktop Window Manager

It so happens that the bit pattern for RGB black (0x00000000) is the same as the bit pattern for 100% transparent ARGB so you can actually draw with “black” GDI brush and assuming you’ve instructed the DWM to blur the painted area, the result will be the desired glass effect.

If i take what they say literally (pixel data with an alpha value of zero), i construct a color with zero alpha, and paint that in the extended area:

Color fillColor = Color.FromArgb(0, 0, 0, 0); //(a, r, g, b)
e.Graphics.FillRectangle(new SolidBrush(fillColor), e.ClipRectangle);

but the glass effect does not appear:

alt text


If i ignore the quoted MSDN topic, and instead use fully opaque black (rather than a completely transparent black):

Color fillColor = Color.FromArgb(255, 0, 0, 0); //(a, r, g, b)
e.Graphics.FillRectangle(new SolidBrush(fillColor), e.ClipRectangle);

the glass effect does appear:

alt text

i am then lead to believe that opaque black is the pixel value that the DWM will look for to replace with glass.

But then how do i paint black items on the glass area?


i've tested painting a black rectangle on the glass area, with a circle next to it. Oddly enough, the rectangle doesn't appear, while the circle does appear; both are the same color:

Brush b = new SolidBrush(Color.FromArgb(255, 0, 0, 0));
e.Graphics.FillRectangle(b, 11, 11, 32, 32);
e.Graphcis.FillEllipse(b, 43, 11, 32, 32);

alt text

So what in the world is going on? What is the proper color to paint in the extended frame area to make glass appear?


Update 2

Using Adisak's suggestion to isolate exactly where the stupidness of Aero lives, here i draw a black rectangle inside the black circle:

alt text

Does FillEllipse not support drawing black circles?


Update 3

Pondidum wondered if calling Graphics.Clear with a transparent black color would make the glass visible:

e.Graphics.Clear(Color.FromArgb(0,0,0,0));

It does work, but you still can't draw opaque black items on the glass:

alt text


Update 4

Looking at Microsoft's Vista Bridge Library (managed wrappers around Vista functionality that won't be added to .NET), they only ever manage to get extended glass frame working on WPF forms, not WinForms.

+1  A: 
Color fillColor = Color.FromArgb(0, 0, 0, 0); //(a, r, g, b)
e.Graphics.FillRectangle(new SolidBrush(fillColor), e.ClipRectangle);

This is actually rather amusing. It means that you are drawing something completely transparent - so this changes absolutely nothing! :-)

Guess: if black (0,0,0) should mean "glass", how about drawing (1,1,1) to get (almost) black?

danbystrom
Would doing `e.Graphics.Clear(Color.FromArgb(0, 0, 0, 0));` not work also?
Pondidum
i suppose i could draw a color that isn't the color i want, but i'd rather draw the color i want.
Ian Boyd
Most amusing is how you can interpret the alpha value: Should it be evaluated for blending the drawing primitive, or should it substitute the buffer's alpha values?
Cecil Has a Name
@Pondium - that is the same as e.Graphics.Clear(Color.FromArgb(x, 0, 0, 0)); where x can be anything, since the form surface is normally 24 bits - the alpha (must be)/is ignored. Which makes it equal to drawing with black. When using .Clear on av 32-bit BitMap, however, the alpha comes into play.
danbystrom
+1  A: 

Try setting the TransparencyKey of the form to Color.FromArgb(1,1,1) (or some other suitable value of your choosing) then setting the backcolor of the form (or the part you want to be glass) to that same value.

That's how I got it to work without it making all of my black text transparent/glass.

I couldn't ever figure out how to paint the "glowy" text on the glass though. It always had a black rectangle behind it.

Jason Diller
i'm not, necessarily, using WinForms in .NET.In order to draw (caption) text, you need to use the theme api. It draws the appropriate black text and white glow behind it.
Ian Boyd
Ah, sorry, I presumed it was WinForms.
Jason Diller
+1  A: 

One of the blog posts that you linked to above has a discussion about this. The native solution was to use SetLayeredWindowAttributes to switch the color key away from black.

Aaron Klotz
SetLayeredWindows attributes trades one set of problems for another. It changes the key color. "Choosing an appropriate color is the hardest part." "Font smoothing will...be blending with the transparency color instead of the actual background." "...specify a color that is unlikely to be used by any controls..."Assume i want to do things the proper way. Or assume that i'm in the pursuit of knowledge. Either way, i still want to know what color/alpha to paint to make the *glass* appear.
Ian Boyd