mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 15:13:28 +00:00
Merge pull request #251 from lightpanda-io/eventlistener-data
events: create an EventHandlerData struct
This commit is contained in:
@@ -73,9 +73,9 @@ pub const EventTarget = struct {
|
|||||||
self,
|
self,
|
||||||
alloc,
|
alloc,
|
||||||
eventType,
|
eventType,
|
||||||
cbk,
|
|
||||||
capture orelse false,
|
|
||||||
EventHandler,
|
EventHandler,
|
||||||
|
.{ .cbk = cbk },
|
||||||
|
capture orelse false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -241,31 +241,23 @@ pub fn testExecFn(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const EventHandler = struct {
|
pub const EventHandler = struct {
|
||||||
fn handle(event: ?*parser.Event, data: ?*anyopaque) callconv(.C) void {
|
fn handle(event: ?*parser.Event, data: parser.EventHandlerData) void {
|
||||||
if (data) |d| {
|
// TODO get the allocator by another way?
|
||||||
const func = parser.event_handler_cbk(d);
|
var res = CallbackResult.init(data.cbk.nat_ctx.alloc);
|
||||||
|
defer res.deinit();
|
||||||
|
|
||||||
// TODO get the allocator by another way?
|
if (event) |evt| {
|
||||||
var res = CallbackResult.init(func.nat_ctx.alloc);
|
data.cbk.trycall(.{
|
||||||
defer res.deinit();
|
Event.toInterface(evt) catch unreachable,
|
||||||
|
}, &res) catch |e| log.err("event handler error: {any}", .{e});
|
||||||
|
} else {
|
||||||
|
data.cbk.trycall(.{event}, &res) catch |e| log.err("event handler error: {any}", .{e});
|
||||||
|
}
|
||||||
|
|
||||||
if (event) |evt| {
|
// in case of function error, we log the result and the trace.
|
||||||
func.trycall(.{
|
if (!res.success) {
|
||||||
Event.toInterface(evt) catch unreachable,
|
log.info("event handler error: {s}", .{res.result orelse "unknown"});
|
||||||
}, &res) catch |e| log.err("event handler error: {any}", .{e});
|
log.debug("{s}", .{res.stack orelse "no stack trace"});
|
||||||
} else {
|
|
||||||
func.trycall(.{event}, &res) catch |e| log.err("event handler error: {any}", .{e});
|
|
||||||
}
|
|
||||||
|
|
||||||
// in case of function error, we log the result and the trace.
|
|
||||||
if (!res.success) {
|
|
||||||
log.info("event handler error: {s}", .{res.result orelse "unknown"});
|
|
||||||
log.debug("{s}", .{res.stack orelse "no stack trace"});
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: we can not call func.deinit here
|
|
||||||
// b/c the handler can be called several times
|
|
||||||
// either on this dispatch event or in anoter one
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.handle;
|
}.handle;
|
||||||
|
|||||||
@@ -522,12 +522,6 @@ pub const EventType = enum(u8) {
|
|||||||
progress_event = 1,
|
progress_event = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
// EventHandler
|
|
||||||
pub fn event_handler_cbk(data: *anyopaque) *Callback {
|
|
||||||
const ptr: *align(@alignOf(*Callback)) anyopaque = @alignCast(data);
|
|
||||||
return @as(*Callback, @ptrCast(ptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
// EventListener
|
// EventListener
|
||||||
pub const EventListener = c.dom_event_listener;
|
pub const EventListener = c.dom_event_listener;
|
||||||
const EventListenerEntry = c.listener_entry;
|
const EventListenerEntry = c.listener_entry;
|
||||||
@@ -587,10 +581,9 @@ pub fn eventTargetHasListener(
|
|||||||
// and capture property,
|
// and capture property,
|
||||||
// let's check if the callback handler is the same
|
// let's check if the callback handler is the same
|
||||||
defer c.dom_event_listener_unref(listener);
|
defer c.dom_event_listener_unref(listener);
|
||||||
const data = eventListenerGetData(listener);
|
const ehd = EventHandlerDataInternal.fromListener(listener);
|
||||||
if (data) |d| {
|
if (ehd) |d| {
|
||||||
const cbk = event_handler_cbk(d);
|
if (cbk_id == d.data.cbk.id()) {
|
||||||
if (cbk_id == cbk.id()) {
|
|
||||||
return lst;
|
return lst;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -608,29 +601,99 @@ pub fn eventTargetHasListener(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EventHandler = fn (event: ?*Event, data: ?*anyopaque) callconv(.C) void;
|
// EventHandlerFunc is a zig function called when the event is dispatched to a
|
||||||
|
// listener.
|
||||||
|
// The EventHandlerFunc is responsible to call the callback included into the
|
||||||
|
// EventHandlerData.
|
||||||
|
pub const EventHandlerFunc = *const fn (event: ?*Event, data: EventHandlerData) void;
|
||||||
|
|
||||||
|
// EventHandler implements the function exposed in C and called by libdom.
|
||||||
|
// It retrieves the EventHandlerInternalData and call the EventHandlerFunc with
|
||||||
|
// the EventHandlerData in parameter.
|
||||||
|
const EventHandler = struct {
|
||||||
|
fn handle(event: ?*Event, data: ?*anyopaque) callconv(.C) void {
|
||||||
|
if (data) |d| {
|
||||||
|
const ehd = EventHandlerDataInternal.get(d);
|
||||||
|
ehd.handler(event, ehd.data);
|
||||||
|
|
||||||
|
// NOTE: we can not call func.deinit here
|
||||||
|
// b/c the handler can be called several times
|
||||||
|
// either on this dispatch event or in anoter one
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.handle;
|
||||||
|
|
||||||
|
// EventHandlerData contains a JS callback and the data associated to the
|
||||||
|
// handler.
|
||||||
|
// If given, deinitFunc is called with the data pointer to allow the creator to
|
||||||
|
// clean memory.
|
||||||
|
// The callback is deinit by EventHandlerDataInternal. It must NOT be deinit
|
||||||
|
// into deinitFunc.
|
||||||
|
pub const EventHandlerData = struct {
|
||||||
|
cbk: Callback,
|
||||||
|
data: ?*anyopaque = null,
|
||||||
|
// deinitFunc implements the data deinitialization.
|
||||||
|
deinitFunc: ?DeinitFunc = null,
|
||||||
|
|
||||||
|
pub const DeinitFunc = *const fn (data: ?*anyopaque, alloc: std.mem.Allocator) void;
|
||||||
|
};
|
||||||
|
|
||||||
|
// EventHandlerDataInternal groups the EventHandlerFunc and the EventHandlerData.
|
||||||
|
const EventHandlerDataInternal = struct {
|
||||||
|
data: EventHandlerData,
|
||||||
|
handler: EventHandlerFunc,
|
||||||
|
|
||||||
|
fn init(alloc: std.mem.Allocator, handler: EventHandlerFunc, data: EventHandlerData) !*EventHandlerDataInternal {
|
||||||
|
const ptr = try alloc.create(EventHandlerDataInternal);
|
||||||
|
ptr.* = .{
|
||||||
|
.data = data,
|
||||||
|
.handler = handler,
|
||||||
|
};
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deinit(self: *EventHandlerDataInternal, alloc: std.mem.Allocator) void {
|
||||||
|
if (self.data.deinitFunc) |d| d(self.data.data, alloc);
|
||||||
|
self.data.cbk.deinit(alloc);
|
||||||
|
alloc.destroy(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(data: *anyopaque) *EventHandlerDataInternal {
|
||||||
|
const ptr: *align(@alignOf(*EventHandlerDataInternal)) anyopaque = @alignCast(data);
|
||||||
|
return @as(*EventHandlerDataInternal, @ptrCast(ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
// retrieve a EventHandlerDataInternal from a listener.
|
||||||
|
fn fromListener(lst: *EventListener) ?*EventHandlerDataInternal {
|
||||||
|
const data = eventListenerGetData(lst);
|
||||||
|
// free cbk allocation made on eventTargetAddEventListener
|
||||||
|
if (data == null) return null;
|
||||||
|
|
||||||
|
return get(data.?);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pub fn eventTargetAddEventListener(
|
pub fn eventTargetAddEventListener(
|
||||||
et: *EventTarget,
|
et: *EventTarget,
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
typ: []const u8,
|
typ: []const u8,
|
||||||
cbk: Callback,
|
handlerFunc: EventHandlerFunc,
|
||||||
|
data: EventHandlerData,
|
||||||
capture: bool,
|
capture: bool,
|
||||||
handler: EventHandler,
|
|
||||||
) !void {
|
) !void {
|
||||||
// this allocation will be removed either on
|
// this allocation will be removed either on
|
||||||
// eventTargetRemoveEventListener or eventTargetRemoveAllEventListeners
|
// eventTargetRemoveEventListener or eventTargetRemoveAllEventListeners
|
||||||
const cbk_ptr = try alloc.create(Callback);
|
const ehd = try EventHandlerDataInternal.init(alloc, handlerFunc, data);
|
||||||
cbk_ptr.* = cbk;
|
errdefer ehd.deinit(alloc);
|
||||||
|
|
||||||
// When a function is used as an event handler, its this parameter is bound
|
// When a function is used as an event handler, its this parameter is bound
|
||||||
// to the DOM element on which the listener is placed.
|
// to the DOM element on which the listener is placed.
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this#this_in_dom_event_handlers
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this#this_in_dom_event_handlers
|
||||||
try cbk_ptr.setThisArg(et);
|
try ehd.data.cbk.setThisArg(et);
|
||||||
|
|
||||||
const ctx = @as(*anyopaque, @ptrCast(cbk_ptr));
|
const ctx = @as(*anyopaque, @ptrCast(ehd));
|
||||||
var listener: ?*EventListener = undefined;
|
var listener: ?*EventListener = undefined;
|
||||||
const errLst = c.dom_event_listener_create(handler, ctx, &listener);
|
const errLst = c.dom_event_listener_create(EventHandler, ctx, &listener);
|
||||||
try DOMErr(errLst);
|
try DOMErr(errLst);
|
||||||
defer c.dom_event_listener_unref(listener);
|
defer c.dom_event_listener_unref(listener);
|
||||||
|
|
||||||
@@ -646,13 +709,9 @@ pub fn eventTargetRemoveEventListener(
|
|||||||
lst: *EventListener,
|
lst: *EventListener,
|
||||||
capture: bool,
|
capture: bool,
|
||||||
) !void {
|
) !void {
|
||||||
const data = eventListenerGetData(lst);
|
// free data allocation made on eventTargetAddEventListener
|
||||||
// free cbk allocation made on eventTargetAddEventListener
|
const ehd = EventHandlerDataInternal.fromListener(lst);
|
||||||
if (data) |d| {
|
if (ehd) |d| d.deinit(alloc);
|
||||||
const cbk_ptr = event_handler_cbk(d);
|
|
||||||
cbk_ptr.deinit(alloc);
|
|
||||||
alloc.destroy(cbk_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
const s = try strFromData(typ);
|
const s = try strFromData(typ);
|
||||||
const err = eventTargetVtable(et).remove_event_listener.?(et, s, lst, capture);
|
const err = eventTargetVtable(et).remove_event_listener.?(et, s, lst, capture);
|
||||||
@@ -680,13 +739,10 @@ pub fn eventTargetRemoveAllEventListeners(
|
|||||||
|
|
||||||
if (lst) |listener| {
|
if (lst) |listener| {
|
||||||
defer c.dom_event_listener_unref(listener);
|
defer c.dom_event_listener_unref(listener);
|
||||||
const data = eventListenerGetData(listener);
|
|
||||||
if (data) |d| {
|
const ehd = EventHandlerDataInternal.fromListener(listener);
|
||||||
// free cbk allocation made on eventTargetAddEventListener
|
if (ehd) |d| d.deinit(alloc);
|
||||||
const cbk = event_handler_cbk(d);
|
|
||||||
cbk.deinit(alloc);
|
|
||||||
alloc.destroy(cbk);
|
|
||||||
}
|
|
||||||
const err = eventTargetVtable(et).remove_event_listener.?(
|
const err = eventTargetVtable(et).remove_event_listener.?(
|
||||||
et,
|
et,
|
||||||
null,
|
null,
|
||||||
|
|||||||
@@ -52,9 +52,9 @@ pub const XMLHttpRequestEventTarget = struct {
|
|||||||
@as(*parser.EventTarget, @ptrCast(self)),
|
@as(*parser.EventTarget, @ptrCast(self)),
|
||||||
alloc,
|
alloc,
|
||||||
typ,
|
typ,
|
||||||
cbk,
|
|
||||||
false,
|
|
||||||
EventHandler,
|
EventHandler,
|
||||||
|
.{ .cbk = cbk },
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
fn unregister(self: *XMLHttpRequestEventTarget, alloc: std.mem.Allocator, typ: []const u8, cbk: Callback) !void {
|
fn unregister(self: *XMLHttpRequestEventTarget, alloc: std.mem.Allocator, typ: []const u8, cbk: Callback) !void {
|
||||||
|
|||||||
Reference in New Issue
Block a user