00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
00063 static const char *standard_names[] = {
00064
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
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
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
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
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
00109
00110
00111
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
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
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 )
00277 return;
00278
00279 if ( m_isOwnCursor )
00280 w->setCursor( m_oldCursor );
00281 else
00282 w->unsetCursor();
00283 }
00284
00285
00286
00287 QWidget* KCursorPrivateAutoHideEventFilter::mouseWidget() const
00288 {
00289 QWidget* w = m_widget;
00290
00291
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
00303
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
00346
00347
00348
00349
00350 return s_self;
00351 }
00352
00353 KCursorPrivate::KCursorPrivate()
00354 {
00355 hideCursorDelay = 5000;
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 );
00387 if (viewport)
00388 viewport->installEventFilter( filter );
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();
00436 delete filter;
00437 }
00438
00439 #include "kcursor_p.moc"