@@ -8157,11 +8157,24 @@ LRESULT wmNotifyToolTip (NMHDR hdr, long wParam, long lParam) {
81578157 if (findCell (pt .x , pt .y , item , index , cellRect , itemRect )) {
81588158 RECT toolRect = toolTipRect (itemRect [0 ]);
81598159 OS .MapWindowPoints (handle , 0 , toolRect , 2 );
8160- int width = toolRect .right - toolRect .left ;
8161- int height = toolRect .bottom - toolRect .top ;
81628160 int flags = OS .SWP_NOACTIVATE | OS .SWP_NOZORDER | OS .SWP_NOSIZE ;
81638161 if (isCustomToolTip ()) flags &= ~OS .SWP_NOSIZE ;
8164- OS .SetWindowPos (itemToolTipHandle , 0 , toolRect .left , toolRect .top , width , height , flags );
8162+ // Retrieve the monitor containing the cursor position, as tool tip placement
8163+ // must occur on the same monitor to avoid potential infinite loops. When a tool tip
8164+ // appears on a different monitor than the cursor, the operating system may
8165+ // attempt to re-scale it based on that monitor's settings. This re-scaling
8166+ // triggers additional display messages to SWT, creating an infinite loop
8167+ // of positioning and re-scaling events.
8168+ // Refer: https://github.com/eclipse-platform/eclipse.platform.swt/issues/557
8169+ Point cursorLocation = display .getCursorLocation ();
8170+ Rectangle monitorBounds = cursorLocation instanceof MonitorAwarePoint monitorAwarePoint
8171+ ? getContainingMonitorBoundsInMultiZoomCoordinateSystem (monitorAwarePoint )
8172+ : getContainingMonitorBoundsInSingleZoomCoordinateSystem (cursorLocation );
8173+ if (monitorBounds == null ) {
8174+ return null ;
8175+ }
8176+ Rectangle adjustedTooltipBounds = fitTooltipBoundsIntoMonitor (toolRect , monitorBounds );
8177+ OS .SetWindowPos (itemToolTipHandle , 0 , adjustedTooltipBounds .x , adjustedTooltipBounds .y , adjustedTooltipBounds .width , adjustedTooltipBounds .height , flags );
81658178 return LRESULT .ONE ;
81668179 }
81678180 return result ;
@@ -8170,6 +8183,45 @@ LRESULT wmNotifyToolTip (NMHDR hdr, long wParam, long lParam) {
81708183 return null ;
81718184}
81728185
8186+ /**
8187+ * Adjust the tool tip to fit in a single monitor either by shifting its position or by adjusting it's width.
8188+ */
8189+ private Rectangle fitTooltipBoundsIntoMonitor (RECT tooltipBounds , Rectangle monitorBounds ) {
8190+ int tooltipWidth = tooltipBounds .right - tooltipBounds .left ;
8191+ int tooltipHeight = tooltipBounds .bottom - tooltipBounds .top ;
8192+ if (tooltipBounds .left < monitorBounds .x ) {
8193+ tooltipBounds .left = monitorBounds .x ;
8194+ }
8195+ int monitorBoundsRightEnd = monitorBounds .x + monitorBounds .width ;
8196+ if (tooltipBounds .right > monitorBoundsRightEnd ) {
8197+ if (tooltipWidth <= monitorBounds .width ) {
8198+ tooltipBounds .left = monitorBoundsRightEnd - tooltipWidth ;
8199+ } else {
8200+ tooltipBounds .left = monitorBounds .x ;
8201+ }
8202+ tooltipWidth = monitorBoundsRightEnd - tooltipBounds .left ;
8203+ }
8204+ return new Rectangle (tooltipBounds .left , tooltipBounds .top , tooltipWidth , tooltipHeight );
8205+ }
8206+
8207+ private Rectangle getContainingMonitorBoundsInSingleZoomCoordinateSystem (Point point ) {
8208+ int zoom = getZoom ();
8209+ point = DPIUtil .scaleUp (point , zoom );
8210+ for (Monitor monitor : display .getMonitors ()) {
8211+ Rectangle monitorBounds = DPIUtil .scaleUp (monitor .getBounds (), zoom );
8212+ if (monitorBounds .contains (point )) {
8213+ return monitorBounds ;
8214+ }
8215+ }
8216+ return null ;
8217+ }
8218+
8219+ private Rectangle getContainingMonitorBoundsInMultiZoomCoordinateSystem (MonitorAwarePoint point ) {
8220+ Monitor monitor = point .getMonitor ();
8221+ return new Rectangle (monitor .x , monitor .y , DPIUtil .scaleUp (monitor .width , monitor .zoom ),
8222+ DPIUtil .scaleUp (monitor .height , monitor .zoom ));
8223+ }
8224+
81738225LRESULT wmNotifyToolTip (NMTTCUSTOMDRAW nmcd , long lParam ) {
81748226 switch (nmcd .dwDrawStage ) {
81758227 case OS .CDDS_PREPAINT : {
0 commit comments