Instead of snatching the window temporarily from kwin simply tell kwin

what to do with it. I've never liked this hack much, and this should
also take care of #49375, and should make sure kstart options will
have higher priority than settings configured in kwin.

svn path=/trunk/kdebase/kwin/; revision=319662
This commit is contained in:
Luboš Luňák 2004-06-11 15:10:09 +00:00
parent 33b11f1f07
commit 0f972d789f
6 changed files with 124 additions and 18 deletions

View file

@ -344,7 +344,7 @@ private slots:
QString readName() const;
void setCaption( const QString& s, bool force = false );
bool hasTransientInternal( const Client* c, bool indirect, ConstClientList& set ) const;
void setupWindowRules();
void setupWindowRules( bool ignore_temporary );
void updateWindowRules();
void finishWindowRules();

View file

@ -111,7 +111,7 @@ bool Client::manage( Window w, bool isMapped )
// and only then really set the caption using setCaption(), which checks for duplicates etc.
// and also relies on rules already existing
cap_normal = readName();
setupWindowRules();
setupWindowRules( false );
setCaption( cap_normal, true );
detectNoBorder();
@ -482,6 +482,9 @@ bool Client::manage( Window w, bool isMapped )
delete session;
ungrabXServer();
if( client_rules->discardTemporary( true ))
setupWindowRules( true );
return true;
}

119
rules.cpp
View file

@ -12,6 +12,9 @@ License. See the file "COPYING" for the exact licensing terms.
#include <kconfig.h>
#include <qregexp.h>
#include <ktempfile.h>
#include <ksimpleconfig.h>
#include <qfile.h>
#include "client.h"
#include "workspace.h"
@ -22,7 +25,8 @@ namespace KWinInternal
static WindowRules dummyRules; // dummy used to avoid NULL checks
WindowRules::WindowRules()
: wmclassregexp( false )
: temporary_state( 0 )
, wmclassregexp( false )
, wmclasscomplete( false )
, windowroleregexp( false )
, titleregexp( false )
@ -53,6 +57,22 @@ WindowRules::WindowRules()
{
}
WindowRules::WindowRules( const QString& str, bool temporary )
: temporary_state( temporary ? 2 : 0 )
{
KTempFile file;
QFile* f = file.file();
if( f != NULL )
{
QCString s = str.utf8();
f->writeBlock( s.data(), s.length());
}
file.close();
KSimpleConfig cfg( file.name());
readFromCfg( cfg );
file.unlink();
}
#define READ_MATCH_STRING( var, func ) \
var = cfg.readEntry( #var ) func; \
var##regexp = cfg.readBoolEntry( #var "regexp" );
@ -70,6 +90,12 @@ WindowRules::WindowRules()
var##rule = readForceRule( cfg, #var "rule" );
WindowRules::WindowRules( KConfig& cfg )
: temporary_state( 0 )
{
readFromCfg( cfg );
}
void WindowRules::readFromCfg( KConfig& cfg )
{
wmclass = cfg.readEntry( "wmclass" ).lower().latin1();
wmclassregexp = cfg.readBoolEntry( "wmclassregexp" );
@ -107,7 +133,7 @@ WindowRules::WindowRules( KConfig& cfg )
READ_FORCE_RULE( acceptfocus, Bool, );
READ_FORCE_RULE( moveresizemode, , Options::stringToMoveResizeMode );
READ_FORCE_RULE( closeable, Bool, );
kdDebug() << "READ RULE:" << wmclass << endl;
kdDebug() << "READ RULE:" << wmclass << "/" << title << endl;
}
#undef READ_MATCH_STRING
@ -212,29 +238,31 @@ bool WindowRules::match( const Client* c ) const
{
if( types != NET::AllTypesMask )
{
if( !NET::typeMatchesMask( c->windowType( true ), types )) // direct
NET::WindowType t = c->windowType( true ); // direct type
if( t == NET::Unknown )
t = NET::Normal; // NET::Unknown->NET::Normal is only here for matching
if( !NET::typeMatchesMask( t, types ))
return false;
}
// TODO exactMatch() for regexp?
if( !wmclass.isEmpty())
{ // TODO optimize?
QCString cwmclass = wmclasscomplete
? c->resourceName() + ' ' + c->resourceClass() : c->resourceClass();
if( wmclassregexp && !QRegExp( wmclass ).exactMatch( cwmclass ))
if( wmclassregexp && QRegExp( wmclass ).search( cwmclass ) == -1 )
return false;
if( !wmclassregexp && wmclass != cwmclass )
return false;
}
if( !windowrole.isEmpty())
{
if( windowroleregexp && !QRegExp( windowrole ).exactMatch( c->windowRole()))
if( windowroleregexp && QRegExp( windowrole ).search( c->windowRole()) == -1 )
return false;
if( !windowroleregexp && windowrole != c->windowRole())
return false;
}
if( !title.isEmpty())
{
if( titleregexp && !QRegExp( title ).exactMatch( c->caption( false )))
if( titleregexp && QRegExp( title ).search( c->caption( false )) == -1 )
return false;
if( !titleregexp && title != c->caption( false ))
return false;
@ -243,8 +271,8 @@ bool WindowRules::match( const Client* c ) const
if( !clientmachine.isEmpty())
{
if( clientmachineregexp
&& !QRegExp( clientmachine ).exactMatch( c->wmClientMachine( true ))
&& !QRegExp( clientmachine ).exactMatch( c->wmClientMachine( false )))
&& QRegExp( clientmachine ).search( c->wmClientMachine( true )) == -1
&& QRegExp( clientmachine ).search( c->wmClientMachine( false )) == -1 )
return false;
if( !clientmachineregexp
&& clientmachine != c->wmClientMachine( true )
@ -404,11 +432,29 @@ bool WindowRules::checkCloseable( bool closeable ) const
return checkForceRule( closeablerule ) ? this->closeable : closeable;
}
bool WindowRules::isTemporary() const
{
return temporary_state > 0;
}
bool WindowRules::discardTemporary( bool force )
{
if( temporary_state == 0 ) // not temporary
return false;
if( force || --temporary_state == 0 ) // too old
{
kdDebug() << "DISCARD:" << wmclass << "/" << title << endl;
delete this;
return true;
}
return false;
}
// Client
void Client::setupWindowRules()
void Client::setupWindowRules( bool ignore_temporary )
{
client_rules = workspace()->findWindowRules( this );
client_rules = workspace()->findWindowRules( this, ignore_temporary );
// check only after getting the rules, because there may be a rule forcing window type
if( isTopMenu()) // TODO cannot have restrictions
client_rules = &dummyRules;
@ -427,17 +473,22 @@ void Client::finishWindowRules()
// Workspace
WindowRules* Workspace::findWindowRules( const Client* c ) const
WindowRules* Workspace::findWindowRules( const Client* c, bool ignore_temporary )
{
for( QValueList< WindowRules* >::ConstIterator it = windowRules.begin();
it != windowRules.end();
++it )
{
// chaining for wildcard matches
if( ignore_temporary && (*it)->isTemporary())
continue;
// TODO chaining for wildcard matches
if( (*it)->match( c ))
{
kdDebug() << "RULE FOUND:" << c << endl;
return *it;
WindowRules* ret = *it;
if( ret->isTemporary())
windowRules.remove( *it );
return ret;
}
}
kdDebug() << "RULE DUMMY:" << c << endl;
@ -478,11 +529,49 @@ void Workspace::writeWindowRules()
int i = 1;
for( QValueList< WindowRules* >::ConstIterator it = windowRules.begin();
it != windowRules.end();
++it, ++i )
++it )
{
if( (*it)->isTemporary())
continue;
cfg.setGroup( QString::number( i ));
(*it)->write( cfg );
++i;
}
}
void Workspace::gotTemporaryRulesMessage( const QString& message )
{
bool was_temporary = false;
for( QValueList< WindowRules* >::ConstIterator it = windowRules.begin();
it != windowRules.end();
++it )
if( (*it)->isTemporary())
was_temporary = true;
WindowRules* rule = new WindowRules( message, true );
windowRules.prepend( rule ); // highest priority first
if( !was_temporary )
QTimer::singleShot( 60000, this, SLOT( cleanupTemporaryRules()));
}
void Workspace::cleanupTemporaryRules()
{
kdDebug() << "CLEANUP" << endl;
bool has_temporary = false;
for( QValueList< WindowRules* >::Iterator it = windowRules.begin();
it != windowRules.end();
)
{
if( (*it)->discardTemporary( false ))
it = windowRules.remove( it );
else
{
if( (*it)->isTemporary())
has_temporary = true;
++it;
}
}
if( has_temporary )
QTimer::singleShot( 60000, this, SLOT( cleanupTemporaryRules()));
}
} // namespace

View file

@ -42,8 +42,11 @@ class WindowRules
public:
WindowRules();
WindowRules( KConfig& );
WindowRules( const QString&, bool temporary );
void write( KConfig& ) const;
void update( Client* );
bool isTemporary() const;
bool discardTemporary( bool force ); // removes if temporary and forced or too old
bool match( const Client* c ) const;
Placement::Policy checkPlacement( Placement::Policy placement ) const;
QRect checkGeometry( const QRect& rect, bool init = false ) const;
@ -68,11 +71,13 @@ class WindowRules
Options::MoveResizeMode checkMoveResizeMode( Options::MoveResizeMode mode ) const;
bool checkCloseable( bool closeable ) const;
private:
void readFromCfg( KConfig& cfg );
static SettingRule readRule( KConfig&, const QString& key );
static SettingRule readForceRule( KConfig&, const QString& key );
static NET::WindowType readType( KConfig&, const QString& key );
static bool checkRule( SettingRule rule, bool init );
static bool checkForceRule( SettingRule rule );
int temporary_state; // e.g. for kstart
QCString wmclass;
bool wmclassregexp;
bool wmclasscomplete;

View file

@ -66,6 +66,7 @@ Workspace::Workspace( bool restore )
number_of_desktops(0),
popup_client (0),
desktop_widget (0),
temporaryRulesMessages( "_KDE_NET_WM_TEMPORARY_RULES", NULL, false ),
active_client (0),
last_active_client (0),
most_recently_raised (0),
@ -109,6 +110,9 @@ Workspace::Workspace( bool restore )
installed_colormap = default_colormap;
session.setAutoDelete( TRUE );
connect( &temporaryRulesMessages, SIGNAL( gotMessage( const QString& )),
this, SLOT( gotTemporaryRulesMessage( const QString& )));
updateXTime(); // needed for proper initialization of user_time in Client ctor
delayFocusTimer = 0;
@ -247,6 +251,7 @@ void Workspace::init()
NET::WM2RestackWindow |
NET::WM2MoveResizeWindow |
NET::WM2ExtendedStrut |
NET::WM2KDETemporaryRules |
0
,
NET::ActionMove |

View file

@ -16,6 +16,7 @@ License. See the file "COPYING" for the exact licensing terms.
#include <kshortcut.h>
#include <qcursor.h>
#include <netwm.h>
#include <kxmessages.h>
#include "KWinInterface.h"
#include "utils.h"
@ -202,7 +203,7 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine
void storeSession( KConfig* config, SMSavePhase phase );
SessionInfo* takeSessionInfo( Client* );
WindowRules* findWindowRules( const Client* ) const;
WindowRules* findWindowRules( const Client*, bool );
// dcop interface
void cascadeDesktop();
@ -330,6 +331,8 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine
void lostTopMenuSelection();
void lostTopMenuOwner();
void delayFocus();
void gotTemporaryRulesMessage( const QString& );
void cleanupTemporaryRules();
protected:
bool keyPressMouseEmulation( XKeyEvent& ev );
@ -431,6 +434,7 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine
QPtrList<SessionInfo> session;
QValueList<WindowRules*> windowRules;
KXMessages temporaryRulesMessages;
static const char* windowTypeToTxt( NET::WindowType type );
static NET::WindowType txtToWindowType( const char* txt );
static bool sessionInfoWindowTypeMatch( Client* c, SessionInfo* info );