modules/graphics/src/main/native-glass/win/GlassWindow.cpp

Print this page

        

@@ -648,38 +648,80 @@
 
 void GlassWindow::HandleDPIEvent(WPARAM wParam, LPARAM lParam) {
     UINT xDPI = LOWORD(wParam);
     UINT yDPI = HIWORD(wParam);
 
-//    fprintf(stderr, "DPI Changed (=> %d, %d)!\n", yDPI, xDPI);
     JNIEnv* env = GetEnv();
-    jfloat newUIScale = GlassApplication::GetUIScale(xDPI);
-    jfloat newRenderScale = GlassApplication::getRenderScale(newUIScale);
-    env->CallVoidMethod(m_grefThis, midNotifyScaleChanged, newUIScale, newRenderScale);
+    jfloat xScale = xDPI / 96.0f;
+    jfloat yScale = yDPI / 96.0f;
+    env->CallVoidMethod(m_grefThis, midNotifyScaleChanged, xScale, yScale, xScale, yScale);
     CheckAndClearException(env);
 
-    LPRECT lprcNewScale = (LPRECT) lParam;
-#if 0
-    RECT oldBounds, oldClient;
+    // Windows provides new bounds for the window, but they assume that
+    // all parts (client and non-client) will be rescaled equally.
+    // Unfortunately, the basic window decoration support does not scale
+    // so we need to adjust the new bounds to represent the new intended
+    // client dimensions padded for the unchanging frame border.
+    LPRECT lprcNewBounds = (LPRECT) lParam;
+    RECT oldBounds, oldClient, padding, newClient, newBounds;
     ::GetWindowRect(GetHWND(), &oldBounds);
     ::GetClientRect(GetHWND(), &oldClient);
+    float rescaleX = ((float) (lprcNewBounds->right - lprcNewBounds->left)) /
+                              (oldBounds.right - oldBounds.left);
+    float rescaleY = ((float) (lprcNewBounds->bottom - lprcNewBounds->top)) /
+                              (oldBounds.bottom - oldBounds.top);
+
+    // First compute the padding between non-client and client for the old
+    // values for the window.  This is the size of the frame border
+    // decorations.  These will remain unchanged after the change in DPI.
+    padding.left   = oldClient.left   - oldBounds.left;
+    padding.top    = oldClient.top    - oldBounds.top;
+    padding.right  = oldBounds.right  - oldClient.right;
+    padding.bottom = oldBounds.bottom - oldClient.bottom;
+
+    // Next compute the correctly scaled new dimensions for the client
+    // area, based on the ratio of the old window bounds to the suggested
+    // new window bounds.
+    jint newClientW = (jint) ceil((oldClient.right - oldClient.left) * rescaleX);
+    jint newClientH = (jint) ceil((oldClient.bottom - oldClient.top) * rescaleY);
+
+    // Next compute the new client bounds implied by the values provided by
+    // the WM event data
+    newClient.left   = lprcNewBounds->left   + padding.left;
+    newClient.top    = lprcNewBounds->top    + padding.top;
+    newClient.right  = newClient.left + newClientW;
+    newClient.bottom = newClient.top  + newClientH;
+
+    // Finally, compute the new bounds of the window by padding out the
+    // correctly scaled new client region.
+    newBounds.left   = newClient.left   - padding.left;
+    newBounds.top    = newClient.top    - padding.top;
+    newBounds.right  = newClient.right  + padding.right;
+    newBounds.bottom = newClient.bottom + padding.bottom;
+#if 0
     POINT cursor;
     ::GetCursorPos(&cursor);
     fprintf(stderr, "    @ %d, %d\n", cursor.x, cursor.y);
-    fprintf(stderr, "    (%d, %d, %d, %d) [%d x %d] in (%d, %d, %d, %d) [%d x %d] => (%d, %d, %d, %d) [%d x %d]\n",
+    fprintf(stderr, "    (%d, %d, %d, %d) [%d x %d] in (%d, %d, %d, %d) [%d x %d]\n",
             oldClient.left, oldClient.top, oldClient.right, oldClient.bottom,
             oldClient.right - oldClient.left, oldClient.bottom - oldClient.top,
             oldBounds.left, oldBounds.top, oldBounds.right, oldBounds.bottom,
-            oldBounds.right - oldBounds.left, oldBounds.bottom - oldBounds.top,
-            lprcNewScale->left, lprcNewScale->top, lprcNewScale->right, lprcNewScale->bottom,
-            lprcNewScale->right - lprcNewScale->left, lprcNewScale->bottom - lprcNewScale->top);
+            oldBounds.right - oldBounds.left, oldBounds.bottom - oldBounds.top);
+    fprintf(stderr, "    => (suggested) (%d, %d, %d, %d) [%d x %d]\n",
+            lprcNewBounds->left,   lprcNewBounds->top,  lprcNewBounds->right,   lprcNewBounds->bottom,
+            lprcNewBounds->right - lprcNewBounds->left, lprcNewBounds->bottom - lprcNewBounds->top);
+    fprintf(stderr, "    => (recomputed) (%d, %d, %d, %d) [%d x %d] in (%d, %d, %d, %d) [%d x %d]\n",
+            newClient.left,   newClient.top,  newClient.right,   newClient.bottom,
+            newClient.right - newClient.left, newClient.bottom - newClient.top,
+            newBounds.left,   newBounds.top,  newBounds.right,   newBounds.bottom,
+            newBounds.right - newBounds.left, newBounds.bottom - newBounds.top);
 #endif
     ::SetWindowPos(GetHWND(), HWND_TOP,
-                   lprcNewScale->left,
-                   lprcNewScale->top,
-                   lprcNewScale->right - lprcNewScale->left,
-                   lprcNewScale->bottom - lprcNewScale->top,
+                   newBounds.left,
+                   newBounds.top,
+                   newBounds.right  - newBounds.left,
+                   newBounds.bottom - newBounds.top,
                    SWP_NOZORDER | SWP_NOACTIVATE);
 }
 
 void GlassWindow::HandleWindowPosChangedEvent()
 {

@@ -1094,11 +1136,11 @@
 
      midNotifyResize = env->GetMethodID(cls, "notifyResize", "(III)V");
      ASSERT(midNotifyResize);
      if (env->ExceptionCheck()) return;
 
-     midNotifyScaleChanged = env->GetMethodID(cls, "notifyScaleChanged", "(FF)V");
+     midNotifyScaleChanged = env->GetMethodID(cls, "notifyScaleChanged", "(FFFF)V");
      ASSERT(midNotifyScaleChanged);
      if (env->ExceptionCheck()) return;
 
      javaIDs.Window.notifyFocus = env->GetMethodID(cls, "notifyFocus", "(I)V");
      ASSERT(javaIDs.Window.notifyFocus);