]> git.sesse.net Git - nageru/blob - nageru/nageru_cef_app.h
IWYU-fix nageru/*.h.
[nageru] / nageru / nageru_cef_app.h
1 #ifndef _NAGERU_CEF_APP_H
2 #define _NAGERU_CEF_APP_H 1
3
4 // NageruCefApp deals with global state around CEF, in particular the global
5 // CEF event loop. CEF is pretty picky about which threads everything runs on;
6 // in particular, the documentation says CefExecute, CefInitialize and
7 // CefRunMessageLoop must all be on the main thread (ie., the first thread
8 // created). However, Qt wants to run _its_ event loop on this thread, too,
9 // and integrating the two has proved problematic (see also the comment in
10 // main.cpp). It seems that as long as you don't have two GLib loops running,
11 // it's completely fine in practice to have a separate thread for the main loop
12 // (running CefInitialize, CefRunMessageLoop, and finally CefDestroy).
13 // Many other tasks (like most things related to interacting with browsers)
14 // have to be run from the message loop, but that's fine; CEF gives us tools
15 // to post tasks to it.
16
17 #include <cef_app.h>
18 #include <cef_base.h>
19 #include <cef_browser.h>
20 #include <cef_browser_process_handler.h>
21 #include <cef_command_line.h>
22 #include <cef_render_process_handler.h>
23 #include <cef_task.h>
24
25 #include <condition_variable>
26 #include <functional>
27 #include <mutex>
28 #include <thread>
29 #include <utility>
30
31 // Takes in arbitrary lambdas and converts them to something CefPostTask() will accept.
32 class CEFTaskAdapter : public CefTask
33 {
34 public:
35         CEFTaskAdapter(const std::function<void()>&& func)
36                 : func(std::move(func)) {}
37         void Execute() override { func(); }
38
39 private:
40         std::function<void()> func;
41
42         IMPLEMENT_REFCOUNTING(CEFTaskAdapter);
43 };
44
45 // Runs and stops the CEF event loop, and also makes some startup tasks.
46 class NageruCefApp : public CefApp, public CefRenderProcessHandler, public CefBrowserProcessHandler {
47 public:
48         NageruCefApp() {}
49
50         // Starts up the CEF main loop if it does not already run, and blocks until
51         // CEF is properly initialized. You can call initialize_ref() multiple times,
52         // which will then increase the refcount.
53         void initialize_cef();
54
55         // If the refcount goes to zero, shut down the main loop and uninitialize CEF.
56         void unref_cef();
57
58         // Closes the given browser, and blocks until it is done closing.
59         //
60         // NOTE: We can't call unref_cef() from close_browser(), since
61         // CefRefPtr<T> does not support move semantics, so it would have a
62         // refcount of either zero or two going into close_browser (not one,
63         // as it should). The latter means the caller would hold on to an extra
64         // reference to the browser (which triggers an assert failure), and the
65         // former would mean that the browser gets deleted before it's closed.
66         void close_browser(CefRefPtr<CefBrowser> browser);
67
68         CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override
69         {
70                 return this;
71         }
72
73         CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() override
74         {
75                 return this;
76         }
77
78         void OnBeforeCommandLineProcessing(const CefString& process_type, CefRefPtr<CefCommandLine> command_line) override;
79
80 private:
81         void cef_thread_func();
82
83         std::thread cef_thread;
84         std::mutex cef_mutex;
85         int cef_thread_refcount = 0;  // Under <cef_mutex>.
86         bool cef_initialized = false;  // Under <cef_mutex>.
87         std::condition_variable cef_initialized_cond;
88
89         IMPLEMENT_REFCOUNTING(NageruCefApp);
90 };
91
92 #endif  // !defined(_NAGERU_CEF_APP_H)