Skip to content

Commit c6bd75f

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 ff6bf58 commit c6bd75f

File tree

3 files changed

+57
-4
lines changed

3 files changed

+57
-4
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: 33 additions & 3 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.*;
@@ -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+
private Event currentDpiChangeEvent;
84+
8185
/**
8286
* Prevents uninitialized instances from being created outside the package.
8387
*/
@@ -4757,7 +4761,7 @@ public boolean setParent (Composite parent) {
47574761
if (parent.nativeZoom != nativeZoom) {
47584762
int newZoom = parent.nativeZoom;
47594763
Event zoomChangedEvent = createZoomChangedEvent(newZoom);
4760-
notifyListeners(SWT.ZoomChanged, zoomChangedEvent);
4764+
sendZoomChangedEvent(zoomChangedEvent, getShell());
47614765
}
47624766
int flags = OS.SWP_NOSIZE | OS.SWP_NOMOVE | OS.SWP_NOACTIVATE;
47634767
OS.SetWindowPos (topHandle, OS.HWND_BOTTOM, 0, 0, 0, 0, flags);
@@ -4950,11 +4954,15 @@ LRESULT WM_DESTROY (long wParam, long lParam) {
49504954
return null;
49514955
}
49524956

4953-
void handleMonitorSpecificDpiChange(int newNativeZoom, Rectangle newBoundsInPixels) {
4957+
private void handleMonitorSpecificDpiChange(int newNativeZoom, Rectangle newBoundsInPixels) {
49544958
DPIUtil.setDeviceZoom (newNativeZoom);
49554959
Event zoomChangedEvent = createZoomChangedEvent(newNativeZoom);
4956-
notifyListeners(SWT.ZoomChanged, zoomChangedEvent);
4960+
if (currentDpiChangeEvent != null) {
4961+
currentDpiChangeEvent.doit = false;
4962+
}
4963+
currentDpiChangeEvent = zoomChangedEvent;
49574964
this.setBoundsInPixels(newBoundsInPixels.x, newBoundsInPixels.y, newBoundsInPixels.width, newBoundsInPixels.height);
4965+
sendZoomChangedEvent(zoomChangedEvent, getShell());
49584966
}
49594967

49604968
private Event createZoomChangedEvent(int zoom) {
@@ -4963,6 +4971,7 @@ private Event createZoomChangedEvent(int zoom) {
49634971
event.widget = this;
49644972
event.detail = zoom;
49654973
event.doit = true;
4974+
event.data = new AtomicInteger(0);
49664975
return event;
49674976
}
49684977

@@ -5876,6 +5885,27 @@ LRESULT wmScrollChild (long wParam, long lParam) {
58765885
return null;
58775886
}
58785887

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

58805910
@Override
58815911
void handleDPIChange(Event event, float scalingFactor) {

0 commit comments

Comments
 (0)