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
00073
00074 }
00075
00076
00077
00078 KGlobalAccelPrivate::KGlobalAccelPrivate()
00079 : KAccelBase( KAccelBase::NATIVE_KEYS )
00080 {
00081 m_sConfigGroup = "Global Shortcuts";
00082 kapp->installX11EventFilter( this );
00083 }
00084
00085 KGlobalAccelPrivate::~KGlobalAccelPrivate()
00086 {
00087
00088
00089
00090
00091 }
00092
00093 void KGlobalAccelPrivate::setEnabled( bool bEnable )
00094 {
00095 m_bEnabled = bEnable;
00096
00097 }
00098
00099 bool KGlobalAccelPrivate::emitSignal( Signal )
00100 {
00101 return false;
00102 }
00103
00104 bool KGlobalAccelPrivate::connectKey( KAccelAction& action, const KKeyServer::Key& key )
00105 { return grabKey( key, true, &action ); }
00106 bool KGlobalAccelPrivate::connectKey( const KKeyServer::Key& key )
00107 { return grabKey( key, true, 0 ); }
00108 bool KGlobalAccelPrivate::disconnectKey( KAccelAction& action, const KKeyServer::Key& key )
00109 { return grabKey( key, false, &action ); }
00110 bool KGlobalAccelPrivate::disconnectKey( const KKeyServer::Key& key )
00111 { return grabKey( key, false, 0 ); }
00112
00113 bool KGlobalAccelPrivate::grabKey( const KKeyServer::Key& key, bool bGrab, KAccelAction* pAction )
00114 {
00115 if( !key.code() ) {
00116 kdWarning(125) << "KGlobalAccelPrivate::grabKey( " << key.key().toStringInternal() << ", " << bGrab << ", \"" << (pAction ? pAction->name().latin1() : "(null)") << "\" ): Tried to grab key with null code." << endl;
00117 return false;
00118 }
00119
00120
00121 if( g_keyModMaskXOnOrOff == 0 )
00122 calculateGrabMasks();
00123
00124 uchar keyCodeX = key.code();
00125 uint keyModX = key.mod() & g_keyModMaskXAccel;
00126
00127 if( key.sym() == XK_Sys_Req ) {
00128 keyModX |= KKeyServer::modXAlt();
00129 keyCodeX = 111;
00130 }
00131
00132 #ifndef __osf__
00133
00134 kdDebug(125) << QString( "grabKey( key: '%1', bGrab: %2 ): keyCodeX: %3 keyModX: %4\n" )
00135 .arg( key.key().toStringInternal() ).arg( bGrab )
00136 .arg( keyCodeX, 0, 16 ).arg( keyModX, 0, 16 );
00137 #endif
00138 if( !keyCodeX )
00139 return false;
00140
00141 #ifdef Q_WS_X11
00142 KXErrorHandler handler( XGrabErrorHandler );
00143 #endif
00144
00145
00146
00147
00148
00149 #ifndef NDEBUG
00150 QString sDebug = QString("\tcode: 0x%1 state: 0x%2 | ").arg(keyCodeX,0,16).arg(keyModX,0,16);
00151 #endif
00152 uint keyModMaskX = ~g_keyModMaskXOnOrOff;
00153 for( uint irrelevantBitsMask = 0; irrelevantBitsMask <= 0xff; irrelevantBitsMask++ ) {
00154 if( (irrelevantBitsMask & keyModMaskX) == 0 ) {
00155 #ifndef NDEBUG
00156 sDebug += QString("0x%3, ").arg(irrelevantBitsMask, 0, 16);
00157 #endif
00158 if( bGrab )
00159 XGrabKey( qt_xdisplay(), keyCodeX, keyModX | irrelevantBitsMask,
00160 qt_xrootwin(), True, GrabModeAsync, GrabModeSync );
00161 else
00162 XUngrabKey( qt_xdisplay(), keyCodeX, keyModX | irrelevantBitsMask, qt_xrootwin() );
00163 }
00164 }
00165 #ifndef NDEBUG
00166 kdDebug(125) << sDebug << endl;
00167 #endif
00168
00169 bool failed = false;
00170 if( bGrab ) {
00171 #ifdef Q_WS_X11
00172 failed = handler.error( true );
00173 #endif
00174
00175 if( failed ) {
00176 kdDebug(125) << "grab failed!\n";
00177 for( uint m = 0; m <= 0xff; m++ ) {
00178 if( m & keyModMaskX == 0 )
00179 XUngrabKey( qt_xdisplay(), keyCodeX, keyModX | m, qt_xrootwin() );
00180 }
00181 }
00182 }
00183 if( !failed )
00184 {
00185 CodeMod codemod;
00186 codemod.code = keyCodeX;
00187 codemod.mod = keyModX;
00188 if( key.mod() & KKeyServer::MODE_SWITCH )
00189 codemod.mod |= KKeyServer::MODE_SWITCH;
00190
00191 if( bGrab )
00192 m_rgCodeModToAction.insert( codemod, pAction );
00193 else
00194 m_rgCodeModToAction.remove( codemod );
00195 }
00196 return !failed;
00197 }
00198
00199 bool KGlobalAccelPrivate::x11Event( XEvent* pEvent )
00200 {
00201
00202 switch( pEvent->type ) {
00203 case MappingNotify:
00204 XRefreshKeyboardMapping( &pEvent->xmapping );
00205 x11MappingNotify();
00206 return false;
00207 case XKeyPress:
00208 if( x11KeyPress( pEvent ) )
00209 return true;
00210 default:
00211 return QWidget::x11Event( pEvent );
00212 }
00213 }
00214
00215 void KGlobalAccelPrivate::x11MappingNotify()
00216 {
00217 kdDebug(125) << "KGlobalAccelPrivate::x11MappingNotify()" << endl;
00218 if( m_bEnabled ) {
00219
00220 KKeyServer::initializeMods();
00221 calculateGrabMasks();
00222
00223 updateConnections();
00224 }
00225 }
00226
00227 bool KGlobalAccelPrivate::x11KeyPress( const XEvent *pEvent )
00228 {
00229
00230 if ( !QWidget::keyboardGrabber() && !QApplication::activePopupWidget() ) {
00231 XUngrabKeyboard( qt_xdisplay(), pEvent->xkey.time );
00232 XFlush( qt_xdisplay());
00233 }
00234
00235 if( !m_bEnabled )
00236 return false;
00237
00238 CodeMod codemod;
00239 codemod.code = pEvent->xkey.keycode;
00240 codemod.mod = pEvent->xkey.state & (g_keyModMaskXAccel | KKeyServer::MODE_SWITCH);
00241
00242
00243
00244 if( pEvent->xkey.state & KKeyServer::modXNumLock() ) {
00245
00246 uint sym = XKeycodeToKeysym( qt_xdisplay(), codemod.code, 0 );
00247
00248 if( sym >= XK_KP_Space && sym <= XK_KP_9 ) {
00249 switch( sym ) {
00250
00251
00252 case XK_KP_Multiply:
00253 case XK_KP_Add:
00254 case XK_KP_Subtract:
00255 case XK_KP_Divide:
00256 break;
00257 default:
00258 if( codemod.mod & KKeyServer::modXShift() )
00259 codemod.mod &= ~KKeyServer::modXShift();
00260 else
00261 codemod.mod |= KKeyServer::modXShift();
00262 }
00263 }
00264 }
00265
00266 KKeyNative keyNative( pEvent );
00267 KKey key = keyNative;
00268
00269 kdDebug(125) << "x11KeyPress: seek " << key.toStringInternal()
00270 << QString( " keyCodeX: %1 state: %2 keyModX: %3" )
00271 .arg( codemod.code, 0, 16 ).arg( pEvent->xkey.state, 0, 16 ).arg( codemod.mod, 0, 16 ) << endl;
00272
00273
00274 if( !m_rgCodeModToAction.contains( codemod ) ) {
00275 #ifndef NDEBUG
00276 for( CodeModMap::ConstIterator it = m_rgCodeModToAction.begin(); it != m_rgCodeModToAction.end(); ++it ) {
00277 KAccelAction* pAction = *it;
00278 kdDebug(125) << "\tcode: " << QString::number(it.key().code, 16) << " mod: " << QString::number(it.key().mod, 16)
00279 << (pAction ? QString(" name: \"%1\" shortcut: %2").arg(pAction->name()).arg(pAction->shortcut().toStringInternal()) : QString::null)
00280 << endl;
00281 }
00282 #endif
00283 return false;
00284 }
00285 KAccelAction* pAction = m_rgCodeModToAction[codemod];
00286
00287 if( !pAction ) {
00288 static bool recursion_block = false;
00289 if( !recursion_block ) {
00290 recursion_block = true;
00291 QPopupMenu* pMenu = createPopupMenu( 0, KKeySequence(key) );
00292 connect( pMenu, SIGNAL(activated(int)), this, SLOT(slotActivated(int)) );
00293 pMenu->exec( QPoint( 0, 0 ) );
00294 disconnect( pMenu, SIGNAL(activated(int)), this, SLOT(slotActivated(int)));
00295 delete pMenu;
00296 recursion_block = false;
00297 }
00298 } else if( !pAction->objSlotPtr() || !pAction->isEnabled() )
00299 return false;
00300 else
00301 activate( pAction, KKeySequence(key) );
00302
00303 return true;
00304 }
00305
00306 void KGlobalAccelPrivate::activate( KAccelAction* pAction, const KKeySequence& seq )
00307 {
00308 kdDebug(125) << "KGlobalAccelPrivate::activate( \"" << pAction->name() << "\" ) " << endl;
00309
00310 QRegExp rexPassIndex( "([ ]*int[ ]*)" );
00311 QRegExp rexPassInfo( " QString" );
00312 QRegExp rexIndex( " ([0-9]+)$" );
00313
00314
00315
00316
00317 if( rexPassIndex.search( pAction->methodSlotPtr() ) >= 0 && rexIndex.search( pAction->name() ) >= 0 ) {
00318 int n = rexIndex.cap(1).toInt();
00319 kdDebug(125) << "Calling " << pAction->methodSlotPtr() << " int = " << n << endl;
00320 int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
00321 if( slot_id >= 0 ) {
00322 QUObject o[2];
00323 static_QUType_int.set(o+1,n);
00324 const_cast< QObject* >( pAction->objSlotPtr())->qt_invoke( slot_id, o );
00325 }
00326 } else if( rexPassInfo.search( pAction->methodSlotPtr() ) ) {
00327 int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
00328 if( slot_id >= 0 ) {
00329 QUObject o[4];
00330 static_QUType_QString.set(o+1,pAction->name());
00331 static_QUType_QString.set(o+2,pAction->label());
00332 static_QUType_ptr.set(o+3,&seq);
00333 const_cast< QObject* >( pAction->objSlotPtr())->qt_invoke( slot_id, o );
00334 }
00335 } else {
00336 int slot_id = pAction->objSlotPtr()->metaObject()->findSlot( normalizeSignalSlot( pAction->methodSlotPtr() ).data() + 1, true );
00337 if( slot_id >= 0 )
00338 const_cast< QObject* >( pAction->objSlotPtr())->qt_invoke( slot_id, 0 );
00339 }
00340 }
00341
00342 void KGlobalAccelPrivate::slotActivated( int iAction )
00343 {
00344 KAccelAction* pAction = actions().actionPtr( iAction );
00345 if( pAction )
00346 activate( pAction, KKeySequence() );
00347 }
00348
00349 #include "kglobalaccel_x11.moc"
00350
00351 #endif // !Q_WS_X11