You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
435 lines
11 KiB
435 lines
11 KiB
/* This file is part of the KDE libraries
|
|
Copyright (C) 1998 Kurt Granroth (granroth@kde.org)
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License version 2 as published by the Free Software Foundation.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#ifdef KDE_USE_FINAL
|
|
#ifdef KeyRelease
|
|
#undef KeyRelease
|
|
#endif
|
|
#endif
|
|
|
|
#include <kcursor.h>
|
|
|
|
#include <qbitmap.h>
|
|
#include <qcursor.h>
|
|
#include <qevent.h>
|
|
#include <qtimer.h>
|
|
#include <qwidget.h>
|
|
|
|
#include <kglobal.h>
|
|
#include <kconfig.h>
|
|
#include <qscrollview.h>
|
|
|
|
#include "kcursor_private.h"
|
|
|
|
KCursor::KCursor()
|
|
{
|
|
}
|
|
|
|
QCursor KCursor::handCursor()
|
|
{
|
|
static QCursor *hand_cursor = 0;
|
|
|
|
if (!hand_cursor)
|
|
{
|
|
KConfig *config = KGlobal::config();
|
|
KConfigGroupSaver saver( config, "General" );
|
|
|
|
#ifndef Q_WS_WIN // this mask doesn't work too well on win32
|
|
if ( config->readEntry("handCursorStyle", "Windows") == "Windows" )
|
|
{
|
|
static const unsigned char HAND_BITS[] = {
|
|
0x80, 0x01, 0x00, 0x40, 0x02, 0x00, 0x40, 0x02, 0x00, 0x40, 0x02,
|
|
0x00, 0x40, 0x02, 0x00, 0x40, 0x02, 0x00, 0x40, 0x1e, 0x00, 0x40,
|
|
0xf2, 0x00, 0x40, 0x92, 0x01, 0x70, 0x92, 0x02, 0x50, 0x92, 0x04,
|
|
0x48, 0x80, 0x04, 0x48, 0x00, 0x04, 0x48, 0x00, 0x04, 0x08, 0x00,
|
|
0x04, 0x08, 0x00, 0x04, 0x10, 0x00, 0x04, 0x10, 0x00, 0x04, 0x20,
|
|
0x00, 0x02, 0x40, 0x00, 0x02, 0x40, 0x00, 0x01, 0xc0, 0xff, 0x01};
|
|
static const unsigned char HAND_MASK_BITS[] = {
|
|
0x80, 0x01, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03,
|
|
0x00, 0xc0, 0x03, 0x00, 0xc0, 0x03, 0x00, 0xc0, 0x1f, 0x00, 0xc0,
|
|
0xff, 0x00, 0xc0, 0xff, 0x01, 0xf0, 0xff, 0x03, 0xf0, 0xff, 0x07,
|
|
0xf8, 0xff, 0x07, 0xf8, 0xff, 0x07, 0xf8, 0xff, 0x07, 0xf8, 0xff,
|
|
0x07, 0xf8, 0xff, 0x07, 0xf0, 0xff, 0x07, 0xf0, 0xff, 0x07, 0xe0,
|
|
0xff, 0x03, 0xc0, 0xff, 0x03, 0xc0, 0xff, 0x01, 0xc0, 0xff, 0x01};
|
|
QBitmap hand_bitmap(22, 22, HAND_BITS, true);
|
|
QBitmap hand_mask(22, 22, HAND_MASK_BITS, true);
|
|
hand_cursor = new QCursor(hand_bitmap, hand_mask, 7, 0);
|
|
// Hack to force QCursor to call XCreatePixmapCursor() immediately
|
|
// so the bitmaps don't get pushed out of the Xcursor LRU cache.
|
|
hand_cursor->handle();
|
|
}
|
|
else
|
|
#endif //! Q_WS_WIN
|
|
hand_cursor = new QCursor(PointingHandCursor);
|
|
}
|
|
|
|
Q_CHECK_PTR(hand_cursor);
|
|
return *hand_cursor;
|
|
}
|
|
|
|
/* XPM */
|
|
static const char * const working_cursor_xpm[]={
|
|
"32 32 3 1",
|
|
"# c None",
|
|
"a c #000000",
|
|
". c #ffffff",
|
|
"..##############################",
|
|
".a.##########.aaaa.#############",
|
|
".aa.#########.aaaa.#############",
|
|
".aaa.#######.aaaaaa.############",
|
|
".aaaa.#####.a...a..a..##########",
|
|
".aaaaa.####a....a...aa##########",
|
|
".aaaaaa.###a...aa...aa##########",
|
|
".aaaaaaa.##a..a.....aa##########",
|
|
".aaaaaaaa.#.aa.....a..##########",
|
|
".aaaaa....##.aaaaaa.############",
|
|
".aa.aa.######.aaaa.#############",
|
|
".a.#.aa.#####.aaaa.#############",
|
|
"..##.aa.########################",
|
|
"#####.aa.#######################",
|
|
"#####.aa.#######################",
|
|
"######..########################",
|
|
"################################",
|
|
"################################",
|
|
"################################",
|
|
"################################",
|
|
"################################",
|
|
"################################",
|
|
"################################",
|
|
"################################",
|
|
"################################",
|
|
"################################",
|
|
"################################",
|
|
"################################",
|
|
"################################",
|
|
"################################",
|
|
"################################",
|
|
"################################"};
|
|
|
|
|
|
QCursor KCursor::workingCursor()
|
|
{
|
|
static QCursor *working_cursor = 0;
|
|
|
|
if (!working_cursor)
|
|
{
|
|
QPixmap pm( const_cast< const char** >( working_cursor_xpm ));
|
|
working_cursor = new QCursor( pm, 1, 1 );
|
|
// Hack to force QCursor to call XCreatePixmapCursor() immediately
|
|
// so the bitmaps don't get pushed out of the Xcursor LRU cache.
|
|
working_cursor->handle();
|
|
}
|
|
|
|
Q_CHECK_PTR(working_cursor);
|
|
return *working_cursor;
|
|
}
|
|
|
|
/**
|
|
* All of the follow functions will return the Qt default for now regardless
|
|
* of the style. This will change at some later date
|
|
*/
|
|
QCursor KCursor::arrowCursor()
|
|
{
|
|
return Qt::arrowCursor;
|
|
}
|
|
|
|
|
|
QCursor KCursor::upArrowCursor()
|
|
{
|
|
return Qt::upArrowCursor;
|
|
}
|
|
|
|
|
|
QCursor KCursor::crossCursor()
|
|
{
|
|
return Qt::crossCursor;
|
|
}
|
|
|
|
|
|
QCursor KCursor::waitCursor()
|
|
{
|
|
return Qt::waitCursor;
|
|
}
|
|
|
|
|
|
QCursor KCursor::ibeamCursor()
|
|
{
|
|
return Qt::ibeamCursor;
|
|
}
|
|
|
|
|
|
QCursor KCursor::sizeVerCursor()
|
|
{
|
|
return Qt::sizeVerCursor;
|
|
}
|
|
|
|
|
|
QCursor KCursor::sizeHorCursor()
|
|
{
|
|
return Qt::sizeHorCursor;
|
|
}
|
|
|
|
|
|
QCursor KCursor::sizeBDiagCursor()
|
|
{
|
|
return Qt::sizeBDiagCursor;
|
|
}
|
|
|
|
|
|
QCursor KCursor::sizeFDiagCursor()
|
|
{
|
|
return Qt::sizeFDiagCursor;
|
|
}
|
|
|
|
|
|
QCursor KCursor::sizeAllCursor()
|
|
{
|
|
return Qt::sizeAllCursor;
|
|
}
|
|
|
|
|
|
QCursor KCursor::blankCursor()
|
|
{
|
|
return Qt::blankCursor;
|
|
}
|
|
|
|
QCursor KCursor::whatsThisCursor()
|
|
{
|
|
return Qt::whatsThisCursor;
|
|
}
|
|
|
|
// auto-hide cursor stuff
|
|
|
|
void KCursor::setAutoHideCursor( QWidget *w, bool enable )
|
|
{
|
|
setAutoHideCursor( w, enable, false );
|
|
}
|
|
|
|
void KCursor::setAutoHideCursor( QWidget *w, bool enable,
|
|
bool customEventFilter )
|
|
{
|
|
KCursorPrivate::self()->setAutoHideCursor( w, enable, customEventFilter );
|
|
}
|
|
|
|
void KCursor::autoHideEventFilter( QObject *o, QEvent *e )
|
|
{
|
|
KCursorPrivate::self()->eventFilter( o, e );
|
|
}
|
|
|
|
void KCursor::setHideCursorDelay( int ms )
|
|
{
|
|
KCursorPrivate::self()->hideCursorDelay = ms;
|
|
}
|
|
|
|
int KCursor::hideCursorDelay()
|
|
{
|
|
return KCursorPrivate::self()->hideCursorDelay;
|
|
}
|
|
|
|
// **************************************************************************
|
|
|
|
KCursorPrivateAutoHideEventFilter::KCursorPrivateAutoHideEventFilter( QWidget* widget )
|
|
: m_widget( widget )
|
|
, m_wasMouseTracking( m_widget->hasMouseTracking() )
|
|
, m_isCursorHidden( false )
|
|
, m_isOwnCursor( false )
|
|
{
|
|
m_widget->setMouseTracking( true );
|
|
connect( &m_autoHideTimer, SIGNAL( timeout() ),
|
|
this, SLOT( hideCursor() ) );
|
|
}
|
|
|
|
KCursorPrivateAutoHideEventFilter::~KCursorPrivateAutoHideEventFilter()
|
|
{
|
|
if( m_widget != NULL )
|
|
m_widget->setMouseTracking( m_wasMouseTracking );
|
|
}
|
|
|
|
void KCursorPrivateAutoHideEventFilter::resetWidget()
|
|
{
|
|
m_widget = NULL;
|
|
}
|
|
|
|
void KCursorPrivateAutoHideEventFilter::hideCursor()
|
|
{
|
|
m_autoHideTimer.stop();
|
|
|
|
if ( m_isCursorHidden )
|
|
return;
|
|
|
|
m_isCursorHidden = true;
|
|
|
|
QWidget* w = actualWidget();
|
|
|
|
m_isOwnCursor = w->ownCursor();
|
|
if ( m_isOwnCursor )
|
|
m_oldCursor = w->cursor();
|
|
|
|
w->setCursor( KCursor::blankCursor() );
|
|
}
|
|
|
|
void KCursorPrivateAutoHideEventFilter::unhideCursor()
|
|
{
|
|
m_autoHideTimer.stop();
|
|
|
|
if ( !m_isCursorHidden )
|
|
return;
|
|
|
|
m_isCursorHidden = false;
|
|
|
|
QWidget* w = actualWidget();
|
|
|
|
if ( w->cursor().shape() != Qt::BlankCursor ) // someone messed with the cursor already
|
|
return;
|
|
|
|
if ( m_isOwnCursor )
|
|
w->setCursor( m_oldCursor );
|
|
else
|
|
w->unsetCursor();
|
|
}
|
|
|
|
QWidget* KCursorPrivateAutoHideEventFilter::actualWidget() const
|
|
{
|
|
QWidget* w = m_widget;
|
|
|
|
// Is w a scrollview ? Call setCursor on the viewport in that case.
|
|
QScrollView * sv = dynamic_cast<QScrollView *>( w );
|
|
if ( sv )
|
|
w = sv->viewport();
|
|
|
|
return w;
|
|
}
|
|
|
|
bool KCursorPrivateAutoHideEventFilter::eventFilter( QObject *o, QEvent *e )
|
|
{
|
|
Q_ASSERT( o == m_widget );
|
|
|
|
switch ( e->type() )
|
|
{
|
|
case QEvent::Create:
|
|
// Qt steals mouseTracking on create()
|
|
m_widget->setMouseTracking( true );
|
|
break;
|
|
case QEvent::Leave:
|
|
case QEvent::FocusOut:
|
|
case QEvent::WindowDeactivate:
|
|
unhideCursor();
|
|
break;
|
|
case QEvent::KeyPress:
|
|
case QEvent::AccelOverride:
|
|
hideCursor();
|
|
break;
|
|
case QEvent::Enter:
|
|
case QEvent::FocusIn:
|
|
case QEvent::MouseButtonPress:
|
|
case QEvent::MouseButtonRelease:
|
|
case QEvent::MouseButtonDblClick:
|
|
case QEvent::MouseMove:
|
|
case QEvent::Show:
|
|
case QEvent::Hide:
|
|
case QEvent::Wheel:
|
|
unhideCursor();
|
|
if ( m_widget->hasFocus() )
|
|
m_autoHideTimer.start( KCursorPrivate::self()->hideCursorDelay, true );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
KCursorPrivate * KCursorPrivate::s_self = 0L;
|
|
|
|
KCursorPrivate * KCursorPrivate::self()
|
|
{
|
|
if ( !s_self )
|
|
s_self = new KCursorPrivate;
|
|
// WABA: We never delete KCursorPrivate. Don't change.
|
|
|
|
return s_self;
|
|
}
|
|
|
|
KCursorPrivate::KCursorPrivate()
|
|
{
|
|
hideCursorDelay = 5000; // 5s default value
|
|
|
|
KConfig *kc = KGlobal::config();
|
|
KConfigGroupSaver ks( kc, QString::fromLatin1("KDE") );
|
|
enabled = kc->readBoolEntry(
|
|
QString::fromLatin1("Autohiding cursor enabled"), true );
|
|
}
|
|
|
|
KCursorPrivate::~KCursorPrivate()
|
|
{
|
|
}
|
|
|
|
void KCursorPrivate::setAutoHideCursor( QWidget *w, bool enable, bool customEventFilter )
|
|
{
|
|
if ( !w || !enabled )
|
|
return;
|
|
|
|
if ( enable )
|
|
{
|
|
if ( m_eventFilters.find( w ) != NULL )
|
|
return;
|
|
KCursorPrivateAutoHideEventFilter* filter = new KCursorPrivateAutoHideEventFilter( w );
|
|
m_eventFilters.insert( w, filter );
|
|
if ( !customEventFilter )
|
|
w->installEventFilter( filter );
|
|
connect( w, SIGNAL( destroyed(QObject*) ),
|
|
this, SLOT( slotWidgetDestroyed(QObject*) ) );
|
|
}
|
|
else
|
|
{
|
|
KCursorPrivateAutoHideEventFilter* filter = m_eventFilters.take( w );
|
|
if ( filter == NULL )
|
|
return;
|
|
w->removeEventFilter( filter );
|
|
delete filter;
|
|
disconnect( w, SIGNAL( destroyed(QObject*) ),
|
|
this, SLOT( slotWidgetDestroyed(QObject*) ) );
|
|
}
|
|
}
|
|
|
|
bool KCursorPrivate::eventFilter( QObject *o, QEvent *e )
|
|
{
|
|
if ( !enabled )
|
|
return false;
|
|
|
|
KCursorPrivateAutoHideEventFilter* filter = m_eventFilters.find( o );
|
|
|
|
Q_ASSERT( filter != NULL );
|
|
if ( filter == NULL )
|
|
return false;
|
|
|
|
return filter->eventFilter( o, e );
|
|
}
|
|
|
|
void KCursorPrivate::slotWidgetDestroyed( QObject* o )
|
|
{
|
|
KCursorPrivateAutoHideEventFilter* filter = m_eventFilters.take( o );
|
|
|
|
Q_ASSERT( filter != NULL );
|
|
|
|
filter->resetWidget(); // so that dtor doesn't access it
|
|
delete filter;
|
|
}
|
|
|
|
#include "kcursor_private.moc"
|