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