[PATCH] user32: Always send WM_NCACTIVATE when changing the foreground window.
Alex Henrie
alexhenrie24 at gmail.com
Sun Mar 5 23:23:19 CST 2017
Fixes https://bugs.winehq.org/show_bug.cgi?id=7198
The problem was that WM_NCACTIVATE was not being sent if the new
foreground window was already an active window.
I added a few tests for this:
- Test to show that calling SetActiveWindow on an already active window
does NOT send WM_NCACTIVATE
- Test to show that calling SetForegroundWindow on an active background
window DOES send WM_NCACTIVATE
- Test to show that calling SetForegroundWindow on the foreground window
(which has to be an active window) does NOT send WM_NCACTIVATE
Based on these tests, the right place and time to send the message is in
set_foreground_window, but only if the foreground window is actually
changing.
It's not necessary to call set_active_window on the active window (or
send WM_WINE_SETACTIVEWINDOW to the active window) if the active window
is not changing because SetActiveWindow and set_active_window are no-ops
in that case.
Signed-off-by: Alex Henrie <alexhenrie24 at gmail.com>
---
dlls/user32/focus.c | 27 +++++++++++++++++----------
dlls/user32/tests/msg.c | 30 +++++++++++++++++++++++++++---
2 files changed, 44 insertions(+), 13 deletions(-)
diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c
index f1c883167e..f97b64f835 100644
--- a/dlls/user32/focus.c
+++ b/dlls/user32/focus.c
@@ -197,18 +197,25 @@ static BOOL set_foreground_window( HWND hwnd, BOOL mouse )
}
SERVER_END_REQ;
- if (ret && previous != hwnd)
+ if (!ret || previous == hwnd)
+ return ret;
+
+ if (send_msg_old) /* old window belongs to other thread */
+ SendNotifyMessageW( previous, WM_WINE_SETACTIVEWINDOW, 0, 0 );
+ else if (send_msg_new) /* old window belongs to us but new one to other thread */
+ ret = set_active_window( 0, NULL, mouse, TRUE );
+
+ if (GetActiveWindow() == hwnd)
{
- if (send_msg_old) /* old window belongs to other thread */
- SendNotifyMessageW( previous, WM_WINE_SETACTIVEWINDOW, 0, 0 );
- else if (send_msg_new) /* old window belongs to us but new one to other thread */
- ret = set_active_window( 0, NULL, mouse, TRUE );
-
- if (send_msg_new) /* new window belongs to other thread */
- SendNotifyMessageW( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0 );
- else /* new window belongs to us */
- ret = set_active_window( hwnd, NULL, mouse, TRUE );
+ SendNotifyMessageW( hwnd, WM_NCACTIVATE, 1, (LPARAM)hwnd );
+ return ret;
}
+
+ if (send_msg_new) /* new window belongs to other thread */
+ SendNotifyMessageW( hwnd, WM_WINE_SETACTIVEWINDOW, (WPARAM)hwnd, 0 );
+ else /* new window belongs to us */
+ ret = set_active_window( hwnd, NULL, mouse, TRUE );
+
return ret;
}
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index 23c261e2ac..3b3ca5c62b 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -13294,6 +13294,11 @@ static void test_SetActiveWindow(void)
if (ret == hwnd) ok_sequence(SetActiveWindowSeq1, "SetActiveWindow(hwnd), hwnd visible", TRUE);
flush_sequence();
+ trace("SetActiveWindow(hwnd), hwnd visible and already active\n");
+ ret = SetActiveWindow(hwnd);
+ if (ret == hwnd) ok_sequence(WmEmptySeq, "SetActiveWindow(hwnd), hwnd visible and already active", FALSE);
+ flush_sequence();
+
trace("SetActiveWindow(popup), hwnd visible, popup visible\n");
ret = SetActiveWindow(popup);
ok( ret == hwnd, "Failed to SetActiveWindow(popup), popup visible\n");
@@ -13321,7 +13326,7 @@ static void test_SetActiveWindow(void)
DestroyWindow(hwnd);
}
-static const struct message SetForegroundWindowSeq[] =
+static const struct message SetForegroundWindowSeq0[] =
{
{ WM_NCACTIVATE, sent|wparam, 0 },
{ WM_GETTEXT, sent|defwinproc|optional },
@@ -13333,6 +13338,14 @@ static const struct message SetForegroundWindowSeq[] =
{ 0 }
};
+static const struct message SetForegroundWindowSeq1[] =
+{
+ { WM_NCACTIVATE, sent|wparam, 1 },
+ { WM_GETTEXT, sent|defwinproc|optional },
+ { WM_WINDOWPOSCHANGING, sent|wparam|optional, SWP_NOSIZE|SWP_NOMOVE }, /* FIXME: Missing in Wine */
+ { 0 }
+};
+
static void test_SetForegroundWindow(void)
{
HWND hwnd;
@@ -13347,10 +13360,21 @@ static void test_SetForegroundWindow(void)
trace("SetForegroundWindow( 0 )\n");
SetForegroundWindow( 0 );
ok_sequence(WmEmptySeq, "SetForegroundWindow( 0 ) away from foreground top level window", FALSE);
+
trace("SetForegroundWindow( GetDesktopWindow() )\n");
SetForegroundWindow( GetDesktopWindow() );
- ok_sequence(SetForegroundWindowSeq, "SetForegroundWindow( desktop ) away from "
- "foreground top level window", FALSE);
+ ok_sequence(SetForegroundWindowSeq0, "SetForegroundWindow( desktop ) away from foreground top level window", FALSE);
+
+ trace("SetForegroundWindow to a background window that is already active\n");
+ SetActiveWindow( hwnd );
+ flush_sequence();
+ SetForegroundWindow( hwnd );
+ ok_sequence(SetForegroundWindowSeq1, "SetForegroundWindow to a background window that is already active", FALSE);
+
+ trace("SetForegroundWindow to the current foreground window\n");
+ SetForegroundWindow( hwnd );
+ ok_sequence(WmEmptySeq, "SetForegroundWindow to the current foreground window", FALSE);
+
trace("done\n");
DestroyWindow(hwnd);
--
2.12.0
More information about the wine-patches
mailing list