local parent, ns = ... local oUF = ns.oUF local Private = oUF.Private local argcheck = Private.argcheck local error = Private.error local frame_metatable = Private.frame_metatable local tinsert, tremove = table.insert, table.remove -- Events local RegisterEvent, UnregisterEvent, IsEventRegistered do local eventFrame = CreateFrame("Frame") local registry = {} local framesForUnit = {} local alternativeUnits = { ['player'] = 'vehicle', ['pet'] = 'player', ['party1'] = 'partypet1', ['party2'] = 'partypet2', ['party3'] = 'partypet3', ['party4'] = 'partypet4', } local RegisterFrameForUnit = function(frame, unit) if not unit then return end if framesForUnit[unit] then framesForUnit[unit][frame] = true else framesForUnit[unit] = { [frame] = true } end end local UnregisterFrameForUnit = function(frame, unit) if not unit then return end local frames = framesForUnit[unit] if frames and frames[frame] then frames[frame] = nil if not next(frames) then framesForUnit[unit] = nil end end end Private.UpdateUnits = function(frame, unit, realUnit) if unit == realUnit then realUnit = nil end if frame.unit ~= unit or frame.realUnit ~= realUnit then if not frame:GetScript('OnUpdate') then UnregisterFrameForUnit(frame, frame.unit) UnregisterFrameForUnit(frame, frame.realUnit) RegisterFrameForUnit(frame, unit) RegisterFrameForUnit(frame, realUnit) end frame.alternativeUnit = alternativeUnits[unit] frame.unit = unit frame.realUnit = realUnit frame.id = unit:match'^.-(%d+)' return true end end -- Holds true for every event, where the first (unit) argument should be ignored. local sharedUnitEvents = { UNIT_ENTERED_VEHICLE = true, UNIT_EXITED_VEHICLE = true, UNIT_PET = true, } eventFrame:SetScript('OnEvent', function(_, event, arg1, ...) local listeners = registry[event] if arg1 and not sharedUnitEvents[event] then local frames = framesForUnit[arg1] if frames then for frame in next, frames do if listeners[frame] and frame:IsVisible() then frame[event](frame, event, arg1, ...) end end end else for frame in next, listeners do if frame:IsVisible() then frame[event](frame, event, arg1, ...) end end end end) function RegisterEvent(self, event, unitless) if(unitless) then sharedUnitEvents[event] = true end if not registry[event] then registry[event] = { [self] = true } eventFrame:RegisterEvent(event) else registry[event][self] = true end end function UnregisterEvent(self, event) if registry[event] then registry[event][self] = nil if not next(registry[event]) then registry[event] = nil eventFrame:UnregisterEvent(event) end end end function IsEventRegistered(self, event) return registry[event] and registry[event][self] end end local event_metatable = { __call = function(funcs, self, ...) for _, func in next, funcs do func(self, ...) end end, } function frame_metatable.__index:RegisterEvent(event, func, unitless) -- Block OnUpdate polled frames from registering events. if(self.__eventless) then return end argcheck(event, 2, 'string') if(type(func) == 'string' and type(self[func]) == 'function') then func = self[func] end local curev = self[event] local kind = type(curev) if(curev and func) then if(kind == 'function' and curev ~= func) then self[event] = setmetatable({curev, func}, event_metatable) elseif(kind == 'table') then for _, infunc in next, curev do if(infunc == func) then return end end tinsert(curev, func) end elseif(IsEventRegistered(self, event)) then return else if(type(func) == 'function') then self[event] = func elseif(not self[event]) then return error("Style [%s] attempted to register event [%s] on unit [%s] with a handler that doesn't exist.", self.style, event, self.unit or 'unknown') end RegisterEvent(self, event, unitless) end end function frame_metatable.__index:UnregisterEvent(event, func) argcheck(event, 2, 'string') local curev = self[event] if(type(curev) == 'table' and func) then for k, infunc in next, curev do if(infunc == func) then tremove(curev, k) local n = #curev if(n == 1) then local _, handler = next(curev) self[event] = handler elseif(n == 0) then UnregisterEvent(self, event) end break end end elseif(curev == func) then self[event] = nil UnregisterEvent(self, event) end end function frame_metatable.__index:IsEventRegistered(event) return IsEventRegistered(self, event) end