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