Follow protocol changes in pointer attach
[profile/ivi/qtwayland.git] / src / plugins / platforms / wayland / qwaylandcursor.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qwaylandcursor.h"
43
44 #include "qwaylanddisplay.h"
45 #include "qwaylandinputdevice.h"
46 #include "qwaylandscreen.h"
47 #include "qwaylandshmbackingstore.h"
48
49 #include <QtGui/QImageReader>
50 #include <QDebug>
51
52 #define DATADIR "/usr/share"
53
54 static const struct pointer_image {
55     const char *filename;
56     int hotspot_x, hotspot_y;
57 } pointer_images[] = {
58     /* FIXME: Half of these are wrong... */
59     /* Qt::ArrowCursor */
60     { DATADIR "/wayland/left_ptr.png",                  10,  5 },
61     /* Qt::UpArrowCursor */
62     { DATADIR "/wayland/top_side.png",                  18,  8 },
63     /* Qt::CrossCursor */
64     { DATADIR "/wayland/top_side.png",                  18,  8 },
65     /* Qt::WaitCursor */
66     { DATADIR "/wayland/top_side.png",                  18,  8 },
67     /* Qt::IBeamCursor */
68     { DATADIR "/wayland/xterm.png",                     15, 15 },
69     /* Qt::SizeVerCursor */
70     { DATADIR "/wayland/top_side.png",                  18,  8 },
71     /* Qt::SizeHorCursor */
72     { DATADIR "/wayland/bottom_left_corner.png",         6, 30 },
73     /* Qt::SizeBDiagCursor */
74     { DATADIR "/wayland/bottom_right_corner.png",       28, 28 },
75     /* Qt::SizeFDiagCursor */
76     { DATADIR "/wayland/bottom_side.png",               16, 20 },
77     /* Qt::SizeAllCursor */
78     { DATADIR "/wayland/left_side.png",                 10, 20 },
79     /* Qt::BlankCursor */
80     { DATADIR "/wayland/right_side.png",                30, 19 },
81     /* Qt::SplitVCursor */
82     { DATADIR "/wayland/sb_v_double_arrow.png",         15, 15 },
83     /* Qt::SplitHCursor */
84     { DATADIR "/wayland/sb_h_double_arrow.png",         15, 15 },
85     /* Qt::PointingHandCursor */
86     { DATADIR "/wayland/hand2.png",                     14,  8 },
87     /* Qt::ForbiddenCursor */
88     { DATADIR "/wayland/top_right_corner.png",          26,  8 },
89     /* Qt::WhatsThisCursor */
90     { DATADIR "/wayland/top_right_corner.png",          26,  8 },
91     /* Qt::BusyCursor */
92     { DATADIR "/wayland/top_right_corner.png",          26,  8 },
93     /* Qt::OpenHandCursor */
94     { DATADIR "/wayland/hand1.png",                     18, 11 },
95     /* Qt::ClosedHandCursor */
96     { DATADIR "/wayland/grabbing.png",                  20, 17 },
97     /* Qt::DragCopyCursor */
98     { DATADIR "/wayland/dnd-copy.png",                  13, 13 },
99     /* Qt::DragMoveCursor */
100     { DATADIR "/wayland/dnd-move.png",                  13, 13 },
101     /* Qt::DragLinkCursor */
102     { DATADIR "/wayland/dnd-link.png",                  13, 13 },
103 };
104
105 QWaylandCursor::QWaylandCursor(QWaylandScreen *screen)
106     : mBuffer(0)
107     , mDisplay(screen->display())
108     , mSurface(0)
109 {
110 }
111
112 QWaylandCursor::~QWaylandCursor()
113 {
114     if (mSurface)
115         wl_surface_destroy(mSurface);
116
117     delete mBuffer;
118 }
119
120 void QWaylandCursor::ensureSurface(const QSize &size)
121 {
122     if (!mBuffer || mBuffer->size() != size) {
123         delete mBuffer;
124         mBuffer = new QWaylandShmBuffer(mDisplay, size,
125                                         QImage::Format_ARGB32);
126     }
127
128     if (!mSurface)
129         mSurface = mDisplay->createSurface(0);
130
131     wl_surface_attach(mSurface, mBuffer->buffer(), 0, 0);
132 }
133
134 void QWaylandCursor::changeCursor(QCursor *cursor, QWindow *window)
135 {
136     const struct pointer_image *p;
137
138     if (window == NULL)
139         return;
140
141     p = NULL;
142     bool isBitmap = false;
143
144     switch (cursor->shape()) {
145     case Qt::ArrowCursor:
146         p = &pointer_images[cursor->shape()];
147         break;
148     case Qt::UpArrowCursor:
149     case Qt::CrossCursor:
150     case Qt::WaitCursor:
151         break;
152     case Qt::IBeamCursor:
153         p = &pointer_images[cursor->shape()];
154         break;
155     case Qt::SizeVerCursor:     /* 5 */
156     case Qt::SizeHorCursor:
157     case Qt::SizeBDiagCursor:
158     case Qt::SizeFDiagCursor:
159     case Qt::SizeAllCursor:
160     case Qt::BlankCursor:       /* 10 */
161         break;
162     case Qt::SplitVCursor:
163     case Qt::SplitHCursor:
164     case Qt::PointingHandCursor:
165         p = &pointer_images[cursor->shape()];
166         break;
167     case Qt::ForbiddenCursor:
168     case Qt::WhatsThisCursor:   /* 15 */
169     case Qt::BusyCursor:
170         break;
171     case Qt::OpenHandCursor:
172     case Qt::ClosedHandCursor:
173     case Qt::DragCopyCursor:
174     case Qt::DragMoveCursor: /* 20 */
175     case Qt::DragLinkCursor:
176         p = &pointer_images[cursor->shape()];
177         break;
178
179     case Qt::BitmapCursor:
180         isBitmap = true;
181         break;
182
183     default:
184         break;
185     }
186
187     if (!p && !isBitmap) {
188         p = &pointer_images[0];
189         qWarning("unhandled cursor %d", cursor->shape());
190     }
191
192     if (isBitmap && !cursor->pixmap().isNull()) {
193         setupPixmapCursor(cursor);
194     } else if (isBitmap && cursor->bitmap()) {
195         qWarning("unsupported QBitmap cursor");
196     } else {
197         QImageReader reader(p->filename);
198         if (!reader.canRead())
199             return;
200         ensureSurface(reader.size());
201         reader.read(mBuffer->image());
202         mDisplay->setCursor(mSurface, p->hotspot_x, p->hotspot_y);
203     }
204 }
205
206 void QWaylandCursor::setupPixmapCursor(QCursor *cursor)
207 {
208     if (!cursor) {
209         delete mBuffer;
210         mBuffer = 0;
211         return;
212     }
213     ensureSurface(cursor->pixmap().size());
214     QImage src = cursor->pixmap().toImage().convertToFormat(QImage::Format_ARGB32);
215     for (int y = 0; y < src.height(); ++y)
216         qMemCopy(mBuffer->image()->scanLine(y), src.scanLine(y), src.bytesPerLine());
217     mDisplay->setCursor(mSurface, cursor->hotSpot().x(), cursor->hotSpot().y());
218 }
219
220 void QWaylandDisplay::setCursor(wl_surface *surface, int32_t x, int32_t y)
221 {
222     /* Qt doesn't tell us which input device we should set the cursor
223      * for, so set it for all devices. */
224     for (int i = 0; i < mInputDevices.count(); i++) {
225         QWaylandInputDevice *inputDevice = mInputDevices.at(i);
226         inputDevice->setCursor(surface, x, y);
227     }
228 }
229
230 void QWaylandCursor::pointerEvent(const QMouseEvent &event)
231 {
232     mLastPos = event.globalPos();
233 }
234
235 QPoint QWaylandCursor::pos() const
236 {
237     return mLastPos;
238 }
239
240 void QWaylandCursor::setPos(const QPoint &pos)
241 {
242     Q_UNUSED(pos);
243     qWarning() << "QWaylandCursor::setPos: not implemented";
244 }