2012-06-10 16:50:54 +00:00
|
|
|
/*
|
2024-09-17 19:00:25 +00:00
|
|
|
* Deskflow -- mouse and keyboard sharing utility
|
2025-01-24 00:11:17 +00:00
|
|
|
* 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
|
2012-06-10 16:50:54 +00:00
|
|
|
*/
|
|
|
|
|
|
2025-03-19 22:14:27 +00:00
|
|
|
#include "common/Constants.h"
|
2025-03-21 12:24:35 +00:00
|
|
|
#include "common/UrlConstants.h"
|
2025-03-28 21:58:30 +00:00
|
|
|
#include "gui/Diagnostic.h"
|
2025-03-19 21:38:50 +00:00
|
|
|
#include "gui/DotEnv.h"
|
2024-08-07 14:05:18 +00:00
|
|
|
#include "gui/Logger.h"
|
2025-03-28 21:58:30 +00:00
|
|
|
#include "gui/MainWindow.h"
|
2025-03-19 21:47:24 +00:00
|
|
|
#include "gui/Messages.h"
|
2025-03-28 21:58:30 +00:00
|
|
|
#include "gui/StyleUtils.h"
|
2024-10-01 13:30:24 +00:00
|
|
|
|
2024-08-03 00:17:29 +00:00
|
|
|
#include <QApplication>
|
2025-04-03 22:34:45 +00:00
|
|
|
#include <QCommandLineParser>
|
2024-10-01 13:30:24 +00:00
|
|
|
#include <QGuiApplication>
|
2025-01-03 05:00:10 +00:00
|
|
|
#include <QLocalSocket>
|
2024-07-02 19:07:06 +00:00
|
|
|
#include <QMessageBox>
|
2025-01-03 05:00:10 +00:00
|
|
|
#include <QSharedMemory>
|
2012-06-10 16:50:54 +00:00
|
|
|
|
2014-01-24 17:53:03 +00:00
|
|
|
#if defined(Q_OS_MAC)
|
|
|
|
|
#include <Carbon/Carbon.h>
|
2017-05-10 14:25:21 +00:00
|
|
|
#include <cstdlib>
|
2014-05-06 13:00:08 +00:00
|
|
|
#endif
|
|
|
|
|
|
2024-12-16 15:52:34 +00:00
|
|
|
#if defined(Q_OS_UNIX) && defined(QT_DEBUG)
|
|
|
|
|
#include <QLoggingCategory>
|
|
|
|
|
#endif
|
|
|
|
|
|
2024-09-17 19:00:25 +00:00
|
|
|
using namespace deskflow::gui;
|
2024-07-22 16:48:02 +00:00
|
|
|
|
2014-01-24 17:53:03 +00:00
|
|
|
#if defined(Q_OS_MAC)
|
|
|
|
|
bool checkMacAssistiveDevices();
|
|
|
|
|
#endif
|
|
|
|
|
|
2024-10-17 18:04:35 +00:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
|
{
|
2024-12-16 15:52:34 +00:00
|
|
|
#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
|
2024-08-03 00:17:29 +00:00
|
|
|
|
|
|
|
|
QCoreApplication::setApplicationName(kAppName);
|
2024-08-09 13:03:48 +00:00
|
|
|
QCoreApplication::setOrganizationName(kAppName);
|
2025-04-03 22:34:45 +00:00
|
|
|
QCoreApplication::setApplicationVersion(kVersion);
|
|
|
|
|
QCoreApplication::setOrganizationDomain(kOrgDomain); // used in prefix, can't be a url
|
2024-11-11 00:47:08 +00:00
|
|
|
QGuiApplication::setDesktopFileName(QStringLiteral("org.deskflow.deskflow"));
|
2024-08-09 13:03:48 +00:00
|
|
|
|
2024-11-09 14:29:58 +00:00
|
|
|
QApplication app(argc, argv);
|
|
|
|
|
|
2025-04-03 22:34:45 +00:00
|
|
|
// Add Command Line Options
|
2025-04-27 16:11:49 +00:00
|
|
|
auto helpOption = QCommandLineOption("help", "Display Help on the command line");
|
|
|
|
|
auto versionOption = QCommandLineOption("version", "Display version information");
|
|
|
|
|
auto noResetOption = QCommandLineOption("no-reset", "Prevent settings reset if DESKFLOW_RESET_ALL is set");
|
2025-04-03 22:34:45 +00:00
|
|
|
|
|
|
|
|
QCommandLineParser parser;
|
|
|
|
|
parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions);
|
|
|
|
|
parser.addOption(helpOption);
|
|
|
|
|
parser.addOption(versionOption);
|
|
|
|
|
parser.addOption(noResetOption);
|
|
|
|
|
parser.parse(QCoreApplication::arguments());
|
|
|
|
|
|
|
|
|
|
const auto header = QStringLiteral("%1: %2\n").arg(kAppName, kDisplayVersion);
|
|
|
|
|
if (parser.isSet(helpOption) || !parser.unknownOptionNames().isEmpty() || !parser.errorText().isEmpty()) {
|
|
|
|
|
QTextStream(stdout) << header << QStringLiteral(" %1\n\n").arg(kAppDescription)
|
|
|
|
|
<< parser.helpText().replace(QApplication::applicationFilePath(), kAppId);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (parser.isSet(versionOption)) {
|
|
|
|
|
QTextStream(stdout) << header << kCopyright << Qt::endl;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-03 05:00:10 +00:00
|
|
|
// 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 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-09 14:29:58 +00:00
|
|
|
#if !defined(Q_OS_MAC)
|
|
|
|
|
// causes dark mode to be used on some DE's
|
|
|
|
|
if (qEnvironmentVariable("XDG_CURRENT_DESKTOP") != QLatin1String("KDE")) {
|
2024-12-24 04:11:47 +00:00
|
|
|
QApplication::setStyle("fusion");
|
2024-11-09 14:29:58 +00:00
|
|
|
}
|
|
|
|
|
#endif
|
2024-08-09 13:03:48 +00:00
|
|
|
|
2025-01-13 03:51:24 +00:00
|
|
|
// Sets the fallback icon path
|
|
|
|
|
setIconFallbackPaths();
|
|
|
|
|
|
2024-09-17 19:00:25 +00:00
|
|
|
qInstallMessageHandler(deskflow::gui::messages::messageHandler);
|
2024-11-27 03:16:34 +00:00
|
|
|
qInfo("%s v%s", kAppName, qPrintable(kVersion));
|
2024-08-03 00:17:29 +00:00
|
|
|
|
2024-08-09 13:03:48 +00:00
|
|
|
dotenv();
|
2024-08-07 14:05:18 +00:00
|
|
|
Logger::instance().loadEnvVars();
|
|
|
|
|
|
2014-01-24 17:53:03 +00:00
|
|
|
#if defined(Q_OS_MAC)
|
2014-01-28 11:33:54 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
if (app.applicationDirPath().startsWith("/Volumes/")) {
|
2025-03-11 00:21:57 +00:00
|
|
|
QString msgBody = QStringLiteral(
|
|
|
|
|
"Please drag %1 to the Applications folder, "
|
|
|
|
|
"and open it from there."
|
|
|
|
|
);
|
2025-04-27 19:39:23 +00:00
|
|
|
QMessageBox::information(nullptr, kAppName, msgBody.arg(kAppName));
|
2024-07-02 19:07:06 +00:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!checkMacAssistiveDevices()) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2014-01-24 17:53:03 +00:00
|
|
|
#endif
|
|
|
|
|
|
2024-08-10 23:58:24 +00:00
|
|
|
// --no-reset
|
2025-03-21 01:15:26 +00:00
|
|
|
const auto resetEnvVar = QVariant(qEnvironmentVariable("DESKFLOW_RESET_ALL")).toBool();
|
2025-04-03 22:34:45 +00:00
|
|
|
if (resetEnvVar && !parser.isSet(noResetOption)) {
|
2025-03-15 02:48:13 +00:00
|
|
|
diagnostic::clearSettings(false);
|
2024-08-10 23:58:24 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-15 03:03:59 +00:00
|
|
|
MainWindow mainWindow;
|
2024-08-03 00:17:29 +00:00
|
|
|
mainWindow.open();
|
2024-10-01 13:30:24 +00:00
|
|
|
|
2024-12-24 04:11:47 +00:00
|
|
|
return QApplication::exec();
|
2012-06-10 16:50:54 +00:00
|
|
|
}
|
|
|
|
|
|
2014-01-24 17:53:03 +00:00
|
|
|
#if defined(Q_OS_MAC)
|
2024-10-17 18:04:35 +00:00
|
|
|
bool checkMacAssistiveDevices()
|
|
|
|
|
{
|
2024-07-02 19:07:06 +00:00
|
|
|
// 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
|
2024-09-17 19:00:25 +00:00
|
|
|
// tab, with a list of allowed applications. deskflow should
|
2024-07-02 19:07:06 +00:00
|
|
|
// show up there automatically, but will be unchecked.
|
2014-01-24 17:53:03 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
if (AXIsProcessTrusted()) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2014-03-21 16:08:33 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
const void *keys[] = {kAXTrustedCheckOptionPrompt};
|
|
|
|
|
const void *trueValue[] = {kCFBooleanTrue};
|
2025-04-27 19:39:23 +00:00
|
|
|
CFDictionaryRef options = CFDictionaryCreate(nullptr, keys, trueValue, 1, nullptr, nullptr);
|
2014-01-24 17:53:03 +00:00
|
|
|
|
2024-07-02 19:07:06 +00:00
|
|
|
bool result = AXIsProcessTrustedWithOptions(options);
|
|
|
|
|
CFRelease(options);
|
|
|
|
|
return result;
|
2014-01-24 17:53:03 +00:00
|
|
|
}
|
|
|
|
|
#endif
|