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:
parent
ce37c50587
commit
90281645bf
5 changed files with 159 additions and 25 deletions
|
@ -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()
|
||||
|
|
9
client.h
9
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
|
||||
|
|
31
events.cpp
31
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
|
||||
|
|
98
layers.cpp
98
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() )
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue