We only care if we have changed the mode and we're changing it back to its
original. Even if the current mode matches the target mode, we may still
need to release the displays and clear the entry from originalDisplayModes.
originalDisplayModes should be used when active, empty when inactive.
latentDisplayModes is used when inactive, empty when active.
The count of entries in originalDisplayModes is used to test whether the
process has the displays captured so adding entries when inactive would give
incorrect results. This could have led us to mistakenly change the display
mode when we don't have the displays captured.
Among other things, this fixes Syberia 2. That game shows, hides, and then
shows its window. Hiding it caused a WINDOW_LOST_FOCUS event to be queued.
By the time it was processed, the window was the foreground window again.
In response to being told it had lost focus, the game minimized its window.
Hiding the window should have prevented or discarded the WINDOW_LOST_FOCUS
event since the change was driven from Wine and the Win32 foreground/active
window state would already be correct. In addition, when the program
re-showed its window and made it foreground, that should have discarded the
event as being out of date. Now they do.
The Win32 window state might have changed while the event was in the queue,
making it obsolete. Sending WM_SYSCOMMAND/SC_RESTORE might re-show a hidden
window, for example.
Cocoa would implictly unhide it when we order a window, anyway. Doing it
early avoids problems from querying -[NSWindow isVisible] while the app is
hidden. That method returns FALSE even for windows which would be visible
if the app weren't hidden.
The -[NSWindow isVisible] method returns FALSE when the process is hidden,
but that's not what we need to know in some cases.
This fixes full-screen games which minimize their window when they lose
focus. Command-Tabbing away hides the process. Because the window was not
visible, the code didn't actually minimize it. When switching back to the
process, no event was sent to the Wine back-end telling it the window had
been restored, so it never resumed drawing to it.
The user is prevented from moving or resizing a maximized window. The zoom
button is still present and enabled for a maximized window but requests that
it be restored rather than simply resizing it, which is what it does for
normal windows.
If a window is not resizable (lacks WS_THICKFRAME) but has a maximize box
(WS_MAXIMIZEBOX), then the zoom button requests that it be maximized rather
than resizing it.
The window menu items are not updated as the window state changes; they only
update when the menu is shown. So the item state is not a reliable indicator
of whether minimization is allowed.
Fixes a problem in some games which repeatedly (re)establish the same cursor
clipping rect, making it exceedingly difficult to move the camera with the
mouse.
This simulates some of what would happen if user32 were managing the drag. The
click in the caption would cause WM_SYSCOMMAND/SC_MOVE. The processing of that
message is synchronous and doesn't return until the move is complete.
Some games require that "blocking" in the internal event loop to prevent them
from misbehaving during the drag.
This fixes a problem where some apps move their window to the front after
the user switches away to another app. OS X prevents the background app
from actually coming in front of the active app's front window, but the
window gets ordered in second place, possibly obscuring other windows of the
active app.
New clipboard formats had been registered for them, but that was pointless.
No Windows app would ever expect or make use of such clipboard formats or the
associated pasteboard data.
It has a non-object pointer from the caller, so it can't allow the caller
to continue until it's finished with it. Also, it discards events from the
event queue and we don't want the caller to process them first.
Fixes brokenness introduced by 784a9139.
Some programs minimize windows which are outside of the desktop. The Mac
driver had been leaving such windows ordered out, which prevented them from
minimizing and appearing on the Dock. That, in turn, made it difficult for
the user to restore them.
Queries can be run out of order because the main thread is waiting on the
response. The main thread didn't really need a response from QUERY_RESIZE_END.
It was only a query for symmetry with QUERY_RESIZE_START.
The Mac driver was already sending these events when the user resizes the
window by dragging its corner/edges, but there are other occasions when the
window frame changes. For example, when the user zooms the window.
The tracking of whether it is over a window or not is only updated when the
mouse moves. If a window was created or moved under it, then the state can be
stale. That caused us to defer hiding the cursor until the mouse was moved.
This happens at the start of games pretty often.
The main dispatch queue is a serial queue and is a shared resource. If we
submit a long-running task to it, then no other tasks, including those submitted
by the system frameworks, can run until it completes.
The standard keyboard shortcut for switching the keyboard layout is Command-
Space, but the Mac driver never sees the Space key press. So, Wine only sees
a press and release of Alt, which puts focus on the menu bar. This prevents
that focus change.
The code had previously set the cursor back to the standard arrow and unhid
it when it left all app windows. Now it restores the cursor image that the
app set and re-hides it if necessary when it moves back over any app window.
Some events get queued for all GUI-connected threads but are only processed
by the first to dequeue them. Other threads which tend their event queue
discard such already-processed events. However, some threads may be
connected to the GUI but never tend their event queue. To prevent such
threads from accumulating zombie events, the zombies are cleared each time a
new event is queued.
This fixes a problem where windows could spontaneously re-minimize after
being unminimized. Cocoa would see the window unminimize. It would queue
a WINDOW_DID_UNMINIMIZE event. While that event was pending, Wine might do
something which caused set_cocoa_window_properties() to be called and tell
Cocoa to conform itself to the current Win32 state. The current Win32 state
still had the window minimized, so Cocoa would re-minimize the window. It
would even discard the WINDOW_DID_UNMINIMIZE event.
Cocoa would automatically do this for a normal app. However, the Mac driver
makes all of its windows inherit from NSPanel and Cocoa ignores panels for
this feature.
They show up in the taskbar on Windows 7. Selecting them from there is
meaningful and useful, as is selecting them from the Window menu.
In addition to just switching among windows from that menu, this is also
important to recovering a minimized window if the user has configured their
system preferences to minimize windows into the process's dock icon (rather
than as separate dock icons).
The Mac driver captures the displays when the program changes the display
mode. If the user types Command-Tab to switch away, it resets the displays
to their original modes and releases them. However, if they switched back,
it didn't restore the mode to what the program had set, so the program often
showed the game window in a corner of the screen with the top behind the Mac
menu bar.
Cocoa won't order a minimized window out of the screen list using -orderOut:.
This leaves a window that should be hidden still visible in the Dock, where
it can be unminimized.
That event can confuse things if the program switches focus from A to B and
then back to A and then processes events. It will get an event saying that
A lost focus in Cocoa, check that A does indeed have current focus in Wine,
and so switch focus away from it (to the desktop window). (It then gets an
event that B lost focus, but that does nothing at that point.)
This matches what Cocoa does when determining how to handle an event so that,
for example, our test if a click is in the window grow box corresponds to
whether Cocoa will run an internal mouse-tracking loop to resize the window
when we pass it the event. This fixes a problem where both Cocoa and user32
would try to run a resize loop and the cursor would get "stuck" resizing the
window after the button was released.
It's fairly common in Mac keyboard layouts that, if you type a dead key twice,
the second key press will both produce a non-dead character and also
perpetuate the dead-key state. For example, with the U.S. layout, Option-E,
E will produce "" and Option-E, Option-E, E will produce "". Windows
keyboard layouts don't tend to do this. The second key press produces the
non-dead character and clears the dead-key state.
The Cocoa parent-child relationship has undesirable side effects and bugs. In
the general case, it's the only way to maintain the z-order of owned windows
relative to their owner. But when the owner is non-topmost and an owned
window is topmost, the Cocoa window level will enforce that and we don't
need it.
It may be necessary to reorder to some extent because the clicked window is
behind a sibling at the same level, but that shouldn't move it later in the
list than higher-level siblings.
Cocoa gets buggy if the list of child windows isn't in z-order.
The right place may not be the end of the list of Cocoa child windows if some
of the siblings are at a higher window level (i.e. floating if the clicked
window is not).
For keys pressed in combination with Command, -[NSApplication sendEvent:]
simply doesn't pass the key-up event through to the window. We have to
track which keys we've told Wine are pressed because Cocoa may consume
key-downs that trigger menus or system behaviors.