Re: winemac.drv: add fullscreen mode support for Mac OS X 10.7+

2013-10-08 Thread Ken Thomases
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+

2013-05-16 Thread Ken Thomases
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+

2013-05-15 Thread Kevin Eaves

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+

2013-05-12 Thread Ken Thomases
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+

2013-05-09 Thread Kevin Eaves
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+

2013-05-09 Thread Ken Thomases
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