Re: winemac.drv: add fullscreen mode support for Mac OS X 10.7+
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
Re: winemac.drv: add fullscreen mode support for Mac OS X 10.7+
On May 15, 2013, at 8:49 PM, Kevin Eaves wrote: … The title is also empty when exiting borderless to titled, which can be fixed here. Hmm, good catch. I'll have to check, but I suspect the window no longer remembers its title at that point. And the Mac driver doesn't currently store it anywhere else. So, we may need to do so in order to restore it. Also, if the Windows program changes a window from resizable to non-resizable, then we should probably pull the window out of Cocoa fullscreen. The Windows program _may_ have intended to make the window full-screen but we can't know that. It may simply be changing the window style for some other purpose, and that may make it no longer a candidate for Cocoa full-screen mode. Allowing Windows fullscreen in Cocoa fullscreen was never a very good idea. I did not want to force the window out, but a borderless window would not be allowed to enter Cocoa fullscreen, so it probably should not be there. Yeah. It may make for a poor user experience to force the window out of Cocoa full-screen, especially if it's just going to go Windows full-screen right afterward, but I think it's probably necessary. I think it's a relatively rare occurrence, anyway. I disagree. Windows programs that are not expecting their window to resize (because they haven't made them resizable) can misbehave badly if the window does resize. Just because that didn't happen in your testing doesn't mean it won't. As you mentioned in your original email, Cocoa full-screen is roughly akin to window resizing. So, it should be disabled if/when the window is made non-resizable. I do not see the reason to disable buttons and make the windows non-resizable. Probably wrong here, but doesn't this just eliminate click-through, which is typical of Windows apps, because the Windows paradigm stinks? Well, that's how it works on Windows. And the X11 driver in Wine. And native Mac apps. (Open TextEdit. Its window has all the buttons enabled and can be resized. Open the modal Open dialog. The document window still has all its buttons and, on 10.6, the grow box, but they're disabled. On 10.7+, the resize cursors around the edge still show, but they're ineffective. I suppose we can achieve that same effect by not using the min and max sizes to prevent resize but do it by overriding -windowWillResize:toSize:, but I prefer it to be obviously not resizable.) The main reason is that some Windows apps will probably freak out if their windows get resized, closed, or minimized when they're supposed to be disabled. I don't follow this. It is possible to resize any window even non-resizable ones? To what are you referring? Possible how? Do you mean specifically just with this full-screen patch? It is possible to do anything we want with a window. The actual Windows program not freaking out is another story. Just pointing out that we are not limited. Sure, but Wine is aiming for compatibility with Windows apps, so the not freaking out thing is kind of a big deal. ;) -Ken
Re: winemac.drv: add fullscreen mode support for Mac OS X 10.7+
On May 12, 2013, at 1:12 PM, Ken Thomases wrote: I'm not seeing that problem happen here. Mind you, I'm currently testing on 10.6. I'll have to run some tests on 10.7+ tomorrow. I find it improbable that removing NSResizableWindowMask from the style doesn't disable the zoom button. That style is the only thing which enables the zoom button to begin with. In other words, in a normal Mac app, one would not need to disable the zoom button separately. Looks like you sent a patch for this. The title is also empty when exiting borderless to titled, which can be fixed here. Also, if the Windows program changes a window from resizable to non-resizable, then we should probably pull the window out of Cocoa fullscreen. The Windows program _may_ have intended to make the window full-screen but we can't know that. It may simply be changing the window style for some other purpose, and that may make it no longer a candidate for Cocoa full-screen mode. Allowing Windows fullscreen in Cocoa fullscreen was never a very good idea. I did not want to force the window out, but a borderless window would not be allowed to enter Cocoa fullscreen, so it probably should not be there. I disagree. Windows programs that are not expecting their window to resize (because they haven't made them resizable) can misbehave badly if the window does resize. Just because that didn't happen in your testing doesn't mean it won't. As you mentioned in your original email, Cocoa full-screen is roughly akin to window resizing. So, it should be disabled if/when the window is made non-resizable. I do not see the reason to disable buttons and make the windows non-resizable. Probably wrong here, but doesn't this just eliminate click-through, which is typical of Windows apps, because the Windows paradigm stinks? I don't follow this. It is possible to resize any window even non-resizable ones? To what are you referring? Possible how? Do you mean specifically just with this full-screen patch? It is possible to do anything we want with a window. The actual Windows program not freaking out is another story. Just pointing out that we are not limited.
Re: winemac.drv: add fullscreen mode support for Mac OS X 10.7+
Hi Kevin, I'm bringing this back to wine-devel. Please CC the list unless you intend to take things private, in which case please say so. On May 10, 2013, at 6:48 PM, Kevin Eaves wrote: I should have made everything clear, sorry. It was for personal use, so it's pretty nasty, but works great. The only real problem is with user32. Everything else is easy to clean up and get working with Wine properly without any issues. Just wanted to show that. Sure, that's what I figured. On May 9, 2013, at 9:56 PM, Ken Thomases wrote: 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. Only windows in the windows cycle should be fullscreen enabled. If the window can be manually moved to its own space, then it should be able to go fullscreen. No dialogs are enabled. These follow the main window to spaces. If in Cocoa fullscreen, the new window automatically opens fullscreen in its own space. Everything works just like Mac applications with this setting. Ah, I failed to notice before that the use of NSWindowCollectionBehaviorFullScreenPrimary was only in the same code path as NSWindowCollectionBehaviorParticipatesInCycle. Yes, that makes sense. From cocoa_window.m.diff: +#import Cocoa/Cocoa.h Was that actually needed? cocoa_window.h already imports AppKit/AppKit.h. ... +if (style NSResizableWindowMask) +[[self standardWindowButton:NSWindowZoomButton] setEnabled:!self.disabled]; These should have not been included in the diff. It's unrelated to Cocoa fullscreen, however, the zoom button is currently bugged. It is not disabled when the window is disabled. To reproduce the problem: launch regedit, open the import window, and click the zoom button on the main window. I sent a patch for it. I'm not seeing that problem happen here. Mind you, I'm currently testing on 10.6. I'll have to run some tests on 10.7+ tomorrow. I find it improbable that removing NSResizableWindowMask from the style doesn't disable the zoom button. That style is the only thing which enables the zoom button to begin with. In other words, in a normal Mac app, one would not need to disable the zoom button separately. -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. The window levels are automatically adjusted and the menu is in a hover state. We need to prevent the menu from being hidden, and hide the menu if the Windows program goes fullscreen while in Cocoa fullscreen (+1 doesn't cut it). I'm going to have to do some testing to understand this, too. NSMainMenuWindowLevel should be in the same level as the menu (meaning could be above or below due to normal window ordering operations). NSMainMenuWindowLevel + 1 should always be above the menu, regardless. NSMainMenuWindowLevel + 2 should not be necessary. But maybe something weird is going on. Also, if the Windows program changes a window from resizable to non-resizable, then we should probably pull the window out of Cocoa fullscreen. The Windows program _may_ have intended to make the window full-screen but we can't know that. It may simply be changing the window style for some other purpose, and that may make it no longer a candidate for Cocoa full-screen mode. +- (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.) This little gem will resize ANY window — non-resizable, disabled, a dialog box... Add this and poof!! There is no reason to ever disable Cocoa fullscreen. Mac applications don't so neither should Wine. I disagree.
winemac.drv: add fullscreen mode support for Mac OS X 10.7+
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. cocoa_window.m.diff Description: Binary data winpos.c.diff Description: Binary data
Re: winemac.drv: add fullscreen mode support for Mac OS X 10.7+
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