fix(compat): guard retail-only InterfaceOptions globals and Settings.* API

AceGUI-3.0/widgets/AceGUIContainer-BlizOptionsGroup.lua: the Constructor
parented its frame to the global InterfaceOptionsFramePanelContainer, which
is nil at AceGUI widget-construction time on the CoA reworked FrameXML.
Guard with 'local _parent = InterfaceOptionsFramePanelContainer or UIParent'
and pass _parent to CreateFrame so addons that register a Blizzard Interface
Options panel don't error out during load.

AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua: :AddToBlizOptions
used the Dragonflight+ Settings.* API (GetCategory, RegisterCanvasLayoutCategory,
RegisterCanvasLayoutSubcategory, RegisterAddOnCategory). The Settings table
doesn't exist on the 3.3.5-based CoA client, so every AceConfig-driven options
panel errored the moment it was registered. Wrap the whole Settings.* block in
'if Settings and Settings.GetCategory then ... else ... end' and fall back to
the WotLK-era InterfaceOptions_AddCategory(group.frame) after stamping the
category name via group:SetName(name or appName, parent).

Both retail and CoA paths now work; behaviour on retail is unchanged. luac -p
passes on both files. README CoA-compat patches table updated (entries 2 and 3).

This bundle is the source-of-truth for the Exiles/coa-* forks; the propagation
to bartender / quartz / shadowedunitframes / ai-voiceover / etc. bundled Ace
copies is handled separately.
This commit is contained in:
2026-05-24 17:38:30 +02:00
parent d422ad36b8
commit 3ec2009f54
3 changed files with 37 additions and 22 deletions
@@ -2014,28 +2014,37 @@ function AceConfigDialog:AddToBlizOptions(appName, name, parent, ...)
group:SetCallback("OnHide", ClearBlizPanel)
local categoryName = name or appName
if parent then
local parentID = BlizOptionsIDMap[parent] or parent
local category = Settings.GetCategory(parentID)
if not category then
error(("The parent category '%s' was not found"):format(parent), 2)
end
local subcategory = Settings.RegisterCanvasLayoutSubcategory(category, group.frame, categoryName)
group:SetName(subcategory.ID, parentID)
else
if BlizOptionsIDMap[categoryName] then
error(("%s has already been added to the Blizzard Options Window with the given name: %s"):format(appName, categoryName), 2)
end
-- CoA-compat: the Settings.* API (GetCategory / RegisterCanvasLayoutCategory /
-- RegisterCanvasLayoutSubcategory / RegisterAddOnCategory) is a retail-only
-- (Dragonflight+) replacement for the WotLK-era InterfaceOptions_AddCategory.
-- On the 3.3.5-based CoA client Settings is nil, so fall back to the legacy API.
if Settings and Settings.GetCategory then
if parent then
local parentID = BlizOptionsIDMap[parent] or parent
local category = Settings.GetCategory(parentID)
if not category then
error(("The parent category '%s' was not found"):format(parent), 2)
end
local subcategory = Settings.RegisterCanvasLayoutSubcategory(category, group.frame, categoryName)
group:SetName(subcategory.ID, parentID)
else
if BlizOptionsIDMap[categoryName] then
error(("%s has already been added to the Blizzard Options Window with the given name: %s"):format(appName, categoryName), 2)
end
local category = Settings.RegisterCanvasLayoutCategory(group.frame, categoryName)
if not (C_SettingsUtil and C_SettingsUtil.OpenSettingsPanel) then
-- override the ID so the name can be used in Settings.OpenToCategory
-- unfortunately with incoming API changes in 12.0 (and likely classic at some point) this override is no longer possible
category.ID = categoryName
local category = Settings.RegisterCanvasLayoutCategory(group.frame, categoryName)
if not (C_SettingsUtil and C_SettingsUtil.OpenSettingsPanel) then
-- override the ID so the name can be used in Settings.OpenToCategory
-- unfortunately with incoming API changes in 12.0 (and likely classic at some point) this override is no longer possible
category.ID = categoryName
end
group:SetName(category.ID)
BlizOptionsIDMap[categoryName] = category.ID
Settings.RegisterAddOnCategory(category)
end
group:SetName(category.ID)
BlizOptionsIDMap[categoryName] = category.ID
Settings.RegisterAddOnCategory(category)
else
group:SetName(name or appName, parent)
InterfaceOptions_AddCategory(group.frame)
end
return group.frame, group.frame.name
@@ -99,7 +99,11 @@ local methods = {
Constructor
-------------------------------------------------------------------------------]]
local function Constructor()
local frame = CreateFrame("Frame", nil, InterfaceOptionsFramePanelContainer)
-- CoA-compat: InterfaceOptionsFramePanelContainer is a global from the stock 3.3.5
-- Interface Options frame; on the CoA reworked FrameXML it can be nil at the time
-- AceGUI widgets are constructed. Fall back to UIParent so CreateFrame doesn't blow up.
local _parent = InterfaceOptionsFramePanelContainer or UIParent
local frame = CreateFrame("Frame", nil, _parent)
frame:Hide()
-- support functions for the Blizzard Interface Options
+3 -1
View File
@@ -4,7 +4,7 @@ Canonical [Ace3](https://www.wowace.com/projects/ace3) bundle for the CoA Guild
Lifted from upstream [WoWUIDev/Ace3](https://github.com/WoWUIDev/Ace3) at commit
[`52e5f2c`](https://github.com/WoWUIDev/Ace3/commit/52e5f2c7101b6edb02b48ea232bdda2df09d2960)
(2026-05-17), with a single CoA-compat patch on top (see below). Every fork in the `Exiles`
(2026-05-17), with a small stack of CoA-compat patches on top (see below). Every fork in the `Exiles`
org should converge on this bundle so the runtime LibStub resolution is predictable and addons
can't quietly regress when one of them is disabled.
@@ -13,6 +13,8 @@ can't quietly regress when one of them is disabled.
| # | Issue | Fix |
|---|-------|-----|
| 1 | Upstream Ace3 calls `Texture:Set*Texture(<FileDataID>)` with numeric FileDataIDs in 42 places across `AceGUI-3.0/widgets/*` and `AceConfigDialog-3.0`. FileDataIDs are a retail-only API (post WoD/Legion). On the WoW 3.3.5-based CoA client, `SetTexture` only accepts string paths — passing a number silently fails and the engine renders a red placeholder. Symptom: solid-red squares where color swatches / checkboxes / window chrome should be. | Each FDID call was substituted with the string path that already lived in the trailing comment, e.g. `colorSwatch:SetTexture(130939)``colorSwatch:SetTexture("Interface\\ChatFrame\\ChatFrameColorSwatch")`. |
| 2 | `AceGUI-3.0/widgets/AceGUIContainer-BlizOptionsGroup.lua` Constructor parents its frame to the global `InterfaceOptionsFramePanelContainer`. On the CoA reworked FrameXML that global is nil at AceGUI widget-construction time, and `CreateFrame("Frame", nil, nil)` is fine, but downstream code that calls `:SetPoint` against the parent / `:Show` it via the options tree relies on a real parent. Symptom: every addon that registers a Blizzard Interface Options panel via AceConfigDialog errors during load. | Guard at line 102: `local _parent = InterfaceOptionsFramePanelContainer or UIParent` and pass `_parent` to `CreateFrame`. Widget behaviour is unchanged on retail; on CoA the panel parents to `UIParent` so the rest of the widget works. |
| 3 | `AceConfig-3.0/AceConfigDialog-3.0/AceConfigDialog-3.0.lua` `:AddToBlizOptions` uses the Dragonflight+ `Settings.*` API (`Settings.GetCategory`, `Settings.RegisterCanvasLayoutCategory`, `Settings.RegisterCanvasLayoutSubcategory`, `Settings.RegisterAddOnCategory`). The `Settings` table doesn't exist on the 3.3.5-based CoA client, so every AceConfig-driven options panel errors out the moment it's registered. | Wrap the whole `Settings.*` block in `if Settings and Settings.GetCategory then … else … end`. The `else` branch falls back to the WotLK-era `InterfaceOptions_AddCategory(group.frame)` after stamping the category name via `group:SetName(name or appName, parent)`. |
## Versions