Repository: LadybirdBrowser/ladybird
File: Libraries/LibWebView/EventLoop/EventLoopImplementationMacOS.mm (Objective-C++)

Code before:
    CFRelease(*timer);
}

struct SocketNotifierCallbackContext : public RefCounted<SocketNotifierCallbackContext> {
    WeakPtr<Core::EventReceiver> notifier;
};

static void const* retain_socket_notifier_callback_context(void const* info)
{
    auto const* ptr = reinterpret_cast<SocketNotifierCallbackContext const*>(info);
    ptr->ref();
    return ptr;
}

static void release_socket_notifier_callback_context(void const* info)
{
    reinterpret_cast<SocketNotifierCallbackContext const*>(info)->unref();
}

static void socket_notifier(CFSocketRef socket, CFSocketCallBackType notification_type, CFDataRef, void const*, void* info)
{
    if (!info)
        return;
    auto& callback_context = *reinterpret_cast<SocketNotifierCallbackContext*>(info);
    if (!callback_context.notifier)
        return;
    auto& notifier = as<Core::Notifier>(*callback_context.notifier);

    // This socket callback is not quite re-entrant. If Core::Notifier::dispatch_event blocks, e.g.
    // to wait upon a Core::Promise, this socket will not receive any more notifications until that
    // promise is resolved or rejected. So we mark this socket as able to receive more notifications
    // before dispatching the event, which allows it to be triggered again.
    CFSocketEnableCallBacks(socket, notification_type);

    Core::NotifierActivationEvent event(notifier.fd(), notifier.type());
    notifier.dispatch_event(event);

    // This manual process of enabling the callbacks also seems to require waking the event loop,
    // otherwise it hangs indefinitely in any ongoing pump(PumpMode::WaitForEvents) invocation.
    post_application_event();
}

void EventLoopManagerMacOS::register_notifier(Core::Notifier& notifier)
{
    auto notification_type = kCFSocketNoCallBack;

    switch (notifier.type()) {
    case Core::Notifier::Type::Read:
        notification_type = kCFSocketReadCallBack;
        break;
    case Core::Notifier::Type::Write:

Review comment (suggestion):
This and the ones above can *probably* be a static cast? We do the same in `handle_signal` below.

Code after:
    auto& thread_data = ThreadData::the();

    auto timer_id = thread_data.timer_id_allocator.allocate();
    auto weak_receiver = receiver.make_weak_ptr();

    auto interval_seconds = static_cast<double>(interval_milliseconds) / 1000.0;
    auto first_fire_time = CFAbsoluteTimeGetCurrent() + interval_seconds;

    auto* timer = CFRunLoopTimerCreateWithHandler(
        kCFAllocatorDefault, first_fire_time, should_reload ? interval_seconds : 0, 0, 0,
        ^(CFRunLoopTimerRef) {
            auto receiver = weak_receiver.strong_ref();
            if (!receiver) {
                return;
            }

            Core::TimerEvent event;
            receiver->dispatch_event(event);
        });

    CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
    thread_data.timers.set(timer_id, timer);

    return timer_id;
}

void EventLoopManagerMacOS::unregister_timer(intptr_t timer_id)
{
    auto& thread_data = ThreadData::the();
    thread_data.timer_id_allocator.deallocate(static_cast<int>(timer_id));

    auto timer = thread_data.timers.take(static_cast<int>(timer_id));
    VERIFY(timer.has_value());
    CFRunLoopTimerInvalidate(*timer);
    CFRelease(*timer);
}

struct SocketNotifierCallbackContext : public RefCounted<SocketNotifierCallbackContext> {
    WeakPtr<Core::EventReceiver> notifier;
};

static void const* retain_socket_notifier_callback_context(void const* info)
{
    auto const* context = static_cast<SocketNotifierCallbackContext const*>(info);
    context->ref();
    return context;
}

static void release_socket_notifier_callback_context(void const* info)
{
    auto const* context = static_cast<SocketNotifierCallbackContext const*>(info);