views:

47

answers:

3

This is kind of a hard question to describe, and I've searched for about an hour now to no avail.

Essentially, picture a small 'flyout' window like the Windows 7 Wireless Control or the Volume Slider from the system tray(notification area). When you click on the icon, the application pops up with focus, and if you click off of it, the window destroys itself.

I thought it woudl be easily solved by simply having my window destroy it self when it loses focus (I've been listening for WM_KILLFOCUS), but the problem is, if the icon is clicked, my window does not always get focus. Since this isn't the case, if the user clicks my icon, and then clicks away because it was a mistake (on the desktop say), then how can I set my app to close?

I've tried messing with SPY++ but checking the volume control / wireless control apps are proving difficult as they disappear when I try to get their window/process handles.

Thanks!

A: 

Have you looked into the Popup? That one will disappear once you click outside it (unless you set StaysOpen to true).

Goblin
How can I create a popup without creating a window to begin with (yet having a tray icon), for if I can do that then I can emulate the behavior with a normal window regardless.
Mason Blier
+2  A: 

The usual way this is implemented is by starting a timer on the window creation. If the window gets the focus before the timer has triggered, this means the user has interacted with the window. In this case, the window will just stop the timer and will destroy itself when it loses the focus. In the case the window did not get the focus before the timer was triggered, the window will destroy itself on the timer event.

This is also usually combined with opacity animation, so that the window is fading out while waiting for the user. Sort of a visual feedback to the user that it will be soon gone. However, the opacity animation is used mostly for notification toasts, and is rarely used for control windows like the volume control.

The alternative is to force set the focus in your window when the user interacts with your systray icon.

Also note that if your window is a top-level window, the preferred message to listen is not WM_KILLFOCUS, but WM_ACTIVATE and WM_MOUSEACTIVATE. You can also listen to WM_NCACTIVATE, but that one has some specifics, if you are doing a custom non-client area.

Update: You can set the focus to your window by calling either SetActiveWindow or SetFocus on it when you create it (or when you make it visible, if you're hiding it).

Franci Penov
Your timer idea will work, and I may use it, but it doesn't seem to be the way official windows tools do this. They force set the focus, which I'm not positive how to do.
Mason Blier
I used Activate(), thanks for the advice.
Mason Blier
+1  A: 

A long, long time ago I wrote a drop-in replacement for the Windows 3.1 Task Manager that accomplished this by handling WM_ACTIVATEAPP. Give that a try.

Aaron Klotz
My window was never activated when it appeared; I realize now it is because I was simply hiding and showing it rather than recreating it. I'm not sure which strategy is better, as recreating it each time requires a hidden window to be always running, at least so far as I can tell from WPF.
Mason Blier