user32: Correct dialog focus behavior.

Alex Henrie alexhenrie24 at gmail.com
Mon Aug 6 18:13:15 CDT 2012


This patch adds four focus behavior tests to user32 and code to make
them pass. Fixes bug 31386.

---
 dlls/user32/defdlg.c       |   21 ++++++++++++++-------
 dlls/user32/tests/dialog.c |   42 +++++++++++++++++++++++++++++++++++-------
 2 files changed, 49 insertions(+), 14 deletions(-)

diff --git a/dlls/user32/defdlg.c b/dlls/user32/defdlg.c
index fecd417..e4b55f3 100644
--- a/dlls/user32/defdlg.c
+++ b/dlls/user32/defdlg.c
@@ -55,9 +55,9 @@ static DLGPROC DEFDLG_GetDlgProc( HWND hwnd )
  *           DEFDLG_SetFocus
  *
  * Set the focus to a control of the dialog, selecting the text if
- * the control is an edit dialog.
+ * the control is an edit dialog that has DLGC_HASSETSEL.
  */
-static void DEFDLG_SetFocus( HWND hwndDlg, HWND hwndCtrl )
+static void DEFDLG_SetFocus( HWND hwndCtrl )
 {
     if (SendMessageW( hwndCtrl, WM_GETDLGCODE, 0, 0 ) & DLGC_HASSETSEL)
         SendMessageW( hwndCtrl, EM_SETSEL, 0, -1 );
@@ -83,7 +83,7 @@ static void DEFDLG_SaveFocus( HWND hwnd )
 /***********************************************************************
  *           DEFDLG_RestoreFocus
  */
-static void DEFDLG_RestoreFocus( HWND hwnd )
+static void DEFDLG_RestoreFocus( HWND hwnd, BOOL justActivate )
 {
     DIALOGINFO *infoPtr;
 
@@ -92,12 +92,19 @@ static void DEFDLG_RestoreFocus( HWND hwnd )
     /* Don't set the focus back to controls if EndDialog is already called.*/
     if (infoPtr->flags & DF_END) return;
     if (!IsWindow(infoPtr->hwndFocus) || infoPtr->hwndFocus == hwnd) {
+        if (justActivate) return;
         /* If no saved focus control exists, set focus to the first visible,
            non-disabled, WS_TABSTOP control in the dialog */
         infoPtr->hwndFocus = GetNextDlgTabItem( hwnd, 0, FALSE );
+        /* If there are no WS_TABSTOP controls, set focus to the first visible,
+           non-disabled control in the dialog */
+        if (!infoPtr->hwndFocus) infoPtr->hwndFocus = GetNextDlgGroupItem( hwnd, 0, FALSE );
         if (!IsWindow( infoPtr->hwndFocus )) return;
     }
-    DEFDLG_SetFocus( hwnd, infoPtr->hwndFocus );
+    if (justActivate)
+        SetFocus( infoPtr->hwndFocus );
+    else
+        DEFDLG_SetFocus( infoPtr->hwndFocus );
 
     /* This used to set infoPtr->hwndFocus to NULL for no apparent reason,
        sometimes losing focus when receiving WM_SETFOCUS messages. */
@@ -250,12 +257,12 @@ static LRESULT DEFDLG_Proc( HWND hwnd, UINT msg, WPARAM wParam,
             return DefWindowProcA( hwnd, msg, wParam, lParam );
 
         case WM_ACTIVATE:
-            if (wParam) DEFDLG_RestoreFocus( hwnd );
+            if (wParam) DEFDLG_RestoreFocus( hwnd, TRUE );
             else DEFDLG_SaveFocus( hwnd );
             return 0;
 
         case WM_SETFOCUS:
-            DEFDLG_RestoreFocus( hwnd );
+            DEFDLG_RestoreFocus( hwnd, FALSE );
             return 0;
 
         case DM_SETDEFID:
@@ -280,7 +287,7 @@ static LRESULT DEFDLG_Proc( HWND hwnd, UINT msg, WPARAM wParam,
                 HWND hwndDest = (HWND)wParam;
                 if (!lParam)
                     hwndDest = GetNextDlgTabItem(hwnd, GetFocus(), wParam);
-                if (hwndDest) DEFDLG_SetFocus( hwnd, hwndDest );
+                if (hwndDest) DEFDLG_SetFocus( hwndDest );
                 DEFDLG_SetDefButton( hwnd, dlgInfo, hwndDest );
             }
             return 0;
diff --git a/dlls/user32/tests/dialog.c b/dlls/user32/tests/dialog.c
index 6bd34b3..0ebab4c 100644
--- a/dlls/user32/tests/dialog.c
+++ b/dlls/user32/tests/dialog.c
@@ -828,7 +828,7 @@ static const char * GetHwndString(HWND hw)
   return "unknown handle";
 }
 
-static void test_initial_focus(void)
+static void test_focus(void)
 {
     /* Test 1:
      * This test intentionally returns FALSE in response to WM_INITDIALOG
@@ -900,6 +900,8 @@ static void test_initial_focus(void)
         HRSRC hResource;
         HANDLE hTemplate;
         DLGTEMPLATE* pTemplate;
+        HWND hTextbox;
+        DWORD selectionStart = 0xdead, selectionEnd = 0xbeef;
 
         hResource = FindResourceA(g_hinst,"FOCUS_TEST_DIALOG", RT_DIALOG);
         hTemplate = LoadResource(g_hinst, hResource);
@@ -912,6 +914,20 @@ static void test_initial_focus(void)
         ok ((g_hwndInitialFocusT1 == 0),
             "Focus should not be set for an invisible DS_CONTROL dialog %p.\n", g_hwndInitialFocusT1);
 
+        /* Also make sure that WM_SETFOCUS selects the textbox's text */
+        hTextbox = GetDlgItem(hDlg, 200);
+        SendMessage(hTextbox, WM_SETTEXT, 0, (LPARAM)"Hello world");
+
+        SendMessage(hDlg, WM_SETFOCUS, 0, 0);
+        SendMessage(hTextbox, EM_GETSEL, (WPARAM)&selectionStart, (LPARAM)&selectionEnd);
+        ok(selectionStart == 0 && selectionEnd == 11, "Text selection after WM_SETFOCUS is [%i, %i) expected [0, 11)\n", selectionStart, selectionEnd);
+
+        /* but WM_ACTIVATE does not */
+        SendMessage(hTextbox, EM_SETSEL, 0, 0);
+        SendMessage(hDlg, WM_ACTIVATE, WA_ACTIVE, 0);
+        SendMessage(hTextbox, EM_GETSEL, (WPARAM)&selectionStart, (LPARAM)&selectionEnd);
+        ok(selectionStart == 0 && selectionEnd == 0, "Text selection after WM_ACTIVATE is [%i, %i) expected [0, 0)\n", selectionStart, selectionEnd);
+
         DestroyWindow(hDlg);
     }
 
@@ -929,13 +945,25 @@ static void test_initial_focus(void)
         pTemplate = LockResource(hTemplate);
 
         hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, focusDlgWinProc, 0);
-        g_hwndInitialFocusT1 = GetFocus();
+        ok(hDlg != 0, "Failed to create test dialog.\n");
         hLabel = GetDlgItem(hDlg, 200);
-        ok (hDlg != 0, "Failed to create test dialog.\n");
 
-        ok ((g_hwndInitialFocusT1 == hLabel),
-            "Focus should have been set to the first control, expected (%p) got (%p).\n",
-            hLabel, g_hwndInitialFocusT1);
+        ok(GetFocus() == hLabel, "Focus not set to label, focus=%p dialog=%p label=%p\n", GetFocus(), hDlg, hLabel);
+
+        DestroyWindow(hDlg);
+
+        /* Also check focus after WM_ACTIVATE and WM_SETFOCUS */
+        hDlg = CreateDialogIndirectParamA(g_hinst, pTemplate, NULL, NULL, 0);
+        ok(hDlg != 0, "Failed to create test dialog.\n");
+        hLabel = GetDlgItem(hDlg, 200);
+
+        SetFocus(NULL);
+        SendMessage(hDlg, WM_ACTIVATE, WA_ACTIVE, 0);
+        ok(GetFocus() == NULL, "Focus set on WM_ACTIVATE, focus=%p dialog=%p label=%p\n", GetFocus(), hDlg, hLabel);
+
+        SetFocus(NULL);
+        SendMessage(hDlg, WM_SETFOCUS, 0, 0);
+        ok(GetFocus() == hLabel, "Focus not set to label on WM_SETFOCUS, focus=%p dialog=%p label=%p\n", GetFocus(), hDlg, hLabel);
 
         DestroyWindow(hDlg);
     }
@@ -1404,7 +1432,7 @@ START_TEST(dialog)
     test_GetNextDlgItem();
     test_IsDialogMessage();
     test_WM_NEXTDLGCTL();
-    test_initial_focus();
+    test_focus();
     test_GetDlgItem();
     test_GetDlgItemText();
     test_DialogBoxParamA();
-- 
1.7.9.5



More information about the wine-patches mailing list