~nick-dedekind/qtubuntu/occlusion-2.0

« back to all changes in this revision

Viewing changes to src/ubuntumirclient/screenobserver.cpp

  • Committer: CI Train Bot
  • Author(s): daniel.dandrada at canonical, Daniel d'Andrada, Nick Dedekind, Gerry Boland, Michał Sawicz
  • Date: 2016-04-28 15:36:07 UTC
  • mfrom: (304.2.42 screen-info-without-dpr)
  • Revision ID: ci-train-bot@canonical.com-20160428153607-oovixgesc0ogfeoi
Proper support for multiple screens and dynamic scaling support Fixes: #1534682, #1573532
Approved by: Nick Dedekind, Unity8 CI Bot, Daniel d'Andrada, Gerry Boland

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 "screenobserver.h"
 
18
#include "screen.h"
 
19
#include "window.h"
 
20
#include "logging.h"
 
21
 
 
22
// Qt
 
23
#include <QMetaObject>
 
24
#include <QPointer>
 
25
 
 
26
// Mir
 
27
#include <mirclient/mir_toolkit/mir_connection.h>
 
28
#include <mirclient/mir_toolkit/mir_display_configuration.h>
 
29
 
 
30
#include <memory>
 
31
 
 
32
namespace {
 
33
    static void displayConfigurationChangedCallback(MirConnection */*connection*/, void* context)
 
34
    {
 
35
        ASSERT(context != NULL);
 
36
        UbuntuScreenObserver *observer = static_cast<UbuntuScreenObserver *>(context);
 
37
        QMetaObject::invokeMethod(observer, "update");
 
38
    }
 
39
 
 
40
    const char *mirFormFactorToStr(MirFormFactor formFactor)
 
41
    {
 
42
        switch (formFactor) {
 
43
        case mir_form_factor_unknown: return "unknown";
 
44
        case mir_form_factor_phone: return "phone";
 
45
        case mir_form_factor_tablet: return "tablet";
 
46
        case mir_form_factor_monitor: return "monitor";
 
47
        case mir_form_factor_tv: return "tv";
 
48
        case mir_form_factor_projector: return "projector";
 
49
        }
 
50
        return "";
 
51
    }
 
52
} // anonymous namespace
 
53
 
 
54
UbuntuScreenObserver::UbuntuScreenObserver(MirConnection *mirConnection)
 
55
    : mMirConnection(mirConnection)
 
56
{
 
57
    mir_connection_set_display_config_change_callback(mirConnection, ::displayConfigurationChangedCallback, this);
 
58
    update();
 
59
}
 
60
 
 
61
void UbuntuScreenObserver::update()
 
62
{
 
63
    // Wrap MirDisplayConfiguration to always delete when out of scope
 
64
    auto configDeleter = [](MirDisplayConfig *config) { mir_display_config_release(config); };
 
65
    using configUp = std::unique_ptr<MirDisplayConfig, decltype(configDeleter)>;
 
66
    configUp displayConfig(mir_connection_create_display_configuration(mMirConnection), configDeleter);
 
67
 
 
68
    // Mir only tells us something changed, it is up to us to figure out what.
 
69
    QList<UbuntuScreen*> newScreenList;
 
70
    QList<UbuntuScreen*> oldScreenList = mScreenList;
 
71
    mScreenList.clear();
 
72
 
 
73
    for (int i = 0; i < mir_display_config_get_num_outputs(displayConfig.get()); i++) {
 
74
        const MirOutput *output = mir_display_config_get_output(displayConfig.get(), i);
 
75
        if (mir_output_is_enabled(output)) {
 
76
            UbuntuScreen *screen = findScreenWithId(oldScreenList, mir_output_get_id(output));
 
77
            if (screen) { // we've already set up this display before
 
78
                screen->updateMirOutput(output);
 
79
                oldScreenList.removeAll(screen);
 
80
            } else {
 
81
                // new display, so create UbuntuScreen for it
 
82
                screen = new UbuntuScreen(output, mMirConnection);
 
83
                newScreenList.append(screen);
 
84
                qCDebug(ubuntumirclient) << "Added Screen with id" << mir_output_get_id(output)
 
85
                                         << "and geometry" << screen->geometry();
 
86
            }
 
87
            mScreenList.append(screen);
 
88
        }
 
89
    }
 
90
 
 
91
    // Announce old & unused Screens, should be deleted by the slot
 
92
    Q_FOREACH (const auto screen, oldScreenList) {
 
93
        Q_EMIT screenRemoved(screen);
 
94
    }
 
95
 
 
96
    /*
 
97
     * Mir's MirDisplayOutput does not include formFactor or scale for some reason, but Qt
 
98
     * will want that information on creating the QScreen. Only way we get that info is when
 
99
     * Mir positions a Window on that Screen. See "handleScreenPropertiesChange" method
 
100
     */
 
101
 
 
102
    // Announce new Screens
 
103
    Q_FOREACH (const auto screen, newScreenList) {
 
104
        Q_EMIT screenAdded(screen);
 
105
    }
 
106
 
 
107
    qCDebug(ubuntumirclient) << "=======================================";
 
108
    for (auto screen: mScreenList) {
 
109
        qCDebug(ubuntumirclient) << screen << "- id:" << screen->mirOutputId()
 
110
                                 << "geometry:" << screen->geometry()
 
111
                                 << "form factor:" << mirFormFactorToStr(screen->formFactor())
 
112
                                 << "scale:" << screen->scale();
 
113
    }
 
114
    qCDebug(ubuntumirclient) << "=======================================";
 
115
}
 
116
 
 
117
UbuntuScreen *UbuntuScreenObserver::findScreenWithId(int id)
 
118
{
 
119
    return findScreenWithId(mScreenList, id);
 
120
}
 
121
 
 
122
UbuntuScreen *UbuntuScreenObserver::findScreenWithId(const QList<UbuntuScreen *> &list, int id)
 
123
{
 
124
    Q_FOREACH (const auto screen, list) {
 
125
        if (screen->mirOutputId() == id) {
 
126
            return screen;
 
127
        }
 
128
    }
 
129
    return nullptr;
 
130
}
 
131
 
 
132
void UbuntuScreenObserver::handleScreenPropertiesChange(UbuntuScreen *screen, int dpi,
 
133
                                                        MirFormFactor formFactor, float scale)
 
134
{
 
135
    screen->setAdditionalMirDisplayProperties(scale, formFactor, dpi);
 
136
}
 
137