From 675b40edd9a9411dc4c119c6b55913fdde1b36d8 Mon Sep 17 00:00:00 2001 From: uklaad Date: Tue, 17 Feb 2026 23:35:08 +0100 Subject: [PATCH 1/3] Fix(cpp): use bind_id in event::get_window() --- include/webui.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/webui.hpp b/include/webui.hpp index 1890893db..320bd20a7 100644 --- a/include/webui.hpp +++ b/include/webui.hpp @@ -209,7 +209,7 @@ namespace webui { // Get current window object pointer webui::window& get_window() { - return event::handler::get_window(window); + return event::handler::get_window(bind_id); } // Get event type From 13cc0aec6db285539473e8c62728472efbe24234 Mon Sep 17 00:00:00 2001 From: uklaad Date: Tue, 17 Feb 2026 23:35:53 +0100 Subject: [PATCH 2/3] Fix(linux): avoid WebKit navigation re-entrancy in webui_navigate() --- src/webui.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/webui.c b/src/webui.c index fd9b42abb..98ef6fb44 100644 --- a/src/webui.c +++ b/src/webui.c @@ -1610,11 +1610,9 @@ void webui_navigate(size_t window, const char* url) { _webui_webview_update(win); } #else - _webui_free_mem((void*) win->webView->url); - char* url_cp = _webui_str_dup(url); - win->webView->url = url_cp; - win->webView->navigate = true; - _webui_webview_update(win); + // In WebKitGTK, navigation can be triggered from navigation-policy callback. + // Route this path through show(), which already applies in_show guard. + (void)webui_show(window, url); #endif } } From 1c17e9b431e4a36a0a5c7269fde5a020de364e90 Mon Sep 17 00:00:00 2001 From: uklaad Date: Tue, 17 Feb 2026 23:36:53 +0100 Subject: [PATCH 3/3] Examples(cpp): refactor serve_a_folder to class-based bind and register target --- CMakeLists.txt | 3 + examples/C++/README.md | 2 +- examples/C++/serve_a_folder/main.cpp | 103 ++++++++++++++------------- 3 files changed, 58 insertions(+), 50 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 38b8c2774..56c79b84c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,17 +123,20 @@ if (WEBUI_BUILD_EXAMPLES) add_executable(minimal ${CMAKE_CURRENT_SOURCE_DIR}/examples/C++/minimal/main.cpp) add_executable(call_js_from_cpp ${CMAKE_CURRENT_SOURCE_DIR}/examples/C++/call_js_from_cpp/main.cpp) add_executable(call_js_from_cpp_class ${CMAKE_CURRENT_SOURCE_DIR}/examples/C++/call_js_from_cpp_class/main.cpp) + add_executable(serve_a_folder ${CMAKE_CURRENT_SOURCE_DIR}/examples/C++/serve_a_folder/main.cpp) add_executable(call_js_from_c ${CMAKE_CURRENT_SOURCE_DIR}/examples/C/call_js_from_c/main.c) target_link_libraries(minimal webui) target_link_libraries(call_js_from_cpp webui) target_link_libraries(call_js_from_cpp_class webui) + target_link_libraries(serve_a_folder webui) target_link_libraries(call_js_from_c webui) if (MSVC) set_target_properties(minimal PROPERTIES LINK_FLAGS "/SubSystem:\"Windows\"" VS_DPI_AWARE "ON") set_target_properties(call_js_from_cpp PROPERTIES LINK_FLAGS "/SubSystem:\"Windows\"" VS_DPI_AWARE "ON") set_target_properties(call_js_from_cpp_class PROPERTIES LINK_FLAGS "/SubSystem:\"Windows\"" VS_DPI_AWARE "ON") + set_target_properties(serve_a_folder PROPERTIES LINK_FLAGS "/SubSystem:\"Windows\"" VS_DPI_AWARE "ON") set_target_properties(call_js_from_c PROPERTIES LINK_FLAGS "/SubSystem:\"Windows\"" VS_DPI_AWARE "ON") endif() diff --git a/examples/C++/README.md b/examples/C++/README.md index 998370c63..64bf9dc59 100644 --- a/examples/C++/README.md +++ b/examples/C++/README.md @@ -8,7 +8,7 @@ The only requirement to build the examples is a a C++11 compiler. - `call_c_from_js`: Calls C++ from JavaScript. - `call_js_from_c`: Calls JavaScript from C++. - `call_js_from_cpp_class`: Calls JavaScript from C++ using class methods and member-function bind. -- `serve_a_folder`: Uses WebUI to serve a folder that contains multiple files. +- `serve_a_folder`: Uses WebUI to serve a folder with multiple files (class-based example using member-function bind). To build an example, cd into its directory and run the make command. diff --git a/examples/C++/serve_a_folder/main.cpp b/examples/C++/serve_a_folder/main.cpp index 549a29065..261050ccb 100644 --- a/examples/C++/serve_a_folder/main.cpp +++ b/examples/C++/serve_a_folder/main.cpp @@ -4,31 +4,71 @@ // Include C++ STD #include -// Making this object global so show_second_window() can access it. -webui::window my_second_window; - -// Example of a simple Class -class MyClass { +class ServeAFolderApp { public: - // This method gets called every time the - // user clicks on "OpenNewWindow" + ServeAFolderApp() { + // Bind HTML element IDs with class methods + my_window.bind("SwitchToSecondPage", this, &ServeAFolderApp::switch_to_second_page); + my_window.bind("OpenNewWindow", this, &ServeAFolderApp::show_second_window); + my_window.bind("Exit", this, &ServeAFolderApp::exit_app); + my_second_window.bind("Exit", this, &ServeAFolderApp::exit_app); + + // Bind all events + my_window.bind("", this, &ServeAFolderApp::events); + my_second_window.bind("", this, &ServeAFolderApp::events); + } + + void run() { + // Print logs (debug build only) + std::cout << "Starting..." << std::endl; + + // Show a new window + my_window.show("index.html"); // my_window.show_browser("index.html", Chrome); + + // Wait until all windows get closed + webui::wait(); + + // Print logs (debug build only) + std::cout << "Thank you." << std::endl; + } + + private: + webui::window my_window; + webui::window my_second_window; + + const char* event_type_to_string(size_t type) const { + switch (type) { + case webui::DISCONNECTED: return "DISCONNECTED"; + case webui::CONNECTED: return "CONNECTED"; + case webui::MOUSE_CLICK: return "MOUSE_CLICK"; + case webui::NAVIGATION: return "NAVIGATION"; + case webui::CALLBACKS: return "CALLBACKS"; + default: return "UNKNOWN"; + } + } + + // This method gets called every time the user clicks on "OpenNewWindow" void show_second_window(webui::window::event* e) { // Show a new window, and navigate to `/second.html` // if the window is already opened, then switch in the same window my_second_window.show("second.html"); } - // This method gets called every time the - // user clicks on "SwitchToSecondPage" + // This method gets called every time the user clicks on "SwitchToSecondPage" void switch_to_second_page(webui::window::event* e) { // Switch to `/second.html` in the same opened window. e->get_window().show("second.html"); } - // Example of a simple function (Not a method) - // This function receives all events because - // it's get bind with an empty HTML ID. + // This method receives all events because it's bind with an empty HTML ID. void events(webui::window::event* e) { + std::cout << "[events] window=" << e->window + << " type=" << e->get_type() + << " (" << event_type_to_string(e->get_type()) << ")" + << " element='" << e->get_element() + << "' event=" << e->get_number() + << std::endl; + if (e->event_type == webui::CONNECTED) std::cout << "Window Connected." << std::endl; else if (e->event_type == webui::DISCONNECTED) @@ -42,50 +82,15 @@ class MyClass { } } - // Example of a simple function (Not a method) void exit_app(webui::window::event* e) { // Close all opened windows webui::exit(); } }; -// -- MyClass C Wrapper ------------------------------------------------------------------------ -// Because WebUI is written in C, so it can not access `MyClass` directly. -// That's why we should create a simple C++ wrapper. -MyClass myClassObj; -void show_second_window_wrp(webui::window::event* e) { myClassObj.show_second_window(e); } -void switch_to_second_page_wrp(webui::window::event* e) { myClassObj.switch_to_second_page(e); } -void events_wrp(webui::window::event* e) { myClassObj.events(e); } -void exit_app_wrp(webui::window::event* e) { myClassObj.exit_app(e); } -// --------------------------------------------------------------------------------------------- - int main() { - - // Print logs (debug build only) - std::cout << "Starting..." << std::endl; - - // Create a new window - webui::window my_window; - - // Bind HTML element IDs with a C functions - my_window.bind("SwitchToSecondPage", switch_to_second_page_wrp); - my_window.bind("OpenNewWindow", show_second_window_wrp); - my_window.bind("Exit", exit_app_wrp); - my_second_window.bind("Exit", exit_app_wrp); - - // Bind all events - my_window.bind("", events_wrp); - my_second_window.bind("", events_wrp); - - // Show a new window - my_window.show("index.html"); // my_window.show_browser("index.html", Chrome); - - // Wait until all windows get closed - webui::wait(); - - // Print logs (debug build only) - std::cout << "Thank you." << std::endl; - + ServeAFolderApp app; + app.run(); return 0; }