1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * dependencyobject.cpp:
5 * Copyright 2007 Novell, Inc. (http://www.novell.com)
7 * See the LICENSE file included with the distribution for details.
18 #include "namescope.h"
20 #include "collection.h"
21 #include "dependencyobject.h"
22 #include "textblock.h"
23 #include "timemanager.h"
25 #include "uielement.h"
26 #include "animation.h"
27 #include "deployment.h"
29 // event handlers for c++
30 class EventClosure
: public List::Node
{
32 EventClosure (EventHandler func
, gpointer data
, GDestroyNotify data_dtor
, int token
) {
35 this->data_dtor
= data_dtor
;
38 pending_removal
= false;
50 GDestroyNotify data_dtor
;
59 int starting_generation
;
60 EventClosure
**closures
;
73 class EmitContextNode
: public List::Node
{
75 EmitContextNode (EmitContext
*ctx
) : ctx (ctx
) { }
77 virtual ~EmitContextNode () { delete ctx
; }
79 EmitContext
*GetEmitContext () { return ctx
; }
87 int last_foreach_generation
;
89 EventClosure
*onevent
;
103 lists
= new EventList
[size
];
104 for (int i
= 0; i
< size
; i
++) {
105 lists
[i
].current_token
= 1;
106 lists
[i
].last_foreach_generation
= -1;
107 lists
[i
].context_stack
= new List();
108 lists
[i
].onevent
= NULL
;
109 lists
[i
].event_list
= new List ();
115 for (int i
= 0; i
< size
; i
++) {
116 delete lists
[i
].event_list
;
117 delete lists
[i
].onevent
;
118 delete lists
[i
].context_stack
;
129 #define OBJECT_TRACK(x,y) Track((x),(y))
131 #define OBJECT_TRACK(x,y)
134 EventObject::EventObject ()
136 Initialize (NULL
, Type::EVENTOBJECT
);
139 EventObject::EventObject (Type::Kind type
)
141 Initialize (NULL
, type
);
144 EventObject::EventObject (Type::Kind type
, bool multi_threaded_safe
)
146 Initialize (NULL
, type
);
147 if (multi_threaded_safe
)
148 flags
|= (gint32
) MultiThreadedSafe
;
151 EventObject::EventObject (Deployment
*deployment
)
153 Initialize (deployment
, Type::EVENTOBJECT
);
156 EventObject::EventObject (Deployment
*deployment
, Type::Kind type
)
158 Initialize (deployment
, type
);
161 static gint current_id
= 0;
164 EventObject::Initialize (Deployment
*depl
, Type::Kind type
)
167 depl
= Deployment::GetCurrent ();
171 if (deployment
!= NULL
&& this != deployment
)
174 flags
= g_atomic_int_exchange_and_add (¤t_id
, 1);
177 toggleNotifyListener
= NULL
;
180 switch (object_type
) {
182 Track ("Created", "<unknown>");
184 case Type::DEPLOYMENT
:
185 Track ("Created", "Deployment");
188 Track ("Created", depl
->GetTypes ()->Find (object_type
)->GetName ());
192 if (object_type
!= Type::DEPLOYMENT
)
193 Deployment::GetCurrent ()->TrackObjectCreated (this);
197 if (object_type
== Type::INVALID
)
198 g_warning ("EventObject::EventObject (): created object with type: INVALID.\n");
199 if (deployment
== NULL
)
200 g_warning ("EventObject::EventObject (): created object with a null deployment.\n");
204 EventObject::~EventObject()
207 if (object_type
!= Type::DEPLOYMENT
)
208 Deployment::GetCurrent ()->TrackObjectDestroyed (this);
209 Track ("Destroyed", "");
214 g_warning ("EventObject::~EventObject () #%i was deleted before its refcount reached 0 (current refcount: %i)\n", GetId (), refcount
);
220 // We can't unref the deployment in Dispose, it breaks
222 if (deployment
&& this != deployment
) {
223 deployment
->unref ();
228 static pthread_rwlock_t surface_lock
= PTHREAD_RWLOCK_INITIALIZER
;
231 EventObject::SetSurfaceLock ()
235 if ((result
= pthread_rwlock_wrlock (&surface_lock
)) != 0) {
236 printf ("EventObject::SetSurface (%p): Couldn't aquire write lock: %s\n", surface
, strerror (result
));
245 EventObject::SetSurface (Surface
*surface
)
247 if (!Surface::InMainThread () && surface
!= this->surface
) {
248 g_warning ("EventObject::SetSurface (): This method must not be called on any other than the main thread!\n");
250 if (debug_flags
& RUNTIME_DEBUG_DP
)
251 print_stack_trace ();
256 this->surface
= surface
;
260 EventObject::SetSurfaceUnlock ()
262 pthread_rwlock_unlock (&surface_lock
);
266 EventObject::AddTickCallSafe (TickCallHandler handler
, EventObject
*data
)
271 * This code assumes that the surface won't be destructed without setting the surface field on to NULL first.
272 * In other words: if we have a read lock here, the surface won't get destroyed, given that setting
273 * the surface field to NULL will block until we release the read lock.
276 if ((result
= pthread_rwlock_rdlock (&surface_lock
)) != 0) {
277 printf ("EventObject::AddTickCallSafe (): Couldn't aquire read lock: %s\n", strerror (result
));
281 AddTickCallInternal (handler
, data
);
283 pthread_rwlock_unlock (&surface_lock
);
287 EventObject::AddTickCall (TickCallHandler handler
, EventObject
*data
)
289 if (!Surface::InMainThread ()) {
290 g_warning ("EventObject::AddTickCall (): This method must not be called on any other than the main thread! Tick call won't be added.\n");
292 if (debug_flags
& RUNTIME_DEBUG_DP
)
293 print_stack_trace ();
298 AddTickCallInternal (handler
, data
);
302 EventObject::AddTickCallInternal (TickCallHandler handler
, EventObject
*data
)
305 TimeManager
*timemanager
;
307 surface
= GetSurface ();
310 surface
= GetDeployment ()->GetSurface ();
313 LOG_DP ("EventObject::AddTickCall (): Could not add tick call, no surface\n");
317 timemanager
= surface
->GetTimeManager ();
320 LOG_DP ("EventObject::AddTickCall (): Could not add tick call, no time manager\n");
324 timemanager
->AddTickCall (handler
, data
? data
: this);
328 EventObject::GetDeployment ()
330 if (deployment
== NULL
)
331 g_warning ("EventObject::GetDeployment () should not be reached with a null deployment");
334 if (deployment
!= Deployment::GetCurrent () && Deployment::GetCurrent () != NULL
) {
335 g_warning ("EventObject::GetDeployment () our deployment %p doesn't match Deployment::GetCurrent () %p", deployment
, Deployment::GetCurrent ());
336 // print_stack_trace ();
344 EventObject::SetCurrentDeployment (bool domain
, bool register_thread
)
346 if (deployment
!= NULL
) {
348 Deployment::RegisterThread (deployment
);
349 Deployment::SetCurrent (deployment
, domain
);
354 EventObject::GetSurface ()
357 Deployment
*current_deployment
= Deployment::GetCurrent ();
358 Application
*current_application
;
359 current_application
= deployment
!= NULL
? deployment
->GetCurrentApplication () : (current_deployment
!= NULL
? current_deployment
->GetCurrentApplication () : NULL
);
361 if (deployment
!= NULL
&& deployment
!= current_deployment
) {
362 printf ("EventObject::GetSurface (): WARNING deployment: %p, Deployment::GetCurrent (): %p type: %s, id: %i\n", deployment
, current_deployment
, GetTypeName (), GET_OBJ_ID (this));
363 print_stack_trace ();
365 // current_application is null in the Surface ctor
366 if (!(current_application
== NULL
|| surface
== NULL
|| current_application
->GetSurface () == surface
))
367 printf ("EventObject::GetSurface (): assert failed: current application: %p, surface: %p, current application's surface: %p\n", current_application
, surface
, current_application
->GetSurface ());
370 return surface
; // When surface have been removed, return the Surface stored on the Deployment.
374 EventObject::Dispose ()
376 if (!IsDisposed () && Surface::InMainThread ()) {
377 // Dispose can be called multiple times, but Emit only once. When DestroyedEvent was in the dtor,
378 // it could only ever be emitted once, don't change that behaviour.
379 Emit (DestroyedEvent
); // TODO: Rename to DisposedEvent
383 // Remove attached flag and set the disposed flag.
384 flags
= (Flags
) (flags
& ~Attached
);
385 flags
= (Flags
) (flags
| Disposed
);
389 EventObject::IsDisposed ()
391 return (flags
& Disposed
) != 0;
397 int v
= g_atomic_int_exchange_and_add (&refcount
, 1);
400 if (GetObjectType () != object_type
)
401 printf ("EventObject::ref (): the type '%s' did not call SetObjectType, object_type is '%s'\n", Type::Find (GetObjectType ())->GetName (), Type::Find (object_type
)->GetName ());
403 if (deployment
!= Deployment::GetCurrent ()) {
404 printf ("EventObject::ref (): the type '%s' whose id is %i was created on a deployment (%p) different from the current deployment (%p).\n", GetTypeName (), GET_OBJ_ID (this), deployment
, Deployment::GetCurrent ());
405 // print_stack_trace ();
410 // Here something really bad happened, this object is probably being reffed again because
411 // of some action in the destructor. There is no way to recover from this now, no matter what
412 // we do the code that called ref now will be accessing a deleted object later on, which may or
413 // may not crash. It might very well be an exploitable security problem. Anyways when unref is called, we
414 // have a second delete on the same object, which *will* crash. To make things easier and safer
415 // lets just abort right away.
419 // Due to our mixed usage of Dispose and dtor, currently there are valid cases of reffing
420 // an object with refcount = 0. Use a warning instead of error until the mixed usage is
422 g_warning ("Ref was called on an object with a refcount of 0.\n");
424 } else if (v
== 1 && toggleNotifyListener
) {
425 if (getenv ("MOONLIGHT_ENABLE_TOGGLEREF"))
426 toggleNotifyListener
->Invoke (false);
429 OBJECT_TRACK ("Ref", GetTypeName ());
433 EventObject::unref ()
435 // we need to retrieve all instance fields into locals before decreasing the refcount
436 // TODO: do we need some sort of gcc foo (volatile variables, memory barries)
437 // to ensure that gcc does not optimize the fetches below away
438 ToggleNotifyListener
*toggle_listener
= this->toggleNotifyListener
;
440 Deployment
*depl
= this->deployment
? this->deployment
: Deployment::GetCurrent ();
441 const char *type_name
= depl
== NULL
? NULL
: Type::Find (depl
, GetObjectType ())->GetName ();
445 if (GetObjectType () != object_type
)
446 printf ("EventObject::unref (): the type '%s' did not call SetObjectType, object_type is '%s'\n", Type::Find (GetObjectType ())->GetName (), Type::Find (object_type
)->GetName ());
449 if (!IsMultiThreadedSafe () && !Surface::InMainThread ()) {
454 int v
= g_atomic_int_exchange_and_add (&refcount
, -1) - 1;
456 // from now on we can't access any instance fields if v > 0
457 // since another thread might have unreffed and caused our destruction
459 if (v
== 0 && events
!= NULL
&& events
->emitting
) {
460 g_atomic_int_exchange_and_add (&refcount
, 1);
465 OBJECT_TRACK ("Unref", type_name
);
468 // here we *can* access instance fields, since we know that we haven't been
469 // desctructed already.
473 if ((flags
& Disposed
) == 0)
474 printf ("EventObject::unref (): the type '%s' (or any of its parent types) forgot to call its base class' Dispose method.\n", GetTypeName ());
477 // We need to check again if the refcount really is zero,
478 // the object might have resurrected in the Dispose.
479 // TODO: we should disallow resurrection, it's not thread-safe
480 // if we got resurrected and unreffed, we'd be deleted by now
481 // in which case we'll double free here.
482 v
= g_atomic_int_get (&refcount
);
486 } else if (v
== 1 && toggle_listener
) {
487 // we know that toggle_listener hasn't been freed, since if it exists, it will have a ref to us which would prevent our destruction
488 // note that the instance field might point to garbage after decreasing the refcount above, so we access the local variable we
489 // retrieved before decreasing the refcount.
490 if (getenv ("MOONLIGHT_ENABLE_TOGGLEREF"))
491 toggle_listener
->Invoke (true);
496 g_warning ("EventObject::Unref (): NEGATIVE REFCOUNT id: %i v: %i refcount: %i", GET_OBJ_ID (this), v
, refcount
);
497 print_stack_trace ();
503 EventObject::AddToggleRefNotifier (ToggleNotifyHandler tr
)
505 if (toggleNotifyListener
)
509 toggleNotifyListener
= new ToggleNotifyListener (this, tr
);
513 EventObject::RemoveToggleRefNotifier ()
515 if (!toggleNotifyListener
)
518 delete toggleNotifyListener
;
519 toggleNotifyListener
= NULL
;
524 // Define the ID of the object you want to track
525 // Object creation, destruction and all ref/unrefs
526 // are logged to the console, with a stacktrace.
527 static bool object_id_fetched
= false;
528 static int object_id
= -1;
529 static const char *track_object_type
= NULL
;
530 static bool use_visi_output
= false;
531 static bool track_all
= false;
533 #define OBJECT_TRACK_ID (0)
535 GHashTable
* EventObject::objects_alive
= NULL
;
538 EventObject::Track (const char* done
, const char* typname
)
541 if (!object_id_fetched
) {
542 object_id_fetched
= true;
543 char *sval
= getenv ("MOONLIGHT_OBJECT_TRACK_ID");
545 object_id
= atoi (sval
);
546 track_object_type
= getenv ("MOONLIGHT_OBJECT_TRACK_TYPE");
547 use_visi_output
= (getenv ("MOONLIGHT_OBJECT_TRACK_VISI") != NULL
);
548 track_all
= (getenv ("MOONLIGHT_OBJECT_TRACK_ALL") != NULL
);
552 printf ("%p\t%s tracked object of type '%s': %i, current refcount: %i deployment: %p\n", this, done
, typname
, id
, refcount
, deployment
);
554 if (id
== object_id
|| (track_object_type
!= NULL
&& typname
!= NULL
&& strcmp (typname
, track_object_type
) == 0)) {
556 // load the stack trace before we print anything
557 // this way there's a lot smaller chance of
558 // ending up with other output between the first line (tracked object of type...)
559 // and the stack trace when using multiple threads.
560 if (!use_visi_output
)
561 st
= get_stack_trace ();
564 printf ("%p\t%s tracked object of type '%s': %i, current refcount: %i deployment: %p\n", this, done
, typname
, id
, refcount
, deployment
);
566 if (!use_visi_output
) {
569 print_reftrace (done
, typname
, refcount
, false);
576 EventObject::GetStackTrace (const char* prefix
)
578 return get_stack_trace_prefix (prefix
);
582 EventObject::PrintStackTrace ()
584 print_stack_trace ();
589 EventObject::AddHandler (const char *event_name
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
)
591 int id
= GetType()->LookupEvent (event_name
);
594 g_warning ("adding handler to event '%s', which has not been registered\n", event_name
);
598 return AddHandler (id
, handler
, data
, data_dtor
);
602 EventObject::AddHandler (int event_id
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
)
604 if (GetType()->GetEventCount() <= 0) {
605 g_warning ("adding handler to event with id %d, which has not been registered\n", event_id
);
610 events
= new EventLists (GetType ()->GetEventCount ());
612 int token
= events
->lists
[event_id
].current_token
++;
614 events
->lists
[event_id
].event_list
->Append (new EventClosure (handler
, data
, data_dtor
, token
));
620 EventObject::AddOnEventHandler (int event_id
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
)
622 if (GetType()->GetEventCount() <= event_id
) {
623 g_warning ("adding OnEvent handler to event with id %d, which has not been registered\n", event_id
);
628 events
= new EventLists (GetType ()->GetEventCount ());
630 events
->lists
[event_id
].onevent
= new EventClosure (handler
, data
, data_dtor
, 0);
634 EventObject::RemoveOnEventHandler (int event_id
, EventHandler handler
, gpointer data
)
636 if (GetType()->GetEventCount() <= event_id
) {
637 g_warning ("adding OnEvent handler to event with id %d, which has not been registered\n", event_id
);
642 events
= new EventLists (GetType ()->GetEventCount ());
644 if (events
->lists
[event_id
].onevent
) {
645 // FIXME check handler + data
646 delete events
->lists
[event_id
].onevent
;
647 events
->lists
[event_id
].onevent
= NULL
;
652 EventObject::AddXamlHandler (const char *event_name
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
)
654 int id
= GetType ()->LookupEvent (event_name
);
657 g_warning ("adding xaml handler to event '%s', which has not been registered\n", event_name
);
661 return AddXamlHandler (id
, handler
, data
, data_dtor
);
665 EventObject::AddXamlHandler (int event_id
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
)
667 if (GetType ()->GetEventCount () <= 0) {
668 g_warning ("adding xaml handler to event with id %d, which has not been registered\n", event_id
);
673 events
= new EventLists (GetType ()->GetEventCount ());
675 events
->lists
[event_id
].event_list
->Append (new EventClosure (handler
, data
, data_dtor
, 0));
681 EventObject::RemoveHandler (const char *event_name
, EventHandler handler
, gpointer data
)
683 int id
= GetType()->LookupEvent (event_name
);
686 g_warning ("removing handler for event '%s', which has not been registered\n", event_name
);
690 RemoveHandler (id
, handler
, data
);
694 EventObject::RemoveHandler (int event_id
, EventHandler handler
, gpointer data
)
697 if (GetType()->GetEventCount() <= 0) {
698 g_warning ("removing handler for event with id %d, which has not been registered\n", event_id
);
703 events
= new EventLists (GetType ()->GetEventCount ());
705 EventClosure
*closure
= (EventClosure
*) events
->lists
[event_id
].event_list
->First ();
707 if (closure
->func
== handler
&& closure
->data
== data
) {
708 token
= closure
->token
;
709 if (!events
->lists
[event_id
].context_stack
->IsEmpty()) {
710 closure
->pending_removal
= true;
712 events
->lists
[event_id
].event_list
->Remove (closure
);
717 closure
= (EventClosure
*) closure
->next
;
723 EventObject::RemoveHandler (int event_id
, int token
)
725 if (GetType()->GetEventCount() <= 0) {
726 g_warning ("removing handler for event with id %d, which has not been registered\n", event_id
);
731 events
= new EventLists (GetType ()->GetEventCount ());
733 EventClosure
*closure
= (EventClosure
*) events
->lists
[event_id
].event_list
->First ();
735 if (closure
->token
== token
) {
736 if (!events
->lists
[event_id
].context_stack
->IsEmpty()) {
737 closure
->pending_removal
= true;
739 events
->lists
[event_id
].event_list
->Remove (closure
);
744 closure
= (EventClosure
*) closure
->next
;
749 EventObject::RemoveAllHandlers (gpointer data
)
752 events
= new EventLists (GetType ()->GetEventCount ());
754 int count
= GetType ()->GetEventCount ();
756 for (int i
= 0; i
< count
- 1; i
++) {
757 EventClosure
*closure
= (EventClosure
*) events
->lists
[i
].event_list
->First ();
759 if (closure
->data
== data
) {
760 if (!events
->lists
[i
].context_stack
->IsEmpty()) {
761 closure
->pending_removal
= true;
763 events
->lists
[i
].event_list
->Remove (closure
);
768 closure
= (EventClosure
*) closure
->next
;
774 EventObject::RemoveMatchingHandlers (int event_id
, bool (*predicate
)(EventHandler cb_handler
, gpointer cb_data
, gpointer data
), gpointer closure
)
776 if (GetType()->GetEventCount() <= 0) {
777 g_warning ("removing handler for event with id %d, which has not been registered\n", event_id
);
782 events
= new EventLists (GetType ()->GetEventCount ());
784 EventClosure
*c
= (EventClosure
*) events
->lists
[event_id
].event_list
->First ();
786 if (predicate (c
->func
, c
->data
, closure
)) {
787 if (!events
->lists
[event_id
].context_stack
->IsEmpty()) {
788 c
->pending_removal
= true;
790 events
->lists
[event_id
].event_list
->Remove (c
);
795 c
= (EventClosure
*) c
->next
;
800 EventObject::ForeachHandler (int event_id
, bool only_new
, HandlerMethod m
, gpointer closure
)
802 if (GetType()->GetEventCount() <= 0)
806 events
= new EventLists (GetType ()->GetEventCount ());
808 EventClosure
*event_closure
= (EventClosure
*) events
->lists
[event_id
].event_list
->First ();
809 while (event_closure
) {
810 if (!only_new
|| event_closure
->token
>= events
->lists
[event_id
].last_foreach_generation
)
811 (*m
) (this, event_closure
->func
, event_closure
->data
, closure
);
812 event_closure
= (EventClosure
*) event_closure
->next
;
815 events
->lists
[event_id
].last_foreach_generation
= GetEventGeneration (event_id
);
819 EventObject::ClearForeachGeneration (int event_id
)
821 if (GetType()->GetEventCount() <= 0)
825 events
= new EventLists (GetType ()->GetEventCount ());
827 events
->lists
[event_id
].last_foreach_generation
= -1;
831 EventObject::ForHandler (int event_id
, int token
, HandlerMethod m
, gpointer closure
)
833 if (GetType()->GetEventCount() <= 0)
837 events
= new EventLists (GetType ()->GetEventCount ());
839 EventClosure
*event_closure
= (EventClosure
*) events
->lists
[event_id
].event_list
->First ();
840 while (event_closure
) {
841 if (event_closure
->token
== token
) {
842 (*m
) (this, event_closure
->func
, event_closure
->data
, closure
);
845 event_closure
= (EventClosure
*) event_closure
->next
;
850 EventObject::HasHandlers (int event_id
, int newer_than_generation
)
852 if (GetType()->GetEventCount() <= 0)
856 events
= new EventLists (GetType ()->GetEventCount ());
858 EventClosure
*event_closure
= (EventClosure
*) events
->lists
[event_id
].event_list
->First ();
859 while (event_closure
) {
860 if (newer_than_generation
!= -1 || event_closure
->token
>= newer_than_generation
)
862 event_closure
= (EventClosure
*) event_closure
->next
;
868 EventObject::GetEventGeneration (int event_id
)
870 if (GetType()->GetEventCount() <= 0) {
871 g_warning ("adding handler to event with id %d, which has not been registered\n", event_id
);
876 events
= new EventLists (GetType ()->GetEventCount ());
878 return events
->lists
[event_id
].current_token
;
882 EventObject::CanEmitEvents (int event_id
)
887 if (deployment
== NULL
)
888 return false; /* how did this happen? */
890 if (deployment
== this)
891 return true; /* Deployment::ShuttingDownEvent and Deployment::AppDomainUnloadedEvent */
893 if (event_id
== DestroyedEvent
) {
894 /* We need to allow this one too, namescopes listen to it to ensure
895 * that they detach from objects that are destroyed. Managed code
896 * doesn't listen to this event, so it's safe. */
900 if (deployment
->IsShuttingDown ()) {
901 /* Don't emit events after we've started shutting down, we might have
902 * managed event handlers, which could crash since the appdomain could
903 * have been unloaded */
911 EventObject::EmitAsync (const char *event_name
, EventArgs
*calldata
, bool only_unemitted
)
915 if ((event_id
= GetType ()->LookupEvent (GetDeployment (), event_name
)) == -1) {
916 g_warning ("trying to emit event '%s', which has not been registered\n", event_name
);
922 if (!CanEmitEvents (event_id
)) {
928 return EmitAsync (event_id
, calldata
, only_unemitted
);
932 EventObject::Emit (const char *event_name
, EventArgs
*calldata
, bool only_unemitted
, int starting_generation
)
934 int id
= GetType ()->LookupEvent (GetDeployment (), event_name
);
937 g_warning ("trying to emit event '%s', which has not been registered\n", event_name
);
943 if (!CanEmitEvents (id
)) {
949 return Emit (id
, calldata
, only_unemitted
, starting_generation
);
952 class AsyncEventClosure
: public EventObject
{
960 AsyncEventClosure (EventObject
*sender
, int event_id
, EventArgs
*args
, bool unemitted
, int generation
)
962 this->sender
= sender
;
963 this->event_id
= event_id
;
965 this->unemitted
= unemitted
;
966 this->generation
= generation
;
972 virtual ~AsyncEventClosure ()
979 EventObject::emit_async (EventObject
*calldata
)
981 AsyncEventClosure
*async
= (AsyncEventClosure
*) calldata
;
983 async
->sender
->Emit (async
->event_id
, async
->args
, async
->unemitted
, async
->generation
);
989 EventObject::EmitAsync (int event_id
, EventArgs
*calldata
, bool only_unemitted
)
991 if (!CanEmitEvents (event_id
)) {
998 events
= new EventLists (GetType ()->GetEventCount ());
1000 AddTickCall (EventObject::emit_async
, new AsyncEventClosure (this, event_id
, calldata
, only_unemitted
, GetEventGeneration (event_id
)));
1006 EventObject
*sender
;
1008 EventArgs
*calldata
;
1009 bool only_unemitted
;
1013 EventObject::EmitCallback (gpointer d
)
1015 EmitData
*data
= (EmitData
*) d
;
1016 data
->sender
->SetCurrentDeployment ();
1017 data
->sender
->Emit (data
->event_id
, data
->calldata
, data
->only_unemitted
);
1018 data
->sender
->unref ();
1021 Deployment::SetCurrent (NULL
);
1027 EventObject::Emit (int event_id
, EventArgs
*calldata
, bool only_unemitted
, int starting_generation
)
1029 if (!CanEmitEvents (event_id
)) {
1035 if (GetType()->GetEventCount() <= 0 || event_id
>= GetType()->GetEventCount()) {
1036 g_warning ("trying to emit event with id %d, which has not been registered\n", event_id
);
1043 events
= new EventLists (GetType ()->GetEventCount ());
1045 if (events
->lists
[event_id
].event_list
->IsEmpty () && events
->lists
[event_id
].onevent
== NULL
) {
1051 if (!Surface::InMainThread ()) {
1052 Surface
*surface
= deployment
? deployment
->GetSurface () : NULL
;
1054 if (surface
== NULL
) {
1055 printf ("EventObject::Emit (): could not emit event, the deployment %p does not have a surface.\n", deployment
);
1059 EmitData
*data
= new EmitData ();
1060 data
->sender
= this;
1061 data
->sender
->ref ();
1062 data
->event_id
= event_id
;
1063 data
->calldata
= calldata
;
1064 data
->only_unemitted
= only_unemitted
;
1065 surface
->GetTimeManager ()->AddTimeout (MOON_PRIORITY_HIGH
, 1, EmitCallback
, data
);
1069 EmitContext
* ctx
= StartEmit (event_id
, only_unemitted
, starting_generation
);
1070 DoEmit (event_id
, calldata
);
1072 FinishEmit (event_id
, ctx
);
1078 EventObject::StartEmit (int event_id
, bool only_unemitted
, int starting_generation
)
1081 events
= new EventLists (GetType ()->GetEventCount ());
1083 EmitContext
*ctx
= new EmitContext();
1084 ctx
->only_unemitted
= only_unemitted
;
1085 ctx
->starting_generation
= starting_generation
;
1086 EventClosure
*closure
;
1088 if (GetType()->GetEventCount() <= 0 || event_id
>= GetType()->GetEventCount()) {
1089 g_warning ("trying to start emit with id %d, which has not been registered\n", event_id
);
1095 events
->lists
[event_id
].context_stack
->Prepend (new EmitContextNode (ctx
));
1097 if (events
->lists
[event_id
].event_list
->IsEmpty ())
1100 ctx
->length
= events
->lists
[event_id
].event_list
->Length();
1101 ctx
->closures
= g_new (EventClosure
*, ctx
->length
);
1103 /* make a copy of the event list to use for emitting */
1104 closure
= (EventClosure
*) events
->lists
[event_id
].event_list
->First ();
1105 for (int i
= 0; closure
!= NULL
; i
++) {
1106 ctx
->closures
[i
] = closure
->pending_removal
? NULL
: closure
;
1107 closure
= (EventClosure
*) closure
->next
;
1114 EventObject::DoEmit (int event_id
, EventArgs
*calldata
)
1116 if (events
->lists
[event_id
].context_stack
->IsEmpty ()) {
1117 g_warning ("DoEmit called with no EmitContexts");
1121 EmitContext
*ctx
= ((EmitContextNode
*)events
->lists
[event_id
].context_stack
->First())->GetEmitContext();
1123 if (events
->lists
[event_id
].onevent
) {
1124 EventClosure
*closure
= events
->lists
[event_id
].onevent
;
1125 closure
->func (this, calldata
, closure
->data
);
1128 DoEmitCurrentContext (event_id
, calldata
);
1134 return ctx
->length
> 0;
1138 EventObject::DoEmitCurrentContext (int event_id
, EventArgs
*calldata
)
1140 if (events
->lists
[event_id
].context_stack
->IsEmpty()) {
1141 g_warning ("DoEmitCurrentContext called with no EmitContexts");
1145 EmitContext
*ctx
= ((EmitContextNode
*)events
->lists
[event_id
].context_stack
->First())->GetEmitContext();
1147 /* emit the events using the copied list in the context*/
1148 for (int i
= 0; i
< ctx
->length
; i
++) {
1149 if (calldata
&& calldata
->Is (Type::ROUTEDEVENTARGS
)) {
1150 RoutedEventArgs
*rea
= (RoutedEventArgs
*)calldata
;
1151 if (rea
->GetHandled ())
1155 EventClosure
*closure
= ctx
->closures
[i
];
1157 if (closure
&& closure
->func
1158 && (!ctx
->only_unemitted
|| closure
->emit_count
== 0)
1159 && (ctx
->starting_generation
== -1 || closure
->token
< ctx
->starting_generation
)) {
1160 closure
->func (this, calldata
, closure
->data
);
1162 closure
->emit_count
++;
1168 EventObject::FinishEmit (int event_id
, EmitContext
*ctx
)
1170 if (GetType()->GetEventCount() <= 0 || event_id
>= GetType()->GetEventCount()) {
1171 g_warning ("trying to finish emit with id %d, which has not been registered\n", event_id
);
1175 if (events
->lists
[event_id
].context_stack
->IsEmpty()) {
1176 g_warning ("FinishEmit called with no EmitContexts");
1180 EmitContextNode
*first_node
= (EmitContextNode
*)events
->lists
[event_id
].context_stack
->First();
1181 EmitContext
*first_ctx
= first_node
->GetEmitContext();
1183 if (first_ctx
!= ctx
) {
1184 g_warning ("FinishEmit called out of order");
1188 events
->lists
[event_id
].context_stack
->Unlink (first_node
);
1193 if (events
->lists
[event_id
].context_stack
->IsEmpty ()) {
1194 // Remove closures which are waiting for removal
1195 EventClosure
*closure
= (EventClosure
*) events
->lists
[event_id
].event_list
->First ();
1196 while (closure
!= NULL
) {
1197 EventClosure
*next
= (EventClosure
*) closure
->next
;
1198 if (closure
->pending_removal
)
1199 events
->lists
[event_id
].event_list
->Remove (closure
);
1206 EventObject::unref_delayed ()
1210 OBJECT_TRACK ("DelayedUnref", GetTypeName ());
1212 // access deployment as long as we have it (until Dispose has been called),
1213 // after that access the static deployment.
1214 depl
= deployment
? deployment
: Deployment::GetCurrent ();
1215 depl
->UnrefDelayed (this);
1220 virtual bool Matches (PropertyChangedEventArgs
*args
) = 0;
1221 virtual void Invoke (DependencyObject
*sender
, PropertyChangedEventArgs
*args
, MoonError
*error
) = 0;
1223 virtual gpointer
GetListener () = 0;
1224 virtual gpointer
GetProperty () = 0;
1227 class WildcardListener
: public Listener
{
1229 WildcardListener (DependencyObject
*obj
, DependencyProperty
*prop
)
1235 virtual bool Matches (PropertyChangedEventArgs
*args
) { return true; }
1236 virtual void Invoke (DependencyObject
*sender
, PropertyChangedEventArgs
*args
, MoonError
*error
)
1238 // FIXME we ignore error here.
1239 obj
->OnSubPropertyChanged (prop
, sender
, args
);
1242 virtual gpointer
GetListener ()
1247 virtual gpointer
GetProperty ()
1254 DependencyObject
*obj
;
1255 DependencyProperty
*prop
;
1258 class CallbackListener
: public Listener
{
1260 CallbackListener (DependencyProperty
*prop
, PropertyChangeHandler cb
, gpointer closure
)
1264 this->closure
= closure
;
1267 virtual bool Matches (PropertyChangedEventArgs
*args
)
1269 return prop
== args
->GetProperty ();
1272 virtual void Invoke (DependencyObject
*sender
, PropertyChangedEventArgs
*args
, MoonError
*error
)
1274 cb (sender
, args
, error
, closure
);
1277 virtual gpointer
GetListener ()
1279 return (gpointer
)cb
;
1282 virtual gpointer
GetProperty ()
1288 PropertyChangeHandler cb
;
1289 DependencyProperty
*prop
;
1294 // Registers @listener as a listener on changes to @child_property of this DO.
1297 DependencyObject::AddPropertyChangeListener (DependencyObject
*listener
, DependencyProperty
*child_property
)
1299 listener_list
= g_slist_append (listener_list
, new WildcardListener (listener
, child_property
));
1303 DependencyObject::RemoveListener (gpointer listener
, DependencyProperty
*child_property
)
1306 for (GSList
*l
= listener_list
; l
; l
= next
) {
1308 Listener
*listen
= (Listener
*) l
->data
;
1310 if ((listen
->GetListener() == listener
)
1311 && (child_property
== NULL
|| listen
->GetProperty() == child_property
)) {
1312 listener_list
= g_slist_delete_link (listener_list
, l
);
1319 // Unregisters @container as a listener on changes to @child_property of this DO.
1322 DependencyObject::RemovePropertyChangeListener (DependencyObject
*listener
, DependencyProperty
*child_property
)
1324 RemoveListener (listener
, child_property
);
1328 DependencyObject::AddPropertyChangeHandler (DependencyProperty
*property
, PropertyChangeHandler cb
, gpointer closure
)
1330 listener_list
= g_slist_append (listener_list
, new CallbackListener (property
, cb
, closure
));
1334 DependencyObject::RemovePropertyChangeHandler (DependencyProperty
*property
, PropertyChangeHandler cb
)
1336 RemoveListener ((gpointer
)cb
, property
);
1340 unregister_depobj_values (gpointer key
,
1344 DependencyObject
*this_obj
= (DependencyObject
*)user_data
;
1345 //DependencyProperty *prop = (DependencyProperty*)key;
1346 Value
*v
= (Value
*)value
;
1348 if (v
!= NULL
&& v
->Is (Type::DEPENDENCY_OBJECT
) && v
->AsDependencyObject() != NULL
) {
1349 //printf ("unregistering from property %s\n", prop->name);
1350 DependencyObject
*obj
= v
->AsDependencyObject ();
1351 obj
->RemovePropertyChangeListener (this_obj
);
1352 obj
->SetParent (NULL
, NULL
);
1357 DependencyObject::RemoveAllListeners ()
1359 AutoCreatePropertyValueProvider
*autocreate
= (AutoCreatePropertyValueProvider
*) providers
[PropertyPrecedence_AutoCreate
];
1362 g_hash_table_foreach (autocreate
->auto_values
, unregister_depobj_values
, this);
1364 g_hash_table_foreach (local_values
, unregister_depobj_values
, this);
1367 static bool listeners_notified
;
1370 DependencyObject::NotifyListenersOfPropertyChange (PropertyChangedEventArgs
*args
, MoonError
*error
)
1372 g_return_if_fail (args
);
1374 listeners_notified
= true;
1376 for (GSList
*l
= listener_list
; l
!= NULL
; l
= l
->next
){
1377 Listener
*listener
= (Listener
*)l
->data
;
1379 if (listener
->Matches (args
))
1380 listener
->Invoke (this, args
, error
);
1381 if (error
&& error
->number
)
1387 DependencyObject::NotifyListenersOfPropertyChange (int id
, MoonError
*error
)
1391 NotifyListenersOfPropertyChange (GetDeployment ()->GetTypes ()->GetProperty (id
), error
);
1395 DependencyObject::NotifyListenersOfPropertyChange (DependencyProperty
*subproperty
, MoonError
*error
)
1397 // XXX I really think this method should go away. we only use it in
1398 // a couple of places, and it abuses things.
1400 Value
*new_value
= subproperty
? GetValue (subproperty
) : NULL
;
1402 PropertyChangedEventArgs
*args
= new PropertyChangedEventArgs (subproperty
, subproperty
->GetId (), NULL
, new_value
);
1404 NotifyListenersOfPropertyChange (args
, error
);
1410 DependencyObject::IsValueValid (DependencyProperty
* property
, Value
* value
, MoonError
*error
)
1412 if (property
== NULL
) {
1413 MoonError::FillIn (error
, MoonError::ARGUMENT_NULL
, 1001,
1414 "NULL property passed to IsValueValid");
1418 if (value
!= NULL
) {
1419 if (value
->Is (Type::EVENTOBJECT
) && !value
->AsEventObject ()) {
1420 // if it's a null DependencyObject, it doesn't matter what type it is
1424 if (value
->Is (Type::MANAGED
)) {
1425 // This is a big hack, we do no type-checking if we try to set a managed type.
1426 // Given that for the moment we might not have the surface available, we can't
1427 // do any type checks since we can't access types registered on the surface.
1431 if (!Type::IsAssignableFrom (property
->GetPropertyType(), value
->GetKind())) {
1432 char *error_msg
= g_strdup_printf ("DependencyObject::SetValue, value cannot be assigned to the "
1433 "property %s::%s (property has type '%s', value has type '%s')",
1434 GetTypeName (), property
->GetName(), Type::Find (property
->GetPropertyType())->GetName (),
1435 Type::Find (value
->GetKind ())->GetName ());
1436 MoonError::FillIn (error
, MoonError::ARGUMENT
, 1001, error_msg
);
1441 // In 2.0, property->GetPropertyType() can return
1442 // something greater than Type::LASTTYPE. Only check
1443 // built-in types for null Types registered on the
1444 // managed side has their own check there.
1445 if (!CanPropertyBeSetToNull (property
)) {
1446 char *error_msg
= g_strdup_printf ("Can not set a non-nullable scalar type to NULL (property: %s)",
1447 property
->GetName());
1448 MoonError::FillIn (error
, MoonError::ARGUMENT
, 1001, error_msg
);
1458 DependencyObject::CanPropertyBeSetToNull (DependencyProperty
* property
)
1460 if (property
->GetPropertyType () > Type::LASTTYPE
)
1463 if (Type::IsSubclassOf (property
->GetPropertyType(), Type::DEPENDENCY_OBJECT
))
1466 if (property
->IsNullable ())
1469 if (Type::IsSubclassOf (property
->GetPropertyType (), Type::STRING
))
1476 DependencyObject::SetValue (int id
, Value
*value
)
1480 return SetValue (GetDeployment ()->GetTypes ()->GetProperty (id
), value
);
1484 DependencyObject::SetValue (int id
, Value value
)
1488 return SetValue (GetDeployment ()->GetTypes ()->GetProperty (id
), value
);
1492 DependencyObject::SetValue (DependencyProperty
*property
, Value
*value
)
1495 return SetValueWithError (property
, value
, &err
);
1499 DependencyObject::SetValue (DependencyProperty
*property
, Value value
)
1502 return SetValueWithError (property
, &value
, &err
);
1506 DependencyObject::SetValueWithError (DependencyProperty
* property
, Value value
, MoonError
*error
)
1508 return SetValueWithError (property
, &value
, error
);
1512 DependencyObject::SetValueWithErrorImpl (DependencyProperty
*property
, Value
*value
, MoonError
*error
)
1515 char *error_msg
= g_strdup_printf ("Cannot set value for property '%s' on frozen DependencyObject '%s'", property
->GetName(), GetTypeName());
1516 MoonError::FillIn (error
, MoonError::UNAUTHORIZED_ACCESS
, error_msg
);
1521 AutoCreatePropertyValueProvider
*autocreate
= (AutoCreatePropertyValueProvider
*) providers
[PropertyPrecedence_AutoCreate
];
1522 Value
*current_value
;
1525 if (!(current_value
= ReadLocalValue (property
)))
1526 if (property
->IsAutoCreated ())
1527 current_value
= autocreate
->ReadLocalValue (property
);
1529 if (current_value
!= NULL
&& value
!= NULL
) {
1530 equal
= !property
->AlwaysChange() && (*current_value
== *value
);
1532 equal
= (current_value
== NULL
) && (value
== NULL
);
1538 // remove the old value
1539 g_hash_table_remove (local_values
, property
);
1541 if (property
->IsAutoCreated ())
1542 autocreate
->ClearValue (property
);
1544 if (value
&& (!property
->IsAutoCreated () || !value
->Is (Type::DEPENDENCY_OBJECT
) || value
->AsDependencyObject () != NULL
))
1545 new_value
= new Value (*value
);
1549 // replace it with the new value
1551 g_hash_table_insert (local_values
, property
, new_value
);
1553 ProviderValueChanged (PropertyPrecedence_LocalValue
, property
, current_value
, new_value
, true, true, error
);
1556 delete current_value
;
1563 DependencyObject::SetValueWithError (DependencyProperty
*property
, Value
*value
, MoonError
*error
)
1565 if (!IsValueValid (property
, value
, error
))
1567 if (!property
->Validate (this, value
, error
))
1570 return SetValueWithErrorImpl (property
, value
, error
);
1573 struct RegisterNamesClosure
{
1579 register_depobj_names (gpointer key
,
1583 RegisterNamesClosure
*closure
= (RegisterNamesClosure
*)user_data
;
1584 if (closure
->error
->number
)
1587 Value
*v
= (Value
*)value
;
1589 if (v
!= NULL
&& v
->Is (Type::DEPENDENCY_OBJECT
) && v
->AsDependencyObject() != NULL
) {
1590 DependencyObject
*obj
= v
->AsDependencyObject ();
1591 obj
->RegisterAllNamesRootedAt (closure
->to_ns
, closure
->error
);
1596 DependencyObject::RegisterAllNamesRootedAt (NameScope
*to_ns
, MoonError
*error
)
1598 AutoCreatePropertyValueProvider
*autocreate
= (AutoCreatePropertyValueProvider
*) providers
[PropertyPrecedence_AutoCreate
];
1603 bool merge_namescope
= false;
1604 bool register_name
= false;
1605 bool recurse
= false;
1607 NameScope
*this_ns
= NameScope::GetNameScope(this);
1609 if (this_ns
&& this_ns
->GetTemporary()) {
1610 merge_namescope
= true;
1612 else if (!this_ns
) {
1614 register_name
= true;
1616 else if (IsHydratedFromXaml ()) {
1617 register_name
= true;
1621 if (merge_namescope
) {
1622 to_ns
->MergeTemporaryScope (this_ns
, error
);
1623 ClearValue (NameScope::NameScopeProperty
, false);
1626 if (register_name
) {
1627 const char *n
= GetName();
1630 DependencyObject
*o
= to_ns
->FindName (n
);
1633 char *error_msg
= g_strdup_printf ("The name already exists in the tree: %s.", n
);
1634 MoonError::FillIn (error
, MoonError::ARGUMENT
, 2028, error_msg
);
1640 to_ns
->RegisterName (n
, this);
1646 RegisterNamesClosure closure
;
1647 closure
.to_ns
= to_ns
;
1648 closure
.error
= error
;
1651 g_hash_table_foreach (autocreate
->auto_values
, register_depobj_names
, &closure
);
1653 g_hash_table_foreach (local_values
, register_depobj_names
, &closure
);
1658 unregister_depobj_names (gpointer key
,
1662 NameScope
*from_ns
= (NameScope
*)user_data
;
1663 Value
*v
= (Value
*)value
;
1664 DependencyProperty
*property
= (DependencyProperty
*)key
;
1666 if (property
->GetId() != UIElement::TagProperty
&& v
!= NULL
&& v
->Is (Type::DEPENDENCY_OBJECT
) && v
->AsDependencyObject() != NULL
) {
1667 DependencyObject
*obj
= v
->AsDependencyObject ();
1668 obj
->UnregisterAllNamesRootedAt (from_ns
);
1673 DependencyObject::UnregisterAllNamesRootedAt (NameScope
*from_ns
)
1675 AutoCreatePropertyValueProvider
*autocreate
= (AutoCreatePropertyValueProvider
*) providers
[PropertyPrecedence_AutoCreate
];
1677 NameScope
*this_ns
= NameScope::GetNameScope(this);
1678 if (IsHydratedFromXaml () || this_ns
== NULL
|| this_ns
->GetTemporary ()) {
1679 // Unregister in the parent scope
1681 const char *n
= GetName();
1683 if (n
&& strlen (n
) > 0)
1684 from_ns
->UnregisterName (n
);
1687 if (this_ns
&& !this_ns
->GetTemporary())
1691 g_hash_table_foreach (autocreate
->auto_values
, unregister_depobj_names
, from_ns
);
1693 g_hash_table_foreach (local_values
, unregister_depobj_names
, from_ns
);
1697 DependencyObject::SetName (const char* name
, NameScope
*scope
)
1699 DependencyProperty
*property
= GetDeployment ()->GetTypes ()->GetProperty (NameProperty
);
1701 if (scope
->FindName (name
))
1704 Value
*new_value
= new Value (name
);
1705 SetValue (property
, new_value
);
1706 scope
->RegisterName (name
, this);
1712 DependencyObject::ReadLocalValue (int id
)
1716 return ReadLocalValue (GetDeployment ()->GetTypes ()->GetProperty (id
));
1720 DependencyObject::ReadLocalValue (DependencyProperty
*property
)
1722 return (Value
*) g_hash_table_lookup (local_values
, property
);
1726 DependencyObject::ReadLocalValueWithError (DependencyProperty
*property
, MoonError
*error
)
1728 if (!HasProperty (Type::INVALID
, property
, true)) {
1729 Type
*pt
= Type::Find (property
->GetOwnerType ());
1730 char *error_msg
= g_strdup_printf ("Cannot get the DependencyProperty %s.%s on an object of type %s", pt
? pt
->GetName () : "<unknown>", property
->GetName (), GetTypeName ());
1731 MoonError::FillIn (error
, MoonError::EXCEPTION
, error_msg
);
1735 return ReadLocalValue (property
);
1739 DependencyObject::GetValueWithError (Type::Kind whatami
, DependencyProperty
*property
, MoonError
*error
)
1741 if (!HasProperty (whatami
, property
, true)) {
1742 Type
*pt
= Type::Find (property
->GetOwnerType ());
1743 char *error_msg
= g_strdup_printf ("Cannot get the DependencyProperty %s.%s on an object of type %s", pt
? pt
->GetName () : "<unknown>", property
->GetName (), GetTypeName ());
1744 MoonError::FillIn (error
, MoonError::EXCEPTION
, error_msg
);
1748 return GetValue (property
);
1752 DependencyObject::GetValue (int id
)
1756 return GetValue (GetDeployment ()->GetTypes ()->GetProperty (id
));
1760 DependencyObject::GetValue (DependencyProperty
*property
)
1762 return GetValue (property
, PropertyPrecedence_Highest
, PropertyPrecedence_Lowest
);
1766 DependencyObject::GetValue (DependencyProperty
*property
, PropertyPrecedence startingAtPrecedence
)
1768 return GetValue (property
, startingAtPrecedence
, PropertyPrecedence_Lowest
);
1772 DependencyObject::GetValue (DependencyProperty
*property
, PropertyPrecedence startingAtPrecedence
, PropertyPrecedence endingAtPrecedence
)
1774 for (int i
= startingAtPrecedence
; i
<= endingAtPrecedence
; i
++) {
1777 Value
*value
= providers
[i
]->GetPropertyValue (property
);
1778 if (value
) return value
;
1784 DependencyObject::GetValueNoDefault (int id
)
1788 return GetValueNoDefault (GetDeployment ()->GetTypes ()->GetProperty (id
));
1792 DependencyObject::GetValueNoDefault (DependencyProperty
*property
)
1794 Value
*value
= NULL
;
1796 for (int i
= 0; i
< PropertyPrecedence_DefaultValue
; i
++) {
1799 value
= providers
[i
]->GetPropertyValue (property
);
1802 return value
&& !value
->GetIsNull () ? value
: NULL
;
1806 DependencyObject::GetValueNoDefaultWithError (DependencyProperty
*property
, MoonError
*error
)
1808 if (!HasProperty (Type::INVALID
, property
, true)) {
1809 Type
*pt
= Type::Find (property
->GetOwnerType ());
1810 char *error_msg
= g_strdup_printf ("Cannot get the DependencyProperty %s.%s on an object of type %s", pt
? pt
->GetName () : "<unknown>", property
->GetName (), GetTypeName ());
1811 MoonError::FillIn (error
, MoonError::EXCEPTION
, error_msg
);
1815 return GetValueNoDefault (property
);
1819 DependencyObject::ProviderValueChanged (PropertyPrecedence providerPrecedence
,
1820 DependencyProperty
*property
,
1821 Value
*old_provider_value
, Value
*new_provider_value
,
1822 bool notify_listeners
, bool set_parent
, MoonError
*error
)
1826 // first we look for a value higher in precedence for this property
1827 for (p
= providerPrecedence
- 1; p
>= PropertyPrecedence_Highest
; p
--) {
1828 if (providers
[p
] && providers
[p
]->GetPropertyValue (property
)) {
1829 // a provider higher in precedence already has
1830 // a value for this property, so the one
1831 // that's changing isn't visible anyway.
1839 if (!old_provider_value
|| !new_provider_value
) {
1840 Value
*lower_priority_value
= GetValue (property
, (PropertyPrecedence
)(providerPrecedence
+ 1));
1842 if (new_provider_value
== NULL
) {
1843 // we're changing from @old_provider_value to whatever the
1844 // value lower on the priority list is.
1845 old_value
= old_provider_value
;
1846 new_value
= lower_priority_value
;
1848 else if (old_provider_value
== NULL
) {
1849 // we're changing from the old value (from a lower
1850 // priority provider) to @new_provider_value.
1851 old_value
= lower_priority_value
;
1852 new_value
= new_provider_value
;
1856 old_value
= old_provider_value
;
1857 new_value
= new_provider_value
;
1862 if (old_value
!= NULL
&& new_value
!= NULL
) {
1863 equal
= !property
->AlwaysChange() && (*old_value
== *new_value
);
1869 DependencyObject
*old_as_dep
= NULL
;
1870 DependencyObject
*new_as_dep
= NULL
;
1872 // XXX this flag should be part of the DP metadata.
1873 // we also need to audit other "typeof (object)" DP's
1874 // to make sure they set parent when they should (and
1875 // don't when they shouldn't.)
1876 bool setsParent
= set_parent
&& !property
->IsCustom ();
1878 if (old_value
&& old_value
->Is (Type::DEPENDENCY_OBJECT
))
1879 old_as_dep
= old_value
->AsDependencyObject ();
1880 if (new_value
&& new_value
->Is (Type::DEPENDENCY_OBJECT
))
1881 new_as_dep
= new_value
->AsDependencyObject ();
1883 if (old_as_dep
&& setsParent
) {
1884 old_as_dep
->SetSurface (NULL
);
1887 old_as_dep
->SetParent (NULL
, NULL
);
1889 // remove ourselves as a target
1890 old_as_dep
->RemoveTarget (this);
1892 // unregister from the existing value
1893 old_as_dep
->RemovePropertyChangeListener (this, property
);
1895 if (old_as_dep
->Is(Type::COLLECTION
)) {
1896 old_as_dep
->RemoveHandler (Collection::ChangedEvent
, collection_changed
, this);
1897 old_as_dep
->RemoveHandler (Collection::ItemChangedEvent
, collection_item_changed
, this);
1901 if (new_as_dep
&& setsParent
) {
1902 new_as_dep
->SetSurface (GetSurface ());
1904 new_as_dep
->SetParent (this, error
);
1908 new_as_dep
->SetResourceBase (GetResourceBase());
1910 if (new_as_dep
->Is(Type::COLLECTION
)) {
1911 new_as_dep
->AddHandler (Collection::ChangedEvent
, collection_changed
, this);
1912 new_as_dep
->AddHandler (Collection::ItemChangedEvent
, collection_item_changed
, this);
1915 // listen for property changes on the new object
1916 new_as_dep
->AddPropertyChangeListener (this, property
);
1918 // add ourselves as a target
1919 new_as_dep
->AddTarget (this);
1922 // we need to make this optional, as doing it for NameScope
1923 // merging is killing performance (and noone should ever care
1924 // about that property changing)
1925 if (notify_listeners
) {
1926 Value
*old_value_copy
= old_value
== NULL
? NULL
: new Value (*old_value
);
1927 Value
*new_value_copy
= new_value
== NULL
? NULL
: new Value (*new_value
);
1929 PropertyChangedEventArgs
*args
= new PropertyChangedEventArgs (property
, property
->GetId (), old_value_copy
, new_value_copy
);
1931 listeners_notified
= false;
1933 OnPropertyChanged (args
, error
);
1935 if (!listeners_notified
) {
1936 g_warning ("setting property %s::%s on object of type %s didn't result in listeners being notified",
1937 Type::Find(property
->GetOwnerType())->GetName (), property
->GetName(), GetTypeName ());
1939 g_warning ("the error was: %s", error
->message
);
1942 if (property
&& property
->GetChangedCallback () != NULL
) {
1943 PropertyChangeHandler callback
= property
->GetChangedCallback ();
1944 callback (this, args
, error
, NULL
);
1948 if (InheritedPropertyValueProvider::IsPropertyInherited (property
->GetId ()))
1949 InheritedPropertyValueProvider::PropagateInheritedProperty (this, property
, old_value_copy
, new_value_copy
);
1953 delete old_value_copy
;
1954 delete new_value_copy
;
1960 DependencyObject::ClearValue (int id
, bool notify_listeners
)
1964 ClearValue (GetDeployment ()->GetTypes ()->GetProperty (id
), notify_listeners
);
1968 DependencyObject::ClearValue (DependencyProperty
*property
, bool notify_listeners
)
1970 ClearValue(property
, notify_listeners
, NULL
);
1974 DependencyObject::ClearValue (DependencyProperty
*property
, bool notify_listeners
, MoonError
*error
)
1976 AutoCreatePropertyValueProvider
*autocreate
= (AutoCreatePropertyValueProvider
*) providers
[PropertyPrecedence_AutoCreate
];
1977 Value
*old_local_value
;
1979 if (!(old_local_value
= ReadLocalValue (property
)))
1980 if (property
->IsAutoCreated ())
1981 old_local_value
= autocreate
->ReadLocalValue (property
);
1983 // detach from the existing value
1984 if (old_local_value
!= NULL
&& old_local_value
->Is (Type::DEPENDENCY_OBJECT
)) {
1985 DependencyObject
*dob
= old_local_value
->AsDependencyObject();
1989 dob
->SetParent (NULL
, NULL
);
1991 // unregister from the existing value
1992 dob
->RemovePropertyChangeListener (this, property
);
1993 dob
->SetSurface (NULL
);
1994 if (dob
->Is(Type::COLLECTION
)) {
1995 dob
->RemoveHandler (Collection::ChangedEvent
, collection_changed
, this);
1996 dob
->RemoveHandler (Collection::ItemChangedEvent
, collection_item_changed
, this);
2001 g_hash_table_remove (local_values
, property
);
2003 if (property
->IsAutoCreated ())
2004 autocreate
->ClearValue (property
);
2006 // this is... yeah, it's disgusting
2007 for (int p
= PropertyPrecedence_LocalValue
+ 1; p
< PropertyPrecedence_Count
; p
++) {
2009 providers
[p
]->RecomputePropertyValue (property
);
2012 ProviderValueChanged (PropertyPrecedence_LocalValue
, property
, old_local_value
, NULL
, notify_listeners
, true, error
);
2014 delete old_local_value
;
2018 DependencyObject::dispose_value (gpointer key
, gpointer value
, gpointer data
)
2020 DependencyObject
*_this
= (DependencyObject
*)data
;
2022 Value
*v
= (Value
*) value
;
2027 // detach from the existing value
2028 if (v
->Is (Type::DEPENDENCY_OBJECT
)){
2029 DependencyObject
*dob
= v
->AsDependencyObject();
2032 if (_this
== dob
->GetParent()) {
2033 // unset its logical parent
2034 dob
->SetParent (NULL
, NULL
);
2037 // unregister from the existing value
2038 dob
->RemovePropertyChangeListener ((DependencyObject
*)data
, NULL
);
2040 if (dob
->Is(Type::COLLECTION
)) {
2041 dob
->RemoveHandler (Collection::ChangedEvent
, collection_changed
, _this
);
2042 dob
->RemoveHandler (Collection::ItemChangedEvent
, collection_item_changed
, _this
);
2047 delete (Value
*) value
;
2053 DependencyObject::collection_changed (EventObject
*sender
, EventArgs
*args
, gpointer closure
)
2055 DependencyObject
*obj
= (DependencyObject
*)closure
;
2056 obj
->OnCollectionChanged ((Collection
*)sender
, (CollectionChangedEventArgs
*)args
);
2060 DependencyObject::collection_item_changed (EventObject
*sender
, EventArgs
*args
, gpointer closure
)
2062 DependencyObject
*obj
= (DependencyObject
*)closure
;
2063 CollectionItemChangedEventArgs
* itemArgs
= (CollectionItemChangedEventArgs
*)args
;
2065 PropertyChangedEventArgs
*propChangedArgs
= new PropertyChangedEventArgs (itemArgs
->GetProperty(),
2066 itemArgs
->GetProperty()->GetId (),
2067 itemArgs
->GetOldValue(),
2068 itemArgs
->GetNewValue());
2070 obj
->OnCollectionItemChanged ((Collection
*)sender
,
2071 itemArgs
->GetCollectionItem(),
2074 propChangedArgs
->unref ();
2077 DependencyObject::DependencyObject ()
2078 : EventObject (Type::DEPENDENCY_OBJECT
)
2083 DependencyObject::DependencyObject (Deployment
*deployment
, Type::Kind object_type
)
2084 : EventObject (deployment
, object_type
)
2089 DependencyObject::DependencyObject (Type::Kind object_type
)
2090 : EventObject (object_type
)
2096 DependencyObject::Initialize ()
2098 providers
= new PropertyValueProvider
*[PropertyPrecedence_Count
];
2100 providers
[PropertyPrecedence_LocalValue
] = new LocalPropertyValueProvider (this, PropertyPrecedence_LocalValue
);
2101 providers
[PropertyPrecedence_DynamicValue
] = NULL
; // subclasses will set this if they need it.
2103 providers
[PropertyPrecedence_LocalStyle
] = NULL
; // this is a frameworkelement specific thing
2104 providers
[PropertyPrecedence_DefaultStyle
] = NULL
; // this is a frameworkelement specific thing
2106 providers
[PropertyPrecedence_Inherited
] = new InheritedPropertyValueProvider (this, PropertyPrecedence_Inherited
);
2107 providers
[PropertyPrecedence_DefaultValue
] = new DefaultValuePropertyValueProvider (this, PropertyPrecedence_DefaultValue
);
2108 providers
[PropertyPrecedence_AutoCreate
] = new AutoCreatePropertyValueProvider (this, PropertyPrecedence_AutoCreate
);
2110 local_values
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
2111 listener_list
= NULL
;
2113 is_hydrated
= false;
2115 resource_base
= NULL
;
2116 storage_hash
= NULL
; // Create it on first usage request
2120 DependencyObject::Freeze()
2125 struct CloneClosure
{
2127 DependencyObject
*old_do
;
2128 DependencyObject
*new_do
;
2132 DependencyObject::clone_local_value (DependencyProperty
*key
, Value
*value
, gpointer data
)
2134 CloneClosure
*closure
= (CloneClosure
*)data
;
2136 // don't clone the name property, or we end up with nasty
2137 // duplicate name errors.
2138 if (key
->GetId() == DependencyObject::NameProperty
)
2141 Value
*cv
= Value::Clone (value
, closure
->types
);
2143 closure
->new_do
->SetValue (key
, cv
);
2149 DependencyObject::clone_autocreated_value (DependencyProperty
*key
, Value
*value
, gpointer data
)
2151 CloneClosure
*closure
= (CloneClosure
*)data
;
2153 Value
*old_value
= closure
->old_do
->GetValue (key
, PropertyPrecedence_AutoCreate
);
2155 // this should create the new object
2156 Value
*new_value
= closure
->new_do
->GetValue (key
, PropertyPrecedence_AutoCreate
);
2158 if (old_value
&& !old_value
->GetIsNull() && old_value
->Is (Type::DEPENDENCY_OBJECT
) &&
2159 new_value
&& !new_value
->GetIsNull() && new_value
->Is (Type::DEPENDENCY_OBJECT
)) {
2160 DependencyObject
*new_obj
= new_value
->AsDependencyObject(closure
->types
);
2161 DependencyObject
*old_obj
= old_value
->AsDependencyObject(closure
->types
);
2163 new_obj
->CloneCore (closure
->types
, old_obj
);
2168 DependencyObject::clone_animation_storage_list (DependencyProperty
*key
, List
*list
, gpointer data
)
2170 if (!list
|| list
->IsEmpty ())
2172 DependencyObject
*d
= (DependencyObject
*)data
;
2173 d
->CloneAnimationStorageList (key
, list
);
2177 DependencyObject::CloneAnimationStorageList (DependencyProperty
*key
, List
*list
)
2180 List
*newlist
= new List();
2182 AnimationStorage::Node
*node
= (AnimationStorage::Node
*) list
->First ();
2184 node
->storage
->SwitchTarget (this);
2185 newlist
->Append (node
->Clone ());
2186 node
= (AnimationStorage::Node
*)node
->next
;
2190 storage_hash
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
2191 g_hash_table_insert (storage_hash
, key
, newlist
);
2195 DependencyObject::Clone (Types
*types
)
2197 Type
*t
= types
->Find (GetObjectType());
2199 DependencyObject
*new_do
= t
->CreateInstance();
2202 new_do
->CloneCore (types
, (DependencyObject
*)this); // this cast should be unnecessary. but C++ const behavior sucks.
2208 DependencyObject::CloneCore (Types
*types
, DependencyObject
* fromObj
)
2210 CloneClosure closure
;
2211 closure
.types
= types
;
2212 closure
.old_do
= fromObj
;
2213 closure
.new_do
= this;
2215 AutoCreatePropertyValueProvider
*autocreate
= (AutoCreatePropertyValueProvider
*) fromObj
->providers
[PropertyPrecedence_AutoCreate
];
2217 g_hash_table_foreach (autocreate
->auto_values
, (GHFunc
)DependencyObject::clone_autocreated_value
, &closure
);
2218 g_hash_table_foreach (fromObj
->local_values
, (GHFunc
)DependencyObject::clone_local_value
, &closure
);
2219 if (fromObj
->storage_hash
) {
2220 g_hash_table_foreach (fromObj
->storage_hash
, (GHFunc
)DependencyObject::clone_animation_storage_list
, this);
2225 clear_storage_list (DependencyProperty
*key
, List
*list
, gpointer unused
)
2227 List::Node
*node
= list
->First ();
2229 delete ((AnimationStorage::Node
*)node
)->storage
;
2235 DependencyObject::~DependencyObject ()
2237 g_hash_table_destroy (local_values
);
2238 local_values
= NULL
;
2241 g_free (resource_base
);
2245 free_listener (gpointer data
, gpointer user_data
)
2247 Listener
* listener
= (Listener
*) data
;
2252 DependencyObject::Dispose ()
2254 AutoCreatePropertyValueProvider
*autocreate
= (AutoCreatePropertyValueProvider
*) providers
[PropertyPrecedence_AutoCreate
];
2256 if (listener_list
!= NULL
) {
2257 g_slist_foreach (listener_list
, free_listener
, NULL
);
2258 g_slist_free (listener_list
);
2259 listener_list
= NULL
;
2262 RemoveAllListeners();
2265 g_hash_table_foreach_remove (autocreate
->auto_values
, dispose_value
, this);
2267 g_hash_table_foreach_remove (local_values
, dispose_value
, this);
2269 for (int i
= 0; i
< PropertyPrecedence_Count
; i
++) {
2270 delete providers
[i
];
2271 providers
[i
] = NULL
;
2275 GHashTable
*tmphash
= storage_hash
; // animation storages may call back to DetachAnimationStorage
2276 storage_hash
= NULL
;
2277 g_hash_table_foreach (tmphash
, (GHFunc
)clear_storage_list
, NULL
);
2278 g_hash_table_destroy (tmphash
);
2281 EventObject::Dispose ();
2285 get_attached_props (gpointer key
, gpointer value
, gpointer user_data
)
2287 DependencyProperty
*prop
= (DependencyProperty
*) key
;
2288 GHashTable
*props
= (GHashTable
*) user_data
;
2290 if (!(g_hash_table_lookup (props
, (gpointer
) prop
->GetHashKey ())))
2291 g_hash_table_insert (props
, (gpointer
) prop
->GetHashKey (), prop
);
2295 hash_keys_to_array (gpointer key
, gpointer value
, gpointer user_data
)
2297 g_ptr_array_add ((GPtrArray
*) user_data
, key
);
2301 hash_values_to_array (gpointer key
, gpointer value
, gpointer user_data
)
2303 g_ptr_array_add ((GPtrArray
*) user_data
, value
);
2306 DependencyProperty
**
2307 DependencyObject::GetProperties (bool only_changed
)
2309 AutoCreatePropertyValueProvider
*autocreate
= (AutoCreatePropertyValueProvider
*) providers
[PropertyPrecedence_AutoCreate
];
2310 DependencyProperty
**props
;
2314 array
= g_ptr_array_new ();
2316 if (!only_changed
) {
2317 // get our class/inherited DependencyProperties
2318 table
= GetType ()->CopyProperties (true);
2320 // find any attached properties that have been set
2321 g_hash_table_foreach (local_values
, get_attached_props
, table
);
2323 // dump them to an array
2324 g_hash_table_foreach (table
, hash_values_to_array
, array
);
2325 g_hash_table_destroy (table
);
2327 g_hash_table_foreach (local_values
, hash_keys_to_array
, array
);
2328 g_hash_table_foreach (autocreate
->auto_values
, hash_keys_to_array
, array
);
2331 g_ptr_array_add (array
, NULL
);
2332 props
= (DependencyProperty
**) array
->pdata
;
2333 g_ptr_array_free (array
, false);
2338 DependencyProperty
*
2339 DependencyObject::GetDependencyProperty (const char *name
)
2341 return DependencyProperty::GetDependencyProperty (GetObjectType (), name
);
2345 DependencyObject::HasProperty (const char *name
, bool inherits
)
2347 return DependencyProperty::GetDependencyProperty (GetObjectType (), name
, inherits
) != NULL
;
2351 DependencyObject::HasProperty (Type::Kind whatami
, DependencyProperty
*property
, bool inherits
)
2353 Type::Kind this_type
= whatami
== Type::INVALID
? GetObjectType () : whatami
;
2355 // TODO: Handle attached properties correctly.
2357 if (property
->IsAttached ())
2361 printf ("DependencyObject::HasProperty (%p, %i (%s), %p (%i %s.%s), %i)..\n",
2363 whatami, Type::Find (whatami)->name,
2364 property, property->GetOwnerType (), Type::Find (property->GetOwnerType ())->name, property->GetName (),
2368 if (property
== NULL
)
2371 if (property
->GetOwnerType () == this_type
)
2377 if (!Type::IsSubclassOf (this_type
, property
->GetOwnerType ())) {
2378 bool is_prop_custom
= property
->IsCustom ();
2379 bool is_owner_custom
= property
->GetOwnerType () > Type::LASTTYPE
;
2380 bool is_this_custom
= this_type
> Type::LASTTYPE
;
2381 bool accept
= false;
2384 // This looks very wrong, but it's what SL seems to do.
2385 if (is_prop_custom
) {
2386 if (!is_owner_custom
&& !is_this_custom
) {
2387 // SL does not throw errors for custom properties defined on a builtin type
2388 // and then used on another (unrelated) builtin type (DO.GetValue usage at least)
2390 } else if (is_owner_custom
) {
2391 // And this is a custom property defined on a custom type and used anywhere.
2402 DependencyObject::FindName (const char *name
)
2404 return FindName (name
, Control::GetIsTemplateItem (this));
2408 DependencyObject::FindName (const char *name
, bool template_item
)
2410 NameScope
*scope
= NameScope::GetNameScope (this);
2412 if (scope
&& (template_item
== scope
->GetIsLocked ()))
2413 return scope
->FindName (name
);
2416 return parent
->FindName (name
, template_item
);
2422 DependencyObject::FindNameScope ()
2424 return FindNameScope (Control::GetIsTemplateItem (this));
2428 DependencyObject::FindNameScope (bool template_namescope
)
2430 NameScope
*scope
= NameScope::GetNameScope (this);
2432 // Only template namescopes are locked (for the moment)
2433 if (scope
&& (template_namescope
== scope
->GetIsLocked ()))
2437 return parent
->FindNameScope (template_namescope
);
2443 DependencyObject::FindName (const char *name
, Type::Kind
*element_kind
)
2445 //printf ("Looking up in %p the string %p\n", obj, name);
2446 //printf (" String: %s\n", name);
2447 DependencyObject
*ret
= FindName (name
);
2452 *element_kind
= ret
->GetObjectType ();
2458 DependencyObject::GetAnimationStorageFor (DependencyProperty
*prop
)
2463 List
*list
= (List
*) g_hash_table_lookup (storage_hash
, prop
);
2464 if (!list
|| !list
->IsEmpty ())
2467 return ((AnimationStorage::Node
*) list
->Last())->storage
;
2471 DependencyObject::AttachAnimationStorage (DependencyProperty
*prop
, AnimationStorage
*storage
)
2473 AnimationStorage
* attached_storage
= NULL
;
2474 // Create hash on first access to save some mem
2476 storage_hash
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
2478 List
*list
= (List
*) g_hash_table_lookup (storage_hash
, prop
);
2481 g_hash_table_insert (storage_hash
, prop
, list
);
2483 else if (!list
->IsEmpty ()) {
2484 attached_storage
= ((AnimationStorage::Node
*) list
->Last())->storage
;
2485 attached_storage
->Disable ();
2488 list
->Append (new AnimationStorage::Node (prop
, storage
));
2489 return attached_storage
;
2493 DependencyObject::DetachAnimationStorage (DependencyProperty
*prop
, AnimationStorage
*storage
)
2498 List
*list
= (List
*) g_hash_table_lookup (storage_hash
, prop
);
2499 if (!list
|| list
->IsEmpty ())
2502 // if the storage to be removed is the last one, activate the previous one (if any)
2503 if (((AnimationStorage::Node
*)list
->Last ())->storage
== storage
) {
2504 list
->Remove (list
->Last ());
2505 if (!list
->IsEmpty ()) {
2506 ((AnimationStorage::Node
*)list
->Last ())->storage
->Enable ();
2509 } else { // if there's more than one storage, that means the storage that was added after
2510 // the one we're removing is configured to reset back to the value of the previous
2511 // storage, so update the stop value so it resets back to the proper value
2512 List::Node
*node
= list
->First ();
2514 if (((AnimationStorage::Node
*)node
)->storage
== storage
) {
2515 List::Node
*remove
= node
;
2517 ((AnimationStorage::Node
*)node
)->storage
->SetStopValue (storage
->GetResetValue ());
2518 list
->Remove (remove
);
2527 // A helper debugging routine for C#
2530 dependency_object_get_name (DependencyObject
*obj
)
2532 return obj
->GetName ();
2536 dependency_object_get_object_type (DependencyObject
*obj
)
2538 return obj
->GetObjectType ();
2542 dependency_object_get_type_name (DependencyObject
*obj
)
2544 return obj
->GetTypeName ();
2547 // Used by routines which need to create DO from code
2549 dependency_object_set_name (DependencyObject
*obj
, const char *name
)
2551 obj
->SetValue (DependencyObject::NameProperty
, Value (name
));
2555 set_surface (gpointer key
, gpointer value
, gpointer data
)
2557 Surface
*s
= (Surface
*) data
;
2558 Value
*v
= (Value
*) value
;
2560 if (v
&& v
->Is (Type::DEPENDENCY_OBJECT
)) {
2561 DependencyObject
*dob
= v
->AsDependencyObject();
2563 dob
->SetSurface (s
);
2568 DependencyObject::SetSurface (Surface
*s
)
2570 AutoCreatePropertyValueProvider
*autocreate
= (AutoCreatePropertyValueProvider
*) providers
[PropertyPrecedence_AutoCreate
];
2572 if (GetSurface() == s
)
2575 EventObject::SetSurface (s
);
2578 g_hash_table_foreach (autocreate
->auto_values
, set_surface
, s
);
2580 g_hash_table_foreach (local_values
, set_surface
, s
);
2584 DependencyObject::SetParent (DependencyObject
*parent
, MoonError
*error
)
2586 if (parent
== this->parent
)
2590 // Check for circular families
2591 DependencyObject
*current
= parent
;
2592 while (current
!= NULL
) {
2593 if (current
== this) {
2594 g_warning ("cycle found in logical tree. bailing out");
2597 current
= current
->GetParent ();
2601 if (!this->parent
) {
2603 NameScope
*this_scope
= NameScope::GetNameScope(this);
2604 NameScope
*parent_scope
= parent
->FindNameScope();
2606 if (this_scope
->GetTemporary()) {
2607 // if we have a temporary name scope, merge it into the
2608 // closest one up the hierarchy.
2610 parent_scope
->MergeTemporaryScope (this_scope
, error
);
2611 ClearValue (NameScope::NameScopeProperty
, false);
2615 // there's no parent
2616 // namescope, we don't
2621 // we have a non-temporary scope. we still have to register the name
2622 // of this element (not the ones in the subtree rooted at this element)
2623 // in the new parent scope. we only register the name in the parent scope
2624 // if the element was hydrated, not when it was created from a string.
2625 if (IsHydratedFromXaml()) {
2626 const char *name
= GetName();
2627 if (parent_scope
&& name
&& *name
) {
2628 DependencyObject
*existing_obj
= parent_scope
->FindName (name
);
2629 if (existing_obj
!= this) {
2631 char *error_msg
= g_strdup_printf ("name `%s' is already registered in new parent namescope.", name
);
2632 MoonError::FillIn (error
, MoonError::ARGUMENT
, error_msg
);
2635 parent_scope
->RegisterName (name
, this);
2642 // we don't have a namescope at all,
2643 // we have to iterate over the subtree
2644 // rooted at this object, and merge
2645 // the names into the parent
2649 NameScope
*temp_scope
= new NameScope();
2650 temp_scope
->SetTemporary (true);
2652 RegisterAllNamesRootedAt (temp_scope
, error
);
2654 if (error
->number
) {
2655 temp_scope
->unref ();
2659 parent_scope
->MergeTemporaryScope (temp_scope
, error
);
2661 temp_scope
->unref ();
2668 NameScope
*parent_scope
= this->parent
->FindNameScope ();
2670 UnregisterAllNamesRootedAt (parent_scope
);
2674 if (!error
|| error
->number
== 0)
2675 this->parent
= parent
;
2679 dependency_object_get_value (DependencyObject
*object
, DependencyProperty
*prop
)
2684 return object
->GetValue (prop
);
2688 dependency_object_get_value_no_default (DependencyObject
*object
, DependencyProperty
*prop
)
2693 return object
->GetValueNoDefault (prop
);
2697 dependency_object_set_value (DependencyObject
*object
, DependencyProperty
*prop
, Value
*val
)
2702 object
->SetValue (prop
, val
);
2706 DependencyObject::OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
)
2708 if (DependencyObject::NameProperty
== args
->GetId ()) {
2709 NameScope
*scope
= FindNameScope ();
2710 if (scope
&& args
->GetNewValue()) {
2711 if (args
->GetOldValue ())
2712 scope
->UnregisterName (args
->GetOldValue ()->AsString ());
2713 scope
->RegisterName (args
->GetNewValue()->AsString (), this);
2715 if (IsHydratedFromXaml () && parent
) {
2716 // we also need to update any parent
2717 // namescope about our name change
2719 scope
= parent
->FindNameScope ();
2721 if (args
->GetOldValue ())
2722 scope
->UnregisterName (args
->GetOldValue ()->AsString ());
2723 scope
->RegisterName (args
->GetNewValue()->AsString (), this);
2729 NotifyListenersOfPropertyChange (args
, error
);
2733 DependencyObject::GetContent()
2735 const char *content_property_name
= GetType()->GetContentPropertyName();
2736 if (!content_property_name
)
2739 DependencyProperty
*content_property
= GetDependencyProperty (content_property_name
);
2740 if (!content_property
)
2743 Value
*content_value
= GetValue(content_property
);
2748 return content_value
->AsDependencyObject();