Skip to content

Add cross-platform autostart-on-login toggle - #744

Merged
mrjimenez merged 3 commits into
amule-project:masterfrom
got3nks:feat/autostart-toggle
May 27, 2026
Merged

Add cross-platform autostart-on-login toggle#744
mrjimenez merged 3 commits into
amule-project:masterfrom
got3nks:feat/autostart-toggle

Conversation

@got3nks

@got3nks got3nks commented May 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #742. Adds a single "Start aMule automatically when I log in" checkbox to Preferences → General that toggles a per-user autostart entry in the OS-native store on all three desktop targets. Splits from #740 which only set autostart at install time on Windows — this gives users a runtime toggle that works everywhere.

Cross-platform backend

State is never persisted in aMule.conf — the OS store is the source of truth, read live each time the dialog opens. Three backends, one frontend (src/AutostartManager.{h,cpp}):

OS Store
Windows HKCU\Software\Microsoft\Windows\CurrentVersion\Run\aMule = "<exe>"
macOS ~/Library/LaunchAgents/org.amule.amule.plist (launchd open -a <bundle> so the launch goes through Gatekeeper, not the bare Mach-O)
Linux $XDG_CONFIG_HOME/autostart/amule.desktop (XDG Autostart spec — what every DE's "Startup Applications" GUI reads)

All three are per-user, no elevation required at toggle time. Toggling writes immediately (no Apply-on-OK) and the checkbox rolls back if the OS write fails (e.g. read-only LaunchAgents dir on a sandboxed install) with a wxMessageBox explaining why.

Self-heal on binary move

AutostartManager::SelfHealOnStartup() runs once at the end of CamuleAppCommon::CommonInit. If an autostart entry exists and its registered path doesn't match the running binary's canonical path (realpath on POSIX, GetModuleFileNameW on Windows), the entry is rewritten.

Why it matters: every backend stores an absolute path. Naively the autostart entry breaks if the user moves the AppImage / .app / install dir. AppImages especially are designed to be portable — users rename them, copy them between machines, drop them on USB sticks. Without self-heal, "enable autostart → move binary" would silently fail at next login forever.

With self-heal, first re-launch after moving the binary updates the entry. User sees a broken-login-launch at most once, then it's fixed. Verified on Linux (moved binary, Exec= line in .desktop rewrote on next launch) and Windows (moved folder to Desktop, HKCU Run\aMule value rewrote on next launch).

Edge cases for future maintainers:

  • User moves binary, never launches manually, just logs out/in: entry stays broken. No way around this without a watchdog process — out of scope.
  • Multiple aMule installs on the same machine: whichever launched last "wins" the autostart entry. Arguably correct.
  • Uninstall via package manager: autostart entry orphaned. Handled by package-side postrm hooks if anyone wants to add them (outside aMule source).
  • macOS argv[0] for .app bundles resolves to <app>.app/Contents/MacOS/<exe>. For the LaunchAgent plist we register open -a <bundle> so users launch the app as a whole rather than the inner Mach-O — sidesteps Gatekeeper / quarantine edge cases.

CLI surface

amule --configure-autostart on|off exposed on amule / amuled / amulegui via CamuleAppCommon's cmdline parser. Lets the Windows installer's Components-page checkbox call into the same code path as the Preferences toggle — follow-up PR after this lands to switch the #740 installer.nsi over to call this CLI instead of writing the registry directly. Keeps OS-specific logic in exactly one place.

UI

New IDC_AUTOSTART_LOGIN = 10334 constant (picked above the wxDesigner-generated range, per existing convention). wxCheckBox added between "Check for new version at startup" and "Start minimized" on PreferencesGeneralTab. New OnAutostartToggle event handler lives separately from OnCheckBoxChange since this widget's value never round-trips through aMule.conf.

i18n

All 4 user-visible strings wrapped with _(). po/amule.pot regenerated via the project's scripts/update-po.sh; that pulled in pre-existing drift from contributors who landed strings since 2026-05-11 without running the script. .po files NOT touched in this PR — translators get the new entries when they next msgmerge.

Test plan

  • macOS: UI checkbox visible on Preferences → General. Toggling writes/removes ~/Library/LaunchAgents/org.amule.amule.plist with correct ProgramArguments = ["/usr/bin/open", "-a", "<bundle>"]. CLI flag works.
  • Linux (Ubuntu 26.04 ARM64): UI checkbox visible. Toggling writes/removes ~/.config/autostart/amule.desktop with correct Exec= line. CLI flag works. Self-heal verified: moved binary, relaunched, Exec= rewrote to new path.
  • Windows 11 ARM64 (CLANGARM64): UI checkbox visible. Toggling writes/removes HKCU\Software\Microsoft\Windows\CurrentVersion\Run\aMule REG_SZ value (quoted path). CLI flag works. Self-heal verified: moved portable tree to Desktop, relaunched, registry value rewrote to new path.
  • Full link test passes on all three platforms.

Out of scope (follow-up)

  • Switching #740's installer.nsi to call amule.exe --configure-autostart on via ExecWait instead of writing the registry directly. Needs to wait until this lands and a release ships with the flag.
  • amuled systemd user service (different mechanism, different audience — daemon Restart=on-failure semantics make sense for amuled but not for the GUI). Worth its own discussion if anyone asks.

@got3nks
got3nks marked this pull request as draft May 27, 2026 14:01
got3nks added 3 commits May 27, 2026 16:03
Adds a single "Start aMule automatically when I log in" checkbox to
Preferences → General that toggles a per-user autostart entry in the
OS-native store on all three desktop targets:

* Windows: HKCU\Software\Microsoft\Windows\CurrentVersion\Run\aMule
* macOS:   ~/Library/LaunchAgents/org.amule.amule.plist
           (launchd `open -a <bundle>` so Gatekeeper-friendly)
* Linux:   $XDG_CONFIG_HOME/autostart/amule.desktop (XDG spec)

State is never persisted in aMule.conf — the OS store is the source
of truth, read live each time the dialog opens. Toggling writes
immediately (no OnOk needed) and rolls the checkbox back if the OS
write fails (e.g. read-only LaunchAgents dir on a sandboxed install).

`src/AutostartManager.{h,cpp}` hides the per-OS plumbing behind:
  bool IsEnabled() / Enable() / Disable()
  GetCanonicalExecutablePath()
  SelfHealOnStartup()

`SelfHealOnStartup()` runs once at the end of CamuleAppCommon::CommonInit.
If an autostart entry exists and its registered path doesn't match
the running binary's canonical path (`realpath` on POSIX,
`GetModuleFileNameW` on Windows), the entry is rewritten. Handles
the "user moved the AppImage / .app / install dir without re-toggling
the checkbox" case so login launches the right binary on the next
boot after a manual launch.

New CLI flag `--configure-autostart on|off` exposed on amule / amuled /
amulegui via CamuleAppCommon's cmdline parser. Lets the Windows
installer's Components-page checkbox call into the same code path as
the Preferences toggle (followup PR after this lands to switch the
installer.nsi over).

UI: new IDC_AUTOSTART_LOGIN constant (picked above the wxDesigner-
generated range), wxCheckBox added between "Check for new version
at startup" and "Start minimized" on PreferencesGeneralTab, and an
EVT_CHECKBOX handler `OnAutostartToggle` that lives separately from
the generic OnCheckBoxChange (since this widget's value never round-
trips through aMule.conf).
Pulls in the four new translatable strings the autostart toggle
adds (checkbox label, tooltip, two error messages, messagebox
title) plus picks up pre-existing drift from contributors who
landed strings since 2026-05-11 without running the update script.

.po files left alone in this commit — msgmerge'ing all 38 of them
would balloon the diff with mechanical line-shift noise without
any new translations. Translators get the new entries on their
next msgmerge run.
…utostart

The installer's "Start aMule when I log in" Components-page section
now calls `amule.exe --configure-autostart on` via ExecWait instead
of writing the HKCU Run key directly. Puts the install-time path
and the Preferences → General checkbox through the same
AutostartManager API — OS-specific store details (HKCU Run on
Windows today; macOS LaunchAgent / Linux XDG .desktop on those
targets in the future) live in exactly one place.

Uninstaller's autostart cleanup left as-is: it has a safety check
that only deletes the Run value if it still points inside $INSTDIR,
so a user's hand-set value with a different path survives uninstall.
A blind `--configure-autostart off` would regress that check; not
worth losing for the symmetry.

UAC caveat preserved from the prior direct write: HKCU resolves to
the elevated context's hive — if a non-admin user enters a different
admin's password at UAC, the entry goes to that admin's HKCU
instead of the asker's. Fixing cleanly needs the UAC.dll plugin
which isn't worth pulling in for an opt-in single-machine convenience.
@got3nks
got3nks force-pushed the feat/autostart-toggle branch from e35e774 to 6a033c4 Compare May 27, 2026 14:04
@got3nks

got3nks commented May 27, 2026

Copy link
Copy Markdown
Contributor Author

#740 merged, so I've rebased this branch onto current master and added 6a033c4c1: the installer's "Start aMule when I log in" Components-page section now calls amule.exe --configure-autostart on via ExecWait instead of writing the HKCU Run key directly. Single source of truth for the autostart logic across install-time and Preferences-time toggling.

Uninstaller's autostart cleanup left as-is — it has a safety check that only deletes the Run value if it still points inside $INSTDIR, so a user's hand-set value with a different path survives uninstall. A blind --configure-autostart off from the uninstaller would regress that check; not worth losing for the symmetry.

@got3nks
got3nks marked this pull request as ready for review May 27, 2026 14:29
@got3nks

got3nks commented May 27, 2026

Copy link
Copy Markdown
Contributor Author

Verified 6a033c4c1 end-to-end on Windows 11 ARM64: ticked "Start aMule when I log in" during install → reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v aMule after install shows REG_SZ "C:\Program Files\aMule\bin\amule.exe". The full pipeline (installer Components → ExecWaitamule.exe --configure-autostart onAutostartManager::Enable → registry) works as designed.

@mrjimenez
mrjimenez merged commit d4ab8ce into amule-project:master May 27, 2026
7 checks passed
@got3nks
got3nks deleted the feat/autostart-toggle branch May 27, 2026 15:15
got3nks added a commit to got3nks/amule that referenced this pull request Jun 4, 2026
…ndex

Adds 55+ merged PRs to the 3.0.0 changelog since the last update
(amule-project#747, 2026-05-27). Narrative additions cover:

- Packaging: expanded the top list to include the macOS per-arch .app
  bundles and the Windows NSIS installer alongside the existing
  AppImage / Flatpak / .dmg / .zip entries. New bullets for amule-project#785
  (alc/alcc/cas/wxcas everywhere + Windows amuleweb), amule-project#794 (.dmg
  amuleweb path), amule-project#789 (<OS>-<arch> artifact naming), amule-project#780 / amule-project#796
  (Windows DPI + comctl32 manifest), amule-project#784 (FHS share/amule paths).

- Bug Fixes & Stability: post-amule-project#744 fixes including EC notification
  leak (amule-project#797), big-library scaling (amule-project#736, amule-project#840 superseding amule-project#728),
  amulegui ghost entries (amule-project#810, amule-project#819, amule-project#841, amule-project#824, amule-project#830, amule-project#760),
  PartFile early hash (amule-project#762), server protocol fixes (amule-project#835, amule-project#788,
  amule-project#721, amule-project#787), crypto stream UB (amule-project#779), UAF prevention (amule-project#756),
  Kad rotation (amule-project#795, amule-project#799/amule-project#805), GTK warning silencing (amule-project#833,
  amule-project#826/amule-project#836), and the clang-tidy worklist (amule-project#770, amule-project#772-amule-project#774).

- Translations: late-cycle wave covering French/Turkish manpages
  (amule-project#753/amule-project#754/amule-project#776), Galician (amule-project#763), Slovenian (amule-project#771), pt-BR
  (amule-project#768/amule-project#775/amule-project#812), French (amule-project#811), plus man-page tooling for
  date+version drift (amule-project#802).

- Contributors: added ngosang for UX feedback on the late-3.0
  cycle (amule-project#817/amule-project#818/amule-project#821/amule-project#828/amule-project#844) and ongoing work on the
  user-facing manual at amule-org.github.io.

- Merged PRs flat index: extended with amule-project#746-amule-project#845 + amule-project#841.
got3nks added a commit to got3nks/amule that referenced this pull request Jun 4, 2026
…ndex

Adds 55+ merged PRs to the 3.0.0 changelog since the last update
(amule-project#747, 2026-05-27). Narrative additions cover:

- Packaging: expanded the top list to include the macOS per-arch .app
  bundles and the Windows NSIS installer alongside the existing
  AppImage / Flatpak / .dmg / .zip entries. New bullets for amule-project#785
  (alc/alcc/cas/wxcas everywhere + Windows amuleweb), amule-project#794 (.dmg
  amuleweb path), amule-project#789 (<OS>-<arch> artifact naming), amule-project#780 / amule-project#796
  (Windows DPI + comctl32 manifest), amule-project#784 (FHS share/amule paths).

- Bug Fixes & Stability: post-amule-project#744 fixes including EC notification
  leak (amule-project#797), big-library scaling (amule-project#736, amule-project#840 superseding amule-project#728),
  amulegui ghost entries (amule-project#810, amule-project#819, amule-project#841, amule-project#824, amule-project#830, amule-project#760),
  PartFile early hash (amule-project#762), server protocol fixes (amule-project#835, amule-project#788,
  amule-project#721, amule-project#787), crypto stream UB (amule-project#779), UAF prevention (amule-project#756),
  Kad rotation (amule-project#795, amule-project#799/amule-project#805), GTK warning silencing (amule-project#833,
  amule-project#826/amule-project#836), and the clang-tidy worklist (amule-project#770, amule-project#772-amule-project#774).

- Translations: late-cycle wave covering French/Turkish manpages
  (amule-project#753/amule-project#754/amule-project#776), Galician (amule-project#763), Slovenian (amule-project#771), pt-BR
  (amule-project#768/amule-project#775/amule-project#812), French (amule-project#811), plus man-page tooling for
  date+version drift (amule-project#802).

- Contributors: added ngosang for UX feedback on the late-3.0
  cycle (amule-project#817/amule-project#818/amule-project#821/amule-project#828/amule-project#844) and ongoing work on the
  user-facing manual at amule-org.github.io.

- Merged PRs flat index: extended with amule-project#746-amule-project#845 + amule-project#841.
mrjimenez pushed a commit that referenced this pull request Jun 4, 2026
Adds 55+ merged PRs to the 3.0.0 changelog since the last update
(#747, 2026-05-27). Narrative additions cover:

- Packaging: expanded the top list to include the macOS per-arch .app
  bundles and the Windows NSIS installer alongside the existing
  AppImage / Flatpak / .dmg / .zip entries. New bullets for #785
  (alc/alcc/cas/wxcas everywhere + Windows amuleweb), #794 (.dmg
  amuleweb path), #789 (<OS>-<arch> artifact naming), #780 / #796
  (Windows DPI + comctl32 manifest), #784 (FHS share/amule paths).

- Bug Fixes & Stability: post-#744 fixes including EC notification
  leak (#797), big-library scaling (#736, #840 superseding #728),
  amulegui ghost entries (#810, #819, #841, #824, #830, #760),
  PartFile early hash (#762), server protocol fixes (#835, #788,
  #721, #787), crypto stream UB (#779), UAF prevention (#756),
  Kad rotation (#795, #799/#805), GTK warning silencing (#833,
  #826/#836), and the clang-tidy worklist (#770, #772-#774).

- Translations: late-cycle wave covering French/Turkish manpages
  (#753/#754/#776), Galician (#763), Slovenian (#771), pt-BR
  (#768/#775/#812), French (#811), plus man-page tooling for
  date+version drift (#802).

- Contributors: added ngosang for UX feedback on the late-3.0
  cycle (#817/#818/#821/#828/#844) and ongoing work on the
  user-facing manual at amule-org.github.io.

- Merged PRs flat index: extended with #746-#845 + #841.
got3nks added a commit to got3nks/amule that referenced this pull request Jul 6, 2026
Wraps OS-level scheme registration behind a cross-platform
ProtocolHandlerManager (mirroring AutostartManager from amule-project#744) so a
browser click on ed2k:// or magnet: reaches aMule directly — no more
.reg imports, mimeapps.list hand-edits, or LaunchServices incantations.

Backends:
  Windows  HKCU\Software\Classes\<scheme> (per-user URL Protocol keys)
  Linux    $XDG_CONFIG_HOME/mimeapps.list [Default Applications]
  macOS    LSSetDefaultHandlerForURLScheme + CFBundleURLTypes plist decl

Four surfaces expose the toggle, all going through the same manager:

  * Preferences → General: two checkboxes below the autostart toggle,
    live OS state on open, with an "Another app is currently the default
    handler for these links, replace with aMule?" confirm dialog before
    overwriting a third-party registration.

  * First-run wizard: new Integrations page between Bootstrap and
    Folders. Folds in the existing autostart toggle plus the two
    URL-scheme toggles. Strings shared verbatim with Preferences so
    translators only see them once.

  * --configure-protocols on|off CLI: one-shot, no prompt, mirrors
    --configure-autostart. Invoked by the Windows installer.

  * Windows installer: new SecProtocols section, default checked.
    Uninstall symmetry only wipes registry keys if they still point
    inside \$INSTDIR (protects a user's hand-set third-party
    registration from being clobbered).

Identity is per-binary (basename on Windows/Linux, bundle id on macOS),
so amule.exe and amulegui.exe each track their own registration state.
The Preferences checkbox in amulegui correctly reads unchecked when
amule.exe holds the registration, and toggling on prompts before
replacing it.

macOS specifics:

  * Info.plist gets CFBundleURLTypes for both schemes via a plutil
    post-build step (both aMule.app and aMuleGUI.app).

  * Runtime scheme delivery uses a kAEGetURL Apple Event handler
    registered in __attribute__((constructor)) at dylib-load time —
    required because macOS dispatches cold-launch scheme URLs between
    applicationWillFinishLaunching: and applicationDidFinishLaunching:,
    before any wxApp OnInit runs.

  * On amulegui, CamuleRemoteGuiApp::Startup() drains ED2KLinks
    explicitly after the poll timer starts so a URL queued pre-EC-
    connect reaches the daemon immediately post-connect rather than
    waiting ~1s for the first poll tick.

  * LaunchServices has no "clear default handler" call, so Disable()
    is a no-op on macOS — the Prefs checkbox is hidden while we're
    the current handler (Linux/Windows Disable works, boxes stay
    visible there).

Magnet handling stays scoped to eD2k-compatible magnets (existing
CMagnetED2KConverter contract). BitTorrent-only magnets are ignored.

SelfHealOnStartup rewrites the registered path if it drifted (user
moved AppImage / .app / install dir) — only when we're already the
current handler, never when a third-party handler owns the scheme.
Mirrors AutostartManager::SelfHealOnStartup.

Closes amule-project#793.
got3nks added a commit to got3nks/amule that referenced this pull request Jul 6, 2026
Wraps OS-level scheme registration behind a cross-platform
ProtocolHandlerManager (mirroring AutostartManager from amule-project#744) so a
browser click on ed2k:// or magnet: reaches aMule directly — no more
.reg imports, mimeapps.list hand-edits, or LaunchServices incantations.

Backends:
  Windows  HKCU\Software\Classes\<scheme> (per-user URL Protocol keys)
  Linux    $XDG_CONFIG_HOME/mimeapps.list [Default Applications]
  macOS    LSSetDefaultHandlerForURLScheme + CFBundleURLTypes plist decl

Four surfaces expose the toggle, all going through the same manager:

  * Preferences → General: two checkboxes below the autostart toggle,
    live OS state on open, with an "Another app is currently the default
    handler for these links, replace with aMule?" confirm dialog before
    overwriting a third-party registration.

  * First-run wizard: new Integrations page between Bootstrap and
    Folders. Folds in the existing autostart toggle plus the two
    URL-scheme toggles. Strings shared verbatim with Preferences so
    translators only see them once.

  * --configure-protocols on|off CLI: one-shot, no prompt, mirrors
    --configure-autostart. Invoked by the Windows installer.

  * Windows installer: new SecProtocols section, default checked.
    Uninstall symmetry only wipes registry keys if they still point
    inside \$INSTDIR (protects a user's hand-set third-party
    registration from being clobbered).

Identity is per-binary (basename on Windows/Linux, bundle id on macOS),
so amule.exe and amulegui.exe each track their own registration state.
The Preferences checkbox in amulegui correctly reads unchecked when
amule.exe holds the registration, and toggling on prompts before
replacing it.

macOS specifics:

  * Info.plist gets CFBundleURLTypes for both schemes via a plutil
    post-build step (both aMule.app and aMuleGUI.app).

  * Runtime scheme delivery uses a kAEGetURL Apple Event handler
    registered in __attribute__((constructor)) at dylib-load time —
    required because macOS dispatches cold-launch scheme URLs between
    applicationWillFinishLaunching: and applicationDidFinishLaunching:,
    before any wxApp OnInit runs.

  * On amulegui, CamuleRemoteGuiApp::Startup() drains ED2KLinks
    explicitly after the poll timer starts so a URL queued pre-EC-
    connect reaches the daemon immediately post-connect rather than
    waiting ~1s for the first poll tick.

  * LaunchServices has no "clear default handler" call, so Disable()
    is a no-op on macOS — the Prefs checkbox is hidden while we're
    the current handler (Linux/Windows Disable works, boxes stay
    visible there).

Magnet handling stays scoped to eD2k-compatible magnets (existing
CMagnetED2KConverter contract). BitTorrent-only magnets are ignored.

SelfHealOnStartup rewrites the registered path if it drifted (user
moved AppImage / .app / install dir) — only when we're already the
current handler, never when a third-party handler owns the scheme.
Mirrors AutostartManager::SelfHealOnStartup.

Closes amule-project#793.
got3nks added a commit to got3nks/amule that referenced this pull request Jul 6, 2026
Wraps OS-level scheme registration behind a cross-platform
ProtocolHandlerManager (mirroring AutostartManager from amule-project#744) so a
browser click on ed2k:// or magnet: reaches aMule directly — no more
.reg imports, mimeapps.list hand-edits, or LaunchServices incantations.

Backends:
  Windows  HKCU\Software\Classes\<scheme> (per-user URL Protocol keys)
  Linux    $XDG_CONFIG_HOME/mimeapps.list [Default Applications]
  macOS    LSSetDefaultHandlerForURLScheme + CFBundleURLTypes plist decl

Four surfaces expose the toggle, all going through the same manager:

  * Preferences → General: two checkboxes below the autostart toggle,
    live OS state on open, with an "Another app is currently the default
    handler for these links, replace with aMule?" confirm dialog before
    overwriting a third-party registration.

  * First-run wizard: new Integrations page between Bootstrap and
    Folders. Folds in the existing autostart toggle plus the two
    URL-scheme toggles. Strings shared verbatim with Preferences so
    translators only see them once.

  * --configure-protocols on|off CLI: one-shot, no prompt, mirrors
    --configure-autostart. Invoked by the Windows installer.

  * Windows installer: new SecProtocols section, default checked.
    Uninstall symmetry only wipes registry keys if they still point
    inside \$INSTDIR (protects a user's hand-set third-party
    registration from being clobbered).

Identity is per-binary (basename on Windows/Linux, bundle id on macOS),
so amule.exe and amulegui.exe each track their own registration state.
The Preferences checkbox in amulegui correctly reads unchecked when
amule.exe holds the registration, and toggling on prompts before
replacing it.

macOS specifics:

  * Info.plist gets CFBundleURLTypes for both schemes via a plutil
    post-build step (both aMule.app and aMuleGUI.app).

  * Runtime scheme delivery uses a kAEGetURL Apple Event handler
    registered in __attribute__((constructor)) at dylib-load time —
    required because macOS dispatches cold-launch scheme URLs between
    applicationWillFinishLaunching: and applicationDidFinishLaunching:,
    before any wxApp OnInit runs.

  * On amulegui, CamuleRemoteGuiApp::Startup() drains ED2KLinks
    explicitly after the poll timer starts so a URL queued pre-EC-
    connect reaches the daemon immediately post-connect rather than
    waiting ~1s for the first poll tick.

  * LaunchServices has no "clear default handler" call, so Disable()
    is a no-op on macOS — the Prefs checkbox is hidden while we're
    the current handler (Linux/Windows Disable works, boxes stay
    visible there).

Magnet handling stays scoped to eD2k-compatible magnets (existing
CMagnetED2KConverter contract). BitTorrent-only magnets are ignored.

SelfHealOnStartup rewrites the registered path if it drifted (user
moved AppImage / .app / install dir) — only when we're already the
current handler, never when a third-party handler owns the scheme.
Mirrors AutostartManager::SelfHealOnStartup.

Closes amule-project#793.
got3nks added a commit to got3nks/amule that referenced this pull request Jul 6, 2026
Wraps OS-level scheme registration behind a cross-platform
ProtocolHandlerManager (mirroring AutostartManager from amule-project#744) so a
browser click on ed2k:// or magnet: reaches aMule directly — no more
.reg imports, mimeapps.list hand-edits, or LaunchServices incantations.

Backends:
  Windows  HKCU\Software\Classes\<scheme> (per-user URL Protocol keys)
  Linux    $XDG_CONFIG_HOME/mimeapps.list [Default Applications]
  macOS    LSSetDefaultHandlerForURLScheme + CFBundleURLTypes plist decl

Four surfaces expose the toggle, all going through the same manager:

  * Preferences → General: two checkboxes below the autostart toggle,
    live OS state on open, with an "Another app is currently the default
    handler for these links, replace with aMule?" confirm dialog before
    overwriting a third-party registration.

  * First-run wizard: new Integrations page between Bootstrap and
    Folders. Folds in the existing autostart toggle plus the two
    URL-scheme toggles. Strings shared verbatim with Preferences so
    translators only see them once.

  * --configure-protocols on|off CLI: one-shot, no prompt, mirrors
    --configure-autostart. Invoked by the Windows installer.

  * Windows installer: new SecProtocols section, default checked.
    Uninstall symmetry only wipes registry keys if they still point
    inside \$INSTDIR (protects a user's hand-set third-party
    registration from being clobbered).

Identity is per-binary (basename on Windows/Linux, bundle id on macOS),
so amule.exe and amulegui.exe each track their own registration state.
The Preferences checkbox in amulegui correctly reads unchecked when
amule.exe holds the registration, and toggling on prompts before
replacing it.

macOS specifics:

  * Info.plist gets CFBundleURLTypes for both schemes via a plutil
    post-build step (both aMule.app and aMuleGUI.app).

  * Runtime scheme delivery uses a kAEGetURL Apple Event handler
    registered in __attribute__((constructor)) at dylib-load time —
    required because macOS dispatches cold-launch scheme URLs between
    applicationWillFinishLaunching: and applicationDidFinishLaunching:,
    before any wxApp OnInit runs.

  * On amulegui, CamuleRemoteGuiApp::Startup() drains ED2KLinks
    explicitly after the poll timer starts so a URL queued pre-EC-
    connect reaches the daemon immediately post-connect rather than
    waiting ~1s for the first poll tick.

  * LaunchServices has no "clear default handler" call, so Disable()
    is a no-op on macOS — the Prefs checkbox is hidden while we're
    the current handler (Linux/Windows Disable works, boxes stay
    visible there).

Magnet handling stays scoped to eD2k-compatible magnets (existing
CMagnetED2KConverter contract). BitTorrent-only magnets are ignored.

SelfHealOnStartup rewrites the registered path if it drifted (user
moved AppImage / .app / install dir) — only when we're already the
current handler, never when a third-party handler owns the scheme.
Mirrors AutostartManager::SelfHealOnStartup.

Closes amule-project#793.
got3nks added a commit to got3nks/amule that referenced this pull request Jul 6, 2026
Wraps OS-level scheme registration behind a cross-platform
ProtocolHandlerManager (mirroring AutostartManager from amule-project#744) so a
browser click on ed2k:// or magnet: reaches aMule directly — no more
.reg imports, mimeapps.list hand-edits, or LaunchServices incantations.

Backends:
  Windows  HKCU\Software\Classes\<scheme> (per-user URL Protocol keys)
  Linux    $XDG_CONFIG_HOME/mimeapps.list [Default Applications]
  macOS    LSSetDefaultHandlerForURLScheme + CFBundleURLTypes plist decl

Four surfaces expose the toggle, all going through the same manager:

  * Preferences → General: two checkboxes below the autostart toggle,
    live OS state on open, with an "Another app is currently the default
    handler for these links, replace with aMule?" confirm dialog before
    overwriting a third-party registration.

  * First-run wizard: new Integrations page between Bootstrap and
    Folders. Folds in the existing autostart toggle plus the two
    URL-scheme toggles. Strings shared verbatim with Preferences so
    translators only see them once.

  * --configure-protocols on|off CLI: one-shot, no prompt, mirrors
    --configure-autostart. Invoked by the Windows installer.

  * Windows installer: new SecProtocols section, default checked.
    Uninstall symmetry only wipes registry keys if they still point
    inside \$INSTDIR (protects a user's hand-set third-party
    registration from being clobbered).

Identity is per-binary (basename on Windows/Linux, bundle id on macOS),
so amule.exe and amulegui.exe each track their own registration state.
The Preferences checkbox in amulegui correctly reads unchecked when
amule.exe holds the registration, and toggling on prompts before
replacing it.

macOS specifics:

  * Info.plist gets CFBundleURLTypes for both schemes via a plutil
    post-build step (both aMule.app and aMuleGUI.app).

  * Runtime scheme delivery uses a kAEGetURL Apple Event handler
    registered in __attribute__((constructor)) at dylib-load time —
    required because macOS dispatches cold-launch scheme URLs between
    applicationWillFinishLaunching: and applicationDidFinishLaunching:,
    before any wxApp OnInit runs.

  * On amulegui, CamuleRemoteGuiApp::Startup() drains ED2KLinks
    explicitly after the poll timer starts so a URL queued pre-EC-
    connect reaches the daemon immediately post-connect rather than
    waiting ~1s for the first poll tick.

  * LaunchServices has no "clear default handler" call, so Disable()
    is a no-op on macOS — the Prefs checkbox is hidden while we're
    the current handler (Linux/Windows Disable works, boxes stay
    visible there).

Magnet handling stays scoped to eD2k-compatible magnets (existing
CMagnetED2KConverter contract). BitTorrent-only magnets are ignored.

SelfHealOnStartup rewrites the registered path if it drifted (user
moved AppImage / .app / install dir) — only when we're already the
current handler, never when a third-party handler owns the scheme.
Mirrors AutostartManager::SelfHealOnStartup.

Closes amule-project#793.
got3nks added a commit to got3nks/amule that referenced this pull request Jul 6, 2026
Wraps OS-level scheme registration behind a cross-platform
ProtocolHandlerManager (mirroring AutostartManager from amule-project#744) so a
browser click on ed2k:// or magnet: reaches aMule directly — no more
.reg imports, mimeapps.list hand-edits, or LaunchServices incantations.

Backends:
  Windows  HKCU\Software\Classes\<scheme> (per-user URL Protocol keys)
  Linux    $XDG_CONFIG_HOME/mimeapps.list [Default Applications]
  macOS    LSSetDefaultHandlerForURLScheme + CFBundleURLTypes plist decl

Four surfaces expose the toggle, all going through the same manager:

  * Preferences → General: two checkboxes below the autostart toggle,
    live OS state on open, with an "Another app is currently the default
    handler for these links, replace with aMule?" confirm dialog before
    overwriting a third-party registration.

  * First-run wizard: new Integrations page between Bootstrap and
    Folders. Folds in the existing autostart toggle plus the two
    URL-scheme toggles. Strings shared verbatim with Preferences so
    translators only see them once.

  * --configure-protocols on|off CLI: one-shot, no prompt, mirrors
    --configure-autostart. Invoked by the Windows installer.

  * Windows installer: new SecProtocols section, default checked.
    Uninstall symmetry only wipes registry keys if they still point
    inside \$INSTDIR (protects a user's hand-set third-party
    registration from being clobbered).

Identity is per-binary (basename on Windows/Linux, bundle id on macOS),
so amule.exe and amulegui.exe each track their own registration state.
The Preferences checkbox in amulegui correctly reads unchecked when
amule.exe holds the registration, and toggling on prompts before
replacing it.

macOS specifics:

  * Info.plist gets CFBundleURLTypes for both schemes via a plutil
    post-build step (both aMule.app and aMuleGUI.app).

  * Runtime scheme delivery uses a kAEGetURL Apple Event handler
    registered in __attribute__((constructor)) at dylib-load time —
    required because macOS dispatches cold-launch scheme URLs between
    applicationWillFinishLaunching: and applicationDidFinishLaunching:,
    before any wxApp OnInit runs.

  * On amulegui, CamuleRemoteGuiApp::Startup() drains ED2KLinks
    explicitly after the poll timer starts so a URL queued pre-EC-
    connect reaches the daemon immediately post-connect rather than
    waiting ~1s for the first poll tick.

  * LaunchServices has no "clear default handler" call, so Disable()
    is a no-op on macOS — the Prefs checkbox is hidden while we're
    the current handler (Linux/Windows Disable works, boxes stay
    visible there).

Magnet handling stays scoped to eD2k-compatible magnets (existing
CMagnetED2KConverter contract). BitTorrent-only magnets are ignored.

SelfHealOnStartup rewrites the registered path if it drifted (user
moved AppImage / .app / install dir) — only when we're already the
current handler, never when a third-party handler owns the scheme.
Mirrors AutostartManager::SelfHealOnStartup.

Closes amule-project#793.
got3nks added a commit to got3nks/amule that referenced this pull request Jul 6, 2026
Wraps OS-level scheme registration behind a cross-platform
ProtocolHandlerManager (mirroring AutostartManager from amule-project#744) so a
browser click on ed2k:// or magnet: reaches aMule directly — no more
.reg imports, mimeapps.list hand-edits, or LaunchServices incantations.

Backends:
  Windows  HKCU\Software\Classes\<scheme> (per-user URL Protocol keys)
  Linux    $XDG_CONFIG_HOME/mimeapps.list [Default Applications]
  macOS    LSSetDefaultHandlerForURLScheme + CFBundleURLTypes plist decl

Four surfaces expose the toggle, all going through the same manager:

  * Preferences → General: two checkboxes below the autostart toggle,
    live OS state on open, with an "Another app is currently the default
    handler for these links, replace with aMule?" confirm dialog before
    overwriting a third-party registration.

  * First-run wizard: new Integrations page between Bootstrap and
    Folders. Folds in the existing autostart toggle plus the two
    URL-scheme toggles. Strings shared verbatim with Preferences so
    translators only see them once.

  * --configure-protocols on|off CLI: one-shot, no prompt, mirrors
    --configure-autostart. Invoked by the Windows installer.

  * Windows installer: new SecProtocols section, default checked.
    Uninstall symmetry only wipes registry keys if they still point
    inside \$INSTDIR (protects a user's hand-set third-party
    registration from being clobbered).

Identity is per-binary (basename on Windows/Linux, bundle id on macOS),
so amule.exe and amulegui.exe each track their own registration state.
The Preferences checkbox in amulegui correctly reads unchecked when
amule.exe holds the registration, and toggling on prompts before
replacing it.

macOS specifics:

  * Info.plist gets CFBundleURLTypes for both schemes via a plutil
    post-build step (both aMule.app and aMuleGUI.app).

  * Runtime scheme delivery uses a kAEGetURL Apple Event handler
    registered in __attribute__((constructor)) at dylib-load time —
    required because macOS dispatches cold-launch scheme URLs between
    applicationWillFinishLaunching: and applicationDidFinishLaunching:,
    before any wxApp OnInit runs.

  * On amulegui, CamuleRemoteGuiApp::Startup() drains ED2KLinks
    explicitly after the poll timer starts so a URL queued pre-EC-
    connect reaches the daemon immediately post-connect rather than
    waiting ~1s for the first poll tick.

  * LaunchServices has no "clear default handler" call, so Disable()
    is a no-op on macOS — the Prefs checkbox is hidden while we're
    the current handler (Linux/Windows Disable works, boxes stay
    visible there).

Magnet handling stays scoped to eD2k-compatible magnets (existing
CMagnetED2KConverter contract). BitTorrent-only magnets are ignored.

SelfHealOnStartup rewrites the registered path if it drifted (user
moved AppImage / .app / install dir) — only when we're already the
current handler, never when a third-party handler owns the scheme.
Mirrors AutostartManager::SelfHealOnStartup.

Closes amule-project#793.
got3nks added a commit to got3nks/amule that referenced this pull request Jul 6, 2026
Wraps OS-level scheme registration behind a cross-platform
ProtocolHandlerManager (mirroring AutostartManager from amule-project#744) so a
browser click on ed2k:// or magnet: reaches aMule directly — no more
.reg imports, mimeapps.list hand-edits, or LaunchServices incantations.

Backends:
  Windows  HKCU\Software\Classes\<scheme> (per-user URL Protocol keys)
  Linux    $XDG_CONFIG_HOME/mimeapps.list [Default Applications]
  macOS    LSSetDefaultHandlerForURLScheme + CFBundleURLTypes plist decl

Four surfaces expose the toggle, all going through the same manager:

  * Preferences → General: two checkboxes below the autostart toggle,
    live OS state on open, with an "Another app is currently the default
    handler for these links, replace with aMule?" confirm dialog before
    overwriting a third-party registration.

  * First-run wizard: new Integrations page between Bootstrap and
    Folders. Folds in the existing autostart toggle plus the two
    URL-scheme toggles. Strings shared verbatim with Preferences so
    translators only see them once.

  * --configure-protocols on|off CLI: one-shot, no prompt, mirrors
    --configure-autostart. Invoked by the Windows installer.

  * Windows installer: new SecProtocols section, default checked.
    Uninstall symmetry only wipes registry keys if they still point
    inside \$INSTDIR (protects a user's hand-set third-party
    registration from being clobbered).

Identity is per-binary (basename on Windows/Linux, bundle id on macOS),
so amule.exe and amulegui.exe each track their own registration state.
The Preferences checkbox in amulegui correctly reads unchecked when
amule.exe holds the registration, and toggling on prompts before
replacing it.

macOS specifics:

  * Info.plist gets CFBundleURLTypes for both schemes via a plutil
    post-build step (both aMule.app and aMuleGUI.app).

  * Runtime scheme delivery uses a kAEGetURL Apple Event handler
    registered in __attribute__((constructor)) at dylib-load time —
    required because macOS dispatches cold-launch scheme URLs between
    applicationWillFinishLaunching: and applicationDidFinishLaunching:,
    before any wxApp OnInit runs.

  * On amulegui, CamuleRemoteGuiApp::Startup() drains ED2KLinks
    explicitly after the poll timer starts so a URL queued pre-EC-
    connect reaches the daemon immediately post-connect rather than
    waiting ~1s for the first poll tick.

  * LaunchServices has no "clear default handler" call, so Disable()
    is a no-op on macOS — the Prefs checkbox is hidden while we're
    the current handler (Linux/Windows Disable works, boxes stay
    visible there).

Magnet handling stays scoped to eD2k-compatible magnets (existing
CMagnetED2KConverter contract). BitTorrent-only magnets are ignored.

SelfHealOnStartup rewrites the registered path if it drifted (user
moved AppImage / .app / install dir) — only when we're already the
current handler, never when a third-party handler owns the scheme.
Mirrors AutostartManager::SelfHealOnStartup.

Closes amule-project#793.
got3nks added a commit to got3nks/amule that referenced this pull request Jul 6, 2026
Wraps OS-level scheme registration behind a cross-platform
ProtocolHandlerManager (mirroring AutostartManager from amule-project#744) so a
browser click on ed2k:// or magnet: reaches aMule directly — no more
.reg imports, mimeapps.list hand-edits, or LaunchServices incantations.

Backends:
  Windows  HKCU\Software\Classes\<scheme> (per-user URL Protocol keys)
  Linux    $XDG_CONFIG_HOME/mimeapps.list [Default Applications]
  macOS    LSSetDefaultHandlerForURLScheme + CFBundleURLTypes plist decl

Four surfaces expose the toggle, all going through the same manager:

  * Preferences → General: two checkboxes below the autostart toggle,
    live OS state on open, with an "Another app is currently the default
    handler for these links, replace with aMule?" confirm dialog before
    overwriting a third-party registration.

  * First-run wizard: new Integrations page between Bootstrap and
    Folders. Folds in the existing autostart toggle plus the two
    URL-scheme toggles. Strings shared verbatim with Preferences so
    translators only see them once.

  * --configure-protocols on|off CLI: one-shot, no prompt, mirrors
    --configure-autostart. Invoked by the Windows installer.

  * Windows installer: new SecProtocols section, default checked.
    Uninstall symmetry only wipes registry keys if they still point
    inside \$INSTDIR (protects a user's hand-set third-party
    registration from being clobbered).

Identity is per-binary (basename on Windows/Linux, bundle id on macOS),
so amule.exe and amulegui.exe each track their own registration state.
The Preferences checkbox in amulegui correctly reads unchecked when
amule.exe holds the registration, and toggling on prompts before
replacing it.

macOS specifics:

  * Info.plist gets CFBundleURLTypes for both schemes via a plutil
    post-build step (both aMule.app and aMuleGUI.app).

  * Runtime scheme delivery uses a kAEGetURL Apple Event handler
    registered in __attribute__((constructor)) at dylib-load time —
    required because macOS dispatches cold-launch scheme URLs between
    applicationWillFinishLaunching: and applicationDidFinishLaunching:,
    before any wxApp OnInit runs.

  * On amulegui, CamuleRemoteGuiApp::Startup() drains ED2KLinks
    explicitly after the poll timer starts so a URL queued pre-EC-
    connect reaches the daemon immediately post-connect rather than
    waiting ~1s for the first poll tick.

  * LaunchServices has no "clear default handler" call, so Disable()
    is a no-op on macOS — the Prefs checkbox is hidden while we're
    the current handler (Linux/Windows Disable works, boxes stay
    visible there).

Magnet handling stays scoped to eD2k-compatible magnets (existing
CMagnetED2KConverter contract). BitTorrent-only magnets are ignored.

SelfHealOnStartup rewrites the registered path if it drifted (user
moved AppImage / .app / install dir) — only when we're already the
current handler, never when a third-party handler owns the scheme.
Mirrors AutostartManager::SelfHealOnStartup.

Closes amule-project#793.
got3nks added a commit to got3nks/amule that referenced this pull request Jul 6, 2026
Wraps OS-level scheme registration behind a cross-platform
ProtocolHandlerManager (mirroring AutostartManager from amule-project#744) so a
browser click on ed2k:// or magnet: reaches aMule directly — no more
.reg imports, mimeapps.list hand-edits, or LaunchServices incantations.

Backends:
  Windows  HKCU\Software\Classes\<scheme> (per-user URL Protocol keys)
  Linux    $XDG_CONFIG_HOME/mimeapps.list [Default Applications]
  macOS    LSSetDefaultHandlerForURLScheme + CFBundleURLTypes plist decl

Four surfaces expose the toggle, all going through the same manager:

  * Preferences → General: two checkboxes below the autostart toggle,
    live OS state on open, with an "Another app is currently the default
    handler for these links, replace with aMule?" confirm dialog before
    overwriting a third-party registration.

  * First-run wizard: new Integrations page between Bootstrap and
    Folders. Folds in the existing autostart toggle plus the two
    URL-scheme toggles. Strings shared verbatim with Preferences so
    translators only see them once.

  * --configure-protocols on|off CLI: one-shot, no prompt, mirrors
    --configure-autostart. Invoked by the Windows installer.

  * Windows installer: new SecProtocols section, default checked.
    Uninstall symmetry only wipes registry keys if they still point
    inside \$INSTDIR (protects a user's hand-set third-party
    registration from being clobbered).

Identity is per-binary (basename on Windows/Linux, bundle id on macOS),
so amule.exe and amulegui.exe each track their own registration state.
The Preferences checkbox in amulegui correctly reads unchecked when
amule.exe holds the registration, and toggling on prompts before
replacing it.

macOS specifics:

  * Info.plist gets CFBundleURLTypes for both schemes via a plutil
    post-build step (both aMule.app and aMuleGUI.app).

  * Runtime scheme delivery uses a kAEGetURL Apple Event handler
    registered in __attribute__((constructor)) at dylib-load time —
    required because macOS dispatches cold-launch scheme URLs between
    applicationWillFinishLaunching: and applicationDidFinishLaunching:,
    before any wxApp OnInit runs.

  * On amulegui, CamuleRemoteGuiApp::Startup() drains ED2KLinks
    explicitly after the poll timer starts so a URL queued pre-EC-
    connect reaches the daemon immediately post-connect rather than
    waiting ~1s for the first poll tick.

  * LaunchServices has no "clear default handler" call, so Disable()
    is a no-op on macOS — the Prefs checkbox is hidden while we're
    the current handler (Linux/Windows Disable works, boxes stay
    visible there).

Magnet handling stays scoped to eD2k-compatible magnets (existing
CMagnetED2KConverter contract). BitTorrent-only magnets are ignored.

SelfHealOnStartup rewrites the registered path if it drifted (user
moved AppImage / .app / install dir) — only when we're already the
current handler, never when a third-party handler owns the scheme.
Mirrors AutostartManager::SelfHealOnStartup.

Closes amule-project#793.
got3nks referenced this pull request in amule-org/amule Jul 6, 2026
* feat: register ed2k:// and magnet: URL schemes cross-platform

Wraps OS-level scheme registration behind a cross-platform
ProtocolHandlerManager (mirroring AutostartManager from #744) so a
browser click on ed2k:// or magnet: reaches aMule directly — no more
.reg imports, mimeapps.list hand-edits, or LaunchServices incantations.

Backends:
  Windows  HKCU\Software\Classes\<scheme> (per-user URL Protocol keys)
  Linux    $XDG_CONFIG_HOME/mimeapps.list [Default Applications]
  macOS    LSSetDefaultHandlerForURLScheme + CFBundleURLTypes plist decl

Four surfaces expose the toggle, all going through the same manager:

  * Preferences → General: two checkboxes below the autostart toggle,
    live OS state on open, with an "Another app is currently the default
    handler for these links, replace with aMule?" confirm dialog before
    overwriting a third-party registration.

  * First-run wizard: new Integrations page between Bootstrap and
    Folders. Folds in the existing autostart toggle plus the two
    URL-scheme toggles. Strings shared verbatim with Preferences so
    translators only see them once.

  * --configure-protocols on|off CLI: one-shot, no prompt, mirrors
    --configure-autostart. Invoked by the Windows installer.

  * Windows installer: new SecProtocols section, default checked.
    Uninstall symmetry only wipes registry keys if they still point
    inside \$INSTDIR (protects a user's hand-set third-party
    registration from being clobbered).

Identity is per-binary (basename on Windows/Linux, bundle id on macOS),
so amule.exe and amulegui.exe each track their own registration state.
The Preferences checkbox in amulegui correctly reads unchecked when
amule.exe holds the registration, and toggling on prompts before
replacing it.

macOS specifics:

  * Info.plist gets CFBundleURLTypes for both schemes via a plutil
    post-build step (both aMule.app and aMuleGUI.app).

  * Runtime scheme delivery uses a kAEGetURL Apple Event handler
    registered in __attribute__((constructor)) at dylib-load time —
    required because macOS dispatches cold-launch scheme URLs between
    applicationWillFinishLaunching: and applicationDidFinishLaunching:,
    before any wxApp OnInit runs.

  * On amulegui, CamuleRemoteGuiApp::Startup() drains ED2KLinks
    explicitly after the poll timer starts so a URL queued pre-EC-
    connect reaches the daemon immediately post-connect rather than
    waiting ~1s for the first poll tick.

  * LaunchServices has no "clear default handler" call, so Disable()
    is a no-op on macOS — the Prefs checkbox is hidden while we're
    the current handler (Linux/Windows Disable works, boxes stay
    visible there).

Magnet handling stays scoped to eD2k-compatible magnets (existing
CMagnetED2KConverter contract). BitTorrent-only magnets are ignored.

SelfHealOnStartup rewrites the registered path if it drifted (user
moved AppImage / .app / install dir) — only when we're already the
current handler, never when a third-party handler owns the scheme.
Mirrors AutostartManager::SelfHealOnStartup.

Closes amule-project#793.

* po: regenerate catalogs after ProtocolHandlerManager string additions

Picks up the msgids added by the feature commit above (Preferences +
Wizard checkbox labels, tooltips, magnet-specific confirm dialog text,
wizard BitTorrent-limitation hint, and the two new installer section
names / descriptions from the ed2k / magnet split).

Required by the App-catalogs-in-sync CI check per scripts/update-po.sh.
mrjimenez pushed a commit to mrjimenez/amule that referenced this pull request Aug 1, 2026
…ct#675) (amule-project#744)

This is a deliberate UI change, not a behaviour-preserving refactor --
worth being explicit about per review discussion on amule-project#675. None of the
74 sites touched here have ever rendered their border: the legacy
`Add(window, proportion, flag, border)` form only applies `border`
when `flag` carries a direction bit (wxALL/wxLEFT/wxRIGHT/wxTOP/
wxBOTTOM), and all 74 omitted it. Converting to wxSizerFlags() and
supplying a real direction bit means these borders render for the
first time, which will reflow the affected dialogs to some degree.

Per amule-project#663 (the case that originally surfaced this pattern): the
recorded border values were never validated by anything, since they
never rendered. Each site was judged against its structural siblings
rather than ported verbatim -- where siblings already carried a
working border, matched to it; where a site was the outlier in an
otherwise-consistent row/grid, adjusted to match rather than
introducing a new, never-tested value. A few sites lost their border
entirely where every sibling in the same row already had none (the
stray value read as leftover noise, not an intended margin).

Three additional non-legacy-syntax inconsistencies folded into the
same pass (found while scoping amule-project#675, confirmed still present):
- PreferencesRemoteControlsTab: "Low rights password" carried
  Border(wxLEFT|wxRIGHT, 20) while every other same-column label in
  the grid ("Web template", "Full rights password") uses
  Border(wxRIGHT, 5) -- the 20px left indent looked like it was
  copy-pasted from the unrelated UPnP-port row's indent, not a
  deliberate choice for this row.
- PreferencesOnlineSigTab: the "Save online signature file in" path
  field had no Expand()/proportion despite sitting in a column its
  parent FlexGridSizer marks growable -- it couldn't actually grow to
  fill the space reserved for it.
- PreferencesGeneralTab: the "Browser Selection" row (text field +
  Browse button) still used the legacy 3-arg Add() form while the
  structurally identical "Video Player" row already used
  wxSizerFlags() -- modernized for consistency, no behaviour change
  (both used border 0).

Scope: src/muuli_wdr.cpp only, matching where amule-project#663/amule-project#473 originally
established (and didn't fully carry through) the wxSizerFlags()
convention.

Testing: full build verified (macOS). Visually walked every dialog
these 20 functions produce that's reachable without live server/
download/client data in a fresh test config: main status bar,
search, transfer panes, shared-files header, servers/Kad tabs,
Friends/Messages panels, and all 15 Preferences tabs -- no clipped or
overlapping controls, and the two directly-testable fixes (the
OnlineSig path field now expanding, the RemoteControls password grid
column now aligned) confirmed visually.

NOT independently verified: fileDetails, clientDetails, commentLstDlg,
and CategoriesEditWindow all require live downloads/shared files/
clients/categories to reach via the UI, which a from-scratch test
config doesn't have -- these got the same siblings-based border
review as everything else, but I have not seen them rendered.
Sizer-border rendering is exactly where wxGTK/wxMSW/wxOSX diverge, so
this needs eyes on Linux and Windows too, per the amule-project#675 review
discussion.
mrjimenez pushed a commit to mrjimenez/amule that referenced this pull request Aug 1, 2026
…ouldn't grow (amule-project#744 follow-up) (amule-project#745)

got3nks, testing amule-project#744 on Windows/Linux:
- PreferencesConnectionTab: "Bind local address to IP" and "Bind to
  network interface" fields weren't right-aligned with each other.
- PreferencesRemoteControlsTab: "Full rights password" (web server)
  didn't extend, unlike "Low rights password" right below it in the
  same grid.

Both fields carried Expand() together with a redundant horizontal
alignment flag (CenterHorizontal() / Right()) on the same
wxSizerFlags() chain, inside a wxFlexGridSizer growable column.
Expand() is supposed to make alignment flags moot, but empirically
that combination was not reliably expanding the control to fill its
grid cell here -- dropping the redundant alignment flag (Expand()
alone, matching how the already-correct sibling rows in both grids
are written) fixes both.

The same Expand()+alignment-flag combination exists at ~18 other call
sites in this file; left untouched since none were reported as
broken and I don't have a confirmed root cause to justify a wider
sweep -- flagging here in case it resurfaces.

Verified via a full amule build (macOS) and a visual, pixel-level
before/after comparison of both fields (both now share the same left
edge and width as their now-consistent siblings).
mrjimenez pushed a commit to mrjimenez/amule that referenced this pull request Aug 4, 2026
…rovider (amule-project#675) (amule-project#747)

* feat(gui): migrate 22 of 27 clientImages() status icons to CamuleArtProvider (amule-project#675)

Continues the icon-system cleanup scoped in amule-project#675. clientImages() is
the last of the raw-bitmap banks, and the riskiest: it's consumed
through a wxImageList built once at startup (Apply_Clients_Skin,
amuleDlg.cpp) by iterating index 0..26 in ClientSkinEnum order, and
four call sites then index that list with arithmetic
(Client_InvalidRating_Smiley + rating - 1) rather than calling
clientImages() directly. The enum order is load-bearing; this PR does
not touch it, the calling loop, or the arithmetic call sites -- only
what clientImages(index) returns for each index.

22 of the 27 icons are generic pictograms (smileys, a checkmark, an
X, stars, an arrow, a key, ...) with no external branding, migrated to
new "amule:client_<name>" SVG/PNG art. The remaining 5 -- indices 12,
15, 16, 17, 18 (eMule/aMule/lphant/Shareaza/xMule) -- are specific
client-software mascots and are deliberately left as the original raw
artwork: a generated pictogram is one thing, but redrawing someone
else's brand mascot risks not matching the real logo, which is worse
than not touching it. amule-project#675 discussion flagged this distinction
explicitly.

New art, per icon:
- Green/Red/Yellow/Grey/White: the 5 base transfer-state smileys.
- ExtendedProtocol/SecIdent/BadGuy/Encryption: badge overlays drawn
  per GenericClientListCtrl.cpp's own comments ("the '-'", "the 'v'",
  "the 'X'", "the '\xc2\xbf' except it's a key").
- CreditsGrey/CreditsYellow: the two credit-system stars.
- Upload: the upload-active arrow.
- Friend: the friend-list badge.
- mlDonkey/eDonkeyHybrid: kept generic/abstract (a checkmark badge, a
  simple ghost) rather than attempting their real logos -- same
  reasoning as the 5 mascots, lower bar since these were already more
  abstract marks than full character art in the original raster.
- Unknown: the unresolved-client-type question mark.
- InvalidRating/PoorRating/FairRating/GoodRating/ExcellentRating: one
  potion-bottle SVG re-tinted per rating (red/red/orange/green/green),
  with Invalid and Excellent composited as two bottles side by side in
  a single 16x16 square canvas -- matching the original art's
  single-vs-double-bottle distinction for the two rating extremes.
- CommentOnly: the comment-icon badge.

Implementation: a static art-id lookup table indexed by ClientSkinEnum
value, checked first; a null entry falls through to the corresponding
raw-bitmap `if (index == N)` block for the 5 mascot indices, which are
otherwise untouched. src/icons/icon_data.c regenerated via
embed_icons.py to match.

Testing: full build verified (macOS), both Release and Debug config.
Debug build launched with a live window (Apply_Clients_Skin runs at
startup, touching all 27 indices) and produced no wxFAIL_MSG assertion
(amule-project#739) -- confirms every index resolves. Each new icon reviewed
individually via rasterized contact sheets at both ~96px and actual
16x16 before being wired in.

NOT independently verified: seeing these icons rendered in an actual
populated client list (Downloads sources, Shared Files clients, Search
results, Friends) requires live eD2k/Kad network data, which a
from-scratch test config doesn't have. Same limitation already flagged
for fileDetails/clientDetails/CategoriesEditWindow in amule-project#744.

* fix(gui): recentre double-bottle rating icons, add ClientSkinEnum static_assert (amule-project#747 review)

got3nks, reviewing amule-project#747:

1. client_invalidrating.svg / client_excellentrating.svg didn't fill
   their 2048x2048 viewport like their poor/fair/good siblings (53%x73%
   fill for those vs. 83%x44% for these, with the left bottle clipped
   at x=-47). Recentred both bottle <g> transforms to
   translate(-110,452)/translate(940,452) with scale raised to 0.8
   (from 0.6), matching the visual weight of the single-bottle ratings
   next to them in the same column. Both files are otherwise identical
   apart from fill colour, so the one fix applies to both.

2. Nothing tied artIds[] to ClientSkinEnum, and wxFAIL_MSG (amule-project#739)
   compiles out in release builds -- so a future enum member could
   silently push a wxNullBitmap into the 16x16 image list instead of
   failing loudly anywhere. Added
   static_assert(WXSIZEOF(artIds) == CLIENT_SKIN_SIZE, ...), which
   catches it at compile time in every build config. Needed
   "amuleDlg.h" (CLIENT_SKIN_SIZE's home) added to muuli_wdr.cpp's
   includes -- checked first that amuleDlg.h doesn't include
   muuli_wdr.h back, no circular include.

Verified via a full amule build (macOS) -- the static_assert compiling
clean confirms artIds[] and ClientSkinEnum agree on 27 entries, and a
visual check that the two rating icons now match their siblings' size
and no longer clip.

* fix(gui): recompute double-bottle composition, verified numerically (amule-project#747 review)

My previous fix (eedcac3) just moved the problem: applying got3nks's
suggested translate values verbatim together with the also-suggested
scale=0.8 pushed the right bottle past the viewBox edge (measured:
x range 13%-107%, i.e. clipped on the right instead of the left).
The two numbers were each individually reasonable but hadn't been
re-verified together -- exactly the mistake the last commit's message
claimed to have checked and hadn't.

Recomputed from the natural bounding box instead of iterating on
coordinates by eye: two bottles at scale 0.68 with a 40-unit gap, each
positioned so both are fully inside the 0-2048 viewBox with equal
margins. Verified numerically (not just visually) before committing:
both groups' bboxes land at x 12.9%-49.0% and 51.0%-87.1%, y
25.2%-74.8% -- fully in bounds, no clipping on either side.

Worth being upfront about the height: overall fill is 74%x50%, not
poor/fair/good's 53%x73%. That's not a leftover bug -- fitting two
full-height copies of the same bottle side by side in a square without
overlap is not geometrically possible; matching the single bottles'
73% height would require the pair to be over twice as wide as the
viewBox. 50% is the tradeoff of choosing "fits, no clipping, similar
per-bottle proportions" over an unreachable exact size match.

Verified via a full amule build (macOS) and the bounding-box
computation above, re-run against the actual committed SVG files
rather than the standalone drafts, to catch exactly the kind of
last-mile mismatch that slipped through last time.

* fix(gui): unify bottle height across all 5 rating icons (amule-project#747 review)

got3nks: rather than treat the double-bottle pair as a special case
with its own (necessarily shorter) height, make all five ratings
share one consistent bottle height, maximizing what the double-bottle
pair allows without clipping and bringing poor/fair/good down to
match -- they sit in the same column, so consistency across the set
matters more than any one icon being as large as it could be alone.

Recomputed from the natural bottle bounding box: scale 0.909 is the
largest that fits two bottles side by side (24-unit gap) inside the
2048x2048 viewBox with no clipping. Applied that same scale to the
single-bottle ratings, centred. All five now render their bottle at
the same height.

Verified numerically against the actual committed files: all five
land at y 16.8%-83.2% (66.3% height) and are within the 0-100% x
range -- identical height across poor/fair/good/invalid/excellent,
zero clipping.

Verified via a full amule build (macOS).

* fix(gui): brighten client_green to match the rest of the set's saturation (amule-project#747 review)

got3nks measured across every opaque pixel: red and yellow gained
brightness/saturation moving to the new art, but green lost both,
landing dimmer (53% mean brightness) than red (64%) and yellow (72%)
-- inverting the original's balance, where green and red were level
at 57%/55%. Green carries the most meaning of the three (actively
transferring), so it being the dimmest state undersells it.

Replaced Material Green 500 (#4CAF50, 57% sat / 69% val) with
#22CC1A (87% sat / 80% val), inside the ~#1BD816-#2ECC1F range
got3nks suggested to restore the original's emphasis. Red and yellow
untouched, per the review ("read fine as they are").

Verified via a full amule build (macOS) and a visual check of the
icon at 96px.

* fix(gui): corner-anchor badge overlays, add null-bitmap guard (amule-project#747 review)

got3nks caught a real functional regression I'd missed (a second,
earlier review comment I hadn't seen when I replied to the later one
about colour): 6 of these icons aren't standalone -- GenericClientListCtrl.cpp
draws them as overlays on top of the base client icon at the same
point.x/realY. The original raw art kept each in a corner so the base
icon stayed visible underneath; my replacements were designed as
standalone centered pictograms, so they covered the icon they were
meant to annotate (creditsyellow at 14x13 was larger than the 12x12
base smiley it sat on).

Recomputed each as a corner badge, scaled/positioned to roughly the
original's measured footprint and anchor (his measurements, converted
from 16x16 pixel terms to the 2048x2048 viewBox):
- extendedprotocol: top-right, ~8x4
- secident: bottom-left, ~7x6
- creditsgrey/creditsyellow: top-right, ~9x9
- encryption: top-left, ~6x8

badguy is the one exception, and deliberately so: the original struck
through the *entire* icon rather than badging a corner, which reads as
intentional (a bad-guy client's status is fully overridden, not just
annotated) -- kept that full-cover behaviour rather than shrinking it
to a corner mark.

Also added the null-bitmap guard he flagged: wxArtProvider::GetBitmap()
returning wxNullBitmap for an unresolvable id was returning straight
through the new early-return path, never reaching the wxFAIL_MSG that
amule-project#739 added for exactly this failure mode. Added a wxASSERT_MSG on the
early-return path so a future icon rename can't silently regress back
to the "fails into a blank icon" state amule-project#725/amule-project#739 fixed.

Verified via a full amule build (macOS) and a visual check of all 6
badges at both 96px and actual 16x16, confirmed each sits in its
corner without covering the centre of the base icon.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cross-platform autostart toggle in Preferences

2 participants