From 90281645bfdf17cb9a4455bb2fb36561ff446205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lubo=C5=A1=20Lu=C5=88=C3=A1k?= Date: Tue, 30 Sep 2003 12:49:23 +0000 Subject: [PATCH] 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 --- activation.cpp | 40 +++++++++++++++++++++ client.h | 9 ++++- events.cpp | 31 ++++------------ layers.cpp | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++ workspace.h | 6 ++++ 5 files changed, 159 insertions(+), 25 deletions(-) diff --git a/activation.cpp b/activation.cpp index 069ed94675..aebb1fab2c 100644 --- a/activation.cpp +++ b/activation.cpp @@ -472,6 +472,46 @@ bool Workspace::allowClientActivation( const Client* c, Time time, bool focus_in 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 // wasn't allowed to activate void Workspace::restoreFocus() diff --git a/client.h b/client.h index 8938803719..94a6c989fe 100644 --- a/client.h +++ b/client.h @@ -228,7 +228,8 @@ class Client : public QObject, public KDecorationDefines const QPoint calculateGravitation( bool invert ) const; // FRAME public? 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 ); static QCString staticWindowRole(WId); @@ -240,6 +241,7 @@ class Client : public QObject, public KDecorationDefines void checkWorkspacePosition(); void updateUserTime( Time time = CurrentTime ); Time userTime() const; + bool hasUserTimeSupport() const; // does 'delete c;' 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 ); } +inline bool Client::hasUserTimeSupport() const + { + return info->userTime() != -1U; + } + #ifdef NDEBUG kndbgstream& operator<<( kndbgstream& stream, const Client* ); #else diff --git a/events.cpp b/events.cpp index 286e2e6fdd..5a992c2963 100644 --- a/events.cpp +++ b/events.cpp @@ -143,6 +143,11 @@ void RootInfo::gotPing( Window w, Time 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 @@ -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 ) { // first, get rid of a window border @@ -785,27 +787,8 @@ void Client::configureRequestEvent( XConfigureRequestEvent* e ) } } - - if ( stacking ) - { - 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; - } - } + if ( e->value_mask & CWStackMode ) + restackWindow( e->above, e->detail, NET::FromApplication ); // 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 diff --git a/layers.cpp b/layers.cpp index ec04074549..5047c0f4b2 100644 --- a/layers.cpp +++ b/layers.cpp @@ -261,6 +261,30 @@ void Workspace::lowerClient( Client* c ) 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 ) { if ( !c ) @@ -284,6 +308,54 @@ void Workspace::raiseClient( Client* 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 ) { if( !active_client || active_client == c ) @@ -485,6 +557,32 @@ bool Workspace::keepTransientAbove( const Client* mainwindow, const Client* tran // 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 ) { if ( b == keepAbove() ) diff --git a/workspace.h b/workspace.h index c81c2fb998..f7420914c2 100644 --- a/workspace.h +++ b/workspace.h @@ -168,6 +168,8 @@ class Workspace : public QObject, virtual public KWinInterface, public KDecorati QPoint adjustClientPosition( Client* c, QPoint pos ); void raiseClient( Client* c ); void lowerClient( Client* c ); + void raiseClientRequest( Client* c ); + void lowerClientRequest( Client* c ); void restackClientUnderActive( Client* ); void updateClientLayer( Client* c ); void raiseOrLowerClient( Client * ); @@ -370,6 +372,9 @@ class Workspace : public QObject, virtual public KWinInterface, public KDecorati void updateStackingOrder( bool propagate_new_clients = false ); void propagateClients( bool propagate_new_clients ); // called only from updateStackingOrder ClientList constrainedStackingOrder(); + void raiseClientWithinApplication( Client* c ); + void lowerClientWithinApplication( Client* c ); + bool allowFullClientRaising( const Client* c ); bool keepTransientAbove( const Client* mainwindow, const Client* transient ); void blockStackingUpdates( bool block ); void updateCurrentTopMenu(); @@ -564,6 +569,7 @@ class RootInfo : public NETRootInfo2 virtual void closeWindow(Window w); virtual void moveResize(Window w, int x_root, int y_root, unsigned long direction); virtual void gotPing(Window w, Time timestamp); + virtual void restackWindow(Window w, Window above, int detail); private: Workspace* workspace; };