Skip to content

Commit bbd5424

Browse files
Merge pull request #15 from developersharif/web-widget
Web widget
2 parents 372d781 + 6fb6946 commit bbd5424

21 files changed

Lines changed: 5950 additions & 30 deletions

.github/workflows/build-libs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
TCL_VERSION: "8.6.16"
1212

1313
steps:
14-
- uses: actions/checkout@v4
14+
- uses: actions/checkout@v5
1515

1616
- name: Install build dependencies
1717
run: |
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
name: Build WebView Helper Binaries
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
build-linux:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v5
16+
17+
- name: Install build dependencies
18+
run: sudo apt-get update && sudo apt-get install -y cmake libgtk-3-dev libwebkit2gtk-4.1-dev
19+
20+
- name: Build helper binary
21+
run: cd src/lib/webview_helper && bash build.sh
22+
23+
- name: Upload artifact
24+
uses: actions/upload-artifact@v5
25+
with:
26+
name: webview_helper_linux_x86_64
27+
path: src/lib/webview_helper_linux_x86_64
28+
29+
build-macos-intel:
30+
runs-on: macos-13
31+
steps:
32+
- uses: actions/checkout@v5
33+
34+
- name: Install CMake
35+
run: brew install cmake || true
36+
37+
- name: Build helper binary
38+
run: cd src/lib/webview_helper && bash build.sh
39+
40+
- name: Upload artifact
41+
uses: actions/upload-artifact@v5
42+
with:
43+
name: webview_helper_darwin_x86_64
44+
path: src/lib/webview_helper_darwin_x86_64
45+
46+
build-macos-arm:
47+
runs-on: macos-latest
48+
steps:
49+
- uses: actions/checkout@v5
50+
51+
- name: Install CMake
52+
run: brew install cmake || true
53+
54+
- name: Build helper binary
55+
run: cd src/lib/webview_helper && bash build.sh
56+
57+
- name: Upload artifact
58+
uses: actions/upload-artifact@v5
59+
with:
60+
name: webview_helper_darwin_arm64
61+
path: src/lib/webview_helper_darwin_arm64
62+
63+
build-windows:
64+
runs-on: windows-latest
65+
steps:
66+
- uses: actions/checkout@v5
67+
68+
- name: Build helper binary
69+
shell: cmd
70+
run: |
71+
cd src\lib\webview_helper
72+
mkdir build
73+
cd build
74+
cmake .. -DCMAKE_BUILD_TYPE=Release
75+
cmake --build . --config Release
76+
77+
- name: Upload artifact
78+
uses: actions/upload-artifact@v5
79+
with:
80+
name: webview_helper_windows_x86_64.exe
81+
path: src/lib/webview_helper_windows_x86_64.exe
82+
83+
release:
84+
needs: [build-linux, build-macos-intel, build-macos-arm, build-windows]
85+
runs-on: ubuntu-latest
86+
steps:
87+
- name: Download all artifacts
88+
uses: actions/download-artifact@v5
89+
with:
90+
path: binaries
91+
merge-multiple: true
92+
93+
- name: List binaries
94+
run: ls -la binaries/
95+
96+
- name: Create GitHub Release
97+
uses: softprops/action-gh-release@v2
98+
with:
99+
generate_release_notes: true
100+
files: binaries/*

.github/workflows/docs.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ jobs:
2121
url: ${{ steps.deployment.outputs.page_url }}
2222
runs-on: ubuntu-latest
2323
steps:
24-
- uses: actions/checkout@v4
24+
- uses: actions/checkout@v5
2525

26-
- uses: actions/configure-pages@v5
26+
- uses: actions/configure-pages@v6
2727

28-
- uses: actions/upload-pages-artifact@v3
28+
- uses: actions/upload-pages-artifact@v4
2929
with:
3030
path: docs
3131

3232
- id: deployment
33-
uses: actions/deploy-pages@v4
33+
uses: actions/deploy-pages@v5

.github/workflows/tests.yml

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
name: Tests
22

33
on:
4+
push:
5+
branches: [main, web-widget]
46
pull_request:
57
branches: [main]
68

@@ -9,7 +11,7 @@ jobs:
911
runs-on: ubuntu-latest
1012

1113
steps:
12-
- uses: actions/checkout@v4
14+
- uses: actions/checkout@v5
1315

1416
- name: Setup PHP
1517
uses: shivammathur/setup-php@v2
@@ -20,10 +22,17 @@ jobs:
2022
- name: Install Composer dependencies
2123
run: composer install --no-interaction
2224

23-
- name: Install virtual display
24-
run: sudo apt-get update && sudo apt-get install -y xvfb
25+
- name: Install virtual display and WebView dependencies
26+
run: |
27+
sudo apt-get update
28+
sudo apt-get install -y xvfb cmake libgtk-3-dev libwebkit2gtk-4.1-dev
29+
30+
- name: Build WebView helper binary
31+
run: |
32+
cd src/lib/webview_helper
33+
bash build.sh
2534
26-
- name: Run tests
35+
- name: Run Tk widget tests
2736
run: |
2837
Xvfb :99 -screen 0 1024x768x24 &
2938
export DISPLAY=:99
@@ -42,11 +51,18 @@ jobs:
4251
php tests/widgets_test/TopLevelWidgetTest.php
4352
php tests/widgets_test/WindowTest.php
4453
54+
- name: Run WebView tests
55+
run: |
56+
export DISPLAY=:99
57+
php tests/webview/HelperBinaryTest.php
58+
php tests/webview/WebViewWidgetTest.php
59+
php tests/webview/EventLoopIntegrationTest.php
60+
4561
test-macos:
4662
runs-on: macos-latest
4763

4864
steps:
49-
- uses: actions/checkout@v4
65+
- uses: actions/checkout@v5
5066

5167
- name: Setup PHP
5268
uses: shivammathur/setup-php@v2
@@ -57,7 +73,15 @@ jobs:
5773
- name: Install Composer dependencies
5874
run: composer install --no-interaction
5975

60-
- name: Run tests
76+
- name: Install CMake
77+
run: brew install cmake || true
78+
79+
- name: Build WebView helper binary
80+
run: |
81+
cd src/lib/webview_helper
82+
bash build.sh
83+
84+
- name: Run Tk widget tests
6185
run: |
6286
php tests/index_test.php
6387
php tests/widgets_test/AdditionalWidgetsTest.php
@@ -73,11 +97,17 @@ jobs:
7397
php tests/widgets_test/TopLevelWidgetTest.php
7498
php tests/widgets_test/WindowTest.php
7599
100+
- name: Run WebView tests
101+
run: |
102+
php tests/webview/HelperBinaryTest.php
103+
php tests/webview/WebViewWidgetTest.php
104+
php tests/webview/EventLoopIntegrationTest.php
105+
76106
test-windows:
77107
runs-on: windows-latest
78108

79109
steps:
80-
- uses: actions/checkout@v4
110+
- uses: actions/checkout@v5
81111

82112
- name: Setup PHP
83113
uses: shivammathur/setup-php@v2
@@ -88,7 +118,16 @@ jobs:
88118
- name: Install Composer dependencies
89119
run: composer install --no-interaction
90120

91-
- name: Run tests
121+
- name: Build WebView helper binary
122+
shell: cmd
123+
run: |
124+
cd src\lib\webview_helper
125+
mkdir build
126+
cd build
127+
cmake .. -DCMAKE_BUILD_TYPE=Release
128+
cmake --build . --config Release
129+
130+
- name: Run Tk widget tests
92131
run: |
93132
php tests/index_test.php
94133
php tests/widgets_test/AdditionalWidgetsTest.php
@@ -103,3 +142,9 @@ jobs:
103142
php tests/widgets_test/MessageTest.php
104143
php tests/widgets_test/TopLevelWidgetTest.php
105144
php tests/widgets_test/WindowTest.php
145+
146+
- name: Run WebView tests
147+
run: |
148+
php tests/webview/HelperBinaryTest.php
149+
php tests/webview/WebViewWidgetTest.php
150+
php tests/webview/EventLoopIntegrationTest.php

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,7 @@
77
/tmp/
88
/*.tmp
99
/lib/
10+
11+
# WebView helper build artifacts
12+
src/lib/webview_helper/build/
13+
src/lib/webview_helper_*

composer.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,10 @@
1010
"psr-4": {
1111
"PhpGui\\": "src/"
1212
}
13+
},
14+
"scripts": {
15+
"post-install-cmd": "@php scripts/install-webview-helper.php",
16+
"post-update-cmd": "@php scripts/install-webview-helper.php",
17+
"install-webview": "@php scripts/install-webview-helper.php"
1318
}
1419
}

docs/dev/webview-progress.md

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# WebView Widget — Development Progress
2+
3+
## Phase 1: C Helper Binary — Completed (2026-04-01)
4+
5+
### What was implemented
6+
- `src/lib/webview_helper/webview_helper.cc`~280 LOC C++ helper binary
7+
- `src/lib/webview_helper/CMakeLists.txt` — CMake build with FetchContent for webview v0.12.0
8+
- `src/lib/webview_helper/build.sh` — convenience build script
9+
- `src/lib/webview_helper/cJSON.c` + `cJSON.h` — vendored JSON parser (v1.7.18)
10+
- `tests/webview/HelperBinaryTest.php` — 16 passing tests
11+
12+
### Deviations from plan
13+
- **File renamed from `.c` to `.cc`**: The webview library is header-only C++ (`webview::core` is an INTERFACE target requiring `cxx_std_11`). The helper source must be compiled as C++ for the webview API symbols to be available. cJSON is wrapped with `extern "C"`.
14+
- **`_exit(0)` instead of `pthread_join`**: After `webview_run()` returns, the reader thread may be blocked on `fgets(stdin)`. Closing stdin from another thread is undefined behavior on Linux. Using `_exit(0)` is the pragmatic solution — all useful work (writing the "closed" event, destroying the webview) is done before exit.
15+
- **`static_cast<webview_hint_t>(hint)`**: C++ requires explicit int-to-enum conversion.
16+
17+
### Known issues
18+
- `bind()` command leaks `strdup(name)` memory (the name string passed to `on_bound_call` is never freed). Minimal impact since bindings are typically created once and live for the process lifetime.
19+
- No malformed JSON test from PHP side (tested at binary level only).
20+
21+
---
22+
23+
## Phase 2: ProcessWebView.php — Completed (2026-04-01)
24+
25+
### What was implemented
26+
- `src/ProcessWebView.php` — process manager with full IPC lifecycle
27+
- Non-blocking stdout with buffer accumulation for partial line handling
28+
- Platform detection for binary path resolution
29+
- Shutdown function for orphan prevention
30+
- Windows `stream_select()` fallback
31+
32+
### Deviations from plan
33+
- Initial config passed via argv (not stdin first-message) — simpler, avoids "first message is special" protocol complication. HTML content sent via `setHtml()` after construction.
34+
35+
### Known issues
36+
- Windows `stream_set_blocking(false)` on pipes from `proc_open` is unreliable. The `stream_select()` fallback is in place but untested on actual Windows.
37+
38+
---
39+
40+
## Phase 3: WebView.php Widget — Completed (2026-04-01)
41+
42+
### What was implemented
43+
- `src/Widget/WebView.php` — full widget API with 23 passing tests
44+
- Command dispatch (JS→PHP) with error handling and automatic error return to JS
45+
- Event dispatch (ready, closed, error, pong)
46+
- Lifecycle callbacks (onReady, onClose, onError)
47+
- `tests/webview/WebViewWidgetTest.php` — 23 tests
48+
- `tests/webview/fixtures/test.html` — deterministic test page
49+
50+
### Design decisions
51+
- Does NOT extend `AbstractWidget` — confirmed as correct. WebView is a separate native window, not a Tcl widget.
52+
- `bind()` sends IPC to helper (Approach A from plan) — each binding creates a real `webview_bind()` in the helper, so JS can call functions directly by name.
53+
54+
---
55+
56+
## Phase 4: Application.php Integration — Completed (2026-04-01)
57+
58+
### What was implemented
59+
- Modified `src/Application.php`: added `$webviews` array, `addWebView()`, `removeWebView()`, `tick()` method
60+
- WebView polling in main event loop with auto-cleanup of closed instances
61+
- Adaptive sleep: 20ms when WebViews active, 100ms when idle
62+
- `quit()` destroys all WebViews before exiting
63+
- `tests/webview/EventLoopIntegrationTest.php` — 7 tests
64+
- **No regression**: existing Tk widget tests (WindowTest, ButtonTest) still pass
65+
66+
### Deviations from plan
67+
- Added `tick()` method for testability — allows running single event loop iterations from tests without blocking.
68+
69+
---
70+
71+
## Code Review Fixes — Completed (2026-04-01)
72+
73+
### Security: Event name injection in emit command
74+
- Event names passed to `window.__phpEmit()` were interpolated directly into JavaScript via `snprintf('%s', ...)`, allowing injection through crafted event names containing quotes.
75+
- **Fix**: Event names are now JSON-encoded via `cJSON_CreateString` + `cJSON_PrintUnformatted`, producing a properly escaped quoted string passed to `__phpEmit()`.
76+
77+
### Memory leak: strdup(name) in bind command
78+
- Each `bind` command called `strdup(name)` but the allocated string was never freed on `unbind` or process exit.
79+
- **Fix**: Added a binding name registry (`binding_names[]` array). `bind` registers the pointer, `unbind` frees it, and `binding_registry_free_all()` cleans up at exit.
80+
81+
### Buffer limitation for large HTML payloads
82+
- The stdin reader used a 64 KiB line buffer (`LINE_BUF_SIZE = 65536`), which would silently truncate large `set_html` payloads.
83+
- **Fix**: Increased to 1 MiB (`1048576`).
84+
85+
### Code duplication in Application.php
86+
- `run()` and `tick()` contained identical Tcl polling, callback dispatch, quit-file checking, and WebView polling logic.
87+
- **Fix**: `run()` now delegates to `tick()` in a loop, with adaptive sleep after each tick.
88+
89+
### MSVC build errors on Windows CI
90+
- Designated initializers (`.field = value`) require C++20 on MSVC; we target C++14. Replaced with sequential assignment.
91+
- `_setmode` / `_O_BINARY` need `<io.h>` and `<fcntl.h>` — added missing includes.
92+
- MSVC multi-config generators place binaries in `Release/` subdirectory, ignoring `RUNTIME_OUTPUT_DIRECTORY`. Added per-config overrides.

0 commit comments

Comments
 (0)