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