File indexing completed on 2024-04-14 05:24:50

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