Why does my window get a WM_ACTIVATE message when it isn’t active?


Say you launch a program, and for whatever reason the program takes a long time to start up, so you start doing something else, say launching Calculator and balancing your checkbook. Eventually, the program you launched a while back gets itself off the ground and creates its main window. And the window sits in the background (since the window manager won't let it steal foreground activation), but the caret is blinking in the edit control, and the program seems to think it's the active window.

If you write a test program to do this, say by sticking a Sleep(10000) at the start of your WinMain, you'll see that your window gets a WM_ACTIVATE message that says "Yup, you're active."

But you're not.

Or are you?

What's going on here?

Let's rewind to 16-bit Windows. The active window was the top-level window that receives input. You could make a window active by clicking on it or by selecting it via Alt+Tab or any number of other operations. A program could change the active window by calling the SetActiveWindow function explicitly, or by performing a number of other operations which imply changing the active window. (For example, depending on the parameters you pass, ShowWindow and SetWindowPos may make the window active as well as showing/repositioning it.) There was only one active window at a time; if a program set itself as the active window, then the previous active window lost activation.

Okay, now let's move forward to Win32. Recall that in Win32, most of the state that used to be global became thread-local.¹ This was done to permit the asynchronous input model, where each thread gets its own input queue. This means each thread gets its own mouse cursor show state, each thread gets its own caret, each thread gets its own focus window, and so on. And one of the and-so-on bits is that each thread gets its own active window.

What you're seeing is a thread which has an active window which is not the foreground window. The thread also has a focus window, and when an edit control gets the focus, it draws a blinky caret. Mind you, the window is not the foreground window, so your input doesn't actually go to it, but the window doesn't know that. It's sitting around as an active window, wondering why nobody is typing anything.

So now you know what's going on. Mind you, there's nothing actually wrong with this situation. In fact, it's a sign that the virtualization is doing what it's supposed to do: The thread is living in its own world, a world designed to be compatible with the 16-bit world where there was only one active window.

Footnote

¹ Or, more nitpickily, local to the input thread group. Since most input thread groups consist of a single thread, I'll just write thread and leave you to insert "or input thread group" as necessary. But you knew that, because it's one of the five things every Win32 programmer should know.

Comments (18)
  1. Motti says:

    So… What are the other four things every Win32 programmer should know?

  2. Tim Dawson says:

    If it's by design that a textbox can have its caret blinking even when typing on the keyboard will not send characters to that textbox, then the design is wrong. Anyone who's ever accidentally typed their password into a different (and plain text) window than they intended will tell you that.

    [This would require the caret to be a global resource, which means you lose asynchronous input. -Raymond]
  3. Evan says:

    "…the window doesn't know that. It's sitting around as an active window, wondering why nobody is typing anything."

    Man, now I feel bad for leaving the window on its own.

  4. Gabe says:

    What I've always wondered is why this situation causes the "activated" window to show up randomly in the Z-order. Let's say I start an app, move on to two other apps (my calculator and my checkbook), and then the app shows its window. I would expect the app to show up either on top, between my checkbook and calculator, or just below my checkbook and calculator.

    In reality what happens is that it will show up anywhere in the Z-order, from the bottom all the way to the top. It can be hard to even know that the app even launched.

  5. pmbAustin says:

    Now if I could only figure out why, when I'm happily typing along, another app pops up some dialog, stealing focus, and causing my typing to go into the dialog… sometimes randomly dismissing the dialog depending on what keys are mapped, meaning I can't even see what happened.  It's very annoying.  Even Outlook has been known to do this occasionally.  I thought the "Another app/window cannot steal your focus" problem had been solved, but apparently that's not strictly true…

  6. Joshua says:

    [This would require the caret to be a global resource, which means you lose asynchronous input. -Raymond]

    Bleh. Easily fixed as follows: The caret blink timer calls GetForegroundWindow (GetActiveWindow won't work here) and not blink if it's not the right window.

    Now for those who implemented their own textboxes with their own carets, it's their problem now.

    [Or apps which rely on the caret blink timer to perform other business logic. (Perhaps inadvertently. For example, maybe it prevents their app from hanging because the timer message wakes up their queue.) -Raymond]
  7. John says:

    Hey somewhat unrelated to the post, but does anyone know when Raymond will be speaking next? (I thought there use to be a blog post that mentioned his upcoming engagements) Also did anyone have any cleaner audio from that PDC linked above?

  8. Joshua says:

    [Or apps which rely on the caret blink timer to perform other business logic. (Perhaps inadvertently. For example, maybe it prevents their app from hanging because the timer message wakes up their queue.) -Raymond]

    Nothing happens. The edit control is what eats the message.

    [Sure, the edit control eats the message, but the presence of the caret timer wakes up the queue. And the app may be relying on the wake-up. (E.g., because it accidentally stalled its queue and the timer message unstalls it.) -Raymond]
  9. Adrian says:

    I agree with the sentiment that an app with the caret blinking but that doesn't actually have the focus is a really bad user experience (especially on multimonitor and especially in schemes with partially transparent window borders or low visual distinction between the foreground window and the other windows).  Is there anything a developer can do to make sure their app is never blinking an an inappropriate moment?  From your description, it doesn't sound like it, but I remain hopeful.

  10. GWO says:

    [This would require the caret to be a global resource, which means you lose asynchronous input. -Raymond]

    (Or well behaved programs that act apporopriately when they gain / lose focus – the docs for WM_SETFOCUS and WM_KILLFOCUS say programs should respect this convention)

    [What a different world it would be if we didn't need to support poorly-behaved programs. -Raymond]
  11. Adam Rosenfield says:

    When I'm working with virtual machines, I sometimes forget whether the VM or the real computer has the mouse focus.  Each machine has its own blinking edit cursor and thinks it owns the mouse, but in reality only one does, so you get multiple blinking cursors.

    That problem is much trickier to solve — you'd either need guest extensions in the VM to communicate to the guest OS that "you just lost focus", or you'd need the hypervisor to pull tricks like tell the guest OS that the mouse was unplugged when it loses focus.

  12. alegr1 says:

    Windows doesn't seem to be handling well some non-respond cases (as I saw recently in Windows 7). Namely when a program hangs inside WM_INITMENU/WM_INITMENUPOPUP message (for example, when debugging a ON_UPDATE_COMMAND_UI handler). The program window then becomes impossible to switch from, and the debugger can never become a top window. You can start Task Manager, but it won't kill the program being debugged. Logout works, though.

  13. Anonymous Coward says:

    [Or apps which rely on the caret blink timer to perform other business logic.]

    Having a visibly blinking caret and having a timer go off are different things though.

    I'm still a bit confused about what creates the unwanted situation though. Even if a window doesn't respond to messages when you switch away from it, shouldn't it still have a notification that it should no longer blink a caret sitting in its message queue?

    [They are different things, but one is implemented in terms of the other, and applications may inadvertently rely on this dependency. -Raymond]
  14. Anonymous Coward says:

    That means it's possible to make sure the caret (for standard controls, again whoever creates his own carets is on his own) will never show up when the window doesn't have focus without breaking backwards compatibility.

    And I still cannot picture the chain of events (and messages) that create the problematic situation to begin with. The text in your article suggests that either Windows forgets to send the unfocus notification or that the window ignores it, in which case I don't see how the caret would ever be properly hidden when the window loses focus.

    [To preserve backward compatibility, you would have to leave the timer running but somehow let it know, "Hey, I'm just running you for compatibility reasons. Don't actually blink anything." (The chain of events is "The frame is created and is given local activation but not foreground. Next, a control on the frame window is given local focus.") -Raymond]
  15. Gabe says:

    I can't think of a time when I've seen two windows in the same desktop with carets blinking simultaneously. Obviously it is a major problem with VMs, RDP clients, and the like. But how often does it happen within a single desktop?

  16. Anonymous Coward says:

    I've been in the situation where PopularBrowser blinks what looks like a caret in the address bar, but the window isn't focussed and you cannot type in the address bar. It usually happens when launching the browser or creating a new window. But to the best of my knowledge they implemented their own caret (badly), so this isn't really what we're talking about here.

    I cannot reproduce Raymond's scenario; I do get a WM_ACTIVATE(WA_ACTIVE, hWndPrevious) but then I get a WM_ACTIVATE(WA_INACTIVE, NULL) too and the edit control doesn't even receive focus, even though it does when I don't switch away during the Sleep. Oh well.

  17. Joshua says:

    I've got it with Raymond's scenario with one wrinkle. The application tried to steal global focus but was prevented from doing so.

    [To preserve backward compatibility, you would have to leave the timer running but somehow let it know, "Hey, I'm just running you for compatibility reasons. Don't actually blink anything." (The chain of events is "The frame is created and is given local activation but not foreground. Next, a control on the frame window is given local focus.") -Raymond]

    Easy only for the standard controls. Custom controls would still blink.

Comments are closed.