From 220b8b7946397b7605e53d97c8b0d3aafe55d4d5 Mon Sep 17 00:00:00 2001 From: Ken Thomases Date: Thu, 6 Jun 2013 17:43:06 -0500 Subject: [PATCH] winemac: Add an option to capture the displays for full-screen windows in addition to display mode changes. Under HKCU\Software\Wine\Mac Driver, set string value CaptureDisplaysForFullscreen to "y" to enable the new behavior. --- dlls/winemac.drv/cocoa_app.h | 2 + dlls/winemac.drv/cocoa_app.m | 58 ++++++++++++++++++++++++--- dlls/winemac.drv/cocoa_window.h | 3 ++ dlls/winemac.drv/cocoa_window.m | 69 ++++++++++++++++++++++++++------- dlls/winemac.drv/macdrv_cocoa.h | 1 + dlls/winemac.drv/macdrv_main.c | 7 ++++ 6 files changed, 120 insertions(+), 20 deletions(-) diff --git a/dlls/winemac.drv/cocoa_app.h b/dlls/winemac.drv/cocoa_app.h index 1338137d79c..0614c76c440 100644 --- a/dlls/winemac.drv/cocoa_app.h +++ b/dlls/winemac.drv/cocoa_app.h @@ -66,6 +66,7 @@ @interface WineApplicationController : NSObject NSUInteger unmatchedMouseDowns; NSMutableDictionary* originalDisplayModes; + BOOL displaysCapturedForFullscreen; NSArray* cursorFrames; int cursorFrame; @@ -109,6 +110,7 @@ - (void) flipRect:(NSRect*)rect; - (WineWindow*) frontWineWindow; - (void) adjustWindowLevels; + - (void) updateFullscreenWindows; - (BOOL) handleEvent:(NSEvent*)anEvent; - (void) didSendEvent:(NSEvent*)anEvent; diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m index 9984114587a..fe9648b069c 100644 --- a/dlls/winemac.drv/cocoa_app.m +++ b/dlls/winemac.drv/cocoa_app.m @@ -575,6 +575,41 @@ - (void) adjustWindowLevels [self adjustWindowLevels:[NSApp isActive]]; } + - (void) updateFullscreenWindows + { + if (capture_displays_for_fullscreen && [NSApp isActive]) + { + BOOL anyFullscreen = FALSE; + NSNumber* windowNumber; + for (windowNumber in [NSWindow windowNumbersWithOptions:0]) + { + WineWindow* window = (WineWindow*)[NSApp windowWithWindowNumber:[windowNumber integerValue]]; + if ([window isKindOfClass:[WineWindow class]] && window.fullscreen) + { + anyFullscreen = TRUE; + break; + } + } + + if (anyFullscreen) + { + if ([self areDisplaysCaptured] || CGCaptureAllDisplays() == CGDisplayNoErr) + displaysCapturedForFullscreen = TRUE; + } + else if (displaysCapturedForFullscreen) + { + if ([originalDisplayModes count] || CGReleaseAllDisplays() == CGDisplayNoErr) + displaysCapturedForFullscreen = FALSE; + } + } + } + + - (void) activeSpaceDidChange + { + [self updateFullscreenWindows]; + [self adjustWindowLevels]; + } + - (void) sendDisplaysChanged:(BOOL)activating { macdrv_event* event; @@ -680,7 +715,8 @@ - (BOOL) setMode:(CGDisplayModeRef)mode forDisplay:(CGDirectDisplayID)displayID if ([originalDisplayModes count] == 1) // If this is the last changed display, do a blanket reset { CGRestorePermanentDisplayConfiguration(); - CGReleaseAllDisplays(); + if (!displaysCapturedForFullscreen) + CGReleaseAllDisplays(); [originalDisplayModes removeAllObjects]; ret = TRUE; } @@ -695,7 +731,8 @@ - (BOOL) setMode:(CGDisplayModeRef)mode forDisplay:(CGDirectDisplayID)displayID } else { - if ([originalDisplayModes count] || CGCaptureAllDisplays() == CGDisplayNoErr) + if ([originalDisplayModes count] || displaysCapturedForFullscreen || + CGCaptureAllDisplays() == CGDisplayNoErr) { if (CGDisplaySetDisplayMode(displayID, mode, NULL) == CGDisplayNoErr) { @@ -705,7 +742,8 @@ - (BOOL) setMode:(CGDisplayModeRef)mode forDisplay:(CGDirectDisplayID)displayID else if (![originalDisplayModes count]) { CGRestorePermanentDisplayConfiguration(); - CGReleaseAllDisplays(); + if (!displaysCapturedForFullscreen) + CGReleaseAllDisplays(); } } } @@ -720,7 +758,7 @@ - (BOOL) setMode:(CGDisplayModeRef)mode forDisplay:(CGDirectDisplayID)displayID - (BOOL) areDisplaysCaptured { - return ([originalDisplayModes count] > 0); + return ([originalDisplayModes count] > 0 || displaysCapturedForFullscreen); } - (void) hideCursor @@ -851,11 +889,12 @@ - (void) handleCommandTab NSRunningApplication* app; NSRunningApplication* otherValidApp = nil; - if ([originalDisplayModes count]) + if ([originalDisplayModes count] || displaysCapturedForFullscreen) { CGRestorePermanentDisplayConfiguration(); CGReleaseAllDisplays(); [originalDisplayModes removeAllObjects]; + displaysCapturedForFullscreen = FALSE; } for (app in [[NSWorkspace sharedWorkspace] runningApplications]) @@ -1661,6 +1700,12 @@ - (void) setupObservations lastTargetWindow = nil; if (window == self.mouseCaptureWindow) self.mouseCaptureWindow = nil; + if ([window isKindOfClass:[WineWindow class]] && [(WineWindow*)window isFullscreen]) + { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0), dispatch_get_main_queue(), ^{ + [self updateFullscreenWindows]; + }); + } }]; [nc addObserver:self @@ -1673,7 +1718,7 @@ - (void) setupObservations [NSTextInputContext self]; [wsnc addObserver:self - selector:@selector(adjustWindowLevels) + selector:@selector(activeSpaceDidChange) name:NSWorkspaceActiveSpaceDidChangeNotification object:nil]; } @@ -1705,6 +1750,7 @@ - (void)applicationDidBecomeActive:(NSNotification *)notification { [self activateCursorClipping]; + [self updateFullscreenWindows]; [self adjustWindowLevels:YES]; if (beenActive && ![self frontWineWindow]) diff --git a/dlls/winemac.drv/cocoa_window.h b/dlls/winemac.drv/cocoa_window.h index 0f7e084fc3e..362d9aa2f4c 100644 --- a/dlls/winemac.drv/cocoa_window.h +++ b/dlls/winemac.drv/cocoa_window.h @@ -29,6 +29,7 @@ @interface WineWindow : NSPanel BOOL disabled; BOOL noActivate; BOOL floating; + BOOL fullscreen; BOOL pendingMinimize; WineWindow* latentParentWindow; @@ -60,7 +61,9 @@ @interface WineWindow : NSPanel @property (retain, readonly, nonatomic) WineEventQueue* queue; @property (readonly, nonatomic) BOOL floating; +@property (readonly, getter=isFullscreen, nonatomic) BOOL fullscreen; - (NSInteger) minimumLevelForActive:(BOOL)active; + - (void) updateFullscreen; @end diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m index 9d8984cea2a..7c2e040e792 100644 --- a/dlls/winemac.drv/cocoa_window.m +++ b/dlls/winemac.drv/cocoa_window.m @@ -450,7 +450,7 @@ - (NSInteger) windowLevel @implementation WineWindow - @synthesize disabled, noActivate, floating, latentParentWindow, hwnd, queue; + @synthesize disabled, noActivate, floating, fullscreen, latentParentWindow, hwnd, queue; @synthesize surface, surface_mutex; @synthesize shape, shapeChangedSinceLastDraw; @synthesize colorKeyed, colorKeyRed, colorKeyGreen, colorKeyBlue; @@ -513,11 +513,18 @@ + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)w [window setContentView:contentView]; [window setInitialFirstResponder:contentView]; + [[NSNotificationCenter defaultCenter] addObserver:window + selector:@selector(updateFullscreen) + name:NSApplicationDidChangeScreenParametersNotification + object:NSApp]; + [window updateFullscreen]; + return window; } - (void) dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; [liveResizeDisplayTimer invalidate]; [liveResizeDisplayTimer release]; [queue release]; @@ -570,13 +577,8 @@ - (BOOL) isOrderedIn - (NSInteger) minimumLevelForActive:(BOOL)active { - NSScreen* screen; - BOOL fullscreen; NSInteger level; - screen = screen_covered_by_rect([self frame], [NSScreen screens]); - fullscreen = (screen != nil); - if (self.floating && (active || topmost_float_inactive == TOPMOST_FLOAT_INACTIVE_ALL || (topmost_float_inactive == TOPMOST_FLOAT_INACTIVE_NONFULLSCREEN && !fullscreen))) level = NSFloatingWindowLevel; @@ -587,7 +589,7 @@ - (NSInteger) minimumLevelForActive:(BOOL)active { BOOL captured; - captured = (screen || [self screen]) && [[WineApplicationController sharedController] areDisplaysCaptured]; + captured = (fullscreen || [self screen]) && [[WineApplicationController sharedController] areDisplaysCaptured]; if (captured || fullscreen) { @@ -717,6 +719,7 @@ - (BOOL) orderBelow:(WineWindow*)prev orAbove:(WineWindow*)next if (on_screen && ![self isMiniaturized]) { BOOL needAdjustWindowLevels = FALSE; + BOOL wasVisible = [self isVisible]; [controller transformProcessToForeground]; @@ -758,7 +761,11 @@ - (BOOL) orderBelow:(WineWindow*)prev orAbove:(WineWindow*)next needAdjustWindowLevels = TRUE; } if (needAdjustWindowLevels) + { + if (!wasVisible && fullscreen && [self isOnActiveSpace]) + [controller updateFullscreenWindows]; [controller adjustWindowLevels]; + } if (pendingMinimize) { @@ -783,15 +790,38 @@ - (BOOL) orderBelow:(WineWindow*)prev orAbove:(WineWindow*)next - (void) doOrderOut { + WineApplicationController* controller = [WineApplicationController sharedController]; + BOOL wasVisible = [self isVisible]; + BOOL wasOnActiveSpace = [self isOnActiveSpace]; + if ([self isMiniaturized]) pendingMinimize = TRUE; self.latentParentWindow = [self parentWindow]; [latentParentWindow removeChildWindow:self]; [self orderOut:nil]; - [[WineApplicationController sharedController] adjustWindowLevels]; + if (wasVisible && wasOnActiveSpace && fullscreen) + [controller updateFullscreenWindows]; + [controller adjustWindowLevels]; [NSApp removeWindowsItem:self]; } + - (void) updateFullscreen + { + NSRect contentRect = [self contentRectForFrameRect:[self frame]]; + BOOL nowFullscreen = (screen_covered_by_rect(contentRect, [NSScreen screens]) != nil); + + if (nowFullscreen != fullscreen) + { + WineApplicationController* controller = [WineApplicationController sharedController]; + + fullscreen = nowFullscreen; + if ([self isVisible] && [self isOnActiveSpace]) + [controller updateFullscreenWindows]; + + [controller adjustWindowLevels]; + } + } + - (BOOL) setFrameIfOnScreen:(NSRect)contentRect { NSArray* screens = [NSScreen screens]; @@ -829,14 +859,10 @@ - (BOOL) setFrameIfOnScreen:(NSRect)contentRect else [self setFrame:frame display:YES]; + [self updateFullscreen]; + if (on_screen) { - BOOL fullscreen = (screen_covered_by_rect(frame, screens) != nil); - BOOL oldFullscreen = (screen_covered_by_rect(oldFrame, screens) != nil); - - if (fullscreen != oldFullscreen) - [[WineApplicationController sharedController] adjustWindowLevels]; - /* In case Cocoa adjusted the frame we tried to set, generate a frame-changed event. The back end will ignore it if nothing actually changed. */ [self windowDidResize:nil]; @@ -929,6 +955,7 @@ - (void) makeFocused:(BOOL)activate WineApplicationController* controller = [WineApplicationController sharedController]; NSArray* screens; WineWindow* front; + BOOL wasVisible = [self isVisible]; [controller transformProcessToForeground]; @@ -961,6 +988,8 @@ - (void) makeFocused:(BOOL)activate if (front && [self level] < [front level]) [self setLevel:[front level]]; [self orderFront:nil]; + if (!wasVisible && fullscreen && [self isOnActiveSpace]) + [controller updateFullscreenWindows]; [controller adjustWindowLevels]; if (pendingMinimize) @@ -1071,6 +1100,7 @@ - (void) makeKeyAndOrderFront:(id)sender { WineApplicationController* controller = [WineApplicationController sharedController]; WineWindow* front = [controller frontWineWindow]; + BOOL wasVisible = [self isVisible]; if (![self isKeyWindow] && !self.disabled && !self.noActivate) [controller windowGotFocus:self]; @@ -1078,6 +1108,8 @@ - (void) makeKeyAndOrderFront:(id)sender if (front && [self level] < [front level]) [self setLevel:[front level]]; [self orderFront:nil]; + if (!wasVisible && fullscreen && [self isOnActiveSpace]) + [controller updateFullscreenWindows]; [controller adjustWindowLevels]; if (pendingMinimize) @@ -1220,6 +1252,8 @@ - (void)windowDidDeminiaturize:(NSNotification *)notification ignore_windowDeminiaturize = FALSE; + if (fullscreen && [self isOnActiveSpace]) + [controller updateFullscreenWindows]; [controller adjustWindowLevels]; if (!self.disabled && !self.noActivate) @@ -1240,6 +1274,12 @@ - (void) windowDidEndLiveResize:(NSNotification *)notification liveResizeDisplayTimer = nil; } + - (void)windowDidMiniaturize:(NSNotification *)notification + { + if (fullscreen && [self isOnActiveSpace]) + [[WineApplicationController sharedController] updateFullscreenWindows]; + } + - (void)windowDidMove:(NSNotification *)notification { [self windowDidResize:notification]; @@ -1281,6 +1321,7 @@ - (void)windowDidResize:(NSNotification *)notification macdrv_release_event(event); [[[self contentView] inputContext] invalidateCharacterCoordinates]; + [self updateFullscreen]; } - (BOOL)windowShouldClose:(id)sender diff --git a/dlls/winemac.drv/macdrv_cocoa.h b/dlls/winemac.drv/macdrv_cocoa.h index 96a9592b54d..92e9892dae3 100644 --- a/dlls/winemac.drv/macdrv_cocoa.h +++ b/dlls/winemac.drv/macdrv_cocoa.h @@ -136,6 +136,7 @@ /* main */ extern int macdrv_err_on; extern int topmost_float_inactive DECLSPEC_HIDDEN; +extern int capture_displays_for_fullscreen DECLSPEC_HIDDEN; extern int macdrv_start_cocoa_app(unsigned long long tickcount) DECLSPEC_HIDDEN; extern void macdrv_window_rejected_focus(const struct macdrv_event *event) DECLSPEC_HIDDEN; diff --git a/dlls/winemac.drv/macdrv_main.c b/dlls/winemac.drv/macdrv_main.c index cf036c49a4f..d72b0365f01 100644 --- a/dlls/winemac.drv/macdrv_main.c +++ b/dlls/winemac.drv/macdrv_main.c @@ -38,11 +38,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(macdrv); #define kCFCoreFoundationVersionNumber10_7 635.00 #endif +#define IS_OPTION_TRUE(ch) \ + ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1') + C_ASSERT(NUM_EVENT_TYPES <= sizeof(macdrv_event_mask) * 8); DWORD thread_data_tls_index = TLS_OUT_OF_INDEXES; int topmost_float_inactive = TOPMOST_FLOAT_INACTIVE_NONFULLSCREEN; +int capture_displays_for_fullscreen = 0; /************************************************************************** @@ -149,6 +153,9 @@ static void setup_options(void) topmost_float_inactive = TOPMOST_FLOAT_INACTIVE_NONFULLSCREEN; } + if (!get_config_key(hkey, appkey, "CaptureDisplaysForFullscreen", buffer, sizeof(buffer))) + capture_displays_for_fullscreen = IS_OPTION_TRUE(buffer[0]); + if (appkey) RegCloseKey(appkey); if (hkey) RegCloseKey(hkey); }