diff options
author | Gareth Stockwell <gareth.stockwell@accenture.com> | 2009-10-21 14:41:21 (GMT) |
---|---|---|
committer | Frans Englich <frans.englich@nokia.com> | 2009-10-23 13:50:52 (GMT) |
commit | d54bc7379de145995534058dd2f6b400c9ab160e (patch) | |
tree | ce27f5081ff2b6d3dea7323970f8d588f91c70f8 | |
parent | df0f099b7ae0ffbea46411276a239d152f36a7e2 (diff) | |
download | Qt-d54bc7379de145995534058dd2f6b400c9ab160e.zip Qt-d54bc7379de145995534058dd2f6b400c9ab160e.tar.gz Qt-d54bc7379de145995534058dd2f6b400c9ab160e.tar.bz2 |
Video screen region is updated in response to ancestors of video widget
being moved.
Because QWidget::moveEvent is only called when a widget moves relative
to its parent, a widget's absolute screen position may change without it
receiving a moveEvent (for example, as a result of its parent being
moved).
The MMF video playback API on Symbian v9.4 requires, in addition to a
window handle, an absolute screen rectangle. Changes in the video
widget's absolute screen position therefore need to be propagated
into the MMF.
This change introduces a new object, AncestorMoveMonitor, which
installs an event filter on the QCoreApplication instance. A
VideoOutput object registers with the AncestorMoveMonitor, which
listens on its behalf for MoveEvents and ParentChangeEvents directed
at any of the ancestors of the VideoOutput. MoveEvents trigger a
callback to the VideoOutput instance, which then notifies the MMF of
the new screen rectangle. ParentChangeEvents cause the
AncestorMoveMonitor to update the ancestor list associated with the
target VideoOutput instance.
The video position now tracks that of the associated widget, but there
are two problems which require further investigation:
1. The video window lags behind. This may be an unavoidable
consequence of the fact that setting a new screen rectangle causes the
MMF to tear down its DSA session and start a new one; this is known to
block the window server and take some time to complete.
2. Artifacts are visible around the edges of the moving video widget.
Task-number: QTBUG-4787
Reviewed-by: Frans Englich
-rw-r--r-- | src/3rdparty/phonon/mmf/ancestormovemonitor.cpp | 175 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/ancestormovemonitor.h | 95 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/backend.cpp | 7 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/backend.h | 7 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/videooutput.cpp | 30 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/videooutput.h | 15 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/videowidget.cpp | 5 | ||||
-rw-r--r-- | src/3rdparty/phonon/mmf/videowidget.h | 3 | ||||
-rw-r--r-- | src/plugins/phonon/mmf/plugin/plugin.pro | 2 |
9 files changed, 328 insertions, 11 deletions
diff --git a/src/3rdparty/phonon/mmf/ancestormovemonitor.cpp b/src/3rdparty/phonon/mmf/ancestormovemonitor.cpp new file mode 100644 index 0000000..876499c --- /dev/null +++ b/src/3rdparty/phonon/mmf/ancestormovemonitor.cpp @@ -0,0 +1,175 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "ancestormovemonitor.h" +#include "utils.h" +#include "videooutput.h" + +#include <QCoreApplication> + +QT_BEGIN_NAMESPACE + +using namespace Phonon::MMF; + +/*! \class MMF::AncestorMoveMonitor + \internal + \brief Class which installs a global event filter, and listens for move + events which may affect the absolute position of widgets registered with + the monitor + See QTBUG-4956 +*/ + +//----------------------------------------------------------------------------- +// Constructor / destructor +//----------------------------------------------------------------------------- + +AncestorMoveMonitor::AncestorMoveMonitor(QObject *parent) + : QObject(parent) +{ + QCoreApplication::instance()->installEventFilter(this); +} + +AncestorMoveMonitor::~AncestorMoveMonitor() +{ + QCoreApplication::instance()->removeEventFilter(this); +} + + +//----------------------------------------------------------------------------- +// Public functions +//----------------------------------------------------------------------------- + +void AncestorMoveMonitor::registerTarget(VideoOutput *target) +{ + TRACE_CONTEXT(AncestorMoveMonitor::registerTarget, EVideoInternal); + TRACE_ENTRY("target 0x%08x", target); + + // First un-register the target, in case this is being called as a result + // of re-parenting. This is not the most efficient way to update the + // target hash, but since this is not likely to be a frequent operation, + // simplicity is preferred over outright speed. In any case, re-parenting + // of the video widget leads to re-creation of native windows, which is + // likely to take far more processing than any implementation of this + // function. + unRegisterTarget(target); + + QWidget *ancestor = target->parentWidget(); + while(ancestor) { + const Hash::iterator it = m_hash.find(ancestor); + if(m_hash.end() == it) { + TargetList targetList; + targetList.append(target); + m_hash.insert(ancestor, targetList); + } else { + TargetList& targetList = it.value(); + Q_ASSERT(targetList.indexOf(target) == -1); + targetList.append(target); + } + ancestor = ancestor->parentWidget(); + } + + dump(); + + TRACE_EXIT_0(); +} + +void AncestorMoveMonitor::unRegisterTarget(VideoOutput *target) +{ + TRACE_CONTEXT(AncestorMoveMonitor::unRegisterTarget, EVideoInternal); + TRACE_ENTRY("target 0x%08x", target); + + Hash::iterator it = m_hash.begin(); + while(it != m_hash.end()) { + TargetList& targetList = it.value(); + const int index = targetList.indexOf(target); + if(index != -1) + targetList.removeAt(index); + if(targetList.count()) + ++it; + else + it = m_hash.erase(it); + } + + dump(); + + TRACE_EXIT_0(); +} + +bool AncestorMoveMonitor::eventFilter(QObject *watched, QEvent *event) +{ + TRACE_CONTEXT(AncestorMoveMonitor::eventFilter, EVideoInternal); + + if(event->type() == QEvent::Move || event->type() == QEvent::ParentChange) { + + TRACE_ENTRY("watched 0x%08x event.type %d", watched, event->type()); + + const Hash::const_iterator it = m_hash.find(watched); + if(it != m_hash.end()) { + const TargetList& targetList = it.value(); + VideoOutput* target = 0; + foreach(target, targetList) { + switch (event->type()) { + + case QEvent::Move: + // Notify the target that its ancestor has moved + target->ancestorMoved(); + break; + + case QEvent::ParentChange: + // Update ancestor list for the target + registerTarget(target); + break; + + default: + Q_ASSERT(false); + } + } + } + + TRACE_EXIT_0(); + } + + // The event is never consumed by this filter + return false; +} + +//----------------------------------------------------------------------------- +// Private functions +//----------------------------------------------------------------------------- + +void AncestorMoveMonitor::dump() +{ +#ifndef QT_NO_DEBUG + TRACE_CONTEXT(AncestorMoveMonitor::dump, EVideoInternal); + for(Hash::const_iterator it = m_hash.begin(); + it != m_hash.end(); ++it) { + const QObject *ancestor = it.key(); + TRACE("ancestor 0x%08x", ancestor); + const TargetList& targetList = it.value(); + VideoOutput* target = 0; + foreach(target, targetList) { + TRACE(" target 0x%08x", target); + } + } +#endif +} + + + +QT_END_NAMESPACE + diff --git a/src/3rdparty/phonon/mmf/ancestormovemonitor.h b/src/3rdparty/phonon/mmf/ancestormovemonitor.h new file mode 100644 index 0000000..0e681aa --- /dev/null +++ b/src/3rdparty/phonon/mmf/ancestormovemonitor.h @@ -0,0 +1,95 @@ +/* This file is part of the KDE project. + +Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + +This library is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 2.1 or 3 of the License. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this library. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef PHONON_MMF_ANCESTORMOVEMONITOR_H +#define PHONON_MMF_ANCESTORMOVEMONITOR_H + +#include <QObject> +#include <QHash> +#include <QList> + +QT_BEGIN_NAMESPACE + +namespace Phonon +{ +namespace MMF +{ +class VideoOutput; + +class AncestorMoveMonitor : public QObject +{ + Q_OBJECT + +public: + explicit AncestorMoveMonitor(QObject *parent); + ~AncestorMoveMonitor(); + + /** + * Register target widget for notification. + * + * The widget receives an ancestorMoveEvent callback when a move event + * is delivered to any of its ancestors: + * + * If the target is already registered, this function causes its + * ancestor list to be updated - therefore it should be called when + * the target receives a ParentChange event. + */ + void registerTarget(VideoOutput *target); + + /** + * Remove target from the monitor. + * + * The target will no longer receive notification when move events are + * delivered to its ancestors. + */ + void unRegisterTarget(VideoOutput *target); + +protected: + /** + * Function which receives events from the global event filter. + */ + bool eventFilter(QObject *watched, QEvent *event); + + void dump(); + +private: + /** + * List of registered target widgets which descend from a given + * ancestor. + * + * Note that the members of the list should be non-redundant; this + * invariant is checked in debug builds. Semantically, the value is + * therefore a set, however we use QList rather than QSet for + * efficiency of iteration. + */ + typedef QList<VideoOutput *> TargetList; + + /** + * Map from widget on which the move event occurs, to widgets which + * descend from it and therefore need to be notified. + */ + typedef QHash<QObject *, TargetList> Hash; + Hash m_hash; + +}; +} +} + +QT_END_NAMESPACE + +#endif diff --git a/src/3rdparty/phonon/mmf/backend.cpp b/src/3rdparty/phonon/mmf/backend.cpp index f542ec9..cac27e3 100644 --- a/src/3rdparty/phonon/mmf/backend.cpp +++ b/src/3rdparty/phonon/mmf/backend.cpp @@ -24,6 +24,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #include <apmstd.h> // for TDataType #include "abstractaudioeffect.h" +#include "ancestormovemonitor.h" #include "audiooutput.h" #include "audioplayer.h" #include "backend.h" @@ -45,7 +46,9 @@ using namespace Phonon::MMF; \internal */ -Backend::Backend(QObject *parent) : QObject(parent) +Backend::Backend(QObject *parent) + : QObject(parent) + , m_ancestorMoveMonitor(new AncestorMoveMonitor(this)) { TRACE_CONTEXT(Backend::Backend, EBackend); TRACE_ENTRY_0(); @@ -87,7 +90,7 @@ QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const return EffectFactory::createAudioEffect(effect, parent); } case VideoWidgetClass: - result = new VideoWidget(qobject_cast<QWidget *>(parent)); + result = new VideoWidget(m_ancestorMoveMonitor.data(), qobject_cast<QWidget *>(parent)); break; default: diff --git a/src/3rdparty/phonon/mmf/backend.h b/src/3rdparty/phonon/mmf/backend.h index 1886ae6..9e3d3b3 100644 --- a/src/3rdparty/phonon/mmf/backend.h +++ b/src/3rdparty/phonon/mmf/backend.h @@ -19,8 +19,11 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. #ifndef PHONON_MMF_BACKEND_H #define PHONON_MMF_BACKEND_H +#include "ancestormovemonitor.h" + #include <Phonon/MediaSource> #include <Phonon/BackendInterface> +#include <QScopedPointer> QT_BEGIN_NAMESPACE @@ -47,6 +50,10 @@ public: Q_SIGNALS: void objectDescriptionChanged(ObjectDescriptionType); + +private: + QScopedPointer<AncestorMoveMonitor> m_ancestorMoveMonitor; + }; } } diff --git a/src/3rdparty/phonon/mmf/videooutput.cpp b/src/3rdparty/phonon/mmf/videooutput.cpp index f0393a7..5288b4d 100644 --- a/src/3rdparty/phonon/mmf/videooutput.cpp +++ b/src/3rdparty/phonon/mmf/videooutput.cpp @@ -16,6 +16,7 @@ along with this library. If not, see <http://www.gnu.org/licenses/>. */ +#include "ancestormovemonitor.h" #include "utils.h" #include "videooutput.h" #include "videooutputobserver.h" @@ -44,8 +45,10 @@ using namespace Phonon::MMF; // Constructor / destructor //----------------------------------------------------------------------------- -MMF::VideoOutput::VideoOutput(QWidget* parent) +MMF::VideoOutput::VideoOutput + (AncestorMoveMonitor* ancestorMoveMonitor, QWidget* parent) : QWidget(parent) + , m_ancestorMoveMonitor(ancestorMoveMonitor) , m_observer(0) { TRACE_CONTEXT(VideoOutput::VideoOutput, EVideoInternal); @@ -63,6 +66,8 @@ MMF::VideoOutput::VideoOutput(QWidget* parent) // to be invisible when running on the target device. qt_widget_private(this)->extraData()->disableBlit = true; + registerForAncestorMoved(); + dump(); TRACE_EXIT_0(); @@ -73,6 +78,8 @@ MMF::VideoOutput::~VideoOutput() TRACE_CONTEXT(VideoOutput::~VideoOutput, EVideoInternal); TRACE_ENTRY_0(); + m_ancestorMoveMonitor->unRegisterTarget(this); + TRACE_EXIT_0(); } @@ -97,6 +104,15 @@ void MMF::VideoOutput::setObserver(VideoOutputObserver* observer) m_observer = observer; } +void MMF::VideoOutput::ancestorMoved() +{ + TRACE_CONTEXT(VideoOutput::ancestorMoved, EVideoInternal); + TRACE_ENTRY_0(); + + videoOutputRegionChanged(); + + TRACE_EXIT_0(); +} //----------------------------------------------------------------------------- // QWidget @@ -154,8 +170,11 @@ bool MMF::VideoOutput::event(QEvent* event) TRACE_0("WinIdChange"); videoOutputRegionChanged(); return true; - } - else + } else if (event->type() == QEvent::ParentChange) { + // Tell ancestor move monitor to update ancestor list for this widget + registerForAncestorMoved(); + return true; + } else return QWidget::event(event); } @@ -171,6 +190,11 @@ void MMF::VideoOutput::videoOutputRegionChanged() m_observer->videoOutputRegionChanged(); } +void MMF::VideoOutput::registerForAncestorMoved() +{ + m_ancestorMoveMonitor->registerTarget(this); +} + void MMF::VideoOutput::dump() const { #ifndef QT_NO_DEBUG diff --git a/src/3rdparty/phonon/mmf/videooutput.h b/src/3rdparty/phonon/mmf/videooutput.h index 7bc0b52..db4d127 100644 --- a/src/3rdparty/phonon/mmf/videooutput.h +++ b/src/3rdparty/phonon/mmf/videooutput.h @@ -30,6 +30,7 @@ namespace Phonon { namespace MMF { +class AncestorMoveMonitor; class VideoOutputObserver; class VideoOutput : public QWidget @@ -37,12 +38,14 @@ class VideoOutput : public QWidget Q_OBJECT public: - explicit VideoOutput(QWidget* parent); + VideoOutput(AncestorMoveMonitor* ancestorMoveMonitor, QWidget* parent); ~VideoOutput(); void setFrameSize(const QSize& size); void setObserver(VideoOutputObserver* observer); + void ancestorMoved(); + protected: // Override QWidget functions QSize sizeHint() const; @@ -55,11 +58,17 @@ private: void dump() const; void videoOutputRegionChanged(); + void registerForAncestorMoved(); + private: - QSize m_frameSize; + // Not owned + AncestorMoveMonitor* m_ancestorMoveMonitor; // Not owned - VideoOutputObserver* m_observer; + VideoOutputObserver* m_observer; + + QSize m_frameSize; + }; } } diff --git a/src/3rdparty/phonon/mmf/videowidget.cpp b/src/3rdparty/phonon/mmf/videowidget.cpp index 8a5c9ff..7d7abf1 100644 --- a/src/3rdparty/phonon/mmf/videowidget.cpp +++ b/src/3rdparty/phonon/mmf/videowidget.cpp @@ -49,9 +49,10 @@ static const qreal DefaultSaturation = 1.0; // Constructor / destructor //----------------------------------------------------------------------------- -MMF::VideoWidget::VideoWidget(QWidget* parent) +MMF::VideoWidget::VideoWidget + (AncestorMoveMonitor* ancestorMoveMonitor, QWidget* parent) : MediaNode(parent) - , m_widget(new VideoOutput(parent)) + , m_widget(new VideoOutput(ancestorMoveMonitor, parent)) , m_aspectRatio(DefaultAspectRatio) , m_brightness(DefaultBrightness) , m_scaleMode(DefaultScaleMode) diff --git a/src/3rdparty/phonon/mmf/videowidget.h b/src/3rdparty/phonon/mmf/videowidget.h index 970f749..318dfae 100644 --- a/src/3rdparty/phonon/mmf/videowidget.h +++ b/src/3rdparty/phonon/mmf/videowidget.h @@ -31,6 +31,7 @@ namespace Phonon { namespace MMF { +class AncestorMoveMonitor; class VideoOutput; class VideoWidget : public MediaNode @@ -40,7 +41,7 @@ class VideoWidget : public MediaNode Q_INTERFACES(Phonon::VideoWidgetInterface) public: - VideoWidget(QWidget* parent); + VideoWidget(AncestorMoveMonitor* ancestorMoveMonitor, QWidget* parent); ~VideoWidget(); // VideoWidgetInterface diff --git a/src/plugins/phonon/mmf/plugin/plugin.pro b/src/plugins/phonon/mmf/plugin/plugin.pro index eb7fd27..793c307 100644 --- a/src/plugins/phonon/mmf/plugin/plugin.pro +++ b/src/plugins/phonon/mmf/plugin/plugin.pro @@ -26,6 +26,7 @@ HEADERS += \ $$PHONON_MMF_DIR/abstractaudioeffect.h \ $$PHONON_MMF_DIR/abstractmediaplayer.h \ $$PHONON_MMF_DIR/abstractplayer.h \ + $$PHONON_MMF_DIR/ancestormovemonitor.h \ $$PHONON_MMF_DIR/audiooutput.h \ $$PHONON_MMF_DIR/audioequalizer.h \ $$PHONON_MMF_DIR/audioplayer.h \ @@ -47,6 +48,7 @@ SOURCES += \ $$PHONON_MMF_DIR/abstractaudioeffect.cpp \ $$PHONON_MMF_DIR/abstractmediaplayer.cpp \ $$PHONON_MMF_DIR/abstractplayer.cpp \ + $$PHONON_MMF_DIR/ancestormovemonitor.cpp \ $$PHONON_MMF_DIR/audiooutput.cpp \ $$PHONON_MMF_DIR/audioequalizer.cpp \ $$PHONON_MMF_DIR/audioplayer.cpp \ |