< 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,171 **** 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; }; --- 151,160 ----
*** 177,190 **** 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; --- 166,175 ----
*** 1125,1164 **** window->InitOwner(awtParent); } else { // specify WS_EX_TOOLWINDOW to remove parentless windows from taskbar exStyle |= WS_EX_TOOLWINDOW; } window->CreateHWnd(env, L"", style, exStyle, ! 0, 0, 0, 0, (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); } } catch (...) { env->DeleteLocalRef(target); throw; } --- 1110,1142 ---- 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, ! x, y, width, height, (awtParent != NULL) ? awtParent->GetHWnd() : NULL, NULL, ::GetSysColor(COLOR_WINDOWTEXT), ::GetSysColor(COLOR_WINDOW), self); /* * 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(); ! window->RecalcNonClient(); } } catch (...) { env->DeleteLocalRef(target); throw; }
*** 1212,1221 **** --- 1190,1240 ---- } 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,1770 **** --- 1780,1798 ---- } } 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,1809 **** // 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(); ! } /* 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); 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)); SendComponentEvent(java_awt_event_ComponentEvent_COMPONENT_MOVED); env->DeleteLocalRef(target); return AwtComponent::WmMove(x, y); } --- 1804,1828 ---- // it's target's position since minimized Win32 windows // move to -32000, -32000 for whatever reason // NOTE: See also AwtWindow::Reshape return mrDoDefault; } ! // 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 target = GetTarget(env); RECT rect; ::GetWindowRect(GetHWnd(), &rect); ! (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,1860 **** } MsgRouting AwtWindow::WmEnterSizeMove() { m_winSizeMove = TRUE; return mrDoDefault; } MsgRouting AwtWindow::WmExitSizeMove() { m_winSizeMove = FALSE; ! CheckWindowDPIChange(); return mrDoDefault; } /* * Override AwtComponent's size handling to first update the --- 1863,1888 ---- } 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(); // workaround return mrDoDefault; } /* * Override AwtComponent's size handling to first update the
*** 1867,1892 **** if (type == SIZE_MINIMIZED) { UpdateSecurityWarningVisibility(); return mrDoDefault; } 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)); if (!AwtWindow::IsResizing()) { WindowResized(); } --- 1895,1915 ---- 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); ! (env)->SetIntField(target, AwtComponent::widthID, ScaleDownX(w)); ! (env)->SetIntField(target, AwtComponent::heightID, ScaleDownY(h)); if (!AwtWindow::IsResizing()) { WindowResized(); }
*** 1964,1973 **** --- 1987,2001 ---- { 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,2124 **** DASSERT(scrnNum > -1); return scrnNum; } ! /* Check to see if we've been moved onto another screen. * If so, update internal data, surfaces, etc. */ ! ! void AwtWindow::CheckIfOnNewScreen() { int curScrn = GetScreenImOn(); if (curScrn != m_screenNum) { // we've been moved JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); jclass peerCls = env->GetObjectClass(m_peerObject); DASSERT(peerCls); CHECK_NULL(peerCls); --- 2135,2166 ---- DASSERT(scrnNum > -1); return scrnNum; } ! /* ! * Check to see if we've been moved onto another screen. * If so, update internal data, surfaces, etc. */ ! 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,2204 **** env->DeleteLocalRef(peerCls); } } void AwtWindow::CheckWindowDPIChange() { ! ! if (prevScaleRec.screen != -1 ) { ! float prevScaleX = prevScaleRec.scaleX; ! float prevScaleY = prevScaleRec.scaleY; ! ! if (prevScaleX >= 1 && prevScaleY >= 1) { Devices::InstanceAccess devices; ! 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; 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) { 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); } BOOL AwtWindow::IsFocusableWindow() { /* * For Window/Frame/Dialog to accept focus it should: --- 2178,2218 ---- 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 && prevScaleRec.screen != m_screenNum) { Devices::InstanceAccess devices; ! AwtWin32GraphicsDevice *device = devices->GetDevice(m_screenNum); if (device) { ! if (prevScaleRec.scaleX != device->GetScaleX() ! || prevScaleRec.scaleY != device->GetScaleY()) { RECT rect; ::GetWindowRect(GetHWnd(), &rect); ! 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); } } ! prevScaleRec.screen = -1; ! prevScaleRec.scaleX = -1.0f; ! prevScaleRec.scaleY = -1.0f; ! } } BOOL AwtWindow::IsFocusableWindow() { /* * For Window/Frame/Dialog to accept focus it should:
*** 2569,2587 **** 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; --- 2583,2597 ----
*** 3244,3286 **** 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" { /* --- 3254,3263 ----
*** 3334,3348 **** 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; } --- 3311,3320 ----
*** 3974,4010 **** 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 --- 3946,3955 ----
< prev index next >