winemac: Implement support for full-screen windows.

This commit is contained in:
Ken Thomases 2013-02-17 19:28:30 -06:00 committed by Alexandre Julliard
parent ba86e67792
commit be6af9a169
3 changed files with 159 additions and 7 deletions

View File

@ -276,7 +276,7 @@ - (void) wineWindow:(WineWindow*)window
index = 0;
for (otherWindow in orderedWineWindows)
{
if ([otherWindow level] <= [window level])
if ([otherWindow levelWhenActive] <= [window levelWhenActive])
break;
index++;
}
@ -298,7 +298,7 @@ - (void) wineWindow:(WineWindow*)window
index = 0;
for (otherWindow in orderedWineWindows)
{
if ([otherWindow level] < [window level])
if ([otherWindow levelWhenActive] < [window levelWhenActive])
break;
index++;
}
@ -328,6 +328,15 @@ - (void) sendEvent:(NSEvent*)anEvent
/*
* ---------- NSApplicationDelegate methods ----------
*/
- (void)applicationDidBecomeActive:(NSNotification *)notification
{
[orderedWineWindows enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL *stop){
WineWindow* window = obj;
if ([window levelWhenActive] != [window level])
[window setLevel:[window levelWhenActive]];
}];
}
- (void)applicationDidChangeScreenParameters:(NSNotification *)notification
{
primaryScreenHeightValid = FALSE;
@ -383,6 +392,16 @@ - (void)applicationWillFinishLaunching:(NSNotification *)notification
self.keyboardType = LMGetKbdType();
}
- (void)applicationWillResignActive:(NSNotification *)notification
{
[orderedWineWindows enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id obj, NSUInteger idx, BOOL *stop){
WineWindow* window = obj;
NSInteger level = window.floating ? NSFloatingWindowLevel : NSNormalWindowLevel;
if ([window level] > level)
[window setLevel:level];
}];
}
@end
/***********************************************************************

View File

@ -51,11 +51,15 @@ @interface WineWindow : NSPanel <NSWindowDelegate>
BOOL forceNextMouseMoveAbsolute;
double mouseMoveDeltaX, mouseMoveDeltaY;
NSInteger levelWhenActive;
BOOL causing_becomeKeyWindow;
BOOL ignore_windowMiniaturize;
BOOL ignore_windowDeminiaturize;
}
@property (retain, readonly, nonatomic) WineEventQueue* queue;
@property (readonly, nonatomic) BOOL floating;
@property (readonly, nonatomic) NSInteger levelWhenActive;
@end

View File

@ -63,6 +63,17 @@ static BOOL frame_intersects_screens(NSRect frame, NSArray* screens)
}
static NSScreen* screen_covered_by_rect(NSRect rect, NSArray* screens)
{
for (NSScreen* screen in screens)
{
if (NSContainsRect(rect, [screen frame]))
return screen;
}
return nil;
}
/* We rely on the supposedly device-dependent modifier flags to distinguish the
keys on the left side of the keyboard from those on the right. Some event
sources don't set those device-depdendent flags. If we see a device-independent
@ -114,7 +125,7 @@ @interface WineWindow ()
@property (nonatomic) BOOL disabled;
@property (nonatomic) BOOL noActivate;
@property (nonatomic) BOOL floating;
@property (readwrite, nonatomic) BOOL floating;
@property (retain, nonatomic) NSWindow* latentParentWindow;
@property (nonatomic) void* hwnd;
@ -131,6 +142,8 @@ @interface WineWindow ()
@property (nonatomic) CGFloat colorKeyRed, colorKeyGreen, colorKeyBlue;
@property (nonatomic) BOOL usePerPixelAlpha;
@property (readwrite, nonatomic) NSInteger levelWhenActive;
+ (void) flipRect:(NSRect*)rect;
@end
@ -231,6 +244,7 @@ @implementation WineWindow
@synthesize shape, shapeChangedSinceLastDraw;
@synthesize colorKeyed, colorKeyRed, colorKeyGreen, colorKeyBlue;
@synthesize usePerPixelAlpha;
@synthesize levelWhenActive;
+ (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)wf
windowFrame:(NSRect)window_frame
@ -321,18 +335,72 @@ - (void) setWindowFeatures:(const struct macdrv_window_features*)wf
[self setHasShadow:wf->shadow];
}
- (void) setMacDrvState:(const struct macdrv_window_state*)state
- (void) adjustWindowLevel
{
NSInteger level;
BOOL fullscreen;
NSScreen* screen;
NSUInteger index;
WineWindow* other = nil;
screen = screen_covered_by_rect([self frame], [NSScreen screens]);
fullscreen = (screen != nil);
if (fullscreen)
{
level = NSMainMenuWindowLevel + 1;
if (self.floating)
level++;
}
else if (self.floating)
level = NSFloatingWindowLevel;
else
level = NSNormalWindowLevel;
index = [[NSApp orderedWineWindows] indexOfObjectIdenticalTo:self];
if (index != NSNotFound && index + 1 < [[NSApp orderedWineWindows] count])
{
other = [[NSApp orderedWineWindows] objectAtIndex:index + 1];
if (level < [other level])
level = [other level];
}
if (level != [self level])
{
[self setLevelWhenActive:level];
/* Setting the window level above has moved this window to the front
of all other windows at the same level. We need to move it
back into its proper place among other windows of that level.
Also, any windows which are supposed to be in front of it had
better have the same or higher window level. If not, bump them
up. */
if (index != NSNotFound)
{
for (; index > 0; index--)
{
other = [[NSApp orderedWineWindows] objectAtIndex:index - 1];
if ([other level] < level)
[other setLevelWhenActive:level];
else
{
[self orderWindow:NSWindowBelow relativeTo:[other windowNumber]];
break;
}
}
}
}
}
- (void) setMacDrvState:(const struct macdrv_window_state*)state
{
NSWindowCollectionBehavior behavior;
self.disabled = state->disabled;
self.noActivate = state->no_activate;
self.floating = state->floating;
level = state->floating ? NSFloatingWindowLevel : NSNormalWindowLevel;
if (level != [self level])
[self setLevel:level];
[self adjustWindowLevel];
behavior = NSWindowCollectionBehaviorDefault;
if (state->excluded_by_expose)
@ -381,16 +449,39 @@ - (BOOL) orderBelow:(WineWindow*)prev orAbove:(WineWindow*)next
if (prev)
{
/* Make sure that windows that should be above this one really are.
This is necessary since a full-screen window gets a boost to its
window level to be in front of the menu bar and Dock and that moves
it out of the z-order that Win32 would otherwise establish. */
if ([prev level] < [self level])
{
NSUInteger index = [[NSApp orderedWineWindows] indexOfObjectIdenticalTo:prev];
if (index != NSNotFound)
{
[prev setLevelWhenActive:[self level]];
for (; index > 0; index--)
{
WineWindow* other = [[NSApp orderedWineWindows] objectAtIndex:index - 1];
if ([other level] < [self level])
[other setLevelWhenActive:[self level]];
}
}
}
[self orderWindow:NSWindowBelow relativeTo:[prev windowNumber]];
[NSApp wineWindow:self ordered:NSWindowBelow relativeTo:prev];
}
else
{
/* Similarly, make sure this window is really above what it should be. */
if (next && [next level] > [self level])
[self setLevelWhenActive:[next level]];
[self orderWindow:NSWindowAbove relativeTo:[next windowNumber]];
[NSApp wineWindow:self ordered:NSWindowAbove relativeTo:next];
}
if (latentParentWindow)
{
if ([latentParentWindow level] > [self level])
[self setLevelWhenActive:[latentParentWindow level]];
[latentParentWindow addChildWindow:self ordered:NSWindowAbove];
[NSApp wineWindow:self ordered:NSWindowAbove relativeTo:latentParentWindow];
self.latentParentWindow = nil;
@ -452,6 +543,8 @@ - (BOOL) setFrameIfOnScreen:(NSRect)contentRect
if (on_screen)
{
[self adjustWindowLevel];
/* 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];
@ -476,6 +569,8 @@ - (void) setMacDrvParentWindow:(WineWindow*)parent
self.latentParentWindow = nil;
if ([self isVisible] && parent)
{
if ([parent level] > [self level])
[self setLevelWhenActive:[parent level]];
[parent addChildWindow:self ordered:NSWindowAbove];
[NSApp wineWindow:self ordered:NSWindowAbove relativeTo:parent];
}
@ -566,6 +661,19 @@ - (void) makeFocused
[self setFrame:frame display:YES];
}
if ([[NSApp orderedWineWindows] count])
{
WineWindow* front;
if (self.floating)
front = [[NSApp orderedWineWindows] objectAtIndex:0];
else
{
for (front in [NSApp orderedWineWindows])
if (!front.floating) break;
}
if (front && [front levelWhenActive] > [self levelWhenActive])
[self setLevelWhenActive:[front levelWhenActive]];
}
[self orderFront:nil];
[NSApp wineWindow:self ordered:NSWindowAbove relativeTo:nil];
causing_becomeKeyWindow = TRUE;
@ -573,6 +681,8 @@ - (void) makeFocused
causing_becomeKeyWindow = FALSE;
if (latentParentWindow)
{
if ([latentParentWindow level] > [self level])
[self setLevelWhenActive:[latentParentWindow level]];
[latentParentWindow addChildWindow:self ordered:NSWindowAbove];
[NSApp wineWindow:self ordered:NSWindowAbove relativeTo:latentParentWindow];
self.latentParentWindow = nil;
@ -666,6 +776,14 @@ - (void) postMouseMovedEvent:(NSEvent *)theEvent
}
}
- (void) setLevelWhenActive:(NSInteger)level
{
levelWhenActive = level;
if (([NSApp isActive] || level <= NSFloatingWindowLevel) &&
level != [self level])
[self setLevel:level];
}
/*
* ---------- NSWindow method overrides ----------
@ -682,6 +800,17 @@ - (BOOL) canBecomeMainWindow
return [self canBecomeKeyWindow];
}
- (NSRect) constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
{
// If a window is sized to completely cover a screen, then it's in
// full-screen mode. In that case, we don't allow NSWindow to constrain
// it.
NSRect contentRect = [self contentRectForFrameRect:frameRect];
if (!screen_covered_by_rect(contentRect, [NSScreen screens]))
frameRect = [super constrainFrameRect:frameRect toScreen:screen];
return frameRect;
}
- (BOOL) isExcludedFromWindowsMenu
{
return !([self collectionBehavior] & NSWindowCollectionBehaviorParticipatesInCycle);