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 
54 QT_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 */
pos(const QScreen * screen)193 QPoint 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(nativePos);
200             return QHighDpi::fromNativePixels(nativePos, 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 */
pos()224 QPoint QCursor::pos()
225 {
226     return QCursor::pos(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 */
setPos(QScreen * screen,int x,int y)250 void QCursor::setPos(QScreen *screen, int x, int y)
251 {
252     if (screen) {
253         if (QPlatformCursor *cursor = screen->handle()->cursor()) {
254             const QPoint devicePos = QHighDpi::toNativePixels(QPoint(x, y), screen);
255             // Need to check, since some X servers generate null mouse move
256             // events, causing looping in applications which call setPos() on
257             // every mouse move event.
258             if (devicePos != cursor->pos())
259                 cursor->setPos(devicePos);
260         }
261     }
262 }
263 
264 /*!
265     \fn void QCursor::setPos(int x, int y)
266 
267     Moves the cursor (hot spot) of the primary screen
268     to the global screen position (\a x, \a y).
269 
270     You can call QWidget::mapToGlobal() to translate widget
271     coordinates to global screen coordinates.
272 
273     \sa pos(), QWidget::mapFromGlobal(), QWidget::mapToGlobal(), QGuiApplication::primaryScreen()
274 */
setPos(int x,int y)275 void QCursor::setPos(int x, int y)
276 {
277     QCursor::setPos(QGuiApplication::primaryScreen(), x, y);
278 }
279 
280 #ifndef QT_NO_CURSOR
281 
282 /*!
283     \fn void QCursor::setPos (const QPoint &p)
284 
285     \overload
286 
287     Moves the cursor (hot spot) to the global screen position at point
288     \a p.
289 */
290 
291 /*!
292     \fn void QCursor::setPos (QScreen *screen,const QPoint &p)
293 
294     \overload
295 
296     Moves the cursor (hot spot) to the global screen position of the
297     \a screen at point \a p.
298 */
299 
300 /*****************************************************************************
301   QCursor stream functions
302  *****************************************************************************/
303 
304 #ifndef QT_NO_DATASTREAM
305 
306 
307 /*!
308     \fn QDataStream &operator<<(QDataStream &stream, const QCursor &cursor)
309     \relates QCursor
310 
311     Writes the \a cursor to the \a stream.
312 
313     \sa {Serializing Qt Data Types}
314 */
315 
operator <<(QDataStream & s,const QCursor & c)316 QDataStream &operator<<(QDataStream &s, const QCursor &c)
317 {
318     s << (qint16)c.shape();                        // write shape id to stream
319     if (c.shape() == Qt::BitmapCursor) {                // bitmap cursor
320         bool isPixmap = false;
321         if (s.version() >= 7) {
322             isPixmap = !c.pixmap().isNull();
323             s << isPixmap;
324         }
325         if (isPixmap)
326             s << c.pixmap();
327         else
328             s << c.bitmap(Qt::ReturnByValue) << c.mask(Qt::ReturnByValue);
329         s << c.hotSpot();
330     }
331     return s;
332 }
333 
334 /*!
335     \fn QDataStream &operator>>(QDataStream &stream, QCursor &cursor)
336     \relates QCursor
337 
338     Reads the \a cursor from the \a stream.
339 
340     \sa {Serializing Qt Data Types}
341 */
342 
operator >>(QDataStream & s,QCursor & c)343 QDataStream &operator>>(QDataStream &s, QCursor &c)
344 {
345     qint16 shape;
346     s >> shape;                                        // read shape id from stream
347     if (shape == Qt::BitmapCursor) {                // read bitmap cursor
348         bool isPixmap = false;
349         if (s.version() >= 7)
350             s >> isPixmap;
351         if (isPixmap) {
352             QPixmap pm;
353             QPoint hot;
354             s >> pm >> hot;
355             c = QCursor(pm, hot.x(), hot.y());
356         } else {
357             QBitmap bm, bmm;
358             QPoint hot;
359             s >> bm >> bmm >> hot;
360             c = QCursor(bm, bmm, hot.x(), hot.y());
361         }
362     } else {
363         c.setShape((Qt::CursorShape)shape);                // create cursor with shape
364     }
365     return s;
366 }
367 #endif // QT_NO_DATASTREAM
368 
369 
370 /*!
371     Constructs a custom pixmap cursor.
372 
373     \a pixmap is the image. It is usual to give it a mask (set using
374     QPixmap::setMask()). \a hotX and \a hotY define the cursor's hot
375     spot.
376 
377     If \a hotX is negative, it is set to the \c{pixmap().width()/2}.
378     If \a hotY is negative, it is set to the \c{pixmap().height()/2}.
379 
380     Valid cursor sizes depend on the display hardware (or the
381     underlying window system). We recommend using 32 x 32 cursors,
382     because this size is supported on all platforms. Some platforms
383     also support 16 x 16, 48 x 48, and 64 x 64 cursors.
384 
385     \sa QPixmap::QPixmap(), QPixmap::setMask()
386 */
387 
QCursor(const QPixmap & pixmap,int hotX,int hotY)388 QCursor::QCursor(const QPixmap &pixmap, int hotX, int hotY)
389     : d(nullptr)
390 {
391     QImage img = pixmap.toImage().convertToFormat(QImage::Format_Indexed8, Qt::ThresholdDither|Qt::AvoidDither);
392     QBitmap bm = QBitmap::fromImage(img, Qt::ThresholdDither|Qt::AvoidDither);
393     QBitmap bmm = pixmap.mask();
394     if (!bmm.isNull()) {
395         QBitmap nullBm;
396         bm.setMask(nullBm);
397     }
398     else if (!pixmap.mask().isNull()) {
399         QImage mimg = pixmap.mask().toImage().convertToFormat(QImage::Format_Indexed8, Qt::ThresholdDither|Qt::AvoidDither);
400         bmm = QBitmap::fromImage(mimg, Qt::ThresholdDither|Qt::AvoidDither);
401     }
402     else {
403         bmm = QBitmap(bm.size());
404         bmm.fill(Qt::color1);
405     }
406 
407     d = QCursorData::setBitmap(bm, bmm, hotX, hotY, pixmap.devicePixelRatio());
408     d->pixmap = pixmap;
409 }
410 
411 
412 
413 /*!
414     Constructs a custom bitmap cursor.
415 
416     \a bitmap and
417     \a mask make up the bitmap.
418     \a hotX and
419     \a hotY define the cursor's hot spot.
420 
421     If \a hotX is negative, it is set to the \c{bitmap().width()/2}.
422     If \a hotY is negative, it is set to the \c{bitmap().height()/2}.
423 
424     The cursor \a bitmap (B) and \a mask (M) bits are combined like this:
425     \list
426     \li B=1 and M=1 gives black.
427     \li B=0 and M=1 gives white.
428     \li B=0 and M=0 gives transparent.
429     \li B=1 and M=0 gives an XOR'd result under Windows, undefined
430     results on all other platforms.
431     \endlist
432 
433     Use the global Qt color Qt::color0 to draw 0-pixels and Qt::color1 to
434     draw 1-pixels in the bitmaps.
435 
436     Valid cursor sizes depend on the display hardware (or the
437     underlying window system). We recommend using 32 x 32 cursors,
438     because this size is supported on all platforms. Some platforms
439     also support 16 x 16, 48 x 48, and 64 x 64 cursors.
440 
441     \sa QBitmap::QBitmap(), QBitmap::setMask()
442 */
443 
QCursor(const QBitmap & bitmap,const QBitmap & mask,int hotX,int hotY)444 QCursor::QCursor(const QBitmap &bitmap, const QBitmap &mask, int hotX, int hotY)
445     : d(nullptr)
446 {
447     d = QCursorData::setBitmap(bitmap, mask, hotX, hotY, 1.0);
448 }
449 
450 /*!
451     Constructs a cursor with the default arrow shape.
452 */
QCursor()453 QCursor::QCursor()
454 {
455     if (!QCursorData::initialized) {
456         if (QCoreApplication::startingUp()) {
457             d = nullptr;
458             return;
459         }
460         QCursorData::initialize();
461     }
462     QCursorData *c = qt_cursorTable[0];
463     c->ref.ref();
464     d = c;
465 }
466 
467 /*!
468     Constructs a cursor with the specified \a shape.
469 
470     See \l Qt::CursorShape for a list of shapes.
471 
472     \sa setShape()
473 */
QCursor(Qt::CursorShape shape)474 QCursor::QCursor(Qt::CursorShape shape)
475     : d(nullptr)
476 {
477     if (!QCursorData::initialized)
478         QCursorData::initialize();
479     setShape(shape);
480 }
481 
482 /*!
483     \fn bool operator==(const QCursor &lhs, const QCursor &rhs)
484     \relates QCursor
485     \since 5.10
486 
487     Equality operator. Returns \c true if \a lhs and \a rhs
488     have the same \l{QCursor::}{shape()} and, in the case of
489     \l{Qt::BitmapCursor}{bitmap cursors}, the same \l{QCursor::}{hotSpot()}
490     and either the same \l{QCursor::}{pixmap()} or the same
491     \l{QCursor::}{bitmap()} and \l{QCursor::}{mask()}.
492 
493     \note When comparing bitmap cursors, this function only
494     compares the bitmaps' \l{QPixmap::cacheKey()}{cache keys},
495     not each pixel.
496 
497     \sa operator!=(const QCursor &lhs, const QCursor &rhs)
498 */
operator ==(const QCursor & lhs,const QCursor & rhs)499 bool operator==(const QCursor &lhs, const QCursor &rhs) noexcept
500 {
501     if (lhs.d == rhs.d)
502         return true; // Copy or same shape
503 
504     // Check pixmaps or bitmaps cache keys. Notice that having BitmapCursor
505     // shape implies either non-null pixmap or non-null bitmap and mask
506     if (lhs.shape() == Qt::BitmapCursor && rhs.shape() == Qt::BitmapCursor
507             && lhs.hotSpot() == rhs.hotSpot()) {
508         if (!lhs.d->pixmap.isNull())
509             return lhs.d->pixmap.cacheKey() == rhs.d->pixmap.cacheKey();
510 
511         if (!rhs.d->pixmap.isNull())
512             return false;
513 
514         return lhs.d->bm->cacheKey() == rhs.d->bm->cacheKey()
515                 && lhs.d->bmm->cacheKey() == rhs.d->bmm->cacheKey();
516     }
517 
518     return false;
519 }
520 
521 /*!
522     \fn bool operator!=(const QCursor &lhs, const QCursor &rhs)
523     \relates QCursor
524     \since 5.10
525 
526     Inequality operator. Returns the equivalent of !(\a lhs == \a rhs).
527 
528     \sa operator==(const QCursor &lhs, const QCursor &rhs)
529 */
530 
531 /*!
532     Returns the cursor shape identifier. The return value is one of
533     the \l Qt::CursorShape enum values (cast to an int).
534 
535     \sa setShape()
536 */
shape() const537 Qt::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 */
setShape(Qt::CursorShape shape)551 void 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 */
bitmap() const577 const 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 
mask() const593 const 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 */
bitmap(Qt::ReturnByValueConstant) const624 QBitmap 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 */
mask(Qt::ReturnByValueConstant) const656 QBitmap 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 
pixmap() const670 QPixmap 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 
hotSpot() const682 QPoint 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 
QCursor(const QCursor & c)693 QCursor::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 
~QCursor()705 QCursor::~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 
operator =(const QCursor & c)717 QCursor &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 */
operator QVariant() const732 QCursor::operator QVariant() const
733 {
734     return QVariant(QMetaType::QCursor, this);
735 }
736 
737 #ifndef QT_NO_DEBUG_STREAM
operator <<(QDebug dbg,const QCursor & c)738 QDebug 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 
750 QCursorData *qt_cursorTable[Qt::LastCursor + 1];
751 bool QCursorData::initialized = false;
752 
QCursorData(Qt::CursorShape s)753 QCursorData::QCursorData(Qt::CursorShape s)
754     : ref(1), cshape(s), bm(nullptr), bmm(nullptr), hx(0), hy(0)
755 {
756 }
757 
~QCursorData()758 QCursorData::~QCursorData()
759 {
760     delete bm;
761     delete bmm;
762 }
763 
764 /*! \internal */
cleanup()765 void 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 */
initialize()780 void 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 
setBitmap(const QBitmap & bitmap,const QBitmap & mask,int hotX,int hotY,qreal devicePixelRatio)789 QCursorData *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("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 
update()809 void QCursorData::update()
810 {
811 }
812 
813 QT_END_NAMESPACE
814 #endif // QT_NO_CURSOR
815 
816