• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KDEUI

  • kdeui
  • util
kcursor.cpp
Go to the documentation of this file.
1/* This file is part of the KDE libraries
2 Copyright (C) 1998 Kurt Granroth (granroth@kde.org)
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License version 2 as published by the Free Software Foundation.
7
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
12
13 You should have received a copy of the GNU Library General Public License
14 along with this library; see the file COPYING.LIB. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
17*/
18
19#ifdef KDE_USE_FINAL
20#ifdef KeyRelease
21#undef KeyRelease
22#endif
23#endif
24
25#include "kcursor.h"
26#include "kcursor_p.h"
27#include <kdebug.h>
28
29#include <QBitmap>
30#include <QCursor>
31#include <QEvent>
32#include <QAbstractScrollArea>
33#include <QTimer>
34#include <QWidget>
35#include <QFile>
36
37#include <kglobal.h>
38#include <ksharedconfig.h>
39#include <kconfiggroup.h>
40
41#include <config.h>
42
43#ifdef Q_WS_X11
44#include <QX11Info>
45
46#include <X11/Xlib.h>
47#include <X11/cursorfont.h>
48
49#ifdef HAVE_XCURSOR
50# include <X11/Xcursor/Xcursor.h>
51#endif
52
53#ifdef HAVE_XFIXES
54# include <X11/extensions/Xfixes.h>
55#endif
56
57#include <fixx11h.h>
58
59
60namespace
61{
62 // Borrowed from xc/lib/Xcursor/library.c
63 static const char * const standard_names[] = {
64 /* 0 */
65 "X_cursor", "arrow", "based_arrow_down", "based_arrow_up",
66 "boat", "bogosity", "bottom_left_corner", "bottom_right_corner",
67 "bottom_side", "bottom_tee", "box_spiral", "center_ptr",
68 "circle", "clock", "coffee_mug", "cross",
69
70 /* 32 */
71 "cross_reverse", "crosshair", "diamond_cross", "dot",
72 "dotbox", "double_arrow", "draft_large", "draft_small",
73 "draped_box", "exchange", "fleur", "gobbler",
74 "gumby", "hand1", "hand2", "heart",
75
76 /* 64 */
77 "icon", "iron_cross", "left_ptr", "left_side",
78 "left_tee", "leftbutton", "ll_angle", "lr_angle",
79 "man", "middlebutton", "mouse", "pencil",
80 "pirate", "plus", "question_arrow", "right_ptr",
81
82 /* 96 */
83 "right_side", "right_tee", "rightbutton", "rtl_logo",
84 "sailboat", "sb_down_arrow", "sb_h_double_arrow", "sb_left_arrow",
85 "sb_right_arrow", "sb_up_arrow", "sb_v_double_arrow", "shuttle",
86 "sizing", "spider", "spraycan", "star",
87
88 /* 128 */
89 "target", "tcross", "top_left_arrow", "top_left_corner",
90 "top_right_corner", "top_side", "top_tee", "trek",
91 "ul_angle", "umbrella", "ur_angle", "watch",
92 "xterm",
93 };
94
95 static Qt::HANDLE x11LoadXcursor(const QString &name)
96 {
97#ifdef HAVE_XCURSOR
98 return XcursorLibraryLoadCursor(QX11Info::display(), QFile::encodeName(name));
99#else
100 return 0;
101#endif
102 }
103
104 static int x11CursorShape(const QString &name)
105 {
106 static QHash<QString, int> shapes;
107
108 // A font cursor is created from two glyphs; a shape glyph and a mask glyph
109 // stored in pairs in the font, with the shape glyph first. There's only one
110 // name for each pair. This function always returns the index for the
111 // shape glyph.
112 if (shapes.isEmpty())
113 {
114 int num = XC_num_glyphs / 2;
115 shapes.reserve(num + 5);
116
117 for (int i = 0; i < num; ++i)
118 shapes.insert(standard_names[i], i << 1);
119
120 // Qt uses alternative names for some core cursors
121 shapes.insert("size_all", XC_fleur);
122 shapes.insert("up_arrow", XC_center_ptr);
123 shapes.insert("ibeam", XC_xterm);
124 shapes.insert("wait", XC_watch);
125 shapes.insert("pointing_hand", XC_hand2);
126 }
127
128 return shapes.value(name, -1);
129 }
130
131 static Qt::HANDLE x11LoadFontCursor(const QString &name)
132 {
133 int shape = x11CursorShape(name);
134
135 if (shape != -1)
136 return XCreateFontCursor(QX11Info::display(), shape);
137
138 return 0;
139 }
140
141 bool x11HaveXfixes()
142 {
143 bool result = false;
144
145#ifdef HAVE_XFIXES
146 int event_base, error_base;
147 if (XFixesQueryExtension(QX11Info::display(), &event_base, &error_base))
148 {
149 int major, minor;
150 XFixesQueryVersion(QX11Info::display(), &major, &minor);
151 result = (major >= 2);
152 }
153#endif
154 return result;
155 }
156
157 static void x11SetCursorName(Qt::HANDLE handle, const QString &name)
158 {
159#ifdef HAVE_XFIXES
160 static bool haveXfixes = x11HaveXfixes();
161
162 if (haveXfixes)
163 XFixesSetCursorName(QX11Info::display(), handle, QFile::encodeName(name));
164#endif
165 }
166}
167#endif // Q_WS_X11
168
169
170KCursor::KCursor( const QString& name, Qt::CursorShape fallback )
171 : QCursor( fallback ),
172 d( 0 )
173{
174#ifdef Q_WS_X11
175 Qt::HANDLE handle = x11LoadXcursor(name);
176
177 if (!handle)
178 handle = x11LoadFontCursor(name);
179
180 // Unfortunately QCursor doesn't have a setHandle()
181 if (handle)
182 *this = KCursor(handle);
183
184 x11SetCursorName(QCursor::handle(), name);
185#else
186 Q_UNUSED( name )
187#endif
188}
189
190
191KCursor::KCursor( const QCursor &cursor )
192 : QCursor( cursor ), d( 0 )
193{
194}
195
196KCursor &KCursor::operator=( const KCursor &cursor )
197{
198 QCursor::operator=( cursor );
199 return *this;
200}
201
202void KCursor::setAutoHideCursor( QWidget *w, bool enable,
203 bool customEventFilter )
204{
205 KCursorPrivate::self()->setAutoHideCursor( w, enable, customEventFilter );
206}
207
208void KCursor::autoHideEventFilter( QObject *o, QEvent *e )
209{
210 KCursorPrivate::self()->eventFilter( o, e );
211}
212
213void KCursor::setHideCursorDelay( int ms )
214{
215 KCursorPrivate::self()->hideCursorDelay = ms;
216}
217
218int KCursor::hideCursorDelay()
219{
220 return KCursorPrivate::self()->hideCursorDelay;
221}
222
223// **************************************************************************
224
225KCursorPrivateAutoHideEventFilter::KCursorPrivateAutoHideEventFilter( QWidget* widget )
226 : m_widget( widget )
227 , m_wasMouseTracking( m_widget->hasMouseTracking() )
228 , m_isCursorHidden( false )
229 , m_isOwnCursor( false )
230{
231 mouseWidget()->setMouseTracking( true );
232 connect( &m_autoHideTimer, SIGNAL(timeout()),
233 this, SLOT(hideCursor()) );
234}
235
236KCursorPrivateAutoHideEventFilter::~KCursorPrivateAutoHideEventFilter()
237{
238 if( m_widget != NULL )
239 mouseWidget()->setMouseTracking( m_wasMouseTracking );
240}
241
242void KCursorPrivateAutoHideEventFilter::resetWidget()
243{
244 m_widget = NULL;
245}
246
247void KCursorPrivateAutoHideEventFilter::hideCursor()
248{
249 m_autoHideTimer.stop();
250
251 if ( m_isCursorHidden )
252 return;
253
254 m_isCursorHidden = true;
255
256 QWidget* w = mouseWidget();
257
258 m_isOwnCursor = w->testAttribute(Qt::WA_SetCursor);
259 if ( m_isOwnCursor )
260 m_oldCursor = w->cursor();
261
262 w->setCursor( QCursor( Qt::BlankCursor ) );
263}
264
265void KCursorPrivateAutoHideEventFilter::unhideCursor()
266{
267 m_autoHideTimer.stop();
268
269 if ( !m_isCursorHidden )
270 return;
271
272 m_isCursorHidden = false;
273
274 QWidget* w = mouseWidget();
275
276 if ( w->cursor().shape() != Qt::BlankCursor ) // someone messed with the cursor already
277 return;
278
279 if ( m_isOwnCursor )
280 w->setCursor( m_oldCursor );
281 else
282 w->unsetCursor();
283}
284
285// The widget which gets mouse events, and that shows the cursor
286// (that is the viewport, for a QAbstractScrollArea)
287QWidget* KCursorPrivateAutoHideEventFilter::mouseWidget() const
288{
289 QWidget* w = m_widget;
290
291 // Is w a QAbstractScrollArea ? Call setCursor on the viewport in that case.
292 QAbstractScrollArea * sv = qobject_cast<QAbstractScrollArea *>( w );
293 if ( sv )
294 w = sv->viewport();
295
296 return w;
297}
298
299bool KCursorPrivateAutoHideEventFilter::eventFilter( QObject *o, QEvent *e )
300{
301 Q_UNUSED(o);
302 // o is m_widget or its viewport
303 //Q_ASSERT( o == m_widget );
304
305 switch ( e->type() )
306 {
307 case QEvent::Leave:
308 case QEvent::FocusOut:
309 case QEvent::WindowDeactivate:
310 unhideCursor();
311 break;
312 case QEvent::KeyPress:
313 case QEvent::ShortcutOverride:
314 hideCursor();
315 break;
316 case QEvent::Enter:
317 case QEvent::FocusIn:
318 case QEvent::MouseButtonPress:
319 case QEvent::MouseButtonRelease:
320 case QEvent::MouseButtonDblClick:
321 case QEvent::MouseMove:
322 case QEvent::Show:
323 case QEvent::Hide:
324 case QEvent::Wheel:
325 unhideCursor();
326 if ( m_widget->hasFocus() )
327 {
328 m_autoHideTimer.setSingleShot( true );
329 m_autoHideTimer.start( KCursorPrivate::self()->hideCursorDelay );
330 }
331 break;
332 default:
333 break;
334 }
335
336 return false;
337}
338
339KCursorPrivate * KCursorPrivate::s_self = 0L;
340
341KCursorPrivate * KCursorPrivate::self()
342{
343 if ( !s_self )
344 s_self = new KCursorPrivate;
345 // WABA: Don't delete KCursorPrivate, it serves no real purpose.
346 // Even worse it causes crashes because it seems to get deleted
347 // during ~QApplication and ~QApplication doesn't seem to like it
348 // when we delete a QCursor. No idea if that is a bug itself.
349
350 return s_self;
351}
352
353KCursorPrivate::KCursorPrivate()
354{
355 hideCursorDelay = 5000; // 5s default value
356
357 KConfigGroup cg( KGlobal::config(), QLatin1String("KDE") );
358 enabled = cg.readEntry( QLatin1String("Autohiding cursor enabled"), true);
359}
360
361KCursorPrivate::~KCursorPrivate()
362{
363}
364
365void KCursorPrivate::setAutoHideCursor( QWidget *w, bool enable, bool customEventFilter )
366{
367 if ( !w || !enabled )
368 return;
369
370 QWidget* viewport = 0;
371 QAbstractScrollArea * sv = qobject_cast<QAbstractScrollArea *>( w );
372 if ( sv )
373 viewport = sv->viewport();
374
375 if ( enable )
376 {
377 if ( m_eventFilters.contains( w ) )
378 return;
379 KCursorPrivateAutoHideEventFilter* filter = new KCursorPrivateAutoHideEventFilter( w );
380 m_eventFilters.insert( w, filter );
381 if (viewport) {
382 m_eventFilters.insert( viewport, filter );
383 connect(viewport, SIGNAL(destroyed(QObject*)), this, SLOT(slotViewportDestroyed(QObject*)));
384 }
385 if ( !customEventFilter ) {
386 w->installEventFilter( filter ); // for key events
387 if (viewport)
388 viewport->installEventFilter( filter ); // for mouse events
389 }
390 connect( w, SIGNAL(destroyed(QObject*)),
391 this, SLOT(slotWidgetDestroyed(QObject*)) );
392 }
393 else
394 {
395 KCursorPrivateAutoHideEventFilter* filter = m_eventFilters.take( w );
396 if ( filter == 0 )
397 return;
398 w->removeEventFilter( filter );
399 if (viewport) {
400 m_eventFilters.remove( viewport );
401 disconnect(viewport, SIGNAL(destroyed(QObject*)), this, SLOT(slotViewportDestroyed(QObject*)));
402 viewport->removeEventFilter( filter );
403 }
404 delete filter;
405 disconnect( w, SIGNAL(destroyed(QObject*)),
406 this, SLOT(slotWidgetDestroyed(QObject*)) );
407 }
408}
409
410bool KCursorPrivate::eventFilter( QObject *o, QEvent *e )
411{
412 if ( !enabled )
413 return false;
414
415 KCursorPrivateAutoHideEventFilter* filter = m_eventFilters.value( o );
416
417 Q_ASSERT( filter != 0 );
418 if ( filter == 0 )
419 return false;
420
421 return filter->eventFilter( o, e );
422}
423
424void KCursorPrivate::slotViewportDestroyed(QObject *o)
425{
426 m_eventFilters.remove(o);
427}
428
429void KCursorPrivate::slotWidgetDestroyed( QObject* o )
430{
431 KCursorPrivateAutoHideEventFilter* filter = m_eventFilters.take( o );
432
433 Q_ASSERT( filter != 0 );
434
435 filter->resetWidget(); // so that dtor doesn't access it
436 delete filter;
437}
438
439#include "kcursor_p.moc"
KConfigGroup
KCursor
The KCursor class extends QCursor with the ability to create an arbitrary named cursor from the curso...
Definition: kcursor.h:37
KCursor::operator=
KCursor & operator=(const KCursor &cursor)
Assigns cursor to this cursor, and returns a reference to this cursor.
Definition: kcursor.cpp:196
KCursor::setAutoHideCursor
static void setAutoHideCursor(QWidget *w, bool enable, bool customEventFilter=false)
Sets auto-hiding the cursor for widget w.
Definition: kcursor.cpp:202
KCursor::hideCursorDelay
static int hideCursorDelay()
Definition: kcursor.cpp:218
KCursor::KCursor
KCursor(const QString &name, Qt::CursorShape fallback=Qt::ArrowCursor)
Attempts to load the requested name cursor from the current theme.
Definition: kcursor.cpp:170
KCursor::setHideCursorDelay
static void setHideCursorDelay(int ms)
Sets the delay time in milliseconds for auto-hiding.
Definition: kcursor.cpp:213
KCursor::autoHideEventFilter
static void autoHideEventFilter(QObject *, QEvent *)
KCursor has to install an eventFilter over the widget you want to auto-hide.
Definition: kcursor.cpp:208
QCursor
QHash
QObject
QWidget
fixx11h.h
kconfiggroup.h
kcursor.h
kdebug.h
kglobal.h
timeout
int timeout
ksharedconfig.h
KGlobal::config
KSharedConfigPtr config()
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEUI

Skip menu "KDEUI"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Modules
  • Related Pages

kdelibs-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal