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

KDEUI

  • sources
  • kde-4.14
  • kdelibs
  • 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 
60 namespace
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 
170 KCursor::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 
191 KCursor::KCursor( const QCursor &cursor )
192  : QCursor( cursor ), d( 0 )
193 {
194 }
195 
196 KCursor &KCursor::operator=( const KCursor &cursor )
197 {
198  QCursor::operator=( cursor );
199  return *this;
200 }
201 
202 void KCursor::setAutoHideCursor( QWidget *w, bool enable,
203  bool customEventFilter )
204 {
205  KCursorPrivate::self()->setAutoHideCursor( w, enable, customEventFilter );
206 }
207 
208 void KCursor::autoHideEventFilter( QObject *o, QEvent *e )
209 {
210  KCursorPrivate::self()->eventFilter( o, e );
211 }
212 
213 void KCursor::setHideCursorDelay( int ms )
214 {
215  KCursorPrivate::self()->hideCursorDelay = ms;
216 }
217 
218 int KCursor::hideCursorDelay()
219 {
220  return KCursorPrivate::self()->hideCursorDelay;
221 }
222 
223 // **************************************************************************
224 
225 KCursorPrivateAutoHideEventFilter::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 
236 KCursorPrivateAutoHideEventFilter::~KCursorPrivateAutoHideEventFilter()
237 {
238  if( m_widget != NULL )
239  mouseWidget()->setMouseTracking( m_wasMouseTracking );
240 }
241 
242 void KCursorPrivateAutoHideEventFilter::resetWidget()
243 {
244  m_widget = NULL;
245 }
246 
247 void 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 
265 void 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)
287 QWidget* 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 
299 bool 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 
339 KCursorPrivate * KCursorPrivate::s_self = 0L;
340 
341 KCursorPrivate * 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 
353 KCursorPrivate::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 
361 KCursorPrivate::~KCursorPrivate()
362 {
363 }
364 
365 void 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 
410 bool 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 
424 void KCursorPrivate::slotViewportDestroyed(QObject *o)
425 {
426  m_eventFilters.remove(o);
427 }
428 
429 void 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"
QEvent
QWidget
QEvent::type
Type type() const
QHash::insert
iterator insert(const Key &key, const T &value)
KCursor::setHideCursorDelay
static void setHideCursorDelay(int ms)
Sets the delay time in milliseconds for auto-hiding.
Definition: kcursor.cpp:213
QWidget::cursor
cursor
kdebug.h
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::hideCursorDelay
static int hideCursorDelay()
Definition: kcursor.cpp:218
timeout
int timeout
QAbstractScrollArea
QX11Info::display
Display * display()
KStandardAction::name
const char * name(StandardAction id)
This will return the internal name of a given standard action.
Definition: kstandardaction.cpp:223
QHash::reserve
void reserve(int size)
QAbstractScrollArea::viewport
QWidget * viewport() const
KCursor::operator=
KCursor & operator=(const KCursor &cursor)
Assigns cursor to this cursor, and returns a reference to this cursor.
Definition: kcursor.cpp:196
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
KGlobal::config
KSharedConfigPtr config()
kcursor.h
kglobal.h
QWidget::testAttribute
bool testAttribute(Qt::WidgetAttribute attribute) const
QObject::installEventFilter
void installEventFilter(QObject *filterObj)
QHash< QString, int >
QObject
ksharedconfig.h
Qt::HANDLE
typedef HANDLE
QString
KCursor::setAutoHideCursor
static void setAutoHideCursor(QWidget *w, bool enable, bool customEventFilter=false)
Sets auto-hiding the cursor for widget w.
Definition: kcursor.cpp:202
QHash::value
const T value(const Key &key) const
fixx11h.h
KConfigGroup
QLatin1String
QHash::isEmpty
bool isEmpty() const
QCursor::handle
HCURSOR_or_HANDLE handle() const
KCursor
The KCursor class extends QCursor with the ability to create an arbitrary named cursor from the curso...
Definition: kcursor.h:36
QCursor::operator=
QCursor & operator=(const QCursor &c)
QtConcurrent::filter
QFuture< void > filter(Sequence &sequence, FilterFunction filterFunction)
QCursor
QObject::removeEventFilter
void removeEventFilter(QObject *obj)
QFile::encodeName
QByteArray encodeName(const QString &fileName)
kconfiggroup.h
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:23:59 by doxygen 1.8.7 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 API Reference

Skip menu "kdelibs 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

Search



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