/* 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_dsa.h"
#include <QCoreApplication>
QT_BEGIN_NAMESPACE
using namespace Phonon::MMF;
/*! \class Phonon::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
*/
/*! \class Phonon::MMF::VideoOutputObserver
\internal
*/
//-----------------------------------------------------------------------------
// Constructor / destructor
//-----------------------------------------------------------------------------
AncestorMoveMonitor::AncestorMoveMonitor(QObject *parent)
: QObject(parent)
{
QCoreApplication::instance()->installEventFilter(this);
}
AncestorMoveMonitor::~AncestorMoveMonitor()
{
QCoreApplication::instance()->removeEventFilter(this);
}
//-----------------------------------------------------------------------------
// Public functions
//-----------------------------------------------------------------------------
void AncestorMoveMonitor::registerTarget(DsaVideoOutput *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(DsaVideoOutput *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();
DsaVideoOutput* 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();
DsaVideoOutput* target = 0;
foreach(target, targetList) {
TRACE(" target 0x%08x", target);
}
}
#endif
}
QT_END_NAMESPACE