Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
64eb76d
feat: upgrade to Wails v3.0.0 stable with GTK4 on Linux
3ace Oct 28, 2026
2ce8dfd
Rename tab menu items to documents and disable document items with no…
3ace Oct 28, 2026
167ff74
Report app state and goroutine stacks when boot smoke shutdown hangs …
3ace Oct 28, 2026
34beab2
Disable GTK portals in the Linux boot smoke step
3ace Oct 28, 2026
a54c02b
Print native thread stacks when boot smoke shutdown hangs on Linux
3ace Oct 28, 2026
ac5ddd0
Run the Linux boot smoke on a private D-Bus session
3ace Oct 28, 2026
c56e44e
Allow WebKit's sandbox user namespaces in the Linux boot smoke
3ace Oct 28, 2026
94ab2d2
Give the Linux boot smoke 10s to exit after SIGTERM
3ace Oct 28, 2026
9c109de
Use native context menus on tree, Pages and Images rows
3ace Oct 29, 2026
d2cf3b4
Ship Linux .deb and .rpm, with an AppArmor profile for WebKit's sandbox
3ace Oct 29, 2026
69ba31c
Boot-smoke the installed .deb in CI with the userns restriction on
3ace Oct 29, 2026
5e281a1
Pin Ubuntu runners to 24.04 and list supported Linux releases
3ace Nov 2, 2026
596b0cc
Raise the Linux window on a second launch and match the desktop entry…
3ace Nov 2, 2026
df46f0f
Raise the Linux window with the launch token alone on Wayland
3ace Nov 2, 2026
d34af48
Read the Linux launch token from the initial environment GTK unsets
3ace Nov 2, 2026
186edd6
Add About to the Help menu on Windows and Linux
3ace Nov 2, 2026
071f32b
Remove the Linux launch-token raise and keep the app ID fix
3ace Nov 2, 2026
56f5ed5
Drop the menu bar from the About window on Linux
3ace Nov 2, 2026
f15cc43
Show About as a dialog in the main window instead of a separate window
3ace Nov 2, 2026
120387f
Keep the menu bar off the splash on Linux
3ace Nov 2, 2026
35c1d4c
Show the Linux splash only once it has painted, and hold the main win…
3ace Nov 2, 2026
457db59
Require glibc 2.39 and GTK 4.14 in the Linux packages
3ace Nov 3, 2026
de3d45e
Never let the Linux splash wait run past the splash timeout
3ace Nov 3, 2026
a0ea5be
Keep drive prefixes, streams and device names out of embedded save names
3ace Nov 3, 2026
48d3473
Bring the main window forward before showing About
3ace Nov 3, 2026
1d2854a
Share one atomic file write between the update cache and Open Recent
3ace Nov 3, 2026
069bebf
List a file once in Open Recent when only its letter case differs
3ace Nov 3, 2026
678f899
Save Open Recent once per multi-file open
3ace Nov 3, 2026
718207e
Build every breadcrumb with one helper
3ace Nov 3, 2026
3a08f74
Open one row menu per key press and carry the object reference with it
3ace Nov 3, 2026
cf75c89
Report the menu state on the first render
3ace Nov 3, 2026
7519182
Record the review fixes in the changelog
3ace Nov 3, 2026
249ff5f
Save Open Recent half a second after the last open from any path
3ace Nov 3, 2026
35f1ec9
Keep a running splash timeout from beating a ready main window
3ace Nov 3, 2026
498b6d9
Replace format and control characters in embedded save names
3ace Nov 3, 2026
b7ea0f8
Match case variants in Open Recent only when both files exist, withou…
3ace Nov 3, 2026
4b404ba
Let a pointer press end the keyboard menu echo guard, and skip it on …
3ace Nov 3, 2026
25adb82
Hold an About request until the frontend has mounted
3ace Nov 3, 2026
3288082
Record the second round of review fixes in the changelog
3ace Nov 3, 2026
c3a8dc4
Save Open Recent once per batch and finish a save in progress on quit
3ace Nov 3, 2026
6a3788c
Map only bidi controls and line separators in embedded save names
3ace Nov 3, 2026
7870fc1
Guard against a keyboard menu echo only for the ContextMenu key
3ace Nov 3, 2026
f2af637
Recheck case variants added while Open Recent stats a path
3ace Nov 3, 2026
0e1e7ab
Update the changelog for the third round of review fixes
3ace Nov 3, 2026
55a4f1b
Route every Open Recent save through the flusher and skip rebuilds af…
3ace Nov 4, 2026
1ad33ba
Record each file as it opens inside an Open Recent batch
3ace Nov 4, 2026
e35de9a
Describe Open Recent saving on quit in the changelog
3ace Nov 4, 2026
75c21d4
Hold Open Recent saves while any open is in flight, for 10 seconds at…
3ace Nov 4, 2026
ff8f09a
Drop the frontend Open Recent batch calls
3ace Nov 4, 2026
194bdcb
Describe when Open Recent saves in the changelog
3ace Nov 4, 2026
3bffa98
Cap the Open Recent hold per open, not from when the list went dirty
3ace Nov 4, 2026
9ee4991
Remove a stray blank line
3ace Nov 4, 2026
6958ed2
Match the Open Recent changelog line to the save timing
3ace Nov 4, 2026
454f3e1
Move a pending Open Recent save only when an open's end changes the h…
3ace Nov 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 51 additions & 32 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
# Linux tests on the oldest supported Ubuntu, the one releases build on.
os: [ubuntu-24.04, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
Expand All @@ -47,28 +48,17 @@ jobs:
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev build-essential xvfb

- name: Configure Linux GTK3 build tag
# Wails alpha.93 promoted GTK4 + WebKitGTK 6.0 to the Linux default;
# the only GTK headers installed on the runner are GTK3 + WebKit2GTK 4.1
# (the "Install Linux native deps" step above). Without the `gtk3` build
# tag, `go vet`, `go test`, `golangci-lint`, and `wails3 generate bindings`
# all type-check `pkg/application/application_linux.go` which `#cgo`s
# `pkg-config gtk4 webkitgtk-6.0` and fails. GOFLAGS propagates the tag
# to every subsequent `go`/`go list`/go-packages-based invocation in
# this job. The Wails build step below still needs `EXTRA_TAGS=gtk3`
# explicitly because the Taskfile combines it with `-tags production`
# to form BUILD_FLAGS (`build/linux/Taskfile.yml:57`); a CLI
# `-tags gtk3` arg on `wails3 build` does NOT reach the Taskfile's
# BUILD_FLAGS construction.
if: runner.os == 'Linux'
shell: bash
run: echo "GOFLAGS=-tags=gtk3" >> "$GITHUB_ENV"
sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev build-essential xvfb

- name: Install Wails v3 CLI
shell: bash
run: go install github.com/wailsapp/wails/v3/cmd/wails3@v3.0.0-beta.18
run: go install github.com/wailsapp/wails/v3/cmd/wails3@v3.0.0

- name: Wails doctor (Linux GTK4 stack)
# Lists the GTK4 / WebKitGTK 6.0 packages the runner builds against.
if: runner.os == 'Linux'
shell: bash
run: wails3 doctor

- name: Install golangci-lint v2
shell: bash
Expand Down Expand Up @@ -190,29 +180,58 @@ jobs:

- name: Wails build (GUI)
shell: bash
# Wails alpha.93 promoted GTK4 + WebKitGTK 6.0 to the Linux default.
# CI installs the libgtk-3-dev + libwebkit2gtk-4.1-dev stack, so on
# Linux we drive the linux:build task with `EXTRA_TAGS=gtk3` (the
# Taskfile combines it into `-tags production,gtk3`, which propagates
# to `wails3 generate bindings -f` -- matches release.yml). macOS and
# Windows use the default `wails3 build` path.
# Linux drives the linux:build task directly (matches release.yml);
# macOS and Windows use the default `wails3 build` path.
run: |
if [ "$RUNNER_OS" = "Linux" ]; then
wails3 task linux:build EXTRA_TAGS=gtk3
wails3 task linux:build
else
wails3 build
fi

- name: CLI build sanity check
shell: bash
run: go build -o bin/pdfdebug ./cmd/cli/

- name: Linux packages
# Builds the .deb and .rpm from the GUI binary above, checks the .deb
# carries the binaries and the AppArmor profile, and installs it so the
# boot smoke runs the packaged binary.
if: runner.os == 'Linux'
shell: bash
run: |
set -euo pipefail
export VERSION=0.0.0-ci GOARCH=amd64
wails3 task linux:generate:deb
wails3 task linux:generate:rpm
contents=$(dpkg-deb -c bin/unidoc-pdf-debugger.deb)
echo "$contents"
for f in ./usr/bin/unidoc-pdf-debugger ./usr/bin/pdfdebug ./etc/apparmor.d/unidoc-pdf-debugger ./usr/share/applications/unidoc-pdf-debugger.desktop; do
grep -q " $f\$" <<<"$contents" || { echo "missing from .deb: $f"; exit 1; }
done
# Recommends would add the portal backend, which the boot smoke's
# private D-Bus session is not set up for.
sudo apt-get install -y --no-install-recommends ./bin/unidoc-pdf-debugger.deb
profiles=$(sudo aa-status)
grep -q unidoc-pdf-debugger <<<"$profiles" || { echo "AppArmor profile not loaded"; exit 1; }

- name: Boot-smoke
shell: bash
timeout-minutes: 5
run: |
if [[ "$RUNNER_OS" == "Linux" ]]; then
cd tests/boot-smoke && xvfb-run -a go test -count=1 -timeout 3m ./...
# gdb lets the boot-smoke hang report print native thread stacks.
sudo apt-get install -y gdb
# The runner, like Ubuntu 24.04, blocks unprivileged user
# namespaces; the installed binary starts only because the
# package's AppArmor profile allows them for WebKit's sandbox.
[ "$(sysctl -n kernel.apparmor_restrict_unprivileged_userns)" = 1 ] \
|| { echo "user namespace restriction is off; the boot smoke would not test the profile"; exit 1; }
# A private session bus: on the runner's systemd user bus the
# desktop portal does not answer, and GTK4's startup D-Bus proxies
# wait the full 25s timeout before the app activates.
cd tests/boot-smoke && BOOT_SMOKE_BINARY=/usr/bin/unidoc-pdf-debugger \
xvfb-run -a dbus-run-session -- go test -count=1 -timeout 3m ./...
else
cd tests/boot-smoke && go test -count=1 -timeout 3m ./...
fi

- name: CLI build sanity check
shell: bash
run: go build -o bin/pdfdebug ./cmd/cli/
53 changes: 23 additions & 30 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ jobs:
# found macos-13 runner queue times unreliable. Re-add if user demand surfaces.
- { os: macos-latest, arch: arm64, goos: darwin, platform: darwin-arm64 }
- { os: windows-latest, arch: amd64, goos: windows, platform: windows-amd64 }
- { os: ubuntu-latest, arch: amd64, goos: linux, platform: linux-amd64 }
# Oldest supported Ubuntu: the binary needs this glibc or newer.
- { os: ubuntu-24.04, arch: amd64, goos: linux, platform: linux-amd64 }
runs-on: ${{ matrix.os }}
timeout-minutes: 25
steps:
Expand Down Expand Up @@ -61,23 +62,11 @@ jobs:
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.1-dev build-essential

- name: Configure Linux GTK3 build tag
# Wails alpha.93 promoted GTK4 + WebKitGTK 6.0 to the Linux default.
# The runner installs the GTK3 stack only, so propagate `-tags=gtk3`
# via GOFLAGS to every Go-tool invocation in this job (most notably
# `wails3 generate bindings -clean=true`, which uses go/packages and
# would otherwise fail to type-check pkg/application's CGo GTK4 file).
# `wails3 task linux:build` below still needs `EXTRA_TAGS=gtk3`
# explicitly because the Taskfile combines it with `-tags production`.
if: runner.os == 'Linux'
shell: bash
run: echo "GOFLAGS=-tags=gtk3" >> "$GITHUB_ENV"
sudo apt-get install -y libgtk-4-dev libwebkitgtk-6.0-dev build-essential

- name: Install Wails v3 CLI
shell: bash
run: go install github.com/wailsapp/wails/v3/cmd/wails3@v3.0.0-beta.18
run: go install github.com/wailsapp/wails/v3/cmd/wails3@v3.0.0

- name: Install frontend deps
shell: bash
Expand Down Expand Up @@ -183,7 +172,7 @@ jobs:
INFO_VERSION="${VERSION%%-*}"
INFO_VERSION="${INFO_VERSION%%+*}"
jq --arg v "$INFO_VERSION" \
'.fixed.file_version = $v | .info["0000"].ProductVersion = $v' \
'.fixed.file_version = $v | .info["0409"].ProductVersion = $v' \
build/windows/info.json > build/windows/info.json.tmp
mv build/windows/info.json.tmp build/windows/info.json
cat build/windows/info.json
Expand Down Expand Up @@ -269,17 +258,13 @@ jobs:
test -f "bin/unidoc-pdf-debugger.exe"

- name: Build Linux GUI
if: matrix.os == 'ubuntu-latest'
if: matrix.os == 'ubuntu-24.04'
shell: bash
env:
ARCH: ${{ matrix.arch }}
# Wails alpha.93 promoted GTK4 + WebKitGTK 6.0 to the Linux default.
# The runner installs the libgtk-3-dev + libwebkit2gtk-4.1-dev stack;
# EXTRA_TAGS=gtk3 opts back into the legacy GTK3 build path so the
# CGo link resolves against the installed headers.
run: |
set -euo pipefail
wails3 task linux:build ARCH="$ARCH" EXTRA_TAGS=gtk3
wails3 task linux:build ARCH="$ARCH"
test -f "bin/unidoc-pdf-debugger"

- name: Install create-dmg
Expand Down Expand Up @@ -341,7 +326,7 @@ jobs:
build_dmg || build_dmg --skip-jenkins
# A failed first attempt leaves its own rw.<pid>.*.dmg scratch that
# the retry (a new pid) does not remove; clear any scratch so only
# the final .dmg reaches the artifact upload (EXPECTED_FILES=6).
# the final .dmg reaches the artifact upload (EXPECTED_FILES=8).
rm -f dist/rw.*.dmg
# Confirm the output is a valid disk image before it feeds the
# SHA256SUMS job.
Expand Down Expand Up @@ -392,6 +377,12 @@ jobs:
cp LICENSE NOTICE "$CLI_STAGE/"
tar -czf "dist/pdfdebug-cli-${VERSION}-${PLATFORM}.tar.gz" \
-C "$CLI_STAGE" .
# .deb (installs the AppArmor profile Ubuntu 23.10+ needs for
# WebKit's sandbox) and .rpm, both with the GUI and the CLI.
GOARCH=amd64 wails3 task linux:generate:deb
GOARCH=amd64 wails3 task linux:generate:rpm
cp bin/unidoc-pdf-debugger.deb "dist/unidoc-pdf-debugger-${VERSION}-${PLATFORM}.deb"
cp bin/unidoc-pdf-debugger.rpm "dist/unidoc-pdf-debugger-${VERSION}-${PLATFORM}.rpm"
;;
esac
ls -la dist/
Expand All @@ -413,7 +404,7 @@ jobs:

release:
needs: build
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
outputs:
# Exposed for the downstream `homebrew` job: the homebrew job gates its
# execution on `needs.release.outputs.prerelease == 'false'` and reuses
Expand Down Expand Up @@ -461,19 +452,21 @@ jobs:
cat SHA256SUMS.txt
# Manifest integrity guard: refuse to publish if the manifest is empty, the
# line count drifts from the number of files staged for release, or the file
# count drifts from the 6 release artifacts = 3 platforms x 2 archives each
# (a GUI archive, which now also embeds the CLI, plus a standalone CLI
# archive). The bundled-in CLI is not a separate file and is not counted.
# The 6 expected filenames are:
# count drifts from the 8 release artifacts: per platform a GUI archive, which
# also embeds the CLI, plus a standalone CLI archive, and on Linux a .deb and
# an .rpm. The bundled-in CLI is not a separate file and is not counted.
# The 8 expected filenames are:
# unidoc-pdf-debugger-<ver>-darwin-arm64.dmg
# pdfdebug-cli-<ver>-darwin-arm64.tar.gz
# unidoc-pdf-debugger-<ver>-windows-amd64.zip
# pdfdebug-cli-<ver>-windows-amd64.zip
# unidoc-pdf-debugger-<ver>-linux-amd64.tar.gz
# pdfdebug-cli-<ver>-linux-amd64.tar.gz
# unidoc-pdf-debugger-<ver>-linux-amd64.deb
# unidoc-pdf-debugger-<ver>-linux-amd64.rpm
# Catches any future staging regression that drops or duplicates an
# artifact before it reaches the Release page.
EXPECTED_FILES=6
EXPECTED_FILES=8
FILES=$(find . -maxdepth 1 -type f ! -name SHA256SUMS.txt | wc -l | tr -d ' ')
LINES=$(wc -l < SHA256SUMS.txt | tr -d ' ')
if [ "$FILES" -eq 0 ]; then
Expand All @@ -485,7 +478,7 @@ jobs:
exit 1
fi
if [ "$FILES" != "$EXPECTED_FILES" ]; then
echo "Expected $EXPECTED_FILES release artifacts (3 platforms x 2 artifacts), got $FILES." >&2
echo "Expected $EXPECTED_FILES release artifacts (a GUI and a CLI archive per platform, plus the Linux .deb and .rpm), got $FILES." >&2
find . -maxdepth 1 -type f ! -name SHA256SUMS.txt | LC_ALL=C sort >&2
exit 1
fi
Expand Down
11 changes: 10 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ dist

# Wails build scaffolding -- ignore everything except config files we customize.
# Tracked config files: config.yml, Taskfile.yml (common tasks included by per-platform
# Taskfiles), darwin/Info.plist, linux/*.desktop, windows/info.json, plus the
# Taskfiles), darwin/Info.plist, linux/*.desktop, the Linux nfpm package config
# and its scripts, the Linux AppArmor profile, windows/info.json, plus the
# per-platform Taskfile.yml (customised with the -X main.version ldflag).
# These are force-added with git add -f.
build/*
Expand All @@ -59,6 +60,14 @@ build/darwin/*
build/linux/*
!build/linux/unidoc-pdf-debugger.desktop
!build/linux/Taskfile.yml
!build/linux/apparmor
!build/linux/nfpm
build/linux/nfpm/*
!build/linux/nfpm/nfpm.yaml
!build/linux/nfpm/scripts
build/linux/nfpm/scripts/*
!build/linux/nfpm/scripts/postinstall.sh
!build/linux/nfpm/scripts/postremove.sh
!build/windows
build/windows/*
!build/windows/info.json
Expand Down
Loading
Loading