File indexing completed on 2024-05-19 05:44:23

0001 /*
0002     SPDX-FileCopyrightText: 2015-2017 Milian Wolff <mail@milianw.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-or-later
0005 */
0006 
0007 #include <QApplication>
0008 #include <QCommandLineParser>
0009 
0010 #include <KAboutData>
0011 #include <KLocalizedString>
0012 #include <kcoreaddons_version.h>
0013 
0014 #include "analyze/suppressions.h"
0015 #include "util/config.h"
0016 
0017 #include "gui_config.h"
0018 #include "mainwindow.h"
0019 #include "proxystyle.h"
0020 
0021 #include <KIconTheme>
0022 #include <QFile>
0023 #include <QResource>
0024 
0025 // FIXME: patch KIconTheme so that this isn't needed here
0026 void Q_DECL_UNUSED initRCCIconTheme()
0027 {
0028     const QString iconThemeRcc = qApp->applicationDirPath() + QStringLiteral("/../share/icons/breeze/breeze-icons.rcc");
0029     if (!QFile::exists(iconThemeRcc)) {
0030         qWarning("cannot find icons rcc: %ls", qUtf16Printable(iconThemeRcc));
0031         return;
0032     }
0033 
0034     const QString iconThemeName = QStringLiteral("kf5_rcc_theme");
0035     const QString iconSubdir = QStringLiteral("/icons/") + iconThemeName;
0036     if (!QResource::registerResource(iconThemeRcc, iconSubdir)) {
0037         qWarning("Invalid rcc file: %ls", qUtf16Printable(iconThemeRcc));
0038     }
0039 
0040     if (!QFile::exists(QLatin1Char(':') + iconSubdir + QStringLiteral("/index.theme"))) {
0041         qWarning("No index.theme found in %ls", qUtf16Printable(iconThemeRcc));
0042         QResource::unregisterResource(iconThemeRcc, iconSubdir);
0043     }
0044 
0045     // Tell Qt about the theme
0046     // Note that since qtbase commit a8621a3f8, this means the QPA (i.e. KIconLoader) will NOT be used.
0047     QIcon::setThemeName(iconThemeName); // Qt looks under :/icons automatically
0048     // Tell KIconTheme about the theme, in case KIconLoader is used directly
0049     KIconTheme::forceThemeForTests(iconThemeName);
0050 }
0051 
0052 int main(int argc, char** argv)
0053 {
0054 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0055     QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
0056 #endif
0057 
0058     QApplication app(argc, argv);
0059     app.setStyle(new ProxyStyle);
0060 
0061 #if APPIMAGE_BUILD
0062     initRCCIconTheme();
0063 #endif
0064 
0065     KLocalizedString::setApplicationDomain("heaptrack");
0066 
0067     KAboutData aboutData(QStringLiteral("heaptrack_gui"), i18n("Heaptrack GUI"),
0068                          QStringLiteral(HEAPTRACK_VERSION_STRING), i18n("A visualizer for heaptrack data files."),
0069                          KAboutLicense::LGPL, i18n("Copyright 2015, Milian Wolff <mail@milianw.de>"), QString(),
0070                          QStringLiteral("mail@milianw.de"));
0071 
0072     aboutData.addAuthor(i18n("Milian Wolff"), i18n("Original author, maintainer"), QStringLiteral("mail@milianw.de"),
0073                         QStringLiteral("http://milianw.de"));
0074 
0075     aboutData.setOrganizationDomain("kde.org");
0076 #if KCOREADDONS_VERSION >= QT_VERSION_CHECK(5, 16, 0)
0077     aboutData.setDesktopFileName(QStringLiteral("org.kde.heaptrack"));
0078 #endif
0079     KAboutData::setApplicationData(aboutData);
0080     app.setWindowIcon(QIcon(QStringLiteral(":/512-heaptrack_app_icon.png")));
0081 
0082     QCommandLineParser parser;
0083     aboutData.setupCommandLine(&parser);
0084 
0085     QCommandLineOption diffOption {{QStringLiteral("d"), QStringLiteral("diff")},
0086                                    i18n("Base profile data to compare other files to."),
0087                                    QStringLiteral("<file>")};
0088     parser.addOption(diffOption);
0089     QCommandLineOption suppressionsOption {
0090         {QStringLiteral("s"), QStringLiteral("suppressions")},
0091         i18n("Load list of leak suppressions from the specified file. Specify one suppression per line, and start each "
0092              "line with 'leak:', i.e. use the LSAN suppression file format."),
0093         QStringLiteral("<file>")};
0094     parser.addOption(suppressionsOption);
0095     QCommandLineOption disableEmbeddedSuppressionsOption {
0096         {QStringLiteral("disable-embedded-suppressions")},
0097         i18n("Ignore suppression definitions that are embedded into the heaptrack data file. By default, heaptrack "
0098              "will copy the suppressions optionally defined via a `const char *__lsan_default_suppressions()` symbol "
0099              "in the debuggee application.  These are then always applied when analyzing the data, unless this feature "
0100              "is explicitly disabled using this command line option.")};
0101     parser.addOption(disableEmbeddedSuppressionsOption);
0102     QCommandLineOption disableBuiltinSuppressionsOption {
0103         {QStringLiteral("disable-builtin-suppressions")},
0104         i18n(
0105             "Ignore suppression definitions that are built into heaptrack. By default, heaptrack will suppress certain "
0106             "known leaks in common system libraries.")};
0107     parser.addOption(disableBuiltinSuppressionsOption);
0108     parser.addPositionalArgument(QStringLiteral("files"), i18n("Files to load"), i18n("[FILE...]"));
0109 
0110     parser.process(app);
0111     aboutData.processCommandLine(&parser);
0112 
0113     bool parsedOk = false;
0114     const auto suppressions = parseSuppressions(parser.value(suppressionsOption).toStdString(), &parsedOk);
0115     if (!parsedOk) {
0116         return 1;
0117     }
0118 
0119     auto createWindow = [&]() -> MainWindow* {
0120         auto window = new MainWindow;
0121         window->setAttribute(Qt::WA_DeleteOnClose);
0122         window->setSuppressions(suppressions);
0123         window->setDisableEmbeddedSuppressions(parser.isSet(disableEmbeddedSuppressionsOption));
0124         window->setDisableBuiltinSuppressions(parser.isSet(disableBuiltinSuppressionsOption));
0125         window->show();
0126         return window;
0127     };
0128 
0129     const auto files = parser.positionalArguments();
0130     for (const auto& file : files) {
0131         createWindow()->loadFile(file, parser.value(diffOption));
0132     }
0133 
0134     if (files.isEmpty()) {
0135         createWindow();
0136     }
0137 
0138 #if APPIMAGE_BUILD
0139     // cleanup the environment when we are running from within the AppImage
0140     // to allow launching system applications using Qt without them loading
0141     // the bundled Qt we ship in the AppImage
0142     auto LD_LIBRARY_PATH = qgetenv("LD_LIBRARY_PATH");
0143     LD_LIBRARY_PATH.remove(0, LD_LIBRARY_PATH.indexOf(':') + 1);
0144     qputenv("LD_LIBRARY_PATH", LD_LIBRARY_PATH);
0145 #endif
0146 
0147     return app.exec();
0148 }