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 plugins 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 "qfbcursor_p.h"
41#include "qfbscreen_p.h"
42#include <QtGui/QPainter>
43#include <QtGui/private/qguiapplication_p.h>
44
45QT_BEGIN_NAMESPACE
46
47bool QFbCursorDeviceListener::hasMouse() const
48{
49 return QGuiApplicationPrivate::inputDeviceManager()->deviceCount(QInputDeviceManager::DeviceTypePointer) > 0;
50}
51
52void QFbCursorDeviceListener::onDeviceListChanged(QInputDeviceManager::DeviceType type)
53{
54 if (type == QInputDeviceManager::DeviceTypePointer)
55 m_cursor->updateMouseStatus();
56}
57
58QFbCursor::QFbCursor(QFbScreen *screen)
59 : mVisible(true),
60 mScreen(screen),
61 mDirty(false),
62 mOnScreen(false),
63 mCursorImage(nullptr),
64 mDeviceListener(nullptr)
65{
66 const char *envVar = "QT_QPA_FB_HIDECURSOR";
67 if (qEnvironmentVariableIsSet(envVar))
68 mVisible = qEnvironmentVariableIntValue(envVar) == 0;
69 if (!mVisible)
70 return;
71
72 mCursorImage = new QPlatformCursorImage(0, 0, 0, 0, 0, 0);
73 setCursor(Qt::ArrowCursor);
74
75 mDeviceListener = new QFbCursorDeviceListener(this);
76 connect(QGuiApplicationPrivate::inputDeviceManager(), &QInputDeviceManager::deviceListChanged,
77 mDeviceListener, &QFbCursorDeviceListener::onDeviceListChanged);
78 updateMouseStatus();
79}
80
81QFbCursor::~QFbCursor()
82{
83 delete mDeviceListener;
84}
85
86QRect QFbCursor::getCurrentRect() const
87{
88 QRect rect = mCursorImage->image()->rect().translated(-mCursorImage->hotspot().x(),
89 -mCursorImage->hotspot().y());
90 rect.translate(m_pos);
91 QPoint mScreenOffset = mScreen->geometry().topLeft();
92 rect.translate(-mScreenOffset); // global to local translation
93 return rect;
94}
95
96QPoint QFbCursor::pos() const
97{
98 return m_pos;
99}
100
101void QFbCursor::setPos(const QPoint &pos)
102{
103 QGuiApplicationPrivate::inputDeviceManager()->setCursorPos(pos);
104 m_pos = pos;
105 if (!mVisible)
106 return;
107 mCurrentRect = getCurrentRect();
108 if (mOnScreen || mScreen->geometry().intersects(mCurrentRect.translated(mScreen->geometry().topLeft())))
109 setDirty();
110}
111
112void QFbCursor::pointerEvent(const QMouseEvent &e)
113{
114 if (e.type() != QEvent::MouseMove)
115 return;
116 m_pos = e.globalPosition().toPoint();
117 if (!mVisible)
118 return;
119 mCurrentRect = getCurrentRect();
120 if (mOnScreen || mScreen->geometry().intersects(mCurrentRect.translated(mScreen->geometry().topLeft())))
121 setDirty();
122}
123
124QRect QFbCursor::drawCursor(QPainter & painter)
125{
126 if (!mVisible)
127 return QRect();
128
129 mDirty = false;
130 if (mCurrentRect.isNull())
131 return QRect();
132
133 // We need this because the cursor might be mDirty due to moving off mScreen
134 QPoint mScreenOffset = mScreen->geometry().topLeft();
135 // global to local translation
136 if (!mCurrentRect.translated(mScreenOffset).intersects(mScreen->geometry()))
137 return QRect();
138
139 mPrevRect = mCurrentRect;
140 painter.drawImage(mPrevRect, *mCursorImage->image());
141 mOnScreen = true;
142 return mPrevRect;
143}
144
145QRect QFbCursor::dirtyRect()
146{
147 if (mOnScreen) {
148 mOnScreen = false;
149 return mPrevRect;
150 }
151 return QRect();
152}
153
154void QFbCursor::setCursor(Qt::CursorShape shape)
155{
156 if (mCursorImage)
157 mCursorImage->set(shape);
158}
159
160void QFbCursor::setCursor(const QImage &image, int hotx, int hoty)
161{
162 if (mCursorImage)
163 mCursorImage->set(image, hotx, hoty);
164}
165
166void QFbCursor::setCursor(const uchar *data, const uchar *mask, int width, int height, int hotX, int hotY)
167{
168 if (mCursorImage)
169 mCursorImage->set(data, mask, width, height, hotX, hotY);
170}
171
172#ifndef QT_NO_CURSOR
173void QFbCursor::changeCursor(QCursor * widgetCursor, QWindow *window)
174{
175 Q_UNUSED(window);
176 if (!mVisible)
177 return;
178 const Qt::CursorShape shape = widgetCursor ? widgetCursor->shape() : Qt::ArrowCursor;
179
180 if (shape == Qt::BitmapCursor) {
181 // application supplied cursor
182 QPoint spot = widgetCursor->hotSpot();
183 setCursor(widgetCursor->pixmap().toImage(), spot.x(), spot.y());
184 } else {
185 // system cursor
186 setCursor(shape);
187 }
188 mCurrentRect = getCurrentRect();
189 QPoint mScreenOffset = mScreen->geometry().topLeft(); // global to local translation
190 if (mOnScreen || mScreen->geometry().intersects(mCurrentRect.translated(mScreenOffset)))
191 setDirty();
192}
193#endif
194
195void QFbCursor::setDirty()
196{
197 if (!mVisible)
198 return;
199
200 if (!mDirty) {
201 mDirty = true;
202 mScreen->scheduleUpdate();
203 }
204}
205
206void QFbCursor::updateMouseStatus()
207{
208 mVisible = mDeviceListener ? mDeviceListener->hasMouse() : false;
209 mScreen->setDirty(mVisible ? getCurrentRect() : lastPainted());
210}
211
212QT_END_NAMESPACE
213