mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-21 09:05:10 -07:00
Define Cockatrice as an editor/handler for .cod files and cockatrice:// protocol on all platforms (#6775)
* [Application] Add single instance guard and mime types. Took 2 hours 39 minutes Took 18 minutes Took 5 minutes Took 12 seconds Took 11 seconds * Rework Took 30 minutes Took 50 seconds * Only enforce single instance if launched with arguments. Took 5 minutes * Prototype intents Took 53 minutes Took 6 seconds * Connect/disconnect and join game/room intents. Took 3 hours 14 minutes Took 2 seconds Took 15 seconds * Fix include. Took 1 minute Took 23 seconds Took 2 seconds * Mac handling. Took 10 minutes Took 12 seconds Took 3 minutes * Lint. Took 3 minutes * Rebase. Took 3 minutes Took 17 seconds * Implement UrlSchemeEventFilter Took 10 minutes Took 7 seconds * Qt Moc Took 3 minutes * Modern PList. Took 21 minutes Took 1 minute * Debug output. Took 6 minutes Took 19 minutes * Watch file:// prefix. Took 15 minutes Took 7 seconds * Better handler. Took 6 minutes * Don't store reference in member Took 5 minutes * Move impl to cpp, fix lifetime issues. Took 11 minutes Took 2 minutes * Better single-instance handoff, url intent harded copy game link context-menu Polish for installers Took 35 minutes Took 8 seconds --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
27fb5e51de
commit
59d90db3c7
43 changed files with 1372 additions and 13 deletions
|
|
@ -23,12 +23,17 @@
|
|||
#include "client/network/update/card_spoiler/spoiler_background_updater.h"
|
||||
#include "client/settings/cache_settings.h"
|
||||
#include "client/sound_engine.h"
|
||||
#include "client/url_scheme_event_filter.h"
|
||||
#include "database/interface/settings_card_preference_provider.h"
|
||||
#include "interface/intents/intent_open_local_deck.h"
|
||||
#include "interface/intents/url_parser.h"
|
||||
#include "interface/logger.h"
|
||||
#include "interface/pixel_map_generator.h"
|
||||
#include "interface/theme_manager.h"
|
||||
#include "interface/widgets/dialogs/dlg_settings.h"
|
||||
#include "interface/widgets/tabs/tab_supervisor.h"
|
||||
#include "interface/window_main.h"
|
||||
#include "single_instance_manager.h"
|
||||
#include "version_string.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
|
@ -37,6 +42,7 @@
|
|||
#include <QDebug>
|
||||
#include <QLibraryInfo>
|
||||
#include <QLocale>
|
||||
#include <QMessageBox>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QTranslator>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
|
|
@ -177,6 +183,7 @@ int main(int argc, char *argv[])
|
|||
SetUnhandledExceptionFilter(CockatriceUnhandledExceptionFilter);
|
||||
#endif
|
||||
|
||||
// Logging setup
|
||||
#ifdef Q_OS_APPLE
|
||||
// <build>/cockatrice/cockatrice.app/Contents/MacOS/cockatrice
|
||||
const QByteArray configPath = "../../../qtlogging.ini";
|
||||
|
|
@ -194,15 +201,29 @@ int main(int argc, char *argv[])
|
|||
// Set the QT_LOGGING_CONF environment variable
|
||||
qputenv("QT_LOGGING_CONF", configPath);
|
||||
}
|
||||
|
||||
qSetMessagePattern(
|
||||
"\033[0m[%{time yyyy-MM-dd h:mm:ss.zzz} "
|
||||
"%{if-debug}\033[36mD%{endif}%{if-info}\033[32mI%{endif}%{if-warning}\033[33mW%{endif}%{if-critical}\033[31mC%{"
|
||||
"endif}%{if-fatal}\033[1;31mF%{endif}\033[0m] [%{function}] - %{message} [%{file}:%{line}]");
|
||||
QApplication app(argc, argv);
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
UrlSchemeEventFilter cockatriceFilter(QStringList{QStringLiteral("cockatrice")});
|
||||
|
||||
QStringList pendingMacUrls;
|
||||
|
||||
const auto cocoaBufferConn =
|
||||
QObject::connect(&cockatriceFilter, &UrlSchemeEventFilter::urlReceived,
|
||||
[&pendingMacUrls](const QString &url) { pendingMacUrls.append(url); });
|
||||
|
||||
app.installEventFilter(&cockatriceFilter);
|
||||
#endif
|
||||
|
||||
QObject::connect(&app, &QApplication::lastWindowClosed, &app, &QApplication::quit);
|
||||
|
||||
qInstallMessageHandler(CockatriceLogger);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
app.addLibraryPath(app.applicationDirPath() + "/plugins");
|
||||
#endif
|
||||
|
|
@ -218,6 +239,7 @@ int main(int argc, char *argv[])
|
|||
qApp->setAttribute(Qt::AA_DontShowIconsInMenus, true);
|
||||
#endif
|
||||
|
||||
// Translations
|
||||
#ifdef Q_OS_MAC
|
||||
translationPath = qApp->applicationDirPath() + "/../Resources/translations";
|
||||
#elif defined(Q_OS_WIN)
|
||||
|
|
@ -226,6 +248,7 @@ int main(int argc, char *argv[])
|
|||
translationPath = qApp->applicationDirPath() + "/../share/cockatrice/translations";
|
||||
#endif
|
||||
|
||||
// Command-line parser
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription("Cockatrice");
|
||||
parser.addHelpOption();
|
||||
|
|
@ -241,6 +264,35 @@ int main(int argc, char *argv[])
|
|||
Logger::getInstance().logToFile(true);
|
||||
}
|
||||
|
||||
// --- Handle files or URLs passed at startup ---
|
||||
// Only positional arguments are treated as files/URLs, so options like
|
||||
// --connect are never handed off to another instance.
|
||||
const QStringList startupFiles = parser.positionalArguments();
|
||||
const bool hasActivationFiles = !startupFiles.isEmpty();
|
||||
|
||||
SingleInstanceManager instance;
|
||||
|
||||
if (hasActivationFiles) {
|
||||
// Activation launch: hand off to the primary instance if one is
|
||||
// running, otherwise become the primary ourselves. Do this before
|
||||
// constructing the main window so a hand-off exits cheaply.
|
||||
if (!instance.tryRun(startupFiles)) {
|
||||
// Sent successfully → exit
|
||||
return 0;
|
||||
}
|
||||
// No primary instance → become server
|
||||
qInfo() << "No existing instance found, becoming primary instance";
|
||||
} else {
|
||||
// Plain launch: if another instance is running, run independently
|
||||
// instead of handing off and exiting.
|
||||
if (!instance.tryRun(QStringList())) {
|
||||
// Another instance is already running → just run independently
|
||||
qInfo() << "Another instance exists, running independently";
|
||||
} else {
|
||||
qInfo() << "No existing instance found, starting server";
|
||||
}
|
||||
}
|
||||
|
||||
rng = new RNG_SFMT;
|
||||
themeManager = new ThemeManager;
|
||||
soundEngine = new SoundEngine;
|
||||
|
|
@ -272,6 +324,26 @@ int main(int argc, char *argv[])
|
|||
CardDatabaseManager::getInstance()->loadCardDatabases();
|
||||
|
||||
MainWindow ui;
|
||||
|
||||
auto handleActivation = [&ui](const QString &file) {
|
||||
if (file.startsWith("cockatrice://")) {
|
||||
auto urlParser = new IntentUrlParser(&ui, &ui);
|
||||
urlParser->handle(file);
|
||||
} else if (QFileInfo(file).exists()) {
|
||||
auto openDeckIntent = new IntentOpenLocalDeck(ui.getTabSupervisor(), file);
|
||||
QObject::connect(openDeckIntent, &Intent::failed, &ui, [&ui](const QString &reason) {
|
||||
QMessageBox::warning(&ui, QObject::tr("Open deck"), reason);
|
||||
});
|
||||
openDeckIntent->execute();
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QObject::disconnect(cocoaBufferConn);
|
||||
|
||||
QObject::connect(&cockatriceFilter, &UrlSchemeEventFilter::urlReceived,
|
||||
[&handleActivation](const QString &url) { handleActivation(url); });
|
||||
#endif
|
||||
if (parser.isSet("connect")) {
|
||||
ui.setConnectTo(parser.value("connect"));
|
||||
}
|
||||
|
|
@ -297,7 +369,26 @@ int main(int argc, char *argv[])
|
|||
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
||||
app.setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
#endif
|
||||
app.exec();
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
for (const QString &url : pendingMacUrls) {
|
||||
handleActivation(url);
|
||||
}
|
||||
pendingMacUrls.clear();
|
||||
#endif
|
||||
|
||||
for (const QString &file : startupFiles) {
|
||||
handleActivation(file);
|
||||
}
|
||||
|
||||
// Connect to future file/URL events from other instances
|
||||
QObject::connect(&instance, &SingleInstanceManager::filesReceived, [&handleActivation](const QStringList &files) {
|
||||
for (const QString &file : files) {
|
||||
handleActivation(file);
|
||||
}
|
||||
});
|
||||
|
||||
int ret = app.exec();
|
||||
|
||||
qCInfo(MainLog) << "Event loop finished, terminating...";
|
||||
delete rng;
|
||||
|
|
@ -305,5 +396,5 @@ int main(int argc, char *argv[])
|
|||
CountryPixmapGenerator::clear();
|
||||
UserLevelPixmapGenerator::clear();
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue