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 <gfiala@s.netic.de>.
(#33701)


svn path=/trunk/KDE/kdebase/workspace/; revision=514057
This commit is contained in:
Luboš Luňák 2006-02-27 10:13:31 +00:00
parent c4e72833fe
commit 3c6af0ff28
7 changed files with 115 additions and 72 deletions

View file

@ -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());

View file

@ -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();
}

View file

@ -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;

View file

@ -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;
}
}
}
}

View file

@ -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;
}

View file

@ -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());

View file

@ -13,6 +13,7 @@ License. See the file "COPYING" for the exact licensing terms.
#define KWIN_WORKSPACE_H
#include <qtimer.h>
#include <qvector.h>
#include <kshortcut.h>
#include <qcursor.h>
#include <netwm.h>
@ -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;