Win32 Wait For Window Focus

Hi everyone,

is there a way on windows to wait for window focus?

I would expect that windows will put the thread to sleep to avoid wasting the user's CPU power. Thanks.

/ Clivi


Edited by clivi on

Asuming you're using PeekMessage to get your window messages, you can use GetMessage instead. When using GetMessage, if there are no new messages, the function will "pause" until there is a message. You can also use GetMessage to read the first message, and then use PeekMessage to read all available message.


Edited by Simon Anciaux on

This is the code i came up with using GetMessage:

if(GetFocus() != window) {
  b32 listen_for_messages = false;
  while(listen_for_messages) {
  listen_for_messages = GetMessage(&msg, NULL, 0, 0);
    if(listen_for_messages) {
       switch(msg.message) {
          case WM_SETFOCUS:
          case WM_QUIT:
          case WM_ACTIVATEAPP:
          case WM_ACTIVATE:
          case WM_DESTROY: {
              listen_for_messages = false;
          } break;
       }
    }
}

It works but i don't understand why WM_SETFOCUS is not enought for handling the waiting. If I don't handle WM_ACTIVATE the app stalls forever.

That's because you're not calling Translate & DispatchMessage for messages received from GetMessage. For window to process messages properly you should call Translate & Dispatch on messages after GetMessage. Also don't forget that some messages are not delivered as result to GetMessage call and instead are passed to WindowProc directly (by internals of window processing when it dispatches messages). For proper message waiting code you would need to keep this listen_for_messages somewhere in global state that you set to false inside WindowProc on message you're interested in.

In my code I have a note that says that WM_KILLFOCUS and WM_SETFOCUS (and some other messages) are never retrieved by PeekMessage and GetMessage, you can only get them in the window procedure callback ( https://docs.microsoft.com/en-us/windows/win32/winmsg/about-messages-and-message-queues#nonqueued-messages ).

To be clear the thing that eventually calls the window procedure is still something in GetMessage and PeekMessage, but those functions will not give you a WM_KILLFOCUS or WM_SETFOCUS message.

b32 window_has_focus = false;

LRESULT CALLBACK window_proc( HWND window, UINT message, WPARAM wParam, LPARAM lParam ) {
    switch( message ) {
        // ...
        case WM_SETFOCUS: { window_has_focus = true; } break;
        case WM_KILLFOCUS: { window_has_focus = false; } break;
        // ...
    }
    // ...
}

int main( int argc, char** argv ) {

    CreateWindow( );

    while ( running ) {
        
        MESSAGE msg;
        
        /* Bad example */
        if ( window_has_focus ) {
            PeekMessage( &msg );
        } else {
            GetMessage( &msg );
        }

        // ...
    }

}

Thanks for clarifing.

Why did you mark your example as "bad"?

Because I didn't think much about what it's doing.


Replying to clivi (#26462)

One way it is bad is because it processes only one message per iteration of your main loop. You really want to process as much messages as you can. So if you do GetMessage case, then afterwards do rest of them with PeekMessage before continuing with your custom main-loop code.


Edited by Mārtiņš Možeiko on