Reputation: 11588
I have a borderless window whose sole child, which is always the size of the window, is a third party component. That component wants to be able to notify me, when a WM_MOUSEDOWN
has occurred in certain areas that is up to its discretion, to move or resize the window (as if it wasn't borderless). It also wants to decide the event to use in question.
Because the window is borderless and the child window has already received the mouse message, I don't think I would be able to override WM_NCHITTEST
, would I? (Or in other words, does the parent window always get WM_NCHITTEST
before my child gets WM_LBUTTONDOWN
? Or only upon first activation/during a capture?)
GTK+ used to call DefWindowProc()
with WM_NCLBUTTONDOWN
to manually trigger that modal event loop. Is this the way to do it?
What about SC_MOVE
in WM_SYSCOMMAND
? Is that only for keyboard-driven window moves and resizes, not mouse-driven ones?
Or am I going to have to do this manually? I know it's a modal loop of its own that uses one of the message filter constants, and I know that Aero Snap would need to be done manually, at the least.
I need to do this on Windows Vista or higher.
Thanks.
Upvotes: 2
Views: 900
Reputation: 595837
Since your parent window is border-less and completely covered by the child window, the parent will not receive WM_NCHITTEST
by default. All WM_NCHITTEST
messages will be received by the child first.
However, you can still allow the user to resize your parent window normally with a little extra coding. There are a few different ways you can handle this:
subclass the child window to intercept the WM_NCHITTEST
message. When received, pass the message to the child's default message handler first, and if it returns HTCLIENT
and the screen coordinates provided in lParam
are within an area of the parent window that you want to use for resizing, return HTTRANSPARENT
instead. That will cause WM_NCHITTEST
to be sent to the parent window next, which can then process WM_NCHITTEST
and return one of the following values depending on the type of resize you want:
HTBOTTOM
HTBOTTOMLEFT
HTBOTTOMRIGHT
HTLEFT
HTRIGHT
HTTOP
HTTOPLEFT
HTTOPRIGHT
in the child window's mousedown event, convert the provided client coordinates of the mouse into screen coordinates, and then call ReleaseCapture()
and send a WM_NCLBUTTONDOWN
message to the parent window, setting wParam
to one of the values mentioned above, and lParam
to the screen coordinates.
in the child window's mousedown event, call ReleaseCapture()
and send a WM_SYSCOMMAND
message to the parent window, setting wParam
to SC_SIZE
plus the desired value below, and lParam
to 0:
SC_SIZE_HTLEFT = 1
SC_SIZE_HTRIGHT = 2
SC_SIZE_HTTOP = 3
SC_SIZE_HTTOPLEFT = 4
SC_SIZE_HTTOPRIGHT = 5
SC_SIZE_HTBOTTOM = 6
SC_SIZE_HTBOTTOMLEFT = 7
SC_SIZE_HTBOTTOMRIGHT = 8
Either way will allow the parent window to resize normally, and everything that involves (mouse tracking, snapping, etc), except for one thing. #1 tricks the OS into thinking the user had moused over the parent window directly, and so it allows the OS to provide visual feedback about which "sizing border" is being used. #2 and #3 will not provide any visual feedback, so you would have to handle that manually via SetCursor()
if desired.
If you want to allow the user to drag the parent window around without resizing it, you can either:
subclass the child WM_NCHITTEST
messages to return HTTRANSPARENT
in the appropriate area, and then have the parent window process WM_NCHITTEST
to return HTCAPTION
.
in the child window's mousedown event, call ReleaseCapture()
and send a WM_SYSCOMMAND
message to the parent window, setting wParam
to SC_DRAGMOVE
(which is undocumented, but its value is $F012
, aka SC_MOVE + 2
), and lParam
set to 0.
Upvotes: 3