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

KDEUI

kcursor.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002    Copyright (C) 1998 Kurt Granroth (granroth@kde.org)
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License version 2 as published by the Free Software Foundation.
00007 
00008    This library is distributed in the hope that it will be useful,
00009    but WITHOUT ANY WARRANTY; without even the implied warranty of
00010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011    Library General Public License for more details.
00012 
00013    You should have received a copy of the GNU Library General Public License
00014    along with this library; see the file COPYING.LIB.  If not, write to
00015    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016    Boston, MA 02110-1301, USA.
00017 */
00018 
00019 #ifdef KDE_USE_FINAL
00020 #ifdef KeyRelease
00021 #undef KeyRelease
00022 #endif
00023 #endif
00024 
00025 #include "kcursor.h"
00026 #include "kcursor_p.h"
00027 #include <kdebug.h>
00028 
00029 #include <QBitmap>
00030 #include <QCursor>
00031 #include <QEvent>
00032 #include <QAbstractScrollArea>
00033 #include <QTimer>
00034 #include <QWidget>
00035 #include <QFile>
00036 
00037 #include <kglobal.h>
00038 #include <ksharedconfig.h>
00039 #include <kconfiggroup.h>
00040 
00041 #include <config.h>
00042 
00043 #ifdef Q_WS_X11
00044 #include <QX11Info>
00045 
00046 #include <X11/Xlib.h>
00047 #include <X11/cursorfont.h>
00048 
00049 #ifdef HAVE_XCURSOR
00050 #  include <X11/Xcursor/Xcursor.h>
00051 #endif
00052 
00053 #ifdef HAVE_XFIXES
00054 #  include <X11/extensions/Xfixes.h>
00055 #endif
00056 
00057 #include <fixx11h.h>
00058 
00059 
00060 namespace
00061 {
00062     // Borrowed from xc/lib/Xcursor/library.c
00063     static const char *standard_names[] = {
00064         /* 0 */
00065         "X_cursor",         "arrow",            "based_arrow_down",     "based_arrow_up",
00066         "boat",             "bogosity",         "bottom_left_corner",   "bottom_right_corner",
00067         "bottom_side",      "bottom_tee",       "box_spiral",           "center_ptr",
00068         "circle",           "clock",            "coffee_mug",           "cross",
00069 
00070         /* 32 */
00071         "cross_reverse",    "crosshair",        "diamond_cross",        "dot",
00072         "dotbox",           "double_arrow",     "draft_large",          "draft_small",
00073         "draped_box",       "exchange",         "fleur",                "gobbler",
00074         "gumby",            "hand1",            "hand2",                "heart",
00075 
00076         /* 64 */
00077         "icon",             "iron_cross",       "left_ptr",             "left_side",
00078         "left_tee",         "leftbutton",       "ll_angle",             "lr_angle",
00079         "man",              "middlebutton",     "mouse",                "pencil",
00080         "pirate",           "plus",             "question_arrow",       "right_ptr",
00081 
00082         /* 96 */
00083         "right_side",       "right_tee",        "rightbutton",          "rtl_logo",
00084         "sailboat",         "sb_down_arrow",    "sb_h_double_arrow",    "sb_left_arrow",
00085         "sb_right_arrow",   "sb_up_arrow",      "sb_v_double_arrow",    "shuttle",
00086         "sizing",           "spider",           "spraycan",             "star",
00087 
00088         /* 128 */
00089         "target",           "tcross",           "top_left_arrow",       "top_left_corner",
00090         "top_right_corner", "top_side",         "top_tee",              "trek",
00091         "ul_angle",         "umbrella",         "ur_angle",             "watch",
00092         "xterm",
00093     };
00094 
00095     static Qt::HANDLE x11LoadXcursor(const QString &name)
00096     {
00097 #ifdef HAVE_XCURSOR
00098         return XcursorLibraryLoadCursor(QX11Info::display(), QFile::encodeName(name));
00099 #else
00100         return 0;
00101 #endif
00102     }
00103 
00104     static int x11CursorShape(const QString &name)
00105     {
00106         static QHash<QString, int> shapes;
00107 
00108         // A font cursor is created from two glyphs; a shape glyph and a mask glyph
00109         // stored in pairs in the font, with the shape glyph first. There's only one
00110         // name for each pair. This function always returns the index for the
00111         // shape glyph.
00112         if (shapes.isEmpty())
00113         {
00114             int num = XC_num_glyphs / 2;
00115             shapes.reserve(num + 5);
00116 
00117             for (int i = 0; i < num; ++i)
00118                 shapes.insert(standard_names[i], i << 1);
00119 
00120             // Qt uses alternative names for some core cursors
00121             shapes.insert("size_all",      XC_fleur);
00122             shapes.insert("up_arrow",      XC_center_ptr);
00123             shapes.insert("ibeam",         XC_xterm);
00124             shapes.insert("wait",          XC_watch);
00125             shapes.insert("pointing_hand", XC_hand2);
00126         }
00127 
00128         return shapes.value(name, -1);
00129     }
00130 
00131     static Qt::HANDLE x11LoadFontCursor(const QString &name)
00132     {
00133         int shape = x11CursorShape(name);
00134 
00135         if (shape != -1)
00136             return XCreateFontCursor(QX11Info::display(), shape);
00137 
00138         return 0;
00139     }
00140 
00141     bool x11HaveXfixes()
00142     {
00143         bool result = false;
00144 
00145 #ifdef HAVE_XFIXES
00146         int event_base, error_base;
00147         if (XFixesQueryExtension(QX11Info::display(), &event_base, &error_base))
00148         {
00149             int major, minor;
00150             XFixesQueryVersion(QX11Info::display(), &major, &minor);
00151             result = (major >= 2);
00152         }
00153 #endif
00154         return result;
00155     }
00156 
00157     static void x11SetCursorName(Qt::HANDLE handle, const QString &name)
00158     {
00159 #ifdef HAVE_XFIXES
00160         static bool haveXfixes = x11HaveXfixes();
00161 
00162         if (haveXfixes)
00163             XFixesSetCursorName(QX11Info::display(), handle, QFile::encodeName(name));
00164 #endif
00165     }
00166 }
00167 #endif // Q_WS_X11
00168 
00169 
00170 KCursor::KCursor( const QString& name, Qt::CursorShape fallback )
00171     : QCursor( fallback ),
00172       d( 0 )
00173 {
00174 #ifdef Q_WS_X11
00175     Qt::HANDLE handle = x11LoadXcursor(name);
00176 
00177     if (!handle)
00178         handle = x11LoadFontCursor(name);
00179 
00180     // Unfortunately QCursor doesn't have a setHandle()
00181     if (handle)
00182         *this = KCursor(handle);
00183 
00184     x11SetCursorName(QCursor::handle(), name);
00185 #else
00186     Q_UNUSED( name )
00187 #endif
00188 }
00189 
00190 
00191 KCursor::KCursor( const QCursor &cursor )
00192     : QCursor( cursor ), d( 0 )
00193 {
00194 }
00195 
00196 KCursor &KCursor::operator=( const KCursor &cursor )
00197 {
00198     QCursor::operator=( cursor );
00199     return *this;
00200 }
00201 
00202 void KCursor::setAutoHideCursor( QWidget *w, bool enable,
00203                                  bool customEventFilter )
00204 {
00205     KCursorPrivate::self()->setAutoHideCursor( w, enable, customEventFilter );
00206 }
00207 
00208 void KCursor::autoHideEventFilter( QObject *o, QEvent *e )
00209 {
00210     KCursorPrivate::self()->eventFilter( o, e );
00211 }
00212 
00213 void KCursor::setHideCursorDelay( int ms )
00214 {
00215     KCursorPrivate::self()->hideCursorDelay = ms;
00216 }
00217 
00218 int KCursor::hideCursorDelay()
00219 {
00220     return KCursorPrivate::self()->hideCursorDelay;
00221 }
00222 
00223 // **************************************************************************
00224 
00225 KCursorPrivateAutoHideEventFilter::KCursorPrivateAutoHideEventFilter( QWidget* widget )
00226     : m_widget( widget )
00227     , m_wasMouseTracking( m_widget->hasMouseTracking() )
00228     , m_isCursorHidden( false )
00229     , m_isOwnCursor( false )
00230 {
00231     mouseWidget()->setMouseTracking( true );
00232     connect( &m_autoHideTimer, SIGNAL( timeout() ),
00233              this, SLOT( hideCursor() ) );
00234 }
00235 
00236 KCursorPrivateAutoHideEventFilter::~KCursorPrivateAutoHideEventFilter()
00237 {
00238     if( m_widget != NULL )
00239         mouseWidget()->setMouseTracking( m_wasMouseTracking );
00240 }
00241 
00242 void KCursorPrivateAutoHideEventFilter::resetWidget()
00243 {
00244     m_widget = NULL;
00245 }
00246 
00247 void KCursorPrivateAutoHideEventFilter::hideCursor()
00248 {
00249     m_autoHideTimer.stop();
00250 
00251     if ( m_isCursorHidden )
00252         return;
00253 
00254     m_isCursorHidden = true;
00255 
00256     QWidget* w = mouseWidget();
00257 
00258     m_isOwnCursor = w->testAttribute(Qt::WA_SetCursor);
00259     if ( m_isOwnCursor )
00260         m_oldCursor = w->cursor();
00261 
00262     w->setCursor( QCursor( Qt::BlankCursor ) );
00263 }
00264 
00265 void KCursorPrivateAutoHideEventFilter::unhideCursor()
00266 {
00267     m_autoHideTimer.stop();
00268 
00269     if ( !m_isCursorHidden )
00270         return;
00271 
00272     m_isCursorHidden = false;
00273 
00274     QWidget* w = mouseWidget();
00275 
00276     if ( w->cursor().shape() != Qt::BlankCursor ) // someone messed with the cursor already
00277     return;
00278 
00279     if ( m_isOwnCursor )
00280         w->setCursor( m_oldCursor );
00281     else
00282         w->unsetCursor();
00283 }
00284 
00285 // The widget which gets mouse events, and that shows the cursor
00286 // (that is the viewport, for a QAbstractScrollArea)
00287 QWidget* KCursorPrivateAutoHideEventFilter::mouseWidget() const
00288 {
00289     QWidget* w = m_widget;
00290 
00291     // Is w a QAbstractScrollArea ? Call setCursor on the viewport in that case.
00292     QAbstractScrollArea * sv = qobject_cast<QAbstractScrollArea *>( w );
00293     if ( sv )
00294         w = sv->viewport();
00295 
00296     return w;
00297 }
00298 
00299 bool KCursorPrivateAutoHideEventFilter::eventFilter( QObject *o, QEvent *e )
00300 {
00301     Q_UNUSED(o);
00302     // o is m_widget or its viewport
00303     //Q_ASSERT( o == m_widget );
00304 
00305     switch ( e->type() )
00306     {
00307     case QEvent::Leave:
00308     case QEvent::FocusOut:
00309     case QEvent::WindowDeactivate:
00310         unhideCursor();
00311         break;
00312     case QEvent::KeyPress:
00313     case QEvent::ShortcutOverride:
00314         hideCursor();
00315         break;
00316     case QEvent::Enter:
00317     case QEvent::FocusIn:
00318     case QEvent::MouseButtonPress:
00319     case QEvent::MouseButtonRelease:
00320     case QEvent::MouseButtonDblClick:
00321     case QEvent::MouseMove:
00322     case QEvent::Show:
00323     case QEvent::Hide:
00324     case QEvent::Wheel:
00325         unhideCursor();
00326         if ( m_widget->hasFocus() )
00327         {
00328             m_autoHideTimer.setSingleShot( true );
00329             m_autoHideTimer.start( KCursorPrivate::self()->hideCursorDelay );
00330         }
00331         break;
00332     default:
00333         break;
00334     }
00335 
00336     return false;
00337 }
00338 
00339 KCursorPrivate * KCursorPrivate::s_self = 0L;
00340 
00341 KCursorPrivate * KCursorPrivate::self()
00342 {
00343     if ( !s_self )
00344         s_self = new KCursorPrivate;
00345     // WABA: Don't delete KCursorPrivate, it serves no real purpose.
00346     // Even worse it causes crashes because it seems to get deleted
00347     // during ~QApplication and ~QApplication doesn't seem to like it
00348     // when we delete a QCursor. No idea if that is a bug itself.
00349 
00350     return s_self;
00351 }
00352 
00353 KCursorPrivate::KCursorPrivate()
00354 {
00355     hideCursorDelay = 5000; // 5s default value
00356 
00357     KConfigGroup cg( KGlobal::config(), QLatin1String("KDE") );
00358     enabled = cg.readEntry( QLatin1String("Autohiding cursor enabled"), true);
00359 }
00360 
00361 KCursorPrivate::~KCursorPrivate()
00362 {
00363 }
00364 
00365 void KCursorPrivate::setAutoHideCursor( QWidget *w, bool enable, bool customEventFilter )
00366 {
00367     if ( !w || !enabled )
00368         return;
00369 
00370     QWidget* viewport = 0;
00371     QAbstractScrollArea * sv = qobject_cast<QAbstractScrollArea *>( w );
00372     if ( sv )
00373         viewport = sv->viewport();
00374 
00375     if ( enable )
00376     {
00377         if ( m_eventFilters.contains( w ) )
00378             return;
00379         KCursorPrivateAutoHideEventFilter* filter = new KCursorPrivateAutoHideEventFilter( w );
00380         m_eventFilters.insert( w, filter );
00381         if (viewport) {
00382             m_eventFilters.insert( viewport, filter );
00383             connect(viewport, SIGNAL(destroyed(QObject *)), this, SLOT(slotViewportDestroyed(QObject *)));
00384         }
00385         if ( !customEventFilter ) {
00386             w->installEventFilter( filter ); // for key events
00387             if (viewport)
00388                 viewport->installEventFilter( filter ); // for mouse events
00389         }
00390         connect( w, SIGNAL( destroyed(QObject*) ),
00391                  this, SLOT( slotWidgetDestroyed(QObject*) ) );
00392     }
00393     else
00394     {
00395         KCursorPrivateAutoHideEventFilter* filter = m_eventFilters.take( w );
00396         if ( filter == 0 )
00397             return;
00398         w->removeEventFilter( filter );
00399         if (viewport) {
00400             m_eventFilters.remove( viewport );
00401             disconnect(viewport, SIGNAL(destroyed(QObject *)), this, SLOT(slotViewportDestroyed(QObject *)));
00402             viewport->removeEventFilter( filter );
00403         }
00404         delete filter;
00405         disconnect( w, SIGNAL( destroyed(QObject*) ),
00406                     this, SLOT( slotWidgetDestroyed(QObject*) ) );
00407     }
00408 }
00409 
00410 bool KCursorPrivate::eventFilter( QObject *o, QEvent *e )
00411 {
00412     if ( !enabled )
00413         return false;
00414 
00415     KCursorPrivateAutoHideEventFilter* filter = m_eventFilters.value( o );
00416 
00417     Q_ASSERT( filter != 0 );
00418     if ( filter == 0 )
00419         return false;
00420 
00421     return filter->eventFilter( o, e );
00422 }
00423 
00424 void KCursorPrivate::slotViewportDestroyed(QObject *o)
00425 {
00426     m_eventFilters.remove(o);
00427 }
00428 
00429 void KCursorPrivate::slotWidgetDestroyed( QObject* o )
00430 {
00431     KCursorPrivateAutoHideEventFilter* filter = m_eventFilters.take( o );
00432 
00433     Q_ASSERT( filter != 0 );
00434 
00435     filter->resetWidget(); // so that dtor doesn't access it
00436     delete filter;
00437 }
00438 
00439 #include "kcursor_p.moc"

KDEUI

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

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal