mirror of
https://github.com/webui-dev/webui
synced 2025-03-28 21:13:17 +00:00
Compare commits
537 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9dd20b5c98 | ||
![]() |
65fd9a8800 | ||
![]() |
3c03d4f45c | ||
![]() |
1f80350564 | ||
![]() |
4c8fc25b2d | ||
![]() |
b59ddf1c0c | ||
![]() |
5fafc9b6b6 | ||
![]() |
995f1ab25f | ||
![]() |
d274723ec6 | ||
![]() |
9430e57040 | ||
![]() |
78b163c350 | ||
![]() |
af455d38ee | ||
![]() |
5c52beebfb | ||
![]() |
ea5e9a57fc | ||
![]() |
c50fcdf5da | ||
![]() |
433dcc25e0 | ||
![]() |
c66b71a98c | ||
![]() |
f21f4f14e1 | ||
![]() |
84758f6742 | ||
![]() |
aec0f654ba | ||
![]() |
ed3aae5790 | ||
![]() |
d2b40ee7e6 | ||
![]() |
25c7e3f16c | ||
![]() |
361237669b | ||
![]() |
c6d5b58352 | ||
![]() |
7e257de1b0 | ||
![]() |
16aec7e181 | ||
![]() |
5415b19b5f | ||
![]() |
c9baba76b7 | ||
![]() |
f4b9043288 | ||
![]() |
facd97c107 | ||
![]() |
223608479b | ||
![]() |
305070eeb1 | ||
![]() |
7d310a7c1f | ||
![]() |
d58e04ff05 | ||
![]() |
1b2f7b637b | ||
![]() |
dacbfcd257 | ||
![]() |
b1595c766c | ||
![]() |
130a26cc21 | ||
![]() |
8bf01b0d3e | ||
![]() |
3a959d0402 | ||
![]() |
6cca39ecac | ||
![]() |
e019f00fad | ||
![]() |
fcd903d424 | ||
![]() |
6b61f311c8 | ||
![]() |
7dddb64d92 | ||
![]() |
bf1c8ada92 | ||
![]() |
e558709118 | ||
![]() |
b6457c88bb | ||
![]() |
8d9c6b275b | ||
![]() |
5ac66da94b | ||
![]() |
92324edf6f | ||
![]() |
9926908e4b | ||
![]() |
fd716ddcac | ||
![]() |
ef5df7f28c | ||
![]() |
5d497e3b83 | ||
![]() |
02328acc6d | ||
![]() |
b4ce0284ae | ||
![]() |
61444bfaa7 | ||
![]() |
70b6689106 | ||
![]() |
7b661f142b | ||
![]() |
72039fa0ca | ||
![]() |
bd2611ba60 | ||
![]() |
93ec28addb | ||
![]() |
52c1777c77 | ||
![]() |
3734f9fe9f | ||
![]() |
fb29c6cac4 | ||
![]() |
18b5d14f8e | ||
![]() |
f4e327208f | ||
![]() |
8c58fcb973 | ||
![]() |
8f5a306574 | ||
![]() |
e92f9b7824 | ||
![]() |
c386758414 | ||
![]() |
0f8925e358 | ||
![]() |
44971f9bca | ||
![]() |
8fa1fdb89d | ||
![]() |
cdebbfee0a | ||
![]() |
bf94687089 | ||
![]() |
36676f68ff | ||
![]() |
56f1e4eb2b | ||
![]() |
553e65e218 | ||
![]() |
d9af5b2c17 | ||
![]() |
27c877f73f | ||
![]() |
c9c7562496 | ||
![]() |
1594f9e40d | ||
![]() |
133da5072b | ||
![]() |
8eb49857c1 | ||
![]() |
6c299e49ed | ||
![]() |
ad869075d2 | ||
![]() |
0d8ed71a8a | ||
![]() |
c512af1e6c | ||
![]() |
63284fe2a7 | ||
![]() |
f2961585e2 | ||
![]() |
fb5c2ab616 | ||
![]() |
c52ac5fc4a | ||
![]() |
3ff8742f3e | ||
![]() |
27088bd5d2 | ||
![]() |
8a7ea878b5 | ||
![]() |
2d3a68ebea | ||
![]() |
1eb06bb0c7 | ||
![]() |
ddc94db8db | ||
![]() |
0268c3723b | ||
![]() |
7f60505709 | ||
![]() |
f412473dca | ||
![]() |
728cd8370d | ||
![]() |
0a088943d5 | ||
![]() |
cdda40df5f | ||
![]() |
2adfee2e04 | ||
![]() |
c05a18a2f4 | ||
![]() |
9e68b911ae | ||
![]() |
5486cb4e9c | ||
![]() |
2e9d65d2bc | ||
![]() |
c9087c35b1 | ||
![]() |
4dcf4ce07c | ||
![]() |
e0b09e3a49 | ||
![]() |
d7a87ed6f9 | ||
![]() |
737ee76cbc | ||
![]() |
b6f70527be | ||
![]() |
c9abbc9cdb | ||
![]() |
d695c5b8fc | ||
![]() |
d757120977 | ||
![]() |
0ff3b1351b | ||
![]() |
41497e1a52 | ||
![]() |
ef18fdc772 | ||
![]() |
09128cefb0 | ||
![]() |
0f4cf1a4b8 | ||
![]() |
734f00aaac | ||
![]() |
3c9137eef5 | ||
![]() |
6511bc56d8 | ||
![]() |
2a5a449900 | ||
![]() |
a3ea3619ee | ||
![]() |
a509155eaf | ||
![]() |
9d2b80d3b3 | ||
![]() |
e67788ad70 | ||
![]() |
9814a18e0a | ||
![]() |
7189093a5d | ||
![]() |
7156f6a1e2 | ||
![]() |
4a67f91554 | ||
![]() |
e01fb64666 | ||
![]() |
984de15efa | ||
![]() |
3084ff3e26 | ||
![]() |
2a406f5276 | ||
![]() |
8fc3d1a39a | ||
![]() |
89a54eb621 | ||
![]() |
39628742aa | ||
![]() |
f59d0463e0 | ||
![]() |
6e7b0dacb2 | ||
![]() |
be972b50a4 | ||
![]() |
ed77621974 | ||
![]() |
e8863a06c1 | ||
![]() |
09cfb561d1 | ||
![]() |
5273ef3925 | ||
![]() |
dc82dabf3b | ||
![]() |
39095cea86 | ||
![]() |
a44283b04d | ||
![]() |
5a710c29ce | ||
![]() |
387bebe2c1 | ||
![]() |
72ae4703aa | ||
![]() |
12dee8bab7 | ||
![]() |
45257c7f8e | ||
![]() |
114ac657e7 | ||
![]() |
c80f2fa1cd | ||
![]() |
8433878d3d | ||
![]() |
5a1e097949 | ||
![]() |
2bef6d9f67 | ||
![]() |
b122b59444 | ||
![]() |
37cdbfde9d | ||
![]() |
6a6385f515 | ||
![]() |
b261ec8c16 | ||
![]() |
b803322edc | ||
![]() |
57c0215069 | ||
![]() |
fb6ea0db5b | ||
![]() |
65b49d1d09 | ||
![]() |
31c0264a04 | ||
![]() |
f161bcaced | ||
![]() |
48df019c84 | ||
![]() |
d5b25ca1a8 | ||
![]() |
5fd3f15ac7 | ||
![]() |
15e2d684df | ||
![]() |
2702d0427b | ||
![]() |
9c7f07bd89 | ||
![]() |
5545881e4c | ||
![]() |
3b0736fb89 | ||
![]() |
cf0c54e2bd | ||
![]() |
f8e0a20820 | ||
![]() |
7cb1493d0a | ||
![]() |
ca379f7ba6 | ||
![]() |
f8172bdbfa | ||
![]() |
3e66411779 | ||
![]() |
ead99700e9 | ||
![]() |
e8aaba6560 | ||
![]() |
069cb1f3a5 | ||
![]() |
924ea94f25 | ||
![]() |
aec67a1e42 | ||
![]() |
2e94629304 | ||
![]() |
ecccc7e820 | ||
![]() |
450197ffbf | ||
![]() |
a89a10120a | ||
![]() |
9c07d87041 | ||
![]() |
0826a2c5f8 | ||
![]() |
47c11dec33 | ||
![]() |
64133f4c30 | ||
![]() |
ef8595ae1c | ||
![]() |
18f7ce3460 | ||
![]() |
78a30109de | ||
![]() |
17a3a75959 | ||
![]() |
0bfe23ceda | ||
![]() |
fb63521042 | ||
![]() |
d213bf487a | ||
![]() |
8008016de8 | ||
![]() |
1dbce3938e | ||
![]() |
13f1ebe1fe | ||
![]() |
c158487417 | ||
![]() |
708d4a16a3 | ||
![]() |
bdd89e22ea | ||
![]() |
fc0c867f25 | ||
![]() |
3f683ea036 | ||
![]() |
633a96c54b | ||
![]() |
1e8642bc6e | ||
![]() |
b2f505a41c | ||
![]() |
af46c34a02 | ||
![]() |
9350a6aa95 | ||
![]() |
d01c8a8352 | ||
![]() |
9ed9279a98 | ||
![]() |
bbcdb9c5e0 | ||
![]() |
de9508653a | ||
![]() |
51d82c82e9 | ||
![]() |
0346f0ffdc | ||
![]() |
ff97452eb0 | ||
![]() |
50e9e4c2c6 | ||
![]() |
0440eeaab1 | ||
![]() |
2a79c2b526 | ||
![]() |
faa02ad708 | ||
![]() |
f888f15dbd | ||
![]() |
4f6fbc58d0 | ||
![]() |
923f48795f | ||
![]() |
e443e318f7 | ||
![]() |
bdf6bac511 | ||
![]() |
600e8d36b1 | ||
![]() |
59f2d077a6 | ||
![]() |
13c889a10e | ||
![]() |
fb1607b3d3 | ||
![]() |
cdc78e4609 | ||
![]() |
89495f919d | ||
![]() |
3b3e4c4ab0 | ||
![]() |
57a5846746 | ||
![]() |
836e1d115f | ||
![]() |
56f787cf73 | ||
![]() |
6ca760163e | ||
![]() |
f25dd98112 | ||
![]() |
e8f6a8abdb | ||
![]() |
efe64ba0af | ||
![]() |
5f33f70d64 | ||
![]() |
c4cc398778 | ||
![]() |
327067cb7d | ||
![]() |
bb887d76f6 | ||
![]() |
cc103aa37f | ||
![]() |
92e98e84e2 | ||
![]() |
4116ec7581 | ||
![]() |
d5a82f98bf | ||
![]() |
da7bb84ca3 | ||
![]() |
4caeb82351 | ||
![]() |
88c9996ce6 | ||
![]() |
5a39692fb8 | ||
![]() |
b65608dfec | ||
![]() |
9b79e7329c | ||
![]() |
b576b2f9de | ||
![]() |
88cd5f3774 | ||
![]() |
d0b013ccda | ||
![]() |
acc77ce5d2 | ||
![]() |
8e8abd2273 | ||
![]() |
b0dd088d56 | ||
![]() |
a93083b2a2 | ||
![]() |
57f5fca41e | ||
![]() |
6b539c376a | ||
![]() |
900e6f8d61 | ||
![]() |
5399c1f2fe | ||
![]() |
3bdacf4c12 | ||
![]() |
f40d35a60b | ||
![]() |
c2f410d700 | ||
![]() |
81c778cc67 | ||
![]() |
aca21d905e | ||
![]() |
775455c809 | ||
![]() |
d32f0932b4 | ||
![]() |
e934fe6eee | ||
![]() |
0af781390d | ||
![]() |
a0595d992b | ||
![]() |
c17dc924fd | ||
![]() |
734511a1ee | ||
![]() |
104fd4803a | ||
![]() |
270c4de9fb | ||
![]() |
a628e0780e | ||
![]() |
6e7a7307cc | ||
![]() |
5aa49f6563 | ||
![]() |
56420d67b0 | ||
![]() |
a046af263c | ||
![]() |
5657f3f481 | ||
![]() |
90e774bb13 | ||
![]() |
c598ac996a | ||
![]() |
c3ce70c384 | ||
![]() |
2730c9d8e9 | ||
![]() |
1048ffaace | ||
![]() |
8ab54084e4 | ||
![]() |
6732b84cc1 | ||
![]() |
56dc82758b | ||
![]() |
a86217ebf5 | ||
![]() |
da61335597 | ||
![]() |
5ed5d688c2 | ||
![]() |
21118a5445 | ||
![]() |
6cefcb1f3d | ||
![]() |
e70f64e2c6 | ||
![]() |
b9c4530b42 | ||
![]() |
63b7cfde5f | ||
![]() |
6d1428ae61 | ||
![]() |
5a40b92cd2 | ||
![]() |
da7be60c78 | ||
![]() |
218093b958 | ||
![]() |
d4c1415fd8 | ||
![]() |
9518b9e844 | ||
![]() |
15d519c13d | ||
![]() |
46b2228ddb | ||
![]() |
18f8a1ea23 | ||
![]() |
23da99b3b7 | ||
![]() |
ea5540c833 | ||
![]() |
e8e4220b46 | ||
![]() |
0ae019b055 | ||
![]() |
486df2efbd | ||
![]() |
92b7fc7ce1 | ||
![]() |
2135b091fb | ||
![]() |
02aeef647e | ||
![]() |
934727b346 | ||
![]() |
d394a2f92a | ||
![]() |
a860746af7 | ||
![]() |
109063e5a4 | ||
![]() |
a4f0490d99 | ||
![]() |
179039bf5a | ||
![]() |
545c4f5e42 | ||
![]() |
1416e001e3 | ||
![]() |
cc3df4f040 | ||
![]() |
d4e6d5f3d5 | ||
![]() |
a1e4ef51bb | ||
![]() |
6e15893135 | ||
![]() |
2257b94a9b | ||
![]() |
cb76e0af53 | ||
![]() |
bf1a443749 | ||
![]() |
7d25559235 | ||
![]() |
911fe332c6 | ||
![]() |
93d78bf7c8 | ||
![]() |
20c350e3cd | ||
![]() |
4fb247ef25 | ||
![]() |
f182a12c8f | ||
![]() |
5be9d902db | ||
![]() |
4f2ccfb834 | ||
![]() |
45c973a387 | ||
![]() |
561c044924 | ||
![]() |
c3e2e821c6 | ||
![]() |
cdce8348bb | ||
![]() |
926dd936cb | ||
![]() |
c2bdc44371 | ||
![]() |
27160810a8 | ||
![]() |
ab827e0b50 | ||
![]() |
ee90585a0a | ||
![]() |
eacce2e00c | ||
![]() |
9039c31e68 | ||
![]() |
ced5d9795e | ||
![]() |
b57a803d5a | ||
![]() |
6c41d8d9b3 | ||
![]() |
1e6196cb9c | ||
![]() |
8b715e61f3 | ||
![]() |
a6aee12de0 | ||
![]() |
0462ca7fdb | ||
![]() |
67179f582b | ||
![]() |
97d7543289 | ||
![]() |
30889511ed | ||
![]() |
3ab322a33f | ||
![]() |
d8008e3d57 | ||
![]() |
386a26030c | ||
![]() |
743fe3d011 | ||
![]() |
6e775b277d | ||
![]() |
62a3b79e4b | ||
![]() |
cf9764a071 | ||
![]() |
4b8b4faa11 | ||
![]() |
d46f806038 | ||
![]() |
a29b0753d9 | ||
![]() |
ecea17cd3b | ||
![]() |
3de023e27e | ||
![]() |
26c9126880 | ||
![]() |
d982e5bd8a | ||
![]() |
33fd4a2f23 | ||
![]() |
62431928d8 | ||
![]() |
bf87e04a6b | ||
![]() |
37bdee47ec | ||
![]() |
4466bcfc4e | ||
![]() |
c853979fb1 | ||
![]() |
bcf08875a7 | ||
![]() |
4694a29389 | ||
![]() |
0878256bf8 | ||
![]() |
ade685fd3f | ||
![]() |
7a1eb111bb | ||
![]() |
0ade1d9b0d | ||
![]() |
41428a172c | ||
![]() |
373c546702 | ||
![]() |
817cc605be | ||
![]() |
6fe3549684 | ||
![]() |
c8c1b2b757 | ||
![]() |
218a129d25 | ||
![]() |
570a917a7d | ||
![]() |
c537df5abe | ||
![]() |
d86a795898 | ||
![]() |
769b011a87 | ||
![]() |
272b44a5e8 | ||
![]() |
43225227fa | ||
![]() |
2e1717272c | ||
![]() |
d3038f6a4a | ||
![]() |
72737eabcf | ||
![]() |
36e268c634 | ||
![]() |
d25ae317f4 | ||
![]() |
6ae5046287 | ||
![]() |
a8709a71b5 | ||
![]() |
34e9b10c68 | ||
![]() |
a1c6802a8a | ||
![]() |
ce3dce4991 | ||
![]() |
6d83d7e403 | ||
![]() |
cdc1d29879 | ||
![]() |
4517ba4982 | ||
![]() |
065cd3f09c | ||
![]() |
b4d428d09c | ||
![]() |
b61b145bb9 | ||
![]() |
19b2e32394 | ||
![]() |
21da984823 | ||
![]() |
a7475d16ee | ||
![]() |
19234368ba | ||
![]() |
9c9b3dc00a | ||
![]() |
8d94cdcae8 | ||
![]() |
225f818ce4 | ||
![]() |
cd0646274d | ||
![]() |
58f764898e | ||
![]() |
9ca7c3c8d0 | ||
![]() |
f94fa664b1 | ||
![]() |
3b3ccdfb03 | ||
![]() |
5baf13a068 | ||
![]() |
c4485be70e | ||
![]() |
6ec0c7bd6c | ||
![]() |
736cd41f9c | ||
![]() |
4f9fc49cfd | ||
![]() |
1f5d52048a | ||
![]() |
a54d90607a | ||
![]() |
f915af388e | ||
![]() |
c31abc32ee | ||
![]() |
587963ff6d | ||
![]() |
b07f5be076 | ||
![]() |
c82b21033f | ||
![]() |
ab175b489b | ||
![]() |
ac2230c4c0 | ||
![]() |
ba7d032377 | ||
![]() |
32d1917ff9 | ||
![]() |
13e2ccf17d | ||
![]() |
4700c2c5ff | ||
![]() |
9a057e1b29 | ||
![]() |
3500b053bb | ||
![]() |
b3c8f78271 | ||
![]() |
e921f0dde4 | ||
![]() |
7e99ecc7bf | ||
![]() |
ca65af8be6 | ||
![]() |
c4769e9cc3 | ||
![]() |
e8d38e4620 | ||
![]() |
c832eced7b | ||
![]() |
c5ddba49fd | ||
![]() |
33ff93f475 | ||
![]() |
d20df6483b | ||
![]() |
9f120e974f | ||
![]() |
bf81ad1b8f | ||
![]() |
cec7b8b756 | ||
![]() |
9a1e116701 | ||
![]() |
fb6618ca79 | ||
![]() |
c448c52182 | ||
![]() |
8ebdb00b43 | ||
![]() |
a3f3174c73 | ||
![]() |
7ca2382f99 | ||
![]() |
deae94bac8 | ||
![]() |
02f05a2936 | ||
![]() |
fc10b42318 | ||
![]() |
24fefb865b | ||
![]() |
4a63099003 | ||
![]() |
32f876a0ae | ||
![]() |
faeb246a03 | ||
![]() |
f37844bd56 | ||
![]() |
b2ea3861d6 | ||
![]() |
a994629f90 | ||
![]() |
7a690a514d | ||
![]() |
ce4b2e0530 | ||
![]() |
a0c42eec91 | ||
![]() |
a33a2a2717 | ||
![]() |
2503683a31 | ||
![]() |
6e5ba97b5b | ||
![]() |
b1adef299f | ||
![]() |
57e6083b7a | ||
![]() |
55e38e89ce | ||
![]() |
bb055f8fa8 | ||
![]() |
a4168b9b19 | ||
![]() |
3fcf8cea97 | ||
![]() |
328705360a | ||
![]() |
88bd588905 | ||
![]() |
2a5f0c98fb | ||
![]() |
841def61bf | ||
![]() |
1fb87145aa | ||
![]() |
350ec1d262 | ||
![]() |
6d99a29e69 | ||
![]() |
e73b3cfecd | ||
![]() |
f936a8c9e1 | ||
![]() |
c56260ff0d | ||
![]() |
146f40fa51 | ||
![]() |
01d025117d | ||
![]() |
5755fead94 | ||
![]() |
70def025c8 | ||
![]() |
b3a2677809 | ||
![]() |
de98b03522 | ||
![]() |
7c1e2c7588 | ||
![]() |
8e990d836d | ||
![]() |
be5e2940e1 | ||
![]() |
8e097357e6 | ||
![]() |
c86fc0ce97 | ||
![]() |
d40ce7caeb | ||
![]() |
c6dc314dbd | ||
![]() |
36b76afeb1 | ||
![]() |
1a495cf2d5 | ||
![]() |
69066b18f9 | ||
![]() |
288f1e9d39 | ||
![]() |
ac4ea8cd7b | ||
![]() |
152ef446c0 | ||
![]() |
29e69a970f | ||
![]() |
663e066f5e | ||
![]() |
c063f07dcd | ||
![]() |
ff6fdb1361 | ||
![]() |
02361e0518 | ||
![]() |
c9801ac2ad | ||
![]() |
4621be9f17 |
27
.github/workflows/ci.yml
vendored
27
.github/workflows/ci.yml
vendored
@ -1,8 +1,9 @@
|
||||
# http://webui.me
|
||||
# https://webui.me
|
||||
# https://github.com/webui-dev/webui
|
||||
# Copyright (c) 2020-2023 Hassan Draga.
|
||||
# Copyright (c) 2020-2025 Hassan Draga.
|
||||
# Licensed under MIT License.
|
||||
# All rights reserved.
|
||||
# Canada.
|
||||
#
|
||||
# Special Thanks to Turiiya (https://github.com/ttytm)
|
||||
|
||||
@ -14,6 +15,10 @@ on:
|
||||
branches: [main]
|
||||
paths-ignore: ['**/*.md']
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref_name == 'main' && github.sha || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
windows:
|
||||
uses: ./.github/workflows/windows.yml
|
||||
@ -29,3 +34,21 @@ jobs:
|
||||
uses: ./.github/workflows/linux.yml
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
linux_arm:
|
||||
uses: ./.github/workflows/linux_arm.yml
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
linux_redhat:
|
||||
uses: ./.github/workflows/linux_redhat.yml
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
linux_arch:
|
||||
uses: ./.github/workflows/linux_arch.yml
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
zig:
|
||||
uses: ./.github/workflows/zig.yml
|
||||
|
174
.github/workflows/linux.yml
vendored
174
.github/workflows/linux.yml
vendored
@ -1,8 +1,9 @@
|
||||
# http://webui.me
|
||||
# https://webui.me
|
||||
# https://github.com/webui-dev/webui
|
||||
# Copyright (c) 2020-2023 Hassan Draga.
|
||||
# Copyright (c) 2020-2025 Hassan Draga.
|
||||
# Licensed under MIT License.
|
||||
# All rights reserved.
|
||||
# Canada.
|
||||
#
|
||||
# Special Thanks to Turiiya (https://github.com/ttytm)
|
||||
|
||||
@ -12,97 +13,102 @@ on:
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Bundle WebUI Bridge
|
||||
run: |
|
||||
npm i -g esbuild
|
||||
chmod +x bridge/build.sh
|
||||
bridge/build.sh
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: bridge/webui_bridge.h
|
||||
key: ${{ runner.os }}-${{ github.sha }}-bridge
|
||||
|
||||
build:
|
||||
needs: setup
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
contents: write
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: [GCC, Clang]
|
||||
arch: [x64]
|
||||
include:
|
||||
- compiler: GCC
|
||||
arch: arm64
|
||||
- compiler: GCC
|
||||
arch: arm
|
||||
- cc: gcc
|
||||
arch: x64
|
||||
- cc: clang
|
||||
arch: x64
|
||||
fail-fast: false
|
||||
env:
|
||||
ARTIFACT: webui-linux-${{ matrix.cc }}-${{ matrix.arch }}
|
||||
CC: ${{ matrix.cc }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache/restore@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: bridge/webui_bridge.h
|
||||
key: ${{ runner.os }}-${{ github.sha }}-bridge
|
||||
fail-on-cache-miss: true
|
||||
- name: Setup Libraries
|
||||
- name: Setup
|
||||
run: |
|
||||
if [ "${{ matrix.compiler }}" == "Clang" ]; then
|
||||
if [ "$CC" == "clang" ]; then
|
||||
sudo ln -s llvm-ar-14 /usr/bin/llvm-ar
|
||||
sudo ln -s llvm-ranlib-14 /usr/bin/llvm-ranlib
|
||||
elif [ "${{ matrix.arch }}" == "arm64" ]; then
|
||||
sudo apt install gcc-aarch64-linux-gnu
|
||||
elif [ "${{ matrix.arch }}" == "arm" ]; then
|
||||
sudo apt install gcc-arm-linux-gnueabihf
|
||||
sudo ln -s llvm-strip-14 /usr/bin/llvm-strip
|
||||
fi
|
||||
- name: Build Debug Target
|
||||
run: |
|
||||
if [ "${{ matrix.arch }}" == "arm64" ]; then
|
||||
make CC=aarch64-linux-gnu-gcc debug
|
||||
elif [ "${{ matrix.arch }}" == "arm" ]; then
|
||||
make CC=arm-linux-gnueabihf-gcc debug
|
||||
else
|
||||
compiler=${{ matrix.compiler }}
|
||||
make CC=${compiler,,} debug
|
||||
fi
|
||||
run: make debug
|
||||
- name: Build Release Target
|
||||
if: ${{ !cancelled() }}
|
||||
run: make
|
||||
- name: Build TLS Debug Target
|
||||
run: make WEBUI_USE_TLS=1 debug
|
||||
- name: Build TLS Release Target
|
||||
run: make WEBUI_USE_TLS=1
|
||||
- name: Build Examples
|
||||
run: |
|
||||
if [ "${{ matrix.arch }}" == "arm64" ]; then
|
||||
make CC=aarch64-linux-gnu-gcc
|
||||
elif [ "${{ matrix.arch }}" == "arm" ]; then
|
||||
make CC=arm-linux-gnueabihf-gcc
|
||||
else
|
||||
compiler=${{ matrix.compiler }}
|
||||
make CC=${compiler,,}
|
||||
fi
|
||||
examples_base_dir=$(pwd)/examples/C
|
||||
for example in $(find $examples_base_dir/* -maxdepth 0 -type d); do
|
||||
echo "> $example"
|
||||
cd $example || (exit_code=1 && continue)
|
||||
if ! make; then
|
||||
echo "Failed to build '$example'"
|
||||
exit_code=1
|
||||
continue
|
||||
fi
|
||||
if [[ ! -e "main" || ! -e "main-dyn" ]] ; then
|
||||
echo "Failed to find executable for '$example'" && find .
|
||||
exit_code=1
|
||||
continue
|
||||
fi
|
||||
done
|
||||
exit $exit_code
|
||||
- name: Setup Browser
|
||||
uses: browser-actions/setup-chrome@v1
|
||||
- name: Prepare Artifact
|
||||
run: |
|
||||
cp -r include dist
|
||||
artifact=webui-${{ runner.os }}-${{ matrix.compiler }}-${{ matrix.arch }}
|
||||
# Convert to lowercase (`,,` ^= lowercase shell param)
|
||||
artifact=${artifact,,}
|
||||
# Add the ARTIFACT name as GitHub environment variable.
|
||||
echo "ARTIFACT=$artifact" >> $GITHUB_ENV
|
||||
mv dist/ $artifact
|
||||
mv dist/ "$ARTIFACT"
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.ARTIFACT }}
|
||||
path: ${{ env.ARTIFACT }}
|
||||
- name: Prepare Release
|
||||
if: github.ref_type == 'tag' || (github.ref_name == 'main' && github.event_name == 'push')
|
||||
if: >
|
||||
github.repository_owner == 'webui-dev'
|
||||
&& (github.ref_type == 'tag' || (github.ref_name == 'main' && github.event_name == 'push'))
|
||||
run: |
|
||||
zip -r ${{ env.ARTIFACT }}.zip ${{ env.ARTIFACT }}
|
||||
zip -r "$ARTIFACT.zip" "$ARTIFACT"
|
||||
if [ $GITHUB_REF_TYPE == tag ]; then
|
||||
echo "TAG=$GITHUB_REF_NAME" >> $GITHUB_ENV
|
||||
else
|
||||
echo "IS_PRERELEASE=true" >> $GITHUB_ENV
|
||||
now=$(date -u +'%Y-%m-%d %H:%M:%S UTC')
|
||||
echo "TAG=nightly" >> $GITHUB_ENV
|
||||
echo "BODY=Generated on <samp>$now</samp> from commit ${{ github.sha }}." >> $GITHUB_ENV
|
||||
echo "TITLE=WebUI Development Build" >> $GITHUB_ENV
|
||||
{
|
||||
echo "IS_PRERELEASE=true";
|
||||
echo "TAG=nightly";
|
||||
echo "TITLE=WebUI Nightly Build $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
|
||||
echo "BODY=Generated from commit $GITHUB_SHA."
|
||||
} >> $GITHUB_ENV
|
||||
fi
|
||||
- name: Update Nightly Tag
|
||||
if: env.IS_PRERELEASE
|
||||
@ -112,7 +118,9 @@ jobs:
|
||||
with:
|
||||
tag_name: nightly
|
||||
- name: Release
|
||||
if: github.ref_type == 'tag' || (github.ref_name == 'main' && github.event_name == 'push')
|
||||
if: >
|
||||
github.repository_owner == 'webui-dev'
|
||||
&& (github.ref_type == 'tag' || (github.ref_name == 'main' && github.event_name == 'push'))
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: ${{ env.ARTIFACT }}.zip
|
||||
@ -121,3 +129,65 @@ jobs:
|
||||
name: ${{ env.TITLE }}
|
||||
prerelease: ${{ env.IS_PRERELEASE }}
|
||||
allowUpdates: true
|
||||
|
||||
build-ubuntu-22:
|
||||
needs: setup
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
contents: write
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- cc: gcc
|
||||
arch: x64
|
||||
- cc: clang
|
||||
arch: x64
|
||||
fail-fast: false
|
||||
env:
|
||||
ARTIFACT: webui-linux-${{ matrix.cc }}-${{ matrix.arch }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: bridge/webui_bridge.h
|
||||
key: ${{ runner.os }}-${{ github.sha }}-bridge
|
||||
fail-on-cache-miss: true
|
||||
- name: Setup
|
||||
run: |
|
||||
CC="${{ matrix.cc }}"
|
||||
if [ "$CC" == "clang" ]; then
|
||||
sudo ln -s llvm-ar-14 /usr/bin/llvm-ar
|
||||
sudo ln -s llvm-ranlib-14 /usr/bin/llvm-ranlib
|
||||
sudo ln -s llvm-strip-14 /usr/bin/llvm-strip
|
||||
else
|
||||
sudo apt -qq install gcc-11
|
||||
CC+="-11"
|
||||
fi
|
||||
echo "CC=$CC" >> $GITHUB_ENV
|
||||
- name: Build Debug Target
|
||||
run: make debug
|
||||
- name: Build Release Target
|
||||
if: ${{ !cancelled() }}
|
||||
run: make
|
||||
- name: Build TLS Debug Target
|
||||
run: make WEBUI_USE_TLS=1 debug
|
||||
- name: Build TLS Release Target
|
||||
run: make WEBUI_USE_TLS=1
|
||||
- name: Build Examples
|
||||
run: |
|
||||
examples_base_dir=$(pwd)/examples/C
|
||||
for example in $(find $examples_base_dir/* -maxdepth 0 -type d); do
|
||||
echo "> $example"
|
||||
cd $example || (exit_code=1 && continue)
|
||||
if ! make; then
|
||||
echo "Failed to build '$example'"
|
||||
exit_code=1
|
||||
continue
|
||||
fi
|
||||
if [[ ! -e "main" || ! -e "main-dyn" ]] ; then
|
||||
echo "Failed to find executable for '$example'" && find .
|
||||
exit_code=1
|
||||
continue
|
||||
fi
|
||||
done
|
||||
exit $exit_code
|
||||
|
111
.github/workflows/linux_arch.yml
vendored
Normal file
111
.github/workflows/linux_arch.yml
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
# https://webui.me
|
||||
# https://github.com/webui-dev/webui
|
||||
# Copyright (c) 2020-2025 Hassan Draga.
|
||||
# Licensed under MIT License.
|
||||
# All rights reserved.
|
||||
# Canada.
|
||||
|
||||
name: Linux-Arch
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- cc: gcc
|
||||
arch: x64
|
||||
- cc: clang
|
||||
arch: x64
|
||||
fail-fast: false
|
||||
env:
|
||||
ARTIFACT: webui-linux-arch-${{ matrix.cc }}-${{ matrix.arch }}
|
||||
CC: ${{ matrix.cc }}
|
||||
steps:
|
||||
- name: Check out the repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Build Arch Linux Docker Image
|
||||
run: |
|
||||
docker build -t archlinux:latest - <<EOF
|
||||
FROM archlinux:latest
|
||||
RUN pacman -Syu --noconfirm git npm make gcc clang llvm lld
|
||||
EOF
|
||||
|
||||
- name: Run build inside Arch Linux container
|
||||
run: |
|
||||
docker run --rm \
|
||||
-v ${{ github.workspace }}:/workspace \
|
||||
-w /workspace \
|
||||
--user root \
|
||||
-e CC=${{ matrix.cc }} \
|
||||
archlinux:latest \
|
||||
bash -c "
|
||||
git config --global --add safe.directory /workspace &&
|
||||
npm i -g esbuild &&
|
||||
chmod +x bridge/build.sh &&
|
||||
if [ '${{ matrix.cc }}' == 'clang' ]; then
|
||||
export AR=llvm-ar
|
||||
export STRIP=llvm-strip
|
||||
fi &&
|
||||
./bridge/build.sh &&
|
||||
make debug &&
|
||||
make &&
|
||||
make WEBUI_USE_TLS=1 debug &&
|
||||
make WEBUI_USE_TLS=1 &&
|
||||
chown -R $(id -u):$(id -g) /workspace
|
||||
"
|
||||
|
||||
- name: Prepare Artifact
|
||||
run: |
|
||||
cp -r include dist
|
||||
mv dist/ "$ARTIFACT"
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.ARTIFACT }}
|
||||
path: ${{ env.ARTIFACT}}
|
||||
|
||||
- name: Prepare Release
|
||||
if: >
|
||||
github.repository_owner == 'webui-dev'
|
||||
&& (github.ref_type == 'tag' || (github.ref_name == 'main' && github.event_name == 'push'))
|
||||
run: |
|
||||
zip -r "$ARTIFACT.zip" "$ARTIFACT"
|
||||
if [ $GITHUB_REF_TYPE == tag ]; then
|
||||
echo "TAG=$GITHUB_REF_NAME" >> $GITHUB_ENV
|
||||
else
|
||||
{
|
||||
echo "IS_PRERELEASE=true";
|
||||
echo "TAG=nightly";
|
||||
echo "TITLE=WebUI Nightly Build $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
|
||||
echo "BODY=Generated from commit $GITHUB_SHA."
|
||||
} >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Update Nightly Tag
|
||||
if: env.IS_PRERELEASE
|
||||
uses: richardsimko/update-tag@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: nightly
|
||||
|
||||
- name: Release
|
||||
if: >
|
||||
github.repository_owner == 'webui-dev'
|
||||
&& (github.ref_type == 'tag' || (github.ref_name == 'main' && github.event_name == 'push'))
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: ${{ env.ARTIFACT }}.zip
|
||||
tag: ${{ env.TAG }}
|
||||
body: ${{ env.BODY }}
|
||||
name: ${{ env.TITLE }}
|
||||
prerelease: ${{ env.IS_PRERELEASE }}
|
||||
allowUpdates: true
|
165
.github/workflows/linux_arm.yml
vendored
Normal file
165
.github/workflows/linux_arm.yml
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
# https://webui.me
|
||||
# https://github.com/webui-dev/webui
|
||||
# Copyright (c) 2020-2025 Hassan Draga.
|
||||
# Licensed under MIT License.
|
||||
# All rights reserved.
|
||||
# Canada.
|
||||
#
|
||||
# Special Thanks to Turiiya (https://github.com/ttytm)
|
||||
|
||||
name: Linux ARM
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
runs-on: buildjet-32vcpu-ubuntu-2204-arm
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Check CPU Architecture
|
||||
run: |
|
||||
ARCH=$(uname -m)
|
||||
if [[ "$ARCH" != "arm"* && "$ARCH" != "aarch64" ]]; then
|
||||
echo "Expected ARM-based CPU architecture. Detected: $ARCH"
|
||||
exit 1
|
||||
else
|
||||
echo "ARM CPU Detected: $ARCH"
|
||||
fi
|
||||
- name: Bundle WebUI Bridge
|
||||
run: |
|
||||
npm i -g esbuild
|
||||
chmod +x bridge/build.sh
|
||||
bridge/build.sh
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: bridge/webui_bridge.h
|
||||
key: ${{ runner.os }}-${{ github.sha }}-bridge
|
||||
|
||||
build:
|
||||
needs: setup
|
||||
# Same as `buildjet-32vcpu-ubuntu-2204-arm`
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
contents: write
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- cc: gcc
|
||||
arch: arm
|
||||
- cc: gcc
|
||||
arch: arm64
|
||||
fail-fast: false
|
||||
env:
|
||||
ARTIFACT: webui-linux-${{ matrix.cc }}-${{ matrix.arch }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: bridge/webui_bridge.h
|
||||
key: ${{ runner.os }}-${{ github.sha }}-bridge
|
||||
fail-on-cache-miss: true
|
||||
- name: Setup
|
||||
run: |
|
||||
CC=${{ matrix.cc }}
|
||||
if [ "${{ matrix.arch }}" == "arm64" ]; then
|
||||
sudo apt update
|
||||
sudo apt install -y gcc-aarch64-linux-gnu
|
||||
CC=aarch64-linux-gnu-gcc
|
||||
wget https://github.com/openssl/openssl/releases/download/openssl-3.3.1/openssl-3.3.1.tar.gz
|
||||
tar -xzf openssl-3.3.1.tar.gz
|
||||
cd openssl-3.3.1
|
||||
./Configure linux-generic64 --prefix=/usr/aarch64-linux-gnu --cross-compile-prefix=aarch64-linux-gnu- --release -latomic
|
||||
make
|
||||
sudo make install
|
||||
elif [ "${{ matrix.arch }}" == "arm" ]; then
|
||||
sudo apt update
|
||||
sudo apt install -y gcc-arm-linux-gnueabi
|
||||
CC=arm-linux-gnueabi-gcc
|
||||
wget https://github.com/openssl/openssl/releases/download/openssl-3.3.1/openssl-3.3.1.tar.gz
|
||||
tar -xzf openssl-3.3.1.tar.gz
|
||||
cd openssl-3.3.1
|
||||
./Configure linux-generic32 --prefix=/usr/arm-linux-gnueabi --cross-compile-prefix=arm-linux-gnueabi- --release -latomic
|
||||
make
|
||||
sudo make install
|
||||
fi
|
||||
echo "CC=$CC" >> $GITHUB_ENV
|
||||
- name: Build Debug Target
|
||||
run: make debug
|
||||
- name: Build Release Target
|
||||
if: ${{ !cancelled() }}
|
||||
run: make
|
||||
- name: Build TLS Debug ARM64 Target
|
||||
if: matrix.arch == 'arm64'
|
||||
run: make WEBUI_USE_TLS=1 debug WEBUI_TLS_INCLUDE="/usr/aarch64-linux-gnu/include" WEBUI_TLS_LIB="/usr/aarch64-linux-gnu/lib"
|
||||
- name: Build TLS Debug ARM Target
|
||||
if: matrix.arch == 'arm'
|
||||
run: make WEBUI_USE_TLS=1 debug WEBUI_TLS_INCLUDE="/usr/arm-linux-gnueabi/include" WEBUI_TLS_LIB="/usr/arm-linux-gnueabi/lib"
|
||||
- name: Build TLS Release ARM64 Target
|
||||
if: matrix.arch == 'arm64'
|
||||
run: make WEBUI_USE_TLS=1 WEBUI_TLS_INCLUDE="/usr/aarch64-linux-gnu/include" WEBUI_TLS_LIB="/usr/aarch64-linux-gnu/lib"
|
||||
- name: Build TLS Release ARM Target
|
||||
if: matrix.arch == 'arm'
|
||||
run: make WEBUI_USE_TLS=1 WEBUI_TLS_INCLUDE="/usr/arm-linux-gnueabi/include" WEBUI_TLS_LIB="/usr/arm-linux-gnueabi/lib"
|
||||
# - name: Build Examples
|
||||
# if: matrix.arch == 'arm64'
|
||||
# run: |
|
||||
# examples_base_dir=$(pwd)/examples/C
|
||||
# for example in $(find $examples_base_dir/* -maxdepth 0 -type d); do
|
||||
# echo "> $example"
|
||||
# cd $example || (exit_code=1 && continue)
|
||||
# if ! make CC=aarch64-linux-gnu-gcc; then
|
||||
# echo "Failed to build '$example'"
|
||||
# exit_code=1
|
||||
# continue
|
||||
# fi
|
||||
# if [[ ! -e "main" || ! -e "main-dyn" ]] ; then
|
||||
# echo "Failed to find executable for '$example'" && find .
|
||||
# exit_code=1
|
||||
# continue
|
||||
# fi
|
||||
# done
|
||||
# exit $exit_code
|
||||
- name: Prepare Artifact
|
||||
run: |
|
||||
cp -r include dist
|
||||
mv dist/ "$ARTIFACT"
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.ARTIFACT }}
|
||||
path: ${{ env.ARTIFACT }}
|
||||
- name: Prepare Release
|
||||
if: >
|
||||
github.repository_owner == 'webui-dev'
|
||||
&& (github.ref_type == 'tag' || (github.ref_name == 'main' && github.event_name == 'push'))
|
||||
run: |
|
||||
zip -r "$ARTIFACT.zip" "$ARTIFACT"
|
||||
if [ $GITHUB_REF_TYPE == tag ]; then
|
||||
echo "TAG=$GITHUB_REF_NAME" >> $GITHUB_ENV
|
||||
else
|
||||
{
|
||||
echo "IS_PRERELEASE=true";
|
||||
echo "TAG=nightly";
|
||||
echo "TITLE=WebUI Nightly Build $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
|
||||
echo "BODY=Generated from commit $GITHUB_SHA."
|
||||
} >> $GITHUB_ENV
|
||||
fi
|
||||
- name: Update Nightly Tag
|
||||
if: env.IS_PRERELEASE
|
||||
uses: richardsimko/update-tag@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: nightly
|
||||
- name: Release
|
||||
if: >
|
||||
github.repository_owner == 'webui-dev'
|
||||
&& (github.ref_type == 'tag' || (github.ref_name == 'main' && github.event_name == 'push'))
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: ${{ env.ARTIFACT }}.zip
|
||||
tag: ${{ env.TAG }}
|
||||
body: ${{ env.BODY }}
|
||||
name: ${{ env.TITLE }}
|
||||
prerelease: ${{ env.IS_PRERELEASE }}
|
||||
allowUpdates: true
|
113
.github/workflows/linux_redhat.yml
vendored
Normal file
113
.github/workflows/linux_redhat.yml
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
# https://webui.me
|
||||
# https://github.com/webui-dev/webui
|
||||
# Copyright (c) 2020-2025 Hassan Draga.
|
||||
# Licensed under MIT License.
|
||||
# All rights reserved.
|
||||
# Canada.
|
||||
|
||||
name: Linux-RedHat
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- cc: gcc
|
||||
arch: x64
|
||||
- cc: clang
|
||||
arch: x64
|
||||
fail-fast: false
|
||||
env:
|
||||
ARTIFACT: webui-linux-redhat-${{ matrix.cc }}-${{ matrix.arch }}
|
||||
CC: ${{ matrix.cc }}
|
||||
steps:
|
||||
- name: Check out the repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Build RedHat Docker Image
|
||||
run: |
|
||||
docker build -t redhat:latest - <<EOF
|
||||
FROM almalinux:9
|
||||
RUN dnf install -y epel-release
|
||||
RUN dnf groupinstall -y "Development Tools"
|
||||
RUN dnf install -y git nodejs npm clang llvm-toolset lld openssl-devel
|
||||
EOF
|
||||
|
||||
- name: Run build inside RedHat container
|
||||
run: |
|
||||
docker run --rm \
|
||||
-v ${{ github.workspace }}:/workspace \
|
||||
-w /workspace \
|
||||
--user root \
|
||||
-e CC=${{ matrix.cc }} \
|
||||
redhat:latest \
|
||||
bash -c "
|
||||
git config --global --add safe.directory /workspace &&
|
||||
npm i -g esbuild &&
|
||||
chmod +x bridge/build.sh &&
|
||||
if [ '${{ matrix.cc }}' == 'clang' ]; then
|
||||
export AR=llvm-ar
|
||||
export STRIP=llvm-strip
|
||||
fi &&
|
||||
./bridge/build.sh &&
|
||||
make debug &&
|
||||
make &&
|
||||
make WEBUI_USE_TLS=1 debug &&
|
||||
make WEBUI_USE_TLS=1 &&
|
||||
chown -R $(id -u):$(id -g) /workspace
|
||||
"
|
||||
|
||||
- name: Prepare Artifact
|
||||
run: |
|
||||
cp -r include dist
|
||||
mv dist/ "$ARTIFACT"
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.ARTIFACT }}
|
||||
path: ${{ env.ARTIFACT }}
|
||||
|
||||
- name: Prepare Release
|
||||
if: >
|
||||
github.repository_owner == 'webui-dev'
|
||||
&& (github.ref_type == 'tag' || (github.ref_name == 'main' && github.event_name == 'push'))
|
||||
run: |
|
||||
zip -r "$ARTIFACT.zip" "$ARTIFACT"
|
||||
if [ $GITHUB_REF_TYPE == tag ]; then
|
||||
echo "TAG=$GITHUB_REF_NAME" >> $GITHUB_ENV
|
||||
else
|
||||
{
|
||||
echo "IS_PRERELEASE=true";
|
||||
echo "TAG=nightly";
|
||||
echo "TITLE=WebUI Nightly Build $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
|
||||
echo "BODY=Generated from commit $GITHUB_SHA."
|
||||
} >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: Update Nightly Tag
|
||||
if: env.IS_PRERELEASE
|
||||
uses: richardsimko/update-tag@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: nightly
|
||||
|
||||
- name: Release
|
||||
if: >
|
||||
github.repository_owner == 'webui-dev'
|
||||
&& (github.ref_type == 'tag' || (github.ref_name == 'main' && github.event_name == 'push'))
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: ${{ env.ARTIFACT }}.zip
|
||||
tag: ${{ env.TAG }}
|
||||
body: ${{ env.BODY }}
|
||||
name: ${{ env.TITLE }}
|
||||
prerelease: ${{ env.IS_PRERELEASE }}
|
||||
allowUpdates: true
|
81
.github/workflows/macos.yml
vendored
81
.github/workflows/macos.yml
vendored
@ -1,8 +1,9 @@
|
||||
# http://webui.me
|
||||
# https://webui.me
|
||||
# https://github.com/webui-dev/webui
|
||||
# Copyright (c) 2020-2023 Hassan Draga.
|
||||
# Copyright (c) 2020-2025 Hassan Draga.
|
||||
# Licensed under MIT License.
|
||||
# All rights reserved.
|
||||
# Canada.
|
||||
#
|
||||
# Special Thanks to Turiiya (https://github.com/ttytm)
|
||||
|
||||
@ -14,13 +15,13 @@ jobs:
|
||||
setup:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Bundle WebUI Bridge
|
||||
run: |
|
||||
npm i -g esbuild
|
||||
chmod +x bridge/build.sh
|
||||
bridge/build.sh
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: bridge/webui_bridge.h
|
||||
key: ${{ runner.os }}-${{ github.sha }}-bridge
|
||||
@ -32,46 +33,76 @@ jobs:
|
||||
contents: write
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: [Clang]
|
||||
cc: [clang]
|
||||
arch: [x64, arm64]
|
||||
fail-fast: false
|
||||
env:
|
||||
ARTIFACT: webui-macos-${{ matrix.cc }}-${{ matrix.arch }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache/restore@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: bridge/webui_bridge.h
|
||||
key: ${{ runner.os }}-${{ github.sha }}-bridge
|
||||
fail-on-cache-miss: true
|
||||
- name: Setup OpenSSL
|
||||
run: |
|
||||
echo "WEBUI_TLS_INCLUDE=$(brew --cellar)/openssl@1.1/1.1.1w/include/" >> $GITHUB_ENV
|
||||
echo "WEBUI_TLS_LIB=$(brew --cellar)/openssl@1.1/1.1.1w/lib/" >> $GITHUB_ENV
|
||||
- name: Build Debug Target
|
||||
run: make ARCH_TARGET=${{ matrix.arch }} debug
|
||||
- name: Build Release Target
|
||||
if: ${{ !cancelled() }}
|
||||
run: make ARCH_TARGET=${{ matrix.arch }}
|
||||
- name: Build TLS Debug Target
|
||||
if: ${{ matrix.arch != 'x64' }}
|
||||
run: make ARCH_TARGET=${{ matrix.arch }} WEBUI_USE_TLS=1 debug
|
||||
- name: Build TLS Release Target
|
||||
if: ${{ matrix.arch != 'x64' }}
|
||||
run: make ARCH_TARGET=${{ matrix.arch }} WEBUI_USE_TLS=1
|
||||
- name: Build examples
|
||||
if: ${{ matrix.arch != 'x64' }}
|
||||
run: |
|
||||
examples_base_dir=$(pwd)/examples/C
|
||||
for example in $(find $examples_base_dir/* -maxdepth 0 -type d); do
|
||||
echo "> $example"
|
||||
cd $example || (exit_code=1 && continue)
|
||||
if ! make ARCH_TARGET=${{ matrix.arch }}; then
|
||||
echo "Failed to build '$example'"
|
||||
exit_code=1
|
||||
continue
|
||||
fi
|
||||
if [[ ! -e "main" || ! -e "main-dyn" ]] ; then
|
||||
echo "Failed to find executable for '$example'" && find .
|
||||
exit_code=1
|
||||
continue
|
||||
fi
|
||||
done
|
||||
exit $exit_code
|
||||
- name: Prepare Artifacts
|
||||
run: |
|
||||
cp -r include dist
|
||||
# Add the ARTIFACT name(lowercased) as GitHub environment variable.
|
||||
artifact=webui-$(echo ${{ runner.os }}-${{ matrix.compiler }}-${{ matrix.arch }} | tr '[:upper:]' '[:lower:]')
|
||||
chmod -x dist/webui-2.dylib
|
||||
chmod -x dist/debug/webui-2.dylib
|
||||
mv dist/ $artifact
|
||||
zip -r $artifact.zip $artifact
|
||||
# Add the artifact name as GitHub environment variable for usage in later steps.
|
||||
echo "ARTIFACT=$artifact" >> $GITHUB_ENV
|
||||
mv dist/ "$ARTIFACT"
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.ARTIFACT }}
|
||||
path: ${{ env.ARTIFACT }}.zip
|
||||
path: ${{ env.ARTIFACT }}
|
||||
- name: Prepare Release
|
||||
if: github.ref_type == 'tag' || (github.ref_name == 'main' && github.event_name == 'push')
|
||||
if: >
|
||||
github.repository_owner == 'webui-dev'
|
||||
&& (github.ref_type == 'tag' || (github.ref_name == 'main' && github.event_name == 'push'))
|
||||
run: |
|
||||
zip -r "$ARTIFACT.zip" "$ARTIFACT"
|
||||
if [ $GITHUB_REF_TYPE == tag ]; then
|
||||
echo "TAG=$GITHUB_REF_NAME" >> $GITHUB_ENV
|
||||
else
|
||||
echo "IS_PRERELEASE=true" >> $GITHUB_ENV
|
||||
now=$(date -u +'%Y-%m-%d %H:%M:%S UTC')
|
||||
echo "TAG=nightly" >> $GITHUB_ENV
|
||||
echo "BODY=Generated on <samp>$now</samp> from commit ${{ github.sha }}." >> $GITHUB_ENV
|
||||
echo "TITLE=WebUI Development Build" >> $GITHUB_ENV
|
||||
{
|
||||
echo "IS_PRERELEASE=true";
|
||||
echo "TAG=nightly";
|
||||
echo "TITLE=WebUI Nightly Build $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
|
||||
echo "BODY=Generated from commit $GITHUB_SHA."
|
||||
} >> $GITHUB_ENV
|
||||
fi
|
||||
- name: Update Nightly Tag
|
||||
if: env.IS_PRERELEASE
|
||||
@ -81,7 +112,9 @@ jobs:
|
||||
with:
|
||||
tag_name: nightly
|
||||
- name: Release
|
||||
if: github.ref_type == 'tag' || (github.ref_name == 'main' && github.event_name == 'push')
|
||||
if: >
|
||||
github.repository_owner == 'webui-dev'
|
||||
&& (github.ref_type == 'tag' || (github.ref_name == 'main' && github.event_name == 'push'))
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: ${{ env.ARTIFACT }}.zip
|
||||
|
102
.github/workflows/windows.yml
vendored
102
.github/workflows/windows.yml
vendored
@ -1,8 +1,9 @@
|
||||
# http://webui.me
|
||||
# https://webui.me
|
||||
# https://github.com/webui-dev/webui
|
||||
# Copyright (c) 2020-2023 Hassan Draga.
|
||||
# Copyright (c) 2020-2025 Hassan Draga.
|
||||
# Licensed under MIT License.
|
||||
# All rights reserved.
|
||||
# Canada.
|
||||
#
|
||||
# Special Thanks to Turiiya (https://github.com/ttytm)
|
||||
|
||||
@ -14,10 +15,10 @@ jobs:
|
||||
setup:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Bundle WebUI Bridge
|
||||
run: bridge/build.ps1
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: bridge/webui_bridge.h
|
||||
key: ${{ runner.os }}-${{ github.sha }}-bridge
|
||||
@ -29,62 +30,87 @@ jobs:
|
||||
contents: write
|
||||
strategy:
|
||||
matrix:
|
||||
compiler: [GCC, MSVC]
|
||||
cc: ['gcc', 'msvc']
|
||||
include:
|
||||
- cc: gcc
|
||||
make: mingw32-make
|
||||
- cc: msvc
|
||||
make: nmake
|
||||
fail-fast: false
|
||||
env:
|
||||
ARTIFACT: webui-windows-${{ matrix.cc }}-x64
|
||||
WEBUI_TLS_INCLUDE: "C:\\Program Files\\OpenSSL\\include"
|
||||
WEBUI_TLS_LIB: "C:\\Program Files\\OpenSSL\\lib"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/cache/restore@v3
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: bridge/webui_bridge.h
|
||||
key: ${{ runner.os }}-${{ github.sha }}-bridge
|
||||
fail-on-cache-miss: true
|
||||
- uses: microsoft/setup-msbuild@v1.1
|
||||
- if: matrix.compiler == 'MSVC'
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
- uses: microsoft/setup-msbuild@v2
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
if: matrix.cc == 'msvc'
|
||||
- name: Build Debug Target
|
||||
run: |
|
||||
if ('${{ matrix.compiler }}' -eq 'MSVC') {
|
||||
nmake debug
|
||||
} else {
|
||||
mingw32-make debug
|
||||
}
|
||||
run: ${{ matrix.make }} debug
|
||||
- name: Build Release Target
|
||||
if: ${{ !cancelled() }}
|
||||
run: ${{ matrix.make }}
|
||||
- name: Build TLS Debug Target
|
||||
run: ${{ matrix.make }} WEBUI_USE_TLS=1 debug
|
||||
- name: Build TLS Release Target
|
||||
run: ${{ matrix.make }} WEBUI_USE_TLS=1
|
||||
- name: Build examples
|
||||
run: |
|
||||
if ('${{ matrix.compiler }}' -eq 'MSVC') {
|
||||
nmake
|
||||
} else {
|
||||
mingw32-make
|
||||
$examples_base_dir = "$(Get-Location)/examples/C/"
|
||||
foreach ($example in Get-ChildItem -Path $examples_base_dir -Directory) {
|
||||
Write-Host "> $example"
|
||||
Set-Location -Path $example.FullName
|
||||
if (!$?) {
|
||||
$exit_code = 1
|
||||
continue
|
||||
}
|
||||
$make_output = Invoke-Expression ${{ matrix.make }}
|
||||
if (!$?) {
|
||||
Write-Host "Failed to build '$example': $make_output"
|
||||
$exit_code = 1
|
||||
continue
|
||||
}
|
||||
Write-Output $make_output
|
||||
if (!(Test-Path "main.exe") -or !(Test-Path "main-dyn.exe")) {
|
||||
Write-Host "Failed to find executable for '$example'"
|
||||
Get-ChildItem
|
||||
$exit_code = 1
|
||||
continue
|
||||
}
|
||||
}
|
||||
exit $exit_code
|
||||
- name: Prepare Artifact
|
||||
shell: bash
|
||||
run: |
|
||||
cp -r include dist
|
||||
artifact=webui-${{ runner.os }}-${{ matrix.compiler }}-x64
|
||||
# Convert to lowercase (`,,` ^= lowercase shell param)
|
||||
artifact=${artifact,,}
|
||||
# Create the directory for the artifact
|
||||
mkdir $artifact
|
||||
# Add the ARTIFACT name as GitHub environment variable.
|
||||
echo "ARTIFACT=$artifact" >> $GITHUB_ENV
|
||||
mv dist/* $artifact/
|
||||
mv dist/ "$ARTIFACT"
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.ARTIFACT }}
|
||||
path: ${{ env.ARTIFACT }}
|
||||
- name: Prepare Release
|
||||
if: github.ref_type == 'tag' || (github.ref_name == 'main' && github.event_name == 'push')
|
||||
if: >
|
||||
github.repository_owner == 'webui-dev'
|
||||
&& (github.ref_type == 'tag' || (github.ref_name == 'main' && github.event_name == 'push'))
|
||||
shell: bash
|
||||
run: |
|
||||
7z a -tzip ${{ env.ARTIFACT }}.zip ${{ env.ARTIFACT }}/*
|
||||
7z a -tzip "$ARTIFACT.zip" "$ARTIFACT/*"
|
||||
if [ $GITHUB_REF_TYPE == tag ]; then
|
||||
echo "TAG=$GITHUB_REF_NAME" >> $GITHUB_ENV
|
||||
else
|
||||
echo "IS_PRERELEASE=true" >> $GITHUB_ENV
|
||||
now=$(date -u +'%Y-%m-%d %H:%M:%S UTC')
|
||||
echo "TAG=nightly" >> $GITHUB_ENV
|
||||
echo "BODY=Generated on <samp>$now</samp> from commit ${{ github.sha }}." >> $GITHUB_ENV
|
||||
echo "TITLE=WebUI Development Build" >> $GITHUB_ENV
|
||||
{
|
||||
echo "IS_PRERELEASE=true";
|
||||
echo "TAG=nightly";
|
||||
echo "TITLE=WebUI Nightly Build $(date -u +'%Y-%m-%d %H:%M:%S UTC')"
|
||||
echo "BODY=Generated from commit $GITHUB_SHA."
|
||||
} >> $GITHUB_ENV
|
||||
fi
|
||||
- name: Update Nightly Tag
|
||||
if: env.IS_PRERELEASE
|
||||
@ -94,7 +120,9 @@ jobs:
|
||||
with:
|
||||
tag_name: nightly
|
||||
- name: Release
|
||||
if: github.ref_type == 'tag' || (github.ref_name == 'main' && github.event_name == 'push')
|
||||
if: >
|
||||
github.repository_owner == 'webui-dev'
|
||||
&& (github.ref_type == 'tag' || (github.ref_name == 'main' && github.event_name == 'push'))
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: ${{ env.ARTIFACT }}.zip
|
||||
|
36
.github/workflows/zig.yml
vendored
Normal file
36
.github/workflows/zig.yml
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
name: Zig Build
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
version: [0.14.0, '']
|
||||
fail-fast: false
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: maxim-lobanov/setup-xcode@v1
|
||||
if: runner.os == 'macOS'
|
||||
with:
|
||||
xcode-version: latest-stable
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Zig
|
||||
uses: goto-bus-stop/setup-zig@v2
|
||||
with:
|
||||
version: ${{ matrix.version }}
|
||||
- name: Build static library
|
||||
run: zig build -Dverbose=debug
|
||||
- name: Build dynamic library
|
||||
if: ${{ !cancelled() }}
|
||||
run: zig build -Ddynamic -Dverbose=debug
|
||||
- name: Build static library with TLS support
|
||||
if: runner.os == 'Linux'
|
||||
run: zig build -Denable-tls -Dverbose=debug
|
||||
- name: Build dynamic library with TLS support
|
||||
if: runner.os == 'Linux'
|
||||
run: zig build -Ddynamic -Denable-tls -Dverbose=debug
|
||||
- name: Build examples
|
||||
run: zig build examples
|
20
.gitignore
vendored
20
.gitignore
vendored
@ -8,6 +8,14 @@ build/
|
||||
*.out
|
||||
*.def
|
||||
|
||||
# All sub-level build binaries
|
||||
*/**/*
|
||||
!*/**/*/
|
||||
!*/**/*.*
|
||||
!*makefile
|
||||
!Makefile
|
||||
*/**/*.exe
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
@ -40,6 +48,7 @@ build/
|
||||
*.recipe
|
||||
*.idb
|
||||
*.iobj
|
||||
*.pdb
|
||||
|
||||
# Visual Studio for Mac
|
||||
.idea/
|
||||
@ -108,11 +117,12 @@ Thumbs.db
|
||||
# User-specific private settings
|
||||
*.DotSettings.user
|
||||
|
||||
# Example binaries
|
||||
examples/**/main
|
||||
examples/**/main-dyn
|
||||
examples/**/text-editor/text-editor
|
||||
|
||||
# Compressed
|
||||
*.zip
|
||||
*.gz
|
||||
|
||||
# CMake
|
||||
**/cmake_install.cmake
|
||||
**/CMakeCache.txt
|
||||
**/CMakeFiles/
|
||||
.zig-cache
|
||||
|
59
CMakeLists.txt
Normal file
59
CMakeLists.txt
Normal file
@ -0,0 +1,59 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
# Project name
|
||||
project(WebUILibrary)
|
||||
|
||||
# Set C++ standard
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# Variables for library names, source files, etc.
|
||||
set(WEBUI_OUT_LIB_NAME "webui-2")
|
||||
|
||||
# Conditional compilation for TLS
|
||||
option(WEBUI_USE_TLS "Enable TLS support" OFF)
|
||||
if(WEBUI_USE_TLS)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
set(WEBUI_OUT_LIB_NAME "webui-2-secure")
|
||||
endif()
|
||||
|
||||
# Source files (already filled)
|
||||
set(SOURCE_FILES
|
||||
src/civetweb/civetweb.c
|
||||
src/webui.c
|
||||
)
|
||||
|
||||
# Library targets
|
||||
add_library(webui ${SOURCE_FILES})
|
||||
target_include_directories(webui PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include>)
|
||||
target_compile_definitions(webui PUBLIC NDEBUG NO_CACHING NO_CGI USE_WEBSOCKET)
|
||||
|
||||
if(BUILD_SHARED_LIBS AND WIN32)
|
||||
target_compile_definitions(webui PRIVATE CIVETWEB_DLL_EXPORTS PUBLIC CIVETWEB_DLL_IMPORTS)
|
||||
endif()
|
||||
|
||||
if(WEBUI_USE_TLS)
|
||||
target_compile_definitions(webui PUBLIC WEBUI_TLS NO_SSL_DL OPENSSL_API_1_1)
|
||||
target_link_libraries(webui PRIVATE OpenSSL::SSL OpenSSL::Crypto)
|
||||
else()
|
||||
target_compile_definitions(webui PUBLIC NO_SSL)
|
||||
endif()
|
||||
|
||||
set_target_properties(webui PROPERTIES
|
||||
OUTPUT_NAME ${WEBUI_OUT_LIB_NAME}
|
||||
PREFIX "")
|
||||
|
||||
# Install headers
|
||||
install(FILES include/webui.h include/webui.hpp DESTINATION include)
|
||||
|
||||
# Install targets
|
||||
install(TARGETS webui
|
||||
EXPORT webui
|
||||
ARCHIVE DESTINATION lib
|
||||
LIBRARY DESTINATION lib)
|
||||
|
||||
install(EXPORT webui
|
||||
FILE webui-config.cmake
|
||||
NAMESPACE webui::
|
||||
DESTINATION share/webui
|
||||
)
|
89
GNUmakefile
89
GNUmakefile
@ -4,16 +4,23 @@
|
||||
|
||||
WEBUI_OUT_LIB_NAME = webui-2
|
||||
|
||||
# Detect the OS once
|
||||
ifeq ($(OS),Windows_NT)
|
||||
DETECTED_OS := Windows
|
||||
else
|
||||
DETECTED_OS := $(shell uname -s)
|
||||
endif
|
||||
|
||||
# TLS
|
||||
WEBUI_USE_TLS =
|
||||
WEBUI_TLS_INCLUDE = .
|
||||
WEBUI_TLS_LIB = .
|
||||
WEBUI_TLS_INCLUDE ?= .
|
||||
WEBUI_TLS_LIB ?= .
|
||||
TLS_CFLAG = -DNO_SSL
|
||||
TLS_LDFLAG_DYNAMIC =
|
||||
ifeq ($(WEBUI_USE_TLS), 1)
|
||||
WEBUI_OUT_LIB_NAME = webui-2-secure
|
||||
TLS_CFLAG = -DWEBUI_TLS -DNO_SSL_DL -DOPENSSL_API_1_1
|
||||
ifeq ($(OS),Windows_NT)
|
||||
ifeq ($(DETECTED_OS),Windows)
|
||||
TLS_LDFLAG_DYNAMIC = -lssl -lcrypto -lbcrypt
|
||||
else
|
||||
TLS_LDFLAG_DYNAMIC = -lssl -lcrypto
|
||||
@ -25,10 +32,13 @@ MAKEFILE_DIR := $(dir $(MAKEFILE_PATH))
|
||||
BUILD_DIR := $(MAKEFILE_DIR)/dist
|
||||
|
||||
# ARGS
|
||||
# Set a compiler when running on Linux via `make CC=gcc` / `make CC=clang`
|
||||
CC = gcc
|
||||
ifneq ($(filter $(CC),gcc clang aarch64-linux-gnu-gcc arm-linux-gnueabihf-gcc musl-gcc),$(CC))
|
||||
$(error Invalid compiler specified: `$(CC)`)
|
||||
CC ?= gcc
|
||||
ifeq ($(CC), cc)
|
||||
ifeq ($(DETECTED_OS),Darwin)
|
||||
CC = clang
|
||||
else
|
||||
CC = gcc
|
||||
endif
|
||||
endif
|
||||
|
||||
# Allow to add arch-target for macOS CI cross compilation
|
||||
@ -37,7 +47,9 @@ ARCH_TARGET ?=
|
||||
# BUILD FLAGS
|
||||
CIVETWEB_BUILD_FLAGS := -o civetweb.o -I"$(MAKEFILE_DIR)/include/" -c "$(MAKEFILE_DIR)/src/civetweb/civetweb.c" -I"$(WEBUI_TLS_INCLUDE)" $(TLS_CFLAG) -w
|
||||
CIVETWEB_DEFINE_FLAGS = -DNDEBUG -DNO_CACHING -DNO_CGI -DUSE_WEBSOCKET $(TLS_CFLAG)
|
||||
WEBUI_BUILD_FLAGS := -o webui.o -I"$(MAKEFILE_DIR)/include/" -c "$(MAKEFILE_DIR)/src/webui.c" -I"$(WEBUI_TLS_INCLUDE)" $(TLS_CFLAG) -w
|
||||
WEBUI_BUILD_FLAGS := -o webui.o -I"$(MAKEFILE_DIR)/include/" -c "$(MAKEFILE_DIR)/src/webui.c" -I"$(WEBUI_TLS_INCLUDE)" $(TLS_CFLAG)
|
||||
WARNING_RELEASE := -w
|
||||
WARNING_LOG := -Wall -Wno-unused
|
||||
|
||||
# OUTPUT FILES
|
||||
# The static output is the same for all platforms
|
||||
@ -45,32 +57,41 @@ WEBUI_BUILD_FLAGS := -o webui.o -I"$(MAKEFILE_DIR)/include/" -c "$(MAKEFILE_DIR)
|
||||
LIB_STATIC_OUT := lib$(WEBUI_OUT_LIB_NAME)-static.a
|
||||
|
||||
# Platform defaults and dynamic library outputs
|
||||
ifeq ($(OS),Windows_NT)
|
||||
ifeq ($(DETECTED_OS),Windows)
|
||||
# Windows
|
||||
SHELL := CMD
|
||||
PLATFORM := windows
|
||||
LIB_DYN_OUT := $(WEBUI_OUT_LIB_NAME).dll
|
||||
LWS2_OPT := -lws2_32
|
||||
LWS2_OPT := -lws2_32 -lole32
|
||||
CIVETWEB_DEFINE_FLAGS += -DMUST_IMPLEMENT_CLOCK_GETTIME
|
||||
else ifeq ($(shell uname),Darwin)
|
||||
else ifeq ($(DETECTED_OS),Darwin)
|
||||
# MacOS
|
||||
PLATFORM := macos
|
||||
CC = clang
|
||||
LIB_DYN_OUT := $(WEBUI_OUT_LIB_NAME).dylib
|
||||
LIB_DYN_OUT := lib$(WEBUI_OUT_LIB_NAME).dylib
|
||||
WEBKIT_OBJ := wkwebview.o
|
||||
WKWEBKIT_BUILD_FLAGS := -o wkwebview.o -c "$(MAKEFILE_DIR)/src/webview/wkwebview.m"
|
||||
WKWEBKIT_LINK_FLAGS := -framework Cocoa -framework WebKit
|
||||
else
|
||||
# Linux
|
||||
PLATFORM := linux
|
||||
LIB_DYN_OUT := $(WEBUI_OUT_LIB_NAME).so
|
||||
LIB_DYN_OUT := lib$(WEBUI_OUT_LIB_NAME).so
|
||||
ifeq ($(CC),clang)
|
||||
LLVM_OPT := llvm-
|
||||
endif
|
||||
endif
|
||||
# macOS can set `ARCH_TARGET=arm64` - intented for CI cross-compilation.
|
||||
|
||||
# macOS can set `ARCH_TARGET=arm64` for cross-compilation.
|
||||
ifneq ($(ARCH_TARGET),)
|
||||
ifneq ($(PLATFORM),macos)
|
||||
$(error ARCH_TARGET is only available on macOS)
|
||||
else ifeq ($(ARCH_TARGET),arm64)
|
||||
TARGET := -target arm64-apple-darwin
|
||||
endif
|
||||
ifeq ($(ARCH_TARGET),arm64)
|
||||
TARGET := -target arm64-apple-darwin -arch arm64
|
||||
else ifeq ($(ARCH_TARGET),x64)
|
||||
TARGET := -target x86_64-apple-darwin -arch x86_64
|
||||
else
|
||||
$(error Unsupported ARCH_TARGET: $(ARCH_TARGET). Use 'arm64' or 'x64'.)
|
||||
endif
|
||||
endif
|
||||
|
||||
@ -93,19 +114,25 @@ ifeq ($(PLATFORM),windows)
|
||||
else
|
||||
@mkdir -p "$(BUILD_DIR)/debug"
|
||||
endif
|
||||
# Build macOS WKWebView
|
||||
ifeq ($(DETECTED_OS),Darwin)
|
||||
@cd "$(BUILD_DIR)/debug" \
|
||||
&& echo "Build WebUI Objective-C WKWebKit ($(CC) $(TARGET) debug)..." \
|
||||
&& $(CC) $(TARGET) $(WKWEBKIT_BUILD_FLAGS) -g -DWEBUI_LOG
|
||||
endif
|
||||
# Static with Debug info
|
||||
@cd "$(BUILD_DIR)/debug" \
|
||||
&& echo "Build WebUI library ($(CC) $(TARGET)debug static)..." \
|
||||
&& echo "Build WebUI library ($(CC) $(TARGET) debug static)..." \
|
||||
&& $(CC) $(TARGET) $(CIVETWEB_BUILD_FLAGS) $(CIVETWEB_DEFINE_FLAGS) -g \
|
||||
&& $(CC) $(TARGET) $(WEBUI_BUILD_FLAGS) -g -DWEBUI_LOG \
|
||||
&& $(LLVM_OPT)ar rc $(LIB_STATIC_OUT) webui.o civetweb.o \
|
||||
&& $(CC) $(TARGET) $(WEBUI_BUILD_FLAGS) $(WARNING_LOG) -g -DWEBUI_LOG \
|
||||
&& $(LLVM_OPT)ar rc $(LIB_STATIC_OUT) webui.o civetweb.o $(WEBKIT_OBJ) \
|
||||
&& $(LLVM_OPT)ranlib $(LIB_STATIC_OUT)
|
||||
# Dynamic with Debug info
|
||||
@cd "$(BUILD_DIR)/debug" \
|
||||
&& echo "Build WebUI library ($(CC) $(TARGET)debug dynamic)..." \
|
||||
&& echo "Build WebUI library ($(CC) $(TARGET) debug dynamic)..." \
|
||||
&& $(CC) $(TARGET) $(CIVETWEB_BUILD_FLAGS) $(CIVETWEB_DEFINE_FLAGS) -g -fPIC \
|
||||
&& $(CC) $(TARGET) $(WEBUI_BUILD_FLAGS) -g -fPIC -DWEBUI_LOG \
|
||||
&& $(CC) $(TARGET) -shared -o $(LIB_DYN_OUT) webui.o civetweb.o -g -L"$(WEBUI_TLS_LIB)" $(TLS_LDFLAG_DYNAMIC) $(LWS2_OPT)
|
||||
&& $(CC) $(TARGET) $(WEBUI_BUILD_FLAGS) $(WARNING_LOG) -g -fPIC -DWEBUI_LOG -DWEBUI_DYNAMIC \
|
||||
&& $(CC) $(TARGET) -shared -o $(LIB_DYN_OUT) webui.o civetweb.o $(WEBKIT_OBJ) -g -L"$(WEBUI_TLS_LIB)" $(TLS_LDFLAG_DYNAMIC) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS)
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@cd "$(BUILD_DIR)/debug" && del *.o >nul 2>&1
|
||||
else
|
||||
@ -120,19 +147,25 @@ ifeq ($(PLATFORM),windows)
|
||||
else
|
||||
@mkdir -p "$(BUILD_DIR)"
|
||||
endif
|
||||
# Build macOS WKWebView
|
||||
ifeq ($(DETECTED_OS),Darwin)
|
||||
@cd "$(BUILD_DIR)" \
|
||||
&& echo "Build WebUI Objective-C WKWebKit ($(CC) $(TARGET) release)..." \
|
||||
&& $(CC) $(TARGET) $(WKWEBKIT_BUILD_FLAGS) -Os
|
||||
endif
|
||||
# Static Release
|
||||
@cd "$(BUILD_DIR)" \
|
||||
&& echo "Build WebUI library ($(CC) $(TARGET)release static)..." \
|
||||
&& echo "Build WebUI library ($(CC) $(TARGET) release static)..." \
|
||||
&& $(CC) $(TARGET) $(CIVETWEB_BUILD_FLAGS) $(CIVETWEB_DEFINE_FLAGS) -Os \
|
||||
&& $(CC) $(TARGET) $(WEBUI_BUILD_FLAGS) -Os \
|
||||
&& $(LLVM_OPT)ar rc $(LIB_STATIC_OUT) webui.o civetweb.o \
|
||||
&& $(CC) $(TARGET) $(WEBUI_BUILD_FLAGS) $(WARNING_RELEASE) -Os \
|
||||
&& $(LLVM_OPT)ar rc $(LIB_STATIC_OUT) webui.o civetweb.o $(WEBKIT_OBJ) \
|
||||
&& $(LLVM_OPT)ranlib $(LIB_STATIC_OUT)
|
||||
# Dynamic Release
|
||||
@cd "$(BUILD_DIR)" \
|
||||
&& echo "Build WebUI library ($(CC) $(TARGET)release dynamic)..." \
|
||||
&& echo "Build WebUI library ($(CC) $(TARGET) release dynamic)..." \
|
||||
&& $(CC) $(TARGET) $(CIVETWEB_BUILD_FLAGS) $(CIVETWEB_DEFINE_FLAGS) -Os -fPIC \
|
||||
&& $(CC) $(TARGET) $(WEBUI_BUILD_FLAGS) -O3 -fPIC \
|
||||
&& $(CC) $(TARGET) -shared -o $(LIB_DYN_OUT) webui.o civetweb.o -L"$(WEBUI_TLS_LIB)" $(TLS_LDFLAG_DYNAMIC) $(LWS2_OPT)
|
||||
&& $(CC) $(TARGET) $(WEBUI_BUILD_FLAGS) $(WARNING_RELEASE) -O3 -fPIC -DWEBUI_DYNAMIC \
|
||||
&& $(CC) $(TARGET) -shared -o $(LIB_DYN_OUT) webui.o civetweb.o $(WEBKIT_OBJ) -L"$(WEBUI_TLS_LIB)" $(TLS_LDFLAG_DYNAMIC) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@strip --strip-unneeded $(BUILD_DIR)/$(LIB_DYN_OUT)
|
||||
|
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Hassan Draga
|
||||
Copyright (c) 2025 Hassan Draga
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
44
Makefile
44
Makefile
@ -4,27 +4,39 @@
|
||||
# == 1. VARIABLES =============================================================
|
||||
|
||||
WEBUI_OUT_LIB_NAME = webui-2
|
||||
TLS_CFLAG = /DNO_SSL
|
||||
|
||||
# TLS
|
||||
WEBUI_USE_TLS =
|
||||
WEBUI_TLS_INCLUDE = .
|
||||
WEBUI_TLS_LIB = .
|
||||
TLS_CFLAG = /D NO_SSL
|
||||
TLS_LDFLAG_DYNAMIC =
|
||||
# TLS Enabled
|
||||
!IF "$(WEBUI_USE_TLS)" == "1"
|
||||
|
||||
WEBUI_OUT_LIB_NAME = webui-2-secure
|
||||
TLS_CFLAG = /D WEBUI_TLS /D NO_SSL_DL /D OPENSSL_API_1_1
|
||||
TLS_CFLAG = /DWEBUI_TLS /DNO_SSL_DL /DOPENSSL_API_1_1
|
||||
TLS_LDFLAG_DYNAMIC = libssl.lib libcrypto.lib
|
||||
|
||||
!IF "$(WEBUI_TLS_INCLUDE)" != ""
|
||||
TLS_CFLAG = $(TLS_CFLAG) /I"$(WEBUI_TLS_INCLUDE)"
|
||||
!ELSE
|
||||
TLS_CFLAG = $(TLS_CFLAG) /I"."
|
||||
!ENDIF
|
||||
|
||||
!IF "$(WEBUI_TLS_LIB)" != ""
|
||||
TLS_LDFLAG_DYNAMIC = $(TLS_LDFLAG_DYNAMIC) /LIBPATH:"$(WEBUI_TLS_LIB)"
|
||||
!ELSE
|
||||
TLS_LDFLAG_DYNAMIC += $(TLS_LDFLAG_DYNAMIC) /LIBPATH:"."
|
||||
!ENDIF
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Build Flags
|
||||
CIVETWEB_BUILD_FLAGS = /Fo"civetweb.obj" /c /EHsc "$(MAKEDIR)/src/civetweb/civetweb.c" /I"$(MAKEDIR)/src/civetweb/" /I"$(WEBUI_TLS_INCLUDE)"
|
||||
CIVETWEB_DEFINE_FLAGS = /D NDEBUG /D NO_CACHING /D NO_CGI /D USE_WEBSOCKET $(TLS_CFLAG)
|
||||
CIVETWEB_BUILD_FLAGS = /Fo"civetweb.obj" /c /EHsc "$(MAKEDIR)/src/civetweb/civetweb.c" /I"$(MAKEDIR)/src/civetweb/" $(TLS_CFLAG)
|
||||
CIVETWEB_DEFINE_FLAGS = /D NDEBUG /D NO_CACHING /D NO_CGI /D USE_WEBSOCKET
|
||||
WEBUI_BUILD_FLAGS = /Fo"webui.obj" /c /EHsc "$(MAKEDIR)/src/webui.c" /I"$(MAKEDIR)/include" /I"$(WEBUI_TLS_INCLUDE)" $(TLS_CFLAG)
|
||||
WARNING_RELEASE = /w
|
||||
WARNING_LOG = /W4
|
||||
|
||||
# Output Commands
|
||||
LIB_STATIC_OUT = /OUT:"$(WEBUI_OUT_LIB_NAME)-static.lib" "webui.obj" "civetweb.obj"
|
||||
LIB_DYN_OUT = /DLL /OUT:"$(WEBUI_OUT_LIB_NAME).dll" "webui.obj" "civetweb.obj" user32.lib Advapi32.lib Shell32.lib /LIBPATH:"$(WEBUI_TLS_LIB)" $(TLS_LDFLAG_DYNAMIC)
|
||||
LIB_DYN_OUT = /DLL /OUT:"$(WEBUI_OUT_LIB_NAME).dll" "webui.obj" "civetweb.obj" user32.lib Advapi32.lib Shell32.lib Ole32.lib $(TLS_LDFLAG_DYNAMIC)
|
||||
|
||||
# == 2.TARGETS ================================================================
|
||||
|
||||
@ -36,18 +48,16 @@ debug:
|
||||
@- cd $(MAKEDIR)/dist/debug
|
||||
@echo Build WebUI Library (MSVC Debug Static)...
|
||||
@cl /Zl /Zi $(CIVETWEB_BUILD_FLAGS) $(CIVETWEB_DEFINE_FLAGS)
|
||||
@cl /Zl /Zi $(WEBUI_BUILD_FLAGS) /D WEBUI_LOG
|
||||
@cl /Zl /Zi $(WEBUI_BUILD_FLAGS) $(WARNING_LOG) /D WEBUI_LOG
|
||||
@lib $(LIB_STATIC_OUT)
|
||||
# Dynamic with Debug info
|
||||
@echo Build WebUI Library (MSVC Debug Dynamic)...
|
||||
@cl /Zi $(CIVETWEB_BUILD_FLAGS) $(CIVETWEB_DEFINE_FLAGS)
|
||||
@cl /Zi $(WEBUI_BUILD_FLAGS) /D WEBUI_LOG
|
||||
@cl /Zi $(WEBUI_BUILD_FLAGS) $(WARNING_LOG) /D WEBUI_LOG /D WEBUI_DYNAMIC
|
||||
@link $(LIB_DYN_OUT)
|
||||
# Clean
|
||||
@- del *.pdb >nul 2>&1
|
||||
@- del *.obj >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@- del *.pdb >nul 2>&1
|
||||
@- del *.exp >nul 2>&1
|
||||
@echo Done.
|
||||
|
||||
@ -57,18 +67,17 @@ release:
|
||||
# Static Release
|
||||
@echo Build WebUI Library (MSVC Release Static)...
|
||||
@cl /Zl $(CIVETWEB_BUILD_FLAGS) $(CIVETWEB_DEFINE_FLAGS)
|
||||
@cl /Zl $(WEBUI_BUILD_FLAGS)
|
||||
@cl /Zl $(WEBUI_BUILD_FLAGS) $(WARNING_RELEASE)
|
||||
@lib $(LIB_STATIC_OUT)
|
||||
# Dynamic Release
|
||||
@echo Build WebUI Library (MSVC Release Dynamic)...
|
||||
@cl $(CIVETWEB_BUILD_FLAGS) $(CIVETWEB_DEFINE_FLAGS)
|
||||
@cl $(WEBUI_BUILD_FLAGS)
|
||||
@cl $(WEBUI_BUILD_FLAGS) $(WARNING_RELEASE) /D WEBUI_DYNAMIC
|
||||
@link $(LIB_DYN_OUT)
|
||||
# Clean
|
||||
@- del *.pdb >nul 2>&1
|
||||
@- del *.obj >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@- del *.pdb >nul 2>&1
|
||||
@- del *.exp >nul 2>&1
|
||||
@- echo Done.
|
||||
|
||||
@ -77,7 +86,6 @@ clean:
|
||||
@- del *.pdb >nul 2>&1
|
||||
@- del *.obj >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@- del *.pdb >nul 2>&1
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.dll >nul 2>&1
|
||||
@- del *.lib >nul 2>&1
|
||||
|
230
README.md
230
README.md
@ -1,8 +1,8 @@
|
||||
<div align="center">
|
||||
|
||||

|
||||

|
||||
|
||||
# WebUI v2.4.1
|
||||
# WebUI v2.5.0-beta.4
|
||||
|
||||
[build-status]: https://img.shields.io/github/actions/workflow/status/webui-dev/webui/ci.yml?branch=main&style=for-the-badge&logo=githubactions&labelColor=414868&logoColor=C0CAF5
|
||||
[last-commit]: https://img.shields.io/github/last-commit/webui-dev/webui?style=for-the-badge&logo=github&logoColor=C0CAF5&labelColor=414868
|
||||
@ -14,9 +14,9 @@
|
||||
[![][release-version]](https://github.com/webui-dev/webui/releases/latest)
|
||||
[![][license]](https://github.com/webui-dev/webui/blob/main/LICENSE)
|
||||
|
||||
> WebUI is not a web-server solution or a framework, but it allows you to use any web browser as a GUI, with your preferred language in the backend and HTML5 in the frontend. All in a lightweight portable lib.
|
||||
> Use any web browser or WebView as GUI, with your preferred language in the backend and modern web technologies in the frontend, all in a lightweight portable library.
|
||||
|
||||

|
||||

|
||||
|
||||
</div>
|
||||
|
||||
@ -39,32 +39,18 @@
|
||||
|
||||
## Features
|
||||
|
||||
- Written in Pure C
|
||||
- Fully Independent (_No need for any third-party runtimes_)
|
||||
- Lightweight ~200 Kb & Small memory footprint
|
||||
- Fast binary communication protocol between WebUI and the browser (_Instead of JSON_)
|
||||
- Portable (*Needs only a web browser or a WebView at runtime*)
|
||||
- One header file
|
||||
- Lightweight (*Few Kb library*) & Small memory footprint
|
||||
- Fast binary communication protocol
|
||||
- Multi-platform & Multi-Browser
|
||||
- Using private profile for safety
|
||||
|
||||
## Showcase
|
||||
|
||||
This [text editor](https://github.com/webui-dev/webui/tree/main/examples/C/text-editor) is a lightweight and portable example written in C using WebUI as the GUI library.
|
||||
|
||||
<div align="center">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
- Cross-platform WebView
|
||||
|
||||
## UI & The Web Technologies
|
||||
|
||||
[Borislav Stanimirov](https://ibob.bg/) discusses using HTML5 in the web browser as GUI at the [C++ Conference 2019 (_YouTube_)](https://www.youtube.com/watch?v=bbbcZd4cuxg).
|
||||
|
||||
<!-- <div align="center">
|
||||
<a href="https://www.youtube.com/watch?v=bbbcZd4cuxg"><img src="https://img.youtube.com/vi/bbbcZd4cuxg/0.jpg" alt="Embrace Modern Technology: Using HTML 5 for GUI in C++ - Borislav Stanimirov - CppCon 2019"></a>
|
||||
</div> -->
|
||||
|
||||
<div align="center">
|
||||
|
||||

|
||||
@ -89,7 +75,7 @@ Think of WebUI like a WebView controller, but instead of embedding the WebView c
|
||||
|
||||
### Runtime Dependencies Comparison
|
||||
|
||||
| | WebView | Qt | WebUI |
|
||||
| | Tauri / WebView | Qt | WebUI |
|
||||
| ------------------------------- | ----------------- | -------------------------- | ------------------- |
|
||||
| Runtime Dependencies on Windows | _WebView2_ | _QtCore, QtGui, QtWidgets_ | **_A Web Browser_** |
|
||||
| Runtime Dependencies on Linux | _GTK3, WebKitGTK_ | _QtCore, QtGui, QtWidgets_ | **_A Web Browser_** |
|
||||
@ -100,27 +86,24 @@ Think of WebUI like a WebView controller, but instead of embedding the WebView c
|
||||
> **Note**
|
||||
> We are currently writing documentation.
|
||||
|
||||
- [Online Documentation - C](https://webui.me/docs/#/c_api)
|
||||
- [Online Documentation - C++](https://webui.me/docs/#/cpp_api)
|
||||
- [Online Documentation](https://webui.me/docs/)
|
||||
|
||||
## Build
|
||||
## Build WebUI Library
|
||||
|
||||
- **Windows**
|
||||
### Windows
|
||||
|
||||
```powershell
|
||||
# GCC
|
||||
mingw32-make
|
||||
|
||||
# MSVC
|
||||
nmake
|
||||
```
|
||||
|
||||
**Windows SSL/TLS (_Optional_)**
|
||||
| Compiler | Command |
|
||||
|----------|---------|
|
||||
| GCC | `mingw32-make` |
|
||||
| MSVC | `nmake` |
|
||||
|
||||
<details>
|
||||
<summary><strong>Windows SSL/TLS (Optional)</strong></summary>
|
||||
|
||||
Download and install the OpenSSL pre-compiled binaries for Windows:
|
||||
|
||||
- MSVC: [x64 OpenSSL v3.1.3](https://slproweb.com/download/Win64OpenSSL-3_1_3.msi) or [_32Bit_](https://slproweb.com/download/Win32OpenSSL-3_1_3.msi). Please check this [Wiki list](https://wiki.openssl.org/index.php/Binaries) for more info.
|
||||
- MinGW: [Curl for Windows win OpenSSL](https://curl.se/windows/)
|
||||
- **MSVC**: [x64 OpenSSL v3.3.1](https://slproweb.com/download/Win64OpenSSL-3_3_1.msi) or [_32Bit_](https://slproweb.com/download/Win32OpenSSL-3_3_1.msi). See the [Wiki list](https://wiki.openssl.org/index.php/Binaries) for more info.
|
||||
- **MinGW**: [Curl for Windows with OpenSSL](https://curl.se/windows/)
|
||||
|
||||
```powershell
|
||||
# GCC
|
||||
@ -129,19 +112,18 @@ Think of WebUI like a WebView controller, but instead of embedding the WebView c
|
||||
# MSVC
|
||||
nmake WEBUI_USE_TLS=1 WEBUI_TLS_INCLUDE="C:\Program Files\OpenSSL-xxx\include" WEBUI_TLS_LIB="C:\Program Files\OpenSSL-xxx\lib"
|
||||
```
|
||||
</details>
|
||||
|
||||
- **Linux**
|
||||
### Linux
|
||||
|
||||
```sh
|
||||
# GCC
|
||||
make
|
||||
|
||||
# Clang
|
||||
make CC=clang
|
||||
```
|
||||
|
||||
**Linux SSL/TLS (_Optional_)**
|
||||
| Compiler | Command |
|
||||
|----------|---------|
|
||||
| GCC | `make` |
|
||||
| Clang | `make CC=clang` |
|
||||
|
||||
<details>
|
||||
<summary><strong>Linux SSL/TLS (Optional)</strong></summary>
|
||||
|
||||
```sh
|
||||
sudo apt update
|
||||
sudo apt install libssl-dev
|
||||
@ -152,38 +134,142 @@ Think of WebUI like a WebView controller, but instead of embedding the WebView c
|
||||
# Clang
|
||||
make WEBUI_USE_TLS=1 CC=clang
|
||||
```
|
||||
</details>
|
||||
|
||||
- **macOS**
|
||||
### macOS
|
||||
|
||||
```sh
|
||||
make
|
||||
```
|
||||
|
||||
**macOS SSL/TLS (_Optional_)**
|
||||
| Compiler | Command |
|
||||
|----------|---------|
|
||||
| Default | `make` |
|
||||
|
||||
<details>
|
||||
<summary><strong>macOS SSL/TLS (Optional)</strong></summary>
|
||||
|
||||
```sh
|
||||
brew install openssl
|
||||
make WEBUI_USE_TLS=1
|
||||
```
|
||||
</details>
|
||||
|
||||
## Examples
|
||||
## Minimal WebUI Application
|
||||
|
||||
- [C](https://github.com/webui-dev/webui/tree/main/examples/C)
|
||||
- [C++](https://github.com/webui-dev/webui/tree/main/examples/C++)
|
||||
- **C**
|
||||
|
||||
```c
|
||||
#include "webui.h"
|
||||
|
||||
int main() {
|
||||
size_t my_window = webui_new_window();
|
||||
webui_show(my_window, "<html><head><script src=\"webui.js\"></script></head> Hello World ! </html>");
|
||||
webui_wait();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
- **C++**
|
||||
|
||||
```cpp
|
||||
#include "webui.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
webui::window my_window;
|
||||
my_window.show("<html><head><script src=\"webui.js\"></script></head> C++ Hello World ! </html>");
|
||||
webui::wait();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
- **More C/C++ Examples**
|
||||
|
||||
- [C](https://github.com/webui-dev/webui/tree/main/examples/C)
|
||||
- [C++](https://github.com/webui-dev/webui/tree/main/examples/C++)
|
||||
|
||||
- **Other Languages**
|
||||
|
||||
- [Wrappers List](#Wrappers)
|
||||
|
||||
## Build WebUI Application
|
||||
|
||||
### Windows
|
||||
|
||||
| Compiler | Type | Command |
|
||||
|----------|--------|---------|
|
||||
| GCC | Static | `gcc -Os -Wl,-subsystem=windows my_application.c -I"_PATH_TO_WEBUI_INCLUDE_" -L"_PATH_TO_WEBUI_LIB_" -lwebui-2-static -lws2_32 -Wall -luser32 -static -lole32 -o my_application.exe` |
|
||||
| GCC | Dynamic | `gcc -Wl,-subsystem=windows my_application.c -I"_PATH_TO_WEBUI_INCLUDE_" -L"_PATH_TO_WEBUI_LIB_" "webui-2.dll" -lws2_32 -Wall -luser32 -lole32 -o my_application.exe` |
|
||||
| MSVC | Static | `cl my_application.c /I"_PATH_TO_WEBUI_INCLUDE_" /link /LIBPATH:"_PATH_TO_WEBUI_LIB_" /SUBSYSTEM:WINDOWS webui-2-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:my_application.exe` |
|
||||
| MSVC | Dynamic | `cl my_application.c /I"_PATH_TO_WEBUI_INCLUDE_" /link /LIBPATH:"_PATH_TO_WEBUI_LIB_" /SUBSYSTEM:WINDOWS webui-2.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:my_application.exe` |
|
||||
|
||||
<details>
|
||||
<summary><strong>Windows With SSL/TLS (Optional)</strong></summary>
|
||||
|
||||
| Compiler | Type | Command |
|
||||
|----------|--------|---------|
|
||||
| GCC | Static | `gcc -Os -Wl,-subsystem=windows my_application.c -I"_PATH_TO_WEBUI_INCLUDE_" -L"_PATH_TO_WEBUI_LIB_" -lwebui-2-secure-static -lws2_32 -Wall -luser32 -static -lole32 -o my_application.exe` |
|
||||
| GCC | Dynamic | `gcc -Wl,-subsystem=windows my_application.c -I"_PATH_TO_WEBUI_INCLUDE_" -L"_PATH_TO_WEBUI_LIB_" "webui-2-secure.dll" -lws2_32 -Wall -luser32 -lole32 -o my_application.exe` |
|
||||
| MSVC | Static | `cl my_application.c /I"_PATH_TO_WEBUI_INCLUDE_" /link /LIBPATH:"_PATH_TO_WEBUI_LIB_" /SUBSYSTEM:WINDOWS webui-2-secure-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:my_application.exe` |
|
||||
| MSVC | Dynamic | `cl my_application.c /I"_PATH_TO_WEBUI_INCLUDE_" /link /LIBPATH:"_PATH_TO_WEBUI_LIB_" /SUBSYSTEM:WINDOWS webui-2-secure.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:my_application.exe` |
|
||||
</details>
|
||||
|
||||
### Linux
|
||||
|
||||
| Compiler | Type | Command |
|
||||
|----------|--------|---------|
|
||||
| GCC | Static | `gcc -Os my_application.c -I"_PATH_TO_WEBUI_INCLUDE_" -L"_PATH_TO_WEBUI_LIB_" -lwebui-2-static -lpthread -lm -ldl -o my_application` |
|
||||
| GCC | Dynamic | `gcc my_application.c -I"_PATH_TO_WEBUI_INCLUDE_" -L"_PATH_TO_WEBUI_LIB_" -lwebui-2 -lpthread -lm -ldl -o my_application` |
|
||||
| Clang | Static | `clang -Os my_application.c -I"_PATH_TO_WEBUI_INCLUDE_" -L"_PATH_TO_WEBUI_LIB_" -lwebui-2-static -lpthread -lm -ldl -o my_application` |
|
||||
| Clang | Dynamic | `clang my_application.c -I"_PATH_TO_WEBUI_INCLUDE_" -L"_PATH_TO_WEBUI_LIB_" -lwebui-2 -lpthread -lm -ldl -o my_application` |
|
||||
|
||||
<details>
|
||||
<summary><strong>Linux With SSL/TLS (Optional)</strong></summary>
|
||||
|
||||
| Compiler | Type | Command |
|
||||
|----------|--------|---------|
|
||||
| GCC | Static | `gcc -Os my_application.c -I"_PATH_TO_WEBUI_INCLUDE_" -L"_PATH_TO_WEBUI_LIB_" -lwebui-2-secure-static -lpthread -lm -ldl -o my_application` |
|
||||
| GCC | Dynamic | `gcc my_application.c -I"_PATH_TO_WEBUI_INCLUDE_" -L"_PATH_TO_WEBUI_LIB_" -lwebui-2-secure -lpthread -lm -ldl -o my_application` |
|
||||
| Clang | Static | `clang -Os my_application.c -I"_PATH_TO_WEBUI_INCLUDE_" -L"_PATH_TO_WEBUI_LIB_" -lwebui-2-secure-static -lpthread -lm -ldl -o my_application` |
|
||||
| Clang | Dynamic | `clang my_application.c -I"_PATH_TO_WEBUI_INCLUDE_" -L"_PATH_TO_WEBUI_LIB_" -lwebui-2-secure -lpthread -lm -ldl -o my_application` |
|
||||
</details>
|
||||
|
||||
### macOS
|
||||
|
||||
| Compiler | Type | Command |
|
||||
|----------|--------|---------|
|
||||
| Clang | Static | `clang -Os my_application.c -I"_PATH_TO_WEBUI_INCLUDE_" -L"_PATH_TO_WEBUI_LIB_" -lwebui-2-static -lpthread -lm -framework Cocoa -framework WebKit -o my_application` |
|
||||
| Clang | Dynamic | `clang my_application.c -I"_PATH_TO_WEBUI_INCLUDE_" -L"_PATH_TO_WEBUI_LIB_" -lwebui-2 -lpthread -lm -framework Cocoa -framework WebKit -o my_application` |
|
||||
|
||||
<details>
|
||||
<summary><strong>macOS With SSL/TLS (Optional)</strong></summary>
|
||||
|
||||
| Compiler | Type | Command |
|
||||
|----------|--------|---------|
|
||||
| Clang | Static | `clang -Os my_application.c -I"_PATH_TO_WEBUI_INCLUDE_" -L"_PATH_TO_WEBUI_LIB_" -lwebui-2-secure-static -lpthread -lm -framework Cocoa -framework WebKit -o my_application` |
|
||||
| Clang | Dynamic | `clang my_application.c -I"_PATH_TO_WEBUI_INCLUDE_" -L"_PATH_TO_WEBUI_LIB_" -lwebui-2-secure -lpthread -lm -framework Cocoa -framework WebKit -o my_application` |
|
||||
</details>
|
||||
|
||||
## Wrappers
|
||||
|
||||
| Language | Status | Link |
|
||||
| ----------------------- | -------------- | --------------------------------------------------------- |
|
||||
| Go | ✔️ | [Go-WebUI](https://github.com/webui-dev/go-webui) |
|
||||
| Nim | ✔️ | [Nim-WebUI](https://github.com/webui-dev/nim-webui) |
|
||||
| Pascal | ✔️ | [Pascal-WebUI](https://github.com/webui-dev/pascal-webui) |
|
||||
| Python | ✔️ | [Python-WebUI](https://github.com/webui-dev/python-webui) |
|
||||
| Rust | _not complete_ | [Rust-WebUI](https://github.com/webui-dev/rust-webui) |
|
||||
| TypeScript / JavaScript | ✔️ | [Deno-WebUI](https://github.com/webui-dev/deno-webui) |
|
||||
| V | ✔️ | [V-WebUI](https://github.com/webui-dev/v-webui) |
|
||||
| Zig | _not complete_ | [Zig-WebUI](https://github.com/webui-dev/zig-webui) |
|
||||
| Odin | _not complete_ | [Odin-WebUI](https://github.com/webui-dev/odin-webui) |
|
||||
| Language | v2.4.0 API | v2.5.0 API | Link |
|
||||
| --------------- | --- | -------------- | --------------------------------------------------------- |
|
||||
| Python | ✔️ | _not complete_ | [Python-WebUI](https://github.com/webui-dev/python-webui) |
|
||||
| Go | ✔️ | _not complete_ | [Go-WebUI](https://github.com/webui-dev/go-webui) |
|
||||
| Zig | ✔️ | _not complete_ | [Zig-WebUI](https://github.com/webui-dev/zig-webui) |
|
||||
| Nim | ✔️ | _not complete_ | [Nim-WebUI](https://github.com/webui-dev/nim-webui) |
|
||||
| V | ✔️ | _not complete_ | [V-WebUI](https://github.com/webui-dev/v-webui) |
|
||||
| Rust | _not complete_ | _not complete_ | [Rust-WebUI](https://github.com/webui-dev/rust-webui) |
|
||||
| TS / JS (Deno) | ✔️ | _not complete_ | [Deno-WebUI](https://github.com/webui-dev/deno-webui) |
|
||||
| TS / JS (Bun) | _not complete_ | _not complete_ | [Bun-WebUI](https://github.com/webui-dev/bun-webui) |
|
||||
| Swift | _not complete_ | _not complete_ | [Swift-WebUI](https://github.com/webui-dev/swift-webui) |
|
||||
| Odin | _not complete_ | _not complete_ | [Odin-WebUI](https://github.com/webui-dev/odin-webui) |
|
||||
| Pascal | _not complete_ | _not complete_ | [Pascal-WebUI](https://github.com/webui-dev/pascal-webui) |
|
||||
| Purebasic | _not complete_ | _not complete_ | [Purebasic-WebUI](https://github.com/webui-dev/purebasic-webui)|
|
||||
| - | | |
|
||||
| Common Lisp | _not complete_ | _not complete_ | [cl-webui](https://github.com/garlic0x1/cl-webui) |
|
||||
| Delphi | _not complete_ | _not complete_ | [WebUI4Delphi](https://github.com/salvadordf/WebUI4Delphi) |
|
||||
| C# | _not complete_ | _not complete_ | [WebUI4CSharp](https://github.com/salvadordf/WebUI4CSharp) |
|
||||
| WebUI.NET | _not complete_ | _not complete_ | [WebUI.NET](https://github.com/Juff-Ma/WebUI.NET) |
|
||||
| QuickJS | _not complete_ | _not complete_ | [QuickUI](https://github.com/xland/QuickUI) |
|
||||
| PHP | _not complete_ | _not complete_ | [PHPWebUiComposer](https://github.com/KingBes/php-webui-composer) |
|
||||
|
||||
## Supported Web Browsers
|
||||
|
||||
@ -200,6 +286,14 @@ Think of WebUI like a WebView controller, but instead of embedding the WebView c
|
||||
| Apple Safari | _not available_ | _coming soon_ | _not available_ |
|
||||
| Opera | _coming soon_ | _coming soon_ | _coming soon_ |
|
||||
|
||||
## Supported WebView
|
||||
|
||||
| WebView | Status |
|
||||
| --------------- | --------------- |
|
||||
| Windows WebView2 | ✔️ |
|
||||
| Linux GTK WebView | ✔️ |
|
||||
| macOS WKWebView | ✔️ |
|
||||
|
||||
### License
|
||||
|
||||
> Licensed under MIT License.
|
||||
|
@ -1,6 +1,6 @@
|
||||
# WebUI Bridge
|
||||
|
||||
The WebUI Bridge connects the UI (_Web Browser_) with the backend application through WebSocket. This bridge is written in TypeScript, and it needs to be transpiled to JavaScript using [ESBuild](https://esbuild.github.io/) to produce `webui_bridge.js`, then converted to C header using the Python script `js2c.py` to generate `webui_bridge.h`.
|
||||
The WebUI Bridge connects the UI (_Web Browser_) with the backend application through WebSocket. This bridge is written in TypeScript, and it needs to be transpiled to JavaScript using [ESBuild](https://esbuild.github.io/) to produce `webui.js`, then converted to C header using the Python script `js2c.py` to generate `webui_bridge.h`.
|
||||
|
||||
### Windows
|
||||
|
||||
@ -8,7 +8,7 @@ The WebUI Bridge connects the UI (_Web Browser_) with the backend application th
|
||||
- Install [Node.js](https://nodejs.org/en/download)
|
||||
- cd `webui\bridge`
|
||||
- `npm install esbuild`
|
||||
- `.\node_modules\.bin\esbuild --bundle --target="chrome90,firefox90,safari15" --format=esm --tree-shaking=false --outdir=.\ .\webui_bridge.ts`
|
||||
- `.\node_modules\.bin\esbuild --bundle --target="chrome90,firefox90,safari15" --format=esm --tree-shaking=false --outdir=.\ .\webui.ts`
|
||||
- `python js2c.py`
|
||||
|
||||
### Windows PowerShell
|
||||
@ -24,7 +24,7 @@ The WebUI Bridge connects the UI (_Web Browser_) with the backend application th
|
||||
- Install [Node.js](https://nodejs.org/en/download)
|
||||
- cd `webui/bridge`
|
||||
- `npm install esbuild`
|
||||
- `./node_modules/.bin/esbuild --bundle --target="chrome90,firefox90,safari15" --format=esm --tree-shaking=false --outdir=./ ./webui_bridge.ts`
|
||||
- `./node_modules/.bin/esbuild --bundle --target="chrome90,firefox90,safari15" --format=esm --tree-shaking=false --outdir=./ ./webui.ts`
|
||||
- `python js2c.py`
|
||||
|
||||
### Linux Bash
|
||||
@ -38,7 +38,7 @@ The WebUI Bridge connects the UI (_Web Browser_) with the backend application th
|
||||
- Install [Node.js](https://nodejs.org/en/download)
|
||||
- cd `webui/bridge`
|
||||
- `npm install esbuild`
|
||||
- `./node_modules/.bin/esbuild --bundle --target="chrome90,firefox90,safari15" --format=esm --tree-shaking=false --outdir=./ ./webui_bridge.ts`
|
||||
- `./node_modules/.bin/esbuild --bundle --target="chrome90,firefox90,safari15" --format=esm --tree-shaking=false --outdir=./ ./webui.ts`
|
||||
- `python js2c.py`
|
||||
|
||||
### macOS Bash
|
||||
|
@ -27,7 +27,7 @@ IF NOT EXIST "%project_root%\bridge\node_modules\esbuild\" (
|
||||
where npm > NUL 2>&1
|
||||
IF %errorlevel%==0 (
|
||||
echo Installing esbuild...
|
||||
npm install esbuild
|
||||
npm install --prefix ./ esbuild
|
||||
) ELSE (
|
||||
echo Error: Please install NPM.
|
||||
cd %cd%
|
||||
@ -37,7 +37,7 @@ IF NOT EXIST "%project_root%\bridge\node_modules\esbuild\" (
|
||||
|
||||
REM Transpile WebUI-Bridge (TS to JS) & Convert WebUI-Bridge (JS to C)
|
||||
echo Transpile and bundle WebUI-Bridge from TypeScript to JavaScript...
|
||||
.\node_modules\.bin\esbuild --bundle --target="chrome90,firefox90,safari15" --format=esm --tree-shaking=false --outdir=. ./webui_bridge.ts & %python_cmd% js2c.py
|
||||
.\node_modules\.bin\esbuild --bundle --target="chrome90,firefox90,safari15" --format=esm --tree-shaking=false --minify-syntax --minify-whitespace --outdir=. ./webui.ts & %python_cmd% js2c.py
|
||||
|
||||
echo Done.
|
||||
cd %cd%
|
||||
|
@ -1,14 +1,20 @@
|
||||
# http://webui.me
|
||||
# https://webui.me
|
||||
# https://github.com/webui-dev/webui
|
||||
# Copyright (c) 2020-2023 Hassan Draga.
|
||||
# Copyright (c) 2020-2025 Hassan Draga.
|
||||
# Licensed under MIT License.
|
||||
# All rights reserved.
|
||||
# Canada.
|
||||
#
|
||||
# Special Thanks to Turiiya (https://github.com/ttytm)
|
||||
|
||||
Set-StrictMode -version latest
|
||||
$ErrorActionPreference="Stop"
|
||||
|
||||
$current_location = Get-Location
|
||||
$project_root = git rev-parse --show-toplevel
|
||||
Set-Location $project_root/bridge
|
||||
$silent=$false
|
||||
$log_level=$null
|
||||
|
||||
# Arguments
|
||||
foreach ($opt in $args) {
|
||||
@ -22,6 +28,7 @@ foreach ($opt in $args) {
|
||||
}
|
||||
if ($silent) { $log_level = "--log-level=warning" }
|
||||
|
||||
$ErrorActionPreference="SilentlyContinue"
|
||||
# Check which python command is available
|
||||
$commandResult = python3 --version 2>&1 > $null
|
||||
if (!$?) {
|
||||
@ -37,12 +44,13 @@ if (!$?) {
|
||||
} else {
|
||||
$python_cmd = "python3"
|
||||
}
|
||||
$ErrorActionPreference="Stop"
|
||||
|
||||
# Check if node_modules\esbuild exists, if not, install using npm
|
||||
if (-not (Test-Path "$project_root\bridge\node_modules\esbuild")) {
|
||||
if (Get-Command npm -ErrorAction SilentlyContinue) {
|
||||
if (!$silent) { Write-Host "Installing esbuild..." }
|
||||
npm install esbuild
|
||||
npm install --prefix ./ esbuild
|
||||
} else {
|
||||
Write-Host "Error: Please install NPM."
|
||||
Set-Location $current_location
|
||||
@ -52,7 +60,7 @@ if (-not (Test-Path "$project_root\bridge\node_modules\esbuild")) {
|
||||
|
||||
# Transpile WebUI-Bridge (TS to JS)
|
||||
if (!$silent) { Write-Host "Transpile and bundle WebUI-Bridge from TypeScript to JavaScript..." }
|
||||
.\node_modules\.bin\esbuild --bundle --target="chrome90,firefox90,safari15" --format=esm --tree-shaking=false --outdir=. ./webui_bridge.ts $log_level
|
||||
.\node_modules\.bin\esbuild --bundle --target="chrome90,firefox90,safari15" --format=esm --tree-shaking=false --minify-syntax --minify-whitespace --outdir=. ./webui.ts $log_level
|
||||
|
||||
# Convert WebUI-Bridge (JS to C)
|
||||
if (!$silent) { Write-Host "Convert WebUI-Bridge JavaScript to C Header..." }
|
||||
|
@ -1,10 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
# http://webui.me
|
||||
# https://webui.me
|
||||
# https://github.com/webui-dev/webui
|
||||
# Copyright (c) 2020-2023 Hassan Draga.
|
||||
# Copyright (c) 2020-2025 Hassan Draga.
|
||||
# Licensed under MIT License.
|
||||
# All rights reserved.
|
||||
# Canada.
|
||||
#
|
||||
# Special Thanks to Turiiya (https://github.com/ttytm)
|
||||
|
||||
@ -28,7 +29,7 @@ done
|
||||
if [ "$silent" = true ]; then log_level=--log-level=warning; fi
|
||||
|
||||
if [ "$silent" != true ]; then echo "Transpile and bundle TS sources to webui.js"; fi
|
||||
esbuild --bundle --target="chrome90,firefox90,safari15" --format=esm --tree-shaking=false --outdir=. ./webui_bridge.ts $log_level
|
||||
esbuild --bundle --target="chrome90,firefox90,safari15" --format=esm --tree-shaking=false --minify-syntax --minify-whitespace --outdir=. ./webui.ts $log_level
|
||||
|
||||
if [ "$silent" != true ]; then echo "Convert JS source to C header"; fi
|
||||
python3 js2c.py
|
||||
|
@ -1,24 +1,44 @@
|
||||
# http://webui.me
|
||||
# https://webui.me
|
||||
# https://github.com/webui-dev/webui
|
||||
# Copyright (c) 2020-2023 Hassan Draga.
|
||||
# Copyright (c) 2020-2025 Hassan Draga.
|
||||
# Licensed under MIT License.
|
||||
# All rights reserved.
|
||||
# Canada.
|
||||
#
|
||||
# WebUI JavaScript to C Header
|
||||
|
||||
def js_to_c_header(input_filename, output_filename):
|
||||
try:
|
||||
# Read JS file content
|
||||
with open(input_filename, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
print(f"Converting '{input_filename}' to '{output_filename}'...")
|
||||
|
||||
# comment
|
||||
comment = (
|
||||
"// WebUI v2.5.0-beta.4\n"
|
||||
"// https://webui.me\n"
|
||||
"// https://github.com/webui-dev/webui\n"
|
||||
"// Copyright (c) 2020-2025 Hassan Draga.\n"
|
||||
"// Licensed under MIT License.\n"
|
||||
"// All rights reserved.\n"
|
||||
"// Canada.\n\n"
|
||||
)
|
||||
|
||||
# Read JS file content
|
||||
with open(input_filename, 'r', encoding='utf-8') as file_js:
|
||||
content = file_js.read()
|
||||
file_js.close()
|
||||
|
||||
# Add comment to js
|
||||
new_content = comment + content
|
||||
with open(input_filename, 'w') as file_js:
|
||||
file_js.write(new_content)
|
||||
file_js.close()
|
||||
|
||||
# Convert each character in JS content to its hexadecimal value
|
||||
hex_values = ["0x{:02x}".format(ord(char)) for char in content]
|
||||
hex_values = ["0x{:02x}".format(ord(char)) for char in new_content]
|
||||
|
||||
# Prepare the content for the C header file
|
||||
header_content = (
|
||||
comment +
|
||||
"// --- PLEASE DO NOT EDIT THIS FILE -------\n"
|
||||
"// --- THIS FILE IS GENERATED BY JS2C.PY --\n\n"
|
||||
"#ifndef WEBUI_BRIDGE_H\n"
|
||||
@ -29,16 +49,16 @@ def js_to_c_header(input_filename, output_filename):
|
||||
# Split the hexadecimal values to make the output more readable, adding a new line every 10 values
|
||||
for i in range(0, len(hex_values), 10):
|
||||
header_content += "\n " + ', '.join(hex_values[i:i+10]) + ','
|
||||
|
||||
header_content += "\n 0x00\n};\n\n#endif // WEBUI_BRIDGE_H"
|
||||
|
||||
# Write the header content to the output file
|
||||
with open(output_filename, 'w', encoding='utf-8') as f:
|
||||
f.write(header_content)
|
||||
with open(output_filename, 'w', encoding='utf-8') as file_h:
|
||||
file_h.write(header_content)
|
||||
file_h.close()
|
||||
|
||||
except FileNotFoundError:
|
||||
print(f"Error: File '{input_filename}' not found.")
|
||||
return
|
||||
|
||||
# Main
|
||||
js_to_c_header('webui_bridge.js', 'webui_bridge.h')
|
||||
js_to_c_header('webui.js', 'webui_bridge.h')
|
||||
|
@ -1,9 +1,13 @@
|
||||
/*
|
||||
WebUI Bridge Utils
|
||||
|
||||
Copyright (c) 2023 Oculi Julien.
|
||||
https://webui.me
|
||||
https://github.com/webui-dev/webui
|
||||
Copyright (c) 2020-2025 Hassan Draga.
|
||||
Licensed under MIT License.
|
||||
All rights reserved.
|
||||
Canada.
|
||||
|
||||
File: WebUI Bridge Utils
|
||||
Copyright (c) 2024 Oculi Julien.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
974
bridge/webui.ts
Normal file
974
bridge/webui.ts
Normal file
@ -0,0 +1,974 @@
|
||||
'use-strict'; // Force strict mode for transpiled
|
||||
|
||||
/*
|
||||
WebUI Bridge
|
||||
|
||||
https://webui.me
|
||||
https://github.com/webui-dev/webui
|
||||
Copyright (c) 2020-2025 Hassan Draga.
|
||||
Licensed under MIT License.
|
||||
All rights reserved.
|
||||
Canada.
|
||||
|
||||
Converted from JavaScript to TypeScript
|
||||
By Oculi Julien. Copyright (c) 2023.
|
||||
*/
|
||||
|
||||
//@ts-ignore use *.ts import real extension
|
||||
import { AsyncFunction, addRefreshableEventListener } from './utils.ts';
|
||||
|
||||
type DataTypes = string | number | boolean | Uint8Array;
|
||||
|
||||
class WebuiBridge {
|
||||
// WebUI Settings
|
||||
#secure: boolean;
|
||||
#token: number;
|
||||
#port: number;
|
||||
#log: boolean;
|
||||
#winX: number;
|
||||
#winY: number;
|
||||
#winW: number;
|
||||
#winH: number;
|
||||
// Frameless Dragging
|
||||
#isDragging: boolean = false;
|
||||
#initialMouseX: number = 0;
|
||||
#initialMouseY: number = 0;
|
||||
#initialWindowX: number = window.screenX || window.screenLeft;
|
||||
#initialWindowY: number = window.screenY || window.screenTop;
|
||||
#currentWindowX: number = window.screenX || window.screenLeft;
|
||||
#currentWindowY: number = window.screenY || window.screenTop;
|
||||
// Internals
|
||||
#ws: WebSocket;
|
||||
#wsStayAlive: boolean = true;
|
||||
#wsStayAliveTimeout: number = 500;
|
||||
#wsWasConnected: boolean = false;
|
||||
#TokenAccepted: boolean = false;
|
||||
#closeReason: number = 0;
|
||||
#closeValue: string;
|
||||
#AllEvents: boolean = false;
|
||||
#callPromiseID: Uint16Array = new Uint16Array(1);
|
||||
#callPromiseResolve: (((data: string) => unknown) | undefined)[] = [];
|
||||
#allowNavigation: boolean = true;
|
||||
#sendQueue: Uint8Array[] = [];
|
||||
#isSending: boolean = false;
|
||||
#bindsList: string[];
|
||||
// WebUI Const
|
||||
#WEBUI_SIGNATURE: number = 221;
|
||||
#CMD_JS: number = 254;
|
||||
#CMD_JS_QUICK: number = 253;
|
||||
#CMD_CLICK: number = 252;
|
||||
#CMD_NAVIGATION: number = 251;
|
||||
#CMD_CLOSE: number = 250;
|
||||
#CMD_CALL_FUNC: number = 249;
|
||||
#CMD_SEND_RAW: number = 248;
|
||||
#CMD_NEW_ID: number = 247;
|
||||
#CMD_MULTI: number = 246;
|
||||
#CMD_CHECK_TK: number = 245;
|
||||
#CMD_WINDOW_DRAG: number = 244;
|
||||
#CMD_WINDOW_RESIZED: number = 243;
|
||||
#MULTI_CHUNK_SIZE: number = 65500;
|
||||
#PROTOCOL_SIZE: number = 8; // Protocol header size in bytes
|
||||
#PROTOCOL_SIGN: number = 0; // Protocol byte position: Signature (1 Byte)
|
||||
#PROTOCOL_TOKEN: number = 1; // Protocol byte position: Token (4 Bytes)
|
||||
#PROTOCOL_ID: number = 5; // Protocol byte position: ID (2 Bytes)
|
||||
#PROTOCOL_CMD: number = 7; // Protocol byte position: Command (1 Byte)
|
||||
#PROTOCOL_DATA: number = 8; // Protocol byte position: Data (n Byte)
|
||||
#Token: Uint32Array = new Uint32Array(1);
|
||||
#Ping: Boolean = true;
|
||||
// Events
|
||||
#eventsCallback: ((event: number) => void) | null = null;
|
||||
event = {
|
||||
// TODO: Make `event` static and solve the ESBUILD `_WebuiBridge` issue.
|
||||
CONNECTED: 0,
|
||||
DISCONNECTED: 1,
|
||||
};
|
||||
// Constructor
|
||||
constructor({
|
||||
secure = false,
|
||||
token = 0,
|
||||
port = 0,
|
||||
log = false,
|
||||
winX = 0,
|
||||
winY = 0,
|
||||
winW = 0,
|
||||
winH = 0,
|
||||
}: {
|
||||
secure: boolean;
|
||||
token: number;
|
||||
port: number;
|
||||
log?: boolean;
|
||||
winX: number;
|
||||
winY: number;
|
||||
winW: number;
|
||||
winH: number;
|
||||
}) {
|
||||
// Constructor arguments are injected by webui.c
|
||||
this.#secure = secure;
|
||||
this.#token = token;
|
||||
this.#port = port;
|
||||
this.#log = log;
|
||||
this.#winX = winX;
|
||||
this.#winY = winY;
|
||||
this.#winW = winW;
|
||||
this.#winH = winH;
|
||||
// Token
|
||||
this.#Token[0] = this.#token;
|
||||
// Instance
|
||||
if ('webui' in globalThis) {
|
||||
throw new Error('Sorry. WebUI is already defined, only one instance is allowed.');
|
||||
}
|
||||
// Positioning the current window
|
||||
if (this.#winX !== undefined && this.#winY !== undefined) {
|
||||
// window.moveTo(this.#winX, this.#winY);
|
||||
}
|
||||
// Resize the current window
|
||||
if (this.#winW !== undefined && this.#winH !== undefined) {
|
||||
// window.resizeTo(this.#winW, this.#winH);
|
||||
}
|
||||
// WebSocket
|
||||
if (!('WebSocket' in window)) {
|
||||
alert('Sorry. WebSocket is not supported by your web browser.');
|
||||
if (!this.#log) globalThis.close();
|
||||
}
|
||||
// Connect to the backend application
|
||||
this.#start();
|
||||
// Navigation event listener
|
||||
if ('navigation' in globalThis) {
|
||||
globalThis.navigation.addEventListener('navigate', (event) => {
|
||||
if (!this.#allowNavigation) {
|
||||
if (this.#AllEvents && (this.#wsIsConnected())) {
|
||||
event.preventDefault();
|
||||
const url = new URL(event.destination.url);
|
||||
if (this.#log) console.log(`WebUI -> DOM -> Navigation Event [${url.href}]`);
|
||||
this.#sendEventNavigation(url.href);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Click navigation event listener
|
||||
addRefreshableEventListener(document.body, 'a', 'click', (event) => {
|
||||
if (!this.#allowNavigation) {
|
||||
if (this.#AllEvents && (this.#wsIsConnected())) {
|
||||
event.preventDefault();
|
||||
const { href } = event.target as HTMLAnchorElement;
|
||||
if (this.#log) console.log(`WebUI -> DOM -> Navigation Click Event [${href}]`);
|
||||
this.#sendEventNavigation(href);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// Prevent F5 refresh
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if (this.#log) return; // Allowed in debug mode
|
||||
if (event.key === 'F5') event.preventDefault();
|
||||
});
|
||||
// Frameless Dragging
|
||||
document.addEventListener("mousemove", (e) => {
|
||||
// WebUI `-webkit-app-region: drag;` custom implementation
|
||||
if (e.buttons !== 1) {
|
||||
this.#isDragging = false;
|
||||
return;
|
||||
}
|
||||
if (!this.#isDragging) {
|
||||
let target = e.target;
|
||||
while (target) {
|
||||
if (window.getComputedStyle(target).getPropertyValue("-webkit-app-region") === "drag") {
|
||||
this.#initialMouseX = e.screenX;
|
||||
this.#initialMouseY = e.screenY;
|
||||
this.#initialWindowX = this.#currentWindowX;
|
||||
this.#initialWindowY = this.#currentWindowY;
|
||||
this.#isDragging = true;
|
||||
break;
|
||||
}
|
||||
target = target.parentElement;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Calculate window position relative to cursor movement
|
||||
const deltaX = e.screenX - this.#initialMouseX;
|
||||
const deltaY = e.screenY - this.#initialMouseY;
|
||||
let newX = this.#initialWindowX + deltaX;
|
||||
let newY = this.#initialWindowY + deltaY;
|
||||
// Fix out of screen
|
||||
if (newX < 0) newX = 0;
|
||||
if (newY < 0) newY = 0;
|
||||
// Move the window
|
||||
this.#sendDrag(newX, newY);
|
||||
// Update the last window position
|
||||
this.#currentWindowX = newX;
|
||||
this.#currentWindowY = newY;
|
||||
});
|
||||
// Stop frameless dragging on mouse release
|
||||
document.addEventListener("mouseup", () => {
|
||||
this.#isDragging = false;
|
||||
});
|
||||
onbeforeunload = () => {
|
||||
this.#close();
|
||||
};
|
||||
setTimeout(() => {
|
||||
if (!this.#wsWasConnected) {
|
||||
alert('Sorry. WebUI failed to connect to the backend application. Please try again.');
|
||||
}
|
||||
}, 1500);
|
||||
}
|
||||
// Methods
|
||||
#close(reason = 0, value = '') {
|
||||
this.#closeReason = reason;
|
||||
this.#closeValue = value;
|
||||
if (this.#wsIsConnected()) {
|
||||
this.#ws.close();
|
||||
}
|
||||
}
|
||||
#freezeUi() {
|
||||
setTimeout(() => {
|
||||
if (!this.#wsIsConnected()) {
|
||||
if (document.getElementById('webui-error-connection-lost')) return;
|
||||
const div = document.createElement('div');
|
||||
div.id = 'webui-error-connection-lost';
|
||||
Object.assign(div.style, {
|
||||
position: 'relative',
|
||||
top: '0',
|
||||
left: '0',
|
||||
width: '100%',
|
||||
backgroundColor: '#ff4d4d',
|
||||
color: '#fff',
|
||||
textAlign: 'center',
|
||||
padding: '2px 0',
|
||||
fontFamily: 'Arial, sans-serif',
|
||||
fontSize: '14px',
|
||||
zIndex: '1000',
|
||||
lineHeight: '1'
|
||||
});
|
||||
div.innerText = 'WebUI Error: Connection with the backend is lost.';
|
||||
document.body.insertBefore(div, document.body.firstChild);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
#unfreezeUI() {
|
||||
const div = document.getElementById('webui-error-connection-lost');
|
||||
if (div) {
|
||||
div.remove();
|
||||
}
|
||||
}
|
||||
#isTextBasedCommand(cmd: number): Boolean {
|
||||
if (cmd !== this.#CMD_SEND_RAW) return true;
|
||||
return false;
|
||||
}
|
||||
#parseDimensions(input: string): {x: number; y: number; width: number; height: number} {
|
||||
try {
|
||||
const parts = input.split(',');
|
||||
if (parts.length !== 4) return {x: 0, y: 0, width: 0, height: 0};
|
||||
const x = parseFloat(parts[0]),
|
||||
y = parseFloat(parts[1]),
|
||||
width = parseFloat(parts[2]),
|
||||
height = parseFloat(parts[3]);
|
||||
return [x, y, width, height].some(isNaN) ? {x: 0, y: 0, width: 0, height: 0} : {x, y, width, height};
|
||||
} catch {
|
||||
return {x: 0, y: 0, width: 0, height: 0};
|
||||
}
|
||||
}
|
||||
#getDataStrFromPacket(buffer: Uint8Array, startIndex: number): string {
|
||||
let stringBytes: number[] = [];
|
||||
for (let i = startIndex; i < buffer.length; i++) {
|
||||
if (buffer[i] === 0) {
|
||||
// Check for null byte
|
||||
break;
|
||||
}
|
||||
stringBytes.push(buffer[i]);
|
||||
}
|
||||
// Convert the array of bytes to a string
|
||||
const stringText = new TextDecoder().decode(new Uint8Array(stringBytes));
|
||||
return stringText;
|
||||
}
|
||||
#getID(buffer: Uint8Array, index: number): number {
|
||||
if (index < 0 || index >= buffer.length - 1) {
|
||||
throw new Error('Index out of bounds or insufficient data.');
|
||||
}
|
||||
const firstByte = buffer[index];
|
||||
const secondByte = buffer[index + 1];
|
||||
const combined = (secondByte << 8) | firstByte; // Works only for little-endian
|
||||
return combined;
|
||||
}
|
||||
#addToken(buffer: Uint8Array, value: number, index: number): void {
|
||||
if (value < 0 || value > 0xffffffff) {
|
||||
throw new Error('Number is out of the range for 4 bytes representation.');
|
||||
}
|
||||
if (index < 0 || index > buffer.length - 4) {
|
||||
throw new Error('Index out of bounds or insufficient space in buffer.');
|
||||
}
|
||||
// WebUI expect Little-endian (Work for Little/Big endian platforms)
|
||||
buffer[index] = value & 0xff; // Least significant byte
|
||||
buffer[index + 1] = (value >>> 8) & 0xff;
|
||||
buffer[index + 2] = (value >>> 16) & 0xff;
|
||||
buffer[index + 3] = (value >>> 24) & 0xff; // Most significant byte
|
||||
}
|
||||
#addID(buffer: Uint8Array, value: number, index: number): void {
|
||||
if (value < 0 || value > 0xffff) {
|
||||
throw new Error('Number is out of the range for 2 bytes representation.');
|
||||
}
|
||||
if (index < 0 || index > buffer.length - 2) {
|
||||
throw new Error('Index out of bounds or insufficient space in buffer.');
|
||||
}
|
||||
// WebUI expect Little-endian (Work for Little/Big endian platforms)
|
||||
buffer[index] = value & 0xff; // Least significant byte
|
||||
buffer[index + 1] = (value >>> 8) & 0xff; // Most significant byte
|
||||
}
|
||||
#start() {
|
||||
this.#keepAlive();
|
||||
this.#callPromiseID[0] = 0;
|
||||
// Connect to the backend application
|
||||
this.#wsConnect();
|
||||
}
|
||||
#keepAlive = async () => {
|
||||
while (true) {
|
||||
if (this.#Ping) {
|
||||
// Some web browsers may close the connection
|
||||
// let's send a void message to keep WS open
|
||||
this.#sendData(new TextEncoder().encode('ping'));
|
||||
} else {
|
||||
// There is an active communication
|
||||
this.#Ping = true;
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 20000));
|
||||
}
|
||||
};
|
||||
#clicksListener() {
|
||||
document.querySelectorAll<HTMLElement>("[id]").forEach(e => {
|
||||
if (this.#AllEvents || ((e.id !== '') && (this.#bindsList.includes(e.id)))) {
|
||||
if (e.id && !e.dataset.webui_click_is_set) {
|
||||
e.dataset.webui_click_is_set = "true";
|
||||
e.addEventListener("click", () => this.#sendClick(e.id));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
async #sendData(packet: Uint8Array) {
|
||||
this.#Ping = false;
|
||||
if ((!this.#wsIsConnected()) || packet === undefined) return;
|
||||
// Enqueue the packet
|
||||
this.#sendQueue.push(packet);
|
||||
if (this.#isSending) return;
|
||||
this.#isSending = true;
|
||||
while (this.#sendQueue.length > 0) {
|
||||
const currentPacket = this.#sendQueue.shift()!;
|
||||
if (currentPacket.length < this.#MULTI_CHUNK_SIZE) {
|
||||
this.#ws.send(currentPacket.buffer);
|
||||
} else {
|
||||
// Pre-packet to let WebUI be ready for multi packet
|
||||
const pre_packet = Uint8Array.of(
|
||||
this.#WEBUI_SIGNATURE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, // Token (4 Bytes)
|
||||
0,
|
||||
0, // ID (2 Bytes)
|
||||
this.#CMD_MULTI,
|
||||
...new TextEncoder().encode(currentPacket.length.toString()),
|
||||
0,
|
||||
);
|
||||
this.#ws.send(pre_packet.buffer);
|
||||
// Send chunks
|
||||
let offset = 0;
|
||||
const sendChunk = async () => {
|
||||
if (offset < currentPacket.length) {
|
||||
const chunkSize = Math.min(this.#MULTI_CHUNK_SIZE, currentPacket.length - offset);
|
||||
const chunk = currentPacket.subarray(offset, offset + chunkSize);
|
||||
this.#ws.send(chunk);
|
||||
offset += chunkSize;
|
||||
await sendChunk();
|
||||
}
|
||||
};
|
||||
await sendChunk();
|
||||
}
|
||||
}
|
||||
this.#isSending = false;
|
||||
}
|
||||
#sendClick(elem: string) {
|
||||
if (this.#wsIsConnected()) {
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [Element]
|
||||
const packet =
|
||||
elem !== ''
|
||||
? Uint8Array.of(
|
||||
this.#WEBUI_SIGNATURE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, // Token (4 Bytes)
|
||||
0,
|
||||
0, // ID (2 Bytes)
|
||||
this.#CMD_CLICK,
|
||||
...new TextEncoder().encode(elem),
|
||||
0,
|
||||
)
|
||||
: Uint8Array.of(
|
||||
this.#WEBUI_SIGNATURE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, // Token (4 Bytes)
|
||||
0,
|
||||
0, // ID (2 Bytes)
|
||||
this.#CMD_CLICK,
|
||||
0,
|
||||
);
|
||||
this.#addToken(packet, this.#token, this.#PROTOCOL_TOKEN);
|
||||
// this.#addID(packet, 0, this.#PROTOCOL_ID)
|
||||
this.#sendData(packet);
|
||||
if (this.#log) console.log(`WebUI -> Send Click [${elem}]`);
|
||||
}
|
||||
}
|
||||
#checkToken() {
|
||||
if (this.#wsIsConnected()) {
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
const packet =
|
||||
Uint8Array.of(
|
||||
this.#WEBUI_SIGNATURE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, // Token (4 Bytes)
|
||||
0,
|
||||
0, // ID (2 Bytes)
|
||||
this.#CMD_CHECK_TK,
|
||||
0,
|
||||
);
|
||||
this.#addToken(packet, this.#token, this.#PROTOCOL_TOKEN);
|
||||
// this.#addID(packet, 0, this.#PROTOCOL_ID)
|
||||
this.#sendData(packet);
|
||||
if (this.#log) console.log(`WebUI -> Send Token [0x${this.#token.toString(16).padStart(8, '0')}]`);
|
||||
}
|
||||
}
|
||||
#sendEventNavigation(url: string) {
|
||||
if (url !== '') {
|
||||
if (this.#wsIsConnected()) {
|
||||
if (this.#log) console.log(`WebUI -> Send Navigation Event [${url}]`);
|
||||
const packet = Uint8Array.of(
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [URL]
|
||||
this.#WEBUI_SIGNATURE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, // Token (4 Bytes)
|
||||
0,
|
||||
0, // ID (2 Bytes)
|
||||
this.#CMD_NAVIGATION,
|
||||
...new TextEncoder().encode(url),
|
||||
);
|
||||
this.#addToken(packet, this.#token, this.#PROTOCOL_TOKEN);
|
||||
// this.#addID(packet, 0, this.#PROTOCOL_ID)
|
||||
this.#sendData(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
#sendDrag(x: number, y: number) {
|
||||
if (this.#wsIsConnected()) {
|
||||
if (this.#log) console.log(`WebUI -> Send Drag Event [${x}, ${y}]`);
|
||||
const packet = Uint8Array.of(
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [X]
|
||||
// 4: [Y]
|
||||
this.#WEBUI_SIGNATURE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, // Token (4 Bytes)
|
||||
0,
|
||||
0, // ID (2 Bytes)
|
||||
this.#CMD_WINDOW_DRAG,
|
||||
...new Uint8Array(new Int32Array([x]).buffer), // X (4 Bytes)
|
||||
...new Uint8Array(new Int32Array([y]).buffer), // Y (4 Bytes)
|
||||
);
|
||||
this.#addToken(packet, this.#token, this.#PROTOCOL_TOKEN);
|
||||
// this.#addID(packet, 0, this.#PROTOCOL_ID)
|
||||
this.#sendData(packet);
|
||||
}
|
||||
}
|
||||
#closeWindowTimer() {
|
||||
setTimeout(function () {
|
||||
globalThis.close();
|
||||
}, 1000);
|
||||
}
|
||||
#updateBindsList() {
|
||||
if (this.#bindsList.includes('')) {
|
||||
this.#AllEvents = true;
|
||||
this.#allowNavigation = false;
|
||||
}
|
||||
this.#generateCallObjects();
|
||||
this.#clicksListener();
|
||||
}
|
||||
#toUint16(value: number): number {
|
||||
return value & 0xffff;
|
||||
}
|
||||
#generateCallObjects() {
|
||||
for (const bind of this.#bindsList) {
|
||||
if (bind.trim()) {
|
||||
const fn = bind;
|
||||
if (fn.trim()) {
|
||||
if (fn !== '__webui_core_api__') {
|
||||
if (typeof (window as any)[fn] === 'undefined') {
|
||||
this[fn] = (...args: DataTypes[]) => this.call(fn, ...args);
|
||||
(window as any)[fn] = (...args: string[]) => this.call(fn, ...args);
|
||||
if (this.#log) console.log(`WebUI -> Binding backend function [${fn}]`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#callPromise(fn: string, ...args: DataTypes[]) {
|
||||
--this.#callPromiseID[0];
|
||||
const callId = this.#toUint16(this.#callPromiseID[0]);
|
||||
// Combine lengths
|
||||
let argsLengths = args
|
||||
.map((arg) => {
|
||||
if (typeof arg === 'object') {
|
||||
// Uint8Array
|
||||
return arg.length;
|
||||
} else {
|
||||
// string, number, boolean
|
||||
return new TextEncoder().encode(arg.toString()).length;
|
||||
}
|
||||
})
|
||||
.join(';');
|
||||
// Combine values
|
||||
let argsValues: Uint8Array = new Uint8Array();
|
||||
for (const arg of args) {
|
||||
let buffer: Uint8Array;
|
||||
if (typeof arg === 'object') {
|
||||
buffer = arg; // Uint8Array
|
||||
} else {
|
||||
// string, number, boolean
|
||||
buffer = new TextEncoder().encode(arg.toString());
|
||||
}
|
||||
const temp = new Uint8Array(argsValues.length + buffer.length + 1);
|
||||
temp.set(argsValues, 0);
|
||||
temp.set(buffer, argsValues.length);
|
||||
temp[argsValues.length + buffer.length] = 0x00;
|
||||
argsValues = temp;
|
||||
}
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [Fn, Null, {LenLen...}, Null, {Data,Null,Data,Null...}]
|
||||
let packet = new Uint8Array(0);
|
||||
const packetPush = (data: Uint8Array) => {
|
||||
const newPacket = new Uint8Array(packet.length + data.length);
|
||||
newPacket.set(packet);
|
||||
newPacket.set(data, packet.length);
|
||||
packet = newPacket;
|
||||
};
|
||||
packetPush(new Uint8Array([this.#WEBUI_SIGNATURE]));
|
||||
packetPush(new Uint8Array([0, 0, 0, 0])); // Token (4 Bytes)
|
||||
packetPush(new Uint8Array([0, 0])); // ID (2 Bytes)
|
||||
packetPush(new Uint8Array([this.#CMD_CALL_FUNC]));
|
||||
packetPush(new TextEncoder().encode(fn));
|
||||
packetPush(new Uint8Array([0]));
|
||||
packetPush(new TextEncoder().encode(argsLengths));
|
||||
packetPush(new Uint8Array([0]));
|
||||
packetPush(new Uint8Array(argsValues));
|
||||
this.#addToken(packet, this.#token, this.#PROTOCOL_TOKEN);
|
||||
this.#addID(packet, callId, this.#PROTOCOL_ID);
|
||||
return new Promise((resolve) => {
|
||||
this.#callPromiseResolve[callId] = resolve;
|
||||
this.#sendData(packet);
|
||||
});
|
||||
}
|
||||
async callCore(fn: string, ...args: DataTypes[]): Promise<DataTypes> {
|
||||
return this.call('__webui_core_api__', fn, ...args);
|
||||
}
|
||||
// -- WebSocket ----------------------------
|
||||
#wsIsConnected(): boolean {
|
||||
return ((this.#ws) && (this.#ws.readyState === WebSocket.OPEN));
|
||||
}
|
||||
#wsConnect(): void {
|
||||
if (this.#wsIsConnected()) {
|
||||
this.#ws.close();
|
||||
}
|
||||
this.#TokenAccepted = false;
|
||||
const host = window.location.hostname;
|
||||
const url = this.#secure ? ('wss://' + host) : ('ws://' + host);
|
||||
this.#ws = new WebSocket(`${url}:${this.#port}/_webui_ws_connect`);
|
||||
this.#ws.binaryType = 'arraybuffer';
|
||||
this.#ws.onopen = this.#wsOnOpen.bind(this);
|
||||
this.#ws.onmessage = this.#wsOnMessage.bind(this);
|
||||
this.#ws.onclose = this.#wsOnClose.bind(this);
|
||||
this.#ws.onerror = this.#wsOnError.bind(this);
|
||||
}
|
||||
#wsOnOpen = (event: Event) => {
|
||||
this.#wsWasConnected = true;
|
||||
this.#unfreezeUI();
|
||||
if (this.#log) console.log('WebUI -> Connected');
|
||||
this.#checkToken();
|
||||
};
|
||||
#wsOnError = (event: Event) => {
|
||||
if (this.#log) console.log(`WebUI -> Connection failed.`);
|
||||
};
|
||||
#wsOnClose = (event: CloseEvent) => {
|
||||
if (this.#closeReason === this.#CMD_NAVIGATION) {
|
||||
this.#closeReason = 0;
|
||||
if (this.#log) console.log(`WebUI -> Connection lost. Navigation to [${this.#closeValue}]`);
|
||||
this.#allowNavigation = true;
|
||||
globalThis.location.replace(this.#closeValue);
|
||||
} else {
|
||||
if (this.#wsStayAlive) {
|
||||
// Re-connect
|
||||
if (this.#log) console.log(`WebUI -> Connection lost (${event.code}). Reconnecting...`);
|
||||
this.#freezeUi();
|
||||
setTimeout(() => this.#wsConnect(), this.#wsStayAliveTimeout);
|
||||
}
|
||||
else if (this.#log) {
|
||||
// Debug close
|
||||
console.log(`WebUI -> Connection lost (${event.code})`);
|
||||
this.#freezeUi();
|
||||
} else {
|
||||
// Release close
|
||||
this.#closeWindowTimer();
|
||||
}
|
||||
}
|
||||
// Event Callback
|
||||
if (this.#eventsCallback) {
|
||||
this.#eventsCallback(this.event.DISCONNECTED);
|
||||
}
|
||||
};
|
||||
#wsOnMessage = async (event: MessageEvent) => {
|
||||
const buffer8 = new Uint8Array(event.data);
|
||||
if (buffer8.length < this.#PROTOCOL_SIZE) return;
|
||||
if (buffer8[this.#PROTOCOL_SIGN] !== this.#WEBUI_SIGNATURE) return;
|
||||
if (this.#isTextBasedCommand(buffer8[this.#PROTOCOL_CMD])) {
|
||||
// UTF8 Text based commands
|
||||
const callId = this.#getID(buffer8, this.#PROTOCOL_ID);
|
||||
// Process Command
|
||||
switch (buffer8[this.#PROTOCOL_CMD]) {
|
||||
case this.#CMD_JS_QUICK:
|
||||
case this.#CMD_JS:
|
||||
{
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [Script]
|
||||
const script: string = this.#getDataStrFromPacket(buffer8, this.#PROTOCOL_DATA);
|
||||
const scriptSanitize = script.replace(/(?:\r\n|\r|\n)/g, '\n');
|
||||
if (this.#log) console.log(`WebUI -> CMD -> JS [${scriptSanitize}]`);
|
||||
// Get callback result
|
||||
let FunReturn = 'undefined';
|
||||
let FunError = false;
|
||||
try {
|
||||
FunReturn = await AsyncFunction(scriptSanitize)();
|
||||
} catch (e) {
|
||||
FunError = true;
|
||||
FunReturn = e.message;
|
||||
}
|
||||
// Stop if this is a quick call
|
||||
if (buffer8[this.#PROTOCOL_CMD] === this.#CMD_JS_QUICK) return;
|
||||
// Get the call return
|
||||
if (FunReturn === undefined) {
|
||||
FunReturn = 'undefined';
|
||||
}
|
||||
// Logging
|
||||
if (this.#log && !FunError) console.log(`WebUI -> CMD -> JS -> Return Success [${FunReturn}]`);
|
||||
if (this.#log && FunError) console.log(`WebUI -> CMD -> JS -> Return Error [${FunReturn}]`);
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [Error, Script Response]
|
||||
let packet = new Uint8Array(0);
|
||||
const packetPush = (data: Uint8Array) => {
|
||||
const newPacket = new Uint8Array(packet.length + data.length);
|
||||
newPacket.set(packet);
|
||||
newPacket.set(data, packet.length);
|
||||
packet = newPacket;
|
||||
};
|
||||
const packetPushStr = (data: string) => {
|
||||
const chunkSize = 1024 * 8;
|
||||
if (data.length > chunkSize) {
|
||||
const encoder = new TextEncoder();
|
||||
for (let i = 0; i < data.length; i += chunkSize) {
|
||||
const chunk = data.substring(i, Math.min(i + chunkSize, data.length));
|
||||
const encodedChunk = encoder.encode(chunk);
|
||||
packetPush(encodedChunk);
|
||||
}
|
||||
} else {
|
||||
packetPush(new TextEncoder().encode(data));
|
||||
}
|
||||
};
|
||||
packetPush(new Uint8Array([this.#WEBUI_SIGNATURE]));
|
||||
packetPush(new Uint8Array([0, 0, 0, 0])); // Token (4 Bytes)
|
||||
packetPush(new Uint8Array([0, 0])); // ID (2 Bytes)
|
||||
packetPush(new Uint8Array([this.#CMD_JS]));
|
||||
packetPush(new Uint8Array(FunError ? [1] : [0]));
|
||||
packetPushStr(FunReturn);
|
||||
packetPush(new Uint8Array([0]));
|
||||
this.#addToken(packet, this.#token, this.#PROTOCOL_TOKEN);
|
||||
this.#addID(packet, callId, this.#PROTOCOL_ID);
|
||||
this.#sendData(packet);
|
||||
}
|
||||
break;
|
||||
case this.#CMD_CALL_FUNC:
|
||||
{
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [Call Response]
|
||||
const callResponse: string = this.#getDataStrFromPacket(buffer8, this.#PROTOCOL_DATA);
|
||||
if (this.#log) {
|
||||
console.log(`WebUI -> CMD -> Call Response [${callResponse}]`);
|
||||
}
|
||||
if (this.#callPromiseResolve[callId]) {
|
||||
if (this.#log) {
|
||||
console.log(`WebUI -> CMD -> Resolving Response #${callId}...`);
|
||||
}
|
||||
this.#callPromiseResolve[callId]?.(callResponse);
|
||||
this.#callPromiseResolve[callId] = undefined;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case this.#CMD_NAVIGATION:
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [URL]
|
||||
const url: string = this.#getDataStrFromPacket(buffer8, this.#PROTOCOL_DATA);
|
||||
if (this.#log) console.log(`WebUI -> CMD -> Navigation [${url}]`);
|
||||
this.#close(this.#CMD_NAVIGATION, url);
|
||||
break;
|
||||
case this.#CMD_WINDOW_RESIZED:
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [x,y,width,height]
|
||||
const widthAndHeight: string = this.#getDataStrFromPacket(buffer8, this.#PROTOCOL_DATA);
|
||||
const { x, y, width, height } = this.#parseDimensions(widthAndHeight);
|
||||
// Update drag positions
|
||||
this.#currentWindowX = x;
|
||||
this.#currentWindowY = y;
|
||||
if (this.#log) console.log(`WebUI -> CMD -> Window Resized [x: ${x}, y: ${y}, width: ${width}, height: ${height}]`);
|
||||
break;
|
||||
case this.#CMD_NEW_ID:
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [New Element]
|
||||
const newElement: string = this.#getDataStrFromPacket(buffer8, this.#PROTOCOL_DATA);
|
||||
if (this.#log) console.log(`WebUI -> CMD -> New Bind ID [${newElement}]`);
|
||||
if (!this.#bindsList.includes(newElement)) this.#bindsList.push(newElement);
|
||||
// Generate objects
|
||||
this.#updateBindsList();
|
||||
break;
|
||||
case this.#CMD_CLOSE:
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
if (this.#log) {
|
||||
// Debug Close
|
||||
console.log(`WebUI -> CMD -> Close`);
|
||||
if (this.#wsIsConnected()) {
|
||||
this.#wsStayAlive = false;
|
||||
this.#ws.close();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Release Close
|
||||
globalThis.close();
|
||||
}
|
||||
break;
|
||||
case this.#CMD_CHECK_TK:
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [Status]
|
||||
// 5: [BindsList]
|
||||
const status = (buffer8[this.#PROTOCOL_DATA] == 0 ? false : true);
|
||||
const tokenHex = `0x${this.#token.toString(16).padStart(8, '0')}`;
|
||||
if (status) {
|
||||
if (this.#log) console.log(`WebUI -> CMD -> Token [${tokenHex}] Accepted`);
|
||||
this.#TokenAccepted = true;
|
||||
// Get binds list (CSV)
|
||||
let csv: string = this.#getDataStrFromPacket(buffer8, this.#PROTOCOL_DATA + 1);
|
||||
csv = csv.endsWith(',') ? csv.slice(0, -1) : csv;
|
||||
this.#bindsList = csv.split(',');
|
||||
// Generate objects
|
||||
this.#updateBindsList();
|
||||
// User event callback
|
||||
if (this.#eventsCallback) {
|
||||
this.#eventsCallback(this.event.CONNECTED);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this.#log) console.log(`WebUI -> CMD -> Token [${tokenHex}] Not Accepted. Reload page...`);
|
||||
// Refresh the page to get a new token
|
||||
this.#allowNavigation = true;
|
||||
this.#wsStayAlive = false;
|
||||
globalThis.location.reload();
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Raw-binary based commands
|
||||
switch (buffer8[this.#PROTOCOL_CMD]) {
|
||||
case this.#CMD_SEND_RAW:
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [Function,Null,Raw Data]
|
||||
// Get function name
|
||||
const functionName: string = this.#getDataStrFromPacket(buffer8, this.#PROTOCOL_DATA);
|
||||
// Get the raw data
|
||||
const rawDataIndex: number = this.#PROTOCOL_DATA + functionName.length + 1;
|
||||
const rawDataSize: number = (buffer8.length - rawDataIndex) - 1;
|
||||
const userRawData = buffer8.subarray(rawDataIndex, (rawDataIndex + rawDataSize));
|
||||
if (this.#log) console.log(`WebUI -> CMD -> Received Raw ${rawDataSize} bytes for [${functionName}()]`);
|
||||
// Call the user function, and pass the raw data
|
||||
if (typeof window[functionName] === 'function') window[functionName](userRawData);
|
||||
else await AsyncFunction(functionName + '(userRawData)')();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
// -- Public APIs --------------------------
|
||||
/**
|
||||
* Call a backend function
|
||||
*
|
||||
* @param fn - binding name
|
||||
* @param data - data to be send to the backend function
|
||||
* @return - Response of the backend callback string
|
||||
* @example - const res = await webui.call("myID", 123, true, "Hi", new Uint8Array([0x42, 0x43, 0x44]))
|
||||
*/
|
||||
async call(fn: string, ...args: DataTypes[]): Promise<DataTypes> {
|
||||
if (!fn) return Promise.reject(new SyntaxError('No binding name is provided'));
|
||||
|
||||
if (!this.#wsIsConnected()) return Promise.reject(new Error('WebSocket is not connected'));
|
||||
|
||||
// Check binding list
|
||||
if (fn !== '__webui_core_api__') {
|
||||
if (!this.#AllEvents && !this.#bindsList.includes(`${fn}`))
|
||||
return Promise.reject(new ReferenceError(`No binding was found for "${fn}"`));
|
||||
}
|
||||
|
||||
// Call backend and wait for response
|
||||
if (this.#log) console.log(`WebUI -> Calling [${fn}(...)]`);
|
||||
const response = (await this.#callPromise(fn, ...args)) as string;
|
||||
|
||||
// WebUI lib accept `DataTypes` but return only string
|
||||
if (typeof response !== 'string') return '';
|
||||
|
||||
return response;
|
||||
}
|
||||
/**
|
||||
* Active or deactivate webui debug logging
|
||||
*
|
||||
* @param status - log status to set
|
||||
*/
|
||||
setLogging(status: boolean) {
|
||||
if (status) {
|
||||
console.log('WebUI -> Log Enabled.');
|
||||
this.#log = true;
|
||||
} else {
|
||||
console.log('WebUI -> Log Disabled.');
|
||||
this.#log = false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Encode text into base64 string
|
||||
*
|
||||
* @param data - text string
|
||||
*/
|
||||
encode(data: string): string {
|
||||
return btoa(data);
|
||||
}
|
||||
/**
|
||||
* Decode base64 string into text
|
||||
*
|
||||
* @param data - base64 string
|
||||
*/
|
||||
decode(data: string): string {
|
||||
return atob(data);
|
||||
}
|
||||
/**
|
||||
* Set a callback to receive events like connect/disconnect
|
||||
*
|
||||
* @param callback - callback function `myCallback(e)`
|
||||
* @example - webui.setEventCallback((e) => {if(e == webui.event.CONNECTED){ ... }});
|
||||
*/
|
||||
setEventCallback(callback: (e: number) => void): void {
|
||||
this.#eventsCallback = callback;
|
||||
}
|
||||
/**
|
||||
* Check if UI is connected to the back-end. The connection
|
||||
* is done by including `webui.js` virtual file in the HTML.
|
||||
*
|
||||
* @return - Boolean `true` if connected
|
||||
*/
|
||||
isConnected(): boolean {
|
||||
return ((this.#wsIsConnected()) && (this.#TokenAccepted));
|
||||
}
|
||||
/**
|
||||
* Get OS high contrast preference.
|
||||
*
|
||||
* @return - Boolean `True` if OS is using high contrast theme
|
||||
*/
|
||||
async isHighContrast(): Promise<boolean> {
|
||||
// Call a core function and wait for response
|
||||
const response = await this.callCore("high_contrast") as boolean;
|
||||
if (this.#log) console.log(`Core Response: [${response}]`);
|
||||
return response;
|
||||
}
|
||||
/**
|
||||
* When binding all events on the backend, WebUI blocks all navigation events
|
||||
* and sends them to the backend. This API allows you to control that behavior.
|
||||
*
|
||||
* @param status - Boolean `True` means WebUI will allow navigations
|
||||
* @example - webui.allowNavigation(true); // Allow navigation
|
||||
* window.location.replace('www.test.com'); // This will now proceed as usual
|
||||
*/
|
||||
allowNavigation(status: boolean): void {
|
||||
this.#allowNavigation = status;
|
||||
}
|
||||
}
|
||||
// Export
|
||||
type webui = WebuiBridge;
|
||||
export default webui;
|
||||
export type { WebuiBridge };
|
||||
// Wait for the html to be parsed
|
||||
addEventListener('load', () => {
|
||||
document.body.addEventListener('contextmenu', (event) => event.preventDefault());
|
||||
addRefreshableEventListener(document.body, 'input', 'contextmenu', (event) => event.stopPropagation());
|
||||
});
|
File diff suppressed because it is too large
Load Diff
@ -1,719 +0,0 @@
|
||||
'use-strict'; // Force strict mode for transpiled
|
||||
|
||||
/*
|
||||
WebUI Bridge
|
||||
|
||||
http://webui.me
|
||||
https://github.com/webui-dev/webui
|
||||
Copyright (c) 2020-2023 Hassan Draga.
|
||||
Licensed under MIT License.
|
||||
All rights reserved.
|
||||
Canada.
|
||||
|
||||
Converted from JavaScript to TypeScript
|
||||
By Oculi Julien. Copyright (c) 2023.
|
||||
*/
|
||||
|
||||
//@ts-ignore use *.ts import real extension
|
||||
import { AsyncFunction, addRefreshableEventListener } from './utils.ts';
|
||||
|
||||
type DataTypes = string | number | boolean | Uint8Array;
|
||||
|
||||
class WebuiBridge {
|
||||
// WebUI settings
|
||||
#secure: boolean;
|
||||
#token: number;
|
||||
#port: number;
|
||||
#winNum: number;
|
||||
#bindList: string[] = [];
|
||||
#log: boolean;
|
||||
#winX: number;
|
||||
#winY: number;
|
||||
#winW: number;
|
||||
#winH: number;
|
||||
// Internals
|
||||
#ws: WebSocket;
|
||||
#wsStatus = false;
|
||||
#wsStatusOnce = false;
|
||||
#closeReason = 0;
|
||||
#closeValue: string;
|
||||
#hasEvents = false;
|
||||
#callPromiseID = new Uint16Array(1);
|
||||
#callPromiseResolve: (((data: string) => unknown) | undefined)[] = [];
|
||||
#allowNavigation = false;
|
||||
#sendQueue: Uint8Array[] = [];
|
||||
#isSending = false;
|
||||
// WebUI const
|
||||
#WEBUI_SIGNATURE = 221;
|
||||
#CMD_JS = 254;
|
||||
#CMD_JS_QUICK = 253;
|
||||
#CMD_CLICK = 252;
|
||||
#CMD_NAVIGATION = 251;
|
||||
#CMD_CLOSE = 250;
|
||||
#CMD_CALL_FUNC = 249;
|
||||
#CMD_SEND_RAW = 248;
|
||||
#CMD_NEW_ID = 247;
|
||||
#CMD_MULTI = 246;
|
||||
#MULTI_CHUNK_SIZE = 65500;
|
||||
#PROTOCOL_SIZE = 8; // Protocol header size in bytes
|
||||
#PROTOCOL_SIGN = 0; // Protocol byte position: Signature (1 Byte)
|
||||
#PROTOCOL_TOKEN = 1; // Protocol byte position: Token (4 Bytes)
|
||||
#PROTOCOL_ID = 5; // Protocol byte position: ID (2 Bytes)
|
||||
#PROTOCOL_CMD = 7; // Protocol byte position: Command (1 Byte)
|
||||
#PROTOCOL_DATA = 8; // Protocol byte position: Data (n Byte)
|
||||
#Token = new Uint32Array(1);
|
||||
#Ping: Boolean = true;
|
||||
constructor({
|
||||
secure,
|
||||
token,
|
||||
port,
|
||||
winNum,
|
||||
bindList,
|
||||
log = false,
|
||||
winX,
|
||||
winY,
|
||||
winW,
|
||||
winH,
|
||||
}: {
|
||||
secure: boolean;
|
||||
token: number;
|
||||
port: number;
|
||||
winNum: number;
|
||||
bindList: string[];
|
||||
log?: boolean;
|
||||
winX: number;
|
||||
winY: number;
|
||||
winW: number;
|
||||
winH: number;
|
||||
}) {
|
||||
// Constructor arguments are injected by webui.c
|
||||
this.#secure = secure;
|
||||
this.#token = token;
|
||||
this.#port = port;
|
||||
this.#winNum = winNum;
|
||||
this.#bindList = bindList;
|
||||
this.#log = log;
|
||||
this.#winX = winX;
|
||||
this.#winY = winY;
|
||||
this.#winW = winW;
|
||||
this.#winH = winH;
|
||||
// Token
|
||||
this.#Token[0] = this.#token;
|
||||
// Instance
|
||||
if ('webui' in globalThis) {
|
||||
throw new Error('Sorry. WebUI is already defined, only one instance is allowed.');
|
||||
}
|
||||
// Positioning the current window
|
||||
if (this.#winX !== undefined && this.#winY !== undefined) {
|
||||
window.moveTo(this.#winX, this.#winY);
|
||||
}
|
||||
// Resize the current window
|
||||
if (this.#winW !== undefined && this.#winH !== undefined) {
|
||||
window.resizeTo(this.#winW, this.#winH);
|
||||
}
|
||||
// WebSocket
|
||||
if (!('WebSocket' in window)) {
|
||||
alert('Sorry. WebSocket is not supported by your web browser.');
|
||||
if (!this.#log) globalThis.close();
|
||||
}
|
||||
// Connect to the backend application
|
||||
this.#start();
|
||||
// Handle navigation server side
|
||||
if ('navigation' in globalThis) {
|
||||
globalThis.navigation.addEventListener('navigate', (event) => {
|
||||
if (!this.#allowNavigation) {
|
||||
event.preventDefault();
|
||||
const url = new URL(event.destination.url);
|
||||
if (this.#hasEvents) {
|
||||
if (this.#log) console.log(`WebUI -> DOM -> Navigation Event [${url.href}]`);
|
||||
this.#sendEventNavigation(url.href);
|
||||
} else {
|
||||
this.#close(this.#CMD_NAVIGATION, url.href);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Handle all link click to prevent natural navigation
|
||||
// Rebind listener if user inject new html
|
||||
addRefreshableEventListener(document.body, 'a', 'click', (event) => {
|
||||
if (!this.#allowNavigation) {
|
||||
event.preventDefault();
|
||||
const { href } = event.target as HTMLAnchorElement;
|
||||
if (this.#hasEvents) {
|
||||
if (this.#log) console.log(`WebUI -> DOM -> Navigation Click Event [${href}]`);
|
||||
this.#sendEventNavigation(href);
|
||||
} else {
|
||||
this.#close(this.#CMD_NAVIGATION, href);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
// Prevent F5 refresh
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if (this.#log) return; // Allowed in debug mode
|
||||
if (event.key === 'F5') event.preventDefault();
|
||||
});
|
||||
onbeforeunload = () => {
|
||||
this.#close();
|
||||
};
|
||||
setTimeout(() => {
|
||||
if (!this.#wsStatusOnce) {
|
||||
this.#freezeUi();
|
||||
alert('Sorry. WebUI failed to connect to the backend application. Please try again.');
|
||||
if (!this.#log) globalThis.close();
|
||||
}
|
||||
}, 1500);
|
||||
}
|
||||
#close(reason = 0, value = '') {
|
||||
this.#wsStatus = false;
|
||||
this.#closeReason = reason;
|
||||
this.#closeValue = value;
|
||||
this.#ws.close();
|
||||
if (reason === this.#CMD_NAVIGATION) {
|
||||
if (this.#log) {
|
||||
console.log(`WebUI -> Close -> Navigation to [${value}]`);
|
||||
}
|
||||
this.#allowNavigation = true;
|
||||
globalThis.location.replace(this.#closeValue);
|
||||
} else {
|
||||
if (this.#log) {
|
||||
console.log(`WebUI -> Close.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
#freezeUi() {
|
||||
document.body.style.filter = 'contrast(1%)';
|
||||
}
|
||||
#isTextBasedCommand(cmd: number): Boolean {
|
||||
if (cmd !== this.#CMD_SEND_RAW) return true;
|
||||
return false;
|
||||
}
|
||||
#getDataStrFromPacket(buffer: Uint8Array, startIndex: number): string {
|
||||
let stringBytes: number[] = [];
|
||||
for (let i = startIndex; i < buffer.length; i++) {
|
||||
if (buffer[i] === 0) {
|
||||
// Check for null byte
|
||||
break;
|
||||
}
|
||||
stringBytes.push(buffer[i]);
|
||||
}
|
||||
// Convert the array of bytes to a string
|
||||
const stringText = new TextDecoder().decode(new Uint8Array(stringBytes));
|
||||
return stringText;
|
||||
}
|
||||
#getID(buffer: Uint8Array, index: number): number {
|
||||
if (index < 0 || index >= buffer.length - 1) {
|
||||
throw new Error('Index out of bounds or insufficient data.');
|
||||
}
|
||||
const firstByte = buffer[index];
|
||||
const secondByte = buffer[index + 1];
|
||||
const combined = (secondByte << 8) | firstByte; // Works only for little-endian
|
||||
return combined;
|
||||
}
|
||||
#addToken(buffer: Uint8Array, value: number, index: number): void {
|
||||
if (value < 0 || value > 0xffffffff) {
|
||||
throw new Error('Number is out of the range for 4 bytes representation.');
|
||||
}
|
||||
if (index < 0 || index > buffer.length - 4) {
|
||||
throw new Error('Index out of bounds or insufficient space in buffer.');
|
||||
}
|
||||
// WebUI expect Little-endian (Work for Little/Big endian platforms)
|
||||
buffer[index] = value & 0xff; // Least significant byte
|
||||
buffer[index + 1] = (value >>> 8) & 0xff;
|
||||
buffer[index + 2] = (value >>> 16) & 0xff;
|
||||
buffer[index + 3] = (value >>> 24) & 0xff; // Most significant byte
|
||||
}
|
||||
#addID(buffer: Uint8Array, value: number, index: number): void {
|
||||
if (value < 0 || value > 0xffff) {
|
||||
throw new Error('Number is out of the range for 2 bytes representation.');
|
||||
}
|
||||
if (index < 0 || index > buffer.length - 2) {
|
||||
throw new Error('Index out of bounds or insufficient space in buffer.');
|
||||
}
|
||||
// WebUI expect Little-endian (Work for Little/Big endian platforms)
|
||||
buffer[index] = value & 0xff; // Least significant byte
|
||||
buffer[index + 1] = (value >>> 8) & 0xff; // Most significant byte
|
||||
}
|
||||
#start() {
|
||||
this.#generateCallObjects();
|
||||
this.#keepAlive();
|
||||
this.#callPromiseID[0] = 0;
|
||||
if (this.#bindList.includes(this.#winNum + '/')) {
|
||||
this.#hasEvents = true;
|
||||
}
|
||||
const url = this.#secure ? 'wss://localhost' : 'ws://localhost';
|
||||
this.#ws = new WebSocket(`${url}:${this.#port}/_webui_ws_connect`);
|
||||
this.#ws.binaryType = 'arraybuffer';
|
||||
this.#ws.onopen = () => {
|
||||
this.#wsStatus = true;
|
||||
this.#wsStatusOnce = true;
|
||||
if (this.#log) console.log('WebUI -> Connected');
|
||||
this.#clicksListener();
|
||||
};
|
||||
this.#ws.onerror = () => {
|
||||
if (this.#log) console.log('WebUI -> Connection Failed');
|
||||
this.#freezeUi();
|
||||
};
|
||||
this.#ws.onclose = (event) => {
|
||||
this.#wsStatus = false;
|
||||
if (this.#closeReason === this.#CMD_NAVIGATION) {
|
||||
if (this.#log) {
|
||||
console.log(`WebUI -> Connection closed du to Navigation to [${this.#closeValue}]`);
|
||||
}
|
||||
} else {
|
||||
if (this.#log) {
|
||||
console.log(`WebUI -> Connection lost (${event.code})`);
|
||||
this.#freezeUi();
|
||||
} else {
|
||||
this.#closeWindowTimer();
|
||||
}
|
||||
}
|
||||
};
|
||||
this.#ws.onmessage = async (event) => {
|
||||
const buffer8 = new Uint8Array(event.data);
|
||||
if (buffer8.length < this.#PROTOCOL_SIZE) return;
|
||||
if (buffer8[this.#PROTOCOL_SIGN] !== this.#WEBUI_SIGNATURE) return;
|
||||
if (this.#isTextBasedCommand(buffer8[this.#PROTOCOL_CMD])) {
|
||||
// UTF8 Text based commands
|
||||
const callId = this.#getID(buffer8, this.#PROTOCOL_ID);
|
||||
// Process Command
|
||||
switch (buffer8[this.#PROTOCOL_CMD]) {
|
||||
case this.#CMD_JS_QUICK:
|
||||
case this.#CMD_JS:
|
||||
{
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [Script]
|
||||
const script = this.#getDataStrFromPacket(buffer8, this.#PROTOCOL_DATA);
|
||||
const scriptSanitize = script.replace(/(?:\r\n|\r|\n)/g, '\n');
|
||||
if (this.#log) console.log(`WebUI -> CMD -> JS [${scriptSanitize}]`);
|
||||
// Get callback result
|
||||
let FunReturn = 'undefined';
|
||||
let FunError = false;
|
||||
try {
|
||||
FunReturn = await AsyncFunction(scriptSanitize)();
|
||||
} catch (e) {
|
||||
FunError = true;
|
||||
FunReturn = e.message;
|
||||
}
|
||||
// Stop if this is a quick call
|
||||
if (buffer8[this.#PROTOCOL_CMD] === this.#CMD_JS_QUICK) return;
|
||||
// Get the call return
|
||||
if (FunReturn === undefined) {
|
||||
FunReturn = 'undefined';
|
||||
}
|
||||
// Logging
|
||||
if (this.#log && !FunError) console.log(`WebUI -> CMD -> JS -> Return Success [${FunReturn}]`);
|
||||
if (this.#log && FunError) console.log(`WebUI -> CMD -> JS -> Return Error [${FunReturn}]`);
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [Error, Script Response]
|
||||
let packet = new Uint8Array(0);
|
||||
const packetPush = (data: Uint8Array) => {
|
||||
const newPacket = new Uint8Array(packet.length + data.length);
|
||||
newPacket.set(packet);
|
||||
newPacket.set(data, packet.length);
|
||||
packet = newPacket;
|
||||
};
|
||||
const packetPushStr = (data: string) => {
|
||||
const chunkSize = 1024 * 8;
|
||||
if (data.length > chunkSize) {
|
||||
const encoder = new TextEncoder();
|
||||
for (let i = 0; i < data.length; i += chunkSize) {
|
||||
const chunk = data.substring(i, Math.min(i + chunkSize, data.length));
|
||||
const encodedChunk = encoder.encode(chunk);
|
||||
packetPush(encodedChunk);
|
||||
}
|
||||
} else {
|
||||
packetPush(new TextEncoder().encode(data));
|
||||
}
|
||||
};
|
||||
packetPush(new Uint8Array([this.#WEBUI_SIGNATURE]));
|
||||
packetPush(new Uint8Array([0, 0, 0, 0])); // Token (4 Bytes)
|
||||
packetPush(new Uint8Array([0, 0])); // ID (2 Bytes)
|
||||
packetPush(new Uint8Array([this.#CMD_JS]));
|
||||
packetPush(new Uint8Array(FunError ? [1] : [0]));
|
||||
packetPushStr(FunReturn);
|
||||
packetPush(new Uint8Array([0]));
|
||||
this.#addToken(packet, this.#token, this.#PROTOCOL_TOKEN);
|
||||
this.#addID(packet, callId, this.#PROTOCOL_ID);
|
||||
this.#sendData(packet);
|
||||
}
|
||||
break;
|
||||
case this.#CMD_CALL_FUNC:
|
||||
{
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [Call Response]
|
||||
const callResponse = this.#getDataStrFromPacket(buffer8, this.#PROTOCOL_DATA);
|
||||
if (this.#log) {
|
||||
console.log(`WebUI -> CMD -> Call Response [${callResponse}]`);
|
||||
}
|
||||
if (this.#callPromiseResolve[callId]) {
|
||||
if (this.#log) {
|
||||
console.log(`WebUI -> CMD -> Resolving Response #${callId}...`);
|
||||
}
|
||||
this.#callPromiseResolve[callId]?.(callResponse);
|
||||
this.#callPromiseResolve[callId] = undefined;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case this.#CMD_NAVIGATION:
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [URL]
|
||||
const url = this.#getDataStrFromPacket(buffer8, this.#PROTOCOL_DATA);
|
||||
console.log(`WebUI -> CMD -> Navigation [${url}]`);
|
||||
this.#close(this.#CMD_NAVIGATION, url);
|
||||
break;
|
||||
case this.#CMD_NEW_ID:
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [New Element]
|
||||
const newElement = this.#getDataStrFromPacket(buffer8, this.#PROTOCOL_DATA);
|
||||
console.log(`WebUI -> CMD -> New Bind ID [${newElement}]`);
|
||||
if (!this.#bindList.includes(newElement)) this.#bindList.push(newElement);
|
||||
break;
|
||||
case this.#CMD_CLOSE:
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
if (!this.#log) globalThis.close();
|
||||
else {
|
||||
console.log(`WebUI -> CMD -> Close`);
|
||||
this.#ws.close();
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Raw-binary based commands
|
||||
switch (buffer8[this.#PROTOCOL_CMD]) {
|
||||
case this.#CMD_SEND_RAW:
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [Function,Null,Raw Data]
|
||||
// Get function name
|
||||
const functionName: string = this.#getDataStrFromPacket(buffer8, this.#PROTOCOL_DATA);
|
||||
// Get the raw data
|
||||
const rawDataIndex: number = 2 + functionName.length + 1;
|
||||
const userRawData = buffer8.subarray(rawDataIndex);
|
||||
if (this.#log) console.log(`WebUI -> CMD -> Send Raw ${buffer8.length} bytes to [${functionName}()]`);
|
||||
// Call the user function, and pass the raw data
|
||||
if (typeof window[functionName] === 'function') window[functionName](userRawData);
|
||||
else await AsyncFunction(functionName + '(userRawData)')();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
#keepAlive = async () => {
|
||||
while (true) {
|
||||
if (this.#Ping) {
|
||||
// Some web browsers may close the connection
|
||||
// let's send a void message to keep WS open
|
||||
this.#sendData(new TextEncoder().encode('ping'));
|
||||
} else {
|
||||
// There is an active communication
|
||||
this.#Ping = true;
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, 20000));
|
||||
}
|
||||
};
|
||||
#clicksListener() {
|
||||
Object.keys(window).forEach((key) => {
|
||||
if (/^on(click)/.test(key)) {
|
||||
globalThis.addEventListener(key.slice(2), (event) => {
|
||||
if (!(event.target instanceof HTMLElement)) return;
|
||||
if (
|
||||
this.#hasEvents ||
|
||||
(event.target.id !== '' && this.#bindList.includes(this.#winNum + '/' + event.target?.id))
|
||||
) {
|
||||
this.#sendClick(event.target.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
async #sendData(packet: Uint8Array) {
|
||||
this.#Ping = false;
|
||||
if (!this.#wsStatus || packet === undefined) return;
|
||||
// Enqueue the packet
|
||||
this.#sendQueue.push(packet);
|
||||
if (this.#isSending) return;
|
||||
this.#isSending = true;
|
||||
while (this.#sendQueue.length > 0) {
|
||||
const currentPacket = this.#sendQueue.shift()!;
|
||||
if (currentPacket.length < this.#MULTI_CHUNK_SIZE) {
|
||||
this.#ws.send(currentPacket.buffer);
|
||||
} else {
|
||||
// Pre-packet to let WebUI be ready for multi packet
|
||||
const pre_packet = Uint8Array.of(
|
||||
this.#WEBUI_SIGNATURE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, // Token (4 Bytes)
|
||||
0,
|
||||
0, // ID (2 Bytes)
|
||||
this.#CMD_MULTI,
|
||||
...new TextEncoder().encode(currentPacket.length.toString()),
|
||||
0,
|
||||
);
|
||||
this.#ws.send(pre_packet.buffer);
|
||||
// Send chunks
|
||||
let offset = 0;
|
||||
const sendChunk = async () => {
|
||||
if (offset < currentPacket.length) {
|
||||
const chunkSize = Math.min(this.#MULTI_CHUNK_SIZE, currentPacket.length - offset);
|
||||
const chunk = currentPacket.subarray(offset, offset + chunkSize);
|
||||
this.#ws.send(chunk);
|
||||
offset += chunkSize;
|
||||
await sendChunk();
|
||||
}
|
||||
};
|
||||
await sendChunk();
|
||||
}
|
||||
}
|
||||
this.#isSending = false;
|
||||
}
|
||||
#sendClick(elem: string) {
|
||||
if (this.#wsStatus) {
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [Element]
|
||||
const packet =
|
||||
elem !== ''
|
||||
? Uint8Array.of(
|
||||
this.#WEBUI_SIGNATURE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, // Token (4 Bytes)
|
||||
0,
|
||||
0, // ID (2 Bytes)
|
||||
this.#CMD_CLICK,
|
||||
...new TextEncoder().encode(elem),
|
||||
0,
|
||||
)
|
||||
: Uint8Array.of(
|
||||
this.#WEBUI_SIGNATURE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, // Token (4 Bytes)
|
||||
0,
|
||||
0, // ID (2 Bytes)
|
||||
this.#CMD_CLICK,
|
||||
0,
|
||||
);
|
||||
this.#addToken(packet, this.#token, this.#PROTOCOL_TOKEN);
|
||||
// this.#addID(packet, 0, this.#PROTOCOL_ID)
|
||||
this.#sendData(packet);
|
||||
if (this.#log) console.log(`WebUI -> Send Click [${elem}]`);
|
||||
}
|
||||
}
|
||||
#sendEventNavigation(url: string) {
|
||||
if (url !== '') {
|
||||
if (this.#hasEvents) {
|
||||
if (this.#log) console.log(`WebUI -> Send Navigation Event [${url}]`);
|
||||
if (this.#wsStatus && this.#hasEvents) {
|
||||
const packet = Uint8Array.of(
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [URL]
|
||||
this.#WEBUI_SIGNATURE,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0, // Token (4 Bytes)
|
||||
0,
|
||||
0, // ID (2 Bytes)
|
||||
this.#CMD_NAVIGATION,
|
||||
...new TextEncoder().encode(url),
|
||||
);
|
||||
this.#addToken(packet, this.#token, this.#PROTOCOL_TOKEN);
|
||||
// this.#addID(packet, 0, this.#PROTOCOL_ID)
|
||||
this.#sendData(packet);
|
||||
}
|
||||
} else {
|
||||
if (this.#log) console.log(`WebUI -> Navigation To [${url}]`);
|
||||
this.#allowNavigation = true;
|
||||
globalThis.location.replace(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
#closeWindowTimer() {
|
||||
setTimeout(function () {
|
||||
globalThis.close();
|
||||
}, 1000);
|
||||
}
|
||||
#toUint16(value: number): number {
|
||||
return value & 0xffff;
|
||||
}
|
||||
#generateCallObjects() {
|
||||
for (const bind of this.#bindList) {
|
||||
if (bind.trim()) {
|
||||
const fn = bind.replace(`${this.#winNum}/`, '');
|
||||
if (fn.trim()) {
|
||||
this[fn] = (...args: DataTypes[]) => this.call(fn, ...args);
|
||||
if (typeof (window as any)[fn] === 'undefined') {
|
||||
(window as any)[fn] = (...args: string[]) => this.call(fn, ...args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#callPromise(fn: string, ...args: DataTypes[]) {
|
||||
--this.#callPromiseID[0];
|
||||
const callId = this.#toUint16(this.#callPromiseID[0]);
|
||||
// Combine lengths
|
||||
let argsLengths = args
|
||||
.map((arg) => {
|
||||
if (typeof arg === 'object') {
|
||||
// Uint8Array
|
||||
return arg.length;
|
||||
} else {
|
||||
// string, number, boolean
|
||||
return new TextEncoder().encode(arg.toString()).length;
|
||||
}
|
||||
})
|
||||
.join(';');
|
||||
// Combine values
|
||||
let argsValues: Uint8Array = new Uint8Array();
|
||||
for (const arg of args) {
|
||||
let buffer: Uint8Array;
|
||||
if (typeof arg === 'object') {
|
||||
buffer = arg; // Uint8Array
|
||||
} else {
|
||||
// string, number, boolean
|
||||
buffer = new TextEncoder().encode(arg.toString());
|
||||
}
|
||||
const temp = new Uint8Array(argsValues.length + buffer.length + 1);
|
||||
temp.set(argsValues, 0);
|
||||
temp.set(buffer, argsValues.length);
|
||||
temp[argsValues.length + buffer.length] = 0x00;
|
||||
argsValues = temp;
|
||||
}
|
||||
// Protocol
|
||||
// 0: [SIGNATURE]
|
||||
// 1: [TOKEN]
|
||||
// 2: [ID]
|
||||
// 3: [CMD]
|
||||
// 4: [Fn, Null, {LenLen...}, Null, {Data,Null,Data,Null...}]
|
||||
let packet = new Uint8Array(0);
|
||||
const packetPush = (data: Uint8Array) => {
|
||||
const newPacket = new Uint8Array(packet.length + data.length);
|
||||
newPacket.set(packet);
|
||||
newPacket.set(data, packet.length);
|
||||
packet = newPacket;
|
||||
};
|
||||
packetPush(new Uint8Array([this.#WEBUI_SIGNATURE]));
|
||||
packetPush(new Uint8Array([0, 0, 0, 0])); // Token (4 Bytes)
|
||||
packetPush(new Uint8Array([0, 0])); // ID (2 Bytes)
|
||||
packetPush(new Uint8Array([this.#CMD_CALL_FUNC]));
|
||||
packetPush(new TextEncoder().encode(fn));
|
||||
packetPush(new Uint8Array([0]));
|
||||
packetPush(new TextEncoder().encode(argsLengths));
|
||||
packetPush(new Uint8Array([0]));
|
||||
packetPush(new Uint8Array(argsValues));
|
||||
this.#addToken(packet, this.#token, this.#PROTOCOL_TOKEN);
|
||||
this.#addID(packet, callId, this.#PROTOCOL_ID);
|
||||
return new Promise((resolve) => {
|
||||
this.#callPromiseResolve[callId] = resolve;
|
||||
this.#sendData(packet);
|
||||
});
|
||||
}
|
||||
// -- APIs --------------------------
|
||||
/**
|
||||
* Call a backend function
|
||||
*
|
||||
* @param fn - binding name
|
||||
* @param data - data to be send to the backend function
|
||||
* @return - Response of the backend callback string
|
||||
* @example - const res = await webui.call("myID", 123, true, "Hi", new Uint8Array([0x42, 0x43, 0x44]))
|
||||
*/
|
||||
async call(fn: string, ...args: DataTypes[]): Promise<DataTypes> {
|
||||
if (!fn) return Promise.reject(new SyntaxError('No binding name is provided'));
|
||||
|
||||
if (!this.#wsStatus) return Promise.reject(new Error('WebSocket is not connected'));
|
||||
|
||||
// Check binding list
|
||||
if (!this.#hasEvents && !this.#bindList.includes(`${this.#winNum}/${fn}`))
|
||||
return Promise.reject(new ReferenceError(`No binding was found for "${fn}"`));
|
||||
|
||||
// Call backend and wait for response
|
||||
if (this.#log) console.log(`WebUI -> Calling [${fn}(...)]`);
|
||||
const response = (await this.#callPromise(fn, ...args)) as string;
|
||||
|
||||
// WebUI lib accept `DataTypes` but return only string
|
||||
if (typeof response !== 'string') return '';
|
||||
|
||||
return response;
|
||||
}
|
||||
/**
|
||||
* Active or deactivate webui debug logging
|
||||
*
|
||||
* @param status - log status to set
|
||||
*/
|
||||
setLogging(status: boolean) {
|
||||
if (status) {
|
||||
console.log('WebUI -> Log Enabled.');
|
||||
this.#log = true;
|
||||
} else {
|
||||
console.log('WebUI -> Log Disabled.');
|
||||
this.#log = false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Encode text into base64 string
|
||||
*
|
||||
* @param data - text string
|
||||
*/
|
||||
encode(data: string): string {
|
||||
return btoa(data);
|
||||
}
|
||||
/**
|
||||
* Decode base64 string into text
|
||||
*
|
||||
* @param data - base64 string
|
||||
*/
|
||||
decode(data: string): string {
|
||||
return atob(data);
|
||||
}
|
||||
}
|
||||
// Export
|
||||
type webui = WebuiBridge;
|
||||
export default webui;
|
||||
export type { WebuiBridge };
|
||||
// Wait for the html to be parsed
|
||||
addEventListener('load', () => {
|
||||
document.body.addEventListener('contextmenu', (event) => event.preventDefault());
|
||||
addRefreshableEventListener(document.body, 'input', 'contextmenu', (event) => event.stopPropagation());
|
||||
});
|
210
build.zig
Normal file
210
build.zig
Normal file
@ -0,0 +1,210 @@
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
const Build = std.Build;
|
||||
const OptimizeMode = std.builtin.OptimizeMode;
|
||||
const Compile = Build.Step.Compile;
|
||||
const Module = Build.Module;
|
||||
|
||||
const lib_name = "webui";
|
||||
var global_log_level: std.log.Level = .warn;
|
||||
|
||||
/// Vendored dependencies of webui.
|
||||
pub const Dependency = enum {
|
||||
civetweb,
|
||||
// TODO: Check and add all vendored dependencies, e.g. "webview"
|
||||
};
|
||||
|
||||
const DebugDependencies = std.EnumSet(Dependency);
|
||||
|
||||
pub fn build(b: *Build) !void {
|
||||
const target = b.standardTargetOptions(.{});
|
||||
const optimize = b.standardOptimizeOption(.{});
|
||||
|
||||
const is_dynamic = b.option(bool, "dynamic", "build the dynamic library") orelse false;
|
||||
const enable_tls = b.option(bool, "enable-tls", "enable TLS support") orelse false;
|
||||
const verbose = b.option(std.log.Level, "verbose", "set verbose output") orelse .warn;
|
||||
global_log_level = verbose;
|
||||
// TODO: Support list of dependencies once support is limited to >0.13.0
|
||||
const debug = b.option(Dependency, "debug", "enable dependency debug output");
|
||||
const debug_dependencies = DebugDependencies.initMany(if (debug) |d| &.{d} else &.{});
|
||||
|
||||
if (enable_tls and !target.query.isNative()) {
|
||||
log(.err, .WebUI, "cross compilation is not supported with TLS enabled", .{});
|
||||
return error.InvalidBuildConfiguration;
|
||||
}
|
||||
|
||||
log(.info, .WebUI, "Building {s} WebUI library{s}...", .{
|
||||
if (is_dynamic) "dynamic" else "static",
|
||||
if (enable_tls) " with TLS support" else "",
|
||||
});
|
||||
defer {
|
||||
log(.info, .WebUI, "Done.", .{});
|
||||
}
|
||||
|
||||
const webui = if (is_dynamic) b.addSharedLibrary(.{
|
||||
.name = lib_name,
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
.pic = true,
|
||||
}) else b.addStaticLibrary(.{
|
||||
.name = lib_name,
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
try addLinkerFlags(b, webui, enable_tls, debug_dependencies);
|
||||
|
||||
b.installArtifact(webui);
|
||||
|
||||
try build_examples(b, webui);
|
||||
}
|
||||
|
||||
fn addLinkerFlags(
|
||||
b: *Build,
|
||||
webui: *Compile,
|
||||
enable_tls: bool,
|
||||
debug_dependencies: DebugDependencies,
|
||||
) !void {
|
||||
const webui_target = webui.rootModuleTarget();
|
||||
const is_windows = webui_target.os.tag == .windows;
|
||||
const is_darwin = webui_target.os.tag == .macos;
|
||||
const debug = webui.root_module.optimize.? == .Debug;
|
||||
|
||||
// Prepare compiler flags.
|
||||
const no_tls_flags: []const []const u8 = &.{"-DNO_SSL"};
|
||||
const tls_flags: []const []const u8 = &.{ "-DWEBUI_TLS", "-DNO_SSL_DL", "-DOPENSSL_API_1_1" };
|
||||
const civetweb_flags: []const []const u8 = &.{
|
||||
"-DNO_CACHING",
|
||||
"-DNO_CGI",
|
||||
"-DUSE_WEBSOCKET",
|
||||
"-Wno-error=date-time",
|
||||
};
|
||||
|
||||
if (debug) {
|
||||
webui.root_module.addCMacro("WEBUI_LOG", "");
|
||||
}
|
||||
webui.addCSourceFile(.{
|
||||
.file = b.path("src/webui.c"),
|
||||
.flags = if (enable_tls) tls_flags else no_tls_flags,
|
||||
});
|
||||
|
||||
const civetweb_debug = debug and debug_dependencies.contains(.civetweb);
|
||||
webui.addCSourceFile(.{
|
||||
.file = b.path("src/civetweb/civetweb.c"),
|
||||
.flags = if (enable_tls and !civetweb_debug)
|
||||
civetweb_flags ++ tls_flags ++ .{"-DNDEBUG"}
|
||||
else if (enable_tls and civetweb_debug)
|
||||
civetweb_flags ++ tls_flags
|
||||
else if (!enable_tls and !civetweb_debug)
|
||||
civetweb_flags ++ .{"-DUSE_WEBSOCKET"} ++ no_tls_flags ++ .{"-DNDEBUG"}
|
||||
else
|
||||
civetweb_flags ++ .{"-DUSE_WEBSOCKET"} ++ no_tls_flags,
|
||||
});
|
||||
webui.linkLibC();
|
||||
webui.addIncludePath(b.path("include"));
|
||||
webui.installHeader(b.path("include/webui.h"), "webui.h");
|
||||
if (is_darwin) {
|
||||
webui.addCSourceFile(.{
|
||||
.file = b.path("src/webview/wkwebview.m"),
|
||||
.flags = &.{},
|
||||
});
|
||||
webui.linkFramework("Cocoa");
|
||||
webui.linkFramework("WebKit");
|
||||
} else if (is_windows) {
|
||||
webui.linkSystemLibrary("ws2_32");
|
||||
webui.linkSystemLibrary("ole32");
|
||||
if (webui_target.abi == .msvc) {
|
||||
webui.linkSystemLibrary("Advapi32");
|
||||
webui.linkSystemLibrary("Shell32");
|
||||
webui.linkSystemLibrary("user32");
|
||||
}
|
||||
if (enable_tls) {
|
||||
webui.linkSystemLibrary("bcrypt");
|
||||
}
|
||||
}
|
||||
if (enable_tls) {
|
||||
webui.linkSystemLibrary("ssl");
|
||||
webui.linkSystemLibrary("crypto");
|
||||
}
|
||||
|
||||
for (webui.root_module.link_objects.items) |lo| {
|
||||
switch (lo) {
|
||||
.c_source_file => |csf| {
|
||||
log(.debug, .WebUI, "{s} linker flags: {s}", .{
|
||||
csf.file.src_path.sub_path,
|
||||
csf.flags,
|
||||
});
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_examples(b: *Build, webui: *Compile) !void {
|
||||
const build_examples_step = b.step("examples", "builds the library and its examples");
|
||||
const target = webui.root_module.resolved_target.?;
|
||||
const optimize = webui.root_module.optimize.?;
|
||||
|
||||
const examples_path = b.path("examples/C").getPath(b);
|
||||
var examples_dir = std.fs.cwd().openDir(
|
||||
examples_path,
|
||||
.{ .iterate = true },
|
||||
) catch |e| switch (e) {
|
||||
// Do not attempt building examples if directory does not exist.
|
||||
error.FileNotFound => return,
|
||||
else => return e,
|
||||
};
|
||||
defer examples_dir.close();
|
||||
|
||||
var paths = examples_dir.iterate();
|
||||
while (try paths.next()) |val| {
|
||||
if (val.kind != .directory) {
|
||||
continue;
|
||||
}
|
||||
const example_name = val.name;
|
||||
|
||||
const exe = b.addExecutable(.{
|
||||
.name = example_name,
|
||||
.target = target,
|
||||
.optimize = optimize,
|
||||
});
|
||||
const path = try std.fmt.allocPrint(b.allocator, "examples/C/{s}/main.c", .{example_name});
|
||||
defer b.allocator.free(path);
|
||||
|
||||
exe.addCSourceFile(.{ .file = b.path(path), .flags = &.{} });
|
||||
exe.linkLibrary(webui);
|
||||
|
||||
const exe_install = b.addInstallArtifact(exe, .{});
|
||||
const exe_run = b.addRunArtifact(exe);
|
||||
const step_name = try std.fmt.allocPrint(b.allocator, "run_{s}", .{example_name});
|
||||
defer b.allocator.free(step_name);
|
||||
const step_desc = try std.fmt.allocPrint(b.allocator, "run example {s}", .{example_name});
|
||||
defer b.allocator.free(step_desc);
|
||||
|
||||
const cwd = try std.fmt.allocPrint(b.allocator, "src/examples/{s}", .{example_name});
|
||||
defer b.allocator.free(cwd);
|
||||
exe_run.setCwd(b.path(cwd));
|
||||
|
||||
exe_run.step.dependOn(&exe_install.step);
|
||||
build_examples_step.dependOn(&exe_install.step);
|
||||
b.step(step_name, step_desc).dependOn(&exe_run.step);
|
||||
}
|
||||
}
|
||||
|
||||
/// Function to runtime-scope log levels based on build flag, for all scopes.
|
||||
fn log(
|
||||
comptime level: std.log.Level,
|
||||
comptime scope: @TypeOf(.EnumLiteral),
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) void {
|
||||
const should_print: bool = @intFromEnum(global_log_level) >= @intFromEnum(level);
|
||||
if (should_print) {
|
||||
switch (comptime level) {
|
||||
.err => std.log.scoped(scope).err(format, args),
|
||||
.warn => std.log.scoped(scope).warn(format, args),
|
||||
.info => std.log.scoped(scope).info(format, args),
|
||||
.debug => std.log.scoped(scope).debug(format, args),
|
||||
}
|
||||
}
|
||||
}
|
14
build.zig.zon
Normal file
14
build.zig.zon
Normal file
@ -0,0 +1,14 @@
|
||||
.{
|
||||
.name = .webui,
|
||||
.version = "2.5.0-beta.4",
|
||||
.fingerprint = 0xac5d87f2e5831aa7,
|
||||
.paths = .{
|
||||
"src",
|
||||
"include",
|
||||
"bridge",
|
||||
"build.zig",
|
||||
"build.zig.zon",
|
||||
"LICENSE",
|
||||
"README.md",
|
||||
},
|
||||
}
|
@ -4,7 +4,11 @@
|
||||
|
||||
MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
PROJECT_DIR := $(dir $(MAKEFILE_PATH))/../../../
|
||||
TARGET := $(firstword $(MAKECMDGOALS))
|
||||
LIB_DIR := $(PROJECT_DIR)/dist
|
||||
ifeq ($(TARGET), debug)
|
||||
LIB_DIR := $(LIB_DIR)/debug
|
||||
endif
|
||||
INCLUDE_DIR := $(PROJECT_DIR)/include
|
||||
WEBUI_LIB_NAME = webui-2
|
||||
ifeq ($(WEBUI_USE_TLS), 1)
|
||||
@ -13,25 +17,28 @@ endif
|
||||
|
||||
# ARGS
|
||||
# Set a compiler when running on Linux via `make CC=g++` / `make CC=clang`
|
||||
CXX = g++
|
||||
CC = g++
|
||||
# Build the WebUI library if running via `make BUILD_LIB=true`
|
||||
BUILD_LIB ?=
|
||||
|
||||
# BUILD FLAGS
|
||||
STATIC_BUILD_FLAGS = -std=c++17 -lstdc++ main.cpp -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
DYN_BUILD_FLAGS = -std=c++17 -lstdc++ main.cpp -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
STATIC_BUILD_FLAGS = main.cpp -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
DYN_BUILD_FLAGS = main.cpp -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
|
||||
# Platform conditions
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# Windows
|
||||
PLATFORM := windows
|
||||
SHELL := CMD
|
||||
STATIC_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)-static -lws2_32 -Wall -Wl,-subsystem=console -luser32 -static
|
||||
DYN_BUILD_FLAGS += "$(LIB_DIR)/$(WEBUI_LIB_NAME).dll" -lws2_32 -Wall -Wl,-subsystem=console -luser32
|
||||
STATIC_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)-static -lws2_32 -Wall -luser32 -static
|
||||
COPY_LIB_CMD := @copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
DYN_BUILD_FLAGS += "$(WEBUI_LIB_NAME).dll" -lws2_32 -Wall -luser32
|
||||
STATIC_OUT := main.exe
|
||||
DYN_OUT := main-dyn.exe
|
||||
LWS2_OPT := -lws2_32
|
||||
LWS2_OPT := -lws2_32 -lole32
|
||||
STRIP_OPT := --strip-all
|
||||
CONSOLE_APP := -Wl,-subsystem=console
|
||||
GUI_APP := -Wl,-subsystem=windows
|
||||
else
|
||||
STATIC_BUILD_FLAGS += -lpthread -lm -l$(WEBUI_LIB_NAME)-static
|
||||
DYN_BUILD_FLAGS += -lpthread -lm
|
||||
@ -40,14 +47,18 @@ else
|
||||
ifeq ($(shell uname),Darwin)
|
||||
# MacOS
|
||||
PLATFORM := macos
|
||||
DYN_BUILD_FLAGS += "$(LIB_DIR)/$(WEBUI_LIB_NAME).dylib"
|
||||
CXX = clang
|
||||
CC = clang
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).dylib" "lib$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)
|
||||
WKWEBKIT_LINK_FLAGS := -framework Cocoa -framework WebKit
|
||||
else
|
||||
# Linux
|
||||
PLATFORM := linux
|
||||
DYN_BUILD_FLAGS += "$(LIB_DIR)/$(WEBUI_LIB_NAME).so"
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).so" "lib$(WEBUI_LIB_NAME).so"
|
||||
STATIC_BUILD_FLAGS += -ldl
|
||||
DYN_BUILD_FLAGS += -ldl -l$(WEBUI_LIB_NAME)
|
||||
STRIP_OPT := --strip-all
|
||||
ifeq ($(CXX),clang)
|
||||
ifeq ($(CC),clang)
|
||||
LLVM_OPT := llvm-
|
||||
endif
|
||||
endif
|
||||
@ -57,19 +68,19 @@ endif
|
||||
|
||||
all: release
|
||||
|
||||
debug: LIB_DIR := $(LIB_DIR)/debug
|
||||
debug: --validate-args
|
||||
ifeq ($(BUILD_LIB),true)
|
||||
@cd "$(PROJECT_DIR)" && $(MAKE) debug
|
||||
endif
|
||||
# Static with Debug info
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CXX) debug static)..."
|
||||
@$(CXX) -g $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@echo "Build C++ Example ($(CC) debug static)..."
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic with Debug info
|
||||
@echo "Build C Example ($(CXX) debug dynamic)..."
|
||||
@$(CXX) -g $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@echo "Build C++ Example ($(CC) debug dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
@ -85,13 +96,14 @@ ifeq ($(BUILD_LIB),true)
|
||||
endif
|
||||
# Static Release
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CXX) release static)..."
|
||||
@$(CXX) -Os $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@echo "Build C++ Example ($(CC) release static)..."
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic Release
|
||||
@echo "Build C Example ($(CXX) release dynamic)..."
|
||||
@$(CXX) $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@echo "Build C++ Example ($(CC) release dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@ -107,8 +119,8 @@ clean: --clean-$(PLATFORM)
|
||||
# INTERNAL TARGETS
|
||||
|
||||
--validate-args:
|
||||
ifneq ($(filter $(CXX),g++ clang),$(CXX))
|
||||
$(error Invalid compiler specified: `$(CXX)`)
|
||||
ifneq ($(filter $(CC),g++ clang aarch64-linux-gnu-g++ arm-linux-gnueabihf-g++ musl-g++),$(CC))
|
||||
$(error Invalid compiler specified: `$(CC)`)
|
||||
endif
|
||||
|
||||
--clean-linux: --clean-unix
|
||||
|
@ -21,11 +21,11 @@ debug:
|
||||
# Static with Debug info
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C++ Example (Debug Static)...
|
||||
@cl /Zi /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)/debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl /Zi /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)/debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic with Debug info
|
||||
@echo Build C++ Example (Debug Dynamic)...
|
||||
@cl /Zi /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)/debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl /Zi /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)/debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@ -41,11 +41,11 @@ release:
|
||||
# Static Release
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C++ Example (Release Static)...
|
||||
@cl /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic Release
|
||||
@echo Build C++ Example (Release Dynamic)...
|
||||
@cl /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
|
@ -9,7 +9,7 @@
|
||||
void my_function_string(webui::window::event* e) {
|
||||
|
||||
// JavaScript:
|
||||
// webui.call('MyID_One', 'Hello', 'World`);
|
||||
// my_function_string('Hello', 'World`);
|
||||
|
||||
std::string str_1 = e->get_string(); // Or e->get_string(0);
|
||||
std::string str_2 = e->get_string(1);
|
||||
@ -21,7 +21,7 @@ void my_function_string(webui::window::event* e) {
|
||||
void my_function_integer(webui::window::event* e) {
|
||||
|
||||
// JavaScript:
|
||||
// webui.call('MyID_Two', 123, 456, 789);
|
||||
// my_function_integer(123, 456, 789);
|
||||
|
||||
long long number_1 = e->get_int(); // Or e->get_int(0);
|
||||
long long number_2 = e->get_int(1);
|
||||
@ -35,7 +35,7 @@ void my_function_integer(webui::window::event* e) {
|
||||
void my_function_boolean(webui::window::event* e) {
|
||||
|
||||
// JavaScript:
|
||||
// webui.call('MyID_Three', true, false);
|
||||
// my_function_boolean(true, false);
|
||||
|
||||
bool status_1 = e->get_bool(); // Or e->get_bool(0);
|
||||
bool status_2 = e->get_bool(1);
|
||||
@ -47,7 +47,7 @@ void my_function_boolean(webui::window::event* e) {
|
||||
void my_function_with_response(webui::window::event* e) {
|
||||
|
||||
// JavaScript:
|
||||
// webui.call('MyID_Four', number, 2).then(...)
|
||||
// my_function_with_response(number, 2).then(...)
|
||||
|
||||
long long number = e->get_int(0);
|
||||
long long times = e->get_int(1);
|
||||
@ -64,58 +64,58 @@ int main() {
|
||||
|
||||
// HTML
|
||||
const std::string my_html = R"V0G0N(
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<script src="webui.js"></script>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<script src="/webui.js"></script>
|
||||
|
||||
<title>Call C++ from JavaScript Example</title>
|
||||
<style>
|
||||
body {
|
||||
background: linear-gradient(to left, #36265a, #654da9);
|
||||
color: AliceBlue;
|
||||
font-size: 16px sans-serif;
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
}
|
||||
button {
|
||||
margin: 5px 0 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>WebUI - Call C++ from JavaScript</h1>
|
||||
<p>Call C++ functions with arguments (<em>See the logs in your terminal</em>)</p>
|
||||
<button onclick="webui.call('MyID_One', 'Hello', 'World');">Call my_function_string()</button>
|
||||
<br>
|
||||
<button onclick="webui.call('MyID_Two', 123, 456, 789);">Call my_function_integer()</button>
|
||||
<br>
|
||||
<button onclick="webui.call('MyID_Three', true, false);">Call my_function_boolean()</button>
|
||||
<br>
|
||||
<p>Call a C++ function that returns a response</p>
|
||||
<button onclick="MyJS();">Call my_function_with_response()</button>
|
||||
<div>Double: <input type="text" id="MyInputID" value="2"></div>
|
||||
<script>
|
||||
function MyJS() {
|
||||
const MyInput = document.getElementById('MyInputID');
|
||||
const number = MyInput.value;
|
||||
webui.call('MyID_Four', number, 2).then((response) => {
|
||||
MyInput.value = response;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
)V0G0N";
|
||||
<title>Call C++ from JavaScript Example</title>
|
||||
<style>
|
||||
body {
|
||||
background: linear-gradient(to left, #36265a, #654da9);
|
||||
color: AliceBlue;
|
||||
font-size: 16px sans-serif;
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
}
|
||||
button {
|
||||
margin: 5px 0 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>WebUI - Call C++ from JavaScript</h1>
|
||||
<p>Call C++ functions with arguments (<em>See the logs in your terminal</em>)</p>
|
||||
<button onclick="my_function_string('Hello', 'World');">Call my_function_string()</button>
|
||||
<br>
|
||||
<button onclick="my_function_integer(123, 456, 789);">Call my_function_integer()</button>
|
||||
<br>
|
||||
<button onclick="my_function_boolean(true, false);">Call my_function_boolean()</button>
|
||||
<br>
|
||||
<p>Call a C++ function that returns a response</p>
|
||||
<button onclick="MyJS();">Call my_function_with_response()</button>
|
||||
<div>Double: <input type="text" id="MyInputID" value="2"></div>
|
||||
<script>
|
||||
function MyJS() {
|
||||
const MyInput = document.getElementById('MyInputID');
|
||||
const number = MyInput.value;
|
||||
my_function_with_response(number, 2).then((response) => {
|
||||
MyInput.value = response;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
)V0G0N";
|
||||
|
||||
// Create a window
|
||||
webui::window my_window;
|
||||
|
||||
// Bind HTML elements with C++ functions
|
||||
my_window.bind("MyID_One", my_function_string);
|
||||
my_window.bind("MyID_Two", my_function_integer);
|
||||
my_window.bind("MyID_Three", my_function_boolean);
|
||||
my_window.bind("MyID_Four", my_function_with_response);
|
||||
my_window.bind("my_function_string", my_function_string);
|
||||
my_window.bind("my_function_integer", my_function_integer);
|
||||
my_window.bind("my_function_boolean", my_function_boolean);
|
||||
my_window.bind("my_function_with_response", my_function_with_response);
|
||||
|
||||
// Show the window
|
||||
my_window.show(my_html); // webui_show_browser(my_window, my_html, Chrome);
|
||||
|
@ -4,7 +4,11 @@
|
||||
|
||||
MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
PROJECT_DIR := $(dir $(MAKEFILE_PATH))/../../../
|
||||
TARGET := $(firstword $(MAKECMDGOALS))
|
||||
LIB_DIR := $(PROJECT_DIR)/dist
|
||||
ifeq ($(TARGET), debug)
|
||||
LIB_DIR := $(LIB_DIR)/debug
|
||||
endif
|
||||
INCLUDE_DIR := $(PROJECT_DIR)/include
|
||||
WEBUI_LIB_NAME = webui-2
|
||||
ifeq ($(WEBUI_USE_TLS), 1)
|
||||
@ -13,25 +17,28 @@ endif
|
||||
|
||||
# ARGS
|
||||
# Set a compiler when running on Linux via `make CC=g++` / `make CC=clang`
|
||||
CXX = g++
|
||||
CC = g++
|
||||
# Build the WebUI library if running via `make BUILD_LIB=true`
|
||||
BUILD_LIB ?=
|
||||
|
||||
# BUILD FLAGS
|
||||
STATIC_BUILD_FLAGS = -std=c++17 -lstdc++ main.cpp -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
DYN_BUILD_FLAGS = -std=c++17 -lstdc++ main.cpp -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
STATIC_BUILD_FLAGS = main.cpp -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
DYN_BUILD_FLAGS = main.cpp -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
|
||||
# Platform conditions
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# Windows
|
||||
PLATFORM := windows
|
||||
SHELL := CMD
|
||||
STATIC_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)-static -lws2_32 -Wall -Wl,-subsystem=console -luser32 -static
|
||||
DYN_BUILD_FLAGS += "$(LIB_DIR)/$(WEBUI_LIB_NAME).dll" -lws2_32 -Wall -Wl,-subsystem=console -luser32
|
||||
STATIC_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)-static -lws2_32 -Wall -luser32 -static
|
||||
COPY_LIB_CMD := @copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
DYN_BUILD_FLAGS += "$(WEBUI_LIB_NAME).dll" -lws2_32 -Wall -luser32
|
||||
STATIC_OUT := main.exe
|
||||
DYN_OUT := main-dyn.exe
|
||||
LWS2_OPT := -lws2_32
|
||||
LWS2_OPT := -lws2_32 -lole32
|
||||
STRIP_OPT := --strip-all
|
||||
CONSOLE_APP := -Wl,-subsystem=console
|
||||
GUI_APP := -Wl,-subsystem=windows
|
||||
else
|
||||
STATIC_BUILD_FLAGS += -lpthread -lm -l$(WEBUI_LIB_NAME)-static
|
||||
DYN_BUILD_FLAGS += -lpthread -lm
|
||||
@ -40,14 +47,18 @@ else
|
||||
ifeq ($(shell uname),Darwin)
|
||||
# MacOS
|
||||
PLATFORM := macos
|
||||
DYN_BUILD_FLAGS += "$(LIB_DIR)/$(WEBUI_LIB_NAME).dylib"
|
||||
CXX = clang
|
||||
CC = clang
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).dylib" "lib$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)
|
||||
WKWEBKIT_LINK_FLAGS := -framework Cocoa -framework WebKit
|
||||
else
|
||||
# Linux
|
||||
PLATFORM := linux
|
||||
DYN_BUILD_FLAGS += "$(LIB_DIR)/$(WEBUI_LIB_NAME).so"
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).so" "lib$(WEBUI_LIB_NAME).so"
|
||||
STATIC_BUILD_FLAGS += -ldl
|
||||
DYN_BUILD_FLAGS += -ldl -l$(WEBUI_LIB_NAME)
|
||||
STRIP_OPT := --strip-all
|
||||
ifeq ($(CXX),clang)
|
||||
ifeq ($(CC),clang)
|
||||
LLVM_OPT := llvm-
|
||||
endif
|
||||
endif
|
||||
@ -57,19 +68,19 @@ endif
|
||||
|
||||
all: release
|
||||
|
||||
debug: LIB_DIR := $(LIB_DIR)/debug
|
||||
debug: --validate-args
|
||||
ifeq ($(BUILD_LIB),true)
|
||||
@cd "$(PROJECT_DIR)" && $(MAKE) debug
|
||||
endif
|
||||
# Static with Debug info
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CXX) debug static)..."
|
||||
@$(CXX) -g $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@echo "Build C++ Example ($(CC) debug static)..."
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic with Debug info
|
||||
@echo "Build C Example ($(CXX) debug dynamic)..."
|
||||
@$(CXX) -g $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@echo "Build C++ Example ($(CC) debug dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
@ -85,13 +96,14 @@ ifeq ($(BUILD_LIB),true)
|
||||
endif
|
||||
# Static Release
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CXX) release static)..."
|
||||
@$(CXX) -Os $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@echo "Build C++ Example ($(CC) release static)..."
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic Release
|
||||
@echo "Build C Example ($(CXX) release dynamic)..."
|
||||
@$(CXX) $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@echo "Build C++ Example ($(CC) release dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@ -107,8 +119,8 @@ clean: --clean-$(PLATFORM)
|
||||
# INTERNAL TARGETS
|
||||
|
||||
--validate-args:
|
||||
ifneq ($(filter $(CXX),g++ clang),$(CXX))
|
||||
$(error Invalid compiler specified: `$(CXX)`)
|
||||
ifneq ($(filter $(CC),g++ clang aarch64-linux-gnu-g++ arm-linux-gnueabihf-g++ musl-g++),$(CC))
|
||||
$(error Invalid compiler specified: `$(CC)`)
|
||||
endif
|
||||
|
||||
--clean-linux: --clean-unix
|
||||
|
@ -21,11 +21,11 @@ debug:
|
||||
# Static with Debug info
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C++ Example (Debug Static)...
|
||||
@cl /Zi /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)/debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl /Zi /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)/debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic with Debug info
|
||||
@echo Build C++ Example (Debug Dynamic)...
|
||||
@cl /Zi /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)/debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl /Zi /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)/debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@ -41,11 +41,11 @@ release:
|
||||
# Static Release
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C++ Example (Release Static)...
|
||||
@cl /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic Release
|
||||
@echo Build C++ Example (Release Dynamic)...
|
||||
@cl /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
|
@ -17,8 +17,6 @@ void my_function_exit(webui::window::event* e) {
|
||||
|
||||
void my_function_count(webui::window::event* e) {
|
||||
|
||||
// This function gets called every time the user clicks on "MyButton1"
|
||||
|
||||
// Create a buffer to hold the response
|
||||
char response[64];
|
||||
|
||||
@ -55,59 +53,59 @@ int main() {
|
||||
|
||||
// HTML
|
||||
const std::string my_html = R"V0G0N(
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<script src="webui.js"></script>
|
||||
<title>Call JavaScript from C++ Example</title>
|
||||
<style>
|
||||
body {
|
||||
background: linear-gradient(to left, #36265a, #654da9);
|
||||
color: AliceBlue;
|
||||
font: 16px sans-serif;
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
}
|
||||
button {
|
||||
margin: 5px 0 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>WebUI - Call JavaScript from C++</h1>
|
||||
<br>
|
||||
<h1 id="count">0</h1>
|
||||
<br>
|
||||
<button id="MyButton1">Manual Count</button>
|
||||
<br>
|
||||
<button id="MyTest" onclick="AutoTest();">Auto Count (Every 10ms)</button>
|
||||
<br>
|
||||
<button id="MyButton2">Exit</button>
|
||||
<script>
|
||||
let count = 0;
|
||||
function GetCount() {
|
||||
return count;
|
||||
}
|
||||
function SetCount(number) {
|
||||
document.getElementById('count').innerHTML = number;
|
||||
count = number;
|
||||
}
|
||||
function AutoTest(number) {
|
||||
setInterval(function() {
|
||||
webui.call('MyButton1');
|
||||
}, 10);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
)V0G0N";
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<script src="/webui.js"></script>
|
||||
<title>Call JavaScript from C++ Example</title>
|
||||
<style>
|
||||
body {
|
||||
background: linear-gradient(to left, #36265a, #654da9);
|
||||
color: AliceBlue;
|
||||
font: 16px sans-serif;
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
}
|
||||
button {
|
||||
margin: 5px 0 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>WebUI - Call JavaScript from C++</h1>
|
||||
<br>
|
||||
<h1 id="count">0</h1>
|
||||
<br>
|
||||
<button OnClick="my_function_count();">Manual Count</button>
|
||||
<br>
|
||||
<button OnClick="AutoTest();">Auto Count (Every 10ms)</button>
|
||||
<br>
|
||||
<button id="Exit">Exit</button>
|
||||
<script>
|
||||
let count = 0;
|
||||
function GetCount() {
|
||||
return count;
|
||||
}
|
||||
function SetCount(number) {
|
||||
document.getElementById('count').innerHTML = number;
|
||||
count = number;
|
||||
}
|
||||
function AutoTest(number) {
|
||||
setInterval(function() {
|
||||
my_function_count();
|
||||
}, 10);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
)V0G0N";
|
||||
|
||||
// Create a window
|
||||
webui::window my_window;
|
||||
|
||||
// Bind HTML elements with C++ functions
|
||||
my_window.bind("MyButton1", my_function_count);
|
||||
my_window.bind("MyButton2", my_function_exit);
|
||||
my_window.bind("my_function_count", my_function_count);
|
||||
my_window.bind("Exit", my_function_exit);
|
||||
|
||||
// Show the window
|
||||
my_window.show(my_html); // my_window.show_browser(my_html, Chrome);
|
||||
|
@ -4,7 +4,11 @@
|
||||
|
||||
MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
PROJECT_DIR := $(dir $(MAKEFILE_PATH))/../../../
|
||||
TARGET := $(firstword $(MAKECMDGOALS))
|
||||
LIB_DIR := $(PROJECT_DIR)/dist
|
||||
ifeq ($(TARGET), debug)
|
||||
LIB_DIR := $(LIB_DIR)/debug
|
||||
endif
|
||||
INCLUDE_DIR := $(PROJECT_DIR)/include
|
||||
WEBUI_LIB_NAME = webui-2
|
||||
ifeq ($(WEBUI_USE_TLS), 1)
|
||||
@ -13,25 +17,28 @@ endif
|
||||
|
||||
# ARGS
|
||||
# Set a compiler when running on Linux via `make CC=g++` / `make CC=clang`
|
||||
CXX = g++
|
||||
CC = g++
|
||||
# Build the WebUI library if running via `make BUILD_LIB=true`
|
||||
BUILD_LIB ?=
|
||||
|
||||
# BUILD FLAGS
|
||||
STATIC_BUILD_FLAGS = -std=c++17 -lstdc++ main.cpp -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
DYN_BUILD_FLAGS = -std=c++17 -lstdc++ main.cpp -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
STATIC_BUILD_FLAGS = main.cpp -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
DYN_BUILD_FLAGS = main.cpp -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
|
||||
# Platform conditions
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# Windows
|
||||
PLATFORM := windows
|
||||
SHELL := CMD
|
||||
STATIC_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)-static -lws2_32 -Wall -Wl,-subsystem=console -luser32 -static
|
||||
DYN_BUILD_FLAGS += "$(LIB_DIR)/$(WEBUI_LIB_NAME).dll" -lws2_32 -Wall -Wl,-subsystem=console -luser32
|
||||
STATIC_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)-static -lws2_32 -Wall -luser32 -static
|
||||
COPY_LIB_CMD := @copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
DYN_BUILD_FLAGS += "$(WEBUI_LIB_NAME).dll" -lws2_32 -Wall -luser32
|
||||
STATIC_OUT := main.exe
|
||||
DYN_OUT := main-dyn.exe
|
||||
LWS2_OPT := -lws2_32
|
||||
LWS2_OPT := -lws2_32 -lole32
|
||||
STRIP_OPT := --strip-all
|
||||
CONSOLE_APP := -Wl,-subsystem=console
|
||||
GUI_APP := -Wl,-subsystem=windows
|
||||
else
|
||||
STATIC_BUILD_FLAGS += -lpthread -lm -l$(WEBUI_LIB_NAME)-static
|
||||
DYN_BUILD_FLAGS += -lpthread -lm
|
||||
@ -40,14 +47,18 @@ else
|
||||
ifeq ($(shell uname),Darwin)
|
||||
# MacOS
|
||||
PLATFORM := macos
|
||||
DYN_BUILD_FLAGS += "$(LIB_DIR)/$(WEBUI_LIB_NAME).dylib"
|
||||
CXX = clang
|
||||
CC = clang
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).dylib" "lib$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)
|
||||
WKWEBKIT_LINK_FLAGS := -framework Cocoa -framework WebKit
|
||||
else
|
||||
# Linux
|
||||
PLATFORM := linux
|
||||
DYN_BUILD_FLAGS += "$(LIB_DIR)/$(WEBUI_LIB_NAME).so"
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).so" "lib$(WEBUI_LIB_NAME).so"
|
||||
STATIC_BUILD_FLAGS += -ldl
|
||||
DYN_BUILD_FLAGS += -ldl -l$(WEBUI_LIB_NAME)
|
||||
STRIP_OPT := --strip-all
|
||||
ifeq ($(CXX),clang)
|
||||
ifeq ($(CC),clang)
|
||||
LLVM_OPT := llvm-
|
||||
endif
|
||||
endif
|
||||
@ -57,19 +68,19 @@ endif
|
||||
|
||||
all: release
|
||||
|
||||
debug: LIB_DIR := $(LIB_DIR)/debug
|
||||
debug: --validate-args
|
||||
ifeq ($(BUILD_LIB),true)
|
||||
@cd "$(PROJECT_DIR)" && $(MAKE) debug
|
||||
endif
|
||||
# Static with Debug info
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CXX) debug static)..."
|
||||
@$(CXX) -g $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@echo "Build C++ Example ($(CC) debug static)..."
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic with Debug info
|
||||
@echo "Build C Example ($(CXX) debug dynamic)..."
|
||||
@$(CXX) -g $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@echo "Build C++ Example ($(CC) debug dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
@ -85,13 +96,14 @@ ifeq ($(BUILD_LIB),true)
|
||||
endif
|
||||
# Static Release
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CXX) release static)..."
|
||||
@$(CXX) -Os $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@echo "Build C++ Example ($(CC) release static)..."
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic Release
|
||||
@echo "Build C Example ($(CXX) release dynamic)..."
|
||||
@$(CXX) $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@echo "Build C++ Example ($(CC) release dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@ -107,8 +119,8 @@ clean: --clean-$(PLATFORM)
|
||||
# INTERNAL TARGETS
|
||||
|
||||
--validate-args:
|
||||
ifneq ($(filter $(CXX),g++ clang),$(CXX))
|
||||
$(error Invalid compiler specified: `$(CXX)`)
|
||||
ifneq ($(filter $(CC),g++ clang aarch64-linux-gnu-g++ arm-linux-gnueabihf-g++ musl-g++),$(CC))
|
||||
$(error Invalid compiler specified: `$(CC)`)
|
||||
endif
|
||||
|
||||
--clean-linux: --clean-unix
|
||||
|
@ -21,11 +21,11 @@ debug:
|
||||
# Static with Debug info
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C++ Example (Debug Static)...
|
||||
@cl /Zi /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)/debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl /Zi /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)/debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic with Debug info
|
||||
@echo Build C++ Example (Debug Dynamic)...
|
||||
@cl /Zi /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)/debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl /Zi /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)/debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@ -41,11 +41,11 @@ release:
|
||||
# Static Release
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C++ Example (Release Static)...
|
||||
@cl /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic Release
|
||||
@echo Build C++ Example (Release Dynamic)...
|
||||
@cl /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
|
@ -4,7 +4,11 @@
|
||||
|
||||
MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
PROJECT_DIR := $(dir $(MAKEFILE_PATH))/../../../
|
||||
TARGET := $(firstword $(MAKECMDGOALS))
|
||||
LIB_DIR := $(PROJECT_DIR)/dist
|
||||
ifeq ($(TARGET), debug)
|
||||
LIB_DIR := $(LIB_DIR)/debug
|
||||
endif
|
||||
INCLUDE_DIR := $(PROJECT_DIR)/include
|
||||
WEBUI_LIB_NAME = webui-2
|
||||
ifeq ($(WEBUI_USE_TLS), 1)
|
||||
@ -13,25 +17,28 @@ endif
|
||||
|
||||
# ARGS
|
||||
# Set a compiler when running on Linux via `make CC=g++` / `make CC=clang`
|
||||
CXX = g++
|
||||
CC = g++
|
||||
# Build the WebUI library if running via `make BUILD_LIB=true`
|
||||
BUILD_LIB ?=
|
||||
|
||||
# BUILD FLAGS
|
||||
STATIC_BUILD_FLAGS = -std=c++17 -lstdc++ main.cpp -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
DYN_BUILD_FLAGS = -std=c++17 -lstdc++ main.cpp -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
STATIC_BUILD_FLAGS = main.cpp -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
DYN_BUILD_FLAGS = main.cpp -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
|
||||
# Platform conditions
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# Windows
|
||||
PLATFORM := windows
|
||||
SHELL := CMD
|
||||
STATIC_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)-static -lws2_32 -Wall -Wl,-subsystem=console -luser32 -static
|
||||
DYN_BUILD_FLAGS += "$(LIB_DIR)/$(WEBUI_LIB_NAME).dll" -lws2_32 -Wall -Wl,-subsystem=console -luser32
|
||||
STATIC_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)-static -lws2_32 -Wall -luser32 -static
|
||||
COPY_LIB_CMD := @copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
DYN_BUILD_FLAGS += "$(WEBUI_LIB_NAME).dll" -lws2_32 -Wall -luser32
|
||||
STATIC_OUT := main.exe
|
||||
DYN_OUT := main-dyn.exe
|
||||
LWS2_OPT := -lws2_32
|
||||
LWS2_OPT := -lws2_32 -lole32
|
||||
STRIP_OPT := --strip-all
|
||||
CONSOLE_APP := -Wl,-subsystem=console
|
||||
GUI_APP := -Wl,-subsystem=windows
|
||||
else
|
||||
STATIC_BUILD_FLAGS += -lpthread -lm -l$(WEBUI_LIB_NAME)-static
|
||||
DYN_BUILD_FLAGS += -lpthread -lm
|
||||
@ -40,14 +47,18 @@ else
|
||||
ifeq ($(shell uname),Darwin)
|
||||
# MacOS
|
||||
PLATFORM := macos
|
||||
DYN_BUILD_FLAGS += "$(LIB_DIR)/$(WEBUI_LIB_NAME).dylib"
|
||||
CXX = clang
|
||||
CC = clang
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).dylib" "lib$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)
|
||||
WKWEBKIT_LINK_FLAGS := -framework Cocoa -framework WebKit
|
||||
else
|
||||
# Linux
|
||||
PLATFORM := linux
|
||||
DYN_BUILD_FLAGS += "$(LIB_DIR)/$(WEBUI_LIB_NAME).so"
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).so" "lib$(WEBUI_LIB_NAME).so"
|
||||
STATIC_BUILD_FLAGS += -ldl
|
||||
DYN_BUILD_FLAGS += -ldl -l$(WEBUI_LIB_NAME)
|
||||
STRIP_OPT := --strip-all
|
||||
ifeq ($(CXX),clang)
|
||||
ifeq ($(CC),clang)
|
||||
LLVM_OPT := llvm-
|
||||
endif
|
||||
endif
|
||||
@ -57,19 +68,19 @@ endif
|
||||
|
||||
all: release
|
||||
|
||||
debug: LIB_DIR := $(LIB_DIR)/debug
|
||||
debug: --validate-args
|
||||
ifeq ($(BUILD_LIB),true)
|
||||
@cd "$(PROJECT_DIR)" && $(MAKE) debug
|
||||
endif
|
||||
# Static with Debug info
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CXX) debug static)..."
|
||||
@$(CXX) -g $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@echo "Build C++ Example ($(CC) debug static)..."
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic with Debug info
|
||||
@echo "Build C Example ($(CXX) debug dynamic)..."
|
||||
@$(CXX) -g $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@echo "Build C++ Example ($(CC) debug dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
@ -85,13 +96,14 @@ ifeq ($(BUILD_LIB),true)
|
||||
endif
|
||||
# Static Release
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CXX) release static)..."
|
||||
@$(CXX) -Os $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@echo "Build C++ Example ($(CC) release static)..."
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic Release
|
||||
@echo "Build C Example ($(CXX) release dynamic)..."
|
||||
@$(CXX) $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@echo "Build C++ Example ($(CC) release dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@ -107,8 +119,8 @@ clean: --clean-$(PLATFORM)
|
||||
# INTERNAL TARGETS
|
||||
|
||||
--validate-args:
|
||||
ifneq ($(filter $(CXX),g++ clang),$(CXX))
|
||||
$(error Invalid compiler specified: `$(CXX)`)
|
||||
ifneq ($(filter $(CC),g++ clang aarch64-linux-gnu-g++ arm-linux-gnueabihf-g++ musl-g++),$(CC))
|
||||
$(error Invalid compiler specified: `$(CC)`)
|
||||
endif
|
||||
|
||||
--clean-linux: --clean-unix
|
||||
|
@ -21,11 +21,11 @@ debug:
|
||||
# Static with Debug info
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C++ Example (Debug Static)...
|
||||
@cl /Zi /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)/debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl /Zi /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)/debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic with Debug info
|
||||
@echo Build C++ Example (Debug Dynamic)...
|
||||
@cl /Zi /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)/debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl /Zi /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)/debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@ -41,11 +41,11 @@ release:
|
||||
# Static Release
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C++ Example (Release Static)...
|
||||
@cl /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic Release
|
||||
@echo Build C++ Example (Release Dynamic)...
|
||||
@cl /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl /EHsc /std:c++17 main.cpp /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
|
@ -35,5 +35,5 @@
|
||||
</body>
|
||||
|
||||
<!-- Connect this window to the background app -->
|
||||
<script src="webui.js"></script>
|
||||
<script src="/webui.js"></script>
|
||||
</html>
|
||||
|
@ -22,5 +22,5 @@
|
||||
</body>
|
||||
|
||||
<!-- Connect this window to the background app -->
|
||||
<script src="webui.js"></script>
|
||||
<script src="/webui.js"></script>
|
||||
</html>
|
||||
|
@ -35,7 +35,7 @@ ifeq ($(OS),Windows_NT)
|
||||
DYN_BUILD_FLAGS += "$(WEBUI_LIB_NAME).dll" -lws2_32 -Wall -luser32
|
||||
STATIC_OUT := main.exe
|
||||
DYN_OUT := main-dyn.exe
|
||||
LWS2_OPT := -lws2_32
|
||||
LWS2_OPT := -lws2_32 -lole32
|
||||
STRIP_OPT := --strip-all
|
||||
CONSOLE_APP := -Wl,-subsystem=console
|
||||
GUI_APP := -Wl,-subsystem=windows
|
||||
@ -44,19 +44,19 @@ else
|
||||
DYN_BUILD_FLAGS += -lpthread -lm
|
||||
STATIC_OUT := main
|
||||
DYN_OUT := main-dyn
|
||||
CONSOLE_APP :=
|
||||
GUI_APP :=
|
||||
ifeq ($(shell uname),Darwin)
|
||||
# MacOS
|
||||
PLATFORM := macos
|
||||
CC = clang
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/$(WEBUI_LIB_NAME).dylib" "$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += "./$(WEBUI_LIB_NAME).dylib"
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).dylib" "lib$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)
|
||||
WKWEBKIT_LINK_FLAGS := -framework Cocoa -framework WebKit
|
||||
else
|
||||
# Linux
|
||||
PLATFORM := linux
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/$(WEBUI_LIB_NAME).so" "$(WEBUI_LIB_NAME).so"
|
||||
DYN_BUILD_FLAGS += "./$(WEBUI_LIB_NAME).so"
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).so" "lib$(WEBUI_LIB_NAME).so"
|
||||
STATIC_BUILD_FLAGS += -ldl
|
||||
DYN_BUILD_FLAGS += -ldl -l$(WEBUI_LIB_NAME)
|
||||
STRIP_OPT := --strip-all
|
||||
ifeq ($(CC),clang)
|
||||
LLVM_OPT := llvm-
|
||||
@ -75,12 +75,12 @@ endif
|
||||
# Static with Debug info
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) debug static)..."
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic with Debug info
|
||||
@echo "Build C Example ($(CC) debug dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
@ -97,13 +97,13 @@ endif
|
||||
# Static Release
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) release static)..."
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic Release
|
||||
@echo "Build C Example ($(CC) release dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
|
@ -21,18 +21,17 @@ debug:
|
||||
# Static with Debug info
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Debug)...
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic with Debug info
|
||||
@echo Build C Example (Dynamic Debug)...
|
||||
@copy "$(LIB_DIR)\debug\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@- del *.lib >nul 2>&1
|
||||
@- del *.obj >nul 2>&1
|
||||
@- del *.pdb >nul 2>&1
|
||||
@echo Done.
|
||||
|
||||
release:
|
||||
@ -42,12 +41,12 @@ release:
|
||||
# Static Release
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Release)...
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic Release
|
||||
@echo Build C Example (Dynamic Release)...
|
||||
@copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
|
@ -5,7 +5,7 @@
|
||||
void my_function_string(webui_event_t* e) {
|
||||
|
||||
// JavaScript:
|
||||
// webui.call('MyID_One', 'Hello', 'World`);
|
||||
// my_function_string('Hello', 'World`);
|
||||
|
||||
const char* str_1 = webui_get_string(e); // Or webui_get_string_at(e, 0);
|
||||
const char* str_2 = webui_get_string_at(e, 1);
|
||||
@ -17,7 +17,10 @@ void my_function_string(webui_event_t* e) {
|
||||
void my_function_integer(webui_event_t* e) {
|
||||
|
||||
// JavaScript:
|
||||
// webui.call('MyID_Two', 123, 456, 789);
|
||||
// my_function_integer(123, 456, 789, 12345.6789);
|
||||
|
||||
size_t count = webui_get_count(e);
|
||||
printf("my_function_integer: There is %zu arguments in this event\n", count); // 4
|
||||
|
||||
long long number_1 = webui_get_int(e); // Or webui_get_int_at(e, 0);
|
||||
long long number_2 = webui_get_int_at(e, 1);
|
||||
@ -26,12 +29,16 @@ void my_function_integer(webui_event_t* e) {
|
||||
printf("my_function_integer 1: %lld\n", number_1); // 123
|
||||
printf("my_function_integer 2: %lld\n", number_2); // 456
|
||||
printf("my_function_integer 3: %lld\n", number_3); // 789
|
||||
|
||||
double float_1 = webui_get_float_at(e, 3);
|
||||
|
||||
printf("my_function_integer 4: %f\n", float_1); // 12345.6789
|
||||
}
|
||||
|
||||
void my_function_boolean(webui_event_t* e) {
|
||||
|
||||
// JavaScript:
|
||||
// webui.call('MyID_Three', true, false);
|
||||
// my_function_boolean(true, false);
|
||||
|
||||
bool status_1 = webui_get_bool(e); // Or webui_get_bool_at(e, 0);
|
||||
bool status_2 = webui_get_bool_at(e, 1);
|
||||
@ -43,7 +50,7 @@ void my_function_boolean(webui_event_t* e) {
|
||||
void my_function_raw_binary(webui_event_t* e) {
|
||||
|
||||
// JavaScript:
|
||||
// webui.call('MyID_RawBinary', new Uint8Array([0x41]), new Uint8Array([0x42, 0x43]));
|
||||
// my_function_raw_binary(new Uint8Array([0x41]), new Uint8Array([0x42, 0x43]));
|
||||
|
||||
const unsigned char* raw_1 = (const unsigned char*)webui_get_string(e); // Or webui_get_string_at(e, 0);
|
||||
const unsigned char* raw_2 = (const unsigned char*)webui_get_string_at(e, 1);
|
||||
@ -70,7 +77,7 @@ void my_function_raw_binary(webui_event_t* e) {
|
||||
void my_function_with_response(webui_event_t* e) {
|
||||
|
||||
// JavaScript:
|
||||
// webui.call('MyID_Four', number, 2).then(...)
|
||||
// my_function_with_response(number, 2).then(...)
|
||||
|
||||
long long number = webui_get_int(e); // Or webui_get_int_at(e, 0);
|
||||
long long times = webui_get_int_at(e, 1);
|
||||
@ -122,13 +129,13 @@ int main() {
|
||||
" <body>"
|
||||
" <h1>WebUI - Call C from JavaScript</h1>"
|
||||
" <p>Call C functions with arguments (<em>See the logs in your terminal</em>)</p>"
|
||||
" <button onclick=\"webui.call('MyID_One', 'Hello', 'World');\">Call my_function_string()</button>"
|
||||
" <button onclick=\"my_function_string('Hello', 'World');\">Call my_function_string()</button>"
|
||||
" <br>"
|
||||
" <button onclick=\"webui.call('MyID_Two', 123, 456, 789);\">Call my_function_integer()</button>"
|
||||
" <button onclick=\"my_function_integer(123, 456, 789, 12345.6789);\">Call my_function_integer()</button>"
|
||||
" <br>"
|
||||
" <button onclick=\"webui.call('MyID_Three', true, false);\">Call my_function_boolean()</button>"
|
||||
" <button onclick=\"my_function_boolean(true, false);\">Call my_function_boolean()</button>"
|
||||
" <br>"
|
||||
" <button onclick=\"webui.call('MyID_RawBinary', new Uint8Array([0x41,0x42,0x43]), big_arr);\"> "
|
||||
" <button onclick=\"my_function_raw_binary(new Uint8Array([0x41,0x42,0x43]), big_arr);\"> "
|
||||
" Call my_function_raw_binary()</button>"
|
||||
" <br>"
|
||||
" <p>Call a C function that returns a response</p>"
|
||||
@ -142,7 +149,7 @@ int main() {
|
||||
" function MyJS() {"
|
||||
" const MyInput = document.getElementById('MyInputID');"
|
||||
" const number = MyInput.value;"
|
||||
" webui.call('MyID_Four', number, 2).then((response) => {"
|
||||
" my_function_with_response(number, 2).then((response) => {"
|
||||
" MyInput.value = response;"
|
||||
" });"
|
||||
" }"
|
||||
@ -154,11 +161,11 @@ int main() {
|
||||
size_t my_window = webui_new_window();
|
||||
|
||||
// Bind HTML elements with C functions
|
||||
webui_bind(my_window, "MyID_One", my_function_string);
|
||||
webui_bind(my_window, "MyID_Two", my_function_integer);
|
||||
webui_bind(my_window, "MyID_Three", my_function_boolean);
|
||||
webui_bind(my_window, "MyID_Four", my_function_with_response);
|
||||
webui_bind(my_window, "MyID_RawBinary", my_function_raw_binary);
|
||||
webui_bind(my_window, "my_function_string", my_function_string);
|
||||
webui_bind(my_window, "my_function_integer", my_function_integer);
|
||||
webui_bind(my_window, "my_function_boolean", my_function_boolean);
|
||||
webui_bind(my_window, "my_function_with_response", my_function_with_response);
|
||||
webui_bind(my_window, "my_function_raw_binary", my_function_raw_binary);
|
||||
|
||||
// Show the window
|
||||
webui_show(my_window, my_html); // webui_show_browser(my_window, my_html, Chrome);
|
||||
|
@ -35,7 +35,7 @@ ifeq ($(OS),Windows_NT)
|
||||
DYN_BUILD_FLAGS += "$(WEBUI_LIB_NAME).dll" -lws2_32 -Wall -luser32
|
||||
STATIC_OUT := main.exe
|
||||
DYN_OUT := main-dyn.exe
|
||||
LWS2_OPT := -lws2_32
|
||||
LWS2_OPT := -lws2_32 -lole32
|
||||
STRIP_OPT := --strip-all
|
||||
CONSOLE_APP := -Wl,-subsystem=console
|
||||
GUI_APP := -Wl,-subsystem=windows
|
||||
@ -44,19 +44,19 @@ else
|
||||
DYN_BUILD_FLAGS += -lpthread -lm
|
||||
STATIC_OUT := main
|
||||
DYN_OUT := main-dyn
|
||||
CONSOLE_APP :=
|
||||
GUI_APP :=
|
||||
ifeq ($(shell uname),Darwin)
|
||||
# MacOS
|
||||
PLATFORM := macos
|
||||
CC = clang
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/$(WEBUI_LIB_NAME).dylib" "$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += "./$(WEBUI_LIB_NAME).dylib"
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).dylib" "lib$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)
|
||||
WKWEBKIT_LINK_FLAGS := -framework Cocoa -framework WebKit
|
||||
else
|
||||
# Linux
|
||||
PLATFORM := linux
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/$(WEBUI_LIB_NAME).so" "$(WEBUI_LIB_NAME).so"
|
||||
DYN_BUILD_FLAGS += "./$(WEBUI_LIB_NAME).so"
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).so" "lib$(WEBUI_LIB_NAME).so"
|
||||
STATIC_BUILD_FLAGS += -ldl
|
||||
DYN_BUILD_FLAGS += -ldl -l$(WEBUI_LIB_NAME)
|
||||
STRIP_OPT := --strip-all
|
||||
ifeq ($(CC),clang)
|
||||
LLVM_OPT := llvm-
|
||||
@ -75,12 +75,12 @@ endif
|
||||
# Static with Debug info
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) debug static)..."
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic with Debug info
|
||||
@echo "Build C Example ($(CC) debug dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
@ -97,13 +97,13 @@ endif
|
||||
# Static Release
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) release static)..."
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic Release
|
||||
@echo "Build C Example ($(CC) release dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
|
@ -21,18 +21,17 @@ debug:
|
||||
# Static with Debug info
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Debug)...
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic with Debug info
|
||||
@echo Build C Example (Dynamic Debug)...
|
||||
@copy "$(LIB_DIR)\debug\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@- del *.lib >nul 2>&1
|
||||
@- del *.obj >nul 2>&1
|
||||
@- del *.pdb >nul 2>&1
|
||||
@echo Done.
|
||||
|
||||
release:
|
||||
@ -42,12 +41,12 @@ release:
|
||||
# Static Release
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Release)...
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic Release
|
||||
@echo Build C Example (Dynamic Release)...
|
||||
@copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
|
@ -10,7 +10,7 @@ void my_function_exit(webui_event_t* e) {
|
||||
|
||||
void my_function_count(webui_event_t* e) {
|
||||
|
||||
// This function gets called every time the user clicks on "MyButton1"
|
||||
// This function gets called every time the user clicks on "my_function_count"
|
||||
|
||||
// Create a buffer to hold the response
|
||||
char response[64];
|
||||
@ -80,11 +80,11 @@ int main() {
|
||||
" <br>"
|
||||
" <h1 id=\"count\">0</h1>"
|
||||
" <br>"
|
||||
" <button id=\"MyButton1\">Manual Count</button>"
|
||||
" <button OnClick=\"my_function_count();\">Manual Count</button>"
|
||||
" <br>"
|
||||
" <button id=\"MyTest\" OnClick=\"AutoTest();\">Auto Count (Every 10ms)</button>"
|
||||
" <br>"
|
||||
" <button id=\"MyButton2\">Exit</button>"
|
||||
" <button OnClick=\"my_function_exit();\">Exit</button>"
|
||||
" <script>"
|
||||
" let count = 0;"
|
||||
" function GetCount() {"
|
||||
@ -95,7 +95,7 @@ int main() {
|
||||
" count = number;"
|
||||
" }"
|
||||
" function AutoTest(number) {"
|
||||
" setInterval(function(){ webui.call('MyButton1'); }, 10);"
|
||||
" setInterval(function(){ my_function_count(); }, 10);"
|
||||
" }"
|
||||
" </script>"
|
||||
" </body>"
|
||||
@ -105,8 +105,8 @@ int main() {
|
||||
size_t my_window = webui_new_window();
|
||||
|
||||
// Bind HTML elements with C functions
|
||||
webui_bind(my_window, "MyButton1", my_function_count);
|
||||
webui_bind(my_window, "MyButton2", my_function_exit);
|
||||
webui_bind(my_window, "my_function_count", my_function_count);
|
||||
webui_bind(my_window, "my_function_exit", my_function_exit);
|
||||
|
||||
// Show the window
|
||||
webui_show(my_window, my_html); // webui_show_browser(my_window, my_html, Chrome);
|
||||
|
141
examples/C/chatgpt_api/GNUmakefile
Normal file
141
examples/C/chatgpt_api/GNUmakefile
Normal file
@ -0,0 +1,141 @@
|
||||
# WebUI C Example
|
||||
|
||||
# == 1. VARIABLES =============================================================
|
||||
|
||||
MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
PROJECT_DIR := $(dir $(MAKEFILE_PATH))/../../../
|
||||
TARGET := $(firstword $(MAKECMDGOALS))
|
||||
LIB_DIR := $(PROJECT_DIR)/dist
|
||||
ifeq ($(TARGET), debug)
|
||||
LIB_DIR := $(LIB_DIR)/debug
|
||||
endif
|
||||
INCLUDE_DIR := $(PROJECT_DIR)/include
|
||||
WEBUI_LIB_NAME = webui-2
|
||||
ifeq ($(WEBUI_USE_TLS), 1)
|
||||
WEBUI_LIB_NAME = webui-2-secure
|
||||
endif
|
||||
|
||||
# ARGS
|
||||
# Set a compiler when running on Linux via `make CC=gcc` / `make CC=clang`
|
||||
CC = gcc
|
||||
# Build the WebUI library if running via `make BUILD_LIB=true`
|
||||
BUILD_LIB ?=
|
||||
|
||||
# BUILD FLAGS
|
||||
STATIC_BUILD_FLAGS = main.c -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
DYN_BUILD_FLAGS = main.c -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
|
||||
# Platform conditions
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# Windows
|
||||
PLATFORM := windows
|
||||
SHELL := CMD
|
||||
STATIC_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)-static -lws2_32 -Wall -luser32 -static
|
||||
COPY_LIB_CMD := @copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
DYN_BUILD_FLAGS += "$(WEBUI_LIB_NAME).dll" -lws2_32 -Wall -luser32
|
||||
STATIC_OUT := main.exe
|
||||
DYN_OUT := main-dyn.exe
|
||||
LWS2_OPT := -lws2_32 -lole32
|
||||
STRIP_OPT := --strip-all
|
||||
CONSOLE_APP := -Wl,-subsystem=console
|
||||
GUI_APP := -Wl,-subsystem=windows
|
||||
else
|
||||
STATIC_BUILD_FLAGS += -lpthread -lm -l$(WEBUI_LIB_NAME)-static
|
||||
DYN_BUILD_FLAGS += -lpthread -lm
|
||||
STATIC_OUT := main
|
||||
DYN_OUT := main-dyn
|
||||
ifeq ($(shell uname),Darwin)
|
||||
# MacOS
|
||||
PLATFORM := macos
|
||||
CC = clang
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).dylib" "lib$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)
|
||||
WKWEBKIT_LINK_FLAGS := -framework Cocoa -framework WebKit
|
||||
else
|
||||
# Linux
|
||||
PLATFORM := linux
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).so" "lib$(WEBUI_LIB_NAME).so"
|
||||
STATIC_BUILD_FLAGS += -ldl
|
||||
DYN_BUILD_FLAGS += -ldl -l$(WEBUI_LIB_NAME)
|
||||
STRIP_OPT := --strip-all
|
||||
ifeq ($(CC),clang)
|
||||
LLVM_OPT := llvm-
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# == 2.TARGETS ================================================================
|
||||
|
||||
all: release
|
||||
|
||||
debug: --validate-args
|
||||
ifeq ($(BUILD_LIB),true)
|
||||
@cd "$(PROJECT_DIR)" && $(MAKE) debug
|
||||
endif
|
||||
# Static with Debug info
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) debug static)..."
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic with Debug info
|
||||
@echo "Build C Example ($(CC) debug dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
else
|
||||
@- rm -f *.o
|
||||
@- rm -rf *.dSYM # macOS
|
||||
endif
|
||||
@echo "Done."
|
||||
|
||||
release: --validate-args
|
||||
ifeq ($(BUILD_LIB),true)
|
||||
@cd "$(PROJECT_DIR)" && $(MAKE)
|
||||
endif
|
||||
# Static Release
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) release static)..."
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic Release
|
||||
@echo "Build C Example ($(CC) release dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
else
|
||||
@- rm -f *.o
|
||||
@- rm -rf *.dSYM # macOS
|
||||
endif
|
||||
@echo "Done."
|
||||
|
||||
clean: --clean-$(PLATFORM)
|
||||
|
||||
# INTERNAL TARGETS
|
||||
|
||||
--validate-args:
|
||||
ifneq ($(filter $(CC),gcc clang aarch64-linux-gnu-gcc arm-linux-gnueabihf-gcc musl-gcc),$(CC))
|
||||
$(error Invalid compiler specified: `$(CC)`)
|
||||
endif
|
||||
|
||||
--clean-linux: --clean-unix
|
||||
|
||||
--clean-macos: --clean-unix
|
||||
|
||||
--clean-unix:
|
||||
- rm -f *.o
|
||||
- rm -f *.a
|
||||
- rm -f *.so
|
||||
- rm -f *.dylib
|
||||
- rm -rf *.dSYM
|
||||
|
||||
--clean-windows:
|
||||
- del *.o >nul 2>&1
|
||||
- del *.dll >nul 2>&1
|
||||
- del *.a >nul 2>&1
|
||||
- del *.exe >nul 2>&1
|
64
examples/C/chatgpt_api/Makefile
Normal file
64
examples/C/chatgpt_api/Makefile
Normal file
@ -0,0 +1,64 @@
|
||||
# WebUI C Example
|
||||
# Windows - Microsoft Visual C
|
||||
|
||||
SHELL = CMD
|
||||
LIB_DIR = ../../../dist
|
||||
INCLUDE_DIR = ../../../include
|
||||
WEBUI_LIB_NAME = webui-2
|
||||
!IF "$(WEBUI_USE_TLS)" == "1"
|
||||
WEBUI_LIB_NAME = webui-2-secure
|
||||
!ENDIF
|
||||
|
||||
# Build the WebUI library if running `nmake BUILD_LIB=true`
|
||||
BUILD_LIB =
|
||||
|
||||
all: release
|
||||
|
||||
debug:
|
||||
!IF "$(BUILD_LIB)" == "true"
|
||||
@cd "$(LIB_DIR)" && cd .. && $(MAKE) debug
|
||||
!ENDIF
|
||||
# Static with Debug info
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Debug)...
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic with Debug info
|
||||
@echo Build C Example (Dynamic Debug)...
|
||||
@copy "$(LIB_DIR)\debug\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@- del *.lib >nul 2>&1
|
||||
@- del *.obj >nul 2>&1
|
||||
@echo Done.
|
||||
|
||||
release:
|
||||
!IF "$(BUILD_LIB)" == "true"
|
||||
@cd "$(LIB_DIR)" && cd .. && $(MAKE)
|
||||
!ENDIF
|
||||
# Static Release
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Release)...
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic Release
|
||||
@echo Build C Example (Dynamic Release)...
|
||||
@copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@- del *.lib >nul 2>&1
|
||||
@- del *.obj >nul 2>&1
|
||||
@- del *.pdb >nul 2>&1
|
||||
@echo Done.
|
||||
|
||||
clean:
|
||||
- del *.obj >nul 2>&1
|
||||
- del *.ilk >nul 2>&1
|
||||
- del *.pdb >nul 2>&1
|
||||
- del *.exp >nul 2>&1
|
||||
- del *.exe >nul 2>&1
|
||||
- del *.lib >nul 2>&1
|
98
examples/C/chatgpt_api/main.c
Normal file
98
examples/C/chatgpt_api/main.c
Normal file
@ -0,0 +1,98 @@
|
||||
// WebUI C - ChatGPT HTTPS API Example
|
||||
|
||||
#include "webui.h"
|
||||
|
||||
// ChatGPT Configuration
|
||||
#define USER_KEY "sk-proj-xxx-xxxxxxxxxxxxxxxxxxxxxxx_xxx"
|
||||
#define USER_MODEL "gpt-4o"
|
||||
#define USER_ASSISTANT "You are an assistant, answer with very short messages."
|
||||
|
||||
#define BUF_SIZE (1024)
|
||||
size_t hiddenWindow = 0;
|
||||
|
||||
// HTML
|
||||
const char* html = "<!DOCTYPE html>"
|
||||
"<html>"
|
||||
" <head>"
|
||||
" <script src=\"webui.js\"></script>"
|
||||
" </head>"
|
||||
" <body>"
|
||||
" <script>"
|
||||
" function run_gpt_api(userKey, userModel, userAssistant, userContent) {"
|
||||
" const xhr = new XMLHttpRequest();"
|
||||
" xhr.open(\"POST\", \"https://api.openai.com/v1/chat/completions\", false);"
|
||||
" xhr.setRequestHeader(\"Content-Type\", \"application/json\");"
|
||||
" xhr.setRequestHeader(\"Authorization\", \"Bearer \" + userKey);"
|
||||
" xhr.send(JSON.stringify({"
|
||||
" model: userModel,"
|
||||
" messages: ["
|
||||
" { role: \"developer\", content: userAssistant },"
|
||||
" { role: \"user\", content: userContent }"
|
||||
" ]"
|
||||
" }));"
|
||||
" const responseJson = JSON.parse(xhr.responseText);"
|
||||
" if (responseJson.error) {"
|
||||
" return 'Error: ' + responseJson.error.message;"
|
||||
" }"
|
||||
" return (responseJson.choices[0].message.content).trim();"
|
||||
" }"
|
||||
" </script>"
|
||||
" </body>"
|
||||
"</html>";
|
||||
|
||||
bool run_ai_query(const char* user_query, char* ai_response) {
|
||||
|
||||
char js[BUF_SIZE];
|
||||
memset(js, 0, BUF_SIZE);
|
||||
|
||||
// Generate JavaScript
|
||||
sprintf(js,
|
||||
"return run_gpt_api('%s', '%s', '%s', '%s');",
|
||||
USER_KEY, USER_MODEL, USER_ASSISTANT, user_query
|
||||
);
|
||||
|
||||
// Run HTTPS API
|
||||
if (webui_script(hiddenWindow, js, 30, ai_response, BUF_SIZE)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Please provide a query.\nExample: %s What is the capital of Canada?\n", argv[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Initializing
|
||||
char ai_response[BUF_SIZE];
|
||||
char user_query[BUF_SIZE];
|
||||
memset(ai_response, 0, BUF_SIZE);
|
||||
memset(user_query, 0, BUF_SIZE);
|
||||
|
||||
// Get user query
|
||||
for (int i = 1; i < argc; i++) {
|
||||
strcat(user_query, argv[i]);
|
||||
strcat(user_query, " ");
|
||||
}
|
||||
|
||||
// Start WebUI server
|
||||
hiddenWindow = webui_new_window();
|
||||
webui_set_hide(hiddenWindow, true);
|
||||
webui_show_browser(hiddenWindow, html, ChromiumBased);
|
||||
|
||||
// Run HTTPS API
|
||||
if (run_ai_query(user_query, ai_response)) {
|
||||
printf("AI Response: %s\n", ai_response);
|
||||
} else {
|
||||
printf("Error:\n%s\n", ai_response);
|
||||
}
|
||||
|
||||
// Exit
|
||||
webui_exit();
|
||||
webui_clean();
|
||||
|
||||
return 0;
|
||||
}
|
@ -35,7 +35,7 @@ ifeq ($(OS),Windows_NT)
|
||||
DYN_BUILD_FLAGS += "$(WEBUI_LIB_NAME).dll" -lws2_32 -Wall -luser32
|
||||
STATIC_OUT := main.exe
|
||||
DYN_OUT := main-dyn.exe
|
||||
LWS2_OPT := -lws2_32
|
||||
LWS2_OPT := -lws2_32 -lole32
|
||||
STRIP_OPT := --strip-all
|
||||
CONSOLE_APP := -Wl,-subsystem=console
|
||||
GUI_APP := -Wl,-subsystem=windows
|
||||
@ -44,19 +44,19 @@ else
|
||||
DYN_BUILD_FLAGS += -lpthread -lm
|
||||
STATIC_OUT := main
|
||||
DYN_OUT := main-dyn
|
||||
CONSOLE_APP :=
|
||||
GUI_APP :=
|
||||
ifeq ($(shell uname),Darwin)
|
||||
# MacOS
|
||||
PLATFORM := macos
|
||||
CC = clang
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/$(WEBUI_LIB_NAME).dylib" "$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += "./$(WEBUI_LIB_NAME).dylib"
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).dylib" "lib$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)
|
||||
WKWEBKIT_LINK_FLAGS := -framework Cocoa -framework WebKit
|
||||
else
|
||||
# Linux
|
||||
PLATFORM := linux
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/$(WEBUI_LIB_NAME).so" "$(WEBUI_LIB_NAME).so"
|
||||
DYN_BUILD_FLAGS += "./$(WEBUI_LIB_NAME).so"
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).so" "lib$(WEBUI_LIB_NAME).so"
|
||||
STATIC_BUILD_FLAGS += -ldl
|
||||
DYN_BUILD_FLAGS += -ldl -l$(WEBUI_LIB_NAME)
|
||||
STRIP_OPT := --strip-all
|
||||
ifeq ($(CC),clang)
|
||||
LLVM_OPT := llvm-
|
||||
@ -75,12 +75,12 @@ endif
|
||||
# Static with Debug info
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) debug static)..."
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic with Debug info
|
||||
@echo "Build C Example ($(CC) debug dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
@ -97,13 +97,13 @@ endif
|
||||
# Static Release
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) release static)..."
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic Release
|
||||
@echo "Build C Example ($(CC) release dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
|
@ -21,18 +21,17 @@ debug:
|
||||
# Static with Debug info
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Debug)...
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic with Debug info
|
||||
@echo Build C Example (Dynamic Debug)...
|
||||
@copy "$(LIB_DIR)\debug\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@- del *.lib >nul 2>&1
|
||||
@- del *.obj >nul 2>&1
|
||||
@- del *.pdb >nul 2>&1
|
||||
@echo Done.
|
||||
|
||||
release:
|
||||
@ -42,12 +41,12 @@ release:
|
||||
# Static Release
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Release)...
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic Release
|
||||
@echo Build C Example (Dynamic Release)...
|
||||
@copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
|
@ -50,9 +50,9 @@ int main() {
|
||||
// Bind HTML elements with C functions
|
||||
webui_bind(window, "my_backend_func", my_backend_func);
|
||||
|
||||
// Set web server network port WebUI should use
|
||||
// this mean `webui.js` will be available at:
|
||||
// http://localhost:8081/webui.js
|
||||
// Set the web-server/WebSocket port that WebUI should
|
||||
// use. This means `webui.js` will be available at:
|
||||
// http://localhost:MY_PORT_NUMBER/webui.js
|
||||
webui_set_port(window, 8081);
|
||||
|
||||
// Show a new window and show our custom web server
|
||||
|
141
examples/C/frameless/GNUmakefile
Normal file
141
examples/C/frameless/GNUmakefile
Normal file
@ -0,0 +1,141 @@
|
||||
# WebUI C Example
|
||||
|
||||
# == 1. VARIABLES =============================================================
|
||||
|
||||
MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
PROJECT_DIR := $(dir $(MAKEFILE_PATH))/../../../
|
||||
TARGET := $(firstword $(MAKECMDGOALS))
|
||||
LIB_DIR := $(PROJECT_DIR)/dist
|
||||
ifeq ($(TARGET), debug)
|
||||
LIB_DIR := $(LIB_DIR)/debug
|
||||
endif
|
||||
INCLUDE_DIR := $(PROJECT_DIR)/include
|
||||
WEBUI_LIB_NAME = webui-2
|
||||
ifeq ($(WEBUI_USE_TLS), 1)
|
||||
WEBUI_LIB_NAME = webui-2-secure
|
||||
endif
|
||||
|
||||
# ARGS
|
||||
# Set a compiler when running on Linux via `make CC=gcc` / `make CC=clang`
|
||||
CC = gcc
|
||||
# Build the WebUI library if running via `make BUILD_LIB=true`
|
||||
BUILD_LIB ?=
|
||||
|
||||
# BUILD FLAGS
|
||||
STATIC_BUILD_FLAGS = main.c -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
DYN_BUILD_FLAGS = main.c -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
|
||||
# Platform conditions
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# Windows
|
||||
PLATFORM := windows
|
||||
SHELL := CMD
|
||||
STATIC_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)-static -lws2_32 -Wall -luser32 -static
|
||||
COPY_LIB_CMD := @copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
DYN_BUILD_FLAGS += "$(WEBUI_LIB_NAME).dll" -lws2_32 -Wall -luser32
|
||||
STATIC_OUT := main.exe
|
||||
DYN_OUT := main-dyn.exe
|
||||
LWS2_OPT := -lws2_32 -lole32
|
||||
STRIP_OPT := --strip-all
|
||||
CONSOLE_APP := -Wl,-subsystem=console
|
||||
GUI_APP := -Wl,-subsystem=windows
|
||||
else
|
||||
STATIC_BUILD_FLAGS += -lpthread -lm -l$(WEBUI_LIB_NAME)-static
|
||||
DYN_BUILD_FLAGS += -lpthread -lm
|
||||
STATIC_OUT := main
|
||||
DYN_OUT := main-dyn
|
||||
ifeq ($(shell uname),Darwin)
|
||||
# MacOS
|
||||
PLATFORM := macos
|
||||
CC = clang
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).dylib" "lib$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)
|
||||
WKWEBKIT_LINK_FLAGS := -framework Cocoa -framework WebKit
|
||||
else
|
||||
# Linux
|
||||
PLATFORM := linux
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).so" "lib$(WEBUI_LIB_NAME).so"
|
||||
STATIC_BUILD_FLAGS += -ldl
|
||||
DYN_BUILD_FLAGS += -ldl -l$(WEBUI_LIB_NAME)
|
||||
STRIP_OPT := --strip-all
|
||||
ifeq ($(CC),clang)
|
||||
LLVM_OPT := llvm-
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# == 2.TARGETS ================================================================
|
||||
|
||||
all: release
|
||||
|
||||
debug: --validate-args
|
||||
ifeq ($(BUILD_LIB),true)
|
||||
@cd "$(PROJECT_DIR)" && $(MAKE) debug
|
||||
endif
|
||||
# Static with Debug info
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) debug static)..."
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic with Debug info
|
||||
@echo "Build C Example ($(CC) debug dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
else
|
||||
@- rm -f *.o
|
||||
@- rm -rf *.dSYM # macOS
|
||||
endif
|
||||
@echo "Done."
|
||||
|
||||
release: --validate-args
|
||||
ifeq ($(BUILD_LIB),true)
|
||||
@cd "$(PROJECT_DIR)" && $(MAKE)
|
||||
endif
|
||||
# Static Release
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) release static)..."
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic Release
|
||||
@echo "Build C Example ($(CC) release dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
else
|
||||
@- rm -f *.o
|
||||
@- rm -rf *.dSYM # macOS
|
||||
endif
|
||||
@echo "Done."
|
||||
|
||||
clean: --clean-$(PLATFORM)
|
||||
|
||||
# INTERNAL TARGETS
|
||||
|
||||
--validate-args:
|
||||
ifneq ($(filter $(CC),gcc clang aarch64-linux-gnu-gcc arm-linux-gnueabihf-gcc musl-gcc),$(CC))
|
||||
$(error Invalid compiler specified: `$(CC)`)
|
||||
endif
|
||||
|
||||
--clean-linux: --clean-unix
|
||||
|
||||
--clean-macos: --clean-unix
|
||||
|
||||
--clean-unix:
|
||||
- rm -f *.o
|
||||
- rm -f *.a
|
||||
- rm -f *.so
|
||||
- rm -f *.dylib
|
||||
- rm -rf *.dSYM
|
||||
|
||||
--clean-windows:
|
||||
- del *.o >nul 2>&1
|
||||
- del *.dll >nul 2>&1
|
||||
- del *.a >nul 2>&1
|
||||
- del *.exe >nul 2>&1
|
64
examples/C/frameless/Makefile
Normal file
64
examples/C/frameless/Makefile
Normal file
@ -0,0 +1,64 @@
|
||||
# WebUI C Example
|
||||
# Windows - Microsoft Visual C
|
||||
|
||||
SHELL = CMD
|
||||
LIB_DIR = ../../../dist
|
||||
INCLUDE_DIR = ../../../include
|
||||
WEBUI_LIB_NAME = webui-2
|
||||
!IF "$(WEBUI_USE_TLS)" == "1"
|
||||
WEBUI_LIB_NAME = webui-2-secure
|
||||
!ENDIF
|
||||
|
||||
# Build the WebUI library if running `nmake BUILD_LIB=true`
|
||||
BUILD_LIB =
|
||||
|
||||
all: release
|
||||
|
||||
debug:
|
||||
!IF "$(BUILD_LIB)" == "true"
|
||||
@cd "$(LIB_DIR)" && cd .. && $(MAKE) debug
|
||||
!ENDIF
|
||||
# Static with Debug info
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Debug)...
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic with Debug info
|
||||
@echo Build C Example (Dynamic Debug)...
|
||||
@copy "$(LIB_DIR)\debug\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@- del *.lib >nul 2>&1
|
||||
@- del *.obj >nul 2>&1
|
||||
@echo Done.
|
||||
|
||||
release:
|
||||
!IF "$(BUILD_LIB)" == "true"
|
||||
@cd "$(LIB_DIR)" && cd .. && $(MAKE)
|
||||
!ENDIF
|
||||
# Static Release
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Release)...
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic Release
|
||||
@echo Build C Example (Dynamic Release)...
|
||||
@copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@- del *.lib >nul 2>&1
|
||||
@- del *.obj >nul 2>&1
|
||||
@- del *.pdb >nul 2>&1
|
||||
@echo Done.
|
||||
|
||||
clean:
|
||||
- del *.obj >nul 2>&1
|
||||
- del *.ilk >nul 2>&1
|
||||
- del *.pdb >nul 2>&1
|
||||
- del *.exp >nul 2>&1
|
||||
- del *.exe >nul 2>&1
|
||||
- del *.lib >nul 2>&1
|
105
examples/C/frameless/main.c
Normal file
105
examples/C/frameless/main.c
Normal file
@ -0,0 +1,105 @@
|
||||
// WebUI C - Frameless Example
|
||||
|
||||
#include "webui.h"
|
||||
|
||||
const char* html =
|
||||
"<html>"
|
||||
" <head>"
|
||||
" <meta charset='UTF-8'>"
|
||||
" <script src=\"webui.js\"></script>"
|
||||
" <style>"
|
||||
" * { margin: 0; padding: 0; box-sizing: border-box; }"
|
||||
" html, body { height: 100%; width: 100%; overflow: hidden; background: transparent; }"
|
||||
" #titlebar {"
|
||||
" height: 40px;"
|
||||
" background: linear-gradient(to right, #2c3e50, #34495e);"
|
||||
" color: white;"
|
||||
" display: flex;"
|
||||
" align-items: center;"
|
||||
" justify-content: space-between;"
|
||||
" padding: 0 15px;"
|
||||
" box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);"
|
||||
" -webkit-app-region: drag;"
|
||||
" font-family: Arial, sans-serif;"
|
||||
" }"
|
||||
" #title { font-size: 16px; font-weight: bold; }"
|
||||
" #buttons { -webkit-app-region: no-drag; }"
|
||||
" .button {"
|
||||
" display: inline-block;"
|
||||
" width: 24px;"
|
||||
" height: 24px;"
|
||||
" margin-left: 8px;"
|
||||
" border-radius: 50%;"
|
||||
" text-align: center;"
|
||||
" line-height: 24px;"
|
||||
" cursor: pointer;"
|
||||
" transition: all 0.2s;"
|
||||
" }"
|
||||
" .minimize { background: #f1c40f; }"
|
||||
" .maximize { background: #2ecc71; }"
|
||||
" .close { background: #e74c3c; }"
|
||||
" .button:hover { filter: brightness(120%); }"
|
||||
" #content {"
|
||||
" height: calc(100% - 40px);"
|
||||
" background: rgba(0, 0, 0, 0.7);"
|
||||
" display: flex;"
|
||||
" align-items: center;"
|
||||
" justify-content: center;"
|
||||
" }"
|
||||
" #message {"
|
||||
" color: white;"
|
||||
" font-size: 32px;"
|
||||
" font-family: Arial, sans-serif;"
|
||||
" text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);"
|
||||
" }"
|
||||
" </style>"
|
||||
" </head>"
|
||||
" <body>"
|
||||
" <div id='titlebar'>"
|
||||
" <span id='title'>WebUI Frameless Window</span>"
|
||||
" <div id='buttons'>"
|
||||
" <span class='button minimize' onclick='minimize()'>–</span>"
|
||||
// " <span class='button maximize' onclick='maximize()'>□</span>"
|
||||
" <span class='button close' onclick='close_win()'>✕</span>"
|
||||
" </div>"
|
||||
" </div>"
|
||||
" <div id='content'>"
|
||||
" <span id='message'>This is a WebUI frameless example</span>"
|
||||
" </div>"
|
||||
" </body>"
|
||||
"</html>";
|
||||
|
||||
void minimize(webui_event_t* e) {
|
||||
webui_minimize(e->window);
|
||||
}
|
||||
|
||||
void maximize(webui_event_t* e) {
|
||||
webui_maximize(e->window);
|
||||
}
|
||||
|
||||
void close_win(webui_event_t* e) {
|
||||
webui_close(e->window);
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
size_t my_window = webui_new_window();
|
||||
|
||||
webui_bind(my_window, "minimize", minimize);
|
||||
webui_bind(my_window, "maximize", maximize);
|
||||
webui_bind(my_window, "close_win", close_win);
|
||||
|
||||
webui_set_size(my_window, 800, 600);
|
||||
webui_set_frameless(my_window, true);
|
||||
webui_set_transparent(my_window, true);
|
||||
webui_set_resizable(my_window, false);
|
||||
webui_set_center(my_window);
|
||||
|
||||
webui_show_wv(my_window, html);
|
||||
webui_wait();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, PSTR cmdline, int cmdshow) { return main(); }
|
||||
#endif
|
BIN
examples/C/frameless/webui_frameless.png
Normal file
BIN
examples/C/frameless/webui_frameless.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 303 KiB |
@ -35,7 +35,7 @@ ifeq ($(OS),Windows_NT)
|
||||
DYN_BUILD_FLAGS += "$(WEBUI_LIB_NAME).dll" -lws2_32 -Wall -luser32
|
||||
STATIC_OUT := main.exe
|
||||
DYN_OUT := main-dyn.exe
|
||||
LWS2_OPT := -lws2_32
|
||||
LWS2_OPT := -lws2_32 -lole32
|
||||
STRIP_OPT := --strip-all
|
||||
CONSOLE_APP := -Wl,-subsystem=console
|
||||
GUI_APP := -Wl,-subsystem=windows
|
||||
@ -44,19 +44,19 @@ else
|
||||
DYN_BUILD_FLAGS += -lpthread -lm
|
||||
STATIC_OUT := main
|
||||
DYN_OUT := main-dyn
|
||||
CONSOLE_APP :=
|
||||
GUI_APP :=
|
||||
ifeq ($(shell uname),Darwin)
|
||||
# MacOS
|
||||
PLATFORM := macos
|
||||
CC = clang
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/$(WEBUI_LIB_NAME).dylib" "$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += "./$(WEBUI_LIB_NAME).dylib"
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).dylib" "lib$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)
|
||||
WKWEBKIT_LINK_FLAGS := -framework Cocoa -framework WebKit
|
||||
else
|
||||
# Linux
|
||||
PLATFORM := linux
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/$(WEBUI_LIB_NAME).so" "$(WEBUI_LIB_NAME).so"
|
||||
DYN_BUILD_FLAGS += "./$(WEBUI_LIB_NAME).so"
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).so" "lib$(WEBUI_LIB_NAME).so"
|
||||
STATIC_BUILD_FLAGS += -ldl
|
||||
DYN_BUILD_FLAGS += -ldl -l$(WEBUI_LIB_NAME)
|
||||
STRIP_OPT := --strip-all
|
||||
ifeq ($(CC),clang)
|
||||
LLVM_OPT := llvm-
|
||||
@ -75,12 +75,12 @@ endif
|
||||
# Static with Debug info
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) debug static)..."
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic with Debug info
|
||||
@echo "Build C Example ($(CC) debug dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
@ -97,13 +97,13 @@ endif
|
||||
# Static Release
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) release static)..."
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic Release
|
||||
@echo "Build C Example ($(CC) release dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
|
@ -21,18 +21,17 @@ debug:
|
||||
# Static with Debug info
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Debug)...
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic with Debug info
|
||||
@echo Build C Example (Dynamic Debug)...
|
||||
@copy "$(LIB_DIR)\debug\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@- del *.lib >nul 2>&1
|
||||
@- del *.obj >nul 2>&1
|
||||
@- del *.pdb >nul 2>&1
|
||||
@echo Done.
|
||||
|
||||
release:
|
||||
@ -42,12 +41,12 @@ release:
|
||||
# Static Release
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Release)...
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic Release
|
||||
@echo Build C Example (Dynamic Release)...
|
||||
@copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
|
141
examples/C/public_network_access/GNUmakefile
Normal file
141
examples/C/public_network_access/GNUmakefile
Normal file
@ -0,0 +1,141 @@
|
||||
# WebUI C Example
|
||||
|
||||
# == 1. VARIABLES =============================================================
|
||||
|
||||
MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
PROJECT_DIR := $(dir $(MAKEFILE_PATH))/../../../
|
||||
TARGET := $(firstword $(MAKECMDGOALS))
|
||||
LIB_DIR := $(PROJECT_DIR)/dist
|
||||
ifeq ($(TARGET), debug)
|
||||
LIB_DIR := $(LIB_DIR)/debug
|
||||
endif
|
||||
INCLUDE_DIR := $(PROJECT_DIR)/include
|
||||
WEBUI_LIB_NAME = webui-2
|
||||
ifeq ($(WEBUI_USE_TLS), 1)
|
||||
WEBUI_LIB_NAME = webui-2-secure
|
||||
endif
|
||||
|
||||
# ARGS
|
||||
# Set a compiler when running on Linux via `make CC=gcc` / `make CC=clang`
|
||||
CC = gcc
|
||||
# Build the WebUI library if running via `make BUILD_LIB=true`
|
||||
BUILD_LIB ?=
|
||||
|
||||
# BUILD FLAGS
|
||||
STATIC_BUILD_FLAGS = main.c -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
DYN_BUILD_FLAGS = main.c -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
|
||||
# Platform conditions
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# Windows
|
||||
PLATFORM := windows
|
||||
SHELL := CMD
|
||||
STATIC_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)-static -lws2_32 -Wall -luser32 -static
|
||||
COPY_LIB_CMD := @copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
DYN_BUILD_FLAGS += "$(WEBUI_LIB_NAME).dll" -lws2_32 -Wall -luser32
|
||||
STATIC_OUT := main.exe
|
||||
DYN_OUT := main-dyn.exe
|
||||
LWS2_OPT := -lws2_32 -lole32
|
||||
STRIP_OPT := --strip-all
|
||||
CONSOLE_APP := -Wl,-subsystem=console
|
||||
GUI_APP := -Wl,-subsystem=windows
|
||||
else
|
||||
STATIC_BUILD_FLAGS += -lpthread -lm -l$(WEBUI_LIB_NAME)-static
|
||||
DYN_BUILD_FLAGS += -lpthread -lm
|
||||
STATIC_OUT := main
|
||||
DYN_OUT := main-dyn
|
||||
ifeq ($(shell uname),Darwin)
|
||||
# MacOS
|
||||
PLATFORM := macos
|
||||
CC = clang
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).dylib" "lib$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)
|
||||
WKWEBKIT_LINK_FLAGS := -framework Cocoa -framework WebKit
|
||||
else
|
||||
# Linux
|
||||
PLATFORM := linux
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).so" "lib$(WEBUI_LIB_NAME).so"
|
||||
STATIC_BUILD_FLAGS += -ldl
|
||||
DYN_BUILD_FLAGS += -ldl -l$(WEBUI_LIB_NAME)
|
||||
STRIP_OPT := --strip-all
|
||||
ifeq ($(CC),clang)
|
||||
LLVM_OPT := llvm-
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# == 2.TARGETS ================================================================
|
||||
|
||||
all: release
|
||||
|
||||
debug: --validate-args
|
||||
ifeq ($(BUILD_LIB),true)
|
||||
@cd "$(PROJECT_DIR)" && $(MAKE) debug
|
||||
endif
|
||||
# Static with Debug info
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) debug static)..."
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic with Debug info
|
||||
@echo "Build C Example ($(CC) debug dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
else
|
||||
@- rm -f *.o
|
||||
@- rm -rf *.dSYM # macOS
|
||||
endif
|
||||
@echo "Done."
|
||||
|
||||
release: --validate-args
|
||||
ifeq ($(BUILD_LIB),true)
|
||||
@cd "$(PROJECT_DIR)" && $(MAKE)
|
||||
endif
|
||||
# Static Release
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) release static)..."
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic Release
|
||||
@echo "Build C Example ($(CC) release dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
else
|
||||
@- rm -f *.o
|
||||
@- rm -rf *.dSYM # macOS
|
||||
endif
|
||||
@echo "Done."
|
||||
|
||||
clean: --clean-$(PLATFORM)
|
||||
|
||||
# INTERNAL TARGETS
|
||||
|
||||
--validate-args:
|
||||
ifneq ($(filter $(CC),gcc clang aarch64-linux-gnu-gcc arm-linux-gnueabihf-gcc musl-gcc),$(CC))
|
||||
$(error Invalid compiler specified: `$(CC)`)
|
||||
endif
|
||||
|
||||
--clean-linux: --clean-unix
|
||||
|
||||
--clean-macos: --clean-unix
|
||||
|
||||
--clean-unix:
|
||||
- rm -f *.o
|
||||
- rm -f *.a
|
||||
- rm -f *.so
|
||||
- rm -f *.dylib
|
||||
- rm -rf *.dSYM
|
||||
|
||||
--clean-windows:
|
||||
- del *.o >nul 2>&1
|
||||
- del *.dll >nul 2>&1
|
||||
- del *.a >nul 2>&1
|
||||
- del *.exe >nul 2>&1
|
64
examples/C/public_network_access/Makefile
Normal file
64
examples/C/public_network_access/Makefile
Normal file
@ -0,0 +1,64 @@
|
||||
# WebUI C Example
|
||||
# Windows - Microsoft Visual C
|
||||
|
||||
SHELL = CMD
|
||||
LIB_DIR = ../../../dist
|
||||
INCLUDE_DIR = ../../../include
|
||||
WEBUI_LIB_NAME = webui-2
|
||||
!IF "$(WEBUI_USE_TLS)" == "1"
|
||||
WEBUI_LIB_NAME = webui-2-secure
|
||||
!ENDIF
|
||||
|
||||
# Build the WebUI library if running `nmake BUILD_LIB=true`
|
||||
BUILD_LIB =
|
||||
|
||||
all: release
|
||||
|
||||
debug:
|
||||
!IF "$(BUILD_LIB)" == "true"
|
||||
@cd "$(LIB_DIR)" && cd .. && $(MAKE) debug
|
||||
!ENDIF
|
||||
# Static with Debug info
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Debug)...
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic with Debug info
|
||||
@echo Build C Example (Dynamic Debug)...
|
||||
@copy "$(LIB_DIR)\debug\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@- del *.lib >nul 2>&1
|
||||
@- del *.obj >nul 2>&1
|
||||
@echo Done.
|
||||
|
||||
release:
|
||||
!IF "$(BUILD_LIB)" == "true"
|
||||
@cd "$(LIB_DIR)" && cd .. && $(MAKE)
|
||||
!ENDIF
|
||||
# Static Release
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Release)...
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic Release
|
||||
@echo Build C Example (Dynamic Release)...
|
||||
@copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@- del *.lib >nul 2>&1
|
||||
@- del *.obj >nul 2>&1
|
||||
@- del *.pdb >nul 2>&1
|
||||
@echo Done.
|
||||
|
||||
clean:
|
||||
- del *.obj >nul 2>&1
|
||||
- del *.ilk >nul 2>&1
|
||||
- del *.pdb >nul 2>&1
|
||||
- del *.exp >nul 2>&1
|
||||
- del *.exe >nul 2>&1
|
||||
- del *.lib >nul 2>&1
|
126
examples/C/public_network_access/main.c
Normal file
126
examples/C/public_network_access/main.c
Normal file
@ -0,0 +1,126 @@
|
||||
// Public Network Access Example
|
||||
|
||||
#include "webui.h"
|
||||
|
||||
// Windows
|
||||
size_t private_window = 0;
|
||||
size_t public_window = 0;
|
||||
|
||||
void app_exit(webui_event_t* e) {
|
||||
webui_exit();
|
||||
}
|
||||
|
||||
void public_window_events(webui_event_t* e) {
|
||||
if (e->event_type == WEBUI_EVENT_CONNECTED) {
|
||||
// New connection
|
||||
webui_run(private_window, "document.getElementById(\"Logs\").value += \"New connection.\\n\";");
|
||||
}
|
||||
else if (e->event_type == WEBUI_EVENT_DISCONNECTED) {
|
||||
// Disconnection
|
||||
webui_run(private_window, "document.getElementById(\"Logs\").value += \"Disconnected.\\n\";");
|
||||
}
|
||||
}
|
||||
|
||||
void private_window_events(webui_event_t* e) {
|
||||
if (e->event_type == WEBUI_EVENT_CONNECTED) {
|
||||
// Get URL of public window
|
||||
const char* public_win_url = webui_get_url(public_window);
|
||||
char javascript[1024];
|
||||
sprintf(javascript, "document.getElementById('urlSpan').innerHTML = '%s';", public_win_url);
|
||||
webui_run(private_window, javascript);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
// Main Private Window HTML
|
||||
const char* private_html = "<!DOCTYPE html>"
|
||||
"<html>"
|
||||
" <head>"
|
||||
" <meta charset=\"UTF-8\">"
|
||||
" <script src=\"webui.js\"></script>"
|
||||
" <title>Public Network Access Example</title>"
|
||||
" <style>"
|
||||
" body {"
|
||||
" font-family: 'Arial', sans-serif;"
|
||||
" color: white;"
|
||||
" background: linear-gradient(to right, #507d91, #1c596f, #022737);"
|
||||
" text-align: center;"
|
||||
" font-size: 18px;"
|
||||
" }"
|
||||
" button, input {"
|
||||
" padding: 10px;"
|
||||
" margin: 10px;"
|
||||
" border-radius: 3px;"
|
||||
" border: 1px solid #ccc;"
|
||||
" box-shadow: 0 3px 5px rgba(0,0,0,0.1);"
|
||||
" transition: 0.2s;"
|
||||
" }"
|
||||
" button {"
|
||||
" background: #3498db;"
|
||||
" color: #fff; "
|
||||
" cursor: pointer;"
|
||||
" font-size: 16px;"
|
||||
" }"
|
||||
" h1 { text-shadow: -7px 10px 7px rgb(67 57 57 / 76%); }"
|
||||
" button:hover { background: #c9913d; }"
|
||||
" input:focus { outline: none; border-color: #3498db; }"
|
||||
" </style>"
|
||||
" </head>"
|
||||
" <body>"
|
||||
" <h1>WebUI - Public Network Access Example</h1>"
|
||||
" <br>"
|
||||
" The second public window is configured to be accessible from <br>"
|
||||
" any device in the public network. <br>"
|
||||
" <br>"
|
||||
" Second public window link: <br>"
|
||||
" <h1 id=\"urlSpan\" style=\"color:#c9913d\">...</h1>"
|
||||
" Second public window events: <br>"
|
||||
" <textarea id=\"Logs\" rows=\"4\" cols=\"50\" style=\"width:80%\"></textarea>"
|
||||
" <br>"
|
||||
" <button id=\"Exit\">Exit</button>"
|
||||
" </body>"
|
||||
"</html>";
|
||||
|
||||
// Public Window HTML
|
||||
const char* public_html = "<!DOCTYPE html>"
|
||||
"<html>"
|
||||
" <head>"
|
||||
" <meta charset=\"UTF-8\">"
|
||||
" <script src=\"webui.js\"></script>"
|
||||
" <title>Welcome to Public UI</title>"
|
||||
" </head>"
|
||||
" <body>"
|
||||
" <h1>Welcome to Public UI!</h1>"
|
||||
" </body>"
|
||||
"</html>";
|
||||
|
||||
// Create windows
|
||||
private_window = webui_new_window();
|
||||
public_window = webui_new_window();
|
||||
|
||||
// App
|
||||
webui_set_timeout(0); // Wait forever (never timeout)
|
||||
|
||||
// Public Window
|
||||
webui_set_public(public_window, true); // Make URL accessible from public networks
|
||||
webui_bind(public_window, "", public_window_events); // Bind all events
|
||||
webui_show_browser(public_window, public_html, NoBrowser); // Set public window HTML
|
||||
|
||||
// Private Window
|
||||
webui_bind(private_window, "", private_window_events); // Run JS
|
||||
webui_bind(private_window, "Exit", app_exit); // Bind exit button
|
||||
webui_show(private_window, private_html); // Show the window
|
||||
|
||||
// Wait until all windows get closed
|
||||
webui_wait();
|
||||
|
||||
// Free all memory resources (Optional)
|
||||
webui_clean();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, PSTR cmdline, int cmdshow) { return main(); }
|
||||
#endif
|
141
examples/C/react/GNUmakefile
Normal file
141
examples/C/react/GNUmakefile
Normal file
@ -0,0 +1,141 @@
|
||||
# WebUI C Example
|
||||
|
||||
# == 1. VARIABLES =============================================================
|
||||
|
||||
MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
PROJECT_DIR := $(dir $(MAKEFILE_PATH))/../../../
|
||||
TARGET := $(firstword $(MAKECMDGOALS))
|
||||
LIB_DIR := $(PROJECT_DIR)/dist
|
||||
ifeq ($(TARGET), debug)
|
||||
LIB_DIR := $(LIB_DIR)/debug
|
||||
endif
|
||||
INCLUDE_DIR := $(PROJECT_DIR)/include
|
||||
WEBUI_LIB_NAME = webui-2
|
||||
ifeq ($(WEBUI_USE_TLS), 1)
|
||||
WEBUI_LIB_NAME = webui-2-secure
|
||||
endif
|
||||
|
||||
# ARGS
|
||||
# Set a compiler when running on Linux via `make CC=gcc` / `make CC=clang`
|
||||
CC = gcc
|
||||
# Build the WebUI library if running via `make BUILD_LIB=true`
|
||||
BUILD_LIB ?=
|
||||
|
||||
# BUILD FLAGS
|
||||
STATIC_BUILD_FLAGS = main.c -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
DYN_BUILD_FLAGS = main.c -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
|
||||
# Platform conditions
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# Windows
|
||||
PLATFORM := windows
|
||||
SHELL := CMD
|
||||
STATIC_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)-static -lws2_32 -Wall -luser32 -static
|
||||
COPY_LIB_CMD := @copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
DYN_BUILD_FLAGS += "$(WEBUI_LIB_NAME).dll" -lws2_32 -Wall -luser32
|
||||
STATIC_OUT := main.exe
|
||||
DYN_OUT := main-dyn.exe
|
||||
LWS2_OPT := -lws2_32 -lole32
|
||||
STRIP_OPT := --strip-all
|
||||
CONSOLE_APP := -Wl,-subsystem=console
|
||||
GUI_APP := -Wl,-subsystem=windows
|
||||
else
|
||||
STATIC_BUILD_FLAGS += -lpthread -lm -l$(WEBUI_LIB_NAME)-static
|
||||
DYN_BUILD_FLAGS += -lpthread -lm
|
||||
STATIC_OUT := main
|
||||
DYN_OUT := main-dyn
|
||||
ifeq ($(shell uname),Darwin)
|
||||
# MacOS
|
||||
PLATFORM := macos
|
||||
CC = clang
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).dylib" "lib$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)
|
||||
WKWEBKIT_LINK_FLAGS := -framework Cocoa -framework WebKit
|
||||
else
|
||||
# Linux
|
||||
PLATFORM := linux
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).so" "lib$(WEBUI_LIB_NAME).so"
|
||||
STATIC_BUILD_FLAGS += -ldl
|
||||
DYN_BUILD_FLAGS += -ldl -l$(WEBUI_LIB_NAME)
|
||||
STRIP_OPT := --strip-all
|
||||
ifeq ($(CC),clang)
|
||||
LLVM_OPT := llvm-
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# == 2.TARGETS ================================================================
|
||||
|
||||
all: release
|
||||
|
||||
debug: --validate-args
|
||||
ifeq ($(BUILD_LIB),true)
|
||||
@cd "$(PROJECT_DIR)" && $(MAKE) debug
|
||||
endif
|
||||
# Static with Debug info
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) debug static)..."
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic with Debug info
|
||||
@echo "Build C Example ($(CC) debug dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
else
|
||||
@- rm -f *.o
|
||||
@- rm -rf *.dSYM # macOS
|
||||
endif
|
||||
@echo "Done."
|
||||
|
||||
release: --validate-args
|
||||
ifeq ($(BUILD_LIB),true)
|
||||
@cd "$(PROJECT_DIR)" && $(MAKE)
|
||||
endif
|
||||
# Static Release
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) release static)..."
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic Release
|
||||
@echo "Build C Example ($(CC) release dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
else
|
||||
@- rm -f *.o
|
||||
@- rm -rf *.dSYM # macOS
|
||||
endif
|
||||
@echo "Done."
|
||||
|
||||
clean: --clean-$(PLATFORM)
|
||||
|
||||
# INTERNAL TARGETS
|
||||
|
||||
--validate-args:
|
||||
ifneq ($(filter $(CC),gcc clang aarch64-linux-gnu-gcc arm-linux-gnueabihf-gcc musl-gcc),$(CC))
|
||||
$(error Invalid compiler specified: `$(CC)`)
|
||||
endif
|
||||
|
||||
--clean-linux: --clean-unix
|
||||
|
||||
--clean-macos: --clean-unix
|
||||
|
||||
--clean-unix:
|
||||
- rm -f *.o
|
||||
- rm -f *.a
|
||||
- rm -f *.so
|
||||
- rm -f *.dylib
|
||||
- rm -rf *.dSYM
|
||||
|
||||
--clean-windows:
|
||||
- del *.o >nul 2>&1
|
||||
- del *.dll >nul 2>&1
|
||||
- del *.a >nul 2>&1
|
||||
- del *.exe >nul 2>&1
|
64
examples/C/react/Makefile
Normal file
64
examples/C/react/Makefile
Normal file
@ -0,0 +1,64 @@
|
||||
# WebUI C Example
|
||||
# Windows - Microsoft Visual C
|
||||
|
||||
SHELL = CMD
|
||||
LIB_DIR = ../../../dist
|
||||
INCLUDE_DIR = ../../../include
|
||||
WEBUI_LIB_NAME = webui-2
|
||||
!IF "$(WEBUI_USE_TLS)" == "1"
|
||||
WEBUI_LIB_NAME = webui-2-secure
|
||||
!ENDIF
|
||||
|
||||
# Build the WebUI library if running `nmake BUILD_LIB=true`
|
||||
BUILD_LIB =
|
||||
|
||||
all: release
|
||||
|
||||
debug:
|
||||
!IF "$(BUILD_LIB)" == "true"
|
||||
@cd "$(LIB_DIR)" && cd .. && $(MAKE) debug
|
||||
!ENDIF
|
||||
# Static with Debug info
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Debug)...
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic with Debug info
|
||||
@echo Build C Example (Dynamic Debug)...
|
||||
@copy "$(LIB_DIR)\debug\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@- del *.lib >nul 2>&1
|
||||
@- del *.obj >nul 2>&1
|
||||
@echo Done.
|
||||
|
||||
release:
|
||||
!IF "$(BUILD_LIB)" == "true"
|
||||
@cd "$(LIB_DIR)" && cd .. && $(MAKE)
|
||||
!ENDIF
|
||||
# Static Release
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Release)...
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic Release
|
||||
@echo Build C Example (Dynamic Release)...
|
||||
@copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@- del *.lib >nul 2>&1
|
||||
@- del *.obj >nul 2>&1
|
||||
@- del *.pdb >nul 2>&1
|
||||
@echo Done.
|
||||
|
||||
clean:
|
||||
- del *.obj >nul 2>&1
|
||||
- del *.ilk >nul 2>&1
|
||||
- del *.pdb >nul 2>&1
|
||||
- del *.exp >nul 2>&1
|
||||
- del *.exe >nul 2>&1
|
||||
- del *.lib >nul 2>&1
|
22
examples/C/react/README.md
Normal file
22
examples/C/react/README.md
Normal file
@ -0,0 +1,22 @@
|
||||
## React WebUI Example
|
||||
|
||||
This is a basic example of how to use WebUI with React to generate a portable single executable program. WebUI will run the internal web server and use any installed web browser as GUI to show the React UI.
|
||||
|
||||
A simple Python script `vfs.py` is used to generate `vfs.h` to embed the whole react's build folder into the portable single executable program.
|
||||
|
||||

|
||||
|
||||
### How to use it?
|
||||
|
||||
1. Run script `build_react` to re-build the React project and compile the C file
|
||||
|
||||
### How to create a React WebUI project from scratch?
|
||||
|
||||
1. Run `npx create-react-app my-react-app` to create a React app using NPM
|
||||
2. Add `<script src="webui.js"></script>` into `public/index.html` to connect UI with the backend
|
||||
3. Run `python vfs.py "./my-react-app/build" "vfs.h"` to embed the build folder
|
||||
4. Now, use any C compiler to compile `main.c` into a portable executable program
|
||||
|
||||
### Other backend languages examples:
|
||||
|
||||
- Coming soon...
|
19
examples/C/react/build_react.bat
Normal file
19
examples/C/react/build_react.bat
Normal file
@ -0,0 +1,19 @@
|
||||
@echo off
|
||||
|
||||
echo.
|
||||
echo * Build React project...
|
||||
|
||||
cd webui-react-example
|
||||
call npm install
|
||||
call npm run build
|
||||
cd ..
|
||||
|
||||
echo.
|
||||
echo * Embedding React's build files into 'vfs.h'
|
||||
|
||||
python vfs.py "./webui-react-example/build" "vfs.h"
|
||||
|
||||
echo.
|
||||
echo * Compiling 'main.c' into 'main.exe' using Microsoft Visual Studio...
|
||||
|
||||
nmake
|
19
examples/C/react/build_react.sh
Normal file
19
examples/C/react/build_react.sh
Normal file
@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo
|
||||
echo "* Build React project..."
|
||||
|
||||
cd webui-react-example
|
||||
npm install || exit
|
||||
npm run build || exit
|
||||
cd ..
|
||||
|
||||
echo
|
||||
echo "* Embedding React's build files into 'vfs.h'"
|
||||
|
||||
python3 vfs.py "./webui-react-example/build" "vfs.h"
|
||||
|
||||
echo
|
||||
echo "* Compiling 'main.c' into 'main' using GCC..."
|
||||
|
||||
make
|
59
examples/C/react/main.c
Normal file
59
examples/C/react/main.c
Normal file
@ -0,0 +1,59 @@
|
||||
// React Example
|
||||
|
||||
#include "webui.h"
|
||||
#include "vfs.h"
|
||||
|
||||
void exit_app(webui_event_t* e) {
|
||||
webui_exit();
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
// Create new windows
|
||||
size_t react_window = webui_new_window();
|
||||
|
||||
// Set window size
|
||||
webui_set_size(react_window, 550, 450);
|
||||
|
||||
// Set window position
|
||||
webui_set_position(react_window, 250, 250);
|
||||
|
||||
// Allow multi-user connection to WebUI window
|
||||
webui_set_config(multi_client, true);
|
||||
|
||||
// Disable WebUI's cookies
|
||||
webui_set_config(use_cookies, false);
|
||||
|
||||
// Bind React HTML element IDs with a C functions
|
||||
webui_bind(react_window, "Exit", exit_app);
|
||||
|
||||
// VSF (Virtual File System) Example
|
||||
//
|
||||
// 1. Run Python script to generate header file of a folder
|
||||
// python vfs.py "/path/to/folder" "vfs.h"
|
||||
//
|
||||
// 2. Include header file in your C project
|
||||
// #include "vfs.h"
|
||||
//
|
||||
// 3. use vfs in your custom files handler `webui_set_file_handler()`
|
||||
// webui_set_file_handler(react_window, vfs);
|
||||
|
||||
// Set a custom files handler
|
||||
webui_set_file_handler(react_window, vfs);
|
||||
|
||||
// Show the React window
|
||||
// webui_show_browser(react_window, "index.html", Chrome);
|
||||
webui_show(react_window, "index.html");
|
||||
|
||||
// Wait until all windows get closed
|
||||
webui_wait();
|
||||
|
||||
// Free all memory resources (Optional)
|
||||
webui_clean();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, PSTR cmdline, int cmdshow) { return main(); }
|
||||
#endif
|
142
examples/C/react/vfs.h
Normal file
142
examples/C/react/vfs.h
Normal file
File diff suppressed because one or more lines are too long
117
examples/C/react/vfs.py
Normal file
117
examples/C/react/vfs.py
Normal file
@ -0,0 +1,117 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
def generate_vfs_header(directory, output_header):
|
||||
files = []
|
||||
index_files = {}
|
||||
|
||||
for root, _, filenames in os.walk(directory):
|
||||
for filename in filenames:
|
||||
filepath = os.path.join(root, filename)
|
||||
relative_path = os.path.relpath(filepath, directory)
|
||||
# Ensure path starts with a slash
|
||||
relative_path = '/' + relative_path.replace('\\', '/')
|
||||
files.append((relative_path, filepath))
|
||||
|
||||
# Check for index files
|
||||
if filename.startswith("index."):
|
||||
dir_path = os.path.dirname(relative_path)
|
||||
if dir_path not in index_files:
|
||||
index_files[dir_path] = relative_path
|
||||
|
||||
with open(output_header, 'w') as header:
|
||||
header.write('#ifndef VIRTUAL_FILE_SYSTEM_H\n')
|
||||
header.write('#define VIRTUAL_FILE_SYSTEM_H\n\n')
|
||||
|
||||
header.write('typedef struct {\n')
|
||||
header.write(' const char *path;\n')
|
||||
header.write(' const unsigned char *data;\n')
|
||||
header.write(' int length;\n')
|
||||
header.write('} VirtualFile;\n\n')
|
||||
|
||||
header.write('static const VirtualFile virtual_files[] = {\n')
|
||||
|
||||
for relative_path, filepath in files:
|
||||
with open(filepath, 'rb') as f:
|
||||
data = f.read()
|
||||
header.write(' {\n')
|
||||
header.write(f' "{relative_path}",\n')
|
||||
header.write(' (const unsigned char[]){')
|
||||
header.write(','.join(f'0x{byte:02x}' for byte in data))
|
||||
header.write('},\n')
|
||||
header.write(f' {len(data)}\n')
|
||||
header.write(' },\n')
|
||||
|
||||
header.write('};\n\n')
|
||||
|
||||
header.write('static const int virtual_files_count = sizeof(virtual_files) / sizeof(virtual_files[0]);\n\n')
|
||||
|
||||
header.write('static const char* index_files[] = {\n')
|
||||
for dir_path, index_path in index_files.items():
|
||||
header.write(f' "{dir_path}/", "{index_path}",\n')
|
||||
header.write(' NULL\n')
|
||||
header.write('};\n\n')
|
||||
|
||||
header.write('bool virtual_file_system(const char* path, const unsigned char** file, int* length) {\n')
|
||||
header.write(' for (int i = 0; i < virtual_files_count; ++i) {\n')
|
||||
header.write(' if (strcmp(virtual_files[i].path, path) == 0) {\n')
|
||||
header.write(' *file = virtual_files[i].data;\n')
|
||||
header.write(' *length = virtual_files[i].length;\n')
|
||||
header.write(' return true;\n')
|
||||
header.write(' }\n')
|
||||
header.write(' }\n')
|
||||
header.write(' return false;\n')
|
||||
header.write('}\n\n')
|
||||
|
||||
header.write('const void* vfs(const char* path, int* length) {\n')
|
||||
header.write(' const unsigned char* file_data;\n')
|
||||
header.write(' int file_length;\n\n')
|
||||
|
||||
header.write(' if (virtual_file_system(path, &file_data, &file_length)) {\n')
|
||||
header.write(' const char* content_type = webui_get_mime_type(path);\n')
|
||||
header.write(' const char* http_header_template = "HTTP/1.1 200 OK\\r\\n"\n')
|
||||
header.write(' "Content-Type: %s\\r\\n"\n')
|
||||
header.write(' "Content-Length: %d\\r\\n"\n')
|
||||
header.write(' "Cache-Control: no-cache\\r\\n\\r\\n";\n')
|
||||
header.write(' int header_length = snprintf(NULL, 0, http_header_template, content_type, file_length);\n')
|
||||
header.write(' *length = header_length + file_length;\n')
|
||||
header.write(' unsigned char* response = (unsigned char*) webui_malloc(*length);\n')
|
||||
header.write(' snprintf((char*) response, header_length + 1, http_header_template, content_type, file_length);\n')
|
||||
header.write(' memcpy(response + header_length, file_data, file_length);\n')
|
||||
header.write(' return response;\n')
|
||||
header.write(' } else {\n')
|
||||
header.write(' // Check for index file redirection\n')
|
||||
header.write(' char redirect_path[1024];\n')
|
||||
header.write(' snprintf(redirect_path, sizeof(redirect_path), "%s", path);\n')
|
||||
header.write(' size_t len = strlen(redirect_path);\n')
|
||||
header.write(' if (redirect_path[len - 1] != \'/\') {\n')
|
||||
header.write(' redirect_path[len] = \'/\';\n')
|
||||
header.write(' redirect_path[len + 1] = \'\\0\';\n')
|
||||
header.write(' }\n')
|
||||
header.write(' for (int i = 0; index_files[i] != NULL; i += 2) {\n')
|
||||
header.write(' if (strcmp(index_files[i], redirect_path) == 0) {\n')
|
||||
header.write(' const char* location_header = "HTTP/1.1 302 Found\\r\\n"\n')
|
||||
header.write(' "Location: %s\\r\\n"\n')
|
||||
header.write(' "Cache-Control: no-cache\\r\\n\\r\\n";\n')
|
||||
header.write(' int header_length = snprintf(NULL, 0, location_header, index_files[i + 1]);\n')
|
||||
header.write(' *length = header_length;\n')
|
||||
header.write(' unsigned char* response = (unsigned char*) webui_malloc(*length);\n')
|
||||
header.write(' snprintf((char*) response, header_length + 1, location_header, index_files[i + 1]);\n')
|
||||
header.write(' return response;\n')
|
||||
header.write(' }\n')
|
||||
header.write(' }\n')
|
||||
header.write(' return NULL;\n')
|
||||
header.write(' }\n')
|
||||
header.write('}\n\n')
|
||||
|
||||
header.write('#endif // VIRTUAL_FILE_SYSTEM_H\n')
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) != 3:
|
||||
print(f'Usage: {sys.argv[0]} <directory> <output_header>')
|
||||
sys.exit(1)
|
||||
|
||||
directory = sys.argv[1]
|
||||
output_header = sys.argv[2]
|
||||
generate_vfs_header(directory, output_header)
|
||||
print(f'Generated {output_header} from {directory}')
|
23
examples/C/react/webui-react-example/.gitignore
vendored
Normal file
23
examples/C/react/webui-react-example/.gitignore
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
19039
examples/C/react/webui-react-example/package-lock.json
generated
Normal file
19039
examples/C/react/webui-react-example/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
38
examples/C/react/webui-react-example/package.json
Normal file
38
examples/C/react/webui-react-example/package.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "webui-react-example",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@testing-library/jest-dom": "^5.17.0",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-scripts": "5.0.1",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
BIN
examples/C/react/webui-react-example/public/favicon.ico
Normal file
BIN
examples/C/react/webui-react-example/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.8 KiB |
47
examples/C/react/webui-react-example/public/index.html
Normal file
47
examples/C/react/webui-react-example/public/index.html
Normal file
@ -0,0 +1,47 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>WebUI React</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
|
||||
<!-- WebUI Script (Virtual File) -->
|
||||
<script src="webui.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
BIN
examples/C/react/webui-react-example/public/logo192.png
Normal file
BIN
examples/C/react/webui-react-example/public/logo192.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.2 KiB |
BIN
examples/C/react/webui-react-example/public/logo512.png
Normal file
BIN
examples/C/react/webui-react-example/public/logo512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
25
examples/C/react/webui-react-example/public/manifest.json
Normal file
25
examples/C/react/webui-react-example/public/manifest.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
3
examples/C/react/webui-react-example/public/robots.txt
Normal file
3
examples/C/react/webui-react-example/public/robots.txt
Normal file
@ -0,0 +1,3 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
38
examples/C/react/webui-react-example/src/App.css
Normal file
38
examples/C/react/webui-react-example/src/App.css
Normal file
@ -0,0 +1,38 @@
|
||||
.App {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.App-logo {
|
||||
height: 40vmin;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.App-logo {
|
||||
animation: App-logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.App-header {
|
||||
background-color: #282c34;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(10px + 2vmin);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.App-link {
|
||||
color: #61dafb;
|
||||
}
|
||||
|
||||
@keyframes App-logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
75
examples/C/react/webui-react-example/src/App.js
Normal file
75
examples/C/react/webui-react-example/src/App.js
Normal file
@ -0,0 +1,75 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
const App = () => {
|
||||
const [value1, setValue1] = useState('');
|
||||
const [value2, setValue2] = useState('');
|
||||
const [result, setResult] = useState(null);
|
||||
|
||||
const calculateSum = () => {
|
||||
const sum = parseFloat(value1 || 0) + parseFloat(value2 || 0);
|
||||
setResult(sum);
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ margin: '20px', fontFamily: 'Arial, sans-serif' }}>
|
||||
<img src="logo192.png" width="64" height="64"></img>
|
||||
<h2>WebUI React Example</h2>
|
||||
<div style={{ marginBottom: '10px' }}>
|
||||
<label>
|
||||
<strong>Input 1:</strong>
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
value={value1}
|
||||
onChange={(e) => setValue1(e.target.value)}
|
||||
style={{ marginLeft: '10px', padding: '5px', fontSize: '16px' }}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ marginBottom: '10px' }}>
|
||||
<label>
|
||||
<strong>Input 2:</strong>
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
value={value2}
|
||||
onChange={(e) => setValue2(e.target.value)}
|
||||
style={{ marginLeft: '10px', padding: '5px', fontSize: '16px' }}
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
onClick={calculateSum}
|
||||
style={{
|
||||
padding: '10px 20px',
|
||||
backgroundColor: '#4CAF50',
|
||||
color: 'white',
|
||||
fontSize: '16px',
|
||||
border: 'none',
|
||||
borderRadius: '5px',
|
||||
cursor: 'pointer',
|
||||
marginRight: '10px',
|
||||
}}
|
||||
>
|
||||
Calculate (React Frontend)
|
||||
</button>
|
||||
<button
|
||||
id="Exit"
|
||||
style={{
|
||||
padding: '10px 20px',
|
||||
backgroundColor: '#f44336',
|
||||
color: 'white',
|
||||
fontSize: '16px',
|
||||
border: 'none',
|
||||
borderRadius: '5px',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
>
|
||||
Exit (WebUI Backend)
|
||||
</button>
|
||||
<div style={{ marginTop: '20px', fontSize: '18px' }}>
|
||||
<strong>Result:</strong> {result !== null ? result : 'N/A'}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
8
examples/C/react/webui-react-example/src/App.test.js
Normal file
8
examples/C/react/webui-react-example/src/App.test.js
Normal file
@ -0,0 +1,8 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import App from './App';
|
||||
|
||||
test('renders learn react link', () => {
|
||||
render(<App />);
|
||||
const linkElement = screen.getByText(/learn react/i);
|
||||
expect(linkElement).toBeInTheDocument();
|
||||
});
|
16
examples/C/react/webui-react-example/src/index.css
Normal file
16
examples/C/react/webui-react-example/src/index.css
Normal file
@ -0,0 +1,16 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
color: #5ed2f2;
|
||||
background-color: #2a2c2e;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
17
examples/C/react/webui-react-example/src/index.js
Normal file
17
examples/C/react/webui-react-example/src/index.js
Normal file
@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
1
examples/C/react/webui-react-example/src/logo.svg
Normal file
1
examples/C/react/webui-react-example/src/logo.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>
|
After Width: | Height: | Size: 2.6 KiB |
13
examples/C/react/webui-react-example/src/reportWebVitals.js
Normal file
13
examples/C/react/webui-react-example/src/reportWebVitals.js
Normal file
@ -0,0 +1,13 @@
|
||||
const reportWebVitals = onPerfEntry => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
5
examples/C/react/webui-react-example/src/setupTests.js
Normal file
5
examples/C/react/webui-react-example/src/setupTests.js
Normal file
@ -0,0 +1,5 @@
|
||||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
BIN
examples/C/react/webui_react.png
Normal file
BIN
examples/C/react/webui_react.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
@ -35,7 +35,7 @@ ifeq ($(OS),Windows_NT)
|
||||
DYN_BUILD_FLAGS += "$(WEBUI_LIB_NAME).dll" -lws2_32 -Wall -luser32
|
||||
STATIC_OUT := main.exe
|
||||
DYN_OUT := main-dyn.exe
|
||||
LWS2_OPT := -lws2_32
|
||||
LWS2_OPT := -lws2_32 -lole32
|
||||
STRIP_OPT := --strip-all
|
||||
CONSOLE_APP := -Wl,-subsystem=console
|
||||
GUI_APP := -Wl,-subsystem=windows
|
||||
@ -44,19 +44,19 @@ else
|
||||
DYN_BUILD_FLAGS += -lpthread -lm
|
||||
STATIC_OUT := main
|
||||
DYN_OUT := main-dyn
|
||||
CONSOLE_APP :=
|
||||
GUI_APP :=
|
||||
ifeq ($(shell uname),Darwin)
|
||||
# MacOS
|
||||
PLATFORM := macos
|
||||
CC = clang
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/$(WEBUI_LIB_NAME).dylib" "$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += "./$(WEBUI_LIB_NAME).dylib"
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).dylib" "lib$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)
|
||||
WKWEBKIT_LINK_FLAGS := -framework Cocoa -framework WebKit
|
||||
else
|
||||
# Linux
|
||||
PLATFORM := linux
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/$(WEBUI_LIB_NAME).so" "$(WEBUI_LIB_NAME).so"
|
||||
DYN_BUILD_FLAGS += "./$(WEBUI_LIB_NAME).so"
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).so" "lib$(WEBUI_LIB_NAME).so"
|
||||
STATIC_BUILD_FLAGS += -ldl
|
||||
DYN_BUILD_FLAGS += -ldl -l$(WEBUI_LIB_NAME)
|
||||
STRIP_OPT := --strip-all
|
||||
ifeq ($(CC),clang)
|
||||
LLVM_OPT := llvm-
|
||||
@ -75,12 +75,12 @@ endif
|
||||
# Static with Debug info
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) debug static)..."
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic with Debug info
|
||||
@echo "Build C Example ($(CC) debug dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
@ -97,13 +97,13 @@ endif
|
||||
# Static Release
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) release static)..."
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic Release
|
||||
@echo "Build C Example ($(CC) release dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
|
@ -21,18 +21,17 @@ debug:
|
||||
# Static with Debug info
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Debug)...
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic with Debug info
|
||||
@echo Build C Example (Dynamic Debug)...
|
||||
@copy "$(LIB_DIR)\debug\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@- del *.lib >nul 2>&1
|
||||
@- del *.obj >nul 2>&1
|
||||
@- del *.pdb >nul 2>&1
|
||||
@echo Done.
|
||||
|
||||
release:
|
||||
@ -42,12 +41,12 @@ release:
|
||||
# Static Release
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Release)...
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic Release
|
||||
@echo Build C Example (Dynamic Release)...
|
||||
@copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
|
26
examples/C/serve_a_folder/bun_test.ts
Normal file
26
examples/C/serve_a_folder/bun_test.ts
Normal file
@ -0,0 +1,26 @@
|
||||
// This file gets called like follow:
|
||||
//
|
||||
// 1. UI `Index.html` request:
|
||||
// `http://localhost:xxx/bun_test.ts?foo=123&bar=456`
|
||||
//
|
||||
// 2. WebUI runs command:
|
||||
// `bun run "bun_test.ts" "foo=123&bar=456"`
|
||||
//
|
||||
// 3. Bun parses args and prints the response
|
||||
|
||||
// Get Query (HTTP GET)
|
||||
const args = process.argv.slice(2);
|
||||
const query = args[0];
|
||||
|
||||
// Variables
|
||||
let foo: string = '';
|
||||
let bar: string = '';
|
||||
|
||||
// Read Query
|
||||
const params = new URLSearchParams(query);
|
||||
for (const [key, value] of params.entries()) {
|
||||
if (key === 'foo') foo = value; // 123
|
||||
else if (key === 'bar') bar = value; // 456
|
||||
}
|
||||
|
||||
console.log('Response from Bun: ' + (parseInt(foo) + parseInt(bar))); // 579
|
@ -1,7 +1,12 @@
|
||||
// This file gets called like follow:
|
||||
// `Index.html` ->
|
||||
// `http://localhost:xxx/deno_test.ts?foo=123&bar=456` ->
|
||||
// `deno run --allow-all --unstable "deno_test.ts" "foo=123&bar=456"`
|
||||
//
|
||||
// 1. UI `Index.html` request:
|
||||
// `http://localhost:xxx/deno_test.ts?foo=123&bar=456`
|
||||
//
|
||||
// 2. WebUI runs command:
|
||||
// `deno run --allow-all --unstable "deno_test.ts" "foo=123&bar=456"`
|
||||
//
|
||||
// 3. Deno parse args and print the response
|
||||
|
||||
// Import parse()
|
||||
import { parse } from 'https://deno.land/std/flags/mod.ts';
|
||||
@ -21,4 +26,4 @@ for (const [key, value] of params.entries()) {
|
||||
else if (key == 'bar') bar = value; // 456
|
||||
}
|
||||
|
||||
console.error('foo + bar = ' + (parseInt(foo) + parseInt(bar))); // 579
|
||||
console.log('Response from Deno: ' + (parseInt(foo) + parseInt(bar))); // 579
|
||||
|
@ -66,7 +66,13 @@
|
||||
By a simple HTTP request "deno_test.ts?foo=60&bar=40"
|
||||
<br />
|
||||
<br />
|
||||
<button OnClick="call_deno_file();">deno_test.ts (Local file)</button>
|
||||
<button OnClick="call_deno_file();">Deno_test.ts (Local file)</button>
|
||||
<br />
|
||||
<br />
|
||||
<button OnClick="call_bun_file();">Bun_test.ts (Local file)</button>
|
||||
<br />
|
||||
<br />
|
||||
<button OnClick="call_nodejs_file();">Nodejs_test.ts (Local file)</button>
|
||||
<br />
|
||||
<h4><a href="second.html">Second Page As A Simple Link (Local file)</a></h4>
|
||||
<br />
|
||||
@ -79,29 +85,109 @@
|
||||
<h4><a href="dynamic.html">Dynamic file example (Embedded)</a></h4>
|
||||
<p>
|
||||
Unicode Test:<br /><br />
|
||||
مرحبًا<br />
|
||||
<!-- Arabic -->
|
||||
你好<br />
|
||||
<!-- Chinese -->
|
||||
こんにちは
|
||||
<!-- Japanese -->
|
||||
مرحبًا<br /> <!-- Arabic -->
|
||||
你好<br /> <!-- Chinese -->
|
||||
こんにちは <!-- Japanese -->
|
||||
</p>
|
||||
</body>
|
||||
|
||||
<!-- Connect this window to the background app -->
|
||||
<script src="webui.js"></script>
|
||||
<script src="/webui.js"></script>
|
||||
|
||||
<script>
|
||||
function call_deno_file() {
|
||||
// Because `main.c` set Deno as the `.ts` and `.js` interpreter
|
||||
// then a simple HTTP request to `/deno_test.ts` will be parsed
|
||||
// of course Deno should be installed.
|
||||
|
||||
function call_deno_file() {
|
||||
// Note:
|
||||
// You need to set Deno as default runtime in the backend
|
||||
// Simple HTTP Request
|
||||
var xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.open('GET', 'deno_test.ts?foo=60&bar=40', false);
|
||||
xmlHttp.open('GET', 'deno_test.ts?foo=123&bar=456', false);
|
||||
xmlHttp.send(null);
|
||||
alert(xmlHttp.responseText);
|
||||
}
|
||||
|
||||
function call_bun_file() {
|
||||
// Note:
|
||||
// You need to set Bun as default runtime in the backend
|
||||
// Simple HTTP Request
|
||||
var xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.open('GET', 'bun_test.ts?foo=123&bar=456', false);
|
||||
xmlHttp.send(null);
|
||||
alert(xmlHttp.responseText);
|
||||
}
|
||||
|
||||
function call_nodejs_file() {
|
||||
// Note:
|
||||
// You need to set Nodejs as default runtime in the backend
|
||||
// Simple HTTP Request
|
||||
var xmlHttp = new XMLHttpRequest();
|
||||
xmlHttp.open('GET', 'node_test.js?foo=123&bar=456', false);
|
||||
xmlHttp.send(null);
|
||||
alert(xmlHttp.responseText);
|
||||
}
|
||||
|
||||
// JavaScript Example
|
||||
/*
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// DOM is loaded. Check if `webui` object is available
|
||||
if (typeof webui !== 'undefined') {
|
||||
// Set events callback
|
||||
webui.setEventCallback((e) => {
|
||||
if (e == webui.event.CONNECTED) {
|
||||
// Connection to the backend is established
|
||||
console.log('Connected.');
|
||||
webuiTest();
|
||||
} else if (e == webui.event.DISCONNECTED) {
|
||||
// Connection to the backend is lost
|
||||
console.log('Disconnected.');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// The virtual file `webui.js` is not included
|
||||
alert('Please add webui.js to your HTML.');
|
||||
}
|
||||
});
|
||||
|
||||
function webuiTest() {
|
||||
// Call a backend function
|
||||
if (webui.isConnected()) {
|
||||
|
||||
// When you bind a func in the backend
|
||||
// webui will create the `func` object
|
||||
// in three places:
|
||||
//
|
||||
// Global : func(...)
|
||||
// Property : webui.func(...)
|
||||
// Method : webui.call('func', ...)
|
||||
//
|
||||
// [!] Note: Objects creation fails when
|
||||
// a similar object already exist.
|
||||
|
||||
const foo = 'Hello';
|
||||
const bar = 123456;
|
||||
|
||||
// Calling as global object
|
||||
myBackendFunction(foo, bar).then((response) => {
|
||||
// Do something with `response`
|
||||
});
|
||||
|
||||
// Calling as property of `webui.` object
|
||||
webui.myBackendFunction(foo, bar).then((response) => {
|
||||
// Do something with `response`
|
||||
});
|
||||
|
||||
// Calling using the method `webui.call()`
|
||||
webui.call('myBackendFunction', foo, bar).then((response) => {
|
||||
// Do something with `response`
|
||||
});
|
||||
|
||||
// Using await
|
||||
// const response = await myBackendFunction(foo, bar);
|
||||
// const response = await webui.myBackendFunction(foo, bar);
|
||||
// const response = await webui.call('myBackendFunction', foo, bar);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
</script>
|
||||
</html>
|
||||
|
@ -10,133 +10,155 @@
|
||||
|
||||
void exit_app(webui_event_t* e) {
|
||||
|
||||
// Close all opened windows
|
||||
webui_exit();
|
||||
// Close all opened windows
|
||||
webui_exit();
|
||||
}
|
||||
|
||||
void events(webui_event_t* e) {
|
||||
|
||||
// This function gets called every time
|
||||
// there is an event
|
||||
// This function gets called every time
|
||||
// there is an event
|
||||
|
||||
if (e->event_type == WEBUI_EVENT_CONNECTED)
|
||||
printf("Connected. \n");
|
||||
else if (e->event_type == WEBUI_EVENT_DISCONNECTED)
|
||||
printf("Disconnected. \n");
|
||||
else if (e->event_type == WEBUI_EVENT_MOUSE_CLICK)
|
||||
printf("Click. \n");
|
||||
else if (e->event_type == WEBUI_EVENT_NAVIGATION) {
|
||||
const char* url = webui_get_string(e);
|
||||
printf("Starting navigation to: %s \n", url);
|
||||
if (e->event_type == WEBUI_EVENT_CONNECTED)
|
||||
printf("Connected. \n");
|
||||
else if (e->event_type == WEBUI_EVENT_DISCONNECTED)
|
||||
printf("Disconnected. \n");
|
||||
else if (e->event_type == WEBUI_EVENT_MOUSE_CLICK)
|
||||
printf("Click. \n");
|
||||
else if (e->event_type == WEBUI_EVENT_NAVIGATION) {
|
||||
const char* url = webui_get_string(e);
|
||||
printf("Starting navigation to: %s \n", url);
|
||||
|
||||
// Because we used `webui_bind(MyWindow, "", events);`
|
||||
// WebUI will block all `href` link clicks and sent here instead.
|
||||
// We can then control the behaviour of links as needed.
|
||||
webui_navigate(e->window, url);
|
||||
}
|
||||
// Because we used `webui_bind(MyWindow, "", events);`
|
||||
// WebUI will block all `href` link clicks and sent here instead.
|
||||
// We can then control the behaviour of links as needed.
|
||||
webui_navigate(e->window, url);
|
||||
}
|
||||
}
|
||||
|
||||
void switch_to_second_page(webui_event_t* e) {
|
||||
|
||||
// This function gets called every
|
||||
// time the user clicks on "SwitchToSecondPage"
|
||||
// This function gets called every
|
||||
// time the user clicks on "SwitchToSecondPage"
|
||||
|
||||
// Switch to `/second.html` in the same opened window.
|
||||
webui_show(e->window, "second.html");
|
||||
// Switch to `/second.html` in the same opened window.
|
||||
webui_show(e->window, "second.html");
|
||||
}
|
||||
|
||||
void show_second_window(webui_event_t* e) {
|
||||
|
||||
// This function gets called every
|
||||
// time the user clicks on "OpenNewWindow"
|
||||
// This function gets called every
|
||||
// time the user clicks on "OpenNewWindow"
|
||||
|
||||
// Show a new window, and navigate to `/second.html`
|
||||
// if it's already open, then switch in the same window
|
||||
webui_show(MySecondWindow, "second.html");
|
||||
// Show a new window, and navigate to `/second.html`
|
||||
// if it's already open, then switch in the same window
|
||||
webui_show(MySecondWindow, "second.html");
|
||||
}
|
||||
|
||||
const void* my_files_handler(const char* filename, int* length) {
|
||||
|
||||
printf("File: %s \n", filename);
|
||||
printf("File: %s \n", filename);
|
||||
|
||||
if (!strcmp(filename, "/test.txt")) {
|
||||
if (!strcmp(filename, "/test.txt")) {
|
||||
|
||||
// Const static file example
|
||||
// Note: The connection will drop if the content
|
||||
// does not have `<script src="webui.js"></script>`
|
||||
return "This is a embedded file content example.";
|
||||
} else if (!strcmp(filename, "/dynamic.html")) {
|
||||
// Const static file example
|
||||
return "HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"Content-Length: 99\r\n\r\n"
|
||||
"<html>"
|
||||
" This is a static embedded file content example."
|
||||
" <script src=\"webui.js\"></script>" // To keep connection with WebUI
|
||||
"</html>";
|
||||
}
|
||||
else if (!strcmp(filename, "/dynamic.html")) {
|
||||
|
||||
// Dynamic file example
|
||||
// Dynamic file example
|
||||
|
||||
// Allocate memory
|
||||
char* dynamic_content = webui_malloc(1024);
|
||||
// Allocate memory
|
||||
char* body = webui_malloc(1024);
|
||||
char* header_and_body = webui_malloc(1024);
|
||||
|
||||
// Generate content
|
||||
static int count = 0;
|
||||
sprintf(
|
||||
dynamic_content,
|
||||
"<html>"
|
||||
" This is a dynamic file content example. <br>"
|
||||
" Count: %d <a href=\"dynamic.html\">[Refresh]</a><br>"
|
||||
" <script src=\"webui.js\"></script>" // To keep connection with WebUI
|
||||
"</html>",
|
||||
++count
|
||||
);
|
||||
// Generate body
|
||||
static int count = 0;
|
||||
sprintf(
|
||||
body,
|
||||
"<html>"
|
||||
" This is a dynamic file content example. <br>"
|
||||
" Count: %d <a href=\"dynamic.html\">[Refresh]</a><br>"
|
||||
" <script src=\"webui.js\"></script>" // To keep connection with WebUI
|
||||
"</html>",
|
||||
++count
|
||||
);
|
||||
|
||||
// Set len (optional)
|
||||
*length = strlen(dynamic_content);
|
||||
// Generate header + body
|
||||
int body_size = strlen(body);
|
||||
sprintf(
|
||||
header_and_body,
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"Content-Length: %d\r\n\r\n"
|
||||
"%s",
|
||||
body_size, body
|
||||
);
|
||||
|
||||
// Free body buffer
|
||||
webui_free(body);
|
||||
|
||||
// By allocating resources using webui_malloc()
|
||||
// WebUI will automaticaly free the resources.
|
||||
return dynamic_content;
|
||||
}
|
||||
// Set len (optional)
|
||||
*length = strlen(header_and_body);
|
||||
|
||||
// Other files:
|
||||
// A NULL return will make WebUI
|
||||
// looks for the file locally.
|
||||
return NULL;
|
||||
// By allocating resources using webui_malloc()
|
||||
// WebUI will automaticaly free the resources.
|
||||
return header_and_body;
|
||||
}
|
||||
|
||||
// Other files:
|
||||
// A NULL return will make WebUI
|
||||
// looks for the file locally.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
// Create new windows
|
||||
webui_new_window_id(MyWindow);
|
||||
webui_new_window_id(MySecondWindow);
|
||||
// Create new windows
|
||||
webui_new_window_id(MyWindow);
|
||||
webui_new_window_id(MySecondWindow);
|
||||
|
||||
// Bind HTML element IDs with a C functions
|
||||
webui_bind(MyWindow, "SwitchToSecondPage", switch_to_second_page);
|
||||
webui_bind(MyWindow, "OpenNewWindow", show_second_window);
|
||||
webui_bind(MyWindow, "Exit", exit_app);
|
||||
webui_bind(MySecondWindow, "Exit", exit_app);
|
||||
// Bind HTML element IDs with a C functions
|
||||
webui_bind(MyWindow, "SwitchToSecondPage", switch_to_second_page);
|
||||
webui_bind(MyWindow, "OpenNewWindow", show_second_window);
|
||||
webui_bind(MyWindow, "Exit", exit_app);
|
||||
webui_bind(MySecondWindow, "Exit", exit_app);
|
||||
|
||||
// Bind events
|
||||
webui_bind(MyWindow, "", events);
|
||||
// Bind events
|
||||
webui_bind(MyWindow, "", events);
|
||||
|
||||
// Make Deno as the `.ts` and `.js` interpreter
|
||||
webui_set_runtime(MyWindow, Deno);
|
||||
// Set the `.ts` and `.js` runtime
|
||||
// webui_set_runtime(MyWindow, NodeJS);
|
||||
// webui_set_runtime(MyWindow, Bun);
|
||||
webui_set_runtime(MyWindow, Deno);
|
||||
|
||||
// Set a custom files handler
|
||||
webui_set_file_handler(MyWindow, my_files_handler);
|
||||
// Set a custom files handler
|
||||
webui_set_file_handler(MyWindow, my_files_handler);
|
||||
|
||||
// Set window size
|
||||
webui_set_size(MyWindow, 800, 800);
|
||||
// Set window size
|
||||
webui_set_size(MyWindow, 800, 800);
|
||||
|
||||
// Set window position
|
||||
webui_set_position(MyWindow, 200, 200);
|
||||
// Set window position
|
||||
webui_set_position(MyWindow, 200, 200);
|
||||
|
||||
// Show a new window
|
||||
// webui_set_root_folder(MyWindow, "_MY_PATH_HERE_");
|
||||
// webui_show_browser(MyWindow, "index.html", Chrome);
|
||||
webui_show(MyWindow, "index.html");
|
||||
// Show a new window
|
||||
// webui_set_root_folder(MyWindow, "_MY_PATH_HERE_");
|
||||
// webui_show_browser(MyWindow, "index.html", Chrome);
|
||||
webui_show(MyWindow, "index.html");
|
||||
|
||||
// Wait until all windows get closed
|
||||
webui_wait();
|
||||
// Wait until all windows get closed
|
||||
webui_wait();
|
||||
|
||||
// Free all memory resources (Optional)
|
||||
webui_clean();
|
||||
// Free all memory resources (Optional)
|
||||
webui_clean();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
26
examples/C/serve_a_folder/node_test.js
Normal file
26
examples/C/serve_a_folder/node_test.js
Normal file
@ -0,0 +1,26 @@
|
||||
// This file gets called like follow:
|
||||
//
|
||||
// 1. UI `Index.html` request:
|
||||
// `http://localhost:xxx/node_test.js?foo=123&bar=456`
|
||||
//
|
||||
// 2. WebUI runs command:
|
||||
// `node node_test.js "foo=123&bar=456"`
|
||||
//
|
||||
// 3. Node.js parses args and prints the response
|
||||
|
||||
// Get Query (HTTP GET)
|
||||
const args = process.argv.slice(2);
|
||||
const query = args[0];
|
||||
|
||||
// Variables
|
||||
let foo = '';
|
||||
let bar = '';
|
||||
|
||||
// Read Query
|
||||
const params = new URLSearchParams(query);
|
||||
for (const [key, value] of params.entries()) {
|
||||
if (key === 'foo') foo = value; // 123
|
||||
else if (key === 'bar') bar = value; // 456
|
||||
}
|
||||
|
||||
console.log('Response from Node.js: ' + (parseInt(foo) + parseInt(bar))); // 579
|
@ -44,5 +44,5 @@
|
||||
</body>
|
||||
|
||||
<!-- Connect this window to the background app -->
|
||||
<script src="webui.js"></script>
|
||||
<script src="/webui.js"></script>
|
||||
</html>
|
||||
|
@ -35,7 +35,7 @@ ifeq ($(OS),Windows_NT)
|
||||
DYN_BUILD_FLAGS += "$(WEBUI_LIB_NAME).dll" -lws2_32 -Wall -luser32
|
||||
STATIC_OUT := main.exe
|
||||
DYN_OUT := main-dyn.exe
|
||||
LWS2_OPT := -lws2_32
|
||||
LWS2_OPT := -lws2_32 -lole32
|
||||
STRIP_OPT := --strip-all
|
||||
CONSOLE_APP := -Wl,-subsystem=console
|
||||
GUI_APP := -Wl,-subsystem=windows
|
||||
@ -44,19 +44,19 @@ else
|
||||
DYN_BUILD_FLAGS += -lpthread -lm
|
||||
STATIC_OUT := main
|
||||
DYN_OUT := main-dyn
|
||||
CONSOLE_APP :=
|
||||
GUI_APP :=
|
||||
ifeq ($(shell uname),Darwin)
|
||||
# MacOS
|
||||
PLATFORM := macos
|
||||
CC = clang
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/$(WEBUI_LIB_NAME).dylib" "$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += "./$(WEBUI_LIB_NAME).dylib"
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).dylib" "lib$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)
|
||||
WKWEBKIT_LINK_FLAGS := -framework Cocoa -framework WebKit
|
||||
else
|
||||
# Linux
|
||||
PLATFORM := linux
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/$(WEBUI_LIB_NAME).so" "$(WEBUI_LIB_NAME).so"
|
||||
DYN_BUILD_FLAGS += "./$(WEBUI_LIB_NAME).so"
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).so" "lib$(WEBUI_LIB_NAME).so"
|
||||
STATIC_BUILD_FLAGS += -ldl
|
||||
DYN_BUILD_FLAGS += -ldl -l$(WEBUI_LIB_NAME)
|
||||
STRIP_OPT := --strip-all
|
||||
ifeq ($(CC),clang)
|
||||
LLVM_OPT := llvm-
|
||||
@ -75,12 +75,12 @@ endif
|
||||
# Static with Debug info
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) debug static)..."
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic with Debug info
|
||||
@echo "Build C Example ($(CC) debug dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
@ -97,13 +97,13 @@ endif
|
||||
# Static Release
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) release static)..."
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) -o $(STATIC_OUT)
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic Release
|
||||
@echo "Build C Example ($(CC) release dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) -o $(DYN_OUT)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
|
@ -21,18 +21,17 @@ debug:
|
||||
# Static with Debug info
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Debug)...
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic with Debug info
|
||||
@echo Build C Example (Dynamic Debug)...
|
||||
@copy "$(LIB_DIR)\debug\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /MACHINE:X64 /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@- del *.lib >nul 2>&1
|
||||
@- del *.obj >nul 2>&1
|
||||
@- del *.pdb >nul 2>&1
|
||||
@echo Done.
|
||||
|
||||
release:
|
||||
@ -42,12 +41,12 @@ release:
|
||||
# Static Release
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Release)...
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic Release
|
||||
@echo Build C Example (Dynamic Release)...
|
||||
@copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /MACHINE:X64 /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include "webui.h"
|
||||
|
||||
void Close(webui_event_t* e) {
|
||||
void close_app(webui_event_t* e) {
|
||||
printf("Exit.\n");
|
||||
|
||||
// Close all opened windows
|
||||
@ -18,10 +18,10 @@ int main() {
|
||||
webui_set_root_folder(MainWindow, "ui");
|
||||
|
||||
// Bind HTML elements with the specified ID to C functions
|
||||
webui_bind(MainWindow, "__close-btn", Close);
|
||||
webui_bind(MainWindow, "close_app", close_app);
|
||||
|
||||
// Show the window, preferably in a chromium based browser
|
||||
if (!webui_show_browser(MainWindow, "index.html", ChromiumBased))
|
||||
if (!webui_show_browser(MainWindow, "index.html", AnyBrowser))
|
||||
webui_show(MainWindow, "index.html");
|
||||
|
||||
// Wait until all windows get closed
|
||||
|
2
examples/C/text-editor/ui/css/all.min.css
vendored
2
examples/C/text-editor/ui/css/all.min.css
vendored
File diff suppressed because one or more lines are too long
@ -16,7 +16,7 @@
|
||||
<nav>
|
||||
<button id="open-btn" title="Open file" type="button"><i class="fas fa-folder-open"></i></button>
|
||||
<button id="save-btn" title="Save file" type="button" disabled><i class="fa fa-floppy-disk"></i></button>
|
||||
<button id="__close-btn" title="Close file" type="button"><i class="fas fa-circle-xmark"></i></button>
|
||||
<button id="close_app" title="Close file" type="button"><i class="fas fa-circle-xmark"></i></button>
|
||||
<button id="about-btn" title="About Info" type="button"><i class="fas fa-question-circle"></i></button>
|
||||
</nav>
|
||||
<div class="main" id="main">
|
||||
@ -27,7 +27,7 @@
|
||||
<h1>WebUI Text Editor</h1>
|
||||
v1.1
|
||||
<p>Example of a text editor software in C using WebUI library.</p>
|
||||
<p><a href="https://webui.me" target="_blank">webui.me</a> | (C)2023 Hassan Draga</p>
|
||||
<p><a href="https://webui.me" target="_blank">webui.me</a> | (C)2025 Hassan Draga</p>
|
||||
</div>
|
||||
</div>
|
||||
<script src="js/codemirror.min.js"></script>
|
||||
|
141
examples/C/virtual_file_system/GNUmakefile
Normal file
141
examples/C/virtual_file_system/GNUmakefile
Normal file
@ -0,0 +1,141 @@
|
||||
# WebUI C Example
|
||||
|
||||
# == 1. VARIABLES =============================================================
|
||||
|
||||
MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
PROJECT_DIR := $(dir $(MAKEFILE_PATH))/../../../
|
||||
TARGET := $(firstword $(MAKECMDGOALS))
|
||||
LIB_DIR := $(PROJECT_DIR)/dist
|
||||
ifeq ($(TARGET), debug)
|
||||
LIB_DIR := $(LIB_DIR)/debug
|
||||
endif
|
||||
INCLUDE_DIR := $(PROJECT_DIR)/include
|
||||
WEBUI_LIB_NAME = webui-2
|
||||
ifeq ($(WEBUI_USE_TLS), 1)
|
||||
WEBUI_LIB_NAME = webui-2-secure
|
||||
endif
|
||||
|
||||
# ARGS
|
||||
# Set a compiler when running on Linux via `make CC=gcc` / `make CC=clang`
|
||||
CC = gcc
|
||||
# Build the WebUI library if running via `make BUILD_LIB=true`
|
||||
BUILD_LIB ?=
|
||||
|
||||
# BUILD FLAGS
|
||||
STATIC_BUILD_FLAGS = main.c -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
DYN_BUILD_FLAGS = main.c -I"$(INCLUDE_DIR)" -L"$(LIB_DIR)"
|
||||
|
||||
# Platform conditions
|
||||
ifeq ($(OS),Windows_NT)
|
||||
# Windows
|
||||
PLATFORM := windows
|
||||
SHELL := CMD
|
||||
STATIC_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)-static -lws2_32 -Wall -luser32 -static
|
||||
COPY_LIB_CMD := @copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
DYN_BUILD_FLAGS += "$(WEBUI_LIB_NAME).dll" -lws2_32 -Wall -luser32
|
||||
STATIC_OUT := main.exe
|
||||
DYN_OUT := main-dyn.exe
|
||||
LWS2_OPT := -lws2_32 -lole32
|
||||
STRIP_OPT := --strip-all
|
||||
CONSOLE_APP := -Wl,-subsystem=console
|
||||
GUI_APP := -Wl,-subsystem=windows
|
||||
else
|
||||
STATIC_BUILD_FLAGS += -lpthread -lm -l$(WEBUI_LIB_NAME)-static
|
||||
DYN_BUILD_FLAGS += -lpthread -lm
|
||||
STATIC_OUT := main
|
||||
DYN_OUT := main-dyn
|
||||
ifeq ($(shell uname),Darwin)
|
||||
# MacOS
|
||||
PLATFORM := macos
|
||||
CC = clang
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).dylib" "lib$(WEBUI_LIB_NAME).dylib"
|
||||
DYN_BUILD_FLAGS += -l$(WEBUI_LIB_NAME)
|
||||
WKWEBKIT_LINK_FLAGS := -framework Cocoa -framework WebKit
|
||||
else
|
||||
# Linux
|
||||
PLATFORM := linux
|
||||
COPY_LIB_CMD := @cp "$(LIB_DIR)/lib$(WEBUI_LIB_NAME).so" "lib$(WEBUI_LIB_NAME).so"
|
||||
STATIC_BUILD_FLAGS += -ldl
|
||||
DYN_BUILD_FLAGS += -ldl -l$(WEBUI_LIB_NAME)
|
||||
STRIP_OPT := --strip-all
|
||||
ifeq ($(CC),clang)
|
||||
LLVM_OPT := llvm-
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# == 2.TARGETS ================================================================
|
||||
|
||||
all: release
|
||||
|
||||
debug: --validate-args
|
||||
ifeq ($(BUILD_LIB),true)
|
||||
@cd "$(PROJECT_DIR)" && $(MAKE) debug
|
||||
endif
|
||||
# Static with Debug info
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) debug static)..."
|
||||
@$(CC) -g $(CONSOLE_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic with Debug info
|
||||
@echo "Build C Example ($(CC) debug dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) -g $(CONSOLE_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
else
|
||||
@- rm -f *.o
|
||||
@- rm -rf *.dSYM # macOS
|
||||
endif
|
||||
@echo "Done."
|
||||
|
||||
release: --validate-args
|
||||
ifeq ($(BUILD_LIB),true)
|
||||
@cd "$(PROJECT_DIR)" && $(MAKE)
|
||||
endif
|
||||
# Static Release
|
||||
ifneq ($(WEBUI_USE_TLS), 1)
|
||||
@echo "Build C Example ($(CC) release static)..."
|
||||
@$(CC) -Os $(GUI_APP) $(STATIC_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(STATIC_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(STATIC_OUT)
|
||||
endif
|
||||
# Dynamic Release
|
||||
@echo "Build C Example ($(CC) release dynamic)..."
|
||||
$(COPY_LIB_CMD)
|
||||
@$(CC) $(GUI_APP) $(DYN_BUILD_FLAGS) $(LWS2_OPT) $(WKWEBKIT_LINK_FLAGS) -o $(DYN_OUT)
|
||||
@$(LLVM_OPT)strip $(STRIP_OPT) $(DYN_OUT)
|
||||
# Clean
|
||||
ifeq ($(PLATFORM),windows)
|
||||
@- del *.o >nul 2>&1
|
||||
else
|
||||
@- rm -f *.o
|
||||
@- rm -rf *.dSYM # macOS
|
||||
endif
|
||||
@echo "Done."
|
||||
|
||||
clean: --clean-$(PLATFORM)
|
||||
|
||||
# INTERNAL TARGETS
|
||||
|
||||
--validate-args:
|
||||
ifneq ($(filter $(CC),gcc clang aarch64-linux-gnu-gcc arm-linux-gnueabihf-gcc musl-gcc),$(CC))
|
||||
$(error Invalid compiler specified: `$(CC)`)
|
||||
endif
|
||||
|
||||
--clean-linux: --clean-unix
|
||||
|
||||
--clean-macos: --clean-unix
|
||||
|
||||
--clean-unix:
|
||||
- rm -f *.o
|
||||
- rm -f *.a
|
||||
- rm -f *.so
|
||||
- rm -f *.dylib
|
||||
- rm -rf *.dSYM
|
||||
|
||||
--clean-windows:
|
||||
- del *.o >nul 2>&1
|
||||
- del *.dll >nul 2>&1
|
||||
- del *.a >nul 2>&1
|
||||
- del *.exe >nul 2>&1
|
64
examples/C/virtual_file_system/Makefile
Normal file
64
examples/C/virtual_file_system/Makefile
Normal file
@ -0,0 +1,64 @@
|
||||
# WebUI C Example
|
||||
# Windows - Microsoft Visual C
|
||||
|
||||
SHELL = CMD
|
||||
LIB_DIR = ../../../dist
|
||||
INCLUDE_DIR = ../../../include
|
||||
WEBUI_LIB_NAME = webui-2
|
||||
!IF "$(WEBUI_USE_TLS)" == "1"
|
||||
WEBUI_LIB_NAME = webui-2-secure
|
||||
!ENDIF
|
||||
|
||||
# Build the WebUI library if running `nmake BUILD_LIB=true`
|
||||
BUILD_LIB =
|
||||
|
||||
all: release
|
||||
|
||||
debug:
|
||||
!IF "$(BUILD_LIB)" == "true"
|
||||
@cd "$(LIB_DIR)" && cd .. && $(MAKE) debug
|
||||
!ENDIF
|
||||
# Static with Debug info
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Debug)...
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic with Debug info
|
||||
@echo Build C Example (Dynamic Debug)...
|
||||
@copy "$(LIB_DIR)\debug\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl /Zi main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)\debug" /SUBSYSTEM:CONSOLE $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@- del *.lib >nul 2>&1
|
||||
@- del *.obj >nul 2>&1
|
||||
@echo Done.
|
||||
|
||||
release:
|
||||
!IF "$(BUILD_LIB)" == "true"
|
||||
@cd "$(LIB_DIR)" && cd .. && $(MAKE)
|
||||
!ENDIF
|
||||
# Static Release
|
||||
!IF "$(WEBUI_USE_TLS)" != "1"
|
||||
@echo Build C Example (Static Release)...
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME)-static.lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main.exe 1>NUL 2>&1
|
||||
!ENDIF
|
||||
# Dynamic Release
|
||||
@echo Build C Example (Dynamic Release)...
|
||||
@copy "$(LIB_DIR)\$(WEBUI_LIB_NAME).dll" "$(WEBUI_LIB_NAME).dll"
|
||||
@cl main.c /I"$(INCLUDE_DIR)" /link /LIBPATH:"$(LIB_DIR)" /SUBSYSTEM:WINDOWS $(WEBUI_LIB_NAME).lib user32.lib Advapi32.lib Shell32.lib Ole32.lib /OUT:main-dyn.exe 1>NUL 2>&1
|
||||
# Clean
|
||||
@- del *.exp >nul 2>&1
|
||||
@- del *.ilk >nul 2>&1
|
||||
@- del *.lib >nul 2>&1
|
||||
@- del *.obj >nul 2>&1
|
||||
@- del *.pdb >nul 2>&1
|
||||
@echo Done.
|
||||
|
||||
clean:
|
||||
- del *.obj >nul 2>&1
|
||||
- del *.ilk >nul 2>&1
|
||||
- del *.pdb >nul 2>&1
|
||||
- del *.exp >nul 2>&1
|
||||
- del *.exe >nul 2>&1
|
||||
- del *.lib >nul 2>&1
|
47
examples/C/virtual_file_system/main.c
Normal file
47
examples/C/virtual_file_system/main.c
Normal file
@ -0,0 +1,47 @@
|
||||
// Virtual File System Example
|
||||
|
||||
#include "webui.h"
|
||||
#include "vfs.h"
|
||||
|
||||
void exit_app(webui_event_t* e) {
|
||||
webui_exit();
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
// Create new windows
|
||||
size_t MyWindow = webui_new_window();
|
||||
|
||||
// Bind HTML element IDs with a C functions
|
||||
webui_bind(MyWindow, "Exit", exit_app);
|
||||
|
||||
// VSF (Virtual File System) Example
|
||||
//
|
||||
// 1. Run Python script to generate header file of a folder
|
||||
// python vfs.py "/path/to/folder" "vfs.h"
|
||||
//
|
||||
// 2. Include header file in your C project
|
||||
// #include "vfs.h"
|
||||
//
|
||||
// 3. use vfs in your custom files handler `webui_set_file_handler()`
|
||||
// webui_set_file_handler(MyWindow, vfs);
|
||||
|
||||
// Set a custom files handler
|
||||
webui_set_file_handler(MyWindow, vfs);
|
||||
|
||||
// Show a new window
|
||||
// webui_show_browser(MyWindow, "index.html", Chrome);
|
||||
webui_show(MyWindow, "index.html");
|
||||
|
||||
// Wait until all windows get closed
|
||||
webui_wait();
|
||||
|
||||
// Free all memory resources (Optional)
|
||||
webui_clean();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, PSTR cmdline, int cmdshow) { return main(); }
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user