#ifndef BW_CEF_CLIENT_HANDLER_H
#define BW_CEF_CLIENT_HANDLER_H
#include <include/cef_client.h>
#include <include/cef_life_span_handler.h>
#include <include/cef_v8.h>
#include <string>
#include <vector>
#include "bw_handle_map.hpp"
#include "../application.h"
#include "../common.h"
struct ExternalInvocationHandlerData {
bw_BrowserWindow* bw;
std::string cmd;
std::vector<std::string> params;
};
class ClientHandler : public CefClient, public CefLifeSpanHandler {
bw_Application* app;
public:
ClientHandler( bw_Application* app ) : app(app) {}
virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override {
return this;
}
virtual bool OnProcessMessageReceived(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefProcessId source_process,
CefRefPtr<CefProcessMessage> message
) override {
if ( message->GetName() == "eval-js-result" ) {
this->onEvalJsResultReceived( browser, frame, source_process, message );
return true;
}
else if ( message->GetName() == "invoke-handler" ) {
this->onInvokeHandlerReceived( browser, frame, source_process, message );
return true;
}
else if ( message->GetName() == "on-browser-created" ) {
this->onBrowserCreated( browser, frame, source_process, message );
return true;
}
else
fprintf(stderr, "Unknown process message received: %s\n", message->GetName().ToString().c_str() );
return false;
}
protected:
static void externalInvocationHandlerFunc( bw_Application* app, void* data );
void onBrowserCreated(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame>,
CefProcessId,
CefRefPtr<CefProcessMessage> msg
) {
auto args = msg->GetArgumentList();
bw_BrowserWindow* bw_handle;
args->GetBinary( 0 )->GetData( (void*)&bw_handle, sizeof( bw_handle ), 0 );
bw_BrowserWindowCreationCallbackFn callback;
args->GetBinary( 1 )->GetData( (void*)&callback, sizeof( callback ), 0 );
void* callback_data;
args->GetBinary( 2 )->GetData( (void*)&callback_data, sizeof( callback_data ), 0 );
bool dev_tools_enabled = args->GetBool( 3 );
CefRefPtr<CefBrowser>* cef_ptr = new CefRefPtr<CefBrowser>( browser );
bw_handle->impl.cef_ptr = (void*)cef_ptr;
bw::bw_handle_map.store( *cef_ptr, bw_handle );
if ( dev_tools_enabled )
this->openDevTools( bw_handle, browser->GetHost() );
callback( bw_handle, callback_data );
}
void onEvalJsResultReceived(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefProcessId source_process,
CefRefPtr<CefProcessMessage> message
) {
(void)(browser);
(void)(frame);
(void)(source_process);
auto msg_args = message->GetArgumentList();
bool success = msg_args->GetBool( 0 );
CefString cef_result = msg_args->GetString( 1 );
std::string result = cef_result.ToString();
bw_BrowserWindow* bw_handle;
CefRefPtr<CefBinaryValue> bw_handle_bin = msg_args->GetBinary( 2 );
bw_handle_bin->GetData( (void*)&bw_handle, sizeof( bw_handle ), 0 );
bw_BrowserWindowJsCallbackFn callback;
CefRefPtr<CefBinaryValue> cb_bin = msg_args->GetBinary( 3 );
cb_bin->GetData( (void*)&callback, sizeof( callback ), 0 );
void* user_data;
CefRefPtr<CefBinaryValue> user_data_bin = msg_args->GetBinary( 4 );
user_data_bin->GetData( (void*)&user_data, sizeof( user_data ), 0 );
if (success) {
callback( bw_handle, user_data, result.c_str(), 0 );
}
else {
bw_Err error = bw_Err_new_with_msg( 1, result.c_str() );
callback( bw_handle, user_data, 0, &error );
bw_Err_free( &error );
}
}
void onInvokeHandlerReceived(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefProcessId source_process,
CefRefPtr<CefProcessMessage> msg
) {
(void)(frame);
(void)(source_process);
std::optional<bw_BrowserWindow*> _bw_handle = bw::bw_handle_map.fetch( browser );
BW_ASSERT( _bw_handle.has_value(), "Link between CEF's browser handle and our handle does not exist!\n" );
bw_BrowserWindow* our_handle = *_bw_handle;
auto msg_args = msg->GetArgumentList();
CefString cmd = msg_args->GetString( 0 );
std::string cmd_str = cmd.ToString();
std::vector<std::string> params; params.reserve( msg_args->GetSize() - 1 );
for ( size_t i = 1; i < msg_args->GetSize(); i++ ) {
std::string param = msg_args->GetString( i ).ToString();
params.push_back( param );
}
auto dispatch_data = new ExternalInvocationHandlerData {
our_handle,
cmd_str,
params
};
bw_Application_dispatch(
our_handle->window->app,
externalInvocationHandlerFunc,
(void*)dispatch_data
);
}
void openDevTools( bw_BrowserWindow* bw, const CefRefPtr<CefBrowserHost>& host ) {
CefRefPtr<CefClient> client;
CefBrowserSettings settings;
CefPoint point;
CefWindowInfo info;
info.SetAsPopup( bw->window->impl.handle, "Dev Tools" );
host->ShowDevTools( info, client, settings, point );
}
IMPLEMENT_REFCOUNTING(ClientHandler);
};
#endif