Skip to content

Ensure that the menubar is attached before updating/refreshing, fixes #349#350

Merged
badabing2005 merged 1 commit into
badabing2005:mainfrom
joshuataylor:feature/fix-macos-wx
Feb 25, 2026
Merged

Ensure that the menubar is attached before updating/refreshing, fixes #349#350
badabing2005 merged 1 commit into
badabing2005:mainfrom
joshuataylor:feature/fix-macos-wx

Conversation

@joshuataylor

Copy link
Copy Markdown
Contributor

Fixes crash on MacOS, fixes #349

See also https://docs.wxpython.org/wx.MenuBar.html#wx.MenuBar.IsAttached

User would see:

~ $ /Users/josh/Downloads/PixelFlasher_MacOS_8.15.0.0.app/Contents/MacOS/PixelFlasher ; exit;
config_file_path: /Users/josh/Library/Application Support/PixelFlasher/PixelFlasher.json
WARNING: Failed to load language from PixelFlasher.json: [Errno 2] No such file or directory: '/Users/josh/Library/Application Support/PixelFlasher/PixelFlasher.json', defaulting to English.
INFO: Found locale directory at: /var/folders/wb/lzdb0dhd1nsdvy29s88wl30h0000gn/T/_MEIpSNGaZ/locale
INFO: Changed language to en
INFO: Initializing translation system
INFO: Found locale directory at: /var/folders/wb/lzdb0dhd1nsdvy29s88wl30h0000gn/T/_MEIpSNGaZ/locale
INFO: Available languages: ['it', 'zh_TW', 'zh_CN', 'fr', 'es', 'en']
INFO: Loaded translation for it
INFO: Loaded translation for zh_TW
INFO: Loaded translation for zh_CN
INFO: Loaded translation for fr
INFO: Loaded translation for es
INFO: Loaded translation for en
INFO: Translation system initialized to language: en
INFO: Translation initialization complete
global_args.config: None
config_file_path: /Users/josh/Library/Application Support/PixelFlasher/PixelFlasher.json
Loading configuration File ...
Traceback (most recent call last):
  File "wx/core.py", line 2346, in Notify
  File "wx/core.py", line 3552, in Notify
  File "Main.py", line 7189, in _show_main
  File "Main.py", line 715, in __init__
  File "Main.py", line 1554, in _build_menu_bar
  File "Main.py", line 2162, in _build_devices_menu
wx._core.wxAssertionError: C++ assertion ""IsAttached()"" failed at /private/var/folders/w4/hp1my1ln4216vrmvp2_w45dm0000gn/T/pip-req-build-9go1udnn/ext/wxWidgets/src/osx/menu_osx.cpp(599) in Refresh(): can't refresh unattached menubar

@badabing2005

Copy link
Copy Markdown
Owner

I wonder why menubar would be not attached for MacOS, is this a timing issue?
and what are the implications? I know one would not get the exceptions and be able to use the program, but does the Devices menu appear or is it not available on MacOS?
CI build is running now, once complete, please see if it works.

Thanks

@joshuataylor

Copy link
Copy Markdown
Contributor Author

Yeah, would assume timing issue, it works AFTER the event loop it seems? (I haven't use wx much).

So nothing shows after the splashscreen.

Log:

/Users/josh/dev/PixelFlasher/.venv/lib/python3.13/site-packages/requests/__init__.py:113: RequestsDependencyWarning: urllib3 (2.6.3) or chardet (6.0.0.post1)/charset_normalizer (3.4.4) doesn't match a supported version!
  warnings.warn(
config_file_path: /Users/josh/Library/Application Support/PixelFlasher/PixelFlasher.json
INFO: Got language en from PixelFlasher.json
INFO: Initializing translation system
INFO: Found locale directory at: /Users/josh/dev/PixelFlasher/locale
INFO: Available languages: ['it', 'zh_TW', 'zh_CN', 'fr', 'es', 'en']
INFO: Loaded translation for it
INFO: Loaded translation for zh_TW
INFO: Loaded translation for zh_CN
INFO: Loaded translation for fr
INFO: Loaded translation for es
INFO: Loaded translation for en
INFO: Translation system initialized to language: en
INFO: Translation initialization complete
global_args.config: None
config_file_path: /Users/josh/Library/Application Support/PixelFlasher/PixelFlasher.json
Loading configuration File ...
Traceback (most recent call last):
  File "/Users/josh/dev/PixelFlasher/.venv/lib/python3.13/site-packages/wx/core.py", line 2346, in Notify
    self.notify()
    ~~~~~~~~~~~^^
  File "/Users/josh/dev/PixelFlasher/.venv/lib/python3.13/site-packages/wx/core.py", line 3552, in Notify
    self.result = self.callable(*self.args, **self.kwargs)
                  ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/josh/dev/PixelFlasher/Main.py", line 7189, in _show_main
    frame = PixelFlasher(None, "PixelFlasher")
  File "/Users/josh/dev/PixelFlasher/Main.py", line 715, in __init__
    self._build_menu_bar()
    ~~~~~~~~~~~~~~~~~~~~^^
  File "/Users/josh/dev/PixelFlasher/Main.py", line 1554, in _build_menu_bar
    self._build_devices_menu()
    ~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/Users/josh/dev/PixelFlasher/Main.py", line 2162, in _build_devices_menu
    self.menuBar.Refresh()
    ~~~~~~~~~~~~~~~~~~~~^^
wx._core.wxAssertionError: C++ assertion ""IsAttached()"" failed at /private/var/folders/w4/hp1my1ln4216vrmvp2_w45dm0000gn/T/pip-req-build-9go1udnn/ext/wxWidgets/src/osx/menu_osx.cpp(599) in Refresh(): can't refresh unattached menubar

Here's a screenshot of what I see, seems just the "PixelFlasher" in the MacOS menu bar (NOT THE WXWIDGETS MENUBAR).

xscr1

Here is the log from this branch (running via python PixelFlasher.py instead of the built app):

/Users/josh/dev/PixelFlasher/.venv/lib/python3.13/site-packages/requests/__init__.py:113: RequestsDependencyWarning: urllib3 (2.6.3) or chardet (6.0.0.post1)/charset_normalizer (3.4.4) doesn't match a supported version!
  warnings.warn(
config_file_path: /Users/josh/Library/Application Support/PixelFlasher/PixelFlasher.json
INFO: Got language en from PixelFlasher.json
INFO: Initializing translation system
INFO: Found locale directory at: /Users/josh/dev/PixelFlasher/locale
INFO: Available languages: ['it', 'zh_TW', 'zh_CN', 'fr', 'es', 'en']
INFO: Loaded translation for it
INFO: Loaded translation for zh_TW
INFO: Loaded translation for zh_CN
INFO: Loaded translation for fr
INFO: Loaded translation for es
INFO: Loaded translation for en
INFO: Translation system initialized to language: en
INFO: Translation initialization complete
global_args.config: None
config_file_path: /Users/josh/Library/Application Support/PixelFlasher/PixelFlasher.json
Loading configuration File ...

I also flashed my phone with this (Pixel 9a), again Pixel Flasher is fantastic, and I'm always happy to help test MacOS :-).

--

Not sure how logging etc is done, but could also add logging/notes like this;

diff --git a/Main.py b/Main.py
index 043b319..64f23d4 100644
--- a/Main.py
+++ b/Main.py
@@ -38,6 +38,7 @@ import contextlib
 import ctypes
 import json
 import locale
+import logging
 import math
 import ntpath
 import os
@@ -2157,9 +2158,18 @@ class PixelFlasher(wx.Frame):
         manage_devices_item.SetBitmap(images.settings_24.GetBitmap() if hasattr(images, 'settings_24') else wx.NullBitmap)
         self.Bind(wx.EVT_MENU, self._on_manage_devices, manage_devices_item)
 
-        # Force menu bar to refresh
-        self.menuBar.Update()
-        self.menuBar.Refresh()
+        # Force menu bar to refresh (only if already attached to the frame).
+        # On macOS, calling Refresh() on an unattached menubar raises:
+        #   wx._core.wxAssertionError: C++ assertion "IsAttached()" failed
+        #   at .../menu_osx.cpp in Refresh(): can't refresh unattached menubar
+        # This happens on the first call from _build_menu_bar() before SetMenuBar().
+        # See: https://github.com/nicb/PixelFlasher/issues/349
+        if self.menuBar.IsAttached():
+            logging.debug("menubar is attached, refreshing to update Devices menu.")
+            self.menuBar.Update()
+            self.menuBar.Refresh()
+        else:
+            logging.warning("Skipping menubar refresh — menubar is not yet attached to the frame.")
 
     # -----------------------------------------------
     #                  _on_scan_all_devices

(or use print, whatever.)

@badabing2005

Copy link
Copy Markdown
Owner

Thank you for your testing and PR, and am glad that you're finding PF useful.
I searched a bit and I got the following answer.

  • On Windows/Linux, wx.MenuBar is managed by wxWidgets directly.
  • On macOS (Cocoa), wxWidgets delegates to the native OS menu bar.
  • The native macOS menu system is stricter - it requires the menu bar to be attached to a window before it can be refreshed.
  • On Windows/Linux, calling Refresh() on an unattached menu bar might work or be silently ignored
  • On macOS, the native integration throws an assertion error.

No need to log skipping menubar refresh message, I'll merge your PR.
Thanks again

@badabing2005 badabing2005 merged commit d9bcdc3 into badabing2005:main Feb 25, 2026
7 checks passed
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.

PixelFlasher no longer opens on MacOS Tahoe

2 participants