|
| 1 | +# WebUI C Starter Kit |
| 2 | + |
| 3 | +A ready-to-use project template for building a professional desktop app in C |
| 4 | +with a web UI — compiled into a **single portable executable** with the |
| 5 | +application icon and every UI file (HTML, CSS, JS, images) embedded inside it. |
| 6 | + |
| 7 | +No runtime files, no installer, no dependencies beyond a C compiler. |
| 8 | + |
| 9 | +## Quick start |
| 10 | + |
| 11 | +1. Clone WebUI: `git clone https://github.com/webui-dev/webui.git` |
| 12 | +2. `cd webui` |
| 13 | +3. Build the WebUI library: |
| 14 | + - Linux / macOS: `make` |
| 15 | + - Windows MinGW: `mingw32-make` |
| 16 | + - Windows MSVC: `nmake` (from a *Developer Command Prompt*) |
| 17 | +4. `cd examples/starter_kit_c` |
| 18 | +5. Build the starter kit: `make` / `mingw32-make` / `nmake` |
| 19 | +6. Done — your app is `bin/my_app` (`bin\my_app.exe` on Windows), and the |
| 20 | + `starter_kit_c` folder is now **self-contained**: copy it anywhere (outside |
| 21 | + the WebUI repository) and continue developing your own project from it. |
| 22 | + |
| 23 | +The first build must happen inside the WebUI repository: it copies the WebUI |
| 24 | +static library and header into `lib/`. Every later build works from the local |
| 25 | +`lib/` snapshot, wherever the folder lives. |
| 26 | + |
| 27 | +## Folder structure |
| 28 | + |
| 29 | +``` |
| 30 | +starter_kit_c/ |
| 31 | +├── Makefile # Windows MSVC (nmake) |
| 32 | +├── GNUmakefile # Linux, macOS, Windows MinGW (make / mingw32-make) |
| 33 | +├── icon.rc # Windows resource: embeds ui/favicon.ico as the EXE icon |
| 34 | +├── src/ |
| 35 | +│ ├── main.c # Your C backend (HTTP handler, bindings, window) |
| 36 | +│ └── vfs.h # GENERATED — the ui/ folder packed as C arrays |
| 37 | +├── tools/ |
| 38 | +│ └── vfs.c # Build-time packer: ui/ -> src/vfs.h (auto-compiled) |
| 39 | +├── ui/ # Your frontend — every file here gets embedded |
| 40 | +│ ├── index.html |
| 41 | +│ ├── style.css |
| 42 | +│ ├── app.js |
| 43 | +│ ├── favicon.ico # App icon: Windows executable icon (via icon.rc) |
| 44 | +│ └── icon.png # App icon: HTML favicon + Linux window/launcher icon |
| 45 | +├── lib/ # GENERATED — snapshot of webui.h + WebUI static library |
| 46 | +└── bin/ # GENERATED — my_app(.exe); Linux: + .desktop + icon.png; macOS: my_app.app |
| 47 | +``` |
| 48 | + |
| 49 | +## Customize |
| 50 | + |
| 51 | +- **App name** — edit `APP_NAME` at the top of `Makefile` and `GNUmakefile`. |
| 52 | +- **Frontend** — edit or add any files under `ui/` (subfolders included). |
| 53 | + They are re-packed into the executable automatically on every build. |
| 54 | +- **Backend** — add C functions in `src/main.c` and expose them with |
| 55 | + `webui_bind()`. Every bound function becomes a global `async` JavaScript |
| 56 | + function: `const reply = await greet('World');` |
| 57 | +- **Icon** — two files in `ui/` (keep the names, swap the artwork): |
| 58 | + `ui/favicon.ico` — the Windows executable icon (resource ID 32512 / |
| 59 | + `IDI_APPLICATION`, used by Explorer, the taskbar, and the WebView window; |
| 60 | + use a real multi-size `.ico`); `ui/icon.png` — the HTML favicon, on |
| 61 | + Linux the window/taskbar icon and the `.desktop` launcher icon (the |
| 62 | + build copies it into `bin/`), and on macOS the app icon (converted to |
| 63 | + `icon.icns` inside the `.app` bundle). |
| 64 | +- **HTTP** — every UI request goes through `http_handler()` in `src/main.c` |
| 65 | + (embedded files via `vfs()`, everything else 404) — add custom routes, |
| 66 | + headers, or dynamic responses there. |
| 67 | +- **Window** — `src/main.c` opens a frameless, transparent WebView window, and |
| 68 | + the UI draws its own title bar (`#titlebar` in `ui/index.html`, with drag |
| 69 | + regions and minimize/maximize/close buttons). For a normal OS window, remove |
| 70 | + the `webui_set_frameless()` / `webui_set_transparent()` lines; for browser |
| 71 | + mode, call `webui_show()` instead of `webui_show_wv()`. |
| 72 | + |
| 73 | +## How it works |
| 74 | + |
| 75 | +- `tools/vfs.c` is compiled with your same C compiler and run at build |
| 76 | + time. It packs `ui/` into `src/vfs.h` as byte arrays plus a `vfs()` lookup |
| 77 | + that serves an embedded file as a full HTTP response (MIME type via |
| 78 | + `webui_get_mime_type()`), or returns `NULL` for unknown paths. |
| 79 | +- Every HTTP request reaches `http_handler()` in `main.c`: embedded files |
| 80 | + are served through `vfs()`, anything else gets a 404 — tweak requests or |
| 81 | + add your own routes there (`webui.js` is always served by WebUI itself). |
| 82 | + Note: using a custom file handler disables WebUI's cookie-based client |
| 83 | + authentication (security becomes your responsibility). |
| 84 | +- `icon.rc` embeds the icon at resource ID 32512 (`IDI_APPLICATION`), which |
| 85 | + WebUI's WebView window class picks up automatically on Windows. |
| 86 | +- `main.c` calls `webui_set_icon_file(win, "icon.png")` before showing the |
| 87 | + window; WebUI resolves the file (working directory first, then next to |
| 88 | + the executable) and, on Linux, applies it to the WebView window, which |
| 89 | + gives the taskbar icon on X11 sessions. |
| 90 | +- The app links against `lib/webui-2-static.lib` (MSVC) or |
| 91 | + `lib/libwebui-2-static.a` (MinGW / Linux / macOS) — fully static, one file. |
| 92 | +- On Linux, the release build copies `ui/icon.png` into `bin/` and generates |
| 93 | + `bin/<app>.desktop` — a launcher pointing at the executable and the icon |
| 94 | + with absolute paths. Nothing is installed or written outside this folder; |
| 95 | + rebuild after moving the folder to refresh the paths. |
| 96 | +- On macOS, the release build wraps the executable into `bin/<app>.app` — |
| 97 | + `Info.plist` plus `icon.icns` (converted from `ui/icon.png` with the |
| 98 | + built-in `sips` tool) — so Finder and the Dock show the app icon. |
| 99 | + |
| 100 | +## Debugging |
| 101 | + |
| 102 | +`make debug` / `nmake debug` builds with debug symbols and a console window, |
| 103 | +so `printf()` from your C code is visible. For WebUI's own internal logs, |
| 104 | +build the library in debug mode at the repository root (`make debug`), then |
| 105 | +copy the static library from `dist/debug/` over the one in `lib/`. |
| 106 | + |
| 107 | +## Updating WebUI |
| 108 | + |
| 109 | +Rebuild the library in the WebUI repository, then run one build of this kit |
| 110 | +while it is inside the repository — `lib/` is refreshed automatically. (If you |
| 111 | +moved the folder out, copy the new static library and `webui.h` into `lib/` |
| 112 | +manually, or rebuild from a fresh clone.) |
| 113 | + |
| 114 | +## Platform notes |
| 115 | + |
| 116 | +- **Windows** — the executable icon works everywhere (Explorer, taskbar, and |
| 117 | + the frameless WebView window). WebUI links the WebView2 loader statically and |
| 118 | + the WebView2 Runtime ships with Windows 10/11, so the single executable is |
| 119 | + all you need. If WebView2 is unavailable, the app falls back to a browser |
| 120 | + app-mode window (the embedded favicon shows as the tab icon). |
| 121 | +- **Linux** — the frameless WebView window needs GTK + WebKitGTK installed |
| 122 | + (the app falls back to a browser app-mode window otherwise). The |
| 123 | + window/taskbar icon comes from `webui_set_icon_file()` using `bin/icon.png` |
| 124 | + (copied next to the executable by the build) and works on X11 sessions |
| 125 | + with nothing installed; Wayland sessions only show icons for apps with an |
| 126 | + installed `.desktop` entry. ELF executables cannot embed icons, so the |
| 127 | + build also generates `bin/my_app.desktop`, a launcher pointing at the |
| 128 | + executable and `bin/icon.png` (absolute paths, regenerated on every |
| 129 | + build — rebuild after moving the folder). Everything stays inside this |
| 130 | + folder; the build never writes to the system. In GNOME Files, right-click |
| 131 | + the `.desktop` and choose "Allow Launching" once — it then shows your app |
| 132 | + icon and launches on double-click. Optional, your choice: copy |
| 133 | + `bin/my_app.desktop` into `~/.local/share/applications/` to add the app |
| 134 | + to the system menu (and the dock icon on Wayland) — the build itself |
| 135 | + never does this. |
| 136 | +- **macOS** — the release build produces `bin/my_app.app` with the |
| 137 | + executable and icon embedded inside the bundle (`icon.icns` is generated |
| 138 | + from `ui/icon.png` using `sips`, which ships with macOS). Launch it from |
| 139 | + Finder or with `open bin/my_app.app`; the Dock and Finder show the app |
| 140 | + icon. The bundle is unsigned — fine for local use; distributing to other |
| 141 | + Macs needs `codesign`/notarization. `make debug` still produces a plain |
| 142 | + `bin/my_app` binary for terminal debugging. |
0 commit comments