Incomplete Linux & Website codes

This commit is contained in:
Hassan DRAGA 2022-10-23 20:06:15 -04:00
parent fd5c43f282
commit 2856dffbdf
13 changed files with 4596 additions and 145 deletions

View File

@ -611,9 +611,9 @@ int sscanf(const char *, const char *, ...);
#endif
#ifndef MG_ENABLE_LOG
#define MG_ENABLE_LOG 1
#endif
//#ifndef MG_ENABLE_LOG
//#define MG_ENABLE_LOG 1
//#endif
#ifndef MG_ENABLE_MIP
#define MG_ENABLE_MIP 0

View File

@ -58,16 +58,23 @@
#define WEBUI_FILE_EXIST _access
#define WEBUI_POPEN _popen
#define WEBUI_PCLOSE _pclose
#define WEBUI_MAX_PATH MAX_PATH
#endif
// -- Linux ---------------------------
#ifdef __linux__
#include <pthread.h> // POSIX threading
#include <unistd.h>
#include <limits.h>
#include <dirent.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <poll.h>
#define WEBUI_GET_CURRENT_DIR getcwd
#define WEBUI_FILE_EXIST _access
#define WEBUI_FILE_EXIST access
#define WEBUI_POPEN popen
#define WEBUI_PCLOSE pclose
#define WEBUI_MAX_PATH PATH_MAX
#endif
// -- macOS ---------------------------
@ -109,7 +116,7 @@ typedef struct webui_window_core_t {
#ifdef _WIN32
HANDLE server_thread;
#else
unsigned int server_thread;
pthread_t server_thread;
#endif
} webui_window_core_t;
@ -285,8 +292,8 @@ EXPORT bool _webui_browser_start(webui_window_t* win, const char* address, unsig
EXPORT DWORD WINAPI _webui_run_browser_task(LPVOID _arg);
EXPORT int _webui_system_win32(char* cmd, bool show);
#else
EXPORT void _webui_cb(void* _arg);
EXPORT void _webui_run_browser_task(void* _arg);
EXPORT void* _webui_cb(void* _arg);
EXPORT void* _webui_run_browser_task(void* _arg);
#endif
#endif /* _WEBUI_H */

View File

@ -39,59 +39,59 @@ static const char* webui_javascript_bridge =
" document.body.style.filter = \"contrast(1%)\"; \n"
"} \n"
"function _webui_start() { \n"
" if (\"WebSocket\" in window) { \n"
" if(\"WebSocket\" in window) { \n"
" _webui_ws = new WebSocket(\"ws://localhost:\" + _webui_port + \"/_ws\"); \n"
" _webui_ws.binaryType = \"arraybuffer\"; \n"
" _webui_ws.onopen = function () { \n"
" _webui_ws.binaryType = \"arraybuffer\"; \n"
" _webui_ws_status = true; \n"
" if (_webui_log) console.log(\"WebUI -> Connected\"); \n"
" if(_webui_log) console.log(\"WebUI -> Connected\"); \n"
" _webui_listener(); \n"
" }; \n"
" _webui_ws.onerror = function () { \n"
" if (_webui_log) console.log(\"WebUI -> Connection error\"); \n"
" if(_webui_log) console.log(\"WebUI -> Connection error\"); \n"
" _webui_close(255, \"\"); \n"
" }; \n"
" _webui_ws.onclose = function (evt) { \n"
" _webui_ws_status = false; \n"
" if (_webui_action8[0] == 252) { \n"
" if (_webui_log) console.log(\"WebUI -> Switch URL\"); \n"
" if(_webui_action8[0] == 252) { \n"
" if(_webui_log) console.log(\"WebUI -> Switch URL\"); \n"
" window.location.replace(_webui_action_val); \n"
" } else { \n"
" if (_webui_log) console.log(\"WebUI -> Connection lost [\" + evt.code + \"][\" + evt.reason + \"]\"); \n"
" if (!_webui_log) window.close(); \n"
" if(_webui_log) console.log(\"WebUI -> Connection lost [\" + evt.code + \"][\" + evt.reason + \"]\"); \n"
" if(!_webui_log) window.close(); \n"
" else _webui_freez_ui(); \n"
" } \n"
" }; \n"
" _webui_ws.onmessage = function (evt) { \n"
" const buffer8 = new Uint8Array(evt.data); \n"
" if (buffer8.length < 4) return; \n"
" if (buffer8[0] !== 255) { \n"
" if (_webui_log) console.log(\"WebUI -> Invalid flag -> 0x\" + buffer8[0] + \n"
" if(buffer8.length < 4) return; \n"
" if(buffer8[0] !== 255) { \n"
" if(_webui_log) console.log(\"WebUI -> Invalid flag -> 0x\" + buffer8[0] + \n"
" \" 0x\" + buffer8[1] + \" 0x\" + buffer8[2]); \n"
" return; \n"
" } \n"
" if (_webui_log) console.log(\"WebUI -> Flag -> 0x\" + buffer8[0] + \" 0x\" + \n"
" if(_webui_log) console.log(\"WebUI -> Flag -> 0x\" + buffer8[0] + \" 0x\" + \n"
" buffer8[1] + \" 0x\" + buffer8[2]); \n"
" var len = buffer8.length - 3; \n"
" if (buffer8[buffer8.length - 1] === 0) \n"
" if(buffer8[buffer8.length - 1] === 0) \n"
" len--; // Null terminated byte can break eval() \n"
" data8 = new Uint8Array(len); \n"
" for (i = 0; i < len; i++) data8[i] = buffer8[i + 3]; \n"
" var data8utf8 = new TextDecoder(\"utf-8\").decode(data8); \n"
" if (buffer8[1] === 252) { \n"
" if(buffer8[1] === 252) { \n"
" _webui_close(252, data8utf8); \n"
" } else if (buffer8[1] === 251) { \n"
" } else if(buffer8[1] === 251) { \n"
" _webui_close(251, \"\"); \n"
" } else if (buffer8[1] === 254) { \n"
" } else if(buffer8[1] === 254) { \n"
" data8utf8 = data8utf8.replace(/(?:\\r\\n|\\r|\\n)/g, \"\\\\n\"); \n"
" if (_webui_log) console.log(\"WebUI -> JS -> Run -> \" + data8utf8); \n"
" if(_webui_log) console.log(\"WebUI -> JS -> Run -> \" + data8utf8); \n"
" var FunReturn = \"undefined\"; \n"
" var FunError = false; \n"
" try { FunReturn = eval('(() => {' + data8utf8 + '})()'); } catch (e) { FunError = true; FunReturn = e.message } \n"
" if (typeof FunReturn === \"undefined\" || FunReturn === undefined) FunReturn = \"undefined\"; \n"
" if (_webui_log && !FunError) console.log(\"WebUI -> JS -> Return -> \" + FunReturn); \n"
" if (_webui_log && FunError) console.log(\"WebUI -> JS -> Return Error -> \" + FunReturn); \n"
" if(typeof FunReturn === \"undefined\" || FunReturn === undefined) FunReturn = \"undefined\"; \n"
" if(_webui_log && !FunError) console.log(\"WebUI -> JS -> Return -> \" + FunReturn); \n"
" if(_webui_log && FunError) console.log(\"WebUI -> JS -> Return Error -> \" + FunReturn); \n"
" var FunReturn8 = new TextEncoder(\"utf-8\").encode(FunReturn); \n"
" var Return8 = new Uint8Array(4 + FunReturn8.length); \n"
" Return8[0] = 255; \n"
@ -101,13 +101,13 @@ static const char* webui_javascript_bridge =
" else Return8[3] = 0; \n"
" var p = -1; \n"
" for (i = 4; i < FunReturn8.length + 4; i++) Return8[i] = FunReturn8[++p]; \n"
" if (Return8[0] !== 255) { \n"
" if (_webui_log) console.log(\"WebUI -> JS -> Generate response failed -> 0x\" + buffer8[0] + \" 0x\" + \n"
" if(Return8[0] !== 255) { \n"
" if(_webui_log) console.log(\"WebUI -> JS -> Generate response failed -> 0x\" + buffer8[0] + \" 0x\" + \n"
" buffer8[1] + \" 0x\" + buffer8[2]); \n"
" return; \n"
" } \n"
" if (_webui_ws_status) _webui_ws.send(Return8.buffer); \n"
" if (_webui_log) { \n"
" if(_webui_ws_status) _webui_ws.send(Return8.buffer); \n"
" if(_webui_log) { \n"
" var buf = \"[ \"; \n"
" for (i = 0; i < Return8.length; i++) buf = buf + \"0x\" + Return8[i] + \" \"; \n"
" buf = buf + \"]\"; \n"
@ -117,11 +117,11 @@ static const char* webui_javascript_bridge =
" }; \n"
" } else { \n"
" alert(\"Sorry. WebSocket not supported by your Browser.\"); \n"
" if (!_webui_log) webui_close_window(); \n"
" if(!_webui_log) webui_close_window(); \n"
" } \n"
"} \n"
"function _webui_SendEvent(name) { \n"
" if (_webui_ws_status && name != \"\") { \n"
" if(_webui_ws_status && name != \"\") { \n"
" var Name8 = new TextEncoder(\"utf-8\").encode(name); \n"
" var Event8 = new Uint8Array(3 + Name8.length); \n"
" Event8[0] = 255; \n"
@ -129,8 +129,8 @@ static const char* webui_javascript_bridge =
" Event8[2] = 0; \n"
" var p = -1; \n"
" for (i = 3; i < Name8.length + 3; i++) Event8[i] = Name8[++p]; \n"
" if (_webui_ws_status) _webui_ws.send(Event8.buffer); \n"
" if (_webui_log) { \n"
" if(_webui_ws_status) _webui_ws.send(Event8.buffer); \n"
" if(_webui_log) { \n"
" var buf = \"[ \"; \n"
" for (i = 0; i < Event8.length; i++) buf = buf + \"0x\" + Event8[i] + \" \"; \n"
" buf = buf + \"]\"; \n"
@ -147,80 +147,80 @@ static const char* webui_javascript_bridge =
" } \n"
" elems = document.getElementsByTagName(\"button\"); \n"
" for (i = 0; i < elems.length; i++) { \n"
" if (elems[i].id == \"\") continue; \n"
" if (_webui_log) console.log(\"WebUI -> Listen -> <Button> -> \" + elems[i].id); \n"
" if(elems[i].id == \"\") continue; \n"
" if(_webui_log) console.log(\"WebUI -> Listen -> <Button> -> \" + elems[i].id); \n"
" elems[i].addEventListener(\"click\", function () { \n"
" _webui_SendEvent(this.id); \n"
" }); \n"
" } \n"
" elems = document.getElementsByTagName(\"div\"); \n"
" for (i = 0; i < elems.length; i++) { \n"
" if (elems[i].id == \"\") continue; \n"
" if (_webui_log) console.log(\"WebUI -> Listen -> <Div> -> \" + elems[i].id); \n"
" if(elems[i].id == \"\") continue; \n"
" if(_webui_log) console.log(\"WebUI -> Listen -> <Div> -> \" + elems[i].id); \n"
" elems[i].addEventListener(\"click\", function () { \n"
" _webui_SendEvent(this.id); \n"
" }); \n"
" } \n"
" elems = document.getElementsByTagName(\"li\"); \n"
" for (i = 0; i < elems.length; i++) { \n"
" if (elems[i].id == \"\") continue; \n"
" if (_webui_log) console.log(\"WebUI -> Listen -> <LI> -> \" + elems[i].id); \n"
" if(elems[i].id == \"\") continue; \n"
" if(_webui_log) console.log(\"WebUI -> Listen -> <LI> -> \" + elems[i].id); \n"
" elems[i].addEventListener(\"click\", function () { \n"
" _webui_SendEvent(this.id); \n"
" }); \n"
" } \n"
" elems = document.getElementsByTagName(\"p\"); \n"
" for (i = 0; i < elems.length; i++) { \n"
" if (elems[i].id == \"\") continue; \n"
" if (_webui_log) console.log(\"WebUI -> Listen -> <P> -> \" + elems[i].id); \n"
" if(elems[i].id == \"\") continue; \n"
" if(_webui_log) console.log(\"WebUI -> Listen -> <P> -> \" + elems[i].id); \n"
" elems[i].addEventListener(\"click\", function () { \n"
" _webui_SendEvent(this.id); \n"
" }); \n"
" } \n"
" elems = document.getElementsByTagName(\"a\"); \n"
" for (i = 0; i < elems.length; i++) { \n"
" if (elems[i].id == \"\") continue; \n"
" if (_webui_log) console.log(\"WebUI -> Listen -> <A> -> \" + elems[i].id); \n"
" if(elems[i].id == \"\") continue; \n"
" if(_webui_log) console.log(\"WebUI -> Listen -> <A> -> \" + elems[i].id); \n"
" elems[i].addEventListener(\"click\", function () { \n"
" _webui_SendEvent(this.id); \n"
" }); \n"
" } \n"
" elems = document.getElementsByTagName(\"p\"); \n"
" for (i = 0; i < elems.length; i++) { \n"
" if (elems[i].id == \"\") continue; \n"
" if (_webui_log) console.log(\"WebUI -> Listen -> <P> -> \" + elems[i].id); \n"
" if(elems[i].id == \"\") continue; \n"
" if(_webui_log) console.log(\"WebUI -> Listen -> <P> -> \" + elems[i].id); \n"
" elems[i].addEventListener(\"click\", function () { \n"
" _webui_SendEvent(this.id); \n"
" }); \n"
" } \n"
" elems = document.getElementsByTagName(\"ul\"); \n"
" for (i = 0; i < elems.length; i++) { \n"
" if (elems[i].id == \"\") continue; \n"
" if (_webui_log) console.log(\"WebUI -> Listen -> <UL> -> \" + elems[i].id); \n"
" if(elems[i].id == \"\") continue; \n"
" if(_webui_log) console.log(\"WebUI -> Listen -> <UL> -> \" + elems[i].id); \n"
" elems[i].addEventListener(\"click\", function () { \n"
" _webui_SendEvent(this.id); \n"
" }); \n"
" } \n"
" elems = document.getElementsByTagName(\"footer\"); \n"
" for (i = 0; i < elems.length; i++) { \n"
" if (elems[i].id == \"\") continue; \n"
" if (_webui_log) console.log(\"WebUI -> Listen -> <FOOTER> -> \" + elems[i].id); \n"
" if(elems[i].id == \"\") continue; \n"
" if(_webui_log) console.log(\"WebUI -> Listen -> <FOOTER> -> \" + elems[i].id); \n"
" elems[i].addEventListener(\"click\", function () { \n"
" _webui_SendEvent(this.id); \n"
" }); \n"
" } \n"
" elems = document.getElementsByTagName(\"nav\"); \n"
" for (i = 0; i < elems.length; i++) { \n"
" if (elems[i].id == \"\") continue; \n"
" if (_webui_log) console.log(\"WebUI -> Listen -> <NAV> -> \" + elems[i].id); \n"
" if(elems[i].id == \"\") continue; \n"
" if(_webui_log) console.log(\"WebUI -> Listen -> <NAV> -> \" + elems[i].id); \n"
" elems[i].addEventListener(\"click\", function () { \n"
" _webui_SendEvent(this.id); \n"
" }); \n"
" } \n"
" elems = document.getElementsByTagName(\"span\"); \n"
" for (i = 0; i < elems.length; i++) { \n"
" if (elems[i].id == \"\") continue; \n"
" if (_webui_log) console.log(\"WebUI -> Listen -> <SPAN> -> \" + elems[i].id); \n"
" if(elems[i].id == \"\") continue; \n"
" if(_webui_log) console.log(\"WebUI -> Listen -> <SPAN> -> \" + elems[i].id); \n"
" elems[i].addEventListener(\"click\", function () { \n"
" _webui_SendEvent(this.id); \n"
" }); \n"
@ -231,14 +231,14 @@ static const char* webui_javascript_bridge =
"} \n"
"_webui_start(); \n"
"setTimeout(function () { \n"
" if (!_webui_ws_status) { \n"
" if(!_webui_ws_status) { \n"
" document.body.style.filter = \"contrast(1%)\"; \n"
" alert(\"WebUI failed to connect to the background application.\"); \n"
" if (!_webui_log) webui_close_window(); \n"
" if(!_webui_log) webui_close_window(); \n"
" } \n"
"}, 1e3); \n"
"document.addEventListener(\"keydown\", function (e) { \n"
" if (e.keyCode === 116) { \n"
" if(e.keyCode === 116) { \n"
" e.preventDefault(); \n"
" e.returnValue = false; \n"
" e.keyCode = 0; \n"
@ -252,9 +252,9 @@ static const char* webui_javascript_bridge =
" _webui_close(255, \"\"); \n"
"}; \n"
"document.addEventListener(\"contextmenu\", function (e) {}); \n"
"if (typeof webui_ready === \"function\") setTimeout(webui_ready, 1); \n"
"if(typeof webui_ready === \"function\") setTimeout(webui_ready, 1); \n"
"function webui_debug(status) { \n"
" if (status) { \n"
" if(status) { \n"
" console.log(\"WebUI -> Debug log enabled.\"); \n"
" _webui_log = true; \n"
" } else { \n"
@ -264,11 +264,11 @@ static const char* webui_javascript_bridge =
"} \n"
"function webui_close_window() { \n"
" _webui_freez_ui(); \n"
" if (_webui_ws_status) _webui_close(255, \"\"); \n"
" if(_webui_ws_status) _webui_close(255, \"\"); \n"
" else window.close(); \n"
"} \n"
"function webui_event(event_name) { \n"
" if (!_webui_ws_status) { \n"
" if(!_webui_ws_status) { \n"
" console.log(\"WebUI -> Send Event -> Failed because status is disconnected.\"); \n"
" return; \n"
" } \n"
@ -279,12 +279,12 @@ static const char* webui_javascript_bridge =
" SendEvent8[2] = 0; \n"
" var p = -1; \n"
" for (i = 3; i < event_name8.length + 3; i++) SendEvent8[i] = event_name8[++p]; \n"
" if (SendEvent8[0] !== 255) { \n"
" if (_webui_log) console.log(\"WebUI -> Send Event -> Generate header failed -> 0x\" + SendEvent8[0] + \" 0x\" + SendEvent8[1] + \" 0x\" + SendEvent8[2]); \n"
" if(SendEvent8[0] !== 255) { \n"
" if(_webui_log) console.log(\"WebUI -> Send Event -> Generate header failed -> 0x\" + SendEvent8[0] + \" 0x\" + SendEvent8[1] + \" 0x\" + SendEvent8[2]); \n"
" return; \n"
" } \n"
" if (_webui_ws_status) _webui_ws.send(SendEvent8.buffer); \n"
" if (_webui_log) { \n"
" if(_webui_ws_status) _webui_ws.send(SendEvent8.buffer); \n"
" if(_webui_log) { \n"
" var buf = \"[ \"; \n"
" for (i = 0; i < SendEvent8.length; i++) buf = buf + \"0x\" + SendEvent8[i] + \" \"; \n"
" buf = buf + \"]\"; \n"
@ -441,7 +441,7 @@ void _webui_sleep(long unsigned int ms) {
#ifdef _WIN32
Sleep(ms);
#else
sleep(ms);
usleep(ms);
#endif
}
@ -462,7 +462,7 @@ bool _webui_is_empty(const char* s) {
// printf("[0] _webui_is_empty()... \n");
#endif
if ((s != NULL) && (s[0] != '\0'))
if((s != NULL) && (s[0] != '\0'))
return false;
return true;
}
@ -502,30 +502,135 @@ unsigned int _webui_get_run_id() {
return ++webui.run_last_id;
}
bool _webui_socket_test_connect_mg(unsigned int port_num) {
#ifdef __linux__
bool _webui_socket_test_connect_mg(unsigned int port_num) {
struct mg_mgr mgr;
struct mg_connection *c;
mg_mgr_init(&mgr);
struct mg_mgr mgr;
struct mg_connection *c;
mg_mgr_init(&mgr);
char url[32];
sprintf(url, "localhost:%d", port_num);
char url[32];
sprintf(url, "localhost:%d", port_num);
c = mg_connect(&mgr, url, NULL, NULL);
if (c == NULL) {
c = mg_connect(&mgr, url, NULL, NULL);
if(c == NULL) {
mg_close_conn(c);
mg_mgr_free(&mgr);
return false;
}
// Cleaning
mg_close_conn(c);
mg_mgr_free(&mgr);
return false;
}
// Cleaning
mg_close_conn(c);
mg_mgr_free(&mgr);
// Connection Success
return true;
}
// Connection Success
return true;
}
int connect_ms(int sockfd, const struct sockaddr *addr, socklen_t addrlen, unsigned int timeout_ms) {
#ifdef WEBUI_LOG
printf("[0] connect_ms([%d] ms)... \n", timeout_ms);
#endif
int rc = 0;
int sockfd_flags_before = 0;
if((sockfd_flags_before = fcntl(sockfd, F_GETFL, 0) < 0))
return -1;
if(fcntl(sockfd, F_SETFL, sockfd_flags_before | O_NONBLOCK) < 0)
return -1;
// Start connecting (asynchronously)
do {
if (connect(sockfd, addr, addrlen)<0) {
// Did connect return an error? If so, we'll fail.
if ((errno != EWOULDBLOCK) && (errno != EINPROGRESS))
rc = -1;
else {
// Otherwise, we'll wait for it to complete.
// Set a deadline timestamp 'timeout' ms from now (needed b/c poll can be interrupted)
struct timespec now;
if(clock_gettime(CLOCK_MONOTONIC, &now) < 0) {
rc = -1;
break;
}
struct timespec deadline = {
.tv_sec = now.tv_sec,
.tv_nsec = now.tv_nsec + timeout_ms * 1000000l
};
// Wait for the connection to complete.
do {
// Calculate how long until the deadline
if(clock_gettime(CLOCK_MONOTONIC, &now) < 0) {
rc = -1;
break;
}
int ms_until_deadline = (int)((deadline.tv_sec - now.tv_sec)*1000l + (deadline.tv_nsec - now.tv_nsec)/1000000l);
if(ms_until_deadline<0) {
rc = 0;
break;
}
// Wait for connect to complete (or for the timeout deadline)
struct pollfd pfds[] = {
{
.fd = sockfd,
.events = POLLOUT
}
};
rc = poll(pfds, 1, ms_until_deadline);
// If poll 'succeeded', make sure it *really* succeeded
if( rc > 0) {
int error = 0;
socklen_t len = sizeof(error);
int retval = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len);
if(retval==0)
errno = error;
if(error!=0)
rc = -1;
}
}
// If poll was interrupted, try again.
while(rc == -1 && errno == EINTR);
// Did poll timeout? If so, fail.
if(rc == 0) {
errno = ETIMEDOUT;
rc = -1;
}
}
}
} while(0);
// Restore original O_NONBLOCK state
if(fcntl(sockfd, F_SETFL, sockfd_flags_before) < 0)
return -1;
// Success
return rc;
}
#endif
bool _webui_socket_test_connect(unsigned int port_num) {
@ -533,6 +638,9 @@ bool _webui_socket_test_connect(unsigned int port_num) {
printf("[0] _webui_socket_test_connect([%d])... \n", port_num);
#endif
// TODO: Detect if port is failed to connect but it's used
// We should tray to bind() to make sure.
#ifdef _WIN32
// -- Win32 ---------------------
WSADATA wsaData;
@ -568,16 +676,34 @@ bool _webui_socket_test_connect(unsigned int port_num) {
WSACleanup();
return false;
}
// Cleaning
closesocket(ConnectSocket);
freeaddrinfo(result);
WSACleanup();
// Connection Success
return true;
#else
// ...
int sockfd;
struct sockaddr_in serv_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
// Opening socket failed
return false;
}
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
// Leave [serv_addr.sin_addr.s_addr] empty to use localhost
serv_addr.sin_port = htons(port_num);
if(connect_ms(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr), 100) != 0) {
// Connection Failed
close(sockfd);
return false;
}
else {
// Connection Success
close(sockfd);
return true;
}
#endif
}
@ -628,16 +754,34 @@ bool _webui_socket_test_listen(unsigned int port_num) {
WSACleanup();
return false;
}
// Clean
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
// Listening Success
return true;
#else
// ...
int sockfd, connfd, len;
struct sockaddr_in servaddr, cli;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0) {
return false;
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port_num);
if((bind(sockfd, (struct sockaddr*) &servaddr, sizeof(servaddr))) != 0) {
close(sockfd);
return false;
}
if((listen(sockfd, 5)) != 0) {
close(sockfd);
return false;
}
// Listening Success
return true;
close(sockfd);
#endif
}
@ -665,7 +809,17 @@ bool _webui_port_is_used(unsigned int port_num) {
// Port is not in use
return false;
#else
// ...
// Connect test
// if(_webui_socket_test_connect(port_num))
// return true;
// Connect test MG
// if(_webui_socket_test_connect_mg(port_num))
// return true;
// Listener test
if(!_webui_socket_test_listen(port_num))
return true; // Port is busy
#endif
}
@ -1333,7 +1487,11 @@ static void _webui_server_event_handler(struct mg_connection *c, int ev, void *e
webui.mg_connections[win->core.window_number] = NULL;
_webui_free_port(win->core.server_port);
return 0;
#ifdef _WIN32
return 0;
#elif __linux__
pthread_exit(NULL);
#endif
}
bool _webui_browser_create_profile_folder(webui_window_t* win, unsigned int browser) {
@ -1378,20 +1536,15 @@ bool _webui_browser_create_profile_folder(webui_window_t* win, unsigned int brow
char firefox_profile_path[1024];
sprintf(firefox_profile_path, "%s%s.WebUI%s%s", temp, webui_sep, webui_sep, profile_name);
char buf[1024];
if(!_webui_folder_exist(buf)) {
if(!_webui_folder_exist(firefox_profile_path)) {
#ifdef _WIN32
sprintf(buf, "%s -CreateProfile \"WebUI %s\"", win->core.browser_path, firefox_profile_path);
_webui_cmd_sync(buf, false);
#else
sprintf(buf, "%s -CreateProfile \"WebUI %s\"", win->core.browser_path, firefox_profile_path);
_webui_cmd_sync(buf, false);
#endif
char buf[2048];
// Wait 10 second while slow PC create the folder..
sprintf(buf, "%s -CreateProfile \"WebUI %s\"", win->core.browser_path, firefox_profile_path);
_webui_cmd_sync(buf, false);
// Wait 10 seconds while slow PCs finish creating the folder...
for(unsigned int n = 0; n <= (webui.startup_timeout * 4); n++) {
if(_webui_folder_exist(firefox_profile_path))
@ -1455,9 +1608,11 @@ bool _webui_folder_exist(char* folder) {
#else
DIR* dir = opendir(folder);
if(dir) {
printf("[0] _webui_folder_exist([%s])... TTTTTTTTTTTTTTT \n", folder);
closedir(dir);
return true;
}
printf("[0] _webui_folder_exist([%s])... NOOOOOOOOOOOOOOOOO \n", folder);
#endif
return false;
@ -1728,7 +1883,7 @@ void _webui_browser_clean() {
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcessA(
if(!CreateProcessA(
NULL, // No module name (use command line)
cmd, // Command line
NULL, // Process handle not inheritable
@ -1750,7 +1905,7 @@ void _webui_browser_clean() {
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
if (Return == 0)
if(Return == 0)
return 0;
else
return -1;
@ -1773,7 +1928,9 @@ int _webui_cmd_sync(char* cmd, bool show) {
return _webui_system_win32(buf, show);
#else
sprintf(buf, "%s >>/dev/null 2>>/dev/null ", cmd);
return system(buf);
int r = system(buf);
r = (r != -1 && r != 127 && WIFEXITED(r)) ? WEXITSTATUS(r) : -1;
return r;
#endif
}
@ -1789,18 +1946,13 @@ int _webui_cmd_async(char* cmd, bool show) {
char buf[1024];
int res = 0;
// Asynchronous command
#ifdef _WIN32
// Make command async
sprintf(buf, "START \"\" %s", cmd);
res = _webui_cmd_sync(buf, show);
#else
// Make command async
if(fork() >= 0) {
_webui_cmd_sync(cmd, show);
return 0;
}
else
res = 1;
sprintf(buf, "%s > /dev/null 2>&1 &", cmd);
res = _webui_cmd_sync(buf, show);
#endif
return res;
@ -1809,7 +1961,7 @@ int _webui_cmd_async(char* cmd, bool show) {
#ifdef _WIN32
DWORD WINAPI _webui_run_browser_detect_proc_task(LPVOID _arg)
#else
void _webui_run_browser_detect_proc_task(void* _arg)
void* _webui_run_browser_detect_proc_task(void* _arg)
#endif
{
webui_cmd_async_t* arg = (webui_cmd_async_t*) _arg;
@ -1827,7 +1979,11 @@ int _webui_cmd_async(char* cmd, bool show) {
// Close app
webui_exit();
return 0;
#ifdef _WIN32
return 0;
#elif __linux__
pthread_exit(NULL);
#endif
}
int _webui_run_browser(webui_window_t* win, char* cmd) {
@ -1852,7 +2008,9 @@ int _webui_run_browser(webui_window_t* win, char* cmd) {
HANDLE user_fun_thread = CreateThread(NULL, 0, _webui_run_browser_detect_proc_task, (void *) arg, 0, NULL);
CloseHandle(user_fun_thread);
#else
// Create posix thread ...
pthread_t thread;
pthread_create(&thread, NULL, &_webui_run_browser_detect_proc_task, (void *) arg);
pthread_detach(thread);
#endif
// TODO: We need to set 'res = -1' when _webui_run_browser_detect_proc_task() fails.
@ -1998,12 +2156,7 @@ bool _webui_browser_start(webui_window_t* win, const char* address, unsigned int
if(browser > 10)
return false;
#ifdef __linux__
if(address[0] == '/') {
address = "file://" + address;
}
#endif
// TODO: Convert address from [/...] to [file://...]
if(browser != 0) {
@ -2048,18 +2201,18 @@ bool _webui_browser_start(webui_window_t* win, const char* address, unsigned int
//webui::exit();
#elif __APPLE__
// macOS
if(!_webui_browser_start_chrome(address))
if(!_webui_browser_start_firefox(address))
if(!_webui_browser_start_edge(address))
if(!_webui_browser_start_custom(address))
if(!_webui_browser_start_chrome(win, address))
if(!_webui_browser_start_firefox(win, address))
if(!_webui_browser_start_edge(win, address))
if(!_webui_browser_start_custom(win, address))
return false;
//webui::exit();
#else
// Linux
if(!_webui_browser_start_chrome(address))
if(!_webui_browser_start_firefox(address))
if(!_webui_browser_start_edge(address))
if(!_webui_browser_start_custom(address))
if(!_webui_browser_start_chrome(win, address))
if(!_webui_browser_start_firefox(win, address))
if(!_webui_browser_start_edge(win, address))
if(!_webui_browser_start_custom(win, address))
return false;
//webui::exit();
#endif
@ -2171,7 +2324,7 @@ webui_window_t* webui_new_window() {
win->core.window_number = _webui_get_new_window_number();
win->core.browser_path = (char*) _webui_malloc(1024);
win->core.profile_path = (char*) _webui_malloc(1024);
win->path = (char*) _webui_malloc(MAX_PATH);
win->path = (char*) _webui_malloc(WEBUI_MAX_PATH);
#ifdef WEBUI_LOG
printf("[0] webui_new_window() -> New window @ %p\n", win);
@ -2264,7 +2417,7 @@ bool webui_set_root_folder(webui_window_t* win, const char* path) {
printf("[%d] webui_set_root_folder([%s])... \n", win->core.window_number, path);
#endif
if(strlen(path) > MAX_PATH)
if(strlen(path) > WEBUI_MAX_PATH)
return false;
win->core.server_root = true;
@ -2317,17 +2470,28 @@ bool webui_show(webui_window_t* win, const char* html, unsigned int browser) {
unsigned int port = _webui_get_free_port();
win->core.server_port = port;
_webui_free_mem((void *) &win->core.url);
win->core.url = (char*) _webui_malloc(128);
win->core.url = (char*) _webui_malloc(256);
sprintf(win->core.url, "http://localhost:%d", port);
// New Server
HANDLE thread = CreateThread(NULL, 0, webui_server_start, (void *) win, 0, NULL);
win->core.server_thread = thread;
CloseHandle(thread);
// Run browser
if(!_webui_browser_start(win, win->core.url, browser))
if(!_webui_browser_start(win, win->core.url, browser)) {
// Browser not available
_webui_free_port(win->core.server_port);
return false;
}
// New Server Thread
#ifdef _WIN32
HANDLE thread = CreateThread(NULL, 0, webui_server_start, (void *) win, 0, NULL);
win->core.server_thread = thread;
CloseHandle(thread);
#elif __linux__
pthread_t thread;
pthread_create(&thread, NULL, &webui_server_start, (void *) win);
pthread_detach(thread);
win->core.server_thread = thread;
#endif
}
else {
@ -2416,7 +2580,7 @@ unsigned int webui_bind(webui_window_t* win, const char* element, void (*func) (
#ifdef _WIN32
DWORD WINAPI _webui_cb(LPVOID _arg)
#else
void _webui_cb(void* _arg)
void* _webui_cb(void* _arg)
#endif
{
webui_cb_t* arg = (webui_cb_t*) _arg;
@ -2456,7 +2620,11 @@ unsigned int webui_bind(webui_window_t* win, const char* element, void (*func) (
_webui_free_mem((void *) &arg->element_name);
_webui_free_mem((void *) &arg);
return 0;
#ifdef _WIN32
return 0;
#elif __linux__
pthread_exit(NULL);
#endif
}
void _webui_window_event(webui_window_t* win, char* element_id, char* element) {
@ -2475,7 +2643,9 @@ void _webui_window_event(webui_window_t* win, char* element_id, char* element) {
HANDLE user_fun_thread = CreateThread(NULL, 0, _webui_cb, (void *) arg, 0, NULL);
CloseHandle(user_fun_thread);
#else
// Create posix thread ...
pthread_t thread;
pthread_create(&thread, NULL, &_webui_cb, (void *) arg);
pthread_detach(thread);
#endif
}
@ -2656,8 +2826,9 @@ char* _webui_get_current_path() {
printf("[0] _webui_get_current_path()... \n");
#endif
char* path = (char*) _webui_malloc(MAX_PATH);
WEBUI_GET_CURRENT_DIR(path, MAX_PATH);
char* path = (char*) _webui_malloc(WEBUI_MAX_PATH);
if(WEBUI_GET_CURRENT_DIR (path, WEBUI_MAX_PATH) == NULL)
path[0] = 0x00;
return path;
}

3876
website/data/highlight.min.js vendored Normal file

File diff suppressed because one or more lines are too long

BIN
website/data/linux.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
website/data/macos.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

112
website/data/main.css Normal file
View File

@ -0,0 +1,112 @@
/* cyrillic-ext */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v21/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNa7lqDY.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v21/6xK3dSBYKcSV-LCoeQqfX1RYOo3qPK7lqDY.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v21/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNK7lqDY.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v21/6xK3dSBYKcSV-LCoeQqfX1RYOo3qO67lqDY.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v21/6xK3dSBYKcSV-LCoeQqfX1RYOo3qN67lqDY.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v21/6xK3dSBYKcSV-LCoeQqfX1RYOo3qNq7lqDY.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v21/6xK3dSBYKcSV-LCoeQqfX1RYOo3qOK7l.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v21/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmhduz8A.woff2) format('woff2');
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v21/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwkxduz8A.woff2) format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v21/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmxduz8A.woff2) format('woff2');
unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v21/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlBduz8A.woff2) format('woff2');
unicode-range: U+0370-03FF;
}
/* vietnamese */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v21/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmBduz8A.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v21/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwmRduz8A.woff2) format('woff2');
unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Source Sans Pro';
font-style: normal;
font-weight: 700;
src: url(https://fonts.gstatic.com/s/sourcesanspro/v21/6xKydSBYKcSV-LCoeQqfX1RYOo3ig4vwlxdu.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

1
website/data/tailwind.min.css vendored Normal file

File diff suppressed because one or more lines are too long

BIN
website/data/webui2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
website/data/windows.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

284
website/index.html Normal file
View File

@ -0,0 +1,284 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>WebUI</title>
<meta name="description" content="Use web browser as GUI">
<meta name="keywords" content="ui, gui, webui, browser">
<meta name="author" content="Hassan Draga">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css">
<link rel="stylesheet" href="./data/tailwind.min.css">
<link href="./data/main.css" rel="stylesheet">
<style>
.gradient {
background: linear-gradient(90deg, #4b2669ff 0%, #a486bcff 100%);
}
.gradient-button {
background: linear-gradient(90deg, #4b2669ff 0%, rgb(88, 47, 122) 100%);
}
.st0 {
fill: #A486BC;
}
.st1 {
fill: #4B2669;
}
.st2 {
fill: #713E90;
}
.text-white .st3 {
fill: #FFFFFF;
}
.text-gray-800 .st3 {
fill: #000000;
}
</style>
</head>
<body class="leading-normal tracking-normal text-white gradient" style="font-family: Source Sans Pro, sans-serif;">
<!--Nav-->
<nav id="header" class="fixed w-full z-30 top-0 text-white">
<div class="w-full container mx-auto flex flex-wrap items-center justify-between mt-0 py-2">
<div class="pl-4 flex items-center">
<a class="toggleColour text-white no-underline hover:no-underline font-bold text-2xl lg:text-4xl" href="https://webui.me/">
WebUI
</a>
</div>
<div class="block lg:hidden pr-4">
<button id="nav-toggle" class="flex items-center p-1 text-white-800">
<svg class="fill-current h-6 w-6" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<title>Menu</title>
<path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z"></path>
</svg>
</button>
</div>
<div class="w-full flex-grow lg:flex lg:items-center lg:w-auto hidden lg:block mt-2 lg:mt-0 lg:bg-transparent text-black p-4 lg:p-0 z-20 bg-gray-100" id="nav-content">
<ul class="list-reset lg:flex justify-end flex-1 items-center my-4">
<li class="mr-3">
<a class="inline-block py-2 px-4 text-black no-underline" href="https://webui.me/">Home</a>
</li>
<li class="mr-3">
<a class="inline-block py-2 px-4 text-black no-underline" href="#features">Features</a>
</li>
</ul>
<a href="#download" id="navAction" class="mx-auto lg:mx-0 hover:underline bg-white text-gray-800 font-bold mt-4 lg:mt-0 py-2 px-4 shadow opacity-75">Download</a>
</div>
</div>
</nav>
<!--Hero-->
<div class="relative pt-24 main-page-hero" style="z-index: 1">
<div class="container px-3 mx-auto flex flex-wrap flex-col md:flex-row items-center">
<!--Left Col-->
<div class="flex flex-col w-full md:w-2/5 justify-center items-start text-center md:text-left">
<h1 class="my-4 text-5xl font-bold leading-tight">Use any web browser as GUI. With your preferred language in the backend</h1>
<p class="leading-normal text-2xl mb-8">Portable, Lightweight, And full OS API's access</p>
<!-- <p class="tracking-loose w-full">Written in Pure C, Independent, Lightweight and small memory footprint.</p>-->
<a href="#download" class="mx-auto lg:mx-0 hover:underline bg-white text-gray-800 font-bold mt-4 lg:mt-0 py-2 px-4 shadow opacity-75">Download</a>
</div>
<!--Right Col-->
<div class="w-full md:w-3/5 py-6 text-right" style="text-align:right;">
<div><img src="./data/webui2.png"></div>
</div>
</div>
</div>
<!-- Waves -->
<div class="relative -mt-12 lg:-mt-24">
<svg viewBox="0 0 1428 174" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g transform="translate(-2.000000, 44.000000)" fill="#FFFFFF" fill-rule="nonzero">
<path d="M0,0 C90.7283404,0.927527913 147.912752,27.187927 291.910178,59.9119003 C387.908462,81.7278826 543.605069,89.334785 759,82.7326078 C469.336065,156.254352 216.336065,153.6679 0,74.9732496" opacity="0.100000001"></path>
<path d="M100,104.708498 C277.413333,72.2345949 426.147877,52.5246657 546.203633,45.5787101 C666.259389,38.6327546 810.524845,41.7979068 979,55.0741668 C931.069965,56.122511 810.303266,74.8455141 616.699903,111.243176 C423.096539,147.640838 250.863238,145.462612 100,104.708498 Z" opacity="0.100000001"></path>
<path d="M1046,51.6521276 C1130.83045,29.328812 1279.08318,17.607883 1439,40.1656806 L1439,120 C1271.17211,77.9435312 1140.17211,55.1609071 1046,51.6521276 Z" id="Path-4" opacity="0.200000003"></path>
</g>
<g transform="translate(-4.000000, 76.000000)" fill="#FFFFFF" fill-rule="nonzero">
<path d="M0.457,34.035 C57.086,53.198 98.208,65.809 123.822,71.865 C181.454,85.495 234.295,90.29 272.033,93.459 C311.355,96.759 396.635,95.801 461.025,91.663 C486.76,90.01 518.727,86.372 556.926,80.752 C595.747,74.596 622.372,70.008 636.799,66.991 C663.913,61.324 712.501,49.503 727.605,46.128 C780.47,34.317 818.839,22.532 856.324,15.904 C922.689,4.169 955.676,2.522 1011.185,0.432 C1060.705,1.477 1097.39,3.129 1121.236,5.387 C1161.703,9.219 1208.621,17.821 1235.4,22.304 C1285.855,30.748 1354.351,47.432 1440.886,72.354 L1441.191,104.352 L1.121,104.031 L0.457,34.035 Z"></path>
</g>
</g>
</svg>
</div>
<section class="bg-white border-b py-8">
<div class="container max-w-5xl mx-auto m-8">
<h1 id="features" class="w-full my-2 text-5xl font-bold leading-tight text-center text-gray-800">Features</h1>
<div class="w-full mb-4">
<div class="h-1 mx-auto gradient w-64 opacity-25 my-0 py-0 rounded-t"></div>
</div>
<div class="flex flex-wrap">
<div class="w-5/6 sm:w-1/2 p-6">
<h3 class="text-3xl text-gray-800 font-bold leading-none mb-3">Multi-language Backend</h3>
<p class="text-gray-600 mb-8" style="text-align: justify">You can easily embed and use the WebUI library in your project using your preferred programming languages, which gives you straightforward and easy-to-use APIs to create UI using web technologies.</p>
<p class="text-gray-600 mb-8" style="text-align: justify">Think of WebUI like a WebView controller, but instead of embedding the WebView controller in your program, which makes it big, and non-portable as it needs the WebView runtimes. Instead, using WebUI, you use a tiny static/dynamic library to run any installed web browser and use it as GUI, making your program small, fast and portable. All it needs is a web browser.</p>
<p class="text-gray-600 mb-8" style="text-align: justify">WebUI support many popular programming languages, like C, C++, Python, Golang, Rust, JavaScript, TypeScript, and more...</p>
</div>
<div class="w-full sm:w-1/2 p-6 text-right" style="text-align:right;">
<div style="text-align:right;"><img src="./data/webui_multi_languages.png"></div>
</div>
</div>
<div class="flex flex-wrap flex-col-reverse sm:flex-row">
<div class="w-full sm:w-1/2 p-6 mt-6 text-left" style="text-align:left;">
<div style="text-align:left;"><img src="./data/webui_multi_browsers.png"></div>
</div>
<div class="w-full sm:w-1/2 p-6 mt-6">
<div class="align-middle">
<h3 class="text-3xl text-gray-800 font-bold leading-none mb-3">Multi-browser Frontend</h3>
<p class="text-gray-600 mb-8">WebUI support many different web browsers, like Chrome, Firefox, Edge, Safari, and more..., Additionally, you can also use any other tool or an external program as a web browser by a simple function call. That means your program will always run on all machines, as all it needs is an installed web browser.</p>
</div>
</div>
</div>
</div>
</section>
<section id="download" class="bg-white border-b py-8">
<div class="container mx-auto flex flex-wrap pt-4 pb-12">
<h1 class="w-full my-2 text-5xl font-bold leading-tight text-center text-gray-800">Download</h1>
<div class="w-full mb-4">
<div class="h-1 mx-auto gradient w-64 opacity-25 my-0 py-0 rounded-t"></div>
</div>
<div class="w-full md:w-1/3 p-6 flex flex-col flex-grow flex-shrink">
<div class="flex-1 bg-white rounded-t rounded-b-none overflow-hidden shadow">
<div class="gradient">
<img class="border-gray-200 border mb-4" src="./data/windows.png">
</div>
<div class="w-full font-bold text-2xl text-gray-800 px-6">Windows</div>
<p class="text-gray-800 text-base px-6 mb-5">
This download include the WebUI prebuilt Windows x64 Static & Dynamic lib binaries.<br><br>
- MSVC 2019 (v142)<br>
- MSVC 2022 (v143)<br>
- GCC <a class="underline" href="https://jmeubank.github.io/tdm-gcc/" target="_blank">TDM</a>(v10.3.0)<br>
- TCC <a class="underline" href="https://github.com/TinyCC/tinycc" target="_blank">MobDev</a>(v0.9.27)<br>
</p>
</div>
<div class="flex-none mt-auto bg-white rounded-b rounded-t-none overflow-hidden shadow p-6">
<div class="flex items-center justify-center">
<a href="#" target="_blank" class="mx-auto lg:mx-0 hover:underline gradient-button text-white font-bold my-6 py-2 px-4 shadow-lg no-underline">
Coming Soon
<!-- Download Windows WebUI v2.0.1 -->
</a>
</div>
</div>
</div>
<div class="w-full md:w-1/3 p-6 flex flex-col flex-grow flex-shrink">
<div class="flex-1 bg-white rounded-t rounded-b-none overflow-hidden shadow">
<div class="gradient">
<img class="border-gray-200 border mb-4" src="./data/linux.png">
</div>
<div class="w-full font-bold text-2xl text-gray-800 px-6">Linux</div>
<p class="text-gray-800 text-base px-6 mb-5">
This download include the WebUI prebuilt Linux x64 Static & Dynamic lib binaries.<br><br>
- GCC<br>
- TCC<br>
- Clang<br>
</p>
</div>
<div class="flex-none mt-auto bg-white rounded-b rounded-t-none overflow-hidden shadow p-6">
<div class="flex items-center justify-center">
<a href="#" target="_blank" class="mx-auto lg:mx-0 hover:underline gradient-button text-white font-bold my-6 py-2 px-4 shadow-lg no-underline">
Coming Soon
</a>
</div>
</div>
</div>
<div class="w-full md:w-1/3 p-6 flex flex-col flex-grow flex-shrink">
<div class="flex-1 bg-white rounded-t rounded-b-none overflow-hidden shadow">
<div class="gradient">
<img class="border-gray-200 border mb-4" src="./data/macos.png">
</div>
<div class="w-full font-bold text-2xl text-gray-800 px-6">macOS</div>
<p class="text-gray-800 text-base px-6 mb-5">
This download include the WebUI prebuilt macOS Static & Dynamic lib binaries.<br><br>
- Clang<br>
</p>
</div>
<div class="flex-none mt-auto bg-white rounded-b rounded-t-none overflow-hidden shadow p-6">
<div class="flex items-center justify-center">
<a href="#" target="_blank" class="mx-auto lg:mx-0 hover:underline gradient-button text-white font-bold my-6 py-2 px-4 shadow-lg no-underline">
Coming Soon
</a>
</div>
</div>
</div>
</div>
</section>
<svg class="wave-top" viewBox="0 0 1439 147" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g transform="translate(-1.000000, -14.000000)" fill-rule="nonzero">
<g class="wave" fill="#f8fafc">
<path d="M1440,84 C1383.555,64.3 1342.555,51.3 1317,45 C1259.5,30.824 1206.707,25.526 1169,22 C1129.711,18.326 1044.426,18.475 980,22 C954.25,23.409 922.25,26.742 884,32 C845.122,37.787 818.455,42.121 804,45 C776.833,50.41 728.136,61.77 713,65 C660.023,76.309 621.544,87.729 584,94 C517.525,105.104 484.525,106.438 429,108 C379.49,106.484 342.823,104.484 319,102 C278.571,97.783 231.737,88.736 205,84 C154.629,75.076 86.296,57.743 0,32 L0,0 L1440,0 L1440,84 Z"></path>
</g>
<g transform="translate(1.000000, 15.000000)" fill="#FFFFFF">
<g transform="translate(719.500000, 68.500000) rotate(-180.000000) translate(-719.500000, -68.500000) ">
<path d="M0,0 C90.7283404,0.927527913 147.912752,27.187927 291.910178,59.9119003 C387.908462,81.7278826 543.605069,89.334785 759,82.7326078 C469.336065,156.254352 216.336065,153.6679 0,74.9732496" opacity="0.100000001"></path>
<path d="M100,104.708498 C277.413333,72.2345949 426.147877,52.5246657 546.203633,45.5787101 C666.259389,38.6327546 810.524845,41.7979068 979,55.0741668 C931.069965,56.122511 810.303266,74.8455141 616.699903,111.243176 C423.096539,147.640838 250.863238,145.462612 100,104.708498 Z" opacity="0.100000001"></path>
<path d="M1046,51.6521276 C1130.83045,29.328812 1279.08318,17.607883 1439,40.1656806 L1439,120 C1271.17211,77.9435312 1140.17211,55.1609071 1046,51.6521276 Z" opacity="0.200000003"></path>
</g>
</g>
</g>
</g>
</svg>
<section id="contact" class="container mx-auto text-center pt-6 mb-12">
<h1 class="w-full my-2 text-5xl font-bold leading-tight text-center text-white">Open Source</h1>
<div class="w-full mb-4">
<div class="h-1 mx-auto bg-white w-1/6 opacity-25 my-0 py-0 rounded-t"></div>
</div>
<h3 class="m-4 text-3xl leading-tight">Contribute to the WebUI project using your preferred programming language!</h3>
</section>
<section class="container mx-auto mb-12 text-center">
<p class="text-center">
WebUI is written in pure C, and the wrappers are written in multiple different language.<br>
This means you can contribute to the WebUI project using your main programming language, we need your expertise.<br>
<a class="underline" href="https://github.com/alifcommunity/webui" target="_blank">GitHub</a><br>
</p>
</section>
<footer class="bg-white">
<div class="container mx-auto">
<div class="w-full flex flex-col md:flex-row p-4 py-6 text-gray-500">
<p>
&copy;2022 <a href="https://github.com/hassandraga" class="text-gray-500">Hassan Draga</a>. <br>
Maintained by <a href="https://github.com/alifcommunity" class="text-gray-500">Alif Community</a>.
</p>
</div>
</div>
</footer>
<script>
var s = document.getElementById("header"),
c = document.getElementById("nav-content"),
u = document.getElementById("navAction"),
l = (document.getElementById("brandname"), document.querySelectorAll(".toggleColour")),
h = function() {
s.classList.add("bg-white"), u.classList.remove("bg-white"), u.classList.add("gradient-button"), u.classList.remove("text-gray-800"), u.classList.add("text-white");
for (var e = 0; e < l.length; e++) l[e].classList.add("text-gray-800"), l[e].classList.remove("text-white");
s.classList.add("shadow"), c.classList.remove("bg-gray-100"), c.classList.add("bg-white"), v.classList.remove("text-white-800"), v.classList.add("text-gray-900")
},
f = function() {
window.scrollY >10 ? h() : function() {
s.classList.remove("bg-white"), u.classList.remove("gradient-button"), u.classList.add("bg-white"), u.classList.remove("text-white"), u.classList.add("text-gray-800");
for (var e = 0; e < l.length; e++) l[e].classList.add("text-white"), l[e].classList.remove("text-gray-800");
s.classList.remove("shadow"), c.classList.remove("bg-white"), c.classList.add("bg-gray-100"), v.classList.remove("text-gray-900"), v.classList.add("text-white-800")
}()
};
window.addEventListener("load", (function() {
document.querySelector(".main-page-hero") ? (document.addEventListener("scroll", (function() {
f()
})), f()) : h()
}));
var d = document.getElementById("nav-content"),
v = document.getElementById("nav-toggle");
function p(e, t) {
for (; e.parentNode; ) {
if (e == t) return !0;
e = e.parentNode;
}
return !1;
}
(document.onclick = function (e) {
var t = (e && e.target) || (event && event.srcElement);
p(t, d) || (p(t, v) && d.classList.contains("hidden") ? d.classList.remove("hidden") : d.classList.add("hidden"));
});
</script>
</body>
</html>