/* * Copyright (C) 2014 Igalia S.L. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #if USE(GLIB) #include "GMainLoopSource.h" #include namespace WTF { GMainLoopSource& GMainLoopSource::createAndDeleteOnDestroy() { return *new GMainLoopSource(DeleteOnDestroy); } GMainLoopSource::GMainLoopSource() : m_deleteOnDestroy(DoNotDeleteOnDestroy) , m_status(Ready) { } GMainLoopSource::GMainLoopSource(DeleteOnDestroyType deleteOnDestroy) : m_deleteOnDestroy(deleteOnDestroy) , m_status(Ready) { } GMainLoopSource::~GMainLoopSource() { cancel(); } bool GMainLoopSource::isScheduled() const { return m_status == Scheduled; } bool GMainLoopSource::isActive() const { return m_status != Ready; } void GMainLoopSource::cancel() { if (!m_source) return; GRefPtr source; m_source.swap(source); if (m_cancellable) g_cancellable_cancel(m_cancellable.get()); g_source_destroy(source.get()); destroy(); } void GMainLoopSource::reset() { m_status = Ready; m_source = nullptr; m_cancellable = nullptr; m_voidCallback = nullptr; m_boolCallback = nullptr; m_destroyCallback = nullptr; } void GMainLoopSource::scheduleIdleSource(const char* name, GSourceFunc sourceFunction, int priority, GMainContext* context) { ASSERT(m_status == Ready); m_status = Scheduled; m_source = adoptGRef(g_idle_source_new()); g_source_set_name(m_source.get(), name); if (priority != G_PRIORITY_DEFAULT_IDLE) g_source_set_priority(m_source.get(), priority); g_source_set_callback(m_source.get(), sourceFunction, this, nullptr); g_source_attach(m_source.get(), context); } void GMainLoopSource::schedule(const char* name, std::function function, int priority, std::function destroyFunction, GMainContext* context) { cancel(); m_voidCallback = WTF::move(function); m_destroyCallback = WTF::move(destroyFunction); scheduleIdleSource(name, reinterpret_cast(voidSourceCallback), priority, context); } void GMainLoopSource::schedule(const char* name, std::function function, int priority, std::function destroyFunction, GMainContext* context) { cancel(); m_boolCallback = WTF::move(function); m_destroyCallback = WTF::move(destroyFunction); scheduleIdleSource(name, reinterpret_cast(boolSourceCallback), priority, context); } void GMainLoopSource::schedule(const char* name, std::function function, GSocket* socket, GIOCondition condition, std::function destroyFunction, GMainContext* context) { cancel(); ASSERT(m_status == Ready); m_status = Scheduled; m_socketCallback = WTF::move(function); m_destroyCallback = WTF::move(destroyFunction); m_cancellable = adoptGRef(g_cancellable_new()); m_source = adoptGRef(g_socket_create_source(socket, condition, m_cancellable.get())); g_source_set_name(m_source.get(), name); g_source_set_callback(m_source.get(), reinterpret_cast(socketSourceCallback), this, nullptr); g_source_attach(m_source.get(), context); } void GMainLoopSource::scheduleTimeoutSource(const char* name, GSourceFunc sourceFunction, int priority, GMainContext* context) { ASSERT(m_status == Ready); m_status = Scheduled; ASSERT(m_source); g_source_set_name(m_source.get(), name); if (priority != G_PRIORITY_DEFAULT) g_source_set_priority(m_source.get(), priority); g_source_set_callback(m_source.get(), sourceFunction, this, nullptr); g_source_attach(m_source.get(), context); } void GMainLoopSource::scheduleAfterDelay(const char* name, std::function function, std::chrono::milliseconds delay, int priority, std::function destroyFunction, GMainContext* context) { cancel(); m_source = adoptGRef(g_timeout_source_new(delay.count())); m_voidCallback = WTF::move(function); m_destroyCallback = WTF::move(destroyFunction); scheduleTimeoutSource(name, reinterpret_cast(voidSourceCallback), priority, context); } void GMainLoopSource::scheduleAfterDelay(const char* name, std::function function, std::chrono::milliseconds delay, int priority, std::function destroyFunction, GMainContext* context) { cancel(); m_source = adoptGRef(g_timeout_source_new(delay.count())); m_boolCallback = WTF::move(function); m_destroyCallback = WTF::move(destroyFunction); scheduleTimeoutSource(name, reinterpret_cast(boolSourceCallback), priority, context); } void GMainLoopSource::scheduleAfterDelay(const char* name, std::function function, std::chrono::seconds delay, int priority, std::function destroyFunction, GMainContext* context) { cancel(); m_source = adoptGRef(g_timeout_source_new_seconds(delay.count())); m_voidCallback = WTF::move(function); m_destroyCallback = WTF::move(destroyFunction); scheduleTimeoutSource(name, reinterpret_cast(voidSourceCallback), priority, context); } void GMainLoopSource::scheduleAfterDelay(const char* name, std::function function, std::chrono::seconds delay, int priority, std::function destroyFunction, GMainContext* context) { cancel(); m_source = adoptGRef(g_timeout_source_new_seconds(delay.count())); m_boolCallback = WTF::move(function); m_destroyCallback = WTF::move(destroyFunction); scheduleTimeoutSource(name, reinterpret_cast(boolSourceCallback), priority, context); } void GMainLoopSource::voidCallback() { if (!m_source) return; ASSERT(m_voidCallback); ASSERT(m_status == Scheduled); m_status = Dispatched; GSource* source = m_source.get(); m_voidCallback(); if (source == m_source.get()) destroy(); } bool GMainLoopSource::boolCallback() { if (!m_source) return false; ASSERT(m_boolCallback); ASSERT(m_status == Scheduled || m_status == Dispatched); m_status = Dispatched; GSource* source = m_source.get(); bool retval = m_boolCallback(); if (!retval && source == m_source.get()) destroy(); return retval; } bool GMainLoopSource::socketCallback(GIOCondition condition) { if (!m_source) return false; ASSERT(m_socketCallback); ASSERT(m_status == Scheduled || m_status == Dispatched); m_status = Dispatched; if (g_cancellable_is_cancelled(m_cancellable.get())) { destroy(); return false; } GSource* source = m_source.get(); bool retval = m_socketCallback(condition); if (!retval && source == m_source.get()) destroy(); return retval; } void GMainLoopSource::destroy() { auto destroyCallback = WTF::move(m_destroyCallback); auto deleteOnDestroy = m_deleteOnDestroy; reset(); if (destroyCallback) destroyCallback(); if (deleteOnDestroy == DoNotDeleteOnDestroy) return; delete this; } gboolean GMainLoopSource::voidSourceCallback(GMainLoopSource* source) { source->voidCallback(); return G_SOURCE_REMOVE; } gboolean GMainLoopSource::boolSourceCallback(GMainLoopSource* source) { return source->boolCallback() == Continue; } gboolean GMainLoopSource::socketSourceCallback(GSocket*, GIOCondition condition, GMainLoopSource* source) { return source->socketCallback(condition) == Continue; } } // namespace WTF #endif // USE(GLIB)