comparison modules/FuBar_ReActionFu/lib/AceEvent-2.0/AceEvent-2.0.lua @ 28:21bcaf8215ff

- converted to Ace3 - rearranged file layout - configGUI menus not working right now
author Flick <flickerstreak@gmail.com>
date Mon, 17 Mar 2008 18:24:53 +0000
parents
children
comparison
equal deleted inserted replaced
27:f1e838841ce1 28:21bcaf8215ff
1 --[[
2 Name: AceEvent-2.0
3 Revision: $Rev: 49307 $
4 Developed by: The Ace Development Team (http://www.wowace.com/index.php/The_Ace_Development_Team)
5 Inspired By: Ace 1.x by Turan (turan@gryphon.com)
6 Website: http://www.wowace.com/
7 Documentation: http://www.wowace.com/index.php/AceEvent-2.0
8 SVN: http://svn.wowace.com/root/trunk/Ace2/AceEvent-2.0
9 Description: Mixin to allow for event handling, scheduling, and inter-addon
10 communication.
11 Dependencies: AceLibrary, AceOO-2.0
12 License: LGPL v2.1
13 ]]
14
15 local MAJOR_VERSION = "AceEvent-2.0"
16 local MINOR_VERSION = "$Revision: 49307 $"
17
18 if not AceLibrary then error(MAJOR_VERSION .. " requires AceLibrary") end
19 if not AceLibrary:IsNewVersion(MAJOR_VERSION, MINOR_VERSION) then return end
20
21 if not AceLibrary:HasInstance("AceOO-2.0") then error(MAJOR_VERSION .. " requires AceOO-2.0") end
22
23 local AceOO = AceLibrary:GetInstance("AceOO-2.0")
24 local Mixin = AceOO.Mixin
25 local AceEvent = Mixin {
26 "RegisterEvent",
27 "RegisterAllEvents",
28 "UnregisterEvent",
29 "UnregisterAllEvents",
30 "TriggerEvent",
31 "ScheduleEvent",
32 "ScheduleRepeatingEvent",
33 "CancelScheduledEvent",
34 "CancelAllScheduledEvents",
35 "IsEventRegistered",
36 "IsEventScheduled",
37 "RegisterBucketEvent",
38 "UnregisterBucketEvent",
39 "UnregisterAllBucketEvents",
40 "IsBucketEventRegistered",
41 "ScheduleLeaveCombatAction",
42 "CancelAllCombatSchedules",
43 }
44
45 local weakKey = {__mode="k"}
46
47 local FAKE_NIL
48 local RATE
49
50 local eventsWhichHappenOnce = {
51 PLAYER_LOGIN = true,
52 AceEvent_FullyInitialized = true,
53 VARIABLES_LOADED = true,
54 PLAYER_LOGOUT = true,
55 }
56 local next = next
57 local pairs = pairs
58 local pcall = pcall
59 local type = type
60 local GetTime = GetTime
61 local gcinfo = gcinfo
62 local unpack = unpack
63 local geterrorhandler = geterrorhandler
64
65 local build = GetBuildInfo()
66 local useTablesAsIDs = build:find("^2%.0%.") or build:find("^2%.1%.") or build:find("^0%.1%.")
67
68 local new, del
69 do
70 local cache = setmetatable({}, {__mode='k'})
71 function new(...)
72 local t = next(cache)
73 if t then
74 cache[t] = nil
75 for i = 1, select('#', ...) do
76 t[i] = select(i, ...)
77 end
78 return t
79 else
80 return { ... }
81 end
82 end
83 function del(t)
84 for k in pairs(t) do
85 t[k] = nil
86 end
87 cache[t] = true
88 return nil
89 end
90 end
91
92 local registeringFromAceEvent
93 --[[----------------------------------------------------------------------------------
94 Notes:
95 * Registers the addon with a Blizzard event or a custom AceEvent, which will cause the given method to be called when that is triggered.
96 Arguments:
97 string - name of the event to register
98 [optional] string or function - name of the method or function to call. Default: same name as "event".
99 [optional] boolean - whether to have method called only once. Default: false
100 ------------------------------------------------------------------------------------]]
101 function AceEvent:RegisterEvent(event, method, once)
102 AceEvent:argCheck(event, 2, "string")
103 if self == AceEvent and not registeringFromAceEvent then
104 AceEvent:argCheck(method, 3, "function")
105 self = method
106 else
107 AceEvent:argCheck(method, 3, "string", "function", "nil", "boolean", "number")
108 if type(method) == "boolean" or type(method) == "number" then
109 AceEvent:argCheck(once, 4, "nil")
110 once, method = method, event
111 end
112 end
113 AceEvent:argCheck(once, 4, "number", "boolean", "nil")
114 if eventsWhichHappenOnce[event] then
115 once = true
116 end
117 local throttleRate
118 if type(once) == "number" then
119 throttleRate, once = once
120 end
121 if not method then
122 method = event
123 end
124 if type(method) == "string" and type(self[method]) ~= "function" then
125 AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
126 else
127 assert(type(method) == "function" or type(method) == "string")
128 end
129
130 local AceEvent_registry = AceEvent.registry
131 if not AceEvent_registry[event] then
132 AceEvent_registry[event] = new()
133 AceEvent.frame:RegisterEvent(event)
134 end
135
136 local remember = true
137 if AceEvent_registry[event][self] then
138 remember = false
139 end
140 AceEvent_registry[event][self] = method
141
142 local AceEvent_onceRegistry = AceEvent.onceRegistry
143 if once then
144 if not AceEvent_onceRegistry then
145 AceEvent.onceRegistry = {}
146 AceEvent_onceRegistry = AceEvent.onceRegistry
147 end
148 if not AceEvent_onceRegistry[event] then
149 AceEvent_onceRegistry[event] = new()
150 end
151 AceEvent_onceRegistry[event][self] = true
152 else
153 if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
154 AceEvent_onceRegistry[event][self] = nil
155 if not next(AceEvent_onceRegistry[event]) then
156 AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
157 end
158 end
159 end
160
161 local AceEvent_throttleRegistry = AceEvent.throttleRegistry
162 if throttleRate then
163 if not AceEvent_throttleRegistry then
164 AceEvent.throttleRegistry = {}
165 AceEvent_throttleRegistry = AceEvent.throttleRegistry
166 end
167 if not AceEvent_throttleRegistry[event] then
168 AceEvent_throttleRegistry[event] = new()
169 end
170 if AceEvent_throttleRegistry[event][self] then
171 AceEvent_throttleRegistry[event][self] = nil
172 end
173 AceEvent_throttleRegistry[event][self] = setmetatable(new(), weakKey)
174 local t = AceEvent_throttleRegistry[event][self]
175 t[RATE] = throttleRate
176 else
177 if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] then
178 if AceEvent_throttleRegistry[event][self] then
179 AceEvent_throttleRegistry[event][self] = nil
180 end
181 if not next(AceEvent_throttleRegistry[event]) then
182 AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
183 end
184 end
185 end
186
187 if remember then
188 AceEvent:TriggerEvent("AceEvent_EventRegistered", self, event)
189 end
190 end
191
192 local ALL_EVENTS
193
194 --[[----------------------------------------------------------------------------------
195 Notes:
196 * Registers all events to the given method
197 * To access the current event, check AceEvent.currentEvent
198 * To access the current event's unique identifier, check AceEvent.currentEventUID
199 * This is only for debugging purposes.
200 Arguments:
201 [optional] string or function - name of the method or function to call. Default: same name as "event".
202 ------------------------------------------------------------------------------------]]
203 function AceEvent:RegisterAllEvents(method)
204 if self == AceEvent then
205 AceEvent:argCheck(method, 1, "function")
206 self = method
207 else
208 AceEvent:argCheck(method, 1, "string", "function")
209 if type(method) == "string" and type(self[method]) ~= "function" then
210 AceEvent:error("Cannot register all events to method %q, it does not exist", method)
211 end
212 end
213
214 local AceEvent_registry = AceEvent.registry
215 if not AceEvent_registry[ALL_EVENTS] then
216 AceEvent_registry[ALL_EVENTS] = new()
217 AceEvent.frame:RegisterAllEvents()
218 end
219
220 local remember = not AceEvent_registry[ALL_EVENTS][self]
221 AceEvent_registry[ALL_EVENTS][self] = method
222 if remember then
223 AceEvent:TriggerEvent("AceEvent_EventRegistered", self, "all")
224 end
225 end
226
227 --[[----------------------------------------------------------------------------------
228 Notes:
229 * Trigger a custom AceEvent.
230 * This should never be called to simulate fake Blizzard events.
231 * Custom events should be in the form of AddonName_SpecificEvent
232 Arguments:
233 string - name of the event
234 tuple - list of arguments to pass along
235 ------------------------------------------------------------------------------------]]
236 function AceEvent:TriggerEvent(event, ...)
237 if type(event) ~= "string" then
238 DEFAULT_CHAT_FRAME:AddMessage(debugstack())
239 end
240 AceEvent:argCheck(event, 2, "string")
241 local AceEvent_registry = AceEvent.registry
242 if (not AceEvent_registry[event] or not next(AceEvent_registry[event])) and (not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS])) then
243 return
244 end
245 local lastEvent = AceEvent.currentEvent
246 AceEvent.currentEvent = event
247 local lastEventUID = AceEvent.currentEventUID
248 local uid = AceEvent.UID_NUM + 1
249 AceEvent.UID_NUM = uid
250 AceEvent.currentEventUID = uid
251
252 local tmp = new()
253
254 local AceEvent_onceRegistry = AceEvent.onceRegistry
255 if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
256 for obj, method in pairs(AceEvent_onceRegistry[event]) do
257 tmp[obj] = AceEvent_registry[event] and AceEvent_registry[event][obj] or nil
258 end
259 local obj = next(tmp)
260 while obj do
261 local method = tmp[obj]
262 AceEvent.UnregisterEvent(obj, event)
263 if type(method) == "string" then
264 local obj_method = obj[method]
265 if obj_method then
266 local success, err = pcall(obj_method, obj, ...)
267 if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
268 end
269 elseif method then -- function
270 local success, err = pcall(method, ...)
271 if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
272 end
273 tmp[obj] = nil
274 obj = next(tmp)
275 end
276 end
277
278 local AceEvent_throttleRegistry = AceEvent.throttleRegistry
279 local throttleTable = AceEvent_throttleRegistry and AceEvent_throttleRegistry[event]
280 if AceEvent_registry[event] then
281 for obj, method in pairs(AceEvent_registry[event]) do
282 tmp[obj] = method
283 end
284 local obj = next(tmp)
285 while obj do
286 local method = tmp[obj]
287 local continue = false
288 if throttleTable and throttleTable[obj] then
289 local a1 = ...
290 if a1 == nil then
291 a1 = FAKE_NIL
292 end
293 if not throttleTable[obj][a1] or GetTime() - throttleTable[obj][a1] >= throttleTable[obj][RATE] then
294 throttleTable[obj][a1] = GetTime()
295 else
296 continue = true
297 end
298 end
299 if not continue then
300 if type(method) == "string" then
301 local obj_method = obj[method]
302 if obj_method then
303 local success, err = pcall(obj_method, obj, ...)
304 if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
305 end
306 elseif method then -- function
307 local success, err = pcall(method, ...)
308 if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
309 end
310 end
311 tmp[obj] = nil
312 obj = next(tmp)
313 end
314 end
315 if AceEvent_registry[ALL_EVENTS] then
316 for obj, method in pairs(AceEvent_registry[ALL_EVENTS]) do
317 tmp[obj] = method
318 end
319 local obj = next(tmp)
320 while obj do
321 local method = tmp[obj]
322 if type(method) == "string" then
323 local obj_method = obj[method]
324 if obj_method then
325 local success, err = pcall(obj_method, obj, ...)
326 if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
327 end
328 elseif method then -- function
329 local success, err = pcall(method, ...)
330 if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
331 end
332 tmp[obj] = nil
333 obj = next(tmp)
334 end
335 end
336 tmp = del(tmp)
337 AceEvent.currentEvent = lastEvent
338 AceEvent.currentEventUID = lastEventUID
339 end
340
341 local delayRegistry
342 local OnUpdate
343 do
344 local tmp = {}
345 OnUpdate = function()
346 local t = GetTime()
347 for k,v in pairs(delayRegistry) do
348 tmp[k] = true
349 end
350 for k in pairs(tmp) do
351 local v = delayRegistry[k]
352 if v then
353 local v_time = v.time
354 if not v_time then
355 delayRegistry[k] = nil
356 elseif v_time <= t then
357 local v_repeatDelay = v.repeatDelay
358 if v_repeatDelay then
359 -- use the event time, not the current time, else timing inaccuracies add up over time
360 v.time = v_time + v_repeatDelay
361 end
362 local event = v.event
363 if type(event) == "function" then
364 local uid = AceEvent.UID_NUM + 1
365 AceEvent.UID_NUM = uid
366 AceEvent.currentEventUID = uid
367 local success, err = pcall(event, unpack(v, 1, v.n))
368 if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
369 AceEvent.currentEventUID = nil
370 else
371 AceEvent:TriggerEvent(event, unpack(v, 1, v.n))
372 end
373 if not v_repeatDelay then
374 local x = delayRegistry[k]
375 if x and x.time == v_time then -- check if it was manually reset
376 if not useTablesAsIDs or type(k) == "string" then
377 del(delayRegistry[k])
378 end
379 delayRegistry[k] = nil
380 end
381 end
382 end
383 end
384 end
385 for k in pairs(tmp) do
386 tmp[k] = nil
387 end
388 if not next(delayRegistry) then
389 AceEvent.frame:Hide()
390 end
391 end
392 end
393
394 local function ScheduleEvent(self, repeating, event, delay, ...)
395 local id
396 if type(event) == "string" or (useTablesAsIDs and type(event) == "table") then
397 if useTablesAsIDs and type(event) == "table" then
398 if not delayRegistry or not delayRegistry[event] then
399 AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
400 end
401 end
402 if type(delay) ~= "number" then
403 id, event, delay = event, delay, ...
404 AceEvent:argCheck(event, 3, "string", "function", --[[ so message is right ]] "number")
405 AceEvent:argCheck(delay, 4, "number")
406 self:CancelScheduledEvent(id)
407 end
408 else
409 AceEvent:argCheck(event, 2, "string", "function")
410 AceEvent:argCheck(delay, 3, "number")
411 end
412
413 if not delayRegistry then
414 AceEvent.delayRegistry = {}
415 delayRegistry = AceEvent.delayRegistry
416 AceEvent.frame:SetScript("OnUpdate", OnUpdate)
417 end
418 local t
419 if useTablesAsIDs and type(id) == "table" then
420 for k in pairs(id) do
421 id[k] = nil
422 end
423 t = id
424 for i = 2, select('#', ...) do
425 t[i-1] = select(i, ...)
426 end
427 t.n = select('#', ...) - 1
428 elseif id then
429 t = new(select(2, ...))
430 t.n = select('#', ...) - 1
431 else
432 t = new(...)
433 t.n = select('#', ...)
434 end
435 t.event = event
436 t.time = GetTime() + delay
437 t.self = self
438 t.id = id or t
439 t.repeatDelay = repeating and delay
440 delayRegistry[t.id] = t
441 AceEvent.frame:Show()
442 if useTablesAsIDs then
443 return t.id
444 else
445 return
446 end
447 end
448
449 --[[----------------------------------------------------------------------------------
450 Notes:
451 * Schedule an event to fire.
452 * To fire on the next frame, specify a delay of 0.
453 Arguments:
454 string or function - name of the event to fire, or a function to call.
455 number - the amount of time to wait until calling.
456 tuple - a list of arguments to pass along.
457 ------------------------------------------------------------------------------------]]
458 function AceEvent:ScheduleEvent(event, delay, ...)
459 if type(event) == "string" or (useTablesAsIDs and type(event) == "table") then
460 if useTablesAsIDs and type(event) == "table" then
461 if not delayRegistry or not delayRegistry[event] then
462 AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
463 end
464 end
465 if type(delay) ~= "number" then
466 AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
467 AceEvent:argCheck(..., 4, "number")
468 end
469 else
470 AceEvent:argCheck(event, 2, "string", "function")
471 AceEvent:argCheck(delay, 3, "number")
472 end
473
474 return ScheduleEvent(self, false, event, delay, ...)
475 end
476
477 function AceEvent:ScheduleRepeatingEvent(event, delay, ...)
478 if type(event) == "string" or (useTablesAsIDs and type(event) == "table") then
479 if useTablesAsIDs and type(event) == "table" then
480 if not delayRegistry or not delayRegistry[event] then
481 AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
482 end
483 end
484 if type(delay) ~= "number" then
485 AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
486 AceEvent:argCheck(..., 4, "number")
487 end
488 else
489 AceEvent:argCheck(event, 2, "string", "function")
490 AceEvent:argCheck(delay, 3, "number")
491 end
492
493 return ScheduleEvent(self, true, event, delay, ...)
494 end
495
496 function AceEvent:CancelScheduledEvent(t)
497 if useTablesAsIDs then
498 AceEvent:argCheck(t, 2, "string", "table")
499 else
500 AceEvent:argCheck(t, 2, "string")
501 end
502 if delayRegistry then
503 local v = delayRegistry[t]
504 if v then
505 if not useTablesAsIDs or type(t) == "string" then
506 del(delayRegistry[t])
507 end
508 delayRegistry[t] = nil
509 if not next(delayRegistry) then
510 AceEvent.frame:Hide()
511 end
512 return true
513 end
514 end
515 return false
516 end
517
518 function AceEvent:IsEventScheduled(t)
519 if useTablesAsIDs then
520 AceEvent:argCheck(t, 2, "string", "table")
521 else
522 AceEvent:argCheck(t, 2, "string")
523 end
524 if delayRegistry then
525 local v = delayRegistry[t]
526 if v then
527 return true, v.time - GetTime()
528 end
529 end
530 return false, nil
531 end
532
533 function AceEvent:UnregisterEvent(event)
534 AceEvent:argCheck(event, 2, "string")
535 local AceEvent_registry = AceEvent.registry
536 if AceEvent_registry[event] and AceEvent_registry[event][self] then
537 AceEvent_registry[event][self] = nil
538 local AceEvent_onceRegistry = AceEvent.onceRegistry
539 if AceEvent_onceRegistry and AceEvent_onceRegistry[event] and AceEvent_onceRegistry[event][self] then
540 AceEvent_onceRegistry[event][self] = nil
541 if not next(AceEvent_onceRegistry[event]) then
542 AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
543 end
544 end
545 local AceEvent_throttleRegistry = AceEvent.throttleRegistry
546 if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] and AceEvent_throttleRegistry[event][self] then
547 AceEvent_throttleRegistry[event][self] = nil
548 if not next(AceEvent_throttleRegistry[event]) then
549 AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
550 end
551 end
552 if not next(AceEvent_registry[event]) then
553 AceEvent_registry[event] = del(AceEvent_registry[event])
554 if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then
555 AceEvent.frame:UnregisterEvent(event)
556 end
557 end
558 else
559 if self == AceEvent then
560 error(("Cannot unregister event %q. Improperly unregistering from AceEvent-2.0."):format(event), 2)
561 else
562 AceEvent:error("Cannot unregister event %q. %q is not registered with it.", event, self)
563 end
564 end
565 AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
566 end
567
568 function AceEvent:UnregisterAllEvents()
569 local AceEvent_registry = AceEvent.registry
570 if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then
571 AceEvent_registry[ALL_EVENTS][self] = nil
572 if not next(AceEvent_registry[ALL_EVENTS]) then
573 AceEvent_registry[ALL_EVENTS] = del(AceEvent_registry[ALL_EVENTS])
574 AceEvent.frame:UnregisterAllEvents()
575 for k,v in pairs(AceEvent_registry) do
576 AceEvent.frame:RegisterEvent(k)
577 end
578 end
579 end
580 if AceEvent_registry.AceEvent_EventUnregistered then
581 local event, data = "AceEvent_EventUnregistered", AceEvent_registry.AceEvent_EventUnregistered
582 local x = data[self]
583 data[self] = nil
584 if x then
585 if not next(data) then
586 if not AceEvent_registry[ALL_EVENTS] then
587 AceEvent.frame:UnregisterEvent(event)
588 end
589 AceEvent_registry[event] = del(AceEvent_registry[event])
590 end
591 AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
592 end
593 end
594 for event, data in pairs(AceEvent_registry) do
595 local x = data[self]
596 data[self] = nil
597 if x and event ~= ALL_EVENTS then
598 if not next(data) then
599 if not AceEvent_registry[ALL_EVENTS] then
600 AceEvent.frame:UnregisterEvent(event)
601 end
602 AceEvent_registry[event] = del(AceEvent_registry[event])
603 end
604 AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
605 end
606 end
607 if AceEvent.onceRegistry then
608 for event, data in pairs(AceEvent.onceRegistry) do
609 data[self] = nil
610 end
611 end
612 end
613
614 function AceEvent:CancelAllScheduledEvents()
615 if delayRegistry then
616 for k,v in pairs(delayRegistry) do
617 if v.self == self then
618 if not useTablesAsIDs or type(k) == "string" then
619 del(delayRegistry[k])
620 end
621 delayRegistry[k] = nil
622 end
623 end
624 if not next(delayRegistry) then
625 AceEvent.frame:Hide()
626 end
627 end
628 end
629
630 function AceEvent:IsEventRegistered(event)
631 AceEvent:argCheck(event, 2, "string")
632 local AceEvent_registry = AceEvent.registry
633 if self == AceEvent then
634 return AceEvent_registry[event] and next(AceEvent_registry[event]) or AceEvent_registry[ALL_EVENTS] and next(AceEvent_registry[ALL_EVENTS]) and true or false
635 end
636 if AceEvent_registry[event] and AceEvent_registry[event][self] then
637 return true, AceEvent_registry[event][self]
638 end
639 if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then
640 return true, AceEvent_registry[ALL_EVENTS][self]
641 end
642 return false, nil
643 end
644
645 local UnitExists = UnitExists
646 local bucketfunc
647 function AceEvent:RegisterBucketEvent(event, delay, method, ...)
648 AceEvent:argCheck(event, 2, "string", "table")
649 if type(event) == "table" then
650 for k,v in pairs(event) do
651 if type(k) ~= "number" then
652 AceEvent:error("All keys to argument #2 to `RegisterBucketEvent' must be numbers.")
653 elseif type(v) ~= "string" then
654 AceEvent:error("All values to argument #2 to `RegisterBucketEvent' must be strings.")
655 end
656 end
657 end
658 AceEvent:argCheck(delay, 3, "number")
659 if AceEvent == self then
660 AceEvent:argCheck(method, 4, "function")
661 self = method
662 else
663 if type(event) == "string" then
664 AceEvent:argCheck(method, 4, "string", "function", "nil")
665 if not method then
666 method = event
667 end
668 else
669 AceEvent:argCheck(method, 4, "string", "function")
670 end
671
672 if type(method) == "string" and type(self[method]) ~= "function" then
673 AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
674 end
675 end
676 local buckets = AceEvent.buckets
677 if not buckets[event] then
678 buckets[event] = new()
679 end
680 if not buckets[event][self] then
681 local t = new()
682 t.current = new()
683 t.self = self
684 buckets[event][self] = t
685 else
686 AceEvent.CancelScheduledEvent(self, buckets[event][self].id)
687 end
688 local bucket = buckets[event][self]
689 bucket.method = method
690
691 local n = select('#', ...)
692 if n > 0 then
693 for i = 1, n do
694 bucket[i] = select(i, ...)
695 end
696 end
697 bucket.n = n
698
699 local func = function(arg1)
700 bucket.run = true
701 if arg1 then
702 bucket.current[arg1] = true
703 end
704 end
705 buckets[event][self].func = func
706 local isUnitBucket = true
707 if type(event) == "string" then
708 AceEvent.RegisterEvent(self, event, func)
709 if not event:find("^UNIT_") then
710 isUnitBucket = false
711 end
712 else
713 for _,v in ipairs(event) do
714 AceEvent.RegisterEvent(self, v, func)
715 if isUnitBucket and not v:find("^UNIT_") then
716 isUnitBucket = false
717 end
718 end
719 end
720 bucket.unit = isUnitBucket
721 if not bucketfunc then
722 bucketfunc = function(bucket)
723 local current = bucket.current
724 local method = bucket.method
725 local self = bucket.self
726 if bucket.run then
727 if bucket.unit then
728 for unit in pairs(current) do
729 if not UnitExists(unit) then
730 current[unit] = nil
731 end
732 end
733 end
734 if type(method) == "string" then
735 self[method](self, current, unpack(bucket, 1, bucket.n))
736 elseif method then -- function
737 method(current, unpack(bucket, 1, bucket.n))
738 end
739 for k in pairs(current) do
740 current[k] = nil
741 k = nil
742 end
743 bucket.run = false
744 end
745 end
746 end
747 bucket.id = "AceEvent-Bucket-" .. tostring(bucket)
748 AceEvent.ScheduleRepeatingEvent(self, bucket.id, bucketfunc, delay, bucket)
749 end
750
751 function AceEvent:IsBucketEventRegistered(event)
752 AceEvent:argCheck(event, 2, "string", "table")
753 return AceEvent.buckets and AceEvent.buckets[event] and AceEvent.buckets[event][self]
754 end
755
756 function AceEvent:UnregisterBucketEvent(event)
757 AceEvent:argCheck(event, 2, "string", "table")
758 if not AceEvent.buckets or not AceEvent.buckets[event] or not AceEvent.buckets[event][self] then
759 AceEvent:error("Cannot unregister bucket event %q. %q is not registered with it.", event, self)
760 end
761
762 local bucket = AceEvent.buckets[event][self]
763
764 if type(event) == "string" then
765 AceEvent.UnregisterEvent(self, event)
766 else
767 for _,v in ipairs(event) do
768 AceEvent.UnregisterEvent(self, v)
769 end
770 end
771 AceEvent:CancelScheduledEvent(bucket.id)
772
773 bucket.current = del(bucket.current)
774 AceEvent.buckets[event][self] = del(bucket)
775 if not next(AceEvent.buckets[event]) then
776 AceEvent.buckets[event] = del(AceEvent.buckets[event])
777 end
778 end
779
780 function AceEvent:UnregisterAllBucketEvents()
781 if not AceEvent.buckets or not next(AceEvent.buckets) then
782 return
783 end
784 for k,v in pairs(AceEvent.buckets) do
785 if v == self then
786 AceEvent.UnregisterBucketEvent(self, k)
787 k = nil
788 end
789 end
790 end
791
792 local combatSchedules
793 function AceEvent:CancelAllCombatSchedules()
794 local i = 0
795 while true do
796 i = i + 1
797 if not combatSchedules[i] then
798 break
799 end
800 local v = combatSchedules[i]
801 if v.self == self then
802 v = del(v)
803 table.remove(combatSchedules, i)
804 i = i - 1
805 end
806 end
807 end
808
809 local inCombat = false
810
811 function AceEvent:PLAYER_REGEN_DISABLED()
812 inCombat = true
813 end
814
815 do
816 local tmp = {}
817 function AceEvent:PLAYER_REGEN_ENABLED()
818 inCombat = false
819 for i, v in ipairs(combatSchedules) do
820 tmp[i] = v
821 combatSchedules[i] = nil
822 end
823 for i, v in ipairs(tmp) do
824 local func = v.func
825 if func then
826 local success, err = pcall(func, unpack(v, 1, v.n))
827 if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
828 else
829 local obj = v.obj or v.self
830 local method = v.method
831 local obj_method = obj[method]
832 if obj_method then
833 local success, err = pcall(obj_method, obj, unpack(v, 1, v.n))
834 if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
835 end
836 end
837 tmp[i] = del(v)
838 end
839 end
840 end
841
842 function AceEvent:ScheduleLeaveCombatAction(method, ...)
843 local style = type(method)
844 if self == AceEvent then
845 if style == "table" then
846 local func = (...)
847 AceEvent:argCheck(func, 3, "string")
848 if type(method[func]) ~= "function" then
849 AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", func)
850 end
851 else
852 AceEvent:argCheck(method, 2, "function", --[[so message is right]] "table")
853 end
854 self = method
855 else
856 AceEvent:argCheck(method, 2, "function", "string", "table")
857 if style == "string" and type(self[method]) ~= "function" then
858 AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", method)
859 elseif style == "table" then
860 local func = (...)
861 AceEvent:argCheck(func, 3, "string")
862 if type(method[func]) ~= "function" then
863 AceEvent:error("Cannot schedule a combat action to method %q, it does not exist", func)
864 end
865 end
866 end
867
868 if not inCombat then
869 local success, err
870 if type(method) == "function" then
871 success, err = pcall(method, ...)
872 elseif type(method) == "table" then
873 local func = (...)
874 success, err = pcall(method[func], method, select(2, ...))
875 else
876 success, err = pcall(self[method], self, ...)
877 end
878 if not success then geterrorhandler()(err:find("%.lua:%d+:") and err or (debugstack():match("(.-: )in.-\n") or "") .. err) end
879 return
880 end
881 local t
882 local n = select('#', ...)
883 if style == "table" then
884 t = new(select(2, ...))
885 t.obj = method
886 t.method = (...)
887 t.n = n-1
888 else
889 t = new(...)
890 t.n = n
891 if style == "function" then
892 t.func = method
893 else
894 t.method = method
895 end
896 end
897 t.self = self
898 table.insert(combatSchedules, t)
899 end
900
901 function AceEvent:OnEmbedDisable(target)
902 self.UnregisterAllEvents(target)
903
904 self.CancelAllScheduledEvents(target)
905
906 self.UnregisterAllBucketEvents(target)
907
908 self.CancelAllCombatSchedules(target)
909 end
910
911 function AceEvent:IsFullyInitialized()
912 return self.postInit or false
913 end
914
915 function AceEvent:IsPostPlayerLogin()
916 return IsLoggedIn() and true or false
917 end
918
919 local function activate(self, oldLib, oldDeactivate)
920 AceEvent = self
921
922 self.onceRegistry = oldLib and oldLib.onceRegistry or {}
923 self.throttleRegistry = oldLib and oldLib.throttleRegistry or {}
924 self.delayRegistry = oldLib and oldLib.delayRegistry or {}
925 self.buckets = oldLib and oldLib.buckets or {}
926 self.registry = oldLib and oldLib.registry or {}
927 self.frame = oldLib and oldLib.frame or CreateFrame("Frame", "AceEvent20Frame")
928 self.playerLogin = IsLoggedIn() and true
929 self.postInit = oldLib and oldLib.postInit or self.playerLogin and ChatTypeInfo and ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.r and true
930 self.ALL_EVENTS = oldLib and oldLib.ALL_EVENTS or _G.newproxy()
931 self.FAKE_NIL = oldLib and oldLib.FAKE_NIL or _G.newproxy()
932 self.RATE = oldLib and oldLib.RATE or _G.newproxy()
933 self.combatSchedules = oldLib and oldLib.combatSchedules or {}
934 self.UID_NUM = oldLib and oldLib.UID_NUM or 0
935
936 -- Delete this down the road. Makes sure that the addonframes from revisions 33121 - 36174 get their events unregistered.
937 local addonframes = oldLib and oldLib.addonframes
938 if addonframes then
939 for _, v in pairs(addonframes) do
940 v:UnregisterAllEvents()
941 end
942 end
943
944 combatSchedules = self.combatSchedules
945 ALL_EVENTS = self.ALL_EVENTS
946 FAKE_NIL = self.FAKE_NIL
947 RATE = self.RATE
948 local inPlw = false
949 local blacklist = {
950 UNIT_INVENTORY_CHANGED = true,
951 BAG_UPDATE = true,
952 ITEM_LOCK_CHANGED = true,
953 ACTIONBAR_SLOT_CHANGED = true,
954 }
955 self.frame:SetScript("OnEvent", function(_, event, ...)
956 if event == "PLAYER_ENTERING_WORLD" then
957 inPlw = false
958 elseif event == "PLAYER_LEAVING_WORLD" then
959 inPlw = true
960 end
961 if event and (not inPlw or not blacklist[event]) then
962 self:TriggerEvent(event, ...)
963 end
964 end)
965 if self.delayRegistry then
966 delayRegistry = self.delayRegistry
967 self.frame:SetScript("OnUpdate", OnUpdate)
968 end
969
970 self:UnregisterAllEvents()
971 self:CancelAllScheduledEvents()
972
973 registeringFromAceEvent = true
974 self:RegisterEvent("LOOT_OPENED", function()
975 SendAddonMessage("LOOT_OPENED", "", "RAID")
976 end)
977 registeringFromAceEvent = nil
978
979 local function handleFullInit()
980 if not self.postInit then
981 local function func()
982 self.postInit = true
983 self:TriggerEvent("AceEvent_FullyInitialized")
984 if self.registry["CHAT_MSG_CHANNEL_NOTICE"] and self.registry["CHAT_MSG_CHANNEL_NOTICE"][self] then
985 self:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE")
986 end
987 if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
988 self:UnregisterEvent("MEETINGSTONE_CHANGED")
989 end
990 if self.registry["MINIMAP_ZONE_CHANGED"] and self.registry["MINIMAP_ZONE_CHANGED"][self] then
991 self:UnregisterEvent("MINIMAP_ZONE_CHANGED")
992 end
993 if self.registry["LANGUAGE_LIST_CHANGED"] and self.registry["LANGUAGE_LIST_CHANGED"][self] then
994 self:UnregisterEvent("LANGUAGE_LIST_CHANGED")
995 end
996 collectgarbage('collect')
997 end
998 registeringFromAceEvent = true
999 local f = function()
1000 self.playerLogin = true
1001 self:ScheduleEvent("AceEvent_FullyInitialized", func, 1)
1002 end
1003 self:RegisterEvent("MEETINGSTONE_CHANGED", f, true)
1004 self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE", function()
1005 self:ScheduleEvent("AceEvent_FullyInitialized", func, 0.15)
1006 end)
1007 self:RegisterEvent("LANGUAGE_LIST_CHANGED", function()
1008 if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
1009 registeringFromAceEvent = true
1010 self:UnregisterEvent("MEETINGSTONE_CHANGED")
1011 self:RegisterEvent("MINIMAP_ZONE_CHANGED", fd, true)
1012 registeringFromAceEvent = nil
1013 end
1014 end)
1015 self:ScheduleEvent("AceEvent_FullyInitialized", func, 10)
1016 registeringFromAceEvent = nil
1017 end
1018 end
1019
1020 if not self.playerLogin then
1021 registeringFromAceEvent = true
1022 self:RegisterEvent("PLAYER_LOGIN", function()
1023 self.playerLogin = true
1024 handleFullInit()
1025 handleFullInit = nil
1026 collectgarbage('collect')
1027 end, true)
1028 registeringFromAceEvent = nil
1029 else
1030 handleFullInit()
1031 handleFullInit = nil
1032 end
1033
1034 if not AceEvent20EditBox then
1035 CreateFrame("Editbox", "AceEvent20EditBox")
1036 end
1037 local editbox = AceEvent20EditBox
1038 function editbox:Execute(line)
1039 local defaulteditbox = DEFAULT_CHAT_FRAME.editBox
1040 self:SetAttribute("chatType", defaulteditbox:GetAttribute("chatType"))
1041 self:SetAttribute("tellTarget", defaulteditbox:GetAttribute("tellTarget"))
1042 self:SetAttribute("channelTarget", defaulteditbox:GetAttribute("channelTarget"))
1043 self:SetText(line)
1044 ChatEdit_SendText(self)
1045 end
1046 editbox:Hide()
1047 _G["SLASH_IN1"] = "/in"
1048 SlashCmdList["IN"] = function(msg)
1049 local seconds, command, rest = msg:match("^([^%s]+)%s+(/[^%s]+)(.*)$")
1050 seconds = tonumber(seconds)
1051 if not seconds then
1052 DEFAULT_CHAT_FRAME:AddMessage("Error, bad arguments to /in. Must be in the form of `/in 5 /say hi'")
1053 return
1054 end
1055 if IsSecureCmd(command) then
1056 DEFAULT_CHAT_FRAME:AddMessage(("Error, /in cannot call secure command: %s"):format(command))
1057 return
1058 end
1059 self:ScheduleEvent("AceEventSlashIn-" .. math.random(1, 1000000000), editbox.Execute, seconds, editbox, command .. rest)
1060 end
1061 registeringFromAceEvent = true
1062 self:RegisterEvent("PLAYER_REGEN_ENABLED")
1063 self:RegisterEvent("PLAYER_REGEN_DISABLED")
1064 inCombat = InCombatLockdown()
1065 registeringFromAceEvent = nil
1066
1067 -- another hack to make sure that we clean up properly from rev 33121 - 36174
1068 if self.registry[ALL_EVENTS] then
1069 self.frame:RegisterAllEvents()
1070 else
1071 for event in pairs(self.registry) do
1072 self.frame:RegisterEvent(event)
1073 end
1074 end
1075
1076 self:activate(oldLib, oldDeactivate)
1077 if oldLib then
1078 oldDeactivate(oldLib)
1079 end
1080 end
1081
1082 AceLibrary:Register(AceEvent, MAJOR_VERSION, MINOR_VERSION, activate)