diff --git a/src/browser/html/window.zig b/src/browser/html/window.zig
index 74fa28b3d..f18b0cd2c 100644
--- a/src/browser/html/window.zig
+++ b/src/browser/html/window.zig
@@ -387,4 +387,19 @@ test "Browser.HTML.Window" {
.{ "window.setTimeout(() => {longCall = true}, 5001);", null },
.{ "longCall;", "false" },
}, .{});
+
+ // window event target
+ try runner.testCases(&.{
+ .{
+ \\ let called = false;
+ \\ window.addEventListener("ready", (e) => {
+ \\ called = (e.currentTarget == window);
+ \\ }, {capture: false, once: false});
+ \\ const evt = new Event("ready", { bubbles: true, cancelable: false });
+ \\ window.dispatchEvent(evt);
+ \\ called;
+ ,
+ "true",
+ },
+ }, .{});
}
diff --git a/src/browser/netsurf.zig b/src/browser/netsurf.zig
index 03db92e24..414dd56d6 100644
--- a/src/browser/netsurf.zig
+++ b/src/browser/netsurf.zig
@@ -775,6 +775,17 @@ pub const EventTargetTBase = extern struct {
.add_event_listener = add_event_listener,
.iter_event_listener = iter_event_listener,
},
+
+ // When we dispatch the event, we need to provide a target. In reality, the
+ // target is the container of this EventTargetTBase. But we can't pass that
+ // to _dom_event_target_dispatch, because it expects a dom_event_target.
+ // If you try to pass an non-event_target, you'll get weird behavior. For
+ // example, libdom might dom_node_ref that memory. Say we passed a *Window
+ // as the target, what happens if libdom calls dom_node_ref(window)? If
+ // you're lucky, you'll crash. If you're unlucky, you'll increment a random
+ // part of the window structure.
+ refcnt: u32 = 0,
+
eti: c.dom_event_target_internal = c.dom_event_target_internal{ .listeners = null },
pub fn add_event_listener(et: [*c]c.dom_event_target, t: [*c]c.dom_string, l: ?*c.struct_dom_event_listener, capture: bool) callconv(.C) c.dom_exception {