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
; }
88 EventClosure
*onevent
;
102 lists
= new EventList
[size
];
103 for (int i
= 0; i
< size
; i
++) {
104 lists
[i
].current_token
= 1;
105 lists
[i
].context_stack
= new List();
106 lists
[i
].onevent
= NULL
;
107 lists
[i
].event_list
= new List ();
113 for (int i
= 0; i
< size
; i
++) {
114 delete lists
[i
].event_list
;
115 delete lists
[i
].onevent
;
116 delete lists
[i
].context_stack
;
127 #define OBJECT_TRACK(x,y) Track((x),(y))
129 #define OBJECT_TRACK(x,y)
132 EventObject::EventObject ()
134 Initialize (NULL
, Type::EVENTOBJECT
);
137 EventObject::EventObject (Type::Kind type
)
139 Initialize (NULL
, type
);
142 EventObject::EventObject (Type::Kind type
, bool multi_threaded_safe
)
144 Initialize (NULL
, type
);
145 if (multi_threaded_safe
)
146 flags
|= (gint32
) MultiThreadedSafe
;
149 EventObject::EventObject (Deployment
*deployment
)
151 Initialize (deployment
, Type::EVENTOBJECT
);
154 EventObject::EventObject (Deployment
*deployment
, Type::Kind type
)
156 Initialize (deployment
, type
);
159 static gint current_id
= 0;
162 EventObject::Initialize (Deployment
*depl
, Type::Kind type
)
165 depl
= Deployment::GetCurrent ();
169 if (deployment
!= NULL
&& this != deployment
)
172 flags
= g_atomic_int_exchange_and_add (¤t_id
, 1);
175 toggleNotifyListener
= NULL
;
178 switch (object_type
) {
180 Track ("Created", "<unknown>");
182 case Type::DEPLOYMENT
:
183 Track ("Created", "Deployment");
186 Track ("Created", depl
->GetTypes ()->Find (object_type
)->GetName ());
190 if (object_type
!= Type::DEPLOYMENT
)
191 Deployment::GetCurrent ()->TrackObjectCreated (this);
195 if (object_type
== Type::INVALID
)
196 g_warning ("EventObject::EventObject (): created object with type: INVALID.\n");
197 if (deployment
== NULL
)
198 g_warning ("EventObject::EventObject (): created object with a null deployment.\n");
202 EventObject::~EventObject()
205 if (object_type
!= Type::DEPLOYMENT
)
206 Deployment::GetCurrent ()->TrackObjectDestroyed (this);
207 Track ("Destroyed", "");
212 g_warning ("EventObject::~EventObject () #%i was deleted before its refcount reached 0 (current refcount: %i)\n", GetId (), refcount
);
218 // We can't unref the deployment in Dispose, it breaks
220 if (deployment
&& this != deployment
) {
221 deployment
->unref ();
226 static pthread_rwlock_t surface_lock
= PTHREAD_RWLOCK_INITIALIZER
;
229 EventObject::SetSurfaceLock ()
233 if ((result
= pthread_rwlock_wrlock (&surface_lock
)) != 0) {
234 printf ("EventObject::SetSurface (%p): Couldn't aquire write lock: %s\n", surface
, strerror (result
));
243 EventObject::SetSurface (Surface
*surface
)
245 if (!Surface::InMainThread () && surface
!= this->surface
) {
246 g_warning ("EventObject::SetSurface (): This method must not be called on any other than the main thread!\n");
248 if (debug_flags
& RUNTIME_DEBUG_DP
)
249 print_stack_trace ();
254 this->surface
= surface
;
258 EventObject::SetSurfaceUnlock ()
260 pthread_rwlock_unlock (&surface_lock
);
264 EventObject::AddTickCallSafe (TickCallHandler handler
, EventObject
*data
)
269 * This code assumes that the surface won't be destructed without setting the surface field on to NULL first.
270 * In other words: if we have a read lock here, the surface won't get destroyed, given that setting
271 * the surface field to NULL will block until we release the read lock.
274 if ((result
= pthread_rwlock_rdlock (&surface_lock
)) != 0) {
275 printf ("EventObject::AddTickCallSafe (): Couldn't aquire read lock: %s\n", strerror (result
));
279 AddTickCallInternal (handler
, data
);
281 pthread_rwlock_unlock (&surface_lock
);
285 EventObject::AddTickCall (TickCallHandler handler
, EventObject
*data
)
287 if (!Surface::InMainThread ()) {
288 g_warning ("EventObject::AddTickCall (): This method must not be called on any other than the main thread! Tick call won't be added.\n");
290 if (debug_flags
& RUNTIME_DEBUG_DP
)
291 print_stack_trace ();
296 AddTickCallInternal (handler
, data
);
300 EventObject::AddTickCallInternal (TickCallHandler handler
, EventObject
*data
)
303 TimeManager
*timemanager
;
305 surface
= GetSurface ();
308 surface
= GetDeployment ()->GetSurface ();
311 LOG_DP ("EventObject::AddTickCall (): Could not add tick call, no surface\n");
315 timemanager
= surface
->GetTimeManager ();
318 LOG_DP ("EventObject::AddTickCall (): Could not add tick call, no time manager\n");
322 timemanager
->AddTickCall (handler
, data
? data
: this);
326 EventObject::GetDeployment ()
328 if (deployment
== NULL
)
329 g_warning ("EventObject::GetDeployment () should not be reached with a null deployment");
332 if (deployment
!= Deployment::GetCurrent () && Deployment::GetCurrent () != NULL
) {
333 g_warning ("EventObject::GetDeployment () our deployment %p doesn't match Deployment::GetCurrent () %p", deployment
, Deployment::GetCurrent ());
334 // print_stack_trace ();
342 EventObject::SetCurrentDeployment (bool domain
, bool register_thread
)
344 if (deployment
!= NULL
) {
346 Deployment::RegisterThread (deployment
);
347 Deployment::SetCurrent (deployment
, domain
);
352 EventObject::GetSurface ()
355 Deployment
*current_deployment
= Deployment::GetCurrent ();
356 Application
*current_application
;
357 current_application
= deployment
!= NULL
? deployment
->GetCurrentApplication () : (current_deployment
!= NULL
? current_deployment
->GetCurrentApplication () : NULL
);
359 if (deployment
!= NULL
&& deployment
!= current_deployment
) {
360 printf ("EventObject::GetSurface (): WARNING deployment: %p, Deployment::GetCurrent (): %p type: %s, id: %i\n", deployment
, current_deployment
, GetTypeName (), GET_OBJ_ID (this));
361 print_stack_trace ();
363 // current_application is null in the Surface ctor
364 if (!(current_application
== NULL
|| surface
== NULL
|| current_application
->GetSurface () == surface
))
365 printf ("EventObject::GetSurface (): assert failed: current application: %p, surface: %p, current application's surface: %p\n", current_application
, surface
, current_application
->GetSurface ());
368 return surface
; // When surface have been removed, return the Surface stored on the Deployment.
372 EventObject::Dispose ()
374 if (!IsDisposed () && Surface::InMainThread ()) {
375 // Dispose can be called multiple times, but Emit only once. When DestroyedEvent was in the dtor,
376 // it could only ever be emitted once, don't change that behaviour.
377 Emit (DestroyedEvent
); // TODO: Rename to DisposedEvent
381 // Remove attached flag and set the disposed flag.
382 flags
= (Flags
) (flags
& ~Attached
);
383 flags
= (Flags
) (flags
| Disposed
);
387 EventObject::IsDisposed ()
389 return (flags
& Disposed
) != 0;
395 int v
= g_atomic_int_exchange_and_add (&refcount
, 1);
398 if (GetObjectType () != object_type
)
399 printf ("EventObject::ref (): the type '%s' did not call SetObjectType, object_type is '%s'\n", Type::Find (GetObjectType ())->GetName (), Type::Find (object_type
)->GetName ());
401 if (deployment
!= Deployment::GetCurrent ()) {
402 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 ());
403 // print_stack_trace ();
408 // Here something really bad happened, this object is probably being reffed again because
409 // of some action in the destructor. There is no way to recover from this now, no matter what
410 // we do the code that called ref now will be accessing a deleted object later on, which may or
411 // may not crash. It might very well be an exploitable security problem. Anyways when unref is called, we
412 // have a second delete on the same object, which *will* crash. To make things easier and safer
413 // lets just abort right away.
417 // Due to our mixed usage of Dispose and dtor, currently there are valid cases of reffing
418 // an object with refcount = 0. Use a warning instead of error until the mixed usage is
420 g_warning ("Ref was called on an object with a refcount of 0.\n");
422 } else if (v
== 1 && toggleNotifyListener
) {
423 if (getenv ("MOONLIGHT_ENABLE_TOGGLEREF"))
424 toggleNotifyListener
->Invoke (false);
427 OBJECT_TRACK ("Ref", GetTypeName ());
431 EventObject::unref ()
433 // we need to retrieve all instance fields into locals before decreasing the refcount
434 // TODO: do we need some sort of gcc foo (volatile variables, memory barries)
435 // to ensure that gcc does not optimize the fetches below away
436 ToggleNotifyListener
*toggle_listener
= this->toggleNotifyListener
;
438 Deployment
*depl
= this->deployment
? this->deployment
: Deployment::GetCurrent ();
439 const char *type_name
= depl
== NULL
? NULL
: Type::Find (depl
, GetObjectType ())->GetName ();
443 if (GetObjectType () != object_type
)
444 printf ("EventObject::unref (): the type '%s' did not call SetObjectType, object_type is '%s'\n", Type::Find (GetObjectType ())->GetName (), Type::Find (object_type
)->GetName ());
447 if (!IsMultiThreadedSafe () && !Surface::InMainThread ()) {
452 int v
= g_atomic_int_exchange_and_add (&refcount
, -1) - 1;
454 // from now on we can't access any instance fields if v > 0
455 // since another thread might have unreffed and caused our destruction
457 if (v
== 0 && events
!= NULL
&& events
->emitting
) {
458 g_atomic_int_exchange_and_add (&refcount
, 1);
463 OBJECT_TRACK ("Unref", type_name
);
466 // here we *can* access instance fields, since we know that we haven't been
467 // desctructed already.
471 if ((flags
& Disposed
) == 0)
472 printf ("EventObject::unref (): the type '%s' (or any of its parent types) forgot to call its base class' Dispose method.\n", GetTypeName ());
475 // We need to check again if the refcount really is zero,
476 // the object might have resurrected in the Dispose.
477 // TODO: we should disallow resurrection, it's not thread-safe
478 // if we got resurrected and unreffed, we'd be deleted by now
479 // in which case we'll double free here.
480 v
= g_atomic_int_get (&refcount
);
484 } else if (v
== 1 && toggle_listener
) {
485 // 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
486 // note that the instance field might point to garbage after decreasing the refcount above, so we access the local variable we
487 // retrieved before decreasing the refcount.
488 if (getenv ("MOONLIGHT_ENABLE_TOGGLEREF"))
489 toggle_listener
->Invoke (true);
494 g_warning ("EventObject::Unref (): NEGATIVE REFCOUNT id: %i v: %i refcount: %i", GET_OBJ_ID (this), v
, refcount
);
495 print_stack_trace ();
501 EventObject::AddToggleRefNotifier (ToggleNotifyHandler tr
)
503 if (toggleNotifyListener
)
507 toggleNotifyListener
= new ToggleNotifyListener (this, tr
);
511 EventObject::RemoveToggleRefNotifier ()
513 if (!toggleNotifyListener
)
516 delete toggleNotifyListener
;
517 toggleNotifyListener
= NULL
;
522 // Define the ID of the object you want to track
523 // Object creation, destruction and all ref/unrefs
524 // are logged to the console, with a stacktrace.
525 static bool object_id_fetched
= false;
526 static int object_id
= -1;
527 static const char *track_object_type
= NULL
;
528 static bool use_visi_output
= false;
529 static bool track_all
= false;
531 #define OBJECT_TRACK_ID (0)
533 GHashTable
* EventObject::objects_alive
= NULL
;
536 EventObject::Track (const char* done
, const char* typname
)
539 if (!object_id_fetched
) {
540 object_id_fetched
= true;
541 char *sval
= getenv ("MOONLIGHT_OBJECT_TRACK_ID");
543 object_id
= atoi (sval
);
544 track_object_type
= getenv ("MOONLIGHT_OBJECT_TRACK_TYPE");
545 use_visi_output
= (getenv ("MOONLIGHT_OBJECT_TRACK_VISI") != NULL
);
546 track_all
= (getenv ("MOONLIGHT_OBJECT_TRACK_ALL") != NULL
);
550 printf ("%p\t%s tracked object of type '%s': %i, current refcount: %i deployment: %p\n", this, done
, typname
, id
, refcount
, deployment
);
552 if (id
== object_id
|| (track_object_type
!= NULL
&& typname
!= NULL
&& strcmp (typname
, track_object_type
) == 0)) {
554 // load the stack trace before we print anything
555 // this way there's a lot smaller chance of
556 // ending up with other output between the first line (tracked object of type...)
557 // and the stack trace when using multiple threads.
558 if (!use_visi_output
)
559 st
= get_stack_trace ();
562 printf ("%p\t%s tracked object of type '%s': %i, current refcount: %i deployment: %p\n", this, done
, typname
, id
, refcount
, deployment
);
564 if (!use_visi_output
) {
567 print_reftrace (done
, typname
, refcount
, false);
574 EventObject::GetStackTrace (const char* prefix
)
576 return get_stack_trace_prefix (prefix
);
580 EventObject::PrintStackTrace ()
582 print_stack_trace ();
587 EventObject::AddHandler (const char *event_name
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
)
589 int id
= GetType()->LookupEvent (event_name
);
592 g_warning ("adding handler to event '%s', which has not been registered\n", event_name
);
596 return AddHandler (id
, handler
, data
, data_dtor
);
600 EventObject::AddHandler (int event_id
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
)
602 if (GetType()->GetEventCount() <= 0) {
603 g_warning ("adding handler to event with id %d, which has not been registered\n", event_id
);
608 events
= new EventLists (GetType ()->GetEventCount ());
610 int token
= events
->lists
[event_id
].current_token
++;
612 events
->lists
[event_id
].event_list
->Append (new EventClosure (handler
, data
, data_dtor
, token
));
618 EventObject::AddOnEventHandler (int event_id
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
)
620 if (GetType()->GetEventCount() <= event_id
) {
621 g_warning ("adding OnEvent handler to event with id %d, which has not been registered\n", event_id
);
626 events
= new EventLists (GetType ()->GetEventCount ());
628 events
->lists
[event_id
].onevent
= new EventClosure (handler
, data
, data_dtor
, 0);
632 EventObject::RemoveOnEventHandler (int event_id
, EventHandler handler
, gpointer data
)
634 if (GetType()->GetEventCount() <= event_id
) {
635 g_warning ("adding OnEvent handler to event with id %d, which has not been registered\n", event_id
);
640 events
= new EventLists (GetType ()->GetEventCount ());
642 if (events
->lists
[event_id
].onevent
) {
643 // FIXME check handler + data
644 delete events
->lists
[event_id
].onevent
;
645 events
->lists
[event_id
].onevent
= NULL
;
650 EventObject::AddXamlHandler (const char *event_name
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
)
652 int id
= GetType ()->LookupEvent (event_name
);
655 g_warning ("adding xaml handler to event '%s', which has not been registered\n", event_name
);
659 return AddXamlHandler (id
, handler
, data
, data_dtor
);
663 EventObject::AddXamlHandler (int event_id
, EventHandler handler
, gpointer data
, GDestroyNotify data_dtor
)
665 if (GetType ()->GetEventCount () <= 0) {
666 g_warning ("adding xaml handler to event with id %d, which has not been registered\n", event_id
);
671 events
= new EventLists (GetType ()->GetEventCount ());
673 events
->lists
[event_id
].event_list
->Append (new EventClosure (handler
, data
, data_dtor
, 0));
679 EventObject::RemoveHandler (const char *event_name
, EventHandler handler
, gpointer data
)
681 int id
= GetType()->LookupEvent (event_name
);
684 g_warning ("removing handler for event '%s', which has not been registered\n", event_name
);
688 RemoveHandler (id
, handler
, data
);
692 EventObject::RemoveHandler (int event_id
, EventHandler handler
, gpointer data
)
694 if (GetType()->GetEventCount() <= 0) {
695 g_warning ("removing handler for event with id %d, which has not been registered\n", event_id
);
700 events
= new EventLists (GetType ()->GetEventCount ());
702 EventClosure
*closure
= (EventClosure
*) events
->lists
[event_id
].event_list
->First ();
704 if (closure
->func
== handler
&& closure
->data
== data
) {
705 if (!events
->lists
[event_id
].context_stack
->IsEmpty()) {
706 closure
->pending_removal
= true;
708 events
->lists
[event_id
].event_list
->Remove (closure
);
713 closure
= (EventClosure
*) closure
->next
;
718 EventObject::RemoveHandler (int event_id
, int token
)
720 if (GetType()->GetEventCount() <= 0) {
721 g_warning ("removing handler for event with id %d, which has not been registered\n", event_id
);
726 events
= new EventLists (GetType ()->GetEventCount ());
728 EventClosure
*closure
= (EventClosure
*) events
->lists
[event_id
].event_list
->First ();
730 if (closure
->token
== token
) {
731 if (!events
->lists
[event_id
].context_stack
->IsEmpty()) {
732 closure
->pending_removal
= true;
734 events
->lists
[event_id
].event_list
->Remove (closure
);
739 closure
= (EventClosure
*) closure
->next
;
744 EventObject::RemoveAllHandlers (gpointer data
)
747 events
= new EventLists (GetType ()->GetEventCount ());
749 int count
= GetType ()->GetEventCount ();
751 for (int i
= 0; i
< count
- 1; i
++) {
752 EventClosure
*closure
= (EventClosure
*) events
->lists
[i
].event_list
->First ();
754 if (closure
->data
== data
) {
755 if (!events
->lists
[i
].context_stack
->IsEmpty()) {
756 closure
->pending_removal
= true;
758 events
->lists
[i
].event_list
->Remove (closure
);
763 closure
= (EventClosure
*) closure
->next
;
769 EventObject::RemoveMatchingHandlers (int event_id
, bool (*predicate
)(EventHandler cb_handler
, gpointer cb_data
, gpointer data
), gpointer closure
)
771 if (GetType()->GetEventCount() <= 0) {
772 g_warning ("removing handler for event with id %d, which has not been registered\n", event_id
);
777 events
= new EventLists (GetType ()->GetEventCount ());
779 EventClosure
*c
= (EventClosure
*) events
->lists
[event_id
].event_list
->First ();
781 if (predicate (c
->func
, c
->data
, closure
)) {
782 if (!events
->lists
[event_id
].context_stack
->IsEmpty()) {
783 c
->pending_removal
= true;
785 events
->lists
[event_id
].event_list
->Remove (c
);
790 c
= (EventClosure
*) c
->next
;
795 EventObject::GetEventGeneration (int event_id
)
797 if (GetType()->GetEventCount() <= 0) {
798 g_warning ("adding handler to event with id %d, which has not been registered\n", event_id
);
803 events
= new EventLists (GetType ()->GetEventCount ());
805 return events
->lists
[event_id
].current_token
;
809 EventObject::CanEmitEvents ()
814 if (deployment
== NULL
)
815 return false; /* how did this happen? */
817 if (deployment
== this)
818 return true; /* Deployment::ShuttingDownEvent and Deployment::AppDomainUnloadedEvent */
820 if (deployment
->IsShuttingDown ())
821 return false; /* don't emit events after we've started shutting down (except the two events on Deployment, which are used for proper shutdown) */
827 EventObject::EmitAsync (const char *event_name
, EventArgs
*calldata
, bool only_unemitted
)
831 if (!CanEmitEvents ()) {
837 if ((event_id
= GetType()->LookupEvent (event_name
)) == -1) {
838 g_warning ("trying to emit event '%s', which has not been registered\n", event_name
);
844 return EmitAsync (event_id
, calldata
, only_unemitted
);
848 EventObject::Emit (const char *event_name
, EventArgs
*calldata
, bool only_unemitted
, int starting_generation
)
850 if (!CanEmitEvents ()) {
856 int id
= GetType()->LookupEvent (event_name
);
859 g_warning ("trying to emit event '%s', which has not been registered\n", event_name
);
865 return Emit (id
, calldata
, only_unemitted
, starting_generation
);
868 class AsyncEventClosure
: public EventObject
{
876 AsyncEventClosure (EventObject
*sender
, int event_id
, EventArgs
*args
, bool unemitted
, int generation
)
878 this->sender
= sender
;
879 this->event_id
= event_id
;
881 this->unemitted
= unemitted
;
882 this->generation
= generation
;
888 virtual ~AsyncEventClosure ()
895 EventObject::emit_async (EventObject
*calldata
)
897 AsyncEventClosure
*async
= (AsyncEventClosure
*) calldata
;
899 async
->sender
->Emit (async
->event_id
, async
->args
, async
->unemitted
, async
->generation
);
905 EventObject::EmitAsync (int event_id
, EventArgs
*calldata
, bool only_unemitted
)
907 if (!CanEmitEvents ()) {
914 events
= new EventLists (GetType ()->GetEventCount ());
916 AddTickCall (EventObject::emit_async
, new AsyncEventClosure (this, event_id
, calldata
, only_unemitted
, GetEventGeneration (event_id
)));
929 EventObject::EmitCallback (gpointer d
)
931 EmitData
*data
= (EmitData
*) d
;
932 data
->sender
->SetCurrentDeployment ();
933 data
->sender
->Emit (data
->event_id
, data
->calldata
, data
->only_unemitted
);
934 data
->sender
->unref ();
937 Deployment::SetCurrent (NULL
);
943 EventObject::Emit (int event_id
, EventArgs
*calldata
, bool only_unemitted
, int starting_generation
)
945 if (!CanEmitEvents ()) {
951 if (GetType()->GetEventCount() <= 0 || event_id
>= GetType()->GetEventCount()) {
952 g_warning ("trying to emit event with id %d, which has not been registered\n", event_id
);
959 events
= new EventLists (GetType ()->GetEventCount ());
961 if (events
->lists
[event_id
].event_list
->IsEmpty () && events
->lists
[event_id
].onevent
== NULL
) {
967 if (!Surface::InMainThread ()) {
968 Surface
*surface
= deployment
? deployment
->GetSurface () : NULL
;
970 if (surface
== NULL
) {
971 printf ("EventObject::Emit (): could not emit event, the deployment %p does not have a surface.\n", deployment
);
975 EmitData
*data
= new EmitData ();
977 data
->sender
->ref ();
978 data
->event_id
= event_id
;
979 data
->calldata
= calldata
;
980 data
->only_unemitted
= only_unemitted
;
981 surface
->GetTimeManager ()->AddTimeout (MOON_PRIORITY_HIGH
, 1, EmitCallback
, data
);
985 EmitContext
* ctx
= StartEmit (event_id
, only_unemitted
, starting_generation
);
986 DoEmit (event_id
, calldata
);
988 FinishEmit (event_id
, ctx
);
994 EventObject::StartEmit (int event_id
, bool only_unemitted
, int starting_generation
)
997 events
= new EventLists (GetType ()->GetEventCount ());
999 EmitContext
*ctx
= new EmitContext();
1000 ctx
->only_unemitted
= only_unemitted
;
1001 ctx
->starting_generation
= starting_generation
;
1002 EventClosure
*closure
;
1004 if (GetType()->GetEventCount() <= 0 || event_id
>= GetType()->GetEventCount()) {
1005 g_warning ("trying to start emit with id %d, which has not been registered\n", event_id
);
1011 events
->lists
[event_id
].context_stack
->Prepend (new EmitContextNode (ctx
));
1013 if (events
->lists
[event_id
].event_list
->IsEmpty ())
1016 ctx
->length
= events
->lists
[event_id
].event_list
->Length();
1017 ctx
->closures
= g_new (EventClosure
*, ctx
->length
);
1019 /* make a copy of the event list to use for emitting */
1020 closure
= (EventClosure
*) events
->lists
[event_id
].event_list
->First ();
1021 for (int i
= 0; closure
!= NULL
; i
++) {
1022 ctx
->closures
[i
] = closure
->pending_removal
? NULL
: closure
;
1023 closure
= (EventClosure
*) closure
->next
;
1030 EventObject::DoEmit (int event_id
, EventArgs
*calldata
)
1032 if (events
->lists
[event_id
].context_stack
->IsEmpty ()) {
1033 g_warning ("DoEmit called with no EmitContexts");
1037 EmitContext
*ctx
= ((EmitContextNode
*)events
->lists
[event_id
].context_stack
->First())->GetEmitContext();
1039 if (events
->lists
[event_id
].onevent
) {
1040 EventClosure
*closure
= events
->lists
[event_id
].onevent
;
1041 closure
->func (this, calldata
, closure
->data
);
1044 DoEmitCurrentContext (event_id
, calldata
);
1050 return ctx
->length
> 0;
1054 EventObject::DoEmitCurrentContext (int event_id
, EventArgs
*calldata
)
1056 if (events
->lists
[event_id
].context_stack
->IsEmpty()) {
1057 g_warning ("DoEmitCurrentContext called with no EmitContexts");
1061 EmitContext
*ctx
= ((EmitContextNode
*)events
->lists
[event_id
].context_stack
->First())->GetEmitContext();
1063 /* emit the events using the copied list in the context*/
1064 for (int i
= 0; i
< ctx
->length
; i
++) {
1065 if (calldata
&& calldata
->Is (Type::ROUTEDEVENTARGS
)) {
1066 RoutedEventArgs
*rea
= (RoutedEventArgs
*)calldata
;
1067 if (rea
->GetHandled ())
1071 EventClosure
*closure
= ctx
->closures
[i
];
1073 if (closure
&& closure
->func
1074 && (!ctx
->only_unemitted
|| closure
->emit_count
== 0)
1075 && (ctx
->starting_generation
== -1 || closure
->token
< ctx
->starting_generation
)) {
1076 closure
->func (this, calldata
, closure
->data
);
1078 closure
->emit_count
++;
1084 EventObject::FinishEmit (int event_id
, EmitContext
*ctx
)
1086 if (GetType()->GetEventCount() <= 0 || event_id
>= GetType()->GetEventCount()) {
1087 g_warning ("trying to finish emit with id %d, which has not been registered\n", event_id
);
1091 if (events
->lists
[event_id
].context_stack
->IsEmpty()) {
1092 g_warning ("FinishEmit called with no EmitContexts");
1096 EmitContextNode
*first_node
= (EmitContextNode
*)events
->lists
[event_id
].context_stack
->First();
1097 EmitContext
*first_ctx
= first_node
->GetEmitContext();
1099 if (first_ctx
!= ctx
) {
1100 g_warning ("FinishEmit called out of order");
1104 events
->lists
[event_id
].context_stack
->Unlink (first_node
);
1109 if (events
->lists
[event_id
].context_stack
->IsEmpty ()) {
1110 // Remove closures which are waiting for removal
1111 EventClosure
*closure
= (EventClosure
*) events
->lists
[event_id
].event_list
->First ();
1112 while (closure
!= NULL
) {
1113 EventClosure
*next
= (EventClosure
*) closure
->next
;
1114 if (closure
->pending_removal
)
1115 events
->lists
[event_id
].event_list
->Remove (closure
);
1122 EventObject::unref_delayed ()
1126 OBJECT_TRACK ("DelayedUnref", GetTypeName ());
1128 // access deployment as long as we have it (until Dispose has been called),
1129 // after that access the static deployment.
1130 depl
= deployment
? deployment
: Deployment::GetCurrent ();
1131 depl
->UnrefDelayed (this);
1136 virtual bool Matches (PropertyChangedEventArgs
*args
) = 0;
1137 virtual void Invoke (DependencyObject
*sender
, PropertyChangedEventArgs
*args
, MoonError
*error
) = 0;
1139 virtual gpointer
GetListener () = 0;
1140 virtual gpointer
GetProperty () = 0;
1143 class WildcardListener
: public Listener
{
1145 WildcardListener (DependencyObject
*obj
, DependencyProperty
*prop
)
1151 virtual bool Matches (PropertyChangedEventArgs
*args
) { return true; }
1152 virtual void Invoke (DependencyObject
*sender
, PropertyChangedEventArgs
*args
, MoonError
*error
)
1154 // FIXME we ignore error here.
1155 obj
->OnSubPropertyChanged (prop
, sender
, args
);
1158 virtual gpointer
GetListener ()
1163 virtual gpointer
GetProperty ()
1170 DependencyObject
*obj
;
1171 DependencyProperty
*prop
;
1174 class CallbackListener
: public Listener
{
1176 CallbackListener (DependencyProperty
*prop
, PropertyChangeHandler cb
, gpointer closure
)
1180 this->closure
= closure
;
1183 virtual bool Matches (PropertyChangedEventArgs
*args
)
1185 return prop
== args
->GetProperty ();
1188 virtual void Invoke (DependencyObject
*sender
, PropertyChangedEventArgs
*args
, MoonError
*error
)
1190 cb (sender
, args
, error
, closure
);
1193 virtual gpointer
GetListener ()
1195 return (gpointer
)cb
;
1198 virtual gpointer
GetProperty ()
1204 PropertyChangeHandler cb
;
1205 DependencyProperty
*prop
;
1210 // Registers @listener as a listener on changes to @child_property of this DO.
1213 DependencyObject::AddPropertyChangeListener (DependencyObject
*listener
, DependencyProperty
*child_property
)
1215 listener_list
= g_slist_append (listener_list
, new WildcardListener (listener
, child_property
));
1219 DependencyObject::RemoveListener (gpointer listener
, DependencyProperty
*child_property
)
1222 for (GSList
*l
= listener_list
; l
; l
= next
) {
1224 Listener
*listen
= (Listener
*) l
->data
;
1226 if ((listen
->GetListener() == listener
)
1227 && (child_property
== NULL
|| listen
->GetProperty() == child_property
)) {
1228 listener_list
= g_slist_delete_link (listener_list
, l
);
1235 // Unregisters @container as a listener on changes to @child_property of this DO.
1238 DependencyObject::RemovePropertyChangeListener (DependencyObject
*listener
, DependencyProperty
*child_property
)
1240 RemoveListener (listener
, child_property
);
1244 DependencyObject::AddPropertyChangeHandler (DependencyProperty
*property
, PropertyChangeHandler cb
, gpointer closure
)
1246 listener_list
= g_slist_append (listener_list
, new CallbackListener (property
, cb
, closure
));
1250 DependencyObject::RemovePropertyChangeHandler (DependencyProperty
*property
, PropertyChangeHandler cb
)
1252 RemoveListener ((gpointer
)cb
, property
);
1256 unregister_depobj_values (gpointer key
,
1260 DependencyObject
*this_obj
= (DependencyObject
*)user_data
;
1261 //DependencyProperty *prop = (DependencyProperty*)key;
1262 Value
*v
= (Value
*)value
;
1264 if (v
!= NULL
&& v
->Is (Type::DEPENDENCY_OBJECT
) && v
->AsDependencyObject() != NULL
) {
1265 //printf ("unregistering from property %s\n", prop->name);
1266 DependencyObject
*obj
= v
->AsDependencyObject ();
1267 obj
->RemovePropertyChangeListener (this_obj
);
1268 obj
->SetParent (NULL
, NULL
);
1273 DependencyObject::RemoveAllListeners ()
1275 AutoCreatePropertyValueProvider
*autocreate
= (AutoCreatePropertyValueProvider
*) providers
[PropertyPrecedence_AutoCreate
];
1278 g_hash_table_foreach (autocreate
->auto_values
, unregister_depobj_values
, this);
1280 g_hash_table_foreach (local_values
, unregister_depobj_values
, this);
1283 static bool listeners_notified
;
1286 DependencyObject::NotifyListenersOfPropertyChange (PropertyChangedEventArgs
*args
, MoonError
*error
)
1288 g_return_if_fail (args
);
1290 listeners_notified
= true;
1292 for (GSList
*l
= listener_list
; l
!= NULL
; l
= l
->next
){
1293 Listener
*listener
= (Listener
*)l
->data
;
1295 if (listener
->Matches (args
))
1296 listener
->Invoke (this, args
, error
);
1297 if (error
&& error
->number
)
1303 DependencyObject::NotifyListenersOfPropertyChange (int id
, MoonError
*error
)
1307 NotifyListenersOfPropertyChange (GetDeployment ()->GetTypes ()->GetProperty (id
), error
);
1311 DependencyObject::NotifyListenersOfPropertyChange (DependencyProperty
*subproperty
, MoonError
*error
)
1313 // XXX I really think this method should go away. we only use it in
1314 // a couple of places, and it abuses things.
1316 Value
*new_value
= subproperty
? GetValue (subproperty
) : NULL
;
1318 PropertyChangedEventArgs
*args
= new PropertyChangedEventArgs (subproperty
, subproperty
->GetId (), NULL
, new_value
);
1320 NotifyListenersOfPropertyChange (args
, error
);
1326 DependencyObject::IsValueValid (DependencyProperty
* property
, Value
* value
, MoonError
*error
)
1328 if (property
== NULL
) {
1329 MoonError::FillIn (error
, MoonError::ARGUMENT_NULL
, 1001,
1330 "NULL property passed to IsValueValid");
1334 if (value
!= NULL
) {
1335 if (value
->Is (Type::EVENTOBJECT
) && !value
->AsEventObject ()) {
1336 // if it's a null DependencyObject, it doesn't matter what type it is
1340 if (value
->Is (Type::MANAGED
)) {
1341 // This is a big hack, we do no type-checking if we try to set a managed type.
1342 // Given that for the moment we might not have the surface available, we can't
1343 // do any type checks since we can't access types registered on the surface.
1347 if (!Type::IsAssignableFrom (property
->GetPropertyType(), value
->GetKind())) {
1348 char *error_msg
= g_strdup_printf ("DependencyObject::SetValue, value cannot be assigned to the "
1349 "property %s::%s (property has type '%s', value has type '%s')",
1350 GetTypeName (), property
->GetName(), Type::Find (property
->GetPropertyType())->GetName (),
1351 Type::Find (value
->GetKind ())->GetName ());
1352 MoonError::FillIn (error
, MoonError::ARGUMENT
, 1001, error_msg
);
1357 // In 2.0, property->GetPropertyType() can return
1358 // something greater than Type::LASTTYPE. Only check
1359 // built-in types for null Types registered on the
1360 // managed side has their own check there.
1361 if (!CanPropertyBeSetToNull (property
)) {
1362 char *error_msg
= g_strdup_printf ("Can not set a non-nullable scalar type to NULL (property: %s)",
1363 property
->GetName());
1364 MoonError::FillIn (error
, MoonError::ARGUMENT
, 1001, error_msg
);
1374 DependencyObject::CanPropertyBeSetToNull (DependencyProperty
* property
)
1376 if (property
->GetPropertyType () > Type::LASTTYPE
)
1379 if (Type::IsSubclassOf (property
->GetPropertyType(), Type::DEPENDENCY_OBJECT
))
1382 if (property
->IsNullable ())
1385 if (Type::IsSubclassOf (property
->GetPropertyType (), Type::STRING
))
1392 DependencyObject::SetValue (int id
, Value
*value
)
1396 return SetValue (GetDeployment ()->GetTypes ()->GetProperty (id
), value
);
1400 DependencyObject::SetValue (int id
, Value value
)
1404 return SetValue (GetDeployment ()->GetTypes ()->GetProperty (id
), value
);
1408 DependencyObject::SetValue (DependencyProperty
*property
, Value
*value
)
1411 return SetValueWithError (property
, value
, &err
);
1415 DependencyObject::SetValue (DependencyProperty
*property
, Value value
)
1418 return SetValueWithError (property
, &value
, &err
);
1422 DependencyObject::SetValueWithError (DependencyProperty
* property
, Value value
, MoonError
*error
)
1424 return SetValueWithError (property
, &value
, error
);
1428 DependencyObject::SetValueWithErrorImpl (DependencyProperty
*property
, Value
*value
, MoonError
*error
)
1431 char *error_msg
= g_strdup_printf ("Cannot set value for property '%s' on frozen DependencyObject '%s'", property
->GetName(), GetTypeName());
1432 MoonError::FillIn (error
, MoonError::UNAUTHORIZED_ACCESS
, error_msg
);
1437 AutoCreatePropertyValueProvider
*autocreate
= (AutoCreatePropertyValueProvider
*) providers
[PropertyPrecedence_AutoCreate
];
1438 Value
*current_value
;
1441 if (!(current_value
= ReadLocalValue (property
)))
1442 if (property
->IsAutoCreated ())
1443 current_value
= autocreate
->ReadLocalValue (property
);
1445 if (current_value
!= NULL
&& value
!= NULL
) {
1446 equal
= !property
->AlwaysChange() && (*current_value
== *value
);
1448 equal
= (current_value
== NULL
) && (value
== NULL
);
1454 // remove the old value
1455 g_hash_table_remove (local_values
, property
);
1457 if (property
->IsAutoCreated ())
1458 autocreate
->ClearValue (property
);
1460 if (value
&& (!property
->IsAutoCreated () || !value
->Is (Type::DEPENDENCY_OBJECT
) || value
->AsDependencyObject () != NULL
))
1461 new_value
= new Value (*value
);
1465 // replace it with the new value
1467 g_hash_table_insert (local_values
, property
, new_value
);
1469 ProviderValueChanged (PropertyPrecedence_LocalValue
, property
, current_value
, new_value
, true, true, error
);
1472 delete current_value
;
1479 DependencyObject::SetValueWithError (DependencyProperty
*property
, Value
*value
, MoonError
*error
)
1481 if (!IsValueValid (property
, value
, error
))
1483 if (!property
->Validate (this, value
, error
))
1486 return SetValueWithErrorImpl (property
, value
, error
);
1489 struct RegisterNamesClosure
{
1495 register_depobj_names (gpointer key
,
1499 RegisterNamesClosure
*closure
= (RegisterNamesClosure
*)user_data
;
1500 if (closure
->error
->number
)
1503 Value
*v
= (Value
*)value
;
1505 if (v
!= NULL
&& v
->Is (Type::DEPENDENCY_OBJECT
) && v
->AsDependencyObject() != NULL
) {
1506 DependencyObject
*obj
= v
->AsDependencyObject ();
1507 obj
->RegisterAllNamesRootedAt (closure
->to_ns
, closure
->error
);
1512 DependencyObject::RegisterAllNamesRootedAt (NameScope
*to_ns
, MoonError
*error
)
1514 AutoCreatePropertyValueProvider
*autocreate
= (AutoCreatePropertyValueProvider
*) providers
[PropertyPrecedence_AutoCreate
];
1519 bool merge_namescope
= false;
1520 bool register_name
= false;
1521 bool recurse
= false;
1523 NameScope
*this_ns
= NameScope::GetNameScope(this);
1525 if (this_ns
&& this_ns
->GetTemporary()) {
1526 merge_namescope
= true;
1528 else if (!this_ns
) {
1530 register_name
= true;
1532 else if (IsHydratedFromXaml ()) {
1533 register_name
= true;
1537 if (merge_namescope
) {
1538 to_ns
->MergeTemporaryScope (this_ns
, error
);
1539 ClearValue (NameScope::NameScopeProperty
, false);
1542 if (register_name
) {
1543 const char *n
= GetName();
1546 DependencyObject
*o
= to_ns
->FindName (n
);
1549 char *error_msg
= g_strdup_printf ("The name already exists in the tree: %s.", n
);
1550 MoonError::FillIn (error
, MoonError::ARGUMENT
, 2028, error_msg
);
1556 to_ns
->RegisterName (n
, this);
1562 RegisterNamesClosure closure
;
1563 closure
.to_ns
= to_ns
;
1564 closure
.error
= error
;
1567 g_hash_table_foreach (autocreate
->auto_values
, register_depobj_names
, &closure
);
1569 g_hash_table_foreach (local_values
, register_depobj_names
, &closure
);
1574 unregister_depobj_names (gpointer key
,
1578 NameScope
*from_ns
= (NameScope
*)user_data
;
1579 Value
*v
= (Value
*)value
;
1580 DependencyProperty
*property
= (DependencyProperty
*)key
;
1582 if (property
->GetId() != UIElement::TagProperty
&& v
!= NULL
&& v
->Is (Type::DEPENDENCY_OBJECT
) && v
->AsDependencyObject() != NULL
) {
1583 DependencyObject
*obj
= v
->AsDependencyObject ();
1584 obj
->UnregisterAllNamesRootedAt (from_ns
);
1589 DependencyObject::UnregisterAllNamesRootedAt (NameScope
*from_ns
)
1591 AutoCreatePropertyValueProvider
*autocreate
= (AutoCreatePropertyValueProvider
*) providers
[PropertyPrecedence_AutoCreate
];
1593 NameScope
*this_ns
= NameScope::GetNameScope(this);
1594 if (IsHydratedFromXaml () || this_ns
== NULL
|| this_ns
->GetTemporary ()) {
1595 // Unregister in the parent scope
1597 const char *n
= GetName();
1599 if (n
&& strlen (n
) > 0)
1600 from_ns
->UnregisterName (n
);
1603 if (this_ns
&& !this_ns
->GetTemporary())
1607 g_hash_table_foreach (autocreate
->auto_values
, unregister_depobj_names
, from_ns
);
1609 g_hash_table_foreach (local_values
, unregister_depobj_names
, from_ns
);
1613 DependencyObject::SetName (const char* name
, NameScope
*scope
)
1615 DependencyProperty
*property
= GetDeployment ()->GetTypes ()->GetProperty (NameProperty
);
1617 if (scope
->FindName (name
))
1620 Value
*new_value
= new Value (name
);
1621 SetValue (property
, new_value
);
1622 scope
->RegisterName (name
, this);
1628 DependencyObject::ReadLocalValue (int id
)
1632 return ReadLocalValue (GetDeployment ()->GetTypes ()->GetProperty (id
));
1636 DependencyObject::ReadLocalValue (DependencyProperty
*property
)
1638 return (Value
*) g_hash_table_lookup (local_values
, property
);
1642 DependencyObject::ReadLocalValueWithError (DependencyProperty
*property
, MoonError
*error
)
1644 if (!HasProperty (Type::INVALID
, property
, true)) {
1645 Type
*pt
= Type::Find (property
->GetOwnerType ());
1646 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 ());
1647 MoonError::FillIn (error
, MoonError::EXCEPTION
, error_msg
);
1651 return ReadLocalValue (property
);
1655 DependencyObject::GetValueWithError (Type::Kind whatami
, DependencyProperty
*property
, MoonError
*error
)
1657 if (!HasProperty (whatami
, property
, true)) {
1658 Type
*pt
= Type::Find (property
->GetOwnerType ());
1659 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 ());
1660 MoonError::FillIn (error
, MoonError::EXCEPTION
, error_msg
);
1664 return GetValue (property
);
1668 DependencyObject::GetValue (int id
)
1672 return GetValue (GetDeployment ()->GetTypes ()->GetProperty (id
));
1676 DependencyObject::GetValue (DependencyProperty
*property
)
1678 return GetValue (property
, PropertyPrecedence_Highest
, PropertyPrecedence_Lowest
);
1682 DependencyObject::GetValue (DependencyProperty
*property
, PropertyPrecedence startingAtPrecedence
)
1684 return GetValue (property
, startingAtPrecedence
, PropertyPrecedence_Lowest
);
1688 DependencyObject::GetValue (DependencyProperty
*property
, PropertyPrecedence startingAtPrecedence
, PropertyPrecedence endingAtPrecedence
)
1690 for (int i
= startingAtPrecedence
; i
<= endingAtPrecedence
; i
++) {
1693 Value
*value
= providers
[i
]->GetPropertyValue (property
);
1694 if (value
) return value
;
1700 DependencyObject::GetValueNoDefault (int id
)
1704 return GetValueNoDefault (GetDeployment ()->GetTypes ()->GetProperty (id
));
1708 DependencyObject::GetValueNoDefault (DependencyProperty
*property
)
1710 Value
*value
= NULL
;
1712 for (int i
= 0; i
< PropertyPrecedence_DefaultValue
; i
++) {
1715 value
= providers
[i
]->GetPropertyValue (property
);
1718 return value
&& !value
->GetIsNull () ? value
: NULL
;
1722 DependencyObject::GetValueNoDefaultWithError (DependencyProperty
*property
, MoonError
*error
)
1724 if (!HasProperty (Type::INVALID
, property
, true)) {
1725 Type
*pt
= Type::Find (property
->GetOwnerType ());
1726 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 ());
1727 MoonError::FillIn (error
, MoonError::EXCEPTION
, error_msg
);
1731 return GetValueNoDefault (property
);
1735 DependencyObject::ProviderValueChanged (PropertyPrecedence providerPrecedence
,
1736 DependencyProperty
*property
,
1737 Value
*old_provider_value
, Value
*new_provider_value
,
1738 bool notify_listeners
, bool set_parent
, MoonError
*error
)
1742 // first we look for a value higher in precedence for this property
1743 for (p
= providerPrecedence
- 1; p
>= PropertyPrecedence_Highest
; p
--) {
1744 if (providers
[p
] && providers
[p
]->GetPropertyValue (property
)) {
1745 // a provider higher in precedence already has
1746 // a value for this property, so the one
1747 // that's changing isn't visible anyway.
1755 if (!old_provider_value
|| !new_provider_value
) {
1756 Value
*lower_priority_value
= GetValue (property
, (PropertyPrecedence
)(providerPrecedence
+ 1));
1758 if (new_provider_value
== NULL
) {
1759 // we're changing from @old_provider_value to whatever the
1760 // value lower on the priority list is.
1761 old_value
= old_provider_value
;
1762 new_value
= lower_priority_value
;
1764 else if (old_provider_value
== NULL
) {
1765 // we're changing from the old value (from a lower
1766 // priority provider) to @new_provider_value.
1767 old_value
= lower_priority_value
;
1768 new_value
= new_provider_value
;
1772 old_value
= old_provider_value
;
1773 new_value
= new_provider_value
;
1778 if (old_value
!= NULL
&& new_value
!= NULL
) {
1779 equal
= !property
->AlwaysChange() && (*old_value
== *new_value
);
1785 DependencyObject
*old_as_dep
= NULL
;
1786 DependencyObject
*new_as_dep
= NULL
;
1788 // XXX this flag should be part of the DP metadata.
1789 // we also need to audit other "typeof (object)" DP's
1790 // to make sure they set parent when they should (and
1791 // don't when they shouldn't.)
1792 bool setsParent
= set_parent
&& !property
->IsCustom ();
1794 if (old_value
&& old_value
->Is (Type::DEPENDENCY_OBJECT
))
1795 old_as_dep
= old_value
->AsDependencyObject ();
1796 if (new_value
&& new_value
->Is (Type::DEPENDENCY_OBJECT
))
1797 new_as_dep
= new_value
->AsDependencyObject ();
1799 if (old_as_dep
&& setsParent
) {
1800 old_as_dep
->SetSurface (NULL
);
1803 old_as_dep
->SetParent (NULL
, NULL
);
1805 // remove ourselves as a target
1806 old_as_dep
->RemoveTarget (this);
1808 // unregister from the existing value
1809 old_as_dep
->RemovePropertyChangeListener (this, property
);
1811 if (old_as_dep
->Is(Type::COLLECTION
)) {
1812 old_as_dep
->RemoveHandler (Collection::ChangedEvent
, collection_changed
, this);
1813 old_as_dep
->RemoveHandler (Collection::ItemChangedEvent
, collection_item_changed
, this);
1817 if (new_as_dep
&& setsParent
) {
1818 new_as_dep
->SetSurface (GetSurface ());
1820 new_as_dep
->SetParent (this, error
);
1824 new_as_dep
->SetResourceBase (GetResourceBase());
1826 if (new_as_dep
->Is(Type::COLLECTION
)) {
1827 new_as_dep
->AddHandler (Collection::ChangedEvent
, collection_changed
, this);
1828 new_as_dep
->AddHandler (Collection::ItemChangedEvent
, collection_item_changed
, this);
1831 // listen for property changes on the new object
1832 new_as_dep
->AddPropertyChangeListener (this, property
);
1834 // add ourselves as a target
1835 new_as_dep
->AddTarget (this);
1838 // we need to make this optional, as doing it for NameScope
1839 // merging is killing performance (and noone should ever care
1840 // about that property changing)
1841 if (notify_listeners
) {
1842 Value
*old_value_copy
= old_value
== NULL
? NULL
: new Value (*old_value
);
1843 Value
*new_value_copy
= new_value
== NULL
? NULL
: new Value (*new_value
);
1845 PropertyChangedEventArgs
*args
= new PropertyChangedEventArgs (property
, property
->GetId (), old_value_copy
, new_value_copy
);
1847 listeners_notified
= false;
1849 OnPropertyChanged (args
, error
);
1851 if (!listeners_notified
) {
1852 g_warning ("setting property %s::%s on object of type %s didn't result in listeners being notified",
1853 Type::Find(property
->GetOwnerType())->GetName (), property
->GetName(), GetTypeName ());
1855 g_warning ("the error was: %s", error
->message
);
1858 if (property
&& property
->GetChangedCallback () != NULL
) {
1859 PropertyChangeHandler callback
= property
->GetChangedCallback ();
1860 callback (this, args
, error
, NULL
);
1864 if (InheritedPropertyValueProvider::IsPropertyInherited (property
->GetId ()))
1865 InheritedPropertyValueProvider::PropagateInheritedProperty (this, property
, old_value_copy
, new_value_copy
);
1869 delete old_value_copy
;
1870 delete new_value_copy
;
1876 DependencyObject::ClearValue (int id
, bool notify_listeners
)
1880 ClearValue (GetDeployment ()->GetTypes ()->GetProperty (id
), notify_listeners
);
1884 DependencyObject::ClearValue (DependencyProperty
*property
, bool notify_listeners
)
1886 ClearValue(property
, notify_listeners
, NULL
);
1890 DependencyObject::ClearValue (DependencyProperty
*property
, bool notify_listeners
, MoonError
*error
)
1892 AutoCreatePropertyValueProvider
*autocreate
= (AutoCreatePropertyValueProvider
*) providers
[PropertyPrecedence_AutoCreate
];
1893 Value
*old_local_value
;
1895 if (!(old_local_value
= ReadLocalValue (property
)))
1896 if (property
->IsAutoCreated ())
1897 old_local_value
= autocreate
->ReadLocalValue (property
);
1899 // detach from the existing value
1900 if (old_local_value
!= NULL
&& old_local_value
->Is (Type::DEPENDENCY_OBJECT
)) {
1901 DependencyObject
*dob
= old_local_value
->AsDependencyObject();
1905 dob
->SetParent (NULL
, NULL
);
1907 // unregister from the existing value
1908 dob
->RemovePropertyChangeListener (this, property
);
1909 dob
->SetSurface (NULL
);
1910 if (dob
->Is(Type::COLLECTION
)) {
1911 dob
->RemoveHandler (Collection::ChangedEvent
, collection_changed
, this);
1912 dob
->RemoveHandler (Collection::ItemChangedEvent
, collection_item_changed
, this);
1917 g_hash_table_remove (local_values
, property
);
1919 if (property
->IsAutoCreated ())
1920 autocreate
->ClearValue (property
);
1922 // this is... yeah, it's disgusting
1923 for (int p
= PropertyPrecedence_LocalValue
+ 1; p
< PropertyPrecedence_Count
; p
++) {
1925 providers
[p
]->RecomputePropertyValue (property
);
1928 ProviderValueChanged (PropertyPrecedence_LocalValue
, property
, old_local_value
, NULL
, notify_listeners
, true, error
);
1930 delete old_local_value
;
1934 DependencyObject::dispose_value (gpointer key
, gpointer value
, gpointer data
)
1936 DependencyObject
*_this
= (DependencyObject
*)data
;
1938 Value
*v
= (Value
*) value
;
1943 // detach from the existing value
1944 if (v
->Is (Type::DEPENDENCY_OBJECT
)){
1945 DependencyObject
*dob
= v
->AsDependencyObject();
1948 if (_this
== dob
->GetParent()) {
1949 // unset its logical parent
1950 dob
->SetParent (NULL
, NULL
);
1953 // unregister from the existing value
1954 dob
->RemovePropertyChangeListener ((DependencyObject
*)data
, NULL
);
1956 if (dob
->Is(Type::COLLECTION
)) {
1957 dob
->RemoveHandler (Collection::ChangedEvent
, collection_changed
, _this
);
1958 dob
->RemoveHandler (Collection::ItemChangedEvent
, collection_item_changed
, _this
);
1963 delete (Value
*) value
;
1969 DependencyObject::collection_changed (EventObject
*sender
, EventArgs
*args
, gpointer closure
)
1971 DependencyObject
*obj
= (DependencyObject
*)closure
;
1972 obj
->OnCollectionChanged ((Collection
*)sender
, (CollectionChangedEventArgs
*)args
);
1976 DependencyObject::collection_item_changed (EventObject
*sender
, EventArgs
*args
, gpointer closure
)
1978 DependencyObject
*obj
= (DependencyObject
*)closure
;
1979 CollectionItemChangedEventArgs
* itemArgs
= (CollectionItemChangedEventArgs
*)args
;
1981 PropertyChangedEventArgs
*propChangedArgs
= new PropertyChangedEventArgs (itemArgs
->GetProperty(),
1982 itemArgs
->GetProperty()->GetId (),
1983 itemArgs
->GetOldValue(),
1984 itemArgs
->GetNewValue());
1986 obj
->OnCollectionItemChanged ((Collection
*)sender
,
1987 itemArgs
->GetCollectionItem(),
1990 propChangedArgs
->unref ();
1993 DependencyObject::DependencyObject ()
1994 : EventObject (Type::DEPENDENCY_OBJECT
)
1999 DependencyObject::DependencyObject (Deployment
*deployment
, Type::Kind object_type
)
2000 : EventObject (deployment
, object_type
)
2005 DependencyObject::DependencyObject (Type::Kind object_type
)
2006 : EventObject (object_type
)
2012 DependencyObject::Initialize ()
2014 providers
= new PropertyValueProvider
*[PropertyPrecedence_Count
];
2016 providers
[PropertyPrecedence_LocalValue
] = new LocalPropertyValueProvider (this, PropertyPrecedence_LocalValue
);
2017 providers
[PropertyPrecedence_DynamicValue
] = NULL
; // subclasses will set this if they need it.
2019 providers
[PropertyPrecedence_LocalStyle
] = NULL
; // this is a frameworkelement specific thing
2020 providers
[PropertyPrecedence_DefaultStyle
] = NULL
; // this is a frameworkelement specific thing
2022 providers
[PropertyPrecedence_Inherited
] = new InheritedPropertyValueProvider (this, PropertyPrecedence_Inherited
);
2023 providers
[PropertyPrecedence_DefaultValue
] = new DefaultValuePropertyValueProvider (this, PropertyPrecedence_DefaultValue
);
2024 providers
[PropertyPrecedence_AutoCreate
] = new AutoCreatePropertyValueProvider (this, PropertyPrecedence_AutoCreate
);
2026 local_values
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
2027 listener_list
= NULL
;
2029 is_hydrated
= false;
2031 resource_base
= NULL
;
2032 storage_hash
= NULL
; // Create it on first usage request
2036 DependencyObject::Freeze()
2041 struct CloneClosure
{
2043 DependencyObject
*old_do
;
2044 DependencyObject
*new_do
;
2048 DependencyObject::clone_local_value (DependencyProperty
*key
, Value
*value
, gpointer data
)
2050 CloneClosure
*closure
= (CloneClosure
*)data
;
2052 // don't clone the name property, or we end up with nasty
2053 // duplicate name errors.
2054 if (key
->GetId() == DependencyObject::NameProperty
)
2057 Value
*cv
= Value::Clone (value
, closure
->types
);
2059 closure
->new_do
->SetValue (key
, cv
);
2065 DependencyObject::clone_autocreated_value (DependencyProperty
*key
, Value
*value
, gpointer data
)
2067 CloneClosure
*closure
= (CloneClosure
*)data
;
2069 Value
*old_value
= closure
->old_do
->GetValue (key
, PropertyPrecedence_AutoCreate
);
2071 // this should create the new object
2072 Value
*new_value
= closure
->new_do
->GetValue (key
, PropertyPrecedence_AutoCreate
);
2074 if (old_value
&& !old_value
->GetIsNull() && old_value
->Is (Type::DEPENDENCY_OBJECT
) &&
2075 new_value
&& !new_value
->GetIsNull() && new_value
->Is (Type::DEPENDENCY_OBJECT
)) {
2076 DependencyObject
*new_obj
= new_value
->AsDependencyObject(closure
->types
);
2077 DependencyObject
*old_obj
= old_value
->AsDependencyObject(closure
->types
);
2079 new_obj
->CloneCore (closure
->types
, old_obj
);
2084 DependencyObject::clone_animation_storage_list (DependencyProperty
*key
, List
*list
, gpointer data
)
2086 if (!list
|| list
->IsEmpty ())
2088 DependencyObject
*d
= (DependencyObject
*)data
;
2089 d
->CloneAnimationStorageList (key
, list
);
2093 DependencyObject::CloneAnimationStorageList (DependencyProperty
*key
, List
*list
)
2096 List
*newlist
= new List();
2098 AnimationStorage::Node
*node
= (AnimationStorage::Node
*) list
->First ();
2100 node
->storage
->SwitchTarget (this);
2101 newlist
->Append (node
->Clone ());
2102 node
= (AnimationStorage::Node
*)node
->next
;
2106 storage_hash
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
2107 g_hash_table_insert (storage_hash
, key
, newlist
);
2111 DependencyObject::Clone (Types
*types
)
2113 Type
*t
= types
->Find (GetObjectType());
2115 DependencyObject
*new_do
= t
->CreateInstance();
2118 new_do
->CloneCore (types
, (DependencyObject
*)this); // this cast should be unnecessary. but C++ const behavior sucks.
2124 DependencyObject::CloneCore (Types
*types
, DependencyObject
* fromObj
)
2126 CloneClosure closure
;
2127 closure
.types
= types
;
2128 closure
.old_do
= fromObj
;
2129 closure
.new_do
= this;
2131 AutoCreatePropertyValueProvider
*autocreate
= (AutoCreatePropertyValueProvider
*) fromObj
->providers
[PropertyPrecedence_AutoCreate
];
2133 g_hash_table_foreach (autocreate
->auto_values
, (GHFunc
)DependencyObject::clone_autocreated_value
, &closure
);
2134 g_hash_table_foreach (fromObj
->local_values
, (GHFunc
)DependencyObject::clone_local_value
, &closure
);
2135 if (fromObj
->storage_hash
) {
2136 g_hash_table_foreach (fromObj
->storage_hash
, (GHFunc
)DependencyObject::clone_animation_storage_list
, this);
2141 clear_storage_list (DependencyProperty
*key
, List
*list
, gpointer unused
)
2143 List::Node
*node
= list
->First ();
2145 delete ((AnimationStorage::Node
*)node
)->storage
;
2151 DependencyObject::~DependencyObject ()
2153 g_hash_table_destroy (local_values
);
2154 local_values
= NULL
;
2157 g_free (resource_base
);
2161 free_listener (gpointer data
, gpointer user_data
)
2163 Listener
* listener
= (Listener
*) data
;
2168 DependencyObject::Dispose ()
2170 AutoCreatePropertyValueProvider
*autocreate
= (AutoCreatePropertyValueProvider
*) providers
[PropertyPrecedence_AutoCreate
];
2172 if (listener_list
!= NULL
) {
2173 g_slist_foreach (listener_list
, free_listener
, NULL
);
2174 g_slist_free (listener_list
);
2175 listener_list
= NULL
;
2178 RemoveAllListeners();
2181 g_hash_table_foreach_remove (autocreate
->auto_values
, dispose_value
, this);
2183 g_hash_table_foreach_remove (local_values
, dispose_value
, this);
2185 for (int i
= 0; i
< PropertyPrecedence_Count
; i
++) {
2186 delete providers
[i
];
2187 providers
[i
] = NULL
;
2191 GHashTable
*tmphash
= storage_hash
; // animation storages may call back to DetachAnimationStorage
2192 storage_hash
= NULL
;
2193 g_hash_table_foreach (tmphash
, (GHFunc
)clear_storage_list
, NULL
);
2194 g_hash_table_destroy (tmphash
);
2197 EventObject::Dispose ();
2201 get_attached_props (gpointer key
, gpointer value
, gpointer user_data
)
2203 DependencyProperty
*prop
= (DependencyProperty
*) key
;
2204 GHashTable
*props
= (GHashTable
*) user_data
;
2206 if (!(g_hash_table_lookup (props
, (gpointer
) prop
->GetHashKey ())))
2207 g_hash_table_insert (props
, (gpointer
) prop
->GetHashKey (), prop
);
2211 hash_keys_to_array (gpointer key
, gpointer value
, gpointer user_data
)
2213 g_ptr_array_add ((GPtrArray
*) user_data
, key
);
2217 hash_values_to_array (gpointer key
, gpointer value
, gpointer user_data
)
2219 g_ptr_array_add ((GPtrArray
*) user_data
, value
);
2222 DependencyProperty
**
2223 DependencyObject::GetProperties (bool only_changed
)
2225 AutoCreatePropertyValueProvider
*autocreate
= (AutoCreatePropertyValueProvider
*) providers
[PropertyPrecedence_AutoCreate
];
2226 DependencyProperty
**props
;
2230 array
= g_ptr_array_new ();
2232 if (!only_changed
) {
2233 // get our class/inherited DependencyProperties
2234 table
= GetType ()->CopyProperties (true);
2236 // find any attached properties that have been set
2237 g_hash_table_foreach (local_values
, get_attached_props
, table
);
2239 // dump them to an array
2240 g_hash_table_foreach (table
, hash_values_to_array
, array
);
2241 g_hash_table_destroy (table
);
2243 g_hash_table_foreach (local_values
, hash_keys_to_array
, array
);
2244 g_hash_table_foreach (autocreate
->auto_values
, hash_keys_to_array
, array
);
2247 g_ptr_array_add (array
, NULL
);
2248 props
= (DependencyProperty
**) array
->pdata
;
2249 g_ptr_array_free (array
, false);
2254 DependencyProperty
*
2255 DependencyObject::GetDependencyProperty (const char *name
)
2257 return DependencyProperty::GetDependencyProperty (GetObjectType (), name
);
2261 DependencyObject::HasProperty (const char *name
, bool inherits
)
2263 return DependencyProperty::GetDependencyProperty (GetObjectType (), name
, inherits
) != NULL
;
2267 DependencyObject::HasProperty (Type::Kind whatami
, DependencyProperty
*property
, bool inherits
)
2269 Type::Kind this_type
= whatami
== Type::INVALID
? GetObjectType () : whatami
;
2271 // TODO: Handle attached properties correctly.
2273 if (property
->IsAttached ())
2277 printf ("DependencyObject::HasProperty (%p, %i (%s), %p (%i %s.%s), %i)..\n",
2279 whatami, Type::Find (whatami)->name,
2280 property, property->GetOwnerType (), Type::Find (property->GetOwnerType ())->name, property->GetName (),
2284 if (property
== NULL
)
2287 if (property
->GetOwnerType () == this_type
)
2293 if (!Type::IsSubclassOf (this_type
, property
->GetOwnerType ())) {
2294 bool is_prop_custom
= property
->IsCustom ();
2295 bool is_owner_custom
= property
->GetOwnerType () > Type::LASTTYPE
;
2296 bool is_this_custom
= this_type
> Type::LASTTYPE
;
2297 bool accept
= false;
2300 // This looks very wrong, but it's what SL seems to do.
2301 if (is_prop_custom
) {
2302 if (!is_owner_custom
&& !is_this_custom
) {
2303 // SL does not throw errors for custom properties defined on a builtin type
2304 // and then used on another (unrelated) builtin type (DO.GetValue usage at least)
2306 } else if (is_owner_custom
) {
2307 // And this is a custom property defined on a custom type and used anywhere.
2318 DependencyObject::FindName (const char *name
)
2320 return FindName (name
, Control::GetIsTemplateItem (this));
2324 DependencyObject::FindName (const char *name
, bool template_item
)
2326 NameScope
*scope
= NameScope::GetNameScope (this);
2328 if (scope
&& (template_item
== scope
->GetIsLocked ()))
2329 return scope
->FindName (name
);
2332 return parent
->FindName (name
, template_item
);
2338 DependencyObject::FindNameScope ()
2340 return FindNameScope (Control::GetIsTemplateItem (this));
2344 DependencyObject::FindNameScope (bool template_namescope
)
2346 NameScope
*scope
= NameScope::GetNameScope (this);
2348 // Only template namescopes are locked (for the moment)
2349 if (scope
&& (template_namescope
== scope
->GetIsLocked ()))
2353 return parent
->FindNameScope (template_namescope
);
2359 DependencyObject::FindName (const char *name
, Type::Kind
*element_kind
)
2361 //printf ("Looking up in %p the string %p\n", obj, name);
2362 //printf (" String: %s\n", name);
2363 DependencyObject
*ret
= FindName (name
);
2368 *element_kind
= ret
->GetObjectType ();
2374 DependencyObject::GetAnimationStorageFor (DependencyProperty
*prop
)
2379 List
*list
= (List
*) g_hash_table_lookup (storage_hash
, prop
);
2380 if (!list
|| !list
->IsEmpty ())
2383 return ((AnimationStorage::Node
*) list
->Last())->storage
;
2387 DependencyObject::AttachAnimationStorage (DependencyProperty
*prop
, AnimationStorage
*storage
)
2389 AnimationStorage
* attached_storage
= NULL
;
2390 // Create hash on first access to save some mem
2392 storage_hash
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
2394 List
*list
= (List
*) g_hash_table_lookup (storage_hash
, prop
);
2397 g_hash_table_insert (storage_hash
, prop
, list
);
2399 else if (!list
->IsEmpty ()) {
2400 attached_storage
= ((AnimationStorage::Node
*) list
->Last())->storage
;
2401 attached_storage
->Disable ();
2404 list
->Append (new AnimationStorage::Node (prop
, storage
));
2405 return attached_storage
;
2409 DependencyObject::DetachAnimationStorage (DependencyProperty
*prop
, AnimationStorage
*storage
)
2414 List
*list
= (List
*) g_hash_table_lookup (storage_hash
, prop
);
2415 if (!list
|| list
->IsEmpty ())
2418 // if the storage to be removed is the last one, activate the previous one (if any)
2419 if (((AnimationStorage::Node
*)list
->Last ())->storage
== storage
) {
2420 list
->Remove (list
->Last ());
2421 if (!list
->IsEmpty ()) {
2422 ((AnimationStorage::Node
*)list
->Last ())->storage
->Enable ();
2425 } else { // if there's more than one storage, that means the storage that was added after
2426 // the one we're removing is configured to reset back to the value of the previous
2427 // storage, so update the stop value so it resets back to the proper value
2428 List::Node
*node
= list
->First ();
2430 if (((AnimationStorage::Node
*)node
)->storage
== storage
) {
2431 List::Node
*remove
= node
;
2433 ((AnimationStorage::Node
*)node
)->storage
->SetStopValue (storage
->GetResetValue ());
2434 list
->Remove (remove
);
2443 // A helper debugging routine for C#
2446 dependency_object_get_name (DependencyObject
*obj
)
2448 return obj
->GetName ();
2452 dependency_object_get_object_type (DependencyObject
*obj
)
2454 return obj
->GetObjectType ();
2458 dependency_object_get_type_name (DependencyObject
*obj
)
2460 return obj
->GetTypeName ();
2463 // Used by routines which need to create DO from code
2465 dependency_object_set_name (DependencyObject
*obj
, const char *name
)
2467 obj
->SetValue (DependencyObject::NameProperty
, Value (name
));
2471 set_surface (gpointer key
, gpointer value
, gpointer data
)
2473 Surface
*s
= (Surface
*) data
;
2474 Value
*v
= (Value
*) value
;
2476 if (v
&& v
->Is (Type::DEPENDENCY_OBJECT
)) {
2477 DependencyObject
*dob
= v
->AsDependencyObject();
2479 dob
->SetSurface (s
);
2484 DependencyObject::SetSurface (Surface
*s
)
2486 AutoCreatePropertyValueProvider
*autocreate
= (AutoCreatePropertyValueProvider
*) providers
[PropertyPrecedence_AutoCreate
];
2488 if (GetSurface() == s
)
2491 EventObject::SetSurface (s
);
2494 g_hash_table_foreach (autocreate
->auto_values
, set_surface
, s
);
2496 g_hash_table_foreach (local_values
, set_surface
, s
);
2500 DependencyObject::SetParent (DependencyObject
*parent
, MoonError
*error
)
2502 if (parent
== this->parent
)
2506 // Check for circular families
2507 DependencyObject
*current
= parent
;
2508 while (current
!= NULL
) {
2509 if (current
== this) {
2510 g_warning ("cycle found in logical tree. bailing out");
2513 current
= current
->GetParent ();
2517 if (!this->parent
) {
2519 NameScope
*this_scope
= NameScope::GetNameScope(this);
2520 NameScope
*parent_scope
= parent
->FindNameScope();
2522 if (this_scope
->GetTemporary()) {
2523 // if we have a temporary name scope, merge it into the
2524 // closest one up the hierarchy.
2526 parent_scope
->MergeTemporaryScope (this_scope
, error
);
2527 ClearValue (NameScope::NameScopeProperty
, false);
2531 // there's no parent
2532 // namescope, we don't
2537 // we have a non-temporary scope. we still have to register the name
2538 // of this element (not the ones in the subtree rooted at this element)
2539 // in the new parent scope. we only register the name in the parent scope
2540 // if the element was hydrated, not when it was created from a string.
2541 if (IsHydratedFromXaml()) {
2542 const char *name
= GetName();
2543 if (parent_scope
&& name
&& *name
) {
2544 DependencyObject
*existing_obj
= parent_scope
->FindName (name
);
2545 if (existing_obj
!= this) {
2547 char *error_msg
= g_strdup_printf ("name `%s' is already registered in new parent namescope.", name
);
2548 MoonError::FillIn (error
, MoonError::ARGUMENT
, error_msg
);
2551 parent_scope
->RegisterName (name
, this);
2558 // we don't have a namescope at all,
2559 // we have to iterate over the subtree
2560 // rooted at this object, and merge
2561 // the names into the parent
2565 NameScope
*temp_scope
= new NameScope();
2566 temp_scope
->SetTemporary (true);
2568 RegisterAllNamesRootedAt (temp_scope
, error
);
2570 if (error
->number
) {
2571 temp_scope
->unref ();
2575 parent_scope
->MergeTemporaryScope (temp_scope
, error
);
2577 temp_scope
->unref ();
2584 NameScope
*parent_scope
= this->parent
->FindNameScope ();
2586 UnregisterAllNamesRootedAt (parent_scope
);
2590 if (!error
|| error
->number
== 0)
2591 this->parent
= parent
;
2595 dependency_object_get_value (DependencyObject
*object
, DependencyProperty
*prop
)
2600 return object
->GetValue (prop
);
2604 dependency_object_get_value_no_default (DependencyObject
*object
, DependencyProperty
*prop
)
2609 return object
->GetValueNoDefault (prop
);
2613 dependency_object_set_value (DependencyObject
*object
, DependencyProperty
*prop
, Value
*val
)
2618 object
->SetValue (prop
, val
);
2622 DependencyObject::OnPropertyChanged (PropertyChangedEventArgs
*args
, MoonError
*error
)
2624 if (DependencyObject::NameProperty
== args
->GetId ()) {
2625 NameScope
*scope
= FindNameScope ();
2626 if (scope
&& args
->GetNewValue()) {
2627 if (args
->GetOldValue ())
2628 scope
->UnregisterName (args
->GetOldValue ()->AsString ());
2629 scope
->RegisterName (args
->GetNewValue()->AsString (), this);
2631 if (IsHydratedFromXaml () && parent
) {
2632 // we also need to update any parent
2633 // namescope about our name change
2635 scope
= parent
->FindNameScope ();
2637 if (args
->GetOldValue ())
2638 scope
->UnregisterName (args
->GetOldValue ()->AsString ());
2639 scope
->RegisterName (args
->GetNewValue()->AsString (), this);
2645 NotifyListenersOfPropertyChange (args
, error
);
2649 DependencyObject::GetContent()
2651 const char *content_property_name
= GetType()->GetContentPropertyName();
2652 if (!content_property_name
)
2655 DependencyProperty
*content_property
= GetDependencyProperty (content_property_name
);
2656 if (!content_property
)
2659 Value
*content_value
= GetValue(content_property
);
2664 return content_value
->AsDependencyObject();