Improve default focus assignment in dialogs (resend)
Zach Gorman
zach at archetypeauction.com
Thu Sep 9 15:43:29 CDT 2004
These tests demonstrate the correctness of 2 previously-sent patches:
1) dialog: Move default focus assignment into SetFocus() handler
2) modal dialog: Wait until message queue runs dry before calling ShowWindow()
The incorrect behavior is flagged as "todo_wine" making this patch
independent of the 2 patches above.
Index: dialog.c
===================================================================
RCS file: /home/wine/wine/dlls/user/tests/dialog.c,v
retrieving revision 1.6
diff -u -r1.6 dialog.c
--- dialog.c 2 Sep 2004 20:09:37 -0000 1.6
+++ dialog.c 9 Sep 2004 20:38:48 -0000
@@ -46,6 +46,10 @@
static HINSTANCE g_hinst; /* This application's HINSTANCE */
static HWND g_hwndMain, g_hwndButton1, g_hwndButton2, g_hwndButtonCancel;
static HWND g_hwndTestDlg, g_hwndTestDlgBut1, g_hwndTestDlgBut2, g_hwndTestDlgEdit;
+static HWND g_hwndInitialFocusT1, g_hwndInitialFocusT2, g_hwndInitialFocusGroupBox;
+
+static LONG g_styleInitialFocusT1, g_styleInitialFocusT2;
+static BOOL g_bInitialFocusInitDlgResult;
static int g_terminated;
@@ -456,7 +460,6 @@
return TRUE;
}
-
static LRESULT CALLBACK main_window_procA (HWND hwnd, UINT uiMsg, WPARAM wParam,
LPARAM lParam)
{
@@ -640,6 +643,7 @@
dwVal = DefDlgProcA(g_hwndTestDlg, DM_GETDEFID, 0, 0);
ok ( IDCANCEL == (LOWORD(dwVal)), "WM_NEXTDLGCTL changed default button\n");
}
+ DestroyWindow(g_hwndTestDlg);
}
static void IsDialogMessageWTest (void)
@@ -671,6 +675,134 @@
ok (g_terminated, "ENTER did not terminate\n");
}
+
+static LRESULT CALLBACK delayFocusDlgWinProc (HWND hDlg, UINT uiMsg, WPARAM wParam,
+ LPARAM lParam)
+{
+ switch (uiMsg)
+ {
+ case WM_INITDIALOG:
+ g_hwndMain = hDlg;
+ g_hwndInitialFocusGroupBox = GetDlgItem(hDlg,100);
+ g_hwndButton1 = GetDlgItem(hDlg,200);
+ g_hwndButton2 = GetDlgItem(hDlg,201);
+ g_hwndButtonCancel = GetDlgItem(hDlg,IDCANCEL);
+ g_styleInitialFocusT1 = GetWindowLong(g_hwndInitialFocusGroupBox, GWL_STYLE);
+
+ /* Initially check the second radio button */
+ SendMessage(g_hwndButton1, BM_SETCHECK, BST_UNCHECKED, 0);
+ SendMessage(g_hwndButton2, BM_SETCHECK, BST_CHECKED , 0);
+ /* Continue testing after dialog initialization */
+ PostMessage(hDlg, WM_USER, 0, 0);
+ return g_bInitialFocusInitDlgResult;
+
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDCANCEL)
+ {
+ EndDialog(hDlg, LOWORD(wParam));
+ return TRUE;
+ }
+ return FALSE;
+
+ case WM_USER:
+ g_styleInitialFocusT2 = GetWindowLong(hDlg, GWL_STYLE);
+ g_hwndInitialFocusT1 = GetFocus();
+ SetFocus(hDlg);
+ g_hwndInitialFocusT2 = GetFocus();
+ PostMessage(hDlg, WM_COMMAND, IDCANCEL, 0);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/* Helper for InitialFocusTest */
+static const char * GetHwndString(HWND hw)
+{
+ if (hw == NULL)
+ return "a null handle";
+ if (hw == g_hwndMain)
+ return "the dialog handle";
+ if (hw == g_hwndInitialFocusGroupBox)
+ return "the group box control";
+ if (hw == g_hwndButton1)
+ return "the first button";
+ if (hw == g_hwndButton2)
+ return "the second button";
+ if (hw == g_hwndButtonCancel)
+ return "the cancel button";
+
+ return "unknown handle";
+}
+
+static void InitialFocusTest (void)
+{
+ /* Test 1:
+ * This test intentionally returns FALSE in response to WM_INITDIALOG
+ * without setting focus to a control. This is not allowed according to
+ * MSDN, but it is exactly what MFC's CFormView does.
+ *
+ * Since the WM_INITDIALOG handler returns FALSE without setting the focus,
+ * the focus should initially be NULL. Later, when we manually set focus to
+ * the dialog, the default handler should set focus to the first control that
+ * is "visible, not disabled, and has the WS_TABSTOP style" (MSDN). Because the
+ * second radio button has been checked, it should be the first control
+ * that meets these criteria and should receive the focus.
+ */
+
+ g_bInitialFocusInitDlgResult = FALSE;
+ g_hwndInitialFocusT1 = (HWND) -1;
+ g_hwndInitialFocusT2 = (HWND) -1;
+ g_styleInitialFocusT1 = -1;
+ g_styleInitialFocusT2 = -1;
+
+ DialogBoxA(g_hinst, "RADIO_TEST_DIALOG", NULL, (DLGPROC)delayFocusDlgWinProc);
+
+ ok (((g_styleInitialFocusT1 & WS_TABSTOP) == 0),
+ "Error in wrc - Detected WS_TABSTOP as default style for GROUPBOX\n");
+
+ todo_wine ok (((g_styleInitialFocusT2 & WS_VISIBLE) == 0),
+ "Modal dialogs should not be shown until the message queue first goes empty\n");
+
+ todo_wine ok ((g_hwndInitialFocusT1 == NULL),
+ "Error in initial focus when WM_INITDIALOG returned FALSE: "
+ "Expected NULL focus, got %s (%p).\n",
+ GetHwndString(g_hwndInitialFocusT1), g_hwndInitialFocusT1);
+
+ todo_wine ok ((g_hwndInitialFocusT2 == g_hwndButton2),
+ "Error after first SetFocus() when WM_INITDIALOG returned FALSE: "
+ "Expected the second button (%p), got %s (%p).\n",
+ g_hwndButton2, GetHwndString(g_hwndInitialFocusT2),
+ g_hwndInitialFocusT2);
+
+ /* Test 2:
+ * This is the same as above, except WM_INITDIALOG is made to return TRUE.
+ * This should cause the focus to go to the second radio button right away
+ * and stay there (until the user indicates otherwise).
+ */
+
+ g_bInitialFocusInitDlgResult = TRUE;
+ g_hwndInitialFocusT1 = (HWND) -1;
+ g_hwndInitialFocusT2 = (HWND) -1;
+ g_styleInitialFocusT1 = -1;
+ g_styleInitialFocusT2 = -1;
+
+ DialogBoxA(g_hinst, "RADIO_TEST_DIALOG", NULL, (DLGPROC)delayFocusDlgWinProc);
+
+ ok ((g_hwndInitialFocusT1 == g_hwndButton2),
+ "Error in initial focus when WM_INITDIALOG returned TRUE: "
+ "Expected the second button (%p), got %s (%p).\n",
+ g_hwndButton2, GetHwndString(g_hwndInitialFocusT2),
+ g_hwndInitialFocusT2);
+
+ ok ((g_hwndInitialFocusT2 == g_hwndButton2),
+ "Error after first SetFocus() when WM_INITDIALOG returned TRUE: "
+ "Expected the second button (%p), got %s (%p).\n",
+ g_hwndButton2, GetHwndString(g_hwndInitialFocusT2),
+ g_hwndInitialFocusT2);
+}
+
+
START_TEST(dialog)
{
g_hinst = GetModuleHandleA (0);
@@ -680,4 +812,5 @@
GetNextDlgItemTest();
IsDialogMessageWTest();
WM_NEXTDLGCTLTest();
+ InitialFocusTest();
}
Index: resource.rc
===================================================================
RCS file: /home/wine/wine/dlls/user/tests/resource.rc,v
retrieving revision 1.4
diff -u -r1.4 resource.rc
--- resource.rc 24 Aug 2004 18:33:03 -0000 1.4
+++ resource.rc 9 Sep 2004 20:38:48 -0000
@@ -32,6 +32,20 @@
DEFPUSHBUTTON "OK", IDOK,4,4,50,14, WS_TABSTOP | WS_GROUP
END
+RADIO_TEST_DIALOG DIALOGEX 0, 0, 160, 80
+STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
+CAPTION "Radio Button Test Dialog"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Static", 100,6,5,92,70
+ CONTROL "Radio1", 200,"Button",BS_AUTORADIOBUTTON |
+ WS_GROUP | WS_TABSTOP,17,27,39,10
+ CONTROL "Radio2", 201,"Button",BS_AUTORADIOBUTTON,17,40,39,10
+ PUSHBUTTON "Cancel", IDCANCEL,109,20,50,14, WS_TABSTOP | WS_GROUP
+END
+
+
+
CLASS_TEST_DIALOG DIALOG DISCARDABLE 0, 0, 91, 28
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "CreateDialogParams Test"
More information about the wine-patches
mailing list