[PATCH 2/3] comctl32/pager: Support tooltip notification conversion.
Zhiyi Zhang
zzhang at codeweavers.com
Mon Aug 27 22:28:16 CDT 2018
Signed-off-by: Zhiyi Zhang <zzhang at codeweavers.com>
---
dlls/comctl32/pager.c | 72 +++++++++++++++++++
dlls/comctl32/tests/pager.c | 137 ++++++++++++++++++++++++++++++++++++
2 files changed, 209 insertions(+)
diff --git a/dlls/comctl32/pager.c b/dlls/comctl32/pager.c
index 0367108db2..9ab492e333 100644
--- a/dlls/comctl32/pager.c
+++ b/dlls/comctl32/pager.c
@@ -84,6 +84,8 @@ typedef struct
INT TLbtnState; /* state of top or left btn */
INT BRbtnState; /* state of bottom or right btn */
INT direction; /* direction of the scroll, (e.g. PGF_SCROLLUP) */
+ WCHAR *pwszBuffer;/* text buffer for converted notifications */
+ INT nBufferSize;/* size of the above buffer */
} PAGER_INFO;
#define TIMERID1 1
@@ -605,6 +607,7 @@ static LRESULT
PAGER_Destroy (PAGER_INFO *infoPtr)
{
SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
+ heap_free (infoPtr->pwszBuffer);
heap_free (infoPtr);
return 0;
}
@@ -1038,10 +1041,25 @@ static UINT PAGER_GetAnsiNtfCode(UINT code)
/* Toolbar */
case TBN_GETBUTTONINFOW: return TBN_GETBUTTONINFOA;
case TBN_GETINFOTIPW: return TBN_GETINFOTIPA;
+ /* Tooltip */
+ case TTN_GETDISPINFOW: return TTN_GETDISPINFOA;
}
return code;
}
+static BOOL PAGER_AdjustBuffer(PAGER_INFO *infoPtr, INT size)
+{
+ if (!infoPtr->pwszBuffer)
+ infoPtr->pwszBuffer = heap_alloc(size);
+ else if (infoPtr->nBufferSize < size)
+ infoPtr->pwszBuffer = heap_realloc(infoPtr->pwszBuffer, size);
+
+ if (!infoPtr->pwszBuffer) return FALSE;
+ if (infoPtr->nBufferSize < size) infoPtr->nBufferSize = size;
+
+ return TRUE;
+}
+
static LRESULT PAGER_SendConvertedNotify(PAGER_INFO *infoPtr, NMHDR *hdr, WCHAR **text, INT *textMax, ConversionFlag flags)
{
WCHAR emptyW[] = {0};
@@ -1093,6 +1111,8 @@ done:
static LRESULT PAGER_Notify(PAGER_INFO *infoPtr, NMHDR *hdr)
{
+ LRESULT ret;
+
if (infoPtr->bUnicode) return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
switch (hdr->code)
@@ -1109,6 +1129,58 @@ static LRESULT PAGER_Notify(PAGER_INFO *infoPtr, NMHDR *hdr)
NMTBGETINFOTIPW *nmtbgit = (NMTBGETINFOTIPW *)hdr;
return PAGER_SendConvertedNotify(infoPtr, hdr, &nmtbgit->pszText, &nmtbgit->cchTextMax, FROM_ANSI);
}
+ /* Tooltip */
+ case TTN_GETDISPINFOW:
+ {
+ NMTTDISPINFOW *nmttdiW = (NMTTDISPINFOW *)hdr;
+ NMTTDISPINFOA nmttdiA = {0};
+ INT size;
+
+ nmttdiA.hdr.code = PAGER_GetAnsiNtfCode(nmttdiW->hdr.code);
+ nmttdiA.hdr.hwndFrom = nmttdiW->hdr.hwndFrom;
+ nmttdiA.hdr.idFrom = nmttdiW->hdr.idFrom;
+ nmttdiA.hinst = nmttdiW->hinst;
+ nmttdiA.uFlags = nmttdiW->uFlags;
+ nmttdiA.lParam = nmttdiW->lParam;
+ nmttdiA.lpszText = nmttdiA.szText;
+ WideCharToMultiByte(CP_ACP, 0, nmttdiW->szText, ARRAY_SIZE(nmttdiW->szText), nmttdiA.szText,
+ ARRAY_SIZE(nmttdiA.szText), NULL, FALSE);
+
+ ret = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)&nmttdiA);
+
+ nmttdiW->hinst = nmttdiA.hinst;
+ nmttdiW->uFlags = nmttdiA.uFlags;
+ nmttdiW->lParam = nmttdiA.lParam;
+
+ MultiByteToWideChar(CP_ACP, 0, nmttdiA.szText, ARRAY_SIZE(nmttdiA.szText), nmttdiW->szText,
+ ARRAY_SIZE(nmttdiW->szText));
+ if (!nmttdiA.lpszText)
+ nmttdiW->lpszText = nmttdiW->szText;
+ else if (!IS_INTRESOURCE(nmttdiA.lpszText))
+ {
+ size = MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, 0, 0);
+ if (size > ARRAY_SIZE(nmttdiW->szText))
+ {
+ if (!PAGER_AdjustBuffer(infoPtr, size * sizeof(WCHAR))) return ret;
+ MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, infoPtr->pwszBuffer, size);
+ nmttdiW->lpszText = infoPtr->pwszBuffer;
+ /* Override content in szText */
+ memcpy(nmttdiW->szText, nmttdiW->lpszText, min(sizeof(nmttdiW->szText), size * sizeof(WCHAR)));
+ }
+ else
+ {
+ MultiByteToWideChar(CP_ACP, 0, nmttdiA.lpszText, -1, nmttdiW->szText, ARRAY_SIZE(nmttdiW->szText));
+ nmttdiW->lpszText = nmttdiW->szText;
+ }
+ }
+ else
+ {
+ nmttdiW->szText[0] = 0;
+ nmttdiW->lpszText = (WCHAR *)nmttdiA.lpszText;
+ }
+
+ return ret;
+ }
}
/* Other notifications or notifications above that don't have text, thus no need to convert */
return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, hdr->idFrom, (LPARAM)hdr);
diff --git a/dlls/comctl32/tests/pager.c b/dlls/comctl32/tests/pager.c
index 46f2eb0acb..bf79f34c5b 100644
--- a/dlls/comctl32/tests/pager.c
+++ b/dlls/comctl32/tests/pager.c
@@ -630,6 +630,53 @@ static LRESULT WINAPI test_notify_proc(HWND hwnd, UINT message, WPARAM wParam, L
wm_notify_text_handler(&nmtbgit->pszText, &nmtbgit->cchTextMax);
break;
}
+ /* Tooltip */
+ case TTN_GETDISPINFOA:
+ {
+ NMTTDISPINFOA *nmttdi = (NMTTDISPINFOA *)hdr;
+ switch (notify_test_data.sub_test_id)
+ {
+ case 0:
+ break;
+ case 1:
+ memcpy(nmttdi->szText, test_a, sizeof(test_a));
+ break;
+ case 2:
+ memcpy(nmttdi->szText, test_a, sizeof(test_a));
+ nmttdi->lpszText = test_a;
+ break;
+ case 3:
+ memcpy(nmttdi->szText, test_a, sizeof(test_a));
+ nmttdi->lpszText = (CHAR *)1;
+ nmttdi->hinst = GetModuleHandleA(0);
+ break;
+ case 4:
+ memcpy(nmttdi->szText, test_a, sizeof(test_a));
+ nmttdi->lpszText = test_a;
+ nmttdi->hinst = GetModuleHandleA(0);
+ break;
+ case 5:
+ nmttdi->lpszText = test_a;
+ break;
+ case 6:
+ memcpy(nmttdi->szText, test_a, 2);
+ nmttdi->szText[2] = 0;
+ nmttdi->lpszText = test_a;
+ break;
+ case 7:
+ expect_eq_text_a(nmttdi->szText, test_a);
+ expect_eq_pointer(nmttdi->lpszText, nmttdi->szText);
+ break;
+ case 8:
+ expect_text_empty(nmttdi->szText);
+ expect_eq_pointer(nmttdi->lpszText, nmttdi->szText);
+ break;
+ case 9:
+ nmttdi->lpszText = large_a;
+ break;
+ }
+ break;
+ }
default:
ok(0, "Unexpected message 0x%08x\n", hdr->code);
}
@@ -828,6 +875,95 @@ static void test_wm_notify_toolbar(HWND pager)
TBN_GETINFOTIPA, FROM_ANSI);
}
+static void test_wm_notify_tooltip(HWND pager)
+{
+ NMTTDISPINFOW nmttdi;
+ WCHAR *buffer_w;
+ INT size;
+
+ /* if lpszText is not set by parent, will be set to the address of szText, even if szText is empty */
+ notify_test_data.sub_test_id = 0;
+ memset(&nmttdi, 0, sizeof(nmttdi));
+ send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+ expect_text_empty(nmttdi.szText);
+ expect_eq_pointer(nmttdi.lpszText, nmttdi.szText);
+
+ /* Parent write szText. If lpszText is not set by parent, will be set to the address of szText */
+ notify_test_data.sub_test_id = 1;
+ memset(&nmttdi, 0, sizeof(nmttdi));
+ send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+ expect_eq_text_w(nmttdi.szText, test_w);
+ expect_eq_pointer(nmttdi.lpszText, nmttdi.szText);
+
+ /* Parent write szText. Parent replace nmttdi.lpszText with pointer */
+ notify_test_data.sub_test_id = 2;
+ memset(&nmttdi, 0, sizeof(nmttdi));
+ send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+ expect_eq_text_w(nmttdi.szText, test_w);
+ expect_eq_pointer(nmttdi.lpszText, nmttdi.szText);
+
+ /* Parent write szText. Parent set int resource. szText end up empty */
+ notify_test_data.sub_test_id = 3;
+ memset(&nmttdi, 0, sizeof(nmttdi));
+ send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+ expect_text_empty(nmttdi.szText);
+ ok(IS_INTRESOURCE(nmttdi.lpszText), "Expect int resource\n");
+ ok(nmttdi.hinst != NULL, "Expect instance gets set\n");
+
+ /* Parent set szText, lpszText and instance */
+ notify_test_data.sub_test_id = 4;
+ memset(&nmttdi, 0, sizeof(nmttdi));
+ send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+ expect_eq_text_w(nmttdi.szText, test_w);
+ expect_eq_pointer(nmttdi.lpszText, nmttdi.szText);
+ ok(nmttdi.hinst != NULL, "Expect instance gets set\n");
+
+ /* Empty szText will be filled with lpszText if lpszText is set */
+ notify_test_data.sub_test_id = 5;
+ memset(&nmttdi, 0, sizeof(nmttdi));
+ send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+ expect_eq_text_w(nmttdi.szText, test_w);
+ expect_eq_pointer(nmttdi.lpszText, nmttdi.szText);
+
+ /* Not empty szText will be overwritten with lpszText if lpszText is set after conversion */
+ notify_test_data.sub_test_id = 6;
+ memset(&nmttdi, 0, sizeof(nmttdi));
+ send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+ expect_eq_text_w(nmttdi.szText, test_w);
+ expect_eq_pointer(nmttdi.lpszText, nmttdi.szText);
+
+ /* Set szText before send_notify. szText got converted for parent */
+ notify_test_data.sub_test_id = 7;
+ memset(&nmttdi, 0, sizeof(nmttdi));
+ memcpy(nmttdi.szText, test_w, sizeof(test_w));
+ send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+ expect_eq_text_w(nmttdi.szText, test_w);
+ expect_eq_pointer(nmttdi.lpszText, nmttdi.szText);
+
+ /* Set lpszText before send_notify. lpszText doesn't get converted for parent */
+ notify_test_data.sub_test_id = 8;
+ memset(&nmttdi, 0, sizeof(nmttdi));
+ nmttdi.lpszText = test_w;
+ send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+ expect_text_empty(nmttdi.szText);
+ expect_eq_pointer(nmttdi.lpszText, nmttdi.szText);
+
+ /* Parent set lpszText to a string larger than the size of szText array */
+ notify_test_data.sub_test_id = 9;
+ memset(&nmttdi, 0, sizeof(nmttdi));
+ send_notify(TTN_GETDISPINFOW, TTN_GETDISPINFOA, (LPARAM)&nmttdi, FALSE, TRUE);
+ size = MultiByteToWideChar(CP_ACP, 0, large_a, -1, 0, 0);
+ buffer_w = heap_alloc(size * sizeof(WCHAR));
+ if (!buffer_w) return;
+ MultiByteToWideChar(CP_ACP, 0, large_a, -1, buffer_w, size);
+ expect_eq_text_w(nmttdi.lpszText, buffer_w);
+ buffer_w[ARRAY_SIZE(nmttdi.szText)] = 0;
+ expect_eq_text_w(nmttdi.szText, buffer_w);
+ /* nmttdi.szText is not null terminated */
+ expect_eq_int(lstrlenW(nmttdi.szText), ARRAY_SIZE(nmttdi.szText));
+ heap_free(buffer_w);
+}
+
static void test_wm_notify(void)
{
static const CHAR *class = "Pager notify class";
@@ -844,6 +980,7 @@ static void test_wm_notify(void)
SendMessageW(pager, PGM_SETCHILD, 0, (LPARAM)child1_wnd);
test_wm_notify_toolbar(pager);
+ test_wm_notify_tooltip(pager);
DestroyWindow(parent);
UnregisterClassA(class, GetModuleHandleA(NULL));
--
2.18.0
More information about the wine-devel
mailing list