JRE-427 HighDPI Scaling not on all screens
diff --git a/src/share/classes/sun/java2d/SunGraphicsEnvironment.java b/src/share/classes/sun/java2d/SunGraphicsEnvironment.java
index 9f29b02..84ce425 100644
--- a/src/share/classes/sun/java2d/SunGraphicsEnvironment.java
+++ b/src/share/classes/sun/java2d/SunGraphicsEnvironment.java
@@ -61,6 +61,7 @@
import sun.awt.DisplayChangedListener;
import sun.awt.FontConfiguration;
import sun.awt.SunDisplayChanger;
+import sun.awt.Win32GraphicsDevice;
import sun.font.CompositeFontDescriptor;
import sun.font.Font2D;
import sun.font.FontManager;
@@ -377,15 +378,29 @@
GraphicsEnvironment env = (ge == null ? getLocalGraphicsEnvironment() : ge);
if (!GraphicsEnvironment.isHeadless()) {
+ boolean fractionalScaleEnabled = "true".equals(AccessController.doPrivileged(
+ new GetPropertyAction("sun.java2d.uiFractScale.enabled", "false")));
+ boolean fractionalScaleOn = false;
for (GraphicsDevice d : env.getScreenDevices()) {
- if (d.getDefaultConfiguration().getDefaultTransform().getScaleX() > 1 ||
- d.getDefaultConfiguration().getDefaultTransform().getScaleY() > 1)
- {
- return uiScaleOn = true;
+ double scaleX = d.getDefaultConfiguration().getDefaultTransform().getScaleX();
+ double scaleY = d.getDefaultConfiguration().getDefaultTransform().getScaleY();
+ if (scaleX != Math.floor(scaleX) || scaleY != Math.floor(scaleY)) {
+ fractionalScaleOn = true;
+ if (!fractionalScaleEnabled) break;
+ }
+ if (scaleX > 1 || scaleY > 1) {
+ uiScaleOn = true;
+ }
+ }
+ if (!fractionalScaleEnabled && fractionalScaleOn) {
+ // Fallback to un-scaled behavior
+ uiScaleOn = false;
+ for (GraphicsDevice d : env.getScreenDevices()) {
+ ((Win32GraphicsDevice)d).resetScaleFactors();
}
}
}
- return uiScaleOn = false;
+ return uiScaleOn;
}
public static double getDebugScale() {
diff --git a/src/windows/classes/sun/awt/Win32GraphicsDevice.java b/src/windows/classes/sun/awt/Win32GraphicsDevice.java
index 466bb07..110dd4b 100644
--- a/src/windows/classes/sun/awt/Win32GraphicsDevice.java
+++ b/src/windows/classes/sun/awt/Win32GraphicsDevice.java
@@ -106,7 +106,7 @@
private static native void initIDs();
native void initDevice(int screen);
- native void initNativeScale(int screen, boolean fractionalScaleEnabled);
+ native void initNativeScale(int screen);
native void setNativeScale(int screen, float scaleX, float scaleY);
native float getNativeScaleX(int screen);
native float getNativeScaleY(int screen);
@@ -150,6 +150,13 @@
return scaleY;
}
+ /**
+ * Temp, until fractional scale is supported. Don't use this method!
+ */
+ public void resetScaleFactors() {
+ setNativeScale(screen, scaleX = 1f, scaleY = 1f);
+ }
+
private void initScaleFactors() {
if (SunGraphicsEnvironment.isUIScaleEnabled()) {
if (debugScaleX > 0 && debugScaleY > 0) {
@@ -157,9 +164,7 @@
scaleY = debugScaleY;
setNativeScale(screen, scaleX, scaleY);
} else {
- boolean fScaleEnabled = "true".equals(AccessController.doPrivileged(
- new GetPropertyAction("sun.java2d.uiFractScale.enabled", "false")));
- initNativeScale(screen, fScaleEnabled);
+ initNativeScale(screen);
scaleX = getNativeScaleX(screen);
scaleY = getNativeScaleY(screen);
}
diff --git a/src/windows/native/sun/windows/awt.h b/src/windows/native/sun/windows/awt.h
index 9191035..7f78497 100644
--- a/src/windows/native/sun/windows/awt.h
+++ b/src/windows/native/sun/windows/awt.h
@@ -52,6 +52,26 @@
} PROCESS_DPI_AWARENESS;
#endif
+#ifndef _WIN32_WINNT_WIN10
+typedef enum _DPI_AWARENESS {
+ DPI_AWARENESS_INVALID = -1,
+ DPI_AWARENESS_UNAWARE = 0,
+ DPI_AWARENESS_SYSTEM_AWARE = 1,
+ DPI_AWARENESS_PER_MONITOR_AWARE = 2
+} DPI_AWARENESS;
+
+DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
+
+#define DPI_AWARENESS_CONTEXT_UNAWARE ((DPI_AWARENESS_CONTEXT)-1)
+#define DPI_AWARENESS_CONTEXT_SYSTEM_AWARE ((DPI_AWARENESS_CONTEXT)-2)
+#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ((DPI_AWARENESS_CONTEXT)-3)
+#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((DPI_AWARENESS_CONTEXT)-4)
+
+typedef DPI_AWARENESS_CONTEXT(WINAPI GetThreadDpiAwarenessContextFunc)(void);
+typedef DPI_AWARENESS_CONTEXT(WINAPI SetThreadDpiAwarenessContextFunc)(DPI_AWARENESS_CONTEXT);
+typedef BOOL(AreDpiAwarenessContextsEqualFunc)(DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT);
+#endif
+
// val >= 0 todo [tav] until switch to VS'12
#define round(val) floor(val + 0.5)
diff --git a/src/windows/native/sun/windows/awt_Toolkit.cpp b/src/windows/native/sun/windows/awt_Toolkit.cpp
index 987403f..075045d 100644
--- a/src/windows/native/sun/windows/awt_Toolkit.cpp
+++ b/src/windows/native/sun/windows/awt_Toolkit.cpp
@@ -127,6 +127,10 @@
#define IDT_AWT_MOUSECHECK 0x101
+GetThreadDpiAwarenessContextFunc* AwtToolkit::lpGetThreadDpiAwarenessContext = NULL;
+SetThreadDpiAwarenessContextFunc* AwtToolkit::lpSetThreadDpiAwarenessContext = NULL;
+AreDpiAwarenessContextsEqualFunc* AwtToolkit::lpAreDpiAwarenessContextsEqual = NULL;
+
static LPCTSTR szAwtToolkitClassName = TEXT("SunAwtToolkit");
static const int MOUSE_BUTTONS_WINDOWS_SUPPORTED = 5; //three standard buttons + XBUTTON1 + XBUTTON2.
@@ -503,9 +507,33 @@
awt_dnd_initialize();
+ HMODULE hLibUser32Dll = JDK_LoadSystemLibrary("User32.dll");
+ if (hLibUser32Dll != NULL) {
+ lpGetThreadDpiAwarenessContext =
+ (GetThreadDpiAwarenessContextFunc*)GetProcAddress(hLibUser32Dll, "GetThreadDpiAwarenessContext");
+ lpSetThreadDpiAwarenessContext =
+ (SetThreadDpiAwarenessContextFunc*)GetProcAddress(hLibUser32Dll, "SetThreadDpiAwarenessContext");
+ lpAreDpiAwarenessContextsEqual =
+ (AreDpiAwarenessContextsEqualFunc*)GetProcAddress(hLibUser32Dll, "AreDpiAwarenessContextsEqual");
+ ::FreeLibrary(hLibUser32Dll);
+ }
+
return TRUE;
}
+void AwtToolkit::_UpdateToolkitDpiAwarenessContext(void* p = NULL)
+{
+ static DPI_AWARENESS_CONTEXT context = NULL;
+ if (p != NULL) context = static_cast<DPI_AWARENESS_CONTEXT>(p); // cache the last context
+
+ if (context != NULL &&
+ lpAreDpiAwarenessContextsEqual != NULL &&
+ !lpAreDpiAwarenessContextsEqual(GetToolkitDpiAwarenessContext(), context))
+ {
+ SetToolkitDpiAwarenessContext(context);
+ }
+}
+
BOOL AwtToolkit::Dispose() {
DTRACE_PRINTLN("In AwtToolkit::Dispose()");
diff --git a/src/windows/native/sun/windows/awt_Toolkit.h b/src/windows/native/sun/windows/awt_Toolkit.h
index 3782aac..aba1a20 100644
--- a/src/windows/native/sun/windows/awt_Toolkit.h
+++ b/src/windows/native/sun/windows/awt_Toolkit.h
@@ -384,6 +384,25 @@
static BOOL CALLBACK CommonPeekMessageFunc(MSG& msg);
static BOOL activateKeyboardLayout(HKL hkl);
+ static INLINE DPI_AWARENESS_CONTEXT GetToolkitDpiAwarenessContext()
+ {
+ return lpGetThreadDpiAwarenessContext != NULL ? lpGetThreadDpiAwarenessContext() : NULL;
+ }
+
+ static INLINE DPI_AWARENESS_CONTEXT SetToolkitDpiAwarenessContext(DPI_AWARENESS_CONTEXT context)
+ {
+ return lpSetThreadDpiAwarenessContext != NULL ? lpSetThreadDpiAwarenessContext(context) : NULL;
+ }
+
+ static INLINE void UpdateToolkitDpiAwarenessContext(DPI_AWARENESS_CONTEXT context = NULL)
+ {
+ if (AwtToolkit::IsMainThread()) {
+ _UpdateToolkitDpiAwarenessContext(context);
+ } else {
+ AwtToolkit::GetInstance().InvokeFunctionLater(_UpdateToolkitDpiAwarenessContext, static_cast<void*>(context));
+ }
+ }
+
HANDLE m_waitEvent;
DWORD eventNumber;
private:
@@ -430,6 +449,11 @@
CriticalSection m_Sync;
+ static GetThreadDpiAwarenessContextFunc *lpGetThreadDpiAwarenessContext;
+ static SetThreadDpiAwarenessContextFunc *lpSetThreadDpiAwarenessContext;
+ static AreDpiAwarenessContextsEqualFunc *lpAreDpiAwarenessContextsEqual;
+ static void _UpdateToolkitDpiAwarenessContext(void*);
+
/* track display changes - used by palette-updating code.
This is a workaround for a windows bug that prevents
WM_PALETTECHANGED event from occurring immediately after
diff --git a/src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp b/src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp
index e59b323..f3e90e0 100644
--- a/src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp
+++ b/src/windows/native/sun/windows/awt_Win32GraphicsDevice.cpp
@@ -696,7 +696,7 @@
pt->y = device == NULL ? pt->y : device->ScaleDownDY(pt->y);
}
-void AwtWin32GraphicsDevice::InitDesktopScales(bool fractionalScaleEnabled)
+void AwtWin32GraphicsDevice::InitDesktopScales()
{
unsigned x = 0;
unsigned y = 0;
@@ -752,8 +752,7 @@
float scaleX = dpiX / 96;
float scaleY = dpiY / 96;
- bool isFractScale = (scaleX != (int)scaleX || scaleY != (int)scaleY);
- if (scaleX > 0 && scaleY > 0 && (fractionalScaleEnabled || !isFractScale)) {
+ if (scaleX > 0 && scaleY > 0) {
SetScale(scaleX, scaleY);
}
}
@@ -1534,12 +1533,12 @@
*/
JNIEXPORT void JNICALL
Java_sun_awt_Win32GraphicsDevice_initNativeScale
-(JNIEnv *env, jobject thisPtr, jint screen, jboolean fractionalScaleEnabled)
+(JNIEnv *env, jobject thisPtr, jint screen)
{
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
if (device != NULL) {
- device->InitDesktopScales((bool)fractionalScaleEnabled);
+ device->InitDesktopScales();
}
}
\ No newline at end of file
diff --git a/src/windows/native/sun/windows/awt_Win32GraphicsDevice.h b/src/windows/native/sun/windows/awt_Win32GraphicsDevice.h
index 335a20e..b7bd33f 100644
--- a/src/windows/native/sun/windows/awt_Win32GraphicsDevice.h
+++ b/src/windows/native/sun/windows/awt_Win32GraphicsDevice.h
@@ -74,7 +74,7 @@
void Release();
void DisableOffscreenAcceleration();
void Invalidate(JNIEnv *env);
- void InitDesktopScales(bool fractionalScaleEnabled);
+ void InitDesktopScales();
void SetScale(float scaleX, float scaleY);
float GetScaleX();
float GetScaleY();
diff --git a/src/windows/native/sun/windows/awt_Win32GraphicsEnv.cpp b/src/windows/native/sun/windows/awt_Win32GraphicsEnv.cpp
index 287f684..81a367d 100644
--- a/src/windows/native/sun/windows/awt_Win32GraphicsEnv.cpp
+++ b/src/windows/native/sun/windows/awt_Win32GraphicsEnv.cpp
@@ -94,7 +94,19 @@
}
if (lpSetProcessDpiAwareness != NULL) {
+ // [tav] has no effect when called repeatedly, therefore the thread DPI_AWARENESS_CONTEXT is set
lpSetProcessDpiAwareness(level);
+ switch (level) {
+ case PROCESS_DPI_UNAWARE:
+ AwtToolkit::UpdateToolkitDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE);
+ break;
+ case PROCESS_SYSTEM_DPI_AWARE:
+ AwtToolkit::UpdateToolkitDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE);
+ break;
+ case PROCESS_PER_MONITOR_DPI_AWARE:
+ AwtToolkit::UpdateToolkitDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
+ break;
+ }
}
}
diff --git a/src/windows/native/sun/windows/awt_Window.cpp b/src/windows/native/sun/windows/awt_Window.cpp
index 152194a..810ac30 100644
--- a/src/windows/native/sun/windows/awt_Window.cpp
+++ b/src/windows/native/sun/windows/awt_Window.cpp
@@ -487,6 +487,12 @@
TweakStyle(windowStyle, windowExStyle);
+ // [tav] It has been noticed experimentally that the thread DPI_AWARENESS_CONTEXT is not passed
+ // to a new toplevel unless is set at processing of the same message which creates HWND.
+ // That is, the thread DPI_AWARENESS_CONTEXT may vary depending on the foreground toplevel.
+ // To make every toplevel inherit the same context, it's updated right before HWND creation.
+ AwtToolkit::UpdateToolkitDpiAwarenessContext();
+
AwtCanvas::CreateHWnd(env, title,
windowStyle,
windowExStyle,