Skip to content

feat+fix(blizzskin): skin the BNet friend online/offline toast and fix a taint issue - #1915

Merged
EllesmereGaming merged 2 commits into
EllesmereGaming:mainfrom
JuJuFX-dev:feature/bnet-toast-skin
Sep 2, 2026
Merged

feat+fix(blizzskin): skin the BNet friend online/offline toast and fix a taint issue#1915
EllesmereGaming merged 2 commits into
EllesmereGaming:mainfrom
JuJuFX-dev:feature/bnet-toast-skin

Conversation

@JuJuFX-dev

Copy link
Copy Markdown
Contributor

What does this PR do?

Adds a Blizzard window skin for the Battle.net toast -- the popup that appears when a friend comes online or goes offline, and for broadcasts and club invites. It was the last visible popup with no EllesmereUI skin, still carrying its gold BACKDROP_TOAST_12_12 frame and Blizzard's default font while every comparable element (loot toasts, loot rolls, group invites, ready check) already runs through the window skin engine.

It appears as a new "Friend Notifications" card under Blizz UI Enhanced > Blizzard Window Skins with the usual EllesmereUI / Modern / Blizz Default choice. Existing accounts do not simply get it switched on: a new style-seed batch gives the toast whichever style the user already runs most of their windows with, "off" included.

The skin is chrome only -- house shell and border in place of the backdrop, house close button, the UI font on the four text lines, and a house panel on the hover tooltip that a truncated broadcast shows. Text colors stay Blizzard's, since ShowToast sets them per toast type. The toast-type icon is left native: it is a SetTexCoord crop out of one sheet, re-picked per type, so squaring it would overwrite those coordinates. The flair glow is cleared rather than alpha'd out, because it carries its own alpha animation that would otherwise animate straight over the write. Position is untouched and stays with the existing Unlock Mode element in the chat module.

Also in this PR: a taint fix that reaches every skinned window

WSkin.Shell kept its backdrop crop current with hooksecurefunc(frame, "SetSize"/"SetWidth"/"SetHeight", ...), which assigns a wrapper onto the Blizzard frame's own table -- a field write that Blizzard then reads back from its own code, against the rule the window engine's own header states. That is not academic for this window: BNToastMixin:ShowToast calls SetHeight immediately before showing the alert, and BNToastMixin:OnClick runs ChatFrameUtil.SendBNetTell(accountInfo.accountName) -- the same chain, with a secret string in it. It is the hazard the chat module already documents for SetPoint on this very frame.

All three hooks are replaced by one HookScript("OnSizeChanged"), which is C-side and writes nothing, and which additionally fires for anchor-driven resizes the setter hooks never saw. The Character Sheet, Inspect Sheet and Group Finder carry their own copy of that shell code and adopt it via WSkin.AdoptShell, so they are converted in the same way -- PVEFrame being the most taint-sensitive of the three. Those three copies were also missing the engine's issecretvalue test, and the zero check they run instead is itself a comparison that throws on a secret size; since the switch widens when that function runs, the guard is added there too. After this, no shell code hooks a Blizzard frame's size setters.

How was it tested?

Tested in game on live.

Screenshots

grafik friend request offline online

Checklist

  • New settings default OFF (no behavior change without opt-in) -- N/A: the new key follows the existing window-skin convention, where an absent value means enabled. Accounts that already have window skins do not get an unasked-for change, because the style-seed batch gives the new key whatever style the majority of their windows already use, including Blizz Default.
  • Zero cost while disabled: no events registered, no polling, no hooks doing work, no frames built
  • Cheap while enabled: event-driven (no polling, no timer-based logic, no per-frame allocations)
  • No writes onto Blizzard-owned frames (weak-table pattern used); HookScript/hooksecurefunc only, never SetScript on Blizzard frames
  • Tested in-game on live; no version gates or pre-Midnight APIs added

BNToastFrame was the last visible popup with no EUI skin, still carrying its
gold BACKDROP_TOAST_12_12 frame and Blizzard's font while every comparable
element (loot toasts, loot rolls, group invites, ready check) already runs
through the window skin engine.

New window pack "bnettoast", wired the usual six ways: enable key
reskinBNetToast, its own style-seed batch so existing accounts inherit their
majority style, an options card under Blizzard Window Skins, a reset entry and
the profile allowlist. Chrome only: shell, border, close button, house font on
the four text lines, house panel on the broadcast tooltip. The toast-type icon
stays native, since it is a SetTexCoord crop out of one sheet that
WSkin.SquareIcon would overwrite, and the flair glow is cleared rather than
alpha'd because it carries its own alpha animation.

WSkin.Shell no longer hooks SetSize/SetWidth/SetHeight with hooksecurefunc.
That form is a field write onto a Blizzard frame whose field Blizzard reads
back, and BNToastMixin:ShowToast calls SetHeight in the very chain whose
OnClick opens a Battle.net whisper - the hazard EllesmereUIChat already
documents for SetPoint on this frame. A HookScript("OnSizeChanged") replaces
all three, which also covers anchor-driven resizes the setter hooks never saw.
The Character Sheet, Inspect Sheet and Group Finder build their own shell and
adopt it through WSkin.AdoptShell rather than going through WSkin.Shell, so the
window engine's conversion did not reach the copy of UpdateBgTexCoords each of
them carries. All three still hooked SetSize/SetWidth/SetHeight with
hooksecurefunc, which is the field write onto a Blizzard frame the engine just
stopped doing. PVEFrame is the most taint-sensitive of the three.

The same three copies were also missing the engine's secrecy test, and the zero
check they run instead is itself a comparison that throws on a secret size.
Switching to OnSizeChanged widens when that function runs, so the guard is added
here rather than left for later.
@EllesmereGaming
EllesmereGaming merged commit 9e8eea2 into EllesmereGaming:main Sep 2, 2026
1 check passed
@JuJuFX-dev
JuJuFX-dev deleted the feature/bnet-toast-skin branch September 2, 2026 17:25
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.

2 participants