Commit 248dadf4 authored by David Edmundson's avatar David Edmundson

[ksmserver] Split startup into separate class

Summary:
Everything related to Plasma startup goes in Startup everything relating
to X session management stays in KSMServer.  Restoring the window
manager currently stays inside ksmserver as it passes the session ID as
an argument and at various points checks if something the client is the
WM.
Relevant methods move to server.cpp to keep one class per cpp file.

KSMServer gains some signals as it can no longer call the startup methods
directly to continue the process.

This is part of a cleanup series in ksmserver. (The friend class will disappear
in the next commit)

Behaviour should remain identical.

Test Plan: Logged in on X

Reviewers: #plasma, graesslin

Reviewed By: #plasma, graesslin

Subscribers: plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D16225
parent 68538b6d
......@@ -41,6 +41,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <kwindowsystem.h>
#include <ksmserver_debug.h>
#include "server.h"
#include "startup.h"
#include <QX11Info>
#include <QApplication>
......@@ -311,6 +312,7 @@ extern "C" Q_DECL_EXPORT int kdemain( int argc, char* argv[] )
}
KSMServer *server = new KSMServer( wm, flags);
auto startup = new Startup(server);
// for the KDE-already-running check in startkde
KSelectionOwner kde_running( "_KDE_RUNNING", 0 );
......@@ -336,6 +338,7 @@ extern "C" Q_DECL_EXPORT int kdemain( int argc, char* argv[] )
server->restoreSession( QStringLiteral( SESSION_BY_USER ) );
else
server->startDefaultSession();
startup->upAndRunning(QStringLiteral( "ksmserver" ));
KDBusService service(KDBusService::Unique);
......
......@@ -617,7 +617,6 @@ KSMServer::KSMServer( const QString& windowManager, InitFlags flags )
new KSMServerInterfaceAdaptor( this );
QDBusConnection::sessionBus().registerObject(QStringLiteral("/KSMServer"), this);
kcminitSignals = nullptr;
the_server = this;
clean = false;
......@@ -1068,6 +1067,182 @@ void KSMServer::setupShortcuts()
}
}
/*! Restores the previous session. Ensures the window manager is
running (if specified).
*/
void KSMServer::restoreSession( const QString &sessionName )
{
if( state != Idle )
return;
#ifdef KSMSERVER_STARTUP_DEBUG1
t.start();
#endif
state = LaunchingWM;
qCDebug(KSMSERVER) << "KSMServer::restoreSession " << sessionName;
KSharedConfig::Ptr config = KSharedConfig::openConfig();
sessionGroup = QStringLiteral("Session: ") + sessionName;
KConfigGroup configSessionGroup( config, sessionGroup);
int count = configSessionGroup.readEntry( "count", 0 );
appsToStart = count;
// find all commands to launch the wm in the session
QList<QStringList> wmStartCommands;
if ( !wm.isEmpty() ) {
for ( int i = 1; i <= count; i++ ) {
QString n = QString::number(i);
if ( isWM( configSessionGroup.readEntry( QStringLiteral("program")+n, QString())) ) {
wmStartCommands << configSessionGroup.readEntry( QStringLiteral("restartCommand")+n, QStringList() );
}
}
}
if( wmStartCommands.isEmpty()) // otherwise use the configured default
wmStartCommands << wmCommands;
launchWM( wmStartCommands );
}
void KSMServer::launchWM( const QList< QStringList >& wmStartCommands )
{
assert( state == LaunchingWM );
if (!(qEnvironmentVariableIsSet("WAYLAND_DISPLAY") || qEnvironmentVariableIsSet("WAYLAND_SOCKET"))) {
// when we have a window manager, we start it first and give
// it some time before launching other processes. Results in a
// visually more appealing startup.
wmProcess = startApplication( wmStartCommands[ 0 ], QString(), QString(), true );
connect( wmProcess, SIGNAL(error(QProcess::ProcessError)), SLOT(wmProcessChange()));
connect( wmProcess, SIGNAL(finished(int,QProcess::ExitStatus)), SLOT(wmProcessChange()));
}
emit windowManagerLoaded();
}
void KSMServer::wmProcessChange()
{
if( state != LaunchingWM )
{ // don't care about the process when not in the wm-launching state anymore
wmProcess = nullptr;
return;
}
if( wmProcess->state() == QProcess::NotRunning )
{ // wm failed to launch for some reason, go with kwin instead
qCWarning(KSMSERVER) << "Window manager" << wm << "failed to launch";
if( wm == QStringLiteral( KWIN_BIN ) )
return; // uhoh, kwin itself failed
qCDebug(KSMSERVER) << "Launching KWin";
wm = QStringLiteral( KWIN_BIN );
wmCommands = ( QStringList() << QStringLiteral( KWIN_BIN ) );
// launch it
launchWM( QList< QStringList >() << wmCommands );
return;
}
}
/*!
Starts the default session.
Currently, that's the window manager only (if specified).
*/
void KSMServer::startDefaultSession()
{
if( state != Idle )
return;
state = LaunchingWM;
#ifdef KSMSERVER_STARTUP_DEBUG1
t.start();
#endif
sessionGroup = QString();
launchWM( QList< QStringList >() << wmCommands );
}
void KSMServer::restoreSubSession( const QString& name )
{
sessionGroup = QStringLiteral( "SubSession: " ) + name;
KConfigGroup configSessionGroup( KSharedConfig::openConfig(), sessionGroup);
int count = configSessionGroup.readEntry( "count", 0 );
appsToStart = count;
lastAppStarted = 0;
lastIdStarted.clear();
state = RestoringSubSession;
tryRestoreNext();
}
void KSMServer::clientSetProgram( KSMClient* client )
{
if( client->program() == wm ) {
emit windowManagerLoaded();
}
}
void KSMServer::clientRegistered( const char* previousId )
{
if ( previousId && lastIdStarted == QString::fromLocal8Bit( previousId ) )
tryRestoreNext();
}
void KSMServer::tryRestoreNext()
{
if( state != Restoring && state != RestoringSubSession )
return;
restoreTimer.stop();
KConfigGroup config(KSharedConfig::openConfig(), sessionGroup );
while ( lastAppStarted < appsToStart ) {
lastAppStarted++;
QString n = QString::number(lastAppStarted);
QString clientId = config.readEntry( QStringLiteral("clientId")+n, QString() );
bool alreadyStarted = false;
foreach ( KSMClient *c, clients ) {
if ( QString::fromLocal8Bit( c->clientId() ) == clientId ) {
alreadyStarted = true;
break;
}
}
if ( alreadyStarted )
continue;
QStringList restartCommand = config.readEntry( QStringLiteral("restartCommand")+n, QStringList() );
if ( restartCommand.isEmpty() ||
(config.readEntry( QStringLiteral("restartStyleHint")+n, 0 ) == SmRestartNever)) {
continue;
}
if ( isWM( config.readEntry( QStringLiteral("program")+n, QString())) )
continue; // wm already started
if( config.readEntry( QStringLiteral( "wasWm" )+n, false ))
continue; // it was wm before, but not now, don't run it (some have --replace in command :( )
startApplication( restartCommand,
config.readEntry( QStringLiteral("clientMachine")+n, QString() ),
config.readEntry( QStringLiteral("userId")+n, QString() ));
lastIdStarted = clientId;
if ( !lastIdStarted.isEmpty() ) {
restoreTimer.setSingleShot( true );
restoreTimer.start( 2000 );
return; // we get called again from the clientRegistered handler
}
}
//all done
appsToStart = 0;
lastIdStarted.clear();
if (state == Restoring) {
emit sessionRestored();
} else { //subsession
emit subSessionOpened();
}
state = Idle;
}
void KSMServer::startupDone()
{
state = Idle;
}
void KSMServer::defaultLogout()
{
shutdown(KWorkSpace::ShutdownConfirmYes, KWorkSpace::ShutdownTypeDefault, KWorkSpace::ShutdownModeDefault);
......
......@@ -51,8 +51,6 @@ extern "C" {
#include <QTime>
#include <QMap>
#include "autostart.h"
#define SESSION_PREVIOUS_LOGOUT "saved at previous logout"
#define SESSION_BY_USER "saved by user"
......@@ -117,7 +115,8 @@ public:
KWorkSpace::ShutdownType sdtype,
KWorkSpace::ShutdownMode sdmode );
void launchWM( const QList< QStringList >& wmStartCommands );
Q_SIGNALS:
void windowManagerLoaded();
public Q_SLOTS:
void cleanUp();
......@@ -129,26 +128,14 @@ private Q_SLOTS:
void protectionTimeout();
void timeoutQuit();
void timeoutWMQuit();
void kcmPhase1Timeout();
void kcmPhase2Timeout();
void pendingShutdownTimeout();
void autoStart0();
void autoStart1();
void autoStart2();
void tryRestoreNext();
void pendingShutdownTimeout();
void wmProcessChange();
void autoStart0Done();
void autoStart1Done();
void autoStart2Done();
void kcmPhase1Done();
void kcmPhase2Done();
void defaultLogout();
void logoutWithoutConfirmation();
void haltWithoutConfirmation();
void rebootWithoutConfirmation();
void secondKDEDPhaseLoaded();
private:
void handlePendingInteractions();
......@@ -165,15 +152,14 @@ private:
void killingCompleted();
void createLogoutEffectWidget();
void runUserAutostart();
bool migrateKDE4Autostart(const QString &autostartFolder);
void discardSession();
void storeSession();
void startProtection();
void endProtection();
void launchWM( const QList< QStringList >& wmStartCommands );
KProcess* startApplication( const QStringList& command,
const QString& clientMachine = QString(),
const QString& userId = QString(),
......@@ -195,8 +181,9 @@ private:
WId windowWmClientLeader(WId w);
QByteArray windowSessionId(WId w, WId leader);
void finishStartup();
void setupShortcuts();
void tryRestoreNext();
void startupDone();
void runShutdownScripts();
......@@ -223,18 +210,16 @@ private:
void subSessionClosed();
void subSessionCloseCanceled();
void subSessionOpened();
void sessionRestored();
private:
QList<KSMListener*> listener;
QList<KSMClient*> clients;
void autoStart(int phase);
void slotAutoStart();
enum State
{
Idle,
LaunchingWM, AutoStart0, KcmInitPhase1, AutoStart1, Restoring, FinishingStartup, // startup
LaunchingWM, Restoring,
Shutdown, Checkpoint, Killing, KillingWM, WaitingForKNotify, // shutdown
ClosingSubSession, KillingSubSession, RestoringSubSession
};
......@@ -257,17 +242,12 @@ private:
QTimer protectionTimer;
QTimer restoreTimer;
QString xonCommand;
bool waitAutoStart2;
bool waitKcmInit2;
QTimer pendingShutdown;
QWidget* logoutEffectWidget;
KWorkSpace::ShutdownConfirm pendingShutdown_confirm;
KWorkSpace::ShutdownType pendingShutdown_sdtype;
KWorkSpace::ShutdownMode pendingShutdown_sdmode;
// ksplash interface
void upAndRunning( const QString& msg );
// sequential startup
int appsToStart;
int lastAppStarted;
......@@ -277,17 +257,17 @@ private:
WindowMap legacyWindows;
QDBusInterface* kcminitSignals;
int inhibitCookie;
AutoStart m_autoStart;
//subSession stuff
QList<KSMClient*> clientsToKill;
QList<KSMClient*> clientsToSave;
int sockets[2];
friend bool readFromPipe(int pipe);
friend class Startup;
};
#endif
This diff is collapsed.
#pragma once
#include <QObject>
#include <QDBusInterface>
#include "autostart.h"
class KProcess;
class KSMServer;
class Startup : public QObject
{
public:
Startup(KSMServer *parent);
void upAndRunning( const QString& msg );
private Q_SLOTS:
void runUserAutostart();
bool migrateKDE4Autostart(const QString &autostartFolder);
void autoStart0();
void autoStart1();
void autoStart2();
void autoStart0Done();
void autoStart1Done();
void autoStart2Done();
void kcmPhase1Done();
void kcmPhase2Done();
// ksplash interface
void finishStartup();
void slotAutoStart();
void secondKDEDPhaseLoaded();
void kcmPhase1Timeout();
void kcmPhase2Timeout();
private:
void autoStart(int phase);
private:
AutoStart m_autoStart;
KSMServer *ksmserver = nullptr;
enum State
{
Waiting, AutoStart0, KcmInitPhase1, AutoStart1, FinishingStartup, // startup
};
State state;
bool waitAutoStart2 = true;
bool waitKcmInit2 = true;
QDBusInterface* kcminitSignals = nullptr;
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment