Skip to content

Add a way to remove a single event listener #20983

@ypujante

Description

@ypujante

As far as I understand the current API in regards to events, you can add as many listeners as you want, but there is no way to remove just one.

Here is an example:

If I call:

emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, window, false, callback1);
emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, window, false, callback2);

in order to remove the callback, you need to call

emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, window, false, nullptr);

but then it will remove both callbacks as the code shows:

        if (eventHandler.callbackfunc) {
          eventHandler.eventListenerFunc = jsEventHandler;
          eventHandler.target.addEventListener(eventHandler.eventTypeString, jsEventHandler, eventHandler.useCapture);
          JSEvents.eventHandlers.push(eventHandler);
          JSEvents.registerRemoveEventListeners();
        } else {
          for (var i = 0; i < JSEvents.eventHandlers.length; ++i) {
            if (JSEvents.eventHandlers[i].target == eventHandler.target
             && JSEvents.eventHandlers[i].eventTypeString == eventHandler.eventTypeString) {
               JSEvents._removeHandler(i--);
             }
          }
        }

The else block is executed which indiscriminately remove all listeners that have the same target and event type.

The issue I am bumping into with this is that the glfw/emscripten/cpp port I am currently implementing, is setting a bunch of listeners for its own purpose. But the client code can also set its own listeners, the typical use case is the one I showed above to react on window resize to call glfwSetSize when the canvas size changes. But if the client then decides to remove its own listener, then it will remove the one from the library as well, thus crippling the proper functioning of the library.

I do realize that the API is named emscripten_set_resize_callback which implies that you are setting (vs adding) a callback, but the underlying code is adding a listener not replacing a current one.

I realize that changing the current APIs may break existing code, but maybe we could add a new set of APIs (and maybe deprecate the current one if that makes sense)... something like:

int emscripten_add_XXXXX_callback(....);
void emscripten_remove_callback(id);
  • instead of set it is add
  • it returns an id (and 0 or negative id means failure)
  • the id is used to remove this specific callback
  • this is similar to emscripten_set_timeout / emscripten_clear_timeout apis

What do you think? I can take a look at some implementation if you think that is an approach you would be interested in.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions