// Copyright 2020 The Chromium Embedded Framework Authors. // Portions copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "cef/libcef/browser/ui_thread.h" #include "base/at_exit.h" #include "base/logging.h" #include "cef/libcef/browser/main_runner.h" #include "cef/libcef/browser/thread_util.h" #include "content/browser/scheduler/browser_task_executor.h" #if BUILDFLAG(IS_LINUX) #include "ui/base/ozone_buildflags.h" #if BUILDFLAG(IS_OZONE_X11) #include "ui/ozone/platform/x11/ozone_platform_x11.h" #endif #endif #if BUILDFLAG(IS_WIN) #include #endif CefUIThread::CefUIThread(CefMainRunner* runner, base::OnceClosure setup_callback) : runner_(runner), setup_callback_(std::move(setup_callback)) {} CefUIThread::~CefUIThread() { Stop(); } void CefUIThread::Start() { base::AutoLock lock(thread_lock_); bool success = base::PlatformThread::CreateWithType( 0, this, &thread_, base::ThreadType::kDefault); if (!success) { LOG(FATAL) << "failed to UI create thread"; } } void CefUIThread::Stop() { base::AutoLock lock(thread_lock_); if (!stopping_) { stopping_ = true; CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefMainRunner::QuitMessageLoop, base::Unretained(runner_))); } // Can't join if the |thread_| is either already gone or is non-joinable. if (thread_.is_null()) { return; } base::PlatformThread::Join(thread_); thread_ = base::PlatformThreadHandle(); stopping_ = false; } bool CefUIThread::WaitUntilThreadStarted() const { DCHECK(owning_sequence_checker_.CalledOnValidSequence()); start_event_.Wait(); return true; } void CefUIThread::InitializeBrowserRunner( content::MainFunctionParams main_function_params) { #if BUILDFLAG(IS_LINUX) #if BUILDFLAG(IS_OZONE_X11) // Disable creation of GtkUi (interface to GTK desktop features) and cause // ui::GetDefaultLinuxUi() (and related functions) to return nullptr. We // can't use GtkUi in combination with multi-threaded-message-loop because // Chromium's GTK implementation doesn't use GDK threads. Light/dark theme // changes will still be detected via DarkModeManagerLinux. ui::SetMultiThreadedMessageLoopX11(); #endif #endif // Use our own browser process runner. browser_runner_ = content::BrowserMainRunner::Create(); // Initialize browser process state. Uses the current thread's message loop. int exit_code = browser_runner_->Initialize(std::move(main_function_params)); CHECK_EQ(exit_code, -1); } void CefUIThread::ThreadMain() { base::PlatformThread::SetName("CefUIThread"); #if BUILDFLAG(IS_WIN) // Initializes the COM library on the current thread. CoInitialize(nullptr); #endif start_event_.Signal(); std::move(setup_callback_).Run(); runner_->RunMessageLoop(); // Stop may be called before InitializeBrowserRunner if // content::ContentMainRun was not successful (for example, due to process // singleton relaunch). if (browser_runner_) { browser_runner_->Shutdown(); browser_runner_.reset(); } // This will be a no-op if there is no BrowserTaskExecutor. content::BrowserTaskExecutor::Shutdown(); if (!shutdown_callback_.is_null()) { std::move(shutdown_callback_).Run(); } // Run exit callbacks on the UI thread to avoid sequence check failures. base::AtExitManager::ProcessCallbacksNow(); #if BUILDFLAG(IS_WIN) // Closes the COM library on the current thread. CoInitialize must // be balanced by a corresponding call to CoUninitialize. CoUninitialize(); #endif }