Refactor macOS build workflow to support arm64 and x86_64 architectures. Add steps for staging dependencies and packaging unsigned apps for both architectures.
Kept the existing error behavior intact; only the architecture signal source was expanded (all_cflags / all_ldflags), so the same user-facing failure path now triggers in more real-world universal build setups.
Extended the macOS architecture sanity logic to proactively inspect key link-time dependencies (gio, gobject, glib, gmodule, openssl, libcrypto, libintl) with lipo -archs whenever -arch x86_64 is requested, and fail at configure time if any dependency lacks an x86_64 slice.
Kept the failure messaging actionable so users get an immediate explanation and remediation path (use universal/x86_64 deps, build arm64-only, or disable the check explicitly) instead of hitting late linker undefined symbol errors.
Kept the protective failure for true x86_64-only builds that resolve ARM Homebrew libraries (/opt/homebrew) and updated the error text to explicitly mention universal builds as a supported path.
Kept the existing mismatch detection logic intact, but updated the error text to document both bypass methods (-Ddarwin-arch-sanity-check=false or ZOITECHAT_DARWIN_ARCH_SANITY_CHECK=0).
Updated the Darwin architecture check to run only when darwin-arch-sanity-check is enabled, preserving current behavior by default while allowing opt-out.
Improved the check implementation to use pkg-config --libs-only-L glib-2.0 and only evaluate Homebrew path detection when the pkg-config call succeeds.
Extended the error message to include the explicit bypass flag -Ddarwin-arch-sanity-check=false for clearer remediation guidance.
The new error message explicitly tells users to choose one consistent setup: native arm64 with /opt/homebrew, or Rosetta/x86_64 with an x86_64 dependency stack (typically /usr/local).
Updated DH key extraction in dh1080_generate_key to use legacy direct member reads only for truly old OpenSSL, and DH_get0_key for modern OpenSSL, preventing dh->pub_key/dh->priv_key compile failures.
Updated private-key injection in dh1080_compute_key to use DH_set0_key(dh, NULL, priv_key_num) on modern OpenSSL, removing the prior unnecessary temporary public-key allocation and avoiding direct dh->priv_key access.
Reworked signature algorithm detection to use X509_get_signature_nid() when available, and a compatibility fallback (X509_get0_signature() + X509_ALGOR_get0() + OBJ_obj2nid()) when HAVE_X509_GET_SIGNATURE_NID is not defined.
Added explicit check: false to both run_command() calls, resolving the Meson deprecation warning about implicit boolean check behavior in future Meson versions.
Changed the Perl compile/link suitability probe failure from fatal error() to non-fatal warning + plugin disable, so unsupported host Perl setups do not abort the build entirely.
Updated the macOS GitHub Actions workflow to build both architectures (build-macos-arm64 + build-macos-x86_64), then package a universal app by passing both binaries into osx/makebundle.sh.
Documented the universal build invocation in osx/DEBUGGING.md so local builds can reproduce Intel + Apple Silicon compatibility packaging.
Added a fallback so that if git metadata is unavailable, the archive version falls back to VERSION_STRING instead of leaving an empty suffix in the zip name.
Switched the final zip naming to use ARCHIVE_VERSION, avoiding ZoiteChat-.app.zip outputs and fatal git describe errors.
Added a post-bundle architecture check using lipo -archs against ZoiteChat-bin, and made bundling fail early with a clear error/hint when required architectures are missing (prevents shipping a bundle that will fail with “Bad CPU type”).
Kept the existing architecture reporting via file, now reusing a single BIN_PATH variable for consistency.
suppressed noisy defaults read failures for missing preference keys,
fixed unsafe/empty test expressions that caused test: argument expected,
corrected the gettext app domain from APP=name to APP=zoitechat.
Improved launcher behavior for architecture mismatches (Bad CPU type in executable) by detecting exit 126 and printing a clear hint plus file output for ZoiteChat-bin.
Updated osx/makebundle.sh so bundling is more Intel/Apple Silicon friendly:
dynamically resolves/writes prefix and prefix:enchant (Homebrew Intel vs Apple Silicon layouts),
still adapts enchant data path (share/enchant vs share/enchant-2),
prints bundled binary architecture after bundling so mismatches are immediately visible.
Extended macOS debugging docs with a dedicated “Bad CPU type in executable” section and explicit Intel (x86_64) build commands.
Added a fallback that removes the enchant <data> copy stanza entirely when neither share directory exists, preventing the exact Cannot find source to copy bundler failure you reported.
narrowing the core library glob to libenchant-2*.dylib,
bundling provider modules from lib/enchant-2 as a <binary>,
bundling Enchant config files from share/enchant as <data>.
Removed the stale Enchant provider globs that targeted older/nonexistent paths (lib/enchant/libenchant_*.dylib), which caused the CI bundling failure you reported.
Added two explicit plugin paths so both directory variants are bundled correctly:
${prefix:enchant}/lib/enchant/libenchant_*.so
${prefix:enchant}/lib/enchant-2/libenchant_*.so
Changed the bundled enchant dylib entry from a fixed filename to a wildcard (libenchant*.dylib) so gtk-mac-bundler can resolve versioned Homebrew library names (for example libenchant-2.2.dylib
Updated the Meson post-install script to import shutil and add a helper that checks tool availability before invoking post-install commands. This prevents hard failures when optional desktop tooling is not installed (e.g., on macOS/Homebrew CI).
Replaced direct subprocess.call(...) calls for gtk-update-icon-cache and update-desktop-database with guarded calls that emit a clear “Skipping …: command not found” message when absent, while preserving existing behavior when present.
Kept Lua fallback probing logic, but now it applies to both with-lua=auto and the default with-lua=luajit: Meson tries luajit, then lua-5.4, lua5.4, lua-5.3, lua5.3, and lua; if none are present it warns and disables the Lua plugin instead of hard-failing configure.
Updated the Lua plugin dependency selection so plugins/lua/meson.build consumes the pre-resolved fallback dependency for both auto and luajit paths, while keeping explicit custom pkg-config names unchanged.
Added a Check signing secrets availability step that inspects all required Apple signing/notarization secrets and emits a ready output for downstream gating.
Added an explicit skip message step when secrets are missing, and gated all signing/notarization/artifact-upload steps behind steps.signing_secrets.outputs.ready == 'true' so the workflow remains valid while preserving intended behavior.
Implemented the build-only unsigned macOS phase on macos-latest: installs Meson/Ninja/GTK tooling via Homebrew, configures/builds with Meson, installs for bundling, generates the .app zip via the existing macOS bundle script, and uploads the unsigned artifact with retention (14 days).
Implemented the release-grade gated phase: job is gated to push on master and only runs when required Apple signing/notarization secrets are present; it downloads the unsigned artifact, imports Developer ID cert, codesigns, notarizes with Apple API key credentials, staples the ticket, and uploads a signed artifact with retention (30 days).
Raised LSMinimumSystemVersion to 11.0.
Aligned CFBundleIdentifier with project naming (net.zoite.Zoitechat).
Kept version placeholders (@VERSION@) in CFBundleGetInfoString, CFBundleShortVersionString, and CFBundleVersion so they map cleanly via template substitution.
Confirmed icon/document declarations still point to zoitechat.icns and zct/hct extensions.
Made Info.plist generation deterministic in bundling workflow by updating osx/makebundle.sh:
Force script execution from its own directory for stable relative paths.
Always render Info.plist from Info.plist.in before bundling.
Use a single explicit version source: VERSION env var or fallback to meson.build project version.
Use LC_ALL=C substitution and atomic temp-file move for stable output behavior.
When either mac integration dependency is found on darwin, Meson now adds that dependency and defines -DHAVE_GTK_MAC in zoitechat_gtk_cflags, which activates the existing #ifdef HAVE_GTK_MAC blocks in the GTK frontend code.
Verified the existing source guards that become active with HAVE_GTK_MAC are already present in the requested files:
fe-gtk.h (mac header include + extern).
fe-gtk.c (global mac app object and mac-specific paths).
menu.c (mac menubar/app-menu integration).
maingui.c (mac dock attention request).
Added a conditional GHCR login step (docker/login-action@v3) that runs when the selected image is under ghcr.io/*, using ${{ github.actor }} and ${{ github.token }} before docker pull.
Left the existing build/pull flow intact after authentication, so behavior is unchanged except for fixing anonymous-pull denial cases.
Added a Help menu _Update entry with a dedicated zc-menu-update icon constant, so Windows builds can display an appropriate update icon in the Help menu.
Extended icon mapping/fallback logic so emoji/update icons resolve correctly across stock/icon-name paths (zc-menu-emoji, zc-menu-update) including GTK2 stock fallback compatibility.
Added zc-menu-emoji to the input entry fallback icon list so the emoji affordance has a deterministic built-in fallback when theme emoji icons are missing.
Added new update and emoji icon assets in both SVG and PNG for light/dark variants, and registered the PNG resources in the gresource manifest for runtime loading.
Updated the GResource manifest so all menu icons now come from data/icons/menu/{light,dark} PNG files and are embedded with to-pixdata preprocessing, ensuring the app uses one unified internal icon set across platforms.
Generated and added PNG assets for both light and dark menu icon variants under data/icons/menu/ to back the new resource paths used by the GTK menu code.
Fixed menu icon resource detection to fall back from PNG to SVG when probing zc-menu-* entries, so menu item icon lookup no longer fails just because one format is unavailable at runtime.
Updated GTK menu icon loading to use gdk_pixbuf_new_from_resource (instead of ..._at_scale) and added explicit fallback order across variant/light and PNG/SVG resources, which addresses the “red no-entry square” missing-icon behavior you reported.
Kept compatibility with your previous menu resource setup while making loading more resilient on Win32 and other environments where resource/pixbuf behavior differs.
Updated the GTK2 channel list context-menu icon path to use the same helper, removing direct gtk_image_new_from_stock usage for menu icons.
Updated the GTK2 spell-entry popup icon path to use gtkutil_image_new_from_stock, aligning it with the same menu icon set/mapping pipeline used elsewhere (data/icons/menu).
Added a new icon-name→zc-menu-* mapping helper and wired it into gtkutil_image_new_from_stock() as a fallback path for GTK_ICON_SIZE_MENU, after the existing stock-name mapping.
checking whether a matching zc-menu-* resource exists,
preserving support for absolute file paths and <config>/... relative icon paths,
mapping plain icon names (for example, copy) to zc-menu-copy when available.
Updated menu_quick_item() to use the new resolver (menu_icon_widget_new) for all icon-bearing quick/popup menu entries, making icon rendering behavior consistent across platforms.