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