Extra controls (including the file type filter choice) have been disabled in sandboxed applications since the 2013-era workaround for #14906: the native save/open panel runs out of process (Powerbox / NSRemoteView) when sandboxed, and inserting wx-created views into the panel's own view hierarchy crashed.
The supported contract for accessory views is to build the NSView entirely in-process and hand the finished view to -[NSSavePanel setAccessoryView:]; the panel then hosts it safely even when it is remote. This PR does exactly that: the extra control and the filter panel are created as children of a hidden in-process host window instead of being parented to the (possibly remote) panel, and only the finished view is handed over.
This makes extra controls and file type filters work in sandboxed applications too, removing the APP_SANDBOX_CONTAINER_ID bail-out. As a safety valve, setting WX_DISABLE_FILEDIALOG_EXTRA_CONTROLS in the environment restores the old behaviour of skipping the extra controls.
This has been shipping for a while in xLights (a sandboxed Mac App Store wxWidgets application) without issues, with the file type filter and custom extra controls working in the sandboxed file dialogs.
🤖 Generated with Claude Code
https://github.com/wxWidgets/wxWidgets/pull/26908
(2 files)
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
@vadz commented on this pull request.
Thanks, this looks good to me, but it would be nice if you could check the issue with the potentially null m_accessoryHost.
And fix the other minor comments too if possible. TIA!
> @@ -91,6 +91,9 @@ class WXDLLIMPEXP_CORE wxFileDialog: public wxFileDialogBase
wxArrayString m_filterNames;
wxChoice* m_filterChoice;
wxWindow* m_filterPanel;
+ // Hidden in-process window owning the accessory controls; see
+ // wxFileDialog::SetupExtraControls() in filedlg.mm.
+ wxWindow* m_accessoryHost;
There is no reason not to initialize new members in their declarations in the new code:
⬇️ Suggested change- wxWindow* m_accessoryHost; + wxWindow* m_accessoryHost = nullptr;
> @@ -111,6 +112,7 @@ - (void)setAllowedExtensions:(const wxArrayString &)extensions
m_filterChoice = nullptr;
m_useFileTypeFilter = false;
m_firstFileTypeFilter = 0;
+ m_accessoryHost = nullptr;
As per above
⬇️ Suggested change- m_accessoryHost = nullptr;
> wxWindow* extrapanel = useExtraControlAsPanel
? extracontrol
- : static_cast<wxWindow*>(new wxPanel(this));
+ : static_cast<wxWindow*>(new wxPanel(m_accessoryHost));
I'm not sure Copilot is wrong here. Couldn't this be called even if there are no extra controls?
> + if ( [panel contentView] == nil ||
+ getenv("WX_DISABLE_FILEDIALOG_EXTRA_CONTROLS") != nullptr )
return;
It's not wrong again here either, although somewhat besides the point: we should use something like wxSystemOptions::GetOptionInt("osx.openfiledialog.disable-extra-controls") here, see the existing uses of ``wxSystemOptions` in wxOSX.
The corresponding env variable would be wx_osx_openfiledialog_disable_extra_controls=1.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
@dkulp pushed 1 commit.
—
View it on GitHub or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
@dkulp commented on this pull request.
> @@ -91,6 +91,9 @@ class WXDLLIMPEXP_CORE wxFileDialog: public wxFileDialogBase
wxArrayString m_filterNames;
wxChoice* m_filterChoice;
wxWindow* m_filterPanel;
+ // Hidden in-process window owning the accessory controls; see
+ // wxFileDialog::SetupExtraControls() in filedlg.mm.
+ wxWindow* m_accessoryHost;
Done in 48df49d.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
@dkulp commented on this pull request.
> wxWindow* extrapanel = useExtraControlAsPanel
? extracontrol
- : static_cast<wxWindow*>(new wxPanel(this));
+ : static_cast<wxWindow*>(new wxPanel(m_accessoryHost));
Right — CreateFilterPanel() is virtual and could in principle be reached without SetupExtraControls() having created the host first. The host window is now created on demand via a GetAccessoryHost() helper used by both call sites, so it can never be null there.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
> + if ( [panel contentView] == nil ||
+ getenv("WX_DISABLE_FILEDIALOG_EXTRA_CONTROLS") != nullptr )
return;
Switched to wxSystemOptions::GetOptionInt(wxOSX_FILEDIALOG_DISABLE_EXTRA_CONTROLS) with the option name osx.openfiledialog.disable-extra-controls (env var wx_osx_openfiledialog_disable_extra_controls=1 via the existing wxSystemOptions environment fallback), following the wxOSX_FILEDIALOG_ALWAYS_SHOW_TYPES precedent, and documented it in interface/wx/sysopt.h.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
> + // The extra controls and the file-type filter panel are created as children + // of a hidden, in-process host window (see SetupExtraControls), so + // destroying the host tears down the whole accessory view hierarchy
Thanks for the review! All comments addressed in 48df49d:
m_accessoryHost is initialized in its declaration.GetAccessoryHost(), so CreateFilterPanel() can no longer see a null host even if called outside of SetupExtraControls().osx.openfiledialog.disable-extra-controls system option (wxOSX_FILEDIALOG_DISABLE_EXTRA_CONTROLS, or wx_osx_openfiledialog_disable_extra_controls=1 in the environment), documented in interface/wx/sysopt.h.Regarding Copilot's remaining comment about a pre-existing m_extraControl not being reparented: on wxOSX the only place that creates it is SetupExtraControls() itself (the base CreateExtraControl() is no longer called), so an already-created control is always parented to the host; the !m_extraControl check just makes a second setup pass reuse it.
Happy to squash before merge if you prefer.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
> @@ -111,6 +112,7 @@ - (void)setAllowedExtensions:(const wxArrayString &)extensions
m_filterChoice = nullptr;
m_useFileTypeFilter = false;
m_firstFileTypeFilter = 0;
+ m_accessoryHost = nullptr;
Done.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
Thanks for the update! This looks good to me now, @csomor any objections to merging?
P.S. I'll try rerunning the CI jobs once GitHub Actions is alive again, but I don't expect this to break anything as we don't have any tests exercising this code anyhow.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
@dkulp thanks a lot, wow, I was not aware of such a documentation for the right workaround at the time I was fighting with these controls, even though I thought I had watched all the corresponding WWDC vidos, great you found it :-)
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
Thanks for the update! This looks good to me now, @csomor any objections to merging?
No, I'm fine with this, really neat :-)
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()
—
Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.![]()