plasma: implement session manager

comes along with plenty of other changes

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2024-05-07 10:46:00 +03:00
parent 51a8d78114
commit fb686dc3c1
42 changed files with 281 additions and 360 deletions

View file

@ -836,7 +836,7 @@ void DolphinMainWindow::openTerminal()
dir = url.toLocalFile();
}
KToolInvocation::invokeTerminal(QString(), dir);
KToolInvocation::self()->invokeTerminal(QString(), dir);
}
void DolphinMainWindow::editSettings()

View file

@ -86,6 +86,7 @@ int main(int argc, char **argv)
{
DolphinApplication app;
app.enableSessionManagement();
if (app.isSessionRestored()) {
app.restoreSession();
}

View file

@ -135,7 +135,8 @@ void KateMailFilesPluginView::slotMail()
} // check selected docs done
if ( ! urls.count() )
return;
KToolInvocation::invokeMailer( QString(), // to
KToolInvocation::self()->invokeMailer(
QString(), // to
QString(), // cc
QString(), // subject
QString(), // body

View file

@ -202,7 +202,7 @@ void KateSessionApplet::slotOnItemClicked(const QModelIndex &index)
else if ( id > 2 )
args <<"-n"<< "--start"<<m_sessions[ id-3 ];
KToolInvocation::kdeinitExec("kate", args);
KToolInvocation::self()->kdeinitExec("kate", args);
}
void KateSessionApplet::createConfigurationInterface(KConfigDialog *parent)

View file

@ -53,7 +53,7 @@ void KateHelpButton::setIconState(IconState state)
void KateHelpButton::invokeHelp()
{
KToolInvocation::invokeHelp(m_section, "kate");
KToolInvocation::self()->invokeHelp(m_section, "kate");
}
void KateHelpButton::setSection(const QString& section)

View file

@ -805,8 +805,9 @@ KateCommandLineBar::KateCommandLineBar (KateView *view, QWidget *parent)
setFocusProxy (m_lineEdit);
}
void KateCommandLineBar::showHelpPage() {
KToolInvocation::invokeHelp("advanced-editing-tools-commandline","kate");
void KateCommandLineBar::showHelpPage()
{
KToolInvocation::self()->invokeHelp("advanced-editing-tools-commandline","kate");
}
KateCommandLineBar::~KateCommandLineBar()

View file

@ -365,7 +365,7 @@ int main( int argc, char **argv )
}
#ifdef Q_WS_X11
// make the world happy, we are started, kind of...
// make the world happy, it are started, kind of...
KStartupInfo::appStarted ();
#endif
@ -377,6 +377,7 @@ int main( int argc, char **argv )
KateApp app (args);
if (app.shouldExit()) return 0;
app.enableSessionManagement();
// execute ourself ;)
return app.exec();
}

View file

@ -825,7 +825,7 @@ void KateMainWindow::slotOpenWithMenuAction(QAction* a)
void KateMainWindow::pluginHelp()
{
KToolInvocation::invokeHelp (QString(), "kate-plugins");
KToolInvocation::self()->invokeHelp (QString(), "kate-plugins");
}
void KateMainWindow::aboutEditor()

View file

@ -672,7 +672,7 @@ void KAccessConfig::save()
// make kaccess reread the configuration
// turning a11y features off needs to be done by kaccess
// so run it to clear any enabled features and it will exit if it should
KToolInvocation::startServiceByDesktopName("kaccess");
KToolInvocation::self()->startServiceByDesktopName("kaccess");
emit changed(false);
}
@ -774,7 +774,7 @@ extern "C"
Q_DECL_EXPORT void kcminit_access()
{
KConfig config("kaccessrc", KConfig::NoGlobals);
KToolInvocation::startServiceByDesktopName("kaccess");
KToolInvocation::self()->startServiceByDesktopName("kaccess");
}
}

View file

@ -68,9 +68,9 @@ extern "C"
// Tell klauncher to set the XCURSOR_THEME and XCURSOR_SIZE environment
// variables when launching applications.
KToolInvocation::setLaunchEnv("XCURSOR_THEME", theme);
KToolInvocation::self()->setLaunchEnv("XCURSOR_THEME", theme);
if (!size.isEmpty()) {
KToolInvocation::setLaunchEnv("XCURSOR_SIZE", size);
KToolInvocation::self()->setLaunchEnv("XCURSOR_SIZE", size);
}
#endif
delete config;

View file

@ -557,7 +557,7 @@ void MouseConfig::save()
group.writeEntry("MKCurve", mk_curve->value());
// restart kaccess
KToolInvocation::startServiceByDesktopName("kaccess");
KToolInvocation::self()->startServiceByDesktopName("kaccess");
emit changed(false);
}

View file

@ -256,7 +256,7 @@ bool ThemePage::applyTheme(const CursorTheme *theme, const int size)
}
// Set up the proper launch environment for newly started apps
KToolInvocation::setLaunchEnv("XCURSOR_THEME", theme->name());
KToolInvocation::self()->setLaunchEnv("XCURSOR_THEME", theme->name());
// Update the Xcursor X resources
runRdb();

View file

@ -92,7 +92,7 @@ static void applyGtkStyles(bool active, int version)
// Pass env. var to klauncher.
QString name = gtkEnvVar(version);
QString value = list.join(":");
KToolInvocation::setLaunchEnv(name, value);
KToolInvocation::self()->setLaunchEnv(name, value);
}
// -----------------------------------------------------------------------------

View file

@ -162,7 +162,7 @@ void RandrMonitorModule::processX11Event( XEvent* e )
void RandrMonitorModule::showKcm()
{
KToolInvocation::kdeinitExec("kcmshell4", QStringList() << "randr");
KToolInvocation::self()->kdeinitExec("kcmshell4", QStringList() << "randr");
}
void RandrMonitorModule::tryAutoConfig()
@ -244,7 +244,7 @@ void RandrMonitorModule::switchDisplay()
return;
}
// no idea what to do here
KToolInvocation::kdeinitExec( "kcmshell4", QStringList() << "randr" );
KToolInvocation::self()->kdeinitExec( "kcmshell4", QStringList() << "randr" );
}
void RandrMonitorModule::resumedFromSuspend()

View file

@ -176,7 +176,7 @@ void KCrashModule::slotDirty(const QString &path)
kcrashargs.append(kcrashdisplay);
}
kDebug() << "Restarting" << kcrashfilepath << kcrashapppath << kcrashargs;
KToolInvocation::kdeinitExec(kcrashapppath, kcrashargs);
KToolInvocation::self()->kdeinitExec(kcrashapppath, kcrashargs);
}
}
}
@ -195,9 +195,9 @@ void KCrashModule::slotReport()
const QString kcrashreporturl = knotification->property("_k_url").toString();
knotification->close();
if (kcrashreporturl.startsWith(QLatin1String("mailto:"))) {
KToolInvocation::invokeMailer(kcrashreporturl, QString::fromLatin1("Crash report"));
KToolInvocation::self()->invokeMailer(kcrashreporturl, QString::fromLatin1("Crash report"));
} else {
KToolInvocation::invokeBrowser(kcrashreporturl);
KToolInvocation::self()->invokeBrowser(kcrashreporturl);
}
}

View file

@ -167,7 +167,7 @@ void KHostName::changeSessionManager()
return;
}
sm = "local/"+newName+sm.mid(i);
KToolInvocation::setLaunchEnv(QString::fromLatin1("SESSION_MANAGER"), sm);
KToolInvocation::self()->setLaunchEnv(QString::fromLatin1("SESSION_MANAGER"), sm);
}
int main(int argc, char **argv)

View file

@ -233,7 +233,7 @@ void KInfoCenter::resetCondition()
void KInfoCenter::helpClickedSlot()
{
KToolInvocation::invokeHelp(QString(), m_contain->serviceName());
KToolInvocation::self()->invokeHelp(QString(), m_contain->serviceName());
}
void KInfoCenter::exportClickedSlot()

View file

@ -84,7 +84,7 @@ void KNetAttach::slotPageChanged(int)
void KNetAttach::slotHelpClicked()
{
KToolInvocation::invokeHelp(QString(), "knetattach");
KToolInvocation::self()->invokeHelp(QString(), "knetattach");
}
void KNetAttach::setInformationText(const QString &type)

View file

@ -495,7 +495,7 @@ void SessionController::handleOpenWithAction()
void SessionController::configureWebShortcuts()
{
KToolInvocation::kdeinitExec("kcmshell4", QStringList() << "ebrowsing");
KToolInvocation::self()->kdeinitExec("kcmshell4", QStringList() << "ebrowsing");
}
void SessionController::sendSignal(QAction* action)

View file

@ -71,6 +71,7 @@ int main(int argc, char** argv)
// create a new application instance
Application app;
app.enableSessionManagement();
// make sure the d&d popup menu provided by libkonq get translated.
KGlobal::locale()->insertCatalog("libkonq");

View file

@ -98,7 +98,7 @@ KStart::KStart()
}
} else {
QString error;
if (KToolInvocation::startServiceByDesktopPath(exe, url, &error) != 0) {
if (KToolInvocation::self()->startServiceByDesktopPath(exe, url, &error) != 0) {
kError() << error;
}
}

View file

@ -224,7 +224,7 @@ bool HostConnector::useCustom() const
void HostConnector::slotHelp()
{
KToolInvocation::invokeHelp( "connectingtootherhosts", "ksysguard" );
KToolInvocation::self()->invokeHelp( "connectingtootherhosts", "ksysguard" );
}
#include "moc_HostConnector.cpp"

View file

@ -57,7 +57,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "atoms.h"
#include "options.h"
#include "sm.h"
#include "utils.h"
#include "effects.h"
#include "workspace.h"
@ -275,6 +274,17 @@ bool Application::setup()
return true;
}
bool Application::saveSession()
{
Workspace::self()->sessionSaveStarted();
RuleBook::self()->setUpdatesDisabled(true);
Workspace::self()->storeSession(kapp->sessionConfig());
kapp->sessionConfig()->sync();
RuleBook::self()->setUpdatesDisabled(false); // re-enable
Workspace::self()->sessionSaveDone();
return KApplication::saveSession();
}
void Application::lostSelection()
{
KCrash::setFlags(0); // too late to restart now
@ -335,6 +345,7 @@ int main(int argc, char * argv[])
KCmdLineArgs::addCmdLineOptions(args);
KWin::Application a;
a.enableSessionManagement();
QDBusInterface plasma("org.kde.plasma-desktop", "/App", "local.PlasmaApp", QDBusConnection::sessionBus());
if (plasma.isValid()) {
plasma.call("suspendStartup", "kwin");
@ -361,8 +372,6 @@ int main(int argc, char * argv[])
if (plasma.isValid()) {
plasma.call("resumeStartup", "kwin");
}
KWin::SessionManager weAreIndeed;
KWin::SessionSaveDoneHelper helper;
KGlobal::locale()->insertCatalog("kwin_effects");
fcntl(XConnectionNumber(KWin::display()), F_SETFD, 1);

View file

@ -42,7 +42,10 @@ protected:
bool x11EventFilter(XEvent*);
bool notify(QObject* o, QEvent* e);
private slots:
private Q_SLOTS:
bool saveSession() final;
private Q_SLOTS:
void lostSelection();
private:

View file

@ -968,7 +968,7 @@ void RuleBook::edit(Client* c, bool whole_app)
args << "--wid" << QString::number(c->window());
if (whole_app)
args << "--whole-app";
KToolInvocation::kdeinitExec("kwin_rules_dialog", args);
KToolInvocation::self()->kdeinitExec("kwin_rules_dialog", args);
}
void RuleBook::load()

View file

@ -31,44 +31,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "workspace.h"
#include "client.h"
#include <QSocketNotifier>
#include <QSessionManager>
#include <kdebug.h>
namespace KWin
{
bool SessionManager::saveState(QSessionManager& sm)
{
// If the session manager is plasma-desktop, save stacking
// order, active window, active desktop etc. in phase 1,
// as plasma-desktop assures no interaction will be done
// before the WM finishes phase 1. Saving in phase 2 is
// too late, as possible user interaction may change some things.
// Phase2 is still needed though (ICCCM 5.2)
char* sm_vendor = SmcVendor(static_cast< SmcConn >(sm.handle()));
bool kde = qstrcmp(sm_vendor, "KDE") == 0;
free(sm_vendor);
if (!sm.isPhase2()) {
Workspace::self()->sessionSaveStarted();
if (kde) // save stacking order etc. before "save file?" etc. dialogs change it
Workspace::self()->storeSession(kapp->sessionConfig(), SMSavePhase0);
sm.release(); // Qt doesn't automatically release in this case (bug?)
sm.requestPhase2();
return true;
}
Workspace::self()->storeSession(kapp->sessionConfig(), kde ? SMSavePhase2 : SMSavePhase2Full);
kapp->sessionConfig()->sync();
return true;
}
// I bet this is broken, just like everywhere else in KDE
bool SessionManager::commitData(QSessionManager& sm)
{
if (!sm.isPhase2())
Workspace::self()->sessionSaveStarted();
return true;
}
// Workspace
/*!
@ -76,7 +43,7 @@ bool SessionManager::commitData(QSessionManager& sm)
\sa loadSessionInfo()
*/
void Workspace::storeSession(KConfig* config, SMSavePhase phase)
void Workspace::storeSession(KConfig* config)
{
KConfigGroup cg(config, "Session");
int count = 0;
@ -92,24 +59,11 @@ void Workspace::storeSession(KConfig* config, SMSavePhase phase)
count++;
if (c->isActive())
active_client = count;
if (phase == SMSavePhase2 || phase == SMSavePhase2Full)
storeClient(cg, count, c);
}
if (phase == SMSavePhase0) {
// it would be much simpler to save these values to the config file,
// but both Qt and KDE treat phase1 and phase2 separately,
// which results in different sessionkey and different config file :(
session_active_client = active_client;
session_desktop = VirtualDesktopManager::self()->current();
} else if (phase == SMSavePhase2) {
cg.writeEntry("count", count);
cg.writeEntry("active", session_active_client);
cg.writeEntry("desktop", session_desktop);
} else { // SMSavePhase2Full
cg.writeEntry("count", count);
cg.writeEntry("active", session_active_client);
cg.writeEntry("desktop", VirtualDesktopManager::self()->current());
}
}
void Workspace::storeClient(KConfigGroup &cg, int num, Client *c)
@ -149,32 +103,6 @@ void Workspace::storeClient(KConfigGroup &cg, int num, Client *c)
cg.writeEntry(QString("tabGroup") + n, static_cast<int>(reinterpret_cast<long>(c->tabGroup())));
}
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;
foreach (Client *c, clients) {
QByteArray sessionId = c->sessionId();
QByteArray wmCommand = c->wmCommand();
if (sessionId.isEmpty())
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());
}
/*!
Loads the session information from the config file.
@ -185,16 +113,11 @@ void Workspace::loadSessionInfo()
session.clear();
KConfigGroup cg(kapp->sessionConfig(), "Session");
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++) {
QString n = QString::number(i);
SessionInfo* info = new SessionInfo;
SessionInfo* info = new SessionInfo();
session.append(info);
info->sessionId = cg.readEntry(QString("sessionId") + n, QString()).toLatin1();
info->windowRole = cg.readEntry(QString("windowRole") + n, QString()).toLatin1();
@ -226,12 +149,6 @@ void Workspace::addSessionInfo(KConfigGroup &cg)
}
}
void Workspace::loadSubSessionInfo(const QString &name)
{
KConfigGroup cg(KGlobal::config(), QString("SubSession: ") + name);
addSessionInfo(cg);
}
/*!
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.
@ -334,157 +251,6 @@ NET::WindowType Workspace::txtToWindowType(const char* txt)
return static_cast< NET::WindowType >(-2); // undefined
}
// KWin's focus stealing prevention causes problems with user interaction
// during session save, as it prevents possible dialogs from getting focus.
// Therefore it's temporarily disabled during session saving. Start of
// session saving can be detected in SessionManager::saveState() above,
// but Qt doesn't have API for saying when session saved finished (either
// successfully, or was canceled). Therefore, create another connection
// to session manager, that will provide this information.
// Similarly the remember feature of window-specific settings should be disabled
// during KDE shutdown when windows may move e.g. because of Kicker going away
// (struts changing). When session saving starts, it can be cancelled, in which
// case the shutdown_cancelled callback is invoked, or it's a checkpoint that
// is immediatelly followed by save_complete, or finally it's a shutdown that
// is immediatelly followed by die callback. So getting save_yourself with shutdown
// set disables window-specific settings remembering, getting shutdown_cancelled
// re-enables, otherwise KWin will go away after die.
static void save_yourself(SmcConn conn_P, SmPointer ptr, int, Bool shutdown, int, Bool)
{
SessionSaveDoneHelper* session = reinterpret_cast< SessionSaveDoneHelper* >(ptr);
if (conn_P != session->connection())
return;
if (shutdown)
RuleBook::self()->setUpdatesDisabled(true);
SmcSaveYourselfDone(conn_P, True);
}
static void die(SmcConn conn_P, SmPointer ptr)
{
SessionSaveDoneHelper* session = reinterpret_cast< SessionSaveDoneHelper* >(ptr);
if (conn_P != session->connection())
return;
// session->saveDone(); we will quit anyway
session->close();
}
static void save_complete(SmcConn conn_P, SmPointer ptr)
{
SessionSaveDoneHelper* session = reinterpret_cast< SessionSaveDoneHelper* >(ptr);
if (conn_P != session->connection())
return;
session->saveDone();
}
static void shutdown_cancelled(SmcConn conn_P, SmPointer ptr)
{
SessionSaveDoneHelper* session = reinterpret_cast< SessionSaveDoneHelper* >(ptr);
if (conn_P != session->connection())
return;
RuleBook::self()->setUpdatesDisabled(false); // re-enable
// no need to differentiate between successful finish and cancel
session->saveDone();
}
void SessionSaveDoneHelper::saveDone()
{
Workspace::self()->sessionSaveDone();
}
SessionSaveDoneHelper::SessionSaveDoneHelper()
{
SmcCallbacks calls;
calls.save_yourself.callback = save_yourself;
calls.save_yourself.client_data = reinterpret_cast< SmPointer >(this);
calls.die.callback = die;
calls.die.client_data = reinterpret_cast< SmPointer >(this);
calls.save_complete.callback = save_complete;
calls.save_complete.client_data = reinterpret_cast< SmPointer >(this);
calls.shutdown_cancelled.callback = shutdown_cancelled;
calls.shutdown_cancelled.client_data = reinterpret_cast< SmPointer >(this);
char* id = NULL;
char err[ 11 ];
conn = SmcOpenConnection(NULL, 0, 1, 0,
SmcSaveYourselfProcMask | SmcDieProcMask | SmcSaveCompleteProcMask
| SmcShutdownCancelledProcMask, &calls, NULL, &id, 10, err);
if (id != NULL)
free(id);
if (conn == NULL)
return; // no SM
// set the required properties, mostly dummy values
SmPropValue propvalue[ 5 ];
SmProp props[ 5 ];
propvalue[ 0 ].length = sizeof(unsigned char);
unsigned char value0 = SmRestartNever; // so that this extra SM connection doesn't interfere
propvalue[ 0 ].value = &value0;
props[ 0 ].name = const_cast< char* >(SmRestartStyleHint);
props[ 0 ].type = const_cast< char* >(SmCARD8);
props[ 0 ].num_vals = 1;
props[ 0 ].vals = &propvalue[ 0 ];
QByteArray username = KUser(KUser::UseEffectiveUID).loginName().toLocal8Bit();
propvalue[ 1 ].length = username.size();
propvalue[ 1 ].value = (SmPointer)(username.isEmpty() ? "" : username.data());
props[ 1 ].name = const_cast< char* >(SmUserID);
props[ 1 ].type = const_cast< char* >(SmARRAY8);
props[ 1 ].num_vals = 1;
props[ 1 ].vals = &propvalue[ 1 ];
propvalue[ 2 ].length = 0;
propvalue[ 2 ].value = (SmPointer)("");
props[ 2 ].name = const_cast< char* >(SmRestartCommand);
props[ 2 ].type = const_cast< char* >(SmLISTofARRAY8);
props[ 2 ].num_vals = 1;
props[ 2 ].vals = &propvalue[ 2 ];
propvalue[ 3 ].length = strlen("kwinsmhelper");
propvalue[ 3 ].value = (SmPointer)"kwinsmhelper";
props[ 3 ].name = const_cast< char* >(SmProgram);
props[ 3 ].type = const_cast< char* >(SmARRAY8);
props[ 3 ].num_vals = 1;
props[ 3 ].vals = &propvalue[ 3 ];
propvalue[ 4 ].length = 0;
propvalue[ 4 ].value = (SmPointer)("");
props[ 4 ].name = const_cast< char* >(SmCloneCommand);
props[ 4 ].type = const_cast< char* >(SmLISTofARRAY8);
props[ 4 ].num_vals = 1;
props[ 4 ].vals = &propvalue[ 4 ];
SmProp* p[ 5 ] = { &props[ 0 ], &props[ 1 ], &props[ 2 ], &props[ 3 ], &props[ 4 ] };
SmcSetProperties(conn, 5, p);
notifier = new QSocketNotifier(IceConnectionNumber(SmcGetIceConnection(conn)),
QSocketNotifier::Read, this);
connect(notifier, SIGNAL(activated(int)), SLOT(processData()));
}
SessionSaveDoneHelper::~SessionSaveDoneHelper()
{
close();
}
void SessionSaveDoneHelper::close()
{
if (conn != NULL) {
delete notifier;
SmcCloseConnection(conn, 0, NULL);
}
conn = NULL;
}
void SessionSaveDoneHelper::processData()
{
if (conn != NULL)
IceProcessMessages(SmcGetIceConnection(conn), 0, 0);
}
void Workspace::sessionSaveDone()
{
session_saving = false;
//remove sessionInteract flag from all clients
foreach (Client * c, clients) {
c->setSessionInteract(false);
}
}
} // namespace
#include "moc_sm.cpp"

View file

@ -24,7 +24,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QDataStream>
#include <kapplication.h>
#include <ksessionmanager.h>
#include <netwm_def.h>
#include <QRect>
@ -71,41 +70,6 @@ struct SessionInfo {
Client* tabGroupClient; // The first client created that has an identical identifier
};
enum SMSavePhase {
SMSavePhase0, // saving global state in "phase 0"
SMSavePhase2, // saving window state in phase 2
SMSavePhase2Full // complete saving in phase2, there was no phase 0
};
class SessionSaveDoneHelper
: public QObject
{
Q_OBJECT
public:
SessionSaveDoneHelper();
virtual ~SessionSaveDoneHelper();
SmcConn connection() const {
return conn;
}
void saveDone();
void close();
private slots:
void processData();
private:
QSocketNotifier* notifier;
SmcConn conn;
};
class SessionManager
: public KSessionManager
{
public:
virtual bool saveState(QSessionManager& sm);
virtual bool commitData(QSessionManager& sm);
};
} // namespace
#endif

View file

@ -223,7 +223,7 @@ void UserActionsMenu::configureWM()
{
QStringList args;
args << "--icon" << "preferences-system-windows" << configModules();
KToolInvocation::kdeinitExec("kcmshell4", args);
KToolInvocation::self()->kdeinitExec("kcmshell4", args);
}
void UserActionsMenu::init()

View file

@ -26,6 +26,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// kwin
#include <kdecoration.h>
#include "sm.h"
#include "client.h"
#include "utils.h"
// Katie
#include <QKeySequence>
@ -225,10 +226,8 @@ public:
void performWindowOperation(Client* c, WindowOperation op);
void storeSession(KConfig* config, SMSavePhase phase);
void storeSession(KConfig* config);
void storeClient(KConfigGroup &cg, int num, Client *c);
void storeSubSession(const QString &name, QSet<QByteArray> sessionIds);
void loadSubSessionInfo(const QString &name);
SessionInfo* takeSessionInfo(Client*);
@ -453,7 +452,6 @@ private:
Client* active_popup_client;
void loadSessionInfo();
void addSessionInfo(KConfigGroup &cg);
QList<SessionInfo*> session;
static const char* windowTypeToTxt(NET::WindowType type);
@ -610,6 +608,20 @@ inline const ToplevelList& Workspace::stackingOrder() const
return stacking_order;
}
inline void Workspace::sessionSaveStarted()
{
session_saving = true;
}
inline void Workspace::sessionSaveDone()
{
session_saving = false;
//remove sessionInteract flag from all clients
foreach (Client * c, clients) {
c->setSessionInteract(false);
}
}
inline void Workspace::setWasUserInteraction()
{
was_user_interaction = true;
@ -620,11 +632,6 @@ inline bool Workspace::wasUserInteraction() const
return was_user_interaction;
}
inline void Workspace::sessionSaveStarted()
{
session_saving = true;
}
inline bool Workspace::sessionSaving() const
{
return session_saving;

View file

@ -383,7 +383,7 @@ void KonqOperations::asyncDrop( const KFileItem & destItem )
{
QString error;
const QStringList urlStrList = m_info->urls.toStringList();
if ( KToolInvocation::startServiceByDesktopPath( m_destUrl.path(), urlStrList, &error ) > 0 )
if ( KToolInvocation::self()->startServiceByDesktopPath( m_destUrl.path(), urlStrList, &error ) > 0 )
KMessageBox::error( parentWidget(), error );
}
else

View file

@ -1806,7 +1806,7 @@ KBookmarkManager* LauncherApplet::bookmarkManager() const
void LauncherApplet::slotEditMenu()
{
if (KToolInvocation::kdeinitExec("kmenuedit") == 0) {
if (KToolInvocation::self()->kdeinitExec("kmenuedit") == 0) {
hidePopup();
} else {
showMessage(KIcon("dialog-error"), i18n("Failed to launch menu editor"), Plasma::MessageButton::ButtonOk);

View file

@ -108,7 +108,7 @@ void BookmarksRunner::run(const Plasma::QueryMatch &action)
const QString term = action.data().toString();
// transforms URLs like "kde.org" to "http://kde.org"
const KUrl url = KUrl::fromUserInput(term);
KToolInvocation::invokeBrowser(url.url());
KToolInvocation::self()->invokeBrowser(url.url());
}
QMimeData* BookmarksRunner::mimeDataForMatch(const Plasma::QueryMatch &match)

View file

@ -64,7 +64,7 @@ void ShellRunner::run(const Plasma::QueryMatch &match)
}
const QString command = match.data().toString();
if (interminal) {
KToolInvocation::invokeTerminal(command);
KToolInvocation::self()->invokeTerminal(command);
} else {
KRun::runCommand(command, nullptr);
}

View file

@ -233,7 +233,7 @@ void SolidRunner::run(const Plasma::QueryMatch &match)
return;
}
const QString actionexe = actioncommand.takeFirst();
const int actionresult = KToolInvocation::kdeinitExec(actionexe, actioncommand);
const int actionresult = KToolInvocation::self()->kdeinitExec(actionexe, actioncommand);
if (actionresult != 0) {
kWarning() << "could not execute action for" << actionname << "in" << actionfilepath << actionresult;
}

View file

@ -106,7 +106,7 @@ void WebshortcutRunner::run(const Plasma::QueryMatch &match)
// kDebug() << location;
if (!location.isEmpty()) {
KToolInvocation::invokeBrowser(location);
KToolInvocation::self()->invokeBrowser(location);
}
}

View file

@ -21,6 +21,9 @@ set(plasma_SRCS
set(plasmaapp_dbusXML dbus/org.kde.plasma.App.xml)
qt4_add_dbus_adaptor(plasma_SRCS ${plasmaapp_dbusXML} plasmaapp.h PlasmaApp)
set(kapplication_xml ${KDE4_DBUS_INTERFACES_INSTALL_DIR}/org.kde.KApplication.xml)
qt4_add_dbus_interface(plasma_SRCS ${kapplication_xml} kapplication_interface)
add_executable(plasma-desktop ${plasma_SRCS})
target_link_libraries(plasma-desktop

View file

@ -1,8 +1,6 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="local.PlasmaApp">
<method name="quit">
</method>
<method name="createWaitingPanels">
</method>
<method name="createWaitingDesktops">
@ -10,16 +8,27 @@
<method name="supportInformation">
<arg type="s" direction="out"/>
</method>
<method name="saveClients">
</method>
<method name="restoreClients">
</method>
<method name="registerClient">
<arg name="client" type="s" direction="in"/>
</method>
<method name="unregisterClient">
<arg name="client" type="s" direction="in"/>
</method>
<method name="suspendStartup">
<arg type="s" direction="in"/>
<arg name="app" type="s" direction="in"/>
</method>
<method name="resumeStartup">
<arg type="s" direction="in"/>
<arg name="app" type="s" direction="in"/>
</method>
<method name="logout">
<arg type="i" direction="in"/>
<arg type="i" direction="in"/>
<arg name="confirm" type="i" direction="in"/>
<arg name="sdtype" type="i" direction="in"/>
</method>
<method name="wmChanged">
</method>
<method name="wmChanged"/>
</interface>
</node>

View file

@ -44,11 +44,13 @@ int main(int argc, char **argv)
ki18n("In memory of his contributions, 1937-1998."),
0, "http://en.wikipedia.org/wiki/John_Lions");
// plasma-desktop is the session manager
::unsetenv("SESSION_MANAGER");
KCmdLineArgs::init(argc, argv, &aboutData);
PlasmaApp *app = PlasmaApp::self();
QApplication::setWindowIcon(KIcon("plasma"));
app->disableSessionManagement(); // autostarted
int rc = app->exec();
delete app;

View file

@ -27,6 +27,7 @@
#include <QTimer>
#include <QVBoxLayout>
#include <QTextStream>
#include <QFileInfo>
#include <KAction>
#include <KCrash>
@ -69,6 +70,8 @@
#include <X11/Xutil.h>
#endif
static const int s_phasedelay = 1000; // ms
static const int s_sessiondelay = 500; // ms
static const QString s_defaultwm = QString::fromLatin1("kwin");
static const QStringList s_defaultwmcommands = QStringList() << s_defaultwm;
@ -114,7 +117,9 @@ PlasmaApp::PlasmaApp()
m_wmproc(nullptr),
m_startupsuspend(0),
m_dialogActive(false),
m_sdtype(KWorkSpace::ShutdownTypeNone)
m_sdtype(KWorkSpace::ShutdownTypeNone),
m_waitingcount(0),
m_sessionManager(false)
{
kDebug() << "!!{} STARTUP TIME" << QTime().msecsTo(QTime::currentTime()) << "plasma app ctor start" << "(line:" << __LINE__ << ")";
@ -175,9 +180,6 @@ PlasmaApp::PlasmaApp()
QDBusConnection::sessionBus(),
this
);
// TODO: m_klauncher->call("setLaunchEnv", "SESSION_MANAGER", "TODO");
m_kcminit = new QDBusInterface(
QLatin1String("org.kde.kcminit"),
QLatin1String("/kcminit"),
@ -185,11 +187,15 @@ PlasmaApp::PlasmaApp()
QDBusConnection::sessionBus(),
this
);
const bool failsafe = (qgetenv("KDE_FAILSAFE").toInt() == 1);
if (!failsafe) {
m_sessionManager = true;
}
KGlobal::dirs()->addResourceType("windowmanagers", "data", "plasma/windowmanagers");
QStringList wmcommands;
if (qgetenv("KDE_FAILSAFE").toInt() != 1) {
if (!failsafe) {
KConfig cfg("plasmarc", KConfig::NoGlobals);
KConfigGroup config(&cfg, "General");
const QString wmname = config.readEntry("windowManager", s_defaultwm);
@ -203,12 +209,28 @@ PlasmaApp::PlasmaApp()
if (wmcommands.isEmpty()) {
wmcommands = s_defaultwmcommands;
}
const QString wmprog = wmcommands.takeFirst();
QString wmprog = wmcommands.takeFirst();
KConfigGroup sessiongroup(KGlobal::config(), "Session");
foreach (const QString &group, sessiongroup.groupList()) {
KConfigGroup clientgroup(&sessiongroup, group);
QStringList restartcommand = clientgroup.readEntry("restartCommand", QStringList());
if (restartcommand.size() < 1) {
kWarning() << "invalid restart command" << group;
continue;
}
QString program = restartcommand.takeFirst();
if (program == wmprog || QFileInfo(program).fileName() == QFileInfo(wmprog).fileName()) {
wmprog = program;
wmcommands = restartcommand;
kDebug() << "using session WM entry" << wmprog << wmcommands;
clientgroup.deleteGroup();
clientgroup.sync();
}
}
m_wmproc = new QProcess(this);
m_wmproc->start(wmprog, wmcommands);
m_wmproc->waitForStarted(4000);
QTimer::singleShot(100, this, SLOT(nextPhase()));
QTimer::singleShot(s_phasedelay, this, SLOT(nextPhase()));
}
PlasmaApp::~PlasmaApp()
@ -954,6 +976,110 @@ QString PlasmaApp::supportInformation() const
return streambuffer;
}
void PlasmaApp::saveClients()
{
if (!m_sessionManager || m_clients.size() < 1) {
doLogout();
return;
}
kDebug() << "initiating session save" << m_clients.size();
m_waitingcount = 0;
QMapIterator<QString,org::kde::KApplication*> iter(m_clients);
iter.toBack();
// window manager should be last to save its state first to restore so iteration is done
// backwards
while (iter.hasPrevious()) {
iter.previous();
kDebug() << "calling saveSession() for" << iter.key();
org::kde::KApplication* clientinterface = iter.value();
clientinterface->asyncCall("saveSession");
}
}
void PlasmaApp::restoreClients()
{
kDebug() << "restoring session";
KConfigGroup sessiongroup(KGlobal::config(), "Session");
foreach (const QString &group, sessiongroup.groupList()) {
KConfigGroup clientgroup(&sessiongroup, group);
QStringList restartcommand = clientgroup.readEntry("restartCommand", QStringList());
if (restartcommand.size() < 1) {
kWarning() << "invalid restart command" << group;
continue;
}
QString program = restartcommand.takeFirst();
kDebug() << "restoring client" << program << restartcommand;
KToolInvocation::self()->kdeinitExec(program, restartcommand);
}
sessiongroup.deleteGroup();
sessiongroup.sync();
}
void PlasmaApp::registerClient(const QString &client)
{
kDebug() << "adding session manager client" << client;
org::kde::KApplication* clientinterface = new org::kde::KApplication(
client, "/MainApplication",
QDBusConnection::sessionBus(),
this
);
connect(
clientinterface, SIGNAL(sessionSaved()),
this, SLOT(clientSaved())
);
connect(
clientinterface, SIGNAL(sessionSaveCanceled()),
this, SLOT(clientSaveCanceled())
);
m_clients.insert(client, clientinterface);
}
void PlasmaApp::unregisterClient(const QString &client)
{
if (!m_clients.contains(client)) {
return;
}
kDebug() << "removing session manager client" << client;
org::kde::KApplication* clientinterface = m_clients.take(client);
delete clientinterface;
}
void PlasmaApp::clientSaved()
{
kDebug() << "client saved its session";
m_waitingcount++;
if (m_waitingcount >= m_clients.size()) {
kDebug() << "saving session";
KConfigGroup sessiongroup(KGlobal::config(), "Session");
int clientcounter = 0;
QMapIterator<QString,org::kde::KApplication*> iter(m_clients);
while (iter.hasNext()) {
iter.next();
kDebug() << "getting restart command for" << iter.key();
org::kde::KApplication* clientinterface = iter.value();
const QStringList restartcommand = clientinterface->restartCommand();
if (restartcommand.isEmpty()) {
kDebug() << "not saving client state due to empty command";
continue;
}
kDebug() << "saving client state" << iter.key();
KConfigGroup clientgroup(&sessiongroup, QString::number(clientcounter));
clientgroup.writeEntry("restartCommand", restartcommand);
clientgroup.sync();
clientcounter++;
}
sessiongroup.sync();
kDebug() << "saving session done";
doLogout();
}
}
void PlasmaApp::clientSaveCanceled()
{
kDebug() << "client canceled session save";
m_waitingcount++;
}
void PlasmaApp::suspendStartup(const QString &app)
{
// TODO: timeout for suspending
@ -970,9 +1096,10 @@ void PlasmaApp::resumeStartup(const QString &app)
void PlasmaApp::logout(int confirm, int sdtype)
{
// TODO: prevent logout while initializing
kDebug() << "logout" << confirm << sdtype;
m_sdtype = static_cast<KWorkSpace::ShutdownType>(sdtype);
if (confirm == KWorkSpace::ShutdownConfirmNo) {
QTimer::singleShot(500, this, SLOT(doLogout()));
QTimer::singleShot(s_sessiondelay, this, SLOT(saveClients()));
return;
}
if (m_dialogActive) {
@ -984,7 +1111,7 @@ void PlasmaApp::logout(int confirm, int sdtype)
const bool choose = (m_sdtype == KWorkSpace::ShutdownTypeDefault);
const bool logoutConfirmed = KSMShutdownDlg::confirmShutdown(maysd, choose, m_sdtype);
if (logoutConfirmed) {
QTimer::singleShot(500, this, SLOT(doLogout()));
QTimer::singleShot(s_sessiondelay, this, SLOT(saveClients()));
}
m_dialogActive = false;
}
@ -996,28 +1123,36 @@ void PlasmaApp::wmChanged()
void PlasmaApp::captureDesktop()
{
KToolInvocation::kdeinitExec("ksnapshot", QStringList() << "--fullscreen");
KToolInvocation::self()->kdeinitExec("ksnapshot", QStringList() << "--fullscreen");
}
void PlasmaApp::captureCurrentWindow()
{
KToolInvocation::kdeinitExec("ksnapshot", QStringList() << "--current");
KToolInvocation::self()->kdeinitExec("ksnapshot", QStringList() << "--current");
}
void PlasmaApp::cleanup()
{
if (m_klauncher) {
m_klauncher->call("cleanup");
m_klauncher->deleteLater();
QDBusPendingReply<void> reply = m_klauncher->asyncCall("cleanup");
kDebug() << "Waiting for klauncher cleanup to finish";
while (!reply.isFinished()) {
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}
delete m_klauncher;
m_klauncher = nullptr;
}
if (m_wmproc) {
m_wmproc->kill();
m_wmproc->waitForFinished();
m_wmproc->deleteLater();
delete m_wmproc;
m_wmproc = nullptr;
}
foreach (const QString &client, m_clients.keys()) {
unregisterClient(client);
}
}
void PlasmaApp::nextPhase()
@ -1031,23 +1166,30 @@ void PlasmaApp::nextPhase()
if (!sessionInterface->isServiceRegistered(kdedInterface)) {
sessionInterface->startService(kdedInterface);
}
m_klauncher->call("autoStart", int(0));
m_kcminit->call("runPhase1");
m_klauncher->asyncCall("autoStart", int(0));
m_kcminit->asyncCall("runPhase1");
QTimer::singleShot(s_phasedelay, this, SLOT(nextPhase()));
break;
}
case 1: {
m_klauncher->call("autoStart", int(1));
m_kcminit->call("runPhase2");
m_klauncher->asyncCall("autoStart", int(1));
m_kcminit->asyncCall("runPhase2");
QTimer::singleShot(s_phasedelay, this, SLOT(nextPhase()));
break;
}
case 2: {
m_klauncher->call("autoStart", int(2));
m_klauncher->asyncCall("autoStart", int(2));
if (m_sessionManager) {
restoreClients();
}
kDebug() << "startup done";
return;
}
}
m_phase++;
}
} else {
QTimer::singleShot(100, this, SLOT(nextPhase()));
}
}
void PlasmaApp::defaultLogout()

View file

@ -38,6 +38,7 @@
#include "desktoptracker.h"
#include "kworkspace/kworkspace.h"
#include "kapplication_interface.h"
namespace Plasma
{
@ -98,6 +99,10 @@ public Q_SLOTS:
QString supportInformation() const;
void saveClients();
void restoreClients();
void registerClient(const QString &client);
void unregisterClient(const QString &client);
void suspendStartup(const QString &app);
void resumeStartup(const QString &app);
void logout(int confirm, int sdtype);
@ -138,6 +143,9 @@ private Q_SLOTS:
void haltWithoutConfirmation();
void rebootWithoutConfirmation();
void doLogout();
private Q_SLOTS:
void clientSaved();
void clientSaveCanceled();
private:
DesktopCorona *m_corona;
@ -161,6 +169,9 @@ private:
int m_startupsuspend;
bool m_dialogActive;
KWorkSpace::ShutdownType m_sdtype;
bool m_sessionManager;
int m_waitingcount;
QMap<QString,org::kde::KApplication*> m_clients;
};
#endif // multiple inclusion guard

View file

@ -111,7 +111,7 @@ static void kExecuteAction(const KServiceAction &kserviceaction, const Solid::De
return;
}
const QString actionexe = actioncommand.takeFirst();
const int actionresult = KToolInvocation::kdeinitExec(actionexe, actioncommand);
const int actionresult = KToolInvocation::self()->kdeinitExec(actionexe, actioncommand);
if (actionresult != 0) {
kWarning() << "could not execute action for" << kserviceaction.name() << actionresult;
}

View file

@ -314,7 +314,7 @@ void ModuleView::moduleHelp()
}
QString moduleService = activeModule->fileName().replace(QLatin1String(".desktop"), QString());
KToolInvocation::invokeHelp(QString(), moduleService);
KToolInvocation::self()->invokeHelp(QString(), moduleService);
}
void ModuleView::activeModuleChanged(KPageWidgetItem * current, KPageWidgetItem * previous)