CallbackHandler-1.0

From WowAce Wiki
Jump to: navigation, search

CallbackHandler is a back-end utility library that makes it easy for a library to fire its events to interested parties. It removes the need for addons to be aware of e.g. AceEvent.

CallbackHandler should not be a required dependency for addons wanting to use your library. Rather, embed it in your library. CallbackHandler is small enough that a few libraries pulling it in has no real impact. We (the Ace3 core team) would like to simplify the library inclusion process so that usually all you have to do is pull in the one single library you're interested in, rather than having to fullfill several dependencies to make it work.

Mixing in the CallbackHandler functions in your library

MyLib.events = MyLib.events or 
  LibStub("CallbackHandler-1.0"):New(MyLib)

This adds 3 methods to your library:

  • MyLib:RegisterCallback("eventName"[, method, [arg]])
  • MyLib:UnregisterCallback("eventname")
  • MyLib:UnregisterAllCallbacks()

The "MyLib.events" object is the callback registry itself, which you need to keep track of across library upgrades. Creating a new callback registry means that old registrations are lost.

Note that the fourth, optional, member "IsRegisteredCallback", will not be added unless specified. See "Renaming the methods" below.

Firing events

Assuming your callback registry is "MyLib.events", firing named events is as easy as:

MyLib.events:Fire("EventName", arg1, arg2, ...)

All arguments supplied to :Fire() are passed to the functions listening to the event.

Advanced uses

Renaming the methods

You can specify your own names for the methods installed by CallbackHandler:

MyLib.events = MyLib.events or 
  LibStub("CallbackHandler-1.0"):New(MyLib, 
    "MyRegisterFunc", 
    "MyUnregisterFunc", 
    "MyUnregisterAllFunc" or false,
    "MyIsRegisteredFunc" or false
  )

Giving false as the name for UnregisterAll / MyIsRegisteredFunc means that you do not want to give users access to that API at all - it will not be installed.

Tracking events being used

In some cases, it makes sense to know which events are being requested by your users. Perhaps to enable/disable code needed to track them.

CallbackHandler will always call registry:OnUsed() and :OnUnused() when an event starts/stops being used:

function MyLib.events:OnUsed(target, eventname)
  -- "target" is == MyLib here
  print("Someone just registered for "..eventname.."!")
end

function MyLib.events:OnUnused(target, eventname)
  print("Noone wants "..eventname.." any more")
end

"OnUsed" is only called if the event was previously unused. "OnUnused" is only called when the last user unregisters from an event. In other words, you won't see an "OnUnused" unless "OnUsed" has been called for an event. And you won't ever see two "OnUsed" in a row without "OnUnused" in between for an event.

Multiple event registries

As you may or may not know, CallbackHandler is the workhorse of AceEvent. It is used twice in AceEvent: once for in-game events, which cannot be fired by users, and once for "messages", which can be fired by users.

Providing multiple registries in AceEvent was as easy as:

AceEvent.events = AceEvent.events or 
  LibStub("CallbackHandler-1.0"):New(AceEvent, 
    "RegisterEvent", "UnregisterEvent", "UnregisterAllEvents", "IsRegisteredEvent")

AceEvent.messages = AceEvent.messages or 
  LibStub("CallbackHandler-1.0"):New(AceEvent, 
    "RegisterMessage", "UnregisterMessage", "UnregisterAllMessages", "IsRegisteredMessage")

AceEvent.SendMessage = AceEvent.messages.Fire

Of course, there is also some code in AceEvent to do the actual driving of in-game events (using OnUsed and OnUnused), but this is really the core of it.

User API

The below documentation is automatically pulled in, using the template {{:CallbackHandler-1.0/User API|RegisterCallback|UnregisterCallback|UnregisterAllCallbacks|''library''|eventName|IsRegisteredCallback}} . Rather than pointing your library users here, pull the template into your own library documentation - your library users shouldn't even have to know about CallbackHandler! See CallbackHandler-1.0/User API for template usage documentation.


:RegisterCallback()

myAddon:RegisterCallback("eventName"[, method[, arg]])
library.RegisterCallback(myTable, "eventName"[, method[, arg]])
library.RegisterCallback("myAddonId", "eventName"[, method[, arg]])
"eventName"
(string) - the name of the event you want to listen to
method
(string or function) - which method to call. If string, self["method"] will be called. If left out (nil), self["eventName"] will be called.
arg
(optional) - If present (even nil), this value will be passed to the receiving function.


Registrations are always associated with the supplied self. This means that you'll want to embed library, or do the call like .RegisterCallback(myTable, ...). Note the use of " . " (period) rather than " : " (colon).

If you do not have a sane self table to associate your registrations with, you can substitute it for a string. Note the use of "." rather than ":".

library.RegisterCallback("myAddonId", "eventName", ...)

This string variant of a self will not be passed to the receiving function.

Callback arguments

If the method is a plain function, it will be called as:

method("eventName", (arguments to the event))
or, with an arg specified when registering:
method(arg, "eventName", (arguments to the event))


If the method is a string (method name), it will be called as:

self["method"](self, "eventName", (arguments to the event))
or, with an arg specified when registering:
self["method"](self, arg, "eventName", (arguments to the event))


:UnregisterCallback()

myAddon:UnregisterCallback("eventName")
library.UnregisterCallback(myTable, "eventName")
library.UnregisterCallback("myAddonId", "eventName")
"eventName"
the name of the event that you no longer wish to receive.

Note that the supplied self must match the self supplied to :RegisterCallback(), or nothing will be unregistered.


:UnregisterAllCallbacks()

:UnregisterAllCallbacks()
library.UnregisterAllCallbacks("myAddonId", myTable, ...)

UnregisterAllCallbacks will unregister all events associated with the given self, as well as with additional arguments given.

:IsRegisteredCallback

myAddon:IsRegisteredCallback("eventName")
library.IsRegisteredCallback(myTable, "eventName")
library.IsRegisteredCallback("myAddonId", "eventName")
"eventName"
the name of the event to test for being registered or not

Note that the supplied self must match the self supplied to :RegisterCallback(), or the return value will always be false.