kcursor.cpp
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 00027 #include <qbitmap.h> 00028 #include <qcursor.h> 00029 #include <qevent.h> 00030 #include <qtimer.h> 00031 #include <qwidget.h> 00032 00033 #include <kglobal.h> 00034 #include <kconfig.h> 00035 #include <qscrollview.h> 00036 00037 #include "kcursor_private.h" 00038 00039 KCursor::KCursor() 00040 { 00041 } 00042 00043 QCursor KCursor::handCursor() 00044 { 00045 static QCursor *hand_cursor = 0; 00046 00047 if (!hand_cursor) 00048 { 00049 KConfig *config = KGlobal::config(); 00050 KConfigGroupSaver saver( config, "General" ); 00051 00052 #ifndef Q_WS_WIN // this mask doesn't work too well on win32 00053 if ( config->readEntry("handCursorStyle", "Windows") == "Windows" ) 00054 { 00055 static const unsigned char HAND_BITS[] = { 00056 0x80, 0x01, 0x00, 0x40, 0x02, 0x00, 0x40, 0x02, 0x00, 0x40, 0x02, 00057 0x00, 0x40, 0x02, 0x00, 0x40, 0x02, 0x00, 0x40, 0x1e, 0x00, 0x40, 00058 0xf2, 0x00, 0x40, 0x92, 0x01, 0x70, 0x92, 0x02, 0x50, 0x92, 0x04, 00059 0x48, 0x80, 0x04, 0x48, 0x00, 0x04, 0x48, 0x00, 0x04, 0x08, 0x00, 00060 0x04, 0x08, 0x00, 0x04, 0x10, 0x00, 0x04, 0x10, 0x00, 0x04, 0x20, 00061 0x00, 0x02, 0x40, 0x00, 0x02, 0x40, 0x00, 0x01, 0xc0, 0xff, 0x01}; 00062 static const unsigned char HAND_MASK_BITS[] = { 00063 0x80, 0x01, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 00064 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x1f, 0x00, 0xc0, 00065 0xff, 0x00, 0xc0, 0xff, 0x01, 0xf0, 0xff, 0x03, 0xf0, 0xff, 0x07, 00066 0xf8, 0xff, 0x07, 0xf8, 0xff, 0x07, 0xf8, 0xff, 0x07, 0xf8, 0xff, 00067 0x07, 0xf8, 0xff, 0x07, 0xf0, 0xff, 0x07, 0xf0, 0xff, 0x07, 0xe0, 00068 0xff, 0x03, 0xc0, 0xff, 0x03, 0xc0, 0xff, 0x01, 0xc0, 0xff, 0x01}; 00069 QBitmap hand_bitmap(22, 22, HAND_BITS, true); 00070 QBitmap hand_mask(22, 22, HAND_MASK_BITS, true); 00071 hand_cursor = new QCursor(hand_bitmap, hand_mask, 7, 0); 00072 // Hack to force QCursor to call XCreatePixmapCursor() immediately 00073 // so the bitmaps don't get pushed out of the Xcursor LRU cache. 00074 hand_cursor->handle(); 00075 } 00076 else 00077 #endif //! Q_WS_WIN 00078 hand_cursor = new QCursor(PointingHandCursor); 00079 } 00080 00081 Q_CHECK_PTR(hand_cursor); 00082 return *hand_cursor; 00083 } 00084 00085 /* XPM */ 00086 static const char * const working_cursor_xpm[]={ 00087 "32 32 3 1", 00088 "# c None", 00089 "a c #000000", 00090 ". c #ffffff", 00091 "..##############################", 00092 ".a.##########.aaaa.#############", 00093 ".aa.#########.aaaa.#############", 00094 ".aaa.#######.aaaaaa.############", 00095 ".aaaa.#####.a...a..a..##########", 00096 ".aaaaa.####a....a...aa##########", 00097 ".aaaaaa.###a...aa...aa##########", 00098 ".aaaaaaa.##a..a.....aa##########", 00099 ".aaaaaaaa.#.aa.....a..##########", 00100 ".aaaaa....##.aaaaaa.############", 00101 ".aa.aa.######.aaaa.#############", 00102 ".a.#.aa.#####.aaaa.#############", 00103 "..##.aa.########################", 00104 "#####.aa.#######################", 00105 "#####.aa.#######################", 00106 "######..########################", 00107 "################################", 00108 "################################", 00109 "################################", 00110 "################################", 00111 "################################", 00112 "################################", 00113 "################################", 00114 "################################", 00115 "################################", 00116 "################################", 00117 "################################", 00118 "################################", 00119 "################################", 00120 "################################", 00121 "################################", 00122 "################################"}; 00123 00124 00125 QCursor KCursor::workingCursor() 00126 { 00127 static QCursor *working_cursor = 0; 00128 00129 if (!working_cursor) 00130 { 00131 QPixmap pm( const_cast< const char** >( working_cursor_xpm )); 00132 working_cursor = new QCursor( pm, 1, 1 ); 00133 // Hack to force QCursor to call XCreatePixmapCursor() immediately 00134 // so the bitmaps don't get pushed out of the Xcursor LRU cache. 00135 working_cursor->handle(); 00136 } 00137 00138 Q_CHECK_PTR(working_cursor); 00139 return *working_cursor; 00140 } 00141 00146 QCursor KCursor::arrowCursor() 00147 { 00148 return Qt::arrowCursor; 00149 } 00150 00151 00152 QCursor KCursor::upArrowCursor() 00153 { 00154 return Qt::upArrowCursor; 00155 } 00156 00157 00158 QCursor KCursor::crossCursor() 00159 { 00160 return Qt::crossCursor; 00161 } 00162 00163 00164 QCursor KCursor::waitCursor() 00165 { 00166 return Qt::waitCursor; 00167 } 00168 00169 00170 QCursor KCursor::ibeamCursor() 00171 { 00172 return Qt::ibeamCursor; 00173 } 00174 00175 00176 QCursor KCursor::sizeVerCursor() 00177 { 00178 return Qt::sizeVerCursor; 00179 } 00180 00181 00182 QCursor KCursor::sizeHorCursor() 00183 { 00184 return Qt::sizeHorCursor; 00185 } 00186 00187 00188 QCursor KCursor::sizeBDiagCursor() 00189 { 00190 return Qt::sizeBDiagCursor; 00191 } 00192 00193 00194 QCursor KCursor::sizeFDiagCursor() 00195 { 00196 return Qt::sizeFDiagCursor; 00197 } 00198 00199 00200 QCursor KCursor::sizeAllCursor() 00201 { 00202 return Qt::sizeAllCursor; 00203 } 00204 00205 00206 QCursor KCursor::blankCursor() 00207 { 00208 return Qt::blankCursor; 00209 } 00210 00211 QCursor KCursor::whatsThisCursor() 00212 { 00213 return Qt::whatsThisCursor; 00214 } 00215 00216 // auto-hide cursor stuff 00217 00218 void KCursor::setAutoHideCursor( QWidget *w, bool enable ) 00219 { 00220 setAutoHideCursor( w, enable, false ); 00221 } 00222 00223 void KCursor::setAutoHideCursor( QWidget *w, bool enable, 00224 bool customEventFilter ) 00225 { 00226 KCursorPrivate::self()->setAutoHideCursor( w, enable, customEventFilter ); 00227 } 00228 00229 void KCursor::autoHideEventFilter( QObject *o, QEvent *e ) 00230 { 00231 KCursorPrivate::self()->eventFilter( o, e ); 00232 } 00233 00234 void KCursor::setHideCursorDelay( int ms ) 00235 { 00236 KCursorPrivate::self()->hideCursorDelay = ms; 00237 } 00238 00239 int KCursor::hideCursorDelay() 00240 { 00241 return KCursorPrivate::self()->hideCursorDelay; 00242 } 00243 00244 // ************************************************************************** 00245 00246 KCursorPrivateAutoHideEventFilter::KCursorPrivateAutoHideEventFilter( QWidget* widget ) 00247 : m_widget( widget ) 00248 , m_wasMouseTracking( m_widget->hasMouseTracking() ) 00249 , m_isCursorHidden( false ) 00250 , m_isOwnCursor( false ) 00251 { 00252 m_widget->setMouseTracking( true ); 00253 connect( &m_autoHideTimer, SIGNAL( timeout() ), 00254 this, SLOT( hideCursor() ) ); 00255 } 00256 00257 KCursorPrivateAutoHideEventFilter::~KCursorPrivateAutoHideEventFilter() 00258 { 00259 if( m_widget != NULL ) 00260 m_widget->setMouseTracking( m_wasMouseTracking ); 00261 } 00262 00263 void KCursorPrivateAutoHideEventFilter::resetWidget() 00264 { 00265 m_widget = NULL; 00266 } 00267 00268 void KCursorPrivateAutoHideEventFilter::hideCursor() 00269 { 00270 m_autoHideTimer.stop(); 00271 00272 if ( m_isCursorHidden ) 00273 return; 00274 00275 m_isCursorHidden = true; 00276 00277 QWidget* w = actualWidget(); 00278 00279 m_isOwnCursor = w->ownCursor(); 00280 if ( m_isOwnCursor ) 00281 m_oldCursor = w->cursor(); 00282 00283 w->setCursor( KCursor::blankCursor() ); 00284 } 00285 00286 void KCursorPrivateAutoHideEventFilter::unhideCursor() 00287 { 00288 m_autoHideTimer.stop(); 00289 00290 if ( !m_isCursorHidden ) 00291 return; 00292 00293 m_isCursorHidden = false; 00294 00295 QWidget* w = actualWidget(); 00296 00297 if ( w->cursor().shape() != Qt::BlankCursor ) // someone messed with the cursor already 00298 return; 00299 00300 if ( m_isOwnCursor ) 00301 w->setCursor( m_oldCursor ); 00302 else 00303 w->unsetCursor(); 00304 } 00305 00306 QWidget* KCursorPrivateAutoHideEventFilter::actualWidget() const 00307 { 00308 QWidget* w = m_widget; 00309 00310 // Is w a scrollview ? Call setCursor on the viewport in that case. 00311 QScrollView * sv = dynamic_cast<QScrollView *>( w ); 00312 if ( sv ) 00313 w = sv->viewport(); 00314 00315 return w; 00316 } 00317 00318 bool KCursorPrivateAutoHideEventFilter::eventFilter( QObject *o, QEvent *e ) 00319 { 00320 Q_ASSERT( o == m_widget ); 00321 00322 switch ( e->type() ) 00323 { 00324 case QEvent::Create: 00325 // Qt steals mouseTracking on create() 00326 m_widget->setMouseTracking( true ); 00327 break; 00328 case QEvent::Leave: 00329 case QEvent::FocusOut: 00330 case QEvent::WindowDeactivate: 00331 unhideCursor(); 00332 break; 00333 case QEvent::KeyPress: 00334 case QEvent::AccelOverride: 00335 hideCursor(); 00336 break; 00337 case QEvent::Enter: 00338 case QEvent::FocusIn: 00339 case QEvent::MouseButtonPress: 00340 case QEvent::MouseButtonRelease: 00341 case QEvent::MouseButtonDblClick: 00342 case QEvent::MouseMove: 00343 case QEvent::Show: 00344 case QEvent::Hide: 00345 case QEvent::Wheel: 00346 unhideCursor(); 00347 if ( m_widget->hasFocus() ) 00348 m_autoHideTimer.start( KCursorPrivate::self()->hideCursorDelay, true ); 00349 break; 00350 default: 00351 break; 00352 } 00353 00354 return false; 00355 } 00356 00357 KCursorPrivate * KCursorPrivate::s_self = 0L; 00358 00359 KCursorPrivate * KCursorPrivate::self() 00360 { 00361 if ( !s_self ) 00362 s_self = new KCursorPrivate; 00363 // WABA: We never delete KCursorPrivate. Don't change. 00364 00365 return s_self; 00366 } 00367 00368 KCursorPrivate::KCursorPrivate() 00369 { 00370 hideCursorDelay = 5000; // 5s default value 00371 00372 KConfig *kc = KGlobal::config(); 00373 KConfigGroupSaver ks( kc, QString::fromLatin1("KDE") ); 00374 enabled = kc->readBoolEntry( 00375 QString::fromLatin1("Autohiding cursor enabled"), true ); 00376 } 00377 00378 KCursorPrivate::~KCursorPrivate() 00379 { 00380 } 00381 00382 void KCursorPrivate::setAutoHideCursor( QWidget *w, bool enable, bool customEventFilter ) 00383 { 00384 if ( !w || !enabled ) 00385 return; 00386 00387 if ( enable ) 00388 { 00389 if ( m_eventFilters.find( w ) != NULL ) 00390 return; 00391 KCursorPrivateAutoHideEventFilter* filter = new KCursorPrivateAutoHideEventFilter( w ); 00392 m_eventFilters.insert( w, filter ); 00393 if ( !customEventFilter ) 00394 w->installEventFilter( filter ); 00395 connect( w, SIGNAL( destroyed(QObject*) ), 00396 this, SLOT( slotWidgetDestroyed(QObject*) ) ); 00397 } 00398 else 00399 { 00400 KCursorPrivateAutoHideEventFilter* filter = m_eventFilters.take( w ); 00401 if ( filter == NULL ) 00402 return; 00403 w->removeEventFilter( filter ); 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.find( o ); 00416 00417 Q_ASSERT( filter != NULL ); 00418 if ( filter == NULL ) 00419 return false; 00420 00421 return filter->eventFilter( o, e ); 00422 } 00423 00424 void KCursorPrivate::slotWidgetDestroyed( QObject* o ) 00425 { 00426 KCursorPrivateAutoHideEventFilter* filter = m_eventFilters.take( o ); 00427 00428 Q_ASSERT( filter != NULL ); 00429 00430 filter->resetWidget(); // so that dtor doesn't access it 00431 delete filter; 00432 } 00433 00434 #include "kcursor_private.moc"