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 int AddHandler (const char *event_name
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
= NULL
);
128 int AddXamlHandler (const char *event_name
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
= NULL
);
129 void RemoveHandler (const char *event_name
, EventHandler handler
, gpointer data
);
131 /* @GenerateCBinding,GeneratePInvoke */
132 void AddOnEventHandler (int event_id
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
= NULL
);
133 /* @GenerateCBinding,GeneratePInvoke */
134 void RemoveOnEventHandler (int event_id
, EventHandler handler
, gpointer data
);
136 // called from the managed layer (Control.cs).
137 /* @GenerateCBinding,GeneratePInvoke */
138 void DoEmitCurrentContext (int event_id
, EventArgs
*calldata
);
140 /* @GenerateCBinding,GeneratePInvoke */
141 int AddHandler (int event_id
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
= NULL
);
142 /* @GenerateCBinding,GeneratePInvoke */
143 int AddXamlHandler (int event_id
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
= NULL
);
144 /* @GenerateCBinding,GeneratePInvoke */
145 void RemoveHandler (int event_id
, EventHandler handler
, gpointer data
);
146 void RemoveHandler (int event_id
, int token
);
147 void RemoveAllHandlers (gpointer data
);
148 void RemoveMatchingHandlers (int event_id
, EventHandlerPredicate predicate
, gpointer closure
);
150 /* @GenerateCBinding,GeneratePInvoke */
151 Surface
*GetSurface ();
152 virtual void SetSurface (Surface
*surface
);
153 // SetSurfaceLock/Unlock
154 // If AddTickCallSafe is called on a type, that type must override SetSurface and surround the call to its base SetSurface implementation
155 // with Lock/Unlock. Catch: none of the base implementation can cause SetSurfaceLock to be called again, it might cause a dead-lock.
156 // (This could happen if a MediaElement could contain another MediaElement, in which case DependencyObject::SetSurface would cause
157 // the contained MediaElement's SetSurface(Lock) to be called).
158 bool SetSurfaceLock ();
159 void SetSurfaceUnlock ();
162 // Queues a delegate which will be called on the main thread.
163 // The delegate's parameter will be the 'this' pointer.
164 // Only AddTickCallSafe is safe to call on threads other than the main thread,
165 // and only if the type on which it is called overrides SetSurface and surrounds
166 // the call to the base type's SetSurface with SetSurfaceLock/Unlock.
167 void AddTickCall (TickCallHandler handler
, EventObject
*data
= NULL
);
168 void AddTickCallSafe (TickCallHandler handler
, EventObject
*data
= NULL
);
170 /* @GenerateCBinding,GeneratePInvoke */
171 void SetObjectType (Type::Kind value
) { object_type
= value
; }
173 /* @GenerateCBinding,GeneratePInvoke */
174 Type::Kind
GetObjectType () { return object_type
; }
176 const static int DestroyedEvent
;
178 void unref_delayed ();
180 EmitContext
*StartEmit (int event_id
, bool only_unemitted
= false, int starting_generation
= -1);
181 bool DoEmit (int event_id
, EventArgs
*calldata
= NULL
);
182 void FinishEmit (int event_id
, EmitContext
*ctx
);
183 static gboolean
EmitCallback (gpointer d
);
185 virtual void Dispose ();
188 void SetIsAttached (bool value
);
190 bool IsMultiThreadedSafe () { return (flags
& MultiThreadedSafe
) != 0; }
192 Deployment
*GetDeployment ();
193 void SetCurrentDeployment (bool domain
= true, bool register_thread
= false);
195 // a public deployment getter for sanity checking without the warnings in GetDeployment.
196 // it may also be used whenever it is known that the current deployment might be wrong
197 // and we want the deployment on this object.
198 Deployment
*GetUnsafeDeployment () { return deployment
; }
200 /* @GenerateCBinding,GeneratePInvoke */
201 void AddToggleRefNotifier (ToggleNotifyHandler tr
);
202 /* @GenerateCBinding,GeneratePInvoke */
203 void RemoveToggleRefNotifier ();
206 virtual ~EventObject ();
208 EventObject (Type::Kind type
);
209 EventObject (Type::Kind type
, bool multi_threaded_safe
);
210 EventObject (Deployment
*deployment
);
211 EventObject (Deployment
*deployment
, Type::Kind type
);
213 // To enable scenarios like Emit ("Event", new EventArgs ())
214 // Emit will call unref on the calldata.
215 bool Emit (const char *event_name
, EventArgs
*calldata
= NULL
, bool only_unemitted
= false, int starting_generation
= -1);
216 bool Emit (int event_id
, EventArgs
*calldata
= NULL
, bool only_unemitted
= false, int starting_generation
= -1);
218 bool EmitAsync (const char *event_name
, EventArgs
*calldata
= NULL
, bool only_unemitted
= false);
219 bool EmitAsync (int event_id
, EventArgs
*calldata
= NULL
, bool only_unemitted
= false);
221 int GetEventGeneration (int event_id
);
224 void AddTickCallInternal (TickCallHandler handler
, EventObject
*data
= NULL
);
225 void Initialize (Deployment
*deployment
, Type::Kind type
);
227 static void emit_async (EventObject
*calldata
);
228 bool CanEmitEvents ();
231 Surface
*surface
; // TODO: Remove this (along with SetSurface)
232 Deployment
*deployment
;
234 gint32 flags
; // Don't define as Flags, we need to keep this reliably at 32 bits.
236 Type::Kind object_type
;
237 ToggleNotifyListener
*toggleNotifyListener
;
241 /* @Namespace=System.Windows */
242 class DependencyObject
: public EventObject
{
244 /* @GenerateCBinding,GeneratePInvoke */
246 virtual void Dispose ();
250 DependencyObject
* Clone (Types
*types
);
252 DependencyProperty
**GetProperties (bool only_changed
);
254 GHashTable
*GetLocalValues () { return local_values
; }
256 // Gets the content property from this object's type, and
257 // returns the value of that dependency property.
259 DependencyObject
*GetContent ();
260 DependencyProperty
*GetDependencyProperty (const char *name
);
262 bool SetValue (DependencyProperty
*property
, Value
*value
);
263 bool SetValue (DependencyProperty
*property
, Value value
);
265 bool SetValue (int property
, Value
*value
);
266 bool SetValue (int property
, Value value
);
268 /* @GenerateCBinding,GeneratePInvoke */
269 bool SetValueWithError (DependencyProperty
*property
, Value
*value
, MoonError
*error
);
270 bool SetValueWithError (DependencyProperty
*property
, Value value
, MoonError
*error
);
272 /* @GenerateCBinding,GeneratePInvoke,Version=2.0 */
273 Value
*GetValueWithError (Type::Kind whatami
, DependencyProperty
*property
, MoonError
*error
);
274 virtual Value
*GetValue (DependencyProperty
*property
);
275 Value
*GetValue (int id
);
277 void ProviderValueChanged (PropertyPrecedence providerPrecedence
, DependencyProperty
*property
, Value
*old_value
, Value
*new_value
, bool notify_listeners
, bool set_parent
, MoonError
*error
);
278 Value
*GetValue (DependencyProperty
*property
, PropertyPrecedence startingAtPrecedence
);
279 Value
*GetValue (DependencyProperty
*property
, PropertyPrecedence startingAtPrecedence
, PropertyPrecedence endingAtPrecedence
);
281 /* @GenerateCBinding,GeneratePInvoke,Version=2.0 */
282 Value
*ReadLocalValueWithError (DependencyProperty
*property
, MoonError
*error
);
283 virtual Value
*ReadLocalValue (DependencyProperty
*property
);
284 virtual Value
*ReadLocalValue (int id
);
286 /* @GenerateCBinding,GeneratePInvoke,Version=2.0 */
287 Value
*GetValueNoDefaultWithError (DependencyProperty
*property
, MoonError
*error
);
288 Value
*GetValueNoDefault (DependencyProperty
*property
);
289 Value
*GetValueNoDefault (int id
);
292 /* @GenerateCBinding,GeneratePInvoke,Version=2.0 */
293 virtual void ClearValue (DependencyProperty
*property
, bool notify_listeners
, MoonError
*error
);
294 void ClearValue (int id
, bool notify_listeners
, MoonError
*error
);
295 void ClearValue (DependencyProperty
*property
, bool notify_listeners
= true /*, error = NULL */);
296 void ClearValue (int id
, bool notify_listeners
= true);
297 bool HasProperty (const char *name
, bool inherits
);
298 bool HasProperty (Type::Kind whatami
, DependencyProperty
*property
, bool inherits
);
300 DependencyObject
*FindName (const char *name
);
301 DependencyObject
*FindName (const char *name
, bool template_item
);
302 /* @GenerateCBinding,GeneratePInvoke */
303 DependencyObject
*FindName (const char *name
, Type::Kind
*element_kind
);
304 NameScope
*FindNameScope ();
305 NameScope
*FindNameScope (bool template_namescope
);
307 AnimationStorage
*AttachAnimationStorage (DependencyProperty
*prop
, AnimationStorage
*storage
);
308 void DetachAnimationStorage (DependencyProperty
*prop
, AnimationStorage
*storage
);
309 AnimationStorage
*GetAnimationStorageFor (DependencyProperty
*prop
);
311 /* @GenerateCBinding,GeneratePInvoke */
312 const char *GetName ();
313 /* @GenerateCBinding,GeneratePInvoke */
314 void SetName (const char *name
);
316 bool SetName (const char *name
, NameScope
*scope
);
318 virtual void SetSurface (Surface
*surface
);
320 /* @GenerateCBinding,GeneratePInvoke */
321 void SetParent (DependencyObject
*parent
, MoonError
*error
);
322 DependencyObject
* GetParent () { return parent
; }
324 virtual bool PermitsMultipleParents () { return true; }
326 void SetResourceBase (const char *resourceBase
) { g_free (resource_base
); resource_base
= g_strdup (resourceBase
); }
327 char *GetResourceBase () { return resource_base
; }
329 virtual void OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
);
331 // See the comment below about AddPropertyChangeListener for
332 // the meaning of the @prop arg in this method. it's not what
333 // you might think it is.
334 virtual void OnSubPropertyChanged (DependencyProperty
*prop
, DependencyObject
*obj
, PropertyChangedEventArgs
*subobj_args
) { }
337 // OnCollectionChanged:
339 // This method is invoked when a change has happened in the @col
340 // collection, the kind of change is described in @type (change start,
341 // change end, adding, removing, or altering an existing item).
343 virtual void OnCollectionChanged (Collection
*col
, CollectionChangedEventArgs
*args
) { }
346 // OnCollectionItemChanged:
348 // This method is invoked when an item in the collection has had a property changed.
350 virtual void OnCollectionItemChanged (Collection
*col
, DependencyObject
*obj
, PropertyChangedEventArgs
*args
) { }
352 // These methods get called on DependencyObjects when they are
353 // set/unset as property values on another DependencyObject.
354 virtual void AddTarget (DependencyObject
*obj
) { }
355 virtual void RemoveTarget (DependencyObject
*obj
) { }
357 // These two methods are a little confusing. @child_property
358 // is *not* the property you're interested in receiving change
359 // notifications on. Listeners are always notified of all
360 // changes. What @child_property is used for is so that the
361 // listener can look at it and know which of its *own*
362 // properties is reporting the change. So, if a object wants
363 // to listen for changes on its BackgroundProperty, it would
366 // background = GetValue(BackgroundProperty)->AsDependencyObject();
367 // background->AddPropertyChangeListener (this, BackgroundProperty);
369 // then in its OnSubPropertyChanged method, it could check prop to
370 // see if it's == BackgroundProperty and act accordingly. The
371 // child's changed property is contained in the @subobj_args
372 // argument of OnSubPropertyChanged.
374 void AddPropertyChangeListener (DependencyObject
*listener
, DependencyProperty
*child_property
= NULL
);
375 void RemovePropertyChangeListener (DependencyObject
*listener
, DependencyProperty
*child_property
= NULL
);
377 // *These* two methods do what you'd expect. You provide this
378 // dependencyobject with a callback and a closure to be
379 // invoked when the given property changes.
381 /* @GenerateCBinding,GeneratePInvoke */
382 void AddPropertyChangeHandler (DependencyProperty
*property
, PropertyChangeHandler cb
, gpointer closure
);
383 /* @GenerateCBinding,GeneratePInvoke */
384 void RemovePropertyChangeHandler (DependencyProperty
*property
, PropertyChangeHandler cb
);
386 virtual void UnregisterAllNamesRootedAt (NameScope
*from_ns
);
387 virtual void RegisterAllNamesRootedAt (NameScope
*to_ns
, MoonError
*error
);
389 /* @PropertyType=string,GenerateAccessors,ManagedDeclaringType=FrameworkElement,Validator=NameValidator,DefaultValue=\"\" */
390 const static int NameProperty
;
392 // parser hook. objects that are parsed using XamlReader.Load
393 // behave differently than those parsed using LoadComponent in
394 // terms of their name registration behavior.
395 void SetIsHydratedFromXaml (bool flag
) { is_hydrated
= flag
; }
396 bool IsHydratedFromXaml () { return is_hydrated
; }
399 virtual ~DependencyObject ();
400 DependencyObject (Deployment
*deployment
, Type::Kind object_type
= Type::DEPENDENCY_OBJECT
);
401 DependencyObject (Type::Kind object_type
);
404 // Returns true if a value is valid. If the value is invalid return false.
405 // If error is non NULL and the value is not valid, error will be given an error code and error message that should be
406 // propogated to OnError
408 bool IsValueValid (DependencyProperty
*property
, Value
*value
, MoonError
*error
);
410 virtual bool SetValueWithErrorImpl (DependencyProperty
*property
, Value
*value
, MoonError
*error
);
412 void NotifyListenersOfPropertyChange (PropertyChangedEventArgs
*args
, MoonError
*error
);
413 void NotifyListenersOfPropertyChange (DependencyProperty
*property
, MoonError
*error
);
414 void NotifyListenersOfPropertyChange (int id
, MoonError
*error
);
416 void RemoveAllListeners ();
418 virtual void CloneCore (Types
*types
, DependencyObject
* from
);
420 PropertyValueProvider
**providers
;
423 void RemoveListener (gpointer listener
, DependencyProperty
*child_property
);
426 static bool CanPropertyBeSetToNull (DependencyProperty
* property
);
428 static void collection_changed (EventObject
*sender
, EventArgs
*args
, gpointer closure
);
429 static void collection_item_changed (EventObject
*sender
, EventArgs
*args
, gpointer closure
);
431 static void clone_local_value (DependencyProperty
*key
, Value
*value
, gpointer data
);
432 static void clone_autocreated_value (DependencyProperty
*key
, Value
*value
, gpointer data
);
433 static void clone_animation_storage_list (DependencyProperty
*key
, List
*list
, gpointer data
);
434 void CloneAnimationStorageList (DependencyProperty
*key
, List
*list
);
436 static gboolean
dispose_value (gpointer key
, gpointer value
, gpointer data
);
438 GHashTable
*storage_hash
; // keys: DependencyProperty, values: animation storage's
440 GHashTable
*local_values
;
441 GSList
*listener_list
;
442 DependencyObject
*parent
;
450 #endif /* __MONO_DEPOBJECT_H__ */