@@ -8157,11 +8157,23 @@ 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+ Point cursorLocation = display .getCursorLocation ();
8169+ Rectangle monitorBounds = cursorLocation instanceof MonitorAwarePoint monitorAwarePoint
8170+ ? getContainingMonitorBoundsInMultiZoomCoordinateSystem (monitorAwarePoint )
8171+ : getContainingMonitorBoundsInSingleZoomCoordinateSystem (cursorLocation );
8172+ if (monitorBounds == null ) {
8173+ return null ;
8174+ }
8175+ Rectangle adjustedTooltip = getAdjustedTooltipIfNeeded (toolRect , monitorBounds );
8176+ OS .SetWindowPos (itemToolTipHandle , 0 , adjustedTooltip .x , adjustedTooltip .y , adjustedTooltip .width , adjustedTooltip .height , flags );
81658177 return LRESULT .ONE ;
81668178 }
81678179 return result ;
@@ -8170,6 +8182,50 @@ LRESULT wmNotifyToolTip (NMHDR hdr, long wParam, long lParam) {
81708182 return null ;
81718183}
81728184
8185+ /**
8186+ * Adjust the tool tip to fit in a single monitor either by shifting its position or by adjusting it's width.
8187+ * @param toolRect
8188+ * @param width
8189+ * @param monitorBounds
8190+ * @return
8191+ */
8192+ private Rectangle getAdjustedTooltipIfNeeded (RECT toolRect , Rectangle monitorBounds ) {
8193+ int width = toolRect .right - toolRect .left ;
8194+ int height = toolRect .bottom - toolRect .top ;
8195+ if (toolRect .left < monitorBounds .x ) {
8196+ int offset = monitorBounds .x - toolRect .left ;
8197+ toolRect .left += offset ;
8198+ }
8199+ if ((toolRect .left + width ) > (monitorBounds .x + monitorBounds .width )) {
8200+ if (width <= monitorBounds .width ) {
8201+ toolRect .left = monitorBounds .x + monitorBounds .width - width ;
8202+ } else {
8203+ toolRect .left = monitorBounds .x ;
8204+ }
8205+ int offset = (toolRect .left + width ) - (monitorBounds .x + monitorBounds .width );
8206+ width -= offset ;
8207+ }
8208+ return new Rectangle (toolRect .left , toolRect .top , width , height );
8209+ }
8210+
8211+ private Rectangle getContainingMonitorBoundsInSingleZoomCoordinateSystem (Point point ) {
8212+ int zoom = getZoom ();
8213+ point = DPIUtil .scaleUp (point , zoom );
8214+ for (Monitor monitor : display .getMonitors ()) {
8215+ Rectangle monitorBounds = DPIUtil .scaleUp (monitor .getBounds (), zoom );
8216+ if (monitorBounds .contains (point )) {
8217+ return monitorBounds ;
8218+ }
8219+ }
8220+ return null ;
8221+ }
8222+
8223+ private Rectangle getContainingMonitorBoundsInMultiZoomCoordinateSystem (MonitorAwarePoint point ) {
8224+ Monitor monitor = point .getMonitor ();
8225+ return new Rectangle (monitor .x , monitor .y , DPIUtil .scaleUp (monitor .width , monitor .zoom ),
8226+ DPIUtil .scaleUp (monitor .height , monitor .zoom ));
8227+ }
8228+
81738229LRESULT wmNotifyToolTip (NMTTCUSTOMDRAW nmcd , long lParam ) {
81748230 switch (nmcd .dwDrawStage ) {
81758231 case OS .CDDS_PREPAINT : {
0 commit comments