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
This commit is contained in:
parent
76ed413d94
commit
8e09a9bc22
15 changed files with 409 additions and 198 deletions
|
@ -11,7 +11,7 @@ kwin_la_SOURCES = workspace.cpp client.cpp placement.cpp atoms.cpp \
|
|||
options.cpp plugins.cpp events.cpp KWinInterface.skel \
|
||||
killwindow.cpp geometrytip.cpp sm.cpp group.cpp bridge.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_LDFLAGS = $(all_libraries) -module -avoid-version
|
||||
|
|
|
@ -320,7 +320,11 @@ void Workspace::takeActivity( Client* c, int flags, bool handled )
|
|||
if( modal != NULL && modal != c )
|
||||
{
|
||||
if( !modal->isOnDesktop( 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),
|
||||
// but it has a modal, there's no need to use handled mode, because
|
||||
// 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);
|
||||
|
||||
Time Client::readUserTimeMapTimestamp( const KStartupInfoId* asn_id, const KStartupInfoData* asn_data,
|
||||
const SessionInfo* session ) const
|
||||
bool session ) const
|
||||
{
|
||||
Time time = info->userTime();
|
||||
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
|
||||
// of session saving and there was no user interaction yet,
|
||||
// this check will be done in Workspace::allowClientActiovationTimestamp().
|
||||
if( session && !session->fake )
|
||||
if( session )
|
||||
return -1U;
|
||||
if( ignoreFocusStealing() && act != NULL )
|
||||
time = act->userTime();
|
||||
|
|
16
client.cpp
16
client.cpp
|
@ -27,6 +27,7 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
#include "workspace.h"
|
||||
#include "atoms.h"
|
||||
#include "notifications.h"
|
||||
#include "rules.h"
|
||||
|
||||
#include <X11/extensions/shape.h>
|
||||
|
||||
|
@ -78,6 +79,7 @@ Client::Client( Workspace *ws )
|
|||
transient_for( NULL ),
|
||||
transient_for_id( None ),
|
||||
original_transient_for_id( None ),
|
||||
client_rules( NULL ),
|
||||
in_group( NULL ),
|
||||
window_group( None ),
|
||||
in_layer( UnknownLayer ),
|
||||
|
@ -133,10 +135,8 @@ Client::Client( Workspace *ws )
|
|||
Pcontexthelp = 0;
|
||||
Pping = 0;
|
||||
input = FALSE;
|
||||
store_settings = FALSE;
|
||||
skip_pager = FALSE;
|
||||
|
||||
|
||||
max_mode = MaximizeRestore;
|
||||
|
||||
cmap = None;
|
||||
|
@ -175,6 +175,7 @@ void Client::releaseWindow( bool on_shutdown )
|
|||
{
|
||||
if (moveResizeMode)
|
||||
leaveMoveResize();
|
||||
updateWindowRules();
|
||||
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)
|
||||
if( !on_shutdown )
|
||||
|
@ -222,6 +223,7 @@ void Client::destroyClient()
|
|||
{
|
||||
if (moveResizeMode)
|
||||
leaveMoveResize();
|
||||
updateWindowRules();
|
||||
++block_geometry;
|
||||
setModal( false );
|
||||
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
|
||||
}
|
||||
|
||||
void Client::toggleOnAllDesktops()
|
||||
{
|
||||
setOnAllDesktops( !isOnAllDesktops());
|
||||
}
|
||||
|
||||
void Client::setDesktop( int desktop )
|
||||
{
|
||||
if( desktop != NET::OnAllDesktops ) // do range check
|
||||
desktop = KMAX( 1, KMIN( workspace()->numberOfDesktops(), desktop ));
|
||||
desktop = rules()->checkDesktop( desktop );
|
||||
if( desk == desktop )
|
||||
return;
|
||||
int was_desk = desk;
|
||||
|
@ -1264,9 +1262,9 @@ void Client::fetchIconicName()
|
|||
|
||||
/*!\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()
|
||||
|
|
30
client.h
30
client.h
|
@ -39,6 +39,7 @@ class Client;
|
|||
class WinInfo;
|
||||
class SessionInfo;
|
||||
class Bridge;
|
||||
class WindowRules;
|
||||
|
||||
class Client : public QObject, public KDecorationDefines
|
||||
{
|
||||
|
@ -66,6 +67,7 @@ class Client : public QObject, public KDecorationDefines
|
|||
void checkGroup( Group* gr = NULL, bool force = false );
|
||||
// prefer isXXX() instead
|
||||
NET::WindowType windowType( bool strict = false, int supported_types = SUPPORTED_WINDOW_TYPES_MASK ) const;
|
||||
const WindowRules* rules() const;
|
||||
|
||||
QRect geometry() const;
|
||||
QSize size() const;
|
||||
|
@ -160,9 +162,6 @@ class Client : public QObject, public KDecorationDefines
|
|||
void setModal( bool modal );
|
||||
bool isModal() const;
|
||||
|
||||
bool storeSettings() const;
|
||||
void setStoreSettings( bool );
|
||||
|
||||
// auxiliary functions, depend on the windowType
|
||||
bool wantsTabFocus() 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
|
||||
void virtualDesktopChange();
|
||||
|
||||
QString caption() const;
|
||||
QString caption( bool full = true ) const;
|
||||
|
||||
void keyPressEvent( uint key_code ); // FRAME ??
|
||||
void updateMouseGrab();
|
||||
|
@ -275,7 +274,6 @@ class Client : public QObject, public KDecorationDefines
|
|||
void closeWindow();
|
||||
void killWindow();
|
||||
void maximize( MaximizeMode );
|
||||
void toggleOnAllDesktops();
|
||||
void toggleShade();
|
||||
void showContextHelp();
|
||||
void cancelAutoRaise();
|
||||
|
@ -343,6 +341,8 @@ private slots:
|
|||
void fetchName();
|
||||
void fetchIconicName();
|
||||
bool hasTransientInternal( const Client* c, bool indirect, ConstClientList& set ) const;
|
||||
void initWindowRules();
|
||||
void updateWindowRules();
|
||||
|
||||
void updateWorkareaDiffs();
|
||||
void checkDirection( int new_diff, int old_diff, QRect& rect, const QRect& area );
|
||||
|
@ -380,7 +380,7 @@ private slots:
|
|||
void rawHide(); // just hides it
|
||||
|
||||
Time readUserTimeMapTimestamp( const KStartupInfoId* asn_id, const KStartupInfoData* asn_data,
|
||||
const SessionInfo* session ) const;
|
||||
bool session ) const;
|
||||
Time readUserCreationTime() const;
|
||||
static bool sameAppWindowRoleMatch( const Client* c1, const Client* c2, bool active_hack );
|
||||
void startupIdChanged();
|
||||
|
@ -438,7 +438,6 @@ private slots:
|
|||
uint Pcontexthelp : 1; // does the window understand the ContextHelp protocol?
|
||||
uint Pping : 1; // does it support _NET_WM_PING?
|
||||
uint input :1; // does the window want input in its wm_hints
|
||||
uint store_settings : 1;
|
||||
uint skip_pager : 1;
|
||||
uint motif_may_resize : 1;
|
||||
uint motif_may_move :1;
|
||||
|
@ -453,6 +452,7 @@ private slots:
|
|||
uint urgency : 1; // XWMHints, UrgencyHint
|
||||
uint ignore_focus_stealing : 1; // don't apply focus stealing prevention to this client
|
||||
uint check_active_modal : 1; // see Client::addTransient()
|
||||
WindowRules* client_rules;
|
||||
void getWMHints();
|
||||
void readIcons();
|
||||
void getWindowProtocols();
|
||||
|
@ -685,17 +685,6 @@ inline bool Client::keepBelow() const
|
|||
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
|
||||
{
|
||||
return is_shape;
|
||||
|
@ -837,6 +826,11 @@ inline bool Client::ignoreFocusStealing() const
|
|||
return ignore_focus_stealing;
|
||||
}
|
||||
|
||||
inline const WindowRules* Client::rules() const
|
||||
{
|
||||
return client_rules;
|
||||
}
|
||||
|
||||
KWIN_PROCEDURE( CheckIgnoreFocusStealingProcedure, cl->ignore_focus_stealing = options->checkIgnoreFocusStealing( cl ));
|
||||
|
||||
inline Window Client::moveResizeGrabWindow() const
|
||||
|
|
|
@ -20,6 +20,7 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
#include "atoms.h"
|
||||
#include "tabbox.h"
|
||||
#include "group.h"
|
||||
#include "rules.h"
|
||||
|
||||
#include <qwhatsthis.h>
|
||||
#include <kkeynative.h>
|
||||
|
|
30
layers.cpp
30
layers.cpp
|
@ -64,13 +64,15 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
|
||||
#include <assert.h>
|
||||
|
||||
#include <kdebug.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "client.h"
|
||||
#include "workspace.h"
|
||||
#include "tabbox.h"
|
||||
#include "popupinfo.h"
|
||||
#include "group.h"
|
||||
#include <kdebug.h>
|
||||
#include "rules.h"
|
||||
|
||||
extern Time qt_x_time;
|
||||
|
||||
|
@ -642,22 +644,36 @@ void Client::restackWindow( Window /*above TODO */, int detail, NET::RequestSour
|
|||
|
||||
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;
|
||||
setKeepBelow( false );
|
||||
}
|
||||
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
|
||||
workspace()->updateClientLayer( this );
|
||||
}
|
||||
|
||||
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;
|
||||
setKeepAbove( false );
|
||||
}
|
||||
keep_below = b;
|
||||
info->setState( b ? NET::KeepBelow : 0, NET::KeepBelow );
|
||||
info->setState( keepBelow() ? NET::KeepBelow : 0, NET::KeepBelow );
|
||||
workspace()->updateClientLayer( this );
|
||||
}
|
||||
|
||||
|
|
|
@ -86,7 +86,8 @@ public:
|
|||
KeepAboveOp,
|
||||
KeepBelowOp,
|
||||
OperationsOp,
|
||||
ToggleStoreSettingsOp,
|
||||
WindowRulesOp,
|
||||
ToggleStoreSettingsOp = WindowRulesOp, ///< @obsolete
|
||||
HMaximizeOp,
|
||||
VMaximizeOp,
|
||||
LowerOp,
|
||||
|
|
28
manage.cpp
28
manage.cpp
|
@ -22,6 +22,7 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
#include <X11/extensions/shape.h>
|
||||
|
||||
#include "notifications.h"
|
||||
#include "rules.h"
|
||||
|
||||
extern Time qt_x_time;
|
||||
extern Atom qt_window_role;
|
||||
|
@ -105,8 +106,11 @@ bool Client::manage( Window w, bool isMapped )
|
|||
}
|
||||
ignore_focus_stealing = options->checkIgnoreFocusStealing( this );
|
||||
|
||||
detectNoBorder();
|
||||
fetchName();
|
||||
window_role = getStringProperty( w, qt_window_role );
|
||||
initWindowRules();
|
||||
|
||||
detectNoBorder();
|
||||
fetchIconicName();
|
||||
getWMHints(); // needs to be done before readTransient() because of reading the group
|
||||
getWmClientLeader(); // needs to be done before readTransient() because of same app comparing
|
||||
|
@ -114,7 +118,6 @@ bool Client::manage( Window w, bool isMapped )
|
|||
getIcons();
|
||||
getWindowProtocols();
|
||||
getWmNormalHints(); // get xSizeHint
|
||||
window_role = getStringProperty( w, qt_window_role );
|
||||
|
||||
// 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;
|
||||
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;
|
||||
KStartupInfoData 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 );
|
||||
|
||||
SessionInfo* session = workspace()->takeSessionInfo( this );
|
||||
|
||||
if ( session )
|
||||
{
|
||||
if ( session->minimized )
|
||||
|
@ -186,6 +183,7 @@ bool Client::manage( Window w, bool isMapped )
|
|||
desk = workspace()->currentDesktop();
|
||||
if( desk != NET::OnAllDesktops ) // do range check
|
||||
desk = KMAX( 1, KMIN( workspace()->numberOfDesktops(), desk ));
|
||||
desk = rules()->checkDesktop( desk, !isMapped );
|
||||
info->setDesktop( desk );
|
||||
workspace()->updateOnAllDesktopsOfTransients( this ); // SELI
|
||||
// onAllDesktopsChange(); decoration doesn't exist here yet
|
||||
|
@ -308,6 +306,8 @@ bool Client::manage( Window w, bool isMapped )
|
|||
// other settings from the previous session
|
||||
if ( session )
|
||||
{
|
||||
// session restored windows are not considered to be new windows WRT rules,
|
||||
// i.e. obey only forcing rules
|
||||
setKeepAbove( session->keepAbove );
|
||||
setKeepBelow( session->keepBelow );
|
||||
setSkipTaskbar( session->skipTaskbar, true );
|
||||
|
@ -368,10 +368,8 @@ bool Client::manage( Window w, bool isMapped )
|
|||
// read other initial states
|
||||
if( info->state() & NET::Shaded )
|
||||
setShade( ShadeNormal );
|
||||
if( info->state() & NET::KeepAbove )
|
||||
setKeepAbove( true );
|
||||
if( info->state() & NET::KeepBelow )
|
||||
setKeepBelow( true );
|
||||
setKeepAbove( rules()->checkKeepAbove( info->state() & NET::KeepAbove, !isMapped ));
|
||||
setKeepBelow( rules()->checkKeepBelow( info->state() & NET::KeepBelow, !isMapped ));
|
||||
if( info->state() & NET::SkipTaskbar )
|
||||
setSkipTaskbar( true, true );
|
||||
if( info->state() & NET::SkipPager )
|
||||
|
@ -433,7 +431,7 @@ bool Client::manage( Window w, bool isMapped )
|
|||
{
|
||||
workspace()->restackClientUnderActive( this );
|
||||
rawShow();
|
||||
if( ( !session || session->fake ) && ( !isSpecialWindow() || isOverride()))
|
||||
if( !session && ( !isSpecialWindow() || isOverride()))
|
||||
demandAttention();
|
||||
}
|
||||
}
|
||||
|
@ -442,7 +440,7 @@ bool Client::manage( Window w, bool isMapped )
|
|||
{
|
||||
virtualDesktopChange();
|
||||
workspace()->raiseClient( this );
|
||||
if( ( !session || session->fake ) && !isMapped )
|
||||
if( !session && !isMapped )
|
||||
demandAttention();
|
||||
}
|
||||
}
|
||||
|
|
238
rules.cpp
Normal file
238
rules.cpp
Normal 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
77
rules.h
Normal 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
121
sm.cpp
|
@ -178,121 +178,21 @@ void Workspace::loadSessionInfo()
|
|||
info->userNoBorder = config->readBoolEntry( QString("userNoBorder")+n, FALSE );
|
||||
info->windowType = txtToWindowType( config->readEntry( QString("windowType")+n ).latin1());
|
||||
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
|
||||
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.
|
||||
We try to find a matching entry in the session. We also try to find
|
||||
a matching entry in the fakeSession to see if the user had seclected the
|
||||
``store settings'' menu entry.
|
||||
We try to find a matching entry in the session.
|
||||
|
||||
May return 0 if there's no session info for the client.
|
||||
*/
|
||||
SessionInfo* Workspace::takeSessionInfo( Client* c )
|
||||
{
|
||||
SessionInfo *realInfo = 0;
|
||||
SessionInfo *fakeInfo = 0;
|
||||
QCString sessionId = c->sessionId();
|
||||
QCString windowRole = c->windowRole();
|
||||
QCString wmCommand = c->wmCommand();
|
||||
|
@ -333,24 +233,7 @@ SessionInfo* Workspace::takeSessionInfo( Client* c )
|
|||
realInfo = session.take();
|
||||
}
|
||||
|
||||
// Now search ``fakeSession''
|
||||
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;
|
||||
return realInfo;
|
||||
}
|
||||
|
||||
bool Workspace::sessionInfoWindowTypeMatch( Client* c, SessionInfo* info )
|
||||
|
|
3
sm.h
3
sm.h
|
@ -45,8 +45,7 @@ struct SessionInfo
|
|||
bool skipPager;
|
||||
bool userNoBorder;
|
||||
NET::WindowType windowType;
|
||||
bool active; // means 'was active in the saved session', not used otherwise
|
||||
bool fake; // fake session, i.e. 'save window settings', not SM restored
|
||||
bool active; // means 'was active in the saved session'
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ QPopupMenu* Workspace::clientPopup()
|
|||
advanced_popup->insertItem( SmallIconSet( "down" ), i18n("Keep &Below Others"), Options::KeepBelowOp );
|
||||
advanced_popup->insertItem( SmallIconSet( "window_fullscreen" ), i18n("&Fullscreen"), Options::FullScreenOp );
|
||||
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 );
|
||||
desk_popup_index = popup->count();
|
||||
|
@ -115,7 +115,6 @@ void Workspace::clientPopupAboutToShow()
|
|||
advanced_popup->setItemChecked( Options::NoBorderOp, popup_client->noBorder() );
|
||||
advanced_popup->setItemEnabled( Options::NoBorderOp, popup_client->userCanSetNoBorder() );
|
||||
popup->setItemEnabled( Options::MinimizeOp, popup_client->isMinimizable() );
|
||||
advanced_popup->setItemChecked( Options::ToggleStoreSettingsOp, popup_client->storeSettings() );
|
||||
popup->setItemEnabled( Options::CloseOp, popup_client->isCloseable() );
|
||||
}
|
||||
|
||||
|
@ -129,7 +128,7 @@ void Workspace::initDesktopPopup()
|
|||
desk_popup->setCheckable( TRUE );
|
||||
desk_popup->setFont(KGlobalSettings::menuFont());
|
||||
connect( desk_popup, SIGNAL( activated(int) ),
|
||||
this, SLOT( sendToDesktop(int) ) );
|
||||
this, SLOT( slotSendToDesktop(int) ) );
|
||||
connect( desk_popup, SIGNAL( aboutToShow() ),
|
||||
this, SLOT( desktopPopupAboutToShow() ) );
|
||||
|
||||
|
@ -278,8 +277,8 @@ void Workspace::performWindowOperation( Client* c, Options::WindowOperation op )
|
|||
case Options::KeepBelowOp:
|
||||
c->setKeepBelow( !c->keepBelow() );
|
||||
break;
|
||||
case Options::ToggleStoreSettingsOp:
|
||||
c->setStoreSettings( !c->storeSettings() );
|
||||
case Options::WindowRulesOp:
|
||||
editWindowRules( c );
|
||||
break;
|
||||
case Options::LowerOp:
|
||||
lowerClient(c);
|
||||
|
@ -666,7 +665,7 @@ void Workspace::slotWindowRaiseOrLower()
|
|||
void Workspace::slotWindowOnAllDesktops()
|
||||
{
|
||||
if( active_client )
|
||||
active_client->toggleOnAllDesktops();
|
||||
active_client->setOnAllDesktops( !active_client->isOnAllDesktops());
|
||||
}
|
||||
|
||||
void Workspace::slotWindowFullScreen()
|
||||
|
@ -737,7 +736,7 @@ void Workspace::slotKillWindow()
|
|||
|
||||
Internal slot for the window operation menu
|
||||
*/
|
||||
void Workspace::sendToDesktop( int desk )
|
||||
void Workspace::slotSendToDesktop( int desk )
|
||||
{
|
||||
if ( !popup_client )
|
||||
return;
|
||||
|
|
|
@ -36,6 +36,7 @@ License. See the file "COPYING" for the exact licensing terms.
|
|||
#include "placement.h"
|
||||
#include "notifications.h"
|
||||
#include "group.h"
|
||||
#include "rules.h"
|
||||
|
||||
#include <X11/extensions/shape.h>
|
||||
#include <X11/keysym.h>
|
||||
|
@ -118,7 +119,7 @@ Workspace::Workspace( bool restore )
|
|||
if ( restore )
|
||||
loadSessionInfo();
|
||||
|
||||
loadFakeSessionInfo();
|
||||
loadWindowRules();
|
||||
|
||||
(void) QApplication::desktop(); // trigger creation of desktop widget
|
||||
|
||||
|
@ -393,9 +394,8 @@ Workspace::~Workspace()
|
|||
++it )
|
||||
{
|
||||
// only release the window
|
||||
if( !(*it)->isDesktop()) // TODO ?
|
||||
storeFakeSessionInfo( *it );
|
||||
(*it)->releaseWindow( true );
|
||||
// no removeClient() is called !
|
||||
}
|
||||
delete desktop_widget;
|
||||
delete tab_box;
|
||||
|
@ -404,7 +404,7 @@ Workspace::~Workspace()
|
|||
if ( root == qt_xrootwin() )
|
||||
XDeleteProperty(qt_xdisplay(), qt_xrootwin(), atoms->kwin_running);
|
||||
|
||||
writeFakeSessionInfo();
|
||||
writeWindowRules();
|
||||
KGlobal::config()->sync();
|
||||
|
||||
delete rootInfo;
|
||||
|
@ -417,6 +417,11 @@ Workspace::~Workspace()
|
|||
delete topmenu_watcher;
|
||||
delete topmenu_selection;
|
||||
delete topmenu_space;
|
||||
while( !windowRules.isEmpty())
|
||||
{
|
||||
delete windowRules.front();
|
||||
windowRules.pop_front();
|
||||
}
|
||||
XDestroyWindow( qt_xdisplay(), null_focus_window );
|
||||
// TODO ungrabXServer();
|
||||
_self = 0;
|
||||
|
@ -487,8 +492,6 @@ void Workspace::removeClient( Client* c, allowed_t )
|
|||
if( c->isNormalWindow())
|
||||
Notify::raise( Notify::Delete );
|
||||
|
||||
storeFakeSessionInfo( c );
|
||||
|
||||
Q_ASSERT( clients.contains( c ) || desktops.contains( c ));
|
||||
clients.remove( c );
|
||||
desktops.remove( c );
|
||||
|
@ -1169,11 +1172,10 @@ void Workspace::setNumberOfDesktops( int n )
|
|||
*/
|
||||
void Workspace::sendClientToDesktop( Client* c, int desk, bool dont_activate )
|
||||
{
|
||||
if ( c->desktop() == desk )
|
||||
return;
|
||||
|
||||
bool was_on_desktop = c->isOnDesktop( desk ) || c->isOnAllDesktops();
|
||||
c->setDesktop( desk );
|
||||
if ( c->desktop() == desk ) // no change or desktop forced
|
||||
return;
|
||||
desk = c->desktop(); // Client did range checking
|
||||
|
||||
if ( c->isOnDesktop( currentDesktop() ) )
|
||||
|
|
17
workspace.h
17
workspace.h
|
@ -40,6 +40,7 @@ class PopupInfo;
|
|||
class RootInfo;
|
||||
class PluginMgr;
|
||||
class Placement;
|
||||
class WindowRules;
|
||||
|
||||
class SystemTrayWindow
|
||||
{
|
||||
|
@ -196,7 +197,7 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine
|
|||
void storeSession( KConfig* config, SMSavePhase phase );
|
||||
|
||||
SessionInfo* takeSessionInfo( Client* );
|
||||
|
||||
WindowRules* findWindowRules( const Client* ) const;
|
||||
|
||||
// dcop interface
|
||||
void cascadeDesktop();
|
||||
|
@ -316,7 +317,7 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine
|
|||
private slots:
|
||||
void desktopPopupAboutToShow();
|
||||
void clientPopupAboutToShow();
|
||||
void sendToDesktop( int );
|
||||
void slotSendToDesktop( int );
|
||||
void clientPopupActivated( int );
|
||||
void configureWM();
|
||||
void desktopResized();
|
||||
|
@ -416,15 +417,15 @@ class Workspace : public QObject, public KWinInterface, public KDecorationDefine
|
|||
|
||||
Client* popup_client;
|
||||
|
||||
void loadSessionInfo();
|
||||
|
||||
QWidget* desktop_widget;
|
||||
|
||||
void loadSessionInfo();
|
||||
void loadWindowRules();
|
||||
void writeWindowRules();
|
||||
void editWindowRules( Client* );
|
||||
|
||||
QPtrList<SessionInfo> session;
|
||||
QPtrList<SessionInfo> fakeSession;
|
||||
void loadFakeSessionInfo();
|
||||
void storeFakeSessionInfo( Client* c );
|
||||
void writeFakeSessionInfo();
|
||||
QValueList<WindowRules*> windowRules;
|
||||
static const char* windowTypeToTxt( NET::WindowType type );
|
||||
static NET::WindowType txtToWindowType( const char* txt );
|
||||
static bool sessionInfoWindowTypeMatch( Client* c, SessionInfo* info );
|
||||
|
|
Loading…
Reference in a new issue