kwin Library API Documentation

kcmkwin/kwinrules/main.cpp

00001 /*
00002  * Copyright (c) 2004 Lubos Lunak <l.lunak@kde.org>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017  */
00018 
00019 #include <kcmdlineargs.h>
00020 #include <kapplication.h>
00021 #include <dcopclient.h>
00022 #include <kconfig.h>
00023 #include <klocale.h>
00024 #include <kwin.h>
00025 
00026 #include <X11/Xlib.h>
00027 #include <fixx11h.h>
00028 
00029 #include "ruleswidget.h"
00030 #include "../../rules.h"
00031 
00032 namespace KWinInternal
00033 {
00034 
00035 static void loadRules( QValueList< Rules* >& rules )
00036     {
00037     KConfig cfg( "kwinrulesrc", true );
00038     cfg.setGroup( "General" );
00039     int count = cfg.readNumEntry( "count" );
00040     for( int i = 1;
00041          i <= count;
00042          ++i )
00043         {
00044         cfg.setGroup( QString::number( i ));
00045         Rules* rule = new Rules( cfg );
00046         rules.append( rule );
00047         }
00048     }
00049 
00050 static void saveRules( const QValueList< Rules* >& rules )
00051     {
00052     KConfig cfg( "kwinrulesrc" );
00053     cfg.setGroup( "General" );
00054     cfg.writeEntry( "count", rules.count());
00055     int i = 1;
00056     for( QValueList< Rules* >::ConstIterator it = rules.begin();
00057          it != rules.end();
00058          ++it )
00059         {
00060         cfg.setGroup( QString::number( i ));
00061         (*it)->write( cfg );
00062         ++i;
00063         }
00064     }
00065 
00066 static Rules* findRule( const QValueList< Rules* >& rules, Window wid )
00067     {
00068     KWin::WindowInfo info = KWin::windowInfo( wid,
00069         NET::WMName | NET::WMWindowType,
00070         NET::WM2WindowClass | NET::WM2WindowRole | NET::WM2ClientMachine );
00071     if( !info.valid()) // shouldn't really happen
00072         return NULL;
00073     QCString wmclass_class = info.windowClassClass().lower();
00074     QCString wmclass_name = info.windowClassName().lower();
00075     QCString role = info.windowRole().lower();
00076     NET::WindowType type = info.windowType( NET::NormalMask | NET::DesktopMask | NET::DockMask
00077         | NET::ToolbarMask | NET::MenuMask | NET::DialogMask | NET::OverrideMask | NET::TopMenuMask
00078         | NET::UtilityMask | NET::SplashMask );
00079     QString title = info.name();
00080 //    QCString extrarole = ""; // TODO
00081     QCString machine = info.clientMachine().lower();
00082     Rules* best_match = NULL;
00083     int match_quality = 0;
00084     for( QValueList< Rules* >::ConstIterator it = rules.begin();
00085          it != rules.end();
00086          ++it )
00087         {
00088         // try to find an exact match, i.e. not a generic rule
00089         Rules* rule = *it;
00090         int quality = 0;
00091         bool generic = true;
00092         if( rule->wmclassmatch != Rules::ExactMatch )
00093             continue; // too generic
00094         if( !rule->matchWMClass( wmclass_class, wmclass_name ))
00095             continue;
00096         // from now on, it matches the app - now try to match for a specific window
00097         if( rule->wmclasscomplete )
00098             {
00099             quality += 1;
00100             generic = false;  // this can be considered specific enough (old X apps)
00101             }
00102         if( rule->windowrolematch != Rules::UnimportantMatch )
00103             {
00104             quality += rule->windowrolematch == Rules::ExactMatch ? 5 : 1;
00105             generic = false;
00106             }
00107         if( rule->titlematch != Rules::UnimportantMatch )
00108             {
00109             quality += rule->titlematch == Rules::ExactMatch ? 3 : 1;
00110             generic = false;
00111             }
00112         if( rule->types != NET::AllTypesMask )
00113             {
00114             int bits = 0;
00115             for( int bit = 1;
00116                  bit < 1 << 31;
00117                  bit <<= 1 )
00118                 if( rule->types & bit )
00119                     ++bits;
00120             if( bits == 1 )
00121                 quality += 2;
00122             }
00123         if( generic ) // ignore generic rules, use only the ones that are for this window
00124             continue;
00125         if( !rule->matchType( type )
00126             || !rule->matchRole( role )
00127             || !rule->matchTitle( title )
00128             || !rule->matchClientMachine( machine ))
00129             continue;
00130         if( quality > match_quality )
00131             {
00132             best_match = rule;
00133             match_quality = quality;
00134             }
00135         }
00136     if( best_match != NULL )
00137         return best_match;
00138     Rules* ret = new Rules;
00139     ret->description = i18n( "Settings for %1" ).arg( wmclass_class );
00140     if( type == NET::Unknown )
00141         ret->types = NET::NormalMask;
00142     else
00143         ret->types = 1 << type; // convert type to its mask
00144     ret->title = title; // set, but make unimportant
00145     ret->titlematch = Rules::UnimportantMatch;
00146     ret->clientmachine = machine; // set, but make unimportant
00147     ret->clientmachine = Rules::UnimportantMatch;
00148 //    ret->extrarole = extra; TODO
00149     ret->extrarolematch = Rules::UnimportantMatch;
00150     if( !role.isEmpty()
00151         && role != "unknown" && role != "unnamed" ) // Qt sets this if not specified
00152         {
00153         ret->windowrole = role;
00154         ret->windowrolematch = Rules::ExactMatch;
00155         if( wmclass_name == wmclass_class )
00156             {
00157             ret->wmclasscomplete = false;
00158             ret->wmclass = wmclass_class;
00159             ret->wmclassmatch = Rules::ExactMatch;
00160             }
00161         else
00162             {
00163             // WM_CLASS components differ - perhaps the app got -name argument
00164             ret->wmclasscomplete = true;
00165             ret->wmclass = wmclass_name + ' ' + wmclass_class;
00166             ret->wmclassmatch = Rules::ExactMatch;
00167             }
00168         }
00169     else // no role set
00170         {
00171         if( wmclass_name != wmclass_class )
00172             {
00173             ret->wmclasscomplete = true;
00174             ret->wmclass = wmclass_name + ' ' + wmclass_class;
00175             ret->wmclassmatch = Rules::ExactMatch;
00176             }
00177         else
00178             {
00179             // This is a window that has no role set, and both components of WM_CLASS
00180             // match (possibly only differing in case), which most likely means either
00181             // the application doesn't give a damn about distinguishing its various
00182             // windows, or it's an app that uses role for that, but this window
00183             // lacks it for some reason. Use non-complete WM_CLASS matching, also
00184             // include window title in the matching, and pray it causes many more positive
00185             // matches than negative matches.
00186             ret->titlematch = Rules::ExactMatch;
00187             ret->wmclasscomplete = false;
00188             ret->wmclass = wmclass_class;
00189             ret->wmclassmatch = Rules::ExactMatch;
00190             }
00191         }
00192     return ret;
00193     }
00194 
00195 static int edit( Window wid )
00196     {
00197     QValueList< Rules* > rules;
00198     loadRules( rules );
00199     Rules* orig_rule = findRule( rules, wid );
00200     RulesDialog dlg;
00201     // dlg.edit() creates new Rules instance if edited
00202     Rules* edited_rule = dlg.edit( orig_rule, wid );
00203     if( edited_rule == NULL || edited_rule->isEmpty())
00204         {
00205         rules.remove( orig_rule );
00206         delete orig_rule;
00207         if( orig_rule != edited_rule )
00208             delete edited_rule;
00209         }
00210     else if( edited_rule != orig_rule )
00211         {
00212         QValueList< Rules* >::Iterator pos = rules.find( orig_rule );
00213         if( pos != rules.end())
00214             *pos = edited_rule;
00215         else
00216             rules.prepend( edited_rule );
00217         delete orig_rule;
00218         }
00219     saveRules( rules );
00220     if( !kapp->dcopClient()->isAttached())
00221         kapp->dcopClient()->attach();
00222     kapp->dcopClient()->send("kwin*", "", "reconfigure()", "");
00223     return 0;
00224     }
00225     
00226 } // namespace
00227 
00228 static const KCmdLineOptions options[] =
00229     {
00230     // no need for I18N_NOOP(), this is not supposed to be used directly
00231         { "wid <wid>", "WId of the window for special window settings.", 0 },
00232         KCmdLineLastOption
00233     };
00234 
00235 extern "C"
00236 KDE_EXPORT int kdemain( int argc, char* argv[] )
00237     {
00238     KLocale::setMainCatalogue( "kcmkwinrules" );
00239     KCmdLineArgs::init( argc, argv, "kwin_rules_dialog", I18N_NOOP( "KWin" ),
00240     I18N_NOOP( "KWin helper utility" ), "1.0" );
00241     KCmdLineArgs::addCmdLineOptions( options );
00242     KApplication app;
00243     KCmdLineArgs* args = KCmdLineArgs::parsedArgs();
00244     bool id_ok = false;
00245     Window id = args->getOption( "wid" ).toULong( &id_ok );
00246     args->clear();
00247     if( !id_ok || id == None )
00248         {
00249     KCmdLineArgs::usage( i18n( "This helper utility is not supposed to be called directly." ));
00250     return 1;
00251         }
00252     return KWinInternal::edit( id );
00253     }
KDE Logo
This file is part of the documentation for kwin Library Version 3.3.90.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Apr 5 03:59:39 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003