Skip to content

fix(blizzskin): anchor stand-in tooltips like the global GameTooltip - #1253

Open
paulbuechner wants to merge 1 commit into
EllesmereGaming:mainfrom
paulbuechner:fix/blizzskin-anchor-stand-in-tooltips
Open

fix(blizzskin): anchor stand-in tooltips like the global GameTooltip#1253
paulbuechner wants to merge 1 commit into
EllesmereGaming:mainfrom
paulbuechner:fix/blizzskin-anchor-stand-in-tooltips

Conversation

@paulbuechner

Copy link
Copy Markdown

DISCLAIMER: AI was used to create this PR (Claude Fable 5 Max)

If "overwriting" other AddOns Tooltips relying on Blizzard's HUD-Tooltip isn't planned, you can close this PR right away.

What does this PR do?

Makes the tooltip anchor settings apply to addon tooltips that stand in for
GameTooltip. Today those tooltips ignore the anchor box and sit at Blizzard's
default bottom-right container while everything else in the game obeys the user's
setting. OPie's ring slice tooltips are the case I hit; the fix is generic.

All three anchor features (cursor anchor, fixed position, growth direction) open
their GameTooltip_SetDefaultAnchor post-hook with:

if tooltip ~= GameTooltip then return end

That refuses anything which is not literally _G.GameTooltip, and some addons
cannot use the global one. A caller driving secure frames from insecure code
taints the global tooltip by touching it, so it builds its own
GameTooltipTemplate frame instead and flags it LIKE_GLOBAL_GAMETOOLTIP, the
established way of asking to be treated as the real thing. OPie does exactly this
(Libs/NotGameTooltip.lua):

tip.LIKE_GLOBAL_GAMETOOLTIP = true
-- External addons: please treat this as you would treat _G.GameTooltip

These stand-ins are not going off on their own: they still anchor through
GameTooltip_SetDefaultAnchor, so our hook does fire for them. It just declines
on the first line, and the tooltip keeps whatever Blizzard's default anchoring
gave it.

TooltipIsGlobalLike accepts the global tooltip or any frame carrying the flag,
and is used for the anchor decision in those three places.

The armed-state bookkeeping deliberately stays on the global tooltip only.
_fixedArmed and _growthDefaultAnchored gate SetPoint enforcement hooked onto
GameTooltip's own setters, so they can only ever describe one tooltip; arming
them for a stand-in would let a later GameTooltip:SetPoint be enforced against
state belonging to a different frame. A stand-in gets the one-shot anchor at
default-anchor time, which is all it needs, since that enforcement exists for
Blizzard's container re-anchoring and Blizzard does not manage third-party frames.

Left on strict identity: _repointTooltipAtCursor (only ever called by our own
frames with the global tooltip), the FadeOut and SetPoint/SetOwner hooks
(bound to the GameTooltip object itself), and the Show Tooltips suppression
block, which reparents into a hidden host and is a visibility feature rather than
an anchor one.

Ordering is unchanged and still correct: the fixed-anchor hook is registered
before the growth-direction hook, so a stand-in is positioned and then has its
growth corner forced, exactly as the global tooltip is.

How was it tested?

Live retail, Interface: 120001, against OPie 8.6.3.

  • Before: with the fixed HUD anchor set, OPie ring slice tooltips appeared at the
    bottom-right default container, ignoring the anchor box.
  • After: ring slice tooltips land on the anchor box like every other tooltip.
  • Also checked with the cursor anchor mode and with growth direction set to up
    and to down, since all three shared the same identity check.
  • Regular tooltips (units, action buttons, bags, items) unchanged in all modes,
    including the case the strict check was protecting: explicitly anchored
    tooltips from other addons still keep their own anchors.

Screenshots

Checklist

  • New settings default OFF (no behavior change without opt-in) - N/A, no new settings; this makes existing settings apply where they already should
  • Zero cost while disabled: no events registered, no polling, no hooks doing work, no frames built - N/A, nothing added to disable; no new hooks, events or frames
  • Cheap while enabled: event-driven (no polling, no timer-based logic, no per-frame allocations) - one extra table read on a path that already ran
  • No writes onto Blizzard-owned frames (weak-table pattern used); HookScript/hooksecurefunc only, never SetScript on Blizzard frames - unchanged; still hooksecurefunc only, and the tooltip is unprotected with its content never touched
  • Tested in-game, works on live retail; no load errors on the 12.1 PTR client

The three tooltip anchor features (cursor anchor, fixed position, growth
direction) all open their GameTooltip_SetDefaultAnchor post-hook with

    if tooltip ~= GameTooltip then return end

That refuses tooltips which are not literally _G.GameTooltip, and some addons
cannot use the global one. A caller driving secure frames from insecure code
taints the global tooltip by touching it, so it builds its own
GameTooltipTemplate frame instead and flags it LIKE_GLOBAL_GAMETOOLTIP, which
is the established way of asking to be treated as the real thing. OPie does
exactly this for its ring slices (Libs/NotGameTooltip.lua):

    tip.LIKE_GLOBAL_GAMETOOLTIP = true
    -- External addons: please treat this as you would treat _G.GameTooltip

Those stand-ins are not going off on their own. They still anchor through
GameTooltip_SetDefaultAnchor, so our hook does fire for them; it just declines
on the first line. The tooltip therefore keeps whatever Blizzard's default
anchoring gave it and sits at the bottom-right container while every other
tooltip in the game obeys the user's anchor box.

TooltipIsGlobalLike accepts the global tooltip or any frame carrying the flag,
and is used for the anchor decision in those three places.

The armed-state bookkeeping deliberately stays on the global tooltip only.
_fixedArmed and _growthDefaultAnchored gate SetPoint enforcement that is hooked
onto GameTooltip's own setters, so they can only ever describe one tooltip;
arming them for a stand-in would let a later GameTooltip:SetPoint be enforced
against state belonging to a different frame. A stand-in gets the one-shot
anchor at default-anchor time, which is all it needs, since that enforcement
exists for Blizzard's container re-anchoring and Blizzard does not manage
third-party frames.

Left on strict identity: _repointTooltipAtCursor (only ever called by our own
frames with the global tooltip), the FadeOut and SetPoint/SetOwner hooks (bound
to the GameTooltip object itself), and the Show Tooltips suppression block,
which reparents into a hidden host and is a visibility feature rather than an
anchor one.

No cost when no stand-in exists: one extra table read on a path that already
ran, and nothing new is hooked, registered or created.
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.

1 participant