Merge branch 'loaded-branch'
[moon.git] / src / dependencyobject.h
blobae3fc4b193ad4237527721fffb6092b6bc6f244c
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 typedef void (* HandlerMethod) (EventObject *object, EventHandler handler, gpointer handler_data, gpointer closure);
44 class EventLists;
47 //
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
50 // 0.
52 // DEBUGGING
53 //
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 {
65 public:
66 ToggleNotifyListener (EventObject *sender, ToggleNotifyHandler callback)
68 this->callback = callback;
69 this->sender = sender;
72 virtual void Invoke (bool isLastRef)
74 callback (sender, isLastRef);
77 private:
78 EventObject *sender;
79 ToggleNotifyHandler callback;
82 class EventObject {
83 private:
84 enum Flags {
85 MultiThreadedSafe = 1 << 29, // if the dtor can be called on any thread
86 Attached = 1 << 30,
87 Disposed = 1 << 31,
88 IdMask = ~(Attached | Disposed | MultiThreadedSafe),
90 public:
91 #if OBJECT_TRACKING
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);
97 #endif
99 /* @GenerateCBinding,GeneratePInvoke */
100 void ref ();
102 /* @GenerateCBinding,GeneratePInvoke */
103 void unref ();
105 int GetRefCount () { return refcount; }
106 int GetId () { return flags & IdMask; }
109 // Is:
110 // Similar to C#'s is: it checks if this object is of this kind or
111 // a derived class.
113 bool Is (Type::Kind k)
115 return Type::IsSubclassOf (GetDeployment (), GetObjectType (), k);
118 Type *GetType ()
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 ();
168 // AddTickCall*:
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 ();
194 bool IsAttached ();
195 void SetIsAttached (bool value);
196 bool IsDisposed ();
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 ();
212 protected:
213 virtual ~EventObject ();
214 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);
230 private:
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);
237 EventLists *events;
238 Surface *surface; // TODO: Remove this (along with SetSurface)
239 Deployment *deployment;
240 gint32 refcount;
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 {
250 public:
251 /* @GenerateCBinding,GeneratePInvoke */
252 DependencyObject ();
253 virtual void Dispose ();
255 void Freeze ();
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
371 // essentially do:
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; }
405 protected:
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;
429 private:
430 void RemoveListener (gpointer listener, DependencyProperty *child_property);
431 void Initialize ();
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;
451 bool is_frozen;
452 bool is_hydrated;
454 char *resource_base;
457 #endif /* __MONO_DEPOBJECT_H__ */