When the display mode changes such that the screen height changes, we'd like
our windows to keep their position relative to the top-left of the primary
screen. That's how WinAPI's coordinate system works and we want the WinAPI
position of the window to not change just because the display mode changed.
Unfortunately that's not achievable in Cocoa. Cocoa keeps the window
stationary relative to the screen it's on, not necessarily the primary screen,
and it's sometimes relative to the bottom-left and sometimes the top-left of
that screen.
So, what we do instead is queue an event to get the back end to reassert the
WinAPI position of the window. This is queued before Cocoa can adjust the
Cocoa position of the window which would queue a WINDOW_FRAME_CHANGED to the
back end and mess up the WinAPI position. The back end's reassertion of the
WinAPI position won't be processed by the Cocoa thread until after Cocoa has
adjusted the position and will thus override it. It will also discard any
wrong WINDOW_FRAME_CHANGED that may have been queued.
Signed-off-by: Ken Thomases <ken@codeweavers.com>
The default behavior is that GL surfaces are on top of all non-GL content in
the window. This maximizes the performance for the common case of games, but
clipping by parents, siblings, and child windows isn't respected.
Setting OpenGLSurfaceMode to "behind" pushes the GL surface to be behind the
Mac window. The window has transparent holes punched through it so that the GL
surface shows through. USER32 and the wineserver take care of making sure the
holes are only where the GL windows would be unclipped and unoccluded. Because
the OS X window server has to composite the GL surface with the window, this
limits the framerate.
Since the Mac driver has no server-side rendering path, GDI rendering to a
window which has a GL surface doesn't work. As a partial workaround, mostly
for cases where a GL surface is created but never used, setting
OpenGLSurfaceMode to "transparent" allows the GDI rendering to show through the
transparent parts of the GL surface. The GDI rendering is drawn to the
top-level window's surface as normal. (The behavior of user32 to exclude the
portion covered by a GL window from GDI rendering is disabled.) The GL surface
is in front of the window but potentially wholly or partially transparent. It
is composited with the window behind it.
The GL surface is initially cleared to be completely transparent. So, if
no GL rendering is done, the window will appear as though the GL surface didn't
exist.
Not sending the brought-forward event for a click that was sent was an artifact
of a time when that branch was only used for posting a request for focus. When
I added the brought-forward event, I didn't reconsider that logic.
OS X doesn't have the same concept of maximized windows as Windows does.
There's no mode that prevents a normally-movable window from being moved. If
a window is "zoomed", it mostly fills the screen but the user can still move
or resize it, at which point it ceases to be in the zoomed state. So, users
are confused and frustrated when they can't move a window that's maximized.
To get similar behavior while still respecting Win32 semantics, we detect when
the user tries to move a maximized window. When they start, a request is
submitted to the app to restore the window. Unless and until the window is
restored, we don't actually allow the window to move.
The user expects to move the window from its current (maximized) position. It
should not jump to its normal position upon being restored. So, we set the
window's normal position to its current position before restoring it.
OS X doesn't have the same concept of maximized windows as Windows does.
There's no mode that prevents a normally-resizable window from being resized.
If a window is "zoomed", it mostly fills the screen but the user can still
move or resize it, at which point it ceases to be in the zoomed state. So,
users are confused and frustrated when they can't resize a window that's
maximized.
To get similar behavior while still respecting Win32 semantics, we now let the
user try to resize maximized windows. (The resize cursors are shown at the
edges of the window frame.) When they start, a request is submitted to the app
to restore the window. Unless and until the window is restored, we don't
actually allow the window to change its size.
The user expects to resize the window from its current (maximized) position.
It should not jump to its normal position upon being restored. So, we set the
window's normal position to its current position before restoring it.
OS X doesn't really have the concept of windows being maximized; that is, being
in a mode where they can't be moved or resized. As a consequence, it doesn't
have a button in the window title bar to restore a maximized window to normal.
So, when a Wine window is maximized, the Mac driver hijacks the green zoom
button to act as a restore button. (When a window is zoomed, the green button
"unzooms" back to its last user size and position, so it's analogous.)
However, with OS X 10.10 (Yosemite), the green button prefers to act as a
toggle for the Cocoa full-screen mode rather than zooming and unzooming. This
made it difficult for users to restore a maximized window. They would have to
Option-click the green button, double-click the title bar, or choose Zoom
from the Window menu, none of which is obvious.
The fix is to disable Cocoa full-screen mode for maximized windows. Then, the
green button reverts to unzoom and restoring the window.
Status items are the things on the right end of the Mac menu bar, like the
clock and volume widget. It turns out that they are displayed at a higher
window level than everything else in the menu bar. For the case where the
displays are not captured for a full-screen window, the window ends up at the
same window level as the status items, and they would sometimes end up on top.
They would draw over the full-screen window and could be clicked.
On high-resolution Retina displays, the OS X window backing store has twice the
pixels as Wine's window backing store. So, our images get scaled up. Core
Graphics had been interpolating/smoothing the image, which resulted in
fuzziness. This tells it not to do that.
I had assumed this wouldn't be necessary since we pass FALSE for the
shouldInterpolate parameter of CGImageCreate() when we create the images.
Apparently, that's not sufficient.
When a window is being dragged, we prevent delivery of clicks to Wine. We were
also preventing telling Wine that a window had been brought forward, but this
was incorrect. It prevented clicks in the title bar from activating the window.
If the mouse is captured, we change which window receives the click event, but
that shouldn't change which window we tell Wine was brought forward by Cocoa.
We can't prevent Cocoa from bringing disabled/no-activate windows forward. So,
we need to tell Wine about the z-order change.
We still do avoid telling Wine to activate disabled/no-activate windows, though.
For some empty RECTs, such as { INT_MAX, INT_MAX, INT_MIN, INT_MIN }, right
minus left or bottom minus top underflow and wrap around to positive values.
On Yosemite, in full-screen mode, Cocoa adds child windows of its own to our
windows. These windows are, of course, not instances of WineWindow. So, when
we call WineWindow-specific methods on them, it throws exceptions.
On Yosemite, double-clicking a window's title bar zooms it. (This is to
compensate for the fact that the zoom button has been replaced by a full-screen
button.) Sometimes, double-clicking in the content area would count as double-
clicking in the title bar.
This is controlled, in part, by the -mouseDownCanMoveWindow method of the view
that was hit in the window. The default implementation of that returns YES
for non-opaque views, as the views are in the Mac driver. Overriding it to
return NO prevents the problem.
NSBezierPath doesn't override the -isEqual: method to actually compare paths,
so it just falls back to object identity which, in our case, makes paths seem
like they're never equal.
Also, memcmp()-ing the rectangle array is almost certainly faster than any
general test for equality between two paths.
This avoids flickering and tearing on some versions of OS X during frequent
redrawing in a shaped window, such as when scrolling a document in Word 2007.
Since we aren't guaranteed that the window surface has updated bits for us to
draw, we mark the whole content view as needing redisplay and draw the window's
shape in the background color on the first -drawRect: after the shape change.
This means the resulting rectangle will be short, but we don't have much
choice. Some apps don't cope properly with the one-past-the-end character.
For example, Excel 2007 gets stuck in an infinite loop.
The Mac driver can generate scroll wheel events with values which are not integral
multiples of WHEEL_DELTA. Apps should handle that by scrolling a corresponding
non-integral multiple of what they'd do for a WHEEL_DELTA-valued scroll or, if
they can't, then at least accumulate scroll distance until its magnitude exceeds
WHEEL_DELTA and do a "chunky" scroll. However, many apps don't do that properly.
They may scroll way too far/fast or even in the opposite direction.
If the registry setting UsePreciseScrolling is set to "n", the Mac driver will do
that accumulation and chunking itself to work around such broken app behavior.
Cocoa will bring an unowned window to the front of its level when it's clicked,
but it doesn't do that for owned windows. The old code went out of its way to
make owned windows behave like unowned windows in this respect. That was
exactly backward. We wish we could control whether windows are raised on a
click. We don't have that opportunity for unowned windows, but, by ripping
out a bunch of code, we do for owned windows.
Many games clip the cursor to the client area of the window. However, on OS X,
the resizing controls extend into that client area. So, it's possible that
while playing, the user might unintentionally click in the resizing area and
drag, resizing the window.
It's not necessary. Unlike with X11, on Mac OS X the pixel format doesn't affect
the properties of windows and views. The pixel format is a property of the GL
context, which can attach to any view.