1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
5 * Copyright 2007 Novell, Inc. (http://www.novell.com)
7 * See the LICENSE file included with the distribution for details.
11 #ifndef __MONO_DEPOBJECT_H__
12 #define __MONO_DEPOBJECT_H__
17 #include "dependencyproperty.h"
22 #define EVENTHANDLER(type, event, objtype, argtype) \
23 static void event##Callback (EventObject *sender, EventArgs *calldata, gpointer closure) \
25 g_return_if_fail (sender != NULL); \
26 ((type *) closure)->event##Handler ((objtype *) sender, (argtype *) calldata); \
28 void event##Handler (objtype *sender, argtype *calldata);
30 class CollectionChangedEventArgs
;
36 /* @CBindingRequisite */
37 typedef void (* TickCallHandler
) (EventObject
*object
);
38 /* @CBindingRequisite */
39 typedef void (* EventHandler
) (EventObject
*sender
, EventArgs
*args
, gpointer closure
);
40 typedef bool (* EventHandlerPredicate
) (EventHandler cb_handler
, gpointer cb_data
, gpointer data
);
46 // An EventObject starts out with a reference count of 1 (no need to
47 // ref it after creation), and will be deleted once the count reaches
52 // To log all creation/destruction/ref/unref of an object,
53 // define OBJECT_TRACK_ID to that object's in dependencyobject.cpp.
54 // (this will require that you first run the program once to print
55 // the id of the object you're interested in).
58 #define GET_OBJ_ID(x) (x ? x->GetId () : 0)
60 /* @CBindingRequisite */
61 typedef void (* ToggleNotifyHandler
) (EventObject
*sender
, bool isLastRef
);
62 class ToggleNotifyListener
{
64 ToggleNotifyListener (EventObject
*sender
, ToggleNotifyHandler callback
)
66 this->callback
= callback
;
67 this->sender
= sender
;
70 virtual void Invoke (bool isLastRef
)
72 callback (sender
, isLastRef
);
77 ToggleNotifyHandler callback
;
83 MultiThreadedSafe
= 1 << 29, // if the dtor can be called on any thread
86 IdMask
= ~(Attached
| Disposed
| MultiThreadedSafe
),
90 static GHashTable
*objects_alive
;
91 char *GetStackTrace (const char *prefix
);
92 char *GetStackTrace () { return GetStackTrace (""); }
93 void PrintStackTrace ();
94 void Track (const char *done
, const char *typname
);
97 /* @GenerateCBinding,GeneratePInvoke */
100 /* @GenerateCBinding,GeneratePInvoke */
103 int GetRefCount () { return refcount
; }
104 int GetId () { return flags
& IdMask
; }
108 // Similar to C#'s is: it checks if this object is of this kind or
111 bool Is (Type::Kind k
)
113 return Type::IsSubclassOf (GetDeployment (), GetObjectType (), k
);
118 return Type::Find (GetDeployment (), GetObjectType ());
121 /* @GenerateCBinding,GeneratePInvoke */
122 virtual const char *GetTypeName ()
124 return Type::Find (GetDeployment (), GetObjectType ())->GetName ();
127 /* @GenerateCBinding,GeneratePInvoke */
128 int AddHandler (const char *event_name
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
= NULL
);
129 /* @GenerateCBinding,GeneratePInvoke */
130 int AddXamlHandler (const char *event_name
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
= NULL
);
131 /* @GenerateCBinding,GeneratePInvoke */
132 void RemoveHandler (const char *event_name
, EventHandler handler
, gpointer data
);
134 int AddHandler (int event_id
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
= NULL
);
135 int AddXamlHandler (int event_id
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
= NULL
);
136 void RemoveHandler (int event_id
, EventHandler handler
, gpointer data
);
137 void RemoveHandler (int event_id
, int token
);
138 void RemoveAllHandlers (gpointer data
);
139 void RemoveMatchingHandlers (int event_id
, EventHandlerPredicate predicate
, gpointer closure
);
141 /* @GenerateCBinding,GeneratePInvoke */
142 Surface
*GetSurface ();
143 virtual void SetSurface (Surface
*surface
);
144 // SetSurfaceLock/Unlock
145 // If AddTickCallSafe is called on a type, that type must override SetSurface and surround the call to its base SetSurface implementation
146 // with Lock/Unlock. Catch: none of the base implementation can cause SetSurfaceLock to be called again, it might cause a dead-lock.
147 // (This could happen if a MediaElement could contain another MediaElement, in which case DependencyObject::SetSurface would cause
148 // the contained MediaElement's SetSurface(Lock) to be called).
149 bool SetSurfaceLock ();
150 void SetSurfaceUnlock ();
153 // Queues a delegate which will be called on the main thread.
154 // The delegate's parameter will be the 'this' pointer.
155 // Only AddTickCallSafe is safe to call on threads other than the main thread,
156 // and only if the type on which it is called overrides SetSurface and surrounds
157 // the call to the base type's SetSurface with SetSurfaceLock/Unlock.
158 void AddTickCall (TickCallHandler handler
, EventObject
*data
= NULL
);
159 void AddTickCallSafe (TickCallHandler handler
, EventObject
*data
= NULL
);
161 /* @GenerateCBinding,GeneratePInvoke */
162 void SetObjectType (Type::Kind value
) { object_type
= value
; }
164 /* @GenerateCBinding,GeneratePInvoke */
165 Type::Kind
GetObjectType () { return object_type
; }
167 const static int DestroyedEvent
;
169 void unref_delayed ();
171 EmitContext
*StartEmit (int event_id
);
172 bool DoEmit (int event_id
, EmitContext
*ctx
, EventArgs
*calldata
= NULL
, bool only_unemitted
= false, int starting_generation
= -1);
173 void FinishEmit (int event_id
, EmitContext
*ctx
);
174 static gboolean
EmitCallback (gpointer d
);
176 virtual void Dispose ();
179 void SetIsAttached (bool value
);
181 bool IsMultiThreadedSafe () { return (flags
& MultiThreadedSafe
) != 0; }
183 Deployment
*GetDeployment ();
184 void SetCurrentDeployment (bool domain
= true);
187 Deployment
*GetUnsafeDeployment () { return deployment
; } // a public deployment getter for sanity checking without the warnings in GetDeployment.
190 /* @GenerateCBinding,GeneratePInvoke */
191 void AddToggleRefNotifier (ToggleNotifyHandler tr
);
192 /* @GenerateCBinding,GeneratePInvoke */
193 void RemoveToggleRefNotifier ();
196 virtual ~EventObject ();
198 EventObject (Type::Kind type
);
199 EventObject (Type::Kind type
, bool multi_threaded_safe
);
200 EventObject (Deployment
*deployment
);
201 EventObject (Deployment
*deployment
, Type::Kind type
);
203 // To enable scenarios like Emit ("Event", new EventArgs ())
204 // Emit will call unref on the calldata.
205 bool Emit (const char *event_name
, EventArgs
*calldata
= NULL
, bool only_unemitted
= false, int starting_generation
= -1);
206 bool Emit (int event_id
, EventArgs
*calldata
= NULL
, bool only_unemitted
= false, int starting_generation
= -1);
208 bool EmitAsync (const char *event_name
, EventArgs
*calldata
= NULL
, bool only_unemitted
= false);
209 bool EmitAsync (int event_id
, EventArgs
*calldata
= NULL
, bool only_unemitted
= false);
211 int GetEventGeneration (int event_id
);
214 void AddTickCallInternal (TickCallHandler handler
, EventObject
*data
= NULL
);
215 void Initialize (Deployment
*deployment
, Type::Kind type
);
217 static void emit_async (EventObject
*calldata
);
220 Surface
*surface
; // TODO: Remove this (along with SetSurface)
221 Deployment
*deployment
;
223 gint32 flags
; // Don't define as Flags, we need to keep this reliably at 32 bits.
225 Type::Kind object_type
;
226 ToggleNotifyListener
*toggleNotifyListener
;
230 /* @Namespace=System.Windows */
231 class DependencyObject
: public EventObject
{
233 /* @GenerateCBinding,GeneratePInvoke */
235 virtual void Dispose ();
239 DependencyObject
* Clone (Types
*types
);
241 DependencyProperty
**GetProperties (bool only_changed
);
243 GHashTable
*GetLocalValues () { return local_values
; }
245 // Gets the content property from this object's type, and
246 // returns the value of that dependency property.
248 DependencyObject
*GetContent ();
249 DependencyProperty
*GetDependencyProperty (const char *name
);
251 bool SetValue (DependencyProperty
*property
, Value
*value
);
252 bool SetValue (DependencyProperty
*property
, Value value
);
254 bool SetValue (int property
, Value
*value
);
255 bool SetValue (int property
, Value value
);
257 /* @GenerateCBinding,GeneratePInvoke */
258 bool SetValueWithError (DependencyProperty
*property
, Value
*value
, MoonError
*error
);
259 bool SetValueWithError (DependencyProperty
*property
, Value value
, MoonError
*error
);
261 /* @GenerateCBinding,GeneratePInvoke,Version=2.0 */
262 Value
*GetValueWithError (Type::Kind whatami
, DependencyProperty
*property
, MoonError
*error
);
263 virtual Value
*GetValue (DependencyProperty
*property
);
264 Value
*GetValue (int id
);
266 void ProviderValueChanged (PropertyPrecedence providerPrecedence
, DependencyProperty
*property
, Value
*old_value
, Value
*new_value
, bool notify_listeners
, bool set_parent
, MoonError
*error
);
267 Value
*GetValue (DependencyProperty
*property
, PropertyPrecedence startingAtPrecedence
);
268 Value
*GetValue (DependencyProperty
*property
, PropertyPrecedence startingAtPrecedence
, PropertyPrecedence endingAtPrecedence
);
270 /* @GenerateCBinding,GeneratePInvoke,Version=2.0 */
271 Value
*ReadLocalValueWithError (DependencyProperty
*property
, MoonError
*error
);
272 virtual Value
*ReadLocalValue (DependencyProperty
*property
);
273 virtual Value
*ReadLocalValue (int id
);
275 /* @GenerateCBinding,GeneratePInvoke,Version=2.0 */
276 Value
*GetValueNoDefaultWithError (DependencyProperty
*property
, MoonError
*error
);
277 Value
*GetValueNoDefault (DependencyProperty
*property
);
278 Value
*GetValueNoDefault (int id
);
281 /* @GenerateCBinding,GeneratePInvoke,Version=2.0 */
282 virtual void ClearValue (DependencyProperty
*property
, bool notify_listeners
, MoonError
*error
);
283 void ClearValue (int id
, bool notify_listeners
, MoonError
*error
);
284 void ClearValue (DependencyProperty
*property
, bool notify_listeners
= true /*, error = NULL */);
285 void ClearValue (int id
, bool notify_listeners
= true);
286 bool HasProperty (const char *name
, bool inherits
);
287 bool HasProperty (Type::Kind whatami
, DependencyProperty
*property
, bool inherits
);
289 DependencyObject
*FindName (const char *name
);
290 DependencyObject
*FindName (const char *name
, bool template_item
);
291 /* @GenerateCBinding,GeneratePInvoke */
292 DependencyObject
*FindName (const char *name
, Type::Kind
*element_kind
);
293 NameScope
*FindNameScope ();
294 NameScope
*FindNameScope (bool template_namescope
);
296 AnimationStorage
*AttachAnimationStorage (DependencyProperty
*prop
, AnimationStorage
*storage
);
297 void DetachAnimationStorage (DependencyProperty
*prop
, AnimationStorage
*storage
);
298 AnimationStorage
*GetAnimationStorageFor (DependencyProperty
*prop
);
300 /* @GenerateCBinding,GeneratePInvoke */
301 const char *GetName ();
302 /* @GenerateCBinding,GeneratePInvoke */
303 void SetName (const char *name
);
305 bool SetName (const char *name
, NameScope
*scope
);
307 virtual void SetSurface (Surface
*surface
);
309 /* @GenerateCBinding,GeneratePInvoke */
310 void SetParent (DependencyObject
*parent
, MoonError
*error
);
311 DependencyObject
* GetParent () { return parent
; }
313 virtual bool PermitsMultipleParents () { return true; }
315 void SetResourceBase (const char *resourceBase
) { g_free (resource_base
); resource_base
= g_strdup (resourceBase
); }
316 char *GetResourceBase () { return resource_base
; }
318 virtual void OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
);
320 // See the comment below about AddPropertyChangeListener for
321 // the meaning of the @prop arg in this method. it's not what
322 // you might think it is.
323 virtual void OnSubPropertyChanged (DependencyProperty
*prop
, DependencyObject
*obj
, PropertyChangedEventArgs
*subobj_args
) { }
326 // OnCollectionChanged:
328 // This method is invoked when a change has happened in the @col
329 // collection, the kind of change is described in @type (change start,
330 // change end, adding, removing, or altering an existing item).
332 virtual void OnCollectionChanged (Collection
*col
, CollectionChangedEventArgs
*args
) { }
335 // OnCollectionItemChanged:
337 // This method is invoked when an item in the collection has had a property changed.
339 virtual void OnCollectionItemChanged (Collection
*col
, DependencyObject
*obj
, PropertyChangedEventArgs
*args
) { }
341 // These methods get called on DependencyObjects when they are
342 // set/unset as property values on another DependencyObject.
343 virtual void AddTarget (DependencyObject
*obj
) { }
344 virtual void RemoveTarget (DependencyObject
*obj
) { }
346 // These two methods are a little confusing. @child_property
347 // is *not* the property you're interested in receiving change
348 // notifications on. Listeners are always notified of all
349 // changes. What @child_property is used for is so that the
350 // listener can look at it and know which of its *own*
351 // properties is reporting the change. So, if a object wants
352 // to listen for changes on its BackgroundProperty, it would
355 // background = GetValue(BackgroundProperty)->AsDependencyObject();
356 // background->AddPropertyChangeListener (this, BackgroundProperty);
358 // then in its OnSubPropertyChanged method, it could check prop to
359 // see if it's == BackgroundProperty and act accordingly. The
360 // child's changed property is contained in the @subobj_args
361 // argument of OnSubPropertyChanged.
363 void AddPropertyChangeListener (DependencyObject
*listener
, DependencyProperty
*child_property
= NULL
);
364 void RemovePropertyChangeListener (DependencyObject
*listener
, DependencyProperty
*child_property
= NULL
);
366 // *These* two methods do what you'd expect. You provide this
367 // dependencyobject with a callback and a closure to be
368 // invoked when the given property changes.
370 /* @GenerateCBinding,GeneratePInvoke */
371 void AddPropertyChangeHandler (DependencyProperty
*property
, PropertyChangeHandler cb
, gpointer closure
);
372 /* @GenerateCBinding,GeneratePInvoke */
373 void RemovePropertyChangeHandler (DependencyProperty
*property
, PropertyChangeHandler cb
);
375 virtual void UnregisterAllNamesRootedAt (NameScope
*from_ns
);
376 virtual void RegisterAllNamesRootedAt (NameScope
*to_ns
, MoonError
*error
);
378 /* @PropertyType=string,GenerateAccessors,ManagedDeclaringType=FrameworkElement,Validator=NameValidator,DefaultValue=\"\" */
379 const static int NameProperty
;
381 // parser hook. objects that are parsed using XamlReader.Load
382 // behave differently than those parsed using LoadComponent in
383 // terms of their name registration behavior.
384 void SetIsHydratedFromXaml (bool flag
) { is_hydrated
= flag
; }
385 bool IsHydratedFromXaml () { return is_hydrated
; }
388 virtual ~DependencyObject ();
389 DependencyObject (Deployment
*deployment
, Type::Kind object_type
= Type::DEPENDENCY_OBJECT
);
390 DependencyObject (Type::Kind object_type
);
393 // Returns true if a value is valid. If the value is invalid return false.
394 // If error is non NULL and the value is not valid, error will be given an error code and error message that should be
395 // propogated to OnError
397 bool IsValueValid (DependencyProperty
*property
, Value
*value
, MoonError
*error
);
399 virtual bool SetValueWithErrorImpl (DependencyProperty
*property
, Value
*value
, MoonError
*error
);
401 void NotifyListenersOfPropertyChange (PropertyChangedEventArgs
*args
, MoonError
*error
);
402 void NotifyListenersOfPropertyChange (DependencyProperty
*property
, MoonError
*error
);
403 void NotifyListenersOfPropertyChange (int id
, MoonError
*error
);
405 void RemoveAllListeners ();
407 virtual void CloneCore (Types
*types
, DependencyObject
* from
);
409 PropertyValueProvider
**providers
;
412 void RemoveListener (gpointer listener
, DependencyProperty
*child_property
);
415 static bool CanPropertyBeSetToNull (DependencyProperty
* property
);
417 static void collection_changed (EventObject
*sender
, EventArgs
*args
, gpointer closure
);
418 static void collection_item_changed (EventObject
*sender
, EventArgs
*args
, gpointer closure
);
420 static void clone_local_value (DependencyProperty
*key
, Value
*value
, gpointer data
);
421 static void clone_autocreated_value (DependencyProperty
*key
, Value
*value
, gpointer data
);
422 static void clone_animation_storage_list (DependencyProperty
*key
, List
*list
, gpointer data
);
423 void CloneAnimationStorageList (DependencyProperty
*key
, List
*list
);
425 static gboolean
dispose_value (gpointer key
, gpointer value
, gpointer data
);
427 GHashTable
*storage_hash
; // keys: DependencyProperty, values: animation storage's
429 GHashTable
*local_values
;
430 GSList
*listener_list
;
431 DependencyObject
*parent
;
439 #endif /* __MONO_DEPOBJECT_H__ */