]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/window.cpp
fixing focus, fixes #11911
[wxWidgets.git] / src / msw / window.cpp
index ed1076ccfa4405b6cc57c267ca07e2546ad4ba45..da62175805dfcb6b06a7923017254dd9b0182a54 100644 (file)
 extern wxMenu *wxCurrentPopupMenu;
 #endif
 
+namespace
+{
+
 // true if we had already created the std colour map, used by
 // wxGetStdColourMap() and wxWindow::OnSysColourChanged()           (FIXME-MT)
-static bool gs_hasStdCmap = false;
+bool gs_hasStdCmap = false;
 
 // last mouse event information we need to filter out the duplicates
 #if wxUSE_MOUSEEVENT_HACK
-static struct MouseEventInfoDummy
+struct MouseEventInfoDummy
 {
     // mouse position (in screen coordinates)
     wxPoint pos;
@@ -194,14 +197,29 @@ WX_DECLARE_HASH_MAP(int, wxWindow::MSWMessageHandler,
                     wxIntegerHash, wxIntegerEqual,
                     MSWMessageHandlers);
 
-static MSWMessageHandlers gs_messageHandlers;
+MSWMessageHandlers gs_messageHandlers;
 
 // hash containing all our windows, it uses HWND keys and wxWindow* values
 WX_DECLARE_HASH_MAP(HWND, wxWindow *,
                     wxPointerHash, wxPointerEqual,
                     WindowHandles);
 
-static WindowHandles gs_windowHandles;
+WindowHandles gs_windowHandles;
+
+#ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK
+
+// temporary override for WM_ERASEBKGND processing: we don't store this in
+// wxWindow itself as we don't need it during most of the time so don't
+// increase the size of all window objects unnecessarily
+WX_DECLARE_HASH_MAP(wxWindow *, wxWindow *,
+                    wxPointerHash, wxPointerEqual,
+                    EraseBgHooks);
+
+EraseBgHooks gs_eraseBgHooks;
+
+#endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
+
+} // anonymous namespace
 
 // ---------------------------------------------------------------------------
 // private functions
@@ -2320,7 +2338,7 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
             // combinations which are always processed)
             LONG lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0);
 
-            // surprizingly, DLGC_WANTALLKEYS bit mask doesn't contain the
+            // surprisingly, DLGC_WANTALLKEYS bit mask doesn't contain the
             // DLGC_WANTTAB nor DLGC_WANTARROWS bits although, logically,
             // it, of course, implies them
             if ( lDlgCode & DLGC_WANTALLKEYS )
@@ -3269,7 +3287,17 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
             break;
 
         case WM_ERASEBKGND:
-            processed = HandleEraseBkgnd((WXHDC)wParam);
+            {
+#ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK
+                // check if an override was configured for this window
+                EraseBgHooks::const_iterator it = gs_eraseBgHooks.find(this);
+                if ( it != gs_eraseBgHooks.end() )
+                    processed = it->second->MSWEraseBgHook((WXHDC)wParam);
+                else
+#endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
+                    processed = HandleEraseBkgnd((WXHDC)wParam);
+            }
+
             if ( processed )
             {
                 // we processed the message, i.e. erased the background
@@ -4196,6 +4224,8 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
             y = pt.y;
         ScreenToClient(&x, &y);
         wxSetCursorEvent event(x, y);
+        event.SetId(GetId());
+        event.SetEventObject(this);
 
         bool processedEvtSetCursor = HandleWindowEvent(event);
         if ( processedEvtSetCursor && event.HasCursor() )
@@ -4711,7 +4741,7 @@ wxColour wxWindowMSW::MSWGetThemeColour(const wchar_t *themeName,
                                         int themePart,
                                         int themeState,
                                         MSWThemeColour themeColour,
-                                        wxSystemColour fallback)
+                                        wxSystemColour fallback) const
 {
 #if wxUSE_UXTHEME
     const wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive();
@@ -4735,7 +4765,7 @@ wxColour wxWindowMSW::MSWGetThemeColour(const wchar_t *themeName,
                 wxFAIL_MSG(wxT("unsupported theme colour"));
         };
 
-        wxUxThemeHandle hTheme(this, themeName);
+        wxUxThemeHandle hTheme((const wxWindow *)this, themeName);
         COLORREF col;
         HRESULT hr = theme->GetThemeColor
                             (
@@ -4768,6 +4798,15 @@ wxColour wxWindowMSW::MSWGetThemeColour(const wchar_t *themeName,
 // painting
 // ---------------------------------------------------------------------------
 
+// this variable is used to check that a paint event handler which processed
+// the event did create a wxPaintDC inside its code and called BeginPaint() to
+// validate the invalidated window area as otherwise we'd keep getting an
+// endless stream of WM_PAINT messages for this window resulting in a lot of
+// difficult to debug problems (e.g. impossibility to repaint other windows,
+// lack of timer and idle events and so on)
+extern bool wxDidCreatePaintDC;
+bool wxDidCreatePaintDC = false;
+
 bool wxWindowMSW::HandlePaint()
 {
     HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle
@@ -4782,11 +4821,20 @@ bool wxWindowMSW::HandlePaint()
 
     m_updateRegion = wxRegion((WXHRGN) hRegion);
 
+    wxDidCreatePaintDC = false;
+
     wxPaintEvent event(m_windowId);
     event.SetEventObject(this);
 
     bool processed = HandleWindowEvent(event);
 
+    if ( processed && !wxDidCreatePaintDC )
+    {
+        // do call MSWDefWindowProc() to validate the update region to avoid
+        // the problems mentioned above
+        processed = false;
+    }
+
     // note that we must generate NC event after the normal one as otherwise
     // BeginPaint() will happily overwrite our decorations with the background
     // colour
@@ -4867,13 +4915,47 @@ bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc)
     return true;
 }
 
+#ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK
+
+bool wxWindowMSW::MSWHasEraseBgHook() const
+{
+    return gs_eraseBgHooks.find(this) != gs_eraseBgHooks.end();
+}
+
+void wxWindowMSW::MSWSetEraseBgHook(wxWindow *child)
+{
+    if ( child )
+    {
+        if ( !gs_eraseBgHooks.insert(
+                EraseBgHooks::value_type(this, child)).second )
+        {
+            wxFAIL_MSG( wxT("Setting erase background hook twice?") );
+        }
+    }
+    else // reset the hook
+    {
+        if ( gs_eraseBgHooks.erase(this) != 1 )
+        {
+            wxFAIL_MSG( wxT("Resetting erase background which was not set?") );
+        }
+    }
+}
+
+#endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
+
 bool wxWindowMSW::DoEraseBackground(WXHDC hDC)
 {
     HBRUSH hbr = (HBRUSH)MSWGetBgBrush(hDC);
     if ( !hbr )
         return false;
 
-    wxFillRect(GetHwnd(), (HDC)hDC, hbr);
+    // erase just the client area of the window, this is important for the
+    // frames to avoid drawing over the toolbar part of the window (you might
+    // think using WS_CLIPCHILDREN would prevent this from happening, but it
+    // clearly doesn't)
+    RECT rc;
+    wxCopyRectToRECT(GetClientRect(), rc);
+    ::FillRect((HDC)hDC, &rc, hbr);
 
     return true;
 }