00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "config.h"
00021
00022 #include <qwindowdefs.h>
00023 #ifdef Q_WS_X11
00024
00025 #include "kglobalaccel_x11.h"
00026 #include "kglobalaccel.h"
00027 #include "kkeyserver_x11.h"
00028
00029 #include <qpopupmenu.h>
00030 #include <qregexp.h>
00031 #include <qwidget.h>
00032 #include <qmetaobject.h>
00033 #include <private/qucomextra_p.h>
00034 #include <kapplication.h>
00035 #include <kdebug.h>
00036 #include <kkeynative.h>
00037
00038 #ifdef Q_WS_X11
00039 #include <kxerrorhandler.h>
00040 #endif
00041
00042 #include <X11/X.h>
00043 #include <X11/Xlib.h>
00044 #include <X11/keysym.h>
00045 #include <fixx11h.h>
00046
00047 extern "C" {
00048 static int XGrabErrorHandler( Display *, XErrorEvent *e ) {
00049 if ( e->error_code != BadAccess ) {
00050 kdWarning() << "grabKey: got X error " << e->type << " instead of BadAccess\n";
00051 }
00052 return 1;
00053 }
00054 }
00055
00056
00057
00058
00059
00060
00061
00062 static uint g_keyModMaskXAccel = 0;
00063 static uint g_keyModMaskXOnOrOff = 0;
00064
00065 static void calculateGrabMasks()
00066 {
00067 g_keyModMaskXAccel = KKeyServer::accelModMaskX();
00068 g_keyModMaskXOnOrOff =
00069 KKeyServer::modXLock() |
00070 KKeyServer::modXNumLock() |
00071 KKeyServer::modXScrollLock() |
00072 KKeyServer::modXModeSwitch();
00073
00074
00075 }
00076
00077
00078
00079 static QValueList< KGlobalAccelPrivate* >* all_accels = 0;
00080
00081 KGlobalAccelPrivate::KGlobalAccelPrivate()
00082 : KAccelBase( KAccelBase::NATIVE_KEYS )
00083 , m_blocked( false )
00084 , m_blockingDisabled( false )
00085 , m_suspended( false )
00086 {
00087 if( all_accels == NULL )
00088 all_accels = new QValueList< KGlobalAccelPrivate* >;
00089 all_accels->append( this );
00090 m_sConfigGroup = "Global Shortcuts";
00091 kapp->installX11EventFilter( this );
00092 }
00093
00094 KGlobalAccelPrivate::~KGlobalAccelPrivate()
00095 {
00096
00097
00098
00099
00100 all_accels->remove( this );
00101 if( all_accels->count() == 0 ) {
00102 delete all_accels;
00103 all_accels = NULL;
00104 }
00105 }
00106
00107 void KGlobalAccelPrivate::setEnabled( bool bEnable )
00108 {
00109 m_bEnabled = bEnable;
00110 updateConnections();
00111 }
00112
00113 void KGlobalAccelPrivate::blockShortcuts( bool block )
00114 {
00115 if( all_accels == NULL )
00116 return;
00117 for( QValueList< KGlobalAccelPrivate* >::ConstIterator it = all_accels->begin();
00118 it != all_accels->end();
00119 ++it ) {
00120 if( (*it)->m_blockingDisabled )
00121 continue;
00122 (*it)->m_blocked = block;
00123 (*it)->updateConnections();
00124 }
00125 }
00126
00127 void KGlobalAccelPrivate::disableBlocking( bool block )
00128 {
00129 m_blockingDisabled = block;
00130 }
00131
00132 bool KGlobalAccelPrivate::isEnabledInternal() const
00133 {
00134 return KAccelBase::isEnabled() && !m_blocked;
00135 }
00136
00137
00138
00139 void KGlobalAccelPrivate::suspend( bool s )
00140 {
00141 m_suspended = s;
00142 }
00143
00144 bool KGlobalAccelPrivate::emitSignal( Signal )
00145 {
00146 return false;
00147 }
00148
00149 bool KGlobalAccelPrivate::connectKey( KAccelAction& action, const KKeyServer::Key& key )
00150 { return grabKey( key, true, &action ); }
00151 bool KGlobalAccelPrivate::connectKey( const KKeyServer::Key& key )
00152 { return grabKey( key, true, 0 ); }
00153 bool KGlobalAccelPrivate::disconnectKey( KAccelAction& action, const KKeyServer::Key& key )
00154 { return grabKey( key, false, &action ); }
00155 bool KGlobalAccelPrivate::disconnectKey( const KKeyServer::Key& key )
00156 { return grabKey( key, false, 0 ); }
00157
00158 bool KGlobalAccelPrivate::grabKey( const KKeyServer::Key& key, bool bGrab, KAccelAction* pAction )
00159 {
00160 if( !key.code() ) {
00161 kdWarning(125) << "KGlobalAccelPrivate::grabKey( " << key.key().toStringInternal() << ", " << bGrab << ", \"" << (pAction ? pAction->name().latin1() : "(null)") << "\" ): Tried to grab key with null code." << endl;
00162 return false;
00163 }
00164
00165
00166 if( g_keyModMaskXOnOrOff == 0 )
00167 calculateGrabMasks();
00168
00169 uchar keyCodeX = key.code();
00170 uint keyModX = key.mod() & g_keyModMaskXAccel;
00171
00172
00173
00174 if( key.sym() == XK_Sys_Req && XKeycodeToKeysym( qt_xdisplay(), 111, 0 ) == XK_Print ) {
00175 keyModX |= KKeyServer::modXAlt();
00176 keyCodeX = 111;
00177 }
00178
00179 #ifndef __osf__
00180
00181 kdDebug(125) << QString( "grabKey( key: '%1', bGrab: %2 ): keyCodeX: %3 keyModX: %4\n" )
00182 .arg( key.key().toStringInternal() ).arg( bGrab )
00183 .arg( keyCodeX, 0, 16 ).arg( keyModX, 0, 16 );
00184 #endif
00185 if( !keyCodeX )
00186 return false;
00187
00188 #ifdef Q_WS_X11
00189 KXErrorHandler handler( XGrabErrorHandler );
00190 #endif
00191
00192
00193
00194
00195
00196 #ifndef NDEBUG
00197 QString sDebug = QString("\tcode: 0x%1 state: 0x%2 | ").arg(keyCodeX,0,16).arg(keyModX,0,16);
00198 #endif
00199 uint keyModMaskX = ~g_keyModMaskXOnOrOff;
00200 for( uint irrelevantBitsMask = 0; irrelevantBitsMask <= 0xff; irrelevantBitsMask++ ) {
00201 if( (irrelevantBitsMask & keyModMaskX) == 0 ) {
00202 #ifndef NDEBUG
00203 sDebug += QString("0x%3, ").arg(irrelevantBitsMask, 0, 16);
00204 #endif
00205 if( bGrab )
00206 XGrabKey( qt_xdisplay(), keyCodeX, keyModX | irrelevantBitsMask,
00207 qt_xrootwin(), True, GrabModeAsync, GrabModeSync );
00208 else
00209 XUngrabKey( qt_xdisplay(), keyCodeX, keyModX | irrelevantBitsMask, qt_xrootwin() );
00210 }
00211 }
00212 #ifndef NDEBUG
00213 kdDebug(125) << sDebug << endl;
00214 #endif
00215
00216 bool failed = false;
00217 if( bGrab ) {
00218 #ifdef Q_WS_X11
00219 failed = handler.error( true );
00220 #endif
00221
00222 if( failed ) {
00223 kdDebug(125) << "grab failed!\n";
00224 for( uint m = 0; m <= 0xff; m++ ) {
00225 if(( m & keyModMaskX ) == 0 )
00226 XUngrabKey( qt_xdisplay(), keyCodeX, keyModX | m, qt_xrootwin() );
00227 }
00228 }
00229 }
00230 if( !failed )
00231 {
00232 CodeMod codemod;
00233 codemod.code = keyCodeX;
00234 codemod.mod = keyModX;
00235 if( key.mod() & KKeyServer::MODE_SWITCH )
00236 codemod.mod |= KKeyServer::MODE_SWITCH;
00237
00238 if( bGrab )
00239 m_rgCodeModToAction.insert( codemod, pAction );
00240 else
00241 m_rgCodeModToAction.remove( codemod );
00242 }
00243 return !failed;
00244 }
00245
00246 bool KGlobalAccelPrivate::x11Event( XEvent* pEvent )
00247 {
00248
00249 switch( pEvent->type ) {
00250 case MappingNotify:
00251 XRefreshKeyboardMapping( &pEvent->xmapping );
00252 x11MappingNotify();
00253 return false;
00254 case XKeyPress:
00255 if( x11KeyPress( pEvent ) )
00256 return true;
00257 default:
00258 return QWidget::x11Event( pEvent );
00259 }
00260 }
00261
00262 void KGlobalAccelPrivate::x11MappingNotify()
00263 {
00264 kdDebug(125) << "KGlobalAccelPrivate::x11MappingNotify()" << endl;
00265
00266 KKeyServer::initializeMods();
00267 calculateGrabMasks();
00268
00269 updateConnections();
00270 }
00271
00272 bool KGlobalAccelPrivate::x11KeyPress( const XEvent *pEvent )
00273 {
00274
00275 if ( !QWidget::keyboardGrabber() && !QApplication::activePopupWidget() ) {
00276 XUngrabKeyboard( qt_xdisplay(), pEvent->xkey.time );
00277 XFlush( qt_xdisplay());
00278 }
00279
00280 if( !isEnabledInternal() || m_suspended )
00281 return false;
00282
00283 CodeMod codemod;
00284 codemod.code = pEvent->xkey.keycode;
00285 codemod.mod = pEvent->xkey.state & (g_keyModMaskXAccel | KKeyServer::MODE_SWITCH);
00286
00287
00288
00289 if( pEvent->xkey.state & KKeyServer::modXNumLock() ) {
00290
00291 uint sym = XKeycodeToKeysym( qt_xdisplay(), codemod.code, 0 );
00292
00293 if( sym >= XK_KP_Space && sym <= XK_KP_9 ) {
00294 switch( sym ) {
00295
00296
00297 case XK_KP_Multiply:
00298 case XK_KP_Add:
00299 case XK_KP_Subtract:
00300 case XK_KP_Divide:
00301 break;
00302 default:
00303 if( codemod.mod & KKeyServer::modXShift() )
00304 codemod.mod &= ~KKeyServer::modXShift();
00305 else
00306 codemod.mod |= KKeyServer::modXShift();
00307 }
00308 }
00309 }
00310
00311 KKeyNative keyNative( pEvent );
00312 KKey key = keyNative;
00313
00314 kdDebug(125) << "x11KeyPress: seek " << key.toStringInternal()
00315 << QString( " keyCodeX: %1 state: %2 keyModX: %3" )
00316 .arg( codemod.code, 0, 16 ).arg( pEvent->xkey.state, 0, 16 ).arg( codemod.mod, 0, 16 ) << endl;
00317
00318
00319 if( !m_rgCodeModToAction.contains( codemod ) ) {
00320 #ifndef NDEBUG
00321 for( CodeModMap::ConstIterator it = m_rgCodeModToAction.begin(); it != m_rgCodeModToAction.end(); ++it ) {
00322 KAccelAction* pAction = *it;
00323 kdDebug(125) << "\tcode: " << QString::number(it.key().code, 16) << " mod: " << QString::number(it.key().mod, 16)
00324 << (pAction ? QString(" name: \"%1\" shortcut: %2").arg(pAction->name()).arg(pAction->shortcut().toStringInternal()) : QString::null)
00325 << endl;
00326 }
00327 #endif
00328 return false;
00329 }
00330
00331 KAccelAction* pAction = m_rgCodeModToAction[codemod];
00332
00333 if( !pAction ) {
00334 static bool recursion_block = false;
00335 if( !recursion_block ) {
00336 recursion_block = true;
00337 QPopupMenu* pMenu = createPopupMenu( 0, KKeySequence(key) );
00338 connect( pMenu, SIGNAL(activated(int)), this, SLOT(slotActivated(int)) );
00339 pMenu->exec( QPoint( 0, 0 ) );
00340 disconnect( pMenu, SIGNAL(activated(int)), this, SLOT(slotActivated(int)));
00341 delete pMenu;
00342 recursion_block = false;
00343 }
00344 } else if( !pAction->objSlotPtr() || !pAction->isEnabled() )
00345 return false;
00346 else
00347 activate( pAction, KKeySequence(key) );
00348
00349 return true;
00350 }
00351
00352 void KGlobalAccelPrivate::activate( KAccelAction* pAction, const KKeySequence& seq )
00353 {
00354 kdDebug(125) << "KGlobalAccelPrivate::activate( \"" << pAction->name() << "\" ) " << endl;
00355
00356 QRegExp rexPassIndex( "([ ]*int[ ]*)" );
00357 QRegExp rexPassInfo( " QString" );
00358 QRegExp rexIndex( " ([0-9]+)$" );
00359
00360
00361
00362
00363 if( rexPassIndex.search( pAction->methodSlotPtr() ) >= 0 && rexIndex.search( pAction->name() ) >= 0 ) {
00364 int n = rexIndex.cap(1).toInt();
00365 kdDebug(125) << "Calling " << pAction->methodSlotPtr() << " int = " << n << endl;
00366 int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
00367 if( slot_id >= 0 ) {
00368 QUObject o[2];
00369 static_QUType_int.set(o+1,n);
00370 const_cast< QObject* >( pAction->objSlotPtr())->qt_invoke( slot_id, o );
00371 }
00372 } else if( rexPassInfo.search( pAction->methodSlotPtr() ) ) {
00373 int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
00374 if( slot_id >= 0 ) {
00375 QUObject o[4];
00376 static_QUType_QString.set(o+1,pAction->name());
00377 static_QUType_QString.set(o+2,pAction->label());
00378 static_QUType_ptr.set(o+3,&seq);
00379 const_cast< QObject* >( pAction->objSlotPtr())->qt_invoke( slot_id, o );
00380 }
00381 } else {
00382 int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
00383 if( slot_id >= 0 )
00384 const_cast< QObject* >( pAction->objSlotPtr())->qt_invoke( slot_id, 0 );
00385 }
00386 }
00387
00388 void KGlobalAccelPrivate::slotActivated( int iAction )
00389 {
00390 KAccelAction* pAction = actions().actionPtr( iAction );
00391 if( pAction )
00392 activate( pAction, KKeySequence() );
00393 }
00394
00395 #include "kglobalaccel_x11.moc"
00396
00397 #endif // !Q_WS_X11