File indexing completed on 2024-05-19 04:29:09

0001 /*
0002  * SPDX-FileCopyrightText: 1998, 1999 Torben Weis <weis@kde.org>
0003  * SPDX-FileCopyrightText: 2012 Boudewijn Rempt <boud@valdyas.org>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.0-or-later
0006  */
0007 
0008 #include "KisApplication.h"
0009 
0010 #include <stdlib.h>
0011 #ifdef Q_OS_WIN
0012 #include <windows.h>
0013 #include <tchar.h>
0014 #include "KisWindowsPackageUtils.h"
0015 #endif
0016 
0017 #ifdef Q_OS_MACOS
0018 #include "osx.h"
0019 #include "KisMacosEntitlements.h"
0020 #endif
0021 
0022 #include <QStandardPaths>
0023 #include <QDesktopWidget>
0024 #include <QDir>
0025 #include <QFile>
0026 #include <QLocale>
0027 #include <QMessageBox>
0028 #include <QProcessEnvironment>
0029 #include <QStringList>
0030 #include <QStyle>
0031 #include <QStyleFactory>
0032 #include <QSysInfo>
0033 #include <QTimer>
0034 #include <QWidget>
0035 #include <QImageReader>
0036 #include <QImageWriter>
0037 #include <QThread>
0038 
0039 #include <klocalizedstring.h>
0040 #include <kdesktopfile.h>
0041 #include <kconfig.h>
0042 #include <kconfiggroup.h>
0043 
0044 #include <KoDockRegistry.h>
0045 #include <KoToolRegistry.h>
0046 #include <KoColorSpaceRegistry.h>
0047 #include <KoPluginLoader.h>
0048 #include <KoShapeRegistry.h>
0049 #include "KoConfig.h"
0050 #include <KoResourcePaths.h>
0051 #include <KisMimeDatabase.h>
0052 #include "thememanager.h"
0053 #include "KisDocument.h"
0054 #include "KisMainWindow.h"
0055 #include "KisAutoSaveRecoveryDialog.h"
0056 #include "KisPart.h"
0057 #include <kis_icon.h>
0058 #include "kis_splash_screen.h"
0059 #include "kis_config.h"
0060 #include "flake/kis_shape_selection.h"
0061 #include <filter/kis_filter.h>
0062 #include <filter/kis_filter_registry.h>
0063 #include <filter/kis_filter_configuration.h>
0064 #include <generator/kis_generator_registry.h>
0065 #include <generator/kis_generator.h>
0066 #include <brushengine/kis_paintop_registry.h>
0067 #include <kis_meta_data_io_backend.h>
0068 #include <kis_meta_data_backend_registry.h>
0069 #include "KisApplicationArguments.h"
0070 #include <kis_debug.h>
0071 #include "kis_action_registry.h"
0072 #include <KoResourceServer.h>
0073 #include <KisResourceServerProvider.h>
0074 #include <KoResourceServerProvider.h>
0075 #include "opengl/kis_opengl.h"
0076 #include "kis_spin_box_unit_manager.h"
0077 #include "kis_document_aware_spin_box_unit_manager.h"
0078 #include "KisViewManager.h"
0079 #include <KisUsageLogger.h>
0080 
0081 #include <KritaVersionWrapper.h>
0082 #include <dialogs/KisSessionManagerDialog.h>
0083 
0084 #include <KisResourceCacheDb.h>
0085 #include <KisResourceLocator.h>
0086 #include <KisResourceLoader.h>
0087 #include <KisResourceLoaderRegistry.h>
0088 
0089 #include <KisBrushTypeMetaDataFixup.h>
0090 #include <kis_gbr_brush.h>
0091 #include <kis_png_brush.h>
0092 #include <kis_svg_brush.h>
0093 #include <kis_imagepipe_brush.h>
0094 #include <KoColorSet.h>
0095 #include <KoSegmentGradient.h>
0096 #include <KoStopGradient.h>
0097 #include <KoPattern.h>
0098 #include <kis_workspace_resource.h>
0099 #include <KisSessionResource.h>
0100 #include <resources/KoSvgSymbolCollectionResource.h>
0101 
0102 #include "widgets/KisScreenColorSampler.h"
0103 #include "KisDlgInternalColorSelector.h"
0104 
0105 #include <dialogs/KisAsyncAnimationFramesSaveDialog.h>
0106 #include <kis_image_animation_interface.h>
0107 #include "kis_file_layer.h"
0108 #include "kis_group_layer.h"
0109 #include "kis_node_commands_adapter.h"
0110 #include "KisSynchronizedConnection.h"
0111 #include <QThreadStorage>
0112 #include <KisWindowsPackageUtils.h>
0113 
0114 #include <kis_psd_layer_style.h>
0115 
0116 #include <config-seexpr.h>
0117 #include <config-safe-asserts.h>
0118 
0119 namespace {
0120 const QTime appStartTime(QTime::currentTime());
0121 }
0122 
0123 namespace {
0124 struct AppRecursionInfo {
0125     ~AppRecursionInfo() {
0126         KIS_SAFE_ASSERT_RECOVER_NOOP(!eventRecursionCount);
0127         KIS_SAFE_ASSERT_RECOVER_NOOP(postponedSynchronizationEvents.empty());
0128     }
0129 
0130     int eventRecursionCount {0};
0131     std::queue<KisSynchronizedConnectionEvent> postponedSynchronizationEvents;
0132 };
0133 
0134 struct AppRecursionGuard {
0135     AppRecursionGuard(AppRecursionInfo *info)
0136         : m_info(info)
0137     {
0138         m_info->eventRecursionCount++;
0139     }
0140 
0141     ~AppRecursionGuard()
0142     {
0143         m_info->eventRecursionCount--;
0144     }
0145 private:
0146     AppRecursionInfo *m_info {0};
0147 };
0148 
0149 }
0150 
0151 /**
0152  * We cannot make the recursion info be a part of KisApplication,
0153  * because KisApplication also owns QQmlThread, which is destroyed
0154  * after KisApplication::Private, which makes QThreadStorage spit
0155  * a warning about being destroyed too early
0156  */
0157 Q_GLOBAL_STATIC(QThreadStorage<AppRecursionInfo>, s_recursionInfo)
0158 
0159 class KisApplication::Private
0160 {
0161 public:
0162     Private() {}
0163     QPointer<KisSplashScreen> splashScreen;
0164     KisAutoSaveRecoveryDialog *autosaveDialog {0};
0165     QPointer<KisMainWindow> mainWindow; // The first mainwindow we create on startup
0166     bool batchRun {false};
0167     QVector<QByteArray> earlyRemoteArguments;
0168     QVector<QString> earlyFileOpenEvents;
0169 };
0170 
0171 class KisApplication::ResetStarting
0172 {
0173 public:
0174     ResetStarting(KisSplashScreen *splash, int fileCount)
0175         : m_splash(splash)
0176         , m_fileCount(fileCount)
0177     {
0178     }
0179 
0180     ~ResetStarting()  {
0181 
0182         if (m_splash) {
0183             m_splash->hide();
0184         }
0185     }
0186 
0187     QPointer<KisSplashScreen> m_splash;
0188     int m_fileCount;
0189 };
0190 
0191 
0192 KisApplication::KisApplication(const QString &key, int &argc, char **argv)
0193     : QtSingleApplication(key, argc, argv)
0194     , d(new Private)
0195 {
0196 #ifdef Q_OS_MACOS
0197     setMouseCoalescingEnabled(false);
0198 #endif
0199 
0200     QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath());
0201 
0202     setApplicationDisplayName("Krita");
0203     setApplicationName("krita");
0204     // Note: Qt docs suggest we set this, but if we do, we get resource paths of the form of krita/krita, which is weird.
0205     //    setOrganizationName("krita");
0206     setOrganizationDomain("krita.org");
0207 
0208     QString version = KritaVersionWrapper::versionString(true);
0209     setApplicationVersion(version);
0210     setWindowIcon(KisIconUtils::loadIcon("krita-branding"));
0211 
0212     if (qgetenv("KRITA_NO_STYLE_OVERRIDE").isEmpty()) {
0213         QStringList styles = QStringList() << "macintosh" << "breeze" << "fusion";
0214         if (!styles.contains(style()->objectName().toLower())) {
0215             Q_FOREACH (const QString & style, styles) {
0216                 if (!setStyle(style)) {
0217                     qDebug() << "No" << style << "available.";
0218                 }
0219                 else {
0220                     qDebug() << "Set style" << style;
0221                     break;
0222                 }
0223             }
0224         }
0225 
0226         // if style is set from config, try to load that
0227         KisConfig cfg(true);
0228         QString widgetStyleFromConfig = cfg.widgetStyle();
0229         if(widgetStyleFromConfig != "") {
0230             qApp->setStyle(widgetStyleFromConfig);
0231         }
0232 
0233     }
0234     else {
0235         qDebug() << "Style override disabled, using" << style()->objectName();
0236     }
0237 
0238     // store the style name
0239     qApp->setProperty(currentUnderlyingStyleNameProperty, style()->objectName());
0240     KisSynchronizedConnectionBase::registerSynchronizedEventBarrier(std::bind(&KisApplication::processPostponedSynchronizationEvents, this));
0241 }
0242 
0243 #if defined(Q_OS_WIN) && defined(ENV32BIT)
0244 typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
0245 
0246 LPFN_ISWOW64PROCESS fnIsWow64Process;
0247 
0248 BOOL isWow64()
0249 {
0250     BOOL bIsWow64 = FALSE;
0251 
0252     //IsWow64Process is not available on all supported versions of Windows.
0253     //Use GetModuleHandle to get a handle to the DLL that contains the function
0254     //and GetProcAddress to get a pointer to the function if available.
0255 
0256     fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
0257                 GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
0258 
0259     if(0 != fnIsWow64Process)
0260     {
0261         if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
0262         {
0263             //handle error
0264         }
0265     }
0266     return bIsWow64;
0267 }
0268 #endif
0269 
0270 void KisApplication::initializeGlobals(const KisApplicationArguments &args)
0271 {
0272     Q_UNUSED(args)
0273     // There are no globals to initialize from the arguments now. There used
0274     // to be the `dpi` argument, but it doesn't do anything anymore.
0275 }
0276 
0277 void KisApplication::addResourceTypes()
0278 {
0279     // All Krita's resource types
0280     KoResourcePaths::addAssetType("markers", "data", "/styles/");
0281     KoResourcePaths::addAssetType("kis_pics", "data", "/pics/");
0282     KoResourcePaths::addAssetType("kis_images", "data", "/images/");
0283     KoResourcePaths::addAssetType("metadata_schema", "data", "/metadata/schemas/");
0284     KoResourcePaths::addAssetType("gmic_definitions", "data", "/gmic/");
0285     KoResourcePaths::addAssetType("kis_shortcuts", "data", "/shortcuts/");
0286     KoResourcePaths::addAssetType("kis_actions", "data", "/actions");
0287     KoResourcePaths::addAssetType("kis_actions", "data", "/pykrita");
0288     KoResourcePaths::addAssetType("icc_profiles", "data", "/color/icc");
0289     KoResourcePaths::addAssetType("icc_profiles", "data", "/profiles/");
0290     KoResourcePaths::addAssetType(ResourceType::FilterEffects, "data", "/effects/");
0291     KoResourcePaths::addAssetType("tags", "data", "/tags/");
0292     KoResourcePaths::addAssetType("templates", "data", "/templates");
0293     KoResourcePaths::addAssetType("pythonscripts", "data", "/pykrita");
0294     KoResourcePaths::addAssetType("preset_icons", "data", "/preset_icons");
0295 #if defined HAVE_SEEXPR
0296     KoResourcePaths::addAssetType(ResourceType::SeExprScripts, "data", "/seexpr_scripts/", true);
0297 #endif
0298 
0299     // Make directories for all resources we can save, and tags
0300     KoResourcePaths::saveLocation("data", "/asl/", true);
0301     KoResourcePaths::saveLocation("data", "/input/", true);
0302     KoResourcePaths::saveLocation("data", "/pykrita/", true);
0303     KoResourcePaths::saveLocation("data", "/color-schemes/", true);
0304     KoResourcePaths::saveLocation("data", "/preset_icons/", true);
0305     KoResourcePaths::saveLocation("data", "/preset_icons/tool_icons/", true);
0306     KoResourcePaths::saveLocation("data", "/preset_icons/emblem_icons/", true);
0307 }
0308 
0309 
0310 bool KisApplication::event(QEvent *event)
0311 {
0312 
0313     #ifdef Q_OS_MACOS
0314     if (event->type() == QEvent::FileOpen) {
0315         QFileOpenEvent *openEvent = static_cast<QFileOpenEvent *>(event);
0316         emit fileOpenRequest(openEvent->file());
0317         return true;
0318     }
0319     #endif
0320     return QApplication::event(event);
0321 }
0322 
0323 
0324 bool KisApplication::registerResources()
0325 {
0326     KisResourceLoaderRegistry *reg = KisResourceLoaderRegistry::instance();
0327 
0328     reg->add(new KisResourceLoader<KisPaintOpPreset>(ResourceSubType::KritaPaintOpPresets, ResourceType::PaintOpPresets, i18n("Brush presets"),
0329                                                      QStringList() << "application/x-krita-paintoppreset"));
0330 
0331     reg->add(new KisResourceLoader<KisGbrBrush>(ResourceSubType::GbrBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/x-gimp-brush"));
0332     reg->add(new KisResourceLoader<KisImagePipeBrush>(ResourceSubType::GihBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/x-gimp-brush-animated"));
0333     reg->add(new KisResourceLoader<KisSvgBrush>(ResourceSubType::SvgBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/svg+xml"));
0334     reg->add(new KisResourceLoader<KisPngBrush>(ResourceSubType::PngBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/png"));
0335 
0336     reg->add(new KisResourceLoader<KoSegmentGradient>(ResourceSubType::SegmentedGradients, ResourceType::Gradients, i18n("Gradients"), QStringList() << "application/x-gimp-gradient"));
0337     reg->add(new KisResourceLoader<KoStopGradient>(ResourceSubType::StopGradients, ResourceType::Gradients, i18n("Gradients"), QStringList() << "image/svg+xml"));
0338 
0339     reg->add(new KisResourceLoader<KoColorSet>(ResourceType::Palettes, ResourceType::Palettes, i18n("Palettes"),
0340                                      QStringList() << KisMimeDatabase::mimeTypeForSuffix("kpl")
0341                                                << KisMimeDatabase::mimeTypeForSuffix("gpl")
0342                                                << KisMimeDatabase::mimeTypeForSuffix("pal")
0343                                                << KisMimeDatabase::mimeTypeForSuffix("act")
0344                                                << KisMimeDatabase::mimeTypeForSuffix("aco")
0345                                                << KisMimeDatabase::mimeTypeForSuffix("css")
0346                                                << KisMimeDatabase::mimeTypeForSuffix("colors")
0347                                                << KisMimeDatabase::mimeTypeForSuffix("xml")
0348                                                << KisMimeDatabase::mimeTypeForSuffix("sbz")));
0349 
0350 
0351     reg->add(new KisResourceLoader<KoPattern>(ResourceType::Patterns, ResourceType::Patterns, i18n("Patterns"), {"application/x-gimp-pattern", "image/x-gimp-pat", "application/x-gimp-pattern", "image/bmp", "image/jpeg", "image/png", "image/tiff"}));
0352     reg->add(new KisResourceLoader<KisWorkspaceResource>(ResourceType::Workspaces, ResourceType::Workspaces, i18n("Workspaces"), QStringList() << "application/x-krita-workspace"));
0353     reg->add(new KisResourceLoader<KoSvgSymbolCollectionResource>(ResourceType::Symbols, ResourceType::Symbols, i18n("SVG symbol libraries"), QStringList() << "image/svg+xml"));
0354     reg->add(new KisResourceLoader<KisWindowLayoutResource>(ResourceType::WindowLayouts, ResourceType::WindowLayouts, i18n("Window layouts"), QStringList() << "application/x-krita-windowlayout"));
0355     reg->add(new KisResourceLoader<KisSessionResource>(ResourceType::Sessions, ResourceType::Sessions, i18n("Sessions"), QStringList() << "application/x-krita-session"));
0356     reg->add(new KisResourceLoader<KoGamutMask>(ResourceType::GamutMasks, ResourceType::GamutMasks, i18n("Gamut masks"), QStringList() << "application/x-krita-gamutmasks"));
0357 #if defined HAVE_SEEXPR
0358     reg->add(new KisResourceLoader<KisSeExprScript>(ResourceType::SeExprScripts, ResourceType::SeExprScripts, i18n("SeExpr Scripts"), QStringList() << "application/x-krita-seexpr-script"));
0359 #endif
0360     // XXX: this covers only individual styles, not the library itself!
0361     reg->add(new KisResourceLoader<KisPSDLayerStyle>(ResourceType::LayerStyles,
0362                                                      ResourceType::LayerStyles,
0363                                                      i18nc("Resource type name", "Layer styles"),
0364                                                      QStringList() << "application/x-photoshop-style"));
0365 
0366     reg->registerFixup(10, new KisBrushTypeMetaDataFixup());
0367 
0368 #ifndef Q_OS_ANDROID
0369     QString databaseLocation = KoResourcePaths::getAppDataLocation();
0370 #else
0371     // Sqlite doesn't support content URIs (obviously). So, we make database location unconfigurable on android.
0372     QString databaseLocation = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
0373 #endif
0374 
0375     if (!KisResourceCacheDb::initialize(databaseLocation)) {
0376         QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita: Fatal error"), i18n("%1\n\nKrita will quit now.", KisResourceCacheDb::lastError()));
0377     }
0378 
0379     KisResourceLocator::LocatorError r = KisResourceLocator::instance()->initialize(KoResourcePaths::getApplicationRoot() + "/share/krita");
0380     connect(KisResourceLocator::instance(), SIGNAL(progressMessage(const QString&)), this, SLOT(setSplashScreenLoadingText(const QString&)));
0381     if (r != KisResourceLocator::LocatorError::Ok && qApp->inherits("KisApplication")) {
0382         QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita: Fatal error"), KisResourceLocator::instance()->errorMessages().join('\n') + i18n("\n\nKrita will quit now."));
0383         return false;
0384     }
0385     return true;
0386 }
0387 
0388 void KisApplication::loadPlugins()
0389 {
0390     //    qDebug() << "loadPlugins();";
0391 
0392     KoShapeRegistry* r = KoShapeRegistry::instance();
0393     r->add(new KisShapeSelectionFactory());
0394     KoColorSpaceRegistry::instance();
0395     KisActionRegistry::instance();
0396     KisFilterRegistry::instance();
0397     KisGeneratorRegistry::instance();
0398     KisPaintOpRegistry::instance();
0399     KoToolRegistry::instance();
0400     KoDockRegistry::instance();
0401     KisMetadataBackendRegistry::instance();
0402 }
0403 
0404 bool KisApplication::start(const KisApplicationArguments &args)
0405 {
0406     KisConfig cfg(false);
0407 
0408 #if defined(Q_OS_WIN)
0409 #ifdef ENV32BIT
0410 
0411     if (isWow64() && !cfg.readEntry("WarnedAbout32Bits", false)) {
0412         QMessageBox::information(qApp->activeWindow(),
0413                                  i18nc("@title:window", "Krita: Warning"),
0414                                  i18n("You are running a 32 bits build on a 64 bits Windows.\n"
0415                                       "This is not recommended.\n"
0416                                       "Please download and install the x64 build instead."));
0417         cfg.writeEntry("WarnedAbout32Bits", true);
0418 
0419     }
0420 #endif
0421 #endif
0422 
0423     QString opengl = cfg.canvasState();
0424     if (opengl == "OPENGL_NOT_TRIED" ) {
0425         cfg.setCanvasState("TRY_OPENGL");
0426     }
0427     else if (opengl != "OPENGL_SUCCESS" && opengl != "TRY_OPENGL") {
0428         cfg.setCanvasState("OPENGL_FAILED");
0429     }
0430 
0431     setSplashScreenLoadingText(i18n("Initializing Globals..."));
0432     processEvents();
0433     initializeGlobals(args);
0434 
0435     const bool doNewImage = args.doNewImage();
0436     const bool doTemplate = args.doTemplate();
0437     const bool exportAs = args.exportAs();
0438     const bool exportSequence = args.exportSequence();
0439     const QString exportFileName = args.exportFileName();
0440 
0441     d->batchRun = (exportAs || exportSequence || !exportFileName.isEmpty());
0442     const bool needsMainWindow = (!exportAs && !exportSequence);
0443     // only show the mainWindow when no command-line mode option is passed
0444     bool showmainWindow = (!exportAs && !exportSequence); // would be !batchRun;
0445 
0446     const bool showSplashScreen = !d->batchRun && qEnvironmentVariableIsEmpty("NOSPLASH");
0447     if (showSplashScreen && d->splashScreen) {
0448         d->splashScreen->show();
0449         d->splashScreen->repaint();
0450         processEvents();
0451     }
0452 
0453     KConfigGroup group(KSharedConfig::openConfig(), "theme");
0454     Digikam::ThemeManager themeManager;
0455     themeManager.setCurrentTheme(group.readEntry("Theme", "Krita dark"));
0456 
0457 
0458     ResetStarting resetStarting(d->splashScreen, args.filenames().count()); // remove the splash when done
0459     Q_UNUSED(resetStarting);
0460 
0461     // Make sure we can save resources and tags
0462     setSplashScreenLoadingText(i18n("Adding resource types..."));
0463     processEvents();
0464     addResourceTypes();
0465 
0466     setSplashScreenLoadingText(i18n("Loading plugins..."));
0467     processEvents();
0468     // Load the plugins
0469     loadPlugins();
0470 
0471     // Load all resources
0472     setSplashScreenLoadingText(i18n("Loading resources..."));
0473     processEvents();
0474     if (!registerResources()) {
0475         return false;
0476     }
0477 
0478     KisPart *kisPart = KisPart::instance();
0479     if (needsMainWindow) {
0480         // show a mainWindow asap, if we want that
0481         setSplashScreenLoadingText(i18n("Loading Main Window..."));
0482         processEvents();
0483 
0484 
0485         bool sessionNeeded = true;
0486         auto sessionMode = cfg.sessionOnStartup();
0487 
0488         if (!args.session().isEmpty()) {
0489             sessionNeeded = !kisPart->restoreSession(args.session());
0490         } else if (sessionMode == KisConfig::SOS_ShowSessionManager) {
0491             showmainWindow = false;
0492             sessionNeeded = false;
0493             kisPart->showSessionManager();
0494         } else if (sessionMode == KisConfig::SOS_PreviousSession) {
0495             KConfigGroup sessionCfg = KSharedConfig::openConfig()->group("session");
0496             const QString &sessionName = sessionCfg.readEntry("previousSession");
0497 
0498             sessionNeeded = !kisPart->restoreSession(sessionName);
0499         }
0500 
0501         if (sessionNeeded) {
0502             kisPart->startBlankSession();
0503         }
0504 
0505         if (!args.windowLayout().isEmpty()) {
0506             KoResourceServer<KisWindowLayoutResource> * rserver = KisResourceServerProvider::instance()->windowLayoutServer();
0507             KisWindowLayoutResourceSP windowLayout = rserver->resource("", "", args.windowLayout());
0508             if (windowLayout) {
0509                 windowLayout->applyLayout();
0510             }
0511         }
0512 
0513         setSplashScreenLoadingText(i18n("Launching..."));
0514 
0515         if (showmainWindow) {
0516             d->mainWindow = kisPart->currentMainwindow();
0517 
0518             if (!args.workspace().isEmpty()) {
0519                 KoResourceServer<KisWorkspaceResource> * rserver = KisResourceServerProvider::instance()->workspaceServer();
0520                 KisWorkspaceResourceSP workspace = rserver->resource("", "", args.workspace());
0521                 if (workspace) {
0522                     d->mainWindow->restoreWorkspace(workspace);
0523                 }
0524             }
0525 
0526             if (args.canvasOnly()) {
0527                 d->mainWindow->viewManager()->switchCanvasOnly(true);
0528             }
0529 
0530             if (args.fullScreen()) {
0531                 d->mainWindow->showFullScreen();
0532             }
0533         } else {
0534             d->mainWindow = kisPart->createMainWindow();
0535         }
0536     }
0537     short int numberOfOpenDocuments = 0; // number of documents open
0538 
0539     // Check for autosave files that can be restored, if we're not running a batch run (test)
0540     if (!d->batchRun) {
0541         checkAutosaveFiles();
0542     }
0543 
0544     setSplashScreenLoadingText(QString()); // done loading, so clear out label
0545     processEvents();
0546 
0547     //configure the unit manager
0548     KisSpinBoxUnitManagerFactory::setDefaultUnitManagerBuilder(new KisDocumentAwareSpinBoxUnitManagerBuilder());
0549     connect(this, &KisApplication::aboutToQuit, &KisSpinBoxUnitManagerFactory::clearUnitManagerBuilder); //ensure the builder is destroyed when the application leave.
0550     //the new syntax slot syntax allow to connect to a non q_object static method.
0551 
0552     // Create a new image, if needed
0553     if (doNewImage) {
0554         KisDocument *doc = args.createDocumentFromArguments();
0555         if (doc) {
0556             kisPart->addDocument(doc);
0557             d->mainWindow->addViewAndNotifyLoadingCompleted(doc);
0558         }
0559     }
0560 
0561     // Get the command line arguments which we have to parse
0562     int argsCount = args.filenames().count();
0563     if (argsCount > 0) {
0564         // Loop through arguments
0565         for (int argNumber = 0; argNumber < argsCount; argNumber++) {
0566             QString fileName = args.filenames().at(argNumber);
0567             // are we just trying to open a template?
0568             if (doTemplate) {
0569                 // called in mix with batch options? ignore and silently skip
0570                 if (d->batchRun) {
0571                     continue;
0572                 }
0573                 if (createNewDocFromTemplate(fileName, d->mainWindow)) {
0574                     ++numberOfOpenDocuments;
0575                 }
0576                 // now try to load
0577             }
0578             else {
0579                 if (exportAs) {
0580                     QString outputMimetype = KisMimeDatabase::mimeTypeForFile(exportFileName, false);
0581                     if (outputMimetype == "application/octetstream") {
0582                         dbgKrita << i18n("Mimetype not found, try using the -mimetype option") << endl;
0583                         return false;
0584                     }
0585 
0586                     KisDocument *doc = kisPart->createDocument();
0587                     doc->setFileBatchMode(d->batchRun);
0588                     bool result = doc->openPath(fileName);
0589 
0590                     if (!result) {
0591                         errKrita << "Could not load " << fileName << ":" << doc->errorMessage();
0592                         QTimer::singleShot(0, this, SLOT(quit()));
0593                         return false;
0594                     }
0595 
0596                     if (exportFileName.isEmpty()) {
0597                         errKrita << "Export destination is not specified for" << fileName << "Please specify export destination with --export-filename option";
0598                         QTimer::singleShot(0, this, SLOT(quit()));
0599                         return false;
0600                     }
0601 
0602                     qApp->processEvents(); // For vector layers to be updated
0603 
0604                     doc->setFileBatchMode(true);
0605                     doc->image()->waitForDone();
0606 
0607                     if (!doc->exportDocumentSync(exportFileName, outputMimetype.toLatin1())) {
0608                         errKrita << "Could not export " << fileName << "to" << exportFileName << ":" << doc->errorMessage();
0609                     }
0610                     QTimer::singleShot(0, this, SLOT(quit()));
0611                     return true;
0612                 }
0613                 else if (exportSequence) {
0614                     KisDocument *doc = kisPart->createDocument();
0615                     doc->setFileBatchMode(d->batchRun);
0616                     doc->openPath(fileName);
0617                     qApp->processEvents(); // For vector layers to be updated
0618                     
0619                     if (!doc->image()->animationInterface()->hasAnimation()) {
0620                         errKrita << "This file has no animation." << endl;
0621                         QTimer::singleShot(0, this, SLOT(quit()));
0622                         return false;
0623                     }
0624 
0625                     doc->setFileBatchMode(true);
0626                     int sequenceStart = 0;
0627 
0628                     KisAsyncAnimationFramesSaveDialog exporter(doc->image(),
0629                                                doc->image()->animationInterface()->documentPlaybackRange(),
0630                                                exportFileName,
0631                                                sequenceStart,
0632                                                false,
0633                                                0);
0634                     exporter.setBatchMode(d->batchRun);
0635                     KisAsyncAnimationFramesSaveDialog::Result result =
0636                         exporter.regenerateRange(0);
0637                     if (result != KisAsyncAnimationFramesSaveDialog::RenderComplete) {
0638                         errKrita << i18n("Failed to render animation frames!") << endl;
0639                     }
0640                     QTimer::singleShot(0, this, SLOT(quit()));
0641                     return true;
0642                 }
0643                 else if (d->mainWindow) {
0644                     if (QFileInfo(fileName).fileName().endsWith(".bundle", Qt::CaseInsensitive)) {
0645                         d->mainWindow->installBundle(fileName);
0646                     }
0647                     else {
0648                         KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
0649 
0650                         if (d->mainWindow->openDocument(fileName, flags)) {
0651                             // Normal case, success
0652                             numberOfOpenDocuments++;
0653                         }
0654                     }
0655                 }
0656             }
0657         }
0658     }
0659 
0660     //add an image as file-layer
0661     if (!args.fileLayer().isEmpty()){
0662         if (d->mainWindow->viewManager()->image()){
0663             KisFileLayer *fileLayer = new KisFileLayer(d->mainWindow->viewManager()->image(), "",
0664                                                     args.fileLayer(), KisFileLayer::None, "Bicubic",
0665                                                     d->mainWindow->viewManager()->image()->nextLayerName(i18n("File layer")), OPACITY_OPAQUE_U8);
0666             QFileInfo fi(fileLayer->path());
0667             if (fi.exists()){
0668                 KisNodeCommandsAdapter adapter(d->mainWindow->viewManager());
0669                 adapter.addNode(fileLayer, d->mainWindow->viewManager()->activeNode()->parent(),
0670                                     d->mainWindow->viewManager()->activeNode());
0671             }
0672             else{
0673                 QMessageBox::warning(qApp->activeWindow(), i18nc("@title:window", "Krita:Warning"),
0674                                             i18n("Cannot add %1 as a file layer: the file does not exist.", fileLayer->path()));
0675             }
0676         }
0677         else if (this->isRunning()){
0678             QMessageBox::warning(qApp->activeWindow(), i18nc("@title:window", "Krita:Warning"),
0679                                 i18n("Cannot add the file layer: no document is open.\n\n"
0680 "You can create a new document using the --new-image option, or you can open an existing file.\n\n"
0681 "If you instead want to add the file layer to a document in an already running instance of Krita, check the \"Allow only one instance of Krita\" checkbox in the settings (Settings -> General -> Window)."));
0682         }
0683         else {
0684             QMessageBox::warning(qApp->activeWindow(), i18nc("@title:window", "Krita: Warning"),
0685                                 i18n("Cannot add the file layer: no document is open.\n"
0686                                      "You can either create a new file using the --new-image option, or you can open an existing file."));
0687         }
0688     }
0689 
0690     // fixes BUG:369308  - Krita crashing on splash screen when loading.
0691     // trying to open a file before Krita has loaded can cause it to hang and crash
0692     if (d->splashScreen) {
0693         d->splashScreen->displayLinks(true);
0694         d->splashScreen->displayRecentFiles(true);
0695     }
0696 
0697     Q_FOREACH(const QByteArray &message, d->earlyRemoteArguments) {
0698         executeRemoteArguments(message, d->mainWindow);
0699     }
0700 
0701     KisUsageLogger::writeSysInfo(KisUsageLogger::screenInformation());
0702 
0703     // process File open event files
0704     if (!d->earlyFileOpenEvents.isEmpty()) {
0705         hideSplashScreen();
0706         Q_FOREACH(QString fileName, d->earlyFileOpenEvents) {
0707             d->mainWindow->openDocument(fileName, QFlags<KisMainWindow::OpenFlag>());
0708         }
0709     }
0710 
0711     verifyMetatypeRegistration();
0712 
0713     // not calling this before since the program will quit there.
0714     return true;
0715 }
0716 
0717 KisApplication::~KisApplication()
0718 {
0719     if (!isRunning()) {
0720         KisResourceCacheDb::deleteTemporaryResources();
0721     }
0722 }
0723 
0724 void KisApplication::setSplashScreen(QWidget *splashScreen)
0725 {
0726     d->splashScreen = qobject_cast<KisSplashScreen*>(splashScreen);
0727 }
0728 
0729 void KisApplication::setSplashScreenLoadingText(const QString &textToLoad)
0730 {
0731     if (d->splashScreen) {
0732         d->splashScreen->setLoadingText(textToLoad);
0733         d->splashScreen->repaint();
0734     }
0735 }
0736 
0737 void KisApplication::hideSplashScreen()
0738 {
0739     if (d->splashScreen) {
0740         // hide the splashscreen to see the dialog
0741         d->splashScreen->hide();
0742     }
0743 }
0744 
0745 
0746 bool KisApplication::notify(QObject *receiver, QEvent *event)
0747 {
0748     try {
0749         bool result = true;
0750 
0751         /**
0752          * KisApplication::notify() is called for every event loop processed in
0753          * any thread, so we need to make sure our counters and postponed events
0754          * queues are stored in a per-thread way.
0755          */
0756         AppRecursionInfo &info = s_recursionInfo->localData();
0757 
0758         {
0759             // QApplication::notify() can throw, so use RAII for counters
0760             AppRecursionGuard guard(&info);
0761 
0762             if (event->type() == KisSynchronizedConnectionBase::eventType()) {
0763 
0764                 if (info.eventRecursionCount > 1) {
0765                     KisSynchronizedConnectionEvent *typedEvent = static_cast<KisSynchronizedConnectionEvent*>(event);
0766                     KIS_SAFE_ASSERT_RECOVER_NOOP(typedEvent->destination == receiver);
0767 
0768                     info.postponedSynchronizationEvents.emplace(KisSynchronizedConnectionEvent(*typedEvent));
0769                 } else {
0770                     result = QApplication::notify(receiver, event);
0771                 }
0772             } else {
0773                 result = QApplication::notify(receiver, event);
0774             }
0775         }
0776 
0777         if (!info.eventRecursionCount) {
0778             processPostponedSynchronizationEvents();
0779 
0780         }
0781 
0782         return result;
0783 
0784     } catch (std::exception &e) {
0785         qWarning("Error %s sending event %i to object %s",
0786                  e.what(), event->type(), qPrintable(receiver->objectName()));
0787     } catch (...) {
0788         qWarning("Error <unknown> sending event %i to object %s",
0789                  event->type(), qPrintable(receiver->objectName()));
0790     }
0791     return false;
0792 }
0793 
0794 void KisApplication::processPostponedSynchronizationEvents()
0795 {
0796     AppRecursionInfo &info = s_recursionInfo->localData();
0797 
0798     while (!info.postponedSynchronizationEvents.empty()) {
0799         // QApplication::notify() can throw, so use RAII for counters
0800         AppRecursionGuard guard(&info);
0801 
0802         /// We must pop event from the queue **before** we call
0803         /// QApplication::notify(), because it can throw!
0804         KisSynchronizedConnectionEvent typedEvent = info.postponedSynchronizationEvents.front();
0805         info.postponedSynchronizationEvents.pop();
0806 
0807         if (!typedEvent.destination) {
0808             qWarning() << "WARNING: the destination object of KisSynchronizedConnection has been destroyed during postponed delivery";
0809             continue;
0810         }
0811 
0812         QApplication::notify(typedEvent.destination, &typedEvent);
0813     }
0814 }
0815 
0816 bool KisApplication::isStoreApplication()
0817 {
0818     if (qEnvironmentVariableIsSet("STEAMAPPID") || qEnvironmentVariableIsSet("SteamAppId")) {
0819         return true;
0820     }
0821 
0822     if (applicationDirPath().toLower().contains("steam")) {
0823         return true;
0824     }
0825 
0826 #ifdef Q_OS_WIN
0827     // This is also true for user-installed MSIX, but that's
0828     // likely only true in institutional situations, where
0829     // we don't want to show the beggin banner either.
0830     if (KisWindowsPackageUtils::isRunningInPackage()) {
0831         return true;
0832     }
0833 #endif
0834 
0835 #ifdef Q_OS_MACOS
0836     KisMacosEntitlements entitlements;
0837     if (entitlements.sandbox()) {
0838        return true;
0839     }
0840 #endif
0841 
0842     return false;
0843 }
0844 
0845 void KisApplication::verifyMetatypeRegistration()
0846 {
0847     /**
0848      * Veryfy that all our statically registered types are actually registered.
0849      * This check is skipped in release builds, when HIDE_SAFE_ASSERTS is defined
0850      */
0851 #if !defined(HIDE_SAFE_ASSERTS) || defined(CRASH_ON_SAFE_ASSERTS)
0852 
0853     auto verifyTypeRegistered = [] (const char *type) {
0854         const int typeId = QMetaType::type(type);
0855 
0856         if (typeId <= 0) {
0857             qFatal("ERROR: type-id for metatype %s is not found", type);
0858         }
0859 
0860         if (!QMetaType::isRegistered(typeId)) {
0861             qFatal("ERROR: metatype %s is not registered", type);
0862         }
0863     };
0864 
0865     verifyTypeRegistered("KisBrushSP");
0866     verifyTypeRegistered("KoSvgText::AutoValue");
0867     verifyTypeRegistered("KoSvgText::BackgroundProperty");
0868     verifyTypeRegistered("KoSvgText::StrokeProperty");
0869     verifyTypeRegistered("KoSvgText::TextTransformInfo");
0870     verifyTypeRegistered("KoSvgText::TextIndentInfo");
0871     verifyTypeRegistered("KoSvgText::TabSizeInfo");
0872     verifyTypeRegistered("KoSvgText::LineHeightInfo");
0873     verifyTypeRegistered("KisPaintopLodLimitations");
0874     verifyTypeRegistered("KisImageSP");
0875     verifyTypeRegistered("KisImageSignalType");
0876     verifyTypeRegistered("KisNodeSP");
0877     verifyTypeRegistered("KisNodeList");
0878     verifyTypeRegistered("KisPaintDeviceSP");
0879     verifyTypeRegistered("KisTimeSpan");
0880     verifyTypeRegistered("KoColor");
0881     verifyTypeRegistered("KoResourceSP");
0882     verifyTypeRegistered("KoResourceCacheInterfaceSP");
0883     verifyTypeRegistered("KisAsyncAnimationRendererBase::CancelReason");
0884     verifyTypeRegistered("KisGridConfig");
0885     verifyTypeRegistered("KisGuidesConfig");
0886     verifyTypeRegistered("KisUpdateInfoSP");
0887     verifyTypeRegistered("KisToolChangesTrackerDataSP");
0888     verifyTypeRegistered("QVector<QImage>");
0889     verifyTypeRegistered("SnapshotDirInfoList");
0890     verifyTypeRegistered("TransformTransactionProperties");
0891     verifyTypeRegistered("ToolTransformArgs");
0892     verifyTypeRegistered("QPainterPath");
0893 #endif
0894 }
0895 
0896 void KisApplication::executeRemoteArguments(QByteArray message, KisMainWindow *mainWindow)
0897 {
0898     KisApplicationArguments args = KisApplicationArguments::deserialize(message);
0899     const bool doTemplate = args.doTemplate();
0900     const bool doNewImage = args.doNewImage();
0901     const int argsCount = args.filenames().count();
0902     bool documentCreated = false;
0903 
0904     // Create a new image, if needed
0905     if (doNewImage) {
0906         KisDocument *doc = args.createDocumentFromArguments();
0907         if (doc) {
0908             KisPart::instance()->addDocument(doc);
0909             d->mainWindow->addViewAndNotifyLoadingCompleted(doc);
0910         }
0911     }
0912     if (argsCount > 0) {
0913         // Loop through arguments
0914         for (int argNumber = 0; argNumber < argsCount; ++argNumber) {
0915             QString filename = args.filenames().at(argNumber);
0916             // are we just trying to open a template?
0917             if (doTemplate) {
0918                 documentCreated |= createNewDocFromTemplate(filename, mainWindow);
0919             }
0920             else if (QFile(filename).exists()) {
0921                 KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
0922                 documentCreated |= mainWindow->openDocument(filename, flags);
0923             }
0924         }
0925     }
0926 
0927     //add an image as file-layer if called in another process and singleApplication is enabled
0928     if (!args.fileLayer().isEmpty()){
0929         if (argsCount > 0  && !documentCreated){
0930             //arg was passed but document was not created so don't add the file layer.
0931             QMessageBox::warning(mainWindow, i18nc("@title:window", "Krita:Warning"),
0932                                             i18n("Couldn't open file %1",args.filenames().at(argsCount - 1)));
0933         }
0934         else if (mainWindow->viewManager()->image()){
0935             KisFileLayer *fileLayer = new KisFileLayer(mainWindow->viewManager()->image(), "",
0936                                                     args.fileLayer(), KisFileLayer::None, "Bicubic",
0937                                                     mainWindow->viewManager()->image()->nextLayerName(i18n("File layer")), OPACITY_OPAQUE_U8);
0938             QFileInfo fi(fileLayer->path());
0939             if (fi.exists()){
0940                 KisNodeCommandsAdapter adapter(d->mainWindow->viewManager());
0941                 adapter.addNode(fileLayer, d->mainWindow->viewManager()->activeNode()->parent(),
0942                                     d->mainWindow->viewManager()->activeNode());
0943             }
0944             else{
0945                 QMessageBox::warning(mainWindow, i18nc("@title:window", "Krita:Warning"),
0946                                             i18n("Cannot add %1 as a file layer: the file does not exist.", fileLayer->path()));
0947             }
0948         }
0949         else {
0950             QMessageBox::warning(mainWindow, i18nc("@title:window", "Krita:Warning"),
0951                                             i18n("Cannot add the file layer: no document is open."));
0952         }
0953     }
0954 }
0955 
0956 
0957 void KisApplication::remoteArguments(QByteArray message, QObject *socket)
0958 {
0959     Q_UNUSED(socket);
0960 
0961     // check if we have any mainwindow
0962     KisMainWindow *mw = qobject_cast<KisMainWindow*>(qApp->activeWindow());
0963 
0964     if (!mw && KisPart::instance()->mainWindows().size() > 0) {
0965         mw = KisPart::instance()->mainWindows().first();
0966     }
0967 
0968     if (!mw) {
0969         d->earlyRemoteArguments << message;
0970         return;
0971     }
0972     executeRemoteArguments(message, mw);
0973 }
0974 
0975 void KisApplication::fileOpenRequested(const QString &url)
0976 {
0977     if (!d->mainWindow) {
0978         d->earlyFileOpenEvents.append(url);
0979         return;
0980     }
0981 
0982     KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
0983     d->mainWindow->openDocument(url, flags);
0984 }
0985 
0986 
0987 void KisApplication::checkAutosaveFiles()
0988 {
0989     if (d->batchRun) return;
0990 
0991     QDir dir = KisAutoSaveRecoveryDialog::autoSaveLocation();
0992 
0993     // Check for autosave files from a previous run. There can be several, and
0994     // we want to offer a restore for every one. Including a nice thumbnail!
0995 
0996     // Hidden autosave files
0997     QStringList filters = QStringList() << QString(".krita-*-*-autosave.kra");
0998 
0999     // all autosave files for our application
1000     QStringList autosaveFiles = dir.entryList(filters, QDir::Files | QDir::Hidden);
1001 
1002     // Visible autosave files
1003     filters = QStringList() << QString("krita-*-*-autosave.kra");
1004     autosaveFiles += dir.entryList(filters, QDir::Files);
1005 
1006     // Allow the user to make their selection
1007     if (autosaveFiles.size() > 0) {
1008         if (d->splashScreen) {
1009             // hide the splashscreen to see the dialog
1010             d->splashScreen->hide();
1011         }
1012         d->autosaveDialog = new KisAutoSaveRecoveryDialog(autosaveFiles, activeWindow());
1013         QDialog::DialogCode result = (QDialog::DialogCode) d->autosaveDialog->exec();
1014 
1015         if (result == QDialog::Accepted) {
1016             QStringList filesToRecover = d->autosaveDialog->recoverableFiles();
1017             Q_FOREACH (const QString &autosaveFile, autosaveFiles) {
1018                 if (!filesToRecover.contains(autosaveFile)) {
1019                     KisUsageLogger::log(QString("Removing autosave file %1").arg(dir.absolutePath() + "/" + autosaveFile));
1020                     QFile::remove(dir.absolutePath() + "/" + autosaveFile);
1021                 }
1022             }
1023             autosaveFiles = filesToRecover;
1024         } else {
1025             autosaveFiles.clear();
1026         }
1027 
1028         if (autosaveFiles.size() > 0) {
1029             QList<QString> autosavePaths;
1030             Q_FOREACH (const QString &autoSaveFile, autosaveFiles) {
1031                 const QString path = dir.absolutePath() + QLatin1Char('/') + autoSaveFile;
1032                 autosavePaths << path;
1033             }
1034             if (d->mainWindow) {
1035                 Q_FOREACH (const QString &path, autosavePaths) {
1036                     KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
1037                     d->mainWindow->openDocument(path, flags | KisMainWindow::RecoveryFile);
1038                 }
1039             }
1040         }
1041         // cleanup
1042         delete d->autosaveDialog;
1043         d->autosaveDialog = nullptr;
1044     }
1045 }
1046 
1047 bool KisApplication::createNewDocFromTemplate(const QString &fileName, KisMainWindow *mainWindow)
1048 {
1049     QString templatePath;
1050 
1051     if (QFile::exists(fileName)) {
1052         templatePath = fileName;
1053         dbgUI << "using full path...";
1054     }
1055     else {
1056         QString desktopName(fileName);
1057         const QString templatesResourcePath =  QStringLiteral("templates/");
1058 
1059         QStringList paths = KoResourcePaths::findAllAssets("data", templatesResourcePath + "*/" + desktopName);
1060         if (paths.isEmpty()) {
1061             paths = KoResourcePaths::findAllAssets("data", templatesResourcePath + desktopName);
1062         }
1063 
1064         if (paths.isEmpty()) {
1065             QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita"),
1066                                   i18n("No template found for: %1", desktopName));
1067         } else if (paths.count() > 1) {
1068             QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita"),
1069                                   i18n("Too many templates found for: %1", desktopName));
1070         } else {
1071             templatePath = paths.at(0);
1072         }
1073     }
1074 
1075     if (!templatePath.isEmpty()) {
1076         KDesktopFile templateInfo(templatePath);
1077 
1078         KisMainWindow::OpenFlags batchFlags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
1079         if (mainWindow->openDocument(templatePath, KisMainWindow::Import | batchFlags)) {
1080             dbgUI << "Template loaded...";
1081             return true;
1082         }
1083         else {
1084             QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita"),
1085                                   i18n("Template %1 failed to load.", fileName));
1086         }
1087     }
1088 
1089     return false;
1090 }
1091 
1092 void KisApplication::resetConfig()
1093 {
1094     KIS_ASSERT_RECOVER_RETURN(qApp->thread() == QThread::currentThread());
1095 
1096     KSharedConfigPtr config =  KSharedConfig::openConfig();
1097     config->markAsClean();
1098     
1099     // find user settings file
1100     const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
1101     QString kritarcPath = configPath + QStringLiteral("/kritarc");
1102     
1103     QFile kritarcFile(kritarcPath);
1104     
1105     if (kritarcFile.exists()) {
1106         if (kritarcFile.open(QFile::ReadWrite)) {
1107             QString backupKritarcPath = kritarcPath + QStringLiteral(".backup");
1108     
1109             QFile backupKritarcFile(backupKritarcPath);
1110     
1111             if (backupKritarcFile.exists()) {
1112                 backupKritarcFile.remove();
1113             }
1114 
1115             QMessageBox::information(qApp->activeWindow(),
1116                                  i18nc("@title:window", "Krita"),
1117                                  i18n("Krita configurations reset!\n\n"
1118                                       "Backup file was created at: %1\n\n"
1119                                       "Restart Krita for changes to take effect.",
1120                                       backupKritarcPath),
1121                                  QMessageBox::Ok, QMessageBox::Ok);
1122 
1123             // clear file
1124             kritarcFile.rename(backupKritarcPath);
1125 
1126             kritarcFile.close();
1127         }
1128         else {
1129             QMessageBox::warning(qApp->activeWindow(),
1130                                  i18nc("@title:window", "Krita"),
1131                                  i18n("Failed to clear %1\n\n"
1132                                       "Please make sure no other program is using the file and try again.",
1133                                       kritarcPath),
1134                                  QMessageBox::Ok, QMessageBox::Ok);
1135         }
1136     }
1137 
1138     // reload from disk; with the user file settings cleared,
1139     // this should load any default configuration files shipping with the program
1140     config->reparseConfiguration();
1141     config->sync();
1142 
1143     // Restore to default workspace
1144     KConfigGroup cfg = KSharedConfig::openConfig()->group("MainWindow");
1145 
1146     QString currentWorkspace = cfg.readEntry<QString>("CurrentWorkspace", "Default");
1147     KoResourceServer<KisWorkspaceResource> * rserver = KisResourceServerProvider::instance()->workspaceServer();
1148     KisWorkspaceResourceSP workspace = rserver->resource("", "", currentWorkspace);
1149 
1150     if (workspace) {
1151         d->mainWindow->restoreWorkspace(workspace);
1152     }
1153 }
1154 
1155 void KisApplication::askResetConfig()
1156 {
1157     bool ok = QMessageBox::question(qApp->activeWindow(),
1158                                     i18nc("@title:window", "Krita"),
1159                                     i18n("Do you want to clear the settings file?"),
1160                                     QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes;
1161     if (ok) {
1162         resetConfig();
1163     }
1164 }