Reputation: 126787
I have a Win32 application with a main window and a child window; in some circumstances, the child window captures the mouse using SetCapture
.
In these circumstances, if I disable the child window using EnableWindow(hChild, FALSE)
I immediately stop receiving mouse events. However, if I disable its parent using EnableWindow(hMainWindow, FALSE)
, the child window keeps receiving events as long as the mouse is captured. Once it's released, the child window regularly stops receiving events until the main window is enabled again.
Why this difference? Aren't child windows disabled as well when any of their parents is disabled?
(inspired by a real problem we had today at work, given that there's not much discussion about SetCapture
& co. I hope this will help someone in future)
Upvotes: 2
Views: 583
Reputation: 126787
Aren't child windows disabled as well when any of their parents is disabled?
When you disable a window, its child windows technically aren't disabled—even if the parent window is disabled, if you call IsWindowEnabled
over any of them you'll get TRUE
, and they won't have the WS_DISABLED
style. However, they are disabled in practice, as normally they won't receive any input.
This comes from how the parent window being disabled affects the "regular" input events dispatch: when Windows has to dispatch a mouse event, it looks recursively for the "most nested" window whose client area contains the cursor1, but stops when it meets a disabled window, and doesn't recurse over its children. This ensures that even the children of a disabled window normally don't receive any input events.
However, when a window captures the mouse, regular dispatch is bypassed: all mouse events will be dispatched straight to the capturing window, regardless of whether it has a disabled parent, or even if it's disabled itself.
But wait: this doesn't match the observation:
if I disable the child window using
EnableWindow(hChild, FALSE)
I immediately stop receiving mouse events.
This comes from the fact that EnableWindow
doesn't just set the WS_DISABLED
style, but does some additional magic; in particular
If the window is being disabled, the system sends a
WM_CANCELMODE
message.
This message was introduced to ask to the receiving window to cancel any "temporary" mode, such as open menus or captured mouse, in preparation to disable the window to e.g. display a dialog box:
For example, the system sends this message to the active window when a dialog box or message box is displayed. Certain functions also send this message explicitly to the specified window regardless of whether it is the active window. For example, the
EnableWindow
function sends this message when disabling the specified window.
These tasks are accomplished by the default window procedure:
When the
WM_CANCELMODE
message is sent, theDefWindowProc
function cancels internal processing of standard scroll bar input, cancels internal menu processing, and releases the mouse capture.
so, if you were so inclined, you could disable this behavior completely by handling WM_CANCELMODE
explicitly in your window procedure, bypassing the default processing (although I wouldn't recommend it). In that case, disabling the child window itself would keep the mouse captured exactly as in the EnableWindow(hMainWindow, FALSE)
case.
So, ultimately the difference arises from the fact that EnableWindow
does this extra trick only for the window that is being disabled, not for its children, so if any of them is still capturing the mouse, it'll remain captured.
Upvotes: 5