/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2020 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #include "xenia/ui/loop_gtk.h" #include #include #include "xenia/base/assert.h" namespace xe { namespace ui { std::unique_ptr Loop::Create() { return std::make_unique(); } GTKLoop::GTKLoop() : thread_id_() { gtk_init(nullptr, nullptr); xe::threading::Fence init_fence; thread_ = std::thread([&init_fence, this]() { xe::threading::set_name("GTK Loop"); thread_id_ = std::this_thread::get_id(); init_fence.Signal(); ThreadMain(); quit_fence_.Signal(); }); init_fence.Wait(); } GTKLoop::~GTKLoop() { Quit(); thread_.join(); } void GTKLoop::ThreadMain() { gtk_main(); } bool GTKLoop::is_on_loop_thread() { return thread_id_ == std::this_thread::get_id(); } gboolean _posted_fn_thunk(gpointer posted_fn) { // convert gpointer back to std::function, call it, then free std::function std::function* f = reinterpret_cast*>(posted_fn); std::function& func = *f; func(); delete f; // Tells GDK we don't want to run this again return G_SOURCE_REMOVE; } void GTKLoop::Post(std::function fn) { assert_true(thread_id_ != std::thread::id()); // converting std::function to a generic pointer for gdk gdk_threads_add_idle(_posted_fn_thunk, reinterpret_cast( new std::function(fn))); } void GTKLoop::PostDelayed(std::function fn, uint64_t delay_millis) { gdk_threads_add_timeout( delay_millis, _posted_fn_thunk, reinterpret_cast(new std::function(fn))); } void GTKLoop::Quit() { assert_true(thread_id_ != std::thread::id()); Post([]() { gtk_main_quit(); }); } void GTKLoop::AwaitQuit() { quit_fence_.Wait(); } } // namespace ui } // namespace xe