From 60ee81cfbe027dc083e487f470fd14ee07edf348 Mon Sep 17 00:00:00 2001 From: BruebachL <44814898+BruebachL@users.noreply.github.com> Date: Mon, 17 Aug 2026 01:03:37 +0200 Subject: [PATCH] [Client] Route cockatrice:// link clicks from chat to the intent chain (#7136) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Client] Route cockatrice:// link clicks from chat to the intent chain A cockatrice:// link clicked in chat is currently handed to the OS (or does nothing in-process). Clicks now emit a cockatriceLinkActivated signal that travels ChatView -> Tab -> TabSupervisor -> MainWindow, which feeds the URL through the same IntentUrlParser the OS activation path uses, so the join runs entirely in-process. card/user schemes and all other links behave as before. * [Client] Route cockatrice:// link clicks from the in-game chat to the intent chain * [Client] Reuse one IntentUrlParser instance for cockatrice:// links Took 59 seconds --------- Co-authored-by: Lukas BrĂ¼bach --- .../src/interface/widgets/server/chat_view/chat_view.cpp | 5 +++++ .../src/interface/widgets/server/chat_view/chat_view.h | 1 + cockatrice/src/interface/widgets/tabs/tab.h | 1 + cockatrice/src/interface/widgets/tabs/tab_game.cpp | 1 + cockatrice/src/interface/widgets/tabs/tab_message.cpp | 1 + cockatrice/src/interface/widgets/tabs/tab_room.cpp | 1 + cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp | 3 +++ cockatrice/src/interface/widgets/tabs/tab_supervisor.h | 1 + cockatrice/src/interface/window_main.cpp | 8 ++++++++ cockatrice/src/interface/window_main.h | 3 +++ 10 files changed, 25 insertions(+) diff --git a/cockatrice/src/interface/widgets/server/chat_view/chat_view.cpp b/cockatrice/src/interface/widgets/server/chat_view/chat_view.cpp index ae39e688e..e62195c2f 100644 --- a/cockatrice/src/interface/widgets/server/chat_view/chat_view.cpp +++ b/cockatrice/src/interface/widgets/server/chat_view/chat_view.cpp @@ -777,6 +777,11 @@ void ChatView::mouseReleaseEvent(QMouseEvent *event) void ChatView::openLink(const QUrl &link) { + if (link.scheme() == "cockatrice") { + emit cockatriceLinkActivated(link.toString(QUrl::FullyEncoded)); + return; + } + if ((link.scheme() == "card") || (link.scheme() == "user")) { return; } diff --git a/cockatrice/src/interface/widgets/server/chat_view/chat_view.h b/cockatrice/src/interface/widgets/server/chat_view/chat_view.h index 9a8b29b52..c58efa2c6 100644 --- a/cockatrice/src/interface/widgets/server/chat_view/chat_view.h +++ b/cockatrice/src/interface/widgets/server/chat_view/chat_view.h @@ -122,6 +122,7 @@ signals: void addMentionTag(QString mentionTag); void messageClickedSignal(); void showMentionPopup(const QString &userName); + void cockatriceLinkActivated(const QString &url); }; #endif diff --git a/cockatrice/src/interface/widgets/tabs/tab.h b/cockatrice/src/interface/widgets/tabs/tab.h index 6ea1f5077..bddf325e2 100644 --- a/cockatrice/src/interface/widgets/tabs/tab.h +++ b/cockatrice/src/interface/widgets/tabs/tab.h @@ -20,6 +20,7 @@ class Tab : public QMainWindow signals: void userEvent(bool globalEvent = true); void tabTextChanged(Tab *tab, const QString &newTabText); + void cockatriceLinkActivated(const QString &url); protected: TabSupervisor *tabSupervisor; diff --git a/cockatrice/src/interface/widgets/tabs/tab_game.cpp b/cockatrice/src/interface/widgets/tabs/tab_game.cpp index 3f165c1d5..513b7c926 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_game.cpp +++ b/cockatrice/src/interface/widgets/tabs/tab_game.cpp @@ -1292,6 +1292,7 @@ void TabGame::createMessageDock(bool bReplay) qOverload(&CardInfoFrameWidget::setCard)); connect(messageLog, &MessageLogWidget::showCardInfoPopup, this, &TabGame::showCardInfoPopup); connect(messageLog, &MessageLogWidget::deleteCardInfoPopup, this, &TabGame::deleteCardInfoPopup); + connect(messageLog, &MessageLogWidget::cockatriceLinkActivated, this, &TabGame::cockatriceLinkActivated); if (!bReplay) { connect(messageLog, &MessageLogWidget::openMessageDialog, this, &TabGame::openMessageDialog); diff --git a/cockatrice/src/interface/widgets/tabs/tab_message.cpp b/cockatrice/src/interface/widgets/tabs/tab_message.cpp index cee7da589..9eccea7a2 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_message.cpp +++ b/cockatrice/src/interface/widgets/tabs/tab_message.cpp @@ -32,6 +32,7 @@ TabMessage::TabMessage(TabSupervisor *_tabSupervisor, connect(chatView, &ChatView::showCardInfoPopup, this, &TabMessage::showCardInfoPopup); connect(chatView, &ChatView::deleteCardInfoPopup, this, &TabMessage::deleteCardInfoPopup); connect(chatView, &ChatView::addMentionTag, this, &TabMessage::addMentionTag); + connect(chatView, &ChatView::cockatriceLinkActivated, this, &TabMessage::cockatriceLinkActivated); sayEdit = new LineEditUnfocusable; sayEdit->setMaxLength(MAX_TEXT_LENGTH); connect(sayEdit, &LineEditUnfocusable::returnPressed, this, &TabMessage::sendMessage); diff --git a/cockatrice/src/interface/widgets/tabs/tab_room.cpp b/cockatrice/src/interface/widgets/tabs/tab_room.cpp index 9b09ba7bb..508d5a048 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_room.cpp +++ b/cockatrice/src/interface/widgets/tabs/tab_room.cpp @@ -70,6 +70,7 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor, connect(chatView, &ChatView::showMentionPopup, this, &TabRoom::actShowMentionPopup); connect(chatView, &ChatView::messageClickedSignal, this, &TabRoom::focusTab); connect(chatView, &ChatView::openMessageDialog, this, &TabRoom::openMessageDialog); + connect(chatView, &ChatView::cockatriceLinkActivated, this, &TabRoom::cockatriceLinkActivated); connect(chatView, &ChatView::showCardInfoPopup, this, &TabRoom::showCardInfoPopup); connect(chatView, &ChatView::deleteCardInfoPopup, this, &TabRoom::deleteCardInfoPopup); connect(chatView, &ChatView::addMentionTag, this, &TabRoom::addMentionTag); diff --git a/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp b/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp index f72542832..1ab812c54 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp +++ b/cockatrice/src/interface/widgets/tabs/tab_supervisor.cpp @@ -406,6 +406,7 @@ int TabSupervisor::myAddTab(Tab *tab, QAction *manager) { connect(tab, &TabGame::userEvent, this, &TabSupervisor::tabUserEvent); connect(tab, &TabGame::tabTextChanged, this, &TabSupervisor::updateTabText); + connect(tab, &TabGame::cockatriceLinkActivated, this, &TabSupervisor::cockatriceLinkActivated); QString tabText = tab->getTabText(); int idx = addTab(tab, sanitizeTabName(tabText)); @@ -851,6 +852,7 @@ void TabSupervisor::addRoomTab(const ServerInfo_Room &info, bool setCurrent) connect(tab, &TabRoom::maximizeClient, this, &TabSupervisor::maximizeMainWindow); connect(tab, &TabRoom::roomClosing, this, &TabSupervisor::roomLeft); connect(tab, &TabRoom::openMessageDialog, this, &TabSupervisor::addMessageTab); + connect(tab, &TabRoom::cockatriceLinkActivated, this, &TabSupervisor::cockatriceLinkActivated); myAddTab(tab); roomTabs.insert(info.room_id(), tab); if (setCurrent) { @@ -924,6 +926,7 @@ TabMessage *TabSupervisor::addMessageTab(const QString &receiverName, bool focus tab = new TabMessage(this, client, *userInfo, otherUser, userOnline); connect(tab, &TabMessage::talkClosing, this, &TabSupervisor::talkLeft); connect(tab, &TabMessage::maximizeClient, this, &TabSupervisor::maximizeMainWindow); + connect(tab, &TabMessage::cockatriceLinkActivated, this, &TabSupervisor::cockatriceLinkActivated); myAddTab(tab); messageTabs.insert(receiverName, tab); if (focus) { diff --git a/cockatrice/src/interface/widgets/tabs/tab_supervisor.h b/cockatrice/src/interface/widgets/tabs/tab_supervisor.h index 0c3542cf3..5ac3eb365 100644 --- a/cockatrice/src/interface/widgets/tabs/tab_supervisor.h +++ b/cockatrice/src/interface/widgets/tabs/tab_supervisor.h @@ -169,6 +169,7 @@ signals: void localGameEnded(); void adminLockChanged(bool lock); void showWindowIfHidden(); + void cockatriceLinkActivated(const QString &url); public slots: void openDeckInNewTab(const LoadedDeck &deckToOpen); diff --git a/cockatrice/src/interface/window_main.cpp b/cockatrice/src/interface/window_main.cpp index c083dccf8..199a2d952 100644 --- a/cockatrice/src/interface/window_main.cpp +++ b/cockatrice/src/interface/window_main.cpp @@ -40,6 +40,7 @@ #include "intents/intent_connect_to_server.h" #include "intents/intent_login.h" #include "intents/intent_open_server_room_by_name.h" +#include "intents/url_parser.h" #include "logger.h" #include "version_string.h" #include "widgets/dialogs/dlg_connect.h" @@ -497,6 +498,7 @@ MainWindow::MainWindow(QWidget *parent) pixmapCacheSizeChanged(SettingsCache::instance().cacheStorage().getPixmapCacheSize()); connectionController = new ConnectionController(this, this); + urlParser = new IntentUrlParser(this, this); createActions(); createMenus(); @@ -508,6 +510,7 @@ MainWindow::MainWindow(QWidget *parent) connect(tabSupervisor, &TabSupervisor::setMenu, this, &MainWindow::updateTabMenu); connect(tabSupervisor, &TabSupervisor::localGameEnded, this, &MainWindow::localGameEnded); connect(tabSupervisor, &TabSupervisor::showWindowIfHidden, this, &MainWindow::showWindowIfHidden); + connect(tabSupervisor, &TabSupervisor::cockatriceLinkActivated, this, &MainWindow::handleCockatriceLink); connect(connectionController, &ConnectionController::tabSupervisorStartRequested, tabSupervisor, &TabSupervisor::start); connect(connectionController, &ConnectionController::tabSupervisorStopRequested, tabSupervisor, @@ -861,6 +864,11 @@ void MainWindow::showWindowIfHidden() show(); } +void MainWindow::handleCockatriceLink(const QString &url) +{ + urlParser->handle(url); +} + void MainWindow::cardDatabaseLoadingFailed() { if (askedForDbUpdater) { diff --git a/cockatrice/src/interface/window_main.h b/cockatrice/src/interface/window_main.h index 73b7c42c5..fc0791832 100644 --- a/cockatrice/src/interface/window_main.h +++ b/cockatrice/src/interface/window_main.h @@ -56,6 +56,7 @@ class TabSupervisor; class WndSets; class DlgTipOfTheDay; struct ContextConnectToServer; +class IntentUrlParser; class MainWindow : public QMainWindow { @@ -84,6 +85,7 @@ private slots: void actOpenSettingsFolder(); void actShow(); void showWindowIfHidden(); + void handleCockatriceLink(const QString &url); void cardUpdateError(QProcess::ProcessError err); void cardUpdateFinished(int exitCode, QProcess::ExitStatus exitStatus); @@ -139,6 +141,7 @@ private: *aOpenSettingsFolder; TabSupervisor *tabSupervisor; + IntentUrlParser *urlParser; WndSets *wndSets; ConnectionController *connectionController; LocalServer *localServer;