1///////////////////////////////////////////////////////////////////////////// 2// Name: src/common/object.cpp 3// Purpose: wxObject implementation 4// Author: Julian Smart 5// Modified by: Ron Lee 6// Created: 04/01/98 7// RCS-ID: $Id: object.cpp 56500 2008-10-23 14:48:31Z MW $ 8// Copyright: (c) 1998 Julian Smart 9// (c) 2001 Ron Lee <ron@debian.org> 10// Licence: wxWindows licence 11///////////////////////////////////////////////////////////////////////////// 12 13// For compilers that support precompilation, includes "wx.h". 14#include "wx/wxprec.h" 15 16#ifdef __BORLANDC__ 17 #pragma hdrstop 18#endif 19 20#ifndef WX_PRECOMP 21 #include "wx/object.h" 22 #include "wx/hash.h" 23 #include "wx/memory.h" 24#endif 25 26#include <string.h> 27 28#if defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT 29 #if defined(__VISAGECPP__) 30 #define DEBUG_PRINTF(NAME) { static int raz=0; \ 31 printf( #NAME " %i\n",raz); fflush(stdout); raz++; } 32 #else 33 #define DEBUG_PRINTF(NAME) 34 #endif 35#endif // __WXDEBUG__ || wxUSE_DEBUG_CONTEXT 36 37// we must disable optimizations for VC.NET because otherwise its too eager 38// linker discards wxClassInfo objects in release build thus breaking many, 39// many things 40#if defined __VISUALC__ && __VISUALC__ >= 1300 41 #pragma optimize("", off) 42#endif 43 44#if wxUSE_EXTENDED_RTTI 45const wxClassInfo* wxObject::ms_classParents[] = { NULL } ; 46 wxObject* wxVariantToObjectConverterwxObject ( wxxVariant &data ) 47{ return data.wxTEMPLATED_MEMBER_CALL(Get , wxObject*) ; } 48 wxObject* wxVariantOfPtrToObjectConverterwxObject ( wxxVariant &data ) 49{ return &data.wxTEMPLATED_MEMBER_CALL(Get , wxObject) ; } 50 wxxVariant wxObjectToVariantConverterwxObject ( wxObject *data ) 51 { return wxxVariant( dynamic_cast<wxObject*> (data) ) ; } 52 wxClassInfo wxObject::ms_classInfo(ms_classParents , wxEmptyString , wxT("wxObject"), 53 (int) sizeof(wxObject), \ 54 (wxObjectConstructorFn) 0 , 55 (wxPropertyInfo*) NULL,(wxHandlerInfo*) NULL,0 , 0 , 56 0 , wxVariantOfPtrToObjectConverterwxObject , wxVariantToObjectConverterwxObject , wxObjectToVariantConverterwxObject); 57 template<> void wxStringReadValue(const wxString & , wxObject * & ){assert(0) ;} 58 template<> void wxStringWriteValue(wxString & , wxObject* const & ){assert(0) ;} 59 template<> void wxStringReadValue(const wxString & , wxObject & ){assert(0) ;} 60 template<> void wxStringWriteValue(wxString & , wxObject const & ){assert(0) ;} 61 wxClassTypeInfo s_typeInfo(wxT_OBJECT_PTR , &wxObject::ms_classInfo , NULL , NULL , typeid(wxObject*).name() ) ; 62 wxClassTypeInfo s_typeInfowxObject(wxT_OBJECT , &wxObject::ms_classInfo , NULL , NULL , typeid(wxObject).name() ) ; 63#else 64wxClassInfo wxObject::ms_classInfo( wxT("wxObject"), 0, 0, 65 (int) sizeof(wxObject), 66 (wxObjectConstructorFn) 0 ); 67#endif 68 69// restore optimizations 70#if defined __VISUALC__ && __VISUALC__ >= 1300 71 #pragma optimize("", on) 72#endif 73 74wxClassInfo* wxClassInfo::sm_first = NULL; 75wxHashTable* wxClassInfo::sm_classTable = NULL; 76 77// when using XTI, this method is already implemented inline inside 78// DECLARE_DYNAMIC_CLASS but otherwise we intentionally make this function 79// non-inline because this allows us to have a non-inline virtual function in 80// all wx classes and this solves linking problems for HP-UX native toolchain 81// and possibly others (we could make dtor non-inline as well but it's more 82// useful to keep it inline than this function) 83#if !wxUSE_EXTENDED_RTTI 84 85wxClassInfo *wxObject::GetClassInfo() const 86{ 87 return &wxObject::ms_classInfo; 88} 89 90#endif // wxUSE_EXTENDED_RTTI 91 92// this variable exists only so that we can avoid 'always true/false' warnings 93const bool wxFalse = false; 94 95// Is this object a kind of (a subclass of) 'info'? 96// E.g. is wxWindow a kind of wxObject? 97// Go from this class to superclass, taking into account 98// two possible base classes. 99bool wxObject::IsKindOf(wxClassInfo *info) const 100{ 101 wxClassInfo *thisInfo = GetClassInfo(); 102 return (thisInfo) ? thisInfo->IsKindOf(info) : false ; 103} 104 105#if defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING && defined( new ) 106 #undef new 107#endif 108 109 110#ifdef _WX_WANT_NEW_SIZET_WXCHAR_INT 111void *wxObject::operator new ( size_t size, const wxChar *fileName, int lineNum ) 112{ 113 return wxDebugAlloc(size, (wxChar*) fileName, lineNum, true); 114} 115#endif 116 117#ifdef _WX_WANT_DELETE_VOID 118void wxObject::operator delete ( void *buf ) 119{ 120 wxDebugFree(buf); 121} 122#endif 123 124#ifdef _WX_WANT_DELETE_VOID_CONSTCHAR_SIZET 125void wxObject::operator delete ( void *buf, const char *_fname, size_t _line ) 126{ 127 wxDebugFree(buf); 128} 129#endif 130 131#ifdef _WX_WANT_DELETE_VOID_WXCHAR_INT 132void wxObject::operator delete ( void *buf, const wxChar *WXUNUSED(fileName), int WXUNUSED(lineNum) ) 133{ 134 wxDebugFree(buf); 135} 136#endif 137 138#ifdef _WX_WANT_ARRAY_NEW_SIZET_WXCHAR_INT 139void *wxObject::operator new[] ( size_t size, const wxChar* fileName, int lineNum ) 140{ 141 return wxDebugAlloc(size, (wxChar*) fileName, lineNum, true, true); 142} 143#endif 144 145#ifdef _WX_WANT_ARRAY_DELETE_VOID 146void wxObject::operator delete[] ( void *buf ) 147{ 148 wxDebugFree(buf, true); 149} 150#endif 151 152#ifdef _WX_WANT_ARRAY_DELETE_VOID_WXCHAR_INT 153void wxObject::operator delete[] (void * buf, const wxChar* WXUNUSED(fileName), int WXUNUSED(lineNum) ) 154{ 155 wxDebugFree(buf, true); 156} 157#endif 158 159 160// ---------------------------------------------------------------------------- 161// wxClassInfo 162// ---------------------------------------------------------------------------- 163 164wxClassInfo::~wxClassInfo() 165{ 166 // remove this object from the linked list of all class infos: if we don't 167 // do it, loading/unloading a DLL containing static wxClassInfo objects is 168 // not going to work 169 if ( this == sm_first ) 170 { 171 sm_first = m_next; 172 } 173 else 174 { 175 wxClassInfo *info = sm_first; 176 while (info) 177 { 178 if ( info->m_next == this ) 179 { 180 info->m_next = m_next; 181 break; 182 } 183 184 info = info->m_next; 185 } 186 } 187 Unregister(); 188} 189 190wxClassInfo *wxClassInfo::FindClass(const wxChar *className) 191{ 192 if ( sm_classTable ) 193 { 194 return (wxClassInfo *)wxClassInfo::sm_classTable->Get(className); 195 } 196 else 197 { 198 for ( wxClassInfo *info = sm_first; info ; info = info->m_next ) 199 { 200 if ( wxStrcmp(info->GetClassName(), className) == 0 ) 201 return info; 202 } 203 204 return NULL; 205 } 206} 207 208// Reentrance can occur on some platforms (Solaris for one), as the use of hash 209// and string objects can cause other modules to load and register classes 210// before the original call returns. This is handled by keeping the hash table 211// local when it is first created and only assigning it to the global variable 212// when the function is ready to return. 213// 214// That does make the assumption that after the function has completed the 215// first time the problem will no longer happen; all the modules it depends on 216// will have been loaded. The assumption is checked using the 'entry' variable 217// as a reentrance guard, it checks that once the hash table is global it is 218// not accessed multiple times simulateously. 219 220void wxClassInfo::Register() 221{ 222#ifdef __WXDEBUG__ 223 // reentrance guard - see note above 224 static int entry = 0; 225#endif 226 227 wxHashTable *classTable; 228 229 if ( !sm_classTable ) 230 { 231 // keep the hash local initially, reentrance is possible 232 classTable = new wxHashTable(wxKEY_STRING); 233 } 234 else 235 { 236 // guard againt reentrance once the global has been created 237 wxASSERT_MSG(++entry == 1, _T("wxClassInfo::Register() reentrance")); 238 classTable = sm_classTable; 239 } 240 241 // Using IMPLEMENT_DYNAMIC_CLASS() macro twice (which may happen if you 242 // link any object module twice mistakenly, or link twice against wx shared 243 // library) will break this function because it will enter an infinite loop 244 // and eventually die with "out of memory" - as this is quite hard to 245 // detect if you're unaware of this, try to do some checks here. 246 wxASSERT_MSG( classTable->Get(m_className) == NULL, 247 wxString::Format 248 ( 249 _T("Class \"%s\" already in RTTI table - have you used IMPLEMENT_DYNAMIC_CLASS() multiple times or linked some object file twice)?"), 250 m_className 251 ) 252 ); 253 254 classTable->Put(m_className, (wxObject *)this); 255 256 // if we're using a local hash we need to try to make it global 257 if ( sm_classTable != classTable ) 258 { 259 if ( !sm_classTable ) 260 { 261 // make the hash global 262 sm_classTable = classTable; 263 } 264 else 265 { 266 // the gobal hash has already been created by a reentrant call, 267 // so delete the local hash and try again 268 delete classTable; 269 Register(); 270 } 271 } 272 273#ifdef __WXDEBUG__ 274 entry = 0; 275#endif 276} 277 278void wxClassInfo::Unregister() 279{ 280 if ( sm_classTable ) 281 { 282 sm_classTable->Delete(m_className); 283 if ( sm_classTable->GetCount() == 0 ) 284 { 285 delete sm_classTable; 286 sm_classTable = NULL; 287 } 288 } 289} 290 291wxObject *wxCreateDynamicObject(const wxChar *name) 292{ 293#if defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT 294 DEBUG_PRINTF(wxObject *wxCreateDynamicObject) 295#endif 296 297 if ( wxClassInfo::sm_classTable ) 298 { 299 wxClassInfo *info = (wxClassInfo *)wxClassInfo::sm_classTable->Get(name); 300 return info ? info->CreateObject() : NULL; 301 } 302 else // no sm_classTable yet 303 { 304 for ( wxClassInfo *info = wxClassInfo::sm_first; 305 info; 306 info = info->m_next ) 307 { 308 if (info->m_className && wxStrcmp(info->m_className, name) == 0) 309 return info->CreateObject(); 310 } 311 312 return NULL; 313 } 314} 315 316 317// ---------------------------------------------------------------------------- 318// wxObject 319// ---------------------------------------------------------------------------- 320 321void wxObject::Ref(const wxObject& clone) 322{ 323#if defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT 324 DEBUG_PRINTF(wxObject::Ref) 325#endif 326 327 // nothing to be done 328 if (m_refData == clone.m_refData) 329 return; 330 331 // delete reference to old data 332 UnRef(); 333 334 // reference new data 335 if ( clone.m_refData ) 336 { 337 m_refData = clone.m_refData; 338 ++(m_refData->m_count); 339 } 340} 341 342void wxObject::UnRef() 343{ 344 if ( m_refData ) 345 { 346 wxASSERT_MSG( m_refData->m_count > 0, _T("invalid ref data count") ); 347 348 if ( --m_refData->m_count == 0 ) 349 delete m_refData; 350 m_refData = NULL; 351 } 352} 353 354void wxObject::AllocExclusive() 355{ 356 if ( !m_refData ) 357 { 358 m_refData = CreateRefData(); 359 } 360 else if ( m_refData->GetRefCount() > 1 ) 361 { 362 // note that ref is not going to be destroyed in this case 363 const wxObjectRefData* ref = m_refData; 364 UnRef(); 365 366 // ... so we can still access it 367 m_refData = CloneRefData(ref); 368 } 369 //else: ref count is 1, we are exclusive owners of m_refData anyhow 370 371 wxASSERT_MSG( m_refData && m_refData->GetRefCount() == 1, 372 _T("wxObject::AllocExclusive() failed.") ); 373} 374 375wxObjectRefData *wxObject::CreateRefData() const 376{ 377 // if you use AllocExclusive() you must override this method 378 wxFAIL_MSG( _T("CreateRefData() must be overridden if called!") ); 379 380 return NULL; 381} 382 383wxObjectRefData * 384wxObject::CloneRefData(const wxObjectRefData * WXUNUSED(data)) const 385{ 386 // if you use AllocExclusive() you must override this method 387 wxFAIL_MSG( _T("CloneRefData() must be overridden if called!") ); 388 389 return NULL; 390} 391