]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/wincmn.cpp
Fix Ok/IsOk() mess in wxGDIObject-derived classes; also added
[wxWidgets.git] / src / common / wincmn.cpp
index 3dc6813f7b86298eebfafe8bfa2806aaa75c0d16..c79c389854d31283884f914182f6801c1f2e6246 100644 (file)
@@ -78,9 +78,6 @@
     #else
         #include <gtk/gtkfeatures.h>
     #endif
-    extern const unsigned int gtk_major_version;
-    extern const unsigned int gtk_minor_version;
-    extern const unsigned int gtk_micro_version;
 #endif
 
 #include "wx/platinfo.h"
@@ -92,13 +89,6 @@ WXDLLIMPEXP_DATA_CORE(wxWindowList) wxTopLevelWindows;
 // static data
 // ----------------------------------------------------------------------------
 
-#if defined(__WXPALMOS__)
-int wxWindowBase::ms_lastControlId = 32767;
-#elif defined(__WXPM__)
-int wxWindowBase::ms_lastControlId = 2000;
-#else
-int wxWindowBase::ms_lastControlId = -200;
-#endif
 
 IMPLEMENT_ABSTRACT_CLASS(wxWindowBase, wxEvtHandler)
 
@@ -177,6 +167,7 @@ wxWindowBase::wxWindowBase()
     m_windowSizer = (wxSizer *) NULL;
     m_containingSizer = (wxSizer *) NULL;
     m_autoLayout = false;
+    m_freeId = false;
 
 #if wxUSE_DRAG_AND_DROP
     m_dropTarget = (wxDropTarget *)NULL;
@@ -202,11 +193,6 @@ wxWindowBase::wxWindowBase()
 
     m_scrollHelper = (wxScrollHelper *) NULL;
 
-    m_minVirtualWidth =
-    m_maxVirtualWidth = wxDefaultCoord;
-    m_minVirtualHeight =
-    m_maxVirtualHeight = wxDefaultCoord;
-
     m_windowVariant = wxWINDOW_VARIANT_NORMAL;
 #if wxUSE_SYSTEM_OPTIONS
     if ( wxSystemOptions::HasOption(wxWINDOW_DEFAULT_VARIANT) )
@@ -245,14 +231,29 @@ bool wxWindowBase::CreateBase(wxWindowBase *parent,
     // 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),
+    wxASSERT_MSG( id == wxID_ANY || (id >= 0 && id < 32767) ||
+                  (id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST),
                   _T("invalid id value") );
 
     // generate a new id if the user doesn't care about it
-    m_windowId = id == wxID_ANY ? NewControlId() : id;
+    if ( id == wxID_ANY )
+    {
+        m_windowId = NewControlId();
+
+        // remember to call ReleaseControlId() when this window is destroyed
+        m_freeId = true;
+    }
+    else // valid id specified
+    {
+        m_windowId = id;
+    }
+
+    // don't use SetWindowStyleFlag() here, this function should only be called
+    // to change the flag after creation as it tries to reflect the changes in
+    // flags by updating the window dynamically and we don't need this here
+    m_windowStyle = style;
 
     SetName(name);
-    SetWindowStyleFlag(style);
     SetParent(parent);
 
 #if wxUSE_VALIDATORS
@@ -270,6 +271,28 @@ bool wxWindowBase::CreateBase(wxWindowBase *parent,
     return true;
 }
 
+bool wxWindowBase::ToggleWindowStyle(int flag)
+{
+    wxASSERT_MSG( flag, _T("flags with 0 value can't be toggled") );
+
+    bool rc;
+    long style = GetWindowStyleFlag();
+    if ( style & flag )
+    {
+        style &= ~flag;
+        rc = false;
+    }
+    else // currently off
+    {
+        style |= flag;
+        rc = true;
+    }
+
+    SetWindowStyleFlag(style);
+
+    return rc;
+}
+
 // ----------------------------------------------------------------------------
 // destruction
 // ----------------------------------------------------------------------------
@@ -279,6 +302,10 @@ wxWindowBase::~wxWindowBase()
 {
     wxASSERT_MSG( GetCapture() != this, wxT("attempt to destroy window with mouse capture") );
 
+    // mark the id as unused if we allocated it for this control
+    if ( m_freeId )
+        ReleaseControlId(m_windowId);
+
     // FIXME if these 2 cases result from programming errors in the user code
     //       we should probably assert here instead of silently fixing them
 
@@ -292,23 +319,9 @@ wxWindowBase::~wxWindowBase()
 
     wxASSERT_MSG( GetChildren().GetCount() == 0, wxT("children not destroyed") );
 
-    // reset the top-level parent's default item if it is this widget
+    // notify the parent about this window destruction
     if ( m_parent )
-    {
-        wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent((wxWindow*)this),
-                                              wxTopLevelWindow);
-        
-        if ( tlw && tlw->GetDefaultItem() == this )
-            tlw->SetDefaultItem(NULL);
-        if ( tlw && tlw->GetTmpDefaultItem() == this )
-            tlw->SetTmpDefaultItem(NULL);
-    }
-
-    // reset the dangling pointer our parent window may keep to us
-    if ( m_parent )
-    {
         m_parent->RemoveChild(this);
-    }
 
 #if wxUSE_CARET
     delete m_caret;
@@ -351,6 +364,14 @@ wxWindowBase::~wxWindowBase()
 #endif
 }
 
+void wxWindowBase::SendDestroyEvent()
+{
+    wxWindowDestroyEvent event;
+    event.SetEventObject(this);
+    event.SetId(GetId());
+    GetEventHandler()->ProcessEvent(event);
+}
+
 bool wxWindowBase::Destroy()
 {
     delete this;
@@ -463,7 +484,7 @@ wxSize wxWindowBase::DoGetBestSize() const
 
     if ( m_windowSizer )
     {
-        best = GetWindowSizeForVirtualSize(m_windowSizer->GetMinSize());
+        best = m_windowSizer->GetMinSize();
     }
 #if wxUSE_CONSTRAINTS
     else if ( m_constraints )
@@ -579,8 +600,78 @@ wxSize wxWindowBase::DoGetBestSize() const
     return best;
 }
 
+// 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)
+{
+    int rc = wxSystemSettings::GetMetric(what);
+    if ( rc == -1 )
+    {
+        switch ( what )
+        {
+            case wxSYS_BORDER_X:
+            case wxSYS_BORDER_Y:
+                // 2D border is by default 1 pixel wide
+                rc = 1;
+                break;
+
+            case wxSYS_EDGE_X:
+            case wxSYS_EDGE_Y:
+                // 3D borders are by default 2 pixels
+                rc = 2;
+                break;
+
+            default:
+                wxFAIL_MSG( _T("unexpected wxGetMetricOrDefault() argument") );
+                rc = 0;
+        }
+    }
+
+    return rc;
+}
 
-wxSize wxWindowBase::GetBestFittingSize() const
+wxSize wxWindowBase::GetWindowBorderSize() const
+{
+    wxSize size;
+
+    switch ( GetBorder() )
+    {
+        case wxBORDER_NONE:
+            // nothing to do, size is already (0, 0)
+            break;
+
+        case wxBORDER_SIMPLE:
+        case wxBORDER_STATIC:
+            size.x = wxGetMetricOrDefault(wxSYS_BORDER_X);
+            size.y = wxGetMetricOrDefault(wxSYS_BORDER_Y);
+            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));
+            break;
+
+        case wxBORDER_DOUBLE:
+            size.x = wxGetMetricOrDefault(wxSYS_EDGE_X) +
+                        wxGetMetricOrDefault(wxSYS_BORDER_X);
+            size.y = wxGetMetricOrDefault(wxSYS_EDGE_Y) +
+                        wxGetMetricOrDefault(wxSYS_BORDER_Y);
+            break;
+
+        default:
+            wxFAIL_MSG(_T("Unknown border style."));
+            break;
+    }
+
+    // we have borders on both sides
+    return size*2;
+}
+
+wxSize wxWindowBase::GetEffectiveMinSize() const
 {
     // merge the best size with the min size, giving priority to the min size
     wxSize min = GetMinSize();
@@ -594,14 +685,14 @@ wxSize wxWindowBase::GetBestFittingSize() const
 }
 
 
-void wxWindowBase::SetBestFittingSize(const wxSize& size)
+void wxWindowBase::SetInitialSize(const wxSize& size)
 {
     // Set the min size to the size passed in.  This will usually either be
     // wxDefaultSize or the size passed to this window's ctor/Create function.
     SetMinSize(size);
 
     // Merge the size with the best size if needed
-    wxSize best = GetBestFittingSize();
+    wxSize best = GetEffectiveMinSize();
 
     // If the current size doesn't match then change it
     if (GetSize() != best)
@@ -660,26 +751,35 @@ void wxWindowBase::DoSetWindowVariant( wxWindowVariant variant )
     SetFont(font);
 }
 
-void wxWindowBase::SetVirtualSizeHints( int minW, int minH,
-                                        int maxW, int maxH )
+void wxWindowBase::DoSetSizeHints( int minW, int minH,
+                                   int maxW, int maxH,
+                                   int WXUNUSED(incW), int WXUNUSED(incH) )
 {
-    m_minVirtualWidth = minW;
-    m_maxVirtualWidth = maxW;
-    m_minVirtualHeight = minH;
-    m_maxVirtualHeight = maxH;
+    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!") );
+
+    m_minWidth = minW;
+    m_maxWidth = maxW;
+    m_minHeight = minH;
+    m_maxHeight = maxH;
 }
 
-void wxWindowBase::DoSetVirtualSize( int x, int y )
+
+#if WXWIN_COMPATIBILITY_2_8
+void wxWindowBase::SetVirtualSizeHints(int WXUNUSED(minW), int WXUNUSED(minH),
+                                       int WXUNUSED(maxW), int WXUNUSED(maxH))
+{
+}
+
+void wxWindowBase::SetVirtualSizeHints(const wxSize& WXUNUSED(minsize),
+                                       const wxSize& WXUNUSED(maxsize))
 {
-    if ( m_minVirtualWidth != wxDefaultCoord && m_minVirtualWidth > x )
-        x = m_minVirtualWidth;
-    if ( m_maxVirtualWidth != wxDefaultCoord && m_maxVirtualWidth < x )
-        x = m_maxVirtualWidth;
-    if ( m_minVirtualHeight != wxDefaultCoord && m_minVirtualHeight > y )
-        y = m_minVirtualHeight;
-    if ( m_maxVirtualHeight != wxDefaultCoord && m_maxVirtualHeight < y )
-        y = m_maxVirtualHeight;
+}
+#endif // WXWIN_COMPATIBILITY_2_8
 
+void wxWindowBase::DoSetVirtualSize( int x, int y )
+{
     m_virtualSize = wxSize(x, y);
 }
 
@@ -728,18 +828,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
@@ -791,6 +928,8 @@ bool wxWindowBase::Reparent(wxWindowBase *newParent)
         return false;
     }
 
+    const bool oldEnabledState = IsEnabled();
+
     // unlink this window from the existing parent.
     if ( oldParent )
     {
@@ -811,6 +950,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;
 }
 
@@ -893,6 +1040,11 @@ bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handler)
     return false;
 }
 
+bool wxWindowBase::HandleWindowEvent(wxEvent& event) const
+{
+    return GetEventHandler()->SafelyProcessEvent(event);
+}
+
 // ----------------------------------------------------------------------------
 // colours, fonts &c
 // ----------------------------------------------------------------------------
@@ -979,8 +1131,6 @@ wxColour wxWindowBase::GetForegroundColour() const
     // logic is the same as above
     if ( !m_hasFgCol && !m_foregroundColour.Ok() )
     {
-        wxASSERT_MSG( !m_hasFgCol, _T("we have invalid explicit fg colour?") );
-
         wxColour colFg = GetDefaultAttributes().colFg;
 
         if ( !colFg.Ok() )
@@ -1501,7 +1651,7 @@ void wxWindowBase::OnHelp(wxHelpEvent& event)
 #endif // wxUSE_HELP
 
 // ----------------------------------------------------------------------------
-// tooltipsroot.Replace("\\", "/");
+// tooltips
 // ----------------------------------------------------------------------------
 
 #if wxUSE_TOOLTIPS
@@ -1985,7 +2135,7 @@ void wxWindowBase::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags) co
 }
 
 // ----------------------------------------------------------------------------
-// do Update UI processing for child controls
+// Update UI processing
 // ----------------------------------------------------------------------------
 
 void wxWindowBase::UpdateWindowUI(long flags)
@@ -2020,23 +2170,6 @@ void wxWindowBase::DoUpdateWindowUI(wxUpdateUIEvent& event)
         Show(event.GetShown());
 }
 
-#if 0
-// call internal idle recursively
-// may be obsolete (wait until OnIdle scheme stabilises)
-void wxWindowBase::ProcessInternalIdle()
-{
-    OnInternalIdle();
-
-    wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
-    while (node)
-    {
-        wxWindow *child = node->GetData();
-        child->ProcessInternalIdle();
-        node = node->GetNext();
-    }
-}
-#endif
-
 // ----------------------------------------------------------------------------
 // dialog units translations
 // ----------------------------------------------------------------------------
@@ -2103,6 +2236,47 @@ void wxWindowBase::OnInitDialog( wxInitDialogEvent &WXUNUSED(event) )
     UpdateWindowUI(wxUPDATE_UI_RECURSE);
 }
 
+// ----------------------------------------------------------------------------
+// menu-related functions
+// ----------------------------------------------------------------------------
+
+#if wxUSE_MENUS
+
+// this is used to pass the id of the selected item from the menu event handler
+// to the main function itself
+//
+// it's ok to use a global here as there can be at most one popup menu shown at
+// any time
+static int gs_popupMenuSelection = wxID_NONE;
+
+void wxWindowBase::InternalOnPopupMenu(wxCommandEvent& event)
+{
+    // store the id in a global variable where we'll retrieve it from later
+    gs_popupMenuSelection = event.GetId();
+}
+
+int
+wxWindowBase::DoGetPopupMenuSelectionFromUser(wxMenu& menu, int x, int y)
+{
+    gs_popupMenuSelection = wxID_NONE;
+
+    Connect(wxEVT_COMMAND_MENU_SELECTED,
+            wxCommandEventHandler(wxWindowBase::InternalOnPopupMenu),
+            NULL,
+            this);
+
+    PopupMenu(&menu, x, y);
+
+    Disconnect(wxEVT_COMMAND_MENU_SELECTED,
+               wxCommandEventHandler(wxWindowBase::InternalOnPopupMenu),
+               NULL,
+               this);
+
+    return gs_popupMenuSelection;
+}
+
+#endif // wxUSE_MENUS
+
 // methods for drawing the sizers in a visible way
 #ifdef __WXDEBUG__
 
@@ -2177,45 +2351,9 @@ void wxWindowBase::OnMiddleClick( wxMouseEvent& event )
             return;
         }
 #endif // __WXDEBUG__
-
-#if wxUSE_MSGDLG
-        // don't translate these strings, they're for diagnostics purposes only
-        wxString msg;
-        msg.Printf(_T("wxWidgets Library (%s port)\n")
-                   _T("Version %d.%d.%d%s%s, compiled at %s %s\n")
-                   _T("Runtime version of toolkit used is %d.%d.%s\n")
-                   _T("Copyright (c) 1995-2006 wxWidgets team"),
-                   wxPlatformInfo::Get().GetPortIdName().c_str(),
-                   wxMAJOR_VERSION,
-                   wxMINOR_VERSION,
-                   wxRELEASE_NUMBER,
-#if wxUSE_UNICODE
-                   L" (Unicode)",
-#else
-                   wxEmptyString,
-#endif
-#ifdef __WXDEBUG__
-                   _T(" Debug build"),
-#else
-                   wxEmptyString,
-#endif
-                   __TDATE__,
-                   __TTIME__,
-                   wxPlatformInfo::Get().GetToolkitMajorVersion(),
-                   wxPlatformInfo::Get().GetToolkitMinorVersion(),
-#ifdef __WXGTK__
-                   wxString::Format(_T("\nThe compile-time GTK+ version is %d.%d.%d."), GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION).c_str()
-#else
-                   wxEmptyString
-#endif
-                   );
-
-        wxMessageBox(msg, _T("wxWidgets information"),
-                     wxICON_INFORMATION | wxOK,
-                     (wxWindow *)this);
+        ::wxInfoMessageBox((wxWindow*)this);
     }
     else
-#endif // wxUSE_MSGDLG
     {
         event.Skip();
     }
@@ -2260,14 +2398,14 @@ wxAccessible* wxWindowBase::CreateAccessible()
 #include "wx/listimpl.cpp"
 WX_DEFINE_LIST(wxWindowList)
 
-#else
+#else // !wxUSE_STL
 
 void wxWindowListNode::DeleteData()
 {
     delete (wxWindow *)GetData();
 }
 
-#endif
+#endif // wxUSE_STL/!wxUSE_STL
 
 // ----------------------------------------------------------------------------
 // borders
@@ -2280,6 +2418,10 @@ wxBorder wxWindowBase::GetBorder(long flags) const
     {
         border = GetDefaultBorder();
     }
+    else if ( border == wxBORDER_THEME )
+    {
+        border = GetDefaultBorderForControl();
+    }
 
     return border;
 }
@@ -2385,6 +2527,10 @@ static void DoNotifyWindowAboutCaptureLost(wxWindow *win)
     event.SetEventObject(win);
     if ( !win->GetEventHandler()->ProcessEvent(event) )
     {
+        // windows must handle this event, otherwise the app wouldn't behave
+        // 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") );
     }
 }
@@ -2436,14 +2582,6 @@ bool wxWindowBase::UnregisterHotKey(int WXUNUSED(hotkeyId))
 
 #endif // wxUSE_HOTKEY
 
-void wxWindowBase::SendDestroyEvent()
-{
-    wxWindowDestroyEvent event;
-    event.SetEventObject(this);
-    event.SetId(GetId());
-    GetEventHandler()->ProcessEvent(event);
-}
-
 // ----------------------------------------------------------------------------
 // event processing
 // ----------------------------------------------------------------------------
@@ -2491,24 +2629,47 @@ bool wxWindowBase::TryParent(wxEvent& event)
     return wxEvtHandler::TryParent(event);
 }
 
+// ----------------------------------------------------------------------------
+// window relationships
+// ----------------------------------------------------------------------------
+
+wxWindow *wxWindowBase::DoGetSibling(WindowOrder order) const
+{
+    wxCHECK_MSG( GetParent(), NULL,
+                    _T("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?") );
+
+    if ( order == OrderBefore )
+        i = i->GetPrevious();
+    else // OrderAfter
+        i = i->GetNext();
+
+    return i ? i->GetData() : NULL;
+}
+
 // ----------------------------------------------------------------------------
 // keyboard navigation
 // ----------------------------------------------------------------------------
 
-// Navigates in the specified direction.
-bool wxWindowBase::Navigate(int flags)
+// Navigates in the specified direction inside this window
+bool wxWindowBase::DoNavigateIn(int flags)
 {
+#ifdef wxHAS_NATIVE_TAB_TRAVERSAL
+    // native code doesn't process our wxNavigationKeyEvents anyhow
+    wxUnusedVar(flags);
+    return false;
+#else // !wxHAS_NATIVE_TAB_TRAVERSAL
     wxNavigationKeyEvent eventNav;
     eventNav.SetFlags(flags);
-    eventNav.SetEventObject(this);
-    if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav) )
-    {
-        return true;
-    }
-    return false;
+    eventNav.SetEventObject(FindFocus());
+    return GetEventHandler()->ProcessEvent(eventNav);
+#endif // wxHAS_NATIVE_TAB_TRAVERSAL/!wxHAS_NATIVE_TAB_TRAVERSAL
 }
 
-void wxWindowBase::DoMoveInTabOrder(wxWindow *win, MoveKind move)
+void wxWindowBase::DoMoveInTabOrder(wxWindow *win, WindowOrder move)
 {
     // check that we're not a top level window
     wxCHECK_RET( GetParent(),
@@ -2528,7 +2689,7 @@ void wxWindowBase::DoMoveInTabOrder(wxWindow *win, MoveKind move)
     // can't just move the node around
     wxWindow *self = (wxWindow *)this;
     siblings.DeleteObject(self);
-    if ( move == MoveAfter )
+    if ( move == OrderAfter )
     {
         i = i->GetNext();
     }
@@ -2537,7 +2698,7 @@ void wxWindowBase::DoMoveInTabOrder(wxWindow *win, MoveKind move)
     {
         siblings.Insert(i, self);
     }
-    else // MoveAfter and win was the last sibling
+    else // OrderAfter and win was the last sibling
     {
         siblings.Append(self);
     }
@@ -3007,3 +3168,125 @@ wxWindowBase::AdjustForLayoutDirection(wxCoord x,
     return x;
 }
 
+// ----------------------------------------------------------------------------
+// Window (and menu items) identifiers management
+// ----------------------------------------------------------------------------
+
+namespace
+{
+
+// this array contains, in packed form, the "in use" flags for the entire
+// auto-generated ids range: N-th element of the array contains the flags for
+// ids in [wxID_AUTO_LOWEST + 8*N, wxID_AUTO_LOWEST + 8*N + 7] range
+//
+// initially no ids are in use and we allocate them consecutively, but after we
+// exhaust the entire range, we wrap around and reuse the ids freed in the
+// meanwhile
+wxByte gs_autoIdsInUse[(wxID_AUTO_HIGHEST - wxID_AUTO_LOWEST + 1)/8 + 1] = { 0 };
+
+// this is an optimization used until we wrap around wxID_AUTO_HIGHEST: if this
+// value is < wxID_AUTO_HIGHEST we know that we haven't wrapped yet and so can
+// allocate the ids simply by incrementing it
+static wxWindowID gs_nextControlId = wxID_AUTO_LOWEST;
+
+void MarkAutoIdUsed(wxWindowID id)
+{
+    id -= wxID_AUTO_LOWEST;
+
+    const int theByte = id / 8;
+    const int theBit = id % 8;
+
+    gs_autoIdsInUse[theByte] |= 1 << theBit;
+}
+
+void FreeAutoId(wxWindowID id)
+{
+    id -= wxID_AUTO_LOWEST;
+
+    const int theByte = id / 8;
+    const int theBit = id % 8;
+
+    gs_autoIdsInUse[theByte] &= ~(1 << theBit);
+}
+
+bool IsAutoIdInUse(wxWindowID id)
+{
+    id -= wxID_AUTO_LOWEST;
+
+    const int theByte = id / 8;
+    const int theBit = id % 8;
+
+    return (gs_autoIdsInUse[theByte] & (1 << theBit)) != 0;
+}
+
+} // anonymous namespace
+
+
+/* static */
+bool wxWindowBase::IsAutoGeneratedId(wxWindowID id)
+{
+    if ( id < wxID_AUTO_LOWEST || id > wxID_AUTO_HIGHEST )
+        return false;
+
+    // we shouldn't have any stray ids in this range
+    wxASSERT_MSG( IsAutoIdInUse(id), "unused automatically generated id?" );
+
+    return true;
+}
+
+wxWindowID wxWindowBase::NewControlId(int count)
+{
+    wxASSERT_MSG( count > 0, "can't allocate less than 1 id" );
+
+    if ( gs_nextControlId + count - 1 <= wxID_AUTO_HIGHEST )
+    {
+        // we haven't wrapped yet, so we can just grab the next count ids
+        wxWindowID id = gs_nextControlId;
+
+        while ( count-- )
+            MarkAutoIdUsed(gs_nextControlId++);
+
+        return id;
+    }
+    else // we've already wrapped or are now going to
+    {
+        // brute-force search for the id values
+
+        // number of consecutive free ids found so far
+        int found = 0;
+
+        for ( wxWindowID id = wxID_AUTO_LOWEST; id <= wxID_AUTO_HIGHEST; id++ )
+        {
+            if ( !IsAutoIdInUse(id) )
+            {
+                // found another consecutive available id
+                found++;
+                if ( found == count )
+                {
+                    // mark all count consecutive free ids we found as being in
+                    // use now and rewind back to the start of available range
+                    // in the process
+                    while ( count-- )
+                        MarkAutoIdUsed(id--);
+
+                    return id;
+                }
+            }
+            else // this id is in use
+            {
+                // reset the number of consecutive free values found
+                found = 0;
+            }
+        }
+    }
+
+    // if we get here, there are not enough consecutive free ids
+    return wxID_NONE;
+}
+
+void wxWindowBase::ReleaseControlId(wxWindowID id)
+{
+    wxCHECK_RET( IsAutoGeneratedId(id), "can't release non auto-generated id" );
+
+    FreeAutoId(id);
+}