Leviathan  0.8.0.0
Leviathan game engine
GlobalCEFHandler.cpp
Go to the documentation of this file.
1 // ------------------------------------ //
2 #include "GlobalCEFHandler.h"
3 
5 
6 #include "include/cef_app.h"
7 
8 #include <boost/filesystem.hpp>
9 
10 #include <iostream>
11 using namespace Leviathan;
12 // ------------------------------------ //
13 
14 
16  int argcount, char* args[], int& returnvalue,
17  std::shared_ptr<CEFApplicationKeeper>& keeper, const std::string& logname
18 #ifdef _WIN32
19 #ifdef CEF_ENABLE_SANDBOX
20  ,
21  CefScopedSandboxInfo& windowssandbox
22 #endif
23  ,
24  HINSTANCE hInstance
25 #endif // _WIN32
26 )
27 {
28  // Check for no graphics mode //
29  for(int i = 0; i < argcount; ++i) {
30  if(std::string_view(args[i]).find("--nogui") != std::string_view::npos) {
31  // No gui commandline specified //
32  std::cout << "Not using CEF because --nogui is specified" << std::endl;
33  return false;
34  }
35  }
36 
37  // Run CEF startup //
38  keeper = std::make_shared<CEFApplicationKeeper>();
39 
40  void* windows_sandbox_info = nullptr;
41 
42 #ifdef CEF_ENABLE_SANDBOX
43  windows_sandbox_info = &sandbox;
44 #endif
45 
46  // Provide CEF with command-line arguments //
47 #ifdef _WIN32
48  CefMainArgs main_args(hInstance);
49 #else
50  // Make a copy of the args to not have CEF mess with them
51  std::vector<char*> cefArgs;
52  std::vector<std::string> cefArgData;
53 
54  cefArgs.resize(argcount);
55  cefArgData.reserve(argcount);
56 
57  for(int i = 0; i < argcount; ++i) {
58 
59  cefArgData.push_back(args[i]);
60  cefArgs[i] = cefArgData.back().data();
61  }
62 
63  CefMainArgs main_args(cefArgs.size(), cefArgs.data());
64  // CefMainArgs main_args(argcount, args);
65 #endif // _WIN32
66 
67  // Callback object //
68  keeper->CEFApp = CefRefPtr<GUI::CefApplication>(new GUI::CefApplication());
69 
70  // Check are we a sub process //
71  int exit_code = CefExecuteProcess(main_args, keeper->CEFApp.get(), windows_sandbox_info);
72  if(exit_code >= 0) {
73  // This was a sub process //
74  returnvalue = exit_code;
75 
76  return true;
77  }
78 
79  // Specify CEF global settings here.
80  CefSettings settings;
81 
82  // Apparently this "just works" on non-windows platforms
83 #if !defined(CEF_ENABLE_SANDBOX) && defined(_WIN32)
84  settings.no_sandbox = true;
85 #endif
86 
87  try {
88  CefString(&settings.locales_dir_path) =
89  boost::filesystem::canonical("Data/locales").wstring();
90 
91  const auto currentCanonical = boost::filesystem::canonical("./").wstring();
92 
93  // CefString(&settings.resources_dir_path) = currentCanonical;
94 
95  CefString(&settings.log_file) =
96  currentCanonical + Convert::Utf8ToUtf16("/" + logname + "LogCEF.txt");
97 
98  const auto cachePath = currentCanonical + L"/Data/Cache/CEF";
99  boost::filesystem::create_directories(cachePath);
100 
101  CefString(&settings.cache_path) = cachePath;
102 
103  } catch(const boost::filesystem::filesystem_error& e) {
104 
105  std::stringstream msg;
106  msg << "Error missing file or accessing cache location: " << e.what() << "\n";
107 
108 
109  std::ofstream write(std::string("Leviathan_start_failure_") +
110 #ifdef __linux
111  std::to_string(::getpid()) +
112 #endif //__linux
113  ".txt");
114  write << msg.str();
115  write << "Args are (" << argcount << ")" << std::endl;
116  for(int i = 0; i < argcount; ++i)
117  write << args[i] << std::endl;
118  write << std::endl;
119  write.close();
120 
121  std::cout << msg.str();
122  abort();
123  }
124 
125  // TODO: log_severity
126  // settings.log_severity = cef_log_severity_t::LOGSEVERITY_DEBUG;
127 
128  // TODO: user agent
129 
130  settings.windowless_rendering_enabled = true;
131 
132  settings.external_message_pump = true;
133 
134  // Apparently this is missing from the windows version but not the linux version. For some
135  // reason?
136  // settings.single_process = false;
137 
138  // // Enable remote debugging
139  // settings.remote_debugging_port = 9090;
140 
141  // Only works on windows
142  // And the OnPaint assumes it is on the main thread so this doesn't work at all
143  settings.multi_threaded_message_loop = false;
144 
145  // Initialize CEF.
146  CefInitialize(main_args, settings, keeper->CEFApp.get(), windows_sandbox_info);
147 
148  CEFInitialized = true;
149 
150  AccessToThese = keeper.get();
151 
152  // Wasn't a sub process //
153  return false;
154 }
155 // ------------------------------------ //
157 {
158  if(!CEFInitialized)
159  return;
160 
161  // Close it down //
162  CefShutdown();
163 
164  // The automatic templates remove the need for this message, which won't be logged anyway
165  // std::cout << "CEF shutdown called" << std::endl;
166 }
167 // ------------------------------------ //
169 {
170  if(!CEFInitialized) {
171  LOG_ERROR("DoCEFMessageLoopWork called before CEF is initialized");
172  return;
173  }
174 
175  CefDoMessageLoopWork();
176 }
177 // ------------------------------------ //
179 {
180  return AccessToThese;
181 }
182 
184  std::shared_ptr<GUI::JSAsyncCustom> ptr)
185 {
186  std::unique_lock<std::recursive_mutex> guard(JSCustomMutex);
187 
188  // Add it //
189  CustomJSHandlers.push_back(ptr);
190 
191  // Notify all //
192  for(size_t i = 0; i < JSAsynToNotify.size(); i++) {
193  GUARD_LOCK_OTHER_NAME(JSAsynToNotify[i], guard2);
194  JSAsynToNotify[i]->RegisterNewCustom(guard2, ptr);
195  }
196 
197  // Things created after this will automatically retrieve the ones that are registered
198  // before it is created
199 }
200 
202  GUI::JSAsyncCustom* toremove)
203 {
204  std::unique_lock<std::recursive_mutex> guard(JSCustomMutex);
205 
206  // Notify all objects //
207  for(size_t i = 0; i < JSAsynToNotify.size(); i++) {
208  JSAsynToNotify[i]->UnregisterCustom(toremove);
209  }
210 
211  // Compare pointers and remove it //
212  for(size_t i = 0; i < CustomJSHandlers.size(); i++) {
213  if(CustomJSHandlers[i].get() == toremove) {
214 
215  CustomJSHandlers.erase(CustomJSHandlers.begin() + i);
216  return;
217  }
218  }
219 }
220 
221 DLLEXPORT const std::vector<std::shared_ptr<GUI::JSAsyncCustom>>&
223 {
224  return CustomJSHandlers;
225 }
226 
228 {
229  std::unique_lock<std::recursive_mutex> guard(JSCustomMutex);
230 
231  JSAsynToNotify.push_back(ptr);
232 }
233 
236 {
237  std::unique_lock<std::recursive_mutex> guard(JSCustomMutex);
238 
239  for(size_t i = 0; i < JSAsynToNotify.size(); i++) {
240 
241  if(JSAsynToNotify[i] == ptr) {
242 
243  JSAsynToNotify.erase(JSAsynToNotify.begin() + i);
244  return;
245  }
246  }
247 }
248 
249 std::recursive_mutex Leviathan::GlobalCEFHandler::JSCustomMutex;
250 
251 std::vector<GUI::LeviathanJavaScriptAsync*> Leviathan::GlobalCEFHandler::JSAsynToNotify;
252 
253 std::vector<std::shared_ptr<GUI::JSAsyncCustom>> Leviathan::GlobalCEFHandler::CustomJSHandlers;
254 
256 
258 
259 // ------------------------------------ //
261  std::shared_ptr<GUI::CustomExtension> extension)
262 {
263  CustomExtensions.push_back(extension);
264  AccessToThese->CEFApp->RegisterCustomExtension(extension);
265 }
266 
268  CefRefPtr<CefBrowser> browser, CefProcessId source_process,
269  CefRefPtr<CefProcessMessage> message)
270 {
271  // Pass to the extensions until it is handled //
272  for(const auto& ext : CustomExtensions) {
273 
274  if(ext->MessageHandler) {
275 
276  if(ext->MessageHandler->OnProcessMessageReceived(browser, source_process, message))
277  return true;
278  }
279  }
280 
281  return false;
282 }
283 
284 std::vector<std::shared_ptr<GUI::CustomExtension>> GlobalCEFHandler::CustomExtensions;
285 
286 // ------------------ CEFSandboxInfoKeeper ------------------ //
288 
290 // ------------------------------------ //
291 DLLEXPORT CefRefPtr<GUI::CefApplication> Leviathan::CEFApplicationKeeper::GetCEFApp() const
292 {
293  return CEFApp;
294 }
Provides client applications and modules (not done) support for defining custom request responses.
static std::vector< std::shared_ptr< GUI::CustomExtension > > CustomExtensions
Custom extension storage here to allow routing messages to the right one.
static DLLEXPORT const std::vector< std::shared_ptr< GUI::JSAsyncCustom > > & GetRegisteredCustomHandlers()
Mainly allows LeviathanJavaScriptAsync to access the list of handlers.
static DLLEXPORT void RegisterCustomJavaScriptQueryHandler(std::shared_ptr< GUI::JSAsyncCustom > ptr)
Registers a new JavaScript query handler.
static std::vector< GUI::LeviathanJavaScriptAsync * > JSAsynToNotify
Stored to be able to notify all LeviathanJavaScriptAsync objects.
static DLLEXPORT bool CEFFirstCheckChildProcess(int argcount, char *args[], int &returnvalue, std::shared_ptr< CEFApplicationKeeper > &keeper, const std::string &logname)
This is the first function called in the Engine to handle CEF child processes.
#define LOG_ERROR(x)
Definition: Define.h:94
static DLLEXPORT std::wstring Utf8ToUtf16(const std::string &utf8str)
Decodes an UTF8 string to an UTF16 string (wide string/wstring)
Definition: Convert.cpp:76
static DLLEXPORT void RegisterCustomExtension(std::shared_ptr< GUI::CustomExtension > extension)
Registers a custom extension for all render processes to load as a V8 extension.
static DLLEXPORT void UnRegisterCustomJavaScriptQueryHandler(GUI::JSAsyncCustom *toremove)
Unregisters a registered query handler.
Handler for new render processes.
DLLEXPORT CefRefPtr< GUI::CefApplication > GetCEFApp() const
Gets the corresponding Gui::CefApplication.
#define GUARD_LOCK_OTHER_NAME(x, y)
Definition: ThreadSafe.h:127
Handles asynchronous javascript requests.
static std::recursive_mutex JSCustomMutex
static DLLEXPORT void UnRegisterJSAsync(GUI::LeviathanJavaScriptAsync *ptr)
Unregisters a registered LeviathanJavaScriptAsync.
Keeps certain CEF objects allocated for long enough.
static DLLEXPORT void RegisterJSAsync(GUI::LeviathanJavaScriptAsync *ptr)
Registers a LeviathanJavaScriptAsync to receive notifications about JSAsyncCustom changes.
static DLLEXPORT void CEFLastThingInProgram()
static bool CEFInitialized
A flag for making sure that functions are only ran if CEF is actually used.
static DLLEXPORT bool HandleCustomExtensionProcessMessage(CefRefPtr< CefBrowser > browser, CefProcessId source_process, CefRefPtr< CefProcessMessage > message)
Handles passing a custom process message.
CefRefPtr< GUI::CefApplication > CEFApp
#define DLLEXPORT
Definition: Include.h:84
The access mask controls which registered functions and classes a script sees.
Definition: GameModule.h:12
static CEFApplicationKeeper * AccessToThese
static DLLEXPORT CEFApplicationKeeper * GetCEFObjects()
static std::vector< std::shared_ptr< GUI::JSAsyncCustom > > CustomJSHandlers
Stores all the custom handlers.
static DLLEXPORT void DoCEFMessageLoopWork()