From f068e329c1fe45a6a55c7a3ea013740dbb4f41db Mon Sep 17 00:00:00 2001 From: Ken Thomases Date: Wed, 11 Dec 2013 12:50:55 -0600 Subject: [PATCH] winemac: Send WM_{ENTER, EXIT}SIZEMOVE before/after window dragging and run an internal event loop during. This simulates some of what would happen if user32 were managing the drag. The click in the caption would cause WM_SYSCOMMAND/SC_MOVE. The processing of that message is synchronous and doesn't return until the move is complete. Some games require that "blocking" in the internal event loop to prevent them from misbehaving during the drag. --- dlls/winemac.drv/cocoa_app.m | 13 ++++++ dlls/winemac.drv/event.c | 13 +++++- dlls/winemac.drv/macdrv.h | 3 ++ dlls/winemac.drv/macdrv_cocoa.h | 2 + dlls/winemac.drv/window.c | 73 ++++++++++++++++++++++++++++++++- 5 files changed, 101 insertions(+), 3 deletions(-) diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m index 857c0199a2c..ce43e277cad 100644 --- a/dlls/winemac.drv/cocoa_app.m +++ b/dlls/winemac.drv/cocoa_app.m @@ -1882,11 +1882,24 @@ - (BOOL) handleEvent:(NSEvent*)anEvent WineWindow* window = (WineWindow*)[anEvent window]; if ([window isKindOfClass:[WineWindow class]]) { + macdrv_event* event; + int eventType; + if (subtype == 20) + { [windowsBeingDragged addObject:window]; + eventType = WINDOW_DRAG_BEGIN; + } else + { [windowsBeingDragged removeObject:window]; + eventType = WINDOW_DRAG_END; + } [self updateCursorClippingState]; + + event = macdrv_create_event(eventType, window); + [window.queue postEvent:event]; + macdrv_release_event(event); } } } diff --git a/dlls/winemac.drv/event.c b/dlls/winemac.drv/event.c index 77df58252e8..13f55f5c447 100644 --- a/dlls/winemac.drv/event.c +++ b/dlls/winemac.drv/event.c @@ -51,6 +51,8 @@ static const char *dbgstr_event(int type) "WINDOW_BROUGHT_FORWARD", "WINDOW_CLOSE_REQUESTED", "WINDOW_DID_UNMINIMIZE", + "WINDOW_DRAG_BEGIN", + "WINDOW_DRAG_END", "WINDOW_FRAME_CHANGED", "WINDOW_GOT_FOCUS", "WINDOW_LOST_FOCUS", @@ -114,6 +116,8 @@ static macdrv_event_mask get_event_mask(DWORD mask) event_mask |= event_mask_for_type(QUERY_EVENT); event_mask |= event_mask_for_type(RELEASE_CAPTURE); event_mask |= event_mask_for_type(WINDOW_BROUGHT_FORWARD); + event_mask |= event_mask_for_type(WINDOW_DRAG_BEGIN); + event_mask |= event_mask_for_type(WINDOW_DRAG_END); event_mask |= event_mask_for_type(WINDOW_MINIMIZE_REQUESTED); event_mask |= event_mask_for_type(WINDOW_RESIZE_ENDED); } @@ -243,6 +247,12 @@ void macdrv_handle_event(const macdrv_event *event) case WINDOW_DID_UNMINIMIZE: macdrv_window_did_unminimize(hwnd); break; + case WINDOW_DRAG_BEGIN: + macdrv_window_drag_begin(hwnd); + break; + case WINDOW_DRAG_END: + macdrv_window_drag_end(hwnd); + break; case WINDOW_FRAME_CHANGED: macdrv_window_frame_changed(hwnd, event); break; @@ -307,7 +317,8 @@ DWORD CDECL macdrv_MsgWaitForMultipleObjectsEx(DWORD count, const HANDLE *handle } if (data->current_event && data->current_event->type != QUERY_EVENT && - data->current_event->type != APP_QUIT_REQUESTED) + data->current_event->type != APP_QUIT_REQUESTED && + data->current_event->type != WINDOW_DRAG_BEGIN) event_mask = 0; /* don't process nested events */ if (process_events(data->queue, event_mask)) ret = count - 1; diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 32a342b4cf4..2234cca4c2e 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -140,6 +140,7 @@ static inline RECT rect_from_cgrect(CGRect cgrect) unsigned int ulw_layered : 1; /* has UpdateLayeredWindow() been called for window? */ unsigned int per_pixel_alpha : 1; /* is window using per-pixel alpha? */ unsigned int minimized : 1; /* is window minimized? */ + unsigned int being_dragged : 1; /* is window being dragged under Cocoa's control? */ struct window_surface *surface; struct window_surface *unminimized_surface; }; @@ -167,6 +168,8 @@ static inline RECT rect_from_cgrect(CGRect cgrect) extern void macdrv_window_did_unminimize(HWND hwnd) DECLSPEC_HIDDEN; extern void macdrv_window_brought_forward(HWND hwnd) DECLSPEC_HIDDEN; extern void macdrv_window_resize_ended(HWND hwnd) DECLSPEC_HIDDEN; +extern void macdrv_window_drag_begin(HWND hwnd) DECLSPEC_HIDDEN; +extern void macdrv_window_drag_end(HWND hwnd) DECLSPEC_HIDDEN; extern BOOL query_resize_start(HWND hwnd) DECLSPEC_HIDDEN; extern BOOL query_min_max_info(HWND hwnd) DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index f7ffc509a5f..5073db81412 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -191,6 +191,8 @@ extern int macdrv_set_display_mode(const struct macdrv_display* display, WINDOW_BROUGHT_FORWARD, WINDOW_CLOSE_REQUESTED, WINDOW_DID_UNMINIMIZE, + WINDOW_DRAG_BEGIN, + WINDOW_DRAG_END, WINDOW_FRAME_CHANGED, WINDOW_GOT_FOCUS, WINDOW_LOST_FOCUS, diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index 6360c3245e0..bd710ceaefe 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -1681,6 +1681,7 @@ void macdrv_window_frame_changed(HWND hwnd, const macdrv_event *event) HWND parent; UINT flags = SWP_NOACTIVATE | SWP_NOZORDER; int width, height; + BOOL being_dragged; if (!hwnd) return; if (!(data = get_win_data(hwnd))) return; @@ -1719,16 +1720,17 @@ void macdrv_window_frame_changed(HWND hwnd, const macdrv_event *event) TRACE("%p resizing from (%dx%d) to (%dx%d)\n", hwnd, data->window_rect.right - data->window_rect.left, data->window_rect.bottom - data->window_rect.top, width, height); + being_dragged = data->being_dragged; release_win_data(data); if (event->window_frame_changed.fullscreen) flags |= SWP_NOSENDCHANGING; if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE)) { - if (!event->window_frame_changed.in_resize) + if (!event->window_frame_changed.in_resize && !being_dragged) SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0); SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags); - if (!event->window_frame_changed.in_resize) + if (!event->window_frame_changed.in_resize && !being_dragged) SendMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0); } } @@ -1916,6 +1918,73 @@ void macdrv_window_resize_ended(HWND hwnd) } +/*********************************************************************** + * macdrv_window_drag_begin + * + * Handler for WINDOW_DRAG_BEGIN events. + */ +void macdrv_window_drag_begin(HWND hwnd) +{ + struct macdrv_win_data *data; + MSG msg; + + TRACE("win %p\n", hwnd); + + if (!(data = get_win_data(hwnd))) return; + if (data->being_dragged) goto done; + + data->being_dragged = 1; + release_win_data(data); + + SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0); + + while (GetMessageW(&msg, 0, 0, 0)) + { + if (!CallMsgFilterW(&msg, MSGF_SIZE) && msg.message != WM_KEYDOWN && + msg.message != WM_MOUSEMOVE && msg.message != WM_LBUTTONDOWN && msg.message != WM_LBUTTONUP) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + + if (msg.message == WM_EXITSIZEMOVE) break; + } + + TRACE("done\n"); + + if ((data = get_win_data(hwnd))) + data->being_dragged = 0; + +done: + release_win_data(data); +} + + +/*********************************************************************** + * macdrv_window_drag_end + * + * Handler for WINDOW_DRAG_END events. + */ +void macdrv_window_drag_end(HWND hwnd) +{ + struct macdrv_win_data *data; + BOOL being_dragged; + + TRACE("win %p\n", hwnd); + + if (!(data = get_win_data(hwnd))) return; + being_dragged = data->being_dragged; + release_win_data(data); + + if (being_dragged) + { + /* Post this rather than sending it, so that the message loop in + macdrv_window_drag_begin() will see it. */ + PostMessageW(hwnd, WM_EXITSIZEMOVE, 0, 0); + } +} + + struct quit_info { HWND *wins; UINT capacity;