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

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