vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 --[[
2 Name: AceEvent-2.0
3 Revision: $Rev: 8054 $
4 Author(s): ckknight (ckknight@gmail.com)
5 facboy (<email here>)
6 Inspired By: AceEvent 1.x by Turan (<email here>)
7 Website: http://www.wowace.com/
8 Documentation: http://wiki.wowace.com/index.php/AceEvent-2.0
9 SVN: http://svn.wowace.com/root/trunk/Ace2/AceEvent-2.0
10 Description: Mixin to allow for event handling, scheduling, and inter-addon
11 communication.
12 Dependencies: AceLibrary, AceOO-2.0
13 ]]
14  
15 local MAJOR_VERSION = "AceEvent-2.0"
16 local MINOR_VERSION = "$Revision: 8054 $"
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 }
42  
43 local weakKey = {__mode="k"}
44 local new, del
45 do
46 local list = setmetatable({}, weakKey)
47 function new()
48 local t = next(list)
49 if t then
50 list[t] = nil
51 return t
52 else
53 return {}
54 end
55 end
56  
57 function del(t)
58 setmetatable(t, nil)
59 for k in pairs(t) do
60 t[k] = nil
61 end
62 list[t] = true
63 end
64 end
65  
66 local FAKE_NIL
67 local RATE
68  
69 local registeringFromAceEvent
70 function AceEvent:RegisterEvent(event, method, once)
71 AceEvent:argCheck(event, 2, "string")
72 if self == AceEvent and not registeringFromAceEvent then
73 AceEvent:argCheck(method, 3, "function")
74 self = method
75 else
76 AceEvent:argCheck(method, 3, "string", "function", "nil", "boolean", "number")
77 if type(method) == "boolean" or type(method) == "number" then
78 AceEvent:argCheck(once, 4, "nil")
79 once, method = method, event
80 end
81 end
82 AceEvent:argCheck(once, 4, "number", "boolean", "nil")
83 local throttleRate
84 if type(once) == "number" then
85 throttleRate, once = once
86 end
87 if not method then
88 method = event
89 end
90 if type(method) == "string" and type(self[method]) ~= "function" then
91 AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
92 end
93  
94 local AceEvent_registry = AceEvent.registry
95 if not AceEvent_registry[event] then
96 AceEvent_registry[event] = new()
97 AceEvent.frame:RegisterEvent(event)
98 end
99  
100 local remember = true
101 if AceEvent_registry[event][self] then
102 remember = false
103 end
104 AceEvent_registry[event][self] = method
105  
106 local AceEvent_onceRegistry = AceEvent.onceRegistry
107 if once then
108 if not AceEvent_onceRegistry then
109 AceEvent.onceRegistry = new()
110 AceEvent_onceRegistry = AceEvent.onceRegistry
111 end
112 if not AceEvent_onceRegistry[event] then
113 AceEvent_onceRegistry[event] = new()
114 end
115 AceEvent_onceRegistry[event][self] = true
116 else
117 if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
118 AceEvent_onceRegistry[event][self] = nil
119 if not next(AceEvent_onceRegistry[event]) then
120 AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
121 end
122 end
123 end
124  
125 local AceEvent_throttleRegistry = AceEvent.throttleRegistry
126 if throttleRate then
127 if not AceEvent_throttleRegistry then
128 AceEvent.throttleRegistry = new()
129 AceEvent_throttleRegistry = AceEvent.throttleRegistry
130 end
131 if not AceEvent_throttleRegistry[event] then
132 AceEvent_throttleRegistry[event] = new()
133 end
134 if AceEvent_throttleRegistry[event][self] then
135 AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self])
136 end
137 AceEvent_throttleRegistry[event][self] = setmetatable(new(), weakKey)
138 local t = AceEvent_throttleRegistry[event][self]
139 t[RATE] = throttleRate
140 else
141 if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] then
142 if AceEvent_throttleRegistry[event][self] then
143 AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self])
144 end
145 if not next(AceEvent_throttleRegistry[event]) then
146 AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
147 end
148 end
149 end
150  
151 if remember then
152 AceEvent:TriggerEvent("AceEvent_EventRegistered", self, event)
153 end
154 end
155  
156 local ALL_EVENTS
157  
158 function AceEvent:RegisterAllEvents(method)
159 if self == AceEvent then
160 AceEvent:argCheck(method, 1, "function")
161 self = method
162 else
163 AceEvent:argCheck(method, 1, "string", "function")
164 if type(method) == "string" and type(self[method]) ~= "function" then
165 AceEvent:error("Cannot register all events to method %q, it does not exist", method)
166 end
167 end
168  
169 if not AceEvent.registry[ALL_EVENTS] then
170 AceEvent.registry[ALL_EVENTS] = new()
171 AceEvent.frame:RegisterAllEvents()
172 end
173  
174 AceEvent.registry[ALL_EVENTS][self] = method
175 end
176  
177 local _G = getfenv(0)
178 local memstack, timestack = {}, {}
179 local memdiff, timediff
180 function AceEvent:TriggerEvent(event, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
181 AceEvent:argCheck(event, 2, "string")
182 local AceEvent_registry = AceEvent.registry
183 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
184 return
185 end
186 local _G_event = _G.event
187 _G.event = event
188  
189 local AceEvent_onceRegistry = AceEvent.onceRegistry
190 local AceEvent_debugTable = AceEvent.debugTable
191 if AceEvent_onceRegistry and AceEvent_onceRegistry[event] then
192 local tmp = new()
193 for obj, method in pairs(AceEvent_onceRegistry[event]) do
194 tmp[obj] = AceEvent_registry[event] and AceEvent_registry[event][obj] or nil
195 end
196 local obj = next(tmp)
197 while obj do
198 local mem, time
199 if AceEvent_debugTable then
200 if not AceEvent_debugTable[event] then
201 AceEvent_debugTable[event] = new()
202 end
203 if not AceEvent_debugTable[event][obj] then
204 AceEvent_debugTable[event][obj] = new()
205 AceEvent_debugTable[event][obj].mem = 0
206 AceEvent_debugTable[event][obj].time = 0
207 AceEvent_debugTable[event][obj].count = 0
208 end
209 if memdiff then
210 table.insert(memstack, memdiff)
211 table.insert(timestack, timediff)
212 end
213 memdiff, timediff = 0, 0
214 mem, time = gcinfo(), GetTime()
215 end
216 local method = tmp[obj]
217 AceEvent.UnregisterEvent(obj, event)
218 if type(method) == "string" then
219 local obj_method = obj[method]
220 if obj_method then
221 obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
222 end
223 elseif method then -- function
224 method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
225 end
226 if AceEvent_debugTable then
227 local dmem, dtime = memdiff, timediff
228 mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
229 AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
230 AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
231 AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
232  
233 memdiff, timediff = table.remove(memstack), table.remove(timestack)
234 if memdiff then
235 memdiff = memdiff + mem + dmem
236 timediff = timediff + time + dtime
237 end
238 end
239 tmp[obj] = nil
240 obj = next(tmp)
241 end
242 del(tmp)
243 end
244  
245 local AceEvent_throttleRegistry = AceEvent.throttleRegistry
246 local throttleTable = AceEvent_throttleRegistry and AceEvent_throttleRegistry[event]
247 if AceEvent_registry[event] then
248 local tmp = new()
249 for obj, method in pairs(AceEvent_registry[event]) do
250 tmp[obj] = method
251 end
252 local obj = next(tmp)
253 while obj do
254 local method = tmp[obj]
255 local continue = false
256 if throttleTable and throttleTable[obj] then
257 local a1 = a1
258 if a1 == nil then
259 a1 = FAKE_NIL
260 end
261 if not throttleTable[obj][a1] or GetTime() - throttleTable[obj][a1] >= throttleTable[obj][RATE] then
262 throttleTable[obj][a1] = GetTime()
263 else
264 continue = true
265 end
266 end
267 if not continue then
268 local mem, time
269 if AceEvent_debugTable then
270 if not AceEvent_debugTable[event] then
271 AceEvent_debugTable[event] = new()
272 end
273 if not AceEvent_debugTable[event][obj] then
274 AceEvent_debugTable[event][obj] = new()
275 AceEvent_debugTable[event][obj].mem = 0
276 AceEvent_debugTable[event][obj].time = 0
277 AceEvent_debugTable[event][obj].count = 0
278 end
279 if memdiff then
280 table.insert(memstack, memdiff)
281 table.insert(timestack, timediff)
282 end
283 memdiff, timediff = 0, 0
284 mem, time = gcinfo(), GetTime()
285 end
286 if type(method) == "string" then
287 local obj_method = obj[method]
288 if obj_method then
289 obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
290 end
291 elseif method then -- function
292 method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
293 end
294 if AceEvent_debugTable then
295 local dmem, dtime = memdiff, timediff
296 mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
297 AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
298 AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
299 AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
300  
301 memdiff, timediff = table.remove(memstack), table.remove(timestack)
302 if memdiff then
303 memdiff = memdiff + mem + dmem
304 timediff = timediff + time + dtime
305 end
306 end
307 end
308 tmp[obj] = nil
309 obj = next(tmp)
310 end
311 del(tmp)
312 end
313 if AceEvent_registry[ALL_EVENTS] then
314 local tmp = new()
315 for obj, method in pairs(AceEvent_registry[ALL_EVENTS]) do
316 tmp[obj] = method
317 end
318 local obj = next(tmp)
319 while obj do
320 local method = tmp[obj]
321 local mem, time
322 if AceEvent_debugTable then
323 if not AceEvent_debugTable[event] then
324 AceEvent_debugTable[event] = new()
325 end
326 if not AceEvent_debugTable[event][obj] then
327 AceEvent_debugTable[event][obj] = new()
328 AceEvent_debugTable[event][obj].mem = 0
329 AceEvent_debugTable[event][obj].time = 0
330 AceEvent_debugTable[event][obj].count = 0
331 end
332 if memdiff then
333 table.insert(memstack, memdiff)
334 table.insert(timestack, timediff)
335 end
336 memdiff, timediff = 0, 0
337 mem, time = gcinfo(), GetTime()
338 end
339 if type(method) == "string" then
340 local obj_method = obj[method]
341 if obj_method then
342 obj_method(obj, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
343 end
344 elseif method then -- function
345 method(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
346 end
347 if AceEvent_debugTable then
348 local dmem, dtime = memdiff, timediff
349 mem, time = gcinfo() - mem - memdiff, GetTime() - time - timediff
350 AceEvent_debugTable[event][obj].mem = AceEvent_debugTable[event][obj].mem + mem
351 AceEvent_debugTable[event][obj].time = AceEvent_debugTable[event][obj].time + time
352 AceEvent_debugTable[event][obj].count = AceEvent_debugTable[event][obj].count + 1
353  
354 memdiff, timediff = table.remove(memstack), table.remove(timestack)
355 if memdiff then
356 memdiff = memdiff + mem + dmem
357 timediff = timediff + time + dtime
358 end
359 end
360 tmp[obj] = nil
361 obj = next(tmp)
362 end
363 del(tmp)
364 end
365 _G.event = _G_event
366 end
367  
368 --------------------
369 -- schedule heap management
370 --------------------
371  
372 -- local accessors
373 local getn = table.getn
374 local setn = table.setn
375 local tinsert = table.insert
376 local tremove = table.remove
377 local floor = math.floor
378  
379 --------------------
380 -- sifting functions
381 local function hSiftUp(heap, pos, schedule)
382 schedule = schedule or heap[pos]
383 local scheduleTime = schedule.time
384  
385 local curr, i = pos, floor(pos/2)
386 local parent = heap[i]
387 while i > 0 and scheduleTime < parent.time do
388 heap[curr], parent.i = parent, curr
389 curr, i = i, floor(i/2)
390 parent = heap[i]
391 end
392 heap[curr], schedule.i = schedule, curr
393 return pos ~= curr
394 end
395  
396 local function hSiftDown(heap, pos, schedule, size)
397 schedule, size = schedule or heap[pos], size or getn(heap)
398 local scheduleTime = schedule.time
399  
400 local curr = pos
401 repeat
402 local child, childTime, c
403 -- determine the child to compare with
404 local j = 2 * curr
405 if j > size then
406 break
407 end
408 local k = j + 1
409 if k > size then
410 child = heap[j]
411 childTime, c = child.time, j
412 else
413 local childj, childk = heap[j], heap[k]
414 local jTime, kTime = childj.time, childk.time
415 if jTime < kTime then
416 child, childTime, c = childj, jTime, j
417 else
418 child, childTime, c = childk, kTime, k
419 end
420 end
421 -- do the comparison
422 if scheduleTime <= childTime then
423 break
424 end
425 heap[curr], child.i = child, curr
426 curr = c
427 until false
428 heap[curr], schedule.i = schedule, curr
429 return pos ~= curr
430 end
431  
432 --------------------
433 -- heap functions
434 local function hMaintain(heap, pos, schedule, size)
435 schedule, size = schedule or heap[pos], size or getn(heap)
436 if not hSiftUp(heap, pos, schedule) then
437 hSiftDown(heap, pos, schedule, size)
438 end
439 end
440  
441 local function hPush(heap, schedule)
442 tinsert(heap, schedule)
443 hSiftUp(heap, getn(heap), schedule)
444 end
445  
446 local function hPop(heap)
447 local head, tail = heap[1], tremove(heap)
448 local size = getn(heap)
449  
450 if size == 1 then
451 heap[1], tail.i = tail, 1
452 elseif size > 1 then
453 hSiftDown(heap, 1, tail, size)
454 end
455 return head
456 end
457  
458 local function hDelete(heap, pos)
459 local size = getn(heap)
460 local tail = tremove(heap)
461 if pos < size then
462 size = size - 1
463 if size == 1 then
464 heap[1], tail.i = tail, 1
465 elseif size > 1 then
466 heap[pos] = tail
467 hMaintain(heap, pos, tail, size)
468 end
469 end
470 end
471  
472 local GetTime = GetTime
473 local delayRegistry
474 local delayHeap
475 local function OnUpdate()
476 local t = GetTime()
477 -- peek at top of heap
478 local v = delayHeap[1]
479 local v_time = v and v.time
480 while v and v_time <= t do
481 local v_repeatDelay = v.repeatDelay
482 if v_repeatDelay then
483 -- use the event time, not the current time, else timing inaccuracies add up over time
484 v.time = v_time + v_repeatDelay
485 -- re-arrange the heap
486 hSiftDown(delayHeap, 1, v)
487 else
488 -- pop the event off the heap, and delete it from the registry
489 hPop(delayHeap)
490 delayRegistry[v.id] = nil
491 end
492 local event = v.event
493 if type(event) == "function" then
494 event(unpack(v))
495 else
496 AceEvent:TriggerEvent(event, unpack(v))
497 end
498 if not v_repeatDelay then
499 del(v)
500 end
501 v = delayHeap[1]
502 v_time = v and v.time
503 end
504 if not v then
505 AceEvent.frame:Hide()
506 end
507 end
508  
509 local function ScheduleEvent(self, repeating, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
510 local id
511 if type(event) == "string" or type(event) == "table" then
512 if type(event) == "table" then
513 if not delayRegistry or not delayRegistry[event] then
514 AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
515 end
516 end
517 if type(delay) ~= "number" then
518 id, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20 = event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20
519 AceEvent:argCheck(event, 3, "string", "function", --[[ so message is right ]] "number")
520 AceEvent:argCheck(delay, 4, "number")
521 self:CancelScheduledEvent(id)
522 end
523 else
524 AceEvent:argCheck(event, 2, "string", "function")
525 AceEvent:argCheck(delay, 3, "number")
526 end
527  
528 if not delayRegistry then
529 AceEvent.delayRegistry = new()
530 AceEvent.delayHeap = new()
531 AceEvent.delayHeap.n = 0
532 delayRegistry = AceEvent.delayRegistry
533 delayHeap = AceEvent.delayHeap
534 AceEvent.frame:SetScript("OnUpdate", OnUpdate)
535 end
536 local t
537 if type(id) == "table" then
538 for k in pairs(id) do
539 id[k] = nil
540 end
541 table.setn(id, 0)
542 t = id
543 else
544 t = new()
545 end
546 t.n = 0
547 tinsert(t, a1)
548 tinsert(t, a2)
549 tinsert(t, a3)
550 tinsert(t, a4)
551 tinsert(t, a5)
552 tinsert(t, a6)
553 tinsert(t, a7)
554 tinsert(t, a8)
555 tinsert(t, a9)
556 tinsert(t, a10)
557 tinsert(t, a11)
558 tinsert(t, a12)
559 tinsert(t, a13)
560 tinsert(t, a14)
561 tinsert(t, a15)
562 tinsert(t, a16)
563 tinsert(t, a17)
564 tinsert(t, a18)
565 tinsert(t, a19)
566 tinsert(t, a20)
567 t.event = event
568 t.time = GetTime() + delay
569 t.self = self
570 t.id = id or t
571 t.repeatDelay = repeating and delay
572 delayRegistry[t.id] = t
573 -- insert into heap
574 hPush(delayHeap, t)
575 AceEvent.frame:Show()
576 return t.id
577 end
578  
579 function AceEvent:ScheduleEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
580 if type(event) == "string" or type(event) == "table" then
581 if type(event) == "table" then
582 if not delayRegistry or not delayRegistry[event] then
583 AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
584 end
585 end
586 if type(delay) ~= "number" then
587 AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
588 AceEvent:argCheck(a1, 4, "number")
589 end
590 else
591 AceEvent:argCheck(event, 2, "string", "function")
592 AceEvent:argCheck(delay, 3, "number")
593 end
594  
595 return ScheduleEvent(self, false, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
596 end
597  
598 function AceEvent:ScheduleRepeatingEvent(event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
599 if type(event) == "string" or type(event) == "table" then
600 if type(event) == "table" then
601 if not delayRegistry or not delayRegistry[event] then
602 AceEvent:error("Bad argument #2 to `ScheduleEvent'. Improper id table fed in.")
603 end
604 end
605 if type(delay) ~= "number" then
606 AceEvent:argCheck(delay, 3, "string", "function", --[[ so message is right ]] "number")
607 AceEvent:argCheck(a1, 4, "number")
608 end
609 else
610 AceEvent:argCheck(event, 2, "string", "function")
611 AceEvent:argCheck(delay, 3, "number")
612 end
613  
614 return ScheduleEvent(self, true, event, delay, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
615 end
616  
617 function AceEvent:CancelScheduledEvent(t)
618 AceEvent:argCheck(t, 2, "string", "table")
619 if delayRegistry then
620 local v = delayRegistry[t]
621 if v then
622 hDelete(delayHeap, v.i)
623 delayRegistry[t] = nil
624 del(v)
625 if not next(delayRegistry) then
626 AceEvent.frame:Hide()
627 end
628 return true
629 end
630 end
631 return false
632 end
633  
634 function AceEvent:IsEventScheduled(t)
635 AceEvent:argCheck(t, 2, "string", "table")
636 if delayRegistry then
637 local v = delayRegistry[t]
638 if v then
639 return true, v.time - GetTime()
640 end
641 end
642 return false, nil
643 end
644  
645  
646 function AceEvent:IsEventRegistered(event)
647 AceEvent:argCheck(event, 2, "string")
648 local AceEvent_registry = AceEvent.registry
649 if self == AceEvent then
650 return AceEvent_registry[event] and next(AceEvent_registry[event]) and true or false
651 end
652 if AceEvent_registry[event] and AceEvent_registry[event][self] then
653 return true, AceEvent_registry[event][self]
654 end
655 return false, nil
656 end
657  
658 function AceEvent:UnregisterEvent(event)
659 AceEvent:argCheck(event, 2, "string")
660 local AceEvent_registry = AceEvent.registry
661 if AceEvent_registry[event] and AceEvent_registry[event][self] then
662 AceEvent_registry[event][self] = nil
663 local AceEvent_onceRegistry = AceEvent.onceRegistry
664 if AceEvent_onceRegistry and AceEvent_onceRegistry[event] and AceEvent_onceRegistry[event][self] then
665 AceEvent_onceRegistry[event][self] = nil
666 if not next(AceEvent_onceRegistry[event]) then
667 AceEvent_onceRegistry[event] = del(AceEvent_onceRegistry[event])
668 end
669 end
670 local AceEvent_throttleRegistry = AceEvent.throttleRegistry
671 if AceEvent_throttleRegistry and AceEvent_throttleRegistry[event] and AceEvent_throttleRegistry[event][self] then
672 AceEvent_throttleRegistry[event][self] = del(AceEvent_throttleRegistry[event][self])
673 if not next(AceEvent_throttleRegistry[event]) then
674 AceEvent_throttleRegistry[event] = del(AceEvent_throttleRegistry[event])
675 end
676 end
677 if not next(AceEvent_registry[event]) then
678 AceEvent_registry[event] = del(AceEvent_registry[event])
679 if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then
680 AceEvent.frame:UnregisterEvent(event)
681 end
682 end
683 else
684 if self == AceEvent then
685 error(string.format("Cannot unregister event %q. Improperly unregistering from AceEvent-2.0.", event), 2)
686 else
687 AceEvent:error("Cannot unregister event %q. %q is not registered with it.", event, self)
688 end
689 end
690 AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
691 end
692  
693 function AceEvent:UnregisterAllEvents()
694 local AceEvent_registry = AceEvent.registry
695 if AceEvent_registry[ALL_EVENTS] and AceEvent_registry[ALL_EVENTS][self] then
696 AceEvent_registry[ALL_EVENTS][self] = nil
697 if not next(AceEvent_registry[ALL_EVENTS]) then
698 del(AceEvent_registry[ALL_EVENTS])
699 AceEvent.frame:UnregisterAllEvents()
700 for k,v in pairs(AceEvent_registry) do
701 if k ~= ALL_EVENTS then
702 AceEvent.frame:RegisterEvent(k)
703 end
704 end
705 AceEvent_registry[event] = nil
706 end
707 end
708 local first = true
709 for event, data in pairs(AceEvent_registry) do
710 if first then
711 if AceEvent_registry.AceEvent_EventUnregistered then
712 event = "AceEvent_EventUnregistered"
713 else
714 first = false
715 end
716 end
717 local x = data[self]
718 data[self] = nil
719 if x and event ~= ALL_EVENTS then
720 if not next(data) then
721 del(data)
722 if not AceEvent_registry[ALL_EVENTS] or not next(AceEvent_registry[ALL_EVENTS]) then
723 AceEvent.frame:UnregisterEvent(event)
724 end
725 AceEvent_registry[event] = nil
726 end
727 AceEvent:TriggerEvent("AceEvent_EventUnregistered", self, event)
728 end
729 if first then
730 event = nil
731 end
732 end
733 if AceEvent.onceRegistry then
734 for event, data in pairs(AceEvent.onceRegistry) do
735 data[self] = nil
736 end
737 end
738 end
739  
740 function AceEvent:CancelAllScheduledEvents()
741 if delayRegistry then
742 for k,v in pairs(delayRegistry) do
743 if v.self == self then
744 hDelete(delayHeap, v.i)
745 del(v)
746 delayRegistry[k] = nil
747 end
748 end
749 if not next(delayRegistry) then
750 AceEvent.frame:Hide()
751 end
752 end
753 end
754  
755 function AceEvent:IsEventRegistered(event)
756 AceEvent:argCheck(event, 2, "string")
757 local AceEvent_registry = AceEvent.registry
758 if self == AceEvent then
759 return AceEvent_registry[event] and next(AceEvent_registry[event]) and true or false
760 end
761 if AceEvent_registry[event] and AceEvent_registry[event][self] then
762 return true, AceEvent_registry[event][self]
763 end
764 return false, nil
765 end
766  
767 local bucketfunc
768 function AceEvent:RegisterBucketEvent(event, delay, method)
769 AceEvent:argCheck(event, 2, "string", "table")
770 if type(event) == "table" then
771 for k,v in pairs(event) do
772 if type(k) ~= "number" then
773 AceEvent:error("All keys to argument #2 to `RegisterBucketEvent' must be numbers.")
774 elseif type(v) ~= "string" then
775 AceEvent:error("All values to argument #2 to `RegisterBucketEvent' must be strings.")
776 end
777 end
778 end
779 AceEvent:argCheck(delay, 3, "number")
780 if AceEvent == self then
781 AceEvent:argCheck(method, 4, "function")
782 self = method
783 else
784 if type(event) == "string" then
785 AceEvent:argCheck(method, 4, "string", "function", "nil")
786 if not method then
787 method = event
788 end
789 else
790 AceEvent:argCheck(method, 4, "string", "function")
791 end
792  
793 if type(method) == "string" and type(self[method]) ~= "function" then
794 AceEvent:error("Cannot register event %q to method %q, it does not exist", event, method)
795 end
796 end
797 if not AceEvent.buckets then
798 AceEvent.buckets = new()
799 end
800 if not AceEvent.buckets[event] then
801 AceEvent.buckets[event] = new()
802 end
803 if not AceEvent.buckets[event][self] then
804 AceEvent.buckets[event][self] = new()
805 AceEvent.buckets[event][self].current = new()
806 AceEvent.buckets[event][self].self = self
807 else
808 AceEvent.CancelScheduledEvent(self, AceEvent.buckets[event][self].id)
809 end
810 local bucket = AceEvent.buckets[event][self]
811 bucket.method = method
812  
813 local func = function(arg1)
814 bucket.run = true
815 if arg1 then
816 bucket.current[arg1] = true
817 end
818 end
819 AceEvent.buckets[event][self].func = func
820 if type(event) == "string" then
821 AceEvent.RegisterEvent(self, event, func)
822 else
823 for _,v in ipairs(event) do
824 AceEvent.RegisterEvent(self, v, func)
825 end
826 end
827 if not bucketfunc then
828 bucketfunc = function(bucket)
829 local current = bucket.current
830 local method = bucket.method
831 local self = bucket.self
832 if bucket.run then
833 if type(method) == "string" then
834 self[method](self, current)
835 elseif method then -- function
836 method(current)
837 end
838 for k in pairs(current) do
839 current[k] = nil
840 k = nil
841 end
842 bucket.run = false
843 end
844 end
845 end
846 bucket.id = AceEvent.ScheduleRepeatingEvent(self, bucketfunc, delay, bucket)
847 end
848  
849 function AceEvent:IsBucketEventRegistered(event)
850 AceEvent:argCheck(event, 2, "string", "table")
851 return AceEvent.buckets and AceEvent.buckets[event] and AceEvent.buckets[event][self]
852 end
853  
854 function AceEvent:UnregisterBucketEvent(event)
855 AceEvent:argCheck(event, 2, "string", "table")
856 if not AceEvent.buckets or not AceEvent.buckets[event] or not AceEvent.buckets[event][self] then
857 AceEvent:error("Cannot unregister bucket event %q. %q is not registered with it.", event, self)
858 end
859  
860 local bucket = AceEvent.buckets[event][self]
861  
862 if type(event) == "string" then
863 AceEvent.UnregisterEvent(bucket.func, event)
864 else
865 for _,v in ipairs(event) do
866 AceEvent.UnregisterEvent(bucket.func, v)
867 end
868 end
869 AceEvent:CancelScheduledEvent(bucket.id)
870  
871 del(bucket.current)
872 AceEvent.buckets[event][self] = del(AceEvent.buckets[event][self])
873 if not next(AceEvent.buckets[event]) then
874 AceEvent.buckets[event] = del(AceEvent.buckets[event])
875 end
876 end
877  
878 function AceEvent:UnregisterAllBucketEvents()
879 if not AceEvent.buckets or not next(AceEvent.buckets) then
880 return
881 end
882 for k,v in pairs(AceEvent.buckets) do
883 if v == self then
884 AceEvent.UnregisterBucketEvent(self, k)
885 k = nil
886 end
887 end
888 end
889  
890 function AceEvent:OnEmbedDisable(target)
891 self.UnregisterAllEvents(target)
892  
893 self.CancelAllScheduledEvents(target)
894  
895 self.UnregisterAllBucketEvents(target)
896 end
897  
898 function AceEvent:EnableDebugging()
899 if not self.debugTable then
900 self.debugTable = new()
901 end
902 end
903  
904 function AceEvent:IsFullyInitialized()
905 return self.postInit or false
906 end
907  
908 function AceEvent:IsPostPlayerLogin()
909 return self.playerLogin or false
910 end
911  
912 function AceEvent:activate(oldLib, oldDeactivate)
913 AceEvent = self
914  
915 if oldLib then
916 self.onceRegistry = oldLib.onceRegistry
917 self.throttleRegistry = oldLib.throttleRegistry
918 self.delayRegistry = oldLib.delayRegistry
919 self.buckets = oldLib.buckets
920 self.delayHeap = oldLib.delayHeap
921 self.registry = oldLib.registry
922 self.frame = oldLib.frame
923 self.debugTable = oldLib.debugTable
924 self.playerLogin = oldLib.pew or DEFAULT_CHAT_FRAME and DEFAULT_CHAT_FRAME.defaultLanguage and true
925 self.postInit = oldLib.postInit or self.playerLogin and ChatTypeInfo and ChatTypeInfo.WHISPER and ChatTypeInfo.WHISPER.r and true
926 self.ALL_EVENTS = oldLib.ALL_EVENTS
927 self.FAKE_NIL = oldLib.FAKE_NIL
928 self.RATE = oldLib.RATE
929 end
930 if not self.registry then
931 self.registry = {}
932 end
933 if not self.frame then
934 self.frame = CreateFrame("Frame", "AceEvent20Frame")
935 end
936 if not self.ALL_EVENTS then
937 self.ALL_EVENTS = {}
938 end
939 if not self.FAKE_NIL then
940 self.FAKE_NIL = {}
941 end
942 if not self.RATE then
943 self.RATE = {}
944 end
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()
956 local event = event
957 if event == "PLAYER_ENTERING_WORLD" then
958 inPlw = false
959 elseif event == "PLAYER_LEAVING_WORLD" then
960 inPlw = true
961 end
962 if event and (not inPlw or not blacklist[event]) then
963 self:TriggerEvent(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
964 end
965 end)
966 if self.delayRegistry then
967 delayRegistry = self.delayRegistry
968 delayHeap = self.delayHeap
969 self.frame:SetScript("OnUpdate", OnUpdate)
970 end
971  
972 self:UnregisterAllEvents()
973 self:CancelAllScheduledEvents()
974  
975 if not self.playerLogin then
976 registeringFromAceEvent = true
977 self:RegisterEvent("PLAYER_LOGIN", function()
978 self.playerLogin = true
979 end, true)
980 registeringFromAceEvent = nil
981 end
982  
983 if not self.postInit then
984 local isReload = true
985 local function func()
986 self.postInit = true
987 self:TriggerEvent("AceEvent_FullyInitialized")
988 if self.registry["CHAT_MSG_CHANNEL_NOTICE"] and self.registry["CHAT_MSG_CHANNEL_NOTICE"][self] then
989 self:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE")
990 end
991 if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
992 self:UnregisterEvent("MEETINGSTONE_CHANGED")
993 end
994 if self.registry["MINIMAP_ZONE_CHANGED"] and self.registry["MINIMAP_ZONE_CHANGED"][self] then
995 self:UnregisterEvent("MINIMAP_ZONE_CHANGED")
996 end
997 if self.registry["LANGUAGE_LIST_CHANGED"] and self.registry["LANGUAGE_LIST_CHANGED"][self] then
998 self:UnregisterEvent("LANGUAGE_LIST_CHANGED")
999 end
1000 end
1001 registeringFromAceEvent = true
1002 local f = function()
1003 self.playerLogin = true
1004 self:ScheduleEvent("AceEvent_FullyInitialized", func, 1)
1005 end
1006 self:RegisterEvent("MEETINGSTONE_CHANGED", f, true)
1007 self:RegisterEvent("CHAT_MSG_CHANNEL_NOTICE", function()
1008 self:ScheduleEvent("AceEvent_FullyInitialized", func, 0.05)
1009 end)
1010 self:RegisterEvent("LANGUAGE_LIST_CHANGED", function()
1011 if self.registry["MEETINGSTONE_CHANGED"] and self.registry["MEETINGSTONE_CHANGED"][self] then
1012 self:UnregisterEvent("MEETINGSTONE_CHANGED")
1013 self:RegisterEvent("MINIMAP_ZONE_CHANGED", f, true)
1014 end
1015 end)
1016 registeringFromAceEvent = nil
1017 end
1018  
1019 self.super.activate(self, oldLib, oldDeactivate)
1020 if oldLib then
1021 oldDeactivate(oldLib)
1022 end
1023 end
1024  
1025 AceLibrary:Register(AceEvent, MAJOR_VERSION, MINOR_VERSION, AceEvent.activate)
1026 AceEvent = AceLibrary(MAJOR_VERSION)