commit 27ad88d3c42d28c3da6fa03d35cf3d9532434caf Author: Chris Toshok Date: Tue Aug 4 19:33:58 2009 -0700 2009-08-04 Chris Toshok * popup.cpp (class GenerationClosure): new closure for emiting the Opened and Closed events. (Popup::emit_opened, Popup::emit_closed): pass the generation from the closure to ->Emit. (Popup::OnPropertyChanged): for the tick call, pass a closure that contains the current event generation. * timemanager.h, timemanager.cpp (TimeManager::InvokeTickCalls): factor out the loop for invoking tick calls here and call it from the source tick method. * window-gtk.cpp (MoonWindowGtk::button_press) (MoonWindowGtk::button_release, MoonWindowGtk::scroll) (MoonWindowGtk::motion_notify, MoonWindowGtk::crossing_notify) (MoonWindowGtk::focus_in, MoonWindowGtk::focus_out) (MoonWindowGtk::key_press, MoonWindowGtk::key_release): call TimeManager::InvokeTickCalls from each of these methods before we call the Surface::HandleUI* method. * dependencyobject.h (class EventObject): make a couple of api changes: (AddTickCall*): add an "EventObject* data" parameter. if it's NULL, pass "this", so we have the current behavior. (DoEmit/Emit): add a "starting_generation" optional argument. if it's supplied, we invoke only those handlers with tokens less than the starting_generation (i.e. those handlers that were registered before the event was generated.) diff --git a/src/ChangeLog b/src/ChangeLog index 28a5010..2e3f59d 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,33 @@ +2009-08-04 Chris Toshok + + * popup.cpp (class GenerationClosure): new closure for emiting the + Opened and Closed events. + (Popup::emit_opened, Popup::emit_closed): pass the generation from + the closure to ->Emit. + (Popup::OnPropertyChanged): for the tick call, pass a closure that + contains the current event generation. + + * timemanager.h, timemanager.cpp (TimeManager::InvokeTickCalls): + factor out the loop for invoking tick calls here and call it from + the source tick method. + + * window-gtk.cpp (MoonWindowGtk::button_press) + (MoonWindowGtk::button_release, MoonWindowGtk::scroll) + (MoonWindowGtk::motion_notify, MoonWindowGtk::crossing_notify) + (MoonWindowGtk::focus_in, MoonWindowGtk::focus_out) + (MoonWindowGtk::key_press, MoonWindowGtk::key_release): call + TimeManager::InvokeTickCalls from each of these methods before we + call the Surface::HandleUI* method. + + * dependencyobject.h (class EventObject): make a couple of api + changes: + (AddTickCall*): add an "EventObject* data" parameter. if it's + NULL, pass "this", so we have the current behavior. + (DoEmit/Emit): add a "starting_generation" optional argument. if + it's supplied, we invoke only those handlers with tokens less than + the starting_generation (i.e. those handlers that were registered + before the event was generated.) + 2009-08-04 Larry Ewing * uielement.cpp (DoMeasure): invalidate up the tree more diff --git a/src/dependencyobject.cpp b/src/dependencyobject.cpp index 5fa08bf..33b03ca 100644 --- a/src/dependencyobject.cpp +++ b/src/dependencyobject.cpp @@ -201,7 +201,7 @@ EventObject::SetSurfaceUnlock () } void -EventObject::AddTickCallSafe (TickCallHandler handler) +EventObject::AddTickCallSafe (TickCallHandler handler, EventObject *data) { int result; @@ -216,13 +216,13 @@ EventObject::AddTickCallSafe (TickCallHandler handler) return; } - AddTickCallInternal (handler); + AddTickCallInternal (handler, data); pthread_rwlock_unlock (&surface_lock); } void -EventObject::AddTickCall (TickCallHandler handler) +EventObject::AddTickCall (TickCallHandler handler, EventObject *data) { if (!Surface::InMainThread ()) { g_warning ("EventObject::AddTickCall (): This method must not be called on any other than the main thread! Tick call won't be added.\n"); @@ -233,11 +233,11 @@ EventObject::AddTickCall (TickCallHandler handler) return; } - AddTickCallInternal (handler); + AddTickCallInternal (handler, data); } void -EventObject::AddTickCallInternal (TickCallHandler handler) +EventObject::AddTickCallInternal (TickCallHandler handler, EventObject *data) { Surface *surface; TimeManager *timemanager; @@ -259,7 +259,7 @@ EventObject::AddTickCallInternal (TickCallHandler handler) return; } - timemanager->AddTickCall (handler, this); + timemanager->AddTickCall (handler, data ? data : this); } Deployment * @@ -723,8 +723,22 @@ EventObject::RemoveMatchingHandlers (int event_id, bool (*predicate)(EventHandle } } +int +EventObject::GetEventGeneration (int event_id) +{ + if (GetType()->GetEventCount() <= 0) { + g_warning ("adding handler to event with id %d, which has not been registered\n", event_id); + return -1; + } + + if (events == NULL) + events = new EventLists (GetType ()->GetEventCount ()); + + return events->lists [event_id].current_token; +} + bool -EventObject::Emit (char *event_name, EventArgs *calldata, bool only_unemitted) +EventObject::Emit (char *event_name, EventArgs *calldata, bool only_unemitted, int starting_generation) { Deployment *deployment = GetDeployment (); if (deployment && deployment->isDead) @@ -762,7 +776,7 @@ EventObject::EmitCallback (gpointer d) } bool -EventObject::Emit (int event_id, EventArgs *calldata, bool only_unemitted) +EventObject::Emit (int event_id, EventArgs *calldata, bool only_unemitted, int starting_generation) { if (IsDisposed ()) return false; @@ -804,7 +818,7 @@ EventObject::Emit (int event_id, EventArgs *calldata, bool only_unemitted) EmitContext* ctx = StartEmit (event_id); - DoEmit (event_id, ctx, calldata, only_unemitted); + DoEmit (event_id, ctx, calldata, only_unemitted, starting_generation); if (calldata) calldata->unref (); @@ -861,7 +875,7 @@ EventObject::StartEmit (int event_id) } bool -EventObject::DoEmit (int event_id, EmitContext *ctx, EventArgs *calldata, bool only_unemitted) +EventObject::DoEmit (int event_id, EmitContext *ctx, EventArgs *calldata, bool only_unemitted, int starting_generation) { EventClosure *xaml_closure = NULL; @@ -880,7 +894,8 @@ EventObject::DoEmit (int event_id, EmitContext *ctx, EventArgs *calldata, bool o #endif if (closure && closure->func - && (!only_unemitted || closure->emit_count == 0)) { + && (!only_unemitted || closure->emit_count == 0) + && (starting_generation == -1 || closure->token < starting_generation)) { closure->func (this, calldata, closure->data); closure->emit_count ++; } diff --git a/src/dependencyobject.h b/src/dependencyobject.h index 6334eaf..20494e3 100644 --- a/src/dependencyobject.h +++ b/src/dependencyobject.h @@ -154,8 +154,8 @@ public: // Only AddTickCallSafe is safe to call on threads other than the main thread, // and only if the type on which it is called overrides SetSurface and surrounds // the call to the base type's SetSurface with SetSurfaceLock/Unlock. - void AddTickCall (TickCallHandler handler); - void AddTickCallSafe (TickCallHandler handler); + void AddTickCall (TickCallHandler handler, EventObject *data = NULL); + void AddTickCallSafe (TickCallHandler handler, EventObject *data = NULL); /* @GenerateCBinding,GeneratePInvoke */ void SetObjectType (Type::Kind value) { object_type = value; } @@ -168,7 +168,7 @@ public: void unref_delayed (); EmitContext *StartEmit (int event_id); - bool DoEmit (int event_id, EmitContext *ctx, EventArgs *calldata = NULL, bool only_unemitted = false); + bool DoEmit (int event_id, EmitContext *ctx, EventArgs *calldata = NULL, bool only_unemitted = false, int starting_generation = -1); void FinishEmit (int event_id, EmitContext *ctx); static gboolean EmitCallback (gpointer d); @@ -201,11 +201,13 @@ protected: // To enable scenarios like Emit ("Event", new EventArgs ()) // Emit will call unref on the calldata. - bool Emit (char *event_name, EventArgs *calldata = NULL, bool only_unemitted = false); - bool Emit (int event_id, EventArgs *calldata = NULL, bool only_unemitted = false); + bool Emit (char *event_name, EventArgs *calldata = NULL, bool only_unemitted = false, int starting_generation = -1); + bool Emit (int event_id, EventArgs *calldata = NULL, bool only_unemitted = false, int starting_generation = -1); + + int GetEventGeneration (int event_id); private: - void AddTickCallInternal (TickCallHandler handler); + void AddTickCallInternal (TickCallHandler handler, EventObject *data = NULL); void Initialize (Deployment *deployment, Type::Kind type); EventLists *events; diff --git a/src/popup.cpp b/src/popup.cpp index 31678fa..c17af8f 100644 --- a/src/popup.cpp +++ b/src/popup.cpp @@ -11,16 +11,48 @@ #include "popup.h" #include "runtime.h" +class GenerationClosure : public EventObject { +public: + GenerationClosure (int generation, Popup *popup) + { + this->generation = generation; + this->popup = popup; + + popup->ref (); + } + + virtual ~GenerationClosure () + { + popup->unref (); + } + + int generation; + Popup *popup; +}; + + void Popup::emit_opened (EventObject *sender) { - ((Popup *)sender)->Emit (Popup::OpenedEvent); + GenerationClosure *closure = (GenerationClosure *)sender; + Popup * popup = closure->popup; + int generation = closure->generation; + + closure->unref (); + + popup->Emit (Popup::OpenedEvent, NULL, false, generation); } void Popup::emit_closed (EventObject *sender) { - ((Popup *)sender)->Emit (Popup::ClosedEvent); + GenerationClosure *closure = (GenerationClosure *)sender; + Popup * popup = closure->popup; + int generation = closure->generation; + + closure->unref (); + + popup->Emit (Popup::ClosedEvent, NULL, false, generation); } Popup::Popup () @@ -62,11 +94,15 @@ Popup::OnPropertyChanged (PropertyChangedEventArgs *args, MoonError *error) // in SL. if (args->GetNewValue () && args->GetNewValue ()->AsBool ()) { Show (GetChild ()); - AddTickCall (Popup::emit_opened); + AddTickCall (Popup::emit_opened, + new GenerationClosure (GetEventGeneration (Popup::OpenedEvent), + this)); } else { Hide (GetChild ()); - AddTickCall (Popup::emit_closed); + AddTickCall (Popup::emit_closed, + new GenerationClosure (GetEventGeneration (Popup::ClosedEvent), + this)); } } else if (args->GetId () == Popup::ChildProperty) { if (args->GetOldValue () && !args->GetOldValue ()->GetIsNull ()) { diff --git a/src/timemanager.cpp b/src/timemanager.cpp index 15c4c58..4b37079 100644 --- a/src/timemanager.cpp +++ b/src/timemanager.cpp @@ -181,6 +181,15 @@ TimeManager::InvokeTickCall () return true; } +void +TimeManager::InvokeTickCalls () +{ + bool remaining_tick_calls = false; + do { + remaining_tick_calls = InvokeTickCall (); + } while (remaining_tick_calls); +} + guint TimeManager::AddTimeout (gint priority, guint ms_interval, GSourceFunc func, gpointer tick_data) { @@ -360,10 +369,7 @@ TimeManager::SourceTick () #endif if (current_flags & TIME_MANAGER_TICK_CALL) { - bool remaining_tick_calls = false; - do { - remaining_tick_calls = InvokeTickCall (); - } while (remaining_tick_calls); + InvokeTickCalls (); } if (current_flags & TIME_MANAGER_UPDATE_CLOCKS) { diff --git a/src/timemanager.h b/src/timemanager.h index 5f4e82c..5957c5d 100644 --- a/src/timemanager.h +++ b/src/timemanager.h @@ -45,6 +45,8 @@ public: void NeedRedraw (); void NeedClockTick (); + void InvokeTickCalls (); + /* @GenerateCBinding, GeneratePInvoke */ guint AddTimeout (gint priority, guint ms_interval, GSourceFunc func, gpointer timeout_data); /* @GenerateCBinding, GeneratePInvoke */ diff --git a/src/window-gtk.cpp b/src/window-gtk.cpp index c556347..286b89e 100644 --- a/src/window-gtk.cpp +++ b/src/window-gtk.cpp @@ -13,6 +13,7 @@ #include "window-gtk.h" #include "deployment.h" +#include "timemanager.h" MoonWindowGtk::MoonWindowGtk (bool fullscreen, int w, int h, MoonWindow *parent) : MoonWindow (w, h) @@ -424,8 +425,10 @@ MoonWindowGtk::button_press (GtkWidget *widget, GdkEventButton *event, gpointer if (event->button != 1 && event->button != 3) return false; - if (window->surface) + if (window->surface) { + window->surface->GetTimeManager()->InvokeTickCalls(); window->surface->HandleUIButtonPress (event); + } // If we don't support right clicks (i.e. inside the browser) // return false here @@ -444,8 +447,10 @@ MoonWindowGtk::button_release (GtkWidget *widget, GdkEventButton *event, gpointe Deployment::SetCurrent (window->GetDeployment ()); - if (window->surface) + if (window->surface) { + window->surface->GetTimeManager()->InvokeTickCalls(); window->surface->HandleUIButtonRelease (event); + } // ignore HandleUIButtonRelease's return value, and always // return true here, or it gets bubbled up to firefox. return true; @@ -458,8 +463,10 @@ MoonWindowGtk::scroll (GtkWidget *widget, GdkEventScroll *event, gpointer data) Deployment::SetCurrent (window->GetDeployment ()); - if (window->surface) + if (window->surface) { + window->surface->GetTimeManager()->InvokeTickCalls(); window->surface->HandleUIScroll (event); + } // ignore HandleUIScroll's return value, and always // return true here, or it gets bubbled up to firefox. return true; @@ -472,8 +479,10 @@ MoonWindowGtk::motion_notify (GtkWidget *widget, GdkEventMotion *event, gpointer Deployment::SetCurrent (window->GetDeployment ()); - if (window->surface) + if (window->surface) { + window->surface->GetTimeManager()->InvokeTickCalls(); window->surface->HandleUIMotion (event); + } // ignore HandleUIMotion's return value, and always // return true here, or it gets bubbled up to firefox. return true; @@ -486,7 +495,13 @@ MoonWindowGtk::crossing_notify (GtkWidget *widget, GdkEventCrossing *event, gpoi Deployment::SetCurrent (window->GetDeployment ()); - return window->surface ? window->surface->HandleUICrossing (event) : false; + if (window->surface) { + window->surface->GetTimeManager()->InvokeTickCalls(); + window->surface->HandleUICrossing (event); + return true; + } + + return false; } gboolean @@ -496,7 +511,13 @@ MoonWindowGtk::focus_in (GtkWidget *widget, GdkEventFocus *event, gpointer user_ Deployment::SetCurrent (window->GetDeployment ()); - return window->surface ? window->surface->HandleUIFocusIn (event) : false; + if (window->surface) { + window->surface->GetTimeManager()->InvokeTickCalls(); + window->surface->HandleUIFocusIn (event); + return true; + } + + return false; } gboolean @@ -506,7 +527,14 @@ MoonWindowGtk::focus_out (GtkWidget *widget, GdkEventFocus *event, gpointer user Deployment::SetCurrent (window->GetDeployment ()); - return window->surface ? window->surface->HandleUIFocusOut (event) : false; + + if (window->surface) { + window->surface->GetTimeManager()->InvokeTickCalls(); + window->surface->HandleUIFocusOut (event); + return true; + } + + return false; } gboolean @@ -515,7 +543,14 @@ MoonWindowGtk::key_press (GtkWidget *widget, GdkEventKey *event, gpointer user_d MoonWindowGtk *window = (MoonWindowGtk*)user_data; Deployment::SetCurrent (window->GetDeployment ()); - return window->surface ? window->surface->HandleUIKeyPress (event) : false; + + if (window->surface) { + window->surface->GetTimeManager()->InvokeTickCalls(); + window->surface->HandleUIKeyPress (event); + return true; + } + + return false; } gboolean @@ -524,7 +559,14 @@ MoonWindowGtk::key_release (GtkWidget *widget, GdkEventKey *event, gpointer user MoonWindowGtk *window = (MoonWindowGtk*)user_data; Deployment::SetCurrent (window->GetDeployment ()); - return window->surface ? window->surface->HandleUIKeyRelease (event) : false; + + if (window->surface) { + window->surface->GetTimeManager()->InvokeTickCalls(); + window->surface->HandleUIKeyRelease (event); + return true; + } + + return false; } void