main.cc 22 KB
Newer Older
1
/*
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
* Copyright (c) 1999 Matthias Elter <me@kde.org>
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
* Copyright (c) 2015 Boudewijn Rempt <boud@valdyas.org>
*
*  This program is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
Boudewijn Rempt's avatar
Boudewijn Rempt committed
20

Boudewijn Rempt's avatar
Boudewijn Rempt committed
21
#include <stdlib.h>
22 23 24

#include <QString>
#include <QPixmap>
25
#include <kis_debug.h>
26 27
#include <QProcess>
#include <QProcessEnvironment>
28
#include <QStandardPaths>
29
#include <QDir>
30
#include <QDate>
31 32
#include <QLocale>
#include <QSettings>
33
#include <QByteArray>
34
#include <QMessageBox>
35
#include <QThread>
36

37
#if QT_VERSION >= 0x050900
38
#include <QOperatingSystemVersion>
39
#endif
40

41 42
#include <time.h>

43
#include <KisApplication.h>
44
#include <KoConfig.h>
45
#include <KoResourcePaths.h>
46
#include <kis_config.h>
47 48

#include "data/splash/splash_screen.xpm"
49
#include "data/splash/splash_holidays.xpm"
50 51
#include "data/splash/splash_screen_x2.xpm"
#include "data/splash/splash_holidays_x2.xpm"
52
#include "KisDocument.h"
53
#include "kis_splash_screen.h"
54
#include "KisPart.h"
55
#include "KisApplicationArguments.h"
56
#include <opengl/kis_opengl.h>
57
#include "input/KisQtWidgetsTweaker.h"
58 59
#include <KisUsageLogger.h>
#include <kis_image_config.h>
60

61 62 63 64
#ifdef Q_OS_ANDROID
#include <QtAndroid>
#endif

65
#if defined Q_OS_WIN
66
#include "config_use_qt_tablet_windows.h"
67
#include <windows.h>
68
#ifndef USE_QT_TABLET_WINDOWS
69
#include <kis_tablet_support_win.h>
70
#include <kis_tablet_support_win8.h>
71 72
#else
#include <dialogs/KisDlgCustomTabletResolution.h>
73
#endif
74
#include "config-high-dpi-scale-factor-rounding-policy.h"
75 76 77
#include "config-set-has-border-in-full-screen-default.h"
#ifdef HAVE_SET_HAS_BORDER_IN_FULL_SCREEN_DEFAULT
#include <QtPlatformHeaders/QWindowsWindowFunctions>
78
#endif
79
#include <QLibrary>
80
#endif
81 82
#if defined HAVE_KCRASH
#include <kcrash.h>
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
#elif defined USE_DRMINGW
namespace
{
void tryInitDrMingw()
{
    wchar_t path[MAX_PATH];
    QString pathStr = QCoreApplication::applicationDirPath().replace(L'/', L'\\') + QStringLiteral("\\exchndl.dll");
    if (pathStr.size() > MAX_PATH - 1) {
        return;
    }
    int pathLen = pathStr.toWCharArray(path);
    path[pathLen] = L'\0'; // toWCharArray doesn't add NULL terminator
    HMODULE hMod = LoadLibraryW(path);
    if (!hMod) {
        return;
    }
    // No need to call ExcHndlInit since the crash handler is installed on DllMain
    auto myExcHndlSetLogFileNameA = reinterpret_cast<BOOL (APIENTRY *)(const char *)>(GetProcAddress(hMod, "ExcHndlSetLogFileNameA"));
    if (!myExcHndlSetLogFileNameA) {
        return;
    }
    // Set the log file path to %LocalAppData%\kritacrash.log
    QString logFile = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation).replace(L'/', L'\\') + QStringLiteral("\\kritacrash.log");
    myExcHndlSetLogFileNameA(logFile.toLocal8Bit());
}
108 109
} // namespace
#endif
110

111 112 113
#ifdef Q_OS_WIN
namespace
{
114 115 116 117 118 119 120 121
typedef enum ORIENTATION_PREFERENCE {
    ORIENTATION_PREFERENCE_NONE = 0x0,
    ORIENTATION_PREFERENCE_LANDSCAPE = 0x1,
    ORIENTATION_PREFERENCE_PORTRAIT = 0x2,
    ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED = 0x4,
    ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED = 0x8
} ORIENTATION_PREFERENCE;
typedef BOOL WINAPI (*pSetDisplayAutoRotationPreferences_t)(
122 123
        ORIENTATION_PREFERENCE orientation
        );
124 125 126 127 128 129 130 131 132 133
void resetRotation()
{
    QLibrary user32Lib("user32");
    if (!user32Lib.load()) {
        qWarning() << "Failed to load user32.dll! This really should not happen.";
        return;
    }
    pSetDisplayAutoRotationPreferences_t pSetDisplayAutoRotationPreferences
            = reinterpret_cast<pSetDisplayAutoRotationPreferences_t>(user32Lib.resolve("SetDisplayAutoRotationPreferences"));
    if (!pSetDisplayAutoRotationPreferences) {
Boudewijn Rempt's avatar
Boudewijn Rempt committed
134
        dbgKrita << "Failed to load function SetDisplayAutoRotationPreferences";
135 136 137
        return;
    }
    bool result = pSetDisplayAutoRotationPreferences(ORIENTATION_PREFERENCE_NONE);
Boudewijn Rempt's avatar
Boudewijn Rempt committed
138
    dbgKrita << "SetDisplayAutoRotationPreferences(ORIENTATION_PREFERENCE_NONE) returned" << result;
139
}
140
} // namespace
141
#endif
142

143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
#ifdef Q_OS_ANDROID
extern "C" JNIEXPORT void JNICALL
Java_org_krita_android_JNIWrappers_saveState(JNIEnv* /*env*/,
                                             jobject /*obj*/,
                                             jint    /*n*/)
{
    KisPart *kisPart = KisPart::instance();
    QList<QPointer<KisDocument>> list = kisPart->documents();
    for (auto doc: list)
    {
        doc->autoSaveOnPause();
    }
}
#endif

158 159 160
#ifdef Q_OS_ANDROID
__attribute__ ((visibility ("default")))
#endif
161
extern "C" int main(int argc, char **argv)
162
{
163 164
    // The global initialization of the random generator
    qsrand(time(0));
165
    bool runningInKDE = !qgetenv("KDE_FULL_SESSION").isEmpty();
166 167 168

#if defined HAVE_X11
    qputenv("QT_QPA_PLATFORM", "xcb");
169 170
#endif

171 172 173
    // Workaround a bug in QNetworkManager
    qputenv("QT_BEARER_POLL_TIMEOUT", QByteArray::number(-1));

174
    // A per-user unique string, without /, because QLocalServer cannot use names with a / in it
175
    QString key = "Krita4" + QStandardPaths::writableLocation(QStandardPaths::HomeLocation).replace("/", "_");
176
    key = key.replace(":", "_").replace("\\","_");
177

178
    QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
179

180
    QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true);
181
    QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
182

183 184 185 186
#if QT_VERSION >= 0x050900
    QCoreApplication::setAttribute(Qt::AA_DisableShaderDiskCache, true);
#endif

187 188 189 190 191 192 193 194 195 196 197 198 199
#ifdef HAVE_HIGH_DPI_SCALE_FACTOR_ROUNDING_POLICY
    // This rounding policy depends on a series of patches to Qt related to
    // https://bugreports.qt.io/browse/QTBUG-53022. These patches are applied
    // in ext_qt for WIndows (patches 0031-0036).
    //
    // The rounding policy can be set externally by setting the environment
    // variable `QT_SCALE_FACTOR_ROUNDING_POLICY` to one of the following:
    //   Round:            Round up for .5 and above.
    //   Ceil:             Always round up.
    //   Floor:            Always round down.
    //   RoundPreferFloor: Round up for .75 and above.
    //   PassThrough:      Don't round.
    //
200
    // The default is set to RoundPreferFloor for better behaviour than before,
201
    // but can be overridden by the above environment variable.
202
    QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::RoundPreferFloor);
203 204
#endif

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
#ifdef Q_OS_ANDROID
    const QString write_permission = "android.permission.WRITE_EXTERNAL_STORAGE";
    const QStringList permissions = { write_permission };
    const QtAndroid::PermissionResultMap resultHash =
            QtAndroid::requestPermissionsSync(QStringList(permissions));

    if (resultHash[write_permission] == QtAndroid::PermissionResult::Denied) {
        // TODO: show a dialog and graciously exit
        dbgKrita << "Permission denied by the user";
    }
    else {
        dbgKrita << "Permission granted";
    }
#endif

220
    const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
221
    QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
Boudewijn Rempt's avatar
Boudewijn Rempt committed
222

223
    bool singleApplication = true;
224 225
    bool enableOpenGLDebug = false;
    bool openGLDebugSynchronous = false;
226
    bool logUsage = true;
Boudewijn Rempt's avatar
Boudewijn Rempt committed
227
    {
228

229
        singleApplication = kritarc.value("EnableSingleApplication", true).toBool();
230
        if (kritarc.value("EnableHiDPI", true).toBool()) {
Boudewijn Rempt's avatar
Boudewijn Rempt committed
231 232 233 234 235
            QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
        }
        if (!qgetenv("KRITA_HIDPI").isEmpty()) {
            QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
        }
236 237 238 239 240
#ifdef HAVE_HIGH_DPI_SCALE_FACTOR_ROUNDING_POLICY
        if (kritarc.value("EnableHiDPIFractionalScaling", true).toBool()) {
            QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
        }
#endif
241

242 243 244 245 246 247 248 249
        if (!qgetenv("KRITA_OPENGL_DEBUG").isEmpty()) {
            enableOpenGLDebug = true;
        } else {
            enableOpenGLDebug = kritarc.value("EnableOpenGLDebug", false).toBool();
        }
        if (enableOpenGLDebug && (qgetenv("KRITA_OPENGL_DEBUG") == "sync" || kritarc.value("OpenGLDebugSynchronous", false).toBool())) {
            openGLDebugSynchronous = true;
        }
250

251 252
        KisConfig::RootSurfaceFormat rootSurfaceFormat = KisConfig::rootSurfaceFormat(&kritarc);
        KisOpenGL::OpenGLRenderer preferredRenderer = KisOpenGL::RendererAuto;
253

254 255
        logUsage = kritarc.value("LogUsage", true).toBool();

256 257
        const QString preferredRendererString = kritarc.value("OpenGLRenderer", "auto").toString();
        preferredRenderer = KisOpenGL::convertConfigToOpenGLRenderer(preferredRendererString);
Alvin Wong's avatar
Alvin Wong committed
258

259
#ifdef Q_OS_WIN
260 261 262
        // Force ANGLE to use Direct3D11. D3D9 doesn't support OpenGL ES 3 and WARP
        //  might get weird crashes atm.
        qputenv("QT_ANGLE_PLATFORM", "d3d11");
263
#endif
264

265 266
        const QSurfaceFormat format =
            KisOpenGL::selectSurfaceFormat(preferredRenderer, rootSurfaceFormat, enableOpenGLDebug);
267

268 269 270 271 272 273 274 275 276
        if (format.renderableType() == QSurfaceFormat::OpenGLES) {
            QCoreApplication::setAttribute(Qt::AA_UseOpenGLES, true);
        } else {
            QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL, true);
        }
        KisOpenGL::setDefaultSurfaceFormat(format);
        KisOpenGL::setDebugSynchronous(openGLDebugSynchronous);

#ifdef Q_OS_WIN
277 278
        // HACK: https://bugs.kde.org/show_bug.cgi?id=390651
        resetRotation();
279
#endif
280
    }
281

282 283 284 285
    if (logUsage) {
        KisUsageLogger::initialize();
    }

286 287

    QString root;
288
    QString language;
289 290 291 292 293
    {
        // Create a temporary application to get the root
        QCoreApplication app(argc, argv);
        Q_UNUSED(app);
        root = KoResourcePaths::getApplicationRoot();
294 295
        QSettings languageoverride(configPath + QStringLiteral("/klanguageoverridesrc"), QSettings::IniFormat);
        languageoverride.beginGroup(QStringLiteral("Language"));
296
        language = languageoverride.value(qAppName(), "").toString();
297 298 299
    }


300
#ifdef Q_OS_LINUX
301 302 303 304 305 306
    {
        QByteArray originalXdgDataDirs = qgetenv("XDG_DATA_DIRS");
        if (originalXdgDataDirs.isEmpty()) {
            // We don't want to completely override the default
            originalXdgDataDirs = "/usr/local/share/:/usr/share/";
        }
307
        qputenv("XDG_DATA_DIRS", QFile::encodeName(root + "share") + ":" + originalXdgDataDirs);
308
    }
309
#else
310
    qputenv("XDG_DATA_DIRS", QFile::encodeName(root + "share"));
311 312
#endif

Boudewijn Rempt's avatar
Boudewijn Rempt committed
313
    dbgKrita << "Setting XDG_DATA_DIRS" << qgetenv("XDG_DATA_DIRS");
314

luz paz's avatar
luz paz committed
315
    // Now that the paths are set, set the language. First check the override from the language
316
    // selection dialog.
Boudewijn Rempt's avatar
Boudewijn Rempt committed
317

Boudewijn Rempt's avatar
Boudewijn Rempt committed
318
    dbgKrita << "Override language:" << language;
319
    bool rightToLeft = false;
320 321 322
    if (!language.isEmpty()) {
        KLocalizedString::setLanguages(language.split(":"));
        // And override Qt's locale, too
323
        qputenv("LANG", language.split(":").first().toLocal8Bit());
324 325
        QLocale locale(language.split(":").first());
        QLocale::setDefault(locale);
326 327 328 329 330 331 332

        const QStringList rtlLanguages = QStringList()
                << "ar" << "dv" << "he" << "ha" << "ku" << "fa" << "ps" << "ur" << "yi";

        if (rtlLanguages.contains(language.split(':').first())) {
            rightToLeft = true;
        }
333 334
    }
    else {
335 336
        dbgKrita << "Qt UI languages:" << QLocale::system().uiLanguages() << qgetenv("LANG");

337 338 339
        // And if there isn't one, check the one set by the system.
        QLocale locale = QLocale::system();
        if (locale.name() != QStringLiteral("en")) {
340 341
            QStringList uiLanguages = locale.uiLanguages();
            for (QString &uiLanguage : uiLanguages) {
342 343 344 345 346 347 348 349 350 351 352 353 354 355

                // This list of language codes that can have a specifier should
                // be extended whenever we have translations that need it; right
                // now, only en, pt, zh are in this situation.

                if (uiLanguage.startsWith("en") || uiLanguage.startsWith("pt")) {
                    uiLanguage.replace(QChar('-'), QChar('_'));
                }
                else if (uiLanguage.startsWith("zh-Hant") || uiLanguage.startsWith("zh-TW")) {
                    uiLanguage = "zh_TW";
                }
                else if (uiLanguage.startsWith("zh-Hans") || uiLanguage.startsWith("zh-CN")) {
                    uiLanguage = "zh_CN";
                }
356
            }
357

358 359 360
            for (int i = 0; i < uiLanguages.size(); i++) {
                QString uiLanguage = uiLanguages[i];
                // Strip the country code
361 362
                int idx = uiLanguage.indexOf(QChar('-'));

363 364
                if (idx != -1) {
                    uiLanguage = uiLanguage.left(idx);
365
                    uiLanguages.replace(i, uiLanguage);
366 367
                }
            }
368
            dbgKrita << "Converted ui languages:" << uiLanguages;
369
            qputenv("LANG", uiLanguages.first().toLocal8Bit());
370 371 372 373 374 375
#ifdef Q_OS_MAC
            // See https://bugs.kde.org/show_bug.cgi?id=396370
            KLocalizedString::setLanguages(QStringList() << uiLanguages.first());
#else
            KLocalizedString::setLanguages(QStringList() << uiLanguages);
#endif
376
        }
Boudewijn Rempt's avatar
Boudewijn Rempt committed
377
    }
378

379 380 381
#if defined Q_OS_WIN && defined USE_QT_TABLET_WINDOWS && defined QT_HAS_WINTAB_SWITCH
    const bool forceWinTab = !KisConfig::useWin8PointerInputNoApp(&kritarc);
    QCoreApplication::setAttribute(Qt::AA_MSWindowsUseWinTabAPI, forceWinTab);
382 383 384 385 386 387 388

    if (qEnvironmentVariableIsEmpty("QT_WINTAB_DESKTOP_RECT") &&
        qEnvironmentVariableIsEmpty("QT_IGNORE_WINTAB_MAPPING")) {

        QRect customTabletRect;
        KisDlgCustomTabletResolution::Mode tabletMode =
            KisDlgCustomTabletResolution::getTabletMode(&customTabletRect);
389
        KisDlgCustomTabletResolution::applyConfiguration(tabletMode, customTabletRect);
390
    }
391 392
#endif

393 394
    // first create the application so we can create a pixmap
    KisApplication app(key, argc, argv);
395

396 397 398 399 400 401
#ifdef HAVE_SET_HAS_BORDER_IN_FULL_SCREEN_DEFAULT
    if (QCoreApplication::testAttribute(Qt::AA_UseDesktopOpenGL)) {
        QWindowsWindowFunctions::setHasBorderInFullScreenDefault(true);
    }
#endif

402 403
    KisUsageLogger::writeHeader();

404 405 406 407 408 409 410 411
    if (!language.isEmpty()) {
        if (rightToLeft) {
            app.setLayoutDirection(Qt::RightToLeft);
        }
        else {
            app.setLayoutDirection(Qt::LeftToRight);
        }
    }
412 413
    KLocalizedString::setApplicationDomain("krita");

Boudewijn Rempt's avatar
Boudewijn Rempt committed
414 415
    dbgKrita << "Available translations" << KLocalizedString::availableApplicationTranslations();
    dbgKrita << "Available domain translations" << KLocalizedString::availableDomainTranslations("krita");
416 417


418
#ifdef Q_OS_WIN
Boudewijn Rempt's avatar
Boudewijn Rempt committed
419
    QDir appdir(KoResourcePaths::getApplicationRoot());
420
    QString path = qgetenv("PATH");
421
    qputenv("PATH", QFile::encodeName(appdir.absolutePath() + "/bin" + ";"
422 423 424 425
                                      + appdir.absolutePath() + "/lib" + ";"
                                      + appdir.absolutePath() + "/Frameworks" + ";"
                                      + appdir.absolutePath() + ";"
                                      + path));
426

Boudewijn Rempt's avatar
Boudewijn Rempt committed
427
    dbgKrita << "PATH" << qgetenv("PATH");
428 429
#endif

430 431 432 433 434
    if (qApp->applicationDirPath().contains(KRITA_BUILD_DIR)) {
        qFatal("FATAL: You're trying to run krita from the build location. You can only run Krita from the installation location.");
    }


435 436
#if defined HAVE_KCRASH
    KCrash::initialize();
437 438
#elif defined USE_DRMINGW
    tryInitDrMingw();
439
#endif
440

441 442 443 444 445
    // If we should clear the config, it has to be done as soon as possible after
    // KisApplication has been created. Otherwise the config file may have been read
    // and stored in a KConfig object we have no control over.
    app.askClearConfig();

446 447
    KisApplicationArguments args(app);

448
    if (singleApplication && app.isRunning()) {
449 450
        // only pass arguments to main instance if they are not for batch processing
        // any batch processing would be done in this separate instance
451
        const bool batchRun = args.exportAs() || args.exportSequence();
452 453

        if (!batchRun) {
454
            QByteArray ba = args.serialize();
455 456 457
            if (app.sendMessage(ba)) {
                return 0;
            }
458 459
        }
    }
460

461 462 463 464
    if (!runningInKDE) {
        // Icons in menus are ugly and distracting
        app.setAttribute(Qt::AA_DontShowIconsInMenus);
    }
465

466 467
    app.installEventFilter(KisQtWidgetsTweaker::instance());

468 469 470 471 472 473 474 475
    if (!args.noSplash()) {
        // then create the pixmap from an xpm: we cannot get the
        // location of our datadir before we've started our components,
        // so use an xpm.
        QDate currentDate = QDate::currentDate();
        QWidget *splash = 0;
        if (currentDate > QDate(currentDate.year(), 12, 4) ||
                currentDate < QDate(currentDate.year(), 1, 9)) {
476
            splash = new KisSplashScreen(app.applicationVersion(), QPixmap(splash_holidays_xpm), QPixmap(splash_holidays_x2_xpm));
477 478
        }
        else {
479
            splash = new KisSplashScreen(app.applicationVersion(), QPixmap(splash_screen_xpm), QPixmap(splash_screen_x2_xpm));
480
        }
481

482 483
        app.setSplashScreen(splash);
    }
484

485
#if defined Q_OS_WIN
486
    KisConfig cfg(false);
487 488 489 490 491 492 493 494 495 496 497 498 499 500
    bool supportedWindowsVersion = true;
#if QT_VERSION >= 0x050900
    QOperatingSystemVersion osVersion = QOperatingSystemVersion::current();
    if (osVersion.type() == QOperatingSystemVersion::Windows) {
        if (osVersion.majorVersion() >= QOperatingSystemVersion::Windows7.majorVersion()) {
            supportedWindowsVersion  = true;
        }
        else {
            supportedWindowsVersion  = false;
            if (cfg.readEntry("WarnedAboutUnsupportedWindows", false)) {
                QMessageBox::information(0,
                                         i18nc("@title:window", "Krita: Warning"),
                                         i18n("You are running an unsupported version of Windows: %1.\n"
                                              "This is not recommended. Do not report any bugs.\n"
501
                                              "Please update to a supported version of Windows: Windows 7, 8, 8.1 or 10.", osVersion.name()));
502 503 504 505 506 507
                cfg.writeEntry("WarnedAboutUnsupportedWindows", true);

            }
        }
    }
#endif
508
#ifndef USE_QT_TABLET_WINDOWS
509
    {
510 511 512 513 514
        if (cfg.useWin8PointerInput() && !KisTabletSupportWin8::isAvailable()) {
            cfg.setUseWin8PointerInput(false);
        }
        if (!cfg.useWin8PointerInput()) {
            bool hasWinTab = KisTabletSupportWin::init();
515
            if (!hasWinTab && supportedWindowsVersion) {
516 517 518 519 520 521
                if (KisTabletSupportWin8::isPenDeviceAvailable()) {
                    // Use WinInk automatically
                    cfg.setUseWin8PointerInput(true);
                } else if (!cfg.readEntry("WarnedAboutMissingWinTab", false)) {
                    if (KisTabletSupportWin8::isAvailable()) {
                        QMessageBox::information(nullptr,
522 523 524
                                                 i18n("Krita Tablet Support"),
                                                 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."),
                                                 QMessageBox::Ok, QMessageBox::Ok);
525 526
                    } else {
                        QMessageBox::information(nullptr,
527 528 529
                                                 i18n("Krita Tablet Support"),
                                                 i18n("Cannot load WinTab driver. If you have a drawing tablet, please make sure the tablet driver is properly installed."),
                                                 QMessageBox::Ok, QMessageBox::Ok);
530 531 532 533 534
                    }
                    cfg.writeEntry("WarnedAboutMissingWinTab", true);
                }
            }
        }
535 536 537 538 539
        if (cfg.useWin8PointerInput()) {
            KisTabletSupportWin8 *penFilter = new KisTabletSupportWin8();
            if (penFilter->init()) {
                // penFilter.registerPointerDeviceNotifications();
                app.installNativeEventFilter(penFilter);
Boudewijn Rempt's avatar
Boudewijn Rempt committed
540
                dbgKrita << "Using Win8 Pointer Input for tablet support";
541
            } else {
Boudewijn Rempt's avatar
Boudewijn Rempt committed
542
                dbgKrita << "No Win8 Pointer Input available";
543 544 545 546
                delete penFilter;
            }
        }
    }
547 548 549 550 551 552 553 554 555
#elif defined QT_HAS_WINTAB_SWITCH

    // Check if WinTab/WinInk has actually activated
    const bool useWinTabAPI = app.testAttribute(Qt::AA_MSWindowsUseWinTabAPI);

    if (useWinTabAPI != !cfg.useWin8PointerInput()) {
        cfg.setUseWin8PointerInput(useWinTabAPI);
    }

556
#endif
557 558
#endif

559
    if (!app.start(args)) {
560
        return 1;
561 562
    }

563 564 565
#if QT_VERSION >= 0x050700
    app.setAttribute(Qt::AA_CompressHighFrequencyEvents, false);
#endif
566

567 568
    // Set up remote arguments.
    QObject::connect(&app, SIGNAL(messageReceived(QByteArray,QObject*)),
569
                     &app, SLOT(remoteArguments(QByteArray,QObject*)));
570 571

    QObject::connect(&app, SIGNAL(fileOpenRequest(QString)),
572
                     &app, SLOT(fileOpenRequested(QString)));
573

574 575 576 577 578 579 580
    // Hardware information
    KisUsageLogger::write("\nHardware Information\n");
    KisUsageLogger::write(QString("  GPU Acceleration: %1").arg(kritarc.value("OpenGLRenderer", "auto").toString()));
    KisUsageLogger::write(QString("  Memory: %1 Mb").arg(KisImageConfig(true).totalRAM()));
    KisUsageLogger::write(QString("  Number of Cores: %1").arg(QThread::idealThreadCount()));
    KisUsageLogger::write(QString("  Swap Location: %1\n").arg(KisImageConfig(true).swapDir()));

581
    int state = app.exec();
582

Boudewijn Rempt's avatar
Boudewijn Rempt committed
583
    {
584
        QSettings kritarc(configPath + QStringLiteral("/kritadisplayrc"), QSettings::IniFormat);
Boudewijn Rempt's avatar
Boudewijn Rempt committed
585 586
        kritarc.setValue("canvasState", "OPENGL_SUCCESS");
    }
587

588 589 590 591
    if (logUsage) {
        KisUsageLogger::close();
    }

Cyrille Berger's avatar
Cyrille Berger committed
592
    return state;
593
}