~gerboland/qtubuntu/enable-debug-mode

« back to all changes in this revision

Viewing changes to src/ubuntumirclient/window.cpp

  • Committer: Gerry Boland
  • Date: 2016-04-12 13:10:43 UTC
  • mfrom: (280.2.34 enable-debug-mode)
  • Revision ID: gerry.boland@canonical.com-20160412131043-t14zmcbheuxclmhr
Merge lp:~dandrader/qtubuntu/enable-debug-mode, he kindly fixed merging this with trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
#include <qpa/qwindowsysteminterface.h>
30
30
#include <QMutexLocker>
31
31
#include <QSize>
 
32
#include <QtMath>
32
33
 
33
34
// Platform API
34
35
#include <ubuntu/application/instance.h>
35
36
 
36
37
#include <EGL/egl.h>
37
38
 
 
39
Q_LOGGING_CATEGORY(ubuntumirclientBufferSwap, "ubuntumirclient.bufferSwap", QtWarningMsg)
 
40
 
 
41
const Qt::WindowType LowChromeWindowHint = (Qt::WindowType)0x00800000;
 
42
 
38
43
namespace
39
44
{
40
45
 
64
69
    return reinterpret_cast<EGLNativeWindowType>(mir_buffer_stream_get_egl_native_window(stream));
65
70
}
66
71
 
67
 
MirSurfaceState qtWindowStateToMirSurfaceState(Qt::WindowState state)
68
 
{
69
 
    switch (state) {
70
 
    case Qt::WindowNoState:
71
 
        return mir_surface_state_restored;
72
 
    case Qt::WindowFullScreen:
73
 
        return mir_surface_state_fullscreen;
74
 
    case Qt::WindowMaximized:
75
 
        return mir_surface_state_maximized;
76
 
    case Qt::WindowMinimized:
77
 
        return mir_surface_state_minimized;
78
 
    default:
79
 
        LOG("Unexpected Qt::WindowState: %d", state);
80
 
        return mir_surface_state_restored;
81
 
    }
82
 
}
83
 
 
84
 
#if !defined(QT_NO_DEBUG)
85
72
const char *qtWindowStateToStr(Qt::WindowState state)
86
73
{
87
74
    switch (state) {
93
80
        return "Maximized";
94
81
    case Qt::WindowMinimized:
95
82
        return "Minimized";
 
83
    case Qt::WindowActive:
 
84
        return "Active";
96
85
    default:
97
86
        return "!?";
98
87
    }
99
88
}
100
 
#endif
 
89
 
 
90
const char *mirSurfaceStateToStr(MirSurfaceState surfaceState)
 
91
{
 
92
    switch (surfaceState) {
 
93
    case mir_surface_state_unknown: return "unknown";
 
94
    case mir_surface_state_restored: return "restored";
 
95
    case mir_surface_state_minimized: return "minimized";
 
96
    case mir_surface_state_maximized: return "vertmaximized";
 
97
    case mir_surface_state_vertmaximized: return "vertmaximized";
 
98
    case mir_surface_state_fullscreen: return "fullscreen";
 
99
    case mir_surface_state_horizmaximized: return "horizmaximized";
 
100
    case mir_surface_state_hidden: return "hidden";
 
101
    default: return "!?";
 
102
    }
 
103
}
 
104
 
 
105
MirSurfaceState qtWindowStateToMirSurfaceState(Qt::WindowState state)
 
106
{
 
107
    switch (state) {
 
108
    case Qt::WindowNoState:
 
109
        return mir_surface_state_restored;
 
110
    case Qt::WindowFullScreen:
 
111
        return mir_surface_state_fullscreen;
 
112
    case Qt::WindowMaximized:
 
113
        return mir_surface_state_maximized;
 
114
    case Qt::WindowMinimized:
 
115
        return mir_surface_state_minimized;
 
116
    default:
 
117
        qCWarning(ubuntumirclient, "Unexpected Qt::WindowState: %d", state);
 
118
        return mir_surface_state_restored;
 
119
    }
 
120
}
101
121
 
102
122
WId makeId()
103
123
{
134
154
 
135
155
Spec makeSurfaceSpec(QWindow *window, UbuntuInput *input, MirConnection *connection)
136
156
{
137
 
   const auto geom = window->geometry();
138
 
   const int width = geom.width() > 0 ? geom.width() : 1;
139
 
   const int height = geom.height() > 0 ? geom.height() : 1;
140
 
   const auto pixelFormat = defaultPixelFormatFor(connection);
141
 
 
142
 
   if (U_ON_SCREEN_KEYBOARD_ROLE == roleFor(window)) {
143
 
       DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating input method surface (width=%d, height=%d", window, width, height);
144
 
       return Spec{mir_connection_create_spec_for_input_method(connection, width, height, pixelFormat)};
145
 
   }
146
 
 
147
 
   const Qt::WindowType type = window->type();
148
 
   if (type == Qt::Popup) {
149
 
       auto parent = transientParentFor(window);
150
 
       if (parent == nullptr) {
151
 
           //NOTE: We cannot have a parentless popup -
152
 
           //try using the last surface to receive input as that will most likely be
153
 
           //the one that caused this popup to be created
154
 
           parent = input->lastFocusedWindow();
155
 
       }
156
 
       if (parent) {
157
 
           auto pos = geom.topLeft();
158
 
           pos -= parent->geometry().topLeft();
159
 
           MirRectangle location{pos.x(), pos.y(), 0, 0};
160
 
           DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating menu surface(width:%d, height:%d)", window, width, height);
161
 
           return Spec{mir_connection_create_spec_for_menu(
162
 
                       connection, width, height, pixelFormat, parent->mirSurface(),
163
 
                       &location, mir_edge_attachment_any)};
164
 
       } else {
165
 
           DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - cannot create a menu without a parent!", window);
166
 
       }
167
 
   } else if (type == Qt::Dialog) {
168
 
       auto parent = transientParentFor(window);
169
 
       if (parent) {
170
 
           // Modal dialog
171
 
           DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating modal dialog (width=%d, height=%d", window, width, height);
172
 
           return Spec{mir_connection_create_spec_for_modal_dialog(connection, width, height, pixelFormat, parent->mirSurface())};
173
 
       } else {
174
 
           // TODO: do Qt parentless dialogs have the same semantics as mir?
175
 
           DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating parentless dialog (width=%d, height=%d)", window, width, height);
176
 
           return Spec{mir_connection_create_spec_for_dialog(connection, width, height, pixelFormat)};
177
 
       }
178
 
   }
179
 
   DLOG("[ubuntumirclient QPA] makeSurfaceSpec(window=%p) - creating normal surface(type=0x%x, width=%d, height=%d)", window, type, width, height);
180
 
   return Spec{mir_connection_create_spec_for_normal_surface(connection, width, height, pixelFormat)};
 
157
    const auto geom = window->geometry();
 
158
    const int width = geom.width() > 0 ? geom.width() : 1;
 
159
    const int height = geom.height() > 0 ? geom.height() : 1;
 
160
    const auto pixelFormat = defaultPixelFormatFor(connection);
 
161
 
 
162
    if (U_ON_SCREEN_KEYBOARD_ROLE == roleFor(window)) {
 
163
        qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating input method surface (width=%d, height=%d", window, width, height);
 
164
        return Spec{mir_connection_create_spec_for_input_method(connection, width, height, pixelFormat)};
 
165
    }
 
166
 
 
167
    const Qt::WindowType type = window->type();
 
168
    if (type == Qt::Popup) {
 
169
        auto parent = transientParentFor(window);
 
170
        if (parent == nullptr) {
 
171
            //NOTE: We cannot have a parentless popup -
 
172
            //try using the last surface to receive input as that will most likely be
 
173
            //the one that caused this popup to be created
 
174
            parent = input->lastFocusedWindow();
 
175
        }
 
176
        if (parent) {
 
177
            auto pos = geom.topLeft();
 
178
            pos -= parent->geometry().topLeft();
 
179
            MirRectangle location{pos.x(), pos.y(), 0, 0};
 
180
            qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating menu surface(width:%d, height:%d)", window, width, height);
 
181
            return Spec{mir_connection_create_spec_for_menu(
 
182
                    connection, width, height, pixelFormat, parent->mirSurface(),
 
183
                    &location, mir_edge_attachment_any)};
 
184
        } else {
 
185
            qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - cannot create a menu without a parent!", window);
 
186
        }
 
187
    } else if (type == Qt::Dialog) {
 
188
        auto parent = transientParentFor(window);
 
189
        if (parent) {
 
190
            // Modal dialog
 
191
            qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating modal dialog (width=%d, height=%d", window, width, height);
 
192
            return Spec{mir_connection_create_spec_for_modal_dialog(connection, width, height, pixelFormat, parent->mirSurface())};
 
193
        } else {
 
194
            // TODO: do Qt parentless dialogs have the same semantics as mir?
 
195
            qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating parentless dialog (width=%d, height=%d)", window, width, height);
 
196
            return Spec{mir_connection_create_spec_for_dialog(connection, width, height, pixelFormat)};
 
197
        }
 
198
    }
 
199
    qCDebug(ubuntumirclient, "makeSurfaceSpec(window=%p) - creating normal surface(type=0x%x, width=%d, height=%d)", window, type, width, height);
 
200
    return Spec{mir_connection_create_spec_for_normal_surface(connection, width, height, pixelFormat)};
 
201
}
 
202
 
 
203
void setSizingConstraints(MirSurfaceSpec *spec, const QSize& minSize, const QSize& maxSize, const QSize& increment)
 
204
{
 
205
    mir_surface_spec_set_min_width(spec, minSize.width());
 
206
    mir_surface_spec_set_min_height(spec, minSize.height());
 
207
    if (maxSize.width() >= minSize.width()) {
 
208
        mir_surface_spec_set_max_width(spec, maxSize.width());
 
209
    }
 
210
    if (maxSize.height() >= minSize.height()) {
 
211
        mir_surface_spec_set_max_height(spec, maxSize.height());
 
212
    }
 
213
    if (increment.width() > 0) {
 
214
        mir_surface_spec_set_width_increment(spec, increment.width());
 
215
    }
 
216
    if (increment.height() > 0) {
 
217
        mir_surface_spec_set_height_increment(spec, increment.height());
 
218
    }
181
219
}
182
220
 
183
221
MirSurface *createMirSurface(QWindow *window, UbuntuScreen *screen, UbuntuInput *input, MirConnection *connection)
186
224
    const auto title = window->title().toUtf8();
187
225
    mir_surface_spec_set_name(spec.get(), title.constData());
188
226
 
 
227
    setSizingConstraints(spec.get(), window->minimumSize(), window->maximumSize(), window->sizeIncrement());
 
228
 
189
229
    if (window->windowState() == Qt::WindowFullScreen) {
190
230
        mir_surface_spec_set_fullscreen_on_output(spec.get(), screen->mirOutputId());
191
231
    }
192
232
 
 
233
    if (window->flags() & LowChromeWindowHint) {
 
234
        mir_surface_spec_set_shell_chrome(spec.get(), mir_shell_chrome_low);
 
235
    }
 
236
 
193
237
    auto surface = mir_surface_create_sync(spec.get());
194
238
    Q_ASSERT(mir_surface_is_valid(surface));
195
239
    return surface;
196
240
}
197
241
 
 
242
// FIXME - in order to work around https://bugs.launchpad.net/mir/+bug/1346633
 
243
// we need to guess the panel height (3GU)
 
244
int panelHeight()
 
245
{
 
246
    const int defaultGridUnit = 8;
 
247
    int gridUnit = defaultGridUnit;
 
248
    QByteArray gridUnitString = qgetenv("GRID_UNIT_PX");
 
249
    if (!gridUnitString.isEmpty()) {
 
250
        bool ok;
 
251
        gridUnit = gridUnitString.toInt(&ok);
 
252
        if (!ok) {
 
253
            gridUnit = defaultGridUnit;
 
254
        }
 
255
    }
 
256
    return gridUnit * 3;
 
257
}
 
258
 
198
259
} //namespace
199
260
 
200
261
class UbuntuSurface
203
264
    UbuntuSurface(UbuntuWindow *platformWindow, UbuntuScreen *screen, UbuntuInput *input, MirConnection *connection)
204
265
        : mWindow(platformWindow->window())
205
266
        , mPlatformWindow(platformWindow)
206
 
        , mScreen(screen)
207
267
        , mInput(input)
208
268
        , mConnection(connection)
209
269
        , mMirSurface(createMirSurface(mWindow, screen, input, connection))
210
270
        , mEglDisplay(screen->eglDisplay())
211
271
        , mEglSurface(eglCreateWindowSurface(mEglDisplay, screen->eglConfig(), nativeWindowFor(mMirSurface), nullptr))
212
 
        , mVisible(false)
213
272
        , mNeedsRepaint(false)
214
273
        , mParented(mWindow->transientParent() || mWindow->parent())
215
 
        , mWindowState(mWindow->windowState())
216
 
 
 
274
        , mShellChrome(mWindow->flags() & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal)
217
275
    {
218
276
        mir_surface_set_event_handler(mMirSurface, surfaceEventCallback, this);
219
277
 
225
283
        auto geom = mWindow->geometry();
226
284
        geom.setWidth(parameters.width);
227
285
        geom.setHeight(parameters.height);
 
286
        if (mWindow->windowState() == Qt::WindowFullScreen) {
 
287
            geom.setY(0);
 
288
        } else {
 
289
            geom.setY(panelHeight());
 
290
        }
228
291
 
229
292
        // Assume that the buffer size matches the surface size at creation time
230
293
        mBufferSize = geom.size();
231
294
        platformWindow->QPlatformWindow::setGeometry(geom);
232
295
        QWindowSystemInterface::handleGeometryChange(mWindow, geom);
233
296
 
234
 
        DLOG("[ubuntumirclient QPA] created surface at (%d, %d) with size (%d, %d), title '%s', role: '%d'\n",
 
297
        qCDebug(ubuntumirclient, "created surface at (%d, %d) with size (%d, %d), title '%s', role: '%d'\n",
235
298
             geom.x(), geom.y(), geom.width(), geom.height(), mWindow->title().toUtf8().constData(), roleFor(mWindow));
236
299
    }
237
300
 
243
306
            mir_surface_release_sync(mMirSurface);
244
307
    }
245
308
 
 
309
    UbuntuSurface(UbuntuSurface const&) = delete;
 
310
    UbuntuSurface& operator=(UbuntuSurface const&) = delete;
 
311
 
246
312
    void resize(const QSize& newSize);
247
 
    void setState(Qt::WindowState newState);
248
 
    void setVisible(bool state);
249
313
    void updateTitle(const QString& title);
250
314
    void setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment);
251
315
 
253
317
    void handleSurfaceResized(int width, int height);
254
318
    int needsRepaint() const;
255
319
 
 
320
    MirSurfaceState state() const { return mir_surface_get_state(mMirSurface); }
 
321
    void setState(MirSurfaceState state);
 
322
 
 
323
    MirSurfaceType type() const { return mir_surface_get_type(mMirSurface); }
 
324
 
 
325
    void setShellChrome(MirShellChrome shellChrome);
 
326
 
256
327
    EGLSurface eglSurface() const { return mEglSurface; }
257
328
    MirSurface *mirSurface() const { return mMirSurface; }
258
329
 
 
330
    void setSurfaceParent(MirSurface*);
 
331
    bool hasParent() const { return mParented; }
 
332
 
259
333
private:
260
334
    static void surfaceEventCallback(MirSurface* surface, const MirEvent *event, void* context);
261
335
    void postEvent(const MirEvent *event);
262
 
    void updateSurface();
263
336
 
264
337
    QWindow * const mWindow;
265
338
    UbuntuWindow * const mPlatformWindow;
266
 
    UbuntuScreen * const mScreen;
267
339
    UbuntuInput * const mInput;
268
340
    MirConnection * const mConnection;
269
341
 
271
343
    const EGLDisplay mEglDisplay;
272
344
    const EGLSurface mEglSurface;
273
345
 
274
 
    bool mVisible;
275
346
    bool mNeedsRepaint;
276
347
    bool mParented;
277
 
    Qt::WindowState mWindowState;
278
348
    QSize mBufferSize;
279
349
 
280
350
    QMutex mTargetSizeMutex;
281
351
    QSize mTargetSize;
 
352
    MirShellChrome mShellChrome;
282
353
};
283
354
 
284
355
void UbuntuSurface::resize(const QSize& size)
285
356
{
286
 
    DLOG("[ubuntumirclient QPA] resize(window=%p, width=%d, height=%d)", mWindow, size.width(), size.height());
 
357
    qCDebug(ubuntumirclient,"resize(window=%p, width=%d, height=%d)", mWindow, size.width(), size.height());
287
358
 
288
 
    if (mWindowState == Qt::WindowFullScreen || mWindowState == Qt::WindowMaximized) {
289
 
        DLOG("[ubuntumirclient QPA] resize(window=%p) - not resizing, window is maximized or fullscreen", mWindow);
 
359
    if (mWindow->windowState() == Qt::WindowFullScreen || mWindow->windowState() == Qt::WindowMaximized) {
 
360
        qCDebug(ubuntumirclient, "resize(window=%p) - not resizing, window is maximized or fullscreen", mWindow);
290
361
        return;
291
362
    }
292
363
 
293
364
    if (size.isEmpty()) {
294
 
        DLOG("[ubuntumirclient QPA] resize(window=%p) - not resizing, size is empty", mWindow);
 
365
        qCDebug(ubuntumirclient, "resize(window=%p) - not resizing, size is empty", mWindow);
295
366
        return;
296
367
    }
297
368
 
301
372
    mir_surface_apply_spec(mMirSurface, spec.get());
302
373
}
303
374
 
304
 
void UbuntuSurface::setState(Qt::WindowState newState)
305
 
{
306
 
    mir_wait_for(mir_surface_set_state(mMirSurface, qtWindowStateToMirSurfaceState(newState)));
307
 
    mWindowState = newState;
308
 
}
309
 
 
310
 
void UbuntuSurface::setVisible(bool visible)
311
 
{
312
 
    if (mVisible == visible)
313
 
        return;
314
 
 
315
 
    mVisible = visible;
316
 
 
317
 
    if (mVisible)
318
 
        updateSurface();
319
 
 
320
 
    // TODO: Use the new mir_surface_state_hidden state instead of mir_surface_state_minimized.
321
 
    //       Will have to change qtmir and unity8 for that.
322
 
    const auto newState = visible ? qtWindowStateToMirSurfaceState(mWindowState) : mir_surface_state_minimized;
323
 
    mir_wait_for(mir_surface_set_state(mMirSurface, newState));
324
 
}
325
 
 
326
375
void UbuntuSurface::updateTitle(const QString& newTitle)
327
376
{
328
377
    const auto title = newTitle.toUtf8();
334
383
void UbuntuSurface::setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment)
335
384
{
336
385
    Spec spec{mir_connection_create_spec_for_changes(mConnection)};
337
 
    mir_surface_spec_set_min_width(spec.get(), minSize.width());
338
 
    mir_surface_spec_set_min_height(spec.get(), minSize.height());
339
 
    if (maxSize.width() >= minSize.width()) {
340
 
        mir_surface_spec_set_max_width(spec.get(), maxSize.width());
341
 
    }
342
 
    if (maxSize.height() >= minSize.height()) {
343
 
        mir_surface_spec_set_max_height(spec.get(), maxSize.height());
344
 
    }
345
 
    if (increment.width() > 0) {
346
 
        mir_surface_spec_set_width_increment(spec.get(), increment.width());
347
 
    }
348
 
    if (increment.height() > 0) {
349
 
        mir_surface_spec_set_height_increment(spec.get(), increment.height());
350
 
    }
 
386
    ::setSizingConstraints(spec.get(), minSize, maxSize, increment);
351
387
    mir_surface_apply_spec(mMirSurface, spec.get());
352
388
}
353
389
 
381
417
    return 0;
382
418
}
383
419
 
 
420
void UbuntuSurface::setState(MirSurfaceState state)
 
421
{
 
422
    mir_wait_for(mir_surface_set_state(mMirSurface, state));
 
423
}
 
424
 
 
425
void UbuntuSurface::setShellChrome(MirShellChrome chrome)
 
426
{
 
427
    if (chrome != mShellChrome) {
 
428
        auto spec = Spec{mir_connection_create_spec_for_changes(mConnection)};
 
429
        mir_surface_spec_set_shell_chrome(spec.get(), chrome);
 
430
        mir_surface_apply_spec(mMirSurface, spec.get());
 
431
 
 
432
        mShellChrome = chrome;
 
433
    }
 
434
}
 
435
 
384
436
void UbuntuSurface::onSwapBuffersDone()
385
437
{
386
 
#if !defined(QT_NO_DEBUG)
387
438
    static int sFrameNumber = 0;
388
439
    ++sFrameNumber;
389
 
#endif
390
440
 
391
441
    EGLint eglSurfaceWidth = -1;
392
442
    EGLint eglSurfaceHeight = -1;
397
447
 
398
448
    if (validSize && (mBufferSize.width() != eglSurfaceWidth || mBufferSize.height() != eglSurfaceHeight)) {
399
449
 
400
 
        DLOG("[ubuntumirclient QPA] onSwapBuffersDone(window=%p) [%d] - size changed (%d, %d) => (%d, %d)",
 
450
        qCDebug(ubuntumirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - size changed (%d, %d) => (%d, %d)",
401
451
               mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height(), eglSurfaceWidth, eglSurfaceHeight);
402
452
 
403
453
        mBufferSize.rwidth() = eglSurfaceWidth;
409
459
        mPlatformWindow->QPlatformWindow::setGeometry(newGeometry);
410
460
        QWindowSystemInterface::handleGeometryChange(mWindow, newGeometry);
411
461
    } else {
412
 
        DLOG("[ubuntumirclient QPA] onSwapBuffersDone(window=%p) [%d] - buffer size (%d,%d)",
 
462
        qCDebug(ubuntumirclientBufferSwap, "onSwapBuffersDone(window=%p) [%d] - buffer size (%d,%d)",
413
463
               mWindow, sFrameNumber, mBufferSize.width(), mBufferSize.height());
414
464
    }
415
465
}
433
483
        const auto resizeEvent = mir_event_get_resize_event(event);
434
484
        const auto width =  mir_resize_event_get_width(resizeEvent);
435
485
        const auto height =  mir_resize_event_get_height(resizeEvent);
436
 
        DLOG("[ubuntumirclient QPA] resizeEvent(window=%p, width=%d, height=%d)", mWindow, width, height);
 
486
        qCDebug(ubuntumirclient, "resizeEvent(window=%p, width=%d, height=%d)", mWindow, width, height);
437
487
 
438
488
        QMutexLocker lock(&mTargetSizeMutex);
439
489
        mTargetSize.rwidth() = width;
443
493
    mInput->postEvent(mPlatformWindow, event);
444
494
}
445
495
 
446
 
void UbuntuSurface::updateSurface()
 
496
void UbuntuSurface::setSurfaceParent(MirSurface* parent)
447
497
{
448
 
    DLOG("[ubuntumirclient QPA] updateSurface(window=%p)", mWindow);
 
498
    qCDebug(ubuntumirclient, "setSurfaceParent(window=%p)", mWindow);
449
499
 
450
 
    if (!mParented && mWindow->type() == Qt::Dialog) {
451
 
        // The dialog may have been parented after creation time
452
 
        // so morph it into a modal dialog
453
 
        auto parent = transientParentFor(mWindow);
454
 
        if (parent) {
455
 
            DLOG("[ubuntumirclient QPA] updateSurface(window=%p) dialog now parented", mWindow);
456
 
            mParented = true;
457
 
            Spec spec{mir_connection_create_spec_for_changes(mConnection)};
458
 
            mir_surface_spec_set_parent(spec.get(), parent->mirSurface());
459
 
            mir_surface_apply_spec(mMirSurface, spec.get());
460
 
        }
461
 
    }
 
500
    mParented = true;
 
501
    Spec spec{mir_connection_create_spec_for_changes(mConnection)};
 
502
    mir_surface_spec_set_parent(spec.get(), parent);
 
503
    mir_surface_apply_spec(mMirSurface, spec.get());
462
504
}
463
505
 
464
506
UbuntuWindow::UbuntuWindow(QWindow *w, UbuntuClientIntegration *integration, UbuntuScreen *screen,
467
509
    , QPlatformWindow(w)
468
510
    , mId(makeId())
469
511
    , mIntegration(integration)
 
512
    , mWindowState(w->windowState())
 
513
    , mWindowFlags(w->flags())
 
514
    , mWindowVisible(false)
470
515
    , mSurface(new UbuntuSurface{this, screen, input, connection})
471
516
{
472
 
    DLOG("[ubuntumirclient QPA] UbuntuWindow(window=%p, screen=%p, input=%p, surf=%p)", w, screen, input, mSurface.get());
 
517
    qCDebug(ubuntumirclient, "UbuntuWindow(window=%p, screen=%p, input=%p, surf=%p)", w, screen, input, mSurface.get());
473
518
}
474
519
 
475
520
UbuntuWindow::~UbuntuWindow()
476
521
{
477
 
    DLOG("[ubuntumirclient QPA] ~UbuntuWindow(window=%p)", this);
 
522
    qCDebug(ubuntumirclient, "~UbuntuWindow(window=%p)", this);
478
523
}
479
524
 
480
525
void UbuntuWindow::handleSurfaceResized(int width, int height)
481
526
{
482
527
    QMutexLocker lock(&mMutex);
483
 
    DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p, width=%d, height=%d)", window(), width, height);
 
528
    qCDebug(ubuntumirclient, "handleSurfaceResize(window=%p, width=%d, height=%d)", window(), width, height);
484
529
 
485
530
    mSurface->handleSurfaceResized(width, height);
486
531
 
490
535
    // updated size but it still needs re-rendering so another redraw may be needed.
491
536
    // A mir API to drop the currently held buffer would help here, so that we wouldn't have to redraw twice
492
537
    auto const numRepaints = mSurface->needsRepaint();
493
 
    DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p) redraw %d times", window(), numRepaints);
 
538
    lock.unlock();
 
539
    qCDebug(ubuntumirclient, "handleSurfaceResize(window=%p) redraw %d times", window(), numRepaints);
494
540
    for (int i = 0; i < numRepaints; i++) {
495
 
        DLOG("[ubuntumirclient QPA] handleSurfaceResize(window=%p) repainting width=%d, height=%d", window(), geometry().size().width(), geometry().size().height());
 
541
        qCDebug(ubuntumirclient, "handleSurfaceResize(window=%p) repainting width=%d, height=%d", window(), geometry().size().width(), geometry().size().height());
496
542
        QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
497
543
    }
498
544
}
499
545
 
500
546
void UbuntuWindow::handleSurfaceFocused()
501
547
{
502
 
    DLOG("[ubuntumirclient QPA] handleSurfaceFocused(window=%p)", window());
 
548
    qCDebug(ubuntumirclient, "handleSurfaceFocused(window=%p)", window());
503
549
 
504
550
    // System clipboard contents might have changed while this window was unfocused and without
505
551
    // this process getting notified about it because it might have been suspended (due to
508
554
    // Therefore let's ensure we are up to date with the system clipboard now that we are getting
509
555
    // focused again.
510
556
    static_cast<UbuntuClipboard*>(mIntegration->clipboard())->requestDBusClipboardContents();
511
 
    QWindowSystemInterface::handleWindowActivated(window(), Qt::ActiveWindowFocusReason);
 
557
}
 
558
 
 
559
void UbuntuWindow::handleSurfaceVisibilityChanged(bool visible)
 
560
{
 
561
    qCDebug(ubuntumirclient, "handleSurfaceFocused(window=%p)", window());
 
562
 
 
563
    if (mWindowVisible == visible) return;
 
564
    mWindowVisible = visible;
 
565
 
 
566
    QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
 
567
}
 
568
 
 
569
void UbuntuWindow::handleSurfaceStateChanged(Qt::WindowState state)
 
570
{
 
571
    qCDebug(ubuntumirclient, "handleSurfaceStateChanged(window=%p, %s)", window(), qtWindowStateToStr(state));
 
572
 
 
573
    if (mWindowState == state) return;
 
574
    mWindowState = state;
 
575
 
 
576
    QWindowSystemInterface::handleWindowStateChanged(window(), state);
512
577
}
513
578
 
514
579
void UbuntuWindow::setWindowState(Qt::WindowState state)
515
580
{
516
581
    QMutexLocker lock(&mMutex);
517
 
    DLOG("[ubuntumirclient QPA] setWindowState(window=%p, %s)", this, qtWindowStateToStr(state));
518
 
    mSurface->setState(state);
 
582
    qCDebug(ubuntumirclient, "setWindowState(window=%p, %s)", this, qtWindowStateToStr(state));
 
583
 
 
584
    if (mWindowState == state) return;
 
585
    mWindowState = state;
 
586
 
 
587
    lock.unlock();
 
588
    updateSurfaceState();
 
589
}
 
590
 
 
591
void UbuntuWindow::setWindowFlags(Qt::WindowFlags flags)
 
592
{
 
593
    QMutexLocker lock(&mMutex);
 
594
    qCDebug(ubuntumirclient, "setWindowFlags(window=%p, 0x%x)", this, (int)flags);
 
595
 
 
596
    if (mWindowFlags == flags) return;
 
597
    mWindowFlags = flags;
 
598
 
 
599
    mSurface->setShellChrome(mWindowFlags & LowChromeWindowHint ? mir_shell_chrome_low : mir_shell_chrome_normal);
 
600
}
 
601
 
 
602
/*
 
603
    FIXME: Mir does not let clients know the position of their windows in the virtual
 
604
    desktop space. So we have this ugly hack that assumes a phone situation where the
 
605
    window is always on the top-left corner, right below the indicators panel if not
 
606
    in fullscreen.
 
607
 */
 
608
void UbuntuWindow::enablePanelHeightHack(bool enable)
 
609
{
 
610
    QMutexLocker lock(&mMutex);
 
611
 
 
612
    QRect newGeometry = geometry();
 
613
    if (enable) {
 
614
        newGeometry.setY(panelHeight());
 
615
    } else {
 
616
        newGeometry.setY(0);
 
617
    }
 
618
 
 
619
    if (newGeometry != geometry()) {
 
620
        lock.unlock();
 
621
        QPlatformWindow::setGeometry(newGeometry);
 
622
        QWindowSystemInterface::handleGeometryChange(window(), newGeometry);
 
623
    }
519
624
}
520
625
 
521
626
void UbuntuWindow::setGeometry(const QRect& rect)
522
627
{
523
628
    QMutexLocker lock(&mMutex);
524
 
    DLOG("[ubuntumirclient QPA] setGeometry (window=%p, x=%d, y=%d, width=%d, height=%d)",
 
629
    qCDebug(ubuntumirclient, "setGeometry (window=%p, x=%d, y=%d, width=%d, height=%d)",
525
630
           window(), rect.x(), rect.y(), rect.width(), rect.height());
526
631
 
527
632
    //NOTE: mir surfaces cannot be moved by the client so ignore the topLeft coordinates
536
641
void UbuntuWindow::setVisible(bool visible)
537
642
{
538
643
    QMutexLocker lock(&mMutex);
539
 
    DLOG("[ubuntumirclient QPA] setVisible (window=%p, visible=%s)", window(), visible ? "true" : "false");
540
 
 
541
 
    mSurface->setVisible(visible);
542
 
    const QRect& exposeRect = visible ? QRect(QPoint(), geometry().size()) : QRect();
 
644
    qCDebug(ubuntumirclient, "setVisible (window=%p, visible=%s)", window(), visible ? "true" : "false");
 
645
 
 
646
    if (mWindowVisible == visible) return;
 
647
    mWindowVisible = visible;
 
648
 
 
649
    if (visible) {
 
650
        if (!mSurface->hasParent() && window()->type() == Qt::Dialog) {
 
651
            // The dialog may have been parented after creation time
 
652
            // so morph it into a modal dialog
 
653
            auto parent = transientParentFor(window());
 
654
            if (parent) {
 
655
                mSurface->setSurfaceParent(parent->mirSurface());
 
656
            }
 
657
        }
 
658
    }
543
659
 
544
660
    lock.unlock();
545
 
    QWindowSystemInterface::handleExposeEvent(window(), exposeRect);
 
661
    updateSurfaceState();
 
662
    QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
546
663
    QWindowSystemInterface::flushWindowSystemEvents();
547
664
}
548
665
 
549
666
void UbuntuWindow::setWindowTitle(const QString& title)
550
667
{
551
668
    QMutexLocker lock(&mMutex);
552
 
    DLOG("[ubuntumirclient QPA] setWindowTitle(window=%p) title=%s)", window(), title.toUtf8().constData());
 
669
    qCDebug(ubuntumirclient, "setWindowTitle(window=%p) title=%s)", window(), title.toUtf8().constData());
553
670
    mSurface->updateTitle(title);
554
671
}
555
672
 
557
674
{
558
675
    QMutexLocker lock(&mMutex);
559
676
    const auto win = window();
560
 
    DLOG("[ubuntumirclient QPA] propagateSizeHints(window=%p) min(%d,%d), max(%d,%d) increment(%d, %d)",
 
677
    qCDebug(ubuntumirclient, "propagateSizeHints(window=%p) min(%d,%d), max(%d,%d) increment(%d, %d)",
561
678
           win, win->minimumSize().width(), win->minimumSize().height(),
562
679
           win->maximumSize().width(), win->maximumSize().height(),
563
680
           win->sizeIncrement().width(), win->sizeIncrement().height());
564
681
    mSurface->setSizingConstraints(win->minimumSize(), win->maximumSize(), win->sizeIncrement());
565
682
}
566
683
 
 
684
bool UbuntuWindow::isExposed() const
 
685
{
 
686
    return mWindowVisible;
 
687
}
 
688
 
567
689
QPoint UbuntuWindow::mapToGlobal(const QPoint &pos) const
568
690
{
569
691
    if (mIntegration->debugExtension()) {
593
715
    QMutexLocker lock(&mMutex);
594
716
    mSurface->onSwapBuffersDone();
595
717
}
 
718
 
 
719
void UbuntuWindow::updateSurfaceState()
 
720
{
 
721
    QMutexLocker lock(&mMutex);
 
722
    MirSurfaceState newState = mWindowVisible ? qtWindowStateToMirSurfaceState(mWindowState) :
 
723
                                                mir_surface_state_hidden;
 
724
    qCDebug(ubuntumirclient, "updateSurfaceState (window=%p, surfaceState=%s)", window(), mirSurfaceStateToStr(newState));
 
725
    if (newState != mSurface->state()) {
 
726
        mSurface->setState(newState);
 
727
 
 
728
        lock.unlock();
 
729
        enablePanelHeightHack(newState != mir_surface_state_fullscreen);
 
730
    }
 
731
}