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