xti introduction
[wxWidgets.git] / src / common / object.cpp
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$
8 // Copyright: (c) 1998 Julian Smart
9 // (c) 2001 Ron Lee <ron@debian.org>
10 // Licence: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
12
13 #ifdef __GNUG__
14 #pragma implementation "object.h"
15 #endif
16
17 // For compilers that support precompilation, includes "wx.h".
18 #include "wx/wxprec.h"
19
20 #ifdef __BORLANDC__
21 #pragma hdrstop
22 #endif
23
24 #ifndef WX_PRECOMP
25 #include "wx/hash.h"
26 #include "wx/object.h"
27 #endif
28
29 #include <string.h>
30
31 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
32 #include "wx/memory.h"
33 #endif
34
35 #if defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT
36 // for wxObject::Dump
37 #include "wx/ioswrap.h"
38
39 #if defined(__VISAGECPP__)
40 #define DEBUG_PRINTF(NAME) { static int raz=0; \
41 printf( #NAME " %i\n",raz); fflush(stdout); raz++; }
42 #else
43 #define DEBUG_PRINTF(NAME)
44 #endif
45 #endif // __WXDEBUG__ || wxUSE_DEBUG_CONTEXT
46
47 // we must disable optimizations for VC.NET because otherwise its too eager
48 // linker discards wxClassInfo objects in release build thus breaking many,
49 // many things
50 #if defined __VISUALC__ && __VISUALC__ >= 1300
51 #pragma optimize("", off)
52 #endif
53
54 #if wxUSE_XTI
55 const wxClassInfo* wxObject::sm_classParentswxObject[] = { NULL } ;
56 wxObject* wxVariantToObjectConverterwxObject ( const wxxVariant &data )
57 { return data.Get<wxObject*>() ; }
58 wxxVariant wxObjectToVariantConverterwxObject ( wxObject *data )
59 { return wxxVariant( dynamic_cast<wxObject*> (data) ) ; }
60 wxClassInfo wxObject::sm_classwxObject(sm_classParentswxObject , wxT("") , wxT("wxObject"),
61 (int) sizeof(wxObject), \
62 (wxObjectConstructorFn) 0 ,
63 (wxPropertyInfo*) NULL,0 , 0 ,
64 0 , wxVariantToObjectConverterwxObject , wxObjectToVariantConverterwxObject);
65 template<> void wxStringReadValue(const wxString & , wxObject * & ){assert(0) ;}
66 template<> void wxStringWriteValue(wxString & , wxObject* const & ){assert(0) ;}
67 template<> const wxTypeInfo* wxGetTypeInfo( wxObject ** )
68 { static wxClassTypeInfo s_typeInfo(&wxObject::sm_classwxObject) ; return &s_typeInfo ; }
69 #else
70 wxClassInfo wxObject::sm_classwxObject( wxT("wxObject"), 0, 0,
71 (int) sizeof(wxObject),
72 (wxObjectConstructorFn) 0 );
73 #endif
74
75 // restore optimizations
76 #if defined __VISUALC__ && __VISUALC__ >= 1300
77 #pragma optimize("", on)
78 #endif
79
80 wxClassInfo* wxClassInfo::sm_first = NULL;
81 wxHashTable* wxClassInfo::sm_classTable = NULL;
82
83 // These are here so we can avoid 'always true/false' warnings
84 // by referring to these instead of TRUE/FALSE
85 const bool wxTrue = TRUE;
86 const bool wxFalse = FALSE;
87
88 // Is this object a kind of (a subclass of) 'info'?
89 // E.g. is wxWindow a kind of wxObject?
90 // Go from this class to superclass, taking into account
91 // two possible base classes.
92 bool wxObject::IsKindOf(wxClassInfo *info) const
93 {
94 wxClassInfo *thisInfo = GetClassInfo();
95 return (thisInfo) ? thisInfo->IsKindOf(info) : FALSE ;
96 }
97
98 #if wxUSE_STD_IOSTREAM && (defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT)
99 void wxObject::Dump(wxSTD ostream& str)
100 {
101 if (GetClassInfo() && GetClassInfo()->GetClassName())
102 str << GetClassInfo()->GetClassName();
103 else
104 str << _T("unknown object class");
105 }
106 #endif
107
108
109 #if defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING && defined( new )
110 #undef new
111 #endif
112
113
114 #ifdef _WX_WANT_NEW_SIZET_WXCHAR_INT
115 void *wxObject::operator new ( size_t size, const wxChar *fileName, int lineNum )
116 {
117 return wxDebugAlloc(size, (wxChar*) fileName, lineNum, TRUE);
118 }
119 #endif
120
121 #ifdef _WX_WANT_DELETE_VOID
122 void wxObject::operator delete ( void *buf )
123 {
124 wxDebugFree(buf);
125 }
126 #endif
127
128 #ifdef _WX_WANT_DELETE_VOID_CONSTCHAR_SIZET
129 void wxObject::operator delete ( void *buf, const char *_fname, size_t _line )
130 {
131 wxDebugFree(buf);
132 }
133 #endif
134
135 #ifdef _WX_WANT_DELETE_VOID_WXCHAR_INT
136 void wxObject::operator delete ( void *buf, const wxChar *WXUNUSED(fileName), int WXUNUSED(lineNum) )
137 {
138 wxDebugFree(buf);
139 }
140 #endif
141
142 #ifdef _WX_WANT_ARRAY_NEW_SIZET_WXCHAR_INT
143 void *wxObject::operator new[] ( size_t size, const wxChar* fileName, int lineNum )
144 {
145 return wxDebugAlloc(size, (wxChar*) fileName, lineNum, TRUE, TRUE);
146 }
147 #endif
148
149 #ifdef _WX_WANT_ARRAY_DELETE_VOID
150 void wxObject::operator delete[] ( void *buf )
151 {
152 wxDebugFree(buf, TRUE);
153 }
154 #endif
155
156 #ifdef _WX_WANT_ARRAY_DELETE_VOID_WXCHAR_INT
157 void wxObject::operator delete[] (void * buf, const wxChar* WXUNUSED(fileName), int WXUNUSED(lineNum) )
158 {
159 wxDebugFree(buf, TRUE);
160 }
161 #endif
162
163
164 // ----------------------------------------------------------------------------
165 // wxClassInfo
166 // ----------------------------------------------------------------------------
167
168 wxClassInfo::~wxClassInfo()
169 {
170 // remove this object from the linked list of all class infos: if we don't
171 // do it, loading/unloading a DLL containing static wxClassInfo objects is
172 // not going to work
173 if ( this == sm_first )
174 {
175 sm_first = m_next;
176 }
177 else
178 {
179 wxClassInfo *info = sm_first;
180 while (info)
181 {
182 if ( info->m_next == this )
183 {
184 info->m_next = m_next;
185 break;
186 }
187
188 info = info->m_next;
189 }
190 }
191 #if wxUSE_XTI
192 Unregister( m_className ) ;
193 #endif
194 }
195
196 wxClassInfo *wxClassInfo::FindClass(const wxChar *className)
197 {
198 if ( sm_classTable )
199 {
200 return (wxClassInfo *)wxClassInfo::sm_classTable->Get(className);
201 }
202 else
203 {
204 for ( wxClassInfo *info = sm_first; info ; info = info->m_next )
205 {
206 if ( wxStrcmp(info->GetClassName(), className) == 0 )
207 return info;
208 }
209
210 return NULL;
211 }
212 }
213
214 // a tiny InitializeClasses() helper
215 /* static */
216 inline wxClassInfo *wxClassInfo::GetBaseByName(const wxChar *name)
217 {
218 if ( !name )
219 return NULL;
220
221 wxClassInfo *classInfo = (wxClassInfo *)sm_classTable->Get(name);
222
223 #ifdef __WXDEBUG__
224 // this must be fixed, other things will work wrongly later if you get this
225 if ( !classInfo )
226 {
227 wxFAIL_MSG( wxString::Format
228 (
229 _T("base class '%s' is unknown to wxWindows RTTI"),
230 name
231 ) );
232 }
233 #endif // __WXDEBUG__
234
235 return classInfo;
236 }
237
238 // Set pointers to base class(es) to speed up IsKindOf
239 void wxClassInfo::InitializeClasses()
240 {
241 // using IMPLEMENT_DYNAMIC_CLASS() macro twice (which may happen if you
242 // link any object module twice mistakenly) will break this function
243 // because it will enter an infinite loop and eventually die with "out of
244 // memory" - as this is quite hard to detect if you're unaware of this,
245 // try to do some checks here
246
247 #ifdef __WXDEBUG__
248 static const size_t nMaxClasses = 10000; // more than we'll ever have
249 size_t nClass = 0;
250 #endif
251
252 sm_classTable = new wxHashTable(wxKEY_STRING);
253
254 // Index all class infos by their class name
255
256 wxClassInfo *info;
257 for(info = sm_first; info; info = info->m_next)
258 {
259 if (info->m_className)
260 {
261 wxASSERT_MSG( ++nClass < nMaxClasses,
262 _T("an infinite loop detected - have you used IMPLEMENT_DYNAMIC_CLASS() twice (may be by linking some object module(s) twice)?") );
263 sm_classTable->Put(info->m_className, (wxObject *)info);
264 }
265 }
266
267 #if wxUSE_XTI == 0
268 // Set base pointers for each wxClassInfo
269
270 for(info = sm_first; info; info = info->m_next)
271 {
272 info->m_baseInfo1 = GetBaseByName(info->GetBaseClassName1());
273 info->m_baseInfo2 = GetBaseByName(info->GetBaseClassName2());
274 }
275 #endif
276 }
277
278 void wxClassInfo::CleanUpClasses()
279 {
280 delete wxClassInfo::sm_classTable;
281 wxClassInfo::sm_classTable = NULL;
282 }
283
284 wxObject *wxCreateDynamicObject(const wxChar *name)
285 {
286 #if defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT
287 DEBUG_PRINTF(wxObject *wxCreateDynamicObject)
288 #endif
289
290 if ( wxClassInfo::sm_classTable )
291 {
292 wxClassInfo *info = (wxClassInfo *)wxClassInfo::sm_classTable->Get(name);
293 return info ? info->CreateObject() : NULL;
294 }
295 else // no sm_classTable yet
296 {
297 for ( wxClassInfo *info = wxClassInfo::sm_first;
298 info;
299 info = info->m_next )
300 {
301 if (info->m_className && wxStrcmp(info->m_className, name) == 0)
302 return info->CreateObject();
303 }
304
305 return NULL;
306 }
307 }
308
309
310 // ----------------------------------------------------------------------------
311 // wxObject
312 // ----------------------------------------------------------------------------
313
314 // Initialize ref data from another object (needed for copy constructor and
315 // assignment operator)
316 void wxObject::InitFrom(const wxObject& other)
317 {
318 m_refData = other.m_refData;
319 if ( m_refData )
320 m_refData->m_count++;
321 }
322
323 void wxObject::Ref(const wxObject& clone)
324 {
325 #if defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT
326 DEBUG_PRINTF(wxObject::Ref)
327 #endif
328
329 // nothing to be done
330 if (m_refData == clone.m_refData)
331 return;
332
333 // delete reference to old data
334 UnRef();
335
336 // reference new data
337 if ( clone.m_refData )
338 {
339 m_refData = clone.m_refData;
340 ++(m_refData->m_count);
341 }
342 }
343
344 void wxObject::UnRef()
345 {
346 if ( m_refData )
347 {
348 wxASSERT_MSG( m_refData->m_count > 0, _T("invalid ref data count") );
349
350 if ( !--m_refData->m_count )
351 delete m_refData;
352 m_refData = NULL;
353 }
354 }
355
356 void wxObject::AllocExclusive()
357 {
358 if ( !m_refData )
359 {
360 m_refData = CreateRefData();
361 }
362 else if ( m_refData->GetRefCount() > 1 )
363 {
364 // note that ref is not going to be destroyed in this case
365 const wxObjectRefData* ref = m_refData;
366 UnRef();
367
368 // ... so we can still access it
369 m_refData = CloneRefData(ref);
370 }
371 //else: ref count is 1, we are exclusive owners of m_refData anyhow
372
373 wxASSERT_MSG( m_refData && m_refData->GetRefCount() == 1,
374 _T("wxObject::AllocExclusive() failed.") );
375 }
376
377 wxObjectRefData *wxObject::CreateRefData() const
378 {
379 // if you use AllocExclusive() you must override this method
380 wxFAIL_MSG( _T("CreateRefData() must be overridden if called!") );
381
382 return NULL;
383 }
384
385 wxObjectRefData *
386 wxObject::CloneRefData(const wxObjectRefData * WXUNUSED(data)) const
387 {
388 // if you use AllocExclusive() you must override this method
389 wxFAIL_MSG( _T("CloneRefData() must be overridden if called!") );
390
391 return NULL;
392 }
393
394 // ----------------------------------------------------------------------------
395 // misc
396 // ----------------------------------------------------------------------------
397
398 #if defined(__DARWIN__) && defined(WXMAKINGDLL)
399
400 extern "C" {
401 void __initialize_Cplusplus(void);
402 void wxWindowsDylibInit(void);
403 };
404
405 // Dynamic shared library (dylib) initialization routine
406 // required to initialize static C++ objects bacause of lazy dynamic linking
407 // http://developer.apple.com/techpubs/macosx/Essentials/
408 // SystemOverview/Frameworks/Dynamic_Shared_Libraries.html
409
410 void wxWindowsDylibInit()
411 {
412 // The function __initialize_Cplusplus() must be called from the shared
413 // library initialization routine to cause the static C++ objects in
414 // the library to be initialized (reference number 2441683).
415
416 // This only seems to be necessary if the library initialization routine
417 // needs to use the static C++ objects
418 __initialize_Cplusplus();
419 }
420
421 #endif
422
423 // vi:sts=4:sw=4:et