Signed-off-by: Nikolay Sivov nsivov@codeweavers.com ---
Fixes https://bugs.winehq.org/show_bug.cgi?id=40002
dlls/comctl32/edit.c | 63 ++++++++++---------- dlls/comctl32/tests/edit.c | 139 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 31 deletions(-)
diff --git a/dlls/comctl32/edit.c b/dlls/comctl32/edit.c index 67d77dafab..10ff5fb0f3 100644 --- a/dlls/comctl32/edit.c +++ b/dlls/comctl32/edit.c @@ -3382,16 +3382,23 @@ static LRESULT EDIT_WM_KeyDown(EDITSTATE *es, INT key) * WM_KILLFOCUS * */ -static LRESULT EDIT_WM_KillFocus(EDITSTATE *es) +static LRESULT EDIT_WM_KillFocus(HTHEME theme, EDITSTATE *es) { - es->flags &= ~EF_FOCUSED; - DestroyCaret(); - if(!(es->style & ES_NOHIDESEL)) - EDIT_InvalidateText(es, es->selection_start, es->selection_end); - EDIT_NOTIFY_PARENT(es, EN_KILLFOCUS); - /* throw away left over scroll when we lose focus */ - es->wheelDeltaRemainder = 0; - return 0; + UINT flags = RDW_INVALIDATE | RDW_UPDATENOW; + + es->flags &= ~EF_FOCUSED; + DestroyCaret(); + if (!(es->style & ES_NOHIDESEL)) + EDIT_InvalidateText(es, es->selection_start, es->selection_end); + EDIT_NOTIFY_PARENT(es, EN_KILLFOCUS); + /* Throw away left over scroll when we lose focus */ + es->wheelDeltaRemainder = 0; + + if (theme) + flags |= RDW_FRAME; + + RedrawWindow(es->hwndSelf, NULL, NULL, flags); + return 0; }
@@ -3656,26 +3663,24 @@ static void EDIT_WM_NCPaint(HWND hwnd, HRGN region) * WM_SETFOCUS * */ -static void EDIT_WM_SetFocus(EDITSTATE *es) +static void EDIT_WM_SetFocus(HTHEME theme, EDITSTATE *es) { - es->flags |= EF_FOCUSED; + UINT flags = RDW_INVALIDATE | RDW_UPDATENOW;
- if (!(es->style & ES_NOHIDESEL)) - EDIT_InvalidateText(es, es->selection_start, es->selection_end); + es->flags |= EF_FOCUSED;
- /* single line edit updates itself */ - if (IsWindowVisible(es->hwndSelf) && !(es->style & ES_MULTILINE)) - { - HDC hdc = GetDC(es->hwndSelf); - EDIT_WM_Paint(es, hdc); - ReleaseDC(es->hwndSelf, hdc); - } + if (!(es->style & ES_NOHIDESEL)) + EDIT_InvalidateText(es, es->selection_start, es->selection_end);
- CreateCaret(es->hwndSelf, 0, 1, es->line_height); - EDIT_SetCaretPos(es, es->selection_end, - es->flags & EF_AFTER_WRAP); - ShowCaret(es->hwndSelf); - EDIT_NOTIFY_PARENT(es, EN_SETFOCUS); + CreateCaret(es->hwndSelf, 0, 1, es->line_height); + EDIT_SetCaretPos(es, es->selection_end, es->flags & EF_AFTER_WRAP); + ShowCaret(es->hwndSelf); + EDIT_NOTIFY_PARENT(es, EN_SETFOCUS); + + if (theme) + flags |= RDW_FRAME | RDW_ERASE; + + RedrawWindow(es->hwndSelf, NULL, NULL, flags); }
@@ -4827,9 +4832,7 @@ static LRESULT CALLBACK EDIT_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPAR break;
case WM_KILLFOCUS: - result = EDIT_WM_KillFocus(es); - if (theme) - RedrawWindow(hwnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW); + result = EDIT_WM_KillFocus(theme, es); break;
case WM_LBUTTONDBLCLK: @@ -4866,9 +4869,7 @@ static LRESULT CALLBACK EDIT_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPAR break;
case WM_SETFOCUS: - EDIT_WM_SetFocus(es); - if (theme) - RedrawWindow(hwnd, NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW); + EDIT_WM_SetFocus(theme, es); break;
case WM_SETFONT: diff --git a/dlls/comctl32/tests/edit.c b/dlls/comctl32/tests/edit.c index 41eb5856e3..7e9e7e7634 100644 --- a/dlls/comctl32/tests/edit.c +++ b/dlls/comctl32/tests/edit.c @@ -23,6 +23,7 @@
#include "wine/test.h" #include "v6util.h" +#include "msg.h"
#ifndef ES_COMBO #define ES_COMBO 0x200 @@ -32,6 +33,20 @@ #define ID_EDITTEST2 99 #define MAXLEN 200
+enum seq_index +{ + COMBINED_SEQ_INDEX = 0, + NUM_MSG_SEQUENCES, +}; + +enum msg_id +{ + PARENT_ID, + EDIT_ID, +}; + +static struct msg_sequence *sequences[NUM_MSG_SEQUENCES]; + struct edit_notify { int en_change, en_maxtext, en_update; }; @@ -865,6 +880,66 @@ static LRESULT CALLBACK edit3_wnd_procA(HWND hWnd, UINT msg, WPARAM wParam, LPAR return DefWindowProcA(hWnd, msg, wParam, lParam); }
+static LRESULT CALLBACK parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + static LONG defwndproc_counter = 0; + struct message msg = { 0 }; + LRESULT ret; + + msg.message = message; + msg.flags = sent|wparam|id; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.id = PARENT_ID; + + if (message != WM_IME_SETCONTEXT && + message != WM_IME_NOTIFY && + message != WM_GETICON && + message != WM_DWMNCRENDERINGCHANGED && + message != WM_GETMINMAXINFO && + message != WM_PAINT && + message != WM_CTLCOLOREDIT && + message < 0xc000) + { + add_message(sequences, COMBINED_SEQ_INDEX, &msg); + } + + defwndproc_counter++; + ret = DefWindowProcA(hwnd, message, wParam, lParam); + defwndproc_counter--; + + return ret; +} + +static LRESULT CALLBACK edit_subclass_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + WNDPROC oldproc = (WNDPROC)GetWindowLongPtrA(hwnd, GWLP_USERDATA); + static LONG defwndproc_counter = 0; + struct message msg = { 0 }; + LRESULT ret; + + msg.message = message; + msg.flags = sent|wparam|id; + if (defwndproc_counter) msg.flags |= defwinproc; + msg.wParam = wParam; + msg.id = EDIT_ID; + + if (message != WM_IME_SETCONTEXT && + message != WM_IME_NOTIFY) + { + add_message(sequences, COMBINED_SEQ_INDEX, &msg); + } + + defwndproc_counter++; + if (IsWindowUnicode(hwnd)) + ret = CallWindowProcW(oldproc, hwnd, message, wParam, lParam); + else + ret = CallWindowProcA(oldproc, hwnd, message, wParam, lParam); + defwndproc_counter--; + + return ret; +} + /* Test behaviour of WM_SETTEXT, WM_REPLACESEL and notifications sent in response * to these messages. */ @@ -2365,6 +2440,7 @@ static BOOL register_classes(void) WNDCLASSA test3; WNDCLASSA test4; WNDCLASSA text_position; + WNDCLASSA wc;
test2.style = 0; test2.lpfnWndProc = ET2_WndProc; @@ -2414,6 +2490,12 @@ static BOOL register_classes(void) text_position.lpfnWndProc = DefWindowProcA; if (!RegisterClassA(&text_position)) return FALSE;
+ memset(&wc, 0, sizeof(wc)); + wc.lpfnWndProc = parent_wnd_proc; + wc.hInstance = GetModuleHandleA(NULL); + wc.lpszClassName = "ParentWnd"; + if (!RegisterClassA(&wc)) return FALSE; + return TRUE; }
@@ -2958,6 +3040,60 @@ static void test_wordbreak_proc(void) DestroyWindow(hwnd); }
+static const struct message setfocus_combined_seq[] = +{ + { WM_KILLFOCUS, sent|id, 0, 0, PARENT_ID }, + { WM_SETFOCUS, sent|id, 0, 0, EDIT_ID }, + { WM_COMMAND, sent|wparam|id, MAKEWPARAM(1, EN_SETFOCUS), 0, PARENT_ID }, + { WM_PAINT, sent|id, 0, 0, EDIT_ID }, + { WM_NCPAINT, sent|id|defwinproc|optional, 0, 0, EDIT_ID }, + { WM_ERASEBKGND, sent|id|defwinproc|optional, 0, 0, EDIT_ID }, + { 0 } +}; + +static const struct message killfocus_combined_seq[] = +{ + { WM_KILLFOCUS, sent|id, 0, 0, EDIT_ID }, + { WM_COMMAND, sent|wparam|id, MAKEWPARAM(1, EN_KILLFOCUS), 0, PARENT_ID }, + { WM_SETFOCUS, sent|id, 0, 0, PARENT_ID }, + { WM_PAINT, sent|id, 0, 0, EDIT_ID }, + { WM_NCPAINT, sent|id|defwinproc|optional, 0, 0, EDIT_ID }, + { 0 } +}; + +static void test_change_focus(void) +{ + HWND hwnd, parent_wnd; + WNDPROC oldproc; + MSG msg; + + parent_wnd = CreateWindowA("ParentWnd", "", WS_OVERLAPPEDWINDOW, + 0, 0, 200, 200, NULL, NULL, GetModuleHandleA(NULL), NULL); + ok(parent_wnd != NULL, "Failed to create control parent.\n"); + SetWindowPos(parent_wnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE); + ShowWindow(parent_wnd, SW_SHOW); + + hwnd = CreateWindowExA(0, WC_EDITA, "Test", WS_CHILD | WS_VISIBLE, 0, 0, 100, 100, + parent_wnd, (HMENU)1, GetModuleHandleA(NULL), NULL); + ok(hwnd != NULL, "Failed to create Edit control.\n"); + + oldproc = (WNDPROC)SetWindowLongPtrA(hwnd, GWLP_WNDPROC, (LONG_PTR)edit_subclass_proc); + SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)oldproc); + + SetFocus(parent_wnd); + flush_sequences(sequences, NUM_MSG_SEQUENCES); + SetFocus(hwnd); + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + ok_sequence(sequences, COMBINED_SEQ_INDEX, setfocus_combined_seq, "Set focus", TRUE); + + flush_sequences(sequences, NUM_MSG_SEQUENCES); + SetFocus(parent_wnd); + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) DispatchMessageA(&msg); + ok_sequence(sequences, COMBINED_SEQ_INDEX, killfocus_combined_seq, "Kill focus", TRUE); + + DestroyWindow(hwnd); +} + START_TEST(edit) { ULONG_PTR ctx_cookie; @@ -2967,6 +3103,8 @@ START_TEST(edit) if (!load_v6_module(&ctx_cookie, &hCtx)) return;
+ init_msg_sequences(sequences, NUM_MSG_SEQUENCES); + hinst = GetModuleHandleA(NULL); b = register_classes(); ok(b, "Failed to register test classes.\n"); @@ -2999,6 +3137,7 @@ START_TEST(edit) test_paste(); test_EM_GETLINE(); test_wordbreak_proc(); + test_change_focus();
UnregisterWindowClasses();