Merge branch 'MoveOutsideShortInterval' of https://github.com/catalinr/wxWidgets
Allow using positions in the entire int range for window positions under MSW, and not just those in (slightly less than) short range, that are supported by the native API. Closes #4262. Closes https://github.com/wxWidgets/wxWidgets/pull/779
This commit is contained in:
commit
2e8516c5fe
@ -91,6 +91,7 @@ wxMSW:
|
||||
- Fix handling of AUX2 mouse button events (Trylz).
|
||||
- Fix saving/restoring window position for maximized windows.
|
||||
- Fix stack corruption when using wxStackWalker (srfisk).
|
||||
- Fix positioning windows at positions >= SHORT_MAX (Cătălin Răceanu).
|
||||
|
||||
|
||||
3.1.1: (released 2018-02-19)
|
||||
|
@ -729,8 +729,27 @@ private:
|
||||
bool MSWSafeIsDialogMessage(WXMSG* msg);
|
||||
#endif // __WXUNIVERSAL__
|
||||
|
||||
#if wxUSE_DEFERRED_SIZING
|
||||
static inline bool MSWIsPositionDirectlySupported(int x, int y)
|
||||
{
|
||||
// The supported coordinate intervals for various functions are:
|
||||
// - MoveWindow, DeferWindowPos: [-32768, 32767] a.k.a. [SHRT_MIN, SHRT_MAX];
|
||||
// - CreateWindow, CreateWindowEx: [-32768, 32554].
|
||||
// CreateXXX will _sometimes_ manage to create the window at higher coordinates
|
||||
// like 32580, 32684, 32710, but that was not consistent and the lowest common
|
||||
// limit was 32554 (so far at least).
|
||||
return (x >= SHRT_MIN && x <= 32554 && y >= SHRT_MIN && y <= 32554);
|
||||
}
|
||||
|
||||
protected:
|
||||
WXHWND MSWCreateWindowAtAnyPosition(WXDWORD exStyle, const wxChar* clName,
|
||||
const wxChar* title, WXDWORD style,
|
||||
int x, int y, int width, int height,
|
||||
WXHWND parent, wxWindowID id);
|
||||
|
||||
void MSWMoveWindowToAnyPosition(WXHWND hwnd, int x, int y,
|
||||
int width, int height, bool bRepaint);
|
||||
|
||||
#if wxUSE_DEFERRED_SIZING
|
||||
// this function is called after the window was resized to its new size
|
||||
virtual void MSWEndDeferWindowPos()
|
||||
{
|
||||
|
@ -132,27 +132,19 @@ bool wxControl::MSWCreateControl(const wxChar *classname,
|
||||
// ... and adjust it to account for a possible parent frames toolbar
|
||||
AdjustForParentClientOrigin(x, y);
|
||||
|
||||
m_hWnd = (WXHWND)::CreateWindowEx
|
||||
(
|
||||
exstyle, // extended style
|
||||
classname, // the kind of control to create
|
||||
label.t_str(), // the window name
|
||||
style, // the window style
|
||||
x, y, w, h, // the window position and size
|
||||
GetHwndOf(GetParent()), // parent
|
||||
(HMENU)wxUIntToPtr(GetId()), // child id
|
||||
wxGetInstance(), // app instance
|
||||
NULL // creation parameters
|
||||
);
|
||||
m_hWnd = MSWCreateWindowAtAnyPosition
|
||||
(
|
||||
exstyle, // extended style
|
||||
classname, // the kind of control to create
|
||||
label.t_str(), // the window name
|
||||
style, // the window style
|
||||
x, y, w, h, // the window position and size
|
||||
GetHwndOf(GetParent()), // parent
|
||||
GetId() // child id
|
||||
);
|
||||
|
||||
if ( !m_hWnd )
|
||||
{
|
||||
wxLogLastError(wxString::Format
|
||||
(
|
||||
wxT("CreateWindowEx(\"%s\", flags=%08lx, ex=%08lx)"),
|
||||
classname, style, exstyle
|
||||
));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -298,19 +298,17 @@ bool wxSpinCtrl::Create(wxWindow *parent,
|
||||
|
||||
// create the text window
|
||||
|
||||
m_hwndBuddy = (WXHWND)::CreateWindowEx
|
||||
(
|
||||
exStyle, // sunken border
|
||||
wxT("EDIT"), // window class
|
||||
NULL, // no window title
|
||||
msStyle, // style (will be shown later)
|
||||
pos.x, pos.y, // position
|
||||
0, 0, // size (will be set later)
|
||||
GetHwndOf(parent), // parent
|
||||
(HMENU)-1, // control id
|
||||
wxGetInstance(), // app instance
|
||||
NULL // unused client data
|
||||
);
|
||||
m_hwndBuddy = MSWCreateWindowAtAnyPosition
|
||||
(
|
||||
exStyle, // sunken border
|
||||
wxT("EDIT"), // window class
|
||||
NULL, // no window title
|
||||
msStyle, // style (will be shown later)
|
||||
pos.x, pos.y, // position
|
||||
0, 0, // size (will be set later)
|
||||
GetHwndOf(parent), // parent
|
||||
-1 // control id
|
||||
);
|
||||
|
||||
if ( !m_hwndBuddy )
|
||||
{
|
||||
|
@ -333,7 +333,7 @@ void wxStaticBitmap::SetImageNoCopy( wxGDIImage* image)
|
||||
w = width;
|
||||
h = height;
|
||||
|
||||
::MoveWindow(GetHwnd(), x, y, width, height, FALSE);
|
||||
MSWMoveWindowToAnyPosition(GetHwnd(), x, y, width, height, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1935,38 +1935,6 @@ void wxWindowMSW::DoClientToScreen(int *x, int *y) const
|
||||
bool
|
||||
wxWindowMSW::DoMoveSibling(WXHWND hwnd, int x, int y, int width, int height)
|
||||
{
|
||||
#if wxUSE_DEFERRED_SIZING
|
||||
// if our parent had prepared a defer window handle for us, use it (unless
|
||||
// we are a top level window)
|
||||
wxWindowMSW * const parent = IsTopLevel() ? NULL : GetParent();
|
||||
|
||||
HDWP hdwp = parent ? (HDWP)parent->m_hDWP : NULL;
|
||||
if ( hdwp )
|
||||
{
|
||||
hdwp = ::DeferWindowPos(hdwp, (HWND)hwnd, NULL, x, y, width, height,
|
||||
SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
|
||||
if ( !hdwp )
|
||||
{
|
||||
wxLogLastError(wxT("DeferWindowPos"));
|
||||
}
|
||||
}
|
||||
|
||||
if ( parent )
|
||||
{
|
||||
// hdwp must be updated as it may have been changed
|
||||
parent->m_hDWP = (WXHANDLE)hdwp;
|
||||
}
|
||||
|
||||
if ( hdwp )
|
||||
{
|
||||
// did deferred move, remember new coordinates of the window as they're
|
||||
// different from what Windows would return for it
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -1986,16 +1954,70 @@ wxWindowMSW::DoMoveSibling(WXHWND hwnd, int x, int y, int width, int height)
|
||||
}
|
||||
}
|
||||
|
||||
if ( !::MoveWindow((HWND)hwnd, x, y, width, height, IsShown()) )
|
||||
#if wxUSE_DEFERRED_SIZING
|
||||
else if ( MSWIsPositionDirectlySupported(x, y) )
|
||||
{
|
||||
wxLogLastError(wxT("MoveWindow"));
|
||||
// if our parent had prepared a defer window handle for us, use it
|
||||
wxWindowMSW * const parent = GetParent();
|
||||
|
||||
HDWP hdwp = parent ? (HDWP)parent->m_hDWP : NULL;
|
||||
if ( hdwp )
|
||||
{
|
||||
hdwp = ::DeferWindowPos(hdwp, (HWND)hwnd, NULL, x, y, width, height,
|
||||
SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
|
||||
if ( !hdwp )
|
||||
{
|
||||
wxLogLastError(wxT("DeferWindowPos"));
|
||||
}
|
||||
}
|
||||
|
||||
if ( parent )
|
||||
{
|
||||
// hdwp must be updated as it may have been changed
|
||||
parent->m_hDWP = (WXHANDLE)hdwp;
|
||||
}
|
||||
|
||||
if ( hdwp )
|
||||
{
|
||||
// did deferred move, remember new coordinates of the window as they're
|
||||
// different from what Windows would return for it
|
||||
return true;
|
||||
}
|
||||
|
||||
// otherwise (or if deferring failed) move the window in place immediately
|
||||
}
|
||||
#endif // wxUSE_DEFERRED_SIZING
|
||||
|
||||
MSWMoveWindowToAnyPosition(hwnd, x, y, width, height, IsShown());
|
||||
|
||||
// if wxUSE_DEFERRED_SIZING, indicates that we didn't use deferred move,
|
||||
// ignored otherwise
|
||||
return false;
|
||||
}
|
||||
|
||||
void wxWindowMSW::MSWMoveWindowToAnyPosition(WXHWND hwnd, int x, int y, int width, int height, bool bRepaint)
|
||||
{
|
||||
bool scroll = GetParent() && !MSWIsPositionDirectlySupported(x, y);
|
||||
|
||||
if ( scroll )
|
||||
{
|
||||
// scroll to the actual position (looks like there is no need to Freeze() the parent)
|
||||
::ScrollWindow(GetHwndOf(GetParent()), -x, -y, NULL, NULL);
|
||||
}
|
||||
|
||||
// move to relative coordinates
|
||||
if ( !::MoveWindow(hwnd, (scroll ? 0 : x), (scroll ? 0 : y), width, height, bRepaint) )
|
||||
{
|
||||
wxLogLastError(wxT("MoveWindow"));
|
||||
}
|
||||
|
||||
if ( scroll )
|
||||
{
|
||||
// scroll back
|
||||
::ScrollWindow(GetHwndOf(GetParent()), x, y, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height)
|
||||
{
|
||||
// TODO: is this consistent with other platforms?
|
||||
@ -2168,15 +2190,9 @@ void wxWindowMSW::DoSetClientSize(int width, int height)
|
||||
// and not defer it here as otherwise the value returned by
|
||||
// GetClient/WindowRect() wouldn't change as the window wouldn't be
|
||||
// really resized
|
||||
if ( !::MoveWindow(GetHwnd(),
|
||||
rectWin.left,
|
||||
rectWin.top,
|
||||
width + widthWin - rectClient.right,
|
||||
height + heightWin - rectClient.bottom,
|
||||
TRUE) )
|
||||
{
|
||||
wxLogLastError(wxT("MoveWindow"));
|
||||
}
|
||||
MSWMoveWindowToAnyPosition(GetHwnd(), rectWin.left, rectWin.top,
|
||||
width + widthWin - rectClient.right,
|
||||
height + heightWin - rectClient.bottom, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3897,23 +3913,19 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
|
||||
// do create the window
|
||||
wxWindowCreationHook hook(this);
|
||||
|
||||
m_hWnd = (WXHWND)::CreateWindowEx
|
||||
(
|
||||
extendedStyle,
|
||||
wclass,
|
||||
title ? title : m_windowName.t_str(),
|
||||
style,
|
||||
x, y, w, h,
|
||||
(HWND)MSWGetParent(),
|
||||
(HMENU)wxUIntToPtr(controlId),
|
||||
wxGetInstance(),
|
||||
NULL // no extra data
|
||||
);
|
||||
m_hWnd = MSWCreateWindowAtAnyPosition
|
||||
(
|
||||
extendedStyle,
|
||||
wclass,
|
||||
title ? title : m_windowName.t_str(),
|
||||
style,
|
||||
x, y, w, h,
|
||||
MSWGetParent(),
|
||||
controlId
|
||||
);
|
||||
|
||||
if ( !m_hWnd )
|
||||
{
|
||||
wxLogSysError(_("Can't create window of class %s"), wclass);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -3922,6 +3934,32 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
|
||||
return true;
|
||||
}
|
||||
|
||||
WXHWND wxWindowMSW::MSWCreateWindowAtAnyPosition(WXDWORD exStyle, const wxChar* clName,
|
||||
const wxChar* title, WXDWORD style,
|
||||
int x, int y, int width, int height,
|
||||
WXHWND parent, wxWindowID id)
|
||||
{
|
||||
WXHWND hWnd = ::CreateWindowEx(exStyle, clName, title, style, x, y, width, height,
|
||||
parent, (HMENU)wxUIntToPtr(id), wxGetInstance(),
|
||||
NULL); // no extra data
|
||||
|
||||
if ( !hWnd )
|
||||
{
|
||||
wxLogLastError(wxString::Format
|
||||
(
|
||||
wxT("CreateWindowEx(\"%s\", flags=%08lx, ex=%08lx)"),
|
||||
clName, style, exStyle
|
||||
));
|
||||
}
|
||||
else if ( !IsTopLevel() && !MSWIsPositionDirectlySupported(x, y) )
|
||||
{
|
||||
// fix position if limited by Short range
|
||||
MSWMoveWindowToAnyPosition(hWnd, x, y, width, height, IsShown());
|
||||
}
|
||||
|
||||
return hWnd;
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// MSW message handlers
|
||||
// ===========================================================================
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "wx/app.h"
|
||||
#include "wx/window.h"
|
||||
#include "wx/button.h"
|
||||
#include "wx/sizer.h"
|
||||
#endif // WX_PRECOMP
|
||||
|
||||
#include "asserthelper.h"
|
||||
@ -49,6 +50,7 @@ private:
|
||||
CPPUNIT_TEST( Children );
|
||||
CPPUNIT_TEST( Focus );
|
||||
CPPUNIT_TEST( Positioning );
|
||||
CPPUNIT_TEST( PositioningBeyondShortLimit );
|
||||
CPPUNIT_TEST( Show );
|
||||
CPPUNIT_TEST( Enable );
|
||||
CPPUNIT_TEST( FindWindowBy );
|
||||
@ -68,6 +70,7 @@ private:
|
||||
void Children();
|
||||
void Focus();
|
||||
void Positioning();
|
||||
void PositioningBeyondShortLimit();
|
||||
void Show();
|
||||
void Enable();
|
||||
void FindWindowBy();
|
||||
@ -327,6 +330,47 @@ void WindowTestCase::Positioning()
|
||||
m_window->GetScreenRect().GetTopLeft());
|
||||
}
|
||||
|
||||
void WindowTestCase::PositioningBeyondShortLimit()
|
||||
{
|
||||
#ifdef __WXMSW__
|
||||
//Positioning under MSW is limited to short relative coordinates
|
||||
|
||||
//
|
||||
//Test window creation beyond SHRT_MAX
|
||||
int commonDim = 10;
|
||||
wxWindow* w = new wxWindow(m_window, wxID_ANY,
|
||||
wxPoint(0, SHRT_MAX + commonDim),
|
||||
wxSize(commonDim, commonDim));
|
||||
CPPUNIT_ASSERT_EQUAL(SHRT_MAX + commonDim, w->GetPosition().y);
|
||||
|
||||
w->Move(0, 0);
|
||||
|
||||
//
|
||||
//Test window moving beyond SHRT_MAX
|
||||
w->Move(0, SHRT_MAX + commonDim);
|
||||
CPPUNIT_ASSERT_EQUAL(SHRT_MAX + commonDim, w->GetPosition().y);
|
||||
|
||||
//
|
||||
//Test window moving below SHRT_MIN
|
||||
w->Move(0, SHRT_MIN - commonDim);
|
||||
CPPUNIT_ASSERT_EQUAL(SHRT_MIN - commonDim, w->GetPosition().y);
|
||||
|
||||
//
|
||||
//Test deferred move beyond SHRT_MAX
|
||||
m_window->SetVirtualSize(-1, SHRT_MAX + 2 * commonDim);
|
||||
wxWindow* bigWin = new wxWindow(m_window, wxID_ANY, wxDefaultPosition,
|
||||
//size is also limited by SHRT_MAX
|
||||
wxSize(commonDim, SHRT_MAX));
|
||||
wxSizer *sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(bigWin);
|
||||
sizer->AddSpacer(commonDim); //add some space to go beyond SHRT_MAX
|
||||
sizer->Add(w);
|
||||
m_window->SetSizer(sizer);
|
||||
m_window->Layout();
|
||||
CPPUNIT_ASSERT_EQUAL(SHRT_MAX + commonDim, w->GetPosition().y);
|
||||
#endif
|
||||
}
|
||||
|
||||
void WindowTestCase::Show()
|
||||
{
|
||||
CPPUNIT_ASSERT(m_window->IsShown());
|
||||
|
Loading…
Reference in New Issue
Block a user