Skip to content

Commit

Permalink
Make CEF call creation callback whenever the DOM content is actually …
Browse files Browse the repository at this point in the history
…loaded.
  • Loading branch information
bamidev committed Mar 1, 2024
1 parent e8df971 commit b92c8b3
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 31 deletions.
2 changes: 1 addition & 1 deletion c/src/cef/bw_handle_map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@



bw::BwHandleMap bw::bw_handle_map;
bw::HandleMap bw::bw_handle_map;
35 changes: 25 additions & 10 deletions c/src/cef/bw_handle_map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,51 +12,66 @@

namespace bw {

struct OnCreateCallback {
bw_BrowserWindowCreationCallbackFn callback;
void* data;
};

struct BrowserInfo {
bw_BrowserWindow* handle;
std::optional<OnCreateCallback> callback;
};

// A thread safe class that links CEF browser handles to our browser window handdles.
// This makes it possible to get a bw_BrowserWindow* from a CefRefPtr<CefBrowser>, from any thread.
class BwHandleMap {
class HandleMap {
// The CefBrowser's GetIdentifier output is used as the key to identify CEF browser handles
std::map<int, bw_BrowserWindow*> map;
std::map<int, BrowserInfo> map;
std::mutex mutex;

public:
// The only constructor is the default constructor
BwHandleMap() {}
HandleMap() {}

// Remove a link
void drop( CefRefPtr<CefBrowser> cef_handle ) {
this->mutex.lock();
this->map.erase( cef_handle->GetIdentifier() );
this->map.erase(cef_handle->GetIdentifier());
this->mutex.unlock();
}

// Stores a link
void store( CefRefPtr<CefBrowser> cef_handle, bw_BrowserWindow* our_handle ) {
void store(CefRefPtr<CefBrowser> cef_handle, bw_BrowserWindow* our_handle, bw_BrowserWindowCreationCallbackFn callback, void* callback_data) {
this->mutex.lock();
this->map[ cef_handle->GetIdentifier() ] = our_handle;
BrowserInfo& bw_info = this->map[cef_handle->GetIdentifier()];
bw_info.handle = our_handle;
bw_info.callback = std::optional(OnCreateCallback {
callback,
data: callback_data
});
this->mutex.unlock();
}

// Fetches a bw_BrowserWindow handle from a cef handle.
// Returns an optional bw_BrowserWindow pointer.
std::optional<bw_BrowserWindow*> fetch( CefRefPtr<CefBrowser> cef_handle ) {
std::optional<BrowserInfo> fetch( CefRefPtr<CefBrowser> cef_handle ) {
this->mutex.lock();
auto it = this->map.find( cef_handle->GetIdentifier() );

// If not found return nothing
if ( it == this->map.end() )
return std::optional<bw_BrowserWindow*>();
return std::optional<BrowserInfo>();

// If found:
std::optional<bw_BrowserWindow*> result( (*it).second );
std::optional<BrowserInfo> result( (*it).second );
this->mutex.unlock();

return result;
}
};

// A global instance
extern BwHandleMap bw_handle_map;
extern HandleMap bw_handle_map;
}


Expand Down
43 changes: 32 additions & 11 deletions c/src/cef/client_handler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <include/cef_v8.h>
#include <string>
#include <vector>
#include <include/cef_load_handler.h>

#include "bw_handle_map.hpp"
#include "../application.h"
Expand All @@ -19,15 +20,37 @@ struct ExternalInvocationHandlerData {
std::vector<std::string> params;
};

class ClientHandler : public CefClient, public CefLifeSpanHandler {
class ClientHandler : public CefClient, public CefLifeSpanHandler, public CefLoadHandler {

bw_Application* app;

public:
ClientHandler( bw_Application* app ) : app(app) {}

virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override {
return this;
virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override { return this; }

virtual CefRefPtr<CefLoadHandler> GetLoadHandler() override { return this; }

virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int httpStatusCode) override {
std::optional<bw::BrowserInfo> bw_info_opt = bw::bw_handle_map.fetch(browser);
BW_ASSERT(bw_info_opt.has_value(), "Link between CEF's browser handle and our handle does not exist!\n");
auto bw_info = bw_info_opt.value();
auto callback_opt = bw_info.callback;
if (callback_opt.has_value()) {
auto value = callback_opt.value();
value.callback(bw_info.handle, value.data);
}
}

virtual void OnLoadError(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefLoadHandler::ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl) override {
std::optional<bw::BrowserInfo> bw_info_opt = bw::bw_handle_map.fetch(browser);
BW_ASSERT(bw_info_opt.has_value(), "Link between CEF's browser handle and our handle does not exist!\n");
auto bw_info = bw_info_opt.value();
auto callback_opt = bw_info.callback;
if (callback_opt.has_value()) {
auto value = callback_opt.value();
value.callback(bw_info.handle, value.data);
}
}

virtual bool OnProcessMessageReceived(
Expand All @@ -47,7 +70,8 @@ class ClientHandler : public CefClient, public CefLifeSpanHandler {
this->onInvokeHandlerReceived( browser, frame, source_process, message );
return true;
}
// The message to send data from within javascript to application code
// The OnBrowserCreated event is fired on another process, so we need to catch it here and
// update the bw_handle_map in this process.
else if ( message->GetName() == "on-browser-created" ) {
this->onBrowserCreated( browser, frame, source_process, message );
return true;
Expand Down Expand Up @@ -84,14 +108,11 @@ class ClientHandler : public CefClient, public CefLifeSpanHandler {
bw_handle->impl.cef_ptr = (void*)cef_ptr;

// Store a link with the cef browser handle and our handle in a global map
bw::bw_handle_map.store( *cef_ptr, bw_handle );
bw::bw_handle_map.store(*cef_ptr, bw_handle, callback, callback_data);

// Open dev-tools window
if ( dev_tools_enabled )
this->openDevTools( bw_handle, browser->GetHost() );

// Invoke the completion callback
callback( bw_handle, callback_data );
}

void onEvalJsResultReceived(
Expand Down Expand Up @@ -151,9 +172,9 @@ class ClientHandler : public CefClient, public CefLifeSpanHandler {
(void)(source_process);

// Obtain our browser window handle
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;
std::optional<bw::BrowserInfo> bw_info = bw::bw_handle_map.fetch(browser);
BW_ASSERT( bw_info.has_value(), "Link between CEF's browser handle and our handle does not exist!\n" );
bw_BrowserWindow* our_handle = bw_info.value().handle;

auto msg_args = msg->GetArgumentList();

Expand Down
4 changes: 2 additions & 2 deletions docs/GETTING-STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ Here are the pros and cons of each browser framework. Choose wisely:
*Pros:*
* Is available on all major platforms: Windows, MacOS, Linux (although MacOS support in _BrowserWindow_ needs some work).
If you want the exact same behavior of your app on all platforms, CEF is recommended.
* The cookie API is supported when using CEF in _BrowserWindow_.
* The cookie API of _BrowserWindow_ is supported.
* Is the only framework option which can be decently cross-compiled to Windows.

*Cons:*
* Can be a pain to set up correctly; requires a lot of files to be present for the executable, and needs the sandbox to have specific permissions.
Expand All @@ -40,7 +41,6 @@ is even a homebrew package for it on MacOS.
*Pro:*
* Preinstalled on Windows 11
* Can be statically linked to when using the `*-pc-windows-msvc` toolchain.
* Is easy to cross-compile for. (Needs some testing.)

*Cons:*
* Currenty not yet working on _BrowserWindow_.
Expand Down
8 changes: 1 addition & 7 deletions examples/terminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,7 @@ fn main() {
.eval_js(format!("initialize({})", &working_dir_js).as_str())
.await
{
Err(_) => bw.exec_js(
format!(
"window.onload = () => {{ initialize({}) }}",
&working_dir_js
)
.as_str(),
),
Err(e) => eprintln!("Javascript Error: {:?}", e),
Ok(_) => {}
};
});
Expand Down

0 comments on commit b92c8b3

Please sign in to comment.