File indexing completed on 2025-01-12 11:03:14
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 }