Files
wxWidgets/src/common/windowid.cpp

257 lines
7.2 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: src/common/windowid.cpp
// Purpose: wxWindowID class - a class for managing window ids
// Author: Brian Vanderburg II
// Created: 2007-09-21
// RCS-ID: $Id$
// Copyright: (c) 2007 Brian Vanderburg II
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// Needed headers
// ----------------------------------------------------------------------------
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/log.h"
#include "wx/intl.h"
#endif //WX_PRECOMP
// Not needed, included in defs.h
// #include "wx/windowid.h"
#define wxTRACE_WINDOWID _T("windowid")
namespace
{
#if wxUSE_AUTOID_MANAGEMENT
// 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
static const wxUint8 ID_FREE = 0;
static const wxUint8 ID_STARTCOUNT = 1;
static const wxUint8 ID_MAXCOUNT = 254;
static const wxUint8 ID_RESERVED = 255;
wxUint8 gs_autoIdsRefCount[wxID_AUTO_HIGHEST - wxID_AUTO_LOWEST + 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
wxWindowID gs_nextAutoId = wxID_AUTO_LOWEST;
// Reserve an ID
void ReserveIdRefCount(wxWindowID id)
{
wxCHECK_RET(id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST,
wxT("invalid id range"));
id -= wxID_AUTO_LOWEST;
wxCHECK_RET(gs_autoIdsRefCount[id] == ID_FREE,
wxT("id already in use or already reserved"));
gs_autoIdsRefCount[id] = ID_RESERVED;
}
// Unreserve and id
void UnreserveIdRefCount(wxWindowID id)
{
wxCHECK_RET(id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST,
wxT("invalid id range"));
id -= wxID_AUTO_LOWEST;
wxCHECK_RET(gs_autoIdsRefCount[id] == ID_RESERVED,
wxT("id already in use or not reserved"));
gs_autoIdsRefCount[id] = ID_FREE;
}
// Get the usage count of an id
int GetIdRefCount(wxWindowID id)
{
wxCHECK_MSG(id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST, 0,
wxT("invalid id range"));
id -= wxID_AUTO_LOWEST;
return gs_autoIdsRefCount[id];
}
// Increase the count for an id
void IncIdRefCount(wxWindowID id)
{
wxCHECK_RET(id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST,
wxT("invalid id range"));
id -= 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"));
if(gs_autoIdsRefCount[id] == ID_RESERVED)
gs_autoIdsRefCount[id] = ID_STARTCOUNT;
else
gs_autoIdsRefCount[id]++;
wxLogTrace(wxTRACE_WINDOWID, wxT("Increasing ref count of ID %d to %d"),
id + wxID_AUTO_LOWEST, gs_autoIdsRefCount[id]);
}
// Decrease the count for an id
void DecIdRefCount(wxWindowID id)
{
wxCHECK_RET(id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST,
wxT("invalid id range"));
id -= wxID_AUTO_LOWEST;
wxCHECK_RET(gs_autoIdsRefCount[id] != 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)
{
wxASSERT_MSG(false, wxT("reserve id being decreased"));
gs_autoIdsRefCount[id] = ID_FREE;
}
else
gs_autoIdsRefCount[id]--;
wxLogTrace(wxTRACE_WINDOWID, wxT("Decreasing ref count of ID %d to %d"),
id + wxID_AUTO_LOWEST, gs_autoIdsRefCount[id]);
}
#else // wxUSE_AUTOID_MANAGEMENT
static wxWindowID gs_nextAutoId = wxID_AUTO_HIGHEST;
#endif
} // anonymous namespace
#if wxUSE_AUTOID_MANAGEMENT
void wxWindowIDRef::Assign(wxWindowID id)
{
if ( id != 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;
// increase count if it is in the managed range
if ( m_id >= wxID_AUTO_LOWEST && m_id <= wxID_AUTO_HIGHEST )
IncIdRefCount(m_id);
}
}
#endif // wxUSE_AUTOID_MANAGEMENT
wxWindowID wxIdManager::ReserveId(int count)
{
wxASSERT_MSG(count > 0, wxT("can't allocate less than 1 id"));
#if wxUSE_AUTOID_MANAGEMENT
if ( gs_nextAutoId + count - 1 <= wxID_AUTO_HIGHEST )
{
wxWindowID id = gs_nextAutoId;
while(count--)
{
ReserveIdRefCount(gs_nextAutoId++);
}
return id;
}
else
{
int found = 0;
for(wxWindowID id = wxID_AUTO_LOWEST; id <= wxID_AUTO_HIGHEST; id++)
{
if(GetIdRefCount(id) == 0)
{
found++;
if(found == count)
{
// Imagine this: 100 free IDs left. Then NewId(50) takes 50
// so 50 left. Then, the 25 before that last 50 are freed, but
// gs_nextAutoId does not decrement and stays where it is at
// with 50 free. Then NewId(75) gets called, and since there
// are only 50 left according to gs_nextAutoId, it does a
// search and finds the 75 at the end. Then NewId(10) gets
// 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;
while(count--)
ReserveIdRefCount(id--);
return id;
}
}
else
{
found = 0;
}
}
}
::wxLogError(_("Out of window IDs. Recommend shutting down application."));
return wxID_NONE;
#else // !wxUSE_AUTOID_MANAGEMENT
// Make sure enough in the range
wxWindowID id;
id = gs_nextAutoId - count + 1;
if ( id >= wxID_AUTO_LOWEST && id <= wxID_AUTO_HIGHEST )
{
// There is enough, but it may be time to wrap
if(id == wxID_AUTO_LOWEST)
gs_nextAutoId = wxID_AUTO_HIGHEST;
else
gs_nextAutoId = id - 1;
return id;
}
else
{
// There is not enough at the low end of the range or
// count was big enough to wrap around to the positive
// Surely 'count' is not so big to take up much of the range
gs_nextAutoId = wxID_AUTO_HIGHEST - count;
return gs_nextAutoId + 1;
}
#endif // wxUSE_AUTOID_MANAGEMENT/!wxUSE_AUTOID_MANAGEMENT
}
void wxIdManager::UnreserveId(wxWindowID id, int count)
{
wxASSERT_MSG(count > 0, wxT("can't unreserve less than 1 id"));
#if wxUSE_AUTOID_MANAGEMENT
while (count--)
UnreserveIdRefCount(id++);
#else
wxUnusedVar(id);
wxUnusedVar(count);
#endif
}