]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/windowid.cpp
Don't block in wxEventLoopManual::Dispatch() if loop was exited.
[wxWidgets.git] / src / common / windowid.cpp
index 8db065e0151340dc62e51d886e760b13eea50b7e..609188384ca66eab0b1cc26d172fc19c3e9058c6 100644 (file)
     #include "wx/intl.h"
 #endif //WX_PRECOMP
 
+#include "wx/hashmap.h"
+
 // Not needed, included in defs.h
 // #include "wx/windowid.h"
 
-#define wxTRACE_WINDOWID _T("windowid")
+#define wxTRACE_WINDOWID wxT("windowid")
 
 namespace
 {
@@ -38,94 +40,137 @@ namespace
 // meanwhile
 static const wxUint8 ID_FREE = 0;
 static const wxUint8 ID_STARTCOUNT = 1;
-static const wxUint8 ID_MAXCOUNT = 254;
+static const wxUint8 ID_COUNTTOOLARGE = 254;
 static const wxUint8 ID_RESERVED = 255;
 
+// we use a two level count, most IDs will be used less than ID_COUNTTOOLARGE-1
+// thus we store their count directly in this array, however when the same ID
+// is reused a great number of times (more than or equal to ID_COUNTTOOLARGE),
+// the hash map stores the actual count
 wxUint8 gs_autoIdsRefCount[wxID_AUTO_HIGHEST - wxID_AUTO_LOWEST + 1] = { 0 };
 
+// NB: this variable is allocated (again) only when an ID gets at least
+// ID_COUNTTOOLARGE refs, and is freed when the latest entry in the map gets
+// freed. The cell storing the count for an ID is freed only when its count
+// gets to zero (not when it goes below ID_COUNTTOOLARGE, so as to avoid
+// degenerate cases)
+wxLongToLongHashMap *gs_autoIdsLargeRefCount = NULL;
+
 // 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
 wxWindowID gs_nextAutoId = wxID_AUTO_LOWEST;
 
 // Reserve an ID
-void ReserveIdRefCount(wxWindowID id)
+void ReserveIdRefCount(wxWindowID winid)
 {
-    wxCHECK_RET(id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST,
+    wxCHECK_RET(winid >= wxID_AUTO_LOWEST && winid <= wxID_AUTO_HIGHEST,
             wxT("invalid id range"));
 
-    id -= wxID_AUTO_LOWEST;
+    winid -= wxID_AUTO_LOWEST;
 
-    wxCHECK_RET(gs_autoIdsRefCount[id] == ID_FREE,
+    wxCHECK_RET(gs_autoIdsRefCount[winid] == ID_FREE,
             wxT("id already in use or already reserved"));
-    gs_autoIdsRefCount[id] = ID_RESERVED;
+    gs_autoIdsRefCount[winid] = ID_RESERVED;
 }
 
 // Unreserve and id
-void UnreserveIdRefCount(wxWindowID id)
+void UnreserveIdRefCount(wxWindowID winid)
 {
-    wxCHECK_RET(id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST,
+    wxCHECK_RET(winid >= wxID_AUTO_LOWEST && winid <= wxID_AUTO_HIGHEST,
             wxT("invalid id range"));
 
-    id -= wxID_AUTO_LOWEST;
+    winid -= wxID_AUTO_LOWEST;
 
-    wxCHECK_RET(gs_autoIdsRefCount[id] == ID_RESERVED,
+    wxCHECK_RET(gs_autoIdsRefCount[winid] == ID_RESERVED,
             wxT("id already in use or not reserved"));
-    gs_autoIdsRefCount[id] = ID_FREE;
+    gs_autoIdsRefCount[winid] = ID_FREE;
 }
 
 // Get the usage count of an id
-int GetIdRefCount(wxWindowID id)
+int GetIdRefCount(wxWindowID winid)
 {
-    wxCHECK_MSG(id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST, 0,
+    wxCHECK_MSG(winid >= wxID_AUTO_LOWEST && winid <= wxID_AUTO_HIGHEST, 0,
             wxT("invalid id range"));
 
-    id -= wxID_AUTO_LOWEST;
-    return gs_autoIdsRefCount[id];
+    winid -= wxID_AUTO_LOWEST;
+    int refCount = gs_autoIdsRefCount[winid];
+    if (refCount == ID_COUNTTOOLARGE)
+        refCount = (*gs_autoIdsLargeRefCount)[winid];
+    return refCount;
 }
 
 // Increase the count for an id
-void IncIdRefCount(wxWindowID id)
+void IncIdRefCount(wxWindowID winid)
 {
-    wxCHECK_RET(id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST,
+    wxCHECK_RET(winid >= wxID_AUTO_LOWEST && winid <= wxID_AUTO_HIGHEST,
             wxT("invalid id range"));
 
-    id -= wxID_AUTO_LOWEST;
+    winid -= wxID_AUTO_LOWEST;
 
-    wxCHECK_RET(gs_autoIdsRefCount[id] != ID_MAXCOUNT, wxT("id count at max"));
-    wxCHECK_RET(gs_autoIdsRefCount[id] != ID_FREE, wxT("id should first be reserved"));
+    wxCHECK_RET(gs_autoIdsRefCount[winid] != ID_FREE, wxT("id should first be reserved"));
+
+    if(gs_autoIdsRefCount[winid] == ID_RESERVED)
+    {
+        gs_autoIdsRefCount[winid] = ID_STARTCOUNT;
+    }
+    else if (gs_autoIdsRefCount[winid] >= ID_COUNTTOOLARGE-1)
+    {
+        if (gs_autoIdsRefCount[winid] == ID_COUNTTOOLARGE-1)
+        {
+            // we need to allocate a cell, and maybe the hash map itself
+            if (!gs_autoIdsLargeRefCount)
+                gs_autoIdsLargeRefCount = new wxLongToLongHashMap;
+            (*gs_autoIdsLargeRefCount)[winid] = ID_COUNTTOOLARGE-1;
 
-    if(gs_autoIdsRefCount[id] == ID_RESERVED)
-        gs_autoIdsRefCount[id] = ID_STARTCOUNT;
+            gs_autoIdsRefCount[winid] = ID_COUNTTOOLARGE;
+        }
+        ++(*gs_autoIdsLargeRefCount)[winid];
+    }
     else
-        gs_autoIdsRefCount[id]++;
+    {
+        gs_autoIdsRefCount[winid]++;
+    }
 
     wxLogTrace(wxTRACE_WINDOWID, wxT("Increasing ref count of ID %d to %d"),
-            id + wxID_AUTO_LOWEST, gs_autoIdsRefCount[id]);
+            winid + wxID_AUTO_LOWEST, GetIdRefCount(winid + wxID_AUTO_LOWEST));
 }
 
 // Decrease the count for an id
-void DecIdRefCount(wxWindowID id)
+void DecIdRefCount(wxWindowID winid)
 {
-    wxCHECK_RET(id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST,
+    wxCHECK_RET(winid >= wxID_AUTO_LOWEST && winid <= wxID_AUTO_HIGHEST,
             wxT("invalid id range"));
 
-    id -= wxID_AUTO_LOWEST;
+    winid -= wxID_AUTO_LOWEST;
 
-    wxCHECK_RET(gs_autoIdsRefCount[id] != ID_FREE, wxT("id count already 0"));
+    wxCHECK_RET(gs_autoIdsRefCount[winid] != ID_FREE, wxT("id count already 0"));
 
     // DecIdRefCount is only called on an ID that has been IncIdRefCount'ed'
     // so it should never be reserved, but test anyway
-    if(gs_autoIdsRefCount[id] == ID_RESERVED)
+    if(gs_autoIdsRefCount[winid] == ID_RESERVED)
     {
         wxFAIL_MSG(wxT("reserve id being decreased"));
-        gs_autoIdsRefCount[id] = ID_FREE;
+        gs_autoIdsRefCount[winid] = ID_FREE;
+    }
+    else if(gs_autoIdsRefCount[winid] == ID_COUNTTOOLARGE)
+    {
+        long &largeCount = (*gs_autoIdsLargeRefCount)[winid];
+        --largeCount;
+        if (largeCount == 0)
+        {
+            gs_autoIdsLargeRefCount->erase (winid);
+            gs_autoIdsRefCount[winid] = ID_FREE;
+
+            if (gs_autoIdsLargeRefCount->empty())
+                wxDELETE (gs_autoIdsLargeRefCount);
+        }
     }
     else
-        gs_autoIdsRefCount[id]--;
+        gs_autoIdsRefCount[winid]--;
 
     wxLogTrace(wxTRACE_WINDOWID, wxT("Decreasing ref count of ID %d to %d"),
-            id + wxID_AUTO_LOWEST, gs_autoIdsRefCount[id]);
+            winid + wxID_AUTO_LOWEST, GetIdRefCount(winid + wxID_AUTO_LOWEST));
 }
 
 #else // wxUSE_AUTOID_MANAGEMENT
@@ -139,15 +184,15 @@ static wxWindowID gs_nextAutoId = wxID_AUTO_HIGHEST;
 
 #if wxUSE_AUTOID_MANAGEMENT
 
-void wxWindowIDRef::Assign(wxWindowID id)
+void wxWindowIDRef::Assign(wxWindowID winid)
 {
-    if ( id != m_id )
+    if ( winid != m_id )
     {
         // decrease count if it is in the managed range
         if ( m_id >= wxID_AUTO_LOWEST && m_id <= wxID_AUTO_HIGHEST )
             DecIdRefCount(m_id);
 
-        m_id = id;
+        m_id = winid;
 
         // increase count if it is in the managed range
         if ( m_id >= wxID_AUTO_LOWEST && m_id <= wxID_AUTO_HIGHEST )
@@ -167,22 +212,22 @@ wxWindowID wxIdManager::ReserveId(int count)
 #if wxUSE_AUTOID_MANAGEMENT
     if ( gs_nextAutoId + count - 1 <= wxID_AUTO_HIGHEST )
     {
-        wxWindowID id = gs_nextAutoId;
+        wxWindowID winid = gs_nextAutoId;
 
         while(count--)
         {
             ReserveIdRefCount(gs_nextAutoId++);
         }
 
-        return id;
+        return winid;
     }
     else
     {
         int found = 0;
 
-        for(wxWindowID id = wxID_AUTO_LOWEST; id <= wxID_AUTO_HIGHEST; id++)
+        for(wxWindowID winid = wxID_AUTO_LOWEST; winid <= wxID_AUTO_HIGHEST; winid++)
         {
-            if(GetIdRefCount(id) == 0)
+            if(GetIdRefCount(winid) == 0)
             {
                 found++;
                 if(found == count)
@@ -196,13 +241,13 @@ wxWindowID wxIdManager::ReserveId(int count)
                     // called, and accorind to gs_nextAutoId, their are still
                     // 50 at the end so it returns them without testing the ref
                     // To fix this, the next ID is also updated here as needed
-                    if(id >= gs_nextAutoId)
-                        gs_nextAutoId = id + 1;
+                    if(winid >= gs_nextAutoId)
+                        gs_nextAutoId = winid + 1;
 
                     while(count--)
-                        ReserveIdRefCount(id--);
+                        ReserveIdRefCount(winid--);
 
-                    return id + 1;
+                    return winid + 1;
                 }
             }
             else
@@ -212,23 +257,23 @@ wxWindowID wxIdManager::ReserveId(int count)
         }
     }
 
-    ::wxLogError(_("Out of window IDs.  Recommend shutting down application."));
+    wxLogError(_("Out of window IDs.  Recommend shutting down application."));
     return wxID_NONE;
 #else // !wxUSE_AUTOID_MANAGEMENT
     // Make sure enough in the range
-    wxWindowID id;
+    wxWindowID winid;
 
-    id = gs_nextAutoId - count + 1;
+    winid = gs_nextAutoId - count + 1;
 
-    if ( id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST )
+    if ( winid >= wxID_AUTO_LOWEST && winid <= wxID_AUTO_HIGHEST )
     {
         // There is enough, but it may be time to wrap
-        if(id == wxID_AUTO_LOWEST)
+        if(winid == wxID_AUTO_LOWEST)
             gs_nextAutoId = wxID_AUTO_HIGHEST;
         else
-            gs_nextAutoId = id - 1;
+            gs_nextAutoId = winid - 1;
 
-        return id;
+        return winid;
     }
     else
     {
@@ -241,15 +286,15 @@ wxWindowID wxIdManager::ReserveId(int count)
 #endif // wxUSE_AUTOID_MANAGEMENT/!wxUSE_AUTOID_MANAGEMENT
 }
 
-void wxIdManager::UnreserveId(wxWindowID id, int count)
+void wxIdManager::UnreserveId(wxWindowID winid, int count)
 {
     wxASSERT_MSG(count > 0, wxT("can't unreserve less than 1 id"));
 
 #if wxUSE_AUTOID_MANAGEMENT
     while (count--)
-        UnreserveIdRefCount(id++);
+        UnreserveIdRefCount(winid++);
 #else
-    wxUnusedVar(id);
+    wxUnusedVar(winid);
     wxUnusedVar(count);
 #endif
 }