Signed-off-by: Elaine Lefler elaineclefler@gmail.com ---
v2: Was PATCH 3/3. Splitting into smaller patches as per feedback. --- dlls/winemac.drv/cocoa_app.h | 2 + dlls/winemac.drv/cocoa_app.m | 59 +++++++--- dlls/winemac.drv/cocoa_window.h | 3 +- dlls/winemac.drv/cocoa_window.m | 201 +++++++++++++++----------------- dlls/winemac.drv/macdrv.h | 1 - dlls/winemac.drv/macdrv_cocoa.h | 5 +- dlls/winemac.drv/surface.c | 124 +++++++++----------- dlls/winemac.drv/window.c | 4 +- 8 files changed, 204 insertions(+), 195 deletions(-)
diff --git a/dlls/winemac.drv/cocoa_app.h b/dlls/winemac.drv/cocoa_app.h index 52c91c0621f..b55c55f2995 100644 --- a/dlls/winemac.drv/cocoa_app.h +++ b/dlls/winemac.drv/cocoa_app.h @@ -124,6 +124,8 @@ @interface WineApplicationController : NSObject <NSApplicationDelegate>
id<WineClipCursorHandler> clipCursorHandler;
+ NSMutableArray* wineWindows; + NSImage* applicationIcon;
BOOL beenActive; diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m index 8c525333e8d..e8b88286d24 100644 --- a/dlls/winemac.drv/cocoa_app.m +++ b/dlls/winemac.drv/cocoa_app.m @@ -47,6 +47,25 @@ + (void) setAllowsAutomaticWindowTabbing:(BOOL)allows; #endif
+@interface NSWindow (WineNSPointExtensions) + +/* Reimplementation of -convertPointFromScreen: which isn't available on all + * supported macOS versions */ +- (NSPoint)wineConvertPointFromScreen:(NSPoint)point; + +@end + +@implementation NSWindow (WineNSPointExtensions) + +- (NSPoint)wineConvertPointFromScreen:(NSPoint)point +{ + NSPoint origin = self.frame.origin; + return NSMakePoint(point.x - origin.x, point.y - origin.y); +} + +@end + + /*********************************************************************** * WineLocalizedString * @@ -204,6 +223,7 @@ - (void) dealloc [keyWindows release]; [eventQueues release]; [eventQueuesLock release]; + [wineWindows release]; if (requestsManipQueue) dispatch_release(requestsManipQueue); [requests release]; if (requestSource) @@ -571,7 +591,6 @@ - (WineWindow*) frontWineWindow - (void) adjustWindowLevels:(BOOL)active { NSArray* windowNumbers; - NSMutableArray* wineWindows; NSNumber* windowNumber; NSUInteger nextFloatingIndex = 0; __block NSInteger maxLevel = NSIntegerMin; @@ -582,6 +601,8 @@ - (void) adjustWindowLevels:(BOOL)active
if ([NSApp isHidden]) return;
+ [wineWindows release]; + windowNumbers = [NSWindow windowNumbersWithOptions:0]; wineWindows = [[NSMutableArray alloc] initWithCapacity:[windowNumbers count]];
@@ -652,8 +673,6 @@ - (void) adjustWindowLevels:(BOOL)active
NSEnableScreenUpdates();
- [wineWindows release]; - // The above took care of the visible windows on the current space. That // leaves windows on other spaces, minimized windows, and windows which // are not ordered in. We want to leave windows on other spaces alone @@ -1337,19 +1356,33 @@ - (void) handleMouseMove:(NSEvent*)anEvent targetWindow = (WineWindow*)[anEvent window]; else { - /* Because of the way -[NSWindow setAcceptsMouseMovedEvents:] works, the - event indicates its window is the main window, even if the cursor is - over a different window. Find the actual WineWindow that is under the - cursor and post the event as being for that window. */ + /* Due to our use of NSTrackingArea and the way Cocoa directs mouse + * moves, the window receiving the event is probably not the one + * with the cursor. Find the window that actually has the cursor by + * hit-testing front to back. */ CGPoint cgpoint = CGEventGetLocation([anEvent CGEvent]); NSPoint point = [self flippedMouseLocation:NSPointFromCGPoint(cgpoint)]; - NSInteger windowUnderNumber; + WineWindow* window;
- windowUnderNumber = [NSWindow windowNumberAtPoint:point - belowWindowWithWindowNumber:0]; - targetWindow = (WineWindow*)[NSApp windowWithWindowNumber:windowUnderNumber]; - if (!NSMouseInRect(point, [targetWindow contentRectForFrameRect:[targetWindow frame]], NO)) - targetWindow = nil; + targetWindow = nil; + + for (window in wineWindows) + { + NSPoint windowPoint = [window wineConvertPointFromScreen:point]; + BOOL isHit = ([window.contentView hitTest:windowPoint] != nil); + + /* Windows with transparency must be instructed to ignore + * mouse-downs when the hovered pixel is not visible. The + * window's tracking area still reports events. */ + if (window.needsTransparency) + [window setIgnoresMouseEvents:!isHit && NSMouseInRect(windowPoint, window.contentView.frame, NO)]; + + if (isHit) + { + targetWindow = (WineWindow*)window; + break; + } + } }
if ([targetWindow isKindOfClass:[WineWindow class]]) diff --git a/dlls/winemac.drv/cocoa_window.h b/dlls/winemac.drv/cocoa_window.h index 596e3c52b3e..675abcc659b 100644 --- a/dlls/winemac.drv/cocoa_window.h +++ b/dlls/winemac.drv/cocoa_window.h @@ -45,7 +45,6 @@ @interface WineWindow : NSPanel <NSWindowDelegate> WineEventQueue* queue;
void* surface; - pthread_mutex_t* surface_mutex;
CGDirectDisplayID _lastDisplayID; NSTimeInterval _lastDisplayTime; @@ -95,6 +94,8 @@ @interface WineWindow : NSPanel <NSWindowDelegate> @property (readonly, nonatomic) BOOL noForeground; @property (readonly, nonatomic) BOOL preventsAppActivation; @property (readonly, nonatomic) BOOL floating; +@property (readonly, nonatomic) BOOL needsTransparency; +@property (readonly, nonatomic) BOOL needsLayerTransparency; @property (readonly, getter=isFullscreen, nonatomic) BOOL fullscreen; @property (readonly, getter=isFakingClose, nonatomic) BOOL fakingClose; @property (readonly, nonatomic) NSRect wine_fractionalFrame; diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m index 656a5ba2283..74a84aab630 100644 --- a/dlls/winemac.drv/cocoa_window.m +++ b/dlls/winemac.drv/cocoa_window.m @@ -309,32 +309,6 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi @end
-#ifndef MAC_OS_X_VERSION_10_14 -@protocol NSViewLayerContentScaleDelegate <NSObject> -@optional - - - (BOOL) layer:(CALayer*)layer shouldInheritContentsScale:(CGFloat)newScale fromWindow:(NSWindow*)window; - -@end -#endif - - -@interface CAShapeLayer (WineShapeMaskExtensions) - -@property(readonly, nonatomic, getter=isEmptyShaped) BOOL emptyShaped; - -@end - -@implementation CAShapeLayer (WineShapeMaskExtensions) - - - (BOOL) isEmptyShaped - { - return CGRectEqualToRect(CGPathGetBoundingBox(self.path), CGRectZero); - } - -@end - - @interface WineBaseView : NSView @end
@@ -351,10 +325,11 @@ - (id) initWithFrame:(NSRect)frame device:(id<MTLDevice>)device; #endif
-@interface WineContentView : WineBaseView <NSTextInputClient, NSViewLayerContentScaleDelegate> +@interface WineContentView : WineBaseView <NSTextInputClient> { NSMutableArray* glContexts; NSMutableArray* pendingGlContexts; + BOOL _shouldBeHidden; BOOL _everHadGLContext; BOOL _cachedHasGLDescendant; BOOL _cachedHasGLDescendantValid; @@ -363,7 +338,6 @@ @interface WineContentView : WineBaseView <NSTextInputClient, NSViewLayerContent NSMutableAttributedString* markedText; NSRange markedTextSelection;
- BOOL _retinaMode; int backingSize[2];
#ifdef HAVE_METAL_METAL_H @@ -402,11 +376,9 @@ @interface WineWindow () @property (retain, readwrite, nonatomic) WineEventQueue* queue;
@property (nonatomic) void* surface; -@property (nonatomic) pthread_mutex_t* surface_mutex;
@property (retain, nonatomic) NSData* shapeData; @property (nonatomic) BOOL shapeChangedSinceLastDraw; -@property (readonly, nonatomic) BOOL needsTransparency;
@property (nonatomic) BOOL colorKeyed; @property (nonatomic) uint8_t colorKeyRed, colorKeyGreen, colorKeyBlue; @@ -490,13 +462,32 @@ - (BOOL) isFlipped return YES; }
+ - (BOOL) wantsDefaultClipping + { + /* Don't need this, we already limit our drawing to the dirty region */ + return NO; + } + + - (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event + { + /* Returning NSNull ensures the layer will never animate itself */ + return [NSNull null]; + } + + - (BOOL) isOpaque + { + WineWindow* window = (WineWindow*)[self window]; + return window.contentView == self && !window.needsLayerTransparency; + } + - (NSView*) hitTest:(NSPoint)point { WineWindow* window = (WineWindow*)[self window]; NSPoint localPoint; CGPoint cgPoint;
- if (window.contentView != self || !window.shapeData) + if (window.contentView != self + || (!window.shapeData && !window.needsLayerTransparency)) return [super hitTest:point];
localPoint = [self convertPoint:point fromView:self.superview]; @@ -523,72 +514,76 @@ - (NSView*) hitTest:(NSPoint)point return nil; }
- return [super hitTest:point]; - } + if (window.needsLayerTransparency) + { + /* Transparent pixels are not supposed to be clickable, but due to + * contentView.layer.drawsAsynchronously, Cocoa does not enforce it. + * Therefore, we must perform our own per-pixel hit test. */ + if (!surface_hit_test(window.surface, cgPoint, window.colorKeyed, + window.colorKeyRed, window.colorKeyGreen, window.colorKeyBlue)) + return nil; + }
- - (BOOL) wantsUpdateLayer - { - return YES /*!_everHadGLContext*/; + return [super hitTest:point]; }
- - (void) updateLayer + - (void) drawRect:(NSRect)rect { WineWindow* window = (WineWindow*)[self window]; - CGImageRef image = NULL; - CGRect imageRect; - CALayer* layer = [self layer]; + CGRect imageRect = cgrect_win_from_mac(NSRectToCGRect(rect)); + CGImageRef image;
- if ([window contentView] != self) - return; + for (WineOpenGLContext* context in pendingGlContexts) + { + if (!clearedGlSurface) + { + context.shouldClearToBlack = TRUE; + clearedGlSurface = TRUE; + } + context.needsUpdate = TRUE; + } + [glContexts addObjectsFromArray:pendingGlContexts]; + [pendingGlContexts removeAllObjects];
- if (window.closing || !window.surface || !window.surface_mutex) + if ([window contentView] != self) return;
- pthread_mutex_lock(window.surface_mutex); - if (get_surface_blit_rects(window.surface, NULL, NULL)) + if ((image = create_surface_image(window.surface, &imageRect, window.colorKeyed, + window.colorKeyRed, window.colorKeyGreen, window.colorKeyBlue)) != NULL) { - imageRect = layer.bounds; - imageRect.origin.x *= layer.contentsScale; - imageRect.origin.y *= layer.contentsScale; - imageRect.size.width *= layer.contentsScale; - imageRect.size.height *= layer.contentsScale; - image = create_surface_image(window.surface, &imageRect, window.colorKeyed, - window.colorKeyRed, window.colorKeyGreen, window.colorKeyBlue); - } - pthread_mutex_unlock(window.surface_mutex); + CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort]; + CGContextSetBlendMode(context, kCGBlendModeCopy); + /* HQ interpolation should be used with retina to prevent artifacts + * on mixed DPI. Not needed for standard DPI. */ + CGContextSetInterpolationQuality(context, retina_on ? kCGInterpolationHigh : kCGInterpolationNone); + + CGContextDrawImage(context, cgrect_mac_from_win(imageRect), image); + CGImageRelease(image);
- if (image) - { - layer.contents = (id)image; - CFRelease(image); [window windowDidDrawContent]; + }
- // If the window may be transparent, then we have to invalidate the - // shadow every time we draw. Also, if this is the first time we've - // drawn since changing from transparent to opaque. - if (window.colorKeyed || window.usePerPixelAlpha || window.shapeChangedSinceLastDraw) - { - window.shapeChangedSinceLastDraw = FALSE; - [window invalidateShadow]; - } + /* If the window may be transparent, then we have to invalidate the + * shadow every time we draw. Also, if this is the first time we've + * drawn since changing from transparent to opaque. */ + if (window.drawnSinceShown && (window.colorKeyed || window.usePerPixelAlpha || window.shapeChangedSinceLastDraw)) + { + window.shapeChangedSinceLastDraw = FALSE; + [window invalidateShadow]; } }
- - (void) viewWillDraw + - (void) setHidden:(BOOL)hidden { - [super viewWillDraw]; - - for (WineOpenGLContext* context in pendingGlContexts) + if (self.window.contentView == self) { - if (!clearedGlSurface) - { - context.shouldClearToBlack = TRUE; - clearedGlSurface = TRUE; - } - context.needsUpdate = TRUE; + [super setHidden:hidden]; + return; } - [glContexts addObjectsFromArray:pendingGlContexts]; - [pendingGlContexts removeAllObjects]; + + /* Client views should always remain hidden, unless we have OpenGL */ + [super setHidden:hidden || !_everHadGLContext]; + _shouldBeHidden = hidden; }
- (void) addGLContext:(WineOpenGLContext*)context @@ -617,7 +612,10 @@ - (void) addGLContext:(WineOpenGLContext*)context
_everHadGLContext = YES; if (!hadContext) + { + [super setHidden:_shouldBeHidden]; [self invalidateHasGLDescendant]; + } [(WineWindow*)[self window] updateForGLSubviews]; }
@@ -721,18 +719,9 @@ - (void) setRetinaMode:(int)mode [self setWantsBestResolutionOpenGLSurface:mode]; [self updateGLContexts];
- _retinaMode = !!mode; - [self layer].contentsScale = mode ? 2.0 : 1.0; - [self layer].minificationFilter = mode ? kCAFilterLinear : kCAFilterNearest; - [self layer].magnificationFilter = mode ? kCAFilterLinear : kCAFilterNearest; [super setRetinaMode:mode]; }
- - (BOOL) layer:(CALayer*)layer shouldInheritContentsScale:(CGFloat)newScale fromWindow:(NSWindow*)window - { - return (_retinaMode || newScale == 1.0); - } - - (void) viewDidHide { [super viewDidHide]; @@ -992,7 +981,7 @@ @implementation WineWindow
@synthesize disabled, noForeground, preventsAppActivation, floating, fullscreen, fakingClose, closing, latentParentWindow, hwnd, queue; @synthesize drawnSinceShown; - @synthesize surface, surface_mutex; + @synthesize surface; @synthesize shapeData, shapeChangedSinceLastDraw; @synthesize colorKeyed, colorKeyRed, colorKeyGreen, colorKeyBlue; @synthesize usePerPixelAlpha; @@ -1026,7 +1015,6 @@ + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)w [window disableCursorRects]; [window setShowsResizeIndicator:NO]; [window setHasShadow:wf->shadow]; - [window setAcceptsMouseMovedEvents:YES]; [window setDelegate:window]; [window setBackgroundColor:[NSColor clearColor]]; [window setOpaque:NO]; @@ -1045,12 +1033,10 @@ + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)w if (!contentView) return nil; [contentView setWantsLayer:YES]; - [contentView layer].minificationFilter = retina_on ? kCAFilterLinear : kCAFilterNearest; - [contentView layer].magnificationFilter = retina_on ? kCAFilterLinear : kCAFilterNearest; - [contentView layer].contentsScale = retina_on ? 2.0 : 1.0; + [contentView.layer setDrawsAsynchronously:YES]; [contentView setAutoresizesSubviews:NO];
- /* We use tracking areas in addition to setAcceptsMouseMovedEvents:YES + /* We use tracking areas instead of setAcceptsMouseMovedEvents:YES because they give us mouse moves in the background. */ trackingArea = [[[NSTrackingArea alloc] initWithRect:[contentView bounds] options:(NSTrackingMouseMoved | @@ -2044,28 +2030,37 @@ - (void) setDisabled:(BOOL)newValue } }
+ - (BOOL) needsLayerTransparency + { + return self.colorKeyed || self.usePerPixelAlpha; + } + - (BOOL) needsTransparency { - return self.contentView.layer.mask || self.colorKeyed || self.usePerPixelAlpha || + return self.shapeData || self.needsLayerTransparency || (gl_surface_mode == GL_SURFACE_BEHIND && [(WineContentView*)self.contentView hasGLDescendant]); }
- (void) checkTransparency { - if (![self isOpaque] && !self.needsTransparency) + if (!self.opaque && !self.needsTransparency) { self.shapeChangedSinceLastDraw = TRUE; - [[self contentView] setNeedsDisplay:YES]; + [self.contentView setNeedsDisplay:YES]; [self setBackgroundColor:[NSColor windowBackgroundColor]]; [self setOpaque:YES]; + /* Ensure WineApplicationController hasn't cut off mouse events */ + [self setIgnoresMouseEvents:NO]; } - else if ([self isOpaque] && self.needsTransparency) + else if (self.opaque && self.needsTransparency) { self.shapeChangedSinceLastDraw = TRUE; - [[self contentView] setNeedsDisplay:YES]; + [self.contentView setNeedsDisplay:YES]; [self setBackgroundColor:[NSColor clearColor]]; [self setOpaque:NO]; } + + [self.contentView.layer setOpaque:!self.needsLayerTransparency]; }
- (void) setShapeData:(NSData*)newShapeData @@ -2712,8 +2707,6 @@ - (void) setRetinaMode:(int)mode
[transform scaleBy:scale];
- [[self contentView] layer].mask.contentsScale = mode ? 2.0 : 1.0; - for (WineBaseView* subview in [self.contentView subviews]) { if ([subview isKindOfClass:[WineBaseView class]]) @@ -3319,6 +3312,7 @@ void macdrv_destroy_cocoa_window(macdrv_window w) WineWindow* window = (WineWindow*)w;
OnMainThread(^{ + window.surface = nil; window.closing = TRUE; [window doOrderOut]; [window close]; @@ -3485,14 +3479,13 @@ void macdrv_set_cocoa_parent_window(macdrv_window w, macdrv_window parent) /*********************************************************************** * macdrv_set_window_surface */ -void macdrv_set_window_surface(macdrv_window w, void *surface, pthread_mutex_t *mutex) +void macdrv_set_window_surface(macdrv_window w, void *surface) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; WineWindow* window = (WineWindow*)w;
OnMainThread(^{ window.surface = surface; - window.surface_mutex = mutex; });
[pool release]; @@ -3659,9 +3652,7 @@ macdrv_view macdrv_create_view(CGRect rect)
view = [[WineContentView alloc] initWithFrame:NSRectFromCGRect(cgrect_mac_from_win(rect))]; [view setWantsLayer:YES]; - [view layer].minificationFilter = retina_on ? kCAFilterLinear : kCAFilterNearest; - [view layer].magnificationFilter = retina_on ? kCAFilterLinear : kCAFilterNearest; - [view layer].contentsScale = retina_on ? 2.0 : 1.0; + [view.layer setDrawsAsynchronously:YES]; [view setAutoresizesSubviews:NO]; [view setAutoresizingMask:NSViewNotSizable]; [view setHidden:YES]; diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 3eecb26a01e..7b410fbdef0 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -209,7 +209,6 @@ extern DWORD CDECL macdrv_MsgWaitForMultipleObjectsEx(DWORD count, const HANDLE extern void activate_on_following_focus(void) DECLSPEC_HIDDEN; extern struct window_surface *create_surface(macdrv_window window, const RECT *rect, struct window_surface *old_surface, BOOL use_alpha) DECLSPEC_HIDDEN; -extern void set_window_surface(macdrv_window window, struct window_surface *window_surface) DECLSPEC_HIDDEN; extern void set_surface_use_alpha(struct window_surface *window_surface, BOOL use_alpha) DECLSPEC_HIDDEN; extern void surface_clip_to_visible_rect(struct window_surface *window_surface, const RECT *visible_rect) DECLSPEC_HIDDEN;
diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index b0eb86133c4..34769771fa7 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -580,10 +580,11 @@ extern void macdrv_order_cocoa_window(macdrv_window w, macdrv_window prev, extern void macdrv_set_cocoa_window_frame(macdrv_window w, const CGRect* new_frame) DECLSPEC_HIDDEN; extern void macdrv_get_cocoa_window_frame(macdrv_window w, CGRect* out_frame) DECLSPEC_HIDDEN; extern void macdrv_set_cocoa_parent_window(macdrv_window w, macdrv_window parent) DECLSPEC_HIDDEN; -extern void macdrv_set_window_surface(macdrv_window w, void *surface, pthread_mutex_t *mutex) DECLSPEC_HIDDEN; +extern void macdrv_set_window_surface(macdrv_window w, void *surface) DECLSPEC_HIDDEN; extern CGImageRef create_surface_image(void *window_surface, CGRect *dirty_area, int color_keyed, uint8_t key_red, uint8_t key_green, uint8_t key_blue) DECLSPEC_HIDDEN; -extern int get_surface_blit_rects(void *window_surface, const CGRect **rects, int *count) DECLSPEC_HIDDEN; +extern int surface_hit_test(void *window_surface, CGPoint point, int color_keyed, + uint8_t key_red, uint8_t key_green, uint8_t key_blue) DECLSPEC_HIDDEN; extern void macdrv_window_needs_display(macdrv_window w, CGRect rect) DECLSPEC_HIDDEN; extern void macdrv_set_window_shape(macdrv_window w, const CGRect *rects, int count) DECLSPEC_HIDDEN; extern void macdrv_set_window_alpha(macdrv_window w, CGFloat alpha) DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/surface.c b/dlls/winemac.drv/surface.c index eed31229473..0eb1f09d417 100644 --- a/dlls/winemac.drv/surface.c +++ b/dlls/winemac.drv/surface.c @@ -64,7 +64,6 @@ struct macdrv_window_surface HRGN region; HRGN drawn; BOOL use_alpha; - RGNDATA *blit_data; struct shadow_surface *shadow; BYTE *bits; pthread_mutex_t mutex; @@ -317,27 +316,6 @@ static void shadow_cfdata_dealloc(void *ptr, void *info) shadow_bitmap_return(info); }
-/*********************************************************************** - * update_blit_data - */ -static void update_blit_data(struct macdrv_window_surface *surface) -{ - HeapFree(GetProcessHeap(), 0, surface->blit_data); - surface->blit_data = NULL; - - if (surface->drawn) - { - HRGN blit = CreateRectRgn(0, 0, 0, 0); - - if (CombineRgn(blit, surface->drawn, 0, RGN_COPY) > NULLREGION && - (!surface->region || CombineRgn(blit, blit, surface->region, RGN_AND) > NULLREGION) && - OffsetRgn(blit, surface->header.rect.left, surface->header.rect.top) > NULLREGION) - surface->blit_data = get_region_data(blit, 0); - - DeleteObject(blit); - } -} - /*********************************************************************** * macdrv_surface_lock */ @@ -401,7 +379,6 @@ static void macdrv_surface_set_region(struct window_surface *window_surface, HRG if (surface->region) DeleteObject(surface->region); surface->region = 0; } - update_blit_data(surface);
window_surface->funcs->unlock(window_surface); } @@ -433,7 +410,6 @@ static void macdrv_surface_flush(struct window_surface *window_surface) else surface->drawn = region; } - update_blit_data(surface); reset_bounds(&surface->bounds);
window_surface->funcs->unlock(window_surface); @@ -459,7 +435,7 @@ static void macdrv_surface_destroy(struct window_surface *window_surface) } if (surface->bits && surface->bits != MAP_FAILED) munmap(surface->bits, surface->info.bmiHeader.biSizeImage); - HeapFree(GetProcessHeap(), 0, surface->blit_data); + pthread_mutex_destroy(&surface->mutex); HeapFree(GetProcessHeap(), 0, surface); } @@ -515,7 +491,7 @@ struct window_surface *create_surface(macdrv_window window, const RECT *rect,
surface->info.bmiHeader.biSize = sizeof(surface->info.bmiHeader); surface->info.bmiHeader.biWidth = width; - surface->info.bmiHeader.biHeight = -height; /* top-down */ + surface->info.bmiHeader.biHeight = height; /* bottom-up */ surface->info.bmiHeader.biPlanes = 1; surface->info.bmiHeader.biBitCount = 32; surface->info.bmiHeader.biSizeImage = get_dib_image_size(&surface->info); @@ -542,7 +518,6 @@ struct window_surface *create_surface(macdrv_window window, const RECT *rect, surface->drawn = 0; } } - update_blit_data(surface); surface->use_alpha = use_alpha; surface->shadow = shadow_surface_create(surface); if (!surface->shadow) goto failed; @@ -574,48 +549,6 @@ void set_surface_use_alpha(struct window_surface *window_surface, BOOL use_alpha if (surface) surface->use_alpha = use_alpha; }
-/*********************************************************************** - * set_window_surface - */ -void set_window_surface(macdrv_window window, struct window_surface *window_surface) -{ - struct macdrv_window_surface *surface = get_mac_surface(window_surface); - macdrv_set_window_surface(window, window_surface, surface ? &surface->mutex : NULL); -} - -/*********************************************************************** - * get_surface_blit_rects - * - * Caller must hold the surface lock. Indirectly returns the surface - * blit region rects. Returns zero if the surface has nothing to blit; - * returns non-zero if the surface does have rects to blit (drawn area - * which isn't clipped away by a surface region). - * - * IMPORTANT: This function is called from non-Wine threads, so it - * must not use Win32 or Wine functions, including debug - * logging. - */ -int get_surface_blit_rects(void *window_surface, const CGRect **rects, int *count) -{ - struct macdrv_window_surface *surface = get_mac_surface(window_surface); - - if (rects && count) - { - if (surface->blit_data) - { - *rects = (const CGRect*)surface->blit_data->Buffer; - *count = surface->blit_data->rdh.nCount; - } - else - { - *rects = NULL; - *count = 0; - } - } - - return (surface->blit_data != NULL && surface->blit_data->rdh.nCount > 0); -} - /*********************************************************************** * create_surface_image * @@ -779,10 +712,59 @@ void surface_clip_to_visible_rect(struct window_surface *window_surface, const R { CombineRgn(surface->drawn, surface->drawn, region, RGN_AND); DeleteObject(region); - - update_blit_data(surface); } }
window_surface->funcs->unlock(window_surface); } + +/*********************************************************************** + * surface_hit_test + * + * Performs a per-pixel hit test on the given surface. Returns FALSE if + * the chosen pixel is transparent or keyed out, TRUE if the pixel is + * clickable. + * + * IMPORTANT: This function is called from non-Wine threads, so it + * must not use Win32 or Wine functions, including debug + * logging. + */ +int surface_hit_test(void *window_surface, CGPoint point, int color_keyed, + uint8_t key_red, uint8_t key_green, uint8_t key_blue) +{ + struct macdrv_window_surface *surface = get_mac_surface(window_surface); + DWORD key = (key_red << 16) | (key_green << 8) | (key_blue); + DWORD pixel; + int surface_width, bytes_per_row; + /* Note: coordinates can be non-integers. Truncate. */ + int point_x = point.x, point_y = point.y; + int retval = TRUE; + + if (!surface) + return TRUE; + + pthread_mutex_lock(&surface->mutex); + surface_width = surface->header.rect.right - surface->header.rect.left; + bytes_per_row = get_dib_stride(surface_width, 32); + + if (!surface->use_alpha && !color_keyed) + /* Opaque surface always succeeds */ + goto done; + + if (point_x < surface->header.rect.left || point_x >= surface->header.rect.right + || point_y < surface->header.rect.top || point_y >= surface->header.rect.bottom) + { + retval = FALSE; + goto done; + } + + pixel = *(DWORD*)(surface->bits + (point_x - surface->header.rect.left) * 4 + + (surface->header.rect.bottom - point_y) * bytes_per_row); + + retval = !((color_keyed && (pixel & 0x00FFFFFF) == key) + || (surface->use_alpha && (pixel & 0xFF000000) == 0)); + +done: + pthread_mutex_unlock(&surface->mutex); + return retval; +} diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c index 9177f493a5f..dba87df37de 100644 --- a/dlls/winemac.drv/window.c +++ b/dlls/winemac.drv/window.c @@ -1899,7 +1899,7 @@ BOOL CDECL macdrv_UpdateLayeredWindow(HWND hwnd, const UPDATELAYEREDWINDOWINFO * if (!surface || !EqualRect(&surface->rect, &rect)) { data->surface = create_surface(data->cocoa_window, &rect, NULL, TRUE); - set_window_surface(data->cocoa_window, data->surface); + macdrv_set_window_surface(data->cocoa_window, data->surface); if (surface) window_surface_release(surface); surface = data->surface; if (data->unminimized_surface) @@ -2139,7 +2139,7 @@ void CDECL macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, UINT swp_flags, } else { - set_window_surface(data->cocoa_window, surface); + macdrv_set_window_surface(data->cocoa_window, surface); if (data->unminimized_surface) { window_surface_release(data->unminimized_surface);