Krita Source Code Documentation
Loading...
Searching...
No Matches
KisApplication.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 1998, 1999 Torben Weis <weis@kde.org>
3 * SPDX-FileCopyrightText: 2012 Boudewijn Rempt <boud@valdyas.org>
4 *
5 * SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7
8#include "KisApplication.h"
9
10#include <stdlib.h>
11#ifdef Q_OS_WIN
12#include <windows.h>
13#include <tchar.h>
15#endif
16
17#ifdef Q_OS_MACOS
18#include "osx.h"
20#endif
21
22#ifdef Q_OS_ANDROID
23#include "KisAndroidDonations.h"
24#endif
25
26#include <QStandardPaths>
27#include <QScreen>
28#include <QDir>
29#include <QFile>
30#include <QLocale>
31#include <QMessageBox>
32#include <QProcessEnvironment>
33#include <QStringList>
34#include <QStyle>
35#include <QStyleFactory>
36#include <QSysInfo>
37#include <QTimer>
38#include <QWidget>
39#include <QImageReader>
40#include <QImageWriter>
41#include <QThread>
42
43#include <klocalizedstring.h>
44#include <kdesktopfile.h>
45#include <kconfig.h>
46#include <kconfiggroup.h>
47
48#include <KoDockRegistry.h>
49#include <KoToolRegistry.h>
51#include <KoPluginLoader.h>
52#include <KoShapeRegistry.h>
53#include "KoConfig.h"
54#include <KoResourcePaths.h>
55#include <KisMimeDatabase.h>
56#include "thememanager.h"
57#include "KisDocument.h"
58#include "KisMainWindow.h"
60#include "KisPart.h"
61#include <kis_icon.h>
62#include "kis_splash_screen.h"
63#include "kis_config.h"
64#include "kis_config_notifier.h"
66#include <filter/kis_filter.h>
75#include <kis_debug.h>
76#include "kis_action_registry.h"
77#include <KoResourceServer.h>
80#include "opengl/kis_opengl.h"
83#include "KisViewManager.h"
84#include <KisUsageLogger.h>
85
86#include <KritaVersionWrapper.h>
88
89#include <KisResourceCacheDb.h>
90#include <KisResourceLocator.h>
91#include <KisResourceLoader.h>
93
95#include <kis_gbr_brush.h>
96#include <kis_png_brush.h>
97#include <kis_svg_brush.h>
98#include <kis_imagepipe_brush.h>
99#include <KoColorSet.h>
100#include <KoSegmentGradient.h>
101#include <KoStopGradient.h>
102#include <KoPattern.h>
104#include <KisSessionResource.h>
107
111
114#include "kis_file_layer.h"
115#include "kis_group_layer.h"
118#include <QThreadStorage>
120
121#include <kis_psd_layer_style.h>
122
123#include <config-seexpr.h>
124#include <config-safe-asserts.h>
125
128
129#include <config-use-surface-color-management-api.h>
130
131#if KRITA_USE_SURFACE_COLOR_MANAGEMENT_API
132
133#include <QWindow>
134#include <QPlatformSurfaceEvent>
136
137#endif /* KRITA_USE_SURFACE_COLOR_MANAGEMENT_API */
138
139namespace {
140const QTime appStartTime(QTime::currentTime());
141}
142
143namespace {
144struct AppRecursionInfo {
145 ~AppRecursionInfo() {
146 KIS_SAFE_ASSERT_RECOVER_NOOP(!eventRecursionCount);
147 KIS_SAFE_ASSERT_RECOVER_NOOP(postponedSynchronizationEvents.empty());
148 }
149
150 int eventRecursionCount {0};
151 std::queue<KisSynchronizedConnectionEvent> postponedSynchronizationEvents;
152};
153
154struct AppRecursionGuard {
155 AppRecursionGuard(AppRecursionInfo *info)
156 : m_info(info)
157 {
158 m_info->eventRecursionCount++;
159 }
160
161 ~AppRecursionGuard()
162 {
163 m_info->eventRecursionCount--;
164 }
165private:
166 AppRecursionInfo *m_info {0};
167};
168
169}
170
177Q_GLOBAL_STATIC(QThreadStorage<AppRecursionInfo>, s_recursionInfo)
178
180{
181public:
184 KisAutoSaveRecoveryDialog *autosaveDialog {0};
185 KisLongPressEventFilter *longPressEventFilter {nullptr};
186 QPointer<KisMainWindow> mainWindow; // The first mainwindow we create on startup
187 bool batchRun {false};
190 QScopedPointer<KisExtendedModifiersMapperPluginInterface> extendedModifiersPluginInterface;
191#ifdef Q_OS_ANDROID
192 KisAndroidDonations *androidDonations {nullptr};
193#endif
194};
195
197{
198public:
199 ResetStarting(KisSplashScreen *splash, int fileCount)
200 : m_splash(splash)
201 , m_fileCount(fileCount)
202 {
203 }
204
206
207 if (m_splash) {
208 m_splash->hide();
209 m_splash->deleteLater();
210 }
211 }
212
215};
216
217
218KisApplication::KisApplication(const QString &key, int &argc, char **argv)
219 : QtSingleApplication(key, argc, argv)
220 , d(new Private)
221{
222#ifdef Q_OS_MACOS
224#endif
225
226 QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath());
227
228 setApplicationDisplayName("Krita");
229 setApplicationName("krita");
230 // Note: Qt docs suggest we set this, but if we do, we get resource paths of the form of krita/krita, which is weird.
231 // setOrganizationName("krita");
232 setOrganizationDomain("krita.org");
233
234 QString version = KritaVersionWrapper::versionString(true);
235 setApplicationVersion(version);
236 setWindowIcon(KisIconUtils::loadIcon("krita-branding"));
237
238 if (qgetenv("KRITA_NO_STYLE_OVERRIDE").isEmpty()) {
239
240#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
241 QStringList styles = QStringList() << "haiku" << "macintosh" << "breeze" << "fusion";
242#else
243 QStringList styles = QStringList() << "haiku" << "macos" << "breeze" << "fusion";
244#endif
245 if (!styles.contains(style()->objectName().toLower())) {
246 Q_FOREACH (const QString & style, styles) {
247 if (!setStyle(style)) {
248 qDebug() << "No" << style << "available.";
249 }
250 else {
251 qDebug() << "Set style" << style;
252 break;
253 }
254 }
255 }
256
257 // if style is set from config, try to load that
258 KisConfig cfg(true);
259 QString widgetStyleFromConfig = cfg.widgetStyle();
260 if(widgetStyleFromConfig != "") {
261 qApp->setStyle(widgetStyleFromConfig);
262#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
263 } else if (style()->objectName().toLower() == "macintosh") {
264 // if no configured style on macOS, default to Fusion
265 qApp->setStyle("fusion");
266 }
267#else
268 } else if (style()->objectName().toLower() == "macos") {
269 // if no configured style on macOS, default to Fusion
270 qApp->setStyle("fusion");
271 }
272#endif
273
274 }
275 else {
276 qDebug() << "Style override disabled, using" << style()->objectName();
277 }
278
282 {
283 d->extendedModifiersPluginInterface.reset(KisPlatformPluginInterfaceFactory::instance()->createExtendedModifiersMapper());
284 }
285
286 // store the style name
287 qApp->setProperty(currentUnderlyingStyleNameProperty, style()->objectName());
289
290
291#if KRITA_USE_SURFACE_COLOR_MANAGEMENT_API
292
297 struct PlatformWindowCreationFilter : QObject
298 {
299 using QObject::QObject;
300
301 bool eventFilter(QObject *watched, QEvent *event) override {
302 if (event->type() == QEvent::PlatformSurface) {
303 QWidget *widget = qobject_cast<QWidget*>(watched);
304 if (!widget) return false;
305
310 if (watched->property("krita_skip_srgb_surface_manager_assignment").toBool()) {
311 return false;
312 }
313
314 QPlatformSurfaceEvent *surfaceEvent = static_cast<QPlatformSurfaceEvent*>(event);
315 if (surfaceEvent->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated) {
316 QWindow *nativeWindow = widget->windowHandle();
317 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(widget->windowHandle(), false);
318
319 if (!nativeWindow->findChild<KisSRGBSurfaceColorSpaceManager*>()) {
321 }
322 }
323 }
324
325 return false;
326 }
327 };
328
329 this->installEventFilter(new PlatformWindowCreationFilter(this));
330#endif /* KRITA_USE_SURFACE_COLOR_MANAGEMENT_API */
331}
332
333#if defined(Q_OS_WIN) && defined(ENV32BIT)
334typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
335
336LPFN_ISWOW64PROCESS fnIsWow64Process;
337
338BOOL isWow64()
339{
340 BOOL bIsWow64 = FALSE;
341
342 //IsWow64Process is not available on all supported versions of Windows.
343 //Use GetModuleHandle to get a handle to the DLL that contains the function
344 //and GetProcAddress to get a pointer to the function if available.
345
346 fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
347 GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
348
349 if(0 != fnIsWow64Process)
350 {
351 if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
352 {
353 //handle error
354 }
355 }
356 return bIsWow64;
357}
358#endif
359
361{
362 Q_UNUSED(args)
363 // There are no globals to initialize from the arguments now. There used
364 // to be the `dpi` argument, but it doesn't do anything anymore.
365}
366
368{
369 // All Krita's resource types
370 KoResourcePaths::addAssetType("markers", "data", "/styles/");
371 KoResourcePaths::addAssetType("kis_pics", "data", "/pics/");
372 KoResourcePaths::addAssetType("kis_images", "data", "/images/");
373 KoResourcePaths::addAssetType("metadata_schema", "data", "/metadata/schemas/");
374 KoResourcePaths::addAssetType("gmic_definitions", "data", "/gmic/");
375 KoResourcePaths::addAssetType("kis_shortcuts", "data", "/shortcuts/");
376 KoResourcePaths::addAssetType("kis_actions", "data", "/actions");
377 KoResourcePaths::addAssetType("kis_actions", "data", "/pykrita");
378 KoResourcePaths::addAssetType("icc_profiles", "data", "/color/icc");
379 KoResourcePaths::addAssetType("icc_profiles", "data", "/profiles/");
381 KoResourcePaths::addAssetType("tags", "data", "/tags/");
382 KoResourcePaths::addAssetType("templates", "data", "/templates");
383 KoResourcePaths::addAssetType("pythonscripts", "data", "/pykrita");
384 KoResourcePaths::addAssetType("preset_icons", "data", "/preset_icons");
385#if defined HAVE_SEEXPR
386 KoResourcePaths::addAssetType(ResourceType::SeExprScripts, "data", "/seexpr_scripts/", true);
387#endif
388
389 // Make directories for all resources we can save, and tags
390 KoResourcePaths::saveLocation("data", "/asl/", true);
391 KoResourcePaths::saveLocation("data", "/css_styles/", true);
392 KoResourcePaths::saveLocation("data", "/input/", true);
393 KoResourcePaths::saveLocation("data", "/pykrita/", true);
394 KoResourcePaths::saveLocation("data", "/color-schemes/", true);
395 KoResourcePaths::saveLocation("data", "/preset_icons/", true);
396 KoResourcePaths::saveLocation("data", "/preset_icons/tool_icons/", true);
397 KoResourcePaths::saveLocation("data", "/preset_icons/emblem_icons/", true);
398}
399
400
401bool KisApplication::event(QEvent *event)
402{
403
404 #ifdef Q_OS_MACOS
405 if (event->type() == QEvent::FileOpen) {
406 QFileOpenEvent *openEvent = static_cast<QFileOpenEvent *>(event);
407 fileOpenRequested(openEvent->file());
408 return true;
409 }
410 #endif
411 return QApplication::event(event);
412}
413
414
416{
418
420 QStringList() << "application/x-krita-paintoppreset"));
421
422 reg->add(new KisResourceLoader<KisGbrBrush>(ResourceSubType::GbrBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/x-gimp-brush"));
423 reg->add(new KisResourceLoader<KisImagePipeBrush>(ResourceSubType::GihBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/x-gimp-brush-animated"));
424 reg->add(new KisResourceLoader<KisSvgBrush>(ResourceSubType::SvgBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/svg+xml"));
426
427 reg->add(new KisResourceLoader<KoSegmentGradient>(ResourceSubType::SegmentedGradients, ResourceType::Gradients, i18n("Gradients"), QStringList() << "application/x-gimp-gradient"));
429
440
441
442 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"}));
443 reg->add(new KisResourceLoader<KisWorkspaceResource>(ResourceType::Workspaces, ResourceType::Workspaces, i18n("Workspaces"), QStringList() << "application/x-krita-workspace"));
444 reg->add(new KisResourceLoader<KoSvgSymbolCollectionResource>(ResourceType::Symbols, ResourceType::Symbols, i18n("SVG symbol libraries"), QStringList() << "image/svg+xml"));
445 reg->add(new KisResourceLoader<KisWindowLayoutResource>(ResourceType::WindowLayouts, ResourceType::WindowLayouts, i18n("Window layouts"), QStringList() << "application/x-krita-windowlayout"));
446 reg->add(new KisResourceLoader<KisSessionResource>(ResourceType::Sessions, ResourceType::Sessions, i18n("Sessions"), QStringList() << "application/x-krita-session"));
447 reg->add(new KisResourceLoader<KoGamutMask>(ResourceType::GamutMasks, ResourceType::GamutMasks, i18n("Gamut masks"), QStringList() << "application/x-krita-gamutmasks"));
448#if defined HAVE_SEEXPR
449 reg->add(new KisResourceLoader<KisSeExprScript>(ResourceType::SeExprScripts, ResourceType::SeExprScripts, i18n("SeExpr Scripts"), QStringList() << "application/x-krita-seexpr-script"));
450#endif
451 // XXX: this covers only individual styles, not the library itself!
454 i18nc("Resource type name", "Layer styles"),
455 QStringList() << "application/x-photoshop-style"));
456
457 reg->add(new KisResourceLoader<KoCssStylePreset>(ResourceType::CssStyles, ResourceType::CssStyles, i18n("Style Presets"), QStringList() << "image/svg+xml"));
458
460
461#ifndef Q_OS_ANDROID
462 QString databaseLocation = KoResourcePaths::getAppDataLocation();
463#else
464 // Sqlite doesn't support content URIs (obviously). So, we make database location unconfigurable on android.
465 QString databaseLocation = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
466#endif
467
468 if (!KisResourceCacheDb::initialize(databaseLocation)) {
469 QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita: Fatal error"), i18n("%1\n\nKrita will quit now.", KisResourceCacheDb::lastError()));
470 }
471
473 connect(KisResourceLocator::instance(), SIGNAL(progressMessage(const QString&)), this, SLOT(setSplashScreenLoadingText(const QString&)));
474 if (r != KisResourceLocator::LocatorError::Ok && qApp->inherits("KisApplication")) {
475 QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita: Fatal error"), KisResourceLocator::instance()->errorMessages().join('\n') + i18n("\n\nKrita will quit now."));
476 return false;
477 }
478 return true;
479}
480
496
498{
499 KisConfig cfg(false);
500
501#if defined(Q_OS_WIN)
502#ifdef ENV32BIT
503
504 if (isWow64() && !cfg.readEntry("WarnedAbout32Bits", false)) {
505 QMessageBox::information(qApp->activeWindow(),
506 i18nc("@title:window", "Krita: Warning"),
507 i18n("You are running a 32 bits build on a 64 bits Windows.\n"
508 "This is not recommended.\n"
509 "Please download and install the x64 build instead."));
510 cfg.writeEntry("WarnedAbout32Bits", true);
511
512 }
513#endif
514#endif
515
516 QString opengl = cfg.canvasState();
517 if (opengl == "OPENGL_NOT_TRIED" ) {
518 cfg.setCanvasState("TRY_OPENGL");
519 }
520 else if (opengl != "OPENGL_SUCCESS" && opengl != "TRY_OPENGL") {
521 cfg.setCanvasState("OPENGL_FAILED");
522 }
523
524 setSplashScreenLoadingText(i18n("Initializing Globals..."));
525 processEvents();
526 initializeGlobals(args);
527
528 const bool doNewImage = args.doNewImage();
529 const bool doTemplate = args.doTemplate();
530 const bool exportAs = args.exportAs();
531 const bool exportSequence = args.exportSequence();
532 const QString exportFileName = args.exportFileName();
533
534 d->batchRun = (exportAs || exportSequence || !exportFileName.isEmpty());
535 const bool needsMainWindow = (!exportAs && !exportSequence);
536 // only show the mainWindow when no command-line mode option is passed
537 bool showmainWindow = (!exportAs && !exportSequence); // would be !batchRun;
538
539 const bool showSplashScreen = !d->batchRun && qEnvironmentVariableIsEmpty("NOSPLASH");
540 if (showSplashScreen && d->splashScreen) {
541 d->splashScreen->show();
542 d->splashScreen->repaint();
543 processEvents();
544 }
545
546 KConfigGroup group(KSharedConfig::openConfig(), "theme");
547#ifndef Q_OS_HAIKU
548 Digikam::ThemeManager themeManager;
549 themeManager.setCurrentTheme(group.readEntry("Theme", "Krita dark"));
550#endif
551
552 ResetStarting resetStarting(d->splashScreen, args.filenames().count()); // remove the splash when done
553 Q_UNUSED(resetStarting);
554
555 // Make sure we can save resources and tags
556 setSplashScreenLoadingText(i18n("Adding resource types..."));
557 processEvents();
559
560 setSplashScreenLoadingText(i18n("Loading plugins..."));
561 processEvents();
562 // Load the plugins
563 loadPlugins();
564
565 // Load all resources
566 setSplashScreenLoadingText(i18n("Loading resources..."));
567 processEvents();
568 if (!registerResources()) {
569 return false;
570 }
571
572 KisPart *kisPart = KisPart::instance();
573 if (needsMainWindow) {
574 // show a mainWindow asap, if we want that
575 setSplashScreenLoadingText(i18n("Loading Main Window..."));
576 processEvents();
577
578
579 bool sessionNeeded = true;
580 auto sessionMode = cfg.sessionOnStartup();
581
582 if (!args.session().isEmpty()) {
583 sessionNeeded = !kisPart->restoreSession(args.session());
584 } else if (sessionMode == KisConfig::SOS_ShowSessionManager) {
585 showmainWindow = false;
586 sessionNeeded = false;
587 kisPart->showSessionManager();
588 } else if (sessionMode == KisConfig::SOS_PreviousSession) {
589 KConfigGroup sessionCfg = KSharedConfig::openConfig()->group("session");
590 const QString &sessionName = sessionCfg.readEntry("previousSession");
591
592 sessionNeeded = !kisPart->restoreSession(sessionName);
593 }
594
595 if (sessionNeeded) {
596 kisPart->startBlankSession();
597 }
598
599 if (!args.windowLayout().isEmpty()) {
601 KisWindowLayoutResourceSP windowLayout = rserver->resource("", "", args.windowLayout());
602 if (windowLayout) {
603 windowLayout->applyLayout();
604 }
605 }
606
607 setSplashScreenLoadingText(i18n("Launching..."));
608
609 if (showmainWindow) {
610 d->mainWindow = kisPart->currentMainwindow();
611
612 if (!args.workspace().isEmpty()) {
614 KisWorkspaceResourceSP workspace = rserver->resource("", "", args.workspace());
615 if (workspace) {
616 d->mainWindow->restoreWorkspace(workspace);
617 }
618 }
619
620 if (args.canvasOnly()) {
621 d->mainWindow->viewManager()->switchCanvasOnly(true);
622 }
623
624 if (args.fullScreen()) {
625 d->mainWindow->showFullScreen();
626 }
627 } else {
628 d->mainWindow = kisPart->createMainWindow();
629 }
630 }
631 short int numberOfOpenDocuments = 0; // number of documents open
632
633 // Check for autosave files that can be restored, if we're not running a batch run (test)
634 if (!d->batchRun) {
636 }
637
638 setSplashScreenLoadingText(QString()); // done loading, so clear out label
639 processEvents();
640
641 //configure the unit manager
643 connect(this, &KisApplication::aboutToQuit, &KisSpinBoxUnitManagerFactory::clearUnitManagerBuilder); //ensure the builder is destroyed when the application leave.
644 //the new syntax slot syntax allow to connect to a non q_object static method.
645
646 // Long-press emulation.
649
650 // Create a new image, if needed
651 if (doNewImage) {
653 if (doc) {
654 kisPart->addDocument(doc);
655 d->mainWindow->addViewAndNotifyLoadingCompleted(doc);
656 }
657 }
658
659 // Get the command line arguments which we have to parse
660 int argsCount = args.filenames().count();
661 if (argsCount > 0) {
662 // Loop through arguments
663 for (int argNumber = 0; argNumber < argsCount; argNumber++) {
664 QString fileName = args.filenames().at(argNumber);
665 // are we just trying to open a template?
666 if (doTemplate) {
667 // called in mix with batch options? ignore and silently skip
668 if (d->batchRun) {
669 continue;
670 }
671 if (createNewDocFromTemplate(fileName, d->mainWindow)) {
672 ++numberOfOpenDocuments;
673 }
674 // now try to load
675 }
676 else {
677 if (exportAs) {
678 QString outputMimetype = KisMimeDatabase::mimeTypeForFile(exportFileName, false);
679 if (outputMimetype == "application/octetstream") {
680 dbgKrita << i18n("Mimetype not found, try using the -mimetype option") << Qt::endl;
681 return false;
682 }
683
684 KisDocument *doc = kisPart->createDocument();
685 doc->setFileBatchMode(d->batchRun);
686 bool result = doc->openPath(fileName);
687
688 if (!result) {
689 errKrita << "Could not load " << fileName << ":" << doc->errorMessage();
690 QTimer::singleShot(0, this, SLOT(quit()));
691 return false;
692 }
693
694 if (exportFileName.isEmpty()) {
695 errKrita << "Export destination is not specified for" << fileName << "Please specify export destination with --export-filename option";
696 QTimer::singleShot(0, this, SLOT(quit()));
697 return false;
698 }
699
700 qApp->processEvents(); // For vector layers to be updated
701
702 doc->setFileBatchMode(true);
703 doc->image()->waitForDone();
704
705 if (!doc->exportDocumentSync(exportFileName, outputMimetype.toLatin1())) {
706 errKrita << "Could not export " << fileName << "to" << exportFileName << ":" << doc->errorMessage();
707 }
708 QTimer::singleShot(0, this, SLOT(quit()));
709 return true;
710 }
711 else if (exportSequence) {
712 KisDocument *doc = kisPart->createDocument();
713 doc->setFileBatchMode(d->batchRun);
714 doc->openPath(fileName);
715 qApp->processEvents(); // For vector layers to be updated
716
717 if (!doc->image()->animationInterface()->hasAnimation()) {
718 errKrita << "This file has no animation." << Qt::endl;
719 QTimer::singleShot(0, this, SLOT(quit()));
720 return false;
721 }
722
723 doc->setFileBatchMode(true);
724 int sequenceStart = 0;
725
726
727 qDebug() << ppVar(exportFileName);
730 exportFileName,
731 sequenceStart,
732 false,
733 0);
734
735 exporter.setBatchMode(d->batchRun);
736
738 qDebug() << ppVar(result);
739
741 errKrita << i18n("Failed to render animation frames!") << Qt::endl;
742 }
743
744 QTimer::singleShot(0, this, SLOT(quit()));
745 return true;
746 }
747 else if (d->mainWindow) {
748 if (QFileInfo(fileName).fileName().endsWith(".bundle", Qt::CaseInsensitive)) {
749 d->mainWindow->installBundle(fileName);
750 }
751 else {
752 KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
753
754 if (d->mainWindow->openDocument(fileName, flags)) {
755 // Normal case, success
756 numberOfOpenDocuments++;
757 }
758 }
759 }
760 }
761 }
762 }
763
764 //add an image as file-layer
765 if (!args.fileLayer().isEmpty()){
766 if (d->mainWindow->viewManager()->image()){
767 KisFileLayer *fileLayer = new KisFileLayer(d->mainWindow->viewManager()->image(), "",
768 args.fileLayer(), KisFileLayer::None, "Bicubic",
769 d->mainWindow->viewManager()->image()->nextLayerName(i18n("File layer")), OPACITY_OPAQUE_U8);
770 QFileInfo fi(fileLayer->path());
771 if (fi.exists()){
772 KisNodeCommandsAdapter adapter(d->mainWindow->viewManager());
773 adapter.addNode(fileLayer, d->mainWindow->viewManager()->activeNode()->parent(),
774 d->mainWindow->viewManager()->activeNode());
775 }
776 else{
777 QMessageBox::warning(qApp->activeWindow(), i18nc("@title:window", "Krita:Warning"),
778 i18n("Cannot add %1 as a file layer: the file does not exist.", fileLayer->path()));
779 }
780 }
781 else if (this->isRunning()){
782 QMessageBox::warning(qApp->activeWindow(), i18nc("@title:window", "Krita:Warning"),
783 i18n("Cannot add the file layer: no document is open.\n\n"
784"You can create a new document using the --new-image option, or you can open an existing file.\n\n"
785"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)."));
786 }
787 else {
788 QMessageBox::warning(qApp->activeWindow(), i18nc("@title:window", "Krita: Warning"),
789 i18n("Cannot add the file layer: no document is open.\n"
790 "You can either create a new file using the --new-image option, or you can open an existing file."));
791 }
792 }
793
794 // fixes BUG:369308 - Krita crashing on splash screen when loading.
795 // trying to open a file before Krita has loaded can cause it to hang and crash
796 if (d->splashScreen) {
797 d->splashScreen->displayLinks(true);
798 d->splashScreen->displayRecentFiles(true);
799 }
800
801 Q_FOREACH(const QByteArray &message, d->earlyRemoteArguments) {
802 executeRemoteArguments(message, d->mainWindow);
803 }
804
806
807 // process File open event files
808 if (!d->earlyFileOpenEvents.isEmpty()) {
810 Q_FOREACH(QString fileName, d->earlyFileOpenEvents) {
811 d->mainWindow->openDocument(fileName, QFlags<KisMainWindow::OpenFlag>());
812 }
813 }
814
816
817 // not calling this before since the program will quit there.
818 return true;
819}
820
828
829void KisApplication::setSplashScreen(QWidget *splashScreen)
830{
831 d->splashScreen = qobject_cast<KisSplashScreen*>(splashScreen);
832}
833
834void KisApplication::setSplashScreenLoadingText(const QString &textToLoad)
835{
836 if (d->splashScreen) {
837 d->splashScreen->setLoadingText(textToLoad);
838 d->splashScreen->repaint();
839 }
840}
841
843{
844 if (d->splashScreen) {
845 // hide the splashscreen to see the dialog
846 d->splashScreen->hide();
847 }
848}
849
850
851bool KisApplication::notify(QObject *receiver, QEvent *event)
852{
853 try {
854 bool result = true;
855
861 AppRecursionInfo &info = s_recursionInfo->localData();
862
863 {
864 // QApplication::notify() can throw, so use RAII for counters
865 AppRecursionGuard guard(&info);
866
868
869 if (info.eventRecursionCount > 1) {
871 KIS_SAFE_ASSERT_RECOVER_NOOP(typedEvent->destination == receiver);
872
873 info.postponedSynchronizationEvents.emplace(KisSynchronizedConnectionEvent(*typedEvent));
874 } else {
875 result = QApplication::notify(receiver, event);
876 }
877 } else {
878 result = QApplication::notify(receiver, event);
879 }
880 }
881
882 if (!info.eventRecursionCount) {
884
885 }
886
887 return result;
888
889 } catch (std::exception &e) {
890 qWarning("Error %s sending event %i to object %s",
891 e.what(), event->type(), qPrintable(receiver->objectName()));
892 } catch (...) {
893 qWarning("Error <unknown> sending event %i to object %s",
894 event->type(), qPrintable(receiver->objectName()));
895 }
896 return false;
897}
898
900{
901 AppRecursionInfo &info = s_recursionInfo->localData();
902
903 while (!info.postponedSynchronizationEvents.empty()) {
904 // QApplication::notify() can throw, so use RAII for counters
905 AppRecursionGuard guard(&info);
906
909 KisSynchronizedConnectionEvent typedEvent = info.postponedSynchronizationEvents.front();
910 info.postponedSynchronizationEvents.pop();
911
912 if (!typedEvent.destination) {
913 qWarning() << "WARNING: the destination object of KisSynchronizedConnection has been destroyed during postponed delivery";
914 continue;
915 }
916
917 QApplication::notify(typedEvent.destination, &typedEvent);
918 }
919}
920
922{
923 if (qEnvironmentVariableIsSet("STEAMAPPID") || qEnvironmentVariableIsSet("SteamAppId")) {
924 return true;
925 }
926
927 if (applicationDirPath().toLower().contains("steam")) {
928 return true;
929 }
930
931#ifdef Q_OS_WIN
932 // This is also true for user-installed MSIX, but that's
933 // likely only true in institutional situations, where
934 // we don't want to show the beginning banner either.
936 return true;
937 }
938#endif
939
940#ifdef Q_OS_MACOS
941 KisMacosEntitlements entitlements;
942 if (entitlements.sandbox()) {
943 return true;
944 }
945#endif
946
947 return false;
948}
949
951{
956#if !defined(HIDE_SAFE_ASSERTS) || defined(CRASH_ON_SAFE_ASSERTS)
957
958 auto verifyTypeRegistered = [] (const char *type) {
959 const int typeId = QMetaType::type(type);
960
961 if (typeId <= 0) {
962 qFatal("ERROR: type-id for metatype %s is not found", type);
963 }
964
965 if (!QMetaType::isRegistered(typeId)) {
966 qFatal("ERROR: metatype %s is not registered", type);
967 }
968 };
969
970 verifyTypeRegistered("KisBrushSP");
971 verifyTypeRegistered("KoSvgText::AutoValue");
972 verifyTypeRegistered("KoSvgText::BackgroundProperty");
973 verifyTypeRegistered("KoSvgText::StrokeProperty");
974 verifyTypeRegistered("KoSvgText::TextTransformInfo");
975 verifyTypeRegistered("KoSvgText::TextIndentInfo");
976 verifyTypeRegistered("KoSvgText::TabSizeInfo");
977 verifyTypeRegistered("KoSvgText::LineHeightInfo");
978 verifyTypeRegistered("KisPaintopLodLimitations");
979 verifyTypeRegistered("KisImageSP");
980 verifyTypeRegistered("KisImageSignalType");
981 verifyTypeRegistered("KisNodeSP");
982 verifyTypeRegistered("KisNodeList");
983 verifyTypeRegistered("KisPaintDeviceSP");
984 verifyTypeRegistered("KisTimeSpan");
985 verifyTypeRegistered("KoColor");
986 verifyTypeRegistered("KoResourceSP");
987 verifyTypeRegistered("KoResourceCacheInterfaceSP");
988 verifyTypeRegistered("KisAsyncAnimationRendererBase::CancelReason");
989 verifyTypeRegistered("KisGridConfig");
990 verifyTypeRegistered("KisGuidesConfig");
991 verifyTypeRegistered("KisUpdateInfoSP");
992 verifyTypeRegistered("KisToolChangesTrackerDataSP");
993 verifyTypeRegistered("QVector<QImage>");
994 verifyTypeRegistered("SnapshotDirInfoList");
995 verifyTypeRegistered("TransformTransactionProperties");
996 verifyTypeRegistered("ToolTransformArgs");
997 verifyTypeRegistered("QPainterPath");
998#endif
999}
1000
1001void KisApplication::executeRemoteArguments(QByteArray message, KisMainWindow *mainWindow)
1002{
1004 const bool doTemplate = args.doTemplate();
1005 const bool doNewImage = args.doNewImage();
1006 const int argsCount = args.filenames().count();
1007 bool documentCreated = false;
1008
1009 // Create a new image, if needed
1010 if (doNewImage) {
1012 if (doc) {
1014 d->mainWindow->addViewAndNotifyLoadingCompleted(doc);
1015 }
1016 }
1017 if (argsCount > 0) {
1018 // Loop through arguments
1019 for (int argNumber = 0; argNumber < argsCount; ++argNumber) {
1020 QString filename = args.filenames().at(argNumber);
1021 // are we just trying to open a template?
1022 if (doTemplate) {
1023 documentCreated |= createNewDocFromTemplate(filename, mainWindow);
1024 }
1025 else if (QFile(filename).exists()) {
1026 KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
1027 documentCreated |= mainWindow->openDocument(filename, flags);
1028 }
1029 }
1030 }
1031
1032 //add an image as file-layer if called in another process and singleApplication is enabled
1033 if (!args.fileLayer().isEmpty()){
1034 if (argsCount > 0 && !documentCreated){
1035 //arg was passed but document was not created so don't add the file layer.
1036 QMessageBox::warning(mainWindow, i18nc("@title:window", "Krita:Warning"),
1037 i18n("Couldn't open file %1",args.filenames().at(argsCount - 1)));
1038 }
1039 else if (mainWindow->viewManager()->image()){
1040 KisFileLayer *fileLayer = new KisFileLayer(mainWindow->viewManager()->image(), "",
1041 args.fileLayer(), KisFileLayer::None, "Bicubic",
1042 mainWindow->viewManager()->image()->nextLayerName(i18n("File layer")), OPACITY_OPAQUE_U8);
1043 QFileInfo fi(fileLayer->path());
1044 if (fi.exists()){
1045 KisNodeCommandsAdapter adapter(d->mainWindow->viewManager());
1046 adapter.addNode(fileLayer, d->mainWindow->viewManager()->activeNode()->parent(),
1047 d->mainWindow->viewManager()->activeNode());
1048 }
1049 else{
1050 QMessageBox::warning(mainWindow, i18nc("@title:window", "Krita:Warning"),
1051 i18n("Cannot add %1 as a file layer: the file does not exist.", fileLayer->path()));
1052 }
1053 }
1054 else {
1055 QMessageBox::warning(mainWindow, i18nc("@title:window", "Krita:Warning"),
1056 i18n("Cannot add the file layer: no document is open."));
1057 }
1058 }
1059}
1060
1061
1062void KisApplication::remoteArguments(const QString &message)
1063{
1064 // check if we have any mainwindow
1065 KisMainWindow *mw = qobject_cast<KisMainWindow*>(qApp->activeWindow());
1066
1067 if (!mw && KisPart::instance()->mainWindows().size() > 0) {
1068 mw = KisPart::instance()->mainWindows().first();
1069 }
1070
1071 const QByteArray unpackedMessage =
1072 QByteArray::fromBase64(message.toLatin1());
1073
1074 if (!mw) {
1075 d->earlyRemoteArguments << unpackedMessage;
1076 return;
1077 }
1078 executeRemoteArguments(unpackedMessage, mw);
1079}
1080
1082{
1083 if (!d->mainWindow) {
1084 d->earlyFileOpenEvents.append(url);
1085 return;
1086 }
1087
1088 KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
1089 d->mainWindow->openDocument(url, flags);
1090}
1091
1092
1094{
1095 if (enabled && !d->longPressEventFilter) {
1096 d->longPressEventFilter = new KisLongPressEventFilter(this);
1097 installEventFilter(d->longPressEventFilter);
1098 } else if (!enabled && d->longPressEventFilter) {
1099 removeEventFilter(d->longPressEventFilter);
1100 d->longPressEventFilter->deleteLater();
1101 d->longPressEventFilter = nullptr;
1102 }
1103}
1104
1106{
1107 if (d->batchRun) return;
1108
1110
1111 // Check for autosave files from a previous run. There can be several, and
1112 // we want to offer a restore for every one. Including a nice thumbnail!
1113
1114 // Hidden autosave files
1115 QStringList filters = QStringList() << QString(".krita-*-*-autosave.kra");
1116
1117 // all autosave files for our application
1118 QStringList autosaveFiles = dir.entryList(filters, QDir::Files | QDir::Hidden);
1119
1120 // Visible autosave files
1121 filters = QStringList() << QString("krita-*-*-autosave.kra");
1122 autosaveFiles += dir.entryList(filters, QDir::Files);
1123
1124 // Allow the user to make their selection
1125 if (autosaveFiles.size() > 0) {
1126 if (d->splashScreen) {
1127 // hide the splashscreen to see the dialog
1128 d->splashScreen->hide();
1129 }
1130 d->autosaveDialog = new KisAutoSaveRecoveryDialog(autosaveFiles, activeWindow());
1131 QDialog::DialogCode result = (QDialog::DialogCode) d->autosaveDialog->exec();
1132
1133 if (result == QDialog::Accepted) {
1134 QStringList filesToRecover = d->autosaveDialog->recoverableFiles();
1135 Q_FOREACH (const QString &autosaveFile, autosaveFiles) {
1136 if (!filesToRecover.contains(autosaveFile)) {
1137 KisUsageLogger::log(QString("Removing autosave file %1").arg(dir.absolutePath() + "/" + autosaveFile));
1138 QFile::remove(dir.absolutePath() + "/" + autosaveFile);
1139 }
1140 }
1141 autosaveFiles = filesToRecover;
1142 } else {
1143 autosaveFiles.clear();
1144 }
1145
1146 if (autosaveFiles.size() > 0) {
1147 QList<QString> autosavePaths;
1148 Q_FOREACH (const QString &autoSaveFile, autosaveFiles) {
1149 const QString path = dir.absolutePath() + QLatin1Char('/') + autoSaveFile;
1150 autosavePaths << path;
1151 }
1152 if (d->mainWindow) {
1153 Q_FOREACH (const QString &path, autosavePaths) {
1154 KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
1155 d->mainWindow->openDocument(path, flags | KisMainWindow::RecoveryFile);
1156 }
1157 }
1158 }
1159 // cleanup
1160 delete d->autosaveDialog;
1161 d->autosaveDialog = nullptr;
1162 }
1163}
1164
1165bool KisApplication::createNewDocFromTemplate(const QString &fileName, KisMainWindow *mainWindow)
1166{
1167 QString templatePath;
1168
1169 if (QFile::exists(fileName)) {
1170 templatePath = fileName;
1171 dbgUI << "using full path...";
1172 }
1173 else {
1174 QString desktopName(fileName);
1175 const QString templatesResourcePath = QStringLiteral("templates/");
1176
1177 QStringList paths = KoResourcePaths::findAllAssets("data", templatesResourcePath + "*/" + desktopName);
1178 if (paths.isEmpty()) {
1179 paths = KoResourcePaths::findAllAssets("data", templatesResourcePath + desktopName);
1180 }
1181
1182 if (paths.isEmpty()) {
1183 QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita"),
1184 i18n("No template found for: %1", desktopName));
1185 } else if (paths.count() > 1) {
1186 QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita"),
1187 i18n("Too many templates found for: %1", desktopName));
1188 } else {
1189 templatePath = paths.at(0);
1190 }
1191 }
1192
1193 if (!templatePath.isEmpty()) {
1194 KDesktopFile templateInfo(templatePath);
1195
1196 KisMainWindow::OpenFlags batchFlags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
1197 if (mainWindow->openDocument(templatePath, KisMainWindow::Import | batchFlags)) {
1198 dbgUI << "Template loaded...";
1199 return true;
1200 }
1201 else {
1202 QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita"),
1203 i18n("Template %1 failed to load.", fileName));
1204 }
1205 }
1206
1207 return false;
1208}
1209
1211{
1212 KIS_ASSERT_RECOVER_RETURN(qApp->thread() == QThread::currentThread());
1213
1214 KSharedConfigPtr config = KSharedConfig::openConfig();
1215 config->markAsClean();
1216
1217 // find user settings file
1218 const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
1219 QString kritarcPath = configPath + QStringLiteral("/kritarc");
1220
1221 QFile kritarcFile(kritarcPath);
1222
1223 if (kritarcFile.exists()) {
1224 if (kritarcFile.open(QFile::ReadWrite)) {
1225 QString backupKritarcPath = kritarcPath + QStringLiteral(".backup");
1226
1227 QFile backupKritarcFile(backupKritarcPath);
1228
1229 if (backupKritarcFile.exists()) {
1230 backupKritarcFile.remove();
1231 }
1232
1233 QMessageBox::information(qApp->activeWindow(),
1234 i18nc("@title:window", "Krita"),
1235 i18n("Krita configurations reset!\n\n"
1236 "Backup file was created at: %1\n\n"
1237 "Restart Krita for changes to take effect.",
1238 backupKritarcPath),
1239 QMessageBox::Ok, QMessageBox::Ok);
1240
1241 // clear file
1242 kritarcFile.rename(backupKritarcPath);
1243
1244 kritarcFile.close();
1245 }
1246 else {
1247 QMessageBox::warning(qApp->activeWindow(),
1248 i18nc("@title:window", "Krita"),
1249 i18n("Failed to clear %1\n\n"
1250 "Please make sure no other program is using the file and try again.",
1251 kritarcPath),
1252 QMessageBox::Ok, QMessageBox::Ok);
1253 }
1254 }
1255
1256 // reload from disk; with the user file settings cleared,
1257 // this should load any default configuration files shipping with the program
1258 config->reparseConfiguration();
1259 config->sync();
1260
1261 // Restore to default workspace
1262 KConfigGroup cfg = KSharedConfig::openConfig()->group("MainWindow");
1263
1264 QString currentWorkspace = cfg.readEntry<QString>("CurrentWorkspace", "Default");
1266 KisWorkspaceResourceSP workspace = rserver->resource("", "", currentWorkspace);
1267
1268 if (workspace) {
1269 d->mainWindow->restoreWorkspace(workspace);
1270 }
1271}
1272
1274{
1275 bool ok = QMessageBox::question(qApp->activeWindow(),
1276 i18nc("@title:window", "Krita"),
1277 i18n("Do you want to clear the settings file?"),
1278 QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes;
1279 if (ok) {
1280 resetConfig();
1281 }
1282}
1283
1285{
1286 return d->extendedModifiersPluginInterface.data();
1287}
1288
1289#ifdef Q_OS_ANDROID
1290KisAndroidDonations *KisApplication::androidDonations()
1291{
1292 if (!d->androidDonations) {
1293 d->androidDonations = new KisAndroidDonations(this);
1294 d->androidDonations->syncState();
1295 }
1296 return d->androidDonations;
1297}
1298#endif
QList< QString > QStringList
Q_GLOBAL_STATIC(KisStoragePluginRegistry, s_instance)
const quint8 OPACITY_OPAQUE_U8
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
void setCurrentTheme(const QString &name)
static KisActionRegistry * instance()
QVector< QByteArray > earlyRemoteArguments
QPointer< KisSplashScreen > splashScreen
QScopedPointer< KisExtendedModifiersMapperPluginInterface > extendedModifiersPluginInterface
QPointer< KisMainWindow > mainWindow
QVector< QString > earlyFileOpenEvents
ResetStarting(KisSplashScreen *splash, int fileCount)
QPointer< KisSplashScreen > m_splash
Base class for the Krita app.
bool notify(QObject *receiver, QEvent *event) override
Overridden to handle exceptions from event handlers.
void setSplashScreenLoadingText(const QString &)
bool event(QEvent *event) override
virtual bool start(const KisApplicationArguments &args)
void remoteArguments(const QString &message)
void executeRemoteArguments(QByteArray message, KisMainWindow *mainWindow)
KisApplication(const QString &key, int &argc, char **argv)
KisExtendedModifiersMapperPluginInterface * extendedModifiersPluginInterface()
void slotSetLongPress(bool enabled)
void setSplashScreen(QWidget *splash)
void fileOpenRequested(const QString &url)
QScopedPointer< Private > d
~KisApplication() override
void initializeGlobals(const KisApplicationArguments &args)
bool createNewDocFromTemplate(const QString &fileName, KisMainWindow *m_mainWindow)
static void verifyMetatypeRegistration()
void processPostponedSynchronizationEvents()
Result regenerateRange(KisViewManager *viewManager) override
start generation of frames and (if not in batch mode) show the dialog
void setBatchMode(bool value)
setting batch mode to true will prevent any dialogs or message boxes from showing on screen....
void sigLongPressChanged(bool enabled)
static KisConfigNotifier * instance()
QString widgetStyle(bool defaultValue=false)
void setCanvasState(const QString &state) const
void writeEntry(const QString &name, const T &value)
Definition kis_config.h:779
SessionOnStartup sessionOnStartup(bool defaultValue=false) const
bool longPressEnabled(bool defaultValue=false) const
T readEntry(const QString &name, const T &defaultValue=T())
Definition kis_config.h:789
QString canvasState(bool defaultValue=false) const
@ SOS_PreviousSession
Definition kis_config.h:345
@ SOS_ShowSessionManager
Definition kis_config.h:346
void setFileBatchMode(const bool batchMode)
KisImageSP image
QString errorMessage() const
bool exportDocumentSync(const QString &path, const QByteArray &mimeType, KisPropertiesConfigurationSP exportConfiguration=0)
bool openPath(const QString &path, OpenFlags flags=None)
openPath Open a Path
The KisFileLayer class loads a particular file as a layer into the layer stack.
QString path() const
static KisFilterRegistry * instance()
static KisGeneratorRegistry * instance()
const KisTimeSpan & documentPlaybackRange() const
documentPlaybackRange
void waitForDone()
KisImageAnimationInterface * animationInterface() const
QString nextLayerName(const QString &baseName="") const
Definition kis_image.cc:715
Main window for Krita.
bool openDocument(const QString &path, OpenFlags flags)
KisViewManager * viewManager
static KisMetadataBackendRegistry * instance()
static QString mimeTypeForFile(const QString &file, bool checkExistingFiles=true)
Find the mimetype for the given filename. The filename must include a suffix.
static QString mimeTypeForSuffix(const QString &suffix)
Find the mimetype for a given extension. The extension may have the form "*.xxx" or "xxx".
void addNode(KisNodeSP node, KisNodeSP parent, KisNodeSP aboveThis, KisImageLayerAddCommand::Flags flags=KisImageLayerAddCommand::DoRedoUpdates|KisImageLayerAddCommand::DoUndoUpdates)
static KisPaintOpRegistry * instance()
QList< QPointer< KisMainWindow > > mainWindows
Definition KisPart.cpp:107
static KisPart * instance()
Definition KisPart.cpp:131
bool restoreSession(const QString &sessionName)
Definition KisPart.cpp:668
void addDocument(KisDocument *document, bool notify=true)
Definition KisPart.cpp:211
KisMainWindow * currentMainwindow() const
Definition KisPart.cpp:483
void startBlankSession()
Definition KisPart.cpp:660
KisDocument * createDocument() const
Definition KisPart.cpp:230
void showSessionManager()
Definition KisPart.cpp:650
KisMainWindow * createMainWindow(QUuid id=QUuid())
Definition KisPart.cpp:260
static KisPlatformPluginInterfaceFactory * instance()
static void performHouseKeepingOnExit()
perform optimize and vacuum when necessary
static void deleteTemporaryResources()
Delete all storages that are Unknown or Memory and all resources that are marked temporary or belong ...
static bool initialize(const QString &location)
initializes the database and updates the scheme if necessary. Does not actually fill the database wit...
static QString lastError()
lastError returns the last SQL error.
The KisResourceLoaderRegistry class manages the loader plugins for resources. Every resource can be l...
static KisResourceLoaderRegistry * instance()
void registerFixup(int priority, ResourceCacheFixup *fixup)
LocatorError initialize(const QString &installationResourcesLocation)
initialize Setup the resource locator for use.
static KisResourceLocator * instance()
static KisResourceServerProvider * instance()
KoResourceServer< KisWorkspaceResource > * workspaceServer()
KoResourceServer< KisWindowLayoutResource > * windowLayoutServer()
static KisSRGBSurfaceColorSpaceManager * tryCreateForCurrentPlatform(QWidget *widget)
static void setDefaultUnitManagerBuilder(KisSpinBoxUnitManagerBuilder *pBuilder)
set a builder the factory can use. The factory should take on the lifecycle of the builder,...
static void registerSynchronizedEventBarrier(std::function< void()> callback)
static void log(const QString &message)
Logs with date/time.
static QString screenInformation()
Returns information about all available screens.
static void writeSysInfo(const QString &message)
Writes to the system information file and Krita log.
KisImageWSP image() const
Return the image this view is displaying.
static KoDockRegistry * instance()
static QString getAppDataLocation()
static void addAssetType(const QString &type, const char *basetype, const QString &relativeName, bool priority=true)
static QString getApplicationRoot()
static QStringList findAllAssets(const QString &type, const QString &filter=QString(), SearchOptions options=NoSearchOptions)
static QString saveLocation(const QString &type, const QString &suffix=QString(), bool create=true)
QSharedPointer< T > resource(const QString &md5, const QString &fileName, const QString &name)
resource retrieves a resource. If the md5sum is not empty, the resource will only be retrieved if a r...
static KoShapeRegistry * instance()
static KoToolRegistry * instance()
The QtSingleApplication class provides an API to detect and communicate with running instances of an ...
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define KIS_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:75
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
#define dbgKrita
Definition kis_debug.h:45
#define errKrita
Definition kis_debug.h:107
#define dbgUI
Definition kis_debug.h:52
#define ppVar(var)
Definition kis_debug.h:155
constexpr const char * currentUnderlyingStyleNameProperty
Definition kis_global.h:116
QIcon loadIcon(const QString &name)
KRITAVERSION_EXPORT QString versionString(bool checkGit=false)
const QString GbrBrushes
const QString PngBrushes
const QString GihBrushes
const QString SvgBrushes
const QString StopGradients
const QString KritaPaintOpPresets
const QString SegmentedGradients
const QString Palettes
const QString Symbols
const QString FilterEffects
const QString CssStyles
const QString LayerStyles
const QString Brushes
const QString GamutMasks
const QString Patterns
const QString SeExprScripts
const QString Gradients
const QString Workspaces
const QString WindowLayouts
const QString Sessions
const QString PaintOpPresets
void setMouseCoalescingEnabled(bool enabled)
Definition osx.mm:17
static KisApplicationArguments deserialize(QByteArray &serialized)
KisDocument * createDocumentFromArguments() const
KisNodeWSP parent
Definition kis_node.cpp:86
Event type used for synchronizing connection in KisSynchronizedConnection.
static KoColorSpaceRegistry * instance()