winemac: Implement support for Cocoa-style full-screen mode.

Based in large part on a patch submitted by Kevin Eaves.
This commit is contained in:
Ken Thomases 2013-10-10 14:22:08 -05:00 committed by Alexandre Julliard
parent 00e53de765
commit f4f50c9e4a
7 changed files with 171 additions and 24 deletions

View File

@ -239,6 +239,11 @@ - (void) transformProcessToForeground
submenu = [[[NSMenu alloc] initWithTitle:@"Window"] autorelease];
[submenu addItemWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@""];
[submenu addItemWithTitle:@"Zoom" action:@selector(performZoom:) keyEquivalent:@""];
if ([NSWindow instancesRespondToSelector:@selector(toggleFullScreen:)])
{
item = [submenu addItemWithTitle:@"Enter Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"];
[item setKeyEquivalentModifierMask:NSCommandKeyMask | NSAlternateKeyMask | NSControlKeyMask];
}
[submenu addItem:[NSMenuItem separatorItem]];
[submenu addItemWithTitle:@"Bring All to Front" action:@selector(arrangeInFront:) keyEquivalent:@""];
item = [[[NSMenuItem alloc] init] autorelease];

View File

@ -58,6 +58,11 @@ @interface WineWindow : NSPanel <NSWindowDelegate>
NSSize savedContentMinSize;
NSSize savedContentMaxSize;
BOOL enteringFullScreen;
BOOL exitingFullScreen;
NSRect nonFullscreenFrame;
NSTimeInterval enteredFullScreenTime;
BOOL ignore_windowDeminiaturize;
BOOL fakingClose;
}

View File

@ -28,6 +28,20 @@
#import "cocoa_opengl.h"
#if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
enum {
NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7,
NSWindowCollectionBehaviorFullScreenAuxiliary = 1 << 8,
NSWindowFullScreenButton = 7,
NSFullScreenWindowMask = 1 << 14,
};
@interface NSWindow (WineFullScreenExtensions)
- (void) toggleFullScreen:(id)sender;
@end
#endif
/* Additional Mac virtual keycode, to complement those in Carbon's <HIToolbox/Events.h>. */
enum {
kVK_RightCommand = 0x36, /* Invented for Wine; was unused */
@ -583,6 +597,39 @@ - (void) adjustFeaturesForState
[[self standardWindowButton:NSWindowMiniaturizeButton] setEnabled:!self.disabled];
if (style & NSResizableWindowMask)
[[self standardWindowButton:NSWindowZoomButton] setEnabled:!self.disabled];
if ([self respondsToSelector:@selector(toggleFullScreen:)])
{
if ([self collectionBehavior] & NSWindowCollectionBehaviorFullScreenPrimary)
[[self standardWindowButton:NSWindowFullScreenButton] setEnabled:!self.disabled];
}
}
- (void) adjustFullScreenBehavior:(NSWindowCollectionBehavior)behavior
{
if ([self respondsToSelector:@selector(toggleFullScreen:)])
{
NSUInteger style = [self styleMask];
if (behavior & NSWindowCollectionBehaviorParticipatesInCycle &&
style & NSResizableWindowMask && !(style & NSUtilityWindowMask))
{
behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
behavior &= ~NSWindowCollectionBehaviorFullScreenAuxiliary;
}
else
{
behavior &= ~NSWindowCollectionBehaviorFullScreenPrimary;
behavior |= NSWindowCollectionBehaviorFullScreenAuxiliary;
if (style & NSFullScreenWindowMask)
[self toggleFullScreen:nil];
}
}
if (behavior != [self collectionBehavior])
{
[self setCollectionBehavior:behavior];
[self adjustFeaturesForState];
}
}
- (void) setWindowFeatures:(const struct macdrv_window_features*)wf
@ -606,6 +653,7 @@ - (void) setWindowFeatures:(const struct macdrv_window_features*)wf
[self setStyleMask:newStyle ^ NSClosableWindowMask];
}
[self setStyleMask:newStyle];
[self adjustFullScreenBehavior:[self collectionBehavior]];
}
[self adjustFeaturesForState];
@ -648,6 +696,19 @@ - (NSInteger) minimumLevelForActive:(BOOL)active
return level;
}
- (void) postDidUnminimizeEvent
{
macdrv_event* event;
/* Coalesce events by discarding any previous ones still in the queue. */
[queue discardEventsMatchingMask:event_mask_for_type(WINDOW_DID_UNMINIMIZE)
forWindow:self];
event = macdrv_create_event(WINDOW_DID_UNMINIMIZE, self);
[queue postEvent:event];
macdrv_release_event(event);
}
- (void) setMacDrvState:(const struct macdrv_window_state*)state
{
NSWindowCollectionBehavior behavior;
@ -703,15 +764,25 @@ - (void) setMacDrvState:(const struct macdrv_window_state*)state
if ([self isOrderedIn])
[NSApp addWindowsItem:self title:[self title] filename:NO];
}
[self setCollectionBehavior:behavior];
[self adjustFullScreenBehavior:behavior];
if (state->minimized_valid)
{
BOOL discardUnminimize = TRUE;
pendingMinimize = FALSE;
if (state->minimized && ![self isMiniaturized])
{
if ([self isVisible])
{
if ([self styleMask] & NSFullScreenWindowMask)
{
[self postDidUnminimizeEvent];
discardUnminimize = FALSE;
}
else
[super miniaturize:nil];
}
else
pendingMinimize = TRUE;
}
@ -721,11 +792,14 @@ - (void) setMacDrvState:(const struct macdrv_window_state*)state
[self deminiaturize:nil];
}
if (discardUnminimize)
{
/* Whatever events regarding minimization might have been in the queue are now stale. */
[queue discardEventsMatchingMask:event_mask_for_type(WINDOW_DID_UNMINIMIZE)
forWindow:self];
}
}
}
- (BOOL) addChildWineWindow:(WineWindow*)child assumeVisible:(BOOL)assumeVisible
{
@ -1076,7 +1150,7 @@ - (void) doOrderOut
- (void) updateFullscreen
{
NSRect contentRect = [self contentRectForFrameRect:[self frame]];
BOOL nowFullscreen = (screen_covered_by_rect(contentRect, [NSScreen screens]) != nil);
BOOL nowFullscreen = !([self styleMask] & NSFullScreenWindowMask) && screen_covered_by_rect(contentRect, [NSScreen screens]);
if (nowFullscreen != fullscreen)
{
@ -1130,6 +1204,10 @@ - (BOOL) setFrameIfOnScreen:(NSRect)contentRect
[self updateColorSpace];
}
if (!enteringFullScreen &&
[[NSProcessInfo processInfo] systemUptime] - enteredFullScreenTime > 1.0)
nonFullscreenFrame = frame;
[self updateFullscreen];
if (on_screen)
@ -1345,6 +1423,8 @@ - (BOOL) validateMenuItem:(NSMenuItem *)menuItem
if ([menuItem action] == @selector(makeKeyAndOrderFront:))
ret = [self isKeyWindow] || (!self.disabled && !self.noActivate);
if ([menuItem action] == @selector(toggleFullScreen:) && self.disabled)
ret = NO;
return ret;
}
@ -1380,6 +1460,12 @@ - (void) miniaturize:(id)sender
macdrv_release_event(event);
}
- (void) toggleFullScreen:(id)sender
{
if (!self.disabled)
[super toggleFullScreen:sender];
}
// We normally use the generic/calibrated RGB color space for the window,
// rather than the device color space, to avoid expensive color conversion
// which slows down drawing. However, for windows displaying OpenGL, having
@ -1483,6 +1569,25 @@ - (void) flagsChanged:(NSEvent *)theEvent
/*
* ---------- NSWindowDelegate methods ----------
*/
- (NSSize) window:(NSWindow*)window willUseFullScreenContentSize:(NSSize)proposedSize
{
macdrv_query* query;
NSSize size;
query = macdrv_create_query();
query->type = QUERY_MIN_MAX_INFO;
query->window = (macdrv_window)[self retain];
[self.queue query:query timeout:0.5];
macdrv_release_query(query);
size = [self contentMaxSize];
if (proposedSize.width < size.width)
size.width = proposedSize.width;
if (proposedSize.height < size.height)
size.height = proposedSize.height;
return size;
}
- (void)windowDidBecomeKey:(NSNotification *)notification
{
WineApplicationController* controller = [WineApplicationController sharedController];
@ -1500,18 +1605,7 @@ - (void)windowDidDeminiaturize:(NSNotification *)notification
WineApplicationController* controller = [WineApplicationController sharedController];
if (!ignore_windowDeminiaturize)
{
macdrv_event* event;
/* Coalesce events by discarding any previous ones still in the queue. */
[queue discardEventsMatchingMask:event_mask_for_type(WINDOW_DID_UNMINIMIZE)
forWindow:self];
event = macdrv_create_event(WINDOW_DID_UNMINIMIZE, self);
[queue postEvent:event];
macdrv_release_event(event);
}
[self postDidUnminimizeEvent];
ignore_windowDeminiaturize = FALSE;
[self becameEligibleParentOrChild];
@ -1546,6 +1640,31 @@ - (void) windowDidEndLiveResize:(NSNotification *)notification
self.liveResizeDisplayTimer = nil;
}
- (void) windowDidEnterFullScreen:(NSNotification*)notification
{
enteringFullScreen = FALSE;
enteredFullScreenTime = [[NSProcessInfo processInfo] systemUptime];
}
- (void) windowDidExitFullScreen:(NSNotification*)notification
{
exitingFullScreen = FALSE;
[self setFrame:nonFullscreenFrame display:YES animate:NO];
[self windowDidResize:nil];
}
- (void) windowDidFailToEnterFullScreen:(NSWindow*)window
{
enteringFullScreen = FALSE;
enteredFullScreenTime = 0;
}
- (void) windowDidFailToExitFullScreen:(NSWindow*)window
{
exitingFullScreen = FALSE;
[self windowDidResize:nil];
}
- (void)windowDidMiniaturize:(NSNotification *)notification
{
if (fullscreen && [self isOnActiveSpace])
@ -1573,6 +1692,8 @@ - (void)windowDidResize:(NSNotification *)notification
macdrv_event* event;
NSRect frame = [self contentRectForFrameRect:[self frame]];
if (exitingFullScreen) return;
if (self.disabled)
{
[self setContentMinSize:frame.size];
@ -1587,6 +1708,7 @@ - (void)windowDidResize:(NSNotification *)notification
event = macdrv_create_event(WINDOW_FRAME_CHANGED, self);
event->window_frame_changed.frame = NSRectToCGRect(frame);
event->window_frame_changed.fullscreen = ([self styleMask] & NSFullScreenWindowMask) != 0;
[queue postEvent:event];
macdrv_release_event(event);
@ -1621,6 +1743,17 @@ - (void) windowWillClose:(NSNotification*)notification
[latentChildWindows removeAllObjects];
}
- (void) windowWillEnterFullScreen:(NSNotification*)notification
{
enteringFullScreen = TRUE;
nonFullscreenFrame = [self frame];
}
- (void) windowWillExitFullScreen:(NSNotification*)notification
{
exitingFullScreen = TRUE;
}
- (void)windowWillMiniaturize:(NSNotification *)notification
{
[self becameIneligibleParentOrChild];

View File

@ -246,7 +246,7 @@ void macdrv_handle_event(const macdrv_event *event)
macdrv_window_did_unminimize(hwnd);
break;
case WINDOW_FRAME_CHANGED:
macdrv_window_frame_changed(hwnd, event->window_frame_changed.frame);
macdrv_window_frame_changed(hwnd, event);
break;
case WINDOW_GOT_FOCUS:
macdrv_window_got_focus(hwnd, event);

View File

@ -155,7 +155,7 @@ static inline RECT rect_from_cgrect(CGRect cgrect)
extern void macdrv_handle_event(const macdrv_event *event) DECLSPEC_HIDDEN;
extern void macdrv_window_close_requested(HWND hwnd) DECLSPEC_HIDDEN;
extern void macdrv_window_frame_changed(HWND hwnd, CGRect frame) DECLSPEC_HIDDEN;
extern void macdrv_window_frame_changed(HWND hwnd, const macdrv_event *event) DECLSPEC_HIDDEN;
extern void macdrv_window_got_focus(HWND hwnd, const macdrv_event *event) DECLSPEC_HIDDEN;
extern void macdrv_window_lost_focus(HWND hwnd, const macdrv_event *event) DECLSPEC_HIDDEN;
extern void macdrv_app_deactivated(void) DECLSPEC_HIDDEN;

View File

@ -274,6 +274,7 @@ extern int macdrv_set_display_mode(const struct macdrv_display* display,
} status_item_mouse_move;
struct {
CGRect frame;
int fullscreen;
} window_frame_changed;
struct {
unsigned long serial;

View File

@ -1654,7 +1654,7 @@ void macdrv_window_close_requested(HWND hwnd)
*
* Handler for WINDOW_FRAME_CHANGED events.
*/
void macdrv_window_frame_changed(HWND hwnd, CGRect frame)
void macdrv_window_frame_changed(HWND hwnd, const macdrv_event *event)
{
struct macdrv_win_data *data;
RECT rect;
@ -1674,9 +1674,10 @@ void macdrv_window_frame_changed(HWND hwnd, CGRect frame)
parent = GetAncestor(hwnd, GA_PARENT);
TRACE("win %p/%p new Cocoa frame %s\n", hwnd, data->cocoa_window, wine_dbgstr_cgrect(frame));
TRACE("win %p/%p new Cocoa frame %s\n", hwnd, data->cocoa_window,
wine_dbgstr_cgrect(event->window_frame_changed.frame));
rect = rect_from_cgrect(frame);
rect = rect_from_cgrect(event->window_frame_changed.frame);
macdrv_mac_to_window_rect(data, &rect);
MapWindowPoints(0, parent, (POINT *)&rect, 2);
@ -1699,6 +1700,8 @@ void macdrv_window_frame_changed(HWND hwnd, CGRect frame)
release_win_data(data);
if (event->window_frame_changed.fullscreen)
flags |= SWP_NOSENDCHANGING;
if (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE))
SetWindowPos(hwnd, 0, rect.left, rect.top, width, height, flags);
}