use wxWindowIDRef to transparently implement auto-generated ids ref-counting (slightly modified patch 1835458)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@51035 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -173,7 +173,6 @@ 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;
|
||||
@@ -247,9 +246,6 @@ bool wxWindowBase::CreateBase(wxWindowBase *parent,
|
||||
if ( id == wxID_ANY )
|
||||
{
|
||||
m_windowId = NewControlId();
|
||||
|
||||
// remember to call ReleaseControlId() when this window is destroyed
|
||||
m_freeId = true;
|
||||
}
|
||||
else // valid id specified
|
||||
{
|
||||
@@ -310,10 +306,6 @@ 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
|
||||
|
||||
@@ -3195,125 +3187,4 @@ 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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user