1 | // Copyright (C) 2016 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 "qfbcursor_p.h" |
5 | #include "qfbscreen_p.h" |
6 | #include <QtGui/QPainter> |
7 | #include <QtGui/private/qguiapplication_p.h> |
8 | |
9 | QT_BEGIN_NAMESPACE |
10 | |
11 | bool QFbCursorDeviceListener::hasMouse() const |
12 | { |
13 | return QGuiApplicationPrivate::inputDeviceManager()->deviceCount(type: QInputDeviceManager::DeviceTypePointer) > 0; |
14 | } |
15 | |
16 | void QFbCursorDeviceListener::onDeviceListChanged(QInputDeviceManager::DeviceType type) |
17 | { |
18 | if (type == QInputDeviceManager::DeviceTypePointer) |
19 | m_cursor->updateMouseStatus(); |
20 | } |
21 | |
22 | QFbCursor::QFbCursor(QFbScreen *screen) |
23 | : mVisible(true), |
24 | mScreen(screen), |
25 | mDirty(false), |
26 | mOnScreen(false), |
27 | mCursorImage(nullptr), |
28 | mDeviceListener(nullptr) |
29 | { |
30 | const char *envVar = "QT_QPA_FB_HIDECURSOR" ; |
31 | if (qEnvironmentVariableIsSet(varName: envVar)) |
32 | mVisible = qEnvironmentVariableIntValue(varName: envVar) == 0; |
33 | if (!mVisible) |
34 | return; |
35 | |
36 | mCursorImage.reset(other: new QPlatformCursorImage(0, 0, 0, 0, 0, 0)); |
37 | setCursor(Qt::ArrowCursor); |
38 | |
39 | mDeviceListener = new QFbCursorDeviceListener(this); |
40 | connect(sender: QGuiApplicationPrivate::inputDeviceManager(), signal: &QInputDeviceManager::deviceListChanged, |
41 | context: mDeviceListener, slot: &QFbCursorDeviceListener::onDeviceListChanged); |
42 | updateMouseStatus(); |
43 | } |
44 | |
45 | QFbCursor::~QFbCursor() |
46 | { |
47 | delete mDeviceListener; |
48 | } |
49 | |
50 | QRect QFbCursor::getCurrentRect() const |
51 | { |
52 | QRect rect = mCursorImage->image()->rect().translated(dx: -mCursorImage->hotspot().x(), |
53 | dy: -mCursorImage->hotspot().y()); |
54 | rect.translate(p: m_pos); |
55 | QPoint mScreenOffset = mScreen->geometry().topLeft(); |
56 | rect.translate(p: -mScreenOffset); // global to local translation |
57 | return rect; |
58 | } |
59 | |
60 | QPoint QFbCursor::pos() const |
61 | { |
62 | return m_pos; |
63 | } |
64 | |
65 | void QFbCursor::setPos(const QPoint &pos) |
66 | { |
67 | QGuiApplicationPrivate::inputDeviceManager()->setCursorPos(pos); |
68 | m_pos = pos; |
69 | if (!mVisible) |
70 | return; |
71 | mCurrentRect = getCurrentRect(); |
72 | if (mOnScreen || mScreen->geometry().intersects(r: mCurrentRect.translated(p: mScreen->geometry().topLeft()))) |
73 | setDirty(); |
74 | } |
75 | |
76 | void QFbCursor::pointerEvent(const QMouseEvent &e) |
77 | { |
78 | if (e.type() != QEvent::MouseMove) |
79 | return; |
80 | m_pos = e.globalPosition().toPoint(); |
81 | if (!mVisible) |
82 | return; |
83 | mCurrentRect = getCurrentRect(); |
84 | if (mOnScreen || mScreen->geometry().intersects(r: mCurrentRect.translated(p: mScreen->geometry().topLeft()))) |
85 | setDirty(); |
86 | } |
87 | |
88 | QRect QFbCursor::drawCursor(QPainter & painter) |
89 | { |
90 | if (!mVisible) |
91 | return QRect(); |
92 | |
93 | mDirty = false; |
94 | if (mCurrentRect.isNull()) |
95 | return QRect(); |
96 | |
97 | // We need this because the cursor might be mDirty due to moving off mScreen |
98 | QPoint mScreenOffset = mScreen->geometry().topLeft(); |
99 | // global to local translation |
100 | if (!mCurrentRect.translated(p: mScreenOffset).intersects(r: mScreen->geometry())) |
101 | return QRect(); |
102 | |
103 | mPrevRect = mCurrentRect; |
104 | painter.drawImage(r: mPrevRect, image: *mCursorImage->image()); |
105 | mOnScreen = true; |
106 | return mPrevRect; |
107 | } |
108 | |
109 | QRect QFbCursor::dirtyRect() |
110 | { |
111 | if (mOnScreen) { |
112 | mOnScreen = false; |
113 | return mPrevRect; |
114 | } |
115 | return QRect(); |
116 | } |
117 | |
118 | void QFbCursor::setCursor(Qt::CursorShape shape) |
119 | { |
120 | if (mCursorImage) |
121 | mCursorImage->set(shape); |
122 | } |
123 | |
124 | void QFbCursor::setCursor(const QImage &image, int hotx, int hoty) |
125 | { |
126 | if (mCursorImage) |
127 | mCursorImage->set(image, hx: hotx, hy: hoty); |
128 | } |
129 | |
130 | void QFbCursor::setCursor(const uchar *data, const uchar *mask, int width, int height, int hotX, int hotY) |
131 | { |
132 | if (mCursorImage) |
133 | mCursorImage->set(data, mask, width, height, hotX, hotY); |
134 | } |
135 | |
136 | #ifndef QT_NO_CURSOR |
137 | void QFbCursor::changeCursor(QCursor * widgetCursor, QWindow *window) |
138 | { |
139 | Q_UNUSED(window); |
140 | if (!mVisible) |
141 | return; |
142 | const Qt::CursorShape shape = widgetCursor ? widgetCursor->shape() : Qt::ArrowCursor; |
143 | |
144 | if (shape == Qt::BitmapCursor) { |
145 | // application supplied cursor |
146 | QPoint spot = widgetCursor->hotSpot(); |
147 | setCursor(image: widgetCursor->pixmap().toImage(), hotx: spot.x(), hoty: spot.y()); |
148 | } else { |
149 | // system cursor |
150 | setCursor(shape); |
151 | } |
152 | mCurrentRect = getCurrentRect(); |
153 | QPoint mScreenOffset = mScreen->geometry().topLeft(); // global to local translation |
154 | if (mOnScreen || mScreen->geometry().intersects(r: mCurrentRect.translated(p: mScreenOffset))) |
155 | setDirty(); |
156 | } |
157 | #endif |
158 | |
159 | void QFbCursor::setDirty() |
160 | { |
161 | if (!mVisible) |
162 | return; |
163 | |
164 | if (!mDirty) { |
165 | mDirty = true; |
166 | mScreen->scheduleUpdate(); |
167 | } |
168 | } |
169 | |
170 | void QFbCursor::updateMouseStatus() |
171 | { |
172 | mVisible = mDeviceListener ? mDeviceListener->hasMouse() : false; |
173 | mScreen->setDirty(mVisible ? getCurrentRect() : lastPainted()); |
174 | } |
175 | |
176 | QT_END_NAMESPACE |
177 | |
178 | #include "moc_qfbcursor_p.cpp" |
179 | |