Activity session support
this implements dbus methods in kwin for saving & restoring activities. internally, kwin creates "sub-sessions" in kwin and ksmserver to represent the saved activities. ksmserver doesn't need to know what activities are :) at the moment the code includes some fake information; it will be changed to use the real stuff once the activities service code is in. svn path=/trunk/KDE/kdebase/workspace/; revision=1187793
This commit is contained in:
parent
4ca657dc45
commit
f3edd534ba
3 changed files with 184 additions and 40 deletions
|
@ -73,5 +73,11 @@
|
|||
<method name="nextTileLayout"/>
|
||||
<method name="previousTileLayout"/>
|
||||
<method name="dumpTiles"/>
|
||||
<method name="storeActivity">
|
||||
<arg type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="loadActivity">
|
||||
<arg type="s" direction="in"/>
|
||||
</method>
|
||||
</interface>
|
||||
</node>
|
||||
|
|
210
sm.cpp
210
sm.cpp
|
@ -30,6 +30,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
#include "workspace.h"
|
||||
#include "client.h"
|
||||
#include <QDBusInterface>
|
||||
#include <QSocketNotifier>
|
||||
#include <QSessionManager>
|
||||
#include <kdebug.h>
|
||||
|
@ -106,47 +107,8 @@ void Workspace::storeSession( KConfig* config, SMSavePhase phase )
|
|||
count++;
|
||||
if( c->isActive())
|
||||
active_client = count;
|
||||
QString n = QString::number(count);
|
||||
if( phase == SMSavePhase2 || phase == SMSavePhase2Full )
|
||||
{
|
||||
cg.writeEntry( QString("sessionId")+n, sessionId.constData() );
|
||||
cg.writeEntry( QString("windowRole")+n, c->windowRole().constData() );
|
||||
cg.writeEntry( QString("wmCommand")+n, wmCommand.constData() );
|
||||
cg.writeEntry( QString("wmClientMachine")+n, c->wmClientMachine( true ).constData() );
|
||||
cg.writeEntry( QString("resourceName")+n, c->resourceName().constData() );
|
||||
cg.writeEntry( QString("resourceClass")+n, c->resourceClass().constData() );
|
||||
cg.writeEntry( QString("geometry")+n, QRect( c->calculateGravitation(true), c->clientSize() ) ); // FRAME
|
||||
cg.writeEntry( QString("restore")+n, c->geometryRestore() );
|
||||
cg.writeEntry( QString("fsrestore")+n, c->geometryFSRestore() );
|
||||
cg.writeEntry( QString("maximize")+n, (int) c->maximizeMode() );
|
||||
cg.writeEntry( QString("fullscreen")+n, (int) c->fullScreenMode() );
|
||||
cg.writeEntry( QString("desktop")+n, c->desktop() );
|
||||
// the config entry is called "iconified" for back. comp. reasons
|
||||
// (kconf_update script for updating session files would be too complicated)
|
||||
cg.writeEntry( QString("iconified")+n, c->isMinimized() );
|
||||
cg.writeEntry( QString("opacity")+n, c->opacity() );
|
||||
// the config entry is called "sticky" for back. comp. reasons
|
||||
cg.writeEntry( QString("sticky")+n, c->isOnAllDesktops() );
|
||||
cg.writeEntry( QString("shaded")+n, c->isShade() );
|
||||
// the config entry is called "staysOnTop" for back. comp. reasons
|
||||
cg.writeEntry( QString("staysOnTop")+n, c->keepAbove() );
|
||||
cg.writeEntry( QString("keepBelow")+n, c->keepBelow() );
|
||||
cg.writeEntry( QString("skipTaskbar")+n, c->skipTaskbar( true ) );
|
||||
cg.writeEntry( QString("skipPager")+n, c->skipPager() );
|
||||
cg.writeEntry( QString("skipSwitcher")+n, c->skipSwitcher() );
|
||||
// not really just set by user, but name kept for back. comp. reasons
|
||||
cg.writeEntry( QString("userNoBorder")+n, c->noBorder() );
|
||||
cg.writeEntry( QString("windowType")+n, windowTypeToTxt( c->windowType()));
|
||||
cg.writeEntry( QString("shortcut")+n, c->shortcut().toString());
|
||||
cg.writeEntry( QString("stackingOrder")+n, unconstrained_stacking_order.indexOf( c ));
|
||||
int group = 0;
|
||||
if( c->clientGroup() )
|
||||
group = c->clientGroup()->clients().count() > 1 ?
|
||||
// KConfig doesn't support long so we need to live with less precision on 64-bit systems
|
||||
static_cast<int>( reinterpret_cast<long>( c->clientGroup() )) : 0;
|
||||
cg.writeEntry( QString("clientGroup")+n, group );
|
||||
cg.writeEntry( QString("activities")+n, c->activities() );
|
||||
}
|
||||
storeClient(cg, count, c);
|
||||
}
|
||||
if( phase == SMSavePhase0 )
|
||||
{
|
||||
|
@ -170,6 +132,140 @@ void Workspace::storeSession( KConfig* config, SMSavePhase phase )
|
|||
}
|
||||
}
|
||||
|
||||
void Workspace::storeClient( KConfigGroup &cg, int num, Client *c )
|
||||
{
|
||||
QString n = QString::number(num);
|
||||
cg.writeEntry( QString("sessionId")+n, c->sessionId().constData() );
|
||||
cg.writeEntry( QString("windowRole")+n, c->windowRole().constData() );
|
||||
cg.writeEntry( QString("wmCommand")+n, c->wmCommand().constData() );
|
||||
cg.writeEntry( QString("wmClientMachine")+n, c->wmClientMachine( true ).constData() );
|
||||
cg.writeEntry( QString("resourceName")+n, c->resourceName().constData() );
|
||||
cg.writeEntry( QString("resourceClass")+n, c->resourceClass().constData() );
|
||||
cg.writeEntry( QString("geometry")+n, QRect( c->calculateGravitation(true), c->clientSize() ) ); // FRAME
|
||||
cg.writeEntry( QString("restore")+n, c->geometryRestore() );
|
||||
cg.writeEntry( QString("fsrestore")+n, c->geometryFSRestore() );
|
||||
cg.writeEntry( QString("maximize")+n, (int) c->maximizeMode() );
|
||||
cg.writeEntry( QString("fullscreen")+n, (int) c->fullScreenMode() );
|
||||
cg.writeEntry( QString("desktop")+n, c->desktop() );
|
||||
// the config entry is called "iconified" for back. comp. reasons
|
||||
// (kconf_update script for updating session files would be too complicated)
|
||||
cg.writeEntry( QString("iconified")+n, c->isMinimized() );
|
||||
cg.writeEntry( QString("opacity")+n, c->opacity() );
|
||||
// the config entry is called "sticky" for back. comp. reasons
|
||||
cg.writeEntry( QString("sticky")+n, c->isOnAllDesktops() );
|
||||
cg.writeEntry( QString("shaded")+n, c->isShade() );
|
||||
// the config entry is called "staysOnTop" for back. comp. reasons
|
||||
cg.writeEntry( QString("staysOnTop")+n, c->keepAbove() );
|
||||
cg.writeEntry( QString("keepBelow")+n, c->keepBelow() );
|
||||
cg.writeEntry( QString("skipTaskbar")+n, c->skipTaskbar( true ) );
|
||||
cg.writeEntry( QString("skipPager")+n, c->skipPager() );
|
||||
cg.writeEntry( QString("skipSwitcher")+n, c->skipSwitcher() );
|
||||
// not really just set by user, but name kept for back. comp. reasons
|
||||
cg.writeEntry( QString("userNoBorder")+n, c->noBorder() );
|
||||
cg.writeEntry( QString("windowType")+n, windowTypeToTxt( c->windowType()));
|
||||
cg.writeEntry( QString("shortcut")+n, c->shortcut().toString());
|
||||
cg.writeEntry( QString("stackingOrder")+n, unconstrained_stacking_order.indexOf( c ));
|
||||
int group = 0;
|
||||
if( c->clientGroup() )
|
||||
group = c->clientGroup()->clients().count() > 1 ?
|
||||
// KConfig doesn't support long so we need to live with less precision on 64-bit systems
|
||||
static_cast<int>( reinterpret_cast<long>( c->clientGroup() )) : 0;
|
||||
cg.writeEntry( QString("clientGroup")+n, group );
|
||||
cg.writeEntry( QString("activities")+n, c->activities() );
|
||||
}
|
||||
|
||||
void Workspace::storeSubSession(const QString &name, QSet<QByteArray> sessionIds)
|
||||
{
|
||||
//TODO clear it first
|
||||
KConfigGroup cg(KGlobal::config(), QString("SubSession: ") + name);
|
||||
int count = 0;
|
||||
int active_client = -1;
|
||||
for (ClientList::Iterator it = clients.begin(); it != clients.end(); ++it)
|
||||
{
|
||||
Client* c = (*it);
|
||||
QByteArray sessionId = c->sessionId();
|
||||
QByteArray wmCommand = c->wmCommand();
|
||||
if ( sessionId.isEmpty() )
|
||||
// remember also applications that are not XSMP capable
|
||||
// and use the obsolete WM_COMMAND / WM_SAVE_YOURSELF
|
||||
if ( wmCommand.isEmpty() )
|
||||
continue;
|
||||
if (!sessionIds.contains(sessionId))
|
||||
continue;
|
||||
|
||||
kDebug() << "storing" << sessionId;
|
||||
count++;
|
||||
if( c->isActive())
|
||||
active_client = count;
|
||||
storeClient(cg, count, c);
|
||||
}
|
||||
cg.writeEntry( "count", count );
|
||||
cg.writeEntry( "active", active_client );
|
||||
//cg.writeEntry( "desktop", currentDesktop());
|
||||
}
|
||||
|
||||
void Workspace::storeActivity(const QString &id)
|
||||
{
|
||||
//TODO check if it's already closed
|
||||
QSet<QByteArray> saveSessionIds;
|
||||
QSet<QByteArray> dontCloseSessionIds;
|
||||
kDebug() << id;
|
||||
for (ClientList::Iterator it = clients.begin(); it != clients.end(); ++it)
|
||||
{
|
||||
Client* c = (*it);
|
||||
QByteArray sessionId = c->sessionId();
|
||||
if ( sessionId.isEmpty() )
|
||||
continue; //TODO support old wm_command apps too?
|
||||
|
||||
kDebug() << sessionId;
|
||||
|
||||
//if it's on the activity that's closing, it needs saving
|
||||
//but if a process is on some other open activity, I don't wanna close it yet
|
||||
//this is, of course, complicated by a process having many windows.
|
||||
if (c->isOnAllActivities())
|
||||
{
|
||||
dontCloseSessionIds << sessionId;
|
||||
continue;
|
||||
}
|
||||
QStringList activities = c->activities();
|
||||
foreach (const QString &activityId, activities)
|
||||
{
|
||||
if (activityId == id)
|
||||
saveSessionIds << sessionId;
|
||||
else if (openActivities_.contains(activityId))
|
||||
dontCloseSessionIds << sessionId;
|
||||
}
|
||||
}
|
||||
|
||||
storeSubSession(id, saveSessionIds);
|
||||
|
||||
QStringList saveAndClose;
|
||||
QStringList saveOnly;
|
||||
foreach (const QByteArray &sessionId, saveSessionIds)
|
||||
{
|
||||
if (dontCloseSessionIds.contains(sessionId))
|
||||
saveOnly << sessionId;
|
||||
else
|
||||
saveAndClose << sessionId;
|
||||
}
|
||||
|
||||
kDebug() << "saveActivity" << id << saveAndClose << saveOnly;
|
||||
|
||||
openActivities_.removeOne(id); //FIXME it's not closed until ksmserver says it's closed
|
||||
|
||||
//pass off to ksmserver
|
||||
QDBusInterface ksmserver("org.kde.ksmserver", "/KSMServer", "org.kde.KSMServerInterface");
|
||||
if (ksmserver.isValid())
|
||||
{
|
||||
QDBusMessage reply = ksmserver.call("saveSubSession", id, saveAndClose, saveOnly);
|
||||
if (reply.type() == QDBusMessage::ErrorMessage)
|
||||
kDebug() << "dbus error:" << reply.errorMessage();
|
||||
else
|
||||
kDebug() << "dbus succeeded";
|
||||
}
|
||||
else
|
||||
kDebug() << "couldn't get ksmserver interface";
|
||||
}
|
||||
|
||||
/*!
|
||||
Loads the session information from the config file.
|
||||
|
@ -183,6 +279,11 @@ void Workspace::loadSessionInfo()
|
|||
|
||||
setTilingEnabled( cg.readEntry( "tiling", false ) );
|
||||
|
||||
addSessionInfo(cg);
|
||||
}
|
||||
|
||||
void Workspace::addSessionInfo(KConfigGroup &cg)
|
||||
{
|
||||
int count = cg.readEntry( "count",0 );
|
||||
int active_client = cg.readEntry( "active",0 );
|
||||
for ( int i = 1; i <= count; i++ )
|
||||
|
@ -222,6 +323,35 @@ void Workspace::loadSessionInfo()
|
|||
}
|
||||
}
|
||||
|
||||
void Workspace::loadSubSessionInfo(const QString &name)
|
||||
{
|
||||
KConfigGroup cg(KGlobal::config(), QString("SubSession: ") + name);
|
||||
addSessionInfo(cg);
|
||||
}
|
||||
|
||||
void Workspace::loadActivity(const QString &id)
|
||||
{
|
||||
if (!allActivities_.contains(id))
|
||||
return; //bogus id
|
||||
if (openActivities_.contains(id))
|
||||
return; //already open
|
||||
|
||||
openActivities_ << id;
|
||||
loadSubSessionInfo(id);
|
||||
|
||||
QDBusInterface ksmserver("org.kde.ksmserver", "/KSMServer", "org.kde.KSMServerInterface");
|
||||
if (ksmserver.isValid())
|
||||
{
|
||||
QDBusMessage reply = ksmserver.call("restoreSubSession", id);
|
||||
if (reply.type() == QDBusMessage::ErrorMessage)
|
||||
kDebug() << "dbus error:" << reply.errorMessage();
|
||||
else
|
||||
kDebug() << "dbus succeeded";
|
||||
}
|
||||
else
|
||||
kDebug() << "couldn't get ksmserver interface";
|
||||
}
|
||||
|
||||
/*!
|
||||
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.
|
||||
|
|
|
@ -318,6 +318,7 @@ class Workspace : public QObject, public KDecorationDefines
|
|||
int currentDesktop_;
|
||||
QString activity_;
|
||||
QStringList allActivities_;
|
||||
QStringList openActivities_;
|
||||
bool desktopLayoutDynamicity_;
|
||||
|
||||
KActivityController activityController_;
|
||||
|
@ -420,6 +421,8 @@ class Workspace : public QObject, public KDecorationDefines
|
|||
void performWindowOperation( Client* c, WindowOperation op );
|
||||
|
||||
void storeSession( KConfig* config, SMSavePhase phase );
|
||||
void storeClient( KConfigGroup &cg, int num, Client *c );
|
||||
void storeSubSession( const QString &name, QSet<QByteArray> sessionIds );
|
||||
|
||||
SessionInfo* takeSessionInfo( Client* );
|
||||
WindowRules findWindowRules( const Client*, bool );
|
||||
|
@ -446,6 +449,8 @@ class Workspace : public QObject, public KDecorationDefines
|
|||
void toggleTiling();
|
||||
void nextTileLayout();
|
||||
void previousTileLayout();
|
||||
void storeActivity( const QString &id );
|
||||
void loadActivity( const QString &id );
|
||||
|
||||
void setCurrentScreen( int new_screen );
|
||||
|
||||
|
@ -875,6 +880,9 @@ class Workspace : public QObject, public KDecorationDefines
|
|||
Client* active_popup_client;
|
||||
|
||||
void loadSessionInfo();
|
||||
void addSessionInfo( KConfigGroup &cg );
|
||||
void loadSubSessionInfo( const QString &name );
|
||||
|
||||
void loadWindowRules();
|
||||
void editWindowRules( Client* c, bool whole_app );
|
||||
|
||||
|
|
Loading…
Reference in a new issue