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