Header bar now holds only Difficulty + Leaderboard. A status bar above the board shows the flag counter (left), the New Game button (center) and the timer (right) as LCD-style panels styled with theme-aware CSS.
5.2 KiB
5.2 KiB
AGENTS.md
GTK4/gtkmm4 Minesweeper clone ("NoMines") in C++20, built with Meson. ~800 lines total.
Build & run
meson setup build # or reuse existing build/
meson compile -C build
./build/nomines
- Dev deps come from the Nix flake via direnv (
.envrcusesuse flake);nix developworks standalone. - Alternative:
nix build/nix run. - No unit tests; two optional release-validation tests (desktop file + AppStream metainfo via
desktop-file-validate/appstreamcli) are auto-added when those tools exist. build/compile_commands.jsonexists for clangd (it's gitignored, regenerate withmeson setup --wipe buildif stale).- WARNING: flake builds only see git-tracked files. New source files must be
git added beforenix buildworks.
Architecture
src/minefield.*— pure game logic, no GTK:Minefield(board state, flag counting, chording),Cellbitfield,GameDifficultypresets,GameStateenum.src/board_widget.*—Gtk::DrawingArea; all rendering is hand-drawn Cairo primitives (draw_cell/draw_digit/draw_flag/draw_bomb), input viaGtk::GestureClick+EventControllerMotion, confetti particle animation on win (frame-rate independent viaGdk::FrameClock).src/window.*—Gtk::ApplicationWindowwith HeaderBar (difficulty + leaderboard popovers, radio-styleCheckButtons) and a status bar above the grid (LCD-style flags/timer panels via thestatus-panelCSS class, New Game button centered); owns theshared_ptr<Minefield>and swaps it on new game. Keyboard shortcuts viaGtk::EventControllerKey(R/Ctrl+N new game, 1-4 difficulties, L leaderboard). App-wide CSS (popover backgrounds, status bar) lives in aGtk::CssProviderin the constructor.src/leaderboard.*— persistent best times per difficulty viaGlib::KeyFileat~/.config/nomines/leaderboard.ini(recorded on win, shown in a header-bar popover; falls back to the pre-1.0~/.config/minesweeper/path for migration). NOTE: uses the glibmm 2.80 refcountedKeyFile::create()API and gtkmm 4.14CheckButton(aWidget+Actionable, not aButton— usesignal_toggled()+get_active(), andset_group(CheckButton&)).- glibmm 2.80 quirk:
SignalProxy<R(T...)>::connect()(non-void return signals likesignal_key_pressed) requires theafterbool explicitly —connect(slot, false). Void signals default it to true. src/main.cpp— singleGtk::Application(io.github.bemagri.nomines);make_window_and_run<MainWindow>.
Release
- Version
1.0.0is stamped in FOUR places:meson.build,flake.nix,default.nix, and the<releases>entry inresources/io.github.bemagri.nomines.metainfo.xml. Bump all four together. - Release sanity:
nix build .(validates the flake),desktop-file-validate+appstreamcli validate --no-neton the resources (wired up as meson tests). - The metainfo screenshot URL points at
raw.githubusercontent.com/bemagri/nomines/main/...— it 404s until the repo is published; replace if the repo moves. - Flatpak:
io.github.bemagri.nomines.ymlbuilds libsigc++/glibmm/cairomm/pangomm/gtkmm from tarballs against the GNOME 46 runtime (matches the gtkmm 4.14/glib 2.80 stack we develop against), then the app from thev1.0.0git tag. The pinnedcommit:must match the pushed tag. The leaderboard needs the--filesystem=xdg-config/nomines:createfinish-arg — don't drop it. Local builds land in.flatpak-builder/(gitignored);flatpak-builder --user --install --force-clean build-flatpak io.github.bemagri.nomines.yml. - Flatpak module version traps (all verified by building): gtkmm 4.14 needs pangomm >= 2.50 (which still installs
pangomm-2.48.pc; 2.48.x is too old), and cairomm tarballs live oncairographics.org/releases, not download.gnome.org.appstream-compose: falseis set in the manifest because flatpak-builder's compose fetches the (still-404) metainfo screenshot URL — remove it once the repo is public. Flatpak's icon validation can't decode SVGs, so PNG icons (128/512) are installed under the app-id name and the svg is cleanup-removed; keep that convention.
Gotchas
resources/gresource.xml+ thegnome.compile_resourcesstep inmeson.buildcompile unused code: the app never loads these SVGs/textures (theconfetti.pngis also unused). All art is Cairo-drawn. Don't extend the GResource to implement visual features; draw with Cairo instead.- README's feature list is mostly accurate but not trustworthy in detail; verify against code. (An older
leaderboard.txtCSV may linger in~/.config/minesweeper/from a previous experiment — the app now uses~/.config/nomines/leaderboard.ini.) - Code style: snake_case methods/fields, trailing
_on private members,#pragma once, nested-struct headers. C++20 stdlib only, no third-party libs beyond gtkmm/sigc++. - Board colors are theme-aware:
BoardWidget::resolve_palette()maps GTK CSS named colors (theme_bg_color,theme_base_color, ...) to a light/dark palette each draw. Don't hardcode light grays indraw_*helpers; thread thePalettethrough instead. - Meson source list is explicit in
meson.build— new source files must be added there. .direnv/andbuild*/are gitignored; flake builds require files to be committed/tracked.