Adds OS-level URL-scheme handlers so users can click a link in a browser,
chat client, or third-party tool to launch Cockatrice straight into a
server / game / Oracle update.
Supported URL forms:
cockatrice://joingame?hostname=H&port=P&roomid=R&gameid=G[&spectate=1]
cockatrice-oracle://update[?spoilers=1]
Credentials passed via URL (username/password query params) are deliberately
ignored — URLs leak through shell history, browser history, EDR capture, etc.
If the target server requires auth and no saved credentials match, the Connect
dialog opens pre-filled with the URL's host/port so the user types their
password locally.
OS integration
- Linux: MimeType=x-scheme-handler/cockatrice (and -oracle) added to the
.desktop files; Exec=cockatrice %u passes the URL through.
- Windows: NSIS installer writes HKCR\cockatrice and HKCR\cockatrice-oracle
registry entries; uninstaller removes them.
- macOS: per-app Info.cockatrice.plist / Info.oracle.plist declare
CFBundleURLTypes; a QFileOpenEvent filter is installed on QApplication
before any nested event loop so cold-start URLs aren't lost.
New abstractions
- Intent (libcockatrice_utility/libcockatrice/utility/intent.h): abstract base
for chained async actions. Guarantees finished() fires at most once,
execute() is idempotent, self-deletes via deleteLater, and
startTimeoutSafetyNet() arms a configurable per-stage deadline. Concrete
intents (IntentConnectToServer, IntentLogin, IntentJoinServerRoom,
IntentJoinServerGame) compose the joingame flow via UrlParser.
- SingleInstanceManager: async per-user local-socket primary/secondary
handshake; URL forwarded from secondary to primary with QDataStream framing
both ways. shared_ptr-backed resolved flag survives every lambda capture.
- UrlSchemeEventFilter (new libcockatrice_utility_gui sibling library): QObject
event filter that translates macOS QFileOpenEvent into a urlReceived(QString)
signal. Lives in its own Gui-bearing lib so libcockatrice_utility stays
Core+Network only and doesn't drag Qt::Gui into servatrice.
- UrlUtils (header-only): pure URL parsing, fully unit-tested.
Wiring
- MainWindow::handleUrl(QString) — single entry point for any URL source.
- DlgConnect::prefillNewHost(host, port) — pre-fills new-host inputs.
- ServersSettings::findSavedCredsByHostPort — case-insensitive saved-creds
lookup.
- TabSupervisor::requestJoinRoom + roomJoinedById / roomJoinFailedById signals,
TabServer::roomAlreadyJoined for the short-circuit "already in this room"
path — single source of truth for duplicate-join handling.
Tests
- 36 new unit tests across four single-purpose targets in tests/:
- url_utils_test (22 tests) — scheme matching, port/room/game validation,
spectator flag, credentials ignored, case-insensitivity.
- url_scheme_event_filter_test (3 tests) — QFileOpenEvent capture.
- intent_test (7 tests) — self-delete, abort propagation, parent-destruction-
mid-flight, finish-once gate, execute() idempotence.
- single_instance_manager_test (4 tests) — per-user socket naming, becoming-
primary alone, forwarding to an existing primary, single-emission of
roleResolved.
Build tooling (incidental)
- Dockerfile.format, docker-compose.format.yml, Makefile — a docker-based
runner for format.sh that mirrors CI's desktop-lint step.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Fix#6659: Correct logging for bottom-of-library card moves
Cause:
- This issue happens due to logic of moving the card from the top of the
deck being reused when moving from the bottom of the deck, in a way
that makes it impossible to check if the card came from the bottom.
Resolution:
- Updated the logging logic in the client for card moves.
- Added a gRPC parameter ('is_from_bottom') for card moves.
- Updates the server logic to reverse the order of the card move if the
'is_from_bottom' parameter is true.
- Added a test to show the expected behaviour of the fix.
NOTE: While the changes in this patch seem big, this is due to changing
the loop in the moveCard function to a helper function, in order to make
the bug fix change. The only change to the loop was to pass a
variable attribution to the moveCard function because it was redundant
to be in the loop.
* chore: run format on test
* refactor: new way to check if a move is from the bottom of the deck
* refactor: change isFromBottom check to static function
* update comments
Co-authored-by: ebbit1q <ebbit1q@gmail.com>
---------
Co-authored-by: ebbit1q <ebbit1q@gmail.com>
* fix(cmake): guard filter_string_test behind WITH_ORACLE or WITH_CLIENT. filter_string_test links against libcockatrice_filters, which is only built when WITH_ORACLE or WITH_CLIENT is enabled. Without this guard, test-only builds fail at configure time because the target doesn't exist. The guard condition mirrors the one in the root CMakeLists.txt that controls whether libcockatrice_filters is built.
* fix(cmake): centralize TEST_QT_MODULES in FindQtRuntime.cmake Each test CMakeLists.txt was independently defining TEST_QT_MODULES with its own subset of Qt modules. This duplicated knowledge that already lives in FindQtRuntime.cmake (which handles module discovery for all other targets: SERVATRICE, COCKATRICE, ORACLE). Consolidate into a single definition using the union of all test requirements (Concurrent Network Svg Widgets), matching the existing pattern for application-target modules. This ensures test-only builds (-DTEST=ON without application targets) discover all necessary Qt components.
* fix(cmake): guard libcockatrice_network behind application targets. libcockatrice_network is only needed by the client, server, and oracle targets. Other application-specific libraries (settings, models, filters) already have similar guards. This was an oversight that caused test-only builds to fail when network dependencies weren't available.
Hand and stack zones had near-identical addCardImpl() implementations, differing only in whether resetState() preserves annotations.
Extract the shared pattern into a template function (CardZoneAlgorithms::addCardToList) to eliminate duplication and enable isolated testing without Qt dependencies.
Pile, table, and zone-view logic are intentionally excluded — their post-add behavior (signals, coordinate placement, hidden cards) is materially different.
* [DeckList] Refactor load from plaintext to take normalizer as param
* update usages
* weaken unit test
* weaken unit test more
* revert unit test
* move CardNameNormalizer to libcockatrice_card
* update unit test
* formatting
* Update UnescapedStringListPart to include parentheses
* also update deck_filter_string
* add unit test
---------
Co-authored-by: RickyRister <ricky.rister.wang@gmail.com>
* add deck hashing tests
* format
* fix header
* fix cmakelists
* fix test
* add 5 second timeout to test
let the optimising begin
* expand tests
* remove debug message
* manually format
* I installed cmake format from the aur
* use decklist library
* format
* Split filters into libraries where applicable.
Took 23 minutes
Took 2 minutes
* Include filter string.
Took 5 minutes
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* Have CardDatabase::getPreferredPrintingInfo respect card provider ID overrides (pinned printings)
Took 13 minutes
Took 37 seconds
Took 10 seconds
Took 10 seconds
# Commit time for manual adjustment:
# Took 30 seconds
Took 15 seconds
Took 8 minutes
Took 21 seconds
* Move settings cache and settings card preference provider out of libcockatrice_settings and into cockatrice
Took 52 minutes
Took 9 minutes
Took 1 minute
* Temp cache.
Took 16 minutes
* Dependency Injection for SettingsCache
* Turn SettingsCache into a QSharedPointer.
* Implement interfaces for settings that need it
Took 2 hours 38 minutes
* Adjust oracle.
Took 5 minutes
* Move abstract/noop interfaces to libcockatrice_interfaces so they can be linked against independently.
Took 52 minutes
* Clean up some links.
Took 3 minutes
* Cleanup two includes.
Took 3 minutes
* More fixes.
Took 7 minutes
* More includes that slipped past.
Took 3 minutes
* Stop mocking and start injecting for tests.
Took 15 minutes
* I don't know why remote_client was including main.
Took 4 minutes
* Include.
Took 3 minutes
* Lint.
Took 2 minutes
* Don't use Qt pointers.
Took 1 hour 7 minutes
* Make parser use CardSettingsInterface
Took 13 minutes
* Also adjust constructor lol.
Took 8 minutes
* Lint.
Took 32 minutes
* Revert "Lint."
This reverts commit ecb596c39e.
Took 3 minutes
* Test.
Took 3 minutes
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* Untangle the card_info.cpp mess and split into individual files.
Took 53 minutes
* Auto-lint was disabled and my pre-commit hook didn't fire. Oh well.
Took 3 minutes
* Fix oracle.
Took 35 seconds
* Lint!
Took 20 seconds
* Fix tests.
Took 3 minutes
* CMakeLists.txt: The reason why I have to disable auto-lint.
Took 2 minutes
* dbconverter.
Took 3 minutes
* Oracle again.
Took 3 minutes
* dbconverter again.
Took 3 minutes
* dbconverter again again.
Took 2 minutes
* More fixes.
Took 4 minutes
Took 21 seconds
* Everything needs everything.
Took 3 minutes
* Everything means everything.
Took 4 minutes
* All the tests.
Took 4 minutes
* I hate everything about this.
Took 3 minutes
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* Simplify add card.
Took 25 minutes
Took 8 minutes
# Commit time for manual adjustment:
# Took 16 minutes
Took 7 seconds
* Refactor out db loading from card db.
Took 39 minutes
Took 9 minutes
Took 2 minutes
Took 17 seconds
* Refactor out db queries from card db.
Took 42 minutes
* Lint.
Took 3 minutes
* I guess.
Took 7 minutes
* Tests.
Took 15 minutes
* I don't understand this.
Took 9 minutes
* fix linker errors
* Rename to querier and promote to QObject
Took 39 minutes
* Lint.
Took 3 minutes
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
Co-authored-by: ebbit1q <ebbit1q@gmail.com>
* big move
* also move game_specific_terms
* fix imports
* alphabetize cmake
* fix build failure
* create database folder and move files into it
* fix includes
* run formatter
* Add option to share decklists on load.
Took 1 hour 58 minutes
Took 9 minutes
Took 39 minutes
* Lint.
Took 14 minutes
Took 2 minutes
* Stuffs
Took 39 minutes
Took 4 seconds
Took 43 minutes
* Process local player first.
Took 45 minutes
* Consider if the setting is set on the game info first.
Took 4 minutes
* Save an indent level.
Took 43 seconds
* Don't commit logging config.
Took 3 minutes
* Remove a debug print.
Took 10 seconds
Took 7 seconds
* Add another optional guard.
Took 5 minutes
* Hide the tab bar if only one (own deck) is visible.
Took 9 minutes
* Rename setting label for clarity
Took 2 minutes
* Capitalization.
Took 3 minutes
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* Add the option to background the oracle wizard, add an option to automatically launch oracle wizard in background every X days since last launch.
* Mocks and a typo.
* Lint.
* Lint?
* qOverload the spinBox.
* Change to a prompt instead.
* An Label.
* Update window_main.cpp
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
Co-authored-by: Zach H <zahalpern+github@gmail.com>
* Add a new dialog that allows editing the default suggested tags.
* Lint.
* Actually hand linting, lol.
* Fix Build
* Add dialog.
* Use show() instead of exec(), properly size hint list item widgets.
* Fix... something to do with the build?
* Cast to abstract tab deck editor instead of regular.
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
Co-authored-by: ZeldaZach <zahalpern+github@gmail.com>
* update hnadling of keywords: AND, OR, NOT in card search
* added and
* update test
* update test
* update OR to not be [oO][rR] and just look for OR
* keyword testing
* adjusted new test
* implement test case for cards with keyword in name
* implement test case to cards with keyword in name
* format
* update test case
* change test cas
* update truth test case
* changed test card search from real cards to fake and added cards
* Update tests/carddatabase/data/cards.xml
Co-authored-by: RickyRister <42636155+RickyRister@users.noreply.github.com>
* Update tests/carddatabase/filter_string_test.cpp
Co-authored-by: RickyRister <42636155+RickyRister@users.noreply.github.com>
* Update tests/carddatabase/filter_string_test.cpp
Co-authored-by: RickyRister <42636155+RickyRister@users.noreply.github.com>
* update formatting
* update cardatabase_test to include +2 cards
* update test case +1 set + 1 type
---------
Co-authored-by: RickyRister <42636155+RickyRister@users.noreply.github.com>
* Implement a little "raise on enter" animation for deck preview widgets.
* Why does the linter need to be run twice?
* Fix build.
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* change settings entry of the cod conversion prompt to a combobox
replace the two checkboxes of which one state is ignored if one is
checked with a three state combobox for better user experience
* Update dlg_settings.cpp
---------
Co-authored-by: Zach H <zahalpern+github@gmail.com>
* fix: Use isRebalanced to detect Arena cards
In #5759 we introduced a setting (off by default) to disable the use of
Arena cards. This was done by checking the `isOnlineOnly` property of
the card, which accidentally also disabled online *printings* of cards
that otherwise exist in paper (e.g. Vintage Masters).
This PR does the same thing but uses the `isRebalanced` property
instead, which is `true` for Arena cards only and should have been used
from the start. This setting does not impact online-only printings such
as Vintage Masters. The settings is still on by default.
* Update setting to mention Alchemy rather than Arena
* Move show folders option next to the search bar.
* Add a new settings button and settings popup, move the folder visibility checkbox there and the ability to hide tags.
* Make popup not close when interacting with child widgets.
* Fix mocks.
* Include cog icon.
* Move PrintingSelector Display options to new quick settings widget.
* Adjust size before first show so as to not overflow.
* Add option to hide card size slider in VDS.
* Qt5 support.
* Fix some warnings by containerizing layouts because addChildLayout is silly.
* Fix an incorrect slot/signal assignment.
* Correct sub-categories for settings to persist them.
* Shuffle some slots and signals around to distinguish between the tag filter and the tags on the deck preview widgets.
* Add a quick setting to draw unused color identities and center them.
* Respect the setting on startup.
* Move card size slider to the quick settings menu.
* Move PrintingSelector card size slider to quick menu, adjust other layout from other options.
* Improve layout, add a gray border.
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>