~alan-griffiths/miral/fix-1645284

« back to all changes in this revision

Viewing changes to miral-qt/src/platforms/mirserver/windowmanagementpolicy.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 "windowmanagementpolicy.h"
18
 
 
19
 
#include "screensmodel.h"
20
 
#include "surfaceobserver.h"
21
 
 
22
 
#include "miral/window_manager_tools.h"
23
 
#include "miral/window_specification.h"
24
 
 
25
 
#include "mirqtconversion.h"
26
 
 
27
 
#include <mir/scene/surface.h>
28
 
#include <QDebug>
29
 
 
30
 
namespace qtmir {
31
 
    std::shared_ptr<ExtraWindowInfo> getExtraInfo(const miral::WindowInfo &windowInfo) {
32
 
        return std::static_pointer_cast<ExtraWindowInfo>(windowInfo.userdata());
33
 
    }
34
 
}
35
 
 
36
 
using namespace qtmir;
37
 
 
38
 
WindowManagementPolicy::WindowManagementPolicy(const miral::WindowManagerTools &tools,
39
 
                                               qtmir::WindowModelNotifier &windowModel,
40
 
                                               qtmir::WindowController &windowController,
41
 
                                               qtmir::AppNotifier &appNotifier,
42
 
                                               const QSharedPointer<ScreensModel> screensModel)
43
 
    : CanonicalWindowManagerPolicy(tools)
44
 
    , m_tools(tools)
45
 
    , m_windowModel(windowModel)
46
 
    , m_appNotifier(appNotifier)
47
 
    , m_eventFeeder(new QtEventFeeder(screensModel))
48
 
{
49
 
    qRegisterMetaType<qtmir::NewWindow>();
50
 
    qRegisterMetaType<std::vector<miral::Window>>();
51
 
    qRegisterMetaType<miral::ApplicationInfo>();
52
 
    windowController.setPolicy(this);
53
 
}
54
 
 
55
 
/* Following are hooks to allow custom policy be imposed */
56
 
miral::WindowSpecification WindowManagementPolicy::place_new_surface(
57
 
    const miral::ApplicationInfo &app_info,
58
 
    const miral::WindowSpecification &request_parameters)
59
 
{
60
 
    auto parameters = CanonicalWindowManagerPolicy::place_new_surface(app_info, request_parameters);
61
 
 
62
 
    parameters.userdata() = std::make_shared<ExtraWindowInfo>();
63
 
 
64
 
    qDebug() << "Place surface" << parameters.top_left().value().x.as_int();
65
 
    return parameters;
66
 
}
67
 
 
68
 
void WindowManagementPolicy::handle_window_ready(miral::WindowInfo &windowInfo)
69
 
{
70
 
    qDebug("Window Ready");
71
 
    CanonicalWindowManagerPolicy::handle_window_ready(windowInfo);
72
 
 
73
 
    Q_EMIT m_windowModel.windowReady(windowInfo);
74
 
 
75
 
    auto appInfo = m_tools.info_for(windowInfo.window().application());
76
 
    Q_EMIT m_appNotifier.appCreatedWindow(appInfo);
77
 
}
78
 
 
79
 
void WindowManagementPolicy::handle_modify_window(
80
 
    miral::WindowInfo &windowInfo,
81
 
    const miral::WindowSpecification &modifications)
82
 
{
83
 
    qDebug("Window Modified!");
84
 
 
85
 
    // TODO this applies the default policy. Qt needs to process the request instead
86
 
    CanonicalWindowManagerPolicy::handle_modify_window(windowInfo, modifications);
87
 
 
88
 
    // TODO Once Qt processes the request we probably don't want to notify from here
89
 
    std::shared_ptr<mir::scene::Surface> surface{windowInfo.window()};
90
 
    if (SurfaceObserver *observer = SurfaceObserver::observerForSurface(surface.get())) {
91
 
        observer->notifySurfaceModifications(modifications);
92
 
    }
93
 
}
94
 
 
95
 
void WindowManagementPolicy::handle_raise_window(miral::WindowInfo &windowInfo)
96
 
{
97
 
    qDebug("Window Raise");
98
 
    CanonicalWindowManagerPolicy::handle_raise_window(windowInfo);
99
 
}
100
 
 
101
 
/* Handle input events - here just inject them into Qt event loop for later processing */
102
 
bool WindowManagementPolicy::handle_keyboard_event(const MirKeyboardEvent *event)
103
 
{
104
 
    m_eventFeeder->dispatchKey(event);
105
 
    return true;
106
 
}
107
 
 
108
 
bool WindowManagementPolicy::handle_touch_event(const MirTouchEvent *event)
109
 
{
110
 
    m_eventFeeder->dispatchTouch(event);
111
 
    return true;
112
 
}
113
 
 
114
 
bool WindowManagementPolicy::handle_pointer_event(const MirPointerEvent *event)
115
 
{
116
 
    m_eventFeeder->dispatchPointer(event);
117
 
    return true;
118
 
}
119
 
 
120
 
void WindowManagementPolicy::advise_new_window(const miral::WindowInfo &windowInfo)
121
 
{
122
 
    // TODO: attach surface observer here
123
 
 
124
 
    getExtraInfo(windowInfo)->persistentId = QString::fromStdString(m_tools.id_for_window(windowInfo.window()));
125
 
 
126
 
    // FIXME: remove when possible
127
 
    getExtraInfo(windowInfo)->state = toQtState(windowInfo.state());
128
 
 
129
 
    Q_EMIT m_windowModel.windowAdded(NewWindow{windowInfo});
130
 
}
131
 
 
132
 
void WindowManagementPolicy::advise_delete_window(const miral::WindowInfo &windowInfo)
133
 
{
134
 
    Q_EMIT m_windowModel.windowRemoved(windowInfo);
135
 
}
136
 
 
137
 
void WindowManagementPolicy::advise_raise(const std::vector<miral::Window> &windows)
138
 
{
139
 
    Q_EMIT m_windowModel.windowsRaised(windows);
140
 
}
141
 
 
142
 
void WindowManagementPolicy::advise_new_app(miral::ApplicationInfo &application)
143
 
{
144
 
    Q_EMIT m_appNotifier.appAdded(application);
145
 
}
146
 
 
147
 
void WindowManagementPolicy::advise_delete_app(const miral::ApplicationInfo &application)
148
 
{
149
 
    Q_EMIT m_appNotifier.appRemoved(application);
150
 
}
151
 
 
152
 
void WindowManagementPolicy::advise_state_change(const miral::WindowInfo &windowInfo, MirSurfaceState state)
153
 
{
154
 
    auto extraWinInfo = getExtraInfo(windowInfo);
155
 
 
156
 
    // FIXME: Remove this mess once MirSurfaceState matches Mir::State
157
 
    if (state == mir_surface_state_restored && extraWinInfo->state != Mir::RestoredState
158
 
            && toMirState(extraWinInfo->state) == state) {
159
 
        // Ignore. That MirSurfaceState is just a placeholder for a Mir::State value that has no counterpart
160
 
        // in MirSurfaceState.
161
 
    } else {
162
 
        extraWinInfo->state = toQtState(state);
163
 
    }
164
 
 
165
 
    Q_EMIT m_windowModel.windowStateChanged(windowInfo, extraWinInfo->state);
166
 
}
167
 
 
168
 
void WindowManagementPolicy::advise_move_to(const miral::WindowInfo &windowInfo, Point topLeft)
169
 
{
170
 
    qDebug("Window Moved to (%d, %d)", topLeft.x.as_int(), topLeft.y.as_int());
171
 
    Q_EMIT m_windowModel.windowMoved(windowInfo, toQPoint(topLeft));
172
 
}
173
 
 
174
 
void WindowManagementPolicy::advise_resize(const miral::WindowInfo &windowInfo, const Size &newSize)
175
 
{
176
 
    qDebug("Window Resized to %dx%d", newSize.width.as_int(), newSize.height.as_int());
177
 
    Q_EMIT m_windowModel.windowResized(windowInfo, toQSize(newSize));
178
 
}
179
 
 
180
 
void WindowManagementPolicy::advise_focus_lost(const miral::WindowInfo &windowInfo)
181
 
{
182
 
    Q_EMIT m_windowModel.windowFocusChanged(windowInfo, false);
183
 
}
184
 
 
185
 
void WindowManagementPolicy::advise_focus_gained(const miral::WindowInfo &windowInfo)
186
 
{
187
 
    // update Qt model ASAP, before applying Mir policy
188
 
    Q_EMIT m_windowModel.windowFocusChanged(windowInfo, true);
189
 
 
190
 
    CanonicalWindowManagerPolicy::advise_focus_gained(windowInfo);
191
 
}
192
 
 
193
 
void WindowManagementPolicy::advise_begin()
194
 
{
195
 
    Q_EMIT m_windowModel.modificationsStarted();
196
 
}
197
 
 
198
 
void WindowManagementPolicy::advise_end()
199
 
{
200
 
    Q_EMIT m_windowModel.modificationsEnded();
201
 
}
202
 
 
203
 
/* Following methods all called from the Qt GUI thread to deliver events to clients */
204
 
void WindowManagementPolicy::deliver_keyboard_event(const MirKeyboardEvent *event,
205
 
                                                    const miral::Window &window)
206
 
{
207
 
    m_tools.invoke_under_lock([&window, this]() {
208
 
        m_tools.select_active_window(window);
209
 
    });
210
 
    auto e = reinterpret_cast<MirEvent const*>(event); // naughty
211
 
 
212
 
    if (auto surface = std::weak_ptr<mir::scene::Surface>(window).lock()) {
213
 
        surface->consume(e);
214
 
    }
215
 
}
216
 
 
217
 
void WindowManagementPolicy::deliver_touch_event(const MirTouchEvent *event,
218
 
                                                 const miral::Window &window)
219
 
{
220
 
    m_tools.invoke_under_lock([&window, this]() {
221
 
        m_tools.select_active_window(window);
222
 
    });
223
 
    auto e = reinterpret_cast<MirEvent const*>(event); // naughty
224
 
 
225
 
    if (auto surface = std::weak_ptr<mir::scene::Surface>(window).lock()) {
226
 
        surface->consume(e);
227
 
    }
228
 
}
229
 
 
230
 
void WindowManagementPolicy::deliver_pointer_event(const MirPointerEvent *event,
231
 
                                                   const miral::Window &window)
232
 
{
233
 
    // Prevent mouse hover events causing window focus to change
234
 
    if (mir_pointer_event_action(event) == mir_pointer_action_button_down) {
235
 
        m_tools.invoke_under_lock([&window, this]() {
236
 
            m_tools.select_active_window(window);
237
 
        });
238
 
    }
239
 
    auto e = reinterpret_cast<MirEvent const*>(event); // naughty
240
 
 
241
 
    if (auto surface = std::weak_ptr<mir::scene::Surface>(window).lock()) {
242
 
        surface->consume(e);
243
 
    }
244
 
}
245
 
 
246
 
/* Methods to allow Shell to request changes to the window stack. Called from the Qt GUI thread */
247
 
 
248
 
// raises the window tree and focus it.
249
 
void WindowManagementPolicy::activate(const miral::Window &window)
250
 
{
251
 
    if (window) {
252
 
        auto &windowInfo = m_tools.info_for(window);
253
 
 
254
 
        // restore from minimized if needed
255
 
        if (windowInfo.state() == mir_surface_state_minimized) {
256
 
            auto extraInfo = getExtraInfo(windowInfo);
257
 
            Q_ASSERT(extraInfo->previousState != Mir::MinimizedState);
258
 
            requestState(window, extraInfo->previousState);
259
 
        }
260
 
    }
261
 
 
262
 
    m_tools.invoke_under_lock([&]() {
263
 
        m_tools.select_active_window(window);
264
 
    });
265
 
}
266
 
 
267
 
// raises the window tree
268
 
void WindowManagementPolicy::raise(const miral::Window &window)
269
 
{
270
 
    m_tools.invoke_under_lock([&window, this]() {
271
 
        m_tools.raise_tree(window);
272
 
    });
273
 
}
274
 
 
275
 
void WindowManagementPolicy::resize(const miral::Window &window, const Size size)
276
 
{
277
 
    miral::WindowSpecification modifications;
278
 
    modifications.size() = size;
279
 
    m_tools.invoke_under_lock([&window, &modifications, this]() {
280
 
        try {
281
 
            m_tools.modify_window(m_tools.info_for(window), modifications);
282
 
        } catch (const std::out_of_range&) {
283
 
            // usually shell trying to operate on a window which already closed, just ignore
284
 
            // TODO: MirSurface extends the miral::Window lifetime by holding a shared pointer to
285
 
            // the mir::scene::Surface, meaning it cannot detect when the window has been closed
286
 
            // and thus avoid calling this method.
287
 
        }
288
 
    });
289
 
}
290
 
 
291
 
void WindowManagementPolicy::move(const miral::Window &window, const Point topLeft)
292
 
{
293
 
    miral::WindowSpecification modifications;
294
 
    modifications.top_left() = topLeft;
295
 
    m_tools.invoke_under_lock([&window, &modifications, this]() {
296
 
        try {
297
 
            m_tools.modify_window(m_tools.info_for(window), modifications);
298
 
        } catch (const std::out_of_range&) {
299
 
            // usually shell trying to operate on a window which already closed, just ignore
300
 
            // TODO: see above comment in resize, same issue
301
 
        }
302
 
    });
303
 
}
304
 
 
305
 
void WindowManagementPolicy::ask_client_to_close(const miral::Window &window)
306
 
{
307
 
    m_tools.invoke_under_lock([&window, this]() {
308
 
        m_tools.ask_client_to_close(window);
309
 
    });
310
 
}
311
 
 
312
 
void WindowManagementPolicy::forceClose(const miral::Window &window)
313
 
{
314
 
    m_tools.invoke_under_lock([&window, this]() {
315
 
        m_tools.force_close(window);
316
 
    });
317
 
}
318
 
 
319
 
void WindowManagementPolicy::requestState(const miral::Window &window, const Mir::State state)
320
 
{
321
 
    auto &windowInfo = m_tools.info_for(window);
322
 
    auto extraWinInfo = getExtraInfo(windowInfo);
323
 
 
324
 
    if (extraWinInfo->state == state)
325
 
        return;
326
 
 
327
 
    miral::WindowSpecification modifications;
328
 
    modifications.state() = toMirState(state);
329
 
 
330
 
    // TODO: What if the window modification fails? Is that possible?
331
 
    //       Assuming here that the state will indeed change
332
 
    extraWinInfo->previousState = extraWinInfo->state;
333
 
    extraWinInfo->state = state;
334
 
 
335
 
    if (modifications.state() == windowInfo.state()) {
336
 
        Q_EMIT m_windowModel.windowStateChanged(windowInfo, state);
337
 
    } else {
338
 
        m_tools.invoke_under_lock([&]() {
339
 
            m_tools.modify_window(windowInfo, modifications);
340
 
        });
341
 
    }
342
 
}