Skip to content

fix(actionbars): only reveal empty slots when the drag can actually pick up - #1208

Merged
EllesmereGaming merged 3 commits into
EllesmereGaming:mainfrom
dfrisone:AB-Still-Shows-Empty-Slots
Aug 7, 2026
Merged

fix(actionbars): only reveal empty slots when the drag can actually pick up#1208
EllesmereGaming merged 3 commits into
EllesmereGaming:mainfrom
dfrisone:AB-Still-Shows-Empty-Slots

Conversation

@dfrisone

@dfrisone dfrisone commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

The report

Reported by @WildKab on 8.7.6, a follow-on to the empty-slot fix in that release. With action bars locked, left-click-dragging a spell lights up the empty-slot boxes on every bar, and they stay there for 5-15 seconds, or until the spell is used, or until it is actually moved with shift.

Cause

The combat-drag belt wraps OnDragStart on every button and set the transient grid bit unconditionally:

ActionButtonController:WrapScript(btn, "OnDragStart", [[
    control:RunAttribute("SetShowGrid", true, 2)
]])

OnDragStart fires on the gesture, not on a successful pickup. Blizzard's own ActionBarActionButtonMixin:OnDragStart checks Settings.GetValue("lockActionBars") and IsModifiedClick("PICKUPACTION") and no-ops when the bars are locked without the modifier.

So a plain left-drag over a locked bar turned the grid on with no pickup behind it. With no pickup there is no ACTIONBAR_HIDEGRID, so the wrapper's assumption that "the matching grid-off arrives via the monitor or, failing that, the regen apply" never came true on this path.

That accounts for all three ways the reporter saw it clear:

  • Shift-drag is a real pickup, so it produces a real SHOWGRID/HIDEGRID pair.
  • Using the spell forces a repaint.
  • 5-15 seconds is however long until some unrelated grid event lands.

This is not a regression of the 8.7.6 fix. That one was about the showgrid reason bitmask, where bit 1 is Blizzard's own CVAR reason so the transient test had to become >= 2 rather than > 0. Same subsystem, different cause.

Fix

Mirror Blizzard's own condition inside the snippet, so the reveal only fires when the drag will actually pick the action up.

IsModifiedClick is available in the restricted environment: it is in DIRECT_MACRO_CONDITIONAL_NAMES, copied into RESTRICTED_FUNCTIONS_SCOPE at Blizzard_RestrictedAddOnEnvironment/RestrictedEnvironment.lua:97, and SecureHandlers.lua ships in that same addon.

The lock setting cannot be read in there, so it rides in as an eab-barslocked attribute on the controller, synced at setup, on PLAYER_ENTERING_WORLD, and on CVAR_UPDATE (name-filtered) and PLAYER_REGEN_ENABLED for a lock toggled during combat.

Fails open. An unseeded or stale attribute reads as "not locked" and you get the previous unconditional reveal, so the combat-drag fix cannot regress into being worse than today.

Notes for review

  • Third commit is a self-review pass. It fixes a real seed-path defect: Settings.GetValue returning nil was accepted as "not locked" because only the pcall status was checked, and the seed runs inside FinishSetup, which can execute before that setting is registered.
  • The write to the controller attribute is guarded on change, since SetAttribute re-runs the controller's _onattributechanged snippet. That snippet only acts on name == "flush", so the new attribute is otherwise inert there.
  • No new chunk-level locals; this file is at Lua 5.1's 200-local cap.
  • luac -p clean.
Cracking Up Lol GIF by MOODMAN

…ick up

Reported by @WildKab on 8.7.6: with bars locked, left-click-dragging a spell
lights the empty-slot boxes on every bar, and they stay for 5-15 seconds or
until the spell is used or actually moved with shift.

The combat-drag belt wraps OnDragStart on every button and unconditionally
sets the transient grid bit. But OnDragStart fires on the GESTURE, not on a
successful pickup: Blizzard's own handler checks lockActionBars and the
PICKUPACTION modifier, and no-ops when the bars are locked and no modifier is
held. So a plain left-drag over a locked bar turned the grid on with no
pickup behind it, and with no pickup there is no ACTIONBAR_HIDEGRID to turn
it back off. The wrapper's comment assumed "the matching grid-off arrives via
the monitor or the regen apply", and on this path neither does.

That accounts for all three ways the reporter saw it clear: a shift-drag is a
real pickup so it produces a real SHOWGRID/HIDEGRID pair, using the spell
forces a repaint, and 5-15 seconds is however long until any unrelated grid
event lands.

Mirror Blizzard's own condition in the snippet. IsModifiedClick is whitelisted
in the restricted environment (RestrictedEnvironment.lua), and the lock
setting rides in as an attribute on the controller, synced at setup, on
PLAYER_ENTERING_WORLD/SPELLS_CHANGED, and on CVAR_UPDATE. An unseeded
attribute reads nil and falls through to the old unconditional reveal, so the
combat-drag fix cannot regress if the sync has not run yet.
Three edges on the previous commit, none of them behavioural but all of them
worth not shipping:

CVAR_UPDATE fires for every cvar and is a firehose at login, so the handler
now filters on arg1 == "lockActionBars" instead of re-syncing on all of them.

The SetAttribute is guarded on change. Writing it re-runs the controller's
_onattributechanged snippet, which is restricted-environment work we have no
reason to repeat for an unchanged value. Matches the guard SetShowGridInsecure
already uses.

A lock toggled during combat deferred with nothing to flush it, so the sync
now also runs on PLAYER_REGEN_ENABLED. Worst case before this was a stale
value that self-healed on the next zone, but it is one line to close.
Self-review before opening the PR turned up one real defect and three
cleanups.

The defect: Settings.GetValue returning nil was accepted as "not locked",
because only the pcall status was checked. The seed call runs inside
FinishSetup, which can execute before that setting is registered, so a user
with locked bars could seed as unlocked and keep the exact bug this branch
fixes until the next PLAYER_ENTERING_WORLD. Now the CVar fallback runs unless
Settings returns a non-nil value.

The rest: drop the _eabApplyDeferred write, since unlike the widget-writing
guards that share that line there is nothing to re-apply and regen re-syncs
this directly; stop re-reading the lock on SPELLS_CHANGED, which has nothing
to do with it; and correct the pre-existing comment above the wrapper, which
still asserted the grid-off always arrives, the assumption that caused the
bug.
@EllesmereGaming
EllesmereGaming merged commit 0f36fc5 into EllesmereGaming:main Aug 7, 2026
1 check 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.

2 participants