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