@@ -8157,11 +8157,24 @@ LRESULT wmNotifyToolTip (NMHDR hdr, long wParam, long lParam) {
8157
8157
if (findCell (pt .x , pt .y , item , index , cellRect , itemRect )) {
8158
8158
RECT toolRect = toolTipRect (itemRect [0 ]);
8159
8159
OS .MapWindowPoints (handle , 0 , toolRect , 2 );
8160
- int width = toolRect .right - toolRect .left ;
8161
- int height = toolRect .bottom - toolRect .top ;
8162
8160
int flags = OS .SWP_NOACTIVATE | OS .SWP_NOZORDER | OS .SWP_NOSIZE ;
8163
8161
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 );
8165
8178
return LRESULT .ONE ;
8166
8179
}
8167
8180
return result ;
@@ -8170,6 +8183,45 @@ LRESULT wmNotifyToolTip (NMHDR hdr, long wParam, long lParam) {
8170
8183
return null ;
8171
8184
}
8172
8185
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
+
8173
8225
LRESULT wmNotifyToolTip (NMTTCUSTOMDRAW nmcd , long lParam ) {
8174
8226
switch (nmcd .dwDrawStage ) {
8175
8227
case OS .CDDS_PREPAINT : {
0 commit comments