I guess I could finally find some time to work on things for 3.3.

Initial work on kwin rules, i.e. #36377 , per window specific settings.
So far only desktop/above/below work, no GUI, and settings from the old
'Save window settings' are ignored for now.

svn path=/trunk/kdebase/kwin/; revision=315446
icc-effect-5.14.5
Luboš Luňák 2004-05-28 13:51:11 +00:00
parent 76ed413d94
commit 8e09a9bc22
15 changed files with 409 additions and 198 deletions

View File

@ -11,7 +11,7 @@ kwin_la_SOURCES = workspace.cpp client.cpp placement.cpp atoms.cpp \
options.cpp plugins.cpp events.cpp KWinInterface.skel \ options.cpp plugins.cpp events.cpp KWinInterface.skel \
killwindow.cpp geometrytip.cpp sm.cpp group.cpp bridge.cpp \ killwindow.cpp geometrytip.cpp sm.cpp group.cpp bridge.cpp \
manage.cpp notifications.cpp activation.cpp useractions.cpp \ manage.cpp notifications.cpp activation.cpp useractions.cpp \
geometry.cpp geometry.cpp rules.cpp
kwin_la_LIBADD = $(LIB_KDEUI) lib/libkdecorations.la kwin_la_LIBADD = $(LIB_KDEUI) lib/libkdecorations.la
kwin_la_LDFLAGS = $(all_libraries) -module -avoid-version kwin_la_LDFLAGS = $(all_libraries) -module -avoid-version

View File

@ -320,7 +320,11 @@ void Workspace::takeActivity( Client* c, int flags, bool handled )
if( modal != NULL && modal != c ) if( modal != NULL && modal != c )
{ {
if( !modal->isOnDesktop( c->desktop())) if( !modal->isOnDesktop( c->desktop()))
{
modal->setDesktop( c->desktop()); modal->setDesktop( c->desktop());
if( modal->desktop() != c->desktop()) // forced desktop
activateClient( modal );
}
// if the click was inside the window (i.e. handled is set), // if the click was inside the window (i.e. handled is set),
// but it has a modal, there's no need to use handled mode, because // but it has a modal, there's no need to use handled mode, because
// the modal doesn't get the click anyway // the modal doesn't get the click anyway
@ -663,7 +667,7 @@ KWIN_COMPARE_PREDICATE( SameApplicationActiveHackPredicate, const Client*,
&& Client::belongToSameApplication( cl, value, true ) && cl != value); && Client::belongToSameApplication( cl, value, true ) && cl != value);
Time Client::readUserTimeMapTimestamp( const KStartupInfoId* asn_id, const KStartupInfoData* asn_data, Time Client::readUserTimeMapTimestamp( const KStartupInfoId* asn_id, const KStartupInfoData* asn_data,
const SessionInfo* session ) const bool session ) const
{ {
Time time = info->userTime(); Time time = info->userTime();
kdDebug( 1212 ) << "User timestamp, initial:" << time << endl; kdDebug( 1212 ) << "User timestamp, initial:" << time << endl;
@ -727,7 +731,7 @@ Time Client::readUserTimeMapTimestamp( const KStartupInfoId* asn_id, const KStar
// Unless it was the active window at the time // Unless it was the active window at the time
// of session saving and there was no user interaction yet, // of session saving and there was no user interaction yet,
// this check will be done in Workspace::allowClientActiovationTimestamp(). // this check will be done in Workspace::allowClientActiovationTimestamp().
if( session && !session->fake ) if( session )
return -1U; return -1U;
if( ignoreFocusStealing() && act != NULL ) if( ignoreFocusStealing() && act != NULL )
time = act->userTime(); time = act->userTime();

View File

@ -27,6 +27,7 @@ License. See the file "COPYING" for the exact licensing terms.
#include "workspace.h" #include "workspace.h"
#include "atoms.h" #include "atoms.h"
#include "notifications.h" #include "notifications.h"
#include "rules.h"
#include <X11/extensions/shape.h> #include <X11/extensions/shape.h>
@ -78,6 +79,7 @@ Client::Client( Workspace *ws )
transient_for( NULL ), transient_for( NULL ),
transient_for_id( None ), transient_for_id( None ),
original_transient_for_id( None ), original_transient_for_id( None ),
client_rules( NULL ),
in_group( NULL ), in_group( NULL ),
window_group( None ), window_group( None ),
in_layer( UnknownLayer ), in_layer( UnknownLayer ),
@ -133,10 +135,8 @@ Client::Client( Workspace *ws )
Pcontexthelp = 0; Pcontexthelp = 0;
Pping = 0; Pping = 0;
input = FALSE; input = FALSE;
store_settings = FALSE;
skip_pager = FALSE; skip_pager = FALSE;
max_mode = MaximizeRestore; max_mode = MaximizeRestore;
cmap = None; cmap = None;
@ -175,6 +175,7 @@ void Client::releaseWindow( bool on_shutdown )
{ {
if (moveResizeMode) if (moveResizeMode)
leaveMoveResize(); leaveMoveResize();
updateWindowRules();
setModal( false ); // otherwise its mainwindow wouldn't get focus setModal( false ); // otherwise its mainwindow wouldn't get focus
hidden = true; // so that it's not considered visible anymore (can't use hideClient(), it would set flags) hidden = true; // so that it's not considered visible anymore (can't use hideClient(), it would set flags)
if( !on_shutdown ) if( !on_shutdown )
@ -222,6 +223,7 @@ void Client::destroyClient()
{ {
if (moveResizeMode) if (moveResizeMode)
leaveMoveResize(); leaveMoveResize();
updateWindowRules();
++block_geometry; ++block_geometry;
setModal( false ); setModal( false );
hidden = true; // so that it's not considered visible anymore hidden = true; // so that it's not considered visible anymore
@ -1077,15 +1079,11 @@ void Client::setModal( bool m )
// _NET_WM_STATE_MODAL should possibly rather be _NET_WM_WINDOW_TYPE_MODAL_DIALOG // _NET_WM_STATE_MODAL should possibly rather be _NET_WM_WINDOW_TYPE_MODAL_DIALOG
} }
void Client::toggleOnAllDesktops()
{
setOnAllDesktops( !isOnAllDesktops());
}
void Client::setDesktop( int desktop ) void Client::setDesktop( int desktop )
{ {
if( desktop != NET::OnAllDesktops ) // do range check if( desktop != NET::OnAllDesktops ) // do range check
desktop = KMAX( 1, KMIN( workspace()->numberOfDesktops(), desktop )); desktop = KMAX( 1, KMIN( workspace()->numberOfDesktops(), desktop ));
desktop = rules()->checkDesktop( desktop );
if( desk == desktop ) if( desk == desktop )
return; return;
int was_desk = desk; int was_desk = desk;
@ -1264,9 +1262,9 @@ void Client::fetchIconicName()
/*!\reimp /*!\reimp
*/ */
QString Client::caption() const QString Client::caption( bool full ) const
{ {
return cap_normal + cap_suffix; return full ? cap_normal + cap_suffix : cap_normal;
} }
void Client::getWMHints() void Client::getWMHints()

View File

@ -39,6 +39,7 @@ class Client;
class WinInfo; class WinInfo;
class SessionInfo; class SessionInfo;
class Bridge; class Bridge;
class WindowRules;
class Client : public QObject, public KDecorationDefines class Client : public QObject, public KDecorationDefines
{ {
@ -66,6 +67,7 @@ class Client : public QObject, public KDecorationDefines
void checkGroup( Group* gr = NULL, bool force = false ); void checkGroup( Group* gr = NULL, bool force = false );
// prefer isXXX() instead // prefer isXXX() instead
NET::WindowType windowType( bool strict = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const; NET::WindowType windowType( bool strict = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const;
const WindowRules* rules() const;
QRect geometry() const; QRect geometry() const;
QSize size() const; QSize size() const;
@ -160,9 +162,6 @@ class Client : public QObject, public KDecorationDefines
void setModal( bool modal ); void setModal( bool modal );
bool isModal() const; bool isModal() const;
bool storeSettings() const;
void setStoreSettings( bool );
// auxiliary functions, depend on the windowType // auxiliary functions, depend on the windowType
bool wantsTabFocus() const; bool wantsTabFocus() const;
bool wantsInput() const; bool wantsInput() const;
@ -237,7 +236,7 @@ class Client : public QObject, public KDecorationDefines
// updates visibility depending on whether it's on the current desktop // updates visibility depending on whether it's on the current desktop
void virtualDesktopChange(); void virtualDesktopChange();
QString caption() const; QString caption( bool full = true ) const;
void keyPressEvent( uint key_code ); // FRAME ?? void keyPressEvent( uint key_code ); // FRAME ??
void updateMouseGrab(); void updateMouseGrab();
@ -275,7 +274,6 @@ class Client : public QObject, public KDecorationDefines
void closeWindow(); void closeWindow();
void killWindow(); void killWindow();
void maximize( MaximizeMode ); void maximize( MaximizeMode );
void toggleOnAllDesktops();
void toggleShade(); void toggleShade();
void showContextHelp(); void showContextHelp();
void cancelAutoRaise(); void cancelAutoRaise();
@ -343,6 +341,8 @@ private slots:
void fetchName(); void fetchName();
void fetchIconicName(); void fetchIconicName();
bool hasTransientInternal( const Client* c, bool indirect, ConstClientList& set ) const; bool hasTransientInternal( const Client* c, bool indirect, ConstClientList& set ) const;
void initWindowRules();
void updateWindowRules();
void updateWorkareaDiffs(); void updateWorkareaDiffs();
void checkDirection( int new_diff, int old_diff, QRect& rect, const QRect& area ); void checkDirection( int new_diff, int old_diff, QRect& rect, const QRect& area );
@ -380,7 +380,7 @@ private slots:
void rawHide(); // just hides it void rawHide(); // just hides it
Time readUserTimeMapTimestamp( const KStartupInfoId* asn_id, const KStartupInfoData* asn_data, Time readUserTimeMapTimestamp( const KStartupInfoId* asn_id, const KStartupInfoData* asn_data,
const SessionInfo* session ) const; bool session ) const;
Time readUserCreationTime() const; Time readUserCreationTime() const;
static bool sameAppWindowRoleMatch( const Client* c1, const Client* c2, bool active_hack ); static bool sameAppWindowRoleMatch( const Client* c1, const Client* c2, bool active_hack );
void startupIdChanged(); void startupIdChanged();
@ -438,7 +438,6 @@ private slots:
uint Pcontexthelp : 1; // does the window understand the ContextHelp protocol? uint Pcontexthelp : 1; // does the window understand the ContextHelp protocol?
uint Pping : 1; // does it support _NET_WM_PING? uint Pping : 1; // does it support _NET_WM_PING?
uint input :1; // does the window want input in its wm_hints uint input :1; // does the window want input in its wm_hints
uint store_settings : 1;
uint skip_pager : 1; uint skip_pager : 1;
uint motif_may_resize : 1; uint motif_may_resize : 1;
uint motif_may_move :1; uint motif_may_move :1;
@ -453,6 +452,7 @@ private slots:
uint urgency : 1; // XWMHints, UrgencyHint uint urgency : 1; // XWMHints, UrgencyHint
uint ignore_focus_stealing : 1; // don't apply focus stealing prevention to this client uint ignore_focus_stealing : 1; // don't apply focus stealing prevention to this client
uint check_active_modal : 1; // see Client::addTransient() uint check_active_modal : 1; // see Client::addTransient()
WindowRules* client_rules;
void getWMHints(); void getWMHints();
void readIcons(); void readIcons();
void getWindowProtocols(); void getWindowProtocols();
@ -685,17 +685,6 @@ inline bool Client::keepBelow() const
return keep_below; return keep_below;
} }
inline bool Client::storeSettings() const
{
return store_settings;
}
inline void Client::setStoreSettings( bool b )
{
store_settings = b;
}
inline bool Client::shape() const inline bool Client::shape() const
{ {
return is_shape; return is_shape;
@ -837,6 +826,11 @@ inline bool Client::ignoreFocusStealing() const
return ignore_focus_stealing; return ignore_focus_stealing;
} }
inline const WindowRules* Client::rules() const
{
return client_rules;
}
KWIN_PROCEDURE( CheckIgnoreFocusStealingProcedure, cl->ignore_focus_stealing = options->checkIgnoreFocusStealing( cl )); KWIN_PROCEDURE( CheckIgnoreFocusStealingProcedure, cl->ignore_focus_stealing = options->checkIgnoreFocusStealing( cl ));
inline Window Client::moveResizeGrabWindow() const inline Window Client::moveResizeGrabWindow() const

View File

@ -20,6 +20,7 @@ License. See the file "COPYING" for the exact licensing terms.
#include "atoms.h" #include "atoms.h"
#include "tabbox.h" #include "tabbox.h"
#include "group.h" #include "group.h"
#include "rules.h"
#include <qwhatsthis.h> #include <qwhatsthis.h>
#include <kkeynative.h> #include <kkeynative.h>

View File

@ -64,13 +64,15 @@ License. See the file "COPYING" for the exact licensing terms.
#include <assert.h> #include <assert.h>
#include <kdebug.h>
#include "utils.h" #include "utils.h"
#include "client.h" #include "client.h"
#include "workspace.h" #include "workspace.h"
#include "tabbox.h" #include "tabbox.h"
#include "popupinfo.h" #include "popupinfo.h"
#include "group.h" #include "group.h"
#include <kdebug.h> #include "rules.h"
extern Time qt_x_time; extern Time qt_x_time;
@ -642,22 +644,36 @@ void Client::restackWindow( Window /*above TODO */, int detail, NET::RequestSour
void Client::setKeepAbove( bool b ) void Client::setKeepAbove( bool b )
{ {
if ( b == keepAbove() ) b = rules()->checkKeepAbove( b );
if( b )
setKeepBelow( false );
if ( b == keepAbove()
|| ( b && keepBelow())) // forced below
{ // force hint change if different
if( bool( info->state() & NET::KeepAbove ) != keepAbove())
info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
return; return;
setKeepBelow( false ); }
keep_above = b; keep_above = b;
info->setState( b ? NET::KeepAbove : 0, NET::KeepAbove ); info->setState( keepAbove() ? NET::KeepAbove : 0, NET::KeepAbove );
// TODO emit a signal about the change to the style plugin // TODO emit a signal about the change to the style plugin
workspace()->updateClientLayer( this ); workspace()->updateClientLayer( this );
} }
void Client::setKeepBelow( bool b ) void Client::setKeepBelow( bool b )
{ {
if ( b == keepBelow() ) b = rules()->checkKeepBelow( b );
if( b )
setKeepAbove( false );
if ( b == keepBelow()
|| ( b && keepAbove())) // forced above
{ // force hint change if different
if( bool( info->state() & NET::KeepBelow ) != keepBelow())
info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
return; return;
setKeepAbove( false ); }
keep_below = b; keep_below = b;
info->setState( b ? NET::KeepBelow : 0, NET::KeepBelow ); info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
workspace()->updateClientLayer( this ); workspace()->updateClientLayer( this );
} }

View File

@ -86,7 +86,8 @@ public:
KeepAboveOp, KeepAboveOp,
KeepBelowOp, KeepBelowOp,
OperationsOp, OperationsOp,
ToggleStoreSettingsOp, WindowRulesOp,
ToggleStoreSettingsOp = WindowRulesOp, ///< @obsolete
HMaximizeOp, HMaximizeOp,
VMaximizeOp, VMaximizeOp,
LowerOp, LowerOp,

View File

@ -22,6 +22,7 @@ License. See the file "COPYING" for the exact licensing terms.
#include <X11/extensions/shape.h> #include <X11/extensions/shape.h>
#include "notifications.h" #include "notifications.h"
#include "rules.h"
extern Time qt_x_time; extern Time qt_x_time;
extern Atom qt_window_role; extern Atom qt_window_role;
@ -105,8 +106,11 @@ bool Client::manage( Window w, bool isMapped )
} }
ignore_focus_stealing = options->checkIgnoreFocusStealing( this ); ignore_focus_stealing = options->checkIgnoreFocusStealing( this );
detectNoBorder();
fetchName(); fetchName();
window_role = getStringProperty( w, qt_window_role );
initWindowRules();
detectNoBorder();
fetchIconicName(); fetchIconicName();
getWMHints(); // needs to be done before readTransient() because of reading the group getWMHints(); // needs to be done before readTransient() because of reading the group
getWmClientLeader(); // needs to be done before readTransient() because of same app comparing getWmClientLeader(); // needs to be done before readTransient() because of same app comparing
@ -114,7 +118,6 @@ bool Client::manage( Window w, bool isMapped )
getIcons(); getIcons();
getWindowProtocols(); getWindowProtocols();
getWmNormalHints(); // get xSizeHint getWmNormalHints(); // get xSizeHint
window_role = getStringProperty( w, qt_window_role );
// TODO try to obey all state information from info->state() // TODO try to obey all state information from info->state()
@ -122,13 +125,6 @@ bool Client::manage( Window w, bool isMapped )
skip_pager = ( info->state() & NET::SkipPager) != 0; skip_pager = ( info->state() & NET::SkipPager) != 0;
modal = ( info->state() & NET::Modal ) != 0; modal = ( info->state() & NET::Modal ) != 0;
// window wants to stay on top?
keep_above = ( info->state() & NET::KeepAbove ) != 0;
// window wants to stay on bottom?
keep_below = ( info->state() & NET::KeepBelow ) != 0;
if( keep_above && keep_below )
keep_above = keep_below = false;
KStartupInfoId asn_id; KStartupInfoId asn_id;
KStartupInfoData asn_data; KStartupInfoData asn_data;
bool asn_valid = workspace()->checkStartupNotification( window(), asn_id, asn_data ); bool asn_valid = workspace()->checkStartupNotification( window(), asn_id, asn_data );
@ -136,6 +132,7 @@ bool Client::manage( Window w, bool isMapped )
workspace()->updateClientLayer( this ); workspace()->updateClientLayer( this );
SessionInfo* session = workspace()->takeSessionInfo( this ); SessionInfo* session = workspace()->takeSessionInfo( this );
if ( session ) if ( session )
{ {
if ( session->minimized ) if ( session->minimized )
@ -186,6 +183,7 @@ bool Client::manage( Window w, bool isMapped )
desk = workspace()->currentDesktop(); desk = workspace()->currentDesktop();
if( desk != NET::OnAllDesktops ) // do range check if( desk != NET::OnAllDesktops ) // do range check
desk = KMAX( 1, KMIN( workspace()->numberOfDesktops(), desk )); desk = KMAX( 1, KMIN( workspace()->numberOfDesktops(), desk ));
desk = rules()->checkDesktop( desk, !isMapped );
info->setDesktop( desk ); info->setDesktop( desk );
workspace()->updateOnAllDesktopsOfTransients( this ); // SELI workspace()->updateOnAllDesktopsOfTransients( this ); // SELI
// onAllDesktopsChange(); decoration doesn't exist here yet // onAllDesktopsChange(); decoration doesn't exist here yet
@ -308,6 +306,8 @@ bool Client::manage( Window w, bool isMapped )
// other settings from the previous session // other settings from the previous session
if ( session ) if ( session )
{ {
// session restored windows are not considered to be new windows WRT rules,
// i.e. obey only forcing rules
setKeepAbove( session->keepAbove ); setKeepAbove( session->keepAbove );
setKeepBelow( session->keepBelow ); setKeepBelow( session->keepBelow );
setSkipTaskbar( session->skipTaskbar, true ); setSkipTaskbar( session->skipTaskbar, true );
@ -368,10 +368,8 @@ bool Client::manage( Window w, bool isMapped )
// read other initial states // read other initial states
if( info->state() & NET::Shaded ) if( info->state() & NET::Shaded )
setShade( ShadeNormal ); setShade( ShadeNormal );
if( info->state() & NET::KeepAbove ) setKeepAbove( rules()->checkKeepAbove( info->state() & NET::KeepAbove, !isMapped ));
setKeepAbove( true ); setKeepBelow( rules()->checkKeepBelow( info->state() & NET::KeepBelow, !isMapped ));
if( info->state() & NET::KeepBelow )
setKeepBelow( true );
if( info->state() & NET::SkipTaskbar ) if( info->state() & NET::SkipTaskbar )
setSkipTaskbar( true, true ); setSkipTaskbar( true, true );
if( info->state() & NET::SkipPager ) if( info->state() & NET::SkipPager )
@ -433,7 +431,7 @@ bool Client::manage( Window w, bool isMapped )
{ {
workspace()->restackClientUnderActive( this ); workspace()->restackClientUnderActive( this );
rawShow(); rawShow();
if( ( !session || session->fake ) && ( !isSpecialWindow() || isOverride())) if( !session && ( !isSpecialWindow() || isOverride()))
demandAttention(); demandAttention();
} }
} }
@ -442,7 +440,7 @@ bool Client::manage( Window w, bool isMapped )
{ {
virtualDesktopChange(); virtualDesktopChange();
workspace()->raiseClient( this ); workspace()->raiseClient( this );
if( ( !session || session->fake ) && !isMapped ) if( !session && !isMapped )
demandAttention(); demandAttention();
} }
} }

238
rules.cpp Normal file
View File

@ -0,0 +1,238 @@
/*****************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2004 Lubos Lunak <l.lunak@kde.org>
You can Freely distribute this program under the GNU General Public
License. See the file "COPYING" for the exact licensing terms.
******************************************************************/
#include "rules.h"
#include <kconfig.h>
#include <qregexp.h>
#include "client.h"
#include "workspace.h"
namespace KWinInternal
{
static WindowRules dummyRules; // dummy used to avoid NULL checks
WindowRules::WindowRules()
: wmclassregexp( false )
, windowroleregexp( false )
, titleregexp( false )
, extraroleregexp( false )
, desktoprule( DontCareRule )
, aboverule( DontCareRule )
, belowrule( DontCareRule )
{
}
WindowRules::WindowRules( KConfig& cfg )
: wmclassregexp( false )
, windowroleregexp( false )
, titleregexp( false )
, extraroleregexp( false )
, desktoprule( DontCareRule )
, aboverule( DontCareRule )
, belowrule( DontCareRule )
{
wmclass = cfg.readEntry( "wmclass" ).lower().latin1();
wmclassregexp = cfg.readBoolEntry( "wmclassregexp" );
windowrole = cfg.readEntry( "windowrole" ).lower().latin1();
windowroleregexp = cfg.readBoolEntry( "windowroleregexp" );
title = cfg.readEntry( "title" );
titleregexp = cfg.readBoolEntry( "titleregexp" );
extrarole = cfg.readEntry( "extrarole" ).lower().latin1();
extraroleregexp = cfg.readBoolEntry( "extraroleregexp" );
desktop = cfg.readNumEntry( "desktop" );
desktoprule = readRule( cfg, "desktoprule" );
above = cfg.readBoolEntry( "above" );
aboverule = readRule( cfg, "aboverule" );
below = cfg.readBoolEntry( "below" );
belowrule = readRule( cfg, "belowrule" );
kdDebug() << "READ RULE:" << wmclass << endl;
}
#define WRITE_MATCH_STRING( var, cast ) \
if( !var.isEmpty()) \
{ \
cfg.writeEntry( #var, cast var ); \
cfg.writeEntry( #var "regexp", var##regexp ); \
} \
else \
{ \
cfg.deleteEntry( #var ); \
cfg.deleteEntry( #var "regexp" ); \
}
#define WRITE_SET_RULE( var ) \
if( var##rule != DontCareRule ) \
{ \
cfg.writeEntry( #var, var ); \
cfg.writeEntry( #var "rule", var##rule ); \
} \
else \
{ \
cfg.deleteEntry( #var ); \
cfg.deleteEntry( #var "rule" ); \
}
void WindowRules::write( KConfig& cfg ) const
{
// always write wmclass
cfg.writeEntry( "wmclass", ( const char* )wmclass );
cfg.writeEntry( "wmclassregexp", wmclassregexp );
WRITE_MATCH_STRING( windowrole, (const char*) );
WRITE_MATCH_STRING( title, );
WRITE_MATCH_STRING( extrarole, (const char*) );
WRITE_SET_RULE( desktop );
WRITE_SET_RULE( above );
WRITE_SET_RULE( below );
}
#undef WRITE_MATCH_STRING
#undef WRITE_SET_RULE
SettingRule WindowRules::readRule( KConfig& cfg, const QString& key )
{
int v = cfg.readNumEntry( key );
if( v >= DontCareRule && v <= LastRule )
return static_cast< SettingRule >( v );
return DontCareRule;
}
void WindowRules::update( Client* c )
{
// TODO check this setting is for this client ?
if( desktoprule == RememberRule )
desktop = c->desktop();
if( aboverule == RememberRule )
above = c->keepAbove();
if( belowrule == RememberRule )
below = c->keepBelow();
}
bool WindowRules::match( const Client* c ) const
{
// TODO exactMatch() for regexp?
if( !wmclass.isEmpty())
{ // TODO optimize?
if( wmclassregexp && !QRegExp( wmclass ).exactMatch( c->resourceClass()))
return false;
if( !wmclassregexp && wmclass != c->resourceClass())
return false;
}
if( !windowrole.isEmpty())
{
if( windowroleregexp && QRegExp( windowrole ).exactMatch( c->windowRole()))
return false;
if( !windowroleregexp && windowrole != c->windowRole())
return false;
}
if( !title.isEmpty())
{
if( titleregexp && QRegExp( title ).exactMatch( c->caption( false )))
return false;
if( !titleregexp && title != c->caption( false ))
return false;
}
// TODO extrarole
return true;
}
int WindowRules::checkDesktop( int req_desktop, bool init ) const
{
// TODO chaining?
return checkRule( desktoprule, init ) ? desktop : req_desktop;
}
bool WindowRules::checkKeepAbove( bool req_above, bool init ) const
{
return checkRule( aboverule, init ) ? above : req_above;
}
bool WindowRules::checkKeepBelow( bool req_below, bool init ) const
{
return checkRule( belowrule, init ) ? below : req_below;
}
// Client
void Client::initWindowRules()
{
client_rules = workspace()->findWindowRules( this );
}
void Client::updateWindowRules()
{
client_rules->update( this );
}
// Workspace
WindowRules* Workspace::findWindowRules( const Client* c ) const
{
if( c->isTopMenu()) // TODO cannot have restrictions
return &dummyRules;
for( QValueList< WindowRules* >::ConstIterator it = windowRules.begin();
it != windowRules.end();
++it )
{
// chaining for wildcard matches
if( (*it)->match( c ))
{
kdDebug() << "RULE FOUND:" << c << endl;
return *it;
}
}
kdDebug() << "RULE DUMMY:" << c << endl;
return &dummyRules;
}
void Workspace::editWindowRules( Client* c )
{
// TODO
}
void Workspace::loadWindowRules()
{
while( !windowRules.isEmpty())
{
delete windowRules.front();
windowRules.pop_front();
}
KConfig cfg( "kwinrulesrc", true );
cfg.setGroup( "General" );
int count = cfg.readNumEntry( "count" );
kdDebug() << "RULES:" << count << endl;
for( int i = 1;
i <= count;
++i )
{
cfg.setGroup( QString::number( i ));
WindowRules* setting = new WindowRules( cfg );
windowRules.append( setting );
}
}
void Workspace::writeWindowRules()
{
KConfig cfg( "kwinrulesrc" );
cfg.setGroup( "General" );
cfg.writeEntry( "count", windowRules.count());
int i = 1;
for( QValueList< WindowRules* >::ConstIterator it = windowRules.begin();
it != windowRules.end();
++it, ++i )
{
cfg.setGroup( QString::number( i ));
(*it)->write( cfg );
}
}
} // namespace

77
rules.h Normal file
View File

@ -0,0 +1,77 @@
/*****************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2004 Lubos Lunak <l.lunak@kde.org>
You can Freely distribute this program under the GNU General Public
License. See the file "COPYING" for the exact licensing terms.
******************************************************************/
#ifndef KWIN_RULES_H
#define KWIN_RULES_H
#include <qstring.h>
class KConfig;
namespace KWinInternal
{
class Client;
enum SettingRule
{
DontCareRule,
ApplyRule,
ForceRule,
RememberRule,
LastRule = RememberRule
};
class WindowRules
{
public:
WindowRules();
WindowRules( KConfig& );
void write( KConfig& ) const;
void update( Client* );
bool match( const Client* c ) const;
int checkDesktop( int desktop, bool init = false ) const;
bool checkKeepAbove( bool above, bool init = false ) const;
bool checkKeepBelow( bool above, bool init = false ) const;
private:
static SettingRule readRule( KConfig&, const QString& key );
static bool checkRule( SettingRule rule, bool init );
QCString wmclass;
bool wmclassregexp;
// TODO bool wmclasscomplete - class+name
QCString windowrole;
bool windowroleregexp;
QString title; // TODO "caption" ?
bool titleregexp;
QCString extrarole;
bool extraroleregexp;
// TODO window type? both to which it applies and to which value to force it
int desktop;
SettingRule desktoprule;
bool above;
SettingRule aboverule;
bool below;
SettingRule belowrule;
};
inline
bool WindowRules::checkRule( SettingRule rule, bool init )
{
if( rule != DontCareRule )
{
if( rule == ForceRule || init )
return true;
}
return false;
}
} // namespace
#endif

121
sm.cpp
View File

@ -178,121 +178,21 @@ void Workspace::loadSessionInfo()
info->userNoBorder = config->readBoolEntry( QString("userNoBorder")+n, FALSE ); info->userNoBorder = config->readBoolEntry( QString("userNoBorder")+n, FALSE );
info->windowType = txtToWindowType( config->readEntry( QString("windowType")+n ).latin1()); info->windowType = txtToWindowType( config->readEntry( QString("windowType")+n ).latin1());
info->active = ( active_client == i ); info->active = ( active_client == i );
info->fake = false;
} }
} }
void Workspace::loadFakeSessionInfo()
{
fakeSession.clear();
KConfig *config = KGlobal::config();
config->setGroup("FakeSession" );
int count = config->readNumEntry( "count" );
for ( int i = 1; i <= count; i++ )
{
QString n = QString::number(i);
SessionInfo* info = new SessionInfo;
fakeSession.append( info );
info->windowRole = config->readEntry( QString("windowRole")+n ).latin1();
info->resourceName = config->readEntry( QString("resourceName")+n ).latin1();
info->resourceClass = config->readEntry( QString("resourceClass")+n ).lower().latin1();
info->wmClientMachine = config->readEntry( QString("clientMachine")+n ).latin1();
info->geometry = config->readRectEntry( QString("geometry")+n );
info->restore = config->readRectEntry( QString("restore")+n );
info->fsrestore = config->readRectEntry( QString("fsrestore")+n );
info->maximized = config->readNumEntry( QString("maximize")+n, 0 );
info->fullscreen = config->readNumEntry( QString("fullscreen")+n, 0 );
info->desktop = config->readNumEntry( QString("desktop")+n, 0 );
info->minimized = config->readBoolEntry( QString("iconified")+n, FALSE );
info->onAllDesktops = config->readBoolEntry( QString("sticky")+n, FALSE );
info->shaded = config->readBoolEntry( QString("shaded")+n, FALSE );
info->keepAbove = config->readBoolEntry( QString("staysOnTop")+n, FALSE );
info->keepBelow = config->readBoolEntry( QString("keepBelow")+n, FALSE );
info->skipTaskbar = config->readBoolEntry( QString("skipTaskbar")+n, FALSE );
info->skipPager = config->readBoolEntry( QString("skipPager")+n, FALSE );
info->userNoBorder = config->readBoolEntry( QString("userNoBorder")+n, FALSE );
info->windowType = txtToWindowType( config->readEntry( QString("windowType")+n ).latin1());
info->active = false;
info->fake = true;
}
}
void Workspace::storeFakeSessionInfo( Client* c )
{
if ( !c->storeSettings() )
return;
SessionInfo* info = new SessionInfo;
fakeSession.append( info );
info->windowRole = c->windowRole();
info->resourceName = c->resourceName();
info->resourceClass = c->resourceClass();
info->wmClientMachine = c->wmClientMachine();
info->geometry = QRect( c->calculateGravitation(TRUE), c->clientSize() ) ; // FRAME
info->restore = c->geometryRestore();
info->fsrestore = c->geometryFSRestore();
info->maximized = (int)c->maximizeMode();
info->fullscreen = (int)c->fullScreenMode();
info->desktop = c->desktop();
info->minimized = c->isMinimized();
info->onAllDesktops = c->isOnAllDesktops();
info->shaded = c->isShade();
info->keepAbove = c->keepAbove();
info->keepBelow = c->keepBelow();
info->skipTaskbar = c->skipTaskbar( true );
info->skipPager = c->skipPager();
info->userNoBorder = c->isUserNoBorder();
info->windowType = c->windowType();
info->active = false;
info->fake = true;
}
void Workspace::writeFakeSessionInfo()
{
KConfig *config = KGlobal::config();
config->setGroup("FakeSession" );
int count = 0;
for ( SessionInfo* info = fakeSession.first(); info; info = fakeSession.next() )
{
count++;
QString n = QString::number(count);
config->writeEntry( QString("windowRole")+n, info->windowRole.data() );
config->writeEntry( QString("resourceName")+n, info->resourceName.data() );
config->writeEntry( QString("resourceClass")+n, info->resourceClass.data() );
config->writeEntry( QString("clientMachine")+n, info->wmClientMachine.data() );
config->writeEntry( QString("geometry")+n, info->geometry );
config->writeEntry( QString("restore")+n, info->restore );
config->writeEntry( QString("fsrestore")+n, info->fsrestore );
config->writeEntry( QString("maximize")+n, info->maximized );
config->writeEntry( QString("fullscreen")+n, info->fullscreen );
config->writeEntry( QString("desktop")+n, info->desktop );
config->writeEntry( QString("iconified")+n, info->minimized );
config->writeEntry( QString("onAllDesktops")+n, info->onAllDesktops );
config->writeEntry( QString("shaded")+n, info->shaded );
config->writeEntry( QString("staysOnTop")+n, info->keepAbove );
config->writeEntry( QString("keepBelow")+n, info->keepBelow );
config->writeEntry( QString("skipTaskbar")+n, info->skipTaskbar );
config->writeEntry( QString("skipPager")+n, info->skipPager );
config->writeEntry( QString("userNoBorder")+n, info->userNoBorder );
config->writeEntry( QString("windowType")+n, windowTypeToTxt( info->windowType ));
}
config->writeEntry( "count", count );
}
/*! /*!
Returns a SessionInfo for client \a c. The returned session Returns a SessionInfo for client \a c. The returned session
info is removed from the storage. It's up to the caller to delete it. info is removed from the storage. It's up to the caller to delete it.
This function is called when a new window is mapped and must be managed. This function is called when a new window is mapped and must be managed.
We try to find a matching entry in the session. We also try to find We try to find a matching entry in the session.
a matching entry in the fakeSession to see if the user had seclected the
``store settings'' menu entry.
May return 0 if there's no session info for the client. May return 0 if there's no session info for the client.
*/ */
SessionInfo* Workspace::takeSessionInfo( Client* c ) SessionInfo* Workspace::takeSessionInfo( Client* c )
{ {
SessionInfo *realInfo = 0; SessionInfo *realInfo = 0;
SessionInfo *fakeInfo = 0;
QCString sessionId = c->sessionId(); QCString sessionId = c->sessionId();
QCString windowRole = c->windowRole(); QCString windowRole = c->windowRole();
QCString wmCommand = c->wmCommand(); QCString wmCommand = c->wmCommand();
@ -333,24 +233,7 @@ SessionInfo* Workspace::takeSessionInfo( Client* c )
realInfo = session.take(); realInfo = session.take();
} }
// Now search ``fakeSession'' return realInfo;
for (SessionInfo* info = fakeSession.first(); info && !fakeInfo; info = fakeSession.next() )
if ( info->resourceName == resourceName &&
info->resourceClass == resourceClass &&
( windowRole.isEmpty() || windowRole == info->windowRole ) &&
sessionInfoWindowTypeMatch( c, info ))
fakeInfo = fakeSession.take();
// Reconciliate
if (fakeInfo)
c->setStoreSettings( TRUE );
if (fakeInfo && realInfo)
delete fakeInfo;
if (realInfo)
return realInfo;
if (fakeInfo)
return fakeInfo;
return 0;
} }
bool Workspace::sessionInfoWindowTypeMatch( Client* c, SessionInfo* info ) bool Workspace::sessionInfoWindowTypeMatch( Client* c, SessionInfo* info )

3
sm.h
View File

@ -45,8 +45,7 @@ struct SessionInfo
bool skipPager; bool skipPager;
bool userNoBorder; bool userNoBorder;
NET::WindowType windowType; NET::WindowType windowType;
bool active; // means 'was active in the saved session', not used otherwise bool active; // means 'was active in the saved session'
bool fake; // fake session, i.e. 'save window settings', not SM restored
}; };

View File

@ -57,7 +57,7 @@ QPopupMenu* Workspace::clientPopup()
advanced_popup->insertItem( SmallIconSet( "down" ), i18n("Keep &Below Others"), Options::KeepBelowOp ); advanced_popup->insertItem( SmallIconSet( "down" ), i18n("Keep &Below Others"), Options::KeepBelowOp );
advanced_popup->insertItem( SmallIconSet( "window_fullscreen" ), i18n("&Fullscreen"), Options::FullScreenOp ); advanced_popup->insertItem( SmallIconSet( "window_fullscreen" ), i18n("&Fullscreen"), Options::FullScreenOp );
advanced_popup->insertItem( i18n("&No Border"), Options::NoBorderOp ); advanced_popup->insertItem( i18n("&No Border"), Options::NoBorderOp );
advanced_popup->insertItem( SmallIconSet( "filesave" ), i18n("Sto&re Window Settings"), Options::ToggleStoreSettingsOp ); advanced_popup->insertItem( SmallIconSet( "filesave" ), i18n("&Special Window Rules"), Options::WindowRulesOp );
popup->insertItem(i18n("Ad&vanced"), advanced_popup ); popup->insertItem(i18n("Ad&vanced"), advanced_popup );
desk_popup_index = popup->count(); desk_popup_index = popup->count();
@ -115,7 +115,6 @@ void Workspace::clientPopupAboutToShow()
advanced_popup->setItemChecked( Options::NoBorderOp, popup_client->noBorder() ); advanced_popup->setItemChecked( Options::NoBorderOp, popup_client->noBorder() );
advanced_popup->setItemEnabled( Options::NoBorderOp, popup_client->userCanSetNoBorder() ); advanced_popup->setItemEnabled( Options::NoBorderOp, popup_client->userCanSetNoBorder() );
popup->setItemEnabled( Options::MinimizeOp, popup_client->isMinimizable() ); popup->setItemEnabled( Options::MinimizeOp, popup_client->isMinimizable() );
advanced_popup->setItemChecked( Options::ToggleStoreSettingsOp, popup_client->storeSettings() );
popup->setItemEnabled( Options::CloseOp, popup_client->isCloseable() ); popup->setItemEnabled( Options::CloseOp, popup_client->isCloseable() );
} }
@ -129,7 +128,7 @@ void Workspace::initDesktopPopup()
desk_popup->setCheckable( TRUE ); desk_popup->setCheckable( TRUE );
desk_popup->setFont(KGlobalSettings::menuFont()); desk_popup->setFont(KGlobalSettings::menuFont());
connect( desk_popup, SIGNAL( activated(int) ), connect( desk_popup, SIGNAL( activated(int) ),
this, SLOT( sendToDesktop(int) ) ); this, SLOT( slotSendToDesktop(int) ) );
connect( desk_popup, SIGNAL( aboutToShow() ), connect( desk_popup, SIGNAL( aboutToShow() ),
this, SLOT( desktopPopupAboutToShow() ) ); this, SLOT( desktopPopupAboutToShow() ) );
@ -278,8 +277,8 @@ void Workspace::performWindowOperation( Client* c, Options::WindowOperation op )
case Options::KeepBelowOp: case Options::KeepBelowOp:
c->setKeepBelow( !c->keepBelow() ); c->setKeepBelow( !c->keepBelow() );
break; break;
case Options::ToggleStoreSettingsOp: case Options::WindowRulesOp:
c->setStoreSettings( !c->storeSettings() ); editWindowRules( c );
break; break;
case Options::LowerOp: case Options::LowerOp:
lowerClient(c); lowerClient(c);
@ -666,7 +665,7 @@ void Workspace::slotWindowRaiseOrLower()
void Workspace::slotWindowOnAllDesktops() void Workspace::slotWindowOnAllDesktops()
{ {
if( active_client ) if( active_client )
active_client->toggleOnAllDesktops(); active_client->setOnAllDesktops( !active_client->isOnAllDesktops());
} }
void Workspace::slotWindowFullScreen() void Workspace::slotWindowFullScreen()
@ -737,7 +736,7 @@ void Workspace::slotKillWindow()
Internal slot for the window operation menu Internal slot for the window operation menu
*/ */
void Workspace::sendToDesktop( int desk ) void Workspace::slotSendToDesktop( int desk )
{ {
if ( !popup_client ) if ( !popup_client )
return; return;

View File

@ -36,6 +36,7 @@ License. See the file "COPYING" for the exact licensing terms.
#include "placement.h" #include "placement.h"
#include "notifications.h" #include "notifications.h"
#include "group.h" #include "group.h"
#include "rules.h"
#include <X11/extensions/shape.h> #include <X11/extensions/shape.h>
#include <X11/keysym.h> #include <X11/keysym.h>
@ -118,7 +119,7 @@ Workspace::Workspace( bool restore )
if ( restore ) if ( restore )
loadSessionInfo(); loadSessionInfo();
loadFakeSessionInfo(); loadWindowRules();
(void) QApplication::desktop(); // trigger creation of desktop widget (void) QApplication::desktop(); // trigger creation of desktop widget
@ -393,9 +394,8 @@ Workspace::~Workspace()
++it ) ++it )
{ {
// only release the window // only release the window
if( !(*it)->isDesktop()) // TODO ?
storeFakeSessionInfo( *it );
(*it)->releaseWindow( true ); (*it)->releaseWindow( true );
// no removeClient() is called !
} }
delete desktop_widget; delete desktop_widget;
delete tab_box; delete tab_box;
@ -404,7 +404,7 @@ Workspace::~Workspace()
if ( root == qt_xrootwin() ) if ( root == qt_xrootwin() )
XDeleteProperty(qt_xdisplay(), qt_xrootwin(), atoms->kwin_running); XDeleteProperty(qt_xdisplay(), qt_xrootwin(), atoms->kwin_running);
writeFakeSessionInfo(); writeWindowRules();
KGlobal::config()->sync(); KGlobal::config()->sync();
delete rootInfo; delete rootInfo;
@ -417,6 +417,11 @@ Workspace::~Workspace()
delete topmenu_watcher; delete topmenu_watcher;
delete topmenu_selection; delete topmenu_selection;
delete topmenu_space; delete topmenu_space;
while( !windowRules.isEmpty())
{
delete windowRules.front();
windowRules.pop_front();
}
XDestroyWindow( qt_xdisplay(), null_focus_window ); XDestroyWindow( qt_xdisplay(), null_focus_window );
// TODO ungrabXServer(); // TODO ungrabXServer();
_self = 0; _self = 0;
@ -487,8 +492,6 @@ void Workspace::removeClient( Client* c, allowed_t )
if( c->isNormalWindow()) if( c->isNormalWindow())
Notify::raise( Notify::Delete ); Notify::raise( Notify::Delete );
storeFakeSessionInfo( c );
Q_ASSERT( clients.contains( c ) || desktops.contains( c )); Q_ASSERT( clients.contains( c ) || desktops.contains( c ));
clients.remove( c ); clients.remove( c );
desktops.remove( c ); desktops.remove( c );
@ -1169,11 +1172,10 @@ void Workspace::setNumberOfDesktops( int n )
*/ */
void Workspace::sendClientToDesktop( Client* c, int desk, bool dont_activate ) void Workspace::sendClientToDesktop( Client* c, int desk, bool dont_activate )
{ {
if ( c->desktop() == desk )
return;
bool was_on_desktop = c->isOnDesktop( desk ) || c->isOnAllDesktops(); bool was_on_desktop = c->isOnDesktop( desk ) || c->isOnAllDesktops();
c->setDesktop( desk ); c->setDesktop( desk );
if ( c->desktop() == desk ) // no change or desktop forced
return;
desk = c->desktop(); // Client did range checking desk = c->desktop(); // Client did range checking
if ( c->isOnDesktop( currentDesktop() ) ) if ( c->isOnDesktop( currentDesktop() ) )

View File

@ -40,6 +40,7 @@ class PopupInfo;
class RootInfo; class RootInfo;
class PluginMgr; class PluginMgr;
class Placement; class Placement;
class WindowRules;
class SystemTrayWindow class SystemTrayWindow
{ {
@ -196,7 +197,7 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine
void storeSession( KConfig* config, SMSavePhase phase ); void storeSession( KConfig* config, SMSavePhase phase );
SessionInfo* takeSessionInfo( Client* ); SessionInfo* takeSessionInfo( Client* );
WindowRules* findWindowRules( const Client* ) const;
// dcop interface // dcop interface
void cascadeDesktop(); void cascadeDesktop();
@ -316,7 +317,7 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine
private slots: private slots:
void desktopPopupAboutToShow(); void desktopPopupAboutToShow();
void clientPopupAboutToShow(); void clientPopupAboutToShow();
void sendToDesktop( int ); void slotSendToDesktop( int );
void clientPopupActivated( int ); void clientPopupActivated( int );
void configureWM(); void configureWM();
void desktopResized(); void desktopResized();
@ -416,15 +417,15 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine
Client* popup_client; Client* popup_client;
void loadSessionInfo();
QWidget* desktop_widget; QWidget* desktop_widget;
void loadSessionInfo();
void loadWindowRules();
void writeWindowRules();
void editWindowRules( Client* );
QPtrList<SessionInfo> session; QPtrList<SessionInfo> session;
QPtrList<SessionInfo> fakeSession; QValueList<WindowRules*> windowRules;
void loadFakeSessionInfo();
void storeFakeSessionInfo( Client* c );
void writeFakeSessionInfo();
static const char* windowTypeToTxt( NET::WindowType type ); static const char* windowTypeToTxt( NET::WindowType type );
static NET::WindowType txtToWindowType( const char* txt ); static NET::WindowType txtToWindowType( const char* txt );
static bool sessionInfoWindowTypeMatch( Client* c, SessionInfo* info ); static bool sessionInfoWindowTypeMatch( Client* c, SessionInfo* info );