1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the plugins of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include "qwindowscursor.h"
43 #include "qwindowscontext.h"
44 #include "qwindowswindow.h"
45 #include "qwindowsscreen.h"
47 #include <QtGui/QPixmap>
48 #include <QtGui/QImage>
49 #include <QtGui/QBitmap>
50 #include <QtGui/QGuiApplication>
51 #include <QtGui/QScreen>
52 #include <QtGui/private/qguiapplication_p.h> // getPixmapCursor()
54 #include <QtCore/QDebug>
55 #include <QtCore/QScopedArrayPointer>
59 Q_GUI_EXPORT HBITMAP qt_pixmapToWinHBITMAP(const QPixmap &p, int hbitmapFormat = 0);
60 Q_GUI_EXPORT HBITMAP qt_createIconMask(const QBitmap &bitmap);
64 \brief Platform cursor implementation
66 Note that whereas under X11, a cursor can be set as a property of
67 a window, there is only a global SetCursor() function on Windows.
68 Each Window sets on the global cursor on receiving a Enter-event
69 as do the Window manager frames (resize/move handles).
71 \ingroup qt-lighthouse-win
72 \sa QWindowsWindowCursor
75 HCURSOR QWindowsCursor::createPixmapCursor(const QPixmap &pixmap, int hotX, int hotY)
78 QBitmap mask = pixmap.mask();
80 mask = QBitmap(pixmap.size());
81 mask.fill(Qt::color1);
84 HBITMAP ic = qt_pixmapToWinHBITMAP(pixmap, /* HBitmapAlpha */ 2);
85 const HBITMAP im = qt_createIconMask(mask);
94 cur = CreateIconIndirect(&ii);
101 HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c)
103 int hx = c.hotSpot().x();
104 int hy = c.hotSpot().y();
105 const Qt::CursorShape cshape = c.shape();
106 if (cshape == Qt::BitmapCursor) {
107 const QPixmap pixmap = c.pixmap();
108 if (!pixmap.isNull())
109 if (const HCURSOR hc = createPixmapCursor(pixmap, hx, hy))
113 // Non-standard Windows cursors are created from bitmaps
115 static const uchar vsplit_bits[] = {
116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 0x00, 0x80, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00,
119 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
120 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00,
121 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0x00,
122 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
123 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00,
124 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
127 static const uchar vsplitm_bits[] = {
128 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
130 0x00, 0xc0, 0x01, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x07, 0x00,
131 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
132 0x00, 0xc0, 0x01, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00,
133 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00,
134 0x80, 0xff, 0xff, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0xc0, 0x01, 0x00,
135 0x00, 0xc0, 0x01, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00,
136 0x00, 0xe0, 0x03, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x80, 0x00, 0x00,
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
139 static const uchar hsplit_bits[] = {
140 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
143 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
144 0x00, 0x41, 0x82, 0x00, 0x80, 0x41, 0x82, 0x01, 0xc0, 0x7f, 0xfe, 0x03,
145 0x80, 0x41, 0x82, 0x01, 0x00, 0x41, 0x82, 0x00, 0x00, 0x40, 0x02, 0x00,
146 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00,
147 0x00, 0x40, 0x02, 0x00, 0x00, 0x40, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
151 static const uchar hsplitm_bits[] = {
152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
154 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
155 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe3, 0xc7, 0x00,
156 0x80, 0xe3, 0xc7, 0x01, 0xc0, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x07,
157 0xc0, 0xff, 0xff, 0x03, 0x80, 0xe3, 0xc7, 0x01, 0x00, 0xe3, 0xc7, 0x00,
158 0x00, 0xe2, 0x47, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00,
159 0x00, 0xe0, 0x07, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
163 static const uchar phand_bits[] = {
164 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00,
165 0x80, 0x04, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00,
166 0x80, 0x1c, 0x00, 0x00, 0x80, 0xe4, 0x00, 0x00, 0x80, 0x24, 0x03, 0x00,
167 0x80, 0x24, 0x05, 0x00, 0xb8, 0x24, 0x09, 0x00, 0xc8, 0x00, 0x09, 0x00,
168 0x88, 0x00, 0x08, 0x00, 0x90, 0x00, 0x08, 0x00, 0xa0, 0x00, 0x08, 0x00,
169 0x20, 0x00, 0x08, 0x00, 0x40, 0x00, 0x08, 0x00, 0x40, 0x00, 0x04, 0x00,
170 0x80, 0x00, 0x04, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x01, 0x02, 0x00,
171 0x00, 0x01, 0x02, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
176 static const uchar phandm_bits[] = {
177 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00,
178 0x80, 0x07, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00,
179 0x80, 0x1f, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x80, 0xff, 0x03, 0x00,
180 0x80, 0xff, 0x07, 0x00, 0xb8, 0xff, 0x0f, 0x00, 0xf8, 0xff, 0x0f, 0x00,
181 0xf8, 0xff, 0x0f, 0x00, 0xf0, 0xff, 0x0f, 0x00, 0xe0, 0xff, 0x0f, 0x00,
182 0xe0, 0xff, 0x0f, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0xc0, 0xff, 0x07, 0x00,
183 0x80, 0xff, 0x07, 0x00, 0x80, 0xff, 0x07, 0x00, 0x00, 0xff, 0x03, 0x00,
184 0x00, 0xff, 0x03, 0x00, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
185 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
186 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
187 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
189 static const uchar openhand_bits[] = {
190 0x80,0x01,0x58,0x0e,0x64,0x12,0x64,0x52,0x48,0xb2,0x48,0x92,
191 0x16,0x90,0x19,0x80,0x11,0x40,0x02,0x40,0x04,0x40,0x04,0x20,
192 0x08,0x20,0x10,0x10,0x20,0x10,0x00,0x00};
193 static const uchar openhandm_bits[] = {
194 0x80,0x01,0xd8,0x0f,0xfc,0x1f,0xfc,0x5f,0xf8,0xff,0xf8,0xff,
195 0xf6,0xff,0xff,0xff,0xff,0x7f,0xfe,0x7f,0xfc,0x7f,0xfc,0x3f,
196 0xf8,0x3f,0xf0,0x1f,0xe0,0x1f,0x00,0x00};
197 static const uchar closedhand_bits[] = {
198 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0x48,0x32,0x08,0x50,
199 0x10,0x40,0x18,0x40,0x04,0x40,0x04,0x20,0x08,0x20,0x10,0x10,
200 0x20,0x10,0x20,0x10,0x00,0x00,0x00,0x00};
201 static const uchar closedhandm_bits[] = {
202 0x00,0x00,0x00,0x00,0x00,0x00,0xb0,0x0d,0xf8,0x3f,0xf8,0x7f,
203 0xf0,0x7f,0xf8,0x7f,0xfc,0x7f,0xfc,0x3f,0xf8,0x3f,0xf0,0x1f,
204 0xe0,0x1f,0xe0,0x1f,0x00,0x00,0x00,0x00};
206 static const uchar * const cursor_bits32[] = {
207 vsplit_bits, vsplitm_bits, hsplit_bits, hsplitm_bits,
208 phand_bits, phandm_bits
212 switch (c.shape()) { // map to windows cursor
213 case Qt::ArrowCursor:
216 case Qt::UpArrowCursor:
219 case Qt::CrossCursor:
225 case Qt::IBeamCursor:
228 case Qt::SizeVerCursor:
231 case Qt::SizeHorCursor:
234 case Qt::SizeBDiagCursor:
237 case Qt::SizeFDiagCursor:
240 case Qt::SizeAllCursor:
243 case Qt::ForbiddenCursor:
246 case Qt::WhatsThisCursor:
250 sh = IDC_APPSTARTING;
252 case Qt::PointingHandCursor:
255 case Qt::BlankCursor:
256 case Qt::SplitVCursor:
257 case Qt::SplitHCursor:
258 case Qt::OpenHandCursor:
259 case Qt::ClosedHandCursor:
260 case Qt::BitmapCursor: {
263 if (cshape == Qt::BlankCursor) {
264 bbits = QImage(32, 32, QImage::Format_Mono);
265 bbits.fill(0); // ignore color table
266 mbits = bbits.copy();
269 } else if (cshape == Qt::OpenHandCursor || cshape == Qt::ClosedHandCursor) {
270 bool open = cshape == Qt::OpenHandCursor;
271 QBitmap cb = QBitmap::fromData(QSize(16, 16), open ? openhand_bits : closedhand_bits);
272 QBitmap cm = QBitmap::fromData(QSize(16, 16), open ? openhandm_bits : closedhandm_bits);
273 bbits = cb.toImage().convertToFormat(QImage::Format_Mono);
274 mbits = cm.toImage().convertToFormat(QImage::Format_Mono);
277 } else if (cshape != Qt::BitmapCursor) {
278 int i = cshape - Qt::SplitVCursor;
279 QBitmap cb = QBitmap::fromData(QSize(32, 32), cursor_bits32[i * 2]);
280 QBitmap cm = QBitmap::fromData(QSize(32, 32), cursor_bits32[i * 2 + 1]);
281 bbits = cb.toImage().convertToFormat(QImage::Format_Mono);
282 mbits = cm.toImage().convertToFormat(QImage::Format_Mono);
283 if (cshape == Qt::PointingHandCursor) {
290 bbits = c.bitmap()->toImage().convertToFormat(QImage::Format_Mono);
291 mbits = c.mask()->toImage().convertToFormat(QImage::Format_Mono);
292 invb = bbits.colorCount() > 1 && qGray(bbits.color(0)) < qGray(bbits.color(1));
293 invm = mbits.colorCount() > 1 && qGray(mbits.color(0)) < qGray(mbits.color(1));
295 const int n = qMax(1, bbits.width() / 8);
296 const int h = bbits.height();
297 QScopedArrayPointer<uchar> xBits(new uchar[h * n]);
298 QScopedArrayPointer<uchar> xMask(new uchar[h * n]);
300 for (int i = 0; i < h; ++i) {
301 uchar *bits = bbits.scanLine(i);
302 uchar *mask = mbits.scanLine(i);
303 for (int j = 0; j < n; ++j) {
315 return CreateCursor(GetModuleHandle(0), hx, hy, bbits.width(), bbits.height(),
316 xBits.data(), xMask.data());
318 case Qt::DragCopyCursor:
319 case Qt::DragMoveCursor:
320 case Qt::DragLinkCursor: {
321 const QPixmap pixmap = QGuiApplicationPrivate::instance()->getPixmapCursor(cshape);
322 return createPixmapCursor(pixmap, hx, hy);
325 qWarning("%s: Invalid cursor shape %d", __FUNCTION__, cshape);
328 return (HCURSOR)LoadImage(0, sh, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE | LR_SHARED);
332 \brief Return cached standard cursor resources or create new ones.
335 QWindowsWindowCursor QWindowsCursor::standardWindowCursor(Qt::CursorShape shape)
337 StandardCursorCache::iterator it = m_standardCursorCache.find(shape);
338 if (it == m_standardCursorCache.end())
339 it = m_standardCursorCache.insert(shape, QWindowsWindowCursor(QCursor(shape)));
344 \brief Set a cursor on a window.
346 This is called frequently as the mouse moves over widgets in the window
350 void QWindowsCursor::changeCursor(QCursor *cursorIn, QWindow *window)
353 if (QWindowsContext::verboseWindows > 1)
354 qDebug() << __FUNCTION__ << cursorIn << window;
355 if (!cursorIn || !window)
357 const QWindowsWindowCursor wcursor =
358 cursorIn->shape() == Qt::BitmapCursor ?
359 QWindowsWindowCursor(*cursorIn) : standardWindowCursor(cursorIn->shape());
360 if (wcursor.handle()) {
361 QWindowsWindow::baseWindowOf(window)->setCursor(wcursor);
363 qWarning("%s: Unable to obtain system cursor for %d",
364 __FUNCTION__, cursorIn->shape());
368 QPoint QWindowsCursor::mousePosition()
372 return QPoint(p.x, p.y);
375 void QWindowsCursor::setPos(const QPoint &pos)
377 if (QWindowsContext::verboseWindows)
378 qDebug("%s %d,%d", __FUNCTION__, pos.x(), pos.y());
379 SetCursorPos(pos.x(), pos.y());
383 \class QWindowsWindowCursor
384 \brief Per-Window cursor. Contains a QCursor and manages its associated system
385 cursor handle resource.
387 Based on QSharedDataPointer, so that it can be passed around and
388 used as a property of QWindowsBaseWindow.
390 \ingroup qt-lighthouse-win
394 class QWindowsWindowCursorData : public QSharedData
397 explicit QWindowsWindowCursorData(const QCursor &c);
398 ~QWindowsWindowCursorData();
400 const QCursor m_cursor;
401 const HCURSOR m_handle;
404 QWindowsWindowCursorData::QWindowsWindowCursorData(const QCursor &c) :
406 m_handle(QWindowsCursor::createSystemCursor(c))
410 QWindowsWindowCursorData::~QWindowsWindowCursorData()
412 DestroyCursor(m_handle);
415 QWindowsWindowCursor::QWindowsWindowCursor(const QCursor &c) :
416 m_data(new QWindowsWindowCursorData(c))
420 QWindowsWindowCursor::~QWindowsWindowCursor()
424 QWindowsWindowCursor::QWindowsWindowCursor(const QWindowsWindowCursor &rhs) :
429 QWindowsWindowCursor & QWindowsWindowCursor::operator =(const QWindowsWindowCursor &rhs)
432 m_data.operator =(rhs.m_data);
436 QCursor QWindowsWindowCursor::cursor() const
438 return m_data->m_cursor;
441 HCURSOR QWindowsWindowCursor::handle() const
443 return m_data->m_handle;