KWidgetsAddons

kcursor.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 1998 Kurt Granroth <granroth@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-only
6*/
7
8#include "kcursor.h"
9#include "kcursor_p.h"
10
11#include <QAbstractScrollArea>
12#include <QCursor>
13#include <QEvent>
14#include <QTimer>
15#include <QWidget>
16
17void KCursor::setAutoHideCursor(QWidget *w, bool enable, bool customEventFilter)
18{
19 KCursorPrivate::self()->setAutoHideCursor(w, enable, customEventFilter);
20}
21
23{
24 KCursorPrivate::self()->eventFilter(o, e);
25}
26
28{
29 KCursorPrivate::self()->hideCursorDelay = ms;
30}
31
33{
34 return KCursorPrivate::self()->hideCursorDelay;
35}
36
37// **************************************************************************
38
39KCursorPrivateAutoHideEventFilter::KCursorPrivateAutoHideEventFilter(QWidget *widget)
40 : m_widget(widget)
41 , m_wasMouseTracking(m_widget->hasMouseTracking())
42 , m_isCursorHidden(false)
43 , m_isOwnCursor(false)
44{
45 mouseWidget()->setMouseTracking(true);
46 connect(&m_autoHideTimer, &QTimer::timeout, this, &KCursorPrivateAutoHideEventFilter::hideCursor);
47}
48
49KCursorPrivateAutoHideEventFilter::~KCursorPrivateAutoHideEventFilter()
50{
51 if (m_widget != nullptr) {
52 mouseWidget()->setMouseTracking(m_wasMouseTracking);
53 }
54}
55
56void KCursorPrivateAutoHideEventFilter::resetWidget()
57{
58 m_widget = nullptr;
59}
60
61void KCursorPrivateAutoHideEventFilter::hideCursor()
62{
63 m_autoHideTimer.stop();
64
65 if (m_isCursorHidden) {
66 return;
67 }
68
69 m_isCursorHidden = true;
70
71 QWidget *w = mouseWidget();
72
73 m_isOwnCursor = w->testAttribute(Qt::WA_SetCursor);
74 if (m_isOwnCursor) {
75 m_oldCursor = w->cursor();
76 }
77
79}
80
81void KCursorPrivateAutoHideEventFilter::unhideCursor()
82{
83 m_autoHideTimer.stop();
84
85 if (!m_isCursorHidden) {
86 return;
87 }
88
89 m_isCursorHidden = false;
90
91 QWidget *w = mouseWidget();
92
93 if (w->cursor().shape() != Qt::BlankCursor) { // someone messed with the cursor already
94 return;
95 }
96
97 if (m_isOwnCursor) {
98 w->setCursor(m_oldCursor);
99 } else {
100 w->unsetCursor();
101 }
102}
103
104// The widget which gets mouse events, and that shows the cursor
105// (that is the viewport, for a QAbstractScrollArea)
106QWidget *KCursorPrivateAutoHideEventFilter::mouseWidget() const
107{
108 QWidget *w = m_widget;
109
110 // Is w a QAbstractScrollArea ? Call setCursor on the viewport in that case.
111 QAbstractScrollArea *sv = qobject_cast<QAbstractScrollArea *>(w);
112 if (sv) {
113 w = sv->viewport();
114 }
115
116 return w;
117}
118
119bool KCursorPrivateAutoHideEventFilter::eventFilter(QObject *o, QEvent *e)
120{
121 Q_UNUSED(o);
122 // o is m_widget or its viewport
123 // Q_ASSERT( o == m_widget );
124
125 switch (e->type()) {
126 case QEvent::Leave:
127 case QEvent::FocusOut:
129 unhideCursor();
130 break;
131 case QEvent::KeyPress:
133 hideCursor();
134 break;
135 case QEvent::Enter:
136 case QEvent::FocusIn:
141 case QEvent::Show:
142 case QEvent::Hide:
143 case QEvent::Wheel:
144 unhideCursor();
145 if (m_widget->hasFocus()) {
146 m_autoHideTimer.setSingleShot(true);
147 m_autoHideTimer.start(KCursorPrivate::self()->hideCursorDelay);
148 }
149 break;
150 default:
151 break;
152 }
153
154 return false;
155}
156
157KCursorPrivate *KCursorPrivate::s_self = nullptr;
158
159KCursorPrivate *KCursorPrivate::self()
160{
161 if (!s_self) {
162 s_self = new KCursorPrivate;
163 }
164 // WABA: Don't delete KCursorPrivate, it serves no real purpose.
165 // Even worse it causes crashes because it seems to get deleted
166 // during ~QApplication and ~QApplication doesn't seem to like it
167 // when we delete a QCursor. No idea if that is a bug itself.
168
169 return s_self;
170}
171
172KCursorPrivate::KCursorPrivate()
173{
174 hideCursorDelay = 5000; // 5s default value
175 enabled = true;
176}
177
178KCursorPrivate::~KCursorPrivate()
179{
180}
181
182void KCursorPrivate::setAutoHideCursor(QWidget *w, bool enable, bool customEventFilter)
183{
184 if (!w || !enabled) {
185 return;
186 }
187
188 QWidget *viewport = nullptr;
189 QAbstractScrollArea *sv = qobject_cast<QAbstractScrollArea *>(w);
190 if (sv) {
191 viewport = sv->viewport();
192 }
193
194 if (enable) {
195 if (m_eventFilters.contains(w)) {
196 return;
197 }
198 KCursorPrivateAutoHideEventFilter *filter = new KCursorPrivateAutoHideEventFilter(w);
199 m_eventFilters.insert(w, filter);
200 if (viewport) {
201 m_eventFilters.insert(viewport, filter);
202 connect(viewport, &QObject::destroyed, this, &KCursorPrivate::slotViewportDestroyed);
203 }
204 if (!customEventFilter) {
205 w->installEventFilter(filter); // for key events
206 if (viewport) {
207 viewport->installEventFilter(filter); // for mouse events
208 }
209 }
210 connect(w, &QObject::destroyed, this, &KCursorPrivate::slotWidgetDestroyed);
211 } else {
212 KCursorPrivateAutoHideEventFilter *filter = m_eventFilters.take(w);
213 if (filter == nullptr) {
214 return;
215 }
216 w->removeEventFilter(filter);
217 if (viewport) {
218 m_eventFilters.remove(viewport);
219 disconnect(viewport, &QObject::destroyed, this, &KCursorPrivate::slotViewportDestroyed);
220 viewport->removeEventFilter(filter);
221 }
222 delete filter;
223 disconnect(w, &QObject::destroyed, this, &KCursorPrivate::slotWidgetDestroyed);
224 }
225}
226
227bool KCursorPrivate::eventFilter(QObject *o, QEvent *e)
228{
229 if (!enabled || e->type() == QEvent::ChildAdded) {
230 return false;
231 }
232
233 KCursorPrivateAutoHideEventFilter *filter = m_eventFilters.value(o);
234
235 Q_ASSERT(filter != nullptr);
236 if (filter == nullptr) {
237 return false;
238 }
239
240 return filter->eventFilter(o, e);
241}
242
243void KCursorPrivate::slotViewportDestroyed(QObject *o)
244{
245 m_eventFilters.remove(o);
246}
247
248void KCursorPrivate::slotWidgetDestroyed(QObject *o)
249{
250 KCursorPrivateAutoHideEventFilter *filter = m_eventFilters.take(o);
251
252 Q_ASSERT(filter != nullptr);
253
254 filter->resetWidget(); // so that dtor doesn't access it
255 delete filter;
256}
257
258#include "moc_kcursor_p.cpp"
static void setAutoHideCursor(QWidget *w, bool enable, bool customEventFilter=false)
Sets auto-hiding the cursor for widget w.
Definition kcursor.cpp:17
static int hideCursorDelay()
Definition kcursor.cpp:32
static void setHideCursorDelay(int ms)
Sets the delay time in milliseconds for auto-hiding.
Definition kcursor.cpp:27
static void autoHideEventFilter(QObject *, QEvent *)
KCursor has to install an eventFilter over the widget you want to auto-hide.
Definition kcursor.cpp:22
QWidget * viewport() const const
Type type() const const
void destroyed(QObject *obj)
void installEventFilter(QObject *filterObj)
void removeEventFilter(QObject *obj)
BlankCursor
WA_SetCursor
QFuture< void > filter(QThreadPool *pool, Sequence &sequence, KeepFunctor &&filterFunction)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void timeout()
bool testAttribute(Qt::WidgetAttribute attribute) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:43 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.