2009-09-12 Chris Toshok <toshok@ximian.com>
[moon.git] / src / dependencyobject.h
blob98a1270a4a71916b0a094080c26302067aeceeb2
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * dependencyobject.h:
5 * Copyright 2007 Novell, Inc. (http://www.novell.com)
7 * See the LICENSE file included with the distribution for details.
8 *
9 */
11 #ifndef __MONO_DEPOBJECT_H__
12 #define __MONO_DEPOBJECT_H__
14 #include <glib.h>
16 #include "provider.h"
17 #include "dependencyproperty.h"
18 #include "value.h"
19 #include "enums.h"
20 #include "list.h"
22 #define EVENTHANDLER(type, event, objtype, argtype) \
23 static void event##Callback (EventObject *sender, EventArgs *calldata, gpointer closure) \
24 { \
25 g_return_if_fail (sender != NULL); \
26 ((type *) closure)->event##Handler ((objtype *) sender, (argtype *) calldata); \
27 } \
28 void event##Handler (objtype *sender, argtype *calldata);
30 class CollectionChangedEventArgs;
31 class EventObject;
32 class EventArgs;
33 struct EmitContext;
34 class MoonError;
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 class EventLists;
45 //
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
48 // 0.
50 // DEBUGGING
51 //
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 {
63 public:
64 ToggleNotifyListener (EventObject *sender, ToggleNotifyHandler callback)
66 this->callback = callback;
67 this->sender = sender;
70 virtual void Invoke (bool isLastRef)
72 callback (sender, isLastRef);
75 private:
76 EventObject *sender;
77 ToggleNotifyHandler callback;
80 class EventObject {
81 private:
82 enum Flags {
83 MultiThreadedSafe = 1 << 29, // if the dtor can be called on any thread
84 Attached = 1 << 30,
85 Disposed = 1 << 31,
86 IdMask = ~(Attached | Disposed | MultiThreadedSafe),
88 public:
89 #if OBJECT_TRACKING
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);
95 #endif
97 /* @GenerateCBinding,GeneratePInvoke */
98 void ref ();
100 /* @GenerateCBinding,GeneratePInvoke */
101 void unref ();
103 int GetRefCount () { return refcount; }
104 int GetId () { return flags & IdMask; }
107 // Is:
108 // Similar to C#'s is: it checks if this object is of this kind or
109 // a derived class.
111 bool Is (Type::Kind k)
113 return Type::IsSubclassOf (GetDeployment (), GetObjectType (), k);
116 Type *GetType ()
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 ();
152 // AddTickCall*:
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 ();
178 bool IsAttached ();
179 void SetIsAttached (bool value);
180 bool IsDisposed ();
181 bool IsMultiThreadedSafe () { return (flags & MultiThreadedSafe) != 0; }
183 Deployment *GetDeployment ();
184 void SetCurrentDeployment (bool domain = true);
186 #if SANITY
187 Deployment *GetUnsafeDeployment () { return deployment; } // a public deployment getter for sanity checking without the warnings in GetDeployment.
188 #endif
190 /* @GenerateCBinding,GeneratePInvoke */
191 void AddToggleRefNotifier (ToggleNotifyHandler tr);
192 /* @GenerateCBinding,GeneratePInvoke */
193 void RemoveToggleRefNotifier ();
195 protected:
196 virtual ~EventObject ();
197 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);
213 private:
214 void AddTickCallInternal (TickCallHandler handler, EventObject *data = NULL);
215 void Initialize (Deployment *deployment, Type::Kind type);
217 static void emit_async (EventObject *calldata);
219 EventLists *events;
220 Surface *surface; // TODO: Remove this (along with SetSurface)
221 Deployment *deployment;
222 gint32 refcount;
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 {
232 public:
233 /* @GenerateCBinding,GeneratePInvoke */
234 DependencyObject ();
235 virtual void Dispose ();
237 void Freeze ();
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
353 // essentially do:
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; }
387 protected:
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;
411 private:
412 void RemoveListener (gpointer listener, DependencyProperty *child_property);
413 void Initialize ();
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;
433 bool is_frozen;
434 bool is_hydrated;
436 char *resource_base;
439 #endif /* __MONO_DEPOBJECT_H__ */