From 7fe16d99be2b38bb5999443a1b8edce021d2dc69 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Mon, 3 Jun 2013 23:39:11 +0200 Subject: [PATCH] Canvas: clear event listeners on destroy Removing all event listeneres on destroying a canvas prevents circular references due to Nasal event listeners keeping a reference to the canvas in their closure. Also fix event handling with direct children of the root group and add some more helpers to the Canvas. --- simgear/canvas/Canvas.cxx | 13 +++++++++++++ simgear/canvas/Canvas.hxx | 17 +++++++++++++++++ simgear/canvas/CanvasEventManager.cxx | 11 +++++------ simgear/canvas/CanvasEventVisitor.cxx | 2 +- simgear/canvas/elements/CanvasElement.cxx | 17 +++++++++-------- simgear/canvas/elements/CanvasElement.hxx | 1 + simgear/canvas/elements/CanvasGroup.cxx | 9 +++++++++ simgear/canvas/elements/CanvasGroup.hxx | 2 ++ 8 files changed, 57 insertions(+), 15 deletions(-) diff --git a/simgear/canvas/Canvas.cxx b/simgear/canvas/Canvas.cxx index 4e425557..a124642c 100644 --- a/simgear/canvas/Canvas.cxx +++ b/simgear/canvas/Canvas.cxx @@ -114,6 +114,9 @@ namespace canvas //---------------------------------------------------------------------------- void Canvas::destroy() { + if( _root_group ) + _root_group->clearEventListener(); + // TODO check if really not in use anymore getProps()->getParent() ->removeChild( getProps()->getName(), @@ -185,6 +188,16 @@ namespace canvas ); } + //---------------------------------------------------------------------------- + GroupPtr Canvas::getOrCreateGroup(const std::string& name) + { + GroupPtr group = getGroup(name); + if( group ) + return group; + + return createGroup(name); + } + //---------------------------------------------------------------------------- GroupPtr Canvas::getRootGroup() { diff --git a/simgear/canvas/Canvas.hxx b/simgear/canvas/Canvas.hxx index 1d508a89..3504b46c 100644 --- a/simgear/canvas/Canvas.hxx +++ b/simgear/canvas/Canvas.hxx @@ -102,8 +102,25 @@ namespace canvas void removeParentCanvas(const CanvasWeakPtr& canvas); void removeChildCanvas(const CanvasWeakPtr& canvas); + /** + * Create a new group + */ GroupPtr createGroup(const std::string& name = ""); + + /** + * Get an existing group with the given name + */ GroupPtr getGroup(const std::string& name); + + /** + * Get an existing group with the given name or otherwise create a new + * group + */ + GroupPtr getOrCreateGroup(const std::string& name); + + /** + * Get the root group of the canvas + */ GroupPtr getRootGroup(); /** diff --git a/simgear/canvas/CanvasEventManager.cxx b/simgear/canvas/CanvasEventManager.cxx index 8801d84a..7a05a23e 100644 --- a/simgear/canvas/CanvasEventManager.cxx +++ b/simgear/canvas/CanvasEventManager.cxx @@ -188,13 +188,12 @@ namespace canvas // http://www.w3.org/TR/DOM-Level-3-Events/#event-flow // Capturing phase -// for( EventTargets::iterator it = _target_path.begin(); -// it != _target_path.end(); -// ++it ) +// for( EventPropagationPath::const_iterator it = path.begin(); +// it != path.end(); +// ++it ) // { -// if( it->element ) -// std::cout << it->element->getProps()->getPath() << " " -// << "(" << it->local_pos.x() << "|" << it->local_pos.y() << ")\n"; +// if( !it->element.expired() ) +// std::cout << it->element.lock()->getProps()->getPath() << std::endl; // } // Bubbling phase diff --git a/simgear/canvas/CanvasEventVisitor.cxx b/simgear/canvas/CanvasEventVisitor.cxx index d931f40b..40d4e26b 100644 --- a/simgear/canvas/CanvasEventVisitor.cxx +++ b/simgear/canvas/CanvasEventVisitor.cxx @@ -73,7 +73,7 @@ namespace canvas // Don't check collision with root element (2nd element in _target_path) // do event listeners attached to the canvas itself (its root group) // always get called even if no element has been hit. - if( _target_path.size() > 2 && !el.hitBound(pos, local_pos) ) + if( _target_path.size() > 1 && !el.hitBound(pos, local_pos) ) return false; const osg::Vec2f& delta = _target_path.back().local_delta; diff --git a/simgear/canvas/elements/CanvasElement.cxx b/simgear/canvas/elements/CanvasElement.cxx index e581e514..fcadfc66 100644 --- a/simgear/canvas/elements/CanvasElement.cxx +++ b/simgear/canvas/elements/CanvasElement.cxx @@ -179,6 +179,12 @@ namespace canvas return naNil(); } + //---------------------------------------------------------------------------- + void Element::clearEventListener() + { + _listener.clear(); + } + //---------------------------------------------------------------------------- bool Element::accept(EventVisitor& visitor) { @@ -220,15 +226,10 @@ namespace canvas // Drawables have a bounding box... if( _drawable ) - { - if( !_drawable->getBound().contains(osg::Vec3f(local_pos, 0)) ) - return false; - } + return _drawable->getBound().contains(osg::Vec3f(local_pos, 0)); // ... for other elements, i.e. groups only a bounding sphere is available - else if( !_transform->getBound().contains(osg::Vec3f(pos, 0)) ) - return false; - - return true; + else + return _transform->getBound().contains(osg::Vec3f(pos, 0)); } //---------------------------------------------------------------------------- diff --git a/simgear/canvas/elements/CanvasElement.hxx b/simgear/canvas/elements/CanvasElement.hxx index 146cd0d4..136fd5fc 100644 --- a/simgear/canvas/elements/CanvasElement.hxx +++ b/simgear/canvas/elements/CanvasElement.hxx @@ -85,6 +85,7 @@ namespace canvas virtual void update(double dt); naRef addEventListener(const nasal::CallContext& ctx); + virtual void clearEventListener(); virtual bool accept(EventVisitor& visitor); virtual bool ascend(EventVisitor& visitor); diff --git a/simgear/canvas/elements/CanvasGroup.cxx b/simgear/canvas/elements/CanvasGroup.cxx index 05e752a3..b290fb0e 100644 --- a/simgear/canvas/elements/CanvasGroup.cxx +++ b/simgear/canvas/elements/CanvasGroup.cxx @@ -133,6 +133,15 @@ namespace canvas return ElementPtr(); } + //---------------------------------------------------------------------------- + void Group::clearEventListener() + { + BOOST_FOREACH( ChildList::value_type child, _children ) + child.second->clearEventListener(); + + Element::clearEventListener(); + } + //---------------------------------------------------------------------------- void Group::update(double dt) { diff --git a/simgear/canvas/elements/CanvasGroup.hxx b/simgear/canvas/elements/CanvasGroup.hxx index d1b86b7b..8a40eaab 100644 --- a/simgear/canvas/elements/CanvasGroup.hxx +++ b/simgear/canvas/elements/CanvasGroup.hxx @@ -57,6 +57,8 @@ namespace canvas */ ElementPtr getElementById(const std::string& id); + virtual void clearEventListener(); + virtual void update(double dt); virtual bool traverse(EventVisitor& visitor); -- 2.39.5