@@ -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 adjustedTooltip = fitTooltipBoundsIntoMonitor (toolRect , monitorBounds );
8177+ OS .SetWindowPos (itemToolTipHandle , 0 , adjustedTooltip .x , adjustedTooltip .y , adjustedTooltip .width , adjustedTooltip .height , flags );
81658178 return LRESULT .ONE ;
81668179 }
81678180 return result ;
@@ -8170,6 +8183,47 @@ 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 toolRect , Rectangle monitorBounds ) {
8190+ int width = toolRect .right - toolRect .left ;
8191+ int height = toolRect .bottom - toolRect .top ;
8192+ if (toolRect .left < monitorBounds .x ) {
8193+ toolRect .left = monitorBounds .x ;
8194+ }
8195+ int tooltipRectangleRightEnd = toolRect .left + width ;
8196+ int monitorBoundsRightEnd = monitorBounds .x + monitorBounds .width ;
8197+ if (tooltipRectangleRightEnd > monitorBoundsRightEnd ) {
8198+ if (width <= monitorBounds .width ) {
8199+ toolRect .left = monitorBounds .x + monitorBounds .width - width ;
8200+ } else {
8201+ toolRect .left = monitorBounds .x ;
8202+ }
8203+ int offset = (toolRect .left + width ) - (monitorBounds .x + monitorBounds .width );
8204+ width -= offset ;
8205+ }
8206+ return new Rectangle (toolRect .left , toolRect .top , width , height );
8207+ }
8208+
8209+ private Rectangle getContainingMonitorBoundsInSingleZoomCoordinateSystem (Point point ) {
8210+ int zoom = getZoom ();
8211+ point = DPIUtil .scaleUp (point , zoom );
8212+ for (Monitor monitor : display .getMonitors ()) {
8213+ Rectangle monitorBounds = DPIUtil .scaleUp (monitor .getBounds (), zoom );
8214+ if (monitorBounds .contains (point )) {
8215+ return monitorBounds ;
8216+ }
8217+ }
8218+ return null ;
8219+ }
8220+
8221+ private Rectangle getContainingMonitorBoundsInMultiZoomCoordinateSystem (MonitorAwarePoint point ) {
8222+ Monitor monitor = point .getMonitor ();
8223+ return new Rectangle (monitor .x , monitor .y , DPIUtil .scaleUp (monitor .width , monitor .zoom ),
8224+ DPIUtil .scaleUp (monitor .height , monitor .zoom ));
8225+ }
8226+
81738227LRESULT wmNotifyToolTip (NMTTCUSTOMDRAW nmcd , long lParam ) {
81748228 switch (nmcd .dwDrawStage ) {
81758229 case OS .CDDS_PREPAINT : {
0 commit comments