From 3c6af0ff2871ecc55d53490d9fd52d7005bb24cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Lu=C5=88=C3=A1k?= Date: Mon, 27 Feb 2006 10:13:31 +0000 Subject: [PATCH] Use a separate focus chain for each virtual desktop - this prevents onalldesktop windows from usually getting focus after every virtual desktop switch. Thanks for most of the work go to Guido Fiala . (#33701) svn path=/trunk/KDE/kdebase/workspace/; revision=514057 --- activation.cpp | 24 +++++------- client.cpp | 5 +++ events.cpp | 5 +-- layers.cpp | 23 ++++++++---- tabbox.cpp | 26 +++++++------ workspace.cpp | 100 ++++++++++++++++++++++++++++++++----------------- workspace.h | 4 +- 7 files changed, 115 insertions(+), 72 deletions(-) diff --git a/activation.cpp b/activation.cpp index 7e09109d0d..1272f1e933 100644 --- a/activation.cpp +++ b/activation.cpp @@ -229,9 +229,7 @@ void Workspace::setActiveClient( Client* c, allowed_t ) last_active_client = active_client; if ( active_client ) { - focus_chain.remove( c ); - if ( c->wantsTabFocus() ) - focus_chain.append( c ); + updateFocusChains( active_client, true ); // make it first in focus chain active_client->demandAttention( false ); } pending_take_activity = NULL; @@ -400,27 +398,25 @@ bool Workspace::activateNextClient( Client* c ) } if( focusChangeEnabled()) { - if ( c != NULL && c->wantsTabFocus() && focus_chain.contains( c ) ) - { - focus_chain.remove( c ); - focus_chain.prepend( c ); - } if ( options->focusPolicyIsReasonable()) { // search the focus_chain for a client to transfer focus to - // if 'c' is transient, transfer focus to the first suitable mainwindow + // if 'c' is transient, transfer focus to the first suitable mainwindow Client* get_focus = NULL; const ClientList mainwindows = ( c != NULL ? c->mainClients() : ClientList()); - for ( int i = focus_chain.size() - 1; i >= 0; --i ) + for ( int i = focus_chain[ currentDesktop() ].size() - 1; + i >= 0; + --i ) { - if( !focus_chain.at( i )->isShown( false ) || !focus_chain.at( i )->isOnCurrentDesktop()) + if( !focus_chain[ currentDesktop() ].at( i )->isShown( false ) + || !focus_chain[ currentDesktop() ].at( i )->isOnCurrentDesktop()) continue; - if( mainwindows.contains( focus_chain.at( i ) )) + if( mainwindows.contains( focus_chain[ currentDesktop() ].at( i ) )) { - get_focus = focus_chain.at( i ); + get_focus = focus_chain[ currentDesktop() ].at( i ); break; } if( get_focus == NULL ) - get_focus = focus_chain.at( i ); + get_focus = focus_chain[ currentDesktop() ].at( i ); } if( get_focus == NULL ) get_focus = findDesktop( true, currentDesktop()); diff --git a/client.cpp b/client.cpp index 5c3de48c8b..0b4a833912 100644 --- a/client.cpp +++ b/client.cpp @@ -574,6 +574,7 @@ void Client::minimize( bool avoid_animation ) updateAllowedActions(); workspace()->updateMinimizedOfTransients( this ); updateWindowRules(); + workspace()->updateFocusChains( this, false ); // make it last in the focus chain } void Client::unminimize( bool avoid_animation ) @@ -1132,6 +1133,7 @@ void Client::processKillerExited() void Client::setSkipTaskbar( bool b, bool from_outside ) { + int was_wants_tab_focus = wantsTabFocus(); if( from_outside ) { b = rules()->checkSkipTaskbar( b ); @@ -1142,6 +1144,8 @@ void Client::setSkipTaskbar( bool b, bool from_outside ) skip_taskbar = b; info->setState( b?NET::SkipTaskbar:0, NET::SkipTaskbar ); updateWindowRules(); + if( was_wants_tab_focus != wantsTabFocus()) + workspace()->updateFocusChains( this, isActive()); } void Client::setSkipPager( bool b ) @@ -1183,6 +1187,7 @@ void Client::setDesktop( int desktop ) } if( decoration != NULL ) decoration->desktopChange(); + workspace()->updateFocusChains( this, true ); updateVisibility(); updateWindowRules(); } diff --git a/events.cpp b/events.cpp index 8aced29952..7c4124f2f8 100644 --- a/events.cpp +++ b/events.cpp @@ -366,11 +366,10 @@ bool Workspace::workspaceEvent( XEvent * e ) XMapRaised( QX11Info::display(), e->xmaprequest.window ); return true; } - if ( c ) + if( c ) { c->windowEvent( e ); - if ( !c->wantsTabFocus()) - focus_chain.remove( c ); // TODO move focus_chain changes to functions + updateFocusChains( c, true ); return true; } break; diff --git a/layers.cpp b/layers.cpp index 76d39f7346..b21c402dfe 100644 --- a/layers.cpp +++ b/layers.cpp @@ -411,16 +411,23 @@ void Workspace::restackClientUnderActive( Client* c ) } } assert( unconstrained_stacking_order.contains( c )); - if( c->wantsTabFocus() && focus_chain.contains( active_client )) - { - // also put in focus_chain after all windows belonging to the active application - focus_chain.remove( c ); - for ( int i = focus_chain.size() - 1; i >= 0 ; i-- ) + for( int desktop = 1; + desktop <= numberOfDesktops(); + ++desktop ) + { // do for every virtual desktop to handle the case of onalldesktop windows + if( c->wantsTabFocus() && c->isOnDesktop( desktop ) && focus_chain[ desktop ].contains( active_client )) { - if( Client::belongToSameApplication( active_client, focus_chain.at( i ) )) + // also put in focus_chain[currentDesktop()] after all windows belonging to the active applicationa + focus_chain[ desktop ].remove( c ); + for ( int i = focus_chain[ desktop ].size() - 1; + i >= 0; + --i ) { - focus_chain.insert( i, c ); - break; + if( Client::belongToSameApplication( active_client, focus_chain[ desktop ].at( i ) )) + { + focus_chain[ desktop ].insert( i, c ); + break; + } } } } diff --git a/tabbox.cpp b/tabbox.cpp index 99ab86067d..9927c45b33 100644 --- a/tabbox.cpp +++ b/tabbox.cpp @@ -1149,13 +1149,14 @@ int Workspace::previousDesktopFocusChain( int iDesktop ) const */ Client* Workspace::nextFocusChainClient( Client* c ) const { - if ( focus_chain.isEmpty() ) + int desktop = c->isOnAllDesktops() ? currentDesktop() : c->desktop(); + if ( focus_chain[desktop].isEmpty() ) return 0; - ClientList::ConstIterator it = focus_chain.find( c ); - if ( it == focus_chain.end() ) - return focus_chain.last(); - if ( it == focus_chain.begin() ) - return focus_chain.last(); + ClientList::ConstIterator it = focus_chain[desktop].find( c ); + if ( it == focus_chain[desktop].end() ) + return focus_chain[desktop].last(); + if ( it == focus_chain[desktop].begin() ) + return focus_chain[desktop].last(); --it; return *it; } @@ -1166,14 +1167,15 @@ Client* Workspace::nextFocusChainClient( Client* c ) const */ Client* Workspace::previousFocusChainClient( Client* c ) const { - if ( focus_chain.isEmpty() ) + int desktop = c->isOnAllDesktops() ? currentDesktop() : c->desktop(); + if ( focus_chain[desktop].isEmpty() ) return 0; - ClientList::ConstIterator it = focus_chain.find( c ); - if ( it == focus_chain.end() ) - return focus_chain.first(); + ClientList::ConstIterator it = focus_chain[desktop].find( c ); + if ( it == focus_chain[desktop].end() ) + return focus_chain[desktop].first(); ++it; - if ( it == focus_chain.end() ) - return focus_chain.first(); + if ( it == focus_chain[desktop].end() ) + return focus_chain[desktop].first(); return *it; } diff --git a/workspace.cpp b/workspace.cpp index 20a1dc7de4..197d671ca8 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -514,8 +514,7 @@ void Workspace::addClient( Client* c, allowed_t ) } else { - if ( c->wantsTabFocus() && !focus_chain.contains( c )) - focus_chain.append( c ); + updateFocusChains( c, true ); clients.append( c ); } if( !unconstrained_stacking_order.contains( c )) @@ -563,7 +562,10 @@ void Workspace::removeClient( Client* c, allowed_t ) desktops.remove( c ); unconstrained_stacking_order.remove( c ); stacking_order.remove( c ); - focus_chain.remove( c ); + for( int i = 1; + i <= numberOfDesktops(); + ++i ) + focus_chain[ i ].remove( c ); attention_chain.remove( c ); if( c->isTopMenu()) removeTopMenu( c ); @@ -590,6 +592,49 @@ void Workspace::removeClient( Client* c, allowed_t ) updateClientArea(); } +void Workspace::updateFocusChains( Client* c, bool make_first ) + { + if( !c->wantsTabFocus()) // doesn't want tab focus, remove + { + for( int i=1; + i<= numberOfDesktops(); + ++i ) + focus_chain[i].remove(c); + return; + } + if(c->desktop() == NET::OnAllDesktops) + { //now on all desktops, add it to focus_chains it is not already in + for( int i=1; i<= numberOfDesktops(); i++) + { // make_first works only on current desktop, don't affect all desktops + if( make_first && i == currentDesktop()) + { + focus_chain[ i ].remove( c ); + focus_chain[ i ].append( c ); + } + else if( !focus_chain[ i ].contains( c )) + focus_chain[ i ].prepend( c ); // otherwise add as the last one + } + } + else //now only on desktop, remove it anywhere else + { + for( int i=1; i<= numberOfDesktops(); i++) + { + if( i == c->desktop()) + { + if( make_first ) + { + focus_chain[ i ].remove( c ); + focus_chain[ i ].append( c ); + } + else if( !focus_chain[ i ].contains( c )) + focus_chain[ i ].prepend( c ); + } + else + focus_chain[ i ].remove( c ); + } + } + } + void Workspace::updateCurrentTopMenu() { if( !managingTopMenus()) @@ -916,6 +961,8 @@ void Workspace::loadDesktopSettings() screenarea = NULL; rootInfo->setNumberOfDesktops( number_of_desktops ); desktop_focus_chain.resize( n ); + // make it +1, so that it can be accessed as [1..numberofdesktops] + focus_chain.resize( n + 1 ); for(int i = 1; i <= n; i++) { QString s = group.readEntry(QString("Name_%1").arg(i), @@ -1140,36 +1187,22 @@ bool Workspace::setCurrentDesktop( int new_desktop ) if ( options->focusPolicyIsReasonable()) { // Search in focus chain - - if ( focus_chain.contains( active_client ) && active_client->isShown( true ) - && active_client->isOnCurrentDesktop()) + if ( movingClient != NULL && active_client == movingClient + && focus_chain[currentDesktop()].contains( active_client ) + && active_client->isShown( true ) && active_client->isOnCurrentDesktop()) { c = active_client; // the requestFocus below will fail, as the client is already active } - - if ( !c ) + if( !c ) { - for( int i = focus_chain.size() - 1; - i >= 0; - --i ) + for( int i = focus_chain[ currentDesktop() ].size() - 1; + i >= 0; + --i ) { - if ( focus_chain.at( i )->isShown( false ) && !focus_chain.at( i )->isOnAllDesktops() && focus_chain.at( i )->isOnCurrentDesktop()) + if( focus_chain[ currentDesktop() ].at( i )->isShown( false ) + && focus_chain[ currentDesktop() ].at( i )->isOnCurrentDesktop()) { - c = focus_chain.at( i ); - break; - } - } - } - - if ( !c ) - { - for( int i = focus_chain.size() - 1; - i >= 0; - --i ) - { - if ( focus_chain.at( i )->isShown( false ) && focus_chain.at( i )->isOnCurrentDesktop()) - { - c = focus_chain.at( i ); + c = focus_chain[ currentDesktop() ].at( i ); break; } } @@ -1202,13 +1235,13 @@ bool Workspace::setCurrentDesktop( int new_desktop ) updateCurrentTopMenu(); // Update focus chain: - // If input: chain = { 1, 2, 3, 4 } and current_desktop = 3, + // If input: chain = { 1, 2, 3, 4 } and currentDesktop() = 3, // Output: chain = { 3, 1, 2, 4 }. // kDebug(1212) << QString("Switching to desktop #%1, at focus_chain index %2\n") -// .arg(current_desktop).arg(desktop_focus_chain.find( current_desktop )); - for( int i = desktop_focus_chain.indexOf( current_desktop ); i > 0; i-- ) +// .arg(currentDesktop()).arg(desktop_focus_chain.find( currentDesktop() )); + for( int i = desktop_focus_chain.indexOf( currentDesktop() ); i > 0; i-- ) desktop_focus_chain[i] = desktop_focus_chain[i-1]; - desktop_focus_chain[0] = current_desktop; + desktop_focus_chain[0] = currentDesktop(); // QString s = "desktop_focus_chain[] = { "; // for( uint i = 0; i < desktop_focus_chain.size(); i++ ) @@ -1381,6 +1414,7 @@ void Workspace::setNumberOfDesktops( int n ) rootInfo->setDesktopViewport( number_of_desktops, *viewports ); delete[] viewports; updateClientArea( true ); + focus_chain.resize( number_of_desktops + 1 ); } // if the number of desktops decreased, move all @@ -1402,6 +1436,7 @@ void Workspace::setNumberOfDesktops( int n ) rootInfo->setDesktopViewport( number_of_desktops, *viewports ); delete[] viewports; updateClientArea( true ); + focus_chain.resize( number_of_desktops + 1 ); } saveDesktopSettings(); @@ -1437,9 +1472,6 @@ void Workspace::sendClientToDesktop( Client* c, int desk, bool dont_activate ) else { raiseClient( c ); - focus_chain.remove( c ); - if ( c->wantsTabFocus() ) - focus_chain.append( c ); } ClientList transients_stacking_order = ensureStackingOrder( c->transients()); diff --git a/workspace.h b/workspace.h index 7c3a726016..6a18655cf6 100644 --- a/workspace.h +++ b/workspace.h @@ -13,6 +13,7 @@ License. See the file "COPYING" for the exact licensing terms. #define KWIN_WORKSPACE_H #include +#include #include #include #include @@ -250,6 +251,7 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine bool checkStartupNotification( Window w, KStartupInfoId& id, KStartupInfoData& data ); void focusToNull(); // SELI public? + void updateFocusChains( Client* c, bool make_first ); bool forcedGlobalMouseGrab() const; void clientShortcutUpdated( Client* c ); @@ -507,7 +509,7 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine ClientList unconstrained_stacking_order; ClientList stacking_order; - ClientList focus_chain; + QVector< ClientList > focus_chain; ClientList should_get_focus; // last is most recent ClientList attention_chain;