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>
108
112
115#include "kis_file_layer.h"
116#include "kis_group_layer.h"
119#include <QThreadStorage>
121
122#include <kis_psd_layer_style.h>
123
124#include <config-seexpr.h>
125#include <config-safe-asserts.h>
126
129
130#include <config-qt-patches-present.h>
131#include <config-use-surface-color-management-api.h>
132
133#if KRITA_USE_SURFACE_COLOR_MANAGEMENT_API
134
135#include <QWindow>
136#include <QPlatformSurfaceEvent>
138
139#endif /* KRITA_USE_SURFACE_COLOR_MANAGEMENT_API */
140
141namespace {
142const QTime appStartTime(QTime::currentTime());
143}
144
145namespace {
146struct AppRecursionInfo {
147 ~AppRecursionInfo() {
148 KIS_SAFE_ASSERT_RECOVER_NOOP(!eventRecursionCount);
149 KIS_SAFE_ASSERT_RECOVER_NOOP(postponedSynchronizationEvents.empty());
150 }
151
152 int eventRecursionCount {0};
153 std::queue<KisSynchronizedConnectionEvent> postponedSynchronizationEvents;
154};
155
156struct AppRecursionGuard {
157 AppRecursionGuard(AppRecursionInfo *info)
158 : m_info(info)
159 {
160 m_info->eventRecursionCount++;
161 }
162
163 ~AppRecursionGuard()
164 {
165 m_info->eventRecursionCount--;
166 }
167private:
168 AppRecursionInfo *m_info {0};
169};
170
171}
172
179Q_GLOBAL_STATIC(QThreadStorage<AppRecursionInfo>, s_recursionInfo)
180
182{
183public:
186 KisAutoSaveRecoveryDialog *autosaveDialog {0};
187 KisLongPressEventFilter *longPressEventFilter {nullptr};
188 QPointer<KisMainWindow> mainWindow; // The first mainwindow we create on startup
189 bool batchRun {false};
192 QScopedPointer<KisExtendedModifiersMapperPluginInterface> extendedModifiersPluginInterface;
193#ifdef Q_OS_ANDROID
194 KisAndroidDonations *androidDonations {nullptr};
195#endif
196};
197
199{
200public:
201 ResetStarting(KisSplashScreen *splash, int fileCount)
202 : m_splash(splash)
203 , m_fileCount(fileCount)
204 {
205 }
206
208
209 if (m_splash) {
210 m_splash->hide();
211 m_splash->deleteLater();
212 }
213 }
214
217};
218
219
220KisApplication::KisApplication(const QString &key, int &argc, char **argv)
221 : QtSingleApplication(key, argc, argv)
222 , d(new Private)
223{
224#ifdef Q_OS_MACOS
226#endif
227
228 QCoreApplication::addLibraryPath(QCoreApplication::applicationDirPath());
229
230 setApplicationDisplayName("Krita");
231 setApplicationName("krita");
232 // Note: Qt docs suggest we set this, but if we do, we get resource paths of the form of krita/krita, which is weird.
233 // setOrganizationName("krita");
234 setOrganizationDomain("krita.org");
235
236 QString version = KritaVersionWrapper::versionString(true);
237 setApplicationVersion(version);
238#ifndef Q_OS_MACOS
239 setWindowIcon(KisIconUtils::loadIcon("krita-branding"));
240#endif
241
242 if (qgetenv("KRITA_NO_STYLE_OVERRIDE").isEmpty()) {
243
244#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
245 QStringList styles = QStringList() << "haiku" << "macintosh" << "breeze" << "fusion";
246#else
247 QStringList styles = QStringList() << "haiku" << "macos" << "breeze" << "fusion";
248#endif
249 if (!styles.contains(style()->objectName().toLower())) {
250 Q_FOREACH (const QString & style, styles) {
251 if (!setStyle(style)) {
252 qDebug() << "No" << style << "available.";
253 }
254 else {
255 qDebug() << "Set style" << style;
256 break;
257 }
258 }
259 }
260
261 // if style is set from config, try to load that
262 KisConfig cfg(true);
263 QString widgetStyleFromConfig = cfg.widgetStyle();
264 if(widgetStyleFromConfig != "") {
265 qApp->setStyle(widgetStyleFromConfig);
266#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
267 } else if (style()->objectName().toLower() == "macintosh") {
268 // if no configured style on macOS, default to Fusion
269 qApp->setStyle("fusion");
270 }
271#else
272 } else if (style()->objectName().toLower() == "macos") {
273 // if no configured style on macOS, default to Fusion
274 qApp->setStyle("fusion");
275 }
276#endif
277
278 }
279 else {
280 qDebug() << "Style override disabled, using" << style()->objectName();
281 }
282
286 {
287 d->extendedModifiersPluginInterface.reset(KisPlatformPluginInterfaceFactory::instance()->createExtendedModifiersMapper());
288 }
289
290 // store the style name
291 qApp->setProperty(currentUnderlyingStyleNameProperty, style()->objectName());
293
294
295#if KRITA_USE_SURFACE_COLOR_MANAGEMENT_API
296
301 struct PlatformWindowCreationFilter : QObject
302 {
303 using QObject::QObject;
304
305 bool eventFilter(QObject *watched, QEvent *event) override {
306 if (event->type() == QEvent::PlatformSurface) {
307 QWidget *widget = qobject_cast<QWidget*>(watched);
308 if (!widget) return false;
309
314 if (watched->property("krita_skip_srgb_surface_manager_assignment").toBool()) {
315 return false;
316 }
317
318 QPlatformSurfaceEvent *surfaceEvent = static_cast<QPlatformSurfaceEvent*>(event);
319 if (surfaceEvent->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated) {
320 QWindow *nativeWindow = widget->windowHandle();
321 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(widget->windowHandle(), false);
322
323 if (!nativeWindow->findChild<KisSRGBSurfaceColorSpaceManager*>()) {
325 }
326 }
327 }
328
329 return false;
330 }
331 };
332
333 this->installEventFilter(new PlatformWindowCreationFilter(this));
334#endif /* KRITA_USE_SURFACE_COLOR_MANAGEMENT_API */
335}
336
337#if defined(Q_OS_WIN) && defined(ENV32BIT)
338typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
339
340LPFN_ISWOW64PROCESS fnIsWow64Process;
341
342BOOL isWow64()
343{
344 BOOL bIsWow64 = FALSE;
345
346 //IsWow64Process is not available on all supported versions of Windows.
347 //Use GetModuleHandle to get a handle to the DLL that contains the function
348 //and GetProcAddress to get a pointer to the function if available.
349
350 fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
351 GetModuleHandle(TEXT("kernel32")),"IsWow64Process");
352
353 if(0 != fnIsWow64Process)
354 {
355 if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
356 {
357 //handle error
358 }
359 }
360 return bIsWow64;
361}
362#endif
363
365{
366 Q_UNUSED(args)
367 // There are no globals to initialize from the arguments now. There used
368 // to be the `dpi` argument, but it doesn't do anything anymore.
369}
370
372{
373 // All Krita's resource types
374 KoResourcePaths::addAssetType("markers", "data", "/styles/");
375 KoResourcePaths::addAssetType("kis_pics", "data", "/pics/");
376 KoResourcePaths::addAssetType("kis_images", "data", "/images/");
377 KoResourcePaths::addAssetType("metadata_schema", "data", "/metadata/schemas/");
378 KoResourcePaths::addAssetType("gmic_definitions", "data", "/gmic/");
379 KoResourcePaths::addAssetType("kis_shortcuts", "data", "/shortcuts/");
380 KoResourcePaths::addAssetType("kis_actions", "data", "/actions");
381 KoResourcePaths::addAssetType("kis_actions", "data", "/pykrita");
382 KoResourcePaths::addAssetType("icc_profiles", "data", "/color/icc");
383 KoResourcePaths::addAssetType("icc_profiles", "data", "/profiles/");
384 KoResourcePaths::addAssetType("tags", "data", "/tags/");
385 KoResourcePaths::addAssetType("templates", "data", "/templates");
386 KoResourcePaths::addAssetType("pythonscripts", "data", "/pykrita");
387 KoResourcePaths::addAssetType("preset_icons", "data", "/preset_icons");
388#if defined HAVE_SEEXPR
389 KoResourcePaths::addAssetType(ResourceType::SeExprScripts, "data", "/seexpr_scripts/", true);
390#endif
391
392 // Make directories for all resources we can save, and tags
393 KoResourcePaths::saveLocation("data", "/asl/", true);
394 KoResourcePaths::saveLocation("data", "/css_styles/", true);
395 KoResourcePaths::saveLocation("data", "/input/", true);
396 KoResourcePaths::saveLocation("data", "/pykrita/", true);
397 KoResourcePaths::saveLocation("data", "/color-schemes/", true);
398 KoResourcePaths::saveLocation("data", "/preset_icons/", true);
399 KoResourcePaths::saveLocation("data", "/preset_icons/tool_icons/", true);
400 KoResourcePaths::saveLocation("data", "/preset_icons/emblem_icons/", true);
401}
402
403
404bool KisApplication::event(QEvent *event)
405{
406
407 #ifdef Q_OS_MACOS
408 if (event->type() == QEvent::FileOpen) {
409 QFileOpenEvent *openEvent = static_cast<QFileOpenEvent *>(event);
410 fileOpenRequested(openEvent->file());
411 return true;
412 }
413 #endif
414 return QApplication::event(event);
415}
416
417
419{
421
423 QStringList() << "application/x-krita-paintoppreset"));
424
425 reg->add(new KisResourceLoader<KisGbrBrush>(ResourceSubType::GbrBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/x-gimp-brush"));
426 reg->add(new KisResourceLoader<KisImagePipeBrush>(ResourceSubType::GihBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/x-gimp-brush-animated"));
427 reg->add(new KisResourceLoader<KisSvgBrush>(ResourceSubType::SvgBrushes, ResourceType::Brushes, i18n("Brush tips"), QStringList() << "image/svg+xml"));
429
430 reg->add(new KisResourceLoader<KoSegmentGradient>(ResourceSubType::SegmentedGradients, ResourceType::Gradients, i18n("Gradients"), QStringList() << "application/x-gimp-gradient"));
432
443
444
445 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"}));
446 reg->add(new KisResourceLoader<KisWorkspaceResource>(ResourceType::Workspaces, ResourceType::Workspaces, i18n("Workspaces"), QStringList() << "application/x-krita-workspace"));
447 reg->add(new KisResourceLoader<KoSvgSymbolCollectionResource>(ResourceType::Symbols, ResourceType::Symbols, i18n("SVG symbol libraries"), QStringList() << "image/svg+xml"));
448 reg->add(new KisResourceLoader<KisWindowLayoutResource>(ResourceType::WindowLayouts, ResourceType::WindowLayouts, i18n("Window layouts"), QStringList() << "application/x-krita-windowlayout"));
449 reg->add(new KisResourceLoader<KisSessionResource>(ResourceType::Sessions, ResourceType::Sessions, i18n("Sessions"), QStringList() << "application/x-krita-session"));
450 reg->add(new KisResourceLoader<KoGamutMask>(ResourceType::GamutMasks, ResourceType::GamutMasks, i18n("Gamut masks"), QStringList() << "application/x-krita-gamutmasks"));
451#if defined HAVE_SEEXPR
452 reg->add(new KisResourceLoader<KisSeExprScript>(ResourceType::SeExprScripts, ResourceType::SeExprScripts, i18n("SeExpr Scripts"), QStringList() << "application/x-krita-seexpr-script"));
453#endif
454 // XXX: this covers only individual styles, not the library itself!
457 i18nc("Resource type name", "Layer styles"),
458 QStringList() << "application/x-photoshop-style"));
459
460 reg->add(new KisResourceLoader<KoFontFamily>(ResourceType::FontFamilies, ResourceType::FontFamilies, i18n("Font Families"), QStringList() << "application/x-font-ttf" << "application/x-font-otf"));
461 reg->add(new KisResourceLoader<KoCssStylePreset>(ResourceType::CssStyles, ResourceType::CssStyles, i18n("Style Presets"), QStringList() << "image/svg+xml"));
462
464
465#ifndef Q_OS_ANDROID
466 QString databaseLocation = KoResourcePaths::getAppDataLocation();
467#else
468 // Sqlite doesn't support content URIs (obviously). So, we make database location unconfigurable on android.
469 QString databaseLocation = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
470#endif
471
472 if (!KisResourceCacheDb::initialize(databaseLocation)) {
473 QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita: Fatal error"), i18n("%1\n\nKrita will quit now.", KisResourceCacheDb::lastError()));
474 }
475
477 connect(KisResourceLocator::instance(), SIGNAL(progressMessage(const QString&)), this, SLOT(setSplashScreenLoadingText(const QString&)));
478 if (r != KisResourceLocator::LocatorError::Ok && qApp->inherits("KisApplication")) {
479 QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita: Fatal error"), KisResourceLocator::instance()->errorMessages().join('\n') + i18n("\n\nKrita will quit now."));
480 return false;
481 }
482 return true;
483}
484
500
502{
503 KisConfig cfg(false);
504
505#if defined(Q_OS_WIN)
506#ifdef ENV32BIT
507
508 if (isWow64() && !cfg.readEntry("WarnedAbout32Bits", false)) {
509 QMessageBox::information(qApp->activeWindow(),
510 i18nc("@title:window", "Krita: Warning"),
511 i18n("You are running a 32 bits build on a 64 bits Windows.\n"
512 "This is not recommended.\n"
513 "Please download and install the x64 build instead."));
514 cfg.writeEntry("WarnedAbout32Bits", true);
515
516 }
517#endif
518#endif
519
520 QString opengl = cfg.canvasState();
521 if (opengl == "OPENGL_NOT_TRIED" ) {
522 cfg.setCanvasState("TRY_OPENGL");
523 }
524 else if (opengl != "OPENGL_SUCCESS" && opengl != "TRY_OPENGL") {
525 cfg.setCanvasState("OPENGL_FAILED");
526 }
527
528 setSplashScreenLoadingText(i18n("Initializing Globals..."));
529 processEvents();
530 initializeGlobals(args);
531
532 const bool doNewImage = args.doNewImage();
533 const bool doTemplate = args.doTemplate();
534 const bool exportAs = args.exportAs();
535 const bool exportSequence = args.exportSequence();
536 const QString exportFileName = args.exportFileName();
537
538 d->batchRun = (exportAs || exportSequence || !exportFileName.isEmpty());
539 const bool needsMainWindow = (!exportAs && !exportSequence);
540 // only show the mainWindow when no command-line mode option is passed
541 bool showmainWindow = (!exportAs && !exportSequence); // would be !batchRun;
542
543 const bool showSplashScreen = !d->batchRun && qEnvironmentVariableIsEmpty("NOSPLASH");
544 if (showSplashScreen && d->splashScreen) {
545 d->splashScreen->show();
546 d->splashScreen->repaint();
547 processEvents();
548 }
549
550 KConfigGroup group(KSharedConfig::openConfig(), "theme");
551#ifndef Q_OS_HAIKU
552 Digikam::ThemeManager themeManager;
553 themeManager.setCurrentTheme(group.readEntry("Theme", "Krita dark"));
554#endif
555
556 ResetStarting resetStarting(d->splashScreen, args.filenames().count()); // remove the splash when done
557 Q_UNUSED(resetStarting);
558
559 // Make sure we can save resources and tags
560 setSplashScreenLoadingText(i18n("Adding resource types..."));
561 processEvents();
563
564 setSplashScreenLoadingText(i18n("Loading plugins..."));
565 processEvents();
566 // Load the plugins
567 loadPlugins();
568
569 // Load all resources
570 setSplashScreenLoadingText(i18n("Loading resources..."));
571 processEvents();
572 if (!registerResources()) {
573 return false;
574 }
575
576 KisPart *kisPart = KisPart::instance();
577 if (needsMainWindow) {
578 // show a mainWindow asap, if we want that
579 setSplashScreenLoadingText(i18n("Loading Main Window..."));
580 processEvents();
581
582
583 bool sessionNeeded = true;
584 auto sessionMode = cfg.sessionOnStartup();
585
586 if (!args.session().isEmpty()) {
587 sessionNeeded = !kisPart->restoreSession(args.session());
588 } else if (sessionMode == KisConfig::SOS_ShowSessionManager) {
589 showmainWindow = false;
590 sessionNeeded = false;
591 kisPart->showSessionManager();
592 } else if (sessionMode == KisConfig::SOS_PreviousSession) {
593 KConfigGroup sessionCfg = KSharedConfig::openConfig()->group("session");
594 const QString &sessionName = sessionCfg.readEntry("previousSession");
595
596 sessionNeeded = !kisPart->restoreSession(sessionName);
597 }
598
599 if (sessionNeeded) {
600 kisPart->startBlankSession();
601 }
602
603 if (!args.windowLayout().isEmpty()) {
605 KisWindowLayoutResourceSP windowLayout = rserver->resource("", "", args.windowLayout());
606 if (windowLayout) {
607 windowLayout->applyLayout();
608 }
609 }
610
611 setSplashScreenLoadingText(i18n("Launching..."));
612
613 if (showmainWindow) {
614 d->mainWindow = kisPart->currentMainwindow();
615
616 if (!args.workspace().isEmpty()) {
618 KisWorkspaceResourceSP workspace = rserver->resource("", "", args.workspace());
619 if (workspace) {
620 d->mainWindow->restoreWorkspace(workspace);
621 }
622 }
623
624 if (args.canvasOnly()) {
625 d->mainWindow->viewManager()->switchCanvasOnly(true);
626 }
627
628 if (args.fullScreen()) {
629 d->mainWindow->showFullScreen();
630 }
631 } else {
632 d->mainWindow = kisPart->createMainWindow();
633 }
634 }
635 short int numberOfOpenDocuments = 0; // number of documents open
636
637 // Check for autosave files that can be restored, if we're not running a batch run (test)
638 if (!d->batchRun) {
640 }
641
642 setSplashScreenLoadingText(QString()); // done loading, so clear out label
643 processEvents();
644
645 //configure the unit manager
647 connect(this, &KisApplication::aboutToQuit, &KisSpinBoxUnitManagerFactory::clearUnitManagerBuilder); //ensure the builder is destroyed when the application leave.
648 //the new syntax slot syntax allow to connect to a non q_object static method.
649
650 // Long-press emulation.
654
655 // Xiaomi workaround: their stylus inexplicably inputs page up and down keys
656 // when pressing stylus buttons. This flag causes the Android platform
657 // integration to turn those into right and middle clicks instead.
658#if KRITA_QT_HAS_ANDROID_EMULATE_MOUSE_BUTTONS_FOR_PAGE_UP_DOWN
659 auto setPageUpDownMouseButtonEmulationWorkaround = [](bool enabled) {
660 QCoreApplication::setKritaAttribute(KRITA_QATTRIBUTE_ANDROID_EMULATE_MOUSE_BUTTONS_FOR_PAGE_UP_DOWN, enabled);
661 };
662 connect(cfgNotifier,
663 &KisConfigNotifier::sigUsePageUpDownMouseButtonEmulationWorkaroundChanged,
664 this,
665 setPageUpDownMouseButtonEmulationWorkaround);
666 setPageUpDownMouseButtonEmulationWorkaround(cfg.usePageUpDownMouseButtonEmulationWorkaround());
667#endif
668
669 // Xiaomi workaround: historic tablet motion events are garbage, they just
670 // connect the actual points that the tablet sampled with a straight line
671 // and no pressure emulation, leading to jagged curves that don't get
672 // smoothed out. This flag disables reading those historic events.
673#if KRITA_QT_HAS_ANDROID_IGNORE_HISTORIC_TABLET_EVENTS
674 auto setIgnoreHistoricTabletEventsWorkaround = [](bool enabled) {
675 QCoreApplication::setKritaAttribute(KRITA_QATTRIBUTE_ANDROID_IGNORE_HISTORIC_TABLET_EVENTS, enabled);
676 };
677 connect(cfgNotifier,
678 &KisConfigNotifier::sigUseIgnoreHistoricTabletEventsWorkaroundChanged,
679 this,
680 setIgnoreHistoricTabletEventsWorkaround);
681 setIgnoreHistoricTabletEventsWorkaround(cfg.usePageUpDownMouseButtonEmulationWorkaround());
682#endif
683
684 // Create a new image, if needed
685 if (doNewImage) {
687 if (doc) {
688 kisPart->addDocument(doc);
689 d->mainWindow->addViewAndNotifyLoadingCompleted(doc);
690 }
691 }
692
693 // Get the command line arguments which we have to parse
694 int argsCount = args.filenames().count();
695 if (argsCount > 0) {
696 // Loop through arguments
697 for (int argNumber = 0; argNumber < argsCount; argNumber++) {
698 QString fileName = args.filenames().at(argNumber);
699 // are we just trying to open a template?
700 if (doTemplate) {
701 // called in mix with batch options? ignore and silently skip
702 if (d->batchRun) {
703 continue;
704 }
705 if (createNewDocFromTemplate(fileName, d->mainWindow)) {
706 ++numberOfOpenDocuments;
707 }
708 // now try to load
709 }
710 else {
711 if (exportAs) {
712 QString outputMimetype = KisMimeDatabase::mimeTypeForFile(exportFileName, false);
713 if (outputMimetype == "application/octetstream") {
714 dbgKrita << i18n("Mimetype not found, try using the -mimetype option") << Qt::endl;
715 return false;
716 }
717
718 KisDocument *doc = kisPart->createDocument();
719 doc->setFileBatchMode(d->batchRun);
720 bool result = doc->openPath(fileName);
721
722 if (!result) {
723 errKrita << "Could not load " << fileName << ":" << doc->errorMessage();
724 QTimer::singleShot(0, this, SLOT(quit()));
725 return false;
726 }
727
728 if (exportFileName.isEmpty()) {
729 errKrita << "Export destination is not specified for" << fileName << "Please specify export destination with --export-filename option";
730 QTimer::singleShot(0, this, SLOT(quit()));
731 return false;
732 }
733
734 qApp->processEvents(); // For vector layers to be updated
735
736 doc->setFileBatchMode(true);
737 doc->image()->waitForDone();
738
739 if (!doc->exportDocumentSync(exportFileName, outputMimetype.toLatin1())) {
740 errKrita << "Could not export " << fileName << "to" << exportFileName << ":" << doc->errorMessage();
741 }
742 QTimer::singleShot(0, this, SLOT(quit()));
743 return true;
744 }
745 else if (exportSequence) {
746 KisDocument *doc = kisPart->createDocument();
747 doc->setFileBatchMode(d->batchRun);
748 doc->openPath(fileName);
749 qApp->processEvents(); // For vector layers to be updated
750
751 if (!doc->image()->animationInterface()->hasAnimation()) {
752 errKrita << "This file has no animation." << Qt::endl;
753 QTimer::singleShot(0, this, SLOT(quit()));
754 return false;
755 }
756
757 doc->setFileBatchMode(true);
758 int sequenceStart = 0;
759
760
761 qDebug() << ppVar(exportFileName);
764 exportFileName,
765 sequenceStart,
766 false,
767 0);
768
769 exporter.setBatchMode(d->batchRun);
770
772 qDebug() << ppVar(result);
773
775 errKrita << i18n("Failed to render animation frames!") << Qt::endl;
776 }
777
778 QTimer::singleShot(0, this, SLOT(quit()));
779 return true;
780 }
781 else if (d->mainWindow) {
782 if (QFileInfo(fileName).fileName().endsWith(".bundle", Qt::CaseInsensitive)) {
783 d->mainWindow->installBundle(fileName);
784 }
785 else {
786 KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
787
788 if (d->mainWindow->openDocument(fileName, flags)) {
789 // Normal case, success
790 numberOfOpenDocuments++;
791 }
792 }
793 }
794 }
795 }
796 }
797
798 //add an image as file-layer
799 if (!args.fileLayer().isEmpty()){
800 if (d->mainWindow->viewManager()->image()){
801 KisFileLayer *fileLayer = new KisFileLayer(d->mainWindow->viewManager()->image(), "",
802 args.fileLayer(), KisFileLayer::None, "Bicubic",
803 d->mainWindow->viewManager()->image()->nextLayerName(i18n("File layer")), OPACITY_OPAQUE_U8);
804 QFileInfo fi(fileLayer->path());
805 if (fi.exists()){
806 KisNodeCommandsAdapter adapter(d->mainWindow->viewManager());
807 adapter.addNode(fileLayer, d->mainWindow->viewManager()->activeNode()->parent(),
808 d->mainWindow->viewManager()->activeNode());
809 }
810 else{
811 QMessageBox::warning(qApp->activeWindow(), i18nc("@title:window", "Krita:Warning"),
812 i18n("Cannot add %1 as a file layer: the file does not exist.", fileLayer->path()));
813 }
814 }
815 else if (this->isRunning()){
816 QMessageBox::warning(qApp->activeWindow(), i18nc("@title:window", "Krita:Warning"),
817 i18n("Cannot add the file layer: no document is open.\n\n"
818"You can create a new document using the --new-image option, or you can open an existing file.\n\n"
819"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)."));
820 }
821 else {
822 QMessageBox::warning(qApp->activeWindow(), i18nc("@title:window", "Krita: Warning"),
823 i18n("Cannot add the file layer: no document is open.\n"
824 "You can either create a new file using the --new-image option, or you can open an existing file."));
825 }
826 }
827
828 // fixes BUG:369308 - Krita crashing on splash screen when loading.
829 // trying to open a file before Krita has loaded can cause it to hang and crash
830 if (d->splashScreen) {
831 d->splashScreen->displayLinks(true);
832 d->splashScreen->displayRecentFiles(true);
833 }
834
835 Q_FOREACH(const QByteArray &message, d->earlyRemoteArguments) {
836 executeRemoteArguments(message, d->mainWindow);
837 }
838
840
841 // process File open event files
842 if (!d->earlyFileOpenEvents.isEmpty()) {
844 Q_FOREACH(QString fileName, d->earlyFileOpenEvents) {
845 d->mainWindow->openDocument(fileName, QFlags<KisMainWindow::OpenFlag>());
846 }
847 }
848
850
851 // not calling this before since the program will quit there.
852 return true;
853}
854
862
863void KisApplication::setSplashScreen(QWidget *splashScreen)
864{
865 d->splashScreen = qobject_cast<KisSplashScreen*>(splashScreen);
866}
867
868void KisApplication::setSplashScreenLoadingText(const QString &textToLoad)
869{
870 if (d->splashScreen) {
871 d->splashScreen->setLoadingText(textToLoad);
872 d->splashScreen->repaint();
873 }
874}
875
877{
878 if (d->splashScreen) {
879 // hide the splashscreen to see the dialog
880 d->splashScreen->hide();
881 }
882}
883
884
885bool KisApplication::notify(QObject *receiver, QEvent *event)
886{
887 try {
888 bool result = true;
889
895 AppRecursionInfo &info = s_recursionInfo->localData();
896
897 {
898 // QApplication::notify() can throw, so use RAII for counters
899 AppRecursionGuard guard(&info);
900
902
903 if (info.eventRecursionCount > 1) {
905 KIS_SAFE_ASSERT_RECOVER_NOOP(typedEvent->destination == receiver);
906
907 info.postponedSynchronizationEvents.emplace(KisSynchronizedConnectionEvent(*typedEvent));
908 } else {
909 result = QApplication::notify(receiver, event);
910 }
911 } else {
912 result = QApplication::notify(receiver, event);
913 }
914 }
915
916 if (!info.eventRecursionCount) {
918
919 }
920
921 return result;
922
923 } catch (std::exception &e) {
924 qWarning("Error %s sending event %i to object %s",
925 e.what(), event->type(), qPrintable(receiver->objectName()));
926 } catch (...) {
927 qWarning("Error <unknown> sending event %i to object %s",
928 event->type(), qPrintable(receiver->objectName()));
929 }
930 return false;
931}
932
934{
935 AppRecursionInfo &info = s_recursionInfo->localData();
936
937 while (!info.postponedSynchronizationEvents.empty()) {
938 // QApplication::notify() can throw, so use RAII for counters
939 AppRecursionGuard guard(&info);
940
943 KisSynchronizedConnectionEvent typedEvent = info.postponedSynchronizationEvents.front();
944 info.postponedSynchronizationEvents.pop();
945
946 if (!typedEvent.destination) {
947 qWarning() << "WARNING: the destination object of KisSynchronizedConnection has been destroyed during postponed delivery";
948 continue;
949 }
950
951 QApplication::notify(typedEvent.destination, &typedEvent);
952 }
953}
954
956{
957 if (qEnvironmentVariableIsSet("STEAMAPPID") || qEnvironmentVariableIsSet("SteamAppId")) {
958 return true;
959 }
960
961 if (applicationDirPath().toLower().contains("steam")) {
962 return true;
963 }
964
965#ifdef Q_OS_WIN
966 // This is also true for user-installed MSIX, but that's
967 // likely only true in institutional situations, where
968 // we don't want to show the beginning banner either.
970 return true;
971 }
972#endif
973
974#ifdef Q_OS_MACOS
975 KisMacosEntitlements entitlements;
976 if (entitlements.sandbox()) {
977 return true;
978 }
979#endif
980
981 return false;
982}
983
985{
990#if !defined(HIDE_SAFE_ASSERTS) || defined(CRASH_ON_SAFE_ASSERTS)
991
992 auto verifyTypeRegistered = [] (const char *type) {
993 const int typeId = QMetaType::type(type);
994
995 if (typeId <= 0) {
996 qFatal("ERROR: type-id for metatype %s is not found", type);
997 }
998
999 if (!QMetaType::isRegistered(typeId)) {
1000 qFatal("ERROR: metatype %s is not registered", type);
1001 }
1002 };
1003
1004 verifyTypeRegistered("KisBrushSP");
1005 verifyTypeRegistered("KoSvgText::AutoValue");
1006 verifyTypeRegistered("KoSvgText::BackgroundProperty");
1007 verifyTypeRegistered("KoSvgText::StrokeProperty");
1008 verifyTypeRegistered("KoSvgText::TextTransformInfo");
1009 verifyTypeRegistered("KoSvgText::TextIndentInfo");
1010 verifyTypeRegistered("KoSvgText::TabSizeInfo");
1011 verifyTypeRegistered("KoSvgText::LineHeightInfo");
1012 verifyTypeRegistered("KisPaintopLodLimitations");
1013 verifyTypeRegistered("KisImageSP");
1014 verifyTypeRegistered("KisImageSignalType");
1015 verifyTypeRegistered("KisNodeSP");
1016 verifyTypeRegistered("KisNodeList");
1017 verifyTypeRegistered("KisPaintDeviceSP");
1018 verifyTypeRegistered("KisTimeSpan");
1019 verifyTypeRegistered("KoColor");
1020 verifyTypeRegistered("KoResourceSP");
1021 verifyTypeRegistered("KoResourceCacheInterfaceSP");
1022 verifyTypeRegistered("KisAsyncAnimationRendererBase::CancelReason");
1023 verifyTypeRegistered("KisGridConfig");
1024 verifyTypeRegistered("KisGuidesConfig");
1025 verifyTypeRegistered("KisUpdateInfoSP");
1026 verifyTypeRegistered("KisToolChangesTrackerDataSP");
1027 verifyTypeRegistered("QVector<QImage>");
1028 verifyTypeRegistered("SnapshotDirInfoList");
1029 verifyTypeRegistered("TransformTransactionProperties");
1030 verifyTypeRegistered("ToolTransformArgs");
1031 verifyTypeRegistered("QPainterPath");
1032#endif
1033}
1034
1035void KisApplication::executeRemoteArguments(QByteArray message, KisMainWindow *mainWindow)
1036{
1038 const bool doTemplate = args.doTemplate();
1039 const bool doNewImage = args.doNewImage();
1040 const int argsCount = args.filenames().count();
1041 bool documentCreated = false;
1042
1043 // Create a new image, if needed
1044 if (doNewImage) {
1046 if (doc) {
1048 d->mainWindow->addViewAndNotifyLoadingCompleted(doc);
1049 }
1050 }
1051 if (argsCount > 0) {
1052 // Loop through arguments
1053 for (int argNumber = 0; argNumber < argsCount; ++argNumber) {
1054 QString filename = args.filenames().at(argNumber);
1055 // are we just trying to open a template?
1056 if (doTemplate) {
1057 documentCreated |= createNewDocFromTemplate(filename, mainWindow);
1058 }
1059 else if (QFile(filename).exists()) {
1060 KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
1061 documentCreated |= mainWindow->openDocument(filename, flags);
1062 }
1063 }
1064 }
1065
1066 //add an image as file-layer if called in another process and singleApplication is enabled
1067 if (!args.fileLayer().isEmpty()){
1068 if (argsCount > 0 && !documentCreated){
1069 //arg was passed but document was not created so don't add the file layer.
1070 QMessageBox::warning(mainWindow, i18nc("@title:window", "Krita:Warning"),
1071 i18n("Couldn't open file %1",args.filenames().at(argsCount - 1)));
1072 }
1073 else if (mainWindow->viewManager()->image()){
1074 KisFileLayer *fileLayer = new KisFileLayer(mainWindow->viewManager()->image(), "",
1075 args.fileLayer(), KisFileLayer::None, "Bicubic",
1076 mainWindow->viewManager()->image()->nextLayerName(i18n("File layer")), OPACITY_OPAQUE_U8);
1077 QFileInfo fi(fileLayer->path());
1078 if (fi.exists()){
1079 KisNodeCommandsAdapter adapter(d->mainWindow->viewManager());
1080 adapter.addNode(fileLayer, d->mainWindow->viewManager()->activeNode()->parent(),
1081 d->mainWindow->viewManager()->activeNode());
1082 }
1083 else{
1084 QMessageBox::warning(mainWindow, i18nc("@title:window", "Krita:Warning"),
1085 i18n("Cannot add %1 as a file layer: the file does not exist.", fileLayer->path()));
1086 }
1087 }
1088 else {
1089 QMessageBox::warning(mainWindow, i18nc("@title:window", "Krita:Warning"),
1090 i18n("Cannot add the file layer: no document is open."));
1091 }
1092 }
1093}
1094
1095
1096void KisApplication::remoteArguments(const QString &message)
1097{
1098 // check if we have any mainwindow
1099 KisMainWindow *mw = qobject_cast<KisMainWindow*>(qApp->activeWindow());
1100
1101 if (!mw && KisPart::instance()->mainWindows().size() > 0) {
1102 mw = KisPart::instance()->mainWindows().first();
1103 }
1104
1105 const QByteArray unpackedMessage =
1106 QByteArray::fromBase64(message.toLatin1());
1107
1108 if (!mw) {
1109 d->earlyRemoteArguments << unpackedMessage;
1110 return;
1111 }
1112 executeRemoteArguments(unpackedMessage, mw);
1113}
1114
1116{
1117 if (!d->mainWindow) {
1118 d->earlyFileOpenEvents.append(url);
1119 return;
1120 }
1121
1122 KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
1123 d->mainWindow->openDocument(url, flags);
1124}
1125
1126
1128{
1129 if (enabled && !d->longPressEventFilter) {
1130 d->longPressEventFilter = new KisLongPressEventFilter(this);
1131 installEventFilter(d->longPressEventFilter);
1132 } else if (!enabled && d->longPressEventFilter) {
1133 removeEventFilter(d->longPressEventFilter);
1134 d->longPressEventFilter->deleteLater();
1135 d->longPressEventFilter = nullptr;
1136 }
1137}
1138
1140{
1141 if (d->batchRun) return;
1142
1144
1145 // Check for autosave files from a previous run. There can be several, and
1146 // we want to offer a restore for every one. Including a nice thumbnail!
1147
1148 // Hidden autosave files
1149 QStringList filters = QStringList() << QString(".krita-*-*-autosave.kra");
1150
1151 // all autosave files for our application
1152 QStringList autosaveFiles = dir.entryList(filters, QDir::Files | QDir::Hidden);
1153
1154 // Visible autosave files
1155 filters = QStringList() << QString("krita-*-*-autosave.kra");
1156 autosaveFiles += dir.entryList(filters, QDir::Files);
1157
1158 // Allow the user to make their selection
1159 if (autosaveFiles.size() > 0) {
1160 if (d->splashScreen) {
1161 // hide the splashscreen to see the dialog
1162 d->splashScreen->hide();
1163 }
1164 d->autosaveDialog = new KisAutoSaveRecoveryDialog(autosaveFiles, activeWindow());
1165 QDialog::DialogCode result = (QDialog::DialogCode) d->autosaveDialog->exec();
1166
1167 if (result == QDialog::Accepted) {
1168 QStringList filesToRecover = d->autosaveDialog->recoverableFiles();
1169 Q_FOREACH (const QString &autosaveFile, autosaveFiles) {
1170 if (!filesToRecover.contains(autosaveFile)) {
1171 KisUsageLogger::log(QString("Removing autosave file %1").arg(dir.absolutePath() + "/" + autosaveFile));
1172 QFile::remove(dir.absolutePath() + "/" + autosaveFile);
1173 }
1174 }
1175 autosaveFiles = filesToRecover;
1176 } else {
1177 autosaveFiles.clear();
1178 }
1179
1180 if (autosaveFiles.size() > 0) {
1181 QList<QString> autosavePaths;
1182 Q_FOREACH (const QString &autoSaveFile, autosaveFiles) {
1183 const QString path = dir.absolutePath() + QLatin1Char('/') + autoSaveFile;
1184 autosavePaths << path;
1185 }
1186 if (d->mainWindow) {
1187 Q_FOREACH (const QString &path, autosavePaths) {
1188 KisMainWindow::OpenFlags flags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
1189 d->mainWindow->openDocument(path, flags | KisMainWindow::RecoveryFile);
1190 }
1191 }
1192 }
1193 // cleanup
1194 delete d->autosaveDialog;
1195 d->autosaveDialog = nullptr;
1196 }
1197}
1198
1199bool KisApplication::createNewDocFromTemplate(const QString &fileName, KisMainWindow *mainWindow)
1200{
1201 QString templatePath;
1202
1203 if (QFile::exists(fileName)) {
1204 templatePath = fileName;
1205 dbgUI << "using full path...";
1206 }
1207 else {
1208 QString desktopName(fileName);
1209 const QString templatesResourcePath = QStringLiteral("templates/");
1210
1211 QStringList paths = KoResourcePaths::findAllAssets("data", templatesResourcePath + "*/" + desktopName);
1212 if (paths.isEmpty()) {
1213 paths = KoResourcePaths::findAllAssets("data", templatesResourcePath + desktopName);
1214 }
1215
1216 if (paths.isEmpty()) {
1217 QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita"),
1218 i18n("No template found for: %1", desktopName));
1219 } else if (paths.count() > 1) {
1220 QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita"),
1221 i18n("Too many templates found for: %1", desktopName));
1222 } else {
1223 templatePath = paths.at(0);
1224 }
1225 }
1226
1227 if (!templatePath.isEmpty()) {
1228 KDesktopFile templateInfo(templatePath);
1229
1230 KisMainWindow::OpenFlags batchFlags = d->batchRun ? KisMainWindow::BatchMode : KisMainWindow::None;
1231 if (mainWindow->openDocument(templatePath, KisMainWindow::Import | batchFlags)) {
1232 dbgUI << "Template loaded...";
1233 return true;
1234 }
1235 else {
1236 QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita"),
1237 i18n("Template %1 failed to load.", fileName));
1238 }
1239 }
1240
1241 return false;
1242}
1243
1245{
1246 KIS_ASSERT_RECOVER_RETURN(qApp->thread() == QThread::currentThread());
1247
1248 KSharedConfigPtr config = KSharedConfig::openConfig();
1249 config->markAsClean();
1250
1251 // find user settings file
1252 const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
1253 QString kritarcPath = configPath + QStringLiteral("/kritarc");
1254
1255 QFile kritarcFile(kritarcPath);
1256
1257 if (kritarcFile.exists()) {
1258 if (kritarcFile.open(QFile::ReadWrite)) {
1259 QString backupKritarcPath = kritarcPath + QStringLiteral(".backup");
1260
1261 QFile backupKritarcFile(backupKritarcPath);
1262
1263 if (backupKritarcFile.exists()) {
1264 backupKritarcFile.remove();
1265 }
1266
1267 QMessageBox::information(qApp->activeWindow(),
1268 i18nc("@title:window", "Krita"),
1269 i18n("Krita configurations reset!\n\n"
1270 "Backup file was created at: %1\n\n"
1271 "Restart Krita for changes to take effect.",
1272 backupKritarcPath),
1273 QMessageBox::Ok, QMessageBox::Ok);
1274
1275 // clear file
1276 kritarcFile.rename(backupKritarcPath);
1277
1278 kritarcFile.close();
1279 }
1280 else {
1281 QMessageBox::warning(qApp->activeWindow(),
1282 i18nc("@title:window", "Krita"),
1283 i18n("Failed to clear %1\n\n"
1284 "Please make sure no other program is using the file and try again.",
1285 kritarcPath),
1286 QMessageBox::Ok, QMessageBox::Ok);
1287 }
1288 }
1289
1290 // reload from disk; with the user file settings cleared,
1291 // this should load any default configuration files shipping with the program
1292 config->reparseConfiguration();
1293 config->sync();
1294
1295 // Restore to default workspace
1296 KConfigGroup cfg = KSharedConfig::openConfig()->group("MainWindow");
1297
1298 QString currentWorkspace = cfg.readEntry<QString>("CurrentWorkspace", "Default");
1300 KisWorkspaceResourceSP workspace = rserver->resource("", "", currentWorkspace);
1301
1302 if (workspace) {
1303 d->mainWindow->restoreWorkspace(workspace);
1304 }
1305}
1306
1308{
1309 bool ok = QMessageBox::question(qApp->activeWindow(),
1310 i18nc("@title:window", "Krita"),
1311 i18n("Do you want to clear the settings file?"),
1312 QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes;
1313 if (ok) {
1314 resetConfig();
1315 }
1316}
1317
1319{
1320 return d->extendedModifiersPluginInterface.data();
1321}
1322
1323#ifdef Q_OS_ANDROID
1324KisAndroidDonations *KisApplication::androidDonations()
1325{
1326 if (!d->androidDonations) {
1327 d->androidDonations = new KisAndroidDonations(this);
1328 d->androidDonations->syncState();
1329 }
1330 return d->androidDonations;
1331}
1332#endif
QList< QString > QStringList
Q_GLOBAL_STATIC(KisStoragePluginRegistry, s_instance)
const quint8 OPACITY_OPAQUE_U8
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:809
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:819
QString canvasState(bool defaultValue=false) const
@ SOS_PreviousSession
Definition kis_config.h:367
@ SOS_ShowSessionManager
Definition kis_config.h:368
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:644
void addDocument(KisDocument *document, bool notify=true)
Definition KisPart.cpp:211
KisMainWindow * currentMainwindow() const
Definition KisPart.cpp:459
void startBlankSession()
Definition KisPart.cpp:636
KisDocument * createDocument() const
Definition KisPart.cpp:230
void showSessionManager()
Definition KisPart.cpp:626
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 FontFamilies
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()