2009-10-09 Chris Toshok <toshok@ximian.com>
[moon.git] / src / dependencyobject.h
blob27bd80522f5de89b8ec475b497fc1df15a677529
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 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 ();
161 // AddTickCall*:
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 ();
187 bool IsAttached ();
188 void SetIsAttached (bool value);
189 bool IsDisposed ();
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 ();
205 protected:
206 virtual ~EventObject ();
207 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);
223 private:
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 ();
230 EventLists *events;
231 Surface *surface; // TODO: Remove this (along with SetSurface)
232 Deployment *deployment;
233 gint32 refcount;
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 {
243 public:
244 /* @GenerateCBinding,GeneratePInvoke */
245 DependencyObject ();
246 virtual void Dispose ();
248 void Freeze ();
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
364 // essentially do:
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; }
398 protected:
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;
422 private:
423 void RemoveListener (gpointer listener, DependencyProperty *child_property);
424 void Initialize ();
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;
444 bool is_frozen;
445 bool is_hydrated;
447 char *resource_base;
450 #endif /* __MONO_DEPOBJECT_H__ */