]> git.saurik.com Git - wxWidgets.git/commitdiff
Worked around an apparent bug in Windows whereby some deferred positioning
authorJulian Smart <julian@anthemion.co.uk>
Thu, 28 Apr 2005 14:45:09 +0000 (14:45 +0000)
committerJulian Smart <julian@anthemion.co.uk>
Thu, 28 Apr 2005 14:45:09 +0000 (14:45 +0000)
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

docs/changes.txt
docs/latex/wx/sysopt.tex
include/wx/msw/private.h
include/wx/msw/window.h
src/msw/radiobox.cpp
src/msw/slider95.cpp
src/msw/spinctrl.cpp
src/msw/window.cpp

index a97a82e1a583273195f4f5b6ab1a20f6dc1459f4..0ca9f953bb7b9f6d791b5fd67cde98a3f88f2999 100644 (file)
@@ -11,7 +11,16 @@ All:
 
 wxMSW:
 
-- 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.
 
 wxMac:
 
index 91ffd8eba42ccced16509b1198a231b20f9b5c45..e865e2bb30b9cb12b6a9ef8f885cb691f3105338 100644 (file)
@@ -28,6 +28,9 @@ pages).}
 \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}
index a2a08d8316ba96e5779684c5114ff52b0d929ca4..f974941a3729233d212058c940a94a94d6553180 100644 (file)
@@ -701,6 +701,9 @@ inline bool wxStyleHasBorder(long style)
                      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
 // ----------------------------------------------------------------------------
index 627f4378f79d123fa4e1adef24798634ff68d2df..377afca91b5d180b5ecce87b4129505323200eaf 100644 (file)
@@ -47,6 +47,9 @@ enum
 
 class WXDLLEXPORT wxWindowMSW : public wxWindowBase
 {
+    friend class wxSpinCtrl;
+    friend class wxSlider;
+    friend class wxRadioBox;
 public:
     wxWindowMSW() { Init(); }
 
@@ -541,5 +544,17 @@ WX_DECLARE_HASH(wxWindowMSW, wxWindowList, wxWinHashTable);
 
 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;
+};
+
 #endif
     // _WX_WINDOW_H_
index c8e8ee0a6b12408cddd8f4d45e2d6af1487c357f..82c3471b219b68ee56a801423ee8c50d0385100d 100644 (file)
@@ -40,6 +40,8 @@
 
 #include "wx/msw/subwin.h"
 
+#define USE_DEFERRED_SIZING 1
+
 #if wxUSE_TOOLTIPS
     #if !defined(__GNUWIN32_OLD__) || defined(__CYGWIN10__)
         #include <commctrl.h>
@@ -545,7 +547,17 @@ void wxRadioBox::DoSetSize(int x, int y, int width, int height, int sizeFlags)
             height = heightOld;
     }
 
-    ::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
@@ -642,6 +654,22 @@ void wxRadioBox::DoSetSize(int x, int y, int width, int height, int sizeFlags)
             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;
+    }
 }
 
 // ----------------------------------------------------------------------------
@@ -687,6 +715,17 @@ wxRadioBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
 
         return 0;
     }
+    // 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);
 }
index 5db488c88c865275609ea9c10e00f9087b99af2a..7efe6d803d66d003162243c1e7247541af6e07bc 100644 (file)
@@ -42,6 +42,8 @@
     #include <commctrl.h>
 #endif
 
+#define USE_DEFERRED_SIZING 1
+
 // ----------------------------------------------------------------------------
 // constants
 // ----------------------------------------------------------------------------
@@ -441,6 +443,16 @@ void wxSlider::DoMoveWindow(int x, int y, int width, int height)
         return;
     }
 
+    // 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
@@ -453,22 +465,21 @@ void wxSlider::DoMoveWindow(int x, int y, int width, int height)
 
         // 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
-        ::MoveWindow(GetHwnd(),
+        wxMoveWindowDeferred(hdwp, this, GetHwnd(),
                      HasFlag(wxSL_LEFT) ? x : x + wLabel + HGAP,
                      y + hLabel/2,
                      width - wLabel - HGAP,
-                     height - hLabel,
-                     TRUE);
+                     height - hLabel);
     }
     else // horizontal
     {
@@ -479,22 +490,37 @@ void wxSlider::DoMoveWindow(int x, int y, int width, int height)
 
         // 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
-        ::MoveWindow(GetHwnd(),
+        wxMoveWindowDeferred(hdwp, this, GetHwnd(),
                      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;
     }
 }
 
index 02319d7e7bc947091aa0327fa7e65fca46d123db..907fb9f882865446d6115335f57d2e718bc9c4fb 100644 (file)
@@ -45,6 +45,8 @@
 
 #include <limits.h>         // for INT_MIN
 
+#define USE_DEFERRED_SIZING 1
+
 // ----------------------------------------------------------------------------
 // macros
 // ----------------------------------------------------------------------------
@@ -567,21 +569,55 @@ void wxSpinCtrl::DoMoveWindow(int x, int y, int width, int height)
         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;
-    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
 {
+    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);
@@ -595,6 +631,14 @@ void wxSpinCtrl::DoGetSize(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;
index 6fc526fac784654f5eee7e7921e9e83a67162873..b17495ed689eea6acb7edbe7b8e7438849f1e9c6 100644 (file)
     #define HAVE_TRACKMOUSEEVENT
 #endif // everything needed for TrackMouseEvent()
 
+#define USE_DEFERRED_SIZING 1
+
 // ---------------------------------------------------------------------------
 // global variables
 // ---------------------------------------------------------------------------
@@ -468,6 +470,12 @@ wxWindowMSW::~wxWindowMSW()
 {
     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() )
@@ -1443,6 +1451,14 @@ void wxWindowMSW::DoSetToolTip(wxToolTip *tooltip)
 // 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 )
@@ -1454,6 +1470,14 @@ void wxWindowMSW::DoGetSize(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 )
@@ -1546,29 +1570,31 @@ void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height)
     // 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(), x, y, width, height);
+
     if ( hdwp )
     {
-        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;
     }
-
-    // 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,
@@ -5931,6 +5957,31 @@ bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam)
 
 #endif // wxUSE_HOTKEY
 
+// 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__