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