1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/windowid.cpp
3 // Purpose: wxWindowID class - a class for managing window ids
4 // Author: Brian Vanderburg II
7 // Copyright: (c) 2007 Brian Vanderburg II
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
11 // ----------------------------------------------------------------------------
13 // ----------------------------------------------------------------------------
14 #include "wx/wxprec.h"
25 // Not needed, included in defs.h
26 // #include "wx/windowid.h"
28 #define wxTRACE_WINDOWID _T("windowid")
33 #if wxUSE_AUTOID_MANAGEMENT
36 // initially no ids are in use and we allocate them consecutively, but after we
37 // exhaust the entire range, we wrap around and reuse the ids freed in the
39 static const wxUint8 ID_FREE
= 0;
40 static const wxUint8 ID_STARTCOUNT
= 1;
41 static const wxUint8 ID_MAXCOUNT
= 254;
42 static const wxUint8 ID_RESERVED
= 255;
44 wxUint8 gs_autoIdsRefCount
[wxID_AUTO_HIGHEST
- wxID_AUTO_LOWEST
+ 1] = { 0 };
46 // this is an optimization used until we wrap around wxID_AUTO_HIGHEST: if this
47 // value is < wxID_AUTO_HIGHEST we know that we haven't wrapped yet and so can
48 // allocate the ids simply by incrementing it
49 wxWindowID gs_nextAutoId
= wxID_AUTO_LOWEST
;
52 void ReserveIdRefCount(wxWindowID id
)
54 wxCHECK_RET(id
>= wxID_AUTO_LOWEST
&& id
<= wxID_AUTO_HIGHEST
,
55 wxT("invalid id range"));
57 id
-= wxID_AUTO_LOWEST
;
59 wxCHECK_RET(gs_autoIdsRefCount
[id
] == ID_FREE
,
60 wxT("id already in use or already reserved"));
61 gs_autoIdsRefCount
[id
] = ID_RESERVED
;
65 void UnreserveIdRefCount(wxWindowID id
)
67 wxCHECK_RET(id
>= wxID_AUTO_LOWEST
&& id
<= wxID_AUTO_HIGHEST
,
68 wxT("invalid id range"));
70 id
-= wxID_AUTO_LOWEST
;
72 wxCHECK_RET(gs_autoIdsRefCount
[id
] == ID_RESERVED
,
73 wxT("id already in use or not reserved"));
74 gs_autoIdsRefCount
[id
] = ID_FREE
;
77 // Get the usage count of an id
78 int GetIdRefCount(wxWindowID id
)
80 wxCHECK_MSG(id
>= wxID_AUTO_LOWEST
&& id
<= wxID_AUTO_HIGHEST
, 0,
81 wxT("invalid id range"));
83 id
-= wxID_AUTO_LOWEST
;
84 return gs_autoIdsRefCount
[id
];
87 // Increase the count for an id
88 void IncIdRefCount(wxWindowID id
)
90 wxCHECK_RET(id
>= wxID_AUTO_LOWEST
&& id
<= wxID_AUTO_HIGHEST
,
91 wxT("invalid id range"));
93 id
-= wxID_AUTO_LOWEST
;
95 wxCHECK_RET(gs_autoIdsRefCount
[id
] != ID_MAXCOUNT
, wxT("id count at max"));
96 wxCHECK_RET(gs_autoIdsRefCount
[id
] != ID_FREE
, wxT("id should first be reserved"));
98 if(gs_autoIdsRefCount
[id
] == ID_RESERVED
)
99 gs_autoIdsRefCount
[id
] = ID_STARTCOUNT
;
101 gs_autoIdsRefCount
[id
]++;
103 wxLogTrace(wxTRACE_WINDOWID
, wxT("Increasing ref count of ID %d to %d"),
104 id
+ wxID_AUTO_LOWEST
, gs_autoIdsRefCount
[id
]);
107 // Decrease the count for an id
108 void DecIdRefCount(wxWindowID id
)
110 wxCHECK_RET(id
>= wxID_AUTO_LOWEST
&& id
<= wxID_AUTO_HIGHEST
,
111 wxT("invalid id range"));
113 id
-= wxID_AUTO_LOWEST
;
115 wxCHECK_RET(gs_autoIdsRefCount
[id
] != ID_FREE
, wxT("id count already 0"));
117 // DecIdRefCount is only called on an ID that has been IncIdRefCount'ed'
118 // so it should never be reserved, but test anyway
119 if(gs_autoIdsRefCount
[id
] == ID_RESERVED
)
121 wxASSERT_MSG(false, wxT("reserve id being decreased"));
122 gs_autoIdsRefCount
[id
] = ID_FREE
;
125 gs_autoIdsRefCount
[id
]--;
127 wxLogTrace(wxTRACE_WINDOWID
, wxT("Decreasing ref count of ID %d to %d"),
128 id
+ wxID_AUTO_LOWEST
, gs_autoIdsRefCount
[id
]);
131 #else // wxUSE_AUTOID_MANAGEMENT
133 static wxWindowID gs_nextAutoId
= wxID_AUTO_HIGHEST
;
137 } // anonymous namespace
140 #if wxUSE_AUTOID_MANAGEMENT
142 void wxWindowIDRef::Assign(wxWindowID id
)
146 // decrease count if it is in the managed range
147 if ( m_id
>= wxID_AUTO_LOWEST
&& m_id
<= wxID_AUTO_HIGHEST
)
152 // increase count if it is in the managed range
153 if ( m_id
>= wxID_AUTO_LOWEST
&& m_id
<= wxID_AUTO_HIGHEST
)
158 #endif // wxUSE_AUTOID_MANAGEMENT
162 wxWindowID
wxIdManager::ReserveId(int count
)
164 wxASSERT_MSG(count
> 0, wxT("can't allocate less than 1 id"));
167 #if wxUSE_AUTOID_MANAGEMENT
168 if ( gs_nextAutoId
+ count
- 1 <= wxID_AUTO_HIGHEST
)
170 wxWindowID id
= gs_nextAutoId
;
174 ReserveIdRefCount(gs_nextAutoId
++);
183 for(wxWindowID id
= wxID_AUTO_LOWEST
; id
<= wxID_AUTO_HIGHEST
; id
++)
185 if(GetIdRefCount(id
) == 0)
190 // Imagine this: 100 free IDs left. Then NewId(50) takes 50
191 // so 50 left. Then, the 25 before that last 50 are freed, but
192 // gs_nextAutoId does not decrement and stays where it is at
193 // with 50 free. Then NewId(75) gets called, and since there
194 // are only 50 left according to gs_nextAutoId, it does a
195 // search and finds the 75 at the end. Then NewId(10) gets
196 // called, and accorind to gs_nextAutoId, their are still
197 // 50 at the end so it returns them without testing the ref
198 // To fix this, the next ID is also updated here as needed
199 if(id
>= gs_nextAutoId
)
200 gs_nextAutoId
= id
+ 1;
203 ReserveIdRefCount(id
--);
215 ::wxLogError(_("Out of window IDs. Recommend shutting down application."));
217 #else // !wxUSE_AUTOID_MANAGEMENT
218 // Make sure enough in the range
221 id
= gs_nextAutoId
- count
+ 1;
223 if ( id
>= wxID_AUTO_LOWEST
&& id
<= wxID_AUTO_HIGHEST
)
225 // There is enough, but it may be time to wrap
226 if(id
== wxID_AUTO_LOWEST
)
227 gs_nextAutoId
= wxID_AUTO_HIGHEST
;
229 gs_nextAutoId
= id
- 1;
235 // There is not enough at the low end of the range or
236 // count was big enough to wrap around to the positive
237 // Surely 'count' is not so big to take up much of the range
238 gs_nextAutoId
= wxID_AUTO_HIGHEST
- count
;
239 return gs_nextAutoId
+ 1;
241 #endif // wxUSE_AUTOID_MANAGEMENT/!wxUSE_AUTOID_MANAGEMENT
244 void wxIdManager::UnreserveId(wxWindowID id
, int count
)
246 wxASSERT_MSG(count
> 0, wxT("can't unreserve less than 1 id"));
248 #if wxUSE_AUTOID_MANAGEMENT
250 UnreserveIdRefCount(id
++);