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
);
42 typedef void (* HandlerMethod
) (EventObject
*object
, EventHandler handler
, gpointer handler_data
, gpointer closure
);
48 // An EventObject starts out with a reference count of 1 (no need to
49 // ref it after creation), and will be deleted once the count reaches
54 // To log all creation/destruction/ref/unref of an object,
55 // define OBJECT_TRACK_ID to that object's in dependencyobject.cpp.
56 // (this will require that you first run the program once to print
57 // the id of the object you're interested in).
60 #define GET_OBJ_ID(x) (x ? x->GetId () : 0)
62 /* @CBindingRequisite */
63 typedef void (* ToggleNotifyHandler
) (EventObject
*sender
, bool isLastRef
);
64 class ToggleNotifyListener
{
66 ToggleNotifyListener (EventObject
*sender
, ToggleNotifyHandler callback
)
68 this->callback
= callback
;
69 this->sender
= sender
;
72 virtual void Invoke (bool isLastRef
)
74 callback (sender
, isLastRef
);
79 ToggleNotifyHandler callback
;
85 MultiThreadedSafe
= 1 << 29, // if the dtor can be called on any thread
88 IdMask
= ~(Attached
| Disposed
| MultiThreadedSafe
),
92 static GHashTable
*objects_alive
;
93 char *GetStackTrace (const char *prefix
);
94 char *GetStackTrace () { return GetStackTrace (""); }
95 void PrintStackTrace ();
96 void Track (const char *done
, const char *typname
);
99 /* @GenerateCBinding,GeneratePInvoke */
102 /* @GenerateCBinding,GeneratePInvoke */
105 int GetRefCount () { return refcount
; }
106 int GetId () { return flags
& IdMask
; }
110 // Similar to C#'s is: it checks if this object is of this kind or
113 bool Is (Type::Kind k
)
115 return Type::IsSubclassOf (GetDeployment (), GetObjectType (), k
);
120 return Type::Find (GetDeployment (), GetObjectType ());
123 /* @GenerateCBinding,GeneratePInvoke */
124 virtual const char *GetTypeName ()
126 return Type::Find (GetDeployment (), GetObjectType ())->GetName ();
129 int AddHandler (const char *event_name
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
= NULL
);
130 int AddXamlHandler (const char *event_name
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
= NULL
);
131 void RemoveHandler (const char *event_name
, EventHandler handler
, gpointer data
);
133 /* @GenerateCBinding,GeneratePInvoke */
134 void AddOnEventHandler (int event_id
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
= NULL
);
135 /* @GenerateCBinding,GeneratePInvoke */
136 void RemoveOnEventHandler (int event_id
, EventHandler handler
, gpointer data
);
138 // called from the managed layer (Control.cs).
139 /* @GenerateCBinding,GeneratePInvoke */
140 void DoEmitCurrentContext (int event_id
, EventArgs
*calldata
);
142 /* @GenerateCBinding,GeneratePInvoke */
143 int AddHandler (int event_id
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
= NULL
);
144 /* @GenerateCBinding,GeneratePInvoke */
145 int AddXamlHandler (int event_id
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
= NULL
);
146 /* @GenerateCBinding,GeneratePInvoke */
147 virtual int RemoveHandler (int event_id
, EventHandler handler
, gpointer data
);
148 virtual void RemoveHandler (int event_id
, int token
);
149 void RemoveAllHandlers (gpointer data
);
150 void RemoveMatchingHandlers (int event_id
, EventHandlerPredicate predicate
, gpointer closure
);
152 void ForeachHandler (int event_id
, bool only_new
, HandlerMethod m
, gpointer closure
);
153 void ClearForeachGeneration (int event_id
);
154 void ForHandler (int event_id
, int token
, HandlerMethod m
, gpointer closure
);
155 bool HasHandlers (int event_id
, int newer_than_generation
= -1);
157 /* @GenerateCBinding,GeneratePInvoke */
158 Surface
*GetSurface ();
159 virtual void SetSurface (Surface
*surface
);
160 // SetSurfaceLock/Unlock
161 // If AddTickCallSafe is called on a type, that type must override SetSurface and surround the call to its base SetSurface implementation
162 // with Lock/Unlock. Catch: none of the base implementation can cause SetSurfaceLock to be called again, it might cause a dead-lock.
163 // (This could happen if a MediaElement could contain another MediaElement, in which case DependencyObject::SetSurface would cause
164 // the contained MediaElement's SetSurface(Lock) to be called).
165 bool SetSurfaceLock ();
166 void SetSurfaceUnlock ();
169 // Queues a delegate which will be called on the main thread.
170 // The delegate's parameter will be the 'this' pointer.
171 // Only AddTickCallSafe is safe to call on threads other than the main thread,
172 // and only if the type on which it is called overrides SetSurface and surrounds
173 // the call to the base type's SetSurface with SetSurfaceLock/Unlock.
174 void AddTickCall (TickCallHandler handler
, EventObject
*data
= NULL
);
175 void AddTickCallSafe (TickCallHandler handler
, EventObject
*data
= NULL
);
177 /* @GenerateCBinding,GeneratePInvoke */
178 void SetObjectType (Type::Kind value
) { object_type
= value
; }
180 /* @GenerateCBinding,GeneratePInvoke */
181 Type::Kind
GetObjectType () { return object_type
; }
183 const static int DestroyedEvent
;
185 void unref_delayed ();
187 EmitContext
*StartEmit (int event_id
, bool only_unemitted
= false, int starting_generation
= -1);
188 bool DoEmit (int event_id
, EventArgs
*calldata
= NULL
);
189 void FinishEmit (int event_id
, EmitContext
*ctx
);
190 static gboolean
EmitCallback (gpointer d
);
192 virtual void Dispose ();
195 void SetIsAttached (bool value
);
197 bool IsMultiThreadedSafe () { return (flags
& MultiThreadedSafe
) != 0; }
199 Deployment
*GetDeployment ();
200 void SetCurrentDeployment (bool domain
= true, bool register_thread
= false);
202 // a public deployment getter for sanity checking without the warnings in GetDeployment.
203 // it may also be used whenever it is known that the current deployment might be wrong
204 // and we want the deployment on this object.
205 Deployment
*GetUnsafeDeployment () { return deployment
; }
207 /* @GenerateCBinding,GeneratePInvoke */
208 void AddToggleRefNotifier (ToggleNotifyHandler tr
);
209 /* @GenerateCBinding,GeneratePInvoke */
210 void RemoveToggleRefNotifier ();
213 virtual ~EventObject ();
215 EventObject (Type::Kind type
);
216 EventObject (Type::Kind type
, bool multi_threaded_safe
);
217 EventObject (Deployment
*deployment
);
218 EventObject (Deployment
*deployment
, Type::Kind type
);
220 // To enable scenarios like Emit ("Event", new EventArgs ())
221 // Emit will call unref on the calldata.
222 bool Emit (const char *event_name
, EventArgs
*calldata
= NULL
, bool only_unemitted
= false, int starting_generation
= -1);
223 bool Emit (int event_id
, EventArgs
*calldata
= NULL
, bool only_unemitted
= false, int starting_generation
= -1);
225 bool EmitAsync (const char *event_name
, EventArgs
*calldata
= NULL
, bool only_unemitted
= false);
226 bool EmitAsync (int event_id
, EventArgs
*calldata
= NULL
, bool only_unemitted
= false);
228 int GetEventGeneration (int event_id
);
231 void AddTickCallInternal (TickCallHandler handler
, EventObject
*data
= NULL
);
232 void Initialize (Deployment
*deployment
, Type::Kind type
);
234 static void emit_async (EventObject
*calldata
);
235 bool CanEmitEvents (int event_id
);
238 Surface
*surface
; // TODO: Remove this (along with SetSurface)
239 Deployment
*deployment
;
241 gint32 flags
; // Don't define as Flags, we need to keep this reliably at 32 bits.
243 Type::Kind object_type
;
244 ToggleNotifyListener
*toggleNotifyListener
;
248 /* @Namespace=System.Windows */
249 class DependencyObject
: public EventObject
{
251 /* @GenerateCBinding,GeneratePInvoke */
253 virtual void Dispose ();
257 DependencyObject
* Clone (Types
*types
);
259 DependencyProperty
**GetProperties (bool only_changed
);
261 GHashTable
*GetLocalValues () { return local_values
; }
263 // Gets the content property from this object's type, and
264 // returns the value of that dependency property.
266 DependencyObject
*GetContent ();
267 DependencyProperty
*GetDependencyProperty (const char *name
);
269 bool SetValue (DependencyProperty
*property
, Value
*value
);
270 bool SetValue (DependencyProperty
*property
, Value value
);
272 bool SetValue (int property
, Value
*value
);
273 bool SetValue (int property
, Value value
);
275 /* @GenerateCBinding,GeneratePInvoke */
276 bool SetValueWithError (DependencyProperty
*property
, Value
*value
, MoonError
*error
);
277 bool SetValueWithError (DependencyProperty
*property
, Value value
, MoonError
*error
);
279 /* @GenerateCBinding,GeneratePInvoke,Version=2.0 */
280 Value
*GetValueWithError (Type::Kind whatami
, DependencyProperty
*property
, MoonError
*error
);
281 virtual Value
*GetValue (DependencyProperty
*property
);
282 Value
*GetValue (int id
);
284 void ProviderValueChanged (PropertyPrecedence providerPrecedence
, DependencyProperty
*property
, Value
*old_value
, Value
*new_value
, bool notify_listeners
, bool set_parent
, MoonError
*error
);
285 Value
*GetValue (DependencyProperty
*property
, PropertyPrecedence startingAtPrecedence
);
286 Value
*GetValue (DependencyProperty
*property
, PropertyPrecedence startingAtPrecedence
, PropertyPrecedence endingAtPrecedence
);
288 /* @GenerateCBinding,GeneratePInvoke,Version=2.0 */
289 Value
*ReadLocalValueWithError (DependencyProperty
*property
, MoonError
*error
);
290 virtual Value
*ReadLocalValue (DependencyProperty
*property
);
291 virtual Value
*ReadLocalValue (int id
);
293 /* @GenerateCBinding,GeneratePInvoke,Version=2.0 */
294 Value
*GetValueNoDefaultWithError (DependencyProperty
*property
, MoonError
*error
);
295 Value
*GetValueNoDefault (DependencyProperty
*property
);
296 Value
*GetValueNoDefault (int id
);
299 /* @GenerateCBinding,GeneratePInvoke,Version=2.0 */
300 virtual void ClearValue (DependencyProperty
*property
, bool notify_listeners
, MoonError
*error
);
301 void ClearValue (int id
, bool notify_listeners
, MoonError
*error
);
302 void ClearValue (DependencyProperty
*property
, bool notify_listeners
= true /*, error = NULL */);
303 void ClearValue (int id
, bool notify_listeners
= true);
304 bool HasProperty (const char *name
, bool inherits
);
305 bool HasProperty (Type::Kind whatami
, DependencyProperty
*property
, bool inherits
);
307 DependencyObject
*FindName (const char *name
);
308 DependencyObject
*FindName (const char *name
, bool template_item
);
309 /* @GenerateCBinding,GeneratePInvoke */
310 DependencyObject
*FindName (const char *name
, Type::Kind
*element_kind
);
311 NameScope
*FindNameScope ();
312 NameScope
*FindNameScope (bool template_namescope
);
314 AnimationStorage
*AttachAnimationStorage (DependencyProperty
*prop
, AnimationStorage
*storage
);
315 void DetachAnimationStorage (DependencyProperty
*prop
, AnimationStorage
*storage
);
316 AnimationStorage
*GetAnimationStorageFor (DependencyProperty
*prop
);
318 /* @GenerateCBinding,GeneratePInvoke */
319 const char *GetName ();
320 /* @GenerateCBinding,GeneratePInvoke */
321 void SetName (const char *name
);
323 bool SetName (const char *name
, NameScope
*scope
);
325 virtual void SetSurface (Surface
*surface
);
327 /* @GenerateCBinding,GeneratePInvoke */
328 void SetParent (DependencyObject
*parent
, MoonError
*error
);
329 DependencyObject
* GetParent () { return parent
; }
331 virtual bool PermitsMultipleParents () { return true; }
333 void SetResourceBase (const char *resourceBase
) { g_free (resource_base
); resource_base
= g_strdup (resourceBase
); }
334 char *GetResourceBase () { return resource_base
; }
336 virtual void OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
);
338 // See the comment below about AddPropertyChangeListener for
339 // the meaning of the @prop arg in this method. it's not what
340 // you might think it is.
341 virtual void OnSubPropertyChanged (DependencyProperty
*prop
, DependencyObject
*obj
, PropertyChangedEventArgs
*subobj_args
) { }
344 // OnCollectionChanged:
346 // This method is invoked when a change has happened in the @col
347 // collection, the kind of change is described in @type (change start,
348 // change end, adding, removing, or altering an existing item).
350 virtual void OnCollectionChanged (Collection
*col
, CollectionChangedEventArgs
*args
) { }
353 // OnCollectionItemChanged:
355 // This method is invoked when an item in the collection has had a property changed.
357 virtual void OnCollectionItemChanged (Collection
*col
, DependencyObject
*obj
, PropertyChangedEventArgs
*args
) { }
359 // These methods get called on DependencyObjects when they are
360 // set/unset as property values on another DependencyObject.
361 virtual void AddTarget (DependencyObject
*obj
) { }
362 virtual void RemoveTarget (DependencyObject
*obj
) { }
364 // These two methods are a little confusing. @child_property
365 // is *not* the property you're interested in receiving change
366 // notifications on. Listeners are always notified of all
367 // changes. What @child_property is used for is so that the
368 // listener can look at it and know which of its *own*
369 // properties is reporting the change. So, if a object wants
370 // to listen for changes on its BackgroundProperty, it would
373 // background = GetValue(BackgroundProperty)->AsDependencyObject();
374 // background->AddPropertyChangeListener (this, BackgroundProperty);
376 // then in its OnSubPropertyChanged method, it could check prop to
377 // see if it's == BackgroundProperty and act accordingly. The
378 // child's changed property is contained in the @subobj_args
379 // argument of OnSubPropertyChanged.
381 void AddPropertyChangeListener (DependencyObject
*listener
, DependencyProperty
*child_property
= NULL
);
382 void RemovePropertyChangeListener (DependencyObject
*listener
, DependencyProperty
*child_property
= NULL
);
384 // *These* two methods do what you'd expect. You provide this
385 // dependencyobject with a callback and a closure to be
386 // invoked when the given property changes.
388 /* @GenerateCBinding,GeneratePInvoke */
389 void AddPropertyChangeHandler (DependencyProperty
*property
, PropertyChangeHandler cb
, gpointer closure
);
390 /* @GenerateCBinding,GeneratePInvoke */
391 void RemovePropertyChangeHandler (DependencyProperty
*property
, PropertyChangeHandler cb
);
393 virtual void UnregisterAllNamesRootedAt (NameScope
*from_ns
);
394 virtual void RegisterAllNamesRootedAt (NameScope
*to_ns
, MoonError
*error
);
396 /* @PropertyType=string,GenerateAccessors,ManagedDeclaringType=FrameworkElement,Validator=NameValidator,DefaultValue=\"\" */
397 const static int NameProperty
;
399 // parser hook. objects that are parsed using XamlReader.Load
400 // behave differently than those parsed using LoadComponent in
401 // terms of their name registration behavior.
402 void SetIsHydratedFromXaml (bool flag
) { is_hydrated
= flag
; }
403 bool IsHydratedFromXaml () { return is_hydrated
; }
406 virtual ~DependencyObject ();
407 DependencyObject (Deployment
*deployment
, Type::Kind object_type
= Type::DEPENDENCY_OBJECT
);
408 DependencyObject (Type::Kind object_type
);
411 // Returns true if a value is valid. If the value is invalid return false.
412 // If error is non NULL and the value is not valid, error will be given an error code and error message that should be
413 // propogated to OnError
415 bool IsValueValid (DependencyProperty
*property
, Value
*value
, MoonError
*error
);
417 virtual bool SetValueWithErrorImpl (DependencyProperty
*property
, Value
*value
, MoonError
*error
);
419 void NotifyListenersOfPropertyChange (PropertyChangedEventArgs
*args
, MoonError
*error
);
420 void NotifyListenersOfPropertyChange (DependencyProperty
*property
, MoonError
*error
);
421 void NotifyListenersOfPropertyChange (int id
, MoonError
*error
);
423 void RemoveAllListeners ();
425 virtual void CloneCore (Types
*types
, DependencyObject
* from
);
427 PropertyValueProvider
**providers
;
430 void RemoveListener (gpointer listener
, DependencyProperty
*child_property
);
433 static bool CanPropertyBeSetToNull (DependencyProperty
* property
);
435 static void collection_changed (EventObject
*sender
, EventArgs
*args
, gpointer closure
);
436 static void collection_item_changed (EventObject
*sender
, EventArgs
*args
, gpointer closure
);
438 static void clone_local_value (DependencyProperty
*key
, Value
*value
, gpointer data
);
439 static void clone_autocreated_value (DependencyProperty
*key
, Value
*value
, gpointer data
);
440 static void clone_animation_storage_list (DependencyProperty
*key
, List
*list
, gpointer data
);
441 void CloneAnimationStorageList (DependencyProperty
*key
, List
*list
);
443 static gboolean
dispose_value (gpointer key
, gpointer value
, gpointer data
);
445 GHashTable
*storage_hash
; // keys: DependencyProperty, values: animation storage's
447 GHashTable
*local_values
;
448 GSList
*listener_list
;
449 DependencyObject
*parent
;
457 #endif /* __MONO_DEPOBJECT_H__ */