Skip to content

Commit 93c6a86

Browse files
committed
[win32] Refresh thread dpi awareness on hooks
This commit resets the DPI awareness for the WH_MSGFILTER hook, if called. For performance reasons that is only done, when runAsyncMessages will be triggered, as this can cause UI updates, which would be executed with the wrong DPI awareness context and cause UI glitches.
1 parent b4fabe5 commit 93c6a86

File tree

1 file changed

+60
-27
lines changed
  • bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets

1 file changed

+60
-27
lines changed

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

Lines changed: 60 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,31 +1456,40 @@ public Widget findWidget (Widget widget, long id) {
14561456
long foregroundIdleProc (long code, long wParam, long lParam) {
14571457
if (code >= 0) {
14581458
if (!synchronizer.isMessagesEmpty()) {
1459-
sendPostExternalEventDispatchEvent ();
1460-
if (runMessagesInIdle) {
1461-
if (runMessagesInMessageProc) {
1462-
OS.PostMessage (hwndMessage, SWT_RUNASYNC, 0, 0);
1463-
} else {
1464-
runAsyncMessages (false);
1459+
Runnable processMesseges = () -> {
1460+
sendPostExternalEventDispatchEvent ();
1461+
if (runMessagesInIdle) {
1462+
if (runMessagesInMessageProc) {
1463+
OS.PostMessage (hwndMessage, SWT_RUNASYNC, 0, 0);
1464+
} else {
1465+
runAsyncMessages (false);
1466+
}
14651467
}
1466-
}
1467-
/*
1468-
* Bug in Windows. For some reason, input events can be lost
1469-
* when a message is posted to the queue from a foreground idle
1470-
* hook. The fix is to detect that there are outstanding input
1471-
* events and avoid posting the wake event.
1472-
*
1473-
* Note that PeekMessage() changes the state of events on the
1474-
* queue to no longer be considered new. If we peek for input
1475-
* events and posted messages (PM_QS_INPUT | PM_QS_POSTMESSAGE),
1476-
* it is possible to cause WaitMessage() to sleep until a new
1477-
* input event is generated causing sync runnables not to be
1478-
* executed.
1479-
*/
1480-
MSG msg = new MSG();
1481-
int flags = OS.PM_NOREMOVE | OS.PM_NOYIELD | OS.PM_QS_INPUT;
1482-
if (!OS.PeekMessage (msg, 0, 0, 0, flags)) wakeThread ();
1483-
sendPreExternalEventDispatchEvent ();
1468+
/*
1469+
* Bug in Windows. For some reason, input events can be lost
1470+
* when a message is posted to the queue from a foreground idle
1471+
* hook. The fix is to detect that there are outstanding input
1472+
* events and avoid posting the wake event.
1473+
*
1474+
* Note that PeekMessage() changes the state of events on the
1475+
* queue to no longer be considered new. If we peek for input
1476+
* events and posted messages (PM_QS_INPUT | PM_QS_POSTMESSAGE),
1477+
* it is possible to cause WaitMessage() to sleep until a new
1478+
* input event is generated causing sync runnables not to be
1479+
* executed.
1480+
*/
1481+
MSG msg = new MSG();
1482+
int flags = OS.PM_NOREMOVE | OS.PM_NOYIELD | OS.PM_QS_INPUT;
1483+
if (!OS.PeekMessage (msg, 0, 0, 0, flags)) wakeThread ();
1484+
sendPreExternalEventDispatchEvent ();
1485+
};
1486+
// Windows hooks will inherit the thread DPI awareness from
1487+
// the process. Whatever DPI awareness was set before on
1488+
// the thread will be overwritten before the hook is called.
1489+
// This requires to reset the thread DPi awareness to make
1490+
// sure, all UI updates caused by this will be executed
1491+
// with the correct DPI awareness
1492+
runWithProperDPIAwareness(processMesseges);
14841493
}
14851494
}
14861495
return OS.CallNextHookEx (idleHook, (int)code, wParam, lParam);
@@ -3425,7 +3434,15 @@ long msgFilterProc (long code, long wParam, long lParam) {
34253434
MSG msg = new MSG ();
34263435
int flags = OS.PM_NOREMOVE | OS.PM_NOYIELD | OS.PM_QS_INPUT | OS.PM_QS_POSTMESSAGE;
34273436
if (!OS.PeekMessage (msg, 0, 0, 0, flags)) {
3428-
if (runAsyncMessages (false)) wakeThread ();
3437+
// Windows hooks will inherit the thread DPI awareness from
3438+
// the process. Whatever DPI awareness was set before on
3439+
// the thread will be overwritten before the hook is called.
3440+
// This requires to reset the thread DPi awareness to make
3441+
// sure, all UI updates caused by this will be executed
3442+
// with the correct DPI awareness
3443+
runWithProperDPIAwareness(() -> {
3444+
if (runAsyncMessages (false)) wakeThread ();
3445+
});
34293446
}
34303447
}
34313448
break;
@@ -5146,7 +5163,7 @@ String wrapText (String text, long handle, int width) {
51465163

51475164
static String withCrLf (String string) {
51485165
/* Create a new string with the CR/LF line terminator. */
5149-
int i = 0;
5166+
int i = 0;
51505167
int length = string.length();
51515168
StringBuilder result = new StringBuilder (length);
51525169
while (i < length) {
@@ -5163,7 +5180,7 @@ static String withCrLf (String string) {
51635180
}
51645181
}
51655182
}
5166-
5183+
51675184
/* Avoid creating a copy of the string if it has not changed */
51685185
if (string.length()== result.length()) return string;
51695186
return result.toString ();
@@ -5382,4 +5399,20 @@ private boolean setDPIAwareness(int desiredDpiAwareness) {
53825399
return true;
53835400
}
53845401

5402+
private void runWithProperDPIAwareness(Runnable operation) {
5403+
if (isRescalingAtRuntime()) {
5404+
// refreshing is only necessary, when monitor specific scaling is active
5405+
long previousDPIAwareness = OS.GetThreadDpiAwarenessContext();
5406+
if (!setDPIAwareness(OS.DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) {
5407+
// awareness was not changed, so no need to reset it
5408+
previousDPIAwareness = 0;
5409+
}
5410+
operation.run();
5411+
if (previousDPIAwareness > 0) {
5412+
OS.SetThreadDpiAwarenessContext(previousDPIAwareness);
5413+
}
5414+
} else {
5415+
operation.run();
5416+
}
5417+
}
53855418
}

0 commit comments

Comments
 (0)