failed: specifically when changing a position from x, to y, to x again.
Added deferred positioning to wxRadioBox, wxSlider and wxSpinCtrl and thereby
eliminated some refresh glitches when resizing.
Eliminated further refresh glitches caused by wxRadioBox (to nearby controls)
by refreshing parent when the radio box moves.
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@33907
c3d73ce0-8a6f-49c7-b76d-
6d57e0e08775
-- Fixed erroneous selection of content in wxComboBox when within a wxStaticBox.
+- Fixed erroneous selection of content in wxComboBox when within a wxStaticBox
+ (checking for selection caused by WM_STYLECHANGED).
+- Worked around an apparent bug in Windows whereby some deferred positioning
+ failed: specifically when changing a position from x, to y, to x again.
+- Added deferred positioning to wxRadioBox, wxSlider and wxSpinCtrl and thereby
+ eliminated some refresh glitches when resizing.
+- Eliminated further refresh glitches caused by wxRadioBox (to nearby controls)
+ by refreshing parent when the radio box moves.
+- Added ability set the system option "msw.staticbox.optimized-paint" to 0 to
+ allow a panel to paint graphics around controls within a static box.
\twocolitem{msw.staticbitmap.htclient}{If set to 1, allows the static bitmap to respond to mouse
events. The default is 0, since a value of 1 can interfere with refresh in static boxes. Note that once set,
this option cannot be unset later in the application.}
\twocolitem{msw.staticbitmap.htclient}{If set to 1, allows the static bitmap to respond to mouse
events. The default is 0, since a value of 1 can interfere with refresh in static boxes. Note that once set,
this option cannot be unset later in the application.}
+\twocolitem{msw.staticbox.optimized-paint}{If set to 0, switches off optimized wxStaticBox painting.
+Setting this to 0 causes more flicker, but allows applications to paint graphics on the parent of a static box
+(the optimized refresh causes any such drawing to disappear).}
\end{twocollist}
\wxheading{Mac}
\end{twocollist}
\wxheading{Mac}
wxSUNKEN_BORDER | wxDOUBLE_BORDER)) != 0;
}
wxSUNKEN_BORDER | wxDOUBLE_BORDER)) != 0;
}
+// Deferred window moving
+bool wxMoveWindowDeferred(HDWP& hdwp, wxWindow* win, HWND hWnd, int x, int y, int width, int height);
+
// ----------------------------------------------------------------------------
// functions mapping HWND to wxWindow
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// functions mapping HWND to wxWindow
// ----------------------------------------------------------------------------
class WXDLLEXPORT wxWindowMSW : public wxWindowBase
{
class WXDLLEXPORT wxWindowMSW : public wxWindowBase
{
+ friend class wxSpinCtrl;
+ friend class wxSlider;
+ friend class wxRadioBox;
public:
wxWindowMSW() { Init(); }
public:
wxWindowMSW() { Init(); }
extern wxWinHashTable *wxWinHandleHash;
extern wxWinHashTable *wxWinHandleHash;
+// ----------------------------------------------------------------------------
+// extra data needed for correcting problems with deferred positioning
+// ----------------------------------------------------------------------------
+
+struct wxExtraWindowData
+{
+ // Stored during deferred positioning
+ wxPoint m_pos;
+ wxSize m_size;
+ bool m_deferring:1;
+};
+
#include "wx/msw/subwin.h"
#include "wx/msw/subwin.h"
+#define USE_DEFERRED_SIZING 1
+
#if wxUSE_TOOLTIPS
#if !defined(__GNUWIN32_OLD__) || defined(__CYGWIN10__)
#include <commctrl.h>
#if wxUSE_TOOLTIPS
#if !defined(__GNUWIN32_OLD__) || defined(__CYGWIN10__)
#include <commctrl.h>
- ::MoveWindow(GetHwnd(), xx, yy, width, height, TRUE);
+ // if our parent had prepared a defer window handle for us, use it (unless
+ // we are a top level window)
+ wxWindowMSW *parent = GetParent();
+
+#if USE_DEFERRED_SIZING
+ HDWP hdwp = parent && !IsTopLevel() ? (HDWP)parent->m_hDWP : NULL;
+#else
+ HDWP hdwp = 0;
+#endif
+
+ wxMoveWindowDeferred(hdwp, this, GetHwnd(), xx, yy, width, height);
// Now position all the buttons: the current button will be put at
// wxPoint(x_offset, y_offset) and the new row/column will start at
// Now position all the buttons: the current button will be put at
// wxPoint(x_offset, y_offset) and the new row/column will start at
x_offset += widthBtn + cx1;
}
}
x_offset += widthBtn + cx1;
}
}
+ if (hdwp)
+ {
+ // Store the size so we can report it accurately
+ wxExtraWindowData* extraData = (wxExtraWindowData*) m_windowReserved;
+ if (!extraData)
+ {
+ extraData = new wxExtraWindowData;
+ m_windowReserved = (void*) extraData;
+ }
+ extraData->m_pos = wxPoint(xx, yy);
+ extraData->m_size = wxSize(width, height);
+ extraData->m_deferring = true;
+
+ // hdwp must be updated as it may have been changed
+ parent->m_hDWP = (WXHANDLE)hdwp;
+ }
}
// ----------------------------------------------------------------------------
}
// ----------------------------------------------------------------------------
+ // FIXME: Without this, the radiobox corrupts other controls as it moves
+ // in a dynamic layout. Refreshing causes flicker, but it's better than
+ // leaving droppings. Note that for some reason, wxStaticBox doesn't need
+ // this (perhaps because it has no real children?)
+ else if (nMsg == WM_MOVE && IsKindOf(CLASSINFO(wxRadioBox)))
+ {
+ WXLRESULT res = wxControl::MSWWindowProc(nMsg, wParam, lParam);
+ wxRect rect = GetRect();
+ GetParent()->Refresh(true, & rect);
+ return res;
+ }
return wxStaticBox::MSWWindowProc(nMsg, wParam, lParam);
}
return wxStaticBox::MSWWindowProc(nMsg, wParam, lParam);
}
#include <commctrl.h>
#endif
#include <commctrl.h>
#endif
+#define USE_DEFERRED_SIZING 1
+
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
+ // if our parent had prepared a defer window handle for us, use it (unless
+ // we are a top level window)
+ wxWindowMSW *parent = GetParent();
+
+#if USE_DEFERRED_SIZING
+ HDWP hdwp = parent && !IsTopLevel() ? (HDWP)parent->m_hDWP : NULL;
+#else
+ HDWP hdwp = 0;
+#endif
+
// be careful to position the slider itself after moving the labels as
// otherwise our GetBoundingBox(), which is called from WM_SIZE handler,
// would return a wrong result and wrong size would be cached internally
// be careful to position the slider itself after moving the labels as
// otherwise our GetBoundingBox(), which is called from WM_SIZE handler,
// would return a wrong result and wrong size would be cached internally
// position all labels: min at the top, value in the middle and max at
// the bottom
// position all labels: min at the top, value in the middle and max at
// the bottom
- ::MoveWindow((*m_labels)[SliderLabel_Min],
- xLabel, y, wLabel, hLabel, TRUE);
+ wxMoveWindowDeferred(hdwp, this, (*m_labels)[SliderLabel_Min],
+ xLabel, y, wLabel, hLabel);
- ::MoveWindow((*m_labels)[SliderLabel_Value],
- xLabel, y + (height - hLabel)/2, wLabel, hLabel, TRUE);
+ wxMoveWindowDeferred(hdwp, this, (*m_labels)[SliderLabel_Value],
+ xLabel, y + (height - hLabel)/2, wLabel, hLabel);
- ::MoveWindow((*m_labels)[SliderLabel_Max],
- xLabel, y + height - hLabel, wLabel, hLabel, TRUE);
+ wxMoveWindowDeferred(hdwp, this, (*m_labels)[SliderLabel_Max],
+ xLabel, y + height - hLabel, wLabel, hLabel);
// position the slider itself along the left/right edge
// position the slider itself along the left/right edge
- ::MoveWindow(GetHwnd(),
+ wxMoveWindowDeferred(hdwp, this, GetHwnd(),
HasFlag(wxSL_LEFT) ? x : x + wLabel + HGAP,
y + hLabel/2,
width - wLabel - HGAP,
HasFlag(wxSL_LEFT) ? x : x + wLabel + HGAP,
y + hLabel/2,
width - wLabel - HGAP,
- height - hLabel,
- TRUE);
// position all labels: min on the left, value in the middle and max to
// the right
// position all labels: min on the left, value in the middle and max to
// the right
- ::MoveWindow((*m_labels)[SliderLabel_Min],
- x, yLabel, wLabel, hLabel, TRUE);
+ wxMoveWindowDeferred(hdwp, this, (*m_labels)[SliderLabel_Min],
+ x, yLabel, wLabel, hLabel);
- ::MoveWindow((*m_labels)[SliderLabel_Value],
- x + (width - wLabel)/2, yLabel, wLabel, hLabel, TRUE);
+ wxMoveWindowDeferred(hdwp, this, (*m_labels)[SliderLabel_Value],
+ x + (width - wLabel)/2, yLabel, wLabel, hLabel);
- ::MoveWindow((*m_labels)[SliderLabel_Max],
- x + width - wLabel, yLabel, wLabel, hLabel, TRUE);
+ wxMoveWindowDeferred(hdwp, this, (*m_labels)[SliderLabel_Max],
+ x + width - wLabel, yLabel, wLabel, hLabel);
// position the slider itself along the top/bottom edge
// position the slider itself along the top/bottom edge
- ::MoveWindow(GetHwnd(),
+ wxMoveWindowDeferred(hdwp, this, GetHwnd(),
x,
HasFlag(wxSL_TOP) ? y : y + hLabel,
width,
x,
HasFlag(wxSL_TOP) ? y : y + hLabel,
width,
- height - hLabel,
- TRUE);
+ height - hLabel);
+ }
+ if ( hdwp )
+ {
+ // Store the size so we can report it accurately
+ wxExtraWindowData* extraData = (wxExtraWindowData*) m_windowReserved;
+ if (!extraData)
+ {
+ extraData = new wxExtraWindowData;
+ m_windowReserved = (void*) extraData;
+ }
+ extraData->m_pos = wxPoint(x, y);
+ extraData->m_size = wxSize(width, height);
+ extraData->m_deferring = true;
+
+ // hdwp must be updated as it may have been changed
+ parent->m_hDWP = (WXHANDLE)hdwp;
#include <limits.h> // for INT_MIN
#include <limits.h> // for INT_MIN
+#define USE_DEFERRED_SIZING 1
+
// ----------------------------------------------------------------------------
// macros
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// macros
// ----------------------------------------------------------------------------
wxLogDebug(_T("not enough space for wxSpinCtrl!"));
}
wxLogDebug(_T("not enough space for wxSpinCtrl!"));
}
- if ( !::MoveWindow(GetBuddyHwnd(), x, y, widthText, height, TRUE) )
- {
- wxLogLastError(wxT("MoveWindow(buddy)"));
- }
+ // if our parent had prepared a defer window handle for us, use it (unless
+ // we are a top level window)
+ wxWindowMSW *parent = GetParent();
+ int originalX = x;
+
+#if USE_DEFERRED_SIZING
+ HDWP hdwp = parent && !IsTopLevel() ? (HDWP)parent->m_hDWP : NULL;
+#else
+ HDWP hdwp = 0;
+#endif
+
+ // 1) The buddy window
+ wxMoveWindowDeferred(hdwp, this, GetBuddyHwnd(),
+ x, y, widthText, height);
+ // 2) The button window
x += widthText + MARGIN_BETWEEN;
x += widthText + MARGIN_BETWEEN;
- if ( !::MoveWindow(GetHwnd(), x, y, widthBtn, height, TRUE) )
+ wxMoveWindowDeferred(hdwp, this, GetHwnd(),
+ x, y, widthBtn, height);
+
+ if (hdwp)
- wxLogLastError(wxT("MoveWindow"));
+ // Store the size so we can report it accurately
+ wxExtraWindowData* extraData = (wxExtraWindowData*) m_windowReserved;
+ if (!extraData)
+ {
+ extraData = new wxExtraWindowData;
+ m_windowReserved = (void*) extraData;
+ }
+ extraData->m_pos = wxPoint(originalX, y);
+ extraData->m_size = wxSize(width, height);
+ extraData->m_deferring = true;
+
+ // hdwp must be updated as it may have been changed
+ parent->m_hDWP = (WXHANDLE)hdwp;
}
}
// get total size of the control
void wxSpinCtrl::DoGetSize(int *x, int *y) const
{
}
}
// get total size of the control
void wxSpinCtrl::DoGetSize(int *x, int *y) const
{
+ wxExtraWindowData* extraData = (wxExtraWindowData*) m_windowReserved;
+ if (extraData && extraData->m_deferring && GetParent() && GetParent()->m_hDWP)
+ {
+ *x = extraData->m_size.x;
+ *y = extraData->m_size.y;
+ return;
+ }
+
RECT spinrect, textrect, ctrlrect;
GetWindowRect(GetHwnd(), &spinrect);
GetWindowRect(GetBuddyHwnd(), &textrect);
RECT spinrect, textrect, ctrlrect;
GetWindowRect(GetHwnd(), &spinrect);
GetWindowRect(GetBuddyHwnd(), &textrect);
void wxSpinCtrl::DoGetPosition(int *x, int *y) const
{
void wxSpinCtrl::DoGetPosition(int *x, int *y) const
{
+ wxExtraWindowData* extraData = (wxExtraWindowData*) m_windowReserved;
+ if (extraData && extraData->m_deferring && GetParent() && GetParent()->m_hDWP)
+ {
+ *x = extraData->m_pos.x;
+ *y = extraData->m_pos.y;
+ return;
+ }
+
// hack: pretend that our HWND is the text control just for a moment
WXHWND hWnd = GetHWND();
wxConstCast(this, wxSpinCtrl)->m_hWnd = m_hwndBuddy;
// hack: pretend that our HWND is the text control just for a moment
WXHWND hWnd = GetHWND();
wxConstCast(this, wxSpinCtrl)->m_hWnd = m_hwndBuddy;
#define HAVE_TRACKMOUSEEVENT
#endif // everything needed for TrackMouseEvent()
#define HAVE_TRACKMOUSEEVENT
#endif // everything needed for TrackMouseEvent()
+#define USE_DEFERRED_SIZING 1
+
// ---------------------------------------------------------------------------
// global variables
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// global variables
// ---------------------------------------------------------------------------
{
m_isBeingDeleted = true;
{
m_isBeingDeleted = true;
+ if (m_windowReserved)
+ {
+ delete (wxExtraWindowData*) m_windowReserved;
+ m_windowReserved = NULL;
+ }
+
#ifndef __WXUNIVERSAL__
// VS: make sure there's no wxFrame with last focus set to us:
for ( wxWindow *win = GetParent(); win; win = win->GetParent() )
#ifndef __WXUNIVERSAL__
// VS: make sure there's no wxFrame with last focus set to us:
for ( wxWindow *win = GetParent(); win; win = win->GetParent() )
// Get total size
void wxWindowMSW::DoGetSize(int *x, int *y) const
{
// Get total size
void wxWindowMSW::DoGetSize(int *x, int *y) const
{
+ wxExtraWindowData* extraData = (wxExtraWindowData*) m_windowReserved;
+ if (extraData && extraData->m_deferring && GetParent() && GetParent()->m_hDWP)
+ {
+ *x = extraData->m_size.x;
+ *y = extraData->m_size.y;
+ return;
+ }
+
RECT rect = wxGetWindowRect(GetHwnd());
if ( x )
RECT rect = wxGetWindowRect(GetHwnd());
if ( x )
// Get size *available for subwindows* i.e. excluding menu bar etc.
void wxWindowMSW::DoGetClientSize(int *x, int *y) const
{
// Get size *available for subwindows* i.e. excluding menu bar etc.
void wxWindowMSW::DoGetClientSize(int *x, int *y) const
{
+ wxExtraWindowData* extraData = (wxExtraWindowData*) m_windowReserved;
+ if (extraData && extraData->m_deferring && GetParent() && GetParent()->m_hDWP)
+ {
+ *x = extraData->m_pos.x;
+ *y = extraData->m_pos.y;
+ return;
+ }
+
RECT rect = wxGetClientRect(GetHwnd());
if ( x )
RECT rect = wxGetClientRect(GetHwnd());
if ( x )
// if our parent had prepared a defer window handle for us, use it (unless
// we are a top level window)
wxWindowMSW *parent = GetParent();
// if our parent had prepared a defer window handle for us, use it (unless
// we are a top level window)
wxWindowMSW *parent = GetParent();
+
+#if USE_DEFERRED_SIZING
HDWP hdwp = parent && !IsTopLevel() ? (HDWP)parent->m_hDWP : NULL;
HDWP hdwp = parent && !IsTopLevel() ? (HDWP)parent->m_hDWP : NULL;
+#else
+ HDWP hdwp = 0;
+#endif
+
+ wxMoveWindowDeferred(hdwp, this, GetHwnd(), x, y, width, height);
+
- hdwp = ::DeferWindowPos(hdwp, GetHwnd(), NULL,
- x, y, width, height,
- SWP_NOZORDER);
- if ( !hdwp )
+ // Store the size so we can report it accurately
+ wxExtraWindowData* extraData = (wxExtraWindowData*) m_windowReserved;
+ if (!extraData)
- wxLogLastError(_T("DeferWindowPos"));
+ extraData = new wxExtraWindowData;
+ m_windowReserved = (void*) extraData;
+ extraData->m_pos = wxPoint(x, y);
+ extraData->m_size = wxSize(width, height);
+ extraData->m_deferring = true;
// hdwp must be updated as it may have been changed
parent->m_hDWP = (WXHANDLE)hdwp;
}
// hdwp must be updated as it may have been changed
parent->m_hDWP = (WXHANDLE)hdwp;
}
-
- // otherwise (or if deferring failed) move the window in place immediately
- if ( !hdwp )
- {
- if ( !::MoveWindow(GetHwnd(), x, y, width, height, IsShown()) )
- {
- wxLogLastError(wxT("MoveWindow"));
- }
- }
}
// set the size of the window: if the dimensions are positive, just use them,
}
// set the size of the window: if the dimensions are positive, just use them,
+// Moves a window by deferred method or normal method
+bool wxMoveWindowDeferred(HDWP& hdwp, wxWindow* win, HWND hWnd, int x, int y, int width, int height)
+{
+ if ( hdwp )
+ {
+ hdwp = ::DeferWindowPos(hdwp, hWnd, NULL,
+ x, y, width, height,
+ SWP_NOZORDER);
+ if ( !hdwp )
+ {
+ wxLogLastError(_T("DeferWindowPos"));
+ }
+ }
+
+ // otherwise (or if deferring failed) move the window in place immediately
+ if ( !hdwp )
+ {
+ if ( !::MoveWindow(hWnd, x, y, width, height, win->IsShown()) )
+ {
+ wxLogLastError(wxT("MoveWindow"));
+ }
+ }
+ return hdwp != NULL;
+}
+
// Not tested under WinCE
#ifndef __WXWINCE__
// Not tested under WinCE
#ifndef __WXWINCE__