diff --git a/kwinbindings.cpp b/kwinbindings.cpp index 5986c8b4ff..3374d83f44 100644 --- a/kwinbindings.cpp +++ b/kwinbindings.cpp @@ -32,6 +32,11 @@ keys->insertItem(i18n("Window resize"),"Window resize", ""); keys->insertItem(i18n("Window raise"),"Window raise", ""); keys->insertItem(i18n("Window lower"),"Window lower", ""); + + keys->insertItem(i18n("Walk through desktops"),"Walk through desktops", "CTRL+Tab"); + keys->insertItem(i18n("Walk back through desktops"),"Walk back through desktops", "SHIFT+CTRL+Tab"); + keys->insertItem(i18n("Walk through windows"),"Walk through windows", "ALT+Tab"); + keys->insertItem(i18n("Walk back through windows"),"Walk back through windows", "SHIFT+ALT+Tab"); keys->insertItem(i18n("Mouse emulation"),"Mouse emulation", "ALT+F12"); diff --git a/options.cpp b/options.cpp index d6ad32b9ca..486289c33a 100644 --- a/options.cpp +++ b/options.cpp @@ -194,8 +194,6 @@ void Options::reload() // desktop settings config->setGroup("Desktops"); - // Enable the grab of control-TAB? - useControlTab = config->readBoolEntry ("ControlTab", TRUE); desktopRows = config->readNumEntry( "DesktopRows", 2 ); if ( desktopRows < 1 ) desktopRows = 1; diff --git a/options.h b/options.h index 70aa98a688..c317ec25e8 100644 --- a/options.h +++ b/options.h @@ -104,11 +104,6 @@ public: AltTabStyle altTabStyle; - /** - Control-TAB shortcut to switch virtual desktop. - */ - bool useControlTab; - /** Number of desktop rowsd */ diff --git a/tabbox.cpp b/tabbox.cpp index 8b32d0cbd2..42132bc3be 100644 --- a/tabbox.cpp +++ b/tabbox.cpp @@ -21,13 +21,12 @@ extern QPixmap* kwin_get_menu_pix_hack(); using namespace KWinInternal; -const bool options_traverse_all = FALSE; // TODO - TabBox::TabBox( Workspace *ws, const char *name ) : QWidget( 0, name, WStyle_Customize | WStyle_NoBorder ) { no_tasks = i18n("*** No Tasks ***"); wspace = ws; + reconfigure(); reset(); connect(&delayedShowTimer, SIGNAL(timeout()), this, SLOT(show())); } @@ -288,6 +287,13 @@ void TabBox::hide() } +void TabBox::reconfigure() +{ + KConfig * c(KGlobal::config()); + c->setGroup("TabBox"); + options_traverse_all = c->readNumEntry("TraverseAll", false ); +} + /*! Rikkus: please document! (Matthias) diff --git a/tabbox.h b/tabbox.h index f14f101a77..9f91fdb837 100644 --- a/tabbox.h +++ b/tabbox.h @@ -37,6 +37,8 @@ public: void hide(); Workspace* workspace() const; + + void reconfigure(); protected: void paintEvent( QPaintEvent* ); @@ -54,6 +56,7 @@ private: int wmax; QTimer delayedShowTimer; QString no_tasks; + bool options_traverse_all; }; diff --git a/workspace.cpp b/workspace.cpp index df337e0dad..97f4d0b203 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -281,12 +281,6 @@ Workspace::Workspace( bool restore ) 1 ); - grabKey(XK_Tab, Mod1Mask); - grabKey(XK_Tab, Mod1Mask | ShiftMask); - - // Do this unless the user disabled it... - grabControlTab(options->useControlTab); - createKeybindings(); tab_box = new TabBox( this ); @@ -682,103 +676,226 @@ void Workspace::freeKeyboard(bool pass){ QApplication::syncX(); } +#if 0 // 4 mods +#define XMODMASK ( ShiftMask | ControlMask | Mod1Mask | Mod4Mask ) +#else +#define XMODMASK ( ShiftMask | ControlMask | Mod1Mask ) +#endif /*! Handles alt-tab / control-tab */ + + +void Workspace::slotWalkThroughWindows() +{ + if ( root != qt_xrootwin() ) + return; + if( tab_grab || control_grab ) + return; + if ( options->altTabStyle == Options::CDE || !options->focusPolicyIsReasonable() ) + // CDE style raise / lower + CDEWalkThroughWindows( true ); + else { + if(( keyToXMod( walkThroughWindowsKeycode ) & XMODMASK ) != 0 ) { + startKDEWalkThroughWindows(); + KDEWalkThroughWindows( true ); + } + else + // if the shortcut has no modifiers, don't show the tabbox, but + // simply go to the next window; if the shortcut has no modifiers, + // the only sane thing to do is to release the key immediately + // anyway, so the tabbox wouldn't appear anyway + // it's done this way without grabbing because with grabbing + // the keyboard wasn't ungrabbed and I really have no idea why + // + KDEOneStepThroughWindows( true ); + } +} + +void Workspace::slotWalkBackThroughWindows() +{ + if ( root != qt_xrootwin() ) + return; + if( tab_grab || control_grab ) + return; + if ( options->altTabStyle == Options::CDE || !options->focusPolicyIsReasonable() ) + // CDE style raise / lower + CDEWalkThroughWindows( true ); + else { + if(( keyToXMod( walkBackThroughWindowsKeycode ) & XMODMASK ) != 0 ) { + startKDEWalkThroughWindows(); + KDEWalkThroughWindows( false ); + } + else + KDEOneStepThroughWindows( false ); + } +} + +void Workspace::slotWalkThroughDesktops() +{ + if ( root != qt_xrootwin() ) + return; + if( tab_grab || control_grab ) + return; + if(( keyToXMod( walkThroughDesktopsKeycode ) & XMODMASK ) != 0 ) { + startWalkThroughDesktops(); + walkThroughDesktops( true ); + } + else + oneStepThroughDesktops( true ); +} + +void Workspace::slotWalkBackThroughDesktops() +{ + if ( root != qt_xrootwin() ) + return; + if( tab_grab || control_grab ) + return; + if(( keyToXMod( walkBackThroughDesktopsKeycode ) & XMODMASK ) != 0 ) { + startWalkThroughDesktops(); + walkThroughDesktops( false ); + } + else + oneStepThroughDesktops( false ); +} + +void Workspace::startKDEWalkThroughWindows() +{ + if ( XGrabPointer( qt_xdisplay(), root, TRUE, + (uint)(ButtonPressMask | ButtonReleaseMask | + ButtonMotionMask | EnterWindowMask | + LeaveWindowMask | PointerMotionMask), + GrabModeSync, GrabModeAsync, + None, None, kwin_time ) != GrabSuccess ) { + freeKeyboard(FALSE); + return; + } + XGrabKeyboard(qt_xdisplay(), + root, FALSE, + GrabModeAsync, GrabModeAsync, + kwin_time); + tab_grab = TRUE; + keys->setEnabled( FALSE ); + tab_box->setMode( TabBox::WindowsMode ); + tab_box->reset(); +} + +void Workspace::startWalkThroughDesktops() +{ + if ( XGrabPointer( qt_xdisplay(), root, TRUE, + (uint)(ButtonPressMask | ButtonReleaseMask | + ButtonMotionMask | EnterWindowMask | + LeaveWindowMask | PointerMotionMask), + GrabModeSync, GrabModeAsync, + None, None, kwin_time ) != GrabSuccess ) { + freeKeyboard(FALSE); + return; + } + XGrabKeyboard(qt_xdisplay(), + root, FALSE, + GrabModeAsync, GrabModeAsync, + kwin_time); + control_grab = TRUE; + keys->setEnabled( FALSE ); + tab_box->setMode( TabBox::DesktopMode ); + tab_box->reset(); +} + +void Workspace::KDEWalkThroughWindows( bool forward ) +{ + tab_box->nextPrev( forward ); + tab_box->delayedShow(); +} + +void Workspace::walkThroughDesktops( bool forward ) +{ + tab_box->nextPrev( forward ); + tab_box->delayedShow(); +} + +void Workspace::CDEWalkThroughWindows( bool forward ) + { + Client* c = topClientOnDesktop(); + Client* nc = c; + if ( !forward ){ + do { + nc = previousStaticClient(nc); + } while (nc && nc != c && + (!nc->isOnDesktop(currentDesktop()) || + nc->isIconified() || !nc->wantsTabFocus() ) ); + } + else + do { + nc = nextStaticClient(nc); + } while (nc && nc != c && + (!nc->isOnDesktop(currentDesktop()) || + nc->isIconified() || !nc->wantsTabFocus() ) ); + if (c && c != nc) + lowerClient( c ); + if (nc) { + if ( options->focusPolicyIsReasonable() ) + activateClient( nc ); + else + raiseClient( nc ); + } + freeKeyboard(FALSE); + } + +void Workspace::KDEOneStepThroughWindows( bool forward ) +{ + tab_box->setMode( TabBox::WindowsMode ); + tab_box->reset(); + tab_box->nextPrev( forward ); + if ( tab_box->currentClient() ){ + activateClient( tab_box->currentClient() ); + } +} + +void Workspace::oneStepThroughDesktops( bool forward ) +{ + tab_box->setMode( TabBox::DesktopMode ); + tab_box->reset(); + tab_box->nextPrev( forward ); + if ( tab_box->currentDesktop() != -1 ) + setCurrentDesktop( tab_box->currentDesktop() ); +} + +/*! + Handles holding alt-tab / control-tab + */ bool Workspace::keyPress(XKeyEvent key) { if ( root != qt_xrootwin() ) return FALSE; - int kc = XKeycodeToKeysym(qt_xdisplay(), key.keycode, 0); - int km = key.state & (ControlMask | Mod1Mask | ShiftMask); - + unsigned int kc = XKeycodeToKeysym(qt_xdisplay(), key.keycode, 0); + unsigned int km = key.state & XMODMASK; if (!control_grab){ - - if( (kc == XK_Tab) && - ( km == (Mod1Mask | ShiftMask) - || km == (Mod1Mask) - )){ - if (!tab_grab){ - if ( options->altTabStyle == Options::CDE || !options->focusPolicyIsReasonable() ){ - // CDE style raise / lower - Client* c = topClientOnDesktop(); - Client* nc = c; - if (km & ShiftMask){ - do { - nc = previousStaticClient(nc); - } while (nc && nc != c && - (!nc->isOnDesktop(currentDesktop()) || - nc->isIconified() || !nc->wantsTabFocus() ) ); - - } - else - do { - nc = nextStaticClient(nc); - } while (nc && nc != c && - (!nc->isOnDesktop(currentDesktop()) || - nc->isIconified() || !nc->wantsTabFocus() ) ); - if (c && c != nc) - lowerClient( c ); - if (nc) { - if ( options->focusPolicyIsReasonable() ) - activateClient( nc ); - else - raiseClient( nc ); - } - freeKeyboard(FALSE); - return TRUE; - } - if ( XGrabPointer( qt_xdisplay(), root, TRUE, - (uint)(ButtonPressMask | ButtonReleaseMask | - ButtonMotionMask | EnterWindowMask | - LeaveWindowMask | PointerMotionMask), - GrabModeSync, GrabModeAsync, - None, None, kwin_time ) != GrabSuccess ) { - freeKeyboard(FALSE); - return TRUE; - } - XGrabKeyboard(qt_xdisplay(), - root, FALSE, - GrabModeAsync, GrabModeAsync, - kwin_time); - tab_grab = TRUE; - tab_box->setMode( TabBox::WindowsMode ); - tab_box->reset(); + + if( ( kc == keyToXSym( walkThroughWindowsKeycode ) + && km == keyToXMod( walkThroughWindowsKeycode )) + || ( kc == keyToXSym( walkBackThroughWindowsKeycode ) + && km == keyToXMod( walkBackThroughWindowsKeycode ))) { + if (!tab_grab) { + freeKeyboard(FALSE); + return FALSE; } - tab_box->nextPrev( (km & ShiftMask) == 0 ); - keys->setEnabled( FALSE ); - tab_box->delayedShow(); + KDEWalkThroughWindows( ( kc == keyToXSym( walkThroughWindowsKeycode ) + && km == keyToXMod( walkThroughWindowsKeycode ))); } } - if (!tab_grab && options->useControlTab){ + if (!tab_grab){ - - if( (kc == XK_Tab) && - ( km == (ControlMask | ShiftMask) - || km == (ControlMask) - )){ - if (!control_grab){ - if ( XGrabPointer( qt_xdisplay(), root, TRUE, - (uint)(ButtonPressMask | ButtonReleaseMask | - ButtonMotionMask | EnterWindowMask | - LeaveWindowMask | PointerMotionMask), - GrabModeSync, GrabModeAsync, - None, None, kwin_time ) != GrabSuccess ) { - freeKeyboard(FALSE); - return TRUE; - } - XGrabKeyboard(qt_xdisplay(), - root, FALSE, - GrabModeAsync, GrabModeAsync, - kwin_time); - control_grab = TRUE; - tab_box->setMode( TabBox::DesktopMode ); - tab_box->reset(); + if( ( kc == keyToXSym( walkThroughDesktopsKeycode ) + && km == keyToXMod( walkThroughDesktopsKeycode )) + || ( kc == keyToXSym( walkBackThroughDesktopsKeycode ) + && km == keyToXMod( walkBackThroughDesktopsKeycode ))) { + if (!control_grab) { + freeKeyboard(FALSE); + return FALSE; } - tab_box->nextPrev( (km & ShiftMask) == 0 ); - keys->setEnabled( FALSE ); - tab_box->delayedShow(); + walkThroughDesktops( ( kc == keyToXSym( walkThroughDesktopsKeycode ) + && km == keyToXMod( walkThroughDesktopsKeycode ))); } } @@ -800,35 +917,52 @@ bool Workspace::keyPress(XKeyEvent key) } /*! - Handles alt-tab / control-tab + Handles alt-tab / control-tab releasing */ bool Workspace::keyRelease(XKeyEvent key) { if ( root != qt_xrootwin() ) return FALSE; - int i; - if (tab_grab){ + if( !tab_grab && !control_grab ) + return FALSE; + unsigned int mk = key.state & XMODMASK; + // key.state is state before the key release, so just checking mk being 0 isn't enough + // using XQueryPointer() also doesn't seem to work well, so the check that all + // modifiers are released is : only one modifier is active and the currently released + // key is this modifier - if yes, release the grab + int mod_index = -1; + for( int i = ShiftMapIndex; + i <= Mod5MapIndex; + ++i ) + if(( mk & ( 1 << i )) != 0 ) { + if( mod_index >= 0 ) + return FALSE; + mod_index = i; + } + bool release = false; + if( mod_index == -1 ) + release = true; + else { XModifierKeymap* xmk = XGetModifierMapping(qt_xdisplay()); - for (i=0; imax_keypermod; i++) - if (xmk->modifiermap[xmk->max_keypermod * Mod1MapIndex + i] - == key.keycode){ + for (int i=0; imax_keypermod; i++) + if (xmk->modifiermap[xmk->max_keypermod * mod_index + i] + == key.keycode) + release = true; + XFreeModifiermap(xmk); + } + if( !release ) + return FALSE; + if (tab_grab){ XUngrabKeyboard(qt_xdisplay(), kwin_time); XUngrabPointer( qt_xdisplay(), kwin_time); tab_box->hide(); keys->setEnabled( TRUE ); tab_grab = false; if ( tab_box->currentClient() ){ - activateClient( tab_box->currentClient() ); } - } - XFreeModifiermap(xmk); } - if (control_grab && options->useControlTab){ - XModifierKeymap* xmk = XGetModifierMapping(qt_xdisplay()); - for (i=0; imax_keypermod; i++) - if (xmk->modifiermap[xmk->max_keypermod * ControlMapIndex + i] - == key.keycode){ + if (control_grab){ XUngrabPointer( qt_xdisplay(), kwin_time); XUngrabKeyboard(qt_xdisplay(), kwin_time); tab_box->hide(); @@ -836,12 +970,12 @@ bool Workspace::keyRelease(XKeyEvent key) control_grab = False; if ( tab_box->currentDesktop() != -1 ) setCurrentDesktop( tab_box->currentDesktop() ); - } - XFreeModifiermap(xmk); } return FALSE; } +#undef XMODMASK + /*! auxiliary functions to travers all clients according the focus order. Useful for kwm´s Alt-tab feature. @@ -927,73 +1061,6 @@ Client* Workspace::topClientOnDesktop() const return 0; } -/* - Grabs the keysymbol \a keysym with the given modifiers \a mod - plus all possibile combinations of Lock and NumLock - */ -void Workspace::grabKey(KeySym keysym, unsigned int mod){ - static int NumLockMask = 0; - if (!keysym||!XKeysymToKeycode(qt_xdisplay(), keysym)) return; - if (!NumLockMask){ - XModifierKeymap* xmk = XGetModifierMapping(qt_xdisplay()); - int i; - for (i=0; i<8; i++){ - if (xmk->modifiermap[xmk->max_keypermod * i] == - XKeysymToKeycode(qt_xdisplay(), XK_Num_Lock)) - NumLockMask = (1<modifiermap[xmk->max_keypermod * i] == - XKeysymToKeycode(qt_xdisplay(), XK_Num_Lock)) - NumLockMask = (1<reparseConfiguration(); options->reload(); keys->readSettings(); - grabControlTab(options->useControlTab); + tab_box->reconfigure(); + walkThroughDesktopsKeycode = keys->currentKey( "Walk through desktops" ); + walkBackThroughDesktopsKeycode = keys->currentKey( "Walk back through desktops" ); + walkThroughWindowsKeycode = keys->currentKey( "Walk through windows" ); + walkBackThroughWindowsKeycode = keys->currentKey( "Walk back through windows" ); mgr->updatePlugin(); // NO need whatsoever to call slotResetAllClientsDelayed here, // updatePlugin resets all clients if necessary anyway. } -/*! - Grab/Ungrab the Control key dynamically - */ -void Workspace::grabControlTab(bool grab) -{ - if (grab) { - grabKey(XK_Tab, ControlMask); - grabKey(XK_Tab, ControlMask | ShiftMask); - } - else { - ungrabKey(XK_Tab,ControlMask); - ungrabKey(XK_Tab, ControlMask | ShiftMask); - } -} - - /*! avoids managing a window with title \a title */ @@ -2215,12 +2270,21 @@ void Workspace::createKeybindings(){ keys->connectItem( "Window raise", this, SLOT( slotWindowRaise() ) ); keys->connectItem( "Window lower", this, SLOT( slotWindowLower() ) ); + keys->connectItem( "Walk through desktops", this, SLOT( slotWalkThroughDesktops())); + keys->connectItem( "Walk back through desktops", this, SLOT( slotWalkBackThroughDesktops())); + keys->connectItem( "Walk through windows",this, SLOT( slotWalkThroughWindows())); + keys->connectItem( "Walk back through windows",this, SLOT( slotWalkBackThroughWindows())); + keys->connectItem( "Mouse emulation", this, SLOT( slotMouseEmulation() ) ); keys->connectItem( "Logout", this, SLOT( slotLogout() ) ); keys->connectItem( "Kill Window", this, SLOT( slotKillWindow() ) ); keys->readSettings(); + walkThroughDesktopsKeycode = keys->currentKey( "Walk through desktops" ); + walkBackThroughDesktopsKeycode = keys->currentKey( "Walk back through desktops" ); + walkThroughWindowsKeycode = keys->currentKey( "Walk through windows" ); + walkBackThroughWindowsKeycode = keys->currentKey( "Walk back through windows" ); } void Workspace::slotSwitchDesktop1(){ diff --git a/workspace.h b/workspace.h index 8dcdfe24ae..223d6679e5 100644 --- a/workspace.h +++ b/workspace.h @@ -146,11 +146,6 @@ public: QWidget* desktopWidget(); - void grabKey(KeySym keysym, unsigned int mod); - void ungrabKey(KeySym keysym, unsigned int mod); - - void grabControlTab(bool grab); - Client* nextClient(Client*) const; Client* previousClient(Client*) const; Client* nextStaticClient(Client*) const; @@ -233,6 +228,11 @@ public slots: void slotWindowRaise(); void slotWindowLower(); + void slotWalkThroughDesktops(); + void slotWalkBackThroughDesktops(); + void slotWalkThroughWindows(); + void slotWalkBackThroughWindows(); + void slotWindowOperations(); void slotWindowClose(); void slotWindowMove(); @@ -264,6 +264,14 @@ private: void init(); void createKeybindings(); void freeKeyboard(bool pass); + + void startKDEWalkThroughWindows(); + void startWalkThroughDesktops(); + void KDEWalkThroughWindows( bool forward ); + void CDEWalkThroughWindows( bool forward ); + void walkThroughDesktops( bool forward ); + void KDEOneStepThroughWindows( bool forward ); + void oneStepThroughDesktops( bool forward ); ClientList constrainedStackingOrder( const ClientList& list ); @@ -334,6 +342,8 @@ private: bool control_grab; bool tab_grab; + unsigned int walkThroughDesktopsKeycode,walkBackThroughDesktopsKeycode; + unsigned int walkThroughWindowsKeycode,walkBackThroughWindowsKeycode; bool mouse_emulation; unsigned int mouse_emulation_state; WId mouse_emulation_window;