1 /*
2 * Copyright (c) 1999 Matthias Elter <me@kde.org>
3 * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
4 * Copyright (c) 2015 Boudewijn Rempt <boud@valdyas.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 #include <stdlib.h>
22
23 #include <QString>
24 #include <QPixmap>
25 #include <kis_debug.h>
26 #include <QProcess>
27 #include <QProcessEnvironment>
28 #include <QStandardPaths>
29 #include <QDir>
30 #include <QDate>
31 #include <QLocale>
32 #include <QSettings>
33 #include <QByteArray>
34 #include <QMessageBox>
35 #include <QThread>
36
37 #include <QOperatingSystemVersion>
38
39 #include <time.h>
40
41 #include <KisApplication.h>
42 #include <KoConfig.h>
43 #include <KoResourcePaths.h>
44 #include <kis_config.h>
45
46 #include "data/splash/splash_screen.xpm"
47 #include "data/splash/splash_holidays.xpm"
48 #include "data/splash/splash_screen_x2.xpm"
49 #include "data/splash/splash_holidays_x2.xpm"
50 #include "KisDocument.h"
51 #include "kis_splash_screen.h"
52 #include "KisPart.h"
53 #include "KisApplicationArguments.h"
54 #include <opengl/kis_opengl.h>
55 #include "input/KisQtWidgetsTweaker.h"
56 #include <KisUsageLogger.h>
57 #include <kis_image_config.h>
58
59 #ifdef Q_OS_ANDROID
60 #include <QtAndroid>
61 #endif
62
63 #if defined Q_OS_WIN
64 #include "config_use_qt_tablet_windows.h"
65 #include <windows.h>
66 #ifndef USE_QT_TABLET_WINDOWS
67 #include <kis_tablet_support_win.h>
68 #include <kis_tablet_support_win8.h>
69 #else
70 #include <dialogs/KisDlgCustomTabletResolution.h>
71 #endif
72 #include "config-high-dpi-scale-factor-rounding-policy.h"
73 #include "config-set-has-border-in-full-screen-default.h"
74 #ifdef HAVE_SET_HAS_BORDER_IN_FULL_SCREEN_DEFAULT
75 #include <QtPlatformHeaders/QWindowsWindowFunctions>
76 #endif
77 #include <QLibrary>
78 #endif
79 #if defined HAVE_KCRASH
80 #include <kcrash.h>
81 #elif defined USE_DRMINGW
82 namespace
83 {
tryInitDrMingw()84 void tryInitDrMingw()
85 {
86 wchar_t path[MAX_PATH];
87 QString pathStr = QCoreApplication::applicationDirPath().replace(L'/', L'\\') + QStringLiteral("\\exchndl.dll");
88 if (pathStr.size() > MAX_PATH - 1) {
89 return;
90 }
91 int pathLen = pathStr.toWCharArray(path);
92 path[pathLen] = L'\0'; // toWCharArray doesn't add NULL terminator
93 HMODULE hMod = LoadLibraryW(path);
94 if (!hMod) {
95 return;
96 }
97 // No need to call ExcHndlInit since the crash handler is installed on DllMain
98 auto myExcHndlSetLogFileNameA = reinterpret_cast<BOOL (APIENTRY *)(const char *)>(GetProcAddress(hMod, "ExcHndlSetLogFileNameA"));
99 if (!myExcHndlSetLogFileNameA) {
100 return;
101 }
102 // Set the log file path to %LocalAppData%\kritacrash.log
103 QString logFile = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation).replace(L'/', L'\\') + QStringLiteral("\\kritacrash.log");
104 myExcHndlSetLogFileNameA(logFile.toLocal8Bit());
105 }
106 } // namespace
107 #endif
108
109 #ifdef Q_OS_WIN
110 namespace
111 {
112 typedef enum ORIENTATION_PREFERENCE {
113 ORIENTATION_PREFERENCE_NONE = 0x0,
114 ORIENTATION_PREFERENCE_LANDSCAPE = 0x1,
115 ORIENTATION_PREFERENCE_PORTRAIT = 0x2,
116 ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED = 0x4,
117 ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED = 0x8
118 } ORIENTATION_PREFERENCE;
119 typedef BOOL WINAPI (*pSetDisplayAutoRotationPreferences_t)(
120 ORIENTATION_PREFERENCE orientation
121 );
resetRotation()122 void resetRotation()
123 {
124 QLibrary user32Lib("user32");
125 if (!user32Lib.load()) {
126 qWarning() << "Failed to load user32.dll! This really should not happen.";
127 return;
128 }
129 pSetDisplayAutoRotationPreferences_t pSetDisplayAutoRotationPreferences
130 = reinterpret_cast<pSetDisplayAutoRotationPreferences_t>(user32Lib.resolve("SetDisplayAutoRotationPreferences"));
131 if (!pSetDisplayAutoRotationPreferences) {
132 dbgKrita << "Failed to load function SetDisplayAutoRotationPreferences";
133 return;
134 }
135 bool result = pSetDisplayAutoRotationPreferences(ORIENTATION_PREFERENCE_NONE);
136 dbgKrita << "SetDisplayAutoRotationPreferences(ORIENTATION_PREFERENCE_NONE) returned" << result;
137 }
138 } // namespace
139 #endif
140
141 #ifdef Q_OS_ANDROID
142 extern "C" JNIEXPORT void JNICALL
Java_org_krita_android_JNIWrappers_saveState(JNIEnv *,jobject,jint)143 Java_org_krita_android_JNIWrappers_saveState(JNIEnv* /*env*/,
144 jobject /*obj*/,
145 jint /*n*/)
146 {
147 if (!KisPart::exists()) return;
148
149 KisPart *kisPart = KisPart::instance();
150 QList<QPointer<KisDocument>> list = kisPart->documents();
151 for (QPointer<KisDocument> &doc: list)
152 {
153 doc->autoSaveOnPause();
154 }
155
156 const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
157 QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
158 kritarc.setValue("canvasState", "OPENGL_SUCCESS");
159 }
160
161 extern "C" JNIEXPORT jboolean JNICALL
Java_org_krita_android_JNIWrappers_exitFullScreen(JNIEnv *,jobject,jint)162 Java_org_krita_android_JNIWrappers_exitFullScreen(JNIEnv* /*env*/,
163 jobject /*obj*/,
164 jint /*n*/)
165 {
166 if (!KisPart::exists()) {
167 return false;
168 }
169
170 KisMainWindow *mainWindow = KisPart::instance()->currentMainwindow();
171 if (mainWindow) {
172 mainWindow->viewFullscreen(false);
173 return true;
174 } else {
175 return false;
176 }
177 }
178
179 extern "C" JNIEXPORT void JNICALL
Java_org_krita_android_JNIWrappers_openFileFromIntent(JNIEnv *,jobject,jstring str)180 Java_org_krita_android_JNIWrappers_openFileFromIntent(JNIEnv* /*env*/,
181 jobject /*obj*/,
182 jstring str)
183 {
184 QAndroidJniObject jUri(str);
185 if (jUri.isValid()) {
186 QString uri = jUri.toString();
187 QMetaObject::invokeMethod(KisApplication::instance(), "fileOpenRequested",
188 Qt::QueuedConnection, Q_ARG(QString, uri));
189 }
190 }
191
192 __attribute__ ((visibility ("default")))
193 #endif
main(int argc,char ** argv)194 extern "C" int main(int argc, char **argv)
195 {
196 // The global initialization of the random generator
197 qsrand(time(0));
198 bool runningInKDE = !qgetenv("KDE_FULL_SESSION").isEmpty();
199
200 #if defined HAVE_X11
201 qputenv("QT_QPA_PLATFORM", "xcb");
202 #endif
203
204 // Workaround a bug in QNetworkManager
205 qputenv("QT_BEARER_POLL_TIMEOUT", QByteArray::number(-1));
206
207 // A per-user unique string, without /, because QLocalServer cannot use names with a / in it
208 QString key = "Krita4" + QStandardPaths::writableLocation(QStandardPaths::HomeLocation).replace("/", "_");
209 key = key.replace(":", "_").replace("\\","_");
210
211 QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
212
213 QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true);
214 QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
215
216 QCoreApplication::setAttribute(Qt::AA_DisableShaderDiskCache, true);
217
218 #ifdef HAVE_HIGH_DPI_SCALE_FACTOR_ROUNDING_POLICY
219 // This rounding policy depends on a series of patches to Qt related to
220 // https://bugreports.qt.io/browse/QTBUG-53022. These patches are applied
221 // in ext_qt for WIndows (patches 0031-0036).
222 //
223 // The rounding policy can be set externally by setting the environment
224 // variable `QT_SCALE_FACTOR_ROUNDING_POLICY` to one of the following:
225 // Round: Round up for .5 and above.
226 // Ceil: Always round up.
227 // Floor: Always round down.
228 // RoundPreferFloor: Round up for .75 and above.
229 // PassThrough: Don't round.
230 //
231 // The default is set to RoundPreferFloor for better behaviour than before,
232 // but can be overridden by the above environment variable.
233 QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor);
234 #endif
235
236 #ifdef Q_OS_ANDROID
237 const QString write_permission = "android.permission.WRITE_EXTERNAL_STORAGE";
238 const QStringList permissions = { write_permission };
239 const QtAndroid::PermissionResultMap resultHash =
240 QtAndroid::requestPermissionsSync(QStringList(permissions));
241
242 if (resultHash[write_permission] == QtAndroid::PermissionResult::Denied) {
243 // TODO: show a dialog and graciously exit
244 dbgKrita << "Permission denied by the user";
245 }
246 else {
247 dbgKrita << "Permission granted";
248 }
249 #endif
250
251 const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
252 QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
253
254 bool singleApplication = true;
255 bool enableOpenGLDebug = false;
256 bool openGLDebugSynchronous = false;
257 bool logUsage = true;
258 {
259
260 singleApplication = kritarc.value("EnableSingleApplication", true).toBool();
261 if (kritarc.value("EnableHiDPI", true).toBool()) {
262 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
263 }
264 if (!qgetenv("KRITA_HIDPI").isEmpty()) {
265 QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
266 }
267 #ifdef HAVE_HIGH_DPI_SCALE_FACTOR_ROUNDING_POLICY
268 if (kritarc.value("EnableHiDPIFractionalScaling", false).toBool()) {
269 QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
270 }
271 #endif
272
273 if (!qgetenv("KRITA_OPENGL_DEBUG").isEmpty()) {
274 enableOpenGLDebug = true;
275 } else {
276 enableOpenGLDebug = kritarc.value("EnableOpenGLDebug", false).toBool();
277 }
278 if (enableOpenGLDebug && (qgetenv("KRITA_OPENGL_DEBUG") == "sync" || kritarc.value("OpenGLDebugSynchronous", false).toBool())) {
279 openGLDebugSynchronous = true;
280 }
281
282 KisConfig::RootSurfaceFormat rootSurfaceFormat = KisConfig::rootSurfaceFormat(&kritarc);
283 KisOpenGL::OpenGLRenderer preferredRenderer = KisOpenGL::RendererAuto;
284
285 logUsage = kritarc.value("LogUsage", true).toBool();
286
287 #ifdef Q_OS_WIN
288 const QString preferredRendererString = kritarc.value("OpenGLRenderer", "angle").toString();
289 #else
290 const QString preferredRendererString = kritarc.value("OpenGLRenderer", "auto").toString();
291 #endif
292 preferredRenderer = KisOpenGL::convertConfigToOpenGLRenderer(preferredRendererString);
293
294 const KisOpenGL::RendererConfig config =
295 KisOpenGL::selectSurfaceConfig(preferredRenderer, rootSurfaceFormat, enableOpenGLDebug);
296
297 KisOpenGL::setDefaultSurfaceConfig(config);
298 KisOpenGL::setDebugSynchronous(openGLDebugSynchronous);
299
300 #ifdef Q_OS_WIN
301 // HACK: https://bugs.kde.org/show_bug.cgi?id=390651
302 resetRotation();
303 #endif
304 }
305
306 if (logUsage) {
307 KisUsageLogger::initialize();
308 }
309
310
311 QString root;
312 QString language;
313 {
314 // Create a temporary application to get the root
315 QCoreApplication app(argc, argv);
316 Q_UNUSED(app);
317 root = KoResourcePaths::getApplicationRoot();
318 QSettings languageoverride(configPath + QStringLiteral("/klanguageoverridesrc"), QSettings::IniFormat);
319 languageoverride.beginGroup(QStringLiteral("Language"));
320 language = languageoverride.value(qAppName(), "").toString();
321 }
322
323
324 #ifdef Q_OS_LINUX
325 {
326 QByteArray originalXdgDataDirs = qgetenv("XDG_DATA_DIRS");
327 if (originalXdgDataDirs.isEmpty()) {
328 // We don't want to completely override the default
329 originalXdgDataDirs = "/usr/local/share/:/usr/share/";
330 }
331 qputenv("XDG_DATA_DIRS", QFile::encodeName(root + "share") + ":" + originalXdgDataDirs);
332
333 // APPIMAGE SOUND ADDITIONS
334 // GStreamer needs a few environment variables to properly function in an appimage context.
335 // The following code should be configured to **only** run when we detect that Krita is being
336 // run within an appimage. Checking for the presence of an APPDIR path env variable seems to be
337 // enough to filter out this step for non-appimage krita builds.
338
339 const bool isInAppimage = qEnvironmentVariableIsSet("APPIMAGE");
340 if (isInAppimage) {
341 QByteArray appimageMountDir = qgetenv("APPDIR");
342
343 //We need to add new gstreamer plugin paths for the system to find the
344 //appropriate plugins.
345 const QByteArray gstPluginSystemPath = qgetenv("GST_PLUGIN_SYSTEM_PATH_1_0");
346 const QByteArray gstPluginScannerPath = qgetenv("GST_PLUGIN_SCANNER");
347
348 //Plugins Path is where libgstreamer-1.0 should expect to find plugin libraries.
349 qputenv("GST_PLUGIN_SYSTEM_PATH_1_0", appimageMountDir + QFile::encodeName("/usr/lib/gstreamer-1.0/") + ":" + gstPluginSystemPath);
350
351 //Plugin scanner is where gstreamer should expect to find the plugin scanner.
352 //Perhaps invoking the scanenr earlier in the code manually could allow ldd to quickly find all plugin dependencies?
353 qputenv("GST_PLUGIN_SCANNER", appimageMountDir + QFile::encodeName("/usr/lib/gstreamer-1.0/gst-plugin-scanner"));
354 }
355 }
356 #else
357 qputenv("XDG_DATA_DIRS", QFile::encodeName(root + "share"));
358 #endif
359
360 dbgKrita << "Setting XDG_DATA_DIRS" << qgetenv("XDG_DATA_DIRS");
361
362 // Now that the paths are set, set the language. First check the override from the language
363 // selection dialog.
364
365 dbgKrita << "Override language:" << language;
366 bool rightToLeft = false;
367 if (!language.isEmpty()) {
368 KLocalizedString::setLanguages(language.split(":"));
369
370 // And override Qt's locale, too
371 QLocale locale(language.split(":").first());
372 QLocale::setDefault(locale);
373 #ifdef Q_OS_MAC
374 // prevents python >=3.7 nl_langinfo(CODESET) fail bug 417312.
375 qputenv("LANG", (locale.name() + ".UTF-8").toLocal8Bit());
376 #else
377 qputenv("LANG", locale.name().toLocal8Bit());
378 #endif
379
380 const QStringList rtlLanguages = QStringList()
381 << "ar" << "dv" << "he" << "ha" << "ku" << "fa" << "ps" << "ur" << "yi";
382
383 if (rtlLanguages.contains(language.split(':').first())) {
384 rightToLeft = true;
385 }
386 }
387 else {
388 dbgKrita << "Qt UI languages:" << QLocale::system().uiLanguages() << qgetenv("LANG");
389
390 // And if there isn't one, check the one set by the system.
391 QLocale locale = QLocale::system();
392
393 #ifdef Q_OS_ANDROID
394 // QLocale::uiLanguages() fails on Android, so if the fallback locale is being
395 // used we, try to fetch the device's default locale.
396 if (locale.name() == QLocale::c().name()) {
397 QAndroidJniObject localeJniObj = QAndroidJniObject::callStaticObjectMethod(
398 "java/util/Locale", "getDefault", "()Ljava/util/Locale;");
399
400 if (localeJniObj.isValid()) {
401 QAndroidJniObject tag = localeJniObj.callObjectMethod("toLanguageTag",
402 "()Ljava/lang/String;");
403 if (tag.isValid()) {
404 locale = QLocale(tag.toString());
405 }
406 }
407 }
408 #endif
409 if (locale.name() != QStringLiteral("en")) {
410 QStringList uiLanguages = locale.uiLanguages();
411 for (QString &uiLanguage : uiLanguages) {
412
413 // This list of language codes that can have a specifier should
414 // be extended whenever we have translations that need it; right
415 // now, only en, pt, zh are in this situation.
416
417 if (uiLanguage.startsWith("en") || uiLanguage.startsWith("pt")) {
418 uiLanguage.replace(QChar('-'), QChar('_'));
419 }
420 else if (uiLanguage.startsWith("zh-Hant") || uiLanguage.startsWith("zh-TW")) {
421 uiLanguage = "zh_TW";
422 }
423 else if (uiLanguage.startsWith("zh-Hans") || uiLanguage.startsWith("zh-CN")) {
424 uiLanguage = "zh_CN";
425 }
426 }
427
428 if (uiLanguages.size() > 0 ) {
429 QString envLanguage = uiLanguages.first();
430 envLanguage.replace(QChar('-'), QChar('_'));
431
432 for (int i = 0; i < uiLanguages.size(); i++) {
433 QString uiLanguage = uiLanguages[i];
434 // Strip the country code
435 int idx = uiLanguage.indexOf(QChar('-'));
436
437 if (idx != -1) {
438 uiLanguage = uiLanguage.left(idx);
439 uiLanguages.replace(i, uiLanguage);
440 }
441 }
442 dbgKrita << "Converted ui languages:" << uiLanguages;
443 #ifdef Q_OS_MAC
444 // See https://bugs.kde.org/show_bug.cgi?id=396370
445 KLocalizedString::setLanguages(QStringList() << uiLanguages.first());
446 qputenv("LANG", (envLanguage + ".UTF-8").toLocal8Bit());
447 #else
448 KLocalizedString::setLanguages(QStringList() << uiLanguages);
449 qputenv("LANG", envLanguage.toLocal8Bit());
450 #endif
451 }
452 }
453 }
454
455 #if defined Q_OS_WIN && defined USE_QT_TABLET_WINDOWS && defined QT_HAS_WINTAB_SWITCH
456 const bool forceWinTab = !KisConfig::useWin8PointerInputNoApp(&kritarc);
457 QCoreApplication::setAttribute(Qt::AA_MSWindowsUseWinTabAPI, forceWinTab);
458
459 if (qEnvironmentVariableIsEmpty("QT_WINTAB_DESKTOP_RECT") &&
460 qEnvironmentVariableIsEmpty("QT_IGNORE_WINTAB_MAPPING")) {
461
462 QRect customTabletRect;
463 KisDlgCustomTabletResolution::Mode tabletMode =
464 KisDlgCustomTabletResolution::getTabletMode(&customTabletRect);
465 KisDlgCustomTabletResolution::applyConfiguration(tabletMode, customTabletRect);
466 }
467 #endif
468
469 // first create the application so we can create a pixmap
470 KisApplication app(key, argc, argv);
471
472 if (app.platformName() == "wayland") {
473 QMessageBox::critical(0, i18nc("@title:window", "Fatal Error"), i18n("Krita does not support the Wayland platform. Use XWayland to run Krita on Wayland. Krita will close now."));
474 return -1;
475 }
476
477 KisUsageLogger::writeHeader();
478 KisOpenGL::initialize();
479
480 #ifdef HAVE_SET_HAS_BORDER_IN_FULL_SCREEN_DEFAULT
481 if (QCoreApplication::testAttribute(Qt::AA_UseDesktopOpenGL)) {
482 QWindowsWindowFunctions::setHasBorderInFullScreenDefault(true);
483 }
484 #endif
485
486
487 if (!language.isEmpty()) {
488 if (rightToLeft) {
489 app.setLayoutDirection(Qt::RightToLeft);
490 }
491 else {
492 app.setLayoutDirection(Qt::LeftToRight);
493 }
494 }
495 #ifdef Q_OS_ANDROID
496 // TODO: remove "share" - sh_zam
497 // points to /data/data/org.krita/files/share/locale
498 KLocalizedString::addDomainLocaleDir("krita", QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/share/locale");
499 #endif
500
501 KLocalizedString::setApplicationDomain("krita");
502
503 dbgKrita << "Available translations" << KLocalizedString::availableApplicationTranslations();
504 dbgKrita << "Available domain translations" << KLocalizedString::availableDomainTranslations("krita");
505
506
507 #ifdef Q_OS_WIN
508 QDir appdir(KoResourcePaths::getApplicationRoot());
509 QString path = qgetenv("PATH");
510 qputenv("PATH", QFile::encodeName(appdir.absolutePath() + "/bin" + ";"
511 + appdir.absolutePath() + "/lib" + ";"
512 + appdir.absolutePath() + "/Frameworks" + ";"
513 + appdir.absolutePath() + ";"
514 + path));
515
516 dbgKrita << "PATH" << qgetenv("PATH");
517 #endif
518
519 if (qApp->applicationDirPath().contains(KRITA_BUILD_DIR)) {
520 qFatal("FATAL: You're trying to run krita from the build location. You can only run Krita from the installation location.");
521 }
522
523
524 #if defined HAVE_KCRASH
525 KCrash::initialize();
526 #elif defined USE_DRMINGW
527 tryInitDrMingw();
528 #endif
529
530 KisApplicationArguments args(app);
531
532 if (singleApplication && app.isRunning()) {
533 // only pass arguments to main instance if they are not for batch processing
534 // any batch processing would be done in this separate instance
535 const bool batchRun = args.exportAs() || args.exportSequence();
536
537 if (!batchRun) {
538 QByteArray ba = args.serialize();
539 if (app.sendMessage(ba)) {
540 return 0;
541 }
542 }
543 }
544
545 if (!runningInKDE) {
546 // Icons in menus are ugly and distracting
547 app.setAttribute(Qt::AA_DontShowIconsInMenus);
548 }
549 #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
550 app.setAttribute(Qt::AA_DisableWindowContextHelpButton);
551 #endif
552 app.installEventFilter(KisQtWidgetsTweaker::instance());
553
554 if (!args.noSplash()) {
555 // then create the pixmap from an xpm: we cannot get the
556 // location of our datadir before we've started our components,
557 // so use an xpm.
558 QDate currentDate = QDate::currentDate();
559 QWidget *splash = 0;
560 if (currentDate > QDate(currentDate.year(), 12, 4) ||
561 currentDate < QDate(currentDate.year(), 1, 9)) {
562 splash = new KisSplashScreen(app.applicationVersion(), QPixmap(splash_holidays_xpm), QPixmap(splash_holidays_x2_xpm));
563 }
564 else {
565 splash = new KisSplashScreen(app.applicationVersion(), QPixmap(splash_screen_xpm), QPixmap(splash_screen_x2_xpm));
566 }
567
568 app.setSplashScreen(splash);
569 }
570
571 #if defined Q_OS_WIN
572 KisConfig cfg(false);
573 bool supportedWindowsVersion = true;
574 QOperatingSystemVersion osVersion = QOperatingSystemVersion::current();
575 if (osVersion.type() == QOperatingSystemVersion::Windows) {
576 if (osVersion.majorVersion() >= QOperatingSystemVersion::Windows7.majorVersion()) {
577 supportedWindowsVersion = true;
578 }
579 else {
580 supportedWindowsVersion = false;
581 if (cfg.readEntry("WarnedAboutUnsupportedWindows", false)) {
582 QMessageBox::information(0,
583 i18nc("@title:window", "Krita: Warning"),
584 i18n("You are running an unsupported version of Windows: %1.\n"
585 "This is not recommended. Do not report any bugs.\n"
586 "Please update to a supported version of Windows: Windows 7, 8, 8.1 or 10.", osVersion.name()));
587 cfg.writeEntry("WarnedAboutUnsupportedWindows", true);
588
589 }
590 }
591 }
592 #ifndef USE_QT_TABLET_WINDOWS
593 {
594 if (cfg.useWin8PointerInput() && !KisTabletSupportWin8::isAvailable()) {
595 cfg.setUseWin8PointerInput(false);
596 }
597 if (!cfg.useWin8PointerInput()) {
598 bool hasWinTab = KisTabletSupportWin::init();
599 if (!hasWinTab && supportedWindowsVersion) {
600 if (KisTabletSupportWin8::isPenDeviceAvailable()) {
601 // Use WinInk automatically
602 cfg.setUseWin8PointerInput(true);
603 } else if (!cfg.readEntry("WarnedAboutMissingWinTab", false)) {
604 if (KisTabletSupportWin8::isAvailable()) {
605 QMessageBox::information(nullptr,
606 i18n("Krita Tablet Support"),
607 i18n("Cannot load WinTab driver and no Windows Ink pen devices are found. If you have a drawing tablet, please make sure the tablet driver is properly installed."),
608 QMessageBox::Ok, QMessageBox::Ok);
609 } else {
610 QMessageBox::information(nullptr,
611 i18n("Krita Tablet Support"),
612 i18n("Cannot load WinTab driver. If you have a drawing tablet, please make sure the tablet driver is properly installed."),
613 QMessageBox::Ok, QMessageBox::Ok);
614 }
615 cfg.writeEntry("WarnedAboutMissingWinTab", true);
616 }
617 }
618 }
619 if (cfg.useWin8PointerInput()) {
620 KisTabletSupportWin8 *penFilter = new KisTabletSupportWin8();
621 if (penFilter->init()) {
622 // penFilter.registerPointerDeviceNotifications();
623 app.installNativeEventFilter(penFilter);
624 dbgKrita << "Using Win8 Pointer Input for tablet support";
625 } else {
626 dbgKrita << "No Win8 Pointer Input available";
627 delete penFilter;
628 }
629 }
630 }
631 #elif defined QT_HAS_WINTAB_SWITCH
632
633 // Check if WinTab/WinInk has actually activated
634 const bool useWinInkAPI = !app.testAttribute(Qt::AA_MSWindowsUseWinTabAPI);
635
636 if (useWinInkAPI != cfg.useWin8PointerInput()) {
637 KisUsageLogger::log("WARNING: WinTab tablet protocol is not supported on this device. Switching to WinInk...");
638
639 cfg.setUseWin8PointerInput(useWinInkAPI);
640 cfg.setUseRightMiddleTabletButtonWorkaround(true);
641 }
642
643 #endif
644 #endif
645 app.setAttribute(Qt::AA_CompressHighFrequencyEvents, false);
646
647 // Set up remote arguments.
648 QObject::connect(&app, SIGNAL(messageReceived(QByteArray,QObject*)),
649 &app, SLOT(remoteArguments(QByteArray,QObject*)));
650
651 QObject::connect(&app, SIGNAL(fileOpenRequest(QString)),
652 &app, SLOT(fileOpenRequested(QString)));
653
654 // Hardware information
655 KisUsageLogger::writeSysInfo("\nHardware Information\n");
656 KisUsageLogger::writeSysInfo(QString(" GPU Acceleration: %1").arg(kritarc.value("OpenGLRenderer", "auto").toString()));
657 KisUsageLogger::writeSysInfo(QString(" Memory: %1 Mb").arg(KisImageConfig(true).totalRAM()));
658 KisUsageLogger::writeSysInfo(QString(" Number of Cores: %1").arg(QThread::idealThreadCount()));
659 KisUsageLogger::writeSysInfo(QString(" Swap Location: %1\n").arg(KisImageConfig(true).swapDir()));
660
661 KisConfig(true).logImportantSettings();
662
663 if (!app.start(args)) {
664 KisUsageLogger::log("Could not start Krita Application");
665 return 1;
666 }
667
668
669 int state = app.exec();
670
671 {
672 QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
673 kritarc.setValue("canvasState", "OPENGL_SUCCESS");
674 }
675
676 if (logUsage) {
677 KisUsageLogger::close();
678 }
679
680 return state;
681 }
682