As KPassivePopup shows, things can be annoying even if they don't steal

the focus and just are there. Therefore, as a part of focus stealing
prevention, let's also block raising of windows. Also added special
request for Kicker, as taskbar requests for raising should be obeyed.
(Not that this does anything to KPassivePopup.)

svn path=/trunk/kdebase/kicker/taskmanager/; revision=255070
This commit is contained in:
Luboš Luňák 2003-09-30 12:49:23 +00:00
parent ce37c50587
commit 90281645bf
5 changed files with 159 additions and 25 deletions

View file

@ -472,6 +472,46 @@ bool Workspace::allowClientActivation( const Client* c, Time time, bool focus_in
return timestampCompare( time, user_time ) >= 0; // time >= user_time return timestampCompare( time, user_time ) >= 0; // time >= user_time
} }
// basically the same like allowClientActivation(), this time allowing
// a window to be fully raised upon its own request (XRaiseWindow),
// if refused, it will be raised only on top of windows belonging
// to the same application
bool Workspace::allowFullClientRaising( const Client* c )
{
if( session_saving
&& options->focusStealingPreventionLevel <= 3 ) // <= normal
{
return true;
}
Client* ac = activeClient();
if( options->focusStealingPreventionLevel == 0 ) // none
return true;
if( options->focusStealingPreventionLevel == 5 ) // extreme
return false;
if( ac == NULL || ac->isDesktop())
{
kdDebug( 1212 ) << "Raising: No client active, allowing" << endl;
return true; // no active client -> always allow
}
// TODO window urgency -> return true?
if( Client::belongToSameApplication( c, ac, true ))
{
kdDebug( 1212 ) << "Raising: Belongs to active application" << endl;
return true;
}
if( options->focusStealingPreventionLevel == 4 ) // high
return false;
if( !c->hasUserTimeSupport())
{
kdDebug() << "Raising: No support" << endl;
if( options->focusStealingPreventionLevel == 1 ) // low
return true;
}
// options->focusStealingPreventionLevel == 2 // normal
kdDebug() << "Raising: Refusing" << endl;
return false;
}
// called from Client after FocusIn that wasn't initiated by KWin and the client // called from Client after FocusIn that wasn't initiated by KWin and the client
// wasn't allowed to activate // wasn't allowed to activate
void Workspace::restoreFocus() void Workspace::restoreFocus()

View file

@ -228,7 +228,8 @@ class Client : public QObject, public KDecorationDefines
const QPoint calculateGravitation( bool invert ) const; // FRAME public? const QPoint calculateGravitation( bool invert ) const; // FRAME public?
void NETMoveResize( int x_root, int y_root, NET::Direction direction ); void NETMoveResize( int x_root, int y_root, NET::Direction direction );
void restackWindow( Window above, int detail, NET::RequestSource source, bool send_event = false );
void gotPing( Time timestamp ); void gotPing( Time timestamp );
static QCString staticWindowRole(WId); static QCString staticWindowRole(WId);
@ -240,6 +241,7 @@ class Client : public QObject, public KDecorationDefines
void checkWorkspacePosition(); void checkWorkspacePosition();
void updateUserTime( Time time = CurrentTime ); void updateUserTime( Time time = CurrentTime );
Time userTime() const; Time userTime() const;
bool hasUserTimeSupport() const;
// does 'delete c;' // does 'delete c;'
static void deleteClient( Client* c, allowed_t ); static void deleteClient( Client* c, allowed_t );
@ -768,6 +770,11 @@ inline void Client::resize( const QSize& s, bool force )
resize( s.width(), s.height(), force ); resize( s.width(), s.height(), force );
} }
inline bool Client::hasUserTimeSupport() const
{
return info->userTime() != -1U;
}
#ifdef NDEBUG #ifdef NDEBUG
kndbgstream& operator<<( kndbgstream& stream, const Client* ); kndbgstream& operator<<( kndbgstream& stream, const Client* );
#else #else

View file

@ -143,6 +143,11 @@ void RootInfo::gotPing( Window w, Time timestamp )
c->gotPing( timestamp ); c->gotPing( timestamp );
} }
void RootInfo::restackWindow( Window w, Window above, int detail )
{
if( Client* c = workspace->findClient( WindowMatchPredicate( w )))
c->restackWindow( above, detail, NET::FromTool, true );
}
// **************************************** // ****************************************
// Workspace // Workspace
@ -684,9 +689,6 @@ void Client::configureRequestEvent( XConfigureRequestEvent* e )
} }
} }
bool stacking = e->value_mask & CWStackMode;
int stack_mode = e->detail;
if ( e->value_mask & CWBorderWidth ) if ( e->value_mask & CWBorderWidth )
{ {
// first, get rid of a window border // first, get rid of a window border
@ -785,27 +787,8 @@ void Client::configureRequestEvent( XConfigureRequestEvent* e )
} }
} }
if ( e->value_mask & CWStackMode )
if ( stacking ) restackWindow( e->above, e->detail, NET::FromApplication );
{
switch (stack_mode)
{
case Above:
case TopIf:
if( workspace()->allowClientActivation( this )) // not really activation,
workspace()->raiseClient( this ); // but it's the same, showing
else // unwanted window on top
workspace()->restackClientUnderActive( this ); // would be obtrusive
break;
case Below:
case BottomIf:
workspace()->lowerClient( this );
break;
case Opposite:
default:
break;
}
}
// TODO sending a synthetic configure notify always is fine, even in cases where // TODO sending a synthetic configure notify always is fine, even in cases where
// the ICCCM doesn't require this - it can be though of as 'the WM decided to move // the ICCCM doesn't require this - it can be though of as 'the WM decided to move

View file

@ -261,6 +261,30 @@ void Workspace::lowerClient( Client* c )
most_recently_raised = 0; most_recently_raised = 0;
} }
void Workspace::lowerClientWithinApplication( Client* c )
{
if ( !c )
return;
StackingUpdatesBlocker blocker( this );
unconstrained_stacking_order.remove( c );
bool lowered = false;
// first try to put it below the bottom-most window of the application
for( ClientList::Iterator it = unconstrained_stacking_order.begin();
it != unconstrained_stacking_order.end();
++it )
if( Client::belongToSameApplication( *it, c ))
{
unconstrained_stacking_order.insert( it, c );
lowered = true;
break;
}
if( !lowered )
unconstrained_stacking_order.prepend( c );
// ignore mainwindows
}
void Workspace::raiseClient( Client* c ) void Workspace::raiseClient( Client* c )
{ {
if ( !c ) if ( !c )
@ -284,6 +308,54 @@ void Workspace::raiseClient( Client* c )
most_recently_raised = c; most_recently_raised = c;
} }
void Workspace::raiseClientWithinApplication( Client* c )
{
if ( !c )
return;
StackingUpdatesBlocker blocker( this );
// ignore mainwindows
unconstrained_stacking_order.remove( c );
bool raised = false;
// first try to put it above the top-most window of the application
for( ClientList::Iterator it = unconstrained_stacking_order.fromLast();
it != unconstrained_stacking_order.end();
--it )
if( Client::belongToSameApplication( *it, c ))
{
++it; // insert after the found one
unconstrained_stacking_order.insert( it, c );
raised = true;
break;
}
if( !raised )
restackClientUnderActive( c );
}
void Workspace::raiseClientRequest( Client* c )
{
if( allowFullClientRaising( c ))
raiseClient( c );
else
{
raiseClientWithinApplication( c );
c->demandAttention();
}
}
void Workspace::lowerClientRequest( Client* c )
{
// If the client has support for all this focus stealing prevention stuff,
// do only lowering within the application, as that's the more logical
// variant of lowering when application requests it.
// No demanding of attention here of course.
if( c->hasUserTimeSupport())
lowerClientWithinApplication( c );
else
lowerClient( c );
}
void Workspace::restackClientUnderActive( Client* c ) void Workspace::restackClientUnderActive( Client* c )
{ {
if( !active_client || active_client == c ) if( !active_client || active_client == c )
@ -485,6 +557,32 @@ bool Workspace::keepTransientAbove( const Client* mainwindow, const Client* tran
// Client // Client
//******************************* //*******************************
void Client::restackWindow( Window /*above TODO */, int detail, NET::RequestSource source, bool send_event )
{
switch ( detail )
{
case Above:
case TopIf:
if( source == NET::FromTool )
workspace()->raiseClient( this );
else
workspace()->raiseClientRequest( this );
break;
case Below:
case BottomIf:
if( source == NET::FromTool )
workspace()->lowerClient( this );
else
workspace()->lowerClientRequest( this );
break;
case Opposite:
default:
break;
}
if( send_event )
sendSyntheticConfigureNotify();
}
void Client::setKeepAbove( bool b ) void Client::setKeepAbove( bool b )
{ {
if ( b == keepAbove() ) if ( b == keepAbove() )

View file

@ -168,6 +168,8 @@ class Workspace : public QObject, virtual public KWinInterface, public KDecorati
QPoint adjustClientPosition( Client* c, QPoint pos ); QPoint adjustClientPosition( Client* c, QPoint pos );
void raiseClient( Client* c ); void raiseClient( Client* c );
void lowerClient( Client* c ); void lowerClient( Client* c );
void raiseClientRequest( Client* c );
void lowerClientRequest( Client* c );
void restackClientUnderActive( Client* ); void restackClientUnderActive( Client* );
void updateClientLayer( Client* c ); void updateClientLayer( Client* c );
void raiseOrLowerClient( Client * ); void raiseOrLowerClient( Client * );
@ -370,6 +372,9 @@ class Workspace : public QObject, virtual public KWinInterface, public KDecorati
void updateStackingOrder( bool propagate_new_clients = false ); void updateStackingOrder( bool propagate_new_clients = false );
void propagateClients( bool propagate_new_clients ); // called only from updateStackingOrder void propagateClients( bool propagate_new_clients ); // called only from updateStackingOrder
ClientList constrainedStackingOrder(); ClientList constrainedStackingOrder();
void raiseClientWithinApplication( Client* c );
void lowerClientWithinApplication( Client* c );
bool allowFullClientRaising( const Client* c );
bool keepTransientAbove( const Client* mainwindow, const Client* transient ); bool keepTransientAbove( const Client* mainwindow, const Client* transient );
void blockStackingUpdates( bool block ); void blockStackingUpdates( bool block );
void updateCurrentTopMenu(); void updateCurrentTopMenu();
@ -564,6 +569,7 @@ class RootInfo : public NETRootInfo2
virtual void closeWindow(Window w); virtual void closeWindow(Window w);
virtual void moveResize(Window w, int x_root, int y_root, unsigned long direction); virtual void moveResize(Window w, int x_root, int y_root, unsigned long direction);
virtual void gotPing(Window w, Time timestamp); virtual void gotPing(Window w, Time timestamp);
virtual void restackWindow(Window w, Window above, int detail);
private: private:
Workspace* workspace; Workspace* workspace;
}; };