diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 11adece..898c9c1 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -127,7 +127,7 @@ jobs: run: | apt-get update apt-get install -y \ - curl wget file \ + curl wget file gcc \ libwebkit2gtk-4.1-dev \ libssl-dev \ libxdo-dev \ @@ -154,21 +154,38 @@ jobs: - name: Stage AppRun and linuxdeploy for AppImage bundler run: | + set -e mkdir -p ~/.cache/tauri cp tools/AppRun-x86_64 ~/.cache/tauri/AppRun-x86_64 chmod +x ~/.cache/tauri/AppRun-x86_64 - # Pre-extract linuxdeploy AppImage so it runs without FUSE in Docker + + # Download and extract linuxdeploy without FUSE. + # Tauri also runs `dd if=/dev/zero bs=1 count=3 seek=8` on the cached file + # to hide AppImage magic bytes — this corrupts a shell script's shebang. + # A compiled ELF binary is safe: bytes 8-10 (EI_OSABI/EI_ABIVERSION/pad) + # are already zero in standard ELF and survive the dd no-op. wget -q \ "https://github.com/tauri-apps/binary-releases/releases/download/linuxdeploy/linuxdeploy-x86_64.AppImage" \ -O /tmp/linuxdeploy.AppImage + + # Find squashfs at a page-aligned boundary after the ELF runtime OFFSET=$(python3 -c " d=open('/tmp/linuxdeploy.AppImage','rb').read() -o=d.find(b'hsqs') -print(o if o!=-1 else d.find(b'sqsh')) +for i in range(4096,len(d),4096): + if d[i:i+4] in (b'hsqs',b'sqsh'): + print(i); break ") unsquashfs -d /tmp/linuxdeploy-root -offset "$OFFSET" /tmp/linuxdeploy.AppImage - printf '#!/bin/sh\nexec /tmp/linuxdeploy-root/AppRun "$@"\n' \ - > ~/.cache/tauri/linuxdeploy-x86_64.AppImage + + # Compile a tiny ELF forwarder as the cached AppImage entry point + cat > /tmp/ld_wrapper.c << 'CSRC' +#include +int main(int argc, char** argv) { + execv("/tmp/linuxdeploy-root/AppRun", argv); + return 1; +} +CSRC + gcc -o ~/.cache/tauri/linuxdeploy-x86_64.AppImage /tmp/ld_wrapper.c chmod +x ~/.cache/tauri/linuxdeploy-x86_64.AppImage - name: Build diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 390f5a9..2e44f91 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -106,7 +106,7 @@ fn set_badge_count(count: u32, window: tauri::Window) -> Result<(), String> { ReleaseDC, SelectObject, SetBkMode, SetTextColor, BITMAPINFO, BITMAPINFOHEADER, BI_RGB, CLIP_DEFAULT_PRECIS, DEFAULT_CHARSET, DEFAULT_PITCH, DEFAULT_QUALITY, DT_CENTER, DT_SINGLELINE, DT_VCENTER, FF_DONTCARE, - FONT_PITCH_AND_FAMILY, FW_BOLD, OUT_DEFAULT_PRECIS, PS_NULL, TRANSPARENT, + FW_BOLD, OUT_DEFAULT_PRECIS, PS_NULL, TRANSPARENT, }, UI::{ Shell::{ITaskbarList3, TaskbarList}, @@ -168,7 +168,7 @@ fn set_badge_count(count: u32, window: tauri::Window) -> Result<(), String> { OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, - FONT_PITCH_AND_FAMILY(DEFAULT_PITCH.0 | FF_DONTCARE.0), + (DEFAULT_PITCH.0 | FF_DONTCARE.0) as u32, windows::core::w!("Segoe UI"), ); let old_font = SelectObject(hdc, hfont.into()); @@ -191,8 +191,11 @@ fn set_badge_count(count: u32, window: tauri::Window) -> Result<(), String> { let _ = DeleteObject(hpen.into()); let _ = DeleteObject(hfont.into()); - let hbm_mask = CreateBitmap(size, size, 1, 1, None) - .map_err(|e| { let _ = DeleteObject(hbm_color.into()); e.to_string() })?; + let hbm_mask = CreateBitmap(size, size, 1, 1, None); + if hbm_mask.0 as usize == 0 { + let _ = DeleteObject(hbm_color.into()); + return Err("CreateBitmap failed".to_string()); + } let icon_info = ICONINFO { fIcon: BOOL(1),