1616
1717
1818import  java .util .*;
19+ import  java .util .concurrent .atomic .*;
1920import  java .util .stream .*;
2021
2122import  org .eclipse .swt .*;
@@ -78,6 +79,9 @@ public abstract class Control extends Widget implements Drawable {
7879	Font  font ;
7980	int  drawCount , foreground , background , backgroundAlpha  = 255 ;
8081
82+ 	/** Cache for currently processed DPI change event to be able to cancel it if a new one is triggered */ 
83+ 	Event  currentDpiChangeEvent ;
84+ 
8185/** 
8286 * Prevents uninitialized instances from being created outside the package. 
8387 */ 
@@ -4760,7 +4764,10 @@ public boolean setParent (Composite parent) {
47604764	if  (parent .nativeZoom  != nativeZoom ) {
47614765		int  newZoom  = parent .nativeZoom ;
47624766		Event  zoomChangedEvent  = createZoomChangedEvent (newZoom );
4763- 		notifyListeners (SWT .ZoomChanged , zoomChangedEvent );
4767+ 		if  (currentDpiChangeEvent  != null ) {
4768+ 			currentDpiChangeEvent .doit  = false ;
4769+ 		}
4770+ 		sendZoomChangedEvent (zoomChangedEvent , getShell ());
47644771	}
47654772	int  flags  = OS .SWP_NOSIZE  | OS .SWP_NOMOVE  | OS .SWP_NOACTIVATE ;
47664773	OS .SetWindowPos  (topHandle , OS .HWND_BOTTOM , 0 , 0 , 0 , 0 , flags );
@@ -4953,19 +4960,24 @@ LRESULT WM_DESTROY (long wParam, long lParam) {
49534960	return  null ;
49544961}
49554962
4956- void  handleMonitorSpecificDpiChange (int  newNativeZoom , Rectangle  newBoundsInPixels ) {
4963+ private   void  handleMonitorSpecificDpiChange (int  newNativeZoom , Rectangle  newBoundsInPixels ) {
49574964	DPIUtil .setDeviceZoom  (newNativeZoom );
49584965	Event  zoomChangedEvent  = createZoomChangedEvent (newNativeZoom );
4966+ 	if  (currentDpiChangeEvent  != null ) {
4967+ 		currentDpiChangeEvent .doit  = false ;
4968+ 	}
4969+ 	currentDpiChangeEvent  = zoomChangedEvent ;
49594970	notifyListeners (SWT .ZoomChanged , zoomChangedEvent );
49604971	this .setBoundsInPixels (newBoundsInPixels .x , newBoundsInPixels .y , newBoundsInPixels .width , newBoundsInPixels .height );
49614972}
49624973
4963- private   Event  createZoomChangedEvent (int  zoom ) {
4974+ Event  createZoomChangedEvent (int  zoom ) {
49644975	Event  event  = new  Event ();
49654976	event .type  = SWT .ZoomChanged ;
49664977	event .widget  = this ;
49674978	event .detail  = zoom ;
49684979	event .doit  = true ;
4980+ 	event .data  = new  DPIChangeExecution ();
49694981	return  event ;
49704982}
49714983
@@ -4974,12 +4986,10 @@ LRESULT WM_DPICHANGED (long wParam, long lParam) {
49744986	int  newNativeZoom  = DPIUtil .mapDPIToZoom  (OS .HIWORD  (wParam ));
49754987	if  (getDisplay ().isRescalingAtRuntime ()) {
49764988		Device .win32_destroyUnusedHandles (getDisplay ());
4977- 		if  (newNativeZoom  != nativeZoom ) {
4978- 			RECT  rect  = new  RECT  ();
4979- 			COM .MoveMemory (rect , lParam , RECT .sizeof );
4980- 			handleMonitorSpecificDpiChange (newNativeZoom , new  Rectangle (rect .left , rect .top , rect .right  - rect .left , rect .bottom -rect .top ));
4981- 			return  LRESULT .ZERO ;
4982- 		}
4989+ 		RECT  rect  = new  RECT  ();
4990+ 		COM .MoveMemory (rect , lParam , RECT .sizeof );
4991+ 		handleMonitorSpecificDpiChange (newNativeZoom , new  Rectangle (rect .left , rect .top , rect .right  - rect .left , rect .bottom -rect .top ));
4992+ 		return  LRESULT .ZERO ;
49834993	} else  {
49844994		int  newZoom  = DPIUtil .getZoomForAutoscaleProperty  (newNativeZoom );
49854995		int  oldZoom  = DPIUtil .getZoomForAutoscaleProperty  (nativeZoom );
@@ -5879,6 +5889,62 @@ LRESULT wmScrollChild (long wParam, long lParam) {
58795889	return  null ;
58805890}
58815891
5892+ static  class  DPIChangeExecution  {
5893+ 	AtomicInteger  taskCount  = new  AtomicInteger ();
5894+ 	private  boolean  asyncExec  = true ;
5895+ 
5896+ 	private  void  process (Control  control , Runnable  operation ) {
5897+ 		boolean  currentAsyncExec  = asyncExec ;
5898+ 		if  (control  instanceof  Composite  comp ) {
5899+ 			// do not execute the DPI change asynchronously, if there is no 
5900+ 			// layout manager available otherwise size calculations could lead 
5901+ 			// to wrong results, because no final layout will be triggered 
5902+ 			asyncExec  &= (comp .layout  != null );
5903+ 		}
5904+ 		if  (asyncExec ) {
5905+ 			control .getDisplay ().asyncExec (operation ::run );
5906+ 		} else  {
5907+ 			operation .run ();
5908+ 		}
5909+ 		// resetting it prevents to break asynchronous execution when the synchronous 
5910+ 		// DPI change handling is finished 
5911+ 		asyncExec  = currentAsyncExec ;
5912+ 	}
5913+ 
5914+ 	private  void  increment () {
5915+ 		taskCount .incrementAndGet ();
5916+ 	}
5917+ 
5918+ 	private  boolean  decrement () {
5919+ 		return  taskCount .decrementAndGet () <= 0 ;
5920+ 	}
5921+ }
5922+ 
5923+ void  sendZoomChangedEvent (Event  event , Shell  shell ) {
5924+ 	this .currentDpiChangeEvent  = event ;
5925+ 	if  (event .data  instanceof  DPIChangeExecution  dpiExecData ) {
5926+ 		dpiExecData .increment ();
5927+ 		dpiExecData .process (this , () -> {
5928+ 			try  {
5929+ 				if  (!this .isDisposed () && event .doit ) {
5930+ 					notifyListeners (SWT .ZoomChanged , event );
5931+ 				}
5932+ 			} finally  {
5933+ 				if  (shell .isDisposed ()) {
5934+ 					return ;
5935+ 				}
5936+ 				if  (dpiExecData .decrement ()) {
5937+ 					if  (event  == currentDpiChangeEvent ) {
5938+ 						currentDpiChangeEvent  = null ;
5939+ 					}
5940+ 					if  (event .doit ) {
5941+ 						shell .WM_SIZE (0 , 0 );
5942+ 					}
5943+ 				}
5944+ 			}
5945+ 		});
5946+ 	}
5947+ }
58825948
58835949@ Override 
58845950void  handleDPIChange (Event  event , float  scalingFactor ) {
0 commit comments