1
/*  This file is part of the KDE project.
2
3
Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4
5
This library is free software: you can redistribute it and/or modify
6
it under the terms of the GNU Lesser General Public License as published by
7
the Free Software Foundation, either version 2.1 or 3 of the License.
8
9
This library is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
GNU Lesser General Public License for more details.
13
14
You should have received a copy of the GNU Lesser General Public License
15
along with this library.  If not, see <http://www.gnu.org/licenses/>.
16
17
*/
18
19
#include "ancestormovemonitor.h"
20
#include "utils.h"
21
22
#include "videooutput_dsa.h"
23
24
#include <QCoreApplication>
25
26
QT_BEGIN_NAMESPACE
27
28
using namespace Phonon::MMF;
29
30
/*! \class Phonon::MMF::AncestorMoveMonitor
31
  \internal
32
  \brief Class which installs a global event filter, and listens for move
33
  events which may affect the absolute position of widgets registered with
34
  the monitor
35
  See QTBUG-4956
36
*/
37
38
39
/*! \class Phonon::MMF::VideoOutputObserver
40
    \internal
41
*/
42
43
//-----------------------------------------------------------------------------
44
// Constructor / destructor
45
//-----------------------------------------------------------------------------
46
47
AncestorMoveMonitor::AncestorMoveMonitor(QObject *parent)
48
    :   QObject(parent)
49
{
50
    QCoreApplication::instance()->installEventFilter(this);
51
}
52
53
AncestorMoveMonitor::~AncestorMoveMonitor()
54
{
55
    QCoreApplication::instance()->removeEventFilter(this);
56
}
57
58
59
//-----------------------------------------------------------------------------
60
// Public functions
61
//-----------------------------------------------------------------------------
62
63
void AncestorMoveMonitor::registerTarget(DsaVideoOutput *target)
64
{
65
    TRACE_CONTEXT(AncestorMoveMonitor::registerTarget, EVideoInternal);
66
    TRACE_ENTRY("target 0x%08x", target);
67
68
    // First un-register the target, in case this is being called as a result
69
    // of re-parenting.  This is not the most efficient way to update the
70
    // target hash, but since this is not likely to be a frequent operation,
71
    // simplicity is preferred over outright speed.  In any case, re-parenting
72
    // of the video widget leads to re-creation of native windows, which is
73
    // likely to take far more processing than any implementation of this
74
    // function.
75
    unRegisterTarget(target);
76
77
    QWidget *ancestor = target->parentWidget();
78
    while(ancestor) {
79
        const Hash::iterator it = m_hash.find(ancestor);
80
        if(m_hash.end() == it) {
81
            TargetList targetList;
82
            targetList.append(target);
83
            m_hash.insert(ancestor, targetList);
84
        } else {
85
            TargetList& targetList = it.value();
86
            Q_ASSERT(targetList.indexOf(target) == -1);
87
            targetList.append(target);
88
        }
89
        ancestor = ancestor->parentWidget();
90
    }
91
92
    dump();
93
94
    TRACE_EXIT_0();
95
}
96
97
void AncestorMoveMonitor::unRegisterTarget(DsaVideoOutput *target)
98
{
99
    TRACE_CONTEXT(AncestorMoveMonitor::unRegisterTarget, EVideoInternal);
100
    TRACE_ENTRY("target 0x%08x", target);
101
102
    Hash::iterator it = m_hash.begin();
103
    while(it != m_hash.end()) {
104
        TargetList& targetList = it.value();
105
        const int index = targetList.indexOf(target);
106
        if(index != -1)
107
            targetList.removeAt(index);
108
        if(targetList.count())
109
            ++it;
110
        else
111
            it = m_hash.erase(it);
112
    }
113
114
    dump();
115
116
    TRACE_EXIT_0();
117
}
118
119
bool AncestorMoveMonitor::eventFilter(QObject *watched, QEvent *event)
120
{
121
    TRACE_CONTEXT(AncestorMoveMonitor::eventFilter, EVideoInternal);
122
123
    if(event->type() == QEvent::Move || event->type() == QEvent::ParentChange) {
124
125
        //TRACE_ENTRY("watched 0x%08x event.type %d", watched, event->type());
126
127
        const Hash::const_iterator it = m_hash.find(watched);
128
        if(it != m_hash.end()) {
129
            const TargetList& targetList = it.value();
130
            DsaVideoOutput* target = 0;
131
            foreach(target, targetList) {
132
                switch (event->type()) {
133
134
                case QEvent::Move:
135
                    // Notify the target that its ancestor has moved
136
                    target->ancestorMoved();
137
                    break;
138
139
                case QEvent::ParentChange:
140
                    // Update ancestor list for the target
141
                    registerTarget(target);
142
                    break;
143
144
                default:
145
                    Q_ASSERT(false);
146
                }
147
            }
148
        }
149
150
        //TRACE_EXIT_0();
151
    }
152
153
    // The event is never consumed by this filter
154
    return false;
155
}
156
157
//-----------------------------------------------------------------------------
158
// Private functions
159
//-----------------------------------------------------------------------------
160
161
void AncestorMoveMonitor::dump()
162
{
163
#ifndef QT_NO_DEBUG
164
    TRACE_CONTEXT(AncestorMoveMonitor::dump, EVideoInternal);
165
    for(Hash::const_iterator it = m_hash.begin();
166
        it != m_hash.end(); ++it) {
167
        const QObject *ancestor = it.key();
168
        TRACE("ancestor 0x%08x", ancestor);
169
        const TargetList& targetList = it.value();
170
        DsaVideoOutput* target = 0;
171
        foreach(target, targetList) {
172
            TRACE("    target 0x%08x", target);
173
        }
174
    }
175
#endif
176
}
177
178
QT_END_NAMESPACE