< prev index next >
src/java.desktop/windows/native/libawt/windows/awt_Window.cpp
Print this page
rev 60071 : 8211999: Window positioning bugs due to overlapping GraphicsDevice bounds (Windows/HiDPI)
Reviewed-by: XXX
@@ -151,21 +151,10 @@
struct SetFullScreenExclusiveModeStateStruct {
jobject window;
jboolean isFSEMState;
};
-// struct for _WindowDPIChange() method
-struct ScaleStruct {
- jobject window;
- jint prevScreen;
- jfloat prevScaleX;
- jfloat prevScaleY;
- jint screen;
- jfloat scaleX;
- jfloat scaleY;
-};
-
struct OverrideHandle {
jobject frame;
HWND handle;
};
@@ -177,14 +166,10 @@
jfieldID AwtWindow::locationByPlatformID;
jfieldID AwtWindow::autoRequestFocusID;
jfieldID AwtWindow::securityWarningWidthID;
jfieldID AwtWindow::securityWarningHeightID;
-jfieldID AwtWindow::sysXID;
-jfieldID AwtWindow::sysYID;
-jfieldID AwtWindow::sysWID;
-jfieldID AwtWindow::sysHID;
jfieldID AwtWindow::windowTypeID;
jmethodID AwtWindow::getWarningStringMID;
jmethodID AwtWindow::calculateSecurityWarningPositionMID;
jmethodID AwtWindow::windowTypeNameMID;
@@ -1125,40 +1110,33 @@
window->InitOwner(awtParent);
} else {
// specify WS_EX_TOOLWINDOW to remove parentless windows from taskbar
exStyle |= WS_EX_TOOLWINDOW;
}
+ jint x = env->GetIntField(target, AwtComponent::xID);
+ jint y = env->GetIntField(target, AwtComponent::yID);
+ jint width = env->GetIntField(target, AwtComponent::widthID);
+ jint height = env->GetIntField(target, AwtComponent::heightID);
+
window->CreateHWnd(env, L"",
style, exStyle,
- 0, 0, 0, 0,
+ x, y, width, height,
(awtParent != NULL) ? awtParent->GetHWnd() : NULL,
NULL,
::GetSysColor(COLOR_WINDOWTEXT),
::GetSysColor(COLOR_WINDOW),
self);
-
- jint x = env->GetIntField(target, AwtComponent::xID);
- jint y = env->GetIntField(target, AwtComponent::yID);
- jint width = env->GetIntField(target, AwtComponent::widthID);
- jint height = env->GetIntField(target, AwtComponent::heightID);
-
/*
* Initialize icon as inherited from parent if it exists
*/
if (parent != NULL) {
window->m_hIcon = awtParent->GetHIcon();
window->m_hIconSm = awtParent->GetHIconSm();
window->m_iconInherited = TRUE;
}
window->DoUpdateIcon();
-
-
- /*
- * Reshape here instead of during create, so that a WM_NCCALCSIZE
- * is sent.
- */
- window->Reshape(x, y, width, height);
+ window->RecalcNonClient();
}
} catch (...) {
env->DeleteLocalRef(target);
throw;
}
@@ -1212,10 +1190,51 @@
}
VERIFY(::DestroyWindow(boggy));
VERIFY(::SetWindowPos(GetHWnd(), NULL, defLoc.left, defLoc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER));
}
+/**
+ * Override AwtComponent::Reshape() to handle absolute screen coordinates used
+ * by the top-level windows.
+ */
+void AwtWindow::Reshape(int x, int y, int w, int h) {
+ if (IsEmbeddedFrame()) {
+ // Not the "real" top level window
+ return AwtComponent::Reshape(x, y, w, h);
+ }
+ // Yes, use x,y in user's space to find the nearest monitor in device space.
+ POINT pt = {x + w / 2, y + h / 2};
+ Devices::InstanceAccess devices;
+ HMONITOR monitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
+ int screen = AwtWin32GraphicsDevice::GetScreenFromHMONITOR(monitor);
+ AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
+ // Try set the correct size and jump to the correct location, even if it is
+ // on the different monitor. Note that for the "size" we use the current
+ // monitor, so the WM_DPICHANGED will adjust it for the "target" monitor.
+ ReshapeNoScale(device->ScaleUpAbsX(x), device->ScaleUpAbsY(y),
+ ScaleUpX(w), ScaleUpY(h));
+ // The window manager may tweak the size for different reasons, so try
+ // to make sure our window has the correct size in the user's space.
+ // NOOP if the size was changed already or changing is in progress.
+ RECT rc;
+ ::GetWindowRect(GetHWnd(), &rc);
+ ReshapeNoScale(rc.left, rc.top, ScaleUpX(w), ScaleUpY(h));
+ // the window manager may ignore our "SetWindowPos" request, in this,
+ // case the WmMove/WmSize will not come and we need to manually resync
+ // the "java.awt.Window" locations, because "java.awt.Window" already
+ // uses location ignored by the window manager.
+ ::GetWindowRect(GetHWnd(), &rc);
+ if (x != ScaleDownAbsX(rc.left) || y != ScaleDownAbsY(rc.top)) {
+ WmMove(rc.left, rc.top);
+ }
+ int userW = ScaleDownX(rc.right - rc.left);
+ int userH = ScaleDownY(rc.bottom - rc.top);
+ if (w != userW || h != userH) {
+ WmSize(SIZENORMAL, rc.right - rc.left, rc.bottom - rc.top);
+ }
+}
+
void AwtWindow::Show()
{
m_visible = true;
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
BOOL done = false;
@@ -1761,10 +1780,19 @@
}
}
return AwtCanvas::WmShowWindow(show, status);
}
+void AwtWindow::WmDPIChanged(const LPARAM &lParam) {
+ // need to update the scales now, otherwise the ReshapeNoScale() will
+ // calculate the bounds wrongly
+ AwtWin32GraphicsDevice::ResetAllDesktopScales();
+ RECT *r = (RECT *) lParam;
+ ReshapeNoScale(r->left, r->top, r->right - r->left, r->bottom - r->top);
+ CheckIfOnNewScreen(true);
+}
+
/*
* Override AwtComponent's move handling to first update the
* java AWT target's position fields directly, since Windows
* and below can be resized from outside of java (by user)
*/
@@ -1776,34 +1804,25 @@
// it's target's position since minimized Win32 windows
// move to -32000, -32000 for whatever reason
// NOTE: See also AwtWindow::Reshape
return mrDoDefault;
}
-
- if (m_screenNum == -1) {
- // Set initial value
- m_screenNum = GetScreenImOn();
- }
- else {
- CheckIfOnNewScreen();
- }
+ // Check for the new screen and update the java peer
+ CheckIfOnNewScreen(false); // postpone if different DPI
/* Update the java AWT target component's fields directly */
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
if (env->EnsureLocalCapacity(1) < 0) {
return mrConsume;
}
- jobject peer = GetPeer(env);
- jobject target = env->GetObjectField(peer, AwtObject::targetID);
+ jobject target = GetTarget(env);
RECT rect;
::GetWindowRect(GetHWnd(), &rect);
- (env)->SetIntField(target, AwtComponent::xID, ScaleDownX(rect.left));
- (env)->SetIntField(target, AwtComponent::yID, ScaleDownY(rect.top));
- (env)->SetIntField(peer, AwtWindow::sysXID, ScaleDownX(rect.left));
- (env)->SetIntField(peer, AwtWindow::sysYID, ScaleDownY(rect.top));
+ (env)->SetIntField(target, AwtComponent::xID, ScaleDownAbsX(rect.left));
+ (env)->SetIntField(target, AwtComponent::yID, ScaleDownAbsY(rect.top));
SendComponentEvent(java_awt_event_ComponentEvent_COMPONENT_MOVED);
env->DeleteLocalRef(target);
return AwtComponent::WmMove(x, y);
}
@@ -1844,17 +1863,26 @@
}
MsgRouting AwtWindow::WmEnterSizeMove()
{
m_winSizeMove = TRUE;
+ // Below is a workaround, see CheckWindowDPIChange
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice* device = devices->GetDevice(m_screenNum);
+ if (device) {
+ prevScaleRec.screen = m_screenNum;
+ prevScaleRec.scaleX = device->GetScaleX();
+ prevScaleRec.scaleY = device->GetScaleY();
+ }
+ // Above is a workaround
return mrDoDefault;
}
MsgRouting AwtWindow::WmExitSizeMove()
{
m_winSizeMove = FALSE;
- CheckWindowDPIChange();
+ CheckWindowDPIChange(); // workaround
return mrDoDefault;
}
/*
* Override AwtComponent's size handling to first update the
@@ -1867,26 +1895,21 @@
if (type == SIZE_MINIMIZED) {
UpdateSecurityWarningVisibility();
return mrDoDefault;
}
+ // Check for the new screen and update the java peer
+ CheckIfOnNewScreen(false); // postpone if different DPI
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
if (env->EnsureLocalCapacity(1) < 0)
return mrDoDefault;
jobject target = GetTarget(env);
// fix 4167248 : ensure the insets are up-to-date before using
BOOL insetsChanged = UpdateInsets(NULL);
- int newWidth = w + m_insets.left + m_insets.right;
- int newHeight = h + m_insets.top + m_insets.bottom;
-
- (env)->SetIntField(target, AwtComponent::widthID, ScaleDownX(newWidth));
- (env)->SetIntField(target, AwtComponent::heightID, ScaleDownY(newHeight));
-
- jobject peer = GetPeer(env);
- (env)->SetIntField(peer, AwtWindow::sysWID, ScaleDownX(newWidth));
- (env)->SetIntField(peer, AwtWindow::sysHID, ScaleDownY(newHeight));
+ (env)->SetIntField(target, AwtComponent::widthID, ScaleDownX(w));
+ (env)->SetIntField(target, AwtComponent::heightID, ScaleDownY(h));
if (!AwtWindow::IsResizing()) {
WindowResized();
}
@@ -1964,10 +1987,15 @@
{
MsgRouting mr = mrDoDefault;
LRESULT retValue = 0L;
switch(message) {
+ case WM_DPICHANGED: {
+ WmDPIChanged(lParam);
+ mr = mrConsume;
+ break;
+ }
case WM_GETICON:
mr = WmGetIcon(wParam, retValue);
break;
case WM_SYSCOMMAND:
//Fixed 6355340: Contents of frame are not layed out properly on maximize
@@ -2107,18 +2135,32 @@
DASSERT(scrnNum > -1);
return scrnNum;
}
-/* Check to see if we've been moved onto another screen.
+/*
+ * Check to see if we've been moved onto another screen.
* If so, update internal data, surfaces, etc.
*/
-
-void AwtWindow::CheckIfOnNewScreen() {
+void AwtWindow::CheckIfOnNewScreen(BOOL force) {
int curScrn = GetScreenImOn();
if (curScrn != m_screenNum) { // we've been moved
+ // if moved from one monitor to another with different DPI, we should
+ // update the m_screenNum only if the size was updated as well in the
+ // WM_DPICHANGED.
+ Devices::InstanceAccess devices;
+ AwtWin32GraphicsDevice* oldDevice = devices->GetDevice(m_screenNum);
+ AwtWin32GraphicsDevice* newDevice = devices->GetDevice(curScrn);
+ if (!force && m_winSizeMove && oldDevice && newDevice) {
+ if (oldDevice->GetScaleX() != newDevice->GetScaleX()
+ || oldDevice->GetScaleY() != newDevice->GetScaleY()) {
+ // scales are different, wait for WM_DPICHANGED
+ return;
+ }
+ }
+
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
jclass peerCls = env->GetObjectClass(m_peerObject);
DASSERT(peerCls);
CHECK_NULL(peerCls);
@@ -2136,69 +2178,41 @@
env->DeleteLocalRef(peerCls);
}
}
+// The shared code is not ready to the top-level window which crosses a few
+// monitors with different DPI. Popup windows will start to use wrong screen,
+// will be placed in the wrong place and will be use wrong size, see 8249164
+// So we will "JUMP TO" the new screen.
void AwtWindow::CheckWindowDPIChange() {
-
- if (prevScaleRec.screen != -1 ) {
- float prevScaleX = prevScaleRec.scaleX;
- float prevScaleY = prevScaleRec.scaleY;
-
- if (prevScaleX >= 1 && prevScaleY >= 1) {
+ if (prevScaleRec.screen != -1 && prevScaleRec.screen != m_screenNum) {
Devices::InstanceAccess devices;
- AwtWin32GraphicsDevice* device = devices->GetDevice(m_screenNum);
+ AwtWin32GraphicsDevice *device = devices->GetDevice(m_screenNum);
if (device) {
- float scaleX = device->GetScaleX();
- float scaleY = device->GetScaleY();
- if (prevScaleX != scaleX || prevScaleY != scaleY) {
- WindowDPIChange(prevScaleRec.screen, prevScaleX, prevScaleY,
- m_screenNum, scaleX, scaleY);
- }
- }
- }
- prevScaleRec.screen = -1;
- }
-}
-
-void AwtWindow::WindowDPIChange(int prevScreen,
- float prevScaleX, float prevScaleY,
- int screen, float scaleX,
- float scaleY)
-{
- int x;
- int y;
- int w;
- int h;
+ if (prevScaleRec.scaleX != device->GetScaleX()
+ || prevScaleRec.scaleY != device->GetScaleY()) {
RECT rect;
-
- if (prevScaleX == scaleX && prevScaleY == scaleY) {
- return;
- }
-
::GetWindowRect(GetHWnd(), &rect);
- x = rect.left;
- y = rect.top;
- w = (rect.right - rect.left) * scaleX / prevScaleX;
- h = (rect.bottom - rect.top) * scaleY / prevScaleY;
-
- if (prevScreen != screen) {
- Devices::InstanceAccess devices;
- AwtWin32GraphicsDevice* device = devices->GetDevice(screen);
- if (device) {
+ int x = rect.left;
+ int y = rect.top;
+ int w = rect.right - rect.left;
+ int h = rect.bottom - rect.top;
RECT bounds;
if (MonitorBounds(device->GetMonitor(), &bounds)) {
x = x < bounds.left ? bounds.left : x;
y = y < bounds.top ? bounds.top : y;
-
x = (x + w > bounds.right) ? bounds.right - w : x;
y = (y + h > bounds.bottom) ? bounds.bottom - h : y;
}
+ ReshapeNoScale(x, y, w, h);
}
}
-
- ReshapeNoScale(x, y, w, h);
+ prevScaleRec.screen = -1;
+ prevScaleRec.scaleX = -1.0f;
+ prevScaleRec.scaleY = -1.0f;
+ }
}
BOOL AwtWindow::IsFocusableWindow() {
/*
* For Window/Frame/Dialog to accept focus it should:
@@ -2569,19 +2583,15 @@
int minHeight = p->ScaleDownY(::GetSystemMetrics(SM_CYMIN));
if (w < minWidth)
{
env->SetIntField(target, AwtComponent::widthID,
w = minWidth);
- env->SetIntField(peer, AwtWindow::sysWID,
- w);
}
if (h < minHeight)
{
env->SetIntField(target, AwtComponent::heightID,
h = minHeight);
- env->SetIntField(peer, AwtWindow::sysHID,
- h);
}
}
env->DeleteLocalRef(target);
RECT *r = new RECT;
@@ -3244,43 +3254,10 @@
ss->h = rc.bottom - rc.top;
env->DeleteGlobalRef(self);
}
-void AwtWindow::_WindowDPIChange(void* param)
-{
- JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
-
- ScaleStruct *ss = (ScaleStruct *)param;
- jobject self = ss->window;
- jint prevScreen = ss->prevScreen;
- jfloat prevScaleX = ss->prevScaleX;
- jfloat prevScaleY = ss->prevScaleY;
- jint screen = ss->screen;
- jfloat scaleX = ss->scaleX;
- jfloat scaleY = ss->scaleY;
-
- PDATA pData;
- JNI_CHECK_PEER_GOTO(self, ret);
- AwtWindow *window = (AwtWindow *)pData;
-
- if (window->m_winSizeMove) {
- if (window->prevScaleRec.screen == -1) {
- window->prevScaleRec.screen = prevScreen;
- window->prevScaleRec.scaleX = prevScaleX;
- window->prevScaleRec.scaleY = prevScaleY;
- }
- }
- else {
- window->WindowDPIChange(prevScreen, prevScaleX, prevScaleY,
- screen, scaleX, scaleY);
- }
-
-ret:
- env->DeleteGlobalRef(self);
- delete ss;
-}
extern "C" int getSystemMetricValue(int msgType);
extern "C" {
/*
@@ -3334,15 +3311,10 @@
JNIEXPORT void JNICALL
Java_sun_awt_windows_WWindowPeer_initIDs(JNIEnv *env, jclass cls)
{
TRY;
- CHECK_NULL(AwtWindow::sysXID = env->GetFieldID(cls, "sysX", "I"));
- CHECK_NULL(AwtWindow::sysYID = env->GetFieldID(cls, "sysY", "I"));
- CHECK_NULL(AwtWindow::sysWID = env->GetFieldID(cls, "sysW", "I"));
- CHECK_NULL(AwtWindow::sysHID = env->GetFieldID(cls, "sysH", "I"));
-
AwtWindow::windowTypeID = env->GetFieldID(cls, "windowType",
"Ljava/awt/Window$Type;");
CATCH_BAD_ALLOC;
}
@@ -3974,37 +3946,10 @@
CATCH_BAD_ALLOC;
}
/*
-* Class: sun_awt_windows_WWindowPeer
-* Method: windowDPIChange
-* Signature: (IFFIFF)V
-*/
-JNIEXPORT void JNICALL
-Java_sun_awt_windows_WWindowPeer_windowDPIChange(JNIEnv *env, jobject self,
- jint prevScreen, jfloat prevScaleX, jfloat prevScaleY,
- jint screen, jfloat scaleX, jfloat scaleY)
-{
- TRY;
-
- ScaleStruct *ss = new ScaleStruct;
- ss->window = env->NewGlobalRef(self);
- ss->prevScreen = prevScreen;
- ss->prevScaleX = prevScaleX;
- ss->prevScaleY = prevScaleY;
- ss->screen = screen;
- ss->scaleX = scaleX;
- ss->scaleY = scaleY;
-
- AwtToolkit::GetInstance().InvokeFunction(AwtWindow::_WindowDPIChange, ss);
- // global refs and ss are deleted in _WindowDPIChange
-
- CATCH_BAD_ALLOC;
-}
-
-/*
* Class: sun_awt_windows_WLightweightFramePeer
* Method: overrideNativeHandle
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_sun_awt_windows_WLightweightFramePeer_overrideNativeHandle
< prev index next >