179 lines
5.5 KiB
C++
179 lines
5.5 KiB
C++
/*
|
|
* Deskflow -- mouse and keyboard sharing utility
|
|
* SPDX-FileCopyrightText: (C) 2024 Chris Rizzitello <sithord48@gmail.com>
|
|
* SPDX-FileCopyrightText: (C) 2012 - 2024 Symless Ltd.
|
|
* SPDX-FileCopyrightText: (C) 2008 Volker Lanz <vl@fidra.de>
|
|
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
|
*/
|
|
|
|
#include "VersionInfo.h"
|
|
#include "common/Constants.h"
|
|
#include "common/ExitCodes.h"
|
|
#include "common/UrlConstants.h"
|
|
#include "gui/Diagnostic.h"
|
|
#include "gui/DotEnv.h"
|
|
#include "gui/Logger.h"
|
|
#include "gui/MainWindow.h"
|
|
#include "gui/Messages.h"
|
|
#include "gui/StyleUtils.h"
|
|
|
|
#include <QApplication>
|
|
#include <QCommandLineParser>
|
|
#include <QLocalSocket>
|
|
#include <QMessageBox>
|
|
#include <QSharedMemory>
|
|
|
|
#if defined(Q_OS_MAC)
|
|
#include <Carbon/Carbon.h>
|
|
#include <cstdlib>
|
|
#endif
|
|
|
|
#if defined(Q_OS_UNIX) && defined(QT_DEBUG)
|
|
#include <QLoggingCategory>
|
|
#endif
|
|
|
|
using namespace deskflow::gui;
|
|
|
|
#if defined(Q_OS_MAC)
|
|
bool checkMacAssistiveDevices();
|
|
#endif
|
|
|
|
const static auto kHeader = QStringLiteral("%1: %2\n").arg(kAppName, kDisplayVersion);
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
#if defined(Q_OS_UNIX) && defined(QT_DEBUG)
|
|
// Fixes Fedora bug where qDebug() messages aren't printed.
|
|
QLoggingCategory::setFilterRules(QStringLiteral("*.debug=true\nqt.*=false"));
|
|
#endif
|
|
|
|
QCoreApplication::setApplicationName(kAppName);
|
|
QCoreApplication::setOrganizationName(kAppName);
|
|
QCoreApplication::setApplicationVersion(kVersion);
|
|
QCoreApplication::setOrganizationDomain(kOrgDomain); // used in prefix, can't be a url
|
|
QGuiApplication::setDesktopFileName(QStringLiteral("org.deskflow.deskflow"));
|
|
|
|
QApplication app(argc, argv);
|
|
|
|
// Add Command Line Options
|
|
auto helpOption = QCommandLineOption({"h", "help"}, "Display Help on the command line");
|
|
auto versionOption = QCommandLineOption({"v", "version"}, "Display version information");
|
|
auto resetOption = QCommandLineOption("reset", "Reset all settings");
|
|
|
|
QCommandLineParser parser;
|
|
parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
|
|
parser.addOption(helpOption);
|
|
parser.addOption(versionOption);
|
|
parser.addOption(resetOption);
|
|
parser.parse(QCoreApplication::arguments());
|
|
|
|
if (!parser.errorText().isEmpty()) {
|
|
qCritical().noquote() << parser.errorText() << "\nUse --help for more information.";
|
|
return s_exitArgs;
|
|
}
|
|
|
|
if (parser.isSet(helpOption)) {
|
|
QTextStream(stdout) << kHeader << QStringLiteral(" %1\n\n").arg(kAppDescription)
|
|
<< parser.helpText().replace(QApplication::applicationFilePath(), kAppId);
|
|
return s_exitSuccess;
|
|
}
|
|
|
|
if (parser.isSet(versionOption)) {
|
|
QTextStream(stdout) << kHeader << kCopyright << Qt::endl;
|
|
return s_exitSuccess;
|
|
}
|
|
|
|
// Create a shared memory segment with a unique key
|
|
// This is to prevent a new instance from running if one is already running
|
|
QSharedMemory sharedMemory("deskflow-gui");
|
|
|
|
// Attempt to attach first and detach in order to clean up stale shm chunks
|
|
// This can happen if the previous instance was killed or crashed
|
|
if (sharedMemory.attach())
|
|
sharedMemory.detach();
|
|
|
|
// If we can create 1 byte of SHM we are the only instance
|
|
if (!sharedMemory.create(1)) {
|
|
// Ping the running instance to have it show itself
|
|
QLocalSocket socket;
|
|
socket.connectToServer("deskflow-gui", QLocalSocket::ReadOnly);
|
|
if (!socket.waitForConnected()) {
|
|
// If we can't connect to the other instance tell the user its running.
|
|
// This should never happen but just incase we should show something
|
|
QMessageBox::information(nullptr, QObject::tr("Deskflow"), QObject::tr("Deskflow is already running"));
|
|
}
|
|
socket.disconnectFromServer();
|
|
return s_exitDuplicate;
|
|
}
|
|
|
|
#if !defined(Q_OS_MAC)
|
|
// causes dark mode to be used on some DE's
|
|
if (qEnvironmentVariable("XDG_CURRENT_DESKTOP") != QLatin1String("KDE")) {
|
|
QApplication::setStyle("fusion");
|
|
}
|
|
#endif
|
|
|
|
// Sets the fallback icon path and fallback theme
|
|
const auto themeName = QStringLiteral("deskflow-%1").arg(iconMode());
|
|
if (QIcon::themeName().isEmpty())
|
|
QIcon::setThemeName(themeName);
|
|
else
|
|
QIcon::setFallbackThemeName(themeName);
|
|
QIcon::setFallbackSearchPaths({QStringLiteral(":/icons/%1").arg(themeName)});
|
|
|
|
qInstallMessageHandler(deskflow::gui::messages::messageHandler);
|
|
qInfo("%s v%s", kAppName, kDisplayVersion);
|
|
|
|
dotenv();
|
|
Logger::instance().loadEnvVars();
|
|
|
|
#if defined(Q_OS_MAC)
|
|
|
|
if (app.applicationDirPath().startsWith("/Volumes/")) {
|
|
QString msgBody = QStringLiteral(
|
|
"Please drag %1 to the Applications folder, "
|
|
"and open it from there."
|
|
);
|
|
QMessageBox::information(nullptr, kAppName, msgBody.arg(kAppName));
|
|
return 1;
|
|
}
|
|
|
|
if (!checkMacAssistiveDevices()) {
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
// --no-reset
|
|
if (parser.isSet(resetOption)) {
|
|
diagnostic::clearSettings(false);
|
|
}
|
|
|
|
MainWindow mainWindow;
|
|
mainWindow.open();
|
|
|
|
return QApplication::exec();
|
|
}
|
|
|
|
#if defined(Q_OS_MAC)
|
|
bool checkMacAssistiveDevices()
|
|
{
|
|
// new in mavericks, applications are trusted individually
|
|
// with use of the accessibility api. this call will show a
|
|
// prompt which can show the security/privacy/accessibility
|
|
// tab, with a list of allowed applications. deskflow should
|
|
// show up there automatically, but will be unchecked.
|
|
|
|
if (AXIsProcessTrusted()) {
|
|
return true;
|
|
}
|
|
|
|
const void *keys[] = {kAXTrustedCheckOptionPrompt};
|
|
const void *trueValue[] = {kCFBooleanTrue};
|
|
CFDictionaryRef options = CFDictionaryCreate(nullptr, keys, trueValue, 1, nullptr, nullptr);
|
|
|
|
bool result = AXIsProcessTrustedWithOptions(options);
|
|
CFRelease(options);
|
|
return result;
|
|
}
|
|
#endif
|