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.
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 ); } // ... } }
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.