Centralizes all clipping behavior into -startClippingCursor: and -stopClippingCursor.
Signed-off-by: Tim Clem tclem@codeweavers.com --- The current methods are confusingly named and, in some cases, broken.
-updateCursorClippingState has an incomplete picture of when clipping should be enabled or disabled. Worse, -deactivateCursorClipping just disables the event tap without calling CGAssociateMouseAndMouseCursorPosition(true), so it will lock up the cursor if called while the app is active. There are two main scenarios where -updateCursorClippingState is called: when a window is being dragged and when the app is (de)activated.
The drag-related calls can be removed entirely because the handlers in window.c call ClipCursor(NULL) when a window is being dragged. (This is in fact the only reason that the cursor doesn't get locked up when windows are dragged right now.)
As for app (de)activation, the tap already ignores events if the app isn't active, so the -updateCursorClippingState calls there can be removed as well. (Moreover, Windows will cancel cursor clipping if the app loses focus; the next patch calls -stopClippingCursor when the app resigns active.)
dlls/winemac.drv/cocoa_app.m | 52 +++++++++++------------------------- 1 file changed, 15 insertions(+), 37 deletions(-)
diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m index 2d18da7f99a8..806252651613 100644 --- a/dlls/winemac.drv/cocoa_app.m +++ b/dlls/winemac.drv/cocoa_app.m @@ -1456,33 +1456,6 @@ - (BOOL) setCursorPosition:(CGPoint)pos return ret; }
- - (void) activateCursorClipping - { - if (cursorClippingEventTap && !CGEventTapIsEnabled(cursorClippingEventTap)) - { - CGEventTapEnable(cursorClippingEventTap, TRUE); - [self setCursorPosition:NSPointToCGPoint([self flippedMouseLocation:[NSEvent mouseLocation]])]; - } - } - - - (void) deactivateCursorClipping - { - if (cursorClippingEventTap && CGEventTapIsEnabled(cursorClippingEventTap)) - { - CGEventTapEnable(cursorClippingEventTap, FALSE); - [warpRecords removeAllObjects]; - lastSetCursorPositionTime = [[NSProcessInfo processInfo] systemUptime]; - } - } - - - (void) updateCursorClippingState - { - if (clippingCursor && [NSApp isActive] && ![windowsBeingDragged count]) - [self activateCursorClipping]; - else - [self deactivateCursorClipping]; - } - - (void) updateWindowsForCursorClipping { WineWindow* window; @@ -1510,7 +1483,10 @@ - (BOOL) startClippingCursor:(CGRect)rect
clippingCursor = TRUE; cursorClipRect = rect; - [self updateCursorClippingState]; + + CGEventTapEnable(cursorClippingEventTap, TRUE); + [self setCursorPosition:NSPointToCGPoint([self flippedMouseLocation:[NSEvent mouseLocation]])]; + [self updateWindowsForCursorClipping];
return TRUE; @@ -1518,12 +1494,21 @@ - (BOOL) startClippingCursor:(CGRect)rect
- (BOOL) stopClippingCursor { - CGError err = CGAssociateMouseAndMouseCursorPosition(true); + CGError err; + + if (!clippingCursor) + return TRUE; + + err = CGAssociateMouseAndMouseCursorPosition(true); if (err != kCGErrorSuccess) return FALSE;
clippingCursor = FALSE; - [self updateCursorClippingState]; + + CGEventTapEnable(cursorClippingEventTap, FALSE); + [warpRecords removeAllObjects]; + lastSetCursorPositionTime = [[NSProcessInfo processInfo] systemUptime]; + [self updateWindowsForCursorClipping];
return TRUE; @@ -1554,7 +1539,6 @@ - (void) window:(WineWindow*)window isBeingDragged:(BOOL)dragged [windowsBeingDragged addObject:window]; else [windowsBeingDragged removeObject:window]; - [self updateCursorClippingState]; }
- (void) windowWillOrderOut:(WineWindow*)window @@ -1584,7 +1568,6 @@ - (void) handleWindowDrag:(WineWindow*)window begin:(BOOL)begin [windowsBeingDragged removeObject:window]; eventType = WINDOW_DRAG_END; } - [self updateCursorClippingState];
event = macdrv_create_event(eventType, window); if (eventType == WINDOW_DRAG_BEGIN) @@ -2161,7 +2144,6 @@ - (void) setupObservations }); } [windowsBeingDragged removeObject:window]; - [self updateCursorClippingState]; }];
if (useDragNotifications) { @@ -2305,8 +2287,6 @@ - (void)applicationDidBecomeActive:(NSNotification *)notification [self setMode:mode forDisplay:[displayID unsignedIntValue]]; }
- [self updateCursorClippingState]; - [self updateFullscreenWindows]; [self adjustWindowLevels:YES];
@@ -2349,8 +2329,6 @@ - (void)applicationDidResignActive:(NSNotification *)notification macdrv_event* event; WineEventQueue* queue;
- [self updateCursorClippingState]; - [self invalidateGotFocusEvents];
event = macdrv_create_event(APP_DEACTIVATED, nil);
Testing on Windows confirms this behavior.
Signed-off-by: Tim Clem tclem@codeweavers.com --- v2: Do this at a lower level so that the server (and, e.g., GetClipCursor) stay in sync.
dlls/winemac.drv/window.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index 622f136930c3..e25e142bd1a6 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -2406,6 +2406,8 @@ void macdrv_app_activated(void) */ void macdrv_app_deactivated(void) { + ClipCursor(NULL); + if (GetActiveWindow() == GetForegroundWindow()) { TRACE("setting fg to desktop\n");
Testing on Windows confirms this behavior.
Signed-off-by: Tim Clem tclem@codeweavers.com --- v2: Do this at a lower level so that the server (and, e.g., GetClipCursor) stay in sync.
Note that ef46771 locked windows when the cursor is clipped by default. The Mac driver registry key CursorClippingLocksWindows must be set to N to enable this behavior.
dlls/winemac.drv/window.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index e25e142bd1a6..eb23812d57c3 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -2873,6 +2873,8 @@ BOOL query_resize_start(HWND hwnd) { TRACE("hwnd %p\n", hwnd);
+ ClipCursor(NULL); + sync_window_min_max_info(hwnd); SendMessageW(hwnd, WM_ENTERSIZEMOVE, 0, 0);
There's no analogous state on Windows, where an app is focused but has no visible windows, but this seems like the best behavior.
Signed-off-by: Tim Clem tclem@codeweavers.com --- v2: Do this at a lower level to keep the server in sync. There was no pre-existing event that mapped to exactly what was needed here, so this patch adds WINDOW_DID_MINIMIZE.
dlls/winemac.drv/cocoa_app.m | 22 ++++++++++++++++++++++ dlls/winemac.drv/cocoa_window.m | 7 +++++++ dlls/winemac.drv/event.c | 3 +++ dlls/winemac.drv/macdrv.h | 1 + dlls/winemac.drv/macdrv_cocoa.h | 2 ++ dlls/winemac.drv/window.c | 15 +++++++++++++++ 6 files changed, 50 insertions(+)
diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m index 806252651613..ff8f15553bb7 100644 --- a/dlls/winemac.drv/cocoa_app.m +++ b/dlls/winemac.drv/cocoa_app.m @@ -1553,6 +1553,17 @@ - (void) windowWillOrderOut:(WineWindow*)window } }
+ - (BOOL) isAnyWineWindowVisible + { + for (WineWindow* w in [NSApp windows]) + { + if ([w isKindOfClass:[WineWindow class]] && ![w isMiniaturized] && [w isVisible]) + return YES; + } + + return NO; + } + - (void) handleWindowDrag:(WineWindow*)window begin:(BOOL)begin { macdrv_event* event; @@ -2823,3 +2834,14 @@ void macdrv_set_cocoa_retina_mode(int new_mode) [[WineApplicationController sharedController] setRetinaMode:new_mode]; }); } + +int macdrv_is_any_wine_window_visible(void) +{ + __block int ret = FALSE; + + OnMainThread(^{ + ret = [[WineApplicationController sharedController] isAnyWineWindowVisible]; + }); + + return ret; +} diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m index 80cb26934096..812b46bee2ca 100644 --- a/dlls/winemac.drv/cocoa_window.m +++ b/dlls/winemac.drv/cocoa_window.m @@ -2896,9 +2896,16 @@ - (void) windowDidFailToExitFullScreen:(NSWindow*)window
- (void)windowDidMiniaturize:(NSNotification *)notification { + macdrv_event* event; + if (fullscreen && [self isOnActiveSpace]) [[WineApplicationController sharedController] updateFullscreenWindows]; + [self checkWineDisplayLink]; + + event = macdrv_create_event(WINDOW_DID_MINIMIZE, self); + [queue postEvent:event]; + macdrv_release_event(event); }
- (void)windowDidMove:(NSNotification *)notification diff --git a/dlls/winemac.drv/event.c b/dlls/winemac.drv/event.c index 7ec59c0f9038..f197af0808eb 100644 --- a/dlls/winemac.drv/event.c +++ b/dlls/winemac.drv/event.c @@ -275,6 +275,9 @@ void macdrv_handle_event(const macdrv_event *event) case WINDOW_CLOSE_REQUESTED: macdrv_window_close_requested(hwnd); break; + case WINDOW_DID_MINIMIZE: + macdrv_window_did_minimize(hwnd); + break; case WINDOW_DID_UNMINIMIZE: macdrv_window_did_unminimize(hwnd); break; diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index a7c0b4cac879..3f986901b2c5 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -170,6 +170,7 @@ static inline RECT rect_from_cgrect(CGRect cgrect) extern void macdrv_app_quit_requested(const macdrv_event *event) DECLSPEC_HIDDEN; extern void macdrv_window_maximize_requested(HWND hwnd) DECLSPEC_HIDDEN; extern void macdrv_window_minimize_requested(HWND hwnd) DECLSPEC_HIDDEN; +extern void macdrv_window_did_minimize(HWND hwnd) DECLSPEC_HIDDEN; 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; diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index 81840e067a9b..2c903bfb12a3 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -339,6 +339,7 @@ extern int macdrv_set_display_mode(const struct macdrv_display* display, STATUS_ITEM_MOUSE_MOVE, WINDOW_BROUGHT_FORWARD, WINDOW_CLOSE_REQUESTED, + WINDOW_DID_MINIMIZE, WINDOW_DID_UNMINIMIZE, WINDOW_DRAG_BEGIN, WINDOW_DRAG_END, @@ -598,6 +599,7 @@ extern void macdrv_set_window_color_key(macdrv_window w, CGFloat keyRed, CGFloat extern uint32_t macdrv_window_background_color(void) DECLSPEC_HIDDEN; extern void macdrv_send_text_input_event(int pressed, unsigned int flags, int repeat, int keyc, void* data, int* done) DECLSPEC_HIDDEN; +extern int macdrv_is_any_wine_window_visible(void) DECLSPEC_HIDDEN;
/* keyboard */ diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index eb23812d57c3..07f04993ee81 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -2438,6 +2438,21 @@ void macdrv_window_minimize_requested(HWND hwnd) }
+/*********************************************************************** + * macdrv_window_did_minimize + * + * Handler for WINDOW_DID_MINIMIZE events. + */ +void macdrv_window_did_minimize(HWND hwnd) +{ + TRACE("win %p\n", hwnd); + + /* If all our windows are minimized, disable cursor clipping. */ + if (!macdrv_is_any_wine_window_visible()) + ClipCursor(NULL); +} + + /*********************************************************************** * macdrv_window_did_unminimize *
We no longer enable or disable the event tap manually, and it re-enables itself on kCGEventTapDisabledByTimeout, so this check is not needed.
Signed-off-by: Tim Clem tclem@codeweavers.com --- dlls/winemac.drv/cocoa_app.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m index ff8f15553bb7..c4c745ff7324 100644 --- a/dlls/winemac.drv/cocoa_app.m +++ b/dlls/winemac.drv/cocoa_app.m @@ -1473,8 +1473,7 @@ - (BOOL) startClippingCursor:(CGRect)rect if (!cursorClippingEventTap && ![self installEventTap]) return FALSE;
- if (clippingCursor && CGRectEqualToRect(rect, cursorClipRect) && - CGEventTapIsEnabled(cursorClippingEventTap)) + if (clippingCursor && CGRectEqualToRect(rect, cursorClipRect)) return TRUE;
err = CGAssociateMouseAndMouseCursorPosition(false);