1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qcursor.h"
5
6#include <qcoreapplication.h>
7#include <qbitmap.h>
8#include <qimage.h>
9#include <qdatastream.h>
10#include <qvariant.h>
11#include <private/qcursor_p.h>
12#include <qdebug.h>
13
14#include <qpa/qplatformcursor.h>
15#include <private/qguiapplication_p.h>
16#include <private/qhighdpiscaling_p.h>
17
18QT_BEGIN_NAMESPACE
19
20/*!
21 \class QCursor
22
23 \brief The QCursor class provides a mouse cursor with an arbitrary
24 shape.
25
26 \inmodule QtGui
27 \ingroup appearance
28 \ingroup shared
29
30
31 This class is mainly used to create mouse cursors that are
32 associated with particular widgets and to get and set the position
33 of the mouse cursor.
34
35 Qt has a number of standard cursor shapes, but you can also make
36 custom cursor shapes based on a QBitmap, a mask and a hotspot.
37
38 To associate a cursor with a widget, use QWidget::setCursor(). To
39 associate a cursor with all widgets (normally for a short period
40 of time), use QGuiApplication::setOverrideCursor().
41
42 To set a cursor shape use QCursor::setShape() or use the QCursor
43 constructor which takes the shape as argument, or you can use one
44 of the predefined cursors defined in the \l Qt::CursorShape enum.
45
46 If you want to create a cursor with your own bitmap, either use
47 the QCursor constructor which takes a bitmap and a mask or the
48 constructor which takes a pixmap as arguments.
49
50 To set or get the position of the mouse cursor use the static
51 methods QCursor::pos() and QCursor::setPos().
52
53 \b{Note:} It is possible to create a QCursor before
54 QGuiApplication, but it is not useful except as a place-holder for a
55 real QCursor created after QGuiApplication. Attempting to use a
56 QCursor that was created before QGuiApplication will result in a
57 crash.
58
59 \section1 A Note for X11 Users
60
61 On X11, Qt supports the \l{Xcursor}{Xcursor}
62 library, which allows for full color icon themes. The table below
63 shows the cursor name used for each Qt::CursorShape value. If a
64 cursor cannot be found using the name shown below, a standard X11
65 cursor will be used instead. Note: X11 does not provide
66 appropriate cursors for all possible Qt::CursorShape values. It
67 is possible that some cursors will be taken from the Xcursor
68 theme, while others will use an internal bitmap cursor.
69
70 \table
71 \header \li Shape \li Qt::CursorShape Value \li Cursor Name
72 \li Shape \li Qt::CursorShape Value \li Cursor Name
73 \row \li \inlineimage cursor-arrow.png
74 \li Qt::ArrowCursor \li \c left_ptr
75 \li \inlineimage cursor-sizev.png
76 \li Qt::SizeVerCursor \li \c size_ver
77 \row \li \inlineimage cursor-uparrow.png
78 \li Qt::UpArrowCursor \li \c up_arrow
79 \li \inlineimage cursor-sizeh.png
80 \li Qt::SizeHorCursor \li \c size_hor
81 \row \li \inlineimage cursor-cross.png
82 \li Qt::CrossCursor \li \c cross
83 \li \inlineimage cursor-sizeb.png
84 \li Qt::SizeBDiagCursor \li \c size_bdiag
85 \row \li \inlineimage cursor-ibeam.png
86 \li Qt::IBeamCursor \li \c ibeam
87 \li \inlineimage cursor-sizef.png
88 \li Qt::SizeFDiagCursor \li \c size_fdiag
89 \row \li \inlineimage cursor-wait.png
90 \li Qt::WaitCursor \li \c wait
91 \li \inlineimage cursor-sizeall.png
92 \li Qt::SizeAllCursor \li \c size_all
93 \row \li \inlineimage cursor-busy.png
94 \li Qt::BusyCursor \li \c left_ptr_watch
95 \li \inlineimage cursor-vsplit.png
96 \li Qt::SplitVCursor \li \c split_v
97 \row \li \inlineimage cursor-forbidden.png
98 \li Qt::ForbiddenCursor \li \c forbidden
99 \li \inlineimage cursor-hsplit.png
100 \li Qt::SplitHCursor \li \c split_h
101 \row \li \inlineimage cursor-hand.png
102 \li Qt::PointingHandCursor \li \c pointing_hand
103 \li \inlineimage cursor-openhand.png
104 \li Qt::OpenHandCursor \li \c openhand
105 \row \li \inlineimage cursor-whatsthis.png
106 \li Qt::WhatsThisCursor \li \c whats_this
107 \li \inlineimage cursor-closedhand.png
108 \li Qt::ClosedHandCursor \li \c closedhand
109 \row \li
110 \li Qt::DragMoveCursor \li \c dnd-move or \c move
111 \li
112 \li Qt::DragCopyCursor \li \c dnd-copy or \c copy
113 \row \li
114 \li Qt::DragLinkCursor \li \c dnd-link or \c link
115 \endtable
116
117 \sa QWidget
118*/
119
120/*!
121 \fn QCursor::QCursor(QCursor &&other)
122 \since 5.5
123
124 Move-constructs a cursor from \a other. After being moved from,
125 the only valid operations on \a other are destruction and
126 (move and copy) assignment. The effects of calling any other
127 member function on a moved-from instance are undefined.
128*/
129
130/*!
131 \fn QCursor &QCursor::operator=(QCursor &&other)
132
133 Move-assigns \a other to this QCursor instance.
134
135 \since 5.2
136*/
137
138/*!
139 \fn void QCursor::swap(QCursor &other)
140
141 Swaps this cursor with the \a other cursor.
142
143 \since 5.7
144 */
145
146/*!
147 \fn QPoint QCursor::pos(const QScreen *screen)
148
149 Returns the position of the cursor (hot spot) of the \a screen
150 in global screen coordinates.
151
152 You can call QWidget::mapFromGlobal() to translate it to widget
153 coordinates.
154
155 \sa setPos(), QWidget::mapFromGlobal(), QWidget::mapToGlobal()
156*/
157QPoint QCursor::pos(const QScreen *screen)
158{
159 if (screen) {
160 if (const QPlatformCursor *cursor = screen->handle()->cursor()) {
161 const QPlatformScreen *ps = screen->handle();
162 QPoint nativePos = cursor->pos();
163 ps = ps->screenForPosition(point: nativePos);
164 return QHighDpi::fromNativePixels(value: nativePos, context: ps->screen());
165 }
166 }
167 return QGuiApplicationPrivate::lastCursorPosition.toPoint();
168}
169
170/*!
171 \fn QPoint QCursor::pos()
172
173 Returns the position of the cursor (hot spot) of
174 the primary screen in global screen coordinates.
175
176 You can call QWidget::mapFromGlobal() to translate it to widget
177 coordinates.
178
179 \note The position is queried from the windowing system. If mouse events are generated
180 via other means (e.g., via QWindowSystemInterface in a unit test), those fake mouse
181 moves will not be reflected in the returned value.
182
183 \note On platforms where there is no windowing system or cursors are not available, the returned
184 position is based on the mouse move events generated via QWindowSystemInterface.
185
186 \sa setPos(), QWidget::mapFromGlobal(), QWidget::mapToGlobal(), QGuiApplication::primaryScreen()
187*/
188QPoint QCursor::pos()
189{
190 return QCursor::pos(screen: QGuiApplication::primaryScreen());
191}
192
193/*!
194 \fn void QCursor::setPos(QScreen *screen, int x, int y)
195
196 Moves the cursor (hot spot) of the \a screen to the global
197 screen position (\a x, \a y).
198
199 You can call QWidget::mapToGlobal() to translate widget
200 coordinates to global screen coordinates.
201
202 \note Calling this function results in changing the cursor position through the windowing
203 system. The windowing system will typically respond by sending mouse events to the application's
204 window. This means that the usage of this function should be avoided in unit tests and
205 everywhere where fake mouse events are being injected via QWindowSystemInterface because the
206 windowing system's mouse state (with regards to buttons for example) may not match the state in
207 the application-generated events.
208
209 \note On platforms where there is no windowing system or cursors are not available, this
210 function may do nothing.
211
212 \sa pos(), QWidget::mapFromGlobal(), QWidget::mapToGlobal()
213*/
214void QCursor::setPos(QScreen *screen, int x, int y)
215{
216 if (screen) {
217 if (QPlatformCursor *cursor = screen->handle()->cursor()) {
218 const QPoint pos(x, y);
219 const QPoint devicePos = QHighDpi::toNativePixels(value: pos, context: screen->virtualSiblingAt(point: pos));
220 // Need to check, since some X servers generate null mouse move
221 // events, causing looping in applications which call setPos() on
222 // every mouse move event.
223 if (devicePos != cursor->pos())
224 cursor->setPos(devicePos);
225 }
226 }
227}
228
229/*!
230 \fn void QCursor::setPos(int x, int y)
231
232 Moves the cursor (hot spot) of the primary screen
233 to the global screen position (\a x, \a y).
234
235 You can call QWidget::mapToGlobal() to translate widget
236 coordinates to global screen coordinates.
237
238 \sa pos(), QWidget::mapFromGlobal(), QWidget::mapToGlobal(), QGuiApplication::primaryScreen()
239*/
240void QCursor::setPos(int x, int y)
241{
242 QCursor::setPos(screen: QGuiApplication::primaryScreen(), x, y);
243}
244
245#ifndef QT_NO_CURSOR
246
247/*!
248 \fn void QCursor::setPos (const QPoint &p)
249
250 \overload
251
252 Moves the cursor (hot spot) to the global screen position at point
253 \a p.
254*/
255
256/*!
257 \fn void QCursor::setPos (QScreen *screen,const QPoint &p)
258
259 \overload
260
261 Moves the cursor (hot spot) to the global screen position of the
262 \a screen at point \a p.
263*/
264
265/*****************************************************************************
266 QCursor stream functions
267 *****************************************************************************/
268
269#ifndef QT_NO_DATASTREAM
270
271
272/*!
273 \fn QDataStream &operator<<(QDataStream &stream, const QCursor &cursor)
274 \relates QCursor
275
276 Writes the \a cursor to the \a stream.
277
278 \sa {Serializing Qt Data Types}
279*/
280
281QDataStream &operator<<(QDataStream &s, const QCursor &c)
282{
283 s << (qint16)c.shape(); // write shape id to stream
284 if (c.shape() == Qt::BitmapCursor) { // bitmap cursor
285 bool isPixmap = false;
286 if (s.version() >= 7) {
287 isPixmap = !c.pixmap().isNull();
288 s << isPixmap;
289 }
290 if (isPixmap)
291 s << c.pixmap();
292 else
293 s << c.bitmap() << c.mask();
294 s << c.hotSpot();
295 }
296 return s;
297}
298
299/*!
300 \fn QDataStream &operator>>(QDataStream &stream, QCursor &cursor)
301 \relates QCursor
302
303 Reads the \a cursor from the \a stream.
304
305 \sa {Serializing Qt Data Types}
306*/
307
308QDataStream &operator>>(QDataStream &s, QCursor &c)
309{
310 qint16 shape;
311 s >> shape; // read shape id from stream
312 if (shape == Qt::BitmapCursor) { // read bitmap cursor
313 bool isPixmap = false;
314 if (s.version() >= 7)
315 s >> isPixmap;
316 if (isPixmap) {
317 QPixmap pm;
318 QPoint hot;
319 s >> pm >> hot;
320 c = QCursor(pm, hot.x(), hot.y());
321 } else {
322 QBitmap bm, bmm;
323 QPoint hot;
324 s >> bm >> bmm >> hot;
325 c = QCursor(bm, bmm, hot.x(), hot.y());
326 }
327 } else {
328 c.setShape((Qt::CursorShape)shape); // create cursor with shape
329 }
330 return s;
331}
332#endif // QT_NO_DATASTREAM
333
334
335/*!
336 Constructs a custom pixmap cursor.
337
338 \a pixmap is the image. It is usual to give it a mask (set using
339 QPixmap::setMask()). \a hotX and \a hotY define the cursor's hot
340 spot.
341
342 If \a hotX is negative, it is set to the \c{pixmap().width()/2}.
343 If \a hotY is negative, it is set to the \c{pixmap().height()/2}.
344
345 Valid cursor sizes depend on the display hardware (or the
346 underlying window system). We recommend using 32 x 32 cursors,
347 because this size is supported on all platforms. Some platforms
348 also support 16 x 16, 48 x 48, and 64 x 64 cursors.
349
350 \sa QPixmap::QPixmap(), QPixmap::setMask()
351*/
352
353QCursor::QCursor(const QPixmap &pixmap, int hotX, int hotY)
354 : d(nullptr)
355{
356 QImage img = pixmap.toImage().convertToFormat(f: QImage::Format_Indexed8, flags: Qt::ThresholdDither|Qt::AvoidDither);
357 QBitmap bm = QBitmap::fromImage(image: img, flags: Qt::ThresholdDither|Qt::AvoidDither);
358 QBitmap bmm = pixmap.mask();
359 if (!bmm.isNull()) {
360 QBitmap nullBm;
361 bm.setMask(nullBm);
362 }
363 else if (!pixmap.mask().isNull()) {
364 QImage mimg = pixmap.mask().toImage().convertToFormat(f: QImage::Format_Indexed8, flags: Qt::ThresholdDither|Qt::AvoidDither);
365 bmm = QBitmap::fromImage(image: mimg, flags: Qt::ThresholdDither|Qt::AvoidDither);
366 }
367 else {
368 bmm = QBitmap(bm.size());
369 bmm.fill(fillColor: Qt::color1);
370 }
371
372 d = QCursorData::setBitmap(bitmap: bm, mask: bmm, hotX, hotY, devicePixelRatio: pixmap.devicePixelRatio());
373 d->pixmap = pixmap;
374}
375
376
377
378/*!
379 Constructs a custom bitmap cursor.
380
381 \a bitmap and
382 \a mask make up the bitmap.
383 \a hotX and
384 \a hotY define the cursor's hot spot.
385
386 If \a hotX is negative, it is set to the \c{bitmap().width()/2}.
387 If \a hotY is negative, it is set to the \c{bitmap().height()/2}.
388
389 The cursor \a bitmap (B) and \a mask (M) bits are combined like this:
390 \list
391 \li B=1 and M=1 gives black.
392 \li B=0 and M=1 gives white.
393 \li B=0 and M=0 gives transparent.
394 \li B=1 and M=0 gives an XOR'd result under Windows, undefined
395 results on all other platforms.
396 \endlist
397
398 Use the global Qt color Qt::color0 to draw 0-pixels and Qt::color1 to
399 draw 1-pixels in the bitmaps.
400
401 Valid cursor sizes depend on the display hardware (or the
402 underlying window system). We recommend using 32 x 32 cursors,
403 because this size is supported on all platforms. Some platforms
404 also support 16 x 16, 48 x 48, and 64 x 64 cursors.
405
406 \sa QBitmap::QBitmap(), QBitmap::setMask()
407*/
408
409QCursor::QCursor(const QBitmap &bitmap, const QBitmap &mask, int hotX, int hotY)
410 : d(nullptr)
411{
412 d = QCursorData::setBitmap(bitmap, mask, hotX, hotY, devicePixelRatio: 1.0);
413}
414
415/*!
416 Constructs a cursor with the default arrow shape.
417*/
418QCursor::QCursor()
419{
420 if (!QCursorData::initialized) {
421 if (QCoreApplication::startingUp()) {
422 d = nullptr;
423 return;
424 }
425 QCursorData::initialize();
426 }
427 QCursorData *c = qt_cursorTable[0];
428 c->ref.ref();
429 d = c;
430}
431
432/*!
433 Constructs a cursor with the specified \a shape.
434
435 See \l Qt::CursorShape for a list of shapes.
436
437 \sa setShape()
438*/
439QCursor::QCursor(Qt::CursorShape shape)
440 : d(nullptr)
441{
442 if (!QCursorData::initialized)
443 QCursorData::initialize();
444 setShape(shape);
445}
446
447/*!
448 \fn bool QCursor::operator==(const QCursor &lhs, const QCursor &rhs)
449 \since 5.10
450
451 Equality operator. Returns \c true if \a lhs and \a rhs
452 have the same \l{QCursor::}{shape()} and, in the case of
453 \l{Qt::BitmapCursor}{bitmap cursors}, the same \l{QCursor::}{hotSpot()}
454 and either the same \l{QCursor::}{pixmap()} or the same
455 \l{QCursor::}{bitmap()} and \l{QCursor::}{mask()}.
456
457 \note When comparing bitmap cursors, this function only
458 compares the bitmaps' \l{QPixmap::cacheKey()}{cache keys},
459 not each pixel.
460
461 \sa operator!=(const QCursor &lhs, const QCursor &rhs)
462*/
463bool operator==(const QCursor &lhs, const QCursor &rhs) noexcept
464{
465 if (lhs.d == rhs.d)
466 return true; // Copy or same shape
467
468 // Check pixmaps or bitmaps cache keys. Notice that having BitmapCursor
469 // shape implies either non-null pixmap or non-null bitmap and mask
470 if (lhs.shape() == Qt::BitmapCursor && rhs.shape() == Qt::BitmapCursor
471 && lhs.hotSpot() == rhs.hotSpot()) {
472 if (!lhs.d->pixmap.isNull())
473 return lhs.d->pixmap.cacheKey() == rhs.d->pixmap.cacheKey();
474
475 if (!rhs.d->pixmap.isNull())
476 return false;
477
478 return lhs.d->bm->cacheKey() == rhs.d->bm->cacheKey()
479 && lhs.d->bmm->cacheKey() == rhs.d->bmm->cacheKey();
480 }
481
482 return false;
483}
484
485/*!
486 \fn bool QCursor::operator!=(const QCursor &lhs, const QCursor &rhs)
487 \since 5.10
488
489 Inequality operator. Returns the equivalent of !(\a lhs == \a rhs).
490
491 \sa operator==(const QCursor &lhs, const QCursor &rhs)
492*/
493
494/*!
495 Returns the cursor shape identifier.
496
497 \sa setShape()
498*/
499Qt::CursorShape QCursor::shape() const
500{
501 if (!QCursorData::initialized)
502 QCursorData::initialize();
503 return d->cshape;
504}
505
506/*!
507 Sets the cursor to the shape identified by \a shape.
508
509 See \l Qt::CursorShape for the list of cursor shapes.
510
511 \sa shape()
512*/
513void QCursor::setShape(Qt::CursorShape shape)
514{
515 if (!QCursorData::initialized)
516 QCursorData::initialize();
517 QCursorData *c = uint(shape) <= Qt::LastCursor ? qt_cursorTable[shape] : nullptr;
518 if (!c)
519 c = qt_cursorTable[0];
520 c->ref.ref();
521 if (!d) {
522 d = c;
523 } else {
524 if (!d->ref.deref())
525 delete d;
526 d = c;
527 }
528}
529
530/*!
531 \fn QBitmap QCursor::bitmap(Qt::ReturnByValueConstant) const
532 \since 5.15
533 \deprecated Use the overload without argument instead.
534
535 Returns the cursor bitmap, or a null bitmap if it is one of the
536 standard cursors.
537
538 Previously, Qt provided a version of \c bitmap() which returned the bitmap
539 by-pointer. That version is now removed. To maintain compatibility
540 with old code, this function was provided to differentiate between the by-pointer
541 function and the by-value function.
542*/
543
544/*!
545 Returns the cursor bitmap, or a null bitmap if it is one of the
546 standard cursors.
547*/
548QBitmap QCursor::bitmap() const
549{
550 if (!QCursorData::initialized)
551 QCursorData::initialize();
552 if (d->bm)
553 return *(d->bm);
554 return QBitmap();
555}
556
557/*!
558 \fn QBitmap QCursor::mask(Qt::ReturnByValueConstant) const
559 \since 5.15
560 \deprecated Use the overload without argument instead.
561
562 Returns the cursor bitmap mask, or a null bitmap if it is one of the
563 standard cursors.
564
565 Previously, Qt provided a version of \c mask() which returned the bitmap
566 by-pointer. That version is now removed. To maintain compatibility
567 with old code, this function was provided to differentiate between the by-pointer
568 function and the by-value function.
569*/
570
571/*!
572 Returns the cursor bitmap mask, or a null bitmap if it is one of the
573 standard cursors.
574*/
575QBitmap QCursor::mask() const
576{
577 if (!QCursorData::initialized)
578 QCursorData::initialize();
579 if (d->bmm)
580 return *(d->bmm);
581 return QBitmap();
582}
583
584/*!
585 Returns the cursor pixmap. This is only valid if the cursor is a
586 pixmap cursor.
587*/
588
589QPixmap QCursor::pixmap() const
590{
591 if (!QCursorData::initialized)
592 QCursorData::initialize();
593 return d->pixmap;
594}
595
596/*!
597 Returns the cursor hot spot, or (0, 0) if it is one of the
598 standard cursors.
599*/
600
601QPoint QCursor::hotSpot() const
602{
603 if (!QCursorData::initialized)
604 QCursorData::initialize();
605 return QPoint(d->hx, d->hy);
606}
607
608/*!
609 Constructs a copy of the cursor \a c.
610*/
611
612QCursor::QCursor(const QCursor &c)
613{
614 if (!QCursorData::initialized)
615 QCursorData::initialize();
616 d = c.d;
617 d->ref.ref();
618}
619
620/*!
621 Destroys the cursor.
622*/
623
624QCursor::~QCursor()
625{
626 if (d && !d->ref.deref())
627 delete d;
628}
629
630
631/*!
632 Assigns \a c to this cursor and returns a reference to this
633 cursor.
634*/
635
636QCursor &QCursor::operator=(const QCursor &c)
637{
638 if (!QCursorData::initialized)
639 QCursorData::initialize();
640 if (c.d)
641 c.d->ref.ref();
642 if (d && !d->ref.deref())
643 delete d;
644 d = c.d;
645 return *this;
646}
647
648/*!
649 Returns the cursor as a QVariant.
650*/
651QCursor::operator QVariant() const
652{
653 return QVariant::fromValue(value: *this);
654}
655
656#ifndef QT_NO_DEBUG_STREAM
657QDebug operator<<(QDebug dbg, const QCursor &c)
658{
659 QDebugStateSaver saver(dbg);
660 dbg.nospace() << "QCursor(Qt::CursorShape(" << c.shape() << "))";
661 return dbg;
662}
663#endif
664
665/*****************************************************************************
666 Internal QCursorData class
667 *****************************************************************************/
668
669QCursorData *qt_cursorTable[Qt::LastCursor + 1];
670bool QCursorData::initialized = false;
671
672QCursorData::QCursorData(Qt::CursorShape s)
673 : ref(1), cshape(s), bm(nullptr), bmm(nullptr), hx(0), hy(0)
674{
675}
676
677QCursorData::~QCursorData()
678{
679 delete bm;
680 delete bmm;
681}
682
683/*! \internal */
684void QCursorData::cleanup()
685{
686 if (!QCursorData::initialized)
687 return;
688
689 for (int shape = 0; shape <= Qt::LastCursor; ++shape) {
690 // In case someone has a static QCursor defined with this shape
691 if (!qt_cursorTable[shape]->ref.deref())
692 delete qt_cursorTable[shape];
693 qt_cursorTable[shape] = nullptr;
694 }
695 QCursorData::initialized = false;
696}
697
698/*! \internal */
699void QCursorData::initialize()
700{
701 if (QCursorData::initialized)
702 return;
703 for (int shape = 0; shape <= Qt::LastCursor; ++shape)
704 qt_cursorTable[shape] = new QCursorData((Qt::CursorShape)shape);
705 QCursorData::initialized = true;
706}
707
708QCursorData *QCursorData::setBitmap(const QBitmap &bitmap, const QBitmap &mask, int hotX, int hotY, qreal devicePixelRatio)
709{
710 if (!QCursorData::initialized)
711 QCursorData::initialize();
712 if (bitmap.depth() != 1 || mask.depth() != 1 || bitmap.size() != mask.size()) {
713 qWarning(msg: "QCursor: Cannot create bitmap cursor; invalid bitmap(s)");
714 QCursorData *c = qt_cursorTable[0];
715 c->ref.ref();
716 return c;
717 }
718 QCursorData *d = new QCursorData;
719 d->bm = new QBitmap(bitmap);
720 d->bmm = new QBitmap(mask);
721 d->cshape = Qt::BitmapCursor;
722 d->hx = hotX >= 0 ? hotX : bitmap.width() / 2 / devicePixelRatio;
723 d->hy = hotY >= 0 ? hotY : bitmap.height() / 2 / devicePixelRatio;
724
725 return d;
726}
727
728void QCursorData::update()
729{
730}
731
732QT_END_NAMESPACE
733#endif // QT_NO_CURSOR
734
735

source code of qtbase/src/gui/kernel/qcursor.cpp