From fd4305eeb00cb38a7b34ffb42bddd85a7cb838d0 Mon Sep 17 00:00:00 2001 From: Amartya Parijat Date: Mon, 16 Jun 2025 15:16:04 +0200 Subject: [PATCH] Fit Table Tooltip in a single monitor for Win32 This commit contributes to the fitting of the table tooltip inside a single monitor if it spans over multiple monitor to avoid any infinite loop because of rescaling triggered by any DPI_CHANGED events. contributes to https://github.com/eclipse-platform/eclipse.platform.swt/issues/62 and https://github.com/eclipse-platform/eclipse.platform.swt/issues/128 --- .../win32/org/eclipse/swt/widgets/Table.java | 137 +++++++++--------- 1 file changed, 66 insertions(+), 71 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Table.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Table.java index 2f01d1ee3ce..4063f808f8a 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Table.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Table.java @@ -7158,82 +7158,77 @@ LRESULT wmNotifyToolTip (NMHDR hdr, long wParam, long lParam) { case OS.TTN_SHOW: { LRESULT result = super.wmNotify (hdr, wParam, lParam); if (result != null) return result; - if (hdr.code != OS.TTN_SHOW) tipRequested = true; - long code = callWindowProc (handle, OS.WM_NOTIFY, wParam, lParam); - if (hdr.code != OS.TTN_SHOW) tipRequested = false; if (toolTipText != null) break; - if (isCustomToolTip ()) { - LVHITTESTINFO pinfo = new LVHITTESTINFO (); - int pos = OS.GetMessagePos (); - POINT pt = new POINT(); - OS.POINTSTOPOINT (pt, pos); - OS.ScreenToClient (handle, pt); - pinfo.x = pt.x; - pinfo.y = pt.y; - /* - * Bug in Windows. When LVM_SUBITEMHITTEST is used to hittest - * a point that is above the table, instead of returning -1 to - * indicate that the hittest failed, a negative index is returned. - * The fix is to consider any value that is negative a failure. - */ - if (OS.SendMessage (handle, OS.LVM_SUBITEMHITTEST, 0, pinfo) >= 0) { - TableItem item = _getItem (pinfo.iItem); - long hDC = OS.GetDC (handle); - long oldFont = 0, newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); - if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont); - long hFont = item.fontHandle (pinfo.iSubItem); - if (hFont != -1) hFont = OS.SelectObject (hDC, hFont); - Event event = sendMeasureItemEvent (item, pinfo.iItem, pinfo.iSubItem, hDC); - if (!isDisposed () && !item.isDisposed ()) { - RECT itemRect = new RECT (); - Rectangle boundsInPixels = DPIUtil.scaleUp(event.getBounds(), getZoom()); - OS.SetRect (itemRect, boundsInPixels.x, boundsInPixels.y, boundsInPixels.x + boundsInPixels.width, boundsInPixels.y + boundsInPixels.height); - if (hdr.code == OS.TTN_SHOW) { - RECT toolRect = toolTipRect (itemRect); - OS.MapWindowPoints (handle, 0, toolRect, 2); - long hwndToolTip = OS.SendMessage (handle, OS.LVM_GETTOOLTIPS, 0, 0); - int flags = OS.SWP_NOACTIVATE | OS.SWP_NOZORDER; - int width = toolRect.right - toolRect.left, height = toolRect.bottom - toolRect.top; - OS.SetWindowPos (hwndToolTip, 0, toolRect.left , toolRect.top, width, height, flags); - } else { - NMTTDISPINFO lpnmtdi = new NMTTDISPINFO (); - OS.MoveMemory (lpnmtdi, lParam, NMTTDISPINFO.sizeof); - if (lpnmtdi.lpszText != 0) { - OS.MoveMemory (lpnmtdi.lpszText, new char [1], 2); - OS.MoveMemory (lParam, lpnmtdi, NMTTDISPINFO.sizeof); - } - RECT cellRect = item.getBounds (pinfo.iItem, pinfo.iSubItem, true, true, true, true, hDC); - RECT clientRect = new RECT (); - OS.GetClientRect (handle, clientRect); - if (itemRect.right > cellRect.right || itemRect.right > clientRect.right) { - //TEMPORARY CODE - String string = " "; -// String string = null; -// if (pinfo.iSubItem == 0) { -// string = item.text; -// } else { -// String [] strings = item.strings; -// if (strings != null) string = strings [pinfo.iSubItem]; -// } - if (string != null) { - Shell shell = getShell (); - char [] chars = new char [string.length () + 1]; - string.getChars (0, string.length (), chars, 0); - shell.setToolTipText (lpnmtdi, chars); - OS.MoveMemory (lParam, lpnmtdi, NMTTDISPINFO.sizeof); - } - } - } - } - if (hFont != -1) hFont = OS.SelectObject (hDC, hFont); - if (newFont != 0) OS.SelectObject (hDC, oldFont); - OS.ReleaseDC (handle, hDC); + result = positionTooltip(hdr, lParam); + return result; + } + } + return null; +} + +private LRESULT positionTooltip(NMHDR hdr, long lParam) { + LRESULT result = null; + LVHITTESTINFO pinfo = new LVHITTESTINFO (); + int pos = OS.GetMessagePos (); + POINT pt = new POINT(); + OS.POINTSTOPOINT (pt, pos); + OS.ScreenToClient (handle, pt); + pinfo.x = pt.x; + pinfo.y = pt.y; + /* + * Bug in Windows. When LVM_SUBITEMHITTEST is used to hittest + * a point that is above the table, instead of returning -1 to + * indicate that the hittest failed, a negative index is returned. + * The fix is to consider any value that is negative a failure. + */ + if (OS.SendMessage (handle, OS.LVM_SUBITEMHITTEST, 0, pinfo) >= 0) { + TableItem item = _getItem (pinfo.iItem); + long hDC = OS.GetDC (handle); + long oldFont = 0, newFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); + if (newFont != 0) oldFont = OS.SelectObject (hDC, newFont); + long hFont = item.fontHandle (pinfo.iSubItem); + if (hFont != -1) hFont = OS.SelectObject (hDC, hFont); + Event event = sendMeasureItemEvent (item, pinfo.iItem, pinfo.iSubItem, hDC); + if (!isDisposed () && !item.isDisposed ()) { + RECT itemRect = new RECT (); + Rectangle boundsInPixels = DPIUtil.scaleUp(event.getBounds(), getZoom()); + OS.SetRect (itemRect, boundsInPixels.x, boundsInPixels.y, boundsInPixels.x + boundsInPixels.width, boundsInPixels.y + boundsInPixels.height); + if (hdr.code == OS.TTN_SHOW) { + RECT toolRect = isCustomToolTip() ? toolTipRect (itemRect) : itemRect; + OS.MapWindowPoints (handle, 0, toolRect, 2); + long hwndToolTip = OS.SendMessage (handle, OS.LVM_GETTOOLTIPS, 0, 0); + int flags = OS.SWP_NOACTIVATE | OS.SWP_NOZORDER; + Rectangle adjustedTooltipBounds = getDisplay().fitRectangleBoundsIntoMonitorWithCursor(toolRect); + OS.SetWindowPos(hwndToolTip, 0, adjustedTooltipBounds.x, adjustedTooltipBounds.y, + adjustedTooltipBounds.width, adjustedTooltipBounds.height, flags); + result = LRESULT.ONE; + } else if (isCustomToolTip()) { + NMTTDISPINFO lpnmtdi = new NMTTDISPINFO (); + OS.MoveMemory (lpnmtdi, lParam, NMTTDISPINFO.sizeof); + if (lpnmtdi.lpszText != 0) { + OS.MoveMemory (lpnmtdi.lpszText, new char [1], 2); + OS.MoveMemory (lParam, lpnmtdi, NMTTDISPINFO.sizeof); + } + RECT cellRect = item.getBounds (pinfo.iItem, pinfo.iSubItem, true, true, true, true, hDC); + RECT clientRect = new RECT (); + OS.GetClientRect (handle, clientRect); + if (itemRect.right > cellRect.right || itemRect.right > clientRect.right) { + //TEMPORARY CODE + String string = " "; + Shell shell = getShell (); + char [] chars = new char [string.length () + 1]; + string.getChars (0, string.length (), chars, 0); + shell.setToolTipText (lpnmtdi, chars); + OS.MoveMemory (lParam, lpnmtdi, NMTTDISPINFO.sizeof); + result = LRESULT.ONE; } } - return new LRESULT (code); } + if (hFont != -1) hFont = OS.SelectObject (hDC, hFont); + if (newFont != 0) OS.SelectObject (hDC, oldFont); + OS.ReleaseDC (handle, hDC); } - return null; + return result; } LRESULT wmNotifyToolTip (NMTTCUSTOMDRAW nmcd, long lParam) {