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