core.cpp 15.2 KB
Newer Older
1
/***************************************************************************
2 3
 *   Copyright 2007 Alexander Dymo <adymo@kdevelop.org>             *
 *   Copyright 2007 Kris Wong <kris.p.wong@gmail.com>               *
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/
#include "core.h"
Amilcar do Carmo Lucas's avatar
Amilcar do Carmo Lucas committed
21
#include "core_p.h"
22

23
#include <QApplication>
24

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
25
#include <KLocalizedString>
26

27
#include <language/backgroundparser/backgroundparser.h>
28
#include <language/duchain/duchain.h>
29

30
#include "mainwindow.h"
31
#include "sessioncontroller.h"
32 33 34 35 36 37
#include "uicontroller.h"
#include "plugincontroller.h"
#include "projectcontroller.h"
#include "partcontroller.h"
#include "languagecontroller.h"
#include "documentcontroller.h"
38
#include "runcontroller.h"
39
#include "session.h"
40
#include "documentationcontroller.h"
41
#include "sourceformattercontroller.h"
42
#include "progresswidget/progressmanager.h"
43
#include "selectioncontroller.h"
44
#include "debugcontroller.h"
45
#include "kdevplatform_version.h"
46
#include "workingsetcontroller.h"
47
#include "testcontroller.h"
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
48
#include "runtimecontroller.h"
Dāvis Mosāns's avatar
Dāvis Mosāns committed
49
#include "debug.h"
50

51 52
#include <csignal>

53
namespace {
54 55
void shutdownGracefully(int sig)
{
56 57
    static volatile std::sig_atomic_t handlingSignal = 0;

58 59
    if ( !handlingSignal ) {
        handlingSignal = 1;
Dāvis Mosāns's avatar
Dāvis Mosāns committed
60
        qCDebug(SHELL) << "signal " << sig << " received, shutting down gracefully";
61
        QCoreApplication* app = QCoreApplication::instance();
62
        if (auto* guiApp = qobject_cast<QApplication*>(app)) {
63 64 65 66
            guiApp->closeAllWindows();
        }
        app->quit();
        return;
67
    }
68 69 70 71

    // re-raise signal with default handler and trigger program termination
    std::signal(sig, SIG_DFL);
    std::raise(sig);
72 73 74 75 76 77 78 79 80 81 82 83 84 85
}

void installSignalHandler()
{
#ifdef SIGHUP
    std::signal(SIGHUP, shutdownGracefully);
#endif
#ifdef SIGINT
    std::signal(SIGINT, shutdownGracefully);
#endif
#ifdef SIGTERM
    std::signal(SIGTERM, shutdownGracefully);
#endif
}
86
}
87

88 89
namespace KDevelop {

90
Core *Core::m_self = nullptr;
91

92 93 94 95
CorePrivate::CorePrivate(Core *core)
    : m_core(core)
    , m_cleanedUp(false)
    , m_shuttingDown(false)
96 97
{
}
98

99
bool CorePrivate::initialize(Core::Setup mode, const QString& session )
100 101
{
    m_mode=mode;
102 103 104

    qCDebug(SHELL) << "Creating controllers";

105
    if( !sessionController )
106
    {
107
        sessionController = new SessionController(m_core);
108
    }
109
    if( !workingSetController && !(mode & Core::NoUi) )
110
    {
111
        workingSetController = new WorkingSetController();
112
    }
Dāvis Mosāns's avatar
Dāvis Mosāns committed
113
    qCDebug(SHELL) << "Creating ui controller";
114
    if( !uiController )
115
    {
116
        uiController = new UiController(m_core);
117
    }
Dāvis Mosāns's avatar
Dāvis Mosāns committed
118
    qCDebug(SHELL) << "Creating plugin controller";
119 120 121

    if( !pluginController )
    {
122
        pluginController = new PluginController(m_core);
123 124 125 126 127 128
        const auto pluginInfos = pluginController->allPluginInfos();
        if (pluginInfos.isEmpty()) {
            QMessageBox::critical(nullptr,
                                  i18n("Could not find any plugins"),
                                  i18n("<p>Could not find any plugins during startup.<br/>"
                                  "Please make sure QT_PLUGIN_PATH is set correctly.</p>"
129
                                  "Refer to <a href=\"https://community.kde.org/Guidelines_and_HOWTOs/Build_from_source#Set_up_the_runtime_environment\">this article</a> for more information."),
130
                                  QMessageBox::Abort, QMessageBox::Abort);
Kevin Funk's avatar
Kevin Funk committed
131
            qCWarning(SHELL) << "Could not find any plugins, aborting";
132 133
            return false;
        }
134
    }
135 136
    if( !partController && !(mode & Core::NoUi))
    {
137
        partController = new PartController(m_core, uiController->defaultMainWindow());
138
    }
139 140 141

    if( !projectController )
    {
142
        projectController = new ProjectController(m_core);
143 144
    }

145
    if( !documentController )
146
    {
147
        documentController = new DocumentController(m_core);
148 149
    }

150
    if( !languageController )
151
    {
152 153 154
        // Must be initialized after documentController, because the background parser depends
        // on the document controller.
        languageController = new LanguageController(m_core);
155
    }
156

157 158 159
    if( !runController )
    {
        runController = new RunController(m_core);
160
    }
161

162
    if( !sourceFormatterController )
163 164
    {
        sourceFormatterController = new SourceFormatterController(m_core);
165
    }
166

Dāvis Mosāns's avatar
Dāvis Mosāns committed
167
    if ( !progressController)
168
    {
169
        progressController = ProgressManager::instance();
170 171
    }

172 173 174 175
    if( !selectionController )
    {
        selectionController = new SelectionController(m_core);
    }
176

177
    if( !documentationController && !(mode & Core::NoUi) )
178 179 180
    {
        documentationController = new DocumentationController(m_core);
    }
181

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
182 183 184 185 186
    if( !runtimeController )
    {
        runtimeController = new RuntimeController(m_core);
    }

187 188 189 190
    if( !debugController )
    {
        debugController = new DebugController(m_core);
    }
191 192 193 194 195 196

    if( !testController )
    {
        testController = new TestController(m_core);
    }

197 198 199
    qCDebug(SHELL) << "Done creating controllers";

    qCDebug(SHELL) << "Initializing controllers";
200

201 202
    sessionController->initialize( session );
    if( !sessionController->activeSessionLock() ) {
203 204
        return false;
    }
205

206 207
    // TODO: Is this early enough, or should we put the loading of the session into
    // the controller construct
208
    DUChain::initialize();
209

Kevin Funk's avatar
Kevin Funk committed
210
    if (!(mode & Core::NoUi)) {
211
        uiController->initialize();
Kevin Funk's avatar
Kevin Funk committed
212
    }
213
    languageController->initialize();
214 215 216 217 218 219
    languageController->backgroundParser()->suspend();
    // eventually resume the background parser once the project controller
    // has been initialized. At that point we know whether there are projects loading
    // which the background parser is handling internally to defer parse jobs
    QObject::connect(projectController.data(), &ProjectController::initialized,
                     m_core, [this]() {
220
                         languageController->backgroundParser()->resume();
221 222
                     });

Kevin Funk's avatar
Kevin Funk committed
223
    if (partController) {
224
        partController->initialize();
Kevin Funk's avatar
Kevin Funk committed
225
    }
226 227
    projectController->initialize();
    documentController->initialize();
228 229 230 231 232 233 234 235 236 237

    /* This is somewhat messy.  We want to load the areas before
        loading the plugins, so that when each plugin is loaded we
        know if an area wants some of the tool view from that plugin.
        OTOH, loading of areas creates documents, and some documents
        might require that a plugin is already loaded.
        Probably, the best approach would be to plugins to just add
        tool views to a list of available tool view, and then grab
        those tool views when loading an area.  */

238
    qCDebug(SHELL) << "Initializing plugin controller (loading session plugins)";
239
    pluginController->initialize();
240

241
    qCDebug(SHELL) << "Initializing working set controller";
242
    if(!(mode & Core::NoUi))
243
    {
244
        workingSetController->initialize();
245 246 247
        /* Need to do this after everything else is loaded.  It's too
            hard to restore position of views, and toolbars, and whatever
            that are not created yet.  */
248 249
        uiController->loadAllAreas(KSharedConfig::openConfig());
        uiController->defaultMainWindow()->show();
250
    }
251 252

    qCDebug(SHELL) << "Initializing remaining controllers";
253 254 255
    runController->initialize();
    sourceFormatterController->initialize();
    selectionController->initialize();
256
    if (documentationController) {
257
        documentationController->initialize();
258
    }
259 260 261
    debugController->initialize();
    testController->initialize();
    runtimeController->initialize();
262 263 264

    installSignalHandler();

265 266
    qCDebug(SHELL) << "Done initializing controllers";

267
    return true;
268 269 270
}
CorePrivate::~CorePrivate()
{
271 272 273 274 275 276 277 278 279 280 281 282 283
    delete selectionController.data();
    delete projectController.data();
    delete languageController.data();
    delete pluginController.data();
    delete uiController.data();
    delete partController.data();
    delete documentController.data();
    delete runController.data();
    delete sessionController.data();
    delete sourceFormatterController.data();
    delete documentationController.data();
    delete debugController.data();
    delete workingSetController.data();
284
    delete testController.data();
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
285
    delete runtimeController.data();
286 287 288 289 290 291 292 293 294 295 296 297 298 299

    selectionController.clear();
    projectController.clear();
    languageController.clear();
    pluginController.clear();
    uiController.clear();
    partController.clear();
    documentController.clear();
    runController.clear();
    sessionController.clear();
    sourceFormatterController.clear();
    documentationController.clear();
    debugController.clear();
    workingSetController.clear();
300
    testController.clear();
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
301
    runtimeController.clear();
302
}
303

304
bool Core::initialize(Setup mode, const QString& session)
305
{
306
    if (m_self)
307
        return true;
Kris Wong's avatar
Kris Wong committed
308

309
    m_self = new Core();
310
    bool ret = m_self->d->initialize(mode, session);
Dāvis Mosāns's avatar
Dāvis Mosāns committed
311

312 313
    if(ret)
        emit m_self->initializationCompleted();
Dāvis Mosāns's avatar
Dāvis Mosāns committed
314

315
    return ret;
316 317 318 319
}

Core *KDevelop::Core::self()
{
320
    return m_self;
321 322 323
}

Core::Core(QObject *parent)
Kris Wong's avatar
Kris Wong committed
324
    : ICore(parent)
325 326
{
    d = new CorePrivate(this);
327

328
    connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &Core::shutdown);
329 330
}

331 332 333
Core::Core(CorePrivate* dd, QObject* parent)
: ICore(parent), d(dd)
{
334
    connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &Core::shutdown);
335 336
}

337 338
Core::~Core()
{
Kevin Funk's avatar
Kevin Funk committed
339 340
    qCDebug(SHELL);

341
    //Cleanup already called before mass destruction of GUI
342
    delete d;
343
    m_self = nullptr;
344 345
}

346 347 348 349 350
Core::Setup Core::setupFlags() const
{
    return d->m_mode;
}

351 352
void Core::shutdown()
{
Kevin Funk's avatar
Kevin Funk committed
353 354
    qCDebug(SHELL);

355 356 357 358
    if (!d->m_shuttingDown) {
        cleanup();
        deleteLater();
    }
Kevin Funk's avatar
Kevin Funk committed
359 360

    qCDebug(SHELL) << "Shutdown done";
361 362
}

363 364 365 366 367
bool Core::shuttingDown() const
{
    return d->m_shuttingDown;
}

368 369
void Core::cleanup()
{
Kevin Funk's avatar
Kevin Funk committed
370 371
    qCDebug(SHELL);

372
    d->m_shuttingDown = true;
373 374
    emit aboutToShutdown();

375
    if (!d->m_cleanedUp) {
376
        // first of all: request stop of all background parser jobs
377 378 379
        d->languageController->backgroundParser()->abortAllJobs();
        d->languageController->backgroundParser()->suspend();

380 381
        d->debugController->cleanup();
        d->selectionController->cleanup();
382
        // Save the layout of the ui here, so run it first
383
        d->uiController->cleanup();
384 385

        if (d->workingSetController)
386
            d->workingSetController->cleanup();
387

388
        /* Must be called before projectController->cleanup(). */
389
        // Closes all documents (discards, as already saved if the user wished earlier)
390 391
        d->documentController->cleanup();
        d->runController->cleanup();
Kevin Funk's avatar
Kevin Funk committed
392 393 394
        if (d->partController) {
            d->partController->cleanup();
        }
395 396
        d->projectController->cleanup();
        d->sourceFormatterController->cleanup();
397 398 399

        // before unloading language plugins, we need to make sure all parse jobs are done
        d->languageController->backgroundParser()->waitForIdle();
400 401 402 403 404

        DUChain::self()->shutdown();

        // Only unload plugins after the DUChain shutdown to prevent issues with non-loaded factories for types
        // See: https://bugs.kde.org/show_bug.cgi?id=379669
405
        d->pluginController->cleanup();
406

407
        d->sessionController->cleanup();
408

409
        d->testController->cleanup();
410

411
        //Disable the functionality of the language controller
412
        d->languageController->cleanup();
413 414 415
    }

    d->m_cleanedUp = true;
416
    emit shutdownCompleted();
417 418 419 420
}

IUiController *Core::uiController()
{
421
    return d->uiController.data();
422 423
}

424 425 426 427 428
ISession* Core::activeSession()
{
    return sessionController()->activeSession();
}

429 430 431 432 433
ISessionLock::Ptr Core::activeSessionLock()
{
    return sessionController()->activeSessionLock();
}

434
SessionController *Core::sessionController()
435
{
436
    return d->sessionController.data();
437 438
}

Kris Wong's avatar
Kris Wong committed
439 440
UiController *Core::uiControllerInternal()
{
441
    return d->uiController.data();
Kris Wong's avatar
Kris Wong committed
442 443 444
}

IPluginController *Core::pluginController()
445
{
446
    return d->pluginController.data();
447 448
}

Kris Wong's avatar
Kris Wong committed
449 450
PluginController *Core::pluginControllerInternal()
{
451
    return d->pluginController.data();
Kris Wong's avatar
Kris Wong committed
452 453 454
}

IProjectController *Core::projectController()
455
{
456
    return d->projectController.data();
457 458
}

Kris Wong's avatar
Kris Wong committed
459
ProjectController *Core::projectControllerInternal()
460
{
461
    return d->projectController.data();
462 463
}

464
IPartController *Core::partController()
465
{
466
    return d->partController.data();
467 468
}

469
PartController *Core::partControllerInternal()
470
{
471
    return d->partController.data();
472 473 474 475
}

ILanguageController *Core::languageController()
{
476
    return d->languageController.data();
477 478
}

Kris Wong's avatar
Kris Wong committed
479
LanguageController *Core::languageControllerInternal()
480
{
481
    return d->languageController.data();
482 483
}

Kris Wong's avatar
Kris Wong committed
484
IDocumentController *Core::documentController()
485
{
486
    return d->documentController.data();
487 488
}

Kris Wong's avatar
Kris Wong committed
489
DocumentController *Core::documentControllerInternal()
490
{
491
    return d->documentController.data();
492 493
}

494 495
IRunController *Core::runController()
{
496
    return d->runController.data();
497 498
}

499 500
RunController *Core::runControllerInternal()
{
501
    return d->runController.data();
502 503
}

504
ISourceFormatterController* Core::sourceFormatterController()
505
{
506
    return d->sourceFormatterController.data();
507
}
508

509 510
SourceFormatterController* Core::sourceFormatterControllerInternal()
{
511
    return d->sourceFormatterController.data();
512 513 514
}


515 516
ProgressManager *Core::progressController()
{
517
    return d->progressController.data();
518 519
}

520 521
ISelectionController* Core::selectionController()
{
522
    return d->selectionController.data();
523 524
}

525 526
IDocumentationController* Core::documentationController()
{
527
    return d->documentationController.data();
528 529
}

530 531
DocumentationController* Core::documentationControllerInternal()
{
532
    return d->documentationController.data();
533 534
}

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
535 536 537 538 539 540 541 542 543 544
IRuntimeController* Core::runtimeController()
{
    return d->runtimeController.data();
}

RuntimeController* Core::runtimeControllerInternal()
{
    return d->runtimeController.data();
}

545 546
IDebugController* Core::debugController()
{
547
    return d->debugController.data();
548 549 550 551
}

DebugController* Core::debugControllerInternal()
{
552
    return d->debugController.data();
553 554
}

555 556 557 558 559 560 561 562 563 564
ITestController* Core::testController()
{
    return d->testController.data();
}

TestController* Core::testControllerInternal()
{
    return d->testController.data();
}

565 566
WorkingSetController* Core::workingSetControllerInternal()
{
567
    return d->workingSetController.data();
568 569
}

570 571
QString Core::version()
{
572
    return QStringLiteral(KDEVPLATFORM_VERSION_STRING);
573 574
}

575
}
576