Skip to main content

Common Pitfalls

The API aims to be easy to use and hard to misuse, however there are still some pitfalls saucer can't detect.
This page tries to document the most common mistakes and how to avoid them.

Construction from another thread

Constructing a saucer::webview or saucer::smartview in a thread different from the one used to initialize the saucer::application is unsafe and will trigger an assertion.

Example: Ill formed program
#include <saucer/smartview.hpp>

int main()
{
auto app = saucer::application::init({
.id = "pitfalls",
});

saucer::smartview webview{{
.application = app,
}};

webview.set_size(500, 600);
webview.set_title("Hello World!");

webview.expose(
"open",
[app](const std::string &url)
{
auto webview = std::make_shared<saucer::smartview<>>(saucer::preferences{.application = app});

webview->set_url(url);
webview->show();

webview->set_dev_tools(true);

// Short explination for the "close" function:
//
// - What you should know:
// * When a webview goes out of scope, it will be closed
//
// - What happens here:
// * as we dont want the webview to go out of scope after "open" is executed, we make a shared_ptr
// * then we capture this shared_ptr in the exposed close function
// * when "close" is invoked, we reset the last reference to the webview
// * the webview now closes :)
//
webview->expose("close", [webview]() mutable { webview.reset(); });
},
saucer::launch::async);

webview.set_url("https://github.com");
webview.show();

app->run();

return 0;
}

To safely construct an object in the main-thread and have it automatically deleted in the main-thread as well, use saucer::application::make.

Example: Well formed program
#include <saucer/smartview.hpp>

int main()
{
auto app = saucer::application::init({
.id = "pitfalls",
});

saucer::smartview webview{{
.application = app,
}};

webview.set_size(500, 600);
webview.set_title("Hello World!");

webview.expose(
"open",
[app](const std::string &url)
{
auto webview = std::make_shared<saucer::smartview<>>(saucer::preferences{.application = app});
auto webview = std::shared_ptr{app->make<saucer::smartview<>>(saucer::preferences{.application = app})};

webview->set_url(url);
webview->show();

webview->set_dev_tools(true);

// Short explination for the "close" function:
//
// - What you should know:
// * When a webview goes out of scope, it will be closed
//
// - What happens here:
// * as we dont want the webview to go out of scope after "open" is executed, we make a shared_ptr
// * then we capture this shared_ptr in the exposed close function
// * when "close" is invoked, we reset the last reference to the webview
// * the webview now closes :)
//
webview->expose("close", [webview]() mutable { webview.reset(); });
},
saucer::launch::async);

webview.set_url("https://github.com");
webview.show();

app->run();

return 0;
}

Execution Order Matters

The order in which you call some methods matters!
Common mistakes that fall under this category are those, in which you call set_url (or serve) before expose.

Example: Ill formed program
#include <saucer/smartview.hpp>

int main()
{
auto app = saucer::application::init({
.id = "pitfalls",
});

saucer::smartview webview{{
.application = app,
}};

webview.set_size(500, 600);
webview.set_title("Hello World!");

webview.set_url("https://github.com");

webview.expose(
"add_random",
[&](float number) {
auto random = webview.evaluate<float>("Math.random()").get();
return number + random;
},
saucer::launch::async);

webview.show();
app->run();

return 0;
}

In this case, it is not guaranteed that the function add_random is available to the web-page immediately.
To fix this issue simply re-order the code.

Example: Well formed program
int main() 
{
auto app = saucer::application::init({
.id = "pitfalls",
});

saucer::smartview webview{{
.application = app,
}};

webview.set_size(500, 600);
webview.set_title("Hello World!");

webview.set_url("https://github.com");

webview.expose(
"add_random",
[&](float number) {
auto random = webview.evaluate<float>("Math.random()").get();
return number + random;
},
saucer::launch::async);

webview.set_url("https://github.com");
webview.show();

app->run();

return 0;
}

Run is blocking

A call to run() is blocking. All code that comes after it will only be executed once the last window is closed.

tip

Check the attributes of the public interface.
They may contain useful information, like in this case, that run is potentially blocking:

template <bool Blocking = true>
[[sc::may_block]] void run() const;
Example: Ill formed program
int main() 
{
auto app = saucer::application::init({
.id = "pitfalls",
});

saucer::smartview webview{{
.application = app,
}};

webview.set_size(500, 600);
webview.set_title("Hello World!");

webview.show();
app->run();

webview.set_url("https://github.com");

return 0;
}

The fix for this should be obvious:

Example: Well formed program
int main() 
{
auto app = saucer::application::init({
.id = "pitfalls",
});

saucer::smartview webview{{
.application = app,
}};

webview.set_size(500, 600);
webview.set_title("Hello World!");

webview.set_url("https://github.com");

webview.show();
app->run();

webview.set_url("https://github.com");

return 0;
}