~ci-train-bot/qtubuntu/qtubuntu-ubuntu-xenial-landing-057

« back to all changes in this revision

Viewing changes to src/ubuntumirclient/window.cpp

  • Committer: CI Train Bot
  • Author(s): Gerry Boland, Nick Dedekind
  • Date: 2016-02-05 11:55:35 UTC
  • mfrom: (310.1.4 qtubuntu-clean)
  • Revision ID: ci-train-bot@canonical.com-20160205115535-99xvn26a75cr399q
React to formFactor and window flag changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
// Local
18
18
#include "window.h"
19
19
#include "clipboard.h"
 
20
#include "nativeinterface.h"
20
21
#include "input.h"
21
22
#include "screen.h"
22
23
#include "logging.h"
36
37
 
37
38
Q_LOGGING_CATEGORY(ubuntumirclientBufferSwap, "ubuntumirclient.bufferSwap", QtWarningMsg)
38
39
 
 
40
const Qt::WindowType WindowHidesShellDecorations = (Qt::WindowType)0x00800000;
 
41
 
39
42
namespace
40
43
{
41
44
 
65
68
    return reinterpret_cast<EGLNativeWindowType>(mir_buffer_stream_get_egl_native_window(stream));
66
69
}
67
70
 
68
 
MirSurfaceState qtWindowStateToMirSurfaceState(Qt::WindowState state)
69
 
{
70
 
    switch (state) {
71
 
    case Qt::WindowNoState:
72
 
        return mir_surface_state_restored;
73
 
    case Qt::WindowFullScreen:
74
 
        return mir_surface_state_fullscreen;
75
 
    case Qt::WindowMaximized:
76
 
        return mir_surface_state_maximized;
77
 
    case Qt::WindowMinimized:
78
 
        return mir_surface_state_minimized;
79
 
    default:
80
 
        qCWarning(ubuntumirclient, "Unexpected Qt::WindowState: %d", state);
81
 
        return mir_surface_state_restored;
82
 
    }
83
 
}
84
 
 
85
71
const char *qtWindowStateToStr(Qt::WindowState state)
86
72
{
87
73
    switch (state) {
98
84
    }
99
85
}
100
86
 
 
87
const char *mirFormFactorToStr(MirFormFactor formFactor)
 
88
{
 
89
    switch (formFactor) {
 
90
    case mir_form_factor_unknown: return "unknown";
 
91
    case mir_form_factor_phone: return "phone";
 
92
    case mir_form_factor_tablet: return "tablet";
 
93
    case mir_form_factor_tv: return "tv";
 
94
    case mir_form_factor_monitor:return "monitor";
 
95
    case mir_form_factor_projector:return "projector";
 
96
    default: return "!?";
 
97
    }
 
98
}
 
99
 
 
100
const char *mirSurfaceStateToStr(MirSurfaceState surfaceState)
 
101
{
 
102
    switch (surfaceState) {
 
103
    case mir_surface_state_unknown: return "unknown";
 
104
    case mir_surface_state_restored: return "restored";
 
105
    case mir_surface_state_minimized: return "minimized";
 
106
    case mir_surface_state_maximized: return "vertmaximized";
 
107
    case mir_surface_state_vertmaximized: return "vertmaximized";
 
108
    case mir_surface_state_fullscreen: return "fullscreen";
 
109
    case mir_surface_state_horizmaximized: return "horizmaximized";
 
110
    case mir_surface_state_hidden: return "hidden";
 
111
    default: return "!?";
 
112
    }
 
113
}
 
114
 
 
115
MirSurfaceState qtWindowStateToMirSurfaceState(Qt::WindowState state)
 
116
{
 
117
    switch (state) {
 
118
    case Qt::WindowNoState:
 
119
        return mir_surface_state_restored;
 
120
    case Qt::WindowFullScreen:
 
121
        return mir_surface_state_fullscreen;
 
122
    case Qt::WindowMaximized:
 
123
        return mir_surface_state_maximized;
 
124
    case Qt::WindowMinimized:
 
125
        return mir_surface_state_minimized;
 
126
    default:
 
127
        qCWarning(ubuntumirclient, "Unexpected Qt::WindowState: %d", state);
 
128
        return mir_surface_state_restored;
 
129
    }
 
130
}
 
131
 
 
132
MirSurfaceState surfaceStateFromWindowProperties(MirFormFactor formFactor, Qt::WindowState state, Qt::WindowFlags flags, bool visible)
 
133
{
 
134
    if (!visible) return mir_surface_state_minimized;
 
135
 
 
136
    bool hideDecorationsHint = flags & WindowHidesShellDecorations;
 
137
 
 
138
    switch (formFactor) {
 
139
        case mir_form_factor_phone:
 
140
        case mir_form_factor_tablet:
 
141
        case mir_form_factor_tv:
 
142
            if (hideDecorationsHint) {
 
143
                return mir_surface_state_fullscreen;
 
144
            }
 
145
            break;
 
146
 
 
147
        case mir_form_factor_unknown:
 
148
        case mir_form_factor_monitor:
 
149
        case mir_form_factor_projector:
 
150
            break;
 
151
    }
 
152
    return qtWindowStateToMirSurfaceState(state);
 
153
}
 
154
 
101
155
WId makeId()
102
156
{
103
157
    static int id = 1;
197
251
    }
198
252
}
199
253
 
200
 
MirSurface *createMirSurface(QWindow *window, UbuntuScreen *screen, UbuntuInput *input, MirConnection *connection)
 
254
MirSurface *createMirSurface(QWindow *window, UbuntuScreen *screen, UbuntuInput *input,
 
255
                             MirConnection *connection, mir_surface_event_callback inputCallback,
 
256
                             void* inputContext)
201
257
{
202
258
    auto spec = makeSurfaceSpec(window, input, connection);
203
259
    const auto title = window->title().toUtf8();
205
261
 
206
262
    setSizingConstraints(spec.get(), window->minimumSize(), window->maximumSize(), window->sizeIncrement());
207
263
 
208
 
    if (window->windowState() == Qt::WindowFullScreen) {
 
264
    MirSurfaceState state = surfaceStateFromWindowProperties(screen->formFactor(),
 
265
                                                             window->windowState(),
 
266
                                                             window->flags(),
 
267
                                                             window->isVisible());
 
268
    if (state == mir_surface_state_fullscreen) {
209
269
        mir_surface_spec_set_fullscreen_on_output(spec.get(), screen->mirOutputId());
210
270
    }
211
271
 
 
272
    mir_surface_spec_set_event_handler(spec.get(), inputCallback, inputContext);
 
273
 
212
274
    auto surface = mir_surface_create_sync(spec.get());
213
275
    Q_ASSERT(mir_surface_is_valid(surface));
214
276
    return surface;
241
303
        , mPlatformWindow(platformWindow)
242
304
        , mInput(input)
243
305
        , mConnection(connection)
244
 
        , mMirSurface(createMirSurface(mWindow, screen, input, connection))
 
306
        , mMirSurface(createMirSurface(mWindow, screen, input, connection, surfaceEventCallback, this))
245
307
        , mEglDisplay(screen->eglDisplay())
246
308
        , mEglSurface(eglCreateWindowSurface(mEglDisplay, screen->eglConfig(), nativeWindowFor(mMirSurface), nullptr))
247
 
        , mVisible(false)
248
309
        , mNeedsRepaint(false)
249
310
        , mParented(mWindow->transientParent() || mWindow->parent())
250
 
        , mWindowState(mWindow->windowState())
251
 
 
252
311
    {
253
 
        mir_surface_set_event_handler(mMirSurface, surfaceEventCallback, this);
254
 
 
255
312
        // Window manager can give us a final size different from what we asked for
256
313
        // so let's check what we ended up getting
257
314
        MirSurfaceParameters parameters;
260
317
        auto geom = mWindow->geometry();
261
318
        geom.setWidth(parameters.width);
262
319
        geom.setHeight(parameters.height);
263
 
        if (mWindowState == Qt::WindowFullScreen) {
264
 
            geom.setY(0);
265
 
        } else {
266
 
            geom.setY(panelHeight());
267
 
        }
268
320
 
269
321
        // Assume that the buffer size matches the surface size at creation time
270
322
        mBufferSize = geom.size();
287
339
    UbuntuSurface& operator=(UbuntuSurface const&) = delete;
288
340
 
289
341
    void resize(const QSize& newSize);
290
 
    void setState(Qt::WindowState newState);
291
 
    void setVisible(bool state);
292
 
    void updateTitle(const QString& title);
293
 
    void setSizingConstraints(const QSize& minSize, const QSize& maxSize, const QSize& increment);
 
342
 
 
343
    void updateTitle(const QString &title);
 
344
    void setSizingConstraints(const QSize &minSizePx, const QSize &maxSizePx, const QSize &incrementPx);
294
345
 
295
346
    void onSwapBuffersDone();
296
347
    void handleSurfaceResized(int width, int height);
297
348
    int needsRepaint() const;
298
349
 
 
350
    MirSurfaceState state() const { return mir_surface_get_state(mMirSurface); }
 
351
    void setState(MirSurfaceState state);
 
352
 
 
353
    MirSurfaceType type() const { return mir_surface_get_type(mMirSurface); }
 
354
 
299
355
    EGLSurface eglSurface() const { return mEglSurface; }
300
356
    MirSurface *mirSurface() const { return mMirSurface; }
301
357
 
 
358
    void updateSurface();
 
359
 
302
360
private:
303
361
    static void surfaceEventCallback(MirSurface* surface, const MirEvent *event, void* context);
304
362
    void postEvent(const MirEvent *event);
305
 
    void updateSurface();
306
363
 
307
364
    QWindow * const mWindow;
308
365
    UbuntuWindow * const mPlatformWindow;
313
370
    const EGLDisplay mEglDisplay;
314
371
    const EGLSurface mEglSurface;
315
372
 
316
 
    bool mVisible;
317
373
    bool mNeedsRepaint;
318
374
    bool mParented;
319
 
    Qt::WindowState mWindowState;
320
375
    QSize mBufferSize;
321
376
 
322
377
    QMutex mTargetSizeMutex;
327
382
{
328
383
    qCDebug(ubuntumirclient,"resize(window=%p, width=%d, height=%d)", mWindow, size.width(), size.height());
329
384
 
330
 
    if (mWindowState == Qt::WindowFullScreen || mWindowState == Qt::WindowMaximized) {
 
385
    if (mWindow->windowState() == Qt::WindowFullScreen || mWindow->windowState() == Qt::WindowMaximized) {
331
386
        qCDebug(ubuntumirclient, "resize(window=%p) - not resizing, window is maximized or fullscreen", mWindow);
332
387
        return;
333
388
    }
343
398
    mir_surface_apply_spec(mMirSurface, spec.get());
344
399
}
345
400
 
346
 
void UbuntuSurface::setState(Qt::WindowState newState)
347
 
{
348
 
    mir_wait_for(mir_surface_set_state(mMirSurface, qtWindowStateToMirSurfaceState(newState)));
349
 
    mWindowState = newState;
350
 
}
351
 
 
352
 
void UbuntuSurface::setVisible(bool visible)
353
 
{
354
 
    if (mVisible == visible)
355
 
        return;
356
 
 
357
 
    mVisible = visible;
358
 
 
359
 
    if (mVisible)
360
 
        updateSurface();
361
 
 
362
 
    // TODO: Use the new mir_surface_state_hidden state instead of mir_surface_state_minimized.
363
 
    //       Will have to change qtmir and unity8 for that.
364
 
    const auto newState = visible ? qtWindowStateToMirSurfaceState(mWindowState) : mir_surface_state_minimized;
365
 
    mir_wait_for(mir_surface_set_state(mMirSurface, newState));
366
 
}
367
 
 
368
401
void UbuntuSurface::updateTitle(const QString& newTitle)
369
402
{
370
403
    const auto title = newTitle.toUtf8();
410
443
    return 0;
411
444
}
412
445
 
 
446
void UbuntuSurface::setState(MirSurfaceState state)
 
447
{
 
448
    mir_wait_for(mir_surface_set_state(mMirSurface, state));
 
449
}
 
450
 
413
451
void UbuntuSurface::onSwapBuffersDone()
414
452
{
415
453
    static int sFrameNumber = 0;
488
526
    }
489
527
}
490
528
 
491
 
UbuntuWindow::UbuntuWindow(QWindow *w, const QSharedPointer<UbuntuClipboard> &clipboard, UbuntuScreen *screen,
492
 
                           UbuntuInput *input, MirConnection *connection)
 
529
UbuntuWindow::UbuntuWindow(QWindow *w, const QSharedPointer<UbuntuClipboard> &clipboard,
 
530
                           UbuntuInput *input, UbuntuNativeInterface *native, MirConnection *connection)
493
531
    : QObject(nullptr)
494
532
    , QPlatformWindow(w)
495
533
    , mId(makeId())
496
534
    , mClipboard(clipboard)
497
 
    , mSurface(new UbuntuSurface{this, screen, input, connection})
 
535
    , mNativeInterface(native)
 
536
    , mWindowState(w->windowState())
 
537
    , mWindowFlags(w->flags())
 
538
    , mWindowVisible(false)
 
539
    , mFormFactor(static_cast<UbuntuScreen*>(w->screen()->handle())->formFactor())
 
540
    , mSurface(new UbuntuSurface{this, static_cast<UbuntuScreen*>(w->screen()->handle()), input, connection})
498
541
{
499
 
    qCDebug(ubuntumirclient, "UbuntuWindow(window=%p, screen=%p, input=%p, surf=%p)", w, screen, input, mSurface.get());
 
542
    qCDebug(ubuntumirclient, "UbuntuWindow(window=%p, screen=%p, input=%p, surf=%p) with title '%s', role: '%d', visible: %s",
 
543
            w, w->screen()->handle(), input, mSurface.get(), qPrintable(window()->title()), roleFor(window()), w->isVisible() ? "true" : "false");
500
544
}
501
545
 
502
546
UbuntuWindow::~UbuntuWindow()
517
561
    // updated size but it still needs re-rendering so another redraw may be needed.
518
562
    // A mir API to drop the currently held buffer would help here, so that we wouldn't have to redraw twice
519
563
    auto const numRepaints = mSurface->needsRepaint();
 
564
    lock.unlock();
520
565
    qCDebug(ubuntumirclient, "handleSurfaceResize(window=%p) redraw %d times", window(), numRepaints);
521
566
    for (int i = 0; i < numRepaints; i++) {
522
567
        qCDebug(ubuntumirclient, "handleSurfaceResize(window=%p) repainting width=%d, height=%d", window(), geometry().size().width(), geometry().size().height());
541
586
{
542
587
    QMutexLocker lock(&mMutex);
543
588
    qCDebug(ubuntumirclient, "setWindowState(window=%p, %s)", this, qtWindowStateToStr(state));
544
 
    mSurface->setState(state);
545
 
 
546
 
    updatePanelHeightHack(state);
 
589
 
 
590
    if (mWindowState == state) return;
 
591
    mWindowState = state;
 
592
 
 
593
    lock.unlock();
 
594
    updateSurfaceState();
 
595
}
 
596
 
 
597
void UbuntuWindow::setWindowFlags(Qt::WindowFlags flags)
 
598
{
 
599
    QMutexLocker lock(&mMutex);
 
600
    qCDebug(ubuntumirclient, "setWindowFlags(window=%p, %d)", this, flags);
 
601
 
 
602
    if (mWindowFlags == flags) return;
 
603
    mWindowFlags = flags;
 
604
 
 
605
    lock.unlock();
 
606
    updateSurfaceState();
547
607
}
548
608
 
549
609
/*
552
612
    window is always on the top-left corner, right below the indicators panel if not
553
613
    in fullscreen.
554
614
 */
555
 
void UbuntuWindow::updatePanelHeightHack(Qt::WindowState state)
 
615
void UbuntuWindow::enablePanelHeightHack(bool enable)
556
616
{
557
 
    if (state == Qt::WindowFullScreen && geometry().y() != 0) {
558
 
        QRect newGeometry = geometry();
 
617
    QMutexLocker lock(&mMutex);
 
618
 
 
619
    QRect newGeometry = geometry();
 
620
    if (enable) {
 
621
        newGeometry.setY(panelHeight());
 
622
    } else {
559
623
        newGeometry.setY(0);
560
 
        QPlatformWindow::setGeometry(newGeometry);
561
 
        QWindowSystemInterface::handleGeometryChange(window(), newGeometry);
562
 
    } else if (geometry().y() == 0) {
563
 
        QRect newGeometry = geometry();
564
 
        newGeometry.setY(panelHeight());
 
624
    }
 
625
 
 
626
    if (newGeometry != geometry()) {
 
627
        lock.unlock();
565
628
        QPlatformWindow::setGeometry(newGeometry);
566
629
        QWindowSystemInterface::handleGeometryChange(window(), newGeometry);
567
630
    }
587
650
    QMutexLocker lock(&mMutex);
588
651
    qCDebug(ubuntumirclient, "setVisible (window=%p, visible=%s)", window(), visible ? "true" : "false");
589
652
 
590
 
    mSurface->setVisible(visible);
591
 
    const QRect& exposeRect = visible ? QRect(QPoint(), geometry().size()) : QRect();
 
653
    if (mWindowVisible == visible) return;
 
654
    mWindowVisible = visible;
 
655
    if (mWindowVisible) mSurface->updateSurface();
592
656
 
593
657
    lock.unlock();
 
658
    updateSurfaceState();
 
659
    const QRect& exposeRect = mWindowVisible ? QRect(QPoint(), geometry().size()) : QRect();
594
660
    QWindowSystemInterface::handleExposeEvent(window(), exposeRect);
595
661
    QWindowSystemInterface::flushWindowSystemEvents();
596
662
}
613
679
    mSurface->setSizingConstraints(win->minimumSize(), win->maximumSize(), win->sizeIncrement());
614
680
}
615
681
 
 
682
bool UbuntuWindow::isExposed() const
 
683
{
 
684
    return mWindowVisible;
 
685
}
 
686
 
616
687
void* UbuntuWindow::eglSurface() const
617
688
{
618
689
    return mSurface->eglSurface();
633
704
    QMutexLocker lock(&mMutex);
634
705
    mSurface->onSwapBuffersDone();
635
706
}
 
707
 
 
708
void UbuntuWindow::handleScreenPropertiesChange(MirFormFactor formFactor)
 
709
{
 
710
    qCDebug(ubuntumirclient, "handleScreenPropertiesChange (window=%p, formFactor=%s)", window(), mirFormFactorToStr(formFactor));
 
711
 
 
712
    // Update the form factor native-interface properties for the windows affected
 
713
    // as there is no convenient way to emit signals for those custom properties on a QScreen
 
714
    if (formFactor != mFormFactor) {
 
715
        mFormFactor = formFactor;
 
716
        updateSurfaceState();
 
717
 
 
718
        Q_EMIT mNativeInterface->windowPropertyChanged(this, QStringLiteral("formFactor"));
 
719
    }
 
720
}
 
721
 
 
722
void UbuntuWindow::updateSurfaceState()
 
723
{
 
724
    QMutexLocker lock(&mMutex);
 
725
    MirSurfaceState newState = surfaceStateFromWindowProperties(mFormFactor,
 
726
                                                                mWindowState,
 
727
                                                                mWindowFlags,
 
728
                                                                mWindowVisible);
 
729
    qCDebug(ubuntumirclient, "updateSurfaceState (window=%p, surfaceState=%s)", window(), mirSurfaceStateToStr(newState));
 
730
    if (newState != mSurface->state()) {
 
731
        mSurface->setState(newState);
 
732
 
 
733
        lock.unlock();
 
734
        enablePanelHeightHack(newState != mir_surface_state_fullscreen &&
 
735
                              mSurface->type() != mir_surface_type_inputmethod);
 
736
    }
 
737
}