Warning, file /plasma/latte-dock/app/main.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2016 Smith AR <audoban@openmailbox.org>
0003     SPDX-FileCopyrightText: 2016 Michail Vourlakos <mvourlakos@gmail.com>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 // local
0009 #include "config-latte.h"
0010 #include "apptypes.h"
0011 #include "lattecorona.h"
0012 #include "layouts/importer.h"
0013 #include "templates/templatesmanager.h"
0014 
0015 // C++
0016 #include <memory>
0017 #include <csignal>
0018 
0019 // Qt
0020 #include <QApplication>
0021 #include <QDebug>
0022 #include <QQuickWindow>
0023 #include <QCommandLineParser>
0024 #include <QCommandLineOption>
0025 #include <QDBusConnection>
0026 #include <QDBusInterface>
0027 #include <QDir>
0028 #include <QFile>
0029 #include <QLockFile>
0030 #include <QSessionManager>
0031 #include <QSharedMemory>
0032 #include <QTextStream>
0033 
0034 // KDE
0035 #include <KCrash>
0036 #include <KLocalizedString>
0037 #include <KAboutData>
0038 #include <KDBusService>
0039 #include <KQuickAddons/QtQuickSettings>
0040 
0041 //! COLORS
0042 #define CNORMAL  "\e[0m"
0043 #define CIGREEN  "\e[1;32m"
0044 #define CGREEN   "\e[0;32m"
0045 #define CICYAN   "\e[1;36m"
0046 #define CCYAN    "\e[0;36m"
0047 #define CIRED    "\e[1;31m"
0048 #define CRED     "\e[0;31m"
0049 
0050 inline void configureAboutData();
0051 inline void detectPlatform(int argc, char **argv);
0052 inline void filterDebugMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);
0053 
0054 QString filterDebugMessageText;
0055 QString filterDebugLogFile;
0056 
0057 int main(int argc, char **argv)
0058 {
0059     //Plasma scales itself to font DPI
0060     //on X, where we don't have compositor scaling, this generally works fine.
0061     //also there are bugs on older Qt, especially when it comes to fractional scaling
0062     //there's advantages to disabling, and (other than small context menu icons) few advantages in enabling
0063 
0064     //On wayland, it's different. Everything is simpler as all co-ordinates are in the same co-ordinate system
0065     //we don't have fractional scaling on the client so don't hit most the remaining bugs and
0066     //even if we don't use Qt scaling the compositor will try to scale us anyway so we have no choice
0067     if (!qEnvironmentVariableIsSet("PLASMA_USE_QT_SCALING")) {
0068         qunsetenv("QT_DEVICE_PIXEL_RATIO");
0069         QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
0070     } else {
0071         QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
0072     }
0073 
0074     QQuickWindow::setDefaultAlphaBuffer(true);
0075 
0076     const bool qpaVariable = qEnvironmentVariableIsSet("QT_QPA_PLATFORM");
0077     detectPlatform(argc, argv);
0078     QApplication app(argc, argv);
0079 
0080     if (!qpaVariable) {
0081         // don't leak the env variable to processes we start
0082         qunsetenv("QT_QPA_PLATFORM");
0083     }
0084 
0085     KQuickAddons::QtQuickSettings::init();
0086 
0087     KLocalizedString::setApplicationDomain("latte-dock");
0088     app.setWindowIcon(QIcon::fromTheme(QStringLiteral("latte-dock")));
0089     //protect from closing app when changing to "alternative session" and back
0090     app.setQuitOnLastWindowClosed(false);
0091 
0092     configureAboutData();
0093 
0094     QCommandLineParser parser;
0095     parser.addHelpOption();
0096     parser.addVersionOption();
0097     parser.addOptions({
0098                           {{"r", "replace"}, i18nc("command line", "Replace the current Latte instance.")}
0099                           , {{"d", "debug"}, i18nc("command line", "Show the debugging messages on stdout.")}
0100                           , {{"cc", "clear-cache"}, i18nc("command line", "Clear qml cache. It can be useful after system upgrades.")}
0101                           , {"enable-autostart", i18nc("command line", "Enable autostart for this application")}
0102                           , {"disable-autostart", i18nc("command line", "Disable autostart for this application")}
0103                           , {"default-layout", i18nc("command line", "Import and load default layout on startup.")}
0104                           , {"available-layouts", i18nc("command line", "Print available layouts")}
0105                           , {"available-dock-templates", i18nc("command line", "Print available dock templates")}
0106                           , {"available-layout-templates", i18nc("command line", "Print available layout templates")}
0107                           , {"layout", i18nc("command line", "Load specific layout on startup."), i18nc("command line: load", "layout_name")}
0108                           , {"import-layout", i18nc("command line", "Import and load a layout."), i18nc("command line: import", "absolute_filepath")}
0109                           , {"suggested-layout-name", i18nc("command line", "Suggested layout name when importing a layout file"), i18nc("command line: import", "suggested_name")}
0110                           , {"import-full", i18nc("command line", "Import full configuration."), i18nc("command line: import", "file_name")}
0111                           , {"add-dock", i18nc("command line", "Add Dock/Panel"), i18nc("command line: add", "template_name")}
0112                           , {"single", i18nc("command line", "Single layout memory mode. Only one layout is active at any case.")}
0113                           , {"multiple", i18nc("command line", "Multiple layouts memory mode. Multiple layouts can be active at any time based on Activities running.")}
0114                       });
0115 
0116     //! START: Hidden options for Developer and Debugging usage
0117     QCommandLineOption graphicsOption(QStringList() << QStringLiteral("graphics"));
0118     graphicsOption.setDescription(QStringLiteral("Draw boxes around of the applets."));
0119     graphicsOption.setFlags(QCommandLineOption::HiddenFromHelp);
0120     parser.addOption(graphicsOption);
0121 
0122     QCommandLineOption withWindowOption(QStringList() << QStringLiteral("with-window"));
0123     withWindowOption.setDescription(QStringLiteral("Open a window with much debug information"));
0124     withWindowOption.setFlags(QCommandLineOption::HiddenFromHelp);
0125     parser.addOption(withWindowOption);
0126 
0127     QCommandLineOption maskOption(QStringList() << QStringLiteral("mask"));
0128     maskOption.setDescription(QStringLiteral("Show messages of debugging for the mask (Only useful to devs)."));
0129     maskOption.setFlags(QCommandLineOption::HiddenFromHelp);
0130     parser.addOption(maskOption);
0131 
0132     QCommandLineOption timersOption(QStringList() << QStringLiteral("timers"));
0133     timersOption.setDescription(QStringLiteral("Show messages for debugging the timers (Only useful to devs)."));
0134     timersOption.setFlags(QCommandLineOption::HiddenFromHelp);
0135     parser.addOption(timersOption);
0136 
0137     QCommandLineOption spacersOption(QStringList() << QStringLiteral("spacers"));
0138     spacersOption.setDescription(QStringLiteral("Show visual indicators for debugging spacers (Only useful to devs)."));
0139     spacersOption.setFlags(QCommandLineOption::HiddenFromHelp);
0140     parser.addOption(spacersOption);
0141 
0142     QCommandLineOption overloadedIconsOption(QStringList() << QStringLiteral("overloaded-icons"));
0143     overloadedIconsOption.setDescription(QStringLiteral("Show visual indicators for debugging overloaded applets icons (Only useful to devs)."));
0144     overloadedIconsOption.setFlags(QCommandLineOption::HiddenFromHelp);
0145     parser.addOption(overloadedIconsOption);
0146 
0147     QCommandLineOption edgesOption(QStringList() << QStringLiteral("kwinedges"));
0148     edgesOption.setDescription(QStringLiteral("Show visual window indicators for hidden screen edge windows."));
0149     edgesOption.setFlags(QCommandLineOption::HiddenFromHelp);
0150     parser.addOption(edgesOption);
0151 
0152     QCommandLineOption localGeometryOption(QStringList() << QStringLiteral("localgeometry"));
0153     localGeometryOption.setDescription(QStringLiteral("Show visual window indicators for calculated local geometry."));
0154     localGeometryOption.setFlags(QCommandLineOption::HiddenFromHelp);
0155     parser.addOption(localGeometryOption);
0156 
0157     QCommandLineOption layouterOption(QStringList() << QStringLiteral("layouter"));
0158     layouterOption.setDescription(QStringLiteral("Show visual debug tags for items sizes."));
0159     layouterOption.setFlags(QCommandLineOption::HiddenFromHelp);
0160     parser.addOption(layouterOption);
0161 
0162     QCommandLineOption filterDebugTextOption(QStringList() << QStringLiteral("debug-text"));
0163     filterDebugTextOption.setDescription(QStringLiteral("Show only debug messages that contain specific text."));
0164     filterDebugTextOption.setFlags(QCommandLineOption::HiddenFromHelp);
0165     filterDebugTextOption.setValueName(i18nc("command line: debug-text", "filter_debug_text"));
0166     parser.addOption(filterDebugTextOption);
0167 
0168     QCommandLineOption filterDebugInputMask(QStringList() << QStringLiteral("input"));
0169     filterDebugInputMask.setDescription(QStringLiteral("Show visual window indicators for calculated input mask."));
0170     filterDebugInputMask.setFlags(QCommandLineOption::HiddenFromHelp);
0171     parser.addOption(filterDebugInputMask);
0172 
0173     QCommandLineOption filterDebugEventSinkMask(QStringList() << QStringLiteral("events-sink"));
0174     filterDebugEventSinkMask.setDescription(QStringLiteral("Show visual indicators for areas of EventsSink."));
0175     filterDebugEventSinkMask.setFlags(QCommandLineOption::HiddenFromHelp);
0176     parser.addOption(filterDebugEventSinkMask);
0177 
0178     QCommandLineOption filterDebugLogCmd(QStringList() << QStringLiteral("log-file"));
0179     filterDebugLogCmd.setDescription(QStringLiteral("Forward debug output in a log text file."));
0180     filterDebugLogCmd.setFlags(QCommandLineOption::HiddenFromHelp);
0181     filterDebugLogCmd.setValueName(i18nc("command line: log-filepath", "filter_log_filepath"));
0182     parser.addOption(filterDebugLogCmd);
0183     //! END: Hidden options
0184 
0185     parser.process(app);
0186 
0187     if (parser.isSet(QStringLiteral("enable-autostart"))) {
0188         Latte::Layouts::Importer::enableAutostart();
0189     }
0190 
0191     if (parser.isSet(QStringLiteral("disable-autostart"))) {
0192         Latte::Layouts::Importer::disableAutostart();
0193         qGuiApp->exit();
0194         return 0;
0195     }
0196 
0197     //! print available-layouts
0198     if (parser.isSet(QStringLiteral("available-layouts"))) {
0199         QStringList layouts = Latte::Layouts::Importer::availableLayouts();
0200 
0201         if (layouts.count() > 0) {
0202             qInfo() << i18n("Available layouts that can be used to start Latte:");
0203 
0204             for (const auto &layout : layouts) {
0205                 qInfo() << "     " << layout;
0206             }
0207         } else {
0208             qInfo() << i18n("There are no available layouts, during startup Default will be used.");
0209         }
0210 
0211         qGuiApp->exit();
0212         return 0;
0213     }
0214 
0215     //! print available-layout-templates
0216     if (parser.isSet(QStringLiteral("available-layout-templates"))) {
0217         QStringList templates = Latte::Layouts::Importer::availableLayoutTemplates();
0218 
0219         if (templates.count() > 0) {
0220             qInfo() << i18n("Available layout templates found in your system:");
0221 
0222             for (const auto &templatename : templates) {
0223                 qInfo() << "     " << templatename;
0224             }
0225         } else {
0226             qInfo() << i18n("There are no available layout templates in your system.");
0227         }
0228 
0229         qGuiApp->exit();
0230         return 0;
0231     }
0232 
0233     //! print available-dock-templates
0234     if (parser.isSet(QStringLiteral("available-dock-templates"))) {
0235         QStringList templates = Latte::Layouts::Importer::availableViewTemplates();
0236 
0237         if (templates.count() > 0) {
0238             qInfo() << i18n("Available dock templates found in your system:");
0239 
0240             for (const auto &templatename : templates) {
0241                 qInfo() << "     " << templatename;
0242             }
0243         } else {
0244             qInfo() << i18n("There are no available dock templates in your system.");
0245         }
0246 
0247         qGuiApp->exit();
0248         return 0;
0249     }
0250 
0251     //! disable restore from session management
0252     //! based on spectacle solution at:
0253     //!   - https://bugs.kde.org/show_bug.cgi?id=430411
0254     //!   - https://invent.kde.org/graphics/spectacle/-/commit/8db27170d63f8a4aaff09615e51e3cc0fb115c4d
0255     QGuiApplication::setFallbackSessionManagementEnabled(false);
0256 
0257     auto disableSessionManagement = [](QSessionManager &sm) {
0258         sm.setRestartHint(QSessionManager::RestartNever);
0259     };
0260     QObject::connect(&app, &QGuiApplication::commitDataRequest, disableSessionManagement);
0261     QObject::connect(&app, &QGuiApplication::saveStateRequest, disableSessionManagement);
0262 
0263     //! choose layout for startup
0264     bool defaultLayoutOnStartup = false;
0265     int memoryUsage = -1;
0266     QString layoutNameOnStartup = "";
0267     QString addViewTemplateNameOnStartup = "";
0268 
0269     //! --default-layout option
0270     if (parser.isSet(QStringLiteral("default-layout"))) {
0271         defaultLayoutOnStartup = true;
0272     } else if (parser.isSet(QStringLiteral("layout"))) {
0273         layoutNameOnStartup = parser.value(QStringLiteral("layout"));
0274 
0275         if (!Latte::Layouts::Importer::layoutExists(layoutNameOnStartup)) {
0276             qInfo() << i18nc("layout missing", "This layout doesn't exist in the system.");
0277             qGuiApp->exit();
0278             return 0;
0279         }
0280     }
0281 
0282     //! --replace option
0283     QString username = qgetenv("USER");
0284 
0285     if (username.isEmpty())
0286         username = qgetenv("USERNAME");
0287 
0288     QLockFile lockFile {QDir::tempPath() + "/latte-dock." + username + ".lock"};
0289 
0290     int timeout {100};
0291 
0292     if (parser.isSet(QStringLiteral("replace")) || parser.isSet(QStringLiteral("import-full"))) {
0293         qint64 pid{ -1};
0294 
0295         if (lockFile.getLockInfo(&pid, nullptr, nullptr)) {
0296             kill(static_cast<pid_t>(pid), SIGINT);
0297             timeout = -1;
0298         }
0299     }
0300 
0301     if (!lockFile.tryLock(timeout)) {
0302         QDBusInterface iface("org.kde.lattedock", "/Latte", "", QDBusConnection::sessionBus());
0303         bool addview{parser.isSet(QStringLiteral("add-dock"))};
0304         bool importlayout{parser.isSet(QStringLiteral("import-layout"))};
0305         bool enableautostart{parser.isSet(QStringLiteral("enable-autostart"))};
0306         bool disableautostart{parser.isSet(QStringLiteral("disable-autostart"))};
0307 
0308         bool validaction{false};
0309 
0310         if (iface.isValid()) {
0311             if (addview) {
0312                 validaction = true;
0313                 iface.call("addView", (uint)0, parser.value(QStringLiteral("add-dock")));
0314                 qGuiApp->exit();
0315                 return 0;
0316             } else if (importlayout) {
0317                 validaction = true;
0318                 QString suggestedname = parser.isSet(QStringLiteral("suggested-layout-name")) ? parser.value(QStringLiteral("suggested-layout-name")) : QString();
0319                 iface.call("importLayoutFile", parser.value(QStringLiteral("import-layout")), suggestedname);
0320                 qGuiApp->exit();
0321                 return 0;
0322             } else if (enableautostart || disableautostart){
0323                 validaction = true;
0324             } else {
0325                 // LayoutPage = 0
0326                 iface.call("showSettingsWindow", 0);
0327             }
0328         }
0329 
0330         if (!validaction) {
0331             qInfo() << i18n("An instance is already running!, use --replace to restart Latte");
0332         }
0333 
0334         qGuiApp->exit();
0335         return 0;
0336     }
0337 
0338     //! clear-cache option
0339     if (parser.isSet(QStringLiteral("clear-cache"))) {
0340         QDir cacheDir(QDir::homePath() + "/.cache/lattedock/qmlcache");
0341 
0342         if (cacheDir.exists()) {
0343             cacheDir.removeRecursively();
0344             qDebug() << "Cache directory found and cleared...";
0345         }
0346     }
0347 
0348     //! import-full option
0349     if (parser.isSet(QStringLiteral("import-full"))) {
0350         bool imported = Latte::Layouts::Importer::importHelper(parser.value(QStringLiteral("import-full")));
0351 
0352         if (!imported) {
0353             qInfo() << i18n("The configuration cannot be imported");
0354             qGuiApp->exit();
0355             return 0;
0356         }
0357     }
0358 
0359     //! import-layout option
0360     if (parser.isSet(QStringLiteral("import-layout"))) {
0361         QString suggestedname = parser.isSet(QStringLiteral("suggested-layout-name")) ? parser.value(QStringLiteral("suggested-layout-name")) : QString();
0362         QString importedLayout = Latte::Layouts::Importer::importLayoutHelper(parser.value(QStringLiteral("import-layout")), suggestedname);
0363 
0364         if (importedLayout.isEmpty()) {
0365             qInfo() << i18n("The layout cannot be imported");
0366             qGuiApp->exit();
0367             return 0;
0368         } else {
0369             layoutNameOnStartup = importedLayout;
0370         }
0371     }
0372 
0373     //! memory usage option
0374     if (parser.isSet(QStringLiteral("multiple"))) {
0375         memoryUsage = (int)(Latte::MemoryUsage::MultipleLayouts);
0376     } else if (parser.isSet(QStringLiteral("single"))) {
0377         memoryUsage = (int)(Latte::MemoryUsage::SingleLayout);
0378     }
0379 
0380     //! add-dock usage option
0381     if (parser.isSet(QStringLiteral("add-dock"))) {
0382         QString viewTemplateName = parser.value(QStringLiteral("add-dock"));
0383         QStringList viewTemplates = Latte::Layouts::Importer::availableViewTemplates();
0384 
0385         if (viewTemplates.contains(viewTemplateName)) {
0386             if (layoutNameOnStartup.isEmpty()) {
0387                 //! Clean layout template is applied and proper name is used
0388                 QString emptytemplatepath = Latte::Layouts::Importer::layoutTemplateSystemFilePath(Latte::Templates::EMPTYLAYOUTTEMPLATENAME);
0389                 QString suggestedname = parser.isSet(QStringLiteral("suggested-layout-name")) ? parser.value(QStringLiteral("suggested-layout-name")) : viewTemplateName;
0390                 QString importedLayout = Latte::Layouts::Importer::importLayoutHelper(emptytemplatepath, suggestedname);
0391 
0392                 if (importedLayout.isEmpty()) {
0393                     qInfo() << i18n("The layout cannot be imported");
0394                     qGuiApp->exit();
0395                     return 0;
0396                 } else {
0397                     layoutNameOnStartup = importedLayout;
0398                 }
0399             }
0400 
0401             addViewTemplateNameOnStartup = viewTemplateName;
0402         }
0403     }
0404 
0405     //! text filter for debug messages
0406     if (parser.isSet(QStringLiteral("debug-text"))) {
0407         filterDebugMessageText = parser.value(QStringLiteral("debug-text"));
0408     }
0409 
0410     //! log file for debug output
0411     if (parser.isSet(QStringLiteral("log-file")) && !parser.value(QStringLiteral("log-file")).isEmpty()) {
0412         filterDebugLogFile = parser.value(QStringLiteral("log-file"));
0413     }
0414 
0415     //! debug/mask options
0416     if (parser.isSet(QStringLiteral("debug")) || parser.isSet(QStringLiteral("mask")) || parser.isSet(QStringLiteral("debug-text"))) {
0417         qInstallMessageHandler(filterDebugMessageOutput);
0418     } else {
0419         const auto noMessageOutput = [](QtMsgType, const QMessageLogContext &, const QString &) {};
0420         qInstallMessageHandler(noMessageOutput);
0421     }
0422 
0423     auto signal_handler = [](int) {
0424         qGuiApp->exit();
0425     };
0426 
0427     std::signal(SIGKILL, signal_handler);
0428     std::signal(SIGINT, signal_handler);
0429 
0430     KCrash::setDrKonqiEnabled(true);
0431     KCrash::setFlags(KCrash::AutoRestart | KCrash::AlwaysDirectly);
0432 
0433     Latte::Corona corona(defaultLayoutOnStartup, layoutNameOnStartup, addViewTemplateNameOnStartup, memoryUsage);
0434     KDBusService service(KDBusService::Unique);
0435 
0436     return app.exec();
0437 }
0438 
0439 inline void filterDebugMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
0440 {
0441     if (msg.endsWith("QML Binding: Not restoring previous value because restoreMode has not been set.This behavior is deprecated.In Qt < 6.0 the default is Binding.RestoreBinding.In Qt >= 6.0 the default is Binding.RestoreBindingOrValue.")
0442         || msg.endsWith("QML Binding: Not restoring previous value because restoreMode has not been set.\nThis behavior is deprecated.\nYou have to import QtQml 2.15 after any QtQuick imports and set\nthe restoreMode of the binding to fix this warning.\nIn Qt < 6.0 the default is Binding.RestoreBinding.\nIn Qt >= 6.0 the default is Binding.RestoreBindingOrValue.\n")
0443         || msg.endsWith("QML Binding: Not restoring previous value because restoreMode has not been set.\nThis behavior is deprecated.\nYou have to import QtQml 2.15 after any QtQuick imports and set\nthe restoreMode of the binding to fix this warning.\nIn Qt < 6.0 the default is Binding.RestoreBinding.\nIn Qt >= 6.0 the default is Binding.RestoreBindingOrValue.")
0444         || msg.endsWith("QML Connections: Implicitly defined onFoo properties in Connections are deprecated. Use this syntax instead: function onFoo(<arguments>) { ... }")) {
0445         //! block warnings because they will be needed only after qt6.0 support. Currently Binding.restoreMode can not be supported because
0446         //! qt5.9 is the minimum supported version.
0447         return;
0448     }
0449 
0450     if (!filterDebugMessageText.isEmpty() && !msg.contains(filterDebugMessageText)) {
0451         return;
0452     }
0453 
0454     const char *function = context.function ? context.function : "";
0455 
0456     QString typeStr;
0457     switch (type) {
0458     case QtDebugMsg:
0459         typeStr = "Debug";
0460         break;
0461     case QtInfoMsg:
0462         typeStr = "Info";
0463         break;
0464     case QtWarningMsg:
0465         typeStr = "Warning" ;
0466         break;
0467     case QtCriticalMsg:
0468         typeStr = "Critical";
0469         break;
0470     case QtFatalMsg:
0471         typeStr = "Fatal";
0472         break;
0473     };
0474 
0475     const char *TypeColor;
0476 
0477     if (type == QtInfoMsg || type == QtWarningMsg) {
0478         TypeColor = CGREEN;
0479     } else if (type == QtCriticalMsg || type == QtFatalMsg) {
0480         TypeColor = CRED;
0481     } else {
0482         TypeColor = CIGREEN;
0483     }
0484 
0485     if (filterDebugLogFile.isEmpty()) {
0486         qDebug().nospace() << TypeColor << "[" << typeStr.toStdString().c_str() << " : " << CGREEN << QTime::currentTime().toString("h:mm:ss.zz").toStdString().c_str() << TypeColor << "]" << CNORMAL
0487                           #ifndef QT_NO_DEBUG
0488                            << CIRED << " [" << CCYAN << function << CIRED << ":" << CCYAN << context.line << CIRED << "]"
0489                           #endif
0490                            << CICYAN << " - " << CNORMAL << msg;
0491     } else {
0492         QFile logfile(filterDebugLogFile);
0493         logfile.open(QIODevice::WriteOnly | QIODevice::Append);
0494         QTextStream logts(&logfile);
0495         logts << "[" << typeStr.toStdString().c_str() << " : " << QTime::currentTime().toString("h:mm:ss.zz").toStdString().c_str() << "]"
0496               <<  " - " << msg << Qt::endl;
0497     }
0498 }
0499 
0500 inline void configureAboutData()
0501 {
0502     KAboutData about(QStringLiteral("lattedock")
0503                      , QStringLiteral("Latte Dock")
0504                      , QStringLiteral(VERSION)
0505                      , i18n("Latte is a dock based on plasma frameworks that provides an elegant and "
0506                             "intuitive experience for your tasks and plasmoids. It animates its contents "
0507                             "by using parabolic zoom effect and tries to be there only when it is needed."
0508                             "\n\n\"Art in Coffee\"")
0509                      , KAboutLicense::GPL_V2
0510                      , QStringLiteral("\251 2016-2017 Michail Vourlakos, Smith AR"));
0511 
0512     about.setHomepage(WEBSITE);
0513     about.setProgramLogo(QIcon::fromTheme(QStringLiteral("latte-dock")));
0514     about.setDesktopFileName(QStringLiteral("latte-dock"));
0515     about.setProductName(QByteArray("lattedock"));
0516 
0517     // Authors
0518     about.addAuthor(QStringLiteral("Michail Vourlakos"), QString(), QStringLiteral("mvourlakos@gmail.com"));
0519     about.addAuthor(QStringLiteral("Smith AR"), QString(), QStringLiteral("audoban@openmailbox.org"));
0520 
0521     KAboutData::setApplicationData(about);
0522 }
0523 
0524 //! used the version provided by PW:KWorkspace
0525 inline void detectPlatform(int argc, char **argv)
0526 {
0527     if (qEnvironmentVariableIsSet("QT_QPA_PLATFORM")) {
0528         return;
0529     }
0530 
0531     for (int i = 0; i < argc; i++) {
0532         if (qstrcmp(argv[i], "-platform") == 0 ||
0533                 qstrcmp(argv[i], "--platform") == 0 ||
0534                 QByteArray(argv[i]).startsWith("-platform=") ||
0535                 QByteArray(argv[i]).startsWith("--platform=")) {
0536             return;
0537         }
0538     }
0539 
0540     const QByteArray sessionType = qgetenv("XDG_SESSION_TYPE");
0541 
0542     if (sessionType.isEmpty()) {
0543         return;
0544     }
0545 
0546     if (qstrcmp(sessionType, "wayland") == 0) {
0547         qputenv("QT_QPA_PLATFORM", "wayland");
0548     } else if (qstrcmp(sessionType, "x11") == 0) {
0549         qputenv("QT_QPA_PLATFORM", "xcb");
0550     }
0551 }