annotate Libs/LibSharedMedia-3.0/CallbackHandler-1.0/CallbackHandler-1.0.lua @ 3:c6f0976069c7

Default value for the welcome / bye notification is now set to false The mailframe checkbox now primarily toggles the mail opening, however if you hold shift you can still disable the entire addon Now properly removes QuickAuction?s mail count Now tracks when a mail lost all attachments rather than it being deleted in order to continue processing the next item (mail sent by players containing text should now work properly). This should also be good for a nice speed increase. Added a variable called ?busy? to the MailOpener object indicating whether or not Mail Opener is currently working. Other addons (or macros) can retrieve it with ?LibStub("AceAddon-3.0"):GetAddon("MailOpener").busy? A mail refresh from the Postal service should no longer occur while mail is being opened but will happen instantly afterwards. Postal?s module toggling will now be handled by Postal itself. Added a short summary to the top of all modules for other developers. The time remaining until next mail box refresh should be displayed for as long as Mail Opener can be sure.
author Zerotorescue
date Tue, 07 Sep 2010 17:46:27 +0200
parents 823e33465b6e
children
rev   line source
Zerotorescue@0 1 --[[ $Id: CallbackHandler-1.0.lua 60548 2008-02-07 11:04:06Z nevcairiel $ ]]
Zerotorescue@0 2 local MAJOR, MINOR = "CallbackHandler-1.0", 3
Zerotorescue@0 3 local CallbackHandler = LibStub:NewLibrary(MAJOR, MINOR)
Zerotorescue@0 4
Zerotorescue@0 5 if not CallbackHandler then return end -- No upgrade needed
Zerotorescue@0 6
Zerotorescue@0 7 local meta = {__index = function(tbl, key) tbl[key] = {} return tbl[key] end}
Zerotorescue@0 8
Zerotorescue@0 9 local type = type
Zerotorescue@0 10 local pcall = pcall
Zerotorescue@0 11 local pairs = pairs
Zerotorescue@0 12 local assert = assert
Zerotorescue@0 13 local concat = table.concat
Zerotorescue@0 14 local loadstring = loadstring
Zerotorescue@0 15 local next = next
Zerotorescue@0 16 local select = select
Zerotorescue@0 17 local type = type
Zerotorescue@0 18 local xpcall = xpcall
Zerotorescue@0 19
Zerotorescue@0 20 local function errorhandler(err)
Zerotorescue@0 21 return geterrorhandler()(err)
Zerotorescue@0 22 end
Zerotorescue@0 23
Zerotorescue@0 24 local function CreateDispatcher(argCount)
Zerotorescue@0 25 local code = [[
Zerotorescue@0 26 local next, xpcall, eh = ...
Zerotorescue@0 27
Zerotorescue@0 28 local method, ARGS
Zerotorescue@0 29 local function call() method(ARGS) end
Zerotorescue@0 30
Zerotorescue@0 31 local function dispatch(handlers, ...)
Zerotorescue@0 32 local index
Zerotorescue@0 33 index, method = next(handlers)
Zerotorescue@0 34 if not method then return end
Zerotorescue@0 35 local OLD_ARGS = ARGS
Zerotorescue@0 36 ARGS = ...
Zerotorescue@0 37 repeat
Zerotorescue@0 38 xpcall(call, eh)
Zerotorescue@0 39 index, method = next(handlers, index)
Zerotorescue@0 40 until not method
Zerotorescue@0 41 ARGS = OLD_ARGS
Zerotorescue@0 42 end
Zerotorescue@0 43
Zerotorescue@0 44 return dispatch
Zerotorescue@0 45 ]]
Zerotorescue@0 46
Zerotorescue@0 47 local ARGS, OLD_ARGS = {}, {}
Zerotorescue@0 48 for i = 1, argCount do ARGS[i], OLD_ARGS[i] = "arg"..i, "old_arg"..i end
Zerotorescue@0 49 code = code:gsub("OLD_ARGS", concat(OLD_ARGS, ", ")):gsub("ARGS", concat(ARGS, ", "))
Zerotorescue@0 50 return assert(loadstring(code, "safecall Dispatcher["..argCount.."]"))(next, xpcall, errorhandler)
Zerotorescue@0 51 end
Zerotorescue@0 52
Zerotorescue@0 53 local Dispatchers = setmetatable({}, {__index=function(self, argCount)
Zerotorescue@0 54 local dispatcher = CreateDispatcher(argCount)
Zerotorescue@0 55 rawset(self, argCount, dispatcher)
Zerotorescue@0 56 return dispatcher
Zerotorescue@0 57 end})
Zerotorescue@0 58
Zerotorescue@0 59 --------------------------------------------------------------------------
Zerotorescue@0 60 -- CallbackHandler:New
Zerotorescue@0 61 --
Zerotorescue@0 62 -- target - target object to embed public APIs in
Zerotorescue@0 63 -- RegisterName - name of the callback registration API, default "RegisterCallback"
Zerotorescue@0 64 -- UnregisterName - name of the callback unregistration API, default "UnregisterCallback"
Zerotorescue@0 65 -- UnregisterAllName - name of the API to unregister all callbacks, default "UnregisterAllCallbacks". false == don't publish this API.
Zerotorescue@0 66
Zerotorescue@0 67 function CallbackHandler:New(target, RegisterName, UnregisterName, UnregisterAllName, OnUsed, OnUnused)
Zerotorescue@0 68 -- TODO: Remove this after beta has gone out
Zerotorescue@0 69 assert(not OnUsed and not OnUnused, "ACE-80: OnUsed/OnUnused are deprecated. Callbacks are now done to registry.OnUsed and registry.OnUnused")
Zerotorescue@0 70
Zerotorescue@0 71 RegisterName = RegisterName or "RegisterCallback"
Zerotorescue@0 72 UnregisterName = UnregisterName or "UnregisterCallback"
Zerotorescue@0 73 if UnregisterAllName==nil then -- false is used to indicate "don't want this method"
Zerotorescue@0 74 UnregisterAllName = "UnregisterAllCallbacks"
Zerotorescue@0 75 end
Zerotorescue@0 76
Zerotorescue@0 77 -- we declare all objects and exported APIs inside this closure to quickly gain access
Zerotorescue@0 78 -- to e.g. function names, the "target" parameter, etc
Zerotorescue@0 79
Zerotorescue@0 80
Zerotorescue@0 81 -- Create the registry object
Zerotorescue@0 82 local events = setmetatable({}, meta)
Zerotorescue@0 83 local registry = { recurse=0, events=events }
Zerotorescue@0 84
Zerotorescue@0 85 -- registry:Fire() - fires the given event/message into the registry
Zerotorescue@0 86 function registry:Fire(eventname, ...)
Zerotorescue@0 87 if not rawget(events, eventname) or not next(events[eventname]) then return end
Zerotorescue@0 88 local oldrecurse = registry.recurse
Zerotorescue@0 89 registry.recurse = oldrecurse + 1
Zerotorescue@0 90
Zerotorescue@0 91 Dispatchers[select('#', ...) + 1](events[eventname], eventname, ...)
Zerotorescue@0 92
Zerotorescue@0 93 registry.recurse = oldrecurse
Zerotorescue@0 94
Zerotorescue@0 95 if registry.insertQueue and oldrecurse==0 then
Zerotorescue@0 96 -- Something in one of our callbacks wanted to register more callbacks; they got queued
Zerotorescue@0 97 for eventname,callbacks in pairs(registry.insertQueue) do
Zerotorescue@0 98 local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
Zerotorescue@0 99 for self,func in pairs(callbacks) do
Zerotorescue@0 100 events[eventname][self] = func
Zerotorescue@0 101 -- fire OnUsed callback?
Zerotorescue@0 102 if first and registry.OnUsed then
Zerotorescue@0 103 registry.OnUsed(registry, target, eventname)
Zerotorescue@0 104 first = nil
Zerotorescue@0 105 end
Zerotorescue@0 106 end
Zerotorescue@0 107 end
Zerotorescue@0 108 registry.insertQueue = nil
Zerotorescue@0 109 end
Zerotorescue@0 110 end
Zerotorescue@0 111
Zerotorescue@0 112 -- Registration of a callback, handles:
Zerotorescue@0 113 -- self["method"], leads to self["method"](self, ...)
Zerotorescue@0 114 -- self with function ref, leads to functionref(...)
Zerotorescue@0 115 -- "addonId" (instead of self) with function ref, leads to functionref(...)
Zerotorescue@0 116 -- all with an optional arg, which, if present, gets passed as first argument (after self if present)
Zerotorescue@0 117 target[RegisterName] = function(self, eventname, method, ... --[[actually just a single arg]])
Zerotorescue@0 118 if type(eventname) ~= "string" then
Zerotorescue@0 119 error("Usage: "..RegisterName.."(eventname, method[, arg]): 'eventname' - string expected.", 2)
Zerotorescue@0 120 end
Zerotorescue@0 121
Zerotorescue@0 122 method = method or eventname
Zerotorescue@0 123
Zerotorescue@0 124 local first = not rawget(events, eventname) or not next(events[eventname]) -- test for empty before. not test for one member after. that one member may have been overwritten.
Zerotorescue@0 125
Zerotorescue@0 126 if type(method) ~= "string" and type(method) ~= "function" then
Zerotorescue@0 127 error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - string or function expected.", 2)
Zerotorescue@0 128 end
Zerotorescue@0 129
Zerotorescue@0 130 local regfunc
Zerotorescue@0 131
Zerotorescue@0 132 if type(method) == "string" then
Zerotorescue@0 133 -- self["method"] calling style
Zerotorescue@0 134 if type(self) ~= "table" then
Zerotorescue@0 135 error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): self was not a table?", 2)
Zerotorescue@0 136 elseif self==target then
Zerotorescue@0 137 error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): do not use Library:"..RegisterName.."(), use your own 'self'", 2)
Zerotorescue@0 138 elseif type(self[method]) ~= "function" then
Zerotorescue@0 139 error("Usage: "..RegisterName.."(\"eventname\", \"methodname\"): 'methodname' - method '"..tostring(method).."' not found on self.", 2)
Zerotorescue@0 140 end
Zerotorescue@0 141
Zerotorescue@0 142 if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
Zerotorescue@0 143 local arg=select(1,...)
Zerotorescue@0 144 regfunc = function(...) self[method](self,arg,...) end
Zerotorescue@0 145 else
Zerotorescue@0 146 regfunc = function(...) self[method](self,...) end
Zerotorescue@0 147 end
Zerotorescue@0 148 else
Zerotorescue@0 149 -- function ref with self=object or self="addonId"
Zerotorescue@0 150 if type(self)~="table" and type(self)~="string" then
Zerotorescue@0 151 error("Usage: "..RegisterName.."(self or \"addonId\", eventname, method): 'self or addonId': table or string expected.", 2)
Zerotorescue@0 152 end
Zerotorescue@0 153
Zerotorescue@0 154 if select("#",...)>=1 then -- this is not the same as testing for arg==nil!
Zerotorescue@0 155 local arg=select(1,...)
Zerotorescue@0 156 regfunc = function(...) method(arg,...) end
Zerotorescue@0 157 else
Zerotorescue@0 158 regfunc = method
Zerotorescue@0 159 end
Zerotorescue@0 160 end
Zerotorescue@0 161
Zerotorescue@0 162
Zerotorescue@0 163 if events[eventname][self] or registry.recurse<1 then
Zerotorescue@0 164 -- if registry.recurse<1 then
Zerotorescue@0 165 -- we're overwriting an existing entry, or not currently recursing. just set it.
Zerotorescue@0 166 events[eventname][self] = regfunc
Zerotorescue@0 167 -- fire OnUsed callback?
Zerotorescue@0 168 if registry.OnUsed and first then
Zerotorescue@0 169 registry.OnUsed(registry, target, eventname)
Zerotorescue@0 170 end
Zerotorescue@0 171 else
Zerotorescue@0 172 -- we're currently processing a callback in this registry, so delay the registration of this new entry!
Zerotorescue@0 173 -- yes, we're a bit wasteful on garbage, but this is a fringe case, so we're picking low implementation overhead over garbage efficiency
Zerotorescue@0 174 registry.insertQueue = registry.insertQueue or setmetatable({},meta)
Zerotorescue@0 175 registry.insertQueue[eventname][self] = regfunc
Zerotorescue@0 176 end
Zerotorescue@0 177 end
Zerotorescue@0 178
Zerotorescue@0 179 -- Unregister a callback
Zerotorescue@0 180 target[UnregisterName] = function(self, eventname)
Zerotorescue@0 181 if not self or self==target then
Zerotorescue@0 182 error("Usage: "..UnregisterName.."(eventname): bad 'self'", 2)
Zerotorescue@0 183 end
Zerotorescue@0 184 if type(eventname) ~= "string" then
Zerotorescue@0 185 error("Usage: "..UnregisterName.."(eventname): 'eventname' - string expected.", 2)
Zerotorescue@0 186 end
Zerotorescue@0 187 if rawget(events, eventname) and events[eventname][self] then
Zerotorescue@0 188 events[eventname][self] = nil
Zerotorescue@0 189 -- Fire OnUnused callback?
Zerotorescue@0 190 if registry.OnUnused and not next(events[eventname]) then
Zerotorescue@0 191 registry.OnUnused(registry, target, eventname)
Zerotorescue@0 192 end
Zerotorescue@0 193 end
Zerotorescue@0 194 if registry.insertQueue and rawget(registry.insertQueue, eventname) and registry.insertQueue[eventname][self] then
Zerotorescue@0 195 registry.insertQueue[eventname][self] = nil
Zerotorescue@0 196 end
Zerotorescue@0 197 end
Zerotorescue@0 198
Zerotorescue@0 199 -- OPTIONAL: Unregister all callbacks for given selfs/addonIds
Zerotorescue@0 200 if UnregisterAllName then
Zerotorescue@0 201 target[UnregisterAllName] = function(...)
Zerotorescue@0 202 if select("#",...)<1 then
Zerotorescue@0 203 error("Usage: "..UnregisterAllName.."([whatFor]): missing 'self' or \"addonId\" to unregister events for.", 2)
Zerotorescue@0 204 end
Zerotorescue@0 205 if select("#",...)==1 and ...==target then
Zerotorescue@0 206 error("Usage: "..UnregisterAllName.."([whatFor]): supply a meaningful 'self' or \"addonId\"", 2)
Zerotorescue@0 207 end
Zerotorescue@0 208
Zerotorescue@0 209
Zerotorescue@0 210 for i=1,select("#",...) do
Zerotorescue@0 211 local self = select(i,...)
Zerotorescue@0 212 if registry.insertQueue then
Zerotorescue@0 213 for eventname, callbacks in pairs(registry.insertQueue) do
Zerotorescue@0 214 if callbacks[self] then
Zerotorescue@0 215 callbacks[self] = nil
Zerotorescue@0 216 end
Zerotorescue@0 217 end
Zerotorescue@0 218 end
Zerotorescue@0 219 for eventname, callbacks in pairs(events) do
Zerotorescue@0 220 if callbacks[self] then
Zerotorescue@0 221 callbacks[self] = nil
Zerotorescue@0 222 -- Fire OnUnused callback?
Zerotorescue@0 223 if registry.OnUnused and not next(callbacks) then
Zerotorescue@0 224 registry.OnUnused(registry, target, eventname)
Zerotorescue@0 225 end
Zerotorescue@0 226 end
Zerotorescue@0 227 end
Zerotorescue@0 228 end
Zerotorescue@0 229 end
Zerotorescue@0 230 end
Zerotorescue@0 231
Zerotorescue@0 232 return registry
Zerotorescue@0 233 end
Zerotorescue@0 234
Zerotorescue@0 235
Zerotorescue@0 236 -- CallbackHandler purposefully does NOT do explicit embedding. Nor does it
Zerotorescue@0 237 -- try to upgrade old implicit embeds since the system is selfcontained and
Zerotorescue@0 238 -- relies on closures to work.
Zerotorescue@0 239