andlabs
andlabs

Reputation: 11588

How do I initiate a user mouse-driven move or resize for custom window borders on Windows on a borderless window when the event comes to a child?

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

Answers (1)

Remy Lebeau
Remy Lebeau

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:

  1. 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
    
  2. 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.

  3. 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:

  1. 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.

  2. 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

Related Questions