Signed-off-by: Sergio Gómez Del Real sdelreal@codeweavers.com --- dlls/comctl32/edit.c | 61 +++++++++++++++++++++++++++++ dlls/comctl32/tests/edit.c | 78 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+)
diff --git a/dlls/comctl32/edit.c b/dlls/comctl32/edit.c index f0180adfbe..e02ba1f8a1 100644 --- a/dlls/comctl32/edit.c +++ b/dlls/comctl32/edit.c @@ -131,6 +131,7 @@ typedef struct should be sent to the first parent. */ HWND hwndListBox; /* handle of ComboBox's listbox or NULL */ INT wheelDeltaRemainder; /* scroll wheel delta left over after scrolling whole lines */ + WCHAR *cue_banner_text; /* * only for multi line controls */ @@ -2181,6 +2182,12 @@ static void EDIT_PaintLine(EDITSTATE *es, HDC dc, INT line, BOOL rev) x += EDIT_PaintText(es, dc, x, y, line, e - li, li + ll - e, FALSE); } else x += EDIT_PaintText(es, dc, x, y, line, 0, ll, FALSE); + + if (es->cue_banner_text && es->text_length == 0 && !(es->flags & EF_FOCUSED)) + { + SetTextColor(dc, GetSysColor(COLOR_GRAYTEXT)); + TextOutW(dc, x, y, es->cue_banner_text, strlenW(es->cue_banner_text)); + } }
@@ -4152,6 +4159,51 @@ static LRESULT EDIT_EM_GetThumb(EDITSTATE *es) EDIT_WM_HScroll(es, EM_GETTHUMB, 0)); }
+static inline WCHAR *heap_strdupW(const WCHAR *str) +{ + int len = strlenW(str) + 1; + WCHAR *ret = heap_alloc(len * sizeof(WCHAR)); + strcpyW(ret, str); + return ret; +} + +/********************************************************************* + * + * EM_SETCUEBANNER + * + */ +static BOOL EDIT_EM_SetCueBanner(EDITSTATE *es, const WCHAR *cue_text) +{ + if (es->style & ES_MULTILINE || !cue_text) + return FALSE; + + heap_free(es->cue_banner_text); + es->cue_banner_text = heap_strdupW(cue_text); + + return TRUE; +} + +/********************************************************************* + * + * EM_GETCUEBANNER + * + */ +static BOOL EDIT_EM_GetCueBanner(EDITSTATE *es, WCHAR *buf, DWORD size) +{ + if (!es->cue_banner_text) + { + if (!(es->style & ES_MULTILINE) && buf && size) + *buf = 0; + return FALSE; + } + else + { + if (buf && size) + lstrcpynW(buf, es->cue_banner_text, size); + return TRUE; + } +} +
/******************************************************************** * @@ -4489,6 +4541,7 @@ static LRESULT EDIT_WM_NCDestroy(EDITSTATE *es)
SetWindowLongPtrW( es->hwndSelf, 0, 0 ); heap_free(es->undo_text); + heap_free(es->cue_banner_text); heap_free(es);
return 0; @@ -4703,6 +4756,14 @@ static LRESULT CALLBACK EDIT_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPAR result = EDIT_EM_CharFromPos(es, (short)LOWORD(lParam), (short)HIWORD(lParam)); break;
+ case EM_SETCUEBANNER: + result = EDIT_EM_SetCueBanner(es, (const WCHAR *)lParam); + break; + + case EM_GETCUEBANNER: + result = EDIT_EM_GetCueBanner(es, (WCHAR *)wParam, (DWORD)lParam); + break; + /* End of the EM_ messages which were in numerical order; what order * are these in? vaguely alphabetical? */ diff --git a/dlls/comctl32/tests/edit.c b/dlls/comctl32/tests/edit.c index a5097d1cbb..bc44d0c240 100644 --- a/dlls/comctl32/tests/edit.c +++ b/dlls/comctl32/tests/edit.c @@ -3061,6 +3061,83 @@ static const struct message killfocus_combined_seq[] = { 0 } };
+static void test_cue_banner(void) +{ + HWND hwnd_edit; + BOOL ret; + static WCHAR getcuetestW[5] = {'T',0}; + static const WCHAR testcmp1W[] = {'T','e','s','t',0}; + static const WCHAR testcmp2W[] = {'T','e','s',0}; + static const WCHAR emptyW[] = {0}; + + hwnd_edit = create_editcontrolW(ES_AUTOHSCROLL | ES_AUTOVSCROLL, 0); + + ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 5); + if (lstrcmpW(getcuetestW, emptyW) != 0) + { + win_skip("skipping for Win XP and 2003 Server.\n"); + DestroyWindow(hwnd_edit); + return; + } + ok(lstrcmpW(getcuetestW, emptyW) == 0, "First char is %c\n", getcuetestW[0]); + ok(ret == FALSE, "EM_GETCUEBANNER should have returned FALSE.\n"); + + lstrcpyW(getcuetestW, testcmp1W); + ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 0); + ok(lstrcmpW(getcuetestW, testcmp1W) == 0, "String was %s.\n", wine_dbgstr_w(getcuetestW)); + ok(ret == FALSE, "EM_GETCUEBANNER should have returned FALSE.\n"); + + ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, 0, 0); + ok(ret == FALSE, "EM_GETCUEBANNER should have returned FALSE.\n"); + + ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, 0); + ok(ret == FALSE, "EM_SETCUEBANNER should have returned FALSE.\n"); + + ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, 0, 0); + ok(ret == FALSE, "EM_GETCUEBANNER should have returned FALSE.\n"); + + lstrcpyW(getcuetestW, testcmp1W); + ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, (LPARAM)getcuetestW); + ok(ret == TRUE, "EM_SETCUEBANNER should have returned TRUE.\n"); + + ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, 0, 5); + ok(ret == TRUE, "EM_GETCUEBANNER should have returned TRUE.\n"); + + ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 5); + ok(ret == TRUE, "EM_GETCUEBANNER should have returned TRUE.\n"); + ok(lstrcmpW(getcuetestW, testcmp1W) == 0, "EM_GETCUEBANNER returned string %s.\n", wine_dbgstr_w(getcuetestW)); + + ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, (LPARAM)emptyW); + ok(ret == TRUE, "EM_SETCUEBANNER should have returned TRUE.\n"); + + ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 5); + ok(ret == TRUE, "EM_GETCUEBANNER should have returned TRUE.\n"); + ok(lstrcmpW(getcuetestW, emptyW) == 0, "EM_GETCUEBANNER returned string %s.\n", wine_dbgstr_w(getcuetestW)); + + /* EM_GETCUEBANNER's buffer size includes null char */ + ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, (LPARAM)testcmp1W); + ok(ret == TRUE, "EM_SETCUEBANNER should have returned TRUE.\n"); + memset(getcuetestW, 0, lstrlenW(testcmp1W)*sizeof(WCHAR)); + ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, (LPARAM)lstrlenW(testcmp1W)+1); + ok(ret == TRUE, "EM_GETCUEBANNER should have returned TRUE.\n"); + ok(lstrcmpW(getcuetestW, testcmp1W) == 0, "EM_GETCUEBANNER returned string %s.\n", wine_dbgstr_w(getcuetestW)); + memset(getcuetestW, 0, lstrlenW(testcmp1W)*sizeof(WCHAR)); + ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, (LPARAM)lstrlenW(testcmp1W)); + ok(lstrcmpW(getcuetestW, testcmp2W) == 0, "EM_GETCUEBANNER returned string %s.\n", wine_dbgstr_w(getcuetestW)); + DestroyWindow(hwnd_edit); + + /* setting cue banner fails for multi-line edit controls */ + hwnd_edit = create_editcontrolW(ES_AUTOHSCROLL | ES_AUTOVSCROLL | ES_MULTILINE, 0); + lstrcpyW(getcuetestW, testcmp1W); + ret = SendMessageW(hwnd_edit, EM_GETCUEBANNER, (WPARAM)getcuetestW, 5); + ok(ret == FALSE, "EM_SETCUEBANNER.\n"); + ok(lstrcmpW(getcuetestW, testcmp1W) == 0, "String was %s.\n", wine_dbgstr_w(getcuetestW)); + ret = SendMessageW(hwnd_edit, EM_SETCUEBANNER, 0, (LPARAM)getcuetestW); + ok(ret == FALSE, "EM_SETCUEBANNER.\n"); + + DestroyWindow(hwnd_edit); +} + static void test_change_focus(void) { HWND hwnd, parent_wnd; @@ -3138,6 +3215,7 @@ START_TEST(edit) test_EM_GETLINE(); test_wordbreak_proc(); test_change_focus(); + test_cue_banner();
UnregisterWindowClasses();
On 10/24/2018 10:46 PM, Sergio Gómez Del Real wrote:
+static BOOL EDIT_EM_GetCueBanner(EDITSTATE *es, WCHAR *buf, DWORD size) +{
- if (!es->cue_banner_text)
- {
if (!(es->style & ES_MULTILINE) && buf && size)
*buf = 0;
return FALSE;
- }
I think it's better to move multiline test outside, before testing anything else.
- else
- {
if (buf && size)
lstrcpynW(buf, es->cue_banner_text, size);
return TRUE;
- }
+}
You can remove zero size check.
- case EM_SETCUEBANNER:
result = EDIT_EM_SetCueBanner(es, (const WCHAR *)lParam);
break;
How did you test wParam flag? It seems to work for me as docs describe.
On 27/10/18 4:55 a. m., Nikolay Sivov wrote:
On 10/24/2018 10:46 PM, Sergio Gómez Del Real wrote:
+static BOOL EDIT_EM_GetCueBanner(EDITSTATE *es, WCHAR *buf, DWORD size) +{ + if (!es->cue_banner_text) + { + if (!(es->style & ES_MULTILINE) && buf && size) + *buf = 0; + return FALSE; + }
I think it's better to move multiline test outside, before testing anything else.
Ok.
+ else + { + if (buf && size) + lstrcpynW(buf, es->cue_banner_text, size); + return TRUE; + } +}
You can remove zero size check.
Ok. Sorry about this; I should've just read these functions to see what they do exactly instead of just assuming things.
+ case EM_SETCUEBANNER: + result = EDIT_EM_SetCueBanner(es, (const WCHAR *)lParam); + break;
How did you test wParam flag? It seems to work for me as docs describe.
I tested writing a sample program on Windows 7, 32-bits. On that same OS, I got the same results using ControlSpy (for WPARAM it said it was unused). Then I googled a bit and read at a couple of places that indeed 'Windows' ignores that flag; it always behaves as if WPARAM is 0. That is not enough to conclude that all versions of Windows behave the same, of course. What version did you try, and what should we do with this OS dependence?
On 10/27/2018 11:10 PM, Sergio Gómez Del Real wrote:
+ case EM_SETCUEBANNER: + result = EDIT_EM_SetCueBanner(es, (const WCHAR *)lParam); + break;
How did you test wParam flag? It seems to work for me as docs describe.
I tested writing a sample program on Windows 7, 32-bits. On that same OS, I got the same results using ControlSpy (for WPARAM it said it was unused). Then I googled a bit and read at a couple of places that indeed 'Windows' ignores that flag; it always behaves as if WPARAM is 0. That is not enough to conclude that all versions of Windows behave the same, of course. What version did you try, and what should we do with this OS dependence?
I tested on Windows 10. You're right, I don't see it in 2k3 SDK, in SDK 10.x they have new macro for this, everything still guarded with XP version. For our implementation it's enough to have a fixme for now, if it's not working with Win7. If you can't test on Win10 right away, feel free to send me your test program.
On 28/10/18 6:47 a. m., Nikolay Sivov wrote:
On 10/27/2018 11:10 PM, Sergio Gómez Del Real wrote:
+ case EM_SETCUEBANNER: + result = EDIT_EM_SetCueBanner(es, (const WCHAR *)lParam); + break;
How did you test wParam flag? It seems to work for me as docs describe.
I tested writing a sample program on Windows 7, 32-bits. On that same OS, I got the same results using ControlSpy (for WPARAM it said it was unused). Then I googled a bit and read at a couple of places that indeed 'Windows' ignores that flag; it always behaves as if WPARAM is 0. That is not enough to conclude that all versions of Windows behave the same, of course. What version did you try, and what should we do with this OS dependence?
I tested on Windows 10. You're right, I don't see it in 2k3 SDK, in SDK 10.x they have new macro for this, everything still guarded with XP version. For our implementation it's enough to have a fixme for now, if it's not working with Win7. If you can't test on Win10 right away, feel free to send me your test program.
I've just tested on Windows 10, and re-tested on Windows 7, and it is working as you said on both platforms. That is, if wParam is TRUE, the text is shown even when the control is focused (but not when you write something in it, of course). The macro Edit_SetCueBannerText() doesn't include this option, though, but since it is still an option to send the message explicitly, instead of using the marco, I think I'll add the FIXME and come back to it later (since now it is possible to overwrite that behavior, so that must be added to tests, and I'm a little caught with other things).