app freezes during WM_KILLFOCUS

Eric Frias efrias at syncad.com
Thu Jun 16 09:09:16 CDT 2011


I've been chasing a bug for a few days, and finally have a good idea of 
what is going on.  When a program brings up a modal dialog box in 
response to a WM_KILLFOCUS message, the program will freeze.  I've 
attached a simple test case, all boilerplate except for:
     case WM_KILLFOCUS:
             MessageBox(hWnd, _T("Killing Focus"), _T("Note"), MB_OK);
in the main event loop.  If you run the program and then give focus to 
another application, the messagebox will pop up and then the program 
will become unresponsive.

What is happening is:
     - x11drv gets a FocusOut event and calls the event handler, which 
ends up SendMessage-ing a WM_KILLFOCUS to the program.
     - The programs's code creates a modal dialog like the MessageBox 
above, and enters the dialog's event loop, which winds up calling 
GetMessage which calls MsgWaitForMultipleObjectsEx to get more X11 events.
     - X11DRV_MsgWaitForMultipleObjectsEx executes this:
             if (data->current_event) mask = 0;  /* don't process nested 
events */
       where data->current_event is true since we're still handling the 
FocusOut event.  Since we're not processing nested events, we'll never 
be able to process the usual events like keys or mouse events which 
could exit this nested event loop.

This type of error occurs in a few places in our application, where a 
WM_KILLFOCUS message to an edit box triggers some input validation and 
displays an error on failure.  This works correctly in the normal case, 
where the user tabs out or clicks on another control in the dialog box 
containing the edit control -- since everything stays in the same 
top-level window, there is no FocusOut event from X11 and the 
WM_KILLFOCUS is generated internally by wine in response to, say, a 
KeyEvent.  I think these key or mouse events are just posted to the 
windows message queue, and the X11 event handler has already exited by 
the time the application gets around to processing the ensuing 
WM_KILLFOCUS.  But in the case where focus is lost by clicking outside 
the dialog containing the edit control, the WM_KILLFOCUS is generated by 
the FocusOut handler which is still executing, and we lock up.

I suspect this is related to bug 11595 "Notepad++ freezes if native 
application changes a file it has open (dogfood)".  My guess is in that 
case, a FocusIn event triggers something like a WM_ACTIVATE, in which 
notepad++ notices a file is changed and displays a messagebox asking if 
you want to reload.  Since wine is still processing the FocusIn event, 
the modal message loop's call to MsgWaitForMultipleObjectsEx will never 
process any useful events because it's a nested event.  Our 
application's built-in text editor has this same problem.

I don't understand the event handling code well enough to propose a 
solution.  As a test, I allowed nested event processing and it solved 
the problem without introducing any obvious errors, but I'm sure that 
check was in there for a reason.  It's probably better to keep the 
application code from being executed from inside the event handler, if 
that's possible.

Eric
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: winetest.cpp
URL: <http://www.winehq.org/pipermail/wine-devel/attachments/20110616/d7cf11cc/attachment-0001.asc>


More information about the wine-devel mailing list