diff --git a/.gitignore b/.gitignore
index 18fb1c4..a0cc7a4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@ zig-cache
zig-out
.direnv
.zig-cache
+examples/comprehensive/examples
\ No newline at end of file
diff --git a/build.zig b/build.zig
index cc7750f..96454eb 100644
--- a/build.zig
+++ b/build.zig
@@ -96,11 +96,18 @@ pub fn build(b: *Build) !void {
// Function to generate API documentation
fn generate_docs(b: *Build, optimize: OptimizeMode, target: Build.ResolvedTarget, flags_module: *Module) void {
// Create a temporary object for documentation generation
- const webui_lib = b.addObject(.{
+ const webui_lib = b.addObject(if (builtin.zig_version.minor == 14) .{
.name = "webui_lib",
.root_source_file = b.path(b.pathJoin(&.{ "src", "webui.zig" })),
.target = target,
.optimize = optimize,
+ } else .{
+ .name = "webui_lib",
+ .root_module = b.addModule("webui_lib", .{
+ .root_source_file = b.path(b.pathJoin(&.{ "src", "webui.zig" })),
+ .target = target,
+ .optimize = optimize,
+ }),
});
webui_lib.root_module.addImport("flags", flags_module);
@@ -153,11 +160,18 @@ fn build_examples(b: *Build, optimize: OptimizeMode, target: Build.ResolvedTarge
const path = b.pathJoin(&.{ "examples", example_name, "main.zig" });
// Create an executable for each example
- const exe = b.addExecutable(.{
+ const exe = b.addExecutable(if (builtin.zig_version.minor == 14) .{
.name = example_name,
.root_source_file = b.path(path),
.target = target,
.optimize = optimize,
+ } else .{
+ .name = example_name,
+ .root_module = b.addModule(example_name, .{
+ .root_source_file = b.path(path),
+ .target = target,
+ .optimize = optimize,
+ }),
});
// Add the webui module and link against the library
diff --git a/build.zig.zon b/build.zig.zon
index 289ed09..0728827 100644
--- a/build.zig.zon
+++ b/build.zig.zon
@@ -1,12 +1,12 @@
-.{
+.{
.name = .zig_webui,
.version = "2.5.0-beta.4",
.fingerprint = 0x95965ed3cdfb8c33,
.minimum_zig_version = "0.14.0",
.dependencies = .{
.webui = .{
- .hash = "webui-2.5.0-beta.4-pxqD5bE4NwCVDCBguzzRmyOubiadAaVRNM0XMxqUv_GS",
- .url = "https://github.com/webui-dev/webui/archive/e673cee5a26b4c475395ce8e2f5fb92608bf3574.tar.gz",
+ .hash = "webui-2.5.0-beta.4-pxqD5bY8NwAOad4eidLvvpn4UbMNNCtWnGlhPj5BScgZ",
+ .url = "https://github.com/webui-dev/webui/archive/ffb235a6e1ad0904a284836c205832bb47ec3ebe.tar.gz",
},
},
.paths = .{
diff --git a/examples/comprehensive/index.html b/examples/comprehensive/index.html
new file mode 100644
index 0000000..b53f225
--- /dev/null
+++ b/examples/comprehensive/index.html
@@ -0,0 +1,883 @@
+
+
+
+
+
+ WebUI Comprehensive Showcase
+
+
+
+
+
+
+
+
+
+
+
👤 User Management
+
+
+
+
+
+
User management ready
+
+
+
+
+
💬 Messaging
+
+
+
+
+
+
+
+
Messaging system ready
+
+
+
+
+
⚙️ Data Processing
+
+
+
+
+
+
Data processing ready
+
+
+
+
+
⚡ Command Execution
+
+
+
+
+
+
Command execution ready
+
+
+
+
+
📊 Performance Testing
+
+
+
+
+
+
+
Performance testing ready
+
+
+
+
+
⚙️ Settings
+
+
+
+
+
+
+
Settings management ready
+
+
+
+
+
+
🖥️ System Information
+
+
+
+
+
+
Click "Get System Info" to load system details
+
+
+
+
+
+
+
+
🌐 Global Controls
+
+
+
+
+
+
+
Global controls ready
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/comprehensive/main.zig b/examples/comprehensive/main.zig
new file mode 100644
index 0000000..77ceef5
--- /dev/null
+++ b/examples/comprehensive/main.zig
@@ -0,0 +1,483 @@
+//! WebUI Zig - Comprehensive Feature Showcase
+//! This example demonstrates multiple WebUI features working together
+const std = @import("std");
+const webui = @import("webui");
+
+const html = @embedFile("index.html");
+
+var allocator = std.heap.page_allocator;
+
+// Settings storage
+var settings_map: std.HashMap([]const u8, []const u8, std.hash_map.StringContext, 80) = undefined;
+
+// Application state
+const AppState = struct {
+ users_online: u32 = 0,
+ messages_sent: u32 = 0,
+ files_uploaded: u32 = 0,
+
+ fn init() AppState {
+ return AppState{};
+ }
+};
+
+// Track unique users
+var online_users: std.HashMap([]const u8, bool, std.hash_map.StringContext, 80) = undefined;
+
+var app_state: AppState = undefined;
+
+pub fn main() !void {
+ // Initialize settings storage
+ settings_map = std.HashMap([]const u8, []const u8, std.hash_map.StringContext, 80).init(allocator);
+ defer {
+ // Clean up all allocated setting keys and values
+ var iterator = settings_map.iterator();
+ while (iterator.next()) |entry| {
+ allocator.free(entry.key_ptr.*);
+ allocator.free(entry.value_ptr.*);
+ }
+ settings_map.deinit();
+ }
+
+ // Initialize online users tracking
+ online_users = std.HashMap([]const u8, bool, std.hash_map.StringContext, 80).init(allocator);
+ defer {
+ // Clean up all allocated user keys
+ var user_iterator = online_users.iterator();
+ while (user_iterator.next()) |entry| {
+ allocator.free(entry.key_ptr.*);
+ }
+ online_users.deinit();
+ }
+
+ app_state = AppState.init();
+ // Configure WebUI
+ webui.setConfig(.multi_client, true);
+ webui.setConfig(.folder_monitor, true);
+ webui.setTimeout(0); // No timeout
+
+ // Create main window
+ var main_window = webui.newWindow();
+
+ // Configure window
+ main_window.setSize(1200, 800);
+ main_window.setCenter();
+ main_window.setPublic(true);
+ main_window.setIcon("", "image/svg+xml");
+
+ // Set up file handling
+ try main_window.setRootFolder("public");
+ main_window.setFileHandler(customFileHandler);
+
+ // Bind comprehensive functions
+ _ = try main_window.binding("get_app_status", getAppStatus);
+ _ = try main_window.binding("user_action", userAction);
+ _ = try main_window.binding("send_notification", sendNotification);
+ _ = try main_window.binding("process_data", processData);
+ _ = try main_window.binding("execute_command", executeCommand);
+ _ = try main_window.binding("get_system_info", getSystemInfo);
+ _ = try main_window.binding("test_performance", testPerformance);
+ _ = try main_window.binding("manage_settings", manageSettings);
+ _ = try main_window.binding("upload_file", uploadFile);
+
+ // Set runtime for enhanced JavaScript support
+ main_window.setRuntime(.NodeJS);
+
+ // Create public directory
+ std.fs.cwd().makeDir("examples/comprehensive/public") catch {};
+
+ // Show window
+ try main_window.show(html);
+
+ std.debug.print("Comprehensive WebUI showcase started\n", .{});
+ std.debug.print("Port: {}\n", .{main_window.getPort() catch 0});
+ std.debug.print("URL: {s}\n", .{main_window.getUrl() catch "unknown"});
+
+ // Wait for window to close
+ webui.wait();
+
+ // Clean up
+ webui.clean();
+}
+
+fn customFileHandler(filename: []const u8) ?[]const u8 {
+ // Handle API endpoints
+ if (std.mem.startsWith(u8, filename, "/api/")) {
+ return handleApiRequest(filename);
+ }
+
+ // Handle static files
+ if (std.mem.eql(u8, filename, "/status")) {
+ const status_html =
+ \\HTTP/1.1 200 OK
+ \\Content-Type: text/html
+ \\
+ \\WebUI Status
Server is running!
+ ;
+ return status_html;
+ }
+
+ return null; // Let default handler take over
+}
+
+fn handleApiRequest(path: []const u8) ?[]const u8 {
+ if (std.mem.eql(u8, path, "/api/stats")) {
+ var buffer: [512]u8 = undefined;
+
+ const json = std.fmt.bufPrint(buffer[0..],
+ \\HTTP/1.1 200 OK
+ \\Content-Type: application/json
+ \\Access-Control-Allow-Origin: *
+ \\
+ \\{{"users":{}, "messages":{}, "files":{}}}
+ , .{ app_state.users_online, app_state.messages_sent, app_state.files_uploaded }) catch return null;
+
+ // Allocate persistent memory for response
+ const response = allocator.dupe(u8, json) catch return null;
+ return response;
+ }
+
+ return null;
+}
+
+fn getAppStatus(e: *webui.Event) void {
+ const win = e.getWindow();
+ const port = win.getPort() catch 0;
+ const url = win.getUrl() catch "unknown";
+
+ var buffer: [1024]u8 = undefined;
+ const json = std.fmt.bufPrintZ(buffer[0..],
+ \\{{"status":"running","users":{},"messages":{},"files":{},"port":{},"url":"{s}","clientId":{},"timestamp":{}}}
+ , .{ app_state.users_online, app_state.messages_sent, app_state.files_uploaded, port, url, e.client_id, std.time.timestamp() }) catch "{\"error\":\"format_error\"}";
+
+ std.debug.print("App Status - Users: {}, Messages: {}, Files: {}\n", .{ app_state.users_online, app_state.messages_sent, app_state.files_uploaded });
+
+ e.returnString(json);
+}
+
+fn userAction(e: *webui.Event, action: [:0]const u8, data: [:0]const u8) void {
+ std.debug.print("User action: {s} with data: {s}\n", .{ action, data });
+
+ var response: [512]u8 = undefined;
+ var result: [:0]const u8 = "";
+
+ if (std.mem.eql(u8, action, "login")) {
+ // Check if user is already online
+ if (online_users.contains(data)) {
+ result = std.fmt.bufPrintZ(response[0..], "User '{s}' is already online. Online users: {}", .{ data, app_state.users_online }) catch "Error";
+ } else {
+ // Add new user
+ const username_copy = allocator.dupe(u8, data) catch {
+ result = "Error: Memory allocation failed";
+ e.returnString(result);
+ return;
+ };
+ online_users.put(username_copy, true) catch {
+ allocator.free(username_copy);
+ result = "Error: Failed to track user";
+ e.returnString(result);
+ return;
+ };
+ app_state.users_online += 1;
+ result = std.fmt.bufPrintZ(response[0..], "User '{s}' logged in. Online users: {}", .{ data, app_state.users_online }) catch "Error";
+ }
+ } else if (std.mem.eql(u8, action, "logout")) {
+ // Check if user is online
+ if (online_users.fetchRemove(data)) |kv| {
+ allocator.free(kv.key);
+ if (app_state.users_online > 0) app_state.users_online -= 1;
+ result = std.fmt.bufPrintZ(response[0..], "User '{s}' logged out. Online users: {}", .{ data, app_state.users_online }) catch "Error";
+ } else {
+ result = std.fmt.bufPrintZ(response[0..], "User '{s}' was not online. Online users: {}", .{ data, app_state.users_online }) catch "Error";
+ }
+ } else if (std.mem.eql(u8, action, "message")) {
+ app_state.messages_sent += 1;
+ result = std.fmt.bufPrintZ(response[0..], "Message sent. Total messages: {}", .{app_state.messages_sent}) catch "Error";
+ } else if (std.mem.eql(u8, action, "upload")) {
+ // For simulation purposes, just acknowledge the upload request
+ const filename = if (data.len > 0) data else "demo_file.txt";
+ result = std.fmt.bufPrintZ(response[0..], "Upload request received for '{s}'. Use the file input for actual upload.", .{filename}) catch "Error";
+ } else {
+ result = "Unknown action";
+ }
+
+ e.returnString(result);
+}
+
+fn sendNotification(e: *webui.Event, message: [:0]const u8, level: [:0]const u8) void {
+ const win = e.getWindow();
+
+ // Send notification to all clients
+ var js_code: [512]u8 = undefined;
+ const script = std.fmt.bufPrintZ(js_code[0..], "showNotification('{s}', '{s}');", .{ message, level }) catch return;
+
+ win.run(script);
+
+ e.returnString("Notification sent to all clients");
+ std.debug.print("Notification sent: {s} ({s})\n", .{ message, level });
+}
+
+fn processData(e: *webui.Event, operation: [:0]const u8, input_data: [:0]const u8) void {
+ std.debug.print("Processing data: {s} on {s}\n", .{ operation, input_data });
+
+ var result: [1024]u8 = undefined;
+ var output: [:0]const u8 = "";
+
+ if (std.mem.eql(u8, operation, "reverse")) {
+ // Reverse string
+ var reversed: [512]u8 = undefined;
+ var i: usize = 0;
+ while (i < input_data.len and i < 512) : (i += 1) {
+ reversed[i] = input_data[input_data.len - 1 - i];
+ }
+ output = std.fmt.bufPrintZ(result[0..], "Reversed: {s}", .{reversed[0..i]}) catch "Error";
+ } else if (std.mem.eql(u8, operation, "uppercase")) {
+ // Convert to uppercase
+ var upper: [512]u8 = undefined;
+ for (input_data, 0..) |c, i| {
+ if (i >= 512) break;
+ upper[i] = std.ascii.toUpper(c);
+ }
+ output = std.fmt.bufPrintZ(result[0..], "Uppercase: {s}", .{upper[0..@min(input_data.len, 512)]}) catch "Error";
+ } else if (std.mem.eql(u8, operation, "hash")) {
+ // Simple hash (sum of bytes)
+ var hash: u32 = 0;
+ for (input_data) |c| {
+ hash = hash *% 31 +% c;
+ }
+ output = std.fmt.bufPrintZ(result[0..], "Hash: {X}", .{hash}) catch "Error";
+ } else {
+ output = "Unknown operation";
+ }
+
+ e.returnString(output);
+}
+
+fn executeCommand(e: *webui.Event, command: [:0]const u8, args: [:0]const u8) void {
+ std.debug.print("Execute command: {s} {s}\n", .{ command, args });
+
+ var response: [512]u8 = undefined;
+ var result: [:0]const u8 = "";
+
+ if (std.mem.eql(u8, command, "echo")) {
+ result = std.fmt.bufPrintZ(response[0..], "Echo: {s}", .{args}) catch "Error";
+ } else if (std.mem.eql(u8, command, "time")) {
+ const timestamp = std.time.timestamp();
+ result = std.fmt.bufPrintZ(response[0..], "Current time: {}", .{timestamp}) catch "Error";
+ } else if (std.mem.eql(u8, command, "random")) {
+ var prng = std.Random.DefaultPrng.init(@intCast(std.time.timestamp()));
+ const random_num = prng.random().int(u32);
+ result = std.fmt.bufPrintZ(response[0..], "Random number: {}", .{random_num}) catch "Error";
+ } else if (std.mem.eql(u8, command, "memory")) {
+ // Simple memory info (simulated)
+ result = std.fmt.bufPrintZ(response[0..], "Memory usage: {}MB", .{50 + @rem(std.time.timestamp(), 100)}) catch "Error";
+ } else {
+ result = "Unknown command";
+ }
+
+ e.returnString(result);
+}
+
+fn getSystemInfo(e: *webui.Event) void {
+ const builtin = @import("builtin");
+
+ var buffer: [1024]u8 = undefined;
+ const info = std.fmt.bufPrintZ(buffer[0..],
+ \\{{"os":"{s}","arch":"{s}","zigVersion":"{s}","webuiVersion":"2.5.0","timestamp":{}}}
+ , .{ @tagName(builtin.os.tag), @tagName(builtin.cpu.arch), @import("builtin").zig_version_string, std.time.timestamp() }) catch "{}";
+
+ e.returnString(info);
+}
+
+fn testPerformance(e: *webui.Event, iterations: i64, operation: [:0]const u8) void {
+ const start_time = std.time.nanoTimestamp();
+
+ var i: i64 = 0;
+ var result: u64 = 0;
+
+ if (std.mem.eql(u8, operation, "math")) {
+ while (i < iterations) : (i += 1) {
+ result = result +% (@as(u64, @intCast(i)) * @as(u64, @intCast(i)));
+ }
+ } else if (std.mem.eql(u8, operation, "string")) {
+ var buffer: [64]u8 = undefined;
+ while (i < iterations) : (i += 1) {
+ _ = std.fmt.bufPrint(buffer[0..], "test{}", .{i}) catch continue;
+ }
+ }
+
+ const end_time = std.time.nanoTimestamp();
+ const duration_ms = @as(f64, @floatFromInt(end_time - start_time)) / 1_000_000.0;
+
+ var response: [256]u8 = undefined;
+ const msg = std.fmt.bufPrintZ(response[0..], "Performance test completed: {} iterations of {s} in {d:.2}ms", .{ iterations, operation, duration_ms }) catch "Error";
+
+ e.returnString(msg);
+ std.debug.print("Performance test: {} iterations in {d:.2}ms\n", .{ iterations, duration_ms });
+}
+
+fn manageSettings(e: *webui.Event, action: [:0]const u8, key: [:0]const u8, value: [:0]const u8) void {
+ std.debug.print("Settings: {s} {s} = {s}\n", .{ action, key, value });
+
+ var response: [512]u8 = undefined;
+ var result: [:0]const u8 = "";
+
+ if (std.mem.eql(u8, action, "set")) {
+ // Store setting in memory
+ const key_copy = allocator.dupe(u8, key) catch {
+ result = "Error: Memory allocation failed for key";
+ e.returnString(result);
+ return;
+ };
+ const value_copy = allocator.dupe(u8, value) catch {
+ allocator.free(key_copy);
+ result = "Error: Memory allocation failed for value";
+ e.returnString(result);
+ return;
+ };
+
+ // Remove old value if exists
+ if (settings_map.get(key)) |old_value| {
+ allocator.free(old_value);
+ }
+
+ settings_map.put(key_copy, value_copy) catch {
+ allocator.free(key_copy);
+ allocator.free(value_copy);
+ result = "Error: Failed to store setting";
+ e.returnString(result);
+ return;
+ };
+
+ result = std.fmt.bufPrintZ(response[0..], "Setting '{s}' set to '{s}'", .{ key, value }) catch "Error";
+ } else if (std.mem.eql(u8, action, "get")) {
+ // Get setting from memory
+ if (settings_map.get(key)) |stored_value| {
+ result = std.fmt.bufPrintZ(response[0..], "Setting '{s}' = '{s}'", .{ key, stored_value }) catch "Error";
+ } else {
+ result = std.fmt.bufPrintZ(response[0..], "Setting '{s}' not found (no value set)", .{key}) catch "Error";
+ }
+ } else if (std.mem.eql(u8, action, "delete")) {
+ // Delete setting from memory
+ if (settings_map.fetchRemove(key)) |kv| {
+ allocator.free(kv.key);
+ allocator.free(kv.value);
+ result = std.fmt.bufPrintZ(response[0..], "Setting '{s}' deleted", .{key}) catch "Error";
+ } else {
+ result = std.fmt.bufPrintZ(response[0..], "Setting '{s}' not found (nothing to delete)", .{key}) catch "Error";
+ }
+ } else {
+ result = "Unknown settings action";
+ }
+
+ e.returnString(result);
+}
+
+fn uploadFile(e: *webui.Event, filename: [:0]const u8, content: [:0]const u8) void {
+ std.debug.print("Upload file: {s} (size: {})\n", .{ filename, content.len });
+
+ var response: [512]u8 = undefined;
+ var result: [:0]const u8 = "";
+
+ // Validate filename
+ if (filename.len == 0) {
+ result = "Error: Filename cannot be empty";
+ e.returnString(result);
+ return;
+ }
+
+ // Ensure public directory exists
+ std.fs.cwd().makePath("examples/comprehensive/public") catch |err| {
+ std.debug.print("Warning: Failed to create public directory: {}\n", .{err});
+ // Continue anyway, maybe directory already exists
+ };
+
+ // Sanitize filename to avoid filesystem issues while preserving Unicode characters (including Chinese)
+ var safe_filename: [512]u8 = undefined;
+ var safe_len: usize = 0;
+
+ // Use Zig's UTF-8 iterator to properly handle Unicode characters
+ const utf8_view = std.unicode.Utf8View.init(filename) catch {
+ // If filename is not valid UTF-8, use a default name
+ const default_name = "uploaded_file.txt";
+ @memcpy(safe_filename[0..default_name.len], default_name);
+ safe_len = default_name.len;
+ safe_filename[safe_len] = 0;
+ return; // Exit early with default name
+ };
+
+ var iter = utf8_view.iterator();
+ while (iter.nextCodepoint()) |codepoint| {
+ if (safe_len >= 500) break; // Leave space for null terminator
+
+ // Check if this is a filesystem-dangerous character (ASCII only)
+ if (codepoint < 128) {
+ const ascii_char = @as(u8, @intCast(codepoint));
+ if (ascii_char == '/' or ascii_char == '\\' or ascii_char == ':' or
+ ascii_char == '*' or ascii_char == '?' or ascii_char == '"' or
+ ascii_char == '<' or ascii_char == '>' or ascii_char == '|' or
+ ascii_char == 0)
+ {
+ // Replace dangerous characters with underscore
+ safe_filename[safe_len] = '_';
+ safe_len += 1;
+ } else {
+ // Safe ASCII character
+ safe_filename[safe_len] = ascii_char;
+ safe_len += 1;
+ }
+ } else {
+ // Unicode character (including Chinese) - encode back to UTF-8
+ var utf8_buffer: [4]u8 = undefined;
+ const utf8_len = std.unicode.utf8Encode(codepoint, &utf8_buffer) catch {
+ // If encoding fails, replace with underscore
+ safe_filename[safe_len] = '_';
+ safe_len += 1;
+ continue;
+ };
+
+ // Check if we have enough space
+ if (safe_len + utf8_len <= 500) {
+ @memcpy(safe_filename[safe_len .. safe_len + utf8_len], utf8_buffer[0..utf8_len]);
+ safe_len += utf8_len;
+ } else {
+ break; // No more space
+ }
+ }
+ }
+ safe_filename[safe_len] = 0; // null terminate
+
+ // Create file path in public directory
+ const file_path = std.fmt.allocPrint(allocator, "examples/comprehensive/public/{s}", .{safe_filename[0..safe_len :0]}) catch {
+ result = "Error: Failed to create file path";
+ e.returnString(result);
+ return;
+ };
+ defer allocator.free(file_path);
+
+ std.debug.print("Creating file at: {s}\n", .{file_path});
+
+ // Create file
+ const file = std.fs.cwd().createFile(file_path, .{}) catch |err| {
+ std.debug.print("Failed to create file {s}: {}\n", .{ file_path, err });
+ result = std.fmt.bufPrintZ(response[0..], "Error: Failed to create file '{s}' ({s})", .{ filename, @errorName(err) }) catch "Error";
+ e.returnString(result);
+ return;
+ };
+ defer file.close();
+
+ // Write content to file
+ file.writeAll(content) catch |err| {
+ std.debug.print("Failed to write to file {s}: {}\n", .{ file_path, err });
+ result = std.fmt.bufPrintZ(response[0..], "Error: Failed to write to file '{s}' ({s})", .{ filename, @errorName(err) }) catch "Error";
+ e.returnString(result);
+ return;
+ };
+
+ // Update counters
+ app_state.files_uploaded += 1;
+
+ // Return success message
+ result = std.fmt.bufPrintZ(response[0..], "File '{s}' uploaded successfully as '{s}'. Size: {} bytes. Total files: {}", .{ filename, safe_filename[0..safe_len :0], content.len, app_state.files_uploaded }) catch "Error";
+ e.returnString(result);
+}
diff --git a/examples/event_handling/index.html b/examples/event_handling/index.html
new file mode 100644
index 0000000..878b6ca
--- /dev/null
+++ b/examples/event_handling/index.html
@@ -0,0 +1,745 @@
+
+
+
+
+
+ Event Handling & Context Management
+
+
+
+
+
🎯 Event Handling & Context Management
+
+
+
+
+
👤 User Session
+
+
+
+
+
+
+
+
No session data
+
+
+
+
+
+
🖱️ Click Tracking
+
+
+
+
+
+
+
Login to track clicks
+
+
+
+
+
+
💬 Multi-Client Messaging
+
+
+
Send Direct Message
+
+
+
+
+
+
+
+
+
+
Broadcast Message
+
+
+
+
+
+
+
+
+
Welcome to the messaging system!
+
+
+
+
+
+
📊 Event Monitoring
+
+
+
Client Information
+
+
+
+ Client Status: Ready
+
+
+
+
+
Event Statistics
+
+ Events processed: 0
+ Last event: None
+ Session time: 00:00:00
+
+
+
+
+
+
+
+
⚡ Advanced Event Features
+
+
+
+
+
+
+
Advanced features ready
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/event_handling/main.zig b/examples/event_handling/main.zig
new file mode 100644
index 0000000..784a8b7
--- /dev/null
+++ b/examples/event_handling/main.zig
@@ -0,0 +1,507 @@
+//! WebUI Zig - Event Handling and Context Management Example
+//! This example demonstrates advanced event handling, context management, and multi-client support
+const std = @import("std");
+const webui = @import("webui");
+
+const html = @embedFile("index.html");
+
+var allocator = std.heap.page_allocator;
+
+// Global user context storage for each window/client
+var global_user_contexts: ?std.AutoHashMap(usize, *UserContext) = null;
+
+// Online user structure
+const OnlineUser = struct {
+ client_id: usize,
+ username: []const u8,
+};
+
+// Online users list for tracking connected clients
+var online_users: ?std.ArrayList(OnlineUser) = null;
+
+// Initialize global user contexts if not already initialized
+fn ensureContextsInitialized() void {
+ if (global_user_contexts == null) {
+ global_user_contexts = std.AutoHashMap(usize, *UserContext).init(allocator);
+ }
+ if (online_users == null) {
+ online_users = std.ArrayList(OnlineUser).init(allocator);
+ }
+}
+
+// Get the global contexts map (ensuring it's initialized)
+fn getContextsMap() *std.AutoHashMap(usize, *UserContext) {
+ ensureContextsInitialized();
+ return &global_user_contexts.?;
+}
+
+// User data structure for context
+const UserContext = struct {
+ user_id: u32,
+ username: []const u8,
+ session_start: i64,
+ click_count: u32,
+
+ fn create(user_id: u32, username: []const u8) !*UserContext {
+ const context = try allocator.create(UserContext);
+ context.* = UserContext{
+ .user_id = user_id,
+ .username = try allocator.dupe(u8, username),
+ .session_start = std.time.timestamp(),
+ .click_count = 0,
+ };
+ return context;
+ }
+
+ fn destroy(self: *UserContext) void {
+ allocator.free(self.username);
+ allocator.destroy(self);
+ }
+};
+
+pub fn main() !void {
+ // Configure for multi-client support
+ webui.setConfig(.multi_client, true); // Enable multi-client mode
+ webui.setConfig(.use_cookies, true); // Use cookies for client identification
+
+ // Set public access to allow connections from other devices
+ // This allows other devices on the same network to connect
+
+ // Create window
+ var nwin = webui.newWindow();
+
+ // Allow public network access (other devices can connect)
+ nwin.setPublic(true);
+
+ // Set event blocking mode
+ nwin.setEventBlocking(false); // Non-blocking events
+
+ // Bind event handlers with context
+ _ = try nwin.bind("user_login", userLogin);
+ _ = try nwin.bind("user_logout", userLogout);
+ _ = try nwin.bind("track_click", trackClick);
+ _ = try nwin.bind("get_user_info", getUserInfo);
+ _ = try nwin.bind("get_online_users", getOnlineUsers);
+ _ = try nwin.bind("send_message", sendMessage);
+ _ = try nwin.bind("broadcast_message", broadcastMessage);
+ _ = try nwin.bind("client_connect", clientConnect);
+ _ = try nwin.bind("client_disconnect", clientDisconnect);
+
+ // Bind interface handlers for advanced event management
+ _ = try nwin.interfaceBind("interface_handler", interfaceEventHandler);
+
+ // Bind universal event handler (empty element name = all events)
+ _ = try nwin.bind("", universalEventHandler);
+
+ // Show window with multi-client support
+ // Try to show embedded HTML first
+ nwin.show(html) catch |err| {
+ // If that fails, try alternative approach
+ std.debug.print("Warning: Failed to show embedded HTML ({}), trying alternative method...\n", .{err});
+
+ // Write HTML to temporary file and use startServer
+ const temp_file = "temp_index.html";
+ const file = std.fs.cwd().createFile(temp_file, .{}) catch |file_err| {
+ std.debug.print("Error: Could not create temporary HTML file: {}\n", .{file_err});
+ return;
+ };
+ defer file.close();
+ defer std.fs.cwd().deleteFile(temp_file) catch {};
+
+ file.writeAll(html) catch |write_err| {
+ std.debug.print("Error: Could not write HTML content: {}\n", .{write_err});
+ return;
+ };
+
+ // Start server with file
+ const url = nwin.startServer(temp_file) catch |server_err| {
+ std.debug.print("Error: Could not start server: {}\n", .{server_err});
+ return;
+ };
+
+ std.debug.print("📍 Server URL: {s}\n", .{url});
+
+ // Open in default browser
+ webui.openUrl(@as([*c]const u8, @ptrCast(url.ptr))[0..url.len :0]);
+ };
+
+ // Get and display server information
+ const port = nwin.getPort() catch |err| blk: {
+ std.debug.print("Warning: Could not get server port ({})\n", .{err});
+ break :blk @as(usize, 0);
+ };
+
+ const url = nwin.getUrl() catch |err| blk: {
+ std.debug.print("Warning: Could not get server URL ({})\n", .{err});
+ break :blk @as([:0]const u8, "unknown");
+ };
+
+ // Print multi-client instructions
+ std.debug.print("\n🌐 Multi-Client Event Handling Server Started!\n", .{});
+ std.debug.print("📍 Server URL: {s}\n", .{url});
+ std.debug.print("🔌 Server Port: {}\n", .{port});
+ std.debug.print("🏠 Local Access: http://localhost:{}\n", .{port});
+ std.debug.print("🌍 Network Access: http://[YOUR_IP]:{}\n", .{port});
+ std.debug.print("\n💡 To find your IP address:\n", .{});
+ std.debug.print(" Windows: ipconfig | findstr IPv4\n", .{});
+ std.debug.print(" Mac/Linux: ifconfig | grep inet\n", .{});
+ std.debug.print(" Or check in network settings\n", .{});
+ std.debug.print("\n" ++ "=" ** 60 ++ "\n", .{});
+ std.debug.print("\n📋 How to test multi-client functionality:\n", .{});
+ std.debug.print("\n🔗 Multi-Client Connection Methods:\n", .{});
+ std.debug.print(" 1. SAME COMPUTER - New Tab/Window:\n", .{});
+ std.debug.print(" → Copy: {s}\n", .{url});
+ std.debug.print(" → Paste in new browser tab\n", .{});
+ std.debug.print("\n 2. SAME COMPUTER - Different Browser:\n", .{});
+ std.debug.print(" → Chrome: {s}\n", .{url});
+ std.debug.print(" → Firefox: {s}\n", .{url});
+ std.debug.print(" → Edge: {s}\n", .{url});
+ std.debug.print("\n 3. OTHER DEVICES (Phone/Tablet/PC):\n", .{});
+ std.debug.print(" → Find your IP address using commands above\n", .{});
+ std.debug.print(" → Replace localhost with your IP\n", .{});
+ std.debug.print(" → Example: http://192.168.1.100:{}\n", .{port});
+ std.debug.print("\n👥 Suggested Test Users:\n", .{});
+ std.debug.print(" 🟦 Window 1: Alice (ID: 1001)\n", .{});
+ std.debug.print(" 🟩 Window 2: Bob (ID: 1002)\n", .{});
+ std.debug.print(" 🟨 Window 3: Carol (ID: 1003)\n", .{});
+ std.debug.print(" 🟪 Window 4: David (ID: 1004)\n", .{});
+ std.debug.print("\n🎯 Test Features:\n", .{});
+ std.debug.print(" • Login with different users\n", .{});
+ std.debug.print(" • Refresh online user list (🔄 button)\n", .{});
+ std.debug.print(" • Send direct messages between users\n", .{});
+ std.debug.print(" • Test broadcast messages\n", .{});
+ std.debug.print(" • Click tracking per user\n\n", .{});
+
+ std.debug.print("Event handling server started. Multi-client support enabled.\n", .{});
+
+ // Wait for all windows to close
+ webui.wait();
+
+ // Clean up any remaining contexts
+ cleanupAllContexts();
+ webui.clean();
+}
+
+fn getLocalIPAddress() ![]const u8 {
+ // Placeholder function - user should check their actual IP address
+ // Use the commands shown in the console output to find your real IP
+ return "192.168.x.x";
+}
+
+fn userLogin(e: *webui.Event) void {
+ const username = e.getString();
+ const user_id = @as(u32, @intCast(e.getIntAt(1)));
+
+ std.debug.print("User login attempt: {} - {s}\n", .{user_id, username});
+
+ // Create user context
+ const context = UserContext.create(user_id, username) catch {
+ e.returnString("Login failed: Unable to create user context");
+ return;
+ };
+
+ // Set context for this element
+ const win = e.getWindow();
+ // Set context for the calling element and make it available globally
+ // We'll use a window-wide context storage
+ win.setContext("user_login", @ptrCast(context));
+
+ // Store context globally using client ID as key
+ getContextsMap().put(e.client_id, context) catch {
+ std.debug.print("Failed to store global context for client {}\n", .{e.client_id});
+ };
+
+ // Add user to online list
+ ensureContextsInitialized();
+ if (online_users) |*users| {
+ users.append(OnlineUser{ .client_id = e.client_id, .username = context.username }) catch {
+ std.debug.print("Failed to add user to online list\n", .{});
+ };
+ }
+
+ // Broadcast user list update to all clients
+ broadcastUserListUpdate();
+
+ // Return success response
+ var response: [257]u8 = undefined; // +1 for null terminator
+ const msg = std.fmt.bufPrint(response[0..256],
+ "Welcome {s}! User ID: {}, Session started.", .{username, user_id}) catch "";
+
+ // Ensure null termination
+ response[msg.len] = 0;
+ const null_terminated: [:0]const u8 = response[0..msg.len :0];
+ e.returnString(null_terminated);
+ std.debug.print("User {s} logged in successfully\n", .{username});
+}
+
+fn userLogout(e: *webui.Event) void {
+ // Get user context from global storage
+ const context = getContextsMap().get(e.client_id) orelse {
+ e.returnString("No active session found");
+ return;
+ };
+
+ // Calculate session duration
+ const session_duration = std.time.timestamp() - context.session_start;
+
+ var response: [257]u8 = undefined; // +1 for null terminator
+ const msg = std.fmt.bufPrint(response[0..256],
+ "Goodbye {s}! Session duration: {}s, Total clicks: {}",
+ .{context.username, session_duration, context.click_count}) catch "";
+
+ // Ensure null termination
+ response[msg.len] = 0;
+ const null_terminated: [:0]const u8 = response[0..msg.len :0];
+ e.returnString(null_terminated);
+ std.debug.print("User {s} logged out. Session: {}s\n", .{context.username, session_duration});
+
+ // Remove from global context storage
+ _ = getContextsMap().remove(e.client_id);
+
+ // Remove from online users list
+ if (online_users) |*users| {
+ var i: usize = 0;
+ while (i < users.items.len) {
+ if (users.items[i].client_id == e.client_id) {
+ _ = users.orderedRemove(i);
+ break;
+ }
+ i += 1;
+ }
+ }
+
+ // Broadcast user list update to all clients
+ broadcastUserListUpdate();
+
+ // Clean up context
+ context.destroy();
+}
+
+fn trackClick(e: *webui.Event) void {
+ const button_name = e.getString();
+
+ // Get user context from global storage
+ const context = getContextsMap().get(e.client_id) orelse {
+ e.returnString("No active session - please login first");
+ return;
+ };
+
+ context.click_count += 1;
+
+ var response: [257]u8 = undefined; // +1 for null terminator
+ const msg = std.fmt.bufPrint(response[0..256],
+ "Button '{s}' clicked by {s}. Total clicks: {}",
+ .{button_name, context.username, context.click_count}) catch "";
+
+ // Ensure null termination
+ response[msg.len] = 0;
+ const null_terminated: [:0]const u8 = response[0..msg.len :0];
+ e.returnString(null_terminated);
+ std.debug.print("Click tracked: {s} by {s} ({})\n", .{button_name, context.username, context.click_count});
+}
+
+fn getUserInfo(e: *webui.Event) void {
+ // Get user context from global storage
+ const context = getContextsMap().get(e.client_id) orelse {
+ e.returnString("{\"error\":\"No active session\"}");
+ return;
+ };
+
+ const session_time = std.time.timestamp() - context.session_start;
+
+ var response: [513]u8 = undefined; // +1 for null terminator
+ const json = std.fmt.bufPrint(response[0..512],
+ "{{\"userId\":{},\"username\":\"{s}\",\"sessionTime\":{},\"clickCount\":{},\"clientId\":{}}}",
+ .{context.user_id, context.username, session_time, context.click_count, e.client_id}) catch "";
+
+ // Ensure null termination
+ response[json.len] = 0;
+ const null_terminated: [:0]const u8 = response[0..json.len :0];
+ e.returnString(null_terminated);
+}
+
+fn sendMessage(e: *webui.Event) void {
+ const message = e.getString();
+ const target_client = e.getIntAt(1);
+
+ // Get sender context from global storage
+ const context = getContextsMap().get(e.client_id) orelse {
+ e.returnString("Authentication required");
+ return;
+ };
+
+ // In a real application, you would send to specific client
+ // For this example, we'll just log the message
+ std.debug.print("Message from {s} to client {}: {s}\n", .{context.username, target_client, message});
+
+ // Send message to specific client (simulated)
+ const win = e.getWindow();
+ var js_code: [513]u8 = undefined; // +1 for null terminator
+ const script = std.fmt.bufPrint(js_code[0..512],
+ "receiveMessage('{s}', '{s}');", .{context.username, message}) catch return;
+
+ // Ensure null termination
+ js_code[script.len] = 0;
+ const null_terminated: [:0]const u8 = js_code[0..script.len :0];
+ win.run(null_terminated);
+
+ e.returnString("Message sent");
+}
+
+fn broadcastUserListUpdate() void {
+ // Create JSON list of online users
+ var users_json: [1024]u8 = undefined;
+ var json_content: []const u8 = undefined;
+
+ if (online_users) |users| {
+ var stream = std.io.fixedBufferStream(&users_json);
+ var writer = stream.writer();
+
+ writer.writeAll("[") catch return;
+ for (users.items, 0..) |user, i| {
+ if (i > 0) writer.writeAll(",") catch return;
+ writer.print("{{\"clientId\":{},\"username\":\"{s}\"}}", .{user.client_id, user.username}) catch return;
+ }
+ writer.writeAll("]") catch return;
+
+ json_content = stream.getWritten();
+ } else {
+ json_content = "[]";
+ }
+
+ // Broadcast to all windows (this is a simplified approach)
+ // In a real implementation, you'd iterate through all active windows
+ std.debug.print("Broadcasting user list update: {s}\n", .{json_content});
+
+ // Note: This is a simplified version. In a full implementation,
+ // you would need to track all active windows and send to each one.
+}
+
+fn getOnlineUsers(e: *webui.Event) void {
+ // Return list of online users as JSON
+ var users_json: [1024]u8 = undefined;
+ var json_content: []const u8 = undefined;
+
+ if (online_users) |users| {
+ var stream = std.io.fixedBufferStream(&users_json);
+ var writer = stream.writer();
+
+ writer.writeAll("[") catch {
+ e.returnString("[]");
+ return;
+ };
+ for (users.items, 0..) |user, i| {
+ if (i > 0) writer.writeAll(",") catch continue;
+ writer.print("{{\"clientId\":{},\"username\":\"{s}\"}}", .{user.client_id, user.username}) catch continue;
+ }
+ writer.writeAll("]") catch {
+ e.returnString("[]");
+ return;
+ };
+
+ json_content = stream.getWritten();
+ } else {
+ json_content = "[]";
+ }
+
+ var response: [1025]u8 = undefined;
+ std.mem.copyForwards(u8, response[0..json_content.len], json_content);
+ response[json_content.len] = 0;
+ const null_terminated: [:0]const u8 = response[0..json_content.len :0];
+ e.returnString(null_terminated);
+}
+
+fn broadcastMessage(e: *webui.Event) void {
+ const message = e.getString();
+
+ // Get sender context from global storage
+ const context = getContextsMap().get(e.client_id) orelse {
+ e.returnString("Authentication required");
+ return;
+ };
+
+ std.debug.print("Broadcast from {s}: {s}\n", .{context.username, message});
+
+ // Broadcast to all clients
+ const win = e.getWindow();
+ var js_code: [513]u8 = undefined; // +1 for null terminator
+ const script = std.fmt.bufPrint(js_code[0..512],
+ "receiveBroadcast('{s}', '{s}');", .{context.username, message}) catch return;
+
+ // Ensure null termination
+ js_code[script.len] = 0;
+ const null_terminated: [:0]const u8 = js_code[0..script.len :0];
+ win.run(null_terminated);
+
+ e.returnString("Message broadcasted to all clients");
+}
+
+fn clientConnect(e: *webui.Event) void {
+ std.debug.print("Client connected: ID={}, Connection={}\n", .{e.client_id, e.connection_id});
+
+ // Send welcome message to the specific client
+ e.runClient("showNotification('Connected to server');");
+
+ var response: [129]u8 = undefined; // +1 for null terminator
+ const msg = std.fmt.bufPrint(response[0..128],
+ "Client {} connected", .{e.client_id}) catch "";
+
+ // Ensure null termination
+ response[msg.len] = 0;
+ const null_terminated: [:0]const u8 = response[0..msg.len :0];
+ e.returnString(null_terminated);
+}
+
+fn clientDisconnect(e: *webui.Event) void {
+ std.debug.print("Client disconnected: ID={}, Connection={}\n", .{e.client_id, e.connection_id});
+
+ // Clean up any client-specific resources
+ e.closeClient();
+}
+
+fn universalEventHandler(e: *webui.Event) void {
+ // This handler catches all events
+ std.debug.print("Universal handler - Event: {s}, Client: {}, Type: {}\n",
+ .{e.element, e.client_id, e.event_type});
+
+ // You could implement global logging, analytics, or security checks here
+}
+
+fn interfaceEventHandler(
+ window_handle: usize,
+ event_type: webui.EventKind,
+ element: []u8,
+ event_number: usize,
+ bind_id: usize,
+) void {
+ std.debug.print("Interface handler - Window: {}, Type: {}, Element: {s}, Event: {}, Bind: {}\n",
+ .{window_handle, event_type, element, event_number, bind_id});
+
+ // Advanced event processing using interface API
+ const win = webui{ .window_handle = window_handle };
+
+ // Get event data using interface methods
+ const arg_count = win.interfaceGetSizeAt(event_number, 0);
+ if (arg_count > 0) {
+ const first_arg = win.interfaceGetStringAt(event_number, 0);
+ std.debug.print("First argument: {s}\n", .{first_arg});
+ }
+
+ // Set response using interface
+ win.interfaceSetResponse(event_number, "Interface handler processed event");
+}
+
+fn cleanupAllContexts() void {
+ // In a real application, you would maintain a list of all contexts
+ // and clean them up here
+ // Clean up all remaining user contexts
+ if (global_user_contexts) |*contexts| {
+ var iterator = contexts.iterator();
+ while (iterator.next()) |entry| {
+ entry.value_ptr.*.destroy();
+ }
+ contexts.clearAndFree();
+ }
+
+ std.debug.print("Cleaning up all user contexts...\n", .{});
+}
diff --git a/examples/js_execution/index.html b/examples/js_execution/index.html
new file mode 100644
index 0000000..d692f24
--- /dev/null
+++ b/examples/js_execution/index.html
@@ -0,0 +1,307 @@
+
+
+
+
+
+ JavaScript Execution Example
+
+
+
+
+
🚀 JavaScript Execution & Communication
+
+
+
Simple JavaScript Execution
+
+
Ready to execute JavaScript...
+
+
+
+
JavaScript with Response
+
+
+
+
+
+
+
Select operation and click Calculate...
+
+
+
+
Complex JavaScript Processing
+
+
+
+
+
Enter text and click Process...
+
+
+
+
Send Data to JavaScript
+
+
+
+
+
+
No data received yet...
+
+
+
+
Raw Binary Data
+
+
+ bytes
+
+
+
Raw data display area...
+
+
+
+
Navigation
+
+
+
+
+
+
Enter URL and navigate...
+
+
+
+
DOM Manipulation
+
+
+
+
+
This content can be updated from Zig
+
+
+
+
JSON Data Exchange
+
+
+
+
+
JSON processing result will appear here...
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/js_execution/main.zig b/examples/js_execution/main.zig
new file mode 100644
index 0000000..8e686dc
--- /dev/null
+++ b/examples/js_execution/main.zig
@@ -0,0 +1,282 @@
+//! WebUI Zig - JavaScript Execution and Communication Example
+//! This example demonstrates running JavaScript from Zig and advanced communication
+const std = @import("std");
+const webui = @import("webui");
+
+const html = @embedFile("index.html");
+
+var allocator = std.heap.page_allocator;
+
+pub fn main() !void {
+ // Create window
+ var nwin = webui.newWindow();
+
+ // Set runtime for JavaScript execution
+ nwin.setRuntime(.NodeJS);
+
+ // Bind functions for JavaScript execution
+ _ = try nwin.binding("run_simple_js", runSimpleJs);
+ _ = try nwin.binding("run_js_with_response", runJsWithResponse);
+ _ = try nwin.binding("run_complex_js", runComplexJs);
+ _ = try nwin.binding("send_data_to_js", sendDataToJs);
+ _ = try nwin.binding("send_raw_data", sendRawData);
+ _ = try nwin.binding("navigate_to_url", navigateToUrl);
+ _ = try nwin.binding("get_page_content", getPageContent);
+ _ = try nwin.binding("manipulate_dom", manipulateDom);
+ _ = try nwin.binding("handle_json_data", handleJsonData);
+
+ // Show window
+ try nwin.show(html);
+
+ // Wait for window to close
+ webui.wait();
+
+ // Clean up
+ webui.clean();
+}
+
+fn runSimpleJs(e: *webui.Event) void {
+ const win = e.getWindow();
+
+ // Run JavaScript without waiting for response
+ win.run("alert('Hello from Zig!'); console.log('JavaScript executed from Zig');");
+
+ e.returnString("Simple JavaScript executed");
+ std.debug.print("Executed simple JavaScript\n", .{});
+}
+
+fn runJsWithResponse(e: *webui.Event, operation: [:0]const u8, a: i64, b: i64) void {
+ const win = e.getWindow();
+
+ // Prepare JavaScript code based on operation
+ var js_code: [256]u8 = undefined;
+ const script = switch (std.mem.eql(u8, operation, "add")) {
+ true => std.fmt.bufPrint(js_code[0..], "return {} + {};", .{a, b}),
+ false => switch (std.mem.eql(u8, operation, "multiply")) {
+ true => std.fmt.bufPrint(js_code[0..], "return {} * {};", .{a, b}),
+ false => switch (std.mem.eql(u8, operation, "power")) {
+ true => std.fmt.bufPrint(js_code[0..], "return Math.pow({}, {});", .{a, b}),
+ false => std.fmt.bufPrint(js_code[0..], "return 'Unknown operation';", .{}),
+ },
+ },
+ } catch return;
+
+ // Execute JavaScript and get response
+ var response_buffer: [64]u8 = undefined;
+ // Ensure script is null-terminated by creating a proper null-terminated string
+ var null_terminated_script: [257]u8 = undefined; // +1 for null terminator
+ @memcpy(null_terminated_script[0..script.len], script);
+ null_terminated_script[script.len] = 0;
+ const script_z: [:0]const u8 = null_terminated_script[0..script.len :0];
+
+ win.script(script_z, 5, response_buffer[0..]) catch {
+ e.returnString("JavaScript execution failed");
+ return;
+ };
+
+ // Find the null terminator
+ var response_len: usize = 0;
+ for (response_buffer) |c| {
+ if (c == 0) break;
+ response_len += 1;
+ }
+
+ e.returnString(response_buffer[0..response_len :0]);
+ std.debug.print("JavaScript result: {s}\n", .{response_buffer[0..response_len]});
+}
+
+fn runComplexJs(e: *webui.Event, data: [:0]const u8) void {
+ const win = e.getWindow();
+
+ // Complex JavaScript that processes data and returns result
+ var js_code: [512]u8 = undefined;
+ const script = std.fmt.bufPrint(js_code[0..],
+ \\const data = '{s}';
+ \\const result = {{
+ \\ original: data,
+ \\ length: data.length,
+ \\ uppercase: data.toUpperCase(),
+ \\ words: data.split(' ').length,
+ \\ reversed: data.split('').reverse().join(''),
+ \\ timestamp: new Date().toISOString()
+ \\}};
+ \\return JSON.stringify(result);
+ , .{data}) catch return;
+
+ var response_buffer: [1024]u8 = undefined;
+ // Ensure script is null-terminated
+ var null_terminated_script: [513]u8 = undefined; // +1 for null terminator
+ @memcpy(null_terminated_script[0..script.len], script);
+ null_terminated_script[script.len] = 0;
+ const script_z: [:0]const u8 = null_terminated_script[0..script.len :0];
+
+ win.script(script_z, 10, response_buffer[0..]) catch {
+ e.returnString("Complex JavaScript execution failed");
+ return;
+ };
+
+ // Find response length
+ var response_len: usize = 0;
+ for (response_buffer) |c| {
+ if (c == 0) break;
+ response_len += 1;
+ }
+
+ e.returnString(response_buffer[0..response_len :0]);
+ std.debug.print("Complex JavaScript result: {s}\n", .{response_buffer[0..response_len]});
+}
+
+fn sendDataToJs(e: *webui.Event, message: [:0]const u8, value: i64) void {
+ const win = e.getWindow();
+
+ // Create data structure to send
+ var data: [256]u8 = undefined;
+ const json_data = std.fmt.bufPrint(data[0..],
+ "{{\"message\":\"{s}\",\"value\":{},\"timestamp\":{}}}",
+ .{message, value, std.time.timestamp()}) catch return;
+
+ // Send data to JavaScript function
+ var js_call: [512]u8 = undefined;
+ const js_code = std.fmt.bufPrint(js_call[0..],
+ "receiveDataFromZig({s});", .{json_data}) catch return;
+
+ // Ensure js_code is null-terminated
+ var null_terminated_js: [513]u8 = undefined; // +1 for null terminator
+ @memcpy(null_terminated_js[0..js_code.len], js_code);
+ null_terminated_js[js_code.len] = 0;
+ const js_code_z: [:0]const u8 = null_terminated_js[0..js_code.len :0];
+
+ win.run(js_code_z);
+
+ e.returnString("Data sent to JavaScript");
+ std.debug.print("Sent data to JavaScript: {s}\n", .{json_data});
+}
+
+fn sendRawData(e: *webui.Event, size: i64) void {
+ const win = e.getWindow();
+
+ // Create raw binary data
+ const data_size: usize = @intCast(@min(size, 1024));
+ const raw_data = allocator.alloc(u8, data_size) catch return;
+ defer allocator.free(raw_data);
+
+ // Fill with sample data
+ for (raw_data, 0..) |*byte, i| {
+ byte.* = @intCast(i % 256);
+ }
+
+ // Send raw data to JavaScript
+ win.sendRaw("receiveRawData", raw_data);
+
+ var response: [64]u8 = undefined;
+ const msg = std.fmt.bufPrint(response[0..],
+ "Sent {} bytes of raw data", .{data_size}) catch return;
+
+ // Ensure msg is null-terminated
+ var null_terminated_msg: [65]u8 = undefined; // +1 for null terminator
+ @memcpy(null_terminated_msg[0..msg.len], msg);
+ null_terminated_msg[msg.len] = 0;
+ const msg_z: [:0]const u8 = null_terminated_msg[0..msg.len :0];
+
+ e.returnString(msg_z);
+ std.debug.print("Sent raw data: {} bytes\n", .{data_size});
+}
+
+fn navigateToUrl(e: *webui.Event, url: [:0]const u8) void {
+ const win = e.getWindow();
+
+ if (std.mem.startsWith(u8, url, "http://") or std.mem.startsWith(u8, url, "https://")) {
+ win.navigate(url);
+ e.returnString("Navigation initiated");
+ std.debug.print("Navigating to: {s}\n", .{url});
+ } else {
+ e.returnString("Invalid URL - must start with http:// or https://");
+ }
+}
+
+fn getPageContent(e: *webui.Event) void {
+ const win = e.getWindow();
+
+ const js_code =
+ \\return JSON.stringify({
+ \\ title: document.title,
+ \\ url: window.location.href,
+ \\ userAgent: navigator.userAgent,
+ \\ cookies: document.cookie,
+ \\ elements: document.querySelectorAll('*').length
+ \\});
+ ;
+
+ var response_buffer: [2048]u8 = undefined;
+ win.script(js_code, 5, response_buffer[0..]) catch {
+ e.returnString("Failed to get page content");
+ return;
+ };
+
+ // Find response length
+ var response_len: usize = 0;
+ for (response_buffer) |c| {
+ if (c == 0) break;
+ response_len += 1;
+ }
+
+ e.returnString(response_buffer[0..response_len :0]);
+ std.debug.print("Page content: {s}\n", .{response_buffer[0..response_len]});
+}
+
+fn manipulateDom(e: *webui.Event, element_id: [:0]const u8, new_text: [:0]const u8) void {
+ const win = e.getWindow();
+
+ var js_code: [512]u8 = undefined;
+ const script = std.fmt.bufPrint(js_code[0..],
+ \\const element = document.getElementById('{s}');
+ \\if (element) {{
+ \\ element.innerHTML = '{s}';
+ \\ element.style.background = 'rgba(0,255,0,0.2)';
+ \\ setTimeout(() => element.style.background = '', 2000);
+ \\ return 'Element updated successfully';
+ \\}} else {{
+ \\ return 'Element not found';
+ \\}}
+ , .{element_id, new_text}) catch return;
+
+ var response_buffer: [128]u8 = undefined;
+ // Ensure script is null-terminated
+ var null_terminated_script: [513]u8 = undefined; // +1 for null terminator
+ @memcpy(null_terminated_script[0..script.len], script);
+ null_terminated_script[script.len] = 0;
+ const script_z: [:0]const u8 = null_terminated_script[0..script.len :0];
+
+ win.script(script_z, 5, response_buffer[0..]) catch {
+ e.returnString("DOM manipulation failed");
+ return;
+ };
+
+ // Find response length
+ var response_len: usize = 0;
+ for (response_buffer) |c| {
+ if (c == 0) break;
+ response_len += 1;
+ }
+
+ e.returnString(response_buffer[0..response_len :0]);
+ std.debug.print("DOM manipulation result: {s}\n", .{response_buffer[0..response_len]});
+}
+
+fn handleJsonData(e: *webui.Event, json_str: [:0]const u8) void {
+ // In a real application, you would parse the JSON properly
+ // For this example, we'll just echo back some processed info
+
+ var response: [512]u8 = undefined;
+ const result = std.fmt.bufPrint(response[0..],
+ "Received JSON data: {s} (length: {})", .{json_str, json_str.len}) catch return;
+
+ // Ensure result is null-terminated
+ var null_terminated_result: [513]u8 = undefined; // +1 for null terminator
+ @memcpy(null_terminated_result[0..result.len], result);
+ null_terminated_result[result.len] = 0;
+ const result_z: [:0]const u8 = null_terminated_result[0..result.len :0];
+
+ e.returnString(result_z);
+ std.debug.print("Processed JSON: {s}\n", .{json_str});
+}
\ No newline at end of file
diff --git a/examples/web_app_multi_client/main.zig b/examples/web_app_multi_client/main.zig
index d16c150..d92d386 100644
--- a/examples/web_app_multi_client/main.zig
+++ b/examples/web_app_multi_client/main.zig
@@ -1,5 +1,6 @@
const std = @import("std");
const webui = @import("webui");
+const builtin = @import("builtin");
// general purpose allocator
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
@@ -40,10 +41,15 @@ fn saveAll(e: *webui.Event) void {
public_input = allocator.dupe(u8, publicInput) catch unreachable;
// general new js
- const js = std.fmt.allocPrintZ(
+ const js = if (builtin.zig_version.minor == 14) std.fmt.allocPrintZ(
allocator,
"document.getElementById(\"publicInput\").value = \"{s}\";",
.{publicInput},
+ ) catch unreachable else std.fmt.allocPrintSentinel(
+ allocator,
+ "document.getElementById(\"publicInput\").value = \"{s}\";",
+ .{publicInput},
+ 0,
) catch unreachable;
// free js
defer allocator.free(js);
diff --git a/examples/window_management/index.html b/examples/window_management/index.html
new file mode 100644
index 0000000..49d29fa
--- /dev/null
+++ b/examples/window_management/index.html
@@ -0,0 +1,202 @@
+
+
+
+
+
+ Window Management Example
+
+
+
+
+
🖼️ Window Management Example
+
+
+
Basic Window Controls
+
+
+
+
+
+
Window Modes
+
+
+
+
+
Browser Features
+
+
+
+
+
+
+
Multiple Windows
+
+
+
+
+
Window Information
+
+
Click "Get Window Info" to see details
+
+
+
+
Result Display
+
+ Ready...
+
+
+
+
+
💡 Browser Mode Tips
+
+
Keyboard Shortcuts:
+
+ - F11 - Toggle fullscreen
+ - Ctrl + Shift + I - Developer tools
+ - Ctrl + R - Refresh page
+ - Alt + F4 - Close window (Windows)
+ - Cmd + W - Close window (macOS)
+ - Esc - Exit fullscreen/kiosk mode
+
+
Features:
+
+ - Kiosk Mode: WebUI native kiosk mode
+ - Fullscreen: Standard fullscreen toggle
+ - Window Info: Real-time browser and window details
+
+
Note: All features use WebUI native APIs.
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/window_management/main.zig b/examples/window_management/main.zig
new file mode 100644
index 0000000..a686886
--- /dev/null
+++ b/examples/window_management/main.zig
@@ -0,0 +1,196 @@
+//! WebUI Zig - Window Management Example
+//! This example demonstrates various window management features
+const std = @import("std");
+const webui = @import("webui");
+
+const html = @embedFile("index.html");
+
+pub fn main() !void {
+ // 配置WebUI全局设置以避免安全警告
+ webui.setConfig(.show_wait_connection, true);
+ webui.setConfig(.use_cookies, true);
+ webui.setConfig(.multi_client, false); // 单客户端模式更安全
+
+ // Create multiple windows
+ var main_window = webui.newWindow();
+ var second_window = webui.newWindow();
+
+ // Configure main window
+ main_window.setSize(800, 600);
+ main_window.setPosition(100, 100);
+ main_window.setCenter();
+ main_window.setIcon("", "image/svg+xml");
+
+ // Configure second window
+ second_window.setSize(400, 300);
+ second_window.setPosition(500, 200);
+ second_window.setKiosk(false);
+ second_window.setResizable(true);
+
+ // Bind window control functions
+ _ = try main_window.binding("close_window", closeWindow);
+ _ = try main_window.binding("toggle_kiosk", toggleKiosk);
+ _ = try main_window.binding("get_window_info", getWindowInfo);
+ _ = try main_window.binding("open_second_window", openSecondWindow);
+ _ = try main_window.binding("set_window_size", setWindowSize);
+ _ = try main_window.binding("center_window", centerWindow);
+ _ = try main_window.binding("show_browser_info", showBrowserInfo);
+
+ // Bind second window controls
+ _ = try second_window.binding("close_second", closeSecondWindow);
+
+
+ // Show main window
+ // 使用普通浏览器模式
+ try main_window.show(html);
+
+ // Wait for all windows to close
+ webui.wait();
+
+ // Clean up
+ webui.clean();
+}
+
+var main_win: ?webui = null;
+var second_win: ?webui = null;
+var is_kiosk = false;
+
+fn closeWindow(e: *webui.Event) void {
+ const win = e.getWindow();
+ win.close();
+ std.debug.print("Window closed\n", .{});
+}
+
+fn toggleKiosk(e: *webui.Event) void {
+ // 使用WebUI原生API设置kiosk模式
+ const win = e.getWindow();
+ is_kiosk = !is_kiosk;
+ win.setKiosk(is_kiosk);
+
+ const response = if (is_kiosk) "Kiosk mode enabled" else "Kiosk mode disabled";
+ e.returnString(response);
+ std.debug.print("Kiosk mode toggled: {}\n", .{is_kiosk});
+}
+
+fn getWindowInfo(e: *webui.Event) void {
+ const win = e.getWindow();
+
+ const port = win.getPort() catch 0;
+ const url = win.getUrl() catch "";
+ const is_shown = win.isShown();
+
+ var buffer: [512]u8 = undefined;
+ const info = std.fmt.bufPrint(buffer[0..],
+ "Port: {}, URL: {s}, Shown: {}", .{port, url, is_shown}) catch "";
+
+ // 确保有足够空间容纳null终止符
+ if (info.len < buffer.len) {
+ buffer[info.len] = 0;
+ e.returnString(buffer[0..info.len :0]);
+ } else {
+ // 如果缓冲区太小,返回错误信息
+ const error_msg = "Buffer too small";
+ e.returnString(error_msg);
+ }
+ std.debug.print("Window info: {s}\n", .{info});
+}
+
+fn openSecondWindow(e: *webui.Event) void {
+ // 检查第二个窗口是否存在且仍在运行
+ if (second_win == null or (second_win != null and !second_win.?.isShown())) {
+ // 如果窗口已经被外部关闭,重置为null
+ if (second_win != null and !second_win.?.isShown()) {
+ std.debug.print("Detected second window was closed externally, resetting\n", .{});
+ second_win = null;
+ }
+
+ second_win = webui.newWindow();
+ if (second_win) |*win| {
+ // 重新绑定第二个窗口的关闭函数
+ _ = win.binding("close_second", closeSecondWindow) catch {
+ std.debug.print("Failed to bind close_second function\n", .{});
+ e.returnString("Failed to bind second window functions");
+ return;
+ };
+
+ // 绑定空的断开连接事件处理器,用于清理状态
+ _ = win.binding("", handleSecondWindowDisconnect) catch {
+ std.debug.print("Failed to bind disconnect handler\n", .{});
+ };
+
+ win.setSize(400, 300);
+ win.show("Second Window
") catch {
+ std.debug.print("Failed to show second window\n", .{});
+ e.returnString("Failed to show second window");
+ return;
+ };
+ e.returnString("Second window opened successfully");
+ } else {
+ e.returnString("Failed to create second window");
+ }
+ } else {
+ e.returnString("Second window already open");
+ }
+}
+
+fn closeSecondWindow(e: *webui.Event) void {
+ const win = e.getWindow();
+ win.close();
+ second_win = null;
+ std.debug.print("Second window closed\n", .{});
+}
+
+fn handleSecondWindowDisconnect(e: *webui.Event) void {
+ // 当第二个窗口断开连接时(包括用户点击x关闭),清理状态
+ _ = e; // 标记参数已使用
+ second_win = null;
+ std.debug.print("Second window disconnected\n", .{});
+}
+
+fn setWindowSize(e: *webui.Event, width: i64, height: i64) void {
+ const win = e.getWindow();
+ win.setSize(@intCast(width), @intCast(height));
+
+ var buffer: [128]u8 = undefined;
+ const response = std.fmt.bufPrint(buffer[0..],
+ "Size set to {}x{}", .{width, height}) catch "";
+
+ // 确保有足够空间容纳null终止符
+ if (response.len < buffer.len) {
+ buffer[response.len] = 0;
+ e.returnString(buffer[0..response.len :0]);
+ } else {
+ // 如果缓冲区太小,返回错误信息
+ const error_msg = "Buffer too small";
+ e.returnString(error_msg);
+ }
+ std.debug.print("Window size set to {}x{}\n", .{width, height});
+}
+
+fn centerWindow(e: *webui.Event) void {
+ const win = e.getWindow();
+ win.setCenter();
+ e.returnString("Window centered");
+ std.debug.print("Window centered\n", .{});
+}
+
+fn showBrowserInfo(e: *webui.Event) void {
+ // 显示浏览器和窗口信息
+ e.runClient(
+ \\const info = {
+ \\ userAgent: navigator.userAgent,
+ \\ screenWidth: screen.width,
+ \\ screenHeight: screen.height,
+ \\ windowWidth: window.innerWidth,
+ \\ windowHeight: window.innerHeight,
+ \\ isFullscreen: !!document.fullscreenElement
+ \\};
+ \\document.getElementById('info-display').innerHTML =
+ \\ 'Browser: ' + info.userAgent.split(' ').pop() + '
' +
+ \\ 'Screen: ' + info.screenWidth + 'x' + info.screenHeight + '
' +
+ \\ 'Window: ' + info.windowWidth + 'x' + info.windowHeight + '
' +
+ \\ 'Fullscreen: ' + info.isFullscreen;
+ );
+ std.debug.print("Browser info displayed\n", .{});
+ e.returnString("Browser information updated");
+}
diff --git a/src/c.zig b/src/c.zig
index 4c1a43c..4f5d47f 100644
--- a/src/c.zig
+++ b/src/c.zig
@@ -13,7 +13,7 @@ const Runtime = webui.Runtime;
/// @return Returns the window number.
///
/// @example const my_window: usize = webui_new_window();
-pub extern fn webui_new_window() callconv(.C) usize;
+pub extern fn webui_new_window() callconv(.c) usize;
/// @brief Create a new webui window object using a specified window number.
///
@@ -22,14 +22,14 @@ pub extern fn webui_new_window() callconv(.C) usize;
/// @return Returns the same window number if success.
///
/// @example const my_window: usize = webui_new_window_id(123);
-pub extern fn webui_new_window_id(window_number: usize) callconv(.C) usize;
+pub extern fn webui_new_window_id(window_number: usize) callconv(.c) usize;
/// @brief Get a free window number that can be used with `webui_new_window_id()`
///
/// @return Returns the first available free window number. Starting from 1.
///
/// @example const my_window: usize = webui_get_new_window_id();
-pub extern fn webui_get_new_window_id() callconv(.C) usize;
+pub extern fn webui_get_new_window_id() callconv(.c) usize;
/// @brief Bind an HTML element and a Javascript object with a backend function. Empty
/// element name means all events.
@@ -44,8 +44,8 @@ pub extern fn webui_get_new_window_id() callconv(.C) usize;
pub extern fn webui_bind(
window: usize,
element: [*:0]const u8,
- func: *const fn (e: *Event) callconv(.C) void,
-) callconv(.C) usize;
+ func: *const fn (e: *Event) callconv(.c) void,
+) callconv(.c) usize;
/// @brief Use this API after using `webui_bind()` to add any user data to it that can be
/// read later using `webui_get_context()`.
@@ -66,7 +66,7 @@ pub extern fn webui_set_context(
window: usize,
element: [*:0]const u8,
context: *anyopaque,
-) callconv(.C) void;
+) callconv(.c) void;
/// @brief Get user data that is set using `webui_set_context()`.
///
@@ -84,7 +84,7 @@ pub extern fn webui_set_context(
/// }
pub extern fn webui_get_context(
e: *Event,
-) callconv(.C) ?*anyopaque;
+) callconv(.c) ?*anyopaque;
/// @brief Get the recommended web browser ID to use. If you
/// are already using one, this function will return the same ID.
@@ -94,7 +94,7 @@ pub extern fn webui_get_context(
/// @return Returns a web browser ID.
///
/// @example const browser_id: usize = webui_get_best_browser(my_window);
-pub extern fn webui_get_best_browser(window: usize) callconv(.C) Browser;
+pub extern fn webui_get_best_browser(window: usize) callconv(.c) Browser;
/// @brief Show a window using embedded HTML, or a file. If the window is already
/// open, it will be refreshed. This will refresh all windows in multi-client mode.
@@ -106,7 +106,7 @@ pub extern fn webui_get_best_browser(window: usize) callconv(.C) Browser;
///
/// @example webui_show(my_window, "..."); |
/// webui_show(my_window, "index.html"); | webui_show(my_window, "http://...");
-pub extern fn webui_show(window: usize, content: [*:0]const u8) callconv(.C) bool;
+pub extern fn webui_show(window: usize, content: [*:0]const u8) callconv(.c) bool;
/// @brief Show a window using embedded HTML, or a file. If the window is already
/// open, it will be refreshed. Single client.
@@ -118,7 +118,7 @@ pub extern fn webui_show(window: usize, content: [*:0]const u8) callconv(.C) boo
///
/// @example webui_show_client(e, "..."); |
/// webui_show_client(e, "index.html"); | webui_show_client(e, "http://...");
-pub extern fn webui_show_client(e: *Event, content: [*:0]const u8) callconv(.C) bool;
+pub extern fn webui_show_client(e: *Event, content: [*:0]const u8) callconv(.c) bool;
/// @brief Same as `webui_show()`. But using a specific web browser.
///
@@ -134,7 +134,7 @@ pub extern fn webui_show_browser(
window: usize,
content: [*:0]const u8,
browser: Browser,
-) callconv(.C) bool;
+) callconv(.c) bool;
/// @brief Same as `webui_show()`. But start only the web server and return the URL.
/// No window will be shown.
@@ -148,7 +148,7 @@ pub extern fn webui_show_browser(
pub extern fn webui_start_server(
window: usize,
content: [*:0]const u8,
-) callconv(.C) [*:0]const u8;
+) callconv(.c) [*:0]const u8;
/// @brief Show a WebView window using embedded HTML, or a file. If the window is already
/// open, it will be refreshed. Note: Win32 need `WebView2Loader.dll`.
@@ -160,7 +160,7 @@ pub extern fn webui_start_server(
///
/// @example webui_show_wv(my_window, "..."); | webui_show_wv(my_window,
/// "index.html"); | webui_show_wv(my_window, "http://...");
-pub extern fn webui_show_wv(window: usize, content: [*:0]const u8) callconv(.C) bool;
+pub extern fn webui_show_wv(window: usize, content: [*:0]const u8) callconv(.c) bool;
/// @brief Set the window in Kiosk mode (Full screen).
///
@@ -168,7 +168,7 @@ pub extern fn webui_show_wv(window: usize, content: [*:0]const u8) callconv(.C)
/// @param status True or False
///
/// @example webui_set_kiosk(my_window, true);
-pub extern fn webui_set_kiosk(window: usize, status: bool) callconv(.C) void;
+pub extern fn webui_set_kiosk(window: usize, status: bool) callconv(.c) void;
/// @brief Add a user-defined web browser's CLI parameters.
///
@@ -176,7 +176,7 @@ pub extern fn webui_set_kiosk(window: usize, status: bool) callconv(.C) void;
/// @param params Command line parameters
///
/// @example webui_set_custom_parameters(myWindow, "--remote-debugging-port=9222");
-pub extern fn webui_set_custom_parameters(window: usize, params: [*:0]const u8) callconv(.C) void;
+pub extern fn webui_set_custom_parameters(window: usize, params: [*:0]const u8) callconv(.c) void;
/// @brief Set the window with high-contrast support. Useful when you want to
/// build a better high-contrast theme with CSS.
@@ -185,7 +185,7 @@ pub extern fn webui_set_custom_parameters(window: usize, params: [*:0]const u8)
/// @param status True or False
///
/// @example webui_set_high_contrast(my_window, true);
-pub extern fn webui_set_high_contrast(window: usize, status: bool) callconv(.C) void;
+pub extern fn webui_set_high_contrast(window: usize, status: bool) callconv(.c) void;
/// @brief Sets whether the window frame is resizable or fixed.
/// Works only on WebView window.
@@ -194,26 +194,26 @@ pub extern fn webui_set_high_contrast(window: usize, status: bool) callconv(.C)
/// @param status True or False
///
/// @example webui_set_resizable(myWindow, true);
-pub extern fn webui_set_resizable(window: usize, status: bool) callconv(.C) void;
+pub extern fn webui_set_resizable(window: usize, status: bool) callconv(.c) void;
/// @brief Get OS high contrast preference.
///
/// @return Returns True if OS is using high contrast theme
///
/// @example const hc: bool = webui_is_high_contrast();
-pub extern fn webui_is_high_contrast() callconv(.C) bool;
+pub extern fn webui_is_high_contrast() callconv(.c) bool;
/// @brief Check if a web browser is installed.
///
/// @return Returns True if the specified browser is available.
///
/// @example const status: bool = webui_browser_exist(.Chrome);
-pub extern fn webui_browser_exist(browser: Browser) callconv(.C) bool;
+pub extern fn webui_browser_exist(browser: Browser) callconv(.c) bool;
/// @brief Wait until all opened windows get closed.
///
/// @example webui_wait();
-pub extern fn webui_wait() callconv(.C) void;
+pub extern fn webui_wait() callconv(.c) void;
/// @brief Close a specific window only. The window object will still exist.
/// All clients.
@@ -221,40 +221,40 @@ pub extern fn webui_wait() callconv(.C) void;
/// @param The window number
///
/// @example webui_close(my_window);
-pub extern fn webui_close(window: usize) callconv(.C) void;
+pub extern fn webui_close(window: usize) callconv(.c) void;
/// @brief Minimize a WebView window.
///
/// @param window The window number
///
/// @example webui_minimize(myWindow);
-pub extern fn webui_minimize(window: usize) callconv(.C) void;
+pub extern fn webui_minimize(window: usize) callconv(.c) void;
/// @brief Maximize a WebView window.
///
/// @param window The window number
///
/// @example webui_maximize(myWindow);
-pub extern fn webui_maximize(window: usize) callconv(.C) void;
+pub extern fn webui_maximize(window: usize) callconv(.c) void;
/// @brief Close a specific client.
///
/// @param e The event struct
///
/// @example webui_close_client(e);
-pub extern fn webui_close_client(e: *Event) callconv(.C) void;
+pub extern fn webui_close_client(e: *Event) callconv(.c) void;
/// @brief Close a specific window and free all memory resources.
///
/// @param window The window number
///
/// @example webui_destroy(my_window);
-pub extern fn webui_destroy(window: usize) callconv(.C) void;
+pub extern fn webui_destroy(window: usize) callconv(.c) void;
/// @brief Close all open windows. `webui_wait()` will return (Break).
///
/// @example webui_exit();
-pub extern fn webui_exit() callconv(.C) void;
+pub extern fn webui_exit() callconv(.c) void;
/// @brief Set the web-server root folder path for a specific window.
///
@@ -262,14 +262,14 @@ pub extern fn webui_exit() callconv(.C) void;
/// @param path The local folder full path
///
/// @example webui_set_root_folder(my_window, "/home/Foo/Bar/");
-pub extern fn webui_set_root_folder(window: usize, path: [*:0]const u8) callconv(.C) bool;
+pub extern fn webui_set_root_folder(window: usize, path: [*:0]const u8) callconv(.c) bool;
/// @brief Set custom browser folder path.
///
/// @param path The browser folder path
///
/// @example webui_set_browser_folder("/home/Foo/Bar/");
-pub extern fn webui_set_browser_folder(path: [*:0]const u8) callconv(.C) void;
+pub extern fn webui_set_browser_folder(path: [*:0]const u8) callconv(.c) void;
/// @brief Set the web-server root folder path for all windows. Should be used
/// before `webui_show()`.
@@ -277,7 +277,7 @@ pub extern fn webui_set_browser_folder(path: [*:0]const u8) callconv(.C) void;
/// @param path The local folder full path
///
/// @example webui_set_default_root_folder("/home/Foo/Bar/");
-pub extern fn webui_set_default_root_folder(path: [*:0]const u8) callconv(.C) bool;
+pub extern fn webui_set_default_root_folder(path: [*:0]const u8) callconv(.c) bool;
/// @brief Set a custom handler to serve files. This custom handler should
/// return full HTTP header and body.
@@ -290,8 +290,8 @@ pub extern fn webui_set_default_root_folder(path: [*:0]const u8) callconv(.C) bo
/// @example webui_set_file_handler(my_window, myHandlerFunction);
pub extern fn webui_set_file_handler(
window: usize,
- handler: *const fn (filename: [*:0]const u8, length: *c_int) callconv(.C) ?*const anyopaque,
-) callconv(.C) void;
+ handler: *const fn (filename: [*:0]const u8, length: *c_int) callconv(.c) ?*const anyopaque,
+) callconv(.c) void;
/// @brief Set a custom handler to serve files. This custom handler should
/// return full HTTP header and body.
@@ -308,8 +308,8 @@ pub extern fn webui_set_file_handler_window(
window: usize,
filename: [*:0]const u8,
length: *c_int,
- ) callconv(.C) ?*const anyopaque,
-) callconv(.C) void;
+ ) callconv(.c) ?*const anyopaque,
+) callconv(.c) void;
///
/// @brief Use this API to set a file handler response if your backend need async
@@ -325,14 +325,14 @@ pub extern fn webui_interface_set_response_file_handler(
window: usize,
response: *const anyopaque,
length: usize,
-) callconv(.C) void;
+) callconv(.c) void;
/// @brief Check if the specified window is still running.
///
/// @param window The window number
///
/// @example webui_is_shown(my_window);
-pub extern fn webui_is_shown(window: usize) callconv(.C) bool;
+pub extern fn webui_is_shown(window: usize) callconv(.c) bool;
/// @brief Set the maximum time in seconds to wait for the window to connect.
/// This effect `show()` and `wait()`. Value of `0` means wait forever.
@@ -340,7 +340,7 @@ pub extern fn webui_is_shown(window: usize) callconv(.C) bool;
/// @param second The timeout in seconds
///
/// @example webui_set_timeout(30);
-pub extern fn webui_set_timeout(second: usize) callconv(.C) void;
+pub extern fn webui_set_timeout(second: usize) callconv(.c) void;
/// @brief Set the default embedded HTML favicon.
///
@@ -353,7 +353,7 @@ pub extern fn webui_set_icon(
window: usize,
icon: [*:0]const u8,
icon_type: [*:0]const u8,
-) callconv(.C) void;
+) callconv(.c) void;
/// @brief Encode text to Base64. The returned buffer need to be freed.
///
@@ -362,7 +362,7 @@ pub extern fn webui_set_icon(
/// @return Returns the base64 encoded string
///
/// @example const base64: [*:0]u8 = webui_encode("Foo Bar");
-pub extern fn webui_encode(str: [*:0]const u8) callconv(.C) ?[*:0]u8;
+pub extern fn webui_encode(str: [*:0]const u8) callconv(.c) ?[*:0]u8;
/// @brief Decode a Base64 encoded text. The returned buffer need to be freed.
///
@@ -371,14 +371,14 @@ pub extern fn webui_encode(str: [*:0]const u8) callconv(.C) ?[*:0]u8;
/// @return Returns the base64 decoded string
///
/// @example const str: [*:0]u8 = webui_decode("SGVsbG8=");
-pub extern fn webui_decode(str: [*:0]const u8) callconv(.C) ?[*:0]u8;
+pub extern fn webui_decode(str: [*:0]const u8) callconv(.c) ?[*:0]u8;
/// @brief Safely free a buffer allocated by WebUI using `webui_malloc()`.
///
/// @param ptr The buffer to be freed
///
/// @example webui_free(my_buffer);
-pub extern fn webui_free(ptr: *anyopaque) callconv(.C) void;
+pub extern fn webui_free(ptr: *anyopaque) callconv(.c) void;
/// @brief Copy raw data.
///
@@ -391,7 +391,7 @@ pub extern fn webui_memcpy(
dest: *anyopaque,
src: *anyopaque,
count: usize,
-) callconv(.C) void;
+) callconv(.c) void;
/// @brief Safely allocate memory using the WebUI memory management system. It
/// can be safely freed using `webui_free()` at any time.
@@ -399,7 +399,7 @@ pub extern fn webui_memcpy(
/// @param size The size of memory in bytes
///
/// @example var my_buffer: [*:0]u8 = @ptrCast(@alignCast(webui_malloc(1024)));
-pub extern fn webui_malloc(size: usize) callconv(.C) ?*anyopaque;
+pub extern fn webui_malloc(size: usize) callconv(.c) ?*anyopaque;
/// @brief Safely send raw data to the UI. All clients.
///
@@ -413,9 +413,9 @@ pub extern fn webui_malloc(size: usize) callconv(.C) ?*anyopaque;
pub extern fn webui_send_raw(
window: usize,
function: [*:0]const u8,
- raw: [*]const anyopaque,
+ raw: *const anyopaque,
size: usize,
-) callconv(.C) void;
+) callconv(.c) void;
/// @brief Safely send raw data to the UI. Single client.
///
@@ -429,9 +429,9 @@ pub extern fn webui_send_raw(
pub extern fn webui_send_raw_client(
e: *Event,
function: [*:0]const u8,
- raw: [*]const anyopaque,
+ raw: *const anyopaque,
size: usize,
-) callconv(.C) void;
+) callconv(.c) void;
/// @brief Set a window in hidden mode. Should be called before `webui_show()`.
///
@@ -439,7 +439,7 @@ pub extern fn webui_send_raw_client(
/// @param status The status: True or False
///
/// @example webui_set_hide(my_window, true);
-pub extern fn webui_set_hide(window: usize, status: bool) callconv(.C) void;
+pub extern fn webui_set_hide(window: usize, status: bool) callconv(.c) void;
/// @brief Set the window size.
///
@@ -448,7 +448,7 @@ pub extern fn webui_set_hide(window: usize, status: bool) callconv(.C) void;
/// @param height The window height
///
/// @example webui_set_size(my_window, 800, 600);
-pub extern fn webui_set_size(window: usize, width: u32, height: u32) callconv(.C) void;
+pub extern fn webui_set_size(window: usize, width: u32, height: u32) callconv(.c) void;
/// @brief Set the window minimum size.
///
@@ -461,7 +461,7 @@ pub extern fn webui_set_minimum_size(
window: usize,
width: u32,
height: u32,
-) callconv(.C) void;
+) callconv(.c) void;
/// @brief Set the window position.
///
@@ -470,7 +470,7 @@ pub extern fn webui_set_minimum_size(
/// @param y The window Y
///
/// @example webui_set_position(my_window, 100, 100);
-pub extern fn webui_set_position(window: usize, x: u32, y: u32) callconv(.C) void;
+pub extern fn webui_set_position(window: usize, x: u32, y: u32) callconv(.c) void;
/// @brief Centers the window on the screen. Works better with
/// WebView. Call this function before `webui_show()` for better results.
@@ -478,7 +478,7 @@ pub extern fn webui_set_position(window: usize, x: u32, y: u32) callconv(.C) voi
/// @param window The window number
///
/// @example webui_set_center(myWindow);
-pub extern fn webui_set_center(window: usize) callconv(.C) void;
+pub extern fn webui_set_center(window: usize) callconv(.c) void;
/// @brief Set the web browser profile to use. An empty `name` and `path` means
/// the default user profile. Need to be called before `webui_show()`.
@@ -493,7 +493,7 @@ pub extern fn webui_set_profile(
window: usize,
name: [*:0]const u8,
path: [*:0]const u8,
-) callconv(.C) void;
+) callconv(.c) void;
/// @brief Set the web browser proxy server to use. Need to be called before `webui_show()`.
///
@@ -504,7 +504,7 @@ pub extern fn webui_set_profile(
pub extern fn webui_set_proxy(
window: usize,
proxy_server: [*:0]const u8,
-) callconv(.C) void;
+) callconv(.c) void;
/// @brief Get current URL of a running window.
///
@@ -513,14 +513,14 @@ pub extern fn webui_set_proxy(
/// @return Returns the full URL string
///
/// @example const url: [*:0]const u8 = webui_get_url(my_window);
-pub extern fn webui_get_url(window: usize) callconv(.C) [*:0]const u8;
+pub extern fn webui_get_url(window: usize) callconv(.c) [*:0]const u8;
/// @brief Open an URL in the native default web browser.
///
/// @param url The URL to open
///
/// @example webui_open_url("https://webui.me");
-pub extern fn webui_open_url(url: [*:0]const u8) callconv(.C) void;
+pub extern fn webui_open_url(url: [*:0]const u8) callconv(.c) void;
/// @brief Allow a specific window address to be accessible from a public network.
///
@@ -528,7 +528,7 @@ pub extern fn webui_open_url(url: [*:0]const u8) callconv(.C) void;
/// @param status True or False
///
/// @example webui_set_public(my_window, true);
-pub extern fn webui_set_public(window: usize, status: bool) callconv(.C) void;
+pub extern fn webui_set_public(window: usize, status: bool) callconv(.c) void;
/// @brief Navigate to a specific URL. All clients.
///
@@ -536,7 +536,7 @@ pub extern fn webui_set_public(window: usize, status: bool) callconv(.C) void;
/// @param url Full HTTP URL
///
/// @example webui_navigate(my_window, "http://domain.com");
-pub extern fn webui_navigate(window: usize, url: [*:0]const u8) callconv(.C) void;
+pub extern fn webui_navigate(window: usize, url: [*:0]const u8) callconv(.c) void;
/// @brief Navigate to a specific URL. Single client.
///
@@ -544,14 +544,14 @@ pub extern fn webui_navigate(window: usize, url: [*:0]const u8) callconv(.C) voi
/// @param url Full HTTP URL
///
/// @example webui_navigate_client(e, "http://domain.com");
-pub extern fn webui_navigate_client(e: *Event, url: [*:0]const u8) callconv(.C) void;
+pub extern fn webui_navigate_client(e: *Event, url: [*:0]const u8) callconv(.c) void;
/// @brief Free all memory resources. Should be called only at the end.
///
/// @example
/// webui_wait();
/// webui_clean();
-pub extern fn webui_clean() callconv(.C) void;
+pub extern fn webui_clean() callconv(.c) void;
/// @brief Delete all local web-browser profiles folder. It should be called at the
/// end.
@@ -560,7 +560,7 @@ pub extern fn webui_clean() callconv(.C) void;
/// webui_wait();
/// webui_delete_all_profiles();
/// webui_clean();
-pub extern fn webui_delete_all_profiles() callconv(.C) void;
+pub extern fn webui_delete_all_profiles() callconv(.c) void;
/// @brief Delete a specific window web-browser local folder profile.
///
@@ -573,7 +573,7 @@ pub extern fn webui_delete_all_profiles() callconv(.C) void;
///
/// @note This can break functionality of other windows if using the same
/// web-browser.
-pub extern fn webui_delete_profile(window: usize) callconv(.C) void;
+pub extern fn webui_delete_profile(window: usize) callconv(.c) void;
/// @brief Get the ID of the parent process (The web browser may re-create
/// another new process).
@@ -583,7 +583,7 @@ pub extern fn webui_delete_profile(window: usize) callconv(.C) void;
/// @return Returns the parent process ID as integer
///
/// @example const id: usize = webui_get_parent_process_id(my_window);
-pub extern fn webui_get_parent_process_id(window: usize) callconv(.C) usize;
+pub extern fn webui_get_parent_process_id(window: usize) callconv(.c) usize;
/// @brief Get the ID of the last child process.
///
@@ -592,7 +592,7 @@ pub extern fn webui_get_parent_process_id(window: usize) callconv(.C) usize;
/// @return Returns the child process ID as integer
///
/// @example const id: usize = webui_get_child_process_id(my_window);
-pub extern fn webui_get_child_process_id(window: usize) callconv(.C) usize;
+pub extern fn webui_get_child_process_id(window: usize) callconv(.c) usize;
/// @brief Gets Win32 window `HWND`. More reliable with WebView
/// than web browser window, as browser PIDs may change on launch.
@@ -602,7 +602,7 @@ pub extern fn webui_get_child_process_id(window: usize) callconv(.C) usize;
/// @return Returns the window `hwnd` as `void*`
///
/// @example HWND hwnd = webui_win32_get_hwnd(myWindow);
-pub extern fn webui_win32_get_hwnd(window: usize) callconv(.C) ?*anyopaque;
+pub extern fn webui_win32_get_hwnd(window: usize) callconv(.c) ?*anyopaque;
/// @brief Get the network port of a running window.
/// This can be useful to determine the HTTP link of `webui.js`
@@ -612,7 +612,7 @@ pub extern fn webui_win32_get_hwnd(window: usize) callconv(.C) ?*anyopaque;
/// @return Returns the network port of the window
///
/// @example const port: usize = webui_get_port(my_window);
-pub extern fn webui_get_port(window: usize) callconv(.C) usize;
+pub extern fn webui_get_port(window: usize) callconv(.c) usize;
/// @brief Set a custom web-server/websocket network port to be used by WebUI.
/// This can be useful to determine the HTTP link of `webui.js` in case
@@ -624,14 +624,14 @@ pub extern fn webui_get_port(window: usize) callconv(.C) usize;
/// @return Returns True if the port is free and usable by WebUI
///
/// @example const ret: bool = webui_set_port(my_window, 8080);
-pub extern fn webui_set_port(window: usize, port: usize) callconv(.C) bool;
+pub extern fn webui_set_port(window: usize, port: usize) callconv(.c) bool;
/// @brief Get an available usable free network port.
///
/// @return Returns a free port
///
/// @example const port: usize = webui_get_free_port();
-pub extern fn webui_get_free_port() callconv(.C) usize;
+pub extern fn webui_get_free_port() callconv(.c) usize;
/// @brief Control the WebUI behaviour. It's recommended to be called at the beginning.
///
@@ -639,7 +639,7 @@ pub extern fn webui_get_free_port() callconv(.C) usize;
/// @param status The status of the option, `true` or `false`
///
/// @example webui_set_config(.show_wait_connection, false);
-pub extern fn webui_set_config(option: Config, status: bool) callconv(.C) void;
+pub extern fn webui_set_config(option: Config, status: bool) callconv(.c) void;
/// @brief Control if UI events coming from this window should be processed
/// one at a time in a single blocking thread `True`, or process every event in
@@ -650,7 +650,7 @@ pub extern fn webui_set_config(option: Config, status: bool) callconv(.C) void;
/// @param status The blocking status `true` or `false`
///
/// @example webui_set_event_blocking(my_window, true);
-pub extern fn webui_set_event_blocking(window: usize, status: bool) callconv(.C) void;
+pub extern fn webui_set_event_blocking(window: usize, status: bool) callconv(.c) void;
/// @brief Make a WebView window frameless.
///
@@ -658,7 +658,7 @@ pub extern fn webui_set_event_blocking(window: usize, status: bool) callconv(.C)
/// @param status The frameless status `true` or `false`
///
/// @example webui_set_frameless(myWindow, true);
-pub extern fn webui_set_frameless(window: usize, status: bool) callconv(.C) void;
+pub extern fn webui_set_frameless(window: usize, status: bool) callconv(.c) void;
/// @brief Make a WebView window transparent.
///
@@ -666,14 +666,14 @@ pub extern fn webui_set_frameless(window: usize, status: bool) callconv(.C) void
/// @param status The transparency status `true` or `false`
///
/// @example webui_set_transparent(myWindow, true);
-pub extern fn webui_set_transparent(window: usize, status: bool) callconv(.C) void;
+pub extern fn webui_set_transparent(window: usize, status: bool) callconv(.c) void;
/// @brief Get the HTTP mime type of a file.
///
/// @return Returns the HTTP mime string
///
/// @example const mime: [*:0]const u8 = webui_get_mime_type("foo.png");
-pub extern fn webui_get_mime_type(file: [*:0]const u8) callconv(.C) [*:0]const u8;
+pub extern fn webui_get_mime_type(file: [*:0]const u8) callconv(.c) [*:0]const u8;
// -- SSL/TLS -------------------------
@@ -691,7 +691,7 @@ pub extern fn webui_get_mime_type(file: [*:0]const u8) callconv(.C) [*:0]const u
pub extern fn webui_set_tls_certificate(
certificate_pem: [*:0]const u8,
private_key_pem: [*:0]const u8,
-) callconv(.C) bool;
+) callconv(.c) bool;
// -- JavaScript ----------------------
@@ -701,7 +701,7 @@ pub extern fn webui_set_tls_certificate(
/// @param script The JavaScript to be run
///
/// @example webui_run(my_window, "alert('Hello');");
-pub extern fn webui_run(window: usize, script: [*:0]const u8) callconv(.C) void;
+pub extern fn webui_run(window: usize, script: [*:0]const u8) callconv(.c) void;
/// @brief Run JavaScript without waiting for the response. Single client.
///
@@ -709,7 +709,7 @@ pub extern fn webui_run(window: usize, script: [*:0]const u8) callconv(.C) void;
/// @param script The JavaScript to be run
///
/// @example webui_run_client(e, "alert('Hello');");
-pub extern fn webui_run_client(e: *Event, script: [*:0]const u8) callconv(.C) void;
+pub extern fn webui_run_client(e: *Event, script: [*:0]const u8) callconv(.c) void;
/// @brief Run JavaScript and get the response back. Work only in single client mode.
/// Make sure your local buffer can hold the response.
@@ -729,7 +729,7 @@ pub extern fn webui_script(
timeout: usize,
buffer: [*]u8,
buffer_length: usize,
-) callconv(.C) bool;
+) callconv(.c) bool;
/// @brief Run JavaScript and get the response back. Single Client.
/// Make sure your local buffer can hold the response.
@@ -749,7 +749,7 @@ pub extern fn webui_script_client(
timeout: usize,
buffer: [*]u8,
buffer_length: usize,
-) callconv(.C) bool;
+) callconv(.c) bool;
/// @brief Choose between Deno and Nodejs as runtime for .js and .ts files.
///
@@ -757,7 +757,7 @@ pub extern fn webui_script_client(
/// @param runtime .Deno | .Bun | .Nodejs | .None
///
/// @example webui_set_runtime(my_window, .Deno);
-pub extern fn webui_set_runtime(window: usize, runtime: Runtime) callconv(.C) void;
+pub extern fn webui_set_runtime(window: usize, runtime: Runtime) callconv(.c) void;
/// @brief Get how many arguments there are in an event.
///
@@ -766,7 +766,7 @@ pub extern fn webui_set_runtime(window: usize, runtime: Runtime) callconv(.C) vo
/// @return Returns the arguments count.
///
/// @example const count: usize = webui_get_count(e);
-pub extern fn webui_get_count(e: *Event) callconv(.C) usize;
+pub extern fn webui_get_count(e: *Event) callconv(.c) usize;
/// @brief Get an argument as integer at a specific index.
///
@@ -776,7 +776,7 @@ pub extern fn webui_get_count(e: *Event) callconv(.C) usize;
/// @return Returns argument as integer
///
/// @example const my_num: i64 = webui_get_int_at(e, 0);
-pub extern fn webui_get_int_at(e: *Event, index: usize) callconv(.C) i64;
+pub extern fn webui_get_int_at(e: *Event, index: usize) callconv(.c) i64;
/// @brief Get the first argument as integer.
///
@@ -785,7 +785,7 @@ pub extern fn webui_get_int_at(e: *Event, index: usize) callconv(.C) i64;
/// @return Returns argument as integer
///
/// @example const my_num: i64 = webui_get_int(e);
-pub extern fn webui_get_int(e: *Event) callconv(.C) i64;
+pub extern fn webui_get_int(e: *Event) callconv(.c) i64;
/// @brief Get an argument as float at a specific index.
///
@@ -795,7 +795,7 @@ pub extern fn webui_get_int(e: *Event) callconv(.C) i64;
/// @return Returns argument as float
///
/// @example const my_num: f64 = webui_get_float_at(e, 0);
-pub extern fn webui_get_float_at(e: *Event, index: usize) callconv(.C) f64;
+pub extern fn webui_get_float_at(e: *Event, index: usize) callconv(.c) f64;
/// @brief Get the first argument as float.
///
@@ -804,7 +804,7 @@ pub extern fn webui_get_float_at(e: *Event, index: usize) callconv(.C) f64;
/// @return Returns argument as float
///
/// @example const my_num: f64 = webui_get_float(e);
-pub extern fn webui_get_float(e: *Event) callconv(.C) f64;
+pub extern fn webui_get_float(e: *Event) callconv(.c) f64;
/// @brief Get an argument as string at a specific index.
///
@@ -814,7 +814,7 @@ pub extern fn webui_get_float(e: *Event) callconv(.C) f64;
/// @return Returns argument as string
///
/// @example const my_str: [*:0]const u8 = webui_get_string_at(e, 0);
-pub extern fn webui_get_string_at(e: *Event, index: usize) callconv(.C) [*:0]const u8;
+pub extern fn webui_get_string_at(e: *Event, index: usize) callconv(.c) [*:0]const u8;
/// @brief Get the first argument as string.
///
@@ -823,7 +823,7 @@ pub extern fn webui_get_string_at(e: *Event, index: usize) callconv(.C) [*:0]con
/// @return Returns argument as string
///
/// @example const my_str: [*:0]const u8 = webui_get_string(e);
-pub extern fn webui_get_string(e: *Event) callconv(.C) [*:0]const u8;
+pub extern fn webui_get_string(e: *Event) callconv(.c) [*:0]const u8;
/// @brief Get an argument as boolean at a specific index.
///
@@ -833,7 +833,7 @@ pub extern fn webui_get_string(e: *Event) callconv(.C) [*:0]const u8;
/// @return Returns argument as boolean
///
/// @example const my_bool: bool = webui_get_bool_at(e, 0);
-pub extern fn webui_get_bool_at(e: *Event, index: usize) callconv(.C) bool;
+pub extern fn webui_get_bool_at(e: *Event, index: usize) callconv(.c) bool;
/// @brief Get the first argument as boolean.
///
@@ -842,7 +842,7 @@ pub extern fn webui_get_bool_at(e: *Event, index: usize) callconv(.C) bool;
/// @return Returns argument as boolean
///
/// @example const my_bool: bool = webui_get_bool(e);
-pub extern fn webui_get_bool(e: *Event) callconv(.C) bool;
+pub extern fn webui_get_bool(e: *Event) callconv(.c) bool;
/// @brief Get the size in bytes of an argument at a specific index.
///
@@ -852,7 +852,7 @@ pub extern fn webui_get_bool(e: *Event) callconv(.C) bool;
/// @return Returns size in bytes
///
/// @example const arg_len: usize = webui_get_size_at(e, 0);
-pub extern fn webui_get_size_at(e: *Event, index: usize) callconv(.C) usize;
+pub extern fn webui_get_size_at(e: *Event, index: usize) callconv(.c) usize;
/// @brief Get size in bytes of the first argument.
///
@@ -861,7 +861,7 @@ pub extern fn webui_get_size_at(e: *Event, index: usize) callconv(.C) usize;
/// @return Returns size in bytes
///
/// @example const arg_len: usize = webui_get_size(e);
-pub extern fn webui_get_size(e: *Event) callconv(.C) usize;
+pub extern fn webui_get_size(e: *Event) callconv(.c) usize;
/// @brief Return the response to JavaScript as integer.
///
@@ -869,7 +869,7 @@ pub extern fn webui_get_size(e: *Event) callconv(.C) usize;
/// @param n The integer to be send to JavaScript
///
/// @example webui_return_int(e, 123);
-pub extern fn webui_return_int(e: *Event, n: i64) callconv(.C) void;
+pub extern fn webui_return_int(e: *Event, n: i64) callconv(.c) void;
/// @brief Return the response to JavaScript as float.
///
@@ -877,7 +877,7 @@ pub extern fn webui_return_int(e: *Event, n: i64) callconv(.C) void;
/// @param f The float number to be send to JavaScript
///
/// @example webui_return_float(e, 123.456);
-pub extern fn webui_return_float(e: *Event, f: f64) callconv(.C) void;
+pub extern fn webui_return_float(e: *Event, f: f64) callconv(.c) void;
/// @brief Return the response to JavaScript as string.
///
@@ -885,7 +885,7 @@ pub extern fn webui_return_float(e: *Event, f: f64) callconv(.C) void;
/// @param n The string to be send to JavaScript
///
/// @example webui_return_string(e, "Response...");
-pub extern fn webui_return_string(e: *Event, s: [*:0]const u8) callconv(.C) void;
+pub extern fn webui_return_string(e: *Event, s: [*:0]const u8) callconv(.c) void;
/// @brief Return the response to JavaScript as boolean.
///
@@ -893,17 +893,17 @@ pub extern fn webui_return_string(e: *Event, s: [*:0]const u8) callconv(.C) void
/// @param n The boolean to be send to JavaScript
///
/// @example webui_return_bool(e, true);
-pub extern fn webui_return_bool(e: *Event, b: bool) callconv(.C) void;
+pub extern fn webui_return_bool(e: *Event, b: bool) callconv(.c) void;
/// @brief Get the last WebUI error code.
///
/// @example int error_num = webui_get_last_error_number();
-pub extern fn webui_get_last_error_number() callconv(.C) c_int;
+pub extern fn webui_get_last_error_number() callconv(.c) c_int;
/// @brief Get the last WebUI error message.
///
/// @example const char* error_msg = webui_get_last_error_message();
-pub extern fn webui_get_last_error_message() callconv(.C) [*:0]const u8;
+pub extern fn webui_get_last_error_message() callconv(.c) [*:0]const u8;
// -- Wrapper's Interface -------------
@@ -925,8 +925,8 @@ pub extern fn webui_interface_bind(
element: [*:0]u8,
event_number: usize,
bind_id: usize,
- ) void,
-) callconv(.C) usize;
+ ) callconv(.c) void,
+) callconv(.c) usize;
/// @brief When using `webui_interface_bind()`, you may need this function to easily set a response.
///
@@ -939,14 +939,14 @@ pub extern fn webui_interface_set_response(
window: usize,
event_number: usize,
response: [*:0]const u8,
-) callconv(.C) void;
+) callconv(.c) void;
/// @brief Check if the app is still running.
///
/// @return Returns True if app is running
///
/// @example const status: bool = webui_interface_is_app_running();
-pub extern fn webui_interface_is_app_running() callconv(.C) bool;
+pub extern fn webui_interface_is_app_running() callconv(.c) bool;
/// @brief Get a unique window ID.
///
@@ -955,7 +955,7 @@ pub extern fn webui_interface_is_app_running() callconv(.C) bool;
/// @return Returns the unique window ID as integer
///
/// @example const id: usize = webui_interface_get_window_id(my_window);
-pub extern fn webui_interface_get_window_id(window: usize) callconv(.C) usize;
+pub extern fn webui_interface_get_window_id(window: usize) callconv(.c) usize;
/// @brief Get an argument as string at a specific index.
///
@@ -970,7 +970,7 @@ pub extern fn webui_interface_get_string_at(
window: usize,
event_number: usize,
index: usize,
-) callconv(.C) [*:0]const u8;
+) callconv(.c) [*:0]const u8;
/// @brief Get an argument as integer at a specific index.
///
@@ -985,7 +985,7 @@ pub extern fn webui_interface_get_int_at(
window: usize,
event_number: usize,
index: usize,
-) callconv(.C) i64;
+) callconv(.c) i64;
/// @brief Get an argument as float at a specific index.
///
@@ -1000,7 +1000,7 @@ pub extern fn webui_interface_get_float_at(
window: usize,
event_number: usize,
index: usize,
-) callconv(.C) f64;
+) callconv(.c) f64;
/// @brief Get an argument as boolean at a specific index.
///
@@ -1015,7 +1015,7 @@ pub extern fn webui_interface_get_bool_at(
window: usize,
event_number: usize,
index: usize,
-) callconv(.C) bool;
+) callconv(.c) bool;
/// @brief Get the size in bytes of an argument at a specific index.
///
@@ -1030,7 +1030,7 @@ pub extern fn webui_interface_get_size_at(
window: usize,
event_number: usize,
index: usize,
-) callconv(.C) usize;
+) callconv(.c) usize;
/// @brief Show a window using embedded HTML, or a file. If the window is already
/// open, it will be refreshed. Single client.
@@ -1047,7 +1047,7 @@ pub extern fn webui_interface_show_client(
window: usize,
event_number: usize,
content: [*:0]const u8,
-) callconv(.C) bool;
+) callconv(.c) bool;
/// @brief Close a specific client.
///
@@ -1058,7 +1058,7 @@ pub extern fn webui_interface_show_client(
pub extern fn webui_interface_close_client(
window: usize,
event_number: usize,
-) callconv(.C) void;
+) callconv(.c) void;
/// @brief Safely send raw data to the UI. Single client.
///
@@ -1076,7 +1076,7 @@ pub extern fn webui_interface_send_raw_client(
function: [*:0]const u8,
raw: [*c]const u8,
size: usize,
-) callconv(.C) void;
+) callconv(.c) void;
/// @brief Navigate to a specific URL. Single client.
///
@@ -1089,7 +1089,7 @@ pub extern fn webui_interface_navigate_client(
window: usize,
event_number: usize,
url: [*:0]const u8,
-) callconv(.C) void;
+) callconv(.c) void;
/// @brief Run JavaScript without waiting for the response. Single client.
///
@@ -1102,7 +1102,7 @@ pub extern fn webui_interface_run_client(
window: usize,
event_number: usize,
script: [*:0]const u8,
-) callconv(.C) void;
+) callconv(.c) void;
/// @brief Run JavaScript and get the response back. Single client.
/// Make sure your local buffer can hold the response.
@@ -1124,4 +1124,4 @@ pub extern fn webui_interface_script_client(
timeout: usize,
buffer: [*c]u8,
buffer_length: usize,
-) callconv(.C) bool;
+) callconv(.c) bool;
diff --git a/src/webui.zig b/src/webui.zig
index f4fd648..e32c848 100644
--- a/src/webui.zig
+++ b/src/webui.zig
@@ -104,7 +104,7 @@ pub fn bind(
comptime func: fn (e: *Event) void,
) !usize {
const tmp_struct = struct {
- fn handle(tmp_e: *Event) callconv(.C) void {
+ fn handle(tmp_e: *Event) callconv(.c) void {
func(tmp_e);
}
};
@@ -231,8 +231,8 @@ pub fn setRootFolder(self: webui, path: [:0]const u8) !void {
}
/// Set custom browser folder path.
-pub fn setBrowserFolder(self: webui, path: [:0]const u8) void {
- c.webui_set_browser_folder(self.window_handle, path.ptr);
+pub fn setBrowserFolder(path: [:0]const u8) void {
+ c.webui_set_browser_folder(path.ptr);
}
/// Set the web-server root folder path for all windows.
@@ -248,7 +248,7 @@ pub fn setDefaultRootFolder(path: [:0]const u8) !void {
/// This deactivates any previous handler set with `setFileHandlerWindow`.
pub fn setFileHandler(self: webui, comptime handler: fn (filename: []const u8) ?[]const u8) void {
const tmp_struct = struct {
- fn handle(tmp_filename: [*:0]const u8, length: *c_int) callconv(.C) ?*const anyopaque {
+ fn handle(tmp_filename: [*:0]const u8, length: *c_int) callconv(.c) ?*const anyopaque {
const len = std.mem.len(tmp_filename);
const content = handler(tmp_filename[0..len]);
if (content) |val| {
@@ -267,7 +267,7 @@ pub fn setFileHandler(self: webui, comptime handler: fn (filename: []const u8) ?
/// This deactivates any previous handler set with `setFileHandler`.
pub fn setFileHandlerWindow(self: webui, comptime handler: fn (window_handle: usize, filename: []const u8) ?[]const u8) void {
const tmp_struct = struct {
- fn handle(window: usize, tmp_filename: [*:0]const u8, length: *c_int) callconv(.C) ?*const anyopaque {
+ fn handle(window: usize, tmp_filename: [*:0]const u8, length: *c_int) callconv(.c) ?*const anyopaque {
const len = std.mem.len(tmp_filename);
const content = handler(window, tmp_filename[0..len]);
if (content) |val| {
@@ -312,9 +312,12 @@ pub fn setIcon(self: webui, icon: [:0]const u8, icon_type: [:0]const u8) void {
/// you need free the return memory with free function
pub fn encode(str: [:0]const u8) ![]u8 {
const ptr = c.webui_encode(str.ptr);
- if (ptr == null) return WebUIError.EncodeError;
- const len = std.mem.len(ptr);
- return ptr[0..len];
+ if (ptr) |valid_ptr| {
+ const len = std.mem.len(valid_ptr);
+ return valid_ptr[0..len];
+ } else {
+ return WebUIError.EncodeError;
+ }
}
/// Base64 decoding.
@@ -323,9 +326,12 @@ pub fn encode(str: [:0]const u8) ![]u8 {
/// you need free the return memory with free function
pub fn decode(str: [:0]const u8) ![]u8 {
const ptr = c.webui_decode(str.ptr);
- if (ptr == null) return WebUIError.DecodeError;
- const len = std.mem.len(ptr);
- return ptr[0..len];
+ if (ptr) |valid_ptr| {
+ const len = std.mem.len(valid_ptr);
+ return valid_ptr[0..len];
+ } else {
+ return WebUIError.DecodeError;
+ }
}
/// Safely free a buffer allocated by WebUI using
@@ -349,7 +355,7 @@ pub fn memcpy(dst: []u8, src: []const u8) void {
/// Safely send raw data to the UI. All clients.
pub fn sendRaw(self: webui, js_func: [:0]const u8, raw: []u8) void {
- c.webui_send_raw(self.window_handle, js_func.ptr, @ptrCast(raw.ptr), raw.len);
+ c.webui_send_raw(self.window_handle, js_func.ptr, raw.ptr, raw.len);
}
/// Set a window in hidden mode.
@@ -631,7 +637,7 @@ pub fn interfaceBind(
event_number: usize,
bind_id: usize,
) void,
-) void {
+) !usize {
const tmp_struct = struct {
fn handle(
tmp_window: usize,
@@ -639,12 +645,14 @@ pub fn interfaceBind(
tmp_element: [*:0]u8,
tmp_event_number: usize,
tmp_bind_id: usize,
- ) callconv(.C) void {
+ ) callconv(.c) void {
const len = std.mem.len(tmp_element);
callback(tmp_window, tmp_event_type, tmp_element[0..len], tmp_event_number, tmp_bind_id);
}
};
- c.webui_interface_bind(self.window_handle, element.ptr, tmp_struct.handle);
+ const index = c.webui_interface_bind(self.window_handle, element.ptr, tmp_struct.handle);
+ if (index == 0) return WebUIError.BindError;
+ return index;
}
/// When using `interfaceBind()`,
@@ -1056,7 +1064,7 @@ pub const Event = extern struct {
c.webui_send_raw_client(
self,
function.ptr,
- @ptrCast(buffer.ptr),
+ buffer.ptr,
buffer.len,
);
}