[PATCH v2] user32: Always send WM_NCACTIVATE when changing the foreground window.

Alex Henrie alexhenrie24 at gmail.com
Fri Mar 10 00:07:07 CST 2017


Fixes https://bugs.winehq.org/show_bug.cgi?id=7198

v2: Use the wineserver to determine if the new foreground window is
already active in its thread.

Signed-off-by: Alex Henrie <alexhenrie24 at gmail.com>
---
 dlls/user32/focus.c            | 32 ++++++++++++++++++++------------
 dlls/user32/tests/msg.c        | 30 +++++++++++++++++++++++++++---
 include/wine/server_protocol.h |  4 ++--
 server/protocol.def            |  1 +
 server/queue.c                 |  1 +
 server/request.h               |  1 +
 server/trace.c                 |  1 +
 7 files changed, 53 insertions(+), 17 deletions(-)

diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c
index f1c883167e..42d1a2b4ab 100644
--- a/dlls/user32/focus.c
+++ b/dlls/user32/focus.c
@@ -182,8 +182,8 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus )
  */
 static BOOL set_foreground_window( HWND hwnd, BOOL mouse )
 {
-    BOOL ret, send_msg_old = FALSE, send_msg_new = FALSE;
-    HWND previous = 0;
+    BOOL ret, send_msg_old, send_msg_new, activate_new;
+    HWND previous;
 
     SERVER_START_REQ( set_foreground_window )
     {
@@ -193,22 +193,30 @@ static BOOL set_foreground_window( HWND hwnd, BOOL mouse )
             previous = wine_server_ptr_handle( reply->previous );
             send_msg_old = reply->send_msg_old;
             send_msg_new = reply->send_msg_new;
+            activate_new = reply->activate_new;
         }
     }
     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 (!activate_new)
     {
-        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);
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index ee9fdd12eb..6b59fb8911 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -4192,7 +4192,7 @@ struct set_foreground_window_reply
     user_handle_t  previous;
     int            send_msg_old;
     int            send_msg_new;
-    char __pad_20[4];
+    int            activate_new;
 };
 
 
@@ -6412,6 +6412,6 @@ union generic_reply
     struct terminate_job_reply terminate_job_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 524
+#define SERVER_PROTOCOL_VERSION 525
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/protocol.def b/server/protocol.def
index 60865a6ffc..4baa149f54 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2969,6 +2969,7 @@ enum coords_relative
     user_handle_t  previous;      /* handle to the previous foreground window */
     int            send_msg_old;  /* whether we have to send a msg to the old window */
     int            send_msg_new;  /* whether we have to send a msg to the new window */
+    int            activate_new;  /* whether we have to activate the new window */
 @END
 
 /* Set the current thread focus window */
diff --git a/server/queue.c b/server/queue.c
index c479b388bd..957ea6d608 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -2957,6 +2957,7 @@ DECL_HANDLER(set_foreground_window)
     {
         set_foreground_input( desktop, thread->queue->input );
         reply->send_msg_new = (desktop->foreground_input != queue->input);
+        reply->activate_new = (thread->queue->input->active != req->handle);
     }
     else set_win32_error( ERROR_INVALID_WINDOW_HANDLE );
 
diff --git a/server/request.h b/server/request.h
index cd396ee3df..a0b494f1ac 100644
--- a/server/request.h
+++ b/server/request.h
@@ -1914,6 +1914,7 @@ C_ASSERT( sizeof(struct set_foreground_window_request) == 16 );
 C_ASSERT( FIELD_OFFSET(struct set_foreground_window_reply, previous) == 8 );
 C_ASSERT( FIELD_OFFSET(struct set_foreground_window_reply, send_msg_old) == 12 );
 C_ASSERT( FIELD_OFFSET(struct set_foreground_window_reply, send_msg_new) == 16 );
+C_ASSERT( FIELD_OFFSET(struct set_foreground_window_reply, activate_new) == 20 );
 C_ASSERT( sizeof(struct set_foreground_window_reply) == 24 );
 C_ASSERT( FIELD_OFFSET(struct set_focus_window_request, handle) == 12 );
 C_ASSERT( sizeof(struct set_focus_window_request) == 16 );
diff --git a/server/trace.c b/server/trace.c
index e0ce45af6d..854b8a6849 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -3537,6 +3537,7 @@ static void dump_set_foreground_window_reply( const struct set_foreground_window
     fprintf( stderr, " previous=%08x", req->previous );
     fprintf( stderr, ", send_msg_old=%d", req->send_msg_old );
     fprintf( stderr, ", send_msg_new=%d", req->send_msg_new );
+    fprintf( stderr, ", activate_new=%d", req->activate_new );
 }
 
 static void dump_set_focus_window_request( const struct set_focus_window_request *req )
-- 
2.12.0




More information about the wine-patches mailing list