~lukas-kde/miral/shellchrome-windowinfo

« back to all changes in this revision

Viewing changes to miral-qt/src/platforms/mirserver/surfaceobserver.cpp

  • Committer: Larry Price
  • Date: 2016-09-13 16:19:29 UTC
  • mto: (330.4.1 miral)
  • mto: This revision was merged to the branch mainline in revision 352.
  • Revision ID: larry.price@canonical.com-20160913161929-vs9ka1capmljq1es
Removing miral-qt from release branch, updating copyright file, and adding GPL3 license to root dir

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2014-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 "surfaceobserver.h"
18
 
 
19
 
#include "namedcursor.h"
20
 
#include "logging.h"
21
 
 
22
 
#include <QImage>
23
 
#include <QMetaObject>
24
 
#include <QMutableMapIterator>
25
 
#include <QMutexLocker>
26
 
#include <QPixmap>
27
 
 
28
 
#include <mir/geometry/size.h>
29
 
#include <mir/shell/surface_specification.h>
30
 
 
31
 
 
32
 
namespace {
33
 
 
34
 
QRect calculateBoundingRect(const std::vector<mir::geometry::Rectangle> &rectVector)
35
 
{
36
 
    QRect boundingRect;
37
 
    for (auto mirRect : rectVector) {
38
 
        boundingRect |= QRect(mirRect.top_left.x.as_int(),
39
 
                mirRect.top_left.y.as_int(),
40
 
                mirRect.size.width.as_int(),
41
 
                mirRect.size.height.as_int());
42
 
    }
43
 
    return boundingRect;
44
 
}
45
 
 
46
 
} // anonymous namespace
47
 
 
48
 
QHash<const mir::scene::Surface*, SurfaceObserver*> SurfaceObserver::m_surfaceToObserverMap;
49
 
QMutex SurfaceObserver::mutex;
50
 
 
51
 
SurfaceObserver::SurfaceObserver()
52
 
    : m_listener(nullptr)
53
 
    , m_framesPosted(false)
54
 
{
55
 
    m_cursorNameToShape["left_ptr"] = Qt::ArrowCursor;
56
 
    m_cursorNameToShape["up_arrow"] = Qt::UpArrowCursor;
57
 
    m_cursorNameToShape["cross"] = Qt::CrossCursor;
58
 
    m_cursorNameToShape["watch"] = Qt::WaitCursor;
59
 
    m_cursorNameToShape["xterm"] = Qt::IBeamCursor;
60
 
    m_cursorNameToShape["size_ver"] = Qt::SizeVerCursor;
61
 
    m_cursorNameToShape["size_hor"] = Qt::SizeHorCursor;
62
 
    m_cursorNameToShape["size_bdiag"] = Qt::SizeBDiagCursor;
63
 
    m_cursorNameToShape["size_fdiag"] = Qt::SizeFDiagCursor;
64
 
    m_cursorNameToShape["size_all"] = Qt::SizeAllCursor;
65
 
    m_cursorNameToShape["blank"] = Qt::BlankCursor;
66
 
    m_cursorNameToShape["split_v"] = Qt::SplitVCursor;
67
 
    m_cursorNameToShape["split_h"] = Qt::SplitHCursor;
68
 
    m_cursorNameToShape["hand"] = Qt::PointingHandCursor;
69
 
    m_cursorNameToShape["forbidden"] = Qt::ForbiddenCursor;
70
 
    m_cursorNameToShape["whats_this"] = Qt::WhatsThisCursor;
71
 
    m_cursorNameToShape["left_ptr_watch"] = Qt::BusyCursor;
72
 
    m_cursorNameToShape["openhand"] = Qt::OpenHandCursor;
73
 
    m_cursorNameToShape["closedhand"] = Qt::ClosedHandCursor;
74
 
    m_cursorNameToShape["dnd-copy"] = Qt::DragCopyCursor;
75
 
    m_cursorNameToShape["dnd-move"] = Qt::DragMoveCursor;
76
 
    m_cursorNameToShape["dnd-link"] = Qt::DragLinkCursor;
77
 
 
78
 
    // Used by Mir client API (mir_*_cursor_name strings)
79
 
    m_cursorNameToShape["default"] = Qt::ArrowCursor;
80
 
    m_cursorNameToShape["disabled"] = Qt::BlankCursor;
81
 
    m_cursorNameToShape["arrow"] = Qt::ArrowCursor;
82
 
    m_cursorNameToShape["busy"] = Qt::WaitCursor;
83
 
    m_cursorNameToShape["caret"] = Qt::IBeamCursor;
84
 
    m_cursorNameToShape["pointing-hand"] = Qt::PointingHandCursor;
85
 
    m_cursorNameToShape["open-hand"] = Qt::OpenHandCursor;
86
 
    m_cursorNameToShape["closed-hand"] = Qt::ClosedHandCursor;
87
 
    m_cursorNameToShape["horizontal-resize"] = Qt::SizeHorCursor;
88
 
    m_cursorNameToShape["vertical-resize"] = Qt::SizeVerCursor;
89
 
    m_cursorNameToShape["diagonal-resize-bottom-to-top"] = Qt::SizeBDiagCursor;
90
 
    m_cursorNameToShape["diagonal-resize-top_to_bottom"] = Qt::SizeFDiagCursor; // current string with typo
91
 
    m_cursorNameToShape["diagonal-resize-top-to-bottom"] = Qt::SizeFDiagCursor; // how it will be when they fix it (if ever)
92
 
    m_cursorNameToShape["omnidirectional-resize"] = Qt::SizeAllCursor;
93
 
    m_cursorNameToShape["vsplit-resize"] = Qt::SplitVCursor;
94
 
    m_cursorNameToShape["hsplit-resize"] = Qt::SplitHCursor;
95
 
    m_cursorNameToShape["crosshair"] = Qt::CrossCursor;
96
 
 
97
 
    qRegisterMetaType<MirShellChrome>("MirShellChrome");
98
 
}
99
 
 
100
 
SurfaceObserver::~SurfaceObserver()
101
 
{
102
 
    QMutexLocker locker(&mutex);
103
 
    QMutableHashIterator<const mir::scene::Surface*, SurfaceObserver*> i(m_surfaceToObserverMap);
104
 
    while (i.hasNext()) {
105
 
        i.next();
106
 
        if (i.value() == this) {
107
 
            i.remove();
108
 
            return;
109
 
        }
110
 
    }
111
 
}
112
 
 
113
 
void SurfaceObserver::setListener(QObject *listener)
114
 
{
115
 
    m_listener = listener;
116
 
    if (m_framesPosted) {
117
 
        Q_EMIT framesPosted();
118
 
    }
119
 
}
120
 
 
121
 
void SurfaceObserver::frame_posted(int /*frames_available*/, mir::geometry::Size const& /*size*/)
122
 
{
123
 
    m_framesPosted = true;
124
 
    if (m_listener) {
125
 
        Q_EMIT framesPosted();
126
 
    }
127
 
}
128
 
 
129
 
void SurfaceObserver::renamed(char const * name)
130
 
{
131
 
    Q_EMIT nameChanged(QString::fromUtf8(name));
132
 
}
133
 
 
134
 
void SurfaceObserver::cursor_image_removed()
135
 
{
136
 
    Q_EMIT cursorChanged(QCursor());
137
 
}
138
 
 
139
 
void SurfaceObserver::attrib_changed(MirSurfaceAttrib attribute, int value)
140
 
{
141
 
    if (m_listener) {
142
 
        Q_EMIT attributeChanged(attribute, value);
143
 
    }
144
 
}
145
 
 
146
 
void SurfaceObserver::resized_to(mir::geometry::Size const&size)
147
 
{
148
 
    Q_EMIT resized(QSize(size.width.as_int(), size.height.as_int()));
149
 
}
150
 
 
151
 
void SurfaceObserver::notifySurfaceModifications(const mir::shell::SurfaceSpecification &modifications)
152
 
{
153
 
    if (modifications.min_width.is_set()) {
154
 
        Q_EMIT minimumWidthChanged(modifications.min_width.value().as_int());
155
 
    }
156
 
    if (modifications.min_height.is_set()) {
157
 
        Q_EMIT minimumHeightChanged(modifications.min_height.value().as_int());
158
 
    }
159
 
    if (modifications.max_width.is_set()) {
160
 
        Q_EMIT maximumWidthChanged(modifications.max_width.value().as_int());
161
 
    }
162
 
    if (modifications.max_height.is_set()) {
163
 
        Q_EMIT maximumHeightChanged(modifications.max_height.value().as_int());
164
 
    }
165
 
    if (modifications.width_inc.is_set()) {
166
 
        Q_EMIT widthIncrementChanged(modifications.width_inc.value().as_int());
167
 
    }
168
 
    if (modifications.height_inc.is_set()) {
169
 
        Q_EMIT heightIncrementChanged(modifications.height_inc.value().as_int());
170
 
    }
171
 
    if (modifications.shell_chrome.is_set()) {
172
 
        Q_EMIT shellChromeChanged(modifications.shell_chrome.value());
173
 
    }
174
 
    if (modifications.input_shape.is_set()) {
175
 
        QRect qRect = calculateBoundingRect(modifications.input_shape.value());
176
 
        Q_EMIT inputBoundsChanged(qRect);
177
 
    }
178
 
}
179
 
 
180
 
SurfaceObserver *SurfaceObserver::observerForSurface(const mir::scene::Surface *surface)
181
 
{
182
 
    if (m_surfaceToObserverMap.contains(surface)) {
183
 
        return m_surfaceToObserverMap.value(surface);
184
 
    } else {
185
 
        return nullptr;
186
 
    }
187
 
}
188
 
 
189
 
void SurfaceObserver::registerObserverForSurface(SurfaceObserver *observer, const mir::scene::Surface *surface)
190
 
{
191
 
    QMutexLocker locker(&mutex);
192
 
    m_surfaceToObserverMap[surface] = observer;
193
 
}
194
 
 
195
 
void SurfaceObserver::cursor_image_set_to(const mir::graphics::CursorImage &cursorImage)
196
 
{
197
 
    QCursor qcursor = createQCursorFromMirCursorImage(cursorImage);
198
 
    Q_EMIT cursorChanged(qcursor);
199
 
}
200
 
 
201
 
void SurfaceObserver::keymap_changed(MirInputDeviceId, const std::string &, const std::string &layout,
202
 
                                     const std::string &variant, const std::string &)
203
 
{
204
 
    Q_EMIT keymapChanged(QString::fromStdString(layout), QString::fromStdString(variant));
205
 
}
206
 
 
207
 
QCursor SurfaceObserver::createQCursorFromMirCursorImage(const mir::graphics::CursorImage &cursorImage) {
208
 
    if (cursorImage.as_argb_8888() == nullptr) {
209
 
        // Must be a named cursor
210
 
        auto namedCursor = dynamic_cast<const qtmir::NamedCursor*>(&cursorImage);
211
 
        Q_ASSERT(namedCursor != nullptr);
212
 
        if (namedCursor) {
213
 
            // NB: If we need a named cursor not covered by Qt::CursorShape, we won't be able to
214
 
            //     used Qt's cursor API anymore for transmitting MirSurface's cursor image.
215
 
 
216
 
            Qt::CursorShape cursorShape = Qt::ArrowCursor;
217
 
            {
218
 
                auto iterator = m_cursorNameToShape.constFind(namedCursor->name());
219
 
                if (iterator == m_cursorNameToShape.constEnd()) {
220
 
                    qCWarning(QTMIR_SURFACES).nospace() << "SurfaceObserver: unrecognized cursor name "
221
 
                        << namedCursor->name();
222
 
                } else {
223
 
                    cursorShape = iterator.value();
224
 
                }
225
 
            }
226
 
            return QCursor(cursorShape);
227
 
        } else {
228
 
            // shouldn't happen
229
 
            return QCursor();
230
 
        }
231
 
    } else {
232
 
        QImage image((const uchar*)cursorImage.as_argb_8888(),
233
 
                cursorImage.size().width.as_int(), cursorImage.size().height.as_int(), QImage::Format_ARGB32);
234
 
 
235
 
        return QCursor(QPixmap::fromImage(image), cursorImage.hotspot().dx.as_int(), cursorImage.hotspot().dy.as_int());
236
 
    }
237
 
}