Fixes: https://bugs.winehq.org/show_bug.cgi?id=14336 https://bugs.winehq.org/show_bug.cgi?id=29864 https://bugs.winehq.org/show_bug.cgi?id=38298
Signed-off-by: Roman Pišl rpisl@seznam.cz --- dlls/comctl32/tooltips.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-)
diff --git a/dlls/comctl32/tooltips.c b/dlls/comctl32/tooltips.c index 12f2d4b81c..f84b203f2b 100644 --- a/dlls/comctl32/tooltips.c +++ b/dlls/comctl32/tooltips.c @@ -589,6 +589,7 @@ TOOLTIPS_Show (TOOLTIPS_INFO *infoPtr, BOOL track_activate) int ptfx = 0; DWORD style = GetWindowLongW(infoPtr->hwndSelf, GWL_STYLE); INT nTool, current; + LRESULT res;
if (track_activate) { @@ -627,11 +628,6 @@ TOOLTIPS_Show (TOOLTIPS_INFO *infoPtr, BOOL track_activate)
TRACE("Show tooltip %d\n", nTool);
- hdr.hwndFrom = infoPtr->hwndSelf; - hdr.idFrom = toolPtr->uId; - hdr.code = TTN_SHOW; - SendMessageW (toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&hdr); - TRACE("%s\n", debugstr_w(infoPtr->szTipText));
TOOLTIPS_CalcTipSize (infoPtr, &size); @@ -824,9 +820,30 @@ TOOLTIPS_Show (TOOLTIPS_INFO *infoPtr, BOOL track_activate) * it is no longer needed */ }
- SetWindowPos (infoPtr->hwndSelf, HWND_TOPMOST, rect.left, rect.top, - rect.right - rect.left, rect.bottom - rect.top, - SWP_SHOWWINDOW | SWP_NOACTIVATE); + /* set calculated windows size and position */ + SetWindowPos (infoPtr->hwndSelf, NULL, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, + SWP_NOZORDER | SWP_NOACTIVATE); + + /* call TTN_SHOW, an application may adjust size and/or position */ + hdr.hwndFrom = infoPtr->hwndSelf; + hdr.idFrom = toolPtr->uId; + hdr.code = TTN_SHOW; + res = SendMessageW (toolPtr->hwnd, WM_NOTIFY, toolPtr->uId, (LPARAM)&hdr); + + if (res) + { + /* TRUE returned if position was changed */ + SetWindowPos (infoPtr->hwndSelf, HWND_TOPMOST, -1, -1, -1, -1, + SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW | SWP_NOACTIVATE); + } + else + { + /* FALSE returned, still the size could have been modified and we have + * to preserve it */ + SetWindowPos (infoPtr->hwndSelf, HWND_TOPMOST, rect.left, rect.top, -1, -1, + SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE); + }
/* repaint the tooltip */ InvalidateRect(infoPtr->hwndSelf, NULL, TRUE);
Signed-off-by: Roman Pišl rpisl@seznam.cz --- dlls/comctl32/tests/tooltips.c | 94 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+)
diff --git a/dlls/comctl32/tests/tooltips.c b/dlls/comctl32/tests/tooltips.c index c260e3d220..6f2ff22f09 100644 --- a/dlls/comctl32/tests/tooltips.c +++ b/dlls/comctl32/tests/tooltips.c @@ -262,8 +262,16 @@ static void test_customdraw(void) { SetCursorPos(orig_pos.x, orig_pos.y); }
+#define TTIP_LEFT 300 +#define TTIP_TOP 300 +#define TTIP_WIDTH 200 +#define TTIP_HEIGHT 50 + static const CHAR testcallbackA[] = "callback";
+static HWND g_hwnd_ttn_show; +static enum { none = 0, size, both } g_resize = none; + static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { if (message == WM_NOTIFY && lParam) @@ -272,6 +280,12 @@ static LRESULT WINAPI parent_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LP
if (ttnmdi->hdr.code == TTN_GETDISPINFOA) lstrcpyA(ttnmdi->lpszText, testcallbackA); + + if (g_resize != none && ttnmdi->hdr.code == TTN_SHOW) { + g_hwnd_ttn_show = ttnmdi->hdr.hwndFrom; + SetWindowPos(ttnmdi->hdr.hwndFrom, 0, TTIP_LEFT, TTIP_TOP, TTIP_WIDTH, TTIP_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE); + return g_resize == both; + } }
return DefWindowProcA(hwnd, message, wParam, lParam); @@ -1134,6 +1148,84 @@ static void test_TTM_ADDTOOL(BOOL is_v6) DestroyWindow(hwnd); }
+static void test_TTN_SHOW(void) +{ + HWND hwndTip, notify; + TTTOOLINFOA toolinfoA; + RECT rect; + LRESULT r; + DWORD major, minor, version; + + version = GetVersion(); + major = LOBYTE(version); + minor = HIBYTE(LOWORD(version)); + if (major < 6 || minor < 1) + { + skip("Test available on Windows 7 and later\n"); + return; + } + + /* Create main window */ + notify = create_parent_window(); + ok(notify != NULL, "Expected notification window to be created\n"); + + /* Put cursor outside the window */ + GetWindowRect(notify, &rect); + SetCursorPos(rect.right + 200, 0); + + /* Create tooltip */ + hwndTip = CreateWindowExA(0, TOOLTIPS_CLASSA, NULL, 0, + 10, 10, 400, 400, + NULL, NULL, NULL, 0); + ok(hwndTip != NULL, "failed to create tooltip wnd\n"); + + toolinfoA.cbSize = sizeof(TTTOOLINFOA); + toolinfoA.hwnd = notify; + toolinfoA.hinst = GetModuleHandleA(NULL); + toolinfoA.uFlags = TTF_SUBCLASS; + toolinfoA.uId = 0x1234ABCD; + toolinfoA.lpszText = (LPSTR)"This is a test tooltip"; + toolinfoA.lParam = 0xdeadbeef; + GetClientRect(notify, &toolinfoA.rect); + r = SendMessageA(hwndTip, TTM_ADDTOOLA, 0, (LPARAM)&toolinfoA); + ok(r, "got %ld\n", r); + + /* Make tooltip appear quickly */ + SendMessageA(hwndTip, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1,0)); + + /* Put cursor inside window, tooltip will appear immediately */ + g_resize = size; + GetWindowRect(notify, &rect); + SetCursorPos((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2); + flush_events(200); + + /* Test actual tooltip window size */ + GetWindowRect(g_hwnd_ttn_show, &rect); + ok(rect.right - rect.left == TTIP_WIDTH && rect.bottom - rect.top == TTIP_HEIGHT, + "Invalid tooltip size %i %i \n", rect.right - rect.left, rect.bottom - rect.top); + ok(rect.left != TTIP_LEFT && rect.top != TTIP_TOP, "Tooltip position should not be modified"); + + /* Put cursor outside the window */ + GetWindowRect(notify, &rect); + SetCursorPos(rect.right + 200, 0); + flush_events(200); + + /* Put cursor inside window, tooltip will appear immediately */ + g_resize = both; + GetWindowRect(notify, &rect); + SetCursorPos((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2); + flush_events(200); + + /* Test actual tooltip window size and position */ + GetWindowRect(g_hwnd_ttn_show, &rect); + ok(rect.left == TTIP_LEFT && rect.top == TTIP_TOP && + rect.right == TTIP_LEFT + TTIP_WIDTH && rect.bottom == TTIP_TOP + TTIP_HEIGHT, + "Invalid tooltip rect %i %i %i %i\n", rect.left, rect.top, rect.right, rect.bottom); + + DestroyWindow(hwndTip); + DestroyWindow(notify); +} + START_TEST(tooltips) { ULONG_PTR ctx_cookie; @@ -1153,6 +1245,7 @@ START_TEST(tooltips) test_setinfo(FALSE); test_margin(); test_TTM_ADDTOOL(FALSE); + test_TTN_SHOW();
if (!load_v6_module(&ctx_cookie, &hCtx)) return; @@ -1164,6 +1257,7 @@ START_TEST(tooltips) test_setinfo(TRUE); test_margin(); test_TTM_ADDTOOL(TRUE); + test_TTN_SHOW();
unload_v6_module(ctx_cookie, hCtx); }
Hi,
While running your changed tests on Windows, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check? Full results can be found at https://testbot.winehq.org/JobDetails.pl?Key=36181
Your paranoid android.
=== w7u (32 bit tooltips) === tooltips.c:1221: Test failed: Invalid tooltip rect 66 68 266 118
Yes, this makes sense. I'll test it a little bit more, in particular if resizing in TTN_SHOW handler clips balloon or adjusts its proportions instead.
OK. I was unfortunately unable to make this test work on Win XP, although behavior is the same, GetWindowRect() on g_hwnd_ttip returns incorrect dimensions and GetWindowRect() on hwndTip returns what is passed to CreateWindowExA(). The one randomly failed test is related probably to flush_events(), I am not sure if it does what is expected.
Dne 26.2.2018 v 13:48 Nikolay Sivov napsal(a):
Yes, this makes sense. I'll test it a little bit more, in particular if resizing in TTN_SHOW handler clips balloon or adjusts its proportions instead.
On 2/26/2018 4:01 PM, Roman Pišl wrote:
OK. I was unfortunately unable to make this test work on Win XP, although behavior is the same, GetWindowRect() on g_hwnd_ttip returns incorrect dimensions and GetWindowRect() on hwndTip returns what is passed to CreateWindowExA(). The one randomly failed test is related probably to flush_events(), I am not sure if it does what is expected.
Yes, I fixed that by matching window style and the way parent is displayed to existing tests, and it worked on XP too.
Anyway, I manually tested how initial size is set, and it's definitely computed before TTN_SHOW, and not touched after. So for example if you resize to reduce width of balloon tooltip in TTN_SHOW handler, you get clipped balloon. I sent a patch for that, https://www.winehq.org/pipermail/wine-devel/2018-February/123359.html.
Handling return value is a separate thing, and I'll send something for it later.