Skip to content

desktop integration: Wayland app_id, SNI tray, macOS dock-restore + tray opt-in (closes #410) - #508

Merged
mrjimenez merged 2 commits into
amule-project:masterfrom
got3nks:pr2-icons-modernize
May 2, 2026
Merged

desktop integration: Wayland app_id, SNI tray, macOS dock-restore + tray opt-in (closes #410)#508
mrjimenez merged 2 commits into
amule-project:masterfrom
got3nks:pr2-icons-modernize

Conversation

@got3nks

@got3nks got3nks commented May 1, 2026

Copy link
Copy Markdown
Contributor

Summary

The proper follow-up to #474, which deliberately punted the libayatana-appindicator port as "out of scope, future follow-up" and shipped Exec=env GDK_BACKEND=x11 amule as the XEmbed-via-XWayland workaround for #410.

This PR rounds out the same theme — making aMule integrate cleanly with the host desktop environment — on macOS too: previously the close-button → dock-click flow was broken (window stayed permanently hidden), and the tray-icon checkbox was deliberately hidden on Mac builds even though wxTaskBarIcon → NSStatusItem is fully wired in wxOSX 3.2.

Two related Linux-icon problems with one canonical fix.

Dock / launcher icon

wxGTK 3.2 + GTK3 on Wayland derives the wl_app_id from g_get_prgname(), which defaults to argv[0]. That diverges across packaging formats (AppImage's argv[0] is aMule, distro packages use amule, Flatpak renames the .desktop entirely). The compositor matches wl_app_id against the .desktop filename to bind windows to the launcher icon — without a deterministic value the icon is generic on every Wayland desktop.

Fix: standardise on the canonical AppStream id org.amule.aMule — matching the .desktop filename, the Wayland app_id (set explicitly via g_set_prgname in CamuleApp::OnInit), the AppStream component id, and the macOS bundle id. Drops the legacy Exec=env GDK_BACKEND=x11 amule fallback from the .desktop files (#474).

System tray icon

aMule's tray feature uses wxTaskBarIcon, which on wxGTK 3.2 (and 3.3 — checked) talks the legacy GtkStatusIcon API. GNOME Shell removed the legacy notification area in 3.26 and wlroots compositors never implemented it, so the icon is silently invisible on Fedora / vanilla GNOME / Sway / Hyprland. Ubuntu's GNOME Shell extension renders both legacy and SNI; that's why the existing path appears to work on Ubuntu but breaks elsewhere.

Fix: add a StatusNotifierItem (SNI) backend in MuleTrayIcon via libayatana-appindicator3, gated on a configure-time pkg-config check. When the dep is present (Linux), tray icon switches to the SNI path. When the dep is missing the legacy wxTaskBarIcon path is preserved unchanged. Windows / macOS keep the existing wxTaskBarIcon → native shell behaviour with zero changes.

The SNI menu is static, rebuilt only on connection-state changes (driven by SetTrayIcon). Earlier iterations included a 2 s timer for live download/upload speed values, but app_indicator_set_menu posts a dbusmenu LayoutUpdated D-Bus signal which some SNI hosts react to with a brief icon redraw — the timer caused visible flicker. Live values are visible in the main aMule window; the tray menu surfaces actions + connection-snapshot info instead.

Menu structure (SNI backend)

aMule GIT vX.Y.Z                       ← static version banner
─────
Client Information ►
    eD2k: Connected (HighID) | (LowID) | Disconnected
    Kad: Connected | (firewalled) | Disconnected
    Server: <name>
    Server IP: <ip>
    IP: <public ip>
    TCP port: <port>
    UDP port: <port>
─────
Upload limit ►   (presets derived from Prefs → Statistics → Max graph upload rate)
Download limit ►
─────
Connect / Disconnect
Show aMule / Hide aMule
─────
Exit

The legacy wxTaskBarIcon menu (Windows/macOS/Linux without libayatana) is unchanged — keeps the rich live-stats menu it always had, since wxTaskBarIcon's CreatePopupMenu is invoked lazily on each right-click and doesn't have the dbusmenu redraw issue.

Dependencies

  • New mandatory dep on Linux GUI builds: glib-2.0 dev headers.
    g_set_prgname() is needed to bind wl_app_id, and wxWidgets has no equivalent: wxApp::SetAppName/SetClassName are X11-only and deprecated, no wx method propagates to the Wayland surface. wxGTK transitively depends on glib but distro packaging doesn't always pull the dev headers as a hard dep, so libglib2.0-dev is added explicitly to ccpp.yml. The g_set_prgname call is wrapped in #ifdef __WXGTK__ so Windows / macOS builds skip both the include and the call entirely — they don't need glib.

  • New optional dep: libayatana-appindicator3 (Linux only). When found at configure time, enables the SNI tray backend. When missing, falls back to wxTaskBarIcon. Configure log reports which backend is in use.

  • Note that upstream AyatanaIndicators has split the library into libayatana-appindicator-glib (GLib-only, GMenu-based, no GTK dep) and started emitting a deprecation warning when the GTK-based libayatana-appindicator3-0.1 is loaded. Migrating to the new library is tracked as future work — -glib isn't yet packaged on Ubuntu / Fedora / openSUSE / Debian, so switching today would lock out every major distro. The warning is harmless console noise.

macOS UX additions (second commit)

Three pre-existing Mac-specific gaps surfaced while testing the SNI / app_id work above; the second commit fixes them.

1. Hide-on-close → Dock click → window doesn't restore

aMule's HideOnClose pref (default-on on Mac, expected behaviour there) hides the main window via Show(false) when the user clicks the close button. But CamuleGuiApp had no MacReopenApp override, so clicking the Dock icon while the window was hidden was a no-op — the only way to bring aMule back was Cmd+Tab.

Fix: override wxApp::MacReopenApp() in CamuleGuiApp to Show(true) + Iconize(false) + Raise() the main dialog. Covers all three hidden states: hidden via Show(false), iconized to the Dock, or just behind other apps.

2. Tray-icon checkbox hidden on macOS

PrefsUnifiedDlg explicitly hid IDC_ENABLETRAYICON / IDC_MINTRAY on __WXMAC__ builds. wxTaskBarIconNSStatusItem is wired in wxOSX 3.2 and works correctly; the checkbox was hidden as a UX preference (Mac apps default to dock-dot indication), not because the implementation was missing.

Fix: drop the __WXMAC__ gate so Mac users can opt in to the menu-bar status-item pattern (Spotify / Discord / Slack-style). "Hide on close" remains visible and default-on; the tray icon is opt-in.

3. Tray-menu Hide/Show "half-state" (also affects non-Mac users in principle)

CMuleTrayIcon::DoShowHide() called Iconize() and Show() in sequence with IsShown() re-read between them. On macOS that left the window half-minimized (a weird mini-Dock tile) AND half-hidden, with the next Dock click only un-hiding the frame and leaving the iconized state set — producing an "only the toolbar shows" state.

Fix (in the first commit, alongside the SNI refactor): replace with a clean Show(true/false) + Raise() toggle. Iconize is the green-button minimize-to-Dock gesture, separate from the hide-to-tray flow. Universal fix; Windows/Linux see no behavioural change because hidden windows aren't in their respective taskbars regardless of iconized flag.

Files renamed

Old New
amule.desktop org.amule.aMule.desktop
amulegui.desktop org.amule.aMule.gui.desktop
amule.png org.amule.aMule.png
org.amule.amule.metainfo.xml org.amule.aMule.metainfo.xml (also <id> updated)

Backwards compatibility

  • Distro packagers: any .deb/.rpm referencing /usr/share/applications/amule.desktop has to update the path. One-line packaging change.
  • AppStream catalog: id changes org.amule.amuleorg.amule.aMule. Software catalogues see a single new id.
  • User configs: wxApp::SetAppName("aMule") is unchanged, so config-dir paths (~/.aMule/) are unaffected.
  • Icon-theme cache: source-from-cmake installs may need gtk-update-icon-cache -f -t <prefix>/share/icons/hicolor/ for the renamed icon to appear immediately. Distro packages bake this into post-install scriptlets; raw cmake --install does not. GNOME Shell's inotify watcher picks up the change on its own within a few seconds without the manual rebuild. Documented in docs/INSTALL.

Verification

Tested on openSUSE Tumbleweed aarch64, Ubuntu 25.10 aarch64, and macOS (Apple Silicon, Homebrew):

Linux (openSUSE + Ubuntu):

  • ✅ Built cleanly via cmake -B build && cmake --build build && cmake --install build
  • ✅ Configure-log line: tray-icon backend StatusNotifierItem (libayatana-appindicator 0.5.93/0.5.94)
  • ✅ Dock icon binds to running window on Wayland (verified visually — aMule's mule icon, not generic gear)
  • ✅ SNI tray icon appears in GNOME top-bar (with [email protected] extension on openSUSE — Ubuntu ships the equivalent enabled by default)
  • ✅ Tray menu items dispatch correctly: Connect/Disconnect, Show/Hide, Exit, Upload/Download limit submenus
  • ✅ Connect/Disconnect label flips when connection state changes
  • ✅ No menu flicker (static menu, only rebuilt on state transitions)

macOS:

  • ✅ Built cleanly via cmake --build build --target amule
  • ✅ "Hide on close" + Dock click → window restores correctly (was broken before)
  • ✅ Tray-icon checkbox visible in Preferences → General; toggling it places an aMule status item in the menu bar via NSStatusItem
  • ✅ Tray menu Hide / Show flips cleanly without the half-iconized mini-Dock tile or "only toolbar visible" state

CI results (got3nks fork — same workflow as upstream ccpp.yml)

Run 25208212862 at HEAD of pr2-icons-modernize:

Job Result
Build CMake Ubuntu (Debug)
Build CMake Ubuntu (Release)
Build CMake MacOS (Debug)
Build CMake MacOS (Release)
Build CMake mingw-w64 (Debug)
Build CMake mingw-w64 (Release)

Confirms:

  • g_set_prgname + glib include compile cleanly on Linux (__WXGTK__ true)
  • libayatana SNI backend wires up on Linux when libayatana-appindicator3-dev is present in the CI deps
  • Mac and Windows compile the unchanged wxTaskBarIcon legacy branch (__WXGTK__ false, WITH_LIBAYATANA_APPINDICATOR undefined → both new code paths excluded, original behaviour preserved)
  • The .desktop / .png / .metainfo.xml renames don't break any platform's install rules

Test plan

  • CI green on Ubuntu Debug + Release
  • CI green on macOS Debug + Release
  • CI green on Windows Debug + Release
  • Configure log on Ubuntu shows tray-icon backend: StatusNotifierItem

Closes #410 properly, supersedes the GDK_BACKEND=x11 workaround shipped in #474.

@got3nks

got3nks commented May 1, 2026

Copy link
Copy Markdown
Contributor Author

Pushed a tiny follow-up: codeql.yml's deps list also needed libglib2.0-dev — its c-cpp analyze step has its own cmake_ubuntu_deps separate from ccpp.yml, and I'd missed it. Same one-line addition as in ccpp.yml.

@got3nks
got3nks force-pushed the pr2-icons-modernize branch from a308cd2 to dafd264 Compare May 1, 2026 09:40
@got3nks got3nks changed the title icons: modernize Wayland app_id binding + StatusNotifierItem tray (closes #410) desktop integration: Wayland app_id, SNI tray, macOS dock-restore + tray opt-in (closes #410) May 1, 2026
@mrjimenez

Copy link
Copy Markdown
Contributor

Hi @got3nks , can you fix the conflicts? If I fix them, the merge won't be fast-forward.

got3nks added 2 commits May 2, 2026 00:11
The proper follow-up to amule-project#474, which deliberately punted the
libayatana-appindicator port as "out of scope, future follow-up" and
shipped `Exec=env GDK_BACKEND=x11 amule` as the XEmbed-via-XWayland
workaround for amule-project#410.

Two related Linux-icon problems with one canonical fix.

== Dock / launcher icon ==

wxGTK 3.2 + GTK3 on Wayland derives the wl_app_id from
g_get_prgname(), which defaults to argv[0]. That diverges across
packaging formats: AppImage's argv[0] is "aMule", distro packages use
"amule", Flatpak renames the .desktop entirely. The compositor matches
wl_app_id against the .desktop filename to bind windows to the
launcher icon — without a deterministic value the icon is generic on
every Wayland desktop.

Fix: standardise on the canonical AppStream id `org.amule.aMule` —
matching the .desktop filename, the Wayland app_id (set explicitly via
g_set_prgname in CamuleApp::OnInit), the AppStream component id, and
the macOS bundle id. Drops the legacy `Exec=env GDK_BACKEND=x11 amule`
fallback from the .desktop files (amule-project#474).

== System tray icon ==

aMule's tray feature uses wxTaskBarIcon, which on wxGTK 3.2 (and 3.3 —
checked) talks the legacy GtkStatusIcon API. GNOME Shell removed the
legacy notification area in 3.26 and wlroots compositors never
implemented it, so the icon is silently invisible on Fedora / vanilla
GNOME / Sway / Hyprland. Ubuntu's GNOME Shell extension renders both
legacy and SNI; that's why the existing path appears to work on
Ubuntu but breaks elsewhere.

Fix: add a StatusNotifierItem (SNI) backend in MuleTrayIcon via
libayatana-appindicator3, gated on a configure-time pkg-config check.
When the dep is present (Linux), tray icon switches to the SNI path
with feature parity (full menu including live download/upload speed,
client info submenu, upload/download speed presets, connect/disconnect
/show/hide/exit). Menu rebuilds every 2s for live values. When the
dep is missing the legacy wxTaskBarIcon path is preserved unchanged.
Windows / macOS keep the existing wxTaskBarIcon → native shell
behaviour with zero changes.

== Dependencies ==

* New mandatory dep: glib-2.0 dev headers (Linux GUI build only).
  `g_set_prgname()` is needed to bind wl_app_id, and wxWidgets has no
  equivalent: `wxApp::SetAppName/SetClassName` are X11-only and
  deprecated, no wx method propagates to the Wayland surface. wxGTK
  transitively depends on glib but distro packaging doesn't always
  pull the dev headers as a hard dep, so we add an explicit
  `libglib2.0-dev` apt entry to ccpp.yml. The `g_set_prgname` call is
  wrapped in `#ifdef __WXGTK__` so Windows / macOS builds skip both
  the include and the call entirely — they don't need glib.

* New optional dep: libayatana-appindicator3 (Linux only). When
  found at configure time, enables the SNI tray backend. When
  missing, falls back to wxTaskBarIcon. Configure log reports which
  backend is in use.

== Files renamed ==

- amule.desktop                  -> org.amule.aMule.desktop
- amulegui.desktop               -> org.amule.aMule.gui.desktop
- amule.png                      -> org.amule.aMule.png
- org.amule.amule.metainfo.xml   -> org.amule.aMule.metainfo.xml
  (also bumps `<id>` to `org.amule.aMule`)

== Backwards compatibility ==

- Distro packagers: any .deb/.rpm referencing /usr/share/applications/
  amule.desktop has to update the path. One-line packaging change.
- AppStream catalog id changed (org.amule.amule -> org.amule.aMule).
  Software catalogues see this as a single new id.
- `wxApp::SetAppName("aMule")` is unchanged, so config-dir paths
  (~/.aMule/) are unaffected. User configs migrate without action.

Closes amule-project#410 properly, supersedes the GDK_BACKEND=x11 workaround
shipped in amule-project#474.
Companion fixes for the desktop-integration pass on macOS, where the
existing wxTaskBarIcon path is wired in wxOSX 3.2 (NSStatusItem) but
the surrounding UX has gaps that made the feature feel broken.

== Dock click doesn't restore a hidden window ==

aMule's HideOnClose pref (default-on on Mac, expected behaviour
there) hides the main window via Show(false) when the user clicks
the close button. But CamuleGuiApp had no MacReopenApp override, so
clicking the Dock icon while the window was hidden was a no-op —
the only way to bring aMule back was Cmd+Tab.

Fix: override wxApp::MacReopenApp() in CamuleGuiApp to
Show(true) + Iconize(false) + Raise() the main dialog. Covers all
three hidden states: hidden via Show(false), iconized to the Dock,
or just behind other apps.

== Tray-icon checkbox hidden on macOS ==

PrefsUnifiedDlg explicitly hid IDC_ENABLETRAYICON / IDC_MINTRAY on
__WXMAC__ builds. wxTaskBarIcon -> NSStatusItem works correctly on
macOS; the checkbox was hidden as a UX preference (Mac apps default
to dock-dot indication), not because the implementation was missing.

Fix: drop the __WXMAC__ gate so Mac users can opt in to the
menu-bar status-item pattern (Spotify / Discord / Slack-style).
"Hide on close" remains visible and default-on; the tray icon is
opt-in.

(The Hide/Show half-state bug from CMuleTrayIcon::DoShowHide is
fixed in the previous commit on this branch as part of the
DoShowHide refactor.)
@got3nks
got3nks force-pushed the pr2-icons-modernize branch from 7ef10bc to 3e59853 Compare May 1, 2026 22:11
@got3nks

got3nks commented May 1, 2026

Copy link
Copy Markdown
Contributor Author

Done — rebased onto current master (post-#507), conflicts in ccpp.yml and codeql.yml were trivial (kept both libglib2.0-dev from this PR and libmaxminddb-dev from #507). Force-pushed; should be fast-forwardable now.

@mrjimenez
mrjimenez merged commit 2fd012f into amule-project:master May 2, 2026
12 checks passed
got3nks added a commit to got3nks/amule that referenced this pull request May 2, 2026
…3nks

mrjimenez flagged on PR amule-project#514 review that these three contributors
were missing from the roster:

* Werner Mahr / Vollstrecker — has merge access on amule-project/amule
  and merges incoming PRs (e.g. amule-project#430, amule-project#385, amule-project#319, amule-project#330, amule-project#286). Goes
  under Maintainers based on that role.
* Pablo Barciela / Sc0w — recent contributor, e.g. wxWidgets 3.2.6
  build fixes, GTK version-check cleanup, dropping gtk1/gtk2 support,
  Chinese translation work. Goes under Developers.
* got3nks — Wayland app_id binding + SNI tray (amule-project#508), macOS UX
  (amule-project#508), libmaxminddb CI fix (amule-project#507), ip2country/upnp/nls/boost
  hard-fail series (amule-project#509/amule-project#511/amule-project#512/amule-project#513), packaging (amule-project#510),
  docs modernize (this PR). Goes under Developers.

Other recent folks may be missing too — those can be added in
follow-up commits as they're identified. mrjimenez explicitly noted
this is the priority subset to not block the rename PR.
mrjimenez pushed a commit that referenced this pull request May 2, 2026
The README's icon image referenced amule.png at the repo root, but
PR #508 (icons modernize) renamed every icon to follow the AppStream
component-id convention org.amule.aMule.<ext>. amule.png no longer
exists at the GitHub raw URL, so the README rendered with a broken
image since #508 merged.

Update the URL to the new filename. While in the file:

* Switch from underline-style headings to ATX (#) headings — more
  common in Markdown ecosystems and renders identically.
* Replace the autotools-era 'configure && make' compile snippet with
  the actual cmake invocation, and link to docs/INSTALL.md for the
  full dep list. The wiki's compile pages are flagged 'may be
  outdated' upstream; pointing at the in-tree INSTALL keeps this
  reference always-current.
* Drop the X-Box claim from the supported-platforms list — that's
  pre-2010 historical and isn't tested today.
* Update the supported-platforms list to current reality (Linux,
  FreeBSD, OpenBSD, macOS, Windows MSYS2 / mingw-w64, x86_64 + ARM64).
* Drop the dead bugs.amule.org link; GitHub Issues is the canonical
  bug tracker.
* Tighten the prose throughout — same content, fewer filler words.
mrjimenez pushed a commit that referenced this pull request May 2, 2026
…3nks

mrjimenez flagged on PR #514 review that these three contributors
were missing from the roster:

* Werner Mahr / Vollstrecker — has merge access on amule-project/amule
  and merges incoming PRs (e.g. #430, #385, #319, #330, #286). Goes
  under Maintainers based on that role.
* Pablo Barciela / Sc0w — recent contributor, e.g. wxWidgets 3.2.6
  build fixes, GTK version-check cleanup, dropping gtk1/gtk2 support,
  Chinese translation work. Goes under Developers.
* got3nks — Wayland app_id binding + SNI tray (#508), macOS UX
  (#508), libmaxminddb CI fix (#507), ip2country/upnp/nls/boost
  hard-fail series (#509/#511/#512/#513), packaging (#510),
  docs modernize (this PR). Goes under Developers.

Other recent folks may be missing too — those can be added in
follow-up commits as they're identified. mrjimenez explicitly noted
this is the priority subset to not block the rename PR.
@got3nks
got3nks deleted the pr2-icons-modernize branch May 2, 2026 14:30
got3nks added a commit to got3nks/amule that referenced this pull request Jul 17, 2026
…amule-project#508)

In amulegui the bottom log notebook (Networks panel) mixed two sources in the
"aMule Log" tab: amulegui's own messages (connection status, reconnects, etc.)
and the daemon/core log forwarded over EC. Split them -- "aMule Log" now carries
only the daemon log, and a new "aMuleGUI Log" tab holds the GUI client's own
messages. Each tab has its own Clear button.

- CamuleDlg::AddLogLine is refactored into a per-view helper (AddLogLineToView).
  AddLogLine feeds ID_LOGVIEW (the daemon log); a new AddGuiLogLine feeds the new
  ID_GUILOGVIEW in the CLIENT_GUI build, and falls back to the single tab in the
  monolithic build. CamuleGuiBase::AddGuiLogLine (the GUI client's own log) now
  routes through it; the EC daemon-log path (AddRemoteLogLine) is unchanged.
- The new tab is inserted at runtime in CServerWnd (compiled per-target with
  CLIENT_GUI) rather than in serverListDlgDown: muuli_wdr is compiled into a
  shared library without CLIENT_GUI and cannot tell the two builds apart.
- Monolithic aMule is unchanged -- it keeps its single "aMule Log" tab.

The new "aMuleGUI Log" string regenerates the app catalogs.
got3nks added a commit to got3nks/amule that referenced this pull request Jul 17, 2026
…ty (amule-project#510)

PR amule-project#508 added an "aMuleGUI Log" tab to the remote GUI's log notebook by
inserting it at index 1. CamuleDlg tracked the network-conditional log tabs
(Server Info / ED2K Info / Kad Info) by position in a fixed m_logpages[4]
array, so the extra tab shifted everything: the GetPageCount() == 4 assert
fired in debug builds, the capture loop wrote past the array end (corrupting
the adjacent m_networkpages), and DoNetworkRearrange re-added the wrong pages
-- dropping the Kad Info tab, as reported on amule-project#508.

Track the network-conditional tabs by identity instead of index: capture each
page via the control it hosts (ID_SERVERINFO / ID_ED2KINFO / ID_KADINFO) and
add/remove those specific pages with FindPage(). This is index- and
build-independent -- the always-on tabs (aMule Log, and aMuleGUI Log in the
remote GUI) are simply left in place -- so the monolithic and amulegui layouts
share one code path and it won't break again if a tab is added or reordered.
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.

amule-2.3.3: tray icon not working on wayland

2 participants