From a0805d32eb7f5569476e00116c803a3c9fa089ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Va=CC=81clav=20Slavi=CC=81k?= Date: Mon, 4 Apr 2016 18:11:14 +0200 Subject: [PATCH] MSW: Fix dialog default positions under RTL locales Toplevel windows use their parent's coordinate system as the reference frame, not desktop's, so need to be adjusted accordingly if its mirrored. Without these changes, default-positioned wxDialogs would end to the right side of the parent window's right border (instead of being slightly inside the window) and changing their size would move them as well. --- src/msw/toplevel.cpp | 7 ++++--- src/msw/window.cpp | 41 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/msw/toplevel.cpp b/src/msw/toplevel.cpp index 0ddfefcbe6..62e6c91c4f 100644 --- a/src/msw/toplevel.cpp +++ b/src/msw/toplevel.cpp @@ -451,10 +451,11 @@ bool wxTopLevelWindowMSW::Create(wxWindow *parent, memset(dlgTemplate, 0, dlgsize); // these values are arbitrary, they won't be used normally anyhow - dlgTemplate->x = 34; + const LONG baseUnits = ::GetDialogBaseUnits(); + dlgTemplate->x = 34; dlgTemplate->y = 22; - dlgTemplate->cx = 144; - dlgTemplate->cy = 75; + dlgTemplate->cx = ::MulDiv(sizeReal.x, 4, LOWORD(baseUnits)); + dlgTemplate->cy = ::MulDiv(sizeReal.y, 8, HIWORD(baseUnits)); // reuse the code in MSWGetStyle() but correct the results slightly for // the dialog diff --git a/src/msw/window.cpp b/src/msw/window.cpp index b2cd66a7dc..a76d66c1f1 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -1822,6 +1822,26 @@ wxWindowMSW::DoMoveSibling(WXHWND hwnd, int x, int y, int width, int height) // otherwise (or if deferring failed) move the window in place immediately #endif // wxUSE_DEFERRED_SIZING + + // toplevel window's coordinates are mirrored if the TLW is a child of another + // RTL window and changing width without moving the position would enlarge the + // window in the wrong direction, so we need to adjust for it + if ( IsTopLevel() ) + { + // note that this may be different from GetParent() for wxDialogs + HWND tlwParent = ::GetParent((HWND)hwnd); + if ( tlwParent && (::GetWindowLong(tlwParent, GWL_EXSTYLE) & WS_EX_LAYOUTRTL) != 0 ) + { + RECT old; + ::GetWindowRect((HWND) hwnd, &old); + if ( old.left == x && old.right - old.left != width ) + { + x -= width - (old.right - old.left); + } + // else: not a simple resize + } + } + if ( !::MoveWindow((HWND)hwnd, x, y, width, height, IsShown()) ) { wxLogLastError(wxT("MoveWindow")); @@ -1967,10 +1987,25 @@ void wxWindowMSW::DoSetClientSize(int width, int height) const int widthWin = rectWin.right - rectWin.left, heightWin = rectWin.bottom - rectWin.top; - // MoveWindow positions the child windows relative to the parent, so - // adjust if necessary - if ( !IsTopLevel() ) + if ( IsTopLevel() ) { + // toplevel window's coordinates are mirrored if the TLW is a child of another + // RTL window and changing width without moving the position would enlarge the + // window in the wrong direction, so we need to adjust for it + + // note that this may be different from GetParent() for wxDialogs + HWND tlwParent = ::GetParent(GetHwnd()); + if ( tlwParent && (::GetWindowLong(tlwParent, GWL_EXSTYLE) & WS_EX_LAYOUTRTL) != 0 ) + { + const int diffWidth = width - (rectClient.right - rectClient.left); + rectWin.left -= diffWidth; + rectWin.right -= diffWidth; + } + } + else + { + // MoveWindow positions the child windows relative to the parent, so + // adjust if necessary wxWindow *parent = GetParent(); if ( parent ) {