2004-06-21 16:25:24 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2004 Lubos Lunak <l.lunak@kde.org>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
2005-07-10 13:44:16 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Steet, Fifth Floor, Cambridge, MA 02110-1301, USA.
|
2004-06-21 16:25:24 +00:00
|
|
|
*/
|
|
|
|
|
2004-07-29 17:08:25 +00:00
|
|
|
#include <kcmdlineargs.h>
|
2004-06-21 16:25:24 +00:00
|
|
|
#include <kapplication.h>
|
|
|
|
#include <dcopclient.h>
|
2004-07-29 17:08:25 +00:00
|
|
|
#include <kconfig.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kwin.h>
|
2004-06-21 16:25:24 +00:00
|
|
|
|
2004-07-29 17:08:25 +00:00
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <fixx11h.h>
|
2004-06-21 16:25:24 +00:00
|
|
|
|
2004-07-29 17:08:25 +00:00
|
|
|
#include "ruleswidget.h"
|
|
|
|
#include "../../rules.h"
|
2004-06-21 16:25:24 +00:00
|
|
|
|
|
|
|
namespace KWinInternal
|
|
|
|
{
|
|
|
|
|
2004-07-29 17:08:25 +00:00
|
|
|
static void loadRules( QValueList< Rules* >& rules )
|
2004-06-21 16:25:24 +00:00
|
|
|
{
|
2004-07-29 17:08:25 +00:00
|
|
|
KConfig cfg( "kwinrulesrc", true );
|
|
|
|
cfg.setGroup( "General" );
|
|
|
|
int count = cfg.readNumEntry( "count" );
|
|
|
|
for( int i = 1;
|
|
|
|
i <= count;
|
|
|
|
++i )
|
|
|
|
{
|
|
|
|
cfg.setGroup( QString::number( i ));
|
|
|
|
Rules* rule = new Rules( cfg );
|
|
|
|
rules.append( rule );
|
|
|
|
}
|
2004-06-21 16:25:24 +00:00
|
|
|
}
|
|
|
|
|
2004-07-29 17:08:25 +00:00
|
|
|
static void saveRules( const QValueList< Rules* >& rules )
|
2004-06-21 16:25:24 +00:00
|
|
|
{
|
2004-07-29 17:08:25 +00:00
|
|
|
KConfig cfg( "kwinrulesrc" );
|
|
|
|
cfg.setGroup( "General" );
|
|
|
|
cfg.writeEntry( "count", rules.count());
|
|
|
|
int i = 1;
|
|
|
|
for( QValueList< Rules* >::ConstIterator it = rules.begin();
|
|
|
|
it != rules.end();
|
|
|
|
++it )
|
|
|
|
{
|
|
|
|
cfg.setGroup( QString::number( i ));
|
|
|
|
(*it)->write( cfg );
|
|
|
|
++i;
|
|
|
|
}
|
2004-06-21 16:25:24 +00:00
|
|
|
}
|
|
|
|
|
2004-07-29 17:08:25 +00:00
|
|
|
static Rules* findRule( const QValueList< Rules* >& rules, Window wid )
|
2004-06-21 16:25:24 +00:00
|
|
|
{
|
2004-07-29 17:08:25 +00:00
|
|
|
KWin::WindowInfo info = KWin::windowInfo( wid,
|
|
|
|
NET::WMName | NET::WMWindowType,
|
|
|
|
NET::WM2WindowClass | NET::WM2WindowRole | NET::WM2ClientMachine );
|
|
|
|
if( !info.valid()) // shouldn't really happen
|
|
|
|
return NULL;
|
|
|
|
QCString wmclass_class = info.windowClassClass().lower();
|
|
|
|
QCString wmclass_name = info.windowClassName().lower();
|
|
|
|
QCString role = info.windowRole().lower();
|
|
|
|
NET::WindowType type = info.windowType( NET::NormalMask | NET::DesktopMask | NET::DockMask
|
|
|
|
| NET::ToolbarMask | NET::MenuMask | NET::DialogMask | NET::OverrideMask | NET::TopMenuMask
|
|
|
|
| NET::UtilityMask | NET::SplashMask );
|
2004-09-13 08:41:00 +00:00
|
|
|
QString title = info.name();
|
2004-07-29 17:08:25 +00:00
|
|
|
// QCString extrarole = ""; // TODO
|
|
|
|
QCString machine = info.clientMachine().lower();
|
|
|
|
Rules* best_match = NULL;
|
2004-11-05 15:29:50 +00:00
|
|
|
int match_quality = 0;
|
2004-07-29 17:08:25 +00:00
|
|
|
for( QValueList< Rules* >::ConstIterator it = rules.begin();
|
|
|
|
it != rules.end();
|
|
|
|
++it )
|
|
|
|
{
|
|
|
|
// try to find an exact match, i.e. not a generic rule
|
|
|
|
Rules* rule = *it;
|
|
|
|
int quality = 0;
|
|
|
|
bool generic = true;
|
|
|
|
if( rule->wmclassmatch != Rules::ExactMatch )
|
|
|
|
continue; // too generic
|
|
|
|
if( !rule->matchWMClass( wmclass_class, wmclass_name ))
|
|
|
|
continue;
|
|
|
|
// from now on, it matches the app - now try to match for a specific window
|
|
|
|
if( rule->wmclasscomplete )
|
|
|
|
{
|
|
|
|
quality += 1;
|
|
|
|
generic = false; // this can be considered specific enough (old X apps)
|
|
|
|
}
|
|
|
|
if( rule->windowrolematch != Rules::UnimportantMatch )
|
|
|
|
{
|
|
|
|
quality += rule->windowrolematch == Rules::ExactMatch ? 5 : 1;
|
|
|
|
generic = false;
|
|
|
|
}
|
|
|
|
if( rule->titlematch != Rules::UnimportantMatch )
|
|
|
|
{
|
|
|
|
quality += rule->titlematch == Rules::ExactMatch ? 3 : 1;
|
|
|
|
generic = false;
|
|
|
|
}
|
|
|
|
if( rule->types != NET::AllTypesMask )
|
|
|
|
{
|
|
|
|
int bits = 0;
|
|
|
|
for( int bit = 1;
|
|
|
|
bit < 1 << 31;
|
|
|
|
bit <<= 1 )
|
|
|
|
if( rule->types & bit )
|
|
|
|
++bits;
|
|
|
|
if( bits == 1 )
|
|
|
|
quality += 2;
|
|
|
|
}
|
2004-11-05 15:29:50 +00:00
|
|
|
if( generic ) // ignore generic rules, use only the ones that are for this window
|
2004-07-29 17:08:25 +00:00
|
|
|
continue;
|
|
|
|
if( !rule->matchType( type )
|
|
|
|
|| !rule->matchRole( role )
|
|
|
|
|| !rule->matchTitle( title )
|
|
|
|
|| !rule->matchClientMachine( machine ))
|
|
|
|
continue;
|
|
|
|
if( quality > match_quality )
|
|
|
|
{
|
|
|
|
best_match = rule;
|
|
|
|
match_quality = quality;
|
|
|
|
}
|
|
|
|
}
|
2004-11-05 15:29:50 +00:00
|
|
|
if( best_match != NULL )
|
|
|
|
return best_match;
|
|
|
|
Rules* ret = new Rules;
|
|
|
|
ret->description = i18n( "Settings for %1" ).arg( wmclass_class );
|
|
|
|
if( type == NET::Unknown )
|
|
|
|
ret->types = NET::NormalMask;
|
|
|
|
else
|
|
|
|
ret->types = 1 << type; // convert type to its mask
|
|
|
|
ret->title = title; // set, but make unimportant
|
|
|
|
ret->titlematch = Rules::UnimportantMatch;
|
2004-11-05 15:36:03 +00:00
|
|
|
ret->clientmachine = machine; // set, but make unimportant
|
2005-05-31 11:30:39 +00:00
|
|
|
ret->clientmachinematch = Rules::UnimportantMatch;
|
2004-11-05 15:29:50 +00:00
|
|
|
// ret->extrarole = extra; TODO
|
|
|
|
ret->extrarolematch = Rules::UnimportantMatch;
|
|
|
|
if( !role.isEmpty()
|
|
|
|
&& role != "unknown" && role != "unnamed" ) // Qt sets this if not specified
|
|
|
|
{
|
|
|
|
ret->windowrole = role;
|
|
|
|
ret->windowrolematch = Rules::ExactMatch;
|
2004-11-05 17:05:40 +00:00
|
|
|
if( wmclass_name == wmclass_class )
|
|
|
|
{
|
|
|
|
ret->wmclasscomplete = false;
|
|
|
|
ret->wmclass = wmclass_class;
|
|
|
|
ret->wmclassmatch = Rules::ExactMatch;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// WM_CLASS components differ - perhaps the app got -name argument
|
|
|
|
ret->wmclasscomplete = true;
|
|
|
|
ret->wmclass = wmclass_name + ' ' + wmclass_class;
|
|
|
|
ret->wmclassmatch = Rules::ExactMatch;
|
|
|
|
}
|
2004-11-05 15:29:50 +00:00
|
|
|
}
|
|
|
|
else // no role set
|
|
|
|
{
|
|
|
|
if( wmclass_name != wmclass_class )
|
|
|
|
{
|
|
|
|
ret->wmclasscomplete = true;
|
|
|
|
ret->wmclass = wmclass_name + ' ' + wmclass_class;
|
|
|
|
ret->wmclassmatch = Rules::ExactMatch;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// This is a window that has no role set, and both components of WM_CLASS
|
|
|
|
// match (possibly only differing in case), which most likely means either
|
|
|
|
// the application doesn't give a damn about distinguishing its various
|
|
|
|
// windows, or it's an app that uses role for that, but this window
|
|
|
|
// lacks it for some reason. Use non-complete WM_CLASS matching, also
|
|
|
|
// include window title in the matching, and pray it causes many more positive
|
|
|
|
// matches than negative matches.
|
|
|
|
ret->titlematch = Rules::ExactMatch;
|
|
|
|
ret->wmclasscomplete = false;
|
|
|
|
ret->wmclass = wmclass_class;
|
|
|
|
ret->wmclassmatch = Rules::ExactMatch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
2004-06-21 16:25:24 +00:00
|
|
|
}
|
|
|
|
|
2004-07-29 17:08:25 +00:00
|
|
|
static int edit( Window wid )
|
2004-06-21 16:25:24 +00:00
|
|
|
{
|
2004-07-29 17:08:25 +00:00
|
|
|
QValueList< Rules* > rules;
|
|
|
|
loadRules( rules );
|
2004-08-04 14:26:34 +00:00
|
|
|
Rules* orig_rule = findRule( rules, wid );
|
2004-07-29 17:08:25 +00:00
|
|
|
RulesDialog dlg;
|
2004-08-04 14:30:59 +00:00
|
|
|
// dlg.edit() creates new Rules instance if edited
|
2004-11-10 11:41:12 +00:00
|
|
|
Rules* edited_rule = dlg.edit( orig_rule, wid );
|
2004-11-05 15:29:50 +00:00
|
|
|
if( edited_rule == NULL || edited_rule->isEmpty())
|
2004-07-29 17:08:25 +00:00
|
|
|
{
|
2004-11-05 15:29:50 +00:00
|
|
|
rules.remove( orig_rule );
|
|
|
|
delete orig_rule;
|
|
|
|
if( orig_rule != edited_rule )
|
2004-08-04 14:26:34 +00:00
|
|
|
delete edited_rule;
|
|
|
|
}
|
2004-08-04 14:30:59 +00:00
|
|
|
else if( edited_rule != orig_rule )
|
2004-08-04 14:26:34 +00:00
|
|
|
{
|
|
|
|
QValueList< Rules* >::Iterator pos = rules.find( orig_rule );
|
|
|
|
if( pos != rules.end())
|
|
|
|
*pos = edited_rule;
|
|
|
|
else
|
|
|
|
rules.prepend( edited_rule );
|
|
|
|
delete orig_rule;
|
2004-07-29 17:08:25 +00:00
|
|
|
}
|
|
|
|
saveRules( rules );
|
|
|
|
if( !kapp->dcopClient()->isAttached())
|
|
|
|
kapp->dcopClient()->attach();
|
|
|
|
kapp->dcopClient()->send("kwin*", "", "reconfigure()", "");
|
|
|
|
return 0;
|
2004-06-21 16:25:24 +00:00
|
|
|
}
|
2004-07-29 17:08:25 +00:00
|
|
|
|
|
|
|
} // namespace
|
2004-06-21 16:25:24 +00:00
|
|
|
|
2004-07-29 17:08:25 +00:00
|
|
|
static const KCmdLineOptions options[] =
|
2004-06-21 16:25:24 +00:00
|
|
|
{
|
2004-07-29 17:08:25 +00:00
|
|
|
// no need for I18N_NOOP(), this is not supposed to be used directly
|
|
|
|
{ "wid <wid>", "WId of the window for special window settings.", 0 },
|
|
|
|
KCmdLineLastOption
|
|
|
|
};
|
2004-06-21 16:25:24 +00:00
|
|
|
|
2004-07-29 17:08:25 +00:00
|
|
|
extern "C"
|
2004-11-17 17:56:22 +00:00
|
|
|
KDE_EXPORT int kdemain( int argc, char* argv[] )
|
2004-06-21 16:25:24 +00:00
|
|
|
{
|
2004-07-29 17:08:25 +00:00
|
|
|
KLocale::setMainCatalogue( "kcmkwinrules" );
|
|
|
|
KCmdLineArgs::init( argc, argv, "kwin_rules_dialog", I18N_NOOP( "KWin" ),
|
|
|
|
I18N_NOOP( "KWin helper utility" ), "1.0" );
|
|
|
|
KCmdLineArgs::addCmdLineOptions( options );
|
|
|
|
KApplication app;
|
|
|
|
KCmdLineArgs* args = KCmdLineArgs::parsedArgs();
|
|
|
|
bool id_ok = false;
|
|
|
|
Window id = args->getOption( "wid" ).toULong( &id_ok );
|
|
|
|
args->clear();
|
|
|
|
if( !id_ok || id == None )
|
|
|
|
{
|
|
|
|
KCmdLineArgs::usage( i18n( "This helper utility is not supposed to be called directly." ));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return KWinInternal::edit( id );
|
2004-06-21 16:25:24 +00:00
|
|
|
}
|