Attached patch is a proof-of-concept for the fullscreen APIs provided in OS X 10.7+, which allows applications to enter fullscreen in a separate desktop space. The fullscreen button appears if a main window is resizable.
Basically this feature is the zoom button on crack. It doesn't actually go fullscreen 'natively' but simply resizes the window fullscreen, and automatically moves it to its own space. As far as Wine is concerned the window resized — just like clicking the zoom button and manually assigning the window to its own space.
I doubled the MaxTrackSize in user32/winpos.c, but it only needs +15 for the height.
Hi,
On May 9, 2013, at 5:48 PM, Kevin Eaves wrote:
Attached patch is a proof-of-concept for the fullscreen APIs provided in OS X 10.7+, which allows applications to enter fullscreen in a separate desktop space.
Thanks for this. It's quite interesting.
The fullscreen button appears if a main window is resizable.
We may want to narrow this down a bit. For example, the common file dialogs are resizable, but probably shouldn't be full-screen-enabled. Perhaps no owned window should be.
Basically this feature is the zoom button on crack. It doesn't actually go fullscreen 'natively' but simply resizes the window fullscreen, and automatically moves it to its own space. As far as Wine is concerned the window resized — just like clicking the zoom button and manually assigning the window to its own space.
Understood.
I doubled the MaxTrackSize in user32/winpos.c, but it only needs +15 for the height.
This is a gross hack that's going to have to be reworked if this is ever going to get accepted. :)
If I'm understanding correctly, user32 is restricting the window to a size that keeps its caption (title bar) within the desktop. Without this hack, the window resizes to be slightly smaller than would actually fill the screen. Is that right?
Maybe we could add a new driver entry point to have user32 offer the driver the opportunity to override the default MINMAXINFO values.
From cocoa_window.m.diff:
+#import <Cocoa/Cocoa.h>
Was that actually needed? cocoa_window.h already imports <AppKit/AppKit.h>.
On a related note, to enable this to compile against the 10.6 SDK, we should have something like:
#if !defined(MAC_OS_X_VERSION_10_7) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7 enum { NSFullScreenWindowMask = 0, NSWindowCollectionBehaviorFullScreenPrimary = 0, NSWindowFullScreenButton = 7, }; #endif
if (self.disabled) style &= ~NSResizableWindowMask;
if (style != [self styleMask])
if (style != [self styleMask] && !([self styleMask] & NSFullScreenWindowMask)) [self setStyleMask:style];
This is to avoid accidentally removing NSFullScreenWindowMask just because it's never in normalStyleMask, right? I think a simpler solution is to just do:
style |= [self styleMask] & NSFullScreenWindowMask;
In fact, we should probably make a mask of the style mask bits that are ever valid in normalStyleMask and only tweak those. That would be more future proof. So, something like:
enum { MACDRV_KNOWN_STYLES = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask | NSUtilityWindowMask | NSBorderlessWindowMask }; … NSUInteger style = normalStyleMask | ([self styleMask] & ~MACDRV_KNOWN_STYLES);
This:
if (style & NSResizableWindowMask)
[[self standardWindowButton:NSWindowZoomButton] setEnabled:!self.disabled];
is to compensate for the fact that you might not call -setStyleMask:, above, right? So it wouldn't be necessary after the change I suggested. Furthermore, it isn't adequate. You've disabled the zoom button but not the resize cursors all around the window border.
However, it does make me realize that we need to disable NSWindowFullScreenButton if the window is disabled. Or is that what you meant to do here? (We'd need to a protect against calling -standardWindowButton: with NSWindowFullScreenButton on OSes that don't support it. It should suffice to test if [self respondsToSelector:@selector(toggleFullScreen:)].)
if (captured || fullscreen)
if (captured || (fullscreen && !(normalStyleMask & NSResizableWindowMask)))
You're trying to distinguish between a window that was full-screened at the instigation of the Windows program versus one which has been full-screened by Cocoa, right? Hmm. I think we need a better technique to determine that. I agree that it's not likely the Windows program would make its window full-screen while still allowing it to be resized but it feels wrong to assume that.
Also, I think we can entirely avoid setting the window level for windows that have been Cocoa full-screened. Setting the window level is mostly about relationship to other windows, but a Cocoa full-screen window should be on a space by itself, shouldn't it?
else if ([self styleMask] & NSFullScreenWindowMask)
level = NSMainMenuWindowLevel + 2;
I'm not following why Cocoa full-screened windows should be at +2 vs. +1.
Also, fair warning: I've got some in-progress changes that will overhaul the management of window levels. I don't think it will be too hard to adapt your patch, but methods will be moving or going away.
if (normalStyleMask & NSResizableWindowMask)
behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
This is in -setMacDrvState: but, since normalStyleMask is changed in -setWindowFeatures:, the collection behavior has to be updated there, too.
- (NSSize)window:(NSWindow *)window willUseFullScreenContentSize:(NSSize)proposedSize
- {
return NSMakeSize(proposedSize.width, proposedSize.height);
- }
Is this actually needed? I assume that's the default behavior when the delegate method is absent. (Also, if it is necessary, it can just return proposedSize without making a new size struct.)
In addition to this work, it would probably good to add an "Enter Full Screen" item in the Window menu. We'd do so only if [NSWindow instancesRespondToSelector:@(toggleFullScreen:)] and the item would use that action and a target of nil (first responder).
Sorry to have nitpicked just about every hunk of the patch. I realize you were just hacking and I appreciate your sharing this with us.
Thanks again, Ken
Hi,
I finally got around to working on support for Cocoa full-screen mode in the Mac driver, based on the work of Kevin Eaves. I've attached a new patch. This patch can only be applied on top of the other Mac driver patches I just submitted to wine-patches.
Some changes from Kevin's original, in no particular oder:
* I have not used the user32 hack to increase the max tracking size and let windows grow so their non-frame area covers the screen. Instead, the call to SetWindowPos() that results from a WINDOW_FRAME_CHANGED event uses SWP_NOSENDCHANGING for Cocoa-full-screen windows. That prevents any immediate modification of the new window rect to be within the max tracking size. However, some programs (e.g. Guild Wars) end up moving the window again shortly afterward and then it gets constrained. This results in a window that doesn't quite fill the screen, showing a plain background around the edges. This isn't ideal. As previously discussed, this may require a new driver entry point to allow it to override the size limits. (Although I got slapped down for trying to add a similar entry point for some other work.)
* Cocoa understandably refuses to minimize a window that's in full-screen mode. So, if Win32-land tries to programmatically minimize a full-screen window, Cocoa just immediately tells it that it's been unminimized. This shouldn't come up much. (One can access a window's system menu using the keyboard to test.)
* We can't distinguish the program trying to make a window Win32 full-screen vs. it merely echoing back the frame set by Cocoa full-screen. So, we never consider a window to be in Win32 full-screen mode if it's in Cocoa full-screen mode. That means that the menu and Dock auto-unhide. Many (most?) apps will modify the window style in addition to just setting the frame such that it becomes incompatible with Cocoa full-screen mode. In that case, the window is first taken out of Cocoa full-screen and then put into Win32 full-screen mode. The menu and Dock are properly hidden, but the window went back to its original space, which may not be what the user wants.
* I have added the standard menu item for controlling Cocoa full-screen, Enter Full Screen, to the Window menu. Cocoa automatically renames that to Exit Full Screen and back as the window enters and exits full-screen mode. As with other items in the Mac menus, I don't allow keyboard shortcuts that don't include Option among the modifiers. So, I've used Command-Option-Control-F instead of just Command-Control-F.
* The menu item and the window widget are properly disabled when the window is disabled.
* The maximum tracking size set by the app for the window is respected in full-screen mode. If the app leaves the default max tracking size alone, then the full-screen size is unconstrained (and so fills the screen) even though the Win32 default is slightly too small to allow that.
* If the app programmatically changes the window rect while the window is in Cocoa full-screen mode, that change is honored. This may end up looking a bit odd, but is necessary for correctness. Furthermore, the changed rect is maintained as the window exits full-screen mode, which is not what Cocoa would normally do. (Cocoa restores the window to the size and position it had before entering full-screen.) This is necessary when, for example, a game switches from windowed (in Cocoa full-screen mode) to Win32 full-screen. It will often change the window style in such a way that forces it out of Cocoa full-screen and changes its size to fill the screen. We don't want Cocoa negating that size change as it transitions out of Cocoa full-screen mode.
Programmatic changes of the window rect that occur during and shortly after the transition into full-screen are not interpreted as setting the frame that should be restored when exiting full-screen mode. Those are probably just responses from Wine and the app to the changes that Cocoa has initiated.
* I set NSWindowCollectionBehaviorFullScreenAuxiliary on any windows which don't get NSWindowCollectionBehaviorFullScreenPrimary. I'm not certain that this is right. That flag is not as clearly documented as I would like. My intent is to allow other Wine windows to share the space with a full-screen-primary window.
* WS_EX_TOOLWINDOW windows (utility windows, in Cocoa parlance) are not eligible for Cocoa full-screen. This means that they get NSWindowCollectionBehaviorFullScreenAuxiliary as per the previous point, so they can share a space with a full-screen primary window.
* I have left out any attempt to reconcile Cocoa full-screen with changes to the display mode which result in the displays being captured. I don't know of an app which does that while leaving its window eligible for Cocoa full-screen, although I haven't tested many yet.
I invite everybody who's interested to test and/or review. Cocoa full-screen was introduced in Mac OS X 10.7, so you have to be running that or later.
Kevin, first, thanks again for your original work on this. Second, you seem to have tested with a variety of apps, including some games or other full-screen apps or ones which changed the display mode. Can you run some new tests and let me know about failures and rough edges? I'd welcome your review and feedback.
Thanks, Ken