From f28f1502e2b5c9f8bb1f56231d4124aca0c64caa Mon Sep 17 00:00:00 2001 From: GenSpark AI Developer Date: Mon, 15 Jun 2026 14:46:53 +0000 Subject: [PATCH] fix(gui): restore BAL status-bar icon (bottom-right) + open settings on click Regression: create_status_bar had been turned into a no-op while chasing the "condensed menu/tabs" bug. The real cause of that bug was a Windows OverflowError (year 2038), already fixed separately -- so the no-op wrongly removed the BAL icon from the status bar. Restore the original (Gitea) behaviour: - Build a StatusBarButton with the bal32x32 icon and add it via addPermanentWidget, so the icon shows the plugin is installed. - Clicking the icon opens settings_dialog (quick access to plugin settings). - Track buttons in self._statusbar_buttons keyed by id(sb.window()); remove the stale button before creating a new one to avoid a duplicated icon on restart / wallet switch. Also: - import StatusBarButton from electrum.gui.qt.main_window; ensure read_QIcon_from_bytes is imported; init self._statusbar_buttons in __init__. - Update tests/gui_fixes_test.py: the regression check now asserts the icon IS added (StatusBarButton + addPermanentWidget + settings_dialog + _statusbar_buttons book-keeping), instead of the previous wrong no-op check. Tests: 182 official tests pass; smoke/windows_overflow/parallel/external_zip OK. Note: from now on all code and code-comments are in English. --- bal/gui/qt/plugin.py | 44 ++++++++++++++++++++++++++++++++--------- tests/gui_fixes_test.py | 31 ++++++++++++++++++----------- 2 files changed, 55 insertions(+), 20 deletions(-) diff --git a/bal/gui/qt/plugin.py b/bal/gui/qt/plugin.py index 8f445d3..04e8fe3 100644 --- a/bal/gui/qt/plugin.py +++ b/bal/gui/qt/plugin.py @@ -14,8 +14,11 @@ One :class:`bal.gui.qt.window.BalWindow` is created per top-level wallet window and cached in ``self.bal_windows``. """ +from electrum.gui.qt.main_window import StatusBarButton + from .common import * from .common import _, _logger # underscore names are not re-exported by "import *" +from .common import read_QIcon_from_bytes from .widgets import BalCheckBox, BalLineEdit, BalTextEdit from .window import BalWindow from .dialogs import BalDialog @@ -38,6 +41,10 @@ class Plugin(BalPlugin): _logger.info("INIT BALPLUGIN") BalPlugin.__init__(self, parent, config, name) self.bal_windows = {} + # Status-bar buttons, keyed by id(sb.window()). Tracking them lets us + # remove a stale button before creating a fresh one when a wallet is + # switched / Electrum is restarted, so the icon is never duplicated. + self._statusbar_buttons = {} @hook def init_qt(self, gui_object): @@ -88,15 +95,34 @@ class Plugin(BalPlugin): @hook def create_status_bar(self, sb): - # NOTE: intentionally a no-op, matching the original plugin. The - # original code had an early ``return`` before building the - # StatusBarButton, i.e. the button was deliberately disabled. Adding - # the button here caused a stray, condensed icon+text element to be - # rendered in the wrong place (near the top, under the Electrum logo) - # after a restart / wallet switch. Settings are already reachable via - # Tools -> Plugins, so we keep the original behaviour. - _logger.info("HOOK create status bar (no-op)") - return + # Show the BAL icon in the status bar (bottom-right): it signals that + # the Bitcoin After Life plugin is installed and, when clicked, quickly + # opens the plugin settings (settings_dialog). + # + # NOTE: this was NOT the "condensed menu/tabs" bug under the Electrum + # logo -- that one was a Windows OverflowError (year 2038), fixed + # separately. The icon must therefore be kept. + # + # To avoid a duplicated icon on restart / wallet switch, we track the + # button by id(sb.window()) and remove the stale one before creating a + # fresh one. + _logger.info("HOOK create status bar") + key = id(sb.window()) + old = self._statusbar_buttons.pop(key, None) + if old is not None: + try: + old.setParent(None) + old.deleteLater() + except Exception: + pass + b = StatusBarButton( + read_QIcon_from_bytes(self.read_file("icons/bal32x32.png")), + "Bal " + _("Bitcoin After Life"), + lambda: self.settings_dialog(sb.window()), + sb.height(), + ) + sb.addPermanentWidget(b) + self._statusbar_buttons[key] = b @hook def init_menubar(self, window): diff --git a/tests/gui_fixes_test.py b/tests/gui_fixes_test.py index 92da482..27c187e 100644 --- a/tests/gui_fixes_test.py +++ b/tests/gui_fixes_test.py @@ -115,22 +115,31 @@ def main(pkg: str) -> int: "on_close must reset _menubar_initialized so the window can be reused") print("[OK] init_menubar_tools is idempotent (no duplicate tabs/menu)") - # REGRESSION: create_status_bar must stay a no-op, like the original plugin - # (whose body had an early ``return`` before building the StatusBarButton). - # Re-adding the status-bar button made a stray condensed icon+text element - # appear in the wrong place after restart / wallet switch. - csb_src = inspect.getsource(plugin_mod.Plugin.create_status_bar) - csb_active = _active_source_without_strings(plugin_mod) # whole module sans strings + # REGRESSION: create_status_bar MUST add the BAL status-bar icon (bottom + # right of the Electrum window). It signals that the plugin is installed + # and, when clicked, opens the plugin settings. An earlier change wrongly + # turned this into a no-op while chasing the "condensed menu" bug (whose + # real cause was a Windows OverflowError, fixed elsewhere), which made the + # icon disappear. The icon must stay, and must not be duplicated on + # restart / wallet switch (hence the _statusbar_buttons book-keeping). csb_body = inspect.getsource(plugin_mod.Plugin.create_status_bar) - # The executable body must not add a permanent widget / build the button. - # Strip comments to avoid matching the explanatory note. csb_code = "\n".join( line for line in csb_body.splitlines() if not line.lstrip().startswith("#") ) - assert "addPermanentWidget" not in csb_code, ( - "create_status_bar must not add a status-bar widget (original is a no-op)") - print("[OK] create_status_bar is a no-op (matches original)") + assert "StatusBarButton" in csb_code, ( + "create_status_bar must build a StatusBarButton (the BAL icon)") + assert "addPermanentWidget" in csb_code, ( + "create_status_bar must add the BAL icon to the status bar") + assert "settings_dialog" in csb_code, ( + "clicking the BAL icon must open settings_dialog") + assert "_statusbar_buttons" in csb_code, ( + "create_status_bar must track buttons to avoid duplicate icons") + # __init__ must initialise the tracking dict. + init_code = inspect.getsource(plugin_mod.Plugin.__init__) + assert "_statusbar_buttons" in init_code, ( + "Plugin.__init__ must initialise self._statusbar_buttons") + print("[OK] create_status_bar adds the BAL icon + opens settings on click") print(f"\n[OK] all GUI-fix checks passed for package {pkg!r}") return 0