1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (info@qt.nokia.com)
7 ** This file is part of the plugins of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qwindowscursor.h"
43 #include "qwindowscontext.h"
44 #include "qwindowswindow.h"
45 #include "qwindowsscreen.h"
46 #include "pixmaputils.h"
48 #include <QtGui/QPixmap>
49 #include <QtGui/QImage>
50 #include <QtGui/QBitmap>
51 #include <QtGui/QGuiApplication>
52 #include <QtGui/QScreen>
53 #include <QtGui/private/qguiapplication_p.h> // getPixmapCursor()
55 #include <QtCore/QDebug>
56 #include <QtCore/QScopedArrayPointer>
62 \brief Platform cursor implementation
64 Note that whereas under X11, a cursor can be set as a property of
65 a window, there is only a global SetCursor() function on Windows.
66 Each Window sets on the global cursor on receiving a Enter-event
67 as do the Window manager frames (resize/move handles).
69 \ingroup qt-lighthouse-win
70 \sa QWindowsWindowCursor
73 QWindowsCursor::QWindowsCursor(QPlatformScreen *s) :
78 HCURSOR QWindowsCursor::createPixmapCursor(const QPixmap &pixmap, int hotX, int hotY)
81 QBitmap mask = pixmap.mask();
83 mask = QBitmap(pixmap.size());
84 mask.fill(Qt::color1);
87 HBITMAP ic = qPixmapToWinHBITMAP(pixmap, HBitmapAlpha);
88 const HBITMAP im = createIconMask(mask);
97 cur = CreateIconIndirect(&ii);
104 HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c)
106 int hx = c.hotSpot().x();
107 int hy = c.hotSpot().y();
108 const Qt::CursorShape cshape = c.shape();
109 if (cshape == Qt::BitmapCursor) {
110 const QPixmap pixmap = c.pixmap();
111 if (!pixmap.isNull())
112 if (const HCURSOR hc = createPixmapCursor(pixmap, hx, hy))
116 // Non-standard Windows cursors are created from bitmaps
118 static const uchar vsplit_bits[] = {
119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00,
122 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
123 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00,
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00,
125 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
126 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00,
127 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
128 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
130 static const uchar vsplitm_bits[] = {
131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
133 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x07, 0x00,
134 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
135 0x00, 0xc0, 0x01, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00,
136 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00,
137 0x80, 0xff, 0xff, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
138 0x00, 0xc0, 0x01, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00,
139 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
140 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
142 static const uchar hsplit_bits[] = {
143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
146 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
147 0x00, 0x41, 0x82, 0x00, 0x80, 0x41, 0x82, 0x01, 0xc0, 0x7f, 0xfe, 0x03,
148 0x80, 0x41, 0x82, 0x01, 0x00, 0x41, 0x82, 0x00, 0x00, 0x40, 0x02, 0x00,
149 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
150 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
154 static const uchar hsplitm_bits[] = {
155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
157 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
158 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe3, 0xc7, 0x00,
159 0x80, 0xe3, 0xc7, 0x01, 0xc0, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x07,
160 0xc0, 0xff, 0xff, 0x03, 0x80, 0xe3, 0xc7, 0x01, 0x00, 0xe3, 0xc7, 0x00,
161 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
162 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
163 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
164 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
166 static const uchar phand_bits[] = {
167 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00,
168 0x80, 0x04, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00,
169 0x80, 0x1c, 0x00, 0x00, 0x80, 0xe4, 0x00, 0x00, 0x80, 0x24, 0x03, 0x00,
170 0x80, 0x24, 0x05, 0x00, 0xb8, 0x24, 0x09, 0x00, 0xc8, 0x00, 0x09, 0x00,
171 0x88, 0x00, 0x08, 0x00, 0x90, 0x00, 0x08, 0x00, 0xa0, 0x00, 0x08, 0x00,
172 0x20, 0x00, 0x08, 0x00, 0x40, 0x00, 0x08, 0x00, 0x40, 0x00, 0x04, 0x00,
173 0x80, 0x00, 0x04, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x01, 0x02, 0x00,
174 0x00, 0x01, 0x02, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
177 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
179 static const uchar phandm_bits[] = {
180 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00,
181 0x80, 0x07, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00,
182 0x80, 0x1f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x80, 0xff, 0x03, 0x00,
183 0x80, 0xff, 0x07, 0x00, 0xb8, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x0f, 0x00,
184 0xf8, 0xff, 0x0f, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0x0f, 0x00,
185 0xe0, 0xff, 0x0f, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0xc0, 0xff, 0x07, 0x00,
186 0x80, 0xff, 0x07, 0x00, 0x80, 0xff, 0x07, 0x00, 0x00, 0xff, 0x03, 0x00,
187 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
188 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
189 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
190 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
192 static const uchar openhand_bits[] = {
193 0x80,0x01,0x58,0x0e,0x64,0x12,0x64,0x52,0x48,0xb2,0x48,0x92,
194 0x16,0x90,0x19,0x80,0x11,0x40,0x02,0x40,0x04,0x40,0x04,0x20,
195 0x08,0x20,0x10,0x10,0x20,0x10,0x00,0x00};
196 static const uchar openhandm_bits[] = {
197 0x80,0x01,0xd8,0x0f,0xfc,0x1f,0xfc,0x5f,0xf8,0xff,0xf8,0xff,
198 0xf6,0xff,0xff,0xff,0xff,0x7f,0xfe,0x7f,0xfc,0x7f,0xfc,0x3f,
199 0xf8,0x3f,0xf0,0x1f,0xe0,0x1f,0x00,0x00};
200 static const uchar closedhand_bits[] = {
201 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0x48,0x32,0x08,0x50,
202 0x10,0x40,0x18,0x40,0x04,0x40,0x04,0x20,0x08,0x20,0x10,0x10,
203 0x20,0x10,0x20,0x10,0x00,0x00,0x00,0x00};
204 static const uchar closedhandm_bits[] = {
205 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0xf8,0x3f,0xf8,0x7f,
206 0xf0,0x7f,0xf8,0x7f,0xfc,0x7f,0xfc,0x3f,0xf8,0x3f,0xf0,0x1f,
207 0xe0,0x1f,0xe0,0x1f,0x00,0x00,0x00,0x00};
209 static const uchar * const cursor_bits32[] = {
210 vsplit_bits, vsplitm_bits, hsplit_bits, hsplitm_bits,
211 phand_bits, phandm_bits
215 switch (c.shape()) { // map to windows cursor
216 case Qt::ArrowCursor:
219 case Qt::UpArrowCursor:
222 case Qt::CrossCursor:
228 case Qt::IBeamCursor:
231 case Qt::SizeVerCursor:
234 case Qt::SizeHorCursor:
237 case Qt::SizeBDiagCursor:
240 case Qt::SizeFDiagCursor:
243 case Qt::SizeAllCursor:
246 case Qt::ForbiddenCursor:
249 case Qt::WhatsThisCursor:
253 sh = IDC_APPSTARTING;
255 case Qt::PointingHandCursor:
258 case Qt::BlankCursor:
259 case Qt::SplitVCursor:
260 case Qt::SplitHCursor:
261 case Qt::OpenHandCursor:
262 case Qt::ClosedHandCursor:
263 case Qt::BitmapCursor: {
266 if (cshape == Qt::BlankCursor) {
267 bbits = QImage(32, 32, QImage::Format_Mono);
268 bbits.fill(0); // ignore color table
269 mbits = bbits.copy();
272 } else if (cshape == Qt::OpenHandCursor || cshape == Qt::ClosedHandCursor) {
273 bool open = cshape == Qt::OpenHandCursor;
274 QBitmap cb = QBitmap::fromData(QSize(16, 16), open ? openhand_bits : closedhand_bits);
275 QBitmap cm = QBitmap::fromData(QSize(16, 16), open ? openhandm_bits : closedhandm_bits);
276 bbits = cb.toImage().convertToFormat(QImage::Format_Mono);
277 mbits = cm.toImage().convertToFormat(QImage::Format_Mono);
280 } else if (cshape != Qt::BitmapCursor) {
281 int i = cshape - Qt::SplitVCursor;
282 QBitmap cb = QBitmap::fromData(QSize(32, 32), cursor_bits32[i * 2]);
283 QBitmap cm = QBitmap::fromData(QSize(32, 32), cursor_bits32[i * 2 + 1]);
284 bbits = cb.toImage().convertToFormat(QImage::Format_Mono);
285 mbits = cm.toImage().convertToFormat(QImage::Format_Mono);
286 if (cshape == Qt::PointingHandCursor) {
293 bbits = c.bitmap()->toImage().convertToFormat(QImage::Format_Mono);
294 mbits = c.mask()->toImage().convertToFormat(QImage::Format_Mono);
295 invb = bbits.colorCount() > 1 && qGray(bbits.color(0)) < qGray(bbits.color(1));
296 invm = mbits.colorCount() > 1 && qGray(mbits.color(0)) < qGray(mbits.color(1));
298 const int n = qMax(1, bbits.width() / 8);
299 const int h = bbits.height();
300 QScopedArrayPointer<uchar> xBits(new uchar[h * n]);
301 QScopedArrayPointer<uchar> xMask(new uchar[h * n]);
303 for (int i = 0; i < h; ++i) {
304 uchar *bits = bbits.scanLine(i);
305 uchar *mask = mbits.scanLine(i);
306 for (int j = 0; j < n; ++j) {
318 return CreateCursor(GetModuleHandle(0), hx, hy, bbits.width(), bbits.height(),
319 xBits.data(), xMask.data());
321 case Qt::DragCopyCursor:
322 case Qt::DragMoveCursor:
323 case Qt::DragLinkCursor: {
324 const QPixmap pixmap = QGuiApplicationPrivate::instance()->getPixmapCursor(cshape);
325 return createPixmapCursor(pixmap, hx, hy);
328 qWarning("%s: Invalid cursor shape %d", __FUNCTION__, cshape);
331 return (HCURSOR)LoadImage(0, sh, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
335 \brief Return cached standard cursor resources or create new ones.
338 QWindowsWindowCursor QWindowsCursor::standardWindowCursor(Qt::CursorShape shape)
340 StandardCursorCache::iterator it = m_standardCursorCache.find(shape);
341 if (it == m_standardCursorCache.end())
342 it = m_standardCursorCache.insert(shape, QWindowsWindowCursor(QCursor(shape)));
347 \brief Set a cursor on a window.
349 This is called frequently as the mouse moves over widgets in the window
353 void QWindowsCursor::changeCursor(QCursor *cursorIn, QWindow *window)
356 if (QWindowsContext::verboseWindows)
357 qDebug() << __FUNCTION__ << cursorIn << window;
358 if (!cursorIn || !window)
360 const QWindowsWindowCursor wcursor =
361 cursorIn->shape() == Qt::BitmapCursor ?
362 QWindowsWindowCursor(*cursorIn) : standardWindowCursor(cursorIn->shape());
363 if (wcursor.handle()) {
364 QWindowsWindow::baseWindowOf(window)->setCursor(wcursor);
366 qWarning("%s: Unable to obtain system cursor for %d",
367 __FUNCTION__, cursorIn->shape());
371 QPoint QWindowsCursor::mousePosition()
375 if (QWindowsContext::verboseWindows)
376 qDebug("%s %ld,%ld", __FUNCTION__, p.x, p.y);
377 return QPoint(p.x, p.y);
380 void QWindowsCursor::setPos(const QPoint &pos)
382 if (QWindowsContext::verboseWindows)
383 qDebug("%s %d,%d", __FUNCTION__, pos.x(), pos.y());
384 SetCursorPos(pos.x(), pos.y());
388 \class QWindowsWindowCursor
389 \brief Per-Window cursor. Contains a QCursor and manages its associated system
390 cursor handle resource.
392 Based on QSharedDataPointer, so that it can be passed around and
393 used as a property of QWindowsBaseWindow.
395 \ingroup qt-lighthouse-win
399 class QWindowsWindowCursorData : public QSharedData
402 explicit QWindowsWindowCursorData(const QCursor &c);
403 ~QWindowsWindowCursorData();
405 const QCursor m_cursor;
406 const HCURSOR m_handle;
409 QWindowsWindowCursorData::QWindowsWindowCursorData(const QCursor &c) :
411 m_handle(QWindowsCursor::createSystemCursor(c))
415 QWindowsWindowCursorData::~QWindowsWindowCursorData()
417 DestroyCursor(m_handle);
420 QWindowsWindowCursor::QWindowsWindowCursor(const QCursor &c) :
421 m_data(new QWindowsWindowCursorData(c))
425 QWindowsWindowCursor::~QWindowsWindowCursor()
429 QWindowsWindowCursor::QWindowsWindowCursor(const QWindowsWindowCursor &rhs) :
434 QWindowsWindowCursor & QWindowsWindowCursor::operator =(const QWindowsWindowCursor &rhs)
437 m_data.operator =(rhs.m_data);
441 QCursor QWindowsWindowCursor::cursor() const
443 return m_data->m_cursor;
446 HCURSOR QWindowsWindowCursor::handle() const
448 return m_data->m_handle;