fix(actionbars): only reveal empty slots when the drag can actually pick up - #1208
Merged
EllesmereGaming merged 3 commits intoAug 7, 2026
Merged
Conversation
…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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
OnDragStarton every button and set the transient grid bit unconditionally:OnDragStartfires on the gesture, not on a successful pickup. Blizzard's ownActionBarActionButtonMixin:OnDragStartchecksSettings.GetValue("lockActionBars")andIsModifiedClick("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:
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
>= 2rather 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.
IsModifiedClickis available in the restricted environment: it is inDIRECT_MACRO_CONDITIONAL_NAMES, copied intoRESTRICTED_FUNCTIONS_SCOPEatBlizzard_RestrictedAddOnEnvironment/RestrictedEnvironment.lua:97, andSecureHandlers.luaships in that same addon.The lock setting cannot be read in there, so it rides in as an
eab-barslockedattribute on the controller, synced at setup, onPLAYER_ENTERING_WORLD, and onCVAR_UPDATE(name-filtered) andPLAYER_REGEN_ENABLEDfor 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
Settings.GetValuereturning nil was accepted as "not locked" because only the pcall status was checked, and the seed runs insideFinishSetup, which can execute before that setting is registered.SetAttributere-runs the controller's_onattributechangedsnippet. That snippet only acts onname == "flush", so the new attribute is otherwise inert there.luac -pclean.