vanilla-wow-addons – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 --[[---------------------------------------------------------------------------------
2 AceHook Library - Embeddable (standalone) or for use through Ace
3 ------------------------------------------------------------------------------------]]
4  
5 local VERSION = 1.0
6  
7 if not AceHook or AceHook.VERSION < VERSION then
8 -- We need to load this version of the library
9  
10 if AceCore then
11 if AceHook then
12 ace:print("|cffff0000[AceHook] REPLACING THE SUPPLIED ACEHOOK WITH AN EMBEDDED VERSION ("..VERSION..").");
13 end
14  
15 AceHook = AceCore:new()
16 else
17 AceHook = {}
18 end
19  
20 --[[----------------------------------------------------------------------
21 AceHook:Hook
22 self:Hook("functionName", ["handlerName" | handler])
23 self:Hook(ObjectName, "Method", ["Handler" | handler])
24 -------------------------------------------------------------------------]]
25 function AceHook:Hook(arg1, arg2, arg3)
26 if not self.Hooks then self.Hooks = {} end
27 if type(arg1) == "string" then
28 self:HookFunc(arg1, arg2)
29 else
30 self:HookMeth(arg1, arg2, arg3)
31 end
32 end
33  
34 function AceHook:HookScript(arg1, arg2, arg3)
35 if not self.Hooks then self.Hooks = {} end
36  
37 self:HookMeth(arg1, arg2, arg3, true)
38 end
39  
40 --[[----------------------------------------------------------------------
41 AceHook:Unhook
42 self:Unhook("functionName")
43 self:Unhook(ObjectName, "Method")
44 -------------------------------------------------------------------------]]
45 function AceHook:Unhook(arg1, arg2)
46 if type(arg1) == "string" then
47 self:UnhookFunc(arg1)
48 else
49 self:UnhookMeth(arg1, arg2)
50 end
51 end
52  
53 --[[----------------------------------------------------------------------
54 AceHook:UnhookAll - Unhooks all active hooks from the calling source
55 -------------------------------------------------------------------------]]
56 function AceHook:UnhookAll(script)
57 if not self.Hooks then return end
58 for key, value in pairs(self.Hooks) do
59 if type(key) == "table" then
60 for method in pairs(value) do
61 if (self.Hooks[key][method].script == script) then
62 self:Unhook(key, method)
63 end
64 end
65 else
66 self:Unhook(key)
67 end
68 end
69 end
70  
71 function AceHook:UnhookAllScripts()
72 self:UnhookAll(true)
73 end
74  
75 --[[----------------------------------------------------------------------
76 AceHook:Print - Utility function for HookReport, for embedding
77 AceHook:HookReport - Lists registered hooks from this source
78 -------------------------------------------------------------------------]]
79 function AceHook:Print(message)
80 if AceCore then
81 ace:print(message)
82 else
83 DEFAULT_CHAT_FRAME:AddMessage(message)
84 end
85 end
86  
87 function AceHook:HookReport()
88 AceHook:Print("|cffffff00 AceHook: HookReport()")
89 if not self.Hooks then AceHook:Print("No registered hooks.") return end
90  
91 for key, value in pairs(self.Hooks) do
92 if type(key) == "table" then
93 for method in pairs(value) do
94 AceHook:Print("AceHook: key: "..tostring(key).." method: "..tostring(method)..((self.Hooks[key][method].active and "|cff00ff00 Active" or "|cffffff00 Inactive")))
95 end
96 else
97 AceHook:Print("AceHook: key: " .. tostring(key) .. " value: " .. tostring(value) .. ((self.Hooks[key].active and "|cff00ff00 Active" or "|cffffff00 Inactive")))
98 end
99 end
100 end
101  
102 --[[----------------------------------------------------------------------
103 AceHook:CallHook("functionName" [, arg1, arg2, arg3, ...])
104 AceHook:CallHook(ObjectName, "Method" [, arg1, arg2, arg3, ...])
105  
106 DEPRECATED: This function has been deprecated and replaced by a direct
107 call from the self.Hooks table. This avoids function calls and decreases
108 the overhead from a CallHook. The new wrapper functions limit any
109 CallHook to 20 arguments. The new forms are as follows:
110  
111 self.Hooks.functionName.orig(arg1, arg2, arg3)
112 self.Hooks[ObjectName].MethodName.orig(ObjectName, arg1, arg2, arg3)
113 -------------------------------------------------------------------------]]
114  
115 function AceHook:CallHook(obj,meth,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
116 if type(obj) == "string" then
117 -- Function Call
118 if not self.Hooks or not self.Hooks[obj] then
119 if self.debug then self.debug( "Attempt to CallHook when no hook exists for " .. obj); return; end
120 else
121 local func = obj
122 return self.Hooks[func].orig(meth,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
123 end
124 else
125 if not self.Hooks[obj] or not self.Hooks[obj][meth] then
126 if self.debug then self.debug( "Attempt to CallHook when no hook exists for " .. tostring(meth)); return; end
127 else
128 return self.Hooks[obj][meth].orig(obj,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
129 end
130 end
131 end
132  
133 --[[----------------------------------------------------------------------
134 AceHook:HookFunc - internal method.
135 o You can only hook each function once from each source.
136 o If there is an inactive hook for this func/handler pair, we reactivate it
137 o If there is an inactive hook for another handler, we error out.
138 o Looks for handler as a method of the calling class, error if not available
139 o If handler is a function, it just uses it directly through the wrapper
140 -------------------------------------------------------------------------]]
141 function AceHook:HookFunc(func, handler)
142 if not handler then handler = func end
143 if self.Hooks[func] then
144 -- We have an active hook from this source. Don't multi-hook
145 if self.Hooks[func].active then
146 if self.debug then self:debug( func .. " already has an active hook from this source.") end
147 return
148 end
149 -- The hook is inactive, so reactivate it
150 if self.Hooks[func].handler == handler then
151 self.Hooks[func].active = true
152 return
153 else
154 error( "There is a stale hook for " .. func .. " can't hook or reactivate.",3)
155 end
156 end
157  
158 local methodHandler
159  
160 if type(handler) == "string" then
161 if self[handler] then
162 methodHandler = true
163 else
164 error( "Could not find the the handler " ..handler.." when hooking function " .. func,3)
165 end
166 elseif type(handler) ~= "function" then
167 error( "Could not find the handler you supplied when hooking " .. func,3)
168 end
169  
170 self.Hooks[func] = {}
171 self.Hooks[func].orig = getglobal(func)
172 self.Hooks[func].active = true
173 self.Hooks[func].handler = handler
174 self.Hooks[func].func = self:_getFunctionHook(func, handler, methodHandler)
175 setglobal(func, self.Hooks[func].func)
176 end
177  
178 --[[----------------------------------------------------------------------
179 AceHook:UnhookFunc - internal method
180 o If you attempt to unhook a function that has never been hooked, or to unhook in a
181 system that has never had a hook before, the system will error with a stack trace
182 o If we own the global function, then put the original back in its place and remove
183 all references to the Hooks[func] structure.
184 o If we don't own the global function (we've been hooked) we deactivate the hook,
185 forcing the handler to passthrough.
186 -------------------------------------------------------------------------]]
187 function AceHook:UnhookFunc(func)
188 if not self.Hooks or not self.Hooks[func] then
189 if self.debug then self:debug("Attempt to unhook a function that is not currently hooked.") end
190 return
191 end
192 if self.Hooks[func].active then
193 -- See if we own the global function
194 if getglobal(func) == self.Hooks[func].func then
195 setglobal(func, self.Hooks[func].orig)
196 self.Hooks[func] = nil
197 -- Magically all-done
198 else
199 self.Hooks[func].active = nil
200 end
201 end
202 end
203  
204 --[[----------------------------------------------------------------------
205 AceHook:_getFunctionHook- internal method
206 -------------------------------------------------------------------------]]
207  
208 function AceHook:_getFunctionHook(func, handler, methodHandler)
209 if methodHandler then
210 -- The handler is a method, need to self it
211 return
212 function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
213 if self.Hooks[func].active then
214 return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
215 else
216 return self.Hooks[func].orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
217 end
218 end
219 else
220 -- The handler is a function, just call it
221 return
222 function(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
223 if self.Hooks[func].active then
224 return handler(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
225 else
226 return self.Hooks[func].orig(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
227 end
228 end
229 end
230 end
231  
232 --[[----------------------------------------------------------------------
233 AceHook:HookMeth - Takes an optional fourth argument
234 o script - Signifies whether this is a script hook or not
235 -------------------------------------------------------------------------]]
236  
237 function AceHook:HookMeth(obj, method, handler, script)
238 if not handler then handler = method end
239 if self.Hooks[obj] and self.Hooks[obj][method] then
240 -- We have an active hook from this source. Don't multi-hook
241 if self.Hooks[obj][method].active then
242 if self.debug then self:debug( method .. " already has an active hook from this source.") end
243 return
244 end
245 -- The hook is inactive, so reactivate it.
246 if self.Hooks[obj][method].handler == handler then
247 self.Hooks[obj][method].active = true
248 return
249 else
250 error( "There is a stale hook for " .. method .. " can't hook or reactivate.",3)
251 end
252 end
253 -- We're clear to try the hook, let's make some checks first
254 local methodHandler
255 if type(handler) == "string" then
256 if self[handler] then
257 methodHandler = true
258 else
259 error( "Could not find the handler ("..handler..") you supplied when hooking method " .. method,3)
260 end
261 elseif type(handler) ~= "function" then
262 error( "Could not find the handler you supplied when hooking method " .. method,3)
263 end
264 -- Handler has been found, so now try to find the method we're trying to hook
265 local orig, setscript
266 -- Script
267 if script then
268 if (not obj) then
269 error("The object you supplied could not be found.", 3)
270 end
271 if not obj.GetScript then
272 error("The object you supplied does not have a GetScript method.", 3)
273 end
274 if not obj:HasScript(method) then
275 error("The object you supplied doesn't allows the " .. method .. " method.", 3)
276 end
277 -- Sometimes there is not a original function for a script.
278 orig = obj:GetScript(method) or function () end
279 -- Method
280 else
281 orig = obj[method]
282 end
283 if not orig then
284 error("Could not find the method or script ("..method..") you are trying to hook.",3)
285 end
286 if not self.Hooks[obj] then self.Hooks[obj] = {} end
287 self.Hooks[obj][method] = {}
288 self.Hooks[obj][method].orig = orig
289 self.Hooks[obj][method].active = true
290 self.Hooks[obj][method].handler = handler
291 self.Hooks[obj][method].script = script
292 self.Hooks[obj][method].func = self:_getMethodHook(obj, method, handler, methodHandler)
293 if script then
294 obj:SetScript(method, self.Hooks[obj][method].func)
295 else
296 obj[method] = self.Hooks[obj][method].func
297 end
298 end
299  
300 --[[----------------------------------------------------------------------
301 AceHook:UnhookMeth - Internal method
302 o If you attempt to unhook a method that has never been hooked, or to unhook in a
303 system that has never had a hook before, the system will error with a stack trace
304 o If we own the global method, then put the original back in its place and remove
305 all references to the Hooks[obj][method] structure.
306 o If we don't own the global method (we've been hooked) we deactivate the hook,
307 forcing the handler to passthrough.
308 -------------------------------------------------------------------------]]
309 function AceHook:UnhookMeth(obj, method)
310 if not self.Hooks or not self.Hooks[obj] or not self.Hooks[obj][method] then
311 if self.debug then self:debug( "Attempt to unhook a method ("..method..") that is not currently hooked.") end
312 return
313 end
314 if self.Hooks[obj][method].active then
315 -- If this is a script
316 if self.Hooks[obj][method].script then
317 if obj:GetScript(method) == self.Hooks[obj][method].func then
318 -- We own the global function. Kill it.
319 obj:SetScript(method, self.Hooks[obj][method].orig)
320 self.Hooks[obj][method] = nil
321 return
322 else
323 self.Hooks[obj][method].active = nil
324 end
325 else
326 if obj[method] == self.Hooks[obj][method].func then
327 -- We own the global function. Kill it.
328 obj[method] = self.Hooks[obj][method].orig
329 self.Hooks[obj][method] = nil
330 return
331 else
332 self.Hooks[obj][method].active = nil
333 end
334 end
335 end
336 if not next(self.Hooks[obj]) then
337 -- Spank the table
338 self.Hooks[obj] = nil
339 end
340 end
341  
342 --[[----------------------------------------------------------------------
343 AceHook:_getMethodHook - Internal Method
344 -------------------------------------------------------------------------]]
345 function AceHook:_getMethodHook(obj, method, handler, methodHook)
346 if methodHook then
347 -- The handler is a method, need to self it
348 return
349 function(o,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
350 if self.Hooks[obj][method].active then
351 return self[handler](self, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
352 elseif self.Hooks[obj][method].orig then
353 return self.Hooks[obj][method].orig(obj, a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
354 end
355 end
356 else
357 -- The handler is a function, just call it
358 return
359 function(o,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
360 if self.Hooks[obj][method].active then
361 return handler(o,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
362 elseif self.Hooks[obj][method].orig then
363 return self.Hooks[obj][method].orig(obj,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20)
364 end
365 end
366 end
367 end
368  
369 --[[----------------------------------------------------------------------
370 AceHook:Embed - Called to embed the vital methods into another object
371 -------------------------------------------------------------------------]]
372 function AceHook:Embed(object)
373 object.Hook = self.Hook
374 object.Unhook = self.Unhook
375 object.UnhookAll = self.UnhookAll
376 object.CallHook = self.CallHook
377 object.HookFunc = self.HookFunc
378 object.HookMeth = self.HookMeth
379 object.UnhookFunc = self.UnhookFunc
380 object.UnhookMeth = self.UnhookMeth
381 object._getFunctionHook = self._getFunctionHook
382 object._getMethodHook = self._getMethodHook
383 object.HookReport = self.HookReport
384  
385 object.HookScript = self.HookScript
386 object.UnhookScript = self.Unhook
387 object.UnhookAllScripts = self.UnhookAllScripts
388 object.CallScript = self.CallHook
389 end
390  
391 if AceCore then ace.hook = AceHook end
392  
393 end