]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/wincmn.cpp
fixing focus, fixes #11911
[wxWidgets.git] / src / common / wincmn.cpp
index 03e49a2a0c49e9461eb0cd78e6abbc223b5110a8..fdeecde22213c39396ba63c56681ab6372c2659d 100644 (file)
@@ -38,6 +38,7 @@
     #include "wx/settings.h"
     #include "wx/dialog.h"
     #include "wx/msgdlg.h"
+    #include "wx/msgout.h"
     #include "wx/statusbr.h"
     #include "wx/toolbar.h"
     #include "wx/dcclient.h"
     #include "wx/sysopt.h"
 #endif
 
-// For reporting compile- and runtime version of GTK+ in the ctrl+alt+mclick dialog.
-// The gtk includes don't pull any other headers in, at least not on my system - MR
-#ifdef __WXGTK__
-    #ifdef __WXGTK20__
-        #include <gtk/gtkversion.h>
-    #else
-        #include <gtk/gtkfeatures.h>
-    #endif
-#endif
-
 #include "wx/platinfo.h"
+#include "wx/private/window.h"
+
+#ifdef __WXMSW__
+    #include "wx/msw/wrapwin.h"
+#endif
 
 // Windows List
 WXDLLIMPEXP_DATA_CORE(wxWindowList) wxTopLevelWindows;
@@ -111,6 +107,7 @@ BEGIN_EVENT_TABLE(wxWindowBase, wxEvtHandler)
     EVT_HELP(wxID_ANY, wxWindowBase::OnHelp)
 #endif // wxUSE_HELP
 
+    EVT_SIZE(wxWindowBase::InternalOnSize)
 END_EVENT_TABLE()
 
 // ============================================================================
@@ -125,7 +122,7 @@ END_EVENT_TABLE()
 wxWindowBase::wxWindowBase()
 {
     // no window yet, no parent nor children
-    m_parent = (wxWindow *)NULL;
+    m_parent = NULL;
     m_windowId = wxID_ANY;
 
     // no constraints on the minimal window size
@@ -146,7 +143,7 @@ wxWindowBase::wxWindowBase()
 
 #if wxUSE_VALIDATORS
     // no validator
-    m_windowValidator = (wxValidator *) NULL;
+    m_windowValidator = NULL;
 #endif // wxUSE_VALIDATORS
 
     // the colours/fonts are default for now, so leave m_font,
@@ -162,28 +159,28 @@ wxWindowBase::wxWindowBase()
     m_exStyle =
     m_windowStyle = 0;
 
-    m_backgroundStyle = wxBG_STYLE_SYSTEM;
+    m_backgroundStyle = wxBG_STYLE_ERASE;
 
 #if wxUSE_CONSTRAINTS
     // no constraints whatsoever
-    m_constraints = (wxLayoutConstraints *) NULL;
-    m_constraintsInvolvedIn = (wxWindowList *) NULL;
+    m_constraints = NULL;
+    m_constraintsInvolvedIn = NULL;
 #endif // wxUSE_CONSTRAINTS
 
-    m_windowSizer = (wxSizer *) NULL;
-    m_containingSizer = (wxSizer *) NULL;
+    m_windowSizer = NULL;
+    m_containingSizer = NULL;
     m_autoLayout = false;
 
 #if wxUSE_DRAG_AND_DROP
-    m_dropTarget = (wxDropTarget *)NULL;
+    m_dropTarget = NULL;
 #endif // wxUSE_DRAG_AND_DROP
 
 #if wxUSE_TOOLTIPS
-    m_tooltip = (wxToolTip *)NULL;
+    m_tooltip = NULL;
 #endif // wxUSE_TOOLTIPS
 
 #if wxUSE_CARET
-    m_caret = (wxCaret *)NULL;
+    m_caret = NULL;
 #endif // wxUSE_CARET
 
 #if wxUSE_PALETTE
@@ -196,7 +193,7 @@ wxWindowBase::wxWindowBase()
 
     m_virtualSize = wxDefaultSize;
 
-    m_scrollHelper = (wxScrollHelper *) NULL;
+    m_scrollHelper = NULL;
 
     m_windowVariant = wxWINDOW_VARIANT_NORMAL;
 #if wxUSE_SYSTEM_OPTIONS
@@ -209,7 +206,9 @@ wxWindowBase::wxWindowBase()
     // Whether we're using the current theme for this window (wxGTK only for now)
     m_themeEnabled = false;
 
-    // VZ: this one shouldn't exist...
+    // This is set to true by SendDestroyEvent() which should be called by the
+    // most derived class to ensure that the destruction event is sent as soon
+    // as possible to allow its handlers to still see the undestroyed window
     m_isBeingDeleted = false;
 
     m_freezeCount = 0;
@@ -219,28 +218,16 @@ wxWindowBase::wxWindowBase()
 bool wxWindowBase::CreateBase(wxWindowBase *parent,
                               wxWindowID id,
                               const wxPoint& WXUNUSED(pos),
-                              const wxSize& WXUNUSED(size),
+                              const wxSize& size,
                               long style,
-                              const wxValidator& wxVALIDATOR_PARAM(validator),
                               const wxString& name)
 {
-#if wxUSE_STATBOX
-    // wxGTK doesn't allow to create controls with static box as the parent so
-    // this will result in a crash when the program is ported to wxGTK so warn
-    // the user about it
-
-    // if you get this assert, the correct solution is to create the controls
-    // as siblings of the static box
-    wxASSERT_MSG( !parent || !wxDynamicCast(parent, wxStaticBox),
-                  _T("wxStaticBox can't be used as a window parent!") );
-#endif // wxUSE_STATBOX
-
     // ids are limited to 16 bits under MSW so if you care about portability,
     // it's not a good idea to use ids out of this range (and negative ids are
     // reserved for wxWidgets own usage)
     wxASSERT_MSG( id == wxID_ANY || (id >= 0 && id < 32767) ||
                   (id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST),
-                  _T("invalid id value") );
+                  wxT("invalid id value") );
 
     // generate a new id if the user doesn't care about it
     if ( id == wxID_ANY )
@@ -257,9 +244,32 @@ bool wxWindowBase::CreateBase(wxWindowBase *parent,
     // flags by updating the window dynamically and we don't need this here
     m_windowStyle = style;
 
+    // assume the user doesn't want this window to shrink beneath its initial
+    // size, this worked like this in wxWidgets 2.8 and before and generally
+    // often makes sense for child windows (for top level ones it definitely
+    // does not as the user should be able to resize the window)
+    //
+    // note that we can't use IsTopLevel() from ctor
+    if ( size != wxDefaultSize && !wxTopLevelWindows.Find((wxWindow *)this) )
+        SetMinSize(size);
+
     SetName(name);
     SetParent(parent);
 
+    return true;
+}
+
+bool wxWindowBase::CreateBase(wxWindowBase *parent,
+                              wxWindowID id,
+                              const wxPoint& pos,
+                              const wxSize& size,
+                              long style,
+                              const wxValidator& wxVALIDATOR_PARAM(validator),
+                              const wxString& name)
+{
+    if ( !CreateBase(parent, id, pos, size, style, name) )
+        return false;
+
 #if wxUSE_VALIDATORS
     SetValidator(validator);
 #endif // wxUSE_VALIDATORS
@@ -277,7 +287,7 @@ bool wxWindowBase::CreateBase(wxWindowBase *parent,
 
 bool wxWindowBase::ToggleWindowStyle(int flag)
 {
-    wxASSERT_MSG( flag, _T("flags with 0 value can't be toggled") );
+    wxASSERT_MSG( flag, wxT("flags with 0 value can't be toggled") );
 
     bool rc;
     long style = GetWindowStyleFlag();
@@ -317,6 +327,12 @@ wxWindowBase::~wxWindowBase()
     // we weren't a dialog class
     wxTopLevelWindows.DeleteObject((wxWindow*)this);
 
+    // Any additional event handlers should be popped before the window is
+    // deleted as otherwise the last handler will be left with a dangling
+    // pointer to this window result in a difficult to diagnose crash later on.
+    wxASSERT_MSG( GetEventHandler() == this,
+                    wxT("any pushed event handlers must have been removed") );
+
 #if wxUSE_MENUS
     // The associated popup menu can still be alive, disassociate from it in
     // this case
@@ -387,6 +403,16 @@ bool wxWindowBase::IsBeingDeleted() const
 
 void wxWindowBase::SendDestroyEvent()
 {
+    if ( m_isBeingDeleted )
+    {
+        // we could have been already called from a more derived class dtor,
+        // e.g. ~wxTLW calls us and so does ~wxWindow and the latter call
+        // should be simply ignored
+        return;
+    }
+
+    m_isBeingDeleted = true;
+
     wxWindowDestroyEvent event;
     event.SetEventObject(this);
     event.SetId(GetId());
@@ -395,6 +421,8 @@ void wxWindowBase::SendDestroyEvent()
 
 bool wxWindowBase::Destroy()
 {
+    SendDestroyEvent();
+
     delete this;
 
     return true;
@@ -423,11 +451,11 @@ bool wxWindowBase::DestroyChildren()
 
         wxWindow *child = node->GetData();
 
-        // note that we really want to call delete and not ->Destroy() here
-        // because we want to delete the child immediately, before we are
-        // deleted, and delayed deletion would result in problems as our (top
-        // level) child could outlive its parent
-        delete child;
+        // note that we really want to delete it immediately so don't call the
+        // possible overridden Destroy() version which might not delete the
+        // child immediately resulting in problems with our (top level) child
+        // outliving its parent
+        child->wxWindowBase::Destroy();
 
         wxASSERT_MSG( !GetChildren().Find(child),
                       wxT("child didn't remove itself using RemoveChild()") );
@@ -444,7 +472,7 @@ bool wxWindowBase::DestroyChildren()
 void wxWindowBase::DoCentre(int dir)
 {
     wxCHECK_RET( !(dir & wxCENTRE_ON_SCREEN) && GetParent(),
-                 _T("this method only implements centering child windows") );
+                 wxT("this method only implements centering child windows") );
 
     SetSize(GetRect().CentreIn(GetParent()->GetClientSize(), dir));
 }
@@ -469,7 +497,7 @@ void wxWindowBase::FitInside()
 }
 
 // On Mac, scrollbars are explicitly children.
-#ifdef __WXMAC__
+#if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__)
 static bool wxHasRealChildren(const wxWindowBase* win)
 {
     int realChildCount = 0;
@@ -479,7 +507,11 @@ static bool wxHasRealChildren(const wxWindowBase* win)
           node = node->GetNext() )
     {
         wxWindow *win = node->GetData();
-        if ( !win->IsTopLevel() && win->IsShown() && !win->IsKindOf(CLASSINFO(wxScrollBar)))
+        if ( !win->IsTopLevel() && win->IsShown()
+#if wxUSE_SCROLLBAR
+            && !win->IsKindOf(CLASSINFO(wxScrollBar))
+#endif
+            )
             realChildCount ++;
     }
     return (realChildCount > 0);
@@ -545,7 +577,7 @@ wxSize wxWindowBase::DoGetBestSize() const
     }
 #endif // wxUSE_CONSTRAINTS
     else if ( !GetChildren().empty()
-#ifdef __WXMAC__
+#if defined( __WXMAC__ ) && !defined(__WXUNIVERSAL__)
               && wxHasRealChildren(this)
 #endif
               )
@@ -594,19 +626,14 @@ wxSize wxWindowBase::DoGetBestSize() const
     }
     else // ! has children
     {
-        // for a generic window there is no natural best size so, if the
-        // minimal size is not set, use the current size but take care to
-        // remember it as minimal size for the next time because our best size
-        // should be constant: otherwise we could get into a situation when the
-        // window is initially at some size, then expanded to a larger size and
-        // then, when the containing window is shrunk back (because our initial
-        // best size had been used for computing the parent min size), we can't
-        // be shrunk back any more because our best size is now bigger
         wxSize size = GetMinSize();
         if ( !size.IsFullySpecified() )
         {
-            size.SetDefaults(GetSize());
-            wxConstCast(this, wxWindowBase)->SetMinSize(size);
+            // if the window doesn't define its best size we assume that it can
+            // be arbitrarily small -- usually this is not the case, of course,
+            // but we have no way to know what the limit is, it should really
+            // override DoGetBestClientSize() itself to tell us
+            size.SetDefaults(wxSize(1, 1));
         }
 
         // return as-is, unadjusted by the client size difference.
@@ -624,9 +651,10 @@ wxSize wxWindowBase::DoGetBestSize() const
 // helper of GetWindowBorderSize(): as many ports don't implement support for
 // wxSYS_BORDER/EDGE_X/Y metrics in their wxSystemSettings, use hard coded
 // fallbacks in this case
-static int wxGetMetricOrDefault(wxSystemMetric what)
+static int wxGetMetricOrDefault(wxSystemMetric what, const wxWindowBase* win)
 {
-    int rc = wxSystemSettings::GetMetric(what);
+    int rc = wxSystemSettings::GetMetric(
+        what, static_cast<wxWindow*>(const_cast<wxWindowBase*>(win)));
     if ( rc == -1 )
     {
         switch ( what )
@@ -644,7 +672,7 @@ static int wxGetMetricOrDefault(wxSystemMetric what)
                 break;
 
             default:
-                wxFAIL_MSG( _T("unexpected wxGetMetricOrDefault() argument") );
+                wxFAIL_MSG( wxT("unexpected wxGetMetricOrDefault() argument") );
                 rc = 0;
         }
     }
@@ -664,27 +692,27 @@ wxSize wxWindowBase::GetWindowBorderSize() const
 
         case wxBORDER_SIMPLE:
         case wxBORDER_STATIC:
-            size.x = wxGetMetricOrDefault(wxSYS_BORDER_X);
-            size.y = wxGetMetricOrDefault(wxSYS_BORDER_Y);
+            size.x = wxGetMetricOrDefault(wxSYS_BORDER_X, this);
+            size.y = wxGetMetricOrDefault(wxSYS_BORDER_Y, this);
             break;
 
         case wxBORDER_SUNKEN:
         case wxBORDER_RAISED:
-            size.x = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_X),
-                           wxGetMetricOrDefault(wxSYS_BORDER_X));
-            size.y = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_Y),
-                           wxGetMetricOrDefault(wxSYS_BORDER_Y));
+            size.x = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_X, this),
+                           wxGetMetricOrDefault(wxSYS_BORDER_X, this));
+            size.y = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_Y, this),
+                           wxGetMetricOrDefault(wxSYS_BORDER_Y, this));
             break;
 
         case wxBORDER_DOUBLE:
-            size.x = wxGetMetricOrDefault(wxSYS_EDGE_X) +
-                        wxGetMetricOrDefault(wxSYS_BORDER_X);
-            size.y = wxGetMetricOrDefault(wxSYS_EDGE_Y) +
-                        wxGetMetricOrDefault(wxSYS_BORDER_Y);
+            size.x = wxGetMetricOrDefault(wxSYS_EDGE_X, this) +
+                        wxGetMetricOrDefault(wxSYS_BORDER_X, this);
+            size.y = wxGetMetricOrDefault(wxSYS_EDGE_Y, this) +
+                        wxGetMetricOrDefault(wxSYS_BORDER_Y, this);
             break;
 
         default:
-            wxFAIL_MSG(_T("Unknown border style."));
+            wxFAIL_MSG(wxT("Unknown border style."));
             break;
     }
 
@@ -696,15 +724,62 @@ wxSize wxWindowBase::GetEffectiveMinSize() const
 {
     // merge the best size with the min size, giving priority to the min size
     wxSize min = GetMinSize();
+
     if (min.x == wxDefaultCoord || min.y == wxDefaultCoord)
     {
         wxSize best = GetBestSize();
         if (min.x == wxDefaultCoord) min.x =  best.x;
         if (min.y == wxDefaultCoord) min.y =  best.y;
     }
+
     return min;
 }
 
+wxSize wxWindowBase::DoGetBorderSize() const
+{
+    // there is one case in which we can implement it for all ports easily:
+    // do it as some classes used by both wxUniv and native ports (e.g.
+    // wxGenericStaticText) do override DoGetBestClientSize() and so this
+    // method must work for them and that ensures that it does, at least in
+    // the default case)
+    if ( GetBorder() == wxBORDER_NONE )
+        return wxSize(0, 0);
+
+    wxFAIL_MSG( "must be overridden if called" );
+
+    return wxDefaultSize;
+}
+
+wxSize wxWindowBase::GetBestSize() const
+{
+    if ( !m_windowSizer && m_bestSizeCache.IsFullySpecified() )
+        return m_bestSizeCache;
+
+    // call DoGetBestClientSize() first, if a derived class overrides it wants
+    // it to be used
+    wxSize size = DoGetBestClientSize();
+    if ( size != wxDefaultSize )
+    {
+        size += DoGetBorderSize();
+
+        CacheBestSize(size);
+        return size;
+    }
+
+    return DoGetBestSize();
+}
+
+void wxWindowBase::SetMinSize(const wxSize& minSize)
+{
+    m_minWidth = minSize.x;
+    m_minHeight = minSize.y;
+}
+
+void wxWindowBase::SetMaxSize(const wxSize& maxSize)
+{
+    m_maxWidth = maxSize.x;
+    m_maxHeight = maxSize.y;
+}
 
 void wxWindowBase::SetInitialSize(const wxSize& size)
 {
@@ -780,7 +855,7 @@ void wxWindowBase::DoSetWindowVariant( wxWindowVariant variant )
             break;
 
         default:
-            wxFAIL_MSG(_T("unexpected window variant"));
+            wxFAIL_MSG(wxT("unexpected window variant"));
             break;
     }
 
@@ -794,7 +869,7 @@ void wxWindowBase::DoSetSizeHints( int minW, int minH,
 {
     wxCHECK_RET( (minW == wxDefaultCoord || maxW == wxDefaultCoord || minW <= maxW) &&
                     (minH == wxDefaultCoord || maxH == wxDefaultCoord || minH <= maxH),
-                 _T("min width/height must be less than max width/height!") );
+                 wxT("min width/height must be less than max width/height!") );
 
     m_minWidth = minW;
     m_maxWidth = maxW;
@@ -864,6 +939,20 @@ void wxWindowBase::SendSizeEventToParent(int flags)
         parent->SendSizeEvent(flags);
 }
 
+bool wxWindowBase::HasScrollbar(int orient) const
+{
+    // if scrolling in the given direction is disabled, we can't have the
+    // corresponding scrollbar no matter what
+    if ( !CanScroll(orient) )
+        return false;
+
+    const wxSize sizeVirt = GetVirtualSize();
+    const wxSize sizeClient = GetClientSize();
+
+    return orient == wxHORIZONTAL ? sizeVirt.x > sizeClient.x
+                                  : sizeVirt.y > sizeClient.y;
+}
+
 // ----------------------------------------------------------------------------
 // show/hide/enable/disable the window
 // ----------------------------------------------------------------------------
@@ -1008,7 +1097,7 @@ void wxWindowBase::AddChild(wxWindowBase *child)
     // this should never happen and it will lead to a crash later if it does
     // because RemoveChild() will remove only one node from the children list
     // and the other(s) one(s) will be left with dangling pointers in them
-    wxASSERT_MSG( !GetChildren().Find((wxWindow*)child), _T("AddChild() called twice") );
+    wxASSERT_MSG( !GetChildren().Find((wxWindow*)child), wxT("AddChild() called twice") );
 
     GetChildren().Append((wxWindow*)child);
     child->SetParent(this);
@@ -1081,83 +1170,135 @@ bool wxWindowBase::Reparent(wxWindowBase *newParent)
 // event handler stuff
 // ----------------------------------------------------------------------------
 
-void wxWindowBase::PushEventHandler(wxEvtHandler *handler)
+void wxWindowBase::SetEventHandler(wxEvtHandler *handler)
+{
+    wxCHECK_RET(handler != NULL, "SetEventHandler(NULL) called");
+
+    m_eventHandler = handler;
+}
+
+void wxWindowBase::SetNextHandler(wxEvtHandler *WXUNUSED(handler))
+{
+    // disable wxEvtHandler chain mechanism for wxWindows:
+    // wxWindow uses its own stack mechanism which doesn't mix well with wxEvtHandler's one
+
+    wxFAIL_MSG("wxWindow cannot be part of a wxEvtHandler chain");
+}
+void wxWindowBase::SetPreviousHandler(wxEvtHandler *WXUNUSED(handler))
 {
+    // we can't simply wxFAIL here as in SetNextHandler: in fact the last
+    // handler of our stack when is destroyed will be Unlink()ed and thus
+    // will call this function to update the pointer of this window...
+
+    //wxFAIL_MSG("wxWindow cannot be part of a wxEvtHandler chain");
+}
+
+void wxWindowBase::PushEventHandler(wxEvtHandler *handlerToPush)
+{
+    wxCHECK_RET( handlerToPush != NULL, "PushEventHandler(NULL) called" );
+
+    // the new handler is going to be part of the wxWindow stack of event handlers:
+    // it can't be part also of an event handler double-linked chain:
+    wxASSERT_MSG(handlerToPush->IsUnlinked(),
+        "The handler being pushed in the wxWindow stack shouldn't be part of "
+        "a wxEvtHandler chain; call Unlink() on it first");
+
     wxEvtHandler *handlerOld = GetEventHandler();
+    wxCHECK_RET( handlerOld, "an old event handler is NULL?" );
+
+    // now use wxEvtHandler double-linked list to implement a stack:
+    handlerToPush->SetNextHandler(handlerOld);
+
+    if (handlerOld != this)
+        handlerOld->SetPreviousHandler(handlerToPush);
 
-    handler->SetNextHandler(handlerOld);
+    SetEventHandler(handlerToPush);
 
-    if ( handlerOld )
-        GetEventHandler()->SetPreviousHandler(handler);
+#if wxDEBUG_LEVEL
+    // final checks of the operations done above:
+    wxASSERT_MSG( handlerToPush->GetPreviousHandler() == NULL,
+        "the first handler of the wxWindow stack should "
+        "have no previous handlers set" );
+    wxASSERT_MSG( handlerToPush->GetNextHandler() != NULL,
+        "the first handler of the wxWindow stack should "
+        "have non-NULL next handler" );
 
-    SetEventHandler(handler);
+    wxEvtHandler* pLast = handlerToPush;
+    while ( pLast && pLast != this )
+        pLast = pLast->GetNextHandler();
+    wxASSERT_MSG( pLast->GetNextHandler() == NULL,
+        "the last handler of the wxWindow stack should "
+        "have this window as next handler" );
+#endif // wxDEBUG_LEVEL
 }
 
 wxEvtHandler *wxWindowBase::PopEventHandler(bool deleteHandler)
 {
-    wxEvtHandler *handlerA = GetEventHandler();
-    if ( handlerA )
-    {
-        wxEvtHandler *handlerB = handlerA->GetNextHandler();
-        handlerA->SetNextHandler((wxEvtHandler *)NULL);
+    // we need to pop the wxWindow stack, i.e. we need to remove the first handler
 
-        if ( handlerB )
-            handlerB->SetPreviousHandler((wxEvtHandler *)NULL);
-        SetEventHandler(handlerB);
+    wxEvtHandler *firstHandler = GetEventHandler();
+    wxCHECK_MSG( firstHandler != NULL, NULL, "wxWindow cannot have a NULL event handler" );
+    wxCHECK_MSG( firstHandler != this, NULL, "cannot pop the wxWindow itself" );
+    wxCHECK_MSG( firstHandler->GetPreviousHandler() == NULL, NULL,
+        "the first handler of the wxWindow stack should have no previous handlers set" );
 
-        if ( deleteHandler )
-        {
-            delete handlerA;
-            handlerA = (wxEvtHandler *)NULL;
-        }
+    wxEvtHandler *secondHandler = firstHandler->GetNextHandler();
+    wxCHECK_MSG( secondHandler != NULL, NULL,
+        "the first handler of the wxWindow stack should have non-NULL next handler" );
+
+    firstHandler->SetNextHandler(NULL);
+    secondHandler->SetPreviousHandler(NULL);
+
+    // now firstHandler is completely unlinked; set secondHandler as the new window event handler
+    SetEventHandler(secondHandler);
+
+    if ( deleteHandler )
+    {
+        delete firstHandler;
+        firstHandler = NULL;
     }
 
-    return handlerA;
+    return firstHandler;
 }
 
-bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handler)
+bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handlerToRemove)
 {
-    wxCHECK_MSG( handler, false, _T("RemoveEventHandler(NULL) called") );
+    wxCHECK_MSG( handlerToRemove != NULL, false, "RemoveEventHandler(NULL) called" );
+    wxCHECK_MSG( handlerToRemove != this, false, "Cannot remove the window itself" );
+
+    if (handlerToRemove == GetEventHandler())
+    {
+        // removing the first event handler is equivalent to "popping" the stack
+        PopEventHandler(false);
+        return true;
+    }
 
-    wxEvtHandler *handlerPrev = NULL,
-                 *handlerCur = GetEventHandler();
-    while ( handlerCur )
+    // NOTE: the wxWindow event handler list is always terminated with "this" handler
+    wxEvtHandler *handlerCur = GetEventHandler()->GetNextHandler();
+    while ( handlerCur != this && handlerCur )
     {
         wxEvtHandler *handlerNext = handlerCur->GetNextHandler();
 
-        if ( handlerCur == handler )
+        if ( handlerCur == handlerToRemove )
         {
-            if ( handlerPrev )
-            {
-                handlerPrev->SetNextHandler(handlerNext);
-            }
-            else
-            {
-                SetEventHandler(handlerNext);
-            }
-
-            if ( handlerNext )
-            {
-                handlerNext->SetPreviousHandler ( handlerPrev );
-            }
-
-            handler->SetNextHandler(NULL);
-            handler->SetPreviousHandler(NULL);
+            handlerCur->Unlink();
 
+            wxASSERT_MSG( handlerCur != GetEventHandler(),
+                        "the case Remove == Pop should was already handled" );
             return true;
         }
 
-        handlerPrev = handlerCur;
         handlerCur = handlerNext;
     }
 
-    wxFAIL_MSG( _T("where has the event handler gone?") );
+    wxFAIL_MSG( wxT("where has the event handler gone?") );
 
     return false;
 }
 
 bool wxWindowBase::HandleWindowEvent(wxEvent& event) const
 {
+    // SafelyProcessEvent() will handle exceptions nicely
     return GetEventHandler()->SafelyProcessEvent(event);
 }
 
@@ -1223,13 +1364,13 @@ wxColour wxWindowBase::GetBackgroundColour() const
 {
     if ( !m_backgroundColour.IsOk() )
     {
-        wxASSERT_MSG( !m_hasBgCol, _T("we have invalid explicit bg colour?") );
+        wxASSERT_MSG( !m_hasBgCol, wxT("we have invalid explicit bg colour?") );
 
         // get our default background colour
         wxColour colBg = GetDefaultAttributes().colBg;
 
         // we must return some valid colour to avoid redoing this every time
-        // and also to avoid surprizing the applications written for older
+        // and also to avoid surprising the applications written for older
         // wxWidgets versions where GetBackgroundColour() always returned
         // something -- so give them something even if it doesn't make sense
         // for this window (e.g. it has a themed background)
@@ -1264,8 +1405,6 @@ bool wxWindowBase::SetBackgroundColour( const wxColour &colour )
         return false;
 
     m_hasBgCol = colour.IsOk();
-    if ( m_backgroundStyle != wxBG_STYLE_CUSTOM )
-        m_backgroundStyle = m_hasBgCol ? wxBG_STYLE_COLOUR : wxBG_STYLE_SYSTEM;
 
     m_inheritBgCol = m_hasBgCol;
     m_backgroundColour = colour;
@@ -1305,7 +1444,7 @@ wxFont wxWindowBase::GetFont() const
     // logic is the same as in GetBackgroundColour()
     if ( !m_font.IsOk() )
     {
-        wxASSERT_MSG( !m_hasFont, _T("we have invalid explicit font?") );
+        wxASSERT_MSG( !m_hasFont, wxT("we have invalid explicit font?") );
 
         wxFont font = GetDefaultAttributes().font;
         if ( !font.IsOk() )
@@ -1440,7 +1579,7 @@ wxWindow *wxWindowBase::FindWindow(long id) const
     if ( id == m_windowId )
         return (wxWindow *)this;
 
-    wxWindowBase *res = (wxWindow *)NULL;
+    wxWindowBase *res = NULL;
     wxWindowList::compatibility_iterator node;
     for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() )
     {
@@ -1456,7 +1595,7 @@ wxWindow *wxWindowBase::FindWindow(const wxString& name) const
     if ( name == m_windowName )
         return (wxWindow *)this;
 
-    wxWindowBase *res = (wxWindow *)NULL;
+    wxWindowBase *res = NULL;
     wxWindowList::compatibility_iterator node;
     for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() )
     {
@@ -1796,6 +1935,11 @@ void wxWindowBase::OnHelp(wxHelpEvent& event)
 
 #if wxUSE_TOOLTIPS
 
+wxString wxWindowBase::GetToolTipText() const
+{
+    return m_tooltip ? m_tooltip->GetTip() : wxString();
+}
+
 void wxWindowBase::SetToolTip( const wxString &tip )
 {
     // don't create the new tooltip if we already have one
@@ -1809,7 +1953,7 @@ void wxWindowBase::SetToolTip( const wxString &tip )
     }
 
     // setting empty tooltip text does not remove the tooltip any more - use
-    // SetToolTip((wxToolTip *)NULL) for this
+    // SetToolTip(NULL) for this
 }
 
 void wxWindowBase::DoSetToolTip(wxToolTip *tooltip)
@@ -1933,7 +2077,7 @@ void wxWindowBase::DeleteRelatedConstraints()
         }
 
         delete m_constraintsInvolvedIn;
-        m_constraintsInvolvedIn = (wxWindowList *) NULL;
+        m_constraintsInvolvedIn = NULL;
     }
 }
 
@@ -1975,7 +2119,7 @@ void wxWindowBase::SetContainingSizer(wxSizer* sizer)
     // associated wxSizerItem we're going to dereference a dangling
     // pointer; so try to detect this as early as possible
     wxASSERT_MSG( !sizer || m_containingSizer != sizer,
-                  _T("Adding a window to the same sizer twice?") );
+                  wxT("Adding a window to the same sizer twice?") );
 
     m_containingSizer = sizer;
 }
@@ -2027,6 +2171,14 @@ bool wxWindowBase::Layout()
     return true;
 }
 
+void wxWindowBase::InternalOnSize(wxSizeEvent& event)
+{
+    if ( GetAutoLayout() )
+        Layout();
+
+    event.Skip();
+}
+
 #if wxUSE_CONSTRAINTS
 
 // first phase of the constraints evaluation: set our own constraints
@@ -2314,28 +2466,57 @@ void wxWindowBase::DoUpdateWindowUI(wxUpdateUIEvent& event)
 // dialog units translations
 // ----------------------------------------------------------------------------
 
-wxPoint wxWindowBase::ConvertPixelsToDialog(const wxPoint& pt)
+// Windows' computes dialog units using average character width over upper-
+// and lower-case ASCII alphabet and not using the average character width
+// metadata stored in the font; see
+// http://support.microsoft.com/default.aspx/kb/145994 for detailed discussion.
+// It's important that we perform the conversion in identical way, because
+// dialog units natively exist only on Windows and Windows HIG is expressed
+// using them.
+wxSize wxWindowBase::GetDlgUnitBase() const
 {
-    int charWidth = GetCharWidth();
-    int charHeight = GetCharHeight();
+    const wxWindow *parent = wxGetTopLevelParent((wxWindow*)this);
+
+    if ( !parent->m_font.IsOk() )
+    {
+        // Default GUI font is used. This is the most common case, so
+        // cache the results.
+        static wxSize s_defFontSize;
+        if ( s_defFontSize.x == 0 )
+            s_defFontSize = wxPrivate::GetAverageASCIILetterSize(*parent);
+        return s_defFontSize;
+    }
+    else
+    {
+        // Custom font, we always need to compute the result
+        return wxPrivate::GetAverageASCIILetterSize(*parent);
+    }
+}
+
+wxPoint wxWindowBase::ConvertPixelsToDialog(const wxPoint& pt) const
+{
+    const wxSize base = GetDlgUnitBase();
+
+    // NB: wxMulDivInt32() is used, because it correctly rounds the result
+
     wxPoint pt2 = wxDefaultPosition;
     if (pt.x != wxDefaultCoord)
-        pt2.x = (int) ((pt.x * 4) / charWidth);
+        pt2.x = wxMulDivInt32(pt.x, 4, base.x);
     if (pt.y != wxDefaultCoord)
-        pt2.y = (int) ((pt.y * 8) / charHeight);
+        pt2.y = wxMulDivInt32(pt.y, 8, base.y);
 
     return pt2;
 }
 
-wxPoint wxWindowBase::ConvertDialogToPixels(const wxPoint& pt)
+wxPoint wxWindowBase::ConvertDialogToPixels(const wxPoint& pt) const
 {
-    int charWidth = GetCharWidth();
-    int charHeight = GetCharHeight();
+    const wxSize base = GetDlgUnitBase();
+
     wxPoint pt2 = wxDefaultPosition;
     if (pt.x != wxDefaultCoord)
-        pt2.x = (int) ((pt.x * charWidth) / 4);
+        pt2.x = wxMulDivInt32(pt.x, base.x, 4);
     if (pt.y != wxDefaultCoord)
-        pt2.y = (int) ((pt.y * charHeight) / 8);
+        pt2.y = wxMulDivInt32(pt.y, base.y, 8);
 
     return pt2;
 }
@@ -2345,7 +2526,7 @@ wxPoint wxWindowBase::ConvertDialogToPixels(const wxPoint& pt)
 // ----------------------------------------------------------------------------
 
 // propagate the colour change event to the subwindows
-void wxWindowBase::OnSysColourChanged(wxSysColourChangedEvent& event)
+void wxWindowBase::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event))
 {
     wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
     while ( node )
@@ -2355,7 +2536,7 @@ void wxWindowBase::OnSysColourChanged(wxSysColourChangedEvent& event)
         if ( !win->IsTopLevel() )
         {
             wxSysColourChangedEvent event2;
-            event.SetEventObject(win);
+            event2.SetEventObject(win);
             win->GetEventHandler()->ProcessEvent(event2);
         }
 
@@ -2406,6 +2587,11 @@ void wxWindowBase::InternalOnPopupMenu(wxCommandEvent& event)
     gs_popupMenuSelection = event.GetId();
 }
 
+void wxWindowBase::InternalOnPopupMenuUpdate(wxUpdateUIEvent& WXUNUSED(event))
+{
+    // nothing to do but do not skip it
+}
+
 int
 wxWindowBase::DoGetPopupMenuSelectionFromUser(wxMenu& menu, int x, int y)
 {
@@ -2416,8 +2602,24 @@ wxWindowBase::DoGetPopupMenuSelectionFromUser(wxMenu& menu, int x, int y)
             NULL,
             this);
 
+    // it is common to construct the menu passed to this function dynamically
+    // using some fixed range of ids which could clash with the ids used
+    // elsewhere in the program, which could result in some menu items being
+    // unintentionally disabled or otherwise modified by update UI handlers
+    // elsewhere in the program code and this is difficult to avoid in the
+    // program itself, so instead we just temporarily suspend UI updating while
+    // this menu is shown
+    Connect(wxEVT_UPDATE_UI,
+            wxUpdateUIEventHandler(wxWindowBase::InternalOnPopupMenuUpdate),
+            NULL,
+            this);
+
     PopupMenu(&menu, x, y);
 
+    Disconnect(wxEVT_UPDATE_UI,
+               wxUpdateUIEventHandler(wxWindowBase::InternalOnPopupMenuUpdate),
+               NULL,
+               this);
     Disconnect(wxEVT_COMMAND_MENU_SELECTED,
                wxCommandEventHandler(wxWindowBase::InternalOnPopupMenu),
                NULL,
@@ -2428,16 +2630,20 @@ wxWindowBase::DoGetPopupMenuSelectionFromUser(wxMenu& menu, int x, int y)
 
 #endif // wxUSE_MENUS
 
-// methods for drawing the sizers in a visible way
-#ifdef __WXDEBUG__
+// methods for drawing the sizers in a visible way: this is currently only
+// enabled for "full debug" builds with wxDEBUG_LEVEL==2 as it doesn't work
+// that well and also because we don't want to leave it enabled in default
+// builds used for production
+#if wxDEBUG_LEVEL > 1
 
 static void DrawSizers(wxWindowBase *win);
 
-static void DrawBorder(wxWindowBase *win, const wxRect& rect, bool fill = false)
+static void DrawBorder(wxWindowBase *win, const wxRect& rect, bool fill, const wxPen* pen)
 {
     wxClientDC dc((wxWindow *)win);
-    dc.SetPen(*wxRED_PEN);
-    dc.SetBrush(fill ? wxBrush(*wxRED, wxBRUSHSTYLE_CROSSDIAG_HATCH) : *wxTRANSPARENT_BRUSH);
+    dc.SetPen(*pen);
+    dc.SetBrush(fill ? wxBrush(pen->GetColour(), wxBRUSHSTYLE_CROSSDIAG_HATCH) :
+                       *wxTRANSPARENT_BRUSH);
     dc.DrawRectangle(rect.Deflate(1, 1));
 }
 
@@ -2452,26 +2658,29 @@ static void DrawSizer(wxWindowBase *win, wxSizer *sizer)
         wxSizerItem *item = *i;
         if ( item->IsSizer() )
         {
-            DrawBorder(win, item->GetRect().Deflate(2));
+            DrawBorder(win, item->GetRect().Deflate(2), false, wxRED_PEN);
             DrawSizer(win, item->GetSizer());
         }
         else if ( item->IsSpacer() )
         {
-            DrawBorder(win, item->GetRect().Deflate(2), true);
+            DrawBorder(win, item->GetRect().Deflate(2), true, wxBLUE_PEN);
         }
         else if ( item->IsWindow() )
         {
             DrawSizers(item->GetWindow());
         }
+        else
+            wxFAIL_MSG("inconsistent wxSizerItem status!");
     }
 }
 
 static void DrawSizers(wxWindowBase *win)
 {
+    DrawBorder(win, win->GetClientSize(), false, wxGREEN_PEN);
+
     wxSizer *sizer = win->GetSizer();
     if ( sizer )
     {
-        DrawBorder(win, win->GetClientSize());
         DrawSizer(win, sizer);
     }
     else // no sizer, still recurse into the children
@@ -2484,25 +2693,48 @@ static void DrawSizers(wxWindowBase *win)
         {
             DrawSizers(*i);
         }
+
+        // show all kind of sizes of this window; see the "window sizing" topic
+        // overview for more info about the various differences:
+        wxSize fullSz = win->GetSize();
+        wxSize clientSz = win->GetClientSize();
+        wxSize bestSz = win->GetBestSize();
+        wxSize minSz = win->GetMinSize();
+        wxSize maxSz = win->GetMaxSize();
+        wxSize virtualSz = win->GetVirtualSize();
+
+        wxMessageOutputDebug dbgout;
+        dbgout.Printf(
+            "%-10s => fullsz=%4d;%-4d  clientsz=%4d;%-4d  bestsz=%4d;%-4d  minsz=%4d;%-4d  maxsz=%4d;%-4d virtualsz=%4d;%-4d\n",
+            win->GetName(),
+            fullSz.x, fullSz.y,
+            clientSz.x, clientSz.y,
+            bestSz.x, bestSz.y,
+            minSz.x, minSz.y,
+            maxSz.x, maxSz.y,
+            virtualSz.x, virtualSz.y);
     }
 }
 
-#endif // __WXDEBUG__
+#endif // wxDEBUG_LEVEL
 
 // process special middle clicks
 void wxWindowBase::OnMiddleClick( wxMouseEvent& event )
 {
     if ( event.ControlDown() && event.AltDown() )
     {
-#ifdef __WXDEBUG__
+#if wxDEBUG_LEVEL > 1
         // Ctrl-Alt-Shift-mclick makes the sizers visible in debug builds
         if ( event.ShiftDown() )
         {
             DrawSizers(this);
-            return;
         }
+        else
 #endif // __WXDEBUG__
-        ::wxInfoMessageBox((wxWindow*)this);
+        {
+            // just Ctrl-Alt-middle click shows information about wx version
+            ::wxInfoMessageBox((wxWindow*)this);
+        }
     }
     else
     {
@@ -2616,9 +2848,9 @@ bool wxWindowBase::ms_winCaptureChanging = false;
 
 void wxWindowBase::CaptureMouse()
 {
-    wxLogTrace(_T("mousecapture"), _T("CaptureMouse(%p)"), wx_static_cast(void*, this));
+    wxLogTrace(wxT("mousecapture"), wxT("CaptureMouse(%p)"), static_cast<void*>(this));
 
-    wxASSERT_MSG( !ms_winCaptureChanging, _T("recursive CaptureMouse call?") );
+    wxASSERT_MSG( !ms_winCaptureChanging, wxT("recursive CaptureMouse call?") );
 
     ms_winCaptureChanging = true;
 
@@ -2643,9 +2875,9 @@ void wxWindowBase::CaptureMouse()
 
 void wxWindowBase::ReleaseMouse()
 {
-    wxLogTrace(_T("mousecapture"), _T("ReleaseMouse(%p)"), wx_static_cast(void*, this));
+    wxLogTrace(wxT("mousecapture"), wxT("ReleaseMouse(%p)"), static_cast<void*>(this));
 
-    wxASSERT_MSG( !ms_winCaptureChanging, _T("recursive ReleaseMouse call?") );
+    wxASSERT_MSG( !ms_winCaptureChanging, wxT("recursive ReleaseMouse call?") );
 
     wxASSERT_MSG( GetCapture() == this,
                   "attempt to release mouse, but this window hasn't captured it" );
@@ -2670,9 +2902,9 @@ void wxWindowBase::ReleaseMouse()
 
     ms_winCaptureChanging = false;
 
-    wxLogTrace(_T("mousecapture"),
-        (const wxChar *) _T("After ReleaseMouse() mouse is captured by %p"),
-        wx_static_cast(void*, GetCapture()));
+    wxLogTrace(wxT("mousecapture"),
+        (const wxChar *) wxT("After ReleaseMouse() mouse is captured by %p"),
+        static_cast<void*>(GetCapture()));
 }
 
 static void DoNotifyWindowAboutCaptureLost(wxWindow *win)
@@ -2685,7 +2917,7 @@ static void DoNotifyWindowAboutCaptureLost(wxWindow *win)
         // correctly if it loses capture unexpectedly; see the discussion here:
         // http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863
         // http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/82376
-        wxFAIL_MSG( _T("window that captured the mouse didn't process wxEVT_MOUSE_CAPTURE_LOST") );
+        wxFAIL_MSG( wxT("window that captured the mouse didn't process wxEVT_MOUSE_CAPTURE_LOST") );
     }
 }
 
@@ -2740,7 +2972,7 @@ bool wxWindowBase::UnregisterHotKey(int WXUNUSED(hotkeyId))
 // event processing
 // ----------------------------------------------------------------------------
 
-bool wxWindowBase::TryValidator(wxEvent& wxVALIDATOR_PARAM(event))
+bool wxWindowBase::TryBefore(wxEvent& event)
 {
 #if wxUSE_VALIDATORS
     // Can only use the validator of the window which
@@ -2755,10 +2987,10 @@ bool wxWindowBase::TryValidator(wxEvent& wxVALIDATOR_PARAM(event))
     }
 #endif // wxUSE_VALIDATORS
 
-    return false;
+    return wxEvtHandler::TryBefore(event);
 }
 
-bool wxWindowBase::TryParent(wxEvent& event)
+bool wxWindowBase::TryAfter(wxEvent& event)
 {
     // carry on up the parent-child hierarchy if the propagation count hasn't
     // reached zero yet
@@ -2780,7 +3012,7 @@ bool wxWindowBase::TryParent(wxEvent& event)
         }
     }
 
-    return wxEvtHandler::TryParent(event);
+    return wxEvtHandler::TryAfter(event);
 }
 
 // ----------------------------------------------------------------------------
@@ -2790,11 +3022,11 @@ bool wxWindowBase::TryParent(wxEvent& event)
 wxWindow *wxWindowBase::DoGetSibling(WindowOrder order) const
 {
     wxCHECK_MSG( GetParent(), NULL,
-                    _T("GetPrev/NextSibling() don't work for TLWs!") );
+                    wxT("GetPrev/NextSibling() don't work for TLWs!") );
 
     wxWindowList& siblings = GetParent()->GetChildren();
     wxWindowList::compatibility_iterator i = siblings.Find((wxWindow *)this);
-    wxCHECK_MSG( i, NULL, _T("window not a child of its parent?") );
+    wxCHECK_MSG( i, NULL, wxT("window not a child of its parent?") );
 
     if ( order == OrderBefore )
         i = i->GetPrevious();
@@ -2848,7 +3080,7 @@ void wxWindowBase::DoMoveInTabOrder(wxWindow *win, WindowOrder move)
 {
     // check that we're not a top level window
     wxCHECK_RET( GetParent(),
-                    _T("MoveBefore/AfterInTabOrder() don't work for TLWs!") );
+                    wxT("MoveBefore/AfterInTabOrder() don't work for TLWs!") );
 
     // detect the special case when we have nothing to do anyhow and when the
     // code below wouldn't work
@@ -2858,7 +3090,7 @@ void wxWindowBase::DoMoveInTabOrder(wxWindow *win, WindowOrder move)
     // find the target window in the siblings list
     wxWindowList& siblings = GetParent()->GetChildren();
     wxWindowList::compatibility_iterator i = siblings.Find(win);
-    wxCHECK_RET( i, _T("MoveBefore/AfterInTabOrder(): win is not a sibling") );
+    wxCHECK_RET( i, wxT("MoveBefore/AfterInTabOrder(): win is not a sibling") );
 
     // unfortunately, when wxUSE_STL == 1 DetachNode() is not implemented so we
     // can't just move the node around
@@ -2896,6 +3128,61 @@ bool wxWindowBase::HasFocus() const
            win == wxConstCast(this, wxWindowBase)->GetMainWindowOfCompositeControl();
 }
 
+// ----------------------------------------------------------------------------
+// drag and drop
+// ----------------------------------------------------------------------------
+
+#if wxUSE_DRAG_AND_DROP && !defined(__WXMSW__)
+
+namespace
+{
+
+class DragAcceptFilesTarget : public wxFileDropTarget
+{
+public:
+    DragAcceptFilesTarget(wxWindowBase *win) : m_win(win) {}
+
+    virtual bool OnDropFiles(wxCoord x, wxCoord y,
+                             const wxArrayString& filenames)
+    {
+        wxDropFilesEvent event(wxEVT_DROP_FILES,
+                               filenames.size(),
+                               wxCArrayString(filenames).Release());
+        event.SetEventObject(m_win);
+        event.m_pos.x = x;
+        event.m_pos.y = y;
+
+        return m_win->HandleWindowEvent(event);
+    }
+
+private:
+    wxWindowBase * const m_win;
+
+    wxDECLARE_NO_COPY_CLASS(DragAcceptFilesTarget);
+};
+
+
+} // anonymous namespace
+
+// Generic version of DragAcceptFiles(). It works by installing a simple
+// wxFileDropTarget-to-EVT_DROP_FILES adaptor and therefore cannot be used
+// together with explicit SetDropTarget() calls.
+void wxWindowBase::DragAcceptFiles(bool accept)
+{
+    if ( accept )
+    {
+        wxASSERT_MSG( !GetDropTarget(),
+                      "cannot use DragAcceptFiles() and SetDropTarget() together" );
+        SetDropTarget(new DragAcceptFilesTarget(this));
+    }
+    else
+    {
+        SetDropTarget(NULL);
+    }
+}
+
+#endif // wxUSE_DRAG_AND_DROP && !defined(__WXMSW__)
+
 // ----------------------------------------------------------------------------
 // global functions
 // ----------------------------------------------------------------------------