Skip to content

Commit 7ea01d5

Browse files
amartya4256akoch-yatta
authored andcommitted
Make DPI_CHANGED event handling async
With this commit, all the widgets scale themselves asynchronously independent of the order saving the wait time over their children to scale.
1 parent 87fa834 commit 7ea01d5

File tree

4 files changed

+64
-9
lines changed

4 files changed

+64
-9
lines changed

bundles/org.eclipse.swt/Eclipse SWT Tests/win32/org/eclipse/swt/internal/DPITestUtil.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
*******************************************************************************/
1414
package org.eclipse.swt.internal;
1515

16+
import java.time.*;
17+
import java.util.concurrent.atomic.*;
18+
1619
import org.eclipse.swt.*;
1720
import org.eclipse.swt.widgets.*;
1821

@@ -21,14 +24,34 @@ public final class DPITestUtil {
2124
private DPITestUtil() {
2225
}
2326

27+
private static final int TIMEOUT_MILLIS = 10000;
28+
2429
public static void changeDPIZoom (Shell shell, int nativeZoom) {
2530
DPIUtil.setDeviceZoom(nativeZoom);
2631
Event event = new Event();
2732
event.type = SWT.ZoomChanged;
2833
event.widget = shell;
2934
event.detail = nativeZoom;
3035
event.doit = true;
36+
AtomicInteger scalingCounter = new AtomicInteger(0);
37+
event.data = scalingCounter;
3138
shell.notifyListeners(SWT.ZoomChanged, event);
39+
waitForDPIChange(shell, TIMEOUT_MILLIS, scalingCounter);
40+
}
41+
42+
public static void waitForPassCondition(Shell shell, int timeout, AtomicInteger scalingCounter) {
43+
final Instant timeOut = Instant.now().plusMillis(timeout);
44+
final Display display = shell == null ? Display.getDefault() : shell.getDisplay();
45+
46+
while (Instant.now().isBefore(timeOut) && scalingCounter.get() != 0) {
47+
if (!display.isDisposed()) {
48+
display.readAndDispatch();
49+
}
50+
}
51+
}
52+
53+
public static void waitForDPIChange(Shell shell, int timeout, AtomicInteger scalingCounter) {
54+
waitForPassCondition(shell, timeout, scalingCounter);
3255
}
3356

3457
}

bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Composite.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1977,7 +1977,7 @@ public String toString() {
19771977
void handleDPIChange(Event event, float scalingFactor) {
19781978
super.handleDPIChange(event, scalingFactor);
19791979
for (Control child : getChildren()) {
1980-
child.notifyListeners(SWT.ZoomChanged, event);
1980+
child.sendZoomChangedEvent(event, getShell());
19811981
}
19821982
}
19831983
}

bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717

1818
import java.util.*;
19+
import java.util.concurrent.atomic.*;
1920
import java.util.stream.*;
2021

2122
import org.eclipse.swt.*;
@@ -4760,7 +4761,7 @@ public boolean setParent (Composite parent) {
47604761
if (parent.nativeZoom != nativeZoom) {
47614762
int newZoom = parent.nativeZoom;
47624763
Event zoomChangedEvent = createZoomChangedEvent(newZoom);
4763-
notifyListeners(SWT.ZoomChanged, zoomChangedEvent);
4764+
sendZoomChangedEvent(zoomChangedEvent, getShell());
47644765
}
47654766
int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE;
47664767
OS.SetWindowPos (topHandle, OS.HWND_BOTTOM, 0, 0, 0, 0, flags);
@@ -4953,9 +4954,14 @@ LRESULT WM_DESTROY (long wParam, long lParam) {
49534954
return null;
49544955
}
49554956

4956-
void handleMonitorSpecificDpiChange(int newNativeZoom, Rectangle newBoundsInPixels) {
4957+
private void handleMonitorSpecificDpiChange(int newNativeZoom, Rectangle newBoundsInPixels) {
49574958
DPIUtil.setDeviceZoom (newNativeZoom);
49584959
Event zoomChangedEvent = createZoomChangedEvent(newNativeZoom);
4960+
Shell shell = getShell();
4961+
if (shell.currentDpiChangeEvent != null) {
4962+
shell.currentDpiChangeEvent.doit = false;
4963+
}
4964+
shell.currentDpiChangeEvent = zoomChangedEvent;
49594965
notifyListeners(SWT.ZoomChanged, zoomChangedEvent);
49604966
this.setBoundsInPixels(newBoundsInPixels.x, newBoundsInPixels.y, newBoundsInPixels.width, newBoundsInPixels.height);
49614967
}
@@ -4966,6 +4972,7 @@ private Event createZoomChangedEvent(int zoom) {
49664972
event.widget = this;
49674973
event.detail = zoom;
49684974
event.doit = true;
4975+
event.data = new AtomicInteger(0);
49694976
return event;
49704977
}
49714978

@@ -4974,12 +4981,10 @@ LRESULT WM_DPICHANGED (long wParam, long lParam) {
49744981
int newNativeZoom = DPIUtil.mapDPIToZoom (OS.HIWORD (wParam));
49754982
if (getDisplay().isRescalingAtRuntime()) {
49764983
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-
}
4984+
RECT rect = new RECT ();
4985+
COM.MoveMemory(rect, lParam, RECT.sizeof);
4986+
handleMonitorSpecificDpiChange(newNativeZoom, new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom-rect.top));
4987+
return LRESULT.ZERO;
49834988
} else {
49844989
int newZoom = DPIUtil.getZoomForAutoscaleProperty (newNativeZoom);
49854990
int oldZoom = DPIUtil.getZoomForAutoscaleProperty (nativeZoom);
@@ -5879,6 +5884,29 @@ LRESULT wmScrollChild (long wParam, long lParam) {
58795884
return null;
58805885
}
58815886

5887+
void sendZoomChangedEvent(Event event, Shell shell) {
5888+
AtomicInteger handleDPIChangedScheduledTasksCount = (AtomicInteger) event.data;
5889+
handleDPIChangedScheduledTasksCount.incrementAndGet();
5890+
getDisplay().asyncExec(() -> {
5891+
try {
5892+
if (!this.isDisposed() && event.doit) {
5893+
notifyListeners(SWT.ZoomChanged, event);
5894+
}
5895+
} finally {
5896+
if (shell.isDisposed()) {
5897+
return;
5898+
}
5899+
if (handleDPIChangedScheduledTasksCount.decrementAndGet() <= 0) {
5900+
if (event == shell.currentDpiChangeEvent) {
5901+
shell.currentDpiChangeEvent = null;
5902+
}
5903+
if (event.doit) {
5904+
shell.WM_SIZE(0, 0);
5905+
}
5906+
}
5907+
}
5908+
});
5909+
}
58825910

58835911
@Override
58845912
void handleDPIChange(Event event, float scalingFactor) {

bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Shell.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ public class Shell extends Decorations {
132132
long toolIcon, balloonIcon;
133133
long windowProc;
134134
Control lastActive;
135+
136+
/** Cache for currently processed DPI change event to be able to cancel it if a new one is triggered */
137+
Event currentDpiChangeEvent;
138+
135139
static /*final*/ long ToolTipProc;
136140
static final long DialogProc;
137141
static final TCHAR DialogClass = new TCHAR (0, "#32770", true);

0 commit comments

Comments
 (0)