Module: wine
Branch: master
Commit: 3e3d982185c62020b7478f433486ade19378ed6e
URL: http://source.winehq.org/git/wine.git/?a=commit;h=3e3d982185c62020b7478f433…
Author: Ken Thomases <ken(a)codeweavers.com>
Date: Tue May 7 03:00:49 2013 -0500
winemac: Prefer absolute mouse moves unless cursor is pinned by clipping or desktop edges.
This fixes an issue with sub-pixel-precise pointing devices on Lion and later.
Wine's notion of the cursor position would get out of sync with the actual position
because deltas don't convey the actual movement distance.
---
dlls/winemac.drv/cocoa_app.h | 1 +
dlls/winemac.drv/cocoa_app.m | 80 +++++++++++++++++++++++++++++++++++++++---
2 files changed, 76 insertions(+), 5 deletions(-)
diff --git a/dlls/winemac.drv/cocoa_app.h b/dlls/winemac.drv/cocoa_app.h
index 5e4d181..3ce8a83 100644
--- a/dlls/winemac.drv/cocoa_app.h
+++ b/dlls/winemac.drv/cocoa_app.h
@@ -57,6 +57,7 @@ enum {
CGFloat primaryScreenHeight;
BOOL primaryScreenHeightValid;
+ NSMutableData* screenFrameCGRects;
WineWindow* lastTargetWindow;
BOOL forceNextMouseMoveAbsolute;
diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m
index e8cca28..b4e15d0 100644
--- a/dlls/winemac.drv/cocoa_app.m
+++ b/dlls/winemac.drv/cocoa_app.m
@@ -170,6 +170,7 @@ int macdrv_err_on;
- (void) dealloc
{
+ [screenFrameCGRects release];
[applicationIcon release];
[warpRecords release];
[cursorTimer release];
@@ -377,10 +378,29 @@ int macdrv_err_on;
if (!primaryScreenHeightValid)
{
NSArray* screens = [NSScreen screens];
- if ([screens count])
+ NSUInteger count = [screens count];
+ if (count)
{
+ NSUInteger size;
+ CGRect* rect;
+ NSScreen* screen;
+
primaryScreenHeight = NSHeight([[screens objectAtIndex:0] frame]);
primaryScreenHeightValid = TRUE;
+
+ size = count * sizeof(CGRect);
+ if (!screenFrameCGRects)
+ screenFrameCGRects = [[NSMutableData alloc] initWithLength:size];
+ else
+ [screenFrameCGRects setLength:size];
+
+ rect = [screenFrameCGRects mutableBytes];
+ for (screen in screens)
+ {
+ CGRect temp = NSRectToCGRect([screen frame]);
+ temp.origin.y = primaryScreenHeight - CGRectGetMaxY(temp);
+ *rect++ = temp;
+ }
}
else
return 1280; /* arbitrary value */
@@ -1157,9 +1177,9 @@ int macdrv_err_on;
if ([targetWindow isKindOfClass:[WineWindow class]])
{
+ CGPoint point = CGEventGetLocation([anEvent CGEvent]);
macdrv_event* event;
- BOOL absolute = forceNextMouseMoveAbsolute || (targetWindow != lastTargetWindow);
- forceNextMouseMoveAbsolute = FALSE;
+ BOOL absolute;
// If we recently warped the cursor (other than in our cursor-clipping
// event tap), discard mouse move events until we see an event which is
@@ -1170,13 +1190,63 @@ int macdrv_err_on;
return;
lastSetCursorPositionTime = 0;
+ forceNextMouseMoveAbsolute = TRUE;
+ }
+
+ if (forceNextMouseMoveAbsolute || targetWindow != lastTargetWindow)
+ {
absolute = TRUE;
+ forceNextMouseMoveAbsolute = FALSE;
+ }
+ else
+ {
+ // Send absolute move events if the cursor is in the interior of
+ // its range. Only send relative moves if the cursor is pinned to
+ // the boundaries of where it can go. We compute the position
+ // that's one additional point in the direction of movement. If
+ // that is outside of the clipping rect or desktop region (the
+ // union of the screen frames), then we figure the cursor would
+ // have moved outside if it could but it was pinned.
+ CGPoint computedPoint = point;
+ CGFloat deltaX = [anEvent deltaX];
+ CGFloat deltaY = [anEvent deltaY];
+
+ if (deltaX > 0.001)
+ computedPoint.x++;
+ else if (deltaX < -0.001)
+ computedPoint.x--;
+
+ if (deltaY > 0.001)
+ computedPoint.y++;
+ else if (deltaY < -0.001)
+ computedPoint.y--;
+
+ // Assume cursor is pinned for now
+ absolute = FALSE;
+ if (!clippingCursor || CGRectContainsPoint(cursorClipRect, computedPoint))
+ {
+ const CGRect* rects;
+ NSUInteger count, i;
+
+ // Caches screenFrameCGRects if necessary
+ [self primaryScreenHeight];
+
+ rects = [screenFrameCGRects bytes];
+ count = [screenFrameCGRects length] / sizeof(rects[0]);
+
+ for (i = 0; i < count; i++)
+ {
+ if (CGRectContainsPoint(rects[i], computedPoint))
+ {
+ absolute = TRUE;
+ break;
+ }
+ }
+ }
}
if (absolute)
{
- CGPoint point = CGEventGetLocation([anEvent CGEvent]);
-
if (clippingCursor)
[self clipCursorLocation:&point];
Module: wine
Branch: master
Commit: d9ae2f3e38663b4f8802b08c13b85da62cf4420b
URL: http://source.winehq.org/git/wine.git/?a=commit;h=d9ae2f3e38663b4f8802b08c1…
Author: Ken Thomases <ken(a)codeweavers.com>
Date: Tue May 7 03:00:44 2013 -0500
winemac: Consolidate scroll wheel handling into -[WineApplicationController handleScrollWheel:].
---
dlls/winemac.drv/cocoa_app.m | 98 +++++++++++++++++++++++++++++++++++++--
dlls/winemac.drv/cocoa_window.m | 79 -------------------------------
2 files changed, 94 insertions(+), 83 deletions(-)
diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m
index bba9859..c518b4e 100644
--- a/dlls/winemac.drv/cocoa_app.m
+++ b/dlls/winemac.drv/cocoa_app.m
@@ -1300,6 +1300,99 @@ int macdrv_err_on;
forceNextMouseMoveAbsolute = TRUE;
}
+ - (void) handleScrollWheel:(NSEvent*)theEvent
+ {
+ WineWindow* window = (WineWindow*)[theEvent window];
+
+ if ([window isKindOfClass:[WineWindow class]])
+ {
+ CGEventRef cgevent = [theEvent CGEvent];
+ CGPoint pt = CGEventGetLocation(cgevent);
+ NSPoint nspoint = [self flippedMouseLocation:NSPointFromCGPoint(pt)];
+ NSRect contentRect = [window contentRectForFrameRect:[window frame]];
+
+ // Only process the event if it was in the window's content area.
+ if (NSPointInRect(nspoint, contentRect))
+ {
+ macdrv_event* event;
+ CGFloat x, y;
+ BOOL continuous = FALSE;
+
+ event = macdrv_create_event(MOUSE_SCROLL, window);
+ event->mouse_scroll.x = pt.x;
+ event->mouse_scroll.y = pt.y;
+ event->mouse_scroll.time_ms = [self ticksForEventTime:[theEvent timestamp]];
+
+ if (CGEventGetIntegerValueField(cgevent, kCGScrollWheelEventIsContinuous))
+ {
+ continuous = TRUE;
+
+ /* Continuous scroll wheel events come from high-precision scrolling
+ hardware like Apple's Magic Mouse, Mighty Mouse, and trackpads.
+ For these, we can get more precise data from the CGEvent API. */
+ /* Axis 1 is vertical, axis 2 is horizontal. */
+ x = CGEventGetDoubleValueField(cgevent, kCGScrollWheelEventPointDeltaAxis2);
+ y = CGEventGetDoubleValueField(cgevent, kCGScrollWheelEventPointDeltaAxis1);
+ }
+ else
+ {
+ double pixelsPerLine = 10;
+ CGEventSourceRef source;
+
+ /* The non-continuous values are in units of "lines", not pixels. */
+ if ((source = CGEventCreateSourceFromEvent(cgevent)))
+ {
+ pixelsPerLine = CGEventSourceGetPixelsPerLine(source);
+ CFRelease(source);
+ }
+
+ x = pixelsPerLine * [theEvent deltaX];
+ y = pixelsPerLine * [theEvent deltaY];
+ }
+
+ /* Mac: negative is right or down, positive is left or up.
+ Win32: negative is left or down, positive is right or up.
+ So, negate the X scroll value to translate. */
+ x = -x;
+
+ /* The x,y values so far are in pixels. Win32 expects to receive some
+ fraction of WHEEL_DELTA == 120. By my estimation, that's roughly
+ 6 times the pixel value. */
+ event->mouse_scroll.x_scroll = 6 * x;
+ event->mouse_scroll.y_scroll = 6 * y;
+
+ if (!continuous)
+ {
+ /* For non-continuous "clicky" wheels, if there was any motion, make
+ sure there was at least WHEEL_DELTA motion. This is so, at slow
+ speeds where the system's acceleration curve is actually reducing the
+ scroll distance, the user is sure to get some action out of each click.
+ For example, this is important for rotating though weapons in a
+ first-person shooter. */
+ if (0 < event->mouse_scroll.x_scroll && event->mouse_scroll.x_scroll < 120)
+ event->mouse_scroll.x_scroll = 120;
+ else if (-120 < event->mouse_scroll.x_scroll && event->mouse_scroll.x_scroll < 0)
+ event->mouse_scroll.x_scroll = -120;
+
+ if (0 < event->mouse_scroll.y_scroll && event->mouse_scroll.y_scroll < 120)
+ event->mouse_scroll.y_scroll = 120;
+ else if (-120 < event->mouse_scroll.y_scroll && event->mouse_scroll.y_scroll < 0)
+ event->mouse_scroll.y_scroll = -120;
+ }
+
+ if (event->mouse_scroll.x_scroll || event->mouse_scroll.y_scroll)
+ [window.queue postEvent:event];
+
+ macdrv_release_event(event);
+
+ // Since scroll wheel events deliver absolute cursor position, the
+ // accumulating delta from move events is invalidated. Make sure next
+ // mouse move event starts over from an absolute baseline.
+ forceNextMouseMoveAbsolute = TRUE;
+ }
+ }
+ }
+
// Returns TRUE if the event was handled and caller should do nothing more
// with it. Returns FALSE if the caller should process it as normal and
// then call -didSendEvent:.
@@ -1327,10 +1420,7 @@ int macdrv_err_on;
}
else if (type == NSScrollWheel)
{
- // Since scroll wheel events deliver absolute cursor position, the
- // accumulating delta from move events is invalidated. Make sure next
- // mouse move event starts over from an absolute baseline.
- forceNextMouseMoveAbsolute = TRUE;
+ [self handleScrollWheel:anEvent];
}
else if (type == NSKeyDown && ![anEvent isARepeat] && [anEvent keyCode] == kVK_Tab)
{
diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m
index 0a751bd..ae69479 100644
--- a/dlls/winemac.drv/cocoa_window.m
+++ b/dlls/winemac.drv/cocoa_window.m
@@ -1102,85 +1102,6 @@ static inline void fix_generic_modifiers_by_device(NSUInteger* modifiers)
}
}
- - (void) scrollWheel:(NSEvent *)theEvent
- {
- CGPoint pt;
- macdrv_event* event;
- CGEventRef cgevent;
- CGFloat x, y;
- BOOL continuous = FALSE;
-
- cgevent = [theEvent CGEvent];
- pt = CGEventGetLocation(cgevent);
-
- event = macdrv_create_event(MOUSE_SCROLL, self);
- event->mouse_scroll.x = pt.x;
- event->mouse_scroll.y = pt.y;
- event->mouse_scroll.time_ms = [[WineApplicationController sharedController] ticksForEventTime:[theEvent timestamp]];
-
- if (CGEventGetIntegerValueField(cgevent, kCGScrollWheelEventIsContinuous))
- {
- continuous = TRUE;
-
- /* Continuous scroll wheel events come from high-precision scrolling
- hardware like Apple's Magic Mouse, Mighty Mouse, and trackpads.
- For these, we can get more precise data from the CGEvent API. */
- /* Axis 1 is vertical, axis 2 is horizontal. */
- x = CGEventGetDoubleValueField(cgevent, kCGScrollWheelEventPointDeltaAxis2);
- y = CGEventGetDoubleValueField(cgevent, kCGScrollWheelEventPointDeltaAxis1);
- }
- else
- {
- double pixelsPerLine = 10;
- CGEventSourceRef source;
-
- /* The non-continuous values are in units of "lines", not pixels. */
- if ((source = CGEventCreateSourceFromEvent(cgevent)))
- {
- pixelsPerLine = CGEventSourceGetPixelsPerLine(source);
- CFRelease(source);
- }
-
- x = pixelsPerLine * [theEvent deltaX];
- y = pixelsPerLine * [theEvent deltaY];
- }
-
- /* Mac: negative is right or down, positive is left or up.
- Win32: negative is left or down, positive is right or up.
- So, negate the X scroll value to translate. */
- x = -x;
-
- /* The x,y values so far are in pixels. Win32 expects to receive some
- fraction of WHEEL_DELTA == 120. By my estimation, that's roughly
- 6 times the pixel value. */
- event->mouse_scroll.x_scroll = 6 * x;
- event->mouse_scroll.y_scroll = 6 * y;
-
- if (!continuous)
- {
- /* For non-continuous "clicky" wheels, if there was any motion, make
- sure there was at least WHEEL_DELTA motion. This is so, at slow
- speeds where the system's acceleration curve is actually reducing the
- scroll distance, the user is sure to get some action out of each click.
- For example, this is important for rotating though weapons in a
- first-person shooter. */
- if (0 < event->mouse_scroll.x_scroll && event->mouse_scroll.x_scroll < 120)
- event->mouse_scroll.x_scroll = 120;
- else if (-120 < event->mouse_scroll.x_scroll && event->mouse_scroll.x_scroll < 0)
- event->mouse_scroll.x_scroll = -120;
-
- if (0 < event->mouse_scroll.y_scroll && event->mouse_scroll.y_scroll < 120)
- event->mouse_scroll.y_scroll = 120;
- else if (-120 < event->mouse_scroll.y_scroll && event->mouse_scroll.y_scroll < 0)
- event->mouse_scroll.y_scroll = -120;
- }
-
- if (event->mouse_scroll.x_scroll || event->mouse_scroll.y_scroll)
- [queue postEvent:event];
-
- macdrv_release_event(event);
- }
-
/*
* ---------- NSWindowDelegate methods ----------