From 47a8a4d5cc3e8fcb2efee4787cb9d244104beea5 Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Fri, 23 Mar 2007 14:01:53 +0000
Subject: [PATCH] make IsEnabled() return false even if the window parent, and
 not the window itself, is disabled and added IsThisEnabled() implementing the
 old IsEnabled() behaviour; also significantly simplify the window state
 management code in all ports by factoring out the common parts in
 wxWindowBase

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@45031 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/changes.txt               |   4 ++
 docs/latex/wx/window.tex       |  18 +++++-
 include/wx/cocoa/window.h      |   7 +--
 include/wx/gtk/textctrl.h      |   2 +-
 include/wx/gtk/window.h        |   7 +--
 include/wx/gtk1/textctrl.h     |   4 +-
 include/wx/gtk1/window.h       |   7 +--
 include/wx/mac/carbon/window.h |   4 +-
 include/wx/msw/window.h        |   4 +-
 include/wx/os2/window.h        |   3 +-
 include/wx/palmos/window.h     |   3 -
 include/wx/window.h            |  55 +++++++++++++++--
 samples/controls/controls.cpp  |  35 +++++++++++
 src/cocoa/window.mm            |  28 +--------
 src/common/wincmn.cpp          |  61 ++++++++++++++++---
 src/gtk/bmpbuttn.cpp           |   2 +-
 src/gtk/textctrl.cpp           |   4 +-
 src/gtk/window.cpp             |  31 +---------
 src/gtk1/bmpbuttn.cpp          |   2 +-
 src/gtk1/textctrl.cpp          |  16 ++---
 src/gtk1/window.cpp            |  29 +--------
 src/mac/carbon/window.cpp      |  25 +-------
 src/msw/window.cpp             | 104 +--------------------------------
 src/os2/window.cpp             |  64 +-------------------
 24 files changed, 189 insertions(+), 330 deletions(-)

diff --git a/docs/changes.txt b/docs/changes.txt
index 8a7f67d72e..fd3c6af7ff 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -11,6 +11,10 @@ Changes in behaviour not resulting in compilation errors, please read this!
 - Default location of wxFileConfig files has changed under Windows, you will
   need to update your code if you access these files directly.
 
+- wxWindow::IsEnabled() now returns false if a window parent (and not
+  necessarily the window itself) is disabled, new function IsThisEnabled()
+  with the same behaviour as old IsEnabled() was added.
+
 Changes in behaviour which may result in compilation errors
 -----------------------------------------------------------
 
diff --git a/docs/latex/wx/window.tex b/docs/latex/wx/window.tex
index 249de56779..4d266a0112 100644
--- a/docs/latex/wx/window.tex
+++ b/docs/latex/wx/window.tex
@@ -1532,7 +1532,13 @@ and transferred to the screen all at once later.
 
 \constfunc{virtual bool}{IsEnabled}{\void}
 
-Returns {\tt true} if the window is enabled for input, {\tt false} otherwise.
+Returns \true if the window is enabled, i.e. if it accepts user input, \false 
+otherwise.
+
+Notice that this method can return \false even if this window itself hadn't
+been explicitly disabled when one of its parent windows is disabled. To get the
+intrinsic status of this window, use 
+\helpref{IsThisEnabled}{wxwindowisthisenabled}
 
 \wxheading{See also}
 
@@ -1608,6 +1614,16 @@ is shown and all its parents up to the toplevel window are shown as well.
 \helpref{wxWindow::IsShown}{wxwindowisshown}
 
 
+\membersection{wxWindow::IsThisEnabled}\label{wxwindowisthisenabled}
+
+\constfunc{bool}{IsThisEnabled}{\void}
+
+Returns \true if this window is intrinsically enabled, \false otherwise, i.e.
+if \helpref{Enable(false)}{wxwindowenable} had been called. This method is
+mostly used for wxWidgets itself, user code should normally use 
+\helpref{IsEnabled}{wxwindowisenabled} instead.
+
+
 \membersection{wxWindow::IsTopLevel}\label{wxwindowistoplevel}
 
 \constfunc{bool}{IsTopLevel}{\void}
diff --git a/include/wx/cocoa/window.h b/include/wx/cocoa/window.h
index ff7205b96d..c8b36b275a 100644
--- a/include/wx/cocoa/window.h
+++ b/include/wx/cocoa/window.h
@@ -81,13 +81,8 @@ public:
     WX_NSAffineTransform CocoaGetWxToBoundsTransform();
 #endif //def __OBJC__
 protected:
-    // enable==false: disables the control
-    // enable==true: enables the control IF it should be enabled
-    bool EnableSelfAndChildren(bool enable);
     // actually enable/disable the cocoa control, overridden by subclasses
     virtual void CocoaSetEnabled(bool enable) { }
-    // Reflects the state for THIS window (ignoring disables by parents)
-    bool m_shouldBeEnabled;
 
     void CocoaCreateNSScrollView();
     void InitMouseEvent(wxMouseEvent &event, WX_NSEvent cocoaEvent);
@@ -198,7 +193,7 @@ public:
     // NOTE: typically Close() is not virtual, but we want this for Cocoa
     virtual bool Close( bool force = false );
     virtual bool Show( bool show = true );
-    virtual bool Enable( bool enable = true );
+    virtual void DoEnable( bool enable );
 
     virtual bool IsDoubleBuffered() const { return true; }
 };
diff --git a/include/wx/gtk/textctrl.h b/include/wx/gtk/textctrl.h
index 510cdbd91e..0d5c118934 100644
--- a/include/wx/gtk/textctrl.h
+++ b/include/wx/gtk/textctrl.h
@@ -155,7 +155,7 @@ public:
     // wxGTK-specific: called recursively by Enable,
     // to give widgets an oppprtunity to correct their colours after they
     // have been changed by Enable
-    virtual void OnParentEnable( bool enable ) ;
+    virtual void OnEnabled( bool enable ) ;
 
     // tell the control to ignore next text changed signal
     void IgnoreNextTextUpdate(int n = 1) { m_countUpdatesToIgnore = n; }
diff --git a/include/wx/gtk/window.h b/include/wx/gtk/window.h
index 9761331c2c..9c92179ca3 100644
--- a/include/wx/gtk/window.h
+++ b/include/wx/gtk/window.h
@@ -61,7 +61,7 @@ public:
     virtual void Lower();
 
     virtual bool Show( bool show = true );
-    virtual bool Enable( bool enable = true );
+    virtual void DoEnable( bool enable );
 
     virtual void SetWindowStyleFlag( long style );
 
@@ -141,11 +141,6 @@ public:
     // For compatibility across platforms (not in event table)
     void OnIdle(wxIdleEvent& WXUNUSED(event)) {}
 
-    // wxGTK-specific: called recursively by Enable,
-    // to give widgets an opportunity to correct their colours after they
-    // have been changed by Enable
-    virtual void OnParentEnable( bool WXUNUSED(enable) ) {}
-
     // Used by all window classes in the widget creation process.
     bool PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size );
     void PostCreation();
diff --git a/include/wx/gtk1/textctrl.h b/include/wx/gtk1/textctrl.h
index f42b1b8193..5abad1b57b 100644
--- a/include/wx/gtk1/textctrl.h
+++ b/include/wx/gtk1/textctrl.h
@@ -106,7 +106,7 @@ public:
     virtual void SetSelection(long from, long to);
     virtual void SetEditable(bool editable);
 
-    virtual bool Enable( bool enable = true );
+    virtual void DoEnable( bool enable );
 
     // Implementation from now on
     void OnDropFiles( wxDropFilesEvent &event );
@@ -153,7 +153,7 @@ public:
     // wxGTK-specific: called recursively by Enable,
     // to give widgets an oppprtunity to correct their colours after they
     // have been changed by Enable
-    virtual void OnParentEnable( bool enable ) ;
+    virtual void OnEnabled( bool enabled ) ;
 
     // tell the control to ignore next text changed signal
     void IgnoreNextTextUpdate();
diff --git a/include/wx/gtk1/window.h b/include/wx/gtk1/window.h
index 21adf05d3c..c1f6a490cc 100644
--- a/include/wx/gtk1/window.h
+++ b/include/wx/gtk1/window.h
@@ -57,7 +57,7 @@ public:
     virtual void Lower();
 
     virtual bool Show( bool show = true );
-    virtual bool Enable( bool enable = true );
+    virtual void DoEnable( bool enable );
 
     virtual void SetWindowStyleFlag( long style );
 
@@ -126,11 +126,6 @@ public:
     // For compatibility across platforms (not in event table)
     void OnIdle(wxIdleEvent& WXUNUSED(event)) {}
 
-    // wxGTK-specific: called recursively by Enable,
-    // to give widgets an opportunity to correct their colours after they
-    // have been changed by Enable
-    virtual void OnParentEnable( bool WXUNUSED(enable) ) {}
-
     // Used by all window classes in the widget creation process.
     bool PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size );
     void PostCreation();
diff --git a/include/wx/mac/carbon/window.h b/include/wx/mac/carbon/window.h
index 05b6163644..097890bf33 100644
--- a/include/wx/mac/carbon/window.h
+++ b/include/wx/mac/carbon/window.h
@@ -55,7 +55,8 @@ public:
     virtual void Lower();
 
     virtual bool Show( bool show = true );
-    virtual bool Enable( bool enable = true );
+    virtual void DoEnable( bool enable );
+    virtual void OnEnabled( bool enabled );
 
     virtual void SetFocus();
 
@@ -310,7 +311,6 @@ protected:
     void                MacUpdateControlFont() ;
 
     void                MacPropagateVisibilityChanged() ;
-    void                MacPropagateEnabledStateChanged() ;
     void                MacPropagateHiliteChanged() ;
 
     // implement the base class pure virtuals
diff --git a/include/wx/msw/window.h b/include/wx/msw/window.h
index 6552fc69ef..8f846c2c9f 100644
--- a/include/wx/msw/window.h
+++ b/include/wx/msw/window.h
@@ -60,7 +60,7 @@ public:
     virtual void Lower();
 
     virtual bool Show( bool show = true );
-    virtual bool Enable( bool enable = true );
+    virtual void DoEnable( bool enable );
 
     virtual void SetFocus();
     virtual void SetFocusFromKbd();
@@ -500,8 +500,6 @@ private:
     bool HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags);
     bool HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result);
 
-    // list of disabled children before last call to our Disable()
-    wxWindowList *m_childrenDisabled;
 
     // number of calls to Freeze() minus number of calls to Thaw()
     unsigned int m_frozenness;
diff --git a/include/wx/os2/window.h b/include/wx/os2/window.h
index 2620abf79d..4e035fa4df 100644
--- a/include/wx/os2/window.h
+++ b/include/wx/os2/window.h
@@ -82,7 +82,7 @@ public:
     virtual void     Raise(void);
     virtual void     Lower(void);
     virtual bool     Show(bool bShow = true);
-    virtual bool     Enable(bool bEnable = true);
+    virtual void     DoEnable(bool bEnable);
     virtual void     SetFocus(void);
     virtual void     SetFocusFromKbd(void);
     virtual bool     Reparent(wxWindow* pNewParent);
@@ -528,7 +528,6 @@ private:
                               ,WXWPARAM    wParam = 0
                              ) const;
 
-    wxWindowList*                   m_pChildrenDisabled;
     HWND                            m_hWndScrollBarHorz;
     HWND                            m_hWndScrollBarVert;
     SWP                             m_vWinSwp;
diff --git a/include/wx/palmos/window.h b/include/wx/palmos/window.h
index ff7d21b46d..81cddb3611 100644
--- a/include/wx/palmos/window.h
+++ b/include/wx/palmos/window.h
@@ -270,9 +270,6 @@ private:
     bool HandleMoving(wxRect& rect);
     bool HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags);
 
-    // list of disabled children before last call to our Disable()
-    wxWindowList *m_childrenDisabled;
-
     // number of calls to Freeze() minus number of calls to Thaw()
     unsigned int m_frozenness;
 
diff --git a/include/wx/window.h b/include/wx/window.h
index 733f3d02da..9e73245752 100644
--- a/include/wx/window.h
+++ b/include/wx/window.h
@@ -49,6 +49,19 @@
     #define wxUSE_MENUS_NATIVE wxUSE_MENUS
 #endif // __WXUNIVERSAL__/!__WXUNIVERSAL__
 
+
+// Define this macro if the corresponding operating system handles the state
+// of children windows automatically when the parent is enabled/disabled.
+// Otherwise wx itself must ensure that when the parent is disabled its
+// children are disabled too, and their initial state is restored when the
+// parent is enabled back.
+#if defined(__WXMSW__) || defined(__WXPM__)
+    // must do everything ourselves
+    #undef wxHAS_NATIVE_ENABLED_MANAGEMENT
+#else
+    #define wxHAS_NATIVE_ENABLED_MANAGEMENT
+#endif
+
 // ----------------------------------------------------------------------------
 // forward declarations
 // ----------------------------------------------------------------------------
@@ -366,7 +379,7 @@ public:
     void SetInitialSize(const wxSize& size=wxDefaultSize);
     wxDEPRECATED( void SetBestFittingSize(const wxSize& size=wxDefaultSize) );  // replaced by SetInitialSize
 
-    
+
         // the generic centre function - centers the window on parent by`
         // default or on screen if it doesn't have parent or
         // wxCENTER_ON_SCREEN flag is given
@@ -389,7 +402,7 @@ public:
         // and it is therefore overridden in wxTLW to do that.
         // In wxWindow(Base), it has (unfortunately) been abused
         // to mean the same as SetMinSize() and SetMaxSize().
-        
+
     virtual void SetSizeHints( int minW, int minH,
                                int maxW = wxDefaultCoord, int maxH = wxDefaultCoord,
                                int incW = wxDefaultCoord, int incH = wxDefaultCoord )
@@ -416,14 +429,14 @@ public:
     }
 
 
-        // Call these to override what GetBestSize() returns. This 
+        // Call these to override what GetBestSize() returns. This
         // method is only virtual because it is overriden in wxTLW
         // as a different API for SetSizeHints().
     virtual void SetMinSize(const wxSize& minSize) { m_minWidth = minSize.x; m_minHeight = minSize.y; }
     virtual void SetMaxSize(const wxSize& maxSize) { m_maxWidth = maxSize.x; m_maxHeight = maxSize.y; }
 
         // Override these methods to impose restrictions on min/max size.
-        // The easier way is to call SetMinSize() and SetMaxSize() which  
+        // The easier way is to call SetMinSize() and SetMaxSize() which
         // will have the same effect. Doing both is non-sense.
     virtual wxSize GetMinSize() const { return wxSize(m_minWidth, m_minHeight); }
     virtual wxSize GetMaxSize() const { return wxSize(m_maxWidth, m_maxHeight); }
@@ -491,7 +504,21 @@ public:
     bool Disable() { return Enable(false); }
 
     virtual bool IsShown() const { return m_isShown; }
-    virtual bool IsEnabled() const { return m_isEnabled; }
+        // returns true if the window is really enabled and false otherwise,
+        // whether because it had been explicitly disabled itself or because
+        // its parent is currently disabled -- then this method returns false
+        // whatever is the intrinsic state of this window, use IsThisEnabled(0
+        // to retrieve it. In other words, this relation always holds:
+        //
+        //   IsEnabled() == IsThisEnabled() && parent.IsEnabled()
+        //
+    bool IsEnabled() const;
+
+        // returns the internal window state independently of the parent(s)
+        // state, i.e. the state in which the window would be if all its
+        // parents were enabled (use IsEnabled() above to get the effective
+        // window state)
+    bool IsThisEnabled() const { return m_isEnabled; }
 
     // returns true if the window is visible, i.e. IsShown() returns true
     // if called on it and all its parents up to the first TLW
@@ -1174,6 +1201,18 @@ protected:
     virtual wxWindow *GetMainWindowOfCompositeControl()
         { return (wxWindow*)this; }
 
+    // this method should be implemented to use operating system specific code
+    // to really enable/disable the widget, it will only be called when we
+    // really need to enable/disable window and so no additional checks on the
+    // widgets state are necessary
+    virtual void DoEnable(bool WXUNUSED(enable)) { }
+
+    // called when the on-screen widget state changes and provides an
+    // an opportunity for the widget to update its visual state (colours,
+    // fonts, anything else) as necessary
+    virtual void OnEnabled(bool WXUNUSED(enabled)) { }
+
+
     // the window id - a number which uniquely identifies a window among
     // its siblings unless it is wxID_ANY
     wxWindowID           m_windowId;
@@ -1394,6 +1433,12 @@ protected:
     static void NotifyCaptureLost();
 
 private:
+    // recursively call our own and our children OnEnabled() when the
+    // enabled/disabled status changed because a parent window had been
+    // enabled/disabled
+    void NotifyWindowOnEnableChange(bool enabled);
+
+
     // contains the last id generated by NewControlId
     static int ms_lastControlId;
 
diff --git a/samples/controls/controls.cpp b/samples/controls/controls.cpp
index aa66f2672c..6ca2a7abd4 100644
--- a/samples/controls/controls.cpp
+++ b/samples/controls/controls.cpp
@@ -190,6 +190,8 @@ public:
 #endif // wxUSE_TOOLTIPS
 
     void OnEnableAll(wxCommandEvent& event);
+    void OnHideAll(wxCommandEvent& event);
+    void OnHideList(wxCommandEvent& event);
     void OnContextHelp(wxCommandEvent& event);
 
     void OnIdle( wxIdleEvent& event );
@@ -381,6 +383,8 @@ enum
 
     // panel menu
     CONTROLS_ENABLE_ALL,
+    CONTROLS_HIDE_ALL,
+    CONTROLS_HIDE_LIST,
     CONTROLS_CONTEXT_HELP
 };
 
@@ -1739,6 +1743,8 @@ BEGIN_EVENT_TABLE(MyFrame, wxFrame)
 #endif // wxUSE_TOOLTIPS
 
     EVT_MENU(CONTROLS_ENABLE_ALL, MyFrame::OnEnableAll)
+    EVT_MENU(CONTROLS_HIDE_ALL,   MyFrame::OnHideAll)
+    EVT_MENU(CONTROLS_HIDE_LIST,   MyFrame::OnHideList)
     EVT_MENU(CONTROLS_CONTEXT_HELP, MyFrame::OnContextHelp)
 
     EVT_ICONIZE(MyFrame::OnIconized)
@@ -1786,6 +1792,10 @@ MyFrame::MyFrame(const wxChar *title, int x, int y)
     wxMenu *panel_menu = new wxMenu;
     panel_menu->Append(CONTROLS_ENABLE_ALL, _T("&Disable all\tCtrl-E"),
                        _T("Enable/disable all panel controls"), true);
+    panel_menu->Append(CONTROLS_HIDE_ALL, _T("&Hide all\tCtrl-I"),
+                       _T("Show/hide thoe whole panel controls"), true);
+    panel_menu->Append(CONTROLS_HIDE_LIST, _T("Hide &list ctrl\tCtrl-S"),
+                       _T("Enable/disable all panel controls"), true);
     panel_menu->Append(CONTROLS_CONTEXT_HELP, _T("&Context help...\tCtrl-H"),
                        _T("Get context help for a control"));
     menu_bar->Append(panel_menu, _T("&Panel"));
@@ -1857,6 +1867,31 @@ void MyFrame::OnEnableAll(wxCommandEvent& WXUNUSED(event))
 
     s_enable = !s_enable;
     m_panel->Enable(s_enable);
+    static bool s_enableCheckbox = true;
+    if ( !s_enable )
+    {
+        // this is a test for correct behaviour of either enabling or disabling
+        // a child when its parent is disabled: the checkbox should have the
+        // correct state when the parent is enabled back
+        m_panel->m_checkbox->Enable(s_enableCheckbox);
+        s_enableCheckbox = !s_enableCheckbox;
+    }
+}
+
+void MyFrame::OnHideAll(wxCommandEvent& WXUNUSED(event))
+{
+    static bool s_show = true;
+
+    s_show = !s_show;
+    m_panel->Show(s_show);
+}
+
+void MyFrame::OnHideList(wxCommandEvent& WXUNUSED(event))
+{
+    static bool s_show = true;
+
+    s_show = !s_show;
+    m_panel->m_listbox->Show(s_show);
 }
 
 void MyFrame::OnContextHelp(wxCommandEvent& WXUNUSED(event))
diff --git a/src/cocoa/window.mm b/src/cocoa/window.mm
index 74ea906beb..91bb13ef99 100644
--- a/src/cocoa/window.mm
+++ b/src/cocoa/window.mm
@@ -313,7 +313,6 @@ void wxWindowCocoa::Init()
     m_wxCocoaScrollView = NULL;
     m_isBeingDeleted = false;
     m_isInPaint = false;
-    m_shouldBeEnabled = true;
 }
 
 // Constructor
@@ -601,32 +600,9 @@ void wxWindow::CocoaReplaceView(WX_NSView oldView, WX_NSView newView)
     [[oldView superview] replaceSubview:oldView with:newView];
 }
 
-bool wxWindow::EnableSelfAndChildren(bool enable)
+void wxWindow::DoEnable(bool enable)
 {
-    // If the state isn't changing, don't do anything
-    if(!wxWindowBase::Enable(enable && m_shouldBeEnabled))
-        return false;
-    // Set the state of the Cocoa window
-    CocoaSetEnabled(m_isEnabled);
-    // Disable all children or (if enabling) return them to their proper state
-    for(wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
-        node; node = node->GetNext())
-    {
-        node->GetData()->EnableSelfAndChildren(enable);
-    }
-    return true;
-}
-
-bool wxWindow::Enable(bool enable)
-{
-    // Keep track of what the window SHOULD be doing
-    m_shouldBeEnabled = enable;
-    // If the parent is disabled for any reason, then this window will be too.
-    if(!IsTopLevel() && GetParent())
-    {
-        enable = enable && GetParent()->IsEnabled();
-    }
-    return EnableSelfAndChildren(enable);
+	CocoaSetEnabled(enable);
 }
 
 bool wxWindow::Show(bool show)
diff --git a/src/common/wincmn.cpp b/src/common/wincmn.cpp
index 41c8a455bd..51b6e771c3 100644
--- a/src/common/wincmn.cpp
+++ b/src/common/wincmn.cpp
@@ -858,18 +858,55 @@ bool wxWindowBase::Show(bool show)
     }
 }
 
-bool wxWindowBase::Enable(bool enable)
+bool wxWindowBase::IsEnabled() const
 {
-    if ( enable != m_isEnabled )
-    {
-        m_isEnabled = enable;
+    return IsThisEnabled() && (IsTopLevel() || !GetParent() || GetParent()->IsEnabled());
+}
 
-        return true;
-    }
-    else
+void wxWindowBase::NotifyWindowOnEnableChange(bool enabled)
+{
+#ifndef wxHAS_NATIVE_ENABLED_MANAGEMENT
+    DoEnable(enabled);
+#endif // !defined(wxHAS_NATIVE_ENABLED_MANAGEMENT)
+
+    OnEnabled(enabled);
+
+    // If we are top-level then the logic doesn't apply - otherwise
+    // showing a modal dialog would result in total greying out (and ungreying
+    // out later) of everything which would be really ugly
+    if ( IsTopLevel() )
+        return;
+
+    for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+          node;
+          node = node->GetNext() )
     {
+        wxWindowBase * const child = node->GetData();
+        if ( !child->IsTopLevel() && child->IsThisEnabled() )
+            child->NotifyWindowOnEnableChange(enabled);
+    }
+}
+
+bool wxWindowBase::Enable(bool enable)
+{
+    if ( enable == IsThisEnabled() )
         return false;
+
+    m_isEnabled = enable;
+
+#ifdef wxHAS_NATIVE_ENABLED_MANAGEMENT
+    DoEnable(enable);
+#else // !defined(wxHAS_NATIVE_ENABLED_MANAGEMENT)
+    wxWindowBase * const parent = GetParent();
+    if( !IsTopLevel() && parent && !parent->IsEnabled() )
+    {
+        return true;
     }
+#endif // !defined(wxHAS_NATIVE_ENABLED_MANAGEMENT)
+
+    NotifyWindowOnEnableChange(enable);
+
+    return true;
 }
 
 bool wxWindowBase::IsShownOnScreen() const
@@ -921,6 +958,8 @@ bool wxWindowBase::Reparent(wxWindowBase *newParent)
         return false;
     }
 
+    const bool oldEnabledState = IsEnabled();
+
     // unlink this window from the existing parent.
     if ( oldParent )
     {
@@ -941,6 +980,14 @@ bool wxWindowBase::Reparent(wxWindowBase *newParent)
         wxTopLevelWindows.Append((wxWindow *)this);
     }
 
+    // We need to notify window (and its subwindows) if by changing the parent
+    // we also change our enabled/disabled status.
+    const bool newEnabledState = IsEnabled();
+    if ( newEnabledState != oldEnabledState )
+    {
+        NotifyWindowOnEnableChange(newEnabledState);
+    }
+
     return true;
 }
 
diff --git a/src/gtk/bmpbuttn.cpp b/src/gtk/bmpbuttn.cpp
index 656db887dc..cc9f6d14e7 100644
--- a/src/gtk/bmpbuttn.cpp
+++ b/src/gtk/bmpbuttn.cpp
@@ -196,7 +196,7 @@ void wxBitmapButton::OnSetBitmap()
     InvalidateBestSize();
 
     wxBitmap the_one;
-    if (!m_isEnabled)
+    if (!IsThisEnabled())
         the_one = m_bmpDisabled;
     else if (m_isSelected)
         the_one = m_bmpSelected;
diff --git a/src/gtk/textctrl.cpp b/src/gtk/textctrl.cpp
index 4518dbd729..7c574619e3 100644
--- a/src/gtk/textctrl.cpp
+++ b/src/gtk/textctrl.cpp
@@ -1288,9 +1288,9 @@ bool wxTextCtrl::Enable( bool enable )
 }
 
 // wxGTK-specific: called recursively by Enable,
-// to give widgets an oppprtunity to correct their colours after they
+// to give widgets an opportunity to correct their colours after they
 // have been changed by Enable
-void wxTextCtrl::OnParentEnable( bool enable )
+void wxTextCtrl::OnEnabled( bool enable )
 {
     // If we have a custom background colour, we use this colour in both
     // disabled and enabled mode, or we end up with a different colour under the
diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp
index 724b780866..1dbf515853 100644
--- a/src/gtk/window.cpp
+++ b/src/gtk/window.cpp
@@ -3021,40 +3021,13 @@ bool wxWindowGTK::Show( bool show )
     return true;
 }
 
-static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable)
+void wxWindowGTK::DoEnable( bool enable )
 {
-    win->OnParentEnable(enable);
-
-    // Recurse, so that children have the opportunity to Do The Right Thing
-    // and reset colours that have been messed up by a parent's (really ancestor's)
-    // Enable call
-    for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
-          node;
-          node = node->GetNext() )
-    {
-        wxWindow *child = node->GetData();
-        if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame)))
-            wxWindowNotifyEnable(child, enable);
-    }
-}
-
-bool wxWindowGTK::Enable( bool enable )
-{
-    wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
-
-    if (!wxWindowBase::Enable(enable))
-    {
-        // nothing to do
-        return false;
-    }
+    wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
 
     gtk_widget_set_sensitive( m_widget, enable );
     if ( m_wxwindow )
         gtk_widget_set_sensitive( m_wxwindow, enable );
-
-    wxWindowNotifyEnable(this, enable);
-
-    return true;
 }
 
 int wxWindowGTK::GetCharHeight() const
diff --git a/src/gtk1/bmpbuttn.cpp b/src/gtk1/bmpbuttn.cpp
index 1d0c7ce962..91ed882377 100644
--- a/src/gtk1/bmpbuttn.cpp
+++ b/src/gtk1/bmpbuttn.cpp
@@ -202,7 +202,7 @@ void wxBitmapButton::OnSetBitmap()
     InvalidateBestSize();
 
     wxBitmap the_one;
-    if (!m_isEnabled)
+    if (!IsThisEnabled())
         the_one = m_bmpDisabled;
     else if (m_isSelected)
         the_one = m_bmpSelected;
diff --git a/src/gtk1/textctrl.cpp b/src/gtk1/textctrl.cpp
index 147486f864..b789f65908 100644
--- a/src/gtk1/textctrl.cpp
+++ b/src/gtk1/textctrl.cpp
@@ -690,32 +690,26 @@ void wxTextCtrl::SetEditable( bool editable )
     }
 }
 
-bool wxTextCtrl::Enable( bool enable )
+void wxTextCtrl::DoEnable( bool enable )
 {
-    if (!wxWindowBase::Enable(enable))
-    {
-        // nothing to do
-        return false;
-    }
-
     if (m_windowStyle & wxTE_MULTILINE)
     {
         gtk_text_set_editable( GTK_TEXT(m_text), enable );
-        OnParentEnable(enable);
     }
     else
     {
         gtk_widget_set_sensitive( m_text, enable );
     }
-
-    return true;
 }
 
 // wxGTK-specific: called recursively by Enable,
 // to give widgets an oppprtunity to correct their colours after they
 // have been changed by Enable
-void wxTextCtrl::OnParentEnable( bool enable )
+void wxTextCtrl::OnEnabled( bool enable )
 {
+    if ( IsSingleLine() )
+        return;
+
     // If we have a custom background colour, we use this colour in both
     // disabled and enabled mode, or we end up with a different colour under the
     // text.
diff --git a/src/gtk1/window.cpp b/src/gtk1/window.cpp
index 12b9216ad7..7405f73826 100644
--- a/src/gtk1/window.cpp
+++ b/src/gtk1/window.cpp
@@ -3203,40 +3203,13 @@ bool wxWindowGTK::Show( bool show )
     return true;
 }
 
-static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable)
-{
-    win->OnParentEnable(enable);
-
-    // Recurse, so that children have the opportunity to Do The Right Thing
-    // and reset colours that have been messed up by a parent's (really ancestor's)
-    // Enable call
-    for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
-          node;
-          node = node->GetNext() )
-    {
-        wxWindow *child = node->GetData();
-        if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame)))
-            wxWindowNotifyEnable(child, enable);
-    }
-}
-
-bool wxWindowGTK::Enable( bool enable )
+void wxWindowGTK::DoEnable( bool enable )
 {
     wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
 
-    if (!wxWindowBase::Enable(enable))
-    {
-        // nothing to do
-        return false;
-    }
-
     gtk_widget_set_sensitive( m_widget, enable );
     if ( m_wxwindow )
         gtk_widget_set_sensitive( m_wxwindow, enable );
-
-    wxWindowNotifyEnable(this, enable);
-
-    return true;
 }
 
 int wxWindowGTK::GetCharHeight() const
diff --git a/src/mac/carbon/window.cpp b/src/mac/carbon/window.cpp
index e141745c0c..f66371e586 100644
--- a/src/mac/carbon/window.cpp
+++ b/src/mac/carbon/window.cpp
@@ -2139,19 +2139,9 @@ bool wxWindowMac::Show(bool show)
     return true;
 }
 
-bool wxWindowMac::Enable(bool enable)
+void wxWindowMac::DoEnable(bool enable)
 {
-    wxASSERT( m_peer->Ok() ) ;
-    bool former = MacIsReallyEnabled() ;
-    if ( !wxWindowBase::Enable(enable) )
-        return false;
-
     m_peer->Enable( enable ) ;
-
-    if ( former != MacIsReallyEnabled() )
-        MacPropagateEnabledStateChanged() ;
-
-    return true;
 }
 
 //
@@ -2176,21 +2166,10 @@ void wxWindowMac::MacPropagateVisibilityChanged()
 #endif
 }
 
-void wxWindowMac::MacPropagateEnabledStateChanged()
+void wxWindowMac::OnEnabled(bool enabled)
 {
 #if !TARGET_API_MAC_OSX
     MacEnabledStateChanged() ;
-
-    wxWindowMac *child;
-    wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
-    while ( node )
-    {
-        child = node->GetData();
-        if ( child->IsEnabled() )
-            child->MacPropagateEnabledStateChanged() ;
-
-        node = node->GetNext();
-    }
 #endif
 }
 
diff --git a/src/msw/window.cpp b/src/msw/window.cpp
index 080310c83c..e04a5e4b60 100644
--- a/src/msw/window.cpp
+++ b/src/msw/window.cpp
@@ -484,7 +484,6 @@ void wxWindowMSW::Init()
     m_mouseInWindow = false;
     m_lastKeydownProcessed = false;
 
-    m_childrenDisabled = NULL;
     m_frozenness = 0;
 
     m_hWnd = 0;
@@ -545,8 +544,6 @@ wxWindowMSW::~wxWindowMSW()
         wxRemoveHandleAssociation(this);
     }
 
-    delete m_childrenDisabled;
-
 }
 
 // real construction (Init() must have been called before!)
@@ -648,110 +645,11 @@ wxWindow *wxWindowBase::DoFindFocus()
     return NULL;
 }
 
-bool wxWindowMSW::Enable(bool enable)
+void wxWindowMSW::DoEnable( bool enable )
 {
-    // we shouldn't really enable the window if our parent is currently
-    // disabled because under MSW this would indeed show the window in enabled
-    // state but it still wouldn't respond to the input (as its parent is
-    // disabled), so just update the internal m_childrenDisabled list in this
-    // case and our state will be really changed when the parent is enabled
-
-    // the logic above doesn't apply to top level windows, of course
-    wxWindowMSW * const parent = IsTopLevel() ? NULL : GetParent();
-    if ( parent && !parent->IsEnabled() && !IsEnabled() )
-    {
-        // it's a reference as we can create it below
-        wxWindowList *& disabledSiblings = parent->m_childrenDisabled;
-
-        bool rc = false;
-        if ( enable )
-        {
-            // shouldn't be disabled when the parent is reenabled
-            if ( disabledSiblings )
-            {
-                wxWindowList::compatibility_iterator
-                    i = disabledSiblings->Find(this);
-                if ( i )
-                {
-                    disabledSiblings->Erase(i);
-                    rc = true;
-                }
-            }
-            //else: nothing to do
-        }
-        else // !enable
-        {
-            // should disable this window when the parent is enabled
-            if ( !disabledSiblings )
-                disabledSiblings = new wxWindowList;
-
-            disabledSiblings->Append(this);
-        }
-
-        return rc;
-    }
-
-    if ( !wxWindowBase::Enable(enable) )
-        return false;
-
     HWND hWnd = GetHwnd();
     if ( hWnd )
         ::EnableWindow(hWnd, (BOOL)enable);
-
-    // the logic below doesn't apply to the top level windows -- otherwise
-    // showing a modal dialog would result in total greying out (and ungreying
-    // out later) of everything which would be really ugly
-    if ( IsTopLevel() )
-        return true;
-
-    // when the parent is disabled, all of its children should be disabled as
-    // well but when it is enabled back, only those of the children which
-    // hadn't been already disabled in the beginning should be enabled again,
-    // so we have to keep the list of those children
-    for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
-          node;
-          node = node->GetNext() )
-    {
-        wxWindow *child = node->GetData();
-        if ( child->IsTopLevel() )
-        {
-            // the logic below doesn't apply to top level children
-            continue;
-        }
-
-        if ( enable )
-        {
-            // re-enable the child unless it had been disabled before us
-            if ( !m_childrenDisabled || !m_childrenDisabled->Find(child) )
-                child->Enable();
-        }
-        else // we're being disabled
-        {
-            if ( child->IsEnabled() )
-            {
-                // disable it as children shouldn't stay enabled while the
-                // parent is not
-                child->Disable();
-            }
-            else // child already disabled, remember it
-            {
-                // have we created the list of disabled children already?
-                if ( !m_childrenDisabled )
-                    m_childrenDisabled = new wxWindowList;
-
-                m_childrenDisabled->Append(child);
-            }
-        }
-    }
-
-    if ( enable && m_childrenDisabled )
-    {
-        // we don't need this list any more, don't keep unused memory
-        delete m_childrenDisabled;
-        m_childrenDisabled = NULL;
-    }
-
-    return true;
 }
 
 bool wxWindowMSW::Show(bool show)
diff --git a/src/os2/window.cpp b/src/os2/window.cpp
index c41347074c..3a80c6337d 100644
--- a/src/os2/window.cpp
+++ b/src/os2/window.cpp
@@ -295,7 +295,6 @@ void wxWindowOS2::Init()
     m_bUseCtl3D             = false;
     m_bMouseInWindow        = false;
     m_bLastKeydownProcessed = false;
-    m_pChildrenDisabled     = NULL;
 
     //
     // wxWnd
@@ -357,7 +356,6 @@ wxWindowOS2::~wxWindowOS2()
         //
         wxRemoveHandleAssociation(this);
     }
-    delete m_pChildrenDisabled;
 } // end of wxWindowOS2::~wxWindowOS2
 
 // real construction (Init() must have been called before!)
@@ -479,70 +477,12 @@ wxWindow* wxWindowBase::DoFindFocus()
     return NULL;
 } // wxWindowBase::DoFindFocus
 
-bool wxWindowOS2::Enable( bool bEnable )
+void wxWindowOS2::DoEnable( bool bEnable )
 {
-    if (!wxWindowBase::Enable(bEnable))
-        return false;
-
     HWND                            hWnd = GetHwnd();
-
     if ( hWnd )
         ::WinEnableWindow(hWnd, (BOOL)bEnable);
-
-    //
-    // The logic below doesn't apply to the top level windows -- otherwise
-    // showing a modal dialog would result in total greying out (and ungreying
-    // out later) of everything which would be really ugly
-    //
-    if (IsTopLevel())
-        return true;
-
-    wxWindowList::compatibility_iterator     node = GetChildren().GetFirst();
-
-    while (node)
-    {
-        wxWindow*                   pChild = node->GetData();
-
-        if (bEnable)
-        {
-            //
-            // Enable the child back unless it had been disabled before us
-            //
-            if (!m_pChildrenDisabled || !m_pChildrenDisabled->Find(pChild))
-                pChild->Enable();
-        }
-        else // we're being disabled
-        {
-            if (pChild->IsEnabled())
-            {
-                //
-                // Disable it as children shouldn't stay enabled while the
-                // parent is not
-                //
-                pChild->Disable();
-            }
-            else // child already disabled, remember it
-            {
-                //
-                // Have we created the list of disabled children already?
-                //
-                if (!m_pChildrenDisabled)
-                    m_pChildrenDisabled = new wxWindowList;
-                m_pChildrenDisabled->Append(pChild);
-            }
-        }
-        node = node->GetNext();
-    }
-    if (bEnable && m_pChildrenDisabled)
-    {
-        //
-        // We don't need this list any more, don't keep unused memory
-        //
-        delete m_pChildrenDisabled;
-        m_pChildrenDisabled = NULL;
-    }
-    return true;
-} // end of wxWindowOS2::Enable
+}
 
 bool wxWindowOS2::Show( bool bShow )
 {
-- 
2.50.0

