~alan-griffiths/miral/fix-1645284

« back to all changes in this revision

Viewing changes to miral-qt/src/modules/Unity/Application/windowmodel.cpp

  • Committer: Alan Griffiths
  • Date: 2016-11-07 17:59:19 UTC
  • mfrom: (436.1.1 miral2)
  • Revision ID: alan@octopull.co.uk-20161107175919-stbb64i7j1htgog2
[miral-qt] delete all as qtmir work on MirAL has shifted to lp:~unity-team/qtmir/miral-qt-integration and this is a needless distration

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2016 Canonical, Ltd.
3
 
 *
4
 
 * This program is free software: you can redistribute it and/or modify it under
5
 
 * the terms of the GNU Lesser General Public License version 3, as published by
6
 
 * the Free Software Foundation.
7
 
 *
8
 
 * This program is distributed in the hope that it will be useful, but WITHOUT
9
 
 * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10
 
 * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
 
 * Lesser General Public License for more details.
12
 
 *
13
 
 * You should have received a copy of the GNU Lesser General Public License
14
 
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
 
 */
16
 
 
17
 
#include "windowmodel.h"
18
 
 
19
 
#include "mirsurface.h"
20
 
 
21
 
// mirserver
22
 
#include "nativeinterface.h"
23
 
 
24
 
// Qt
25
 
#include <QGuiApplication>
26
 
#include <QDebug>
27
 
 
28
 
using namespace qtmir;
29
 
 
30
 
WindowModel::WindowModel()
31
 
{
32
 
    auto nativeInterface = dynamic_cast<NativeInterface*>(QGuiApplication::platformNativeInterface());
33
 
 
34
 
    if (!nativeInterface) {
35
 
        qFatal("ERROR: Unity.Application QML plugin requires use of the 'mirserver' QPA plugin");
36
 
    }
37
 
 
38
 
    m_windowController = static_cast<WindowControllerInterface*>(nativeInterface->nativeResourceForIntegration("WindowController"));
39
 
 
40
 
    auto windowModel = static_cast<WindowModelNotifier*>(nativeInterface->nativeResourceForIntegration("WindowModelNotifier"));
41
 
    connectToWindowModelNotifier(windowModel);
42
 
}
43
 
 
44
 
WindowModel::WindowModel(WindowModelNotifier *notifier,
45
 
                         WindowControllerInterface *controller)
46
 
    : m_windowController(controller)
47
 
{
48
 
    connectToWindowModelNotifier(notifier);
49
 
}
50
 
 
51
 
void WindowModel::connectToWindowModelNotifier(WindowModelNotifier *notifier)
52
 
{
53
 
    connect(notifier, &WindowModelNotifier::windowAdded,        this, &WindowModel::onWindowAdded,        Qt::QueuedConnection);
54
 
    connect(notifier, &WindowModelNotifier::windowRemoved,      this, &WindowModel::onWindowRemoved,      Qt::QueuedConnection);
55
 
    connect(notifier, &WindowModelNotifier::windowReady,        this, &WindowModel::onWindowReady,        Qt::QueuedConnection);
56
 
    connect(notifier, &WindowModelNotifier::windowMoved,        this, &WindowModel::onWindowMoved,        Qt::QueuedConnection);
57
 
    connect(notifier, &WindowModelNotifier::windowStateChanged, this, &WindowModel::onWindowStateChanged, Qt::QueuedConnection);
58
 
    connect(notifier, &WindowModelNotifier::windowFocusChanged, this, &WindowModel::onWindowFocusChanged, Qt::QueuedConnection);
59
 
    connect(notifier, &WindowModelNotifier::windowsRaised,      this, &WindowModel::onWindowsRaised,      Qt::QueuedConnection);
60
 
}
61
 
 
62
 
QHash<int, QByteArray> WindowModel::roleNames() const
63
 
{
64
 
    QHash<int, QByteArray> roleNames;
65
 
    roleNames.insert(SurfaceRole, "surface");
66
 
    return roleNames;
67
 
}
68
 
 
69
 
void WindowModel::onWindowAdded(const NewWindow &window)
70
 
{
71
 
    if (window.windowInfo.type() == mir_surface_type_inputmethod) {
72
 
        addInputMethodWindow(window);
73
 
        return;
74
 
    }
75
 
 
76
 
    const int index = m_windowModel.count();
77
 
    beginInsertRows(QModelIndex(), index, index);
78
 
    m_windowModel.append(new MirSurface(window, m_windowController));
79
 
    endInsertRows();
80
 
    Q_EMIT countChanged();
81
 
}
82
 
 
83
 
void WindowModel::onWindowRemoved(const miral::WindowInfo &windowInfo)
84
 
{
85
 
    if (windowInfo.type() == mir_surface_type_inputmethod) {
86
 
        removeInputMethodWindow();
87
 
        return;
88
 
    }
89
 
 
90
 
    const int index = findIndexOf(windowInfo.window());
91
 
 
92
 
    beginRemoveRows(QModelIndex(), index, index);
93
 
    m_windowModel.takeAt(index);
94
 
    endRemoveRows();
95
 
    Q_EMIT countChanged();
96
 
}
97
 
 
98
 
void WindowModel::onWindowReady(const miral::WindowInfo &windowInfo)
99
 
{
100
 
    if (auto mirSurface = find(windowInfo)) {
101
 
        mirSurface->setReady();
102
 
    }
103
 
}
104
 
 
105
 
void WindowModel::onWindowMoved(const miral::WindowInfo &windowInfo, const QPoint topLeft)
106
 
{
107
 
    if (auto mirSurface = find(windowInfo)) {
108
 
        mirSurface->setPosition(topLeft);
109
 
    }
110
 
}
111
 
 
112
 
void WindowModel::onWindowFocusChanged(const miral::WindowInfo &windowInfo, bool focused)
113
 
{
114
 
    if (auto mirSurface = find(windowInfo)) {
115
 
        mirSurface->setFocused(focused);
116
 
    }
117
 
}
118
 
 
119
 
void WindowModel::onWindowStateChanged(const miral::WindowInfo &windowInfo, Mir::State state)
120
 
{
121
 
    if (auto mirSurface = find(windowInfo)) {
122
 
        mirSurface->updateState(state);
123
 
    }
124
 
}
125
 
 
126
 
void WindowModel::addInputMethodWindow(const NewWindow &windowInfo)
127
 
{
128
 
    if (m_inputMethodSurface) {
129
 
        qDebug("Multiple Input Method Surfaces created, removing the old one!");
130
 
        delete m_inputMethodSurface;
131
 
    }
132
 
    m_inputMethodSurface = new MirSurface(windowInfo, m_windowController);
133
 
    Q_EMIT inputMethodSurfaceChanged(m_inputMethodSurface);
134
 
}
135
 
 
136
 
void WindowModel::removeInputMethodWindow()
137
 
{
138
 
    if (m_inputMethodSurface) {
139
 
        delete m_inputMethodSurface;
140
 
        m_inputMethodSurface = nullptr;
141
 
        Q_EMIT inputMethodSurfaceChanged(m_inputMethodSurface);
142
 
    }
143
 
}
144
 
 
145
 
void WindowModel::onWindowsRaised(const std::vector<miral::Window> &windows)
146
 
{
147
 
    // Reminder: last item in the "windows" list should end up at the top of the model
148
 
    const int modelCount = m_windowModel.count();
149
 
    const int raiseCount = windows.size();
150
 
 
151
 
    // Assumption: no NO-OPs are in this list - Qt will crash on endMoveRows() if you try NO-OPs!!!
152
 
    // A NO-OP is if
153
 
    //    1. "indices" is an empty list
154
 
    //    2. "indices" of the form (..., modelCount - 2, modelCount - 1) which results in an unchanged list
155
 
 
156
 
    // Precompute the list of indices of Windows/Surfaces to raise, including the offsets due to
157
 
    // indices which have already been moved.
158
 
    QVector<QPair<int /*from*/, int /*to*/>> moveList;
159
 
 
160
 
    for (int i=raiseCount-1; i>=0; i--) {
161
 
        int from = findIndexOf(windows[i]);
162
 
        const int to = modelCount - raiseCount + i;
163
 
 
164
 
        int moveCount = 0;
165
 
        // how many list items under "index" have been moved so far, correct "from" to suit
166
 
        for (int j=raiseCount-1; j>i; j--) {
167
 
            if (findIndexOf(windows[j]) < from) {
168
 
                moveCount++;
169
 
            }
170
 
        }
171
 
        from -= moveCount;
172
 
 
173
 
        if (from == to) {
174
 
            // is NO-OP, would result in moving element to itself
175
 
        } else {
176
 
            moveList.prepend({from, to});
177
 
        }
178
 
    }
179
 
 
180
 
    // Perform the moving, trusting the moveList is correct for each iteration.
181
 
    QModelIndex parent;
182
 
    for (int i=moveList.count()-1; i>=0; i--) {
183
 
        const int from = moveList[i].first;
184
 
        const int to = moveList[i].second;
185
 
 
186
 
        beginMoveRows(parent, from, from, parent, to+1);
187
 
#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
188
 
        const auto &window = m_windowModel.takeAt(from);
189
 
        m_windowModel.insert(to, window);
190
 
#else
191
 
        m_windowModel.move(from, to);
192
 
#endif
193
 
 
194
 
        endMoveRows();
195
 
    }
196
 
}
197
 
 
198
 
int WindowModel::rowCount(const QModelIndex &/*parent*/) const
199
 
{
200
 
    return m_windowModel.count();
201
 
}
202
 
 
203
 
QVariant WindowModel::data(const QModelIndex &index, int role) const
204
 
{
205
 
    if (index.row() < 0 || index.row() >= m_windowModel.count())
206
 
        return QVariant();
207
 
 
208
 
    if (role == SurfaceRole) {
209
 
        auto &surface = m_windowModel.at(index.row());
210
 
        return QVariant::fromValue(surface);
211
 
    } else {
212
 
        return QVariant();
213
 
    }
214
 
}
215
 
 
216
 
MirSurface *WindowModel::find(const miral::WindowInfo &needle) const
217
 
{
218
 
    auto window = needle.window();
219
 
    Q_FOREACH(const auto mirSurface, m_windowModel) {
220
 
        if (mirSurface->window() == window) {
221
 
            return mirSurface;
222
 
        }
223
 
    }
224
 
    return nullptr;
225
 
}
226
 
 
227
 
int WindowModel::findIndexOf(const miral::Window &needle) const
228
 
{
229
 
    for (int i=0; i<m_windowModel.count(); i++) {
230
 
        if (m_windowModel[i]->window() == needle) {
231
 
            return i;
232
 
        }
233
 
    }
234
 
    return -1;
235
 
}