Run formatter

This commit is contained in:
Turiiya 2023-10-27 06:26:54 +02:00
parent 1866d2573c
commit 8bf9bf2279
6 changed files with 1707 additions and 2393 deletions

View File

@ -8,7 +8,4 @@ IndentWrappedFunctionNames: true
AccessModifierOffset: 0
AlignAfterOpenBracket: BlockIndent
PointerAlignment: Left
AlignConsecutiveMacros:
Enabled: true
AcrossEmptyLines: true
AcrossComments: false
AlignConsecutiveMacros: AcrossEmptyLines

View File

@ -107,10 +107,11 @@ Think of WebUI like a WebView controller, but instead of embedding the WebView c
nmake
```
**Windows SSL/TLS (*Optional*)**
**Windows SSL/TLS (_Optional_)**
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.
- 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/)
```powershell
@ -131,7 +132,7 @@ Think of WebUI like a WebView controller, but instead of embedding the WebView c
make CC=clang
```
**Linux SSL/TLS (*Optional*)**
**Linux SSL/TLS (_Optional_)**
```sh
sudo apt update
@ -145,11 +146,12 @@ Think of WebUI like a WebView controller, but instead of embedding the WebView c
```
- **macOS**
```sh
make
```
**macOS SSL/TLS (*Optional*)**
**macOS SSL/TLS (_Optional_)**
```sh
brew install openssl

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
'use-strict' // Force strict mode for transpiled
'use-strict'; // Force strict mode for transpiled
/*
WebUI Bridge
@ -15,54 +15,54 @@
*/
//@ts-ignore use *.ts import real extension
import { AsyncFunction, addRefreshableEventListener } from './utils.ts'
import { AsyncFunction, addRefreshableEventListener } from './utils.ts';
type DataTypes = string | number | boolean | Uint8Array
type DataTypes = string | number | boolean | Uint8Array;
class WebuiBridge {
// WebUI settings
#secure: boolean
#token: number
#port: number
#winNum: number
#bindList: unknown[] = []
#log: boolean
#winX: number
#winY: number
#winW: number
#winH: number
#secure: boolean;
#token: number;
#port: number;
#winNum: number;
#bindList: unknown[] = [];
#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
#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
#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,
@ -75,206 +75,206 @@ class WebuiBridge {
winW,
winH,
}: {
secure: boolean
token: number
port: number
winNum: number
bindList: unknown[]
log?: boolean
winX: number
winY: number
winW: number
winH: number
secure: boolean;
token: number;
port: number;
winNum: number;
bindList: unknown[];
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
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
this.#Token[0] = this.#token;
// Instance
if ('webui' in globalThis) {
throw new Error('Sorry. WebUI is already defined, only one instance is allowed.')
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)
window.moveTo(this.#winX, this.#winY);
}
// Resize the current window
if (this.#winW !== undefined && this.#winH !== undefined) {
window.resizeTo(this.#winW, this.#winH)
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()
alert('Sorry. WebSocket is not supported by your web browser.');
if (!this.#log) globalThis.close();
}
// Connect to the backend application
this.#start()
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)
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)
if (this.#log) console.log(`WebUI -> DOM -> Navigation Event [${url.href}]`);
this.#sendEventNavigation(url.href);
} else {
this.#close(this.#CMD_NAVIGATION, url.href)
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
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)
if (this.#log) console.log(`WebUI -> DOM -> Navigation Click Event [${href}]`);
this.#sendEventNavigation(href);
} else {
this.#close(this.#CMD_NAVIGATION, href)
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()
})
if (this.#log) return; // Allowed in debug mode
if (event.key === 'F5') event.preventDefault();
});
onbeforeunload = () => {
this.#close()
}
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()
this.#freezeUi();
alert('Sorry. WebUI failed to connect to the backend application. Please try again.');
if (!this.#log) globalThis.close();
}
}, 1500)
}, 1500);
}
#close(reason = 0, value = '') {
this.#wsStatus = false
this.#closeReason = reason
this.#closeValue = value
this.#ws.close()
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}]`)
console.log(`WebUI -> Close -> Navigation to [${value}]`);
}
this.#allowNavigation = true
globalThis.location.replace(this.#closeValue)
this.#allowNavigation = true;
globalThis.location.replace(this.#closeValue);
} else {
if (this.#log) {
console.log(`WebUI -> Close.`)
console.log(`WebUI -> Close.`);
}
}
}
#freezeUi() {
document.body.style.filter = 'contrast(1%)'
document.body.style.filter = 'contrast(1%)';
}
#isTextBasedCommand(cmd: number): Boolean {
if (cmd !== this.#CMD_SEND_RAW) return true
return false
if (cmd !== this.#CMD_SEND_RAW) return true;
return false;
}
#getDataStrFromPacket(buffer: Uint8Array, startIndex: number): string {
let stringBytes: number[] = []
let stringBytes: number[] = [];
for (let i = startIndex; i < buffer.length; i++) {
if (buffer[i] === 0) {
// Check for null byte
break
break;
}
stringBytes.push(buffer[i])
stringBytes.push(buffer[i]);
}
// Convert the array of bytes to a string
const stringText = new TextDecoder().decode(new Uint8Array(stringBytes))
return stringText
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.')
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
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.')
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.')
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
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.')
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.')
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
buffer[index] = value & 0xff; // Least significant byte
buffer[index + 1] = (value >>> 8) & 0xff; // Most significant byte
}
#start() {
this.#keepAlive()
this.#callPromiseID[0] = 0
this.#keepAlive();
this.#callPromiseID[0] = 0;
if (this.#bindList.includes(this.#winNum + '/')) {
this.#hasEvents = true
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'
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.#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()
}
if (this.#log) console.log('WebUI -> Connection Failed');
this.#freezeUi();
};
this.#ws.onclose = (event) => {
this.#wsStatus = false
this.#wsStatus = false;
if (this.#closeReason === this.#CMD_NAVIGATION) {
if (this.#log) {
console.log(`WebUI -> Connection closed du to Navigation to [${this.#closeValue}]`)
console.log(`WebUI -> Connection closed du to Navigation to [${this.#closeValue}]`);
}
} else {
if (this.#log) {
console.log(`WebUI -> Connection lost (${event.code})`)
this.#freezeUi()
console.log(`WebUI -> Connection lost (${event.code})`);
this.#freezeUi();
} else {
this.#closeWindowTimer()
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
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)
const callId = this.#getID(buffer8, this.#PROTOCOL_ID);
// Process Command
switch (buffer8[this.#PROTOCOL_CMD]) {
case this.#CMD_JS_QUICK:
@ -286,27 +286,27 @@ class WebuiBridge {
// 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}]`)
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
let FunReturn = 'undefined';
let FunError = false;
try {
FunReturn = await AsyncFunction(scriptSanitize)()
FunReturn = await AsyncFunction(scriptSanitize)();
} catch (e) {
FunError = true
FunReturn = e.message
FunError = true;
FunReturn = e.message;
}
// Stop if this is a quick call
if (buffer8[this.#PROTOCOL_CMD] === this.#CMD_JS_QUICK) return
if (buffer8[this.#PROTOCOL_CMD] === this.#CMD_JS_QUICK) return;
// Get the call return
if (FunReturn === undefined) {
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}]`)
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]
@ -315,17 +315,21 @@ class WebuiBridge {
// 4: [Error, Script Response]
const Return8 = Uint8Array.of(
this.#WEBUI_SIGNATURE,
0, 0, 0, 0, // Token (4 Bytes)
0, 0, // ID (2 Bytes)
0,
0,
0,
0, // Token (4 Bytes)
0,
0, // ID (2 Bytes)
this.#CMD_JS,
FunError ? 1 : 0,
...new TextEncoder().encode(FunReturn),
)
this.#addToken(Return8, this.#token, this.#PROTOCOL_TOKEN)
this.#addID(Return8, callId, this.#PROTOCOL_ID)
this.#sendData(Return8)
);
this.#addToken(Return8, this.#token, this.#PROTOCOL_TOKEN);
this.#addID(Return8, callId, this.#PROTOCOL_ID);
this.#sendData(Return8);
}
break
break;
case this.#CMD_CALL_FUNC:
{
// Protocol
@ -334,19 +338,19 @@ class WebuiBridge {
// 2: [ID]
// 3: [CMD]
// 4: [Call Response]
const callResponse = this.#getDataStrFromPacket(buffer8, this.#PROTOCOL_DATA)
const callResponse = this.#getDataStrFromPacket(buffer8, this.#PROTOCOL_DATA);
if (this.#log) {
console.log(`WebUI -> CMD -> Call Response [${callResponse}]`)
console.log(`WebUI -> CMD -> Call Response [${callResponse}]`);
}
if (this.#callPromiseResolve[callId]) {
if (this.#log) {
console.log(`WebUI -> CMD -> Resolving Response #${callId}...`)
console.log(`WebUI -> CMD -> Resolving Response #${callId}...`);
}
this.#callPromiseResolve[callId]?.(callResponse)
this.#callPromiseResolve[callId] = undefined
this.#callPromiseResolve[callId]?.(callResponse);
this.#callPromiseResolve[callId] = undefined;
}
}
break
break;
case this.#CMD_NAVIGATION:
// Protocol
@ -355,10 +359,10 @@ class WebuiBridge {
// 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
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]
@ -366,22 +370,22 @@ class WebuiBridge {
// 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
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()
if (!this.#log) globalThis.close();
else {
console.log(`WebUI -> CMD -> Close`)
this.#ws.close()
console.log(`WebUI -> CMD -> Close`);
this.#ws.close();
}
break
break;
}
} else {
// Raw-binary based commands
@ -394,87 +398,89 @@ class WebuiBridge {
// 3: [CMD]
// 4: [Function,Null,Raw Data]
// Get function name
const functionName: string = this.#getDataStrFromPacket(buffer8, this.#PROTOCOL_DATA)
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}()]`)
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
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'))
this.#sendData(new TextEncoder().encode('ping'));
} else {
// There is an active communication
this.#Ping = true
this.#Ping = true;
}
await new Promise((resolve) => setTimeout(resolve, 20000))
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 (!(event.target instanceof HTMLElement)) return;
if (
this.#hasEvents ||
(event.target.id !== '' && this.#bindList.includes(this.#winNum + '/' + event.target?.id))
) {
this.#sendClick(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
}
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
@ -507,17 +513,17 @@ class WebuiBridge {
0, // ID (2 Bytes)
this.#CMD_CLICK,
0,
)
this.#addToken(packet, this.#token, this.#PROTOCOL_TOKEN)
);
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}]`)
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.#log) console.log(`WebUI -> Send Navigation Event [${url}]`);
if (this.#wsStatus && this.#hasEvents) {
const packet = Uint8Array.of(
// Protocol
@ -527,60 +533,64 @@ class WebuiBridge {
// 3: [CMD]
// 4: [URL]
this.#WEBUI_SIGNATURE,
0, 0, 0, 0, // Token (4 Bytes)
0, 0, // ID (2 Bytes)
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.#addToken(packet, this.#token, this.#PROTOCOL_TOKEN);
// this.#addID(packet, 0, this.#PROTOCOL_ID)
this.#sendData(packet)
this.#sendData(packet);
}
} else {
if (this.#log) console.log(`WebUI -> Navigation To [${url}]`)
this.#allowNavigation = true
globalThis.location.replace(url)
if (this.#log) console.log(`WebUI -> Navigation To [${url}]`);
this.#allowNavigation = true;
globalThis.location.replace(url);
}
}
}
#closeWindowTimer() {
setTimeout(function () {
globalThis.close()
}, 1000)
globalThis.close();
}, 1000);
}
#toUint16(value: number): number {
return value & 0xffff
return value & 0xffff;
}
#callPromise(fn: string, ...args: DataTypes[]) {
--this.#callPromiseID[0]
const callId = this.#toUint16(this.#callPromiseID[0])
--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
return arg.length;
} else {
// string, number, boolean
return new TextEncoder().encode(arg.toString()).length
return new TextEncoder().encode(arg.toString()).length;
}
})
.join(';');
// Combine values
let argsValues: Uint8Array = new Uint8Array()
let argsValues: Uint8Array = new Uint8Array();
for (const arg of args) {
let buffer: Uint8Array
let buffer: Uint8Array;
if (typeof arg === 'object') {
buffer = arg // Uint8Array
buffer = arg; // Uint8Array
} else {
// string, number, boolean
buffer = new TextEncoder().encode(arg.toString())
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
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]
@ -590,21 +600,25 @@ class WebuiBridge {
// 4: [Fn, Null, {LenLen...}, Null, {Data,Null,Data,Null...}]
const packet = Uint8Array.of(
this.#WEBUI_SIGNATURE,
0, 0, 0, 0, // Token (4 Bytes)
0, 0, // ID (2 Bytes)
0,
0,
0,
0, // Token (4 Bytes)
0,
0, // ID (2 Bytes)
this.#CMD_CALL_FUNC,
...new TextEncoder().encode(fn),
0,
...new TextEncoder().encode(argsLengths),
0,
...argsValues,
)
this.#addToken(packet, this.#token, this.#PROTOCOL_TOKEN)
this.#addID(packet, callId, this.#PROTOCOL_ID)
);
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)
})
this.#callPromiseResolve[callId] = resolve;
this.#sendData(packet);
});
}
// -- APIs --------------------------
/**
@ -616,22 +630,22 @@ class WebuiBridge {
* @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 (!fn) return Promise.reject(new SyntaxError('No binding name is provided'));
if (!this.#wsStatus) return Promise.reject(new Error('WebSocket is not connected'))
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}"`))
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
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 ''
if (typeof response !== 'string') return '';
return response
return response;
}
/**
* Active or deactivate webui debug logging
@ -640,11 +654,11 @@ class WebuiBridge {
*/
setLogging(status: boolean) {
if (status) {
console.log('WebUI -> Log Enabled.')
this.#log = true
console.log('WebUI -> Log Enabled.');
this.#log = true;
} else {
console.log('WebUI -> Log Disabled.')
this.#log = false
console.log('WebUI -> Log Disabled.');
this.#log = false;
}
}
/**
@ -653,7 +667,7 @@ class WebuiBridge {
* @param data - text string
*/
encode(data: string): string {
return btoa(data)
return btoa(data);
}
/**
* Decode base64 string into text
@ -661,15 +675,15 @@ class WebuiBridge {
* @param data - base64 string
*/
decode(data: string): string {
return atob(data)
return atob(data);
}
}
// Export
type webui = WebuiBridge
export default webui
export type { WebuiBridge }
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())
})
document.body.addEventListener('contextmenu', (event) => event.preventDefault());
addRefreshableEventListener(document.body, 'input', 'contextmenu', (event) => event.stopPropagation());
});

View File

@ -169,7 +169,8 @@ WEBUI_EXPORT size_t webui_new_window(void);
WEBUI_EXPORT size_t webui_new_window_id(size_t window_number);
/**
* @brief Get a free window number that can be used with `webui_new_window_id()`.
* @brief Get a free window number that can be used with
* `webui_new_window_id()`.
*
* @return Returns the first available free window number. Starting from 1.
*
@ -178,7 +179,8 @@ WEBUI_EXPORT size_t webui_new_window_id(size_t window_number);
WEBUI_EXPORT size_t webui_get_new_window_id(void);
/**
* @brief Bind a specific html element click event with a function. Empty element means all events.
* @brief Bind a specific html element click event with a function. Empty
* element means all events.
*
* @param window The window number
* @param element The HTML ID
@ -191,14 +193,16 @@ WEBUI_EXPORT size_t webui_get_new_window_id(void);
WEBUI_EXPORT size_t webui_bind(size_t window, const char* element, void (*func)(webui_event_t* e));
/**
* @brief Show a window using embedded HTML, or a file. If the window is already open, it will be refreshed.
* @brief Show a window using embedded HTML, or a file. If the window is already
* open, it will be refreshed.
*
* @param window The window number
* @param content The HTML, Or a local file
*
* @return Returns True if showing the window is successed.
*
* @example webui_show(myWindow, "<html>...</html>"); | webui_show(myWindow, "index.html");
* @example webui_show(myWindow, "<html>...</html>"); | webui_show(myWindow,
* "index.html");
*/
WEBUI_EXPORT bool webui_show(size_t window, const char* content);
@ -211,7 +215,8 @@ WEBUI_EXPORT bool webui_show(size_t window, const char* content);
*
* @return Returns True if showing the window is successed.
*
* @example webui_show_browser(myWindow, "<html>...</html>", Chrome); | webui_show(myWindow, "index.html", Firefox);
* @example webui_show_browser(myWindow, "<html>...</html>", Chrome); |
* webui_show(myWindow, "index.html", Firefox);
*/
WEBUI_EXPORT bool webui_show_browser(size_t window, const char* content, size_t browser);
@ -268,7 +273,8 @@ WEBUI_EXPORT void webui_exit(void);
WEBUI_EXPORT bool webui_set_root_folder(size_t window, const char* path);
/**
* @brief Set the web-server root folder path for all windows. Should be used before `webui_show()`.
* @brief Set the web-server root folder path for all windows. Should be used
* before `webui_show()`.
*
* @param path The local folder full path
*
@ -280,7 +286,8 @@ WEBUI_EXPORT bool webui_set_default_root_folder(const char* path);
* @brief Set a custom handler to serve files.
*
* @param window The window number
* @param handler The handler function: `void myHandler(const char* filename, int* length)`
* @param handler The handler function: `void myHandler(const char* filename,
* int* length)`
*
* @return Returns a unique bind ID.
*
@ -318,7 +325,8 @@ WEBUI_EXPORT void webui_set_timeout(size_t second);
WEBUI_EXPORT void webui_set_icon(size_t window, const char* icon, const char* icon_type);
/**
* @brief Base64 encoding. Use this to safely send text based data to the UI. If it fails it will return NULL.
* @brief Base64 encoding. Use this to safely send text based data to the UI. If
* it fails it will return NULL.
*
* @param str The string to encode (Should be null terminated)
*
@ -327,7 +335,8 @@ WEBUI_EXPORT void webui_set_icon(size_t window, const char* icon, const char* ic
WEBUI_EXPORT char* webui_encode(const char* str);
/**
* @brief Base64 decoding. Use this to safely decode received Base64 text from the UI. If it fails it will return NULL.
* @brief Base64 decoding. Use this to safely decode received Base64 text from
* the UI. If it fails it will return NULL.
*
* @param str The string to decode (Should be null terminated)
*
@ -345,8 +354,8 @@ WEBUI_EXPORT char* webui_decode(const char* str);
WEBUI_EXPORT void webui_free(void* ptr);
/**
* @brief Safely allocate memory using the WebUI memory management system. It can be safely freed using `webui_free()`
* at any time.
* @brief Safely allocate memory using the WebUI memory management system. It
* can be safely freed using `webui_free()` at any time.
*
* @param size The size of memory in bytes
*
@ -358,7 +367,8 @@ WEBUI_EXPORT void* webui_malloc(size_t size);
* @brief Safely send raw data to the UI.
*
* @param window The window number
* @param function The JavaScript function to receive raw data: `function myFunc(myData){}`
* @param function The JavaScript function to receive raw data: `function
* myFunc(myData){}`
* @param raw The raw data buffer
* @param size The raw data size in bytes
*
@ -399,14 +409,15 @@ WEBUI_EXPORT void webui_set_size(size_t window, unsigned int width, unsigned int
WEBUI_EXPORT void webui_set_position(size_t window, unsigned int x, unsigned int y);
/**
* @brief Set the web browser profile to use. An empty `name` and `path` means the default user profile. Need to be
* called before `webui_show()`.
* @brief Set the web browser profile to use. An empty `name` and `path` means
* the default user profile. Need to be called before `webui_show()`.
*
* @param window The window number
* @param name The web browser profile name
* @param path The web browser profile full path
*
* @example webui_set_profile(myWindow, "Bar", "/Home/Foo/Bar"); | webui_set_profile(myWindow, "", "");
* @example webui_set_profile(myWindow, "Bar", "/Home/Foo/Bar"); |
* webui_set_profile(myWindow, "", "");
*/
WEBUI_EXPORT void webui_set_profile(size_t window, const char* name, const char* path);
@ -441,7 +452,8 @@ WEBUI_EXPORT void webui_navigate(size_t window, const char* url);
WEBUI_EXPORT void webui_clean();
/**
* @brief Delete all local web-browser profiles folder. It should called at the end.
* @brief Delete all local web-browser profiles folder. It should called at the
* end.
*
* @example
* webui_wait();
@ -460,12 +472,14 @@ WEBUI_EXPORT void webui_delete_all_profiles();
* webui_delete_profile(myWindow);
* webui_clean();
*
* @note This can break functionality of other windows if using the same web-browser.
* @note This can break functionality of other windows if using the same
* web-browser.
*/
WEBUI_EXPORT void webui_delete_profile(size_t window);
/**
* @brief Get the ID of the parent process (The web browser may re-create another new process).
* @brief Get the ID of the parent process (The web browser may re-create
* another new process).
*
* @param window The window number
*
@ -489,14 +503,17 @@ WEBUI_EXPORT size_t webui_get_child_process_id(size_t window);
// -- SSL/TLS -------------------------
/**
* @brief Set the SSL/TLS certificate and the private key content, both in PEM format. This works only with `webui-2-secure` library. If set empty WebUI will generate a self-signed certificate.
* @brief Set the SSL/TLS certificate and the private key content, both in PEM
* format. This works only with `webui-2-secure` library. If set empty WebUI
* will generate a self-signed certificate.
*
* @param certificate_pem The SSL/TLS certificate content in PEM format
* @param private_key_pem The private key content in PEM format
*
* @return Returns True if the certificate and the key are valid.
*
* @example bool ret = webui_set_tls_certificate("-----BEGIN CERTIFICATE-----\n...", "-----BEGIN PRIVATE KEY-----\n...");
* @example bool ret = webui_set_tls_certificate("-----BEGIN
* CERTIFICATE-----\n...", "-----BEGIN PRIVATE KEY-----\n...");
*/
WEBUI_EXPORT bool webui_set_tls_certificate(const char* certificate_pem, const char* private_key_pem);
@ -505,7 +522,8 @@ WEBUI_EXPORT bool webui_set_tls_certificate(const char* certificate_pem, const c
// Run JavaScript without waiting for the response.
WEBUI_EXPORT void webui_run(size_t window, const char* script);
// Run JavaScript and get the response back (Make sure your local buffer can hold the response).
// Run JavaScript and get the response back (Make sure your local buffer can
// hold the response).
WEBUI_EXPORT bool webui_script(size_t window, const char* script, size_t timeout, char* buffer, size_t buffer_length);
// Chose between Deno and Nodejs as runtime for .js and .ts files.
@ -546,12 +564,14 @@ WEBUI_EXPORT void webui_return_bool(webui_event_t* e, bool b);
// -- Wrapper's Interface -------------
// Bind a specific html element click event with a function. Empty element means all events. This replaces
// `webui_bind()`. The func is (Window, EventType, Element, EventNumber, BindID).
// Bind a specific html element click event with a function. Empty element means
// all events. This replaces `webui_bind()`. The func is (Window, EventType,
// Element, EventNumber, BindID).
WEBUI_EXPORT size_t
webui_interface_bind(size_t window, const char* element, void (*func)(size_t, size_t, char*, size_t, size_t));
// When using `webui_interface_bind()`, you may need this function to easily set your callback response.
// When using `webui_interface_bind()`, you may need this function to easily set
// your callback response.
WEBUI_EXPORT void webui_interface_set_response(size_t window, size_t event_number, const char* response);
// Check if the app still running.

View File

@ -345,52 +345,78 @@ static _webui_core_t _webui_core;
static const char* webui_html_served =
"<html><head><title>Access Denied</title><script "
"src=\"/webui.js\"></"
"script><style>body{margin:0;background-repeat:no-repeat;background-attachment:fixed;background-color:#FF3CAC;"
"script><style>body{margin:0;background-repeat:no-repeat;background-"
"attachment:fixed;background-color:#FF3CAC;"
"background-image:linear-gradient(225deg,#FF3CAC 0%,#784BA0 45%,#2B86C5 "
"100%);font-family:sans-serif;margin:20px;color:#fff}a{color:#fff}</style></head><body><h2>&#9888; Access "
"Denied</h2><p>You can't access this content<br>because it's already in use in<br>another window.</p><br><a "
"100%);font-family:sans-serif;margin:20px;color:#fff}a{color:#fff}</"
"style></head><body><h2>&#9888; Access "
"Denied</h2><p>You can't access this content<br>because it's already in "
"use in<br>another window.</p><br><a "
"href=\"https://www.webui.me\"><small>WebUI v" WEBUI_VERSION "<small></a></body></html>";
static const char* webui_html_res_not_available =
"<html><head><title>Resource Not Available</title><script "
"src=\"/webui.js\"></"
"script><style>body{margin:0;background-repeat:no-repeat;background-attachment:fixed;background-color:#FF3CAC;"
"script><style>body{margin:0;background-repeat:no-repeat;background-"
"attachment:fixed;background-color:#FF3CAC;"
"background-image:linear-gradient(225deg,#FF3CAC 0%,#784BA0 45%,#2B86C5 "
"100%);font-family:sans-serif;margin:20px;color:#fff}a{color:#fff}</style></head><body><h2>&#9888; Resource Not "
"Available</h2><p>The requested resource is not available.</p><br><a href=\"https://www.webui.me\"><small>WebUI "
"100%);font-family:sans-serif;margin:20px;color:#fff}a{color:#fff}</"
"style></head><body><h2>&#9888; Resource Not "
"Available</h2><p>The requested resource is not available.</p><br><a "
"href=\"https://www.webui.me\"><small>WebUI "
"v" WEBUI_VERSION "<small></a></body></html>";
static const char* webui_deno_not_found =
"<html><head><title>Deno Not Found</title><script "
"src=\"/webui.js\"></"
"script><style>body{margin:0;background-repeat:no-repeat;background-attachment:fixed;background-color:#FF3CAC;"
"script><style>body{margin:0;background-repeat:no-repeat;background-"
"attachment:fixed;background-color:#FF3CAC;"
"background-image:linear-gradient(225deg,#FF3CAC 0%,#784BA0 45%,#2B86C5 "
"100%);font-family:sans-serif;margin:20px;color:#fff}a{color:#fff}</style></head><body><h2>&#9888; Deno Not "
"Found</h2><p>Deno is not found on this system.<br>Please download it from <a "
"href=\"https://github.com/denoland/deno/releases\">https://github.com/denoland/deno/releases</a></p><br><a "
"100%);font-family:sans-serif;margin:20px;color:#fff}a{color:#fff}</"
"style></head><body><h2>&#9888; Deno Not "
"Found</h2><p>Deno is not found on this system.<br>Please download it from "
"<a "
"href=\"https://github.com/denoland/deno/releases\">https://github.com/"
"denoland/deno/releases</a></p><br><a "
"href=\"https://www.webui.me\"><small>WebUI v" WEBUI_VERSION "<small></a></body></html>";
static const char* webui_nodejs_not_found =
"<html><head><title>Node.js Not Found</title><script "
"src=\"/webui.js\"></"
"script><style>body{margin:0;background-repeat:no-repeat;background-attachment:fixed;background-color:#FF3CAC;"
"script><style>body{margin:0;background-repeat:no-repeat;background-"
"attachment:fixed;background-color:#FF3CAC;"
"background-image:linear-gradient(225deg,#FF3CAC 0%,#784BA0 45%,#2B86C5 "
"100%);font-family:sans-serif;margin:20px;color:#fff}a{color:#fff}</style></head><body><h2>&#9888; Node.js Not "
"Found</h2><p>Node.js is not found on this system.<br>Please download it from <a "
"href=\"https://nodejs.org/en/download/\">https://nodejs.org/en/download/</a></p><br><a "
"100%);font-family:sans-serif;margin:20px;color:#fff}a{color:#fff}</"
"style></head><body><h2>&#9888; Node.js Not "
"Found</h2><p>Node.js is not found on this system.<br>Please download it "
"from <a "
"href=\"https://nodejs.org/en/download/\">https://nodejs.org/en/download/</"
"a></p><br><a "
"href=\"https://www.webui.me\"><small>WebUI v" WEBUI_VERSION "<small></a></body></html>";
static const char* webui_def_icon =
"<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"64\" height=\"64\" viewBox=\"0 0 64 64\" version=\"1.1\"><path "
"d=\"M 35.315 15.983 C 30.885 17.816, 29.305 25.835, 33.500 25.195 C 34.600 25.027, 37.177 24.802, 39.227 24.695 C "
"44.084 24.441, 49.054 19.899, 47.386 17.239 C 46.146 15.262, 38.884 14.507, 35.315 15.983 M 54.602 17.835 C "
"54.058 18.716, 60.204 22.022, 62.284 21.968 C 63.958 21.925, 58.228 17, 56.503 17 C 55.741 17, 54.886 17.376, "
"54.602 17.835\" stroke=\"none\" fill=\"#789dcc\" fill-rule=\"evenodd\"/><path d=\"M 3.635 19.073 C 2.098 20.282, "
"1 22.144, 1 23.542 C 1 26.692, 12.655 53.139, 14.754 54.750 C 15.650 55.437, 17.882 56, 19.716 56 C 23.227 56, "
"22.667 56.645, 30.331 43.762 L 32.163 40.684 36.109 47.830 C 40.333 55.479, 42.889 57.131, 47.815 55.394 C 49.855 "
"54.675, 51.575 51.765, 56.620 40.500 C 60.068 32.800, 62.904 25.600, 62.921 24.500 C 62.944 23.042, 61.572 "
"21.893, 57.862 20.262 C 55.062 19.031, 52.336 18.292, 51.806 18.620 C 51.275 18.948, 49.385 22.428, 47.604 26.353 "
"L 44.367 33.490 42.504 30.647 C 41.121 28.536, 40.907 27.379, 41.673 26.152 C 42.567 24.721, 42.224 24.526, "
"39.103 24.695 C 37.121 24.802, 34.600 25.027, 33.500 25.195 C 31.780 25.457, 31.517 24.966, 31.620 21.688 L "
"31.739 17.876 28.799 20.688 C 27.182 22.235, 24.694 25.637, 23.270 28.250 C 21.847 30.863, 20.354 33, 19.954 33 C "
"19.553 33, 17.969 30.044, 16.433 26.431 C 12.452 17.064, 8.833 14.984, 3.635 19.073\" stroke=\"none\" "
"fill=\"#294fb7\" fill-rule=\"evenodd\"/></svg>";
static const char* webui_def_icon = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"64\" height=\"64\" "
"viewBox=\"0 0 64 64\" version=\"1.1\"><path "
"d=\"M 35.315 15.983 C 30.885 17.816, 29.305 25.835, 33.500 25.195 C "
"34.600 25.027, 37.177 24.802, 39.227 24.695 C "
"44.084 24.441, 49.054 19.899, 47.386 17.239 C 46.146 15.262, 38.884 "
"14.507, 35.315 15.983 M 54.602 17.835 C "
"54.058 18.716, 60.204 22.022, 62.284 21.968 C 63.958 21.925, 58.228 17, "
"56.503 17 C 55.741 17, 54.886 17.376, "
"54.602 17.835\" stroke=\"none\" fill=\"#789dcc\" "
"fill-rule=\"evenodd\"/><path d=\"M 3.635 19.073 C 2.098 20.282, "
"1 22.144, 1 23.542 C 1 26.692, 12.655 53.139, 14.754 54.750 C 15.650 "
"55.437, 17.882 56, 19.716 56 C 23.227 56, "
"22.667 56.645, 30.331 43.762 L 32.163 40.684 36.109 47.830 C 40.333 "
"55.479, 42.889 57.131, 47.815 55.394 C 49.855 "
"54.675, 51.575 51.765, 56.620 40.500 C 60.068 32.800, 62.904 25.600, "
"62.921 24.500 C 62.944 23.042, 61.572 "
"21.893, 57.862 20.262 C 55.062 19.031, 52.336 18.292, 51.806 18.620 C "
"51.275 18.948, 49.385 22.428, 47.604 26.353 "
"L 44.367 33.490 42.504 30.647 C 41.121 28.536, 40.907 27.379, 41.673 "
"26.152 C 42.567 24.721, 42.224 24.526, "
"39.103 24.695 C 37.121 24.802, 34.600 25.027, 33.500 25.195 C 31.780 "
"25.457, 31.517 24.966, 31.620 21.688 L "
"31.739 17.876 28.799 20.688 C 27.182 22.235, 24.694 25.637, 23.270 28.250 "
"C 21.847 30.863, 20.354 33, 19.954 33 C "
"19.553 33, 17.969 30.044, 16.433 26.431 C 12.452 17.064, 8.833 14.984, "
"3.635 19.073\" stroke=\"none\" "
"fill=\"#294fb7\" fill-rule=\"evenodd\"/></svg>";
static const char* webui_def_icon_type = "image/svg+xml";
// -- Functions -----------------------
@ -1465,7 +1491,8 @@ static bool _webui_check_certificate(const char* certificate_pem, const char* pr
// Use certificate
if (SSL_CTX_use_certificate(ctx, cert) <= 0) {
#ifdef WEBUI_LOG
printf("[Core]\t\t_webui_check_certificate() -> SSL_CTX_use_certificate failed\n");
printf("[Core]\t\t_webui_check_certificate() -> SSL_CTX_use_certificate "
"failed\n");
#endif
BIO_free_all(bio_cert);
X509_free(cert);
@ -1478,7 +1505,8 @@ static bool _webui_check_certificate(const char* certificate_pem, const char* pr
EVP_PKEY* private_key = PEM_read_bio_PrivateKey(bio_key, NULL, 0, NULL);
if (private_key == NULL) {
#ifdef WEBUI_LOG
printf("[Core]\t\t_webui_check_certificate() -> PEM_read_bio_PrivateKey failed\n");
printf("[Core]\t\t_webui_check_certificate() -> PEM_read_bio_PrivateKey "
"failed\n");
#endif
EVP_PKEY_free(private_key);
BIO_free_all(bio_key);
@ -1492,7 +1520,8 @@ static bool _webui_check_certificate(const char* certificate_pem, const char* pr
// Use key
if (SSL_CTX_use_PrivateKey(ctx, private_key) <= 0) {
#ifdef WEBUI_LOG
printf("[Core]\t\t_webui_check_certificate() -> SSL_CTX_use_PrivateKey failed\n");
printf("[Core]\t\t_webui_check_certificate() -> SSL_CTX_use_PrivateKey "
"failed\n");
#endif
EVP_PKEY_free(private_key);
BIO_free_all(bio_key);
@ -1604,7 +1633,8 @@ size_t webui_get_child_process_id(size_t window) {
if (!dir)
return win->process_id;
while ((entry = readdir(dir)) != NULL) {
// Ensure we're looking at a process directory (directories that are just numbers)
// Ensure we're looking at a process directory (directories that are just
// numbers)
if (entry->d_type == DT_DIR && strspn(entry->d_name, "0123456789") == strlen(entry->d_name)) {
char statFilepath[1024];
snprintf(statFilepath, sizeof(statFilepath), "/proc/%s/stat", entry->d_name);
@ -2199,7 +2229,8 @@ static void _webui_interface_bind_handler(webui_event_t* e) {
// Call cb
#ifdef WEBUI_LOG
printf("[Core]\t\t_webui_interface_bind_handler() -> Calling user callback...\n[Call]\n");
printf("[Core]\t\t_webui_interface_bind_handler() -> Calling user "
"callback...\n[Call]\n");
#endif
_webui_core.cb_interface[cb_index](e->window, e->event_type, e->element, e->event_number, e->bind_id);
}
@ -2219,7 +2250,11 @@ static void _webui_interface_bind_handler(webui_event_t* e) {
response = event_inf->response;
}
printf("[Core]\t\t_webui_interface_bind_handler() -> user-callback response [%s]\n", response);
printf(
"[Core]\t\t_webui_interface_bind_handler() -> user-callback response "
"[%s]\n",
response
);
#endif
}
@ -2403,7 +2438,8 @@ static void _webui_ptr_add(void* ptr, size_t size) {
if (_webui_core.ptr_list[i] == NULL) {
#ifdef WEBUI_LOG
// printf("[Core]\t\t_webui_ptr_add(0x%p) -> Allocate %zu bytes\n", ptr, size);
// printf("[Core]\t\t_webui_ptr_add(0x%p) -> Allocate %zu bytes\n", ptr,
// size);
#endif
_webui_core.ptr_list[i] = ptr;
@ -2413,7 +2449,8 @@ static void _webui_ptr_add(void* ptr, size_t size) {
}
#ifdef WEBUI_LOG
// printf("[Core]\t\t_webui_ptr_add(0x%p) -> Allocate %zu bytes\n", ptr, size);
// printf("[Core]\t\t_webui_ptr_add(0x%p) -> Allocate %zu bytes\n", ptr,
// size);
#endif
_webui_core.ptr_list[_webui_core.ptr_position] = ptr;
@ -3228,14 +3265,16 @@ static int _webui_interpret_file(_webui_window_t* win, struct mg_connection* con
#ifdef _WIN32
sprintf(
cmd,
"Set NO_COLOR=1 & Set DENO_NO_UPDATE_CHECK=1 & deno run --quiet --allow-all "
"Set NO_COLOR=1 & Set DENO_NO_UPDATE_CHECK=1 & deno run "
"--quiet --allow-all "
"--unstable \"%s\" \"%s\"",
full_path, query
);
#else
sprintf(
cmd,
"NO_COLOR=1; DENO_NO_UPDATE_CHECK=1; deno run --quiet --allow-all --unstable "
"NO_COLOR=1; DENO_NO_UPDATE_CHECK=1; deno run --quiet "
"--allow-all --unstable "
"\"%s\" \"%s\"",
full_path, query
);
@ -3343,7 +3382,8 @@ static const char* _webui_generate_js_bridge(_webui_window_t* win) {
#ifdef WEBUI_LOG
// Non-authorized connection
else
printf("[Core]\t\t_webui_generate_js_bridge() -> Non-authorized connection.\n");
printf("[Core]\t\t_webui_generate_js_bridge() -> Non-authorized "
"connection.\n");
#endif
if (token == 0) {
@ -3387,7 +3427,8 @@ static const char* _webui_generate_js_bridge(_webui_window_t* win) {
char* js = (char*)_webui_malloc(len);
int c = sprintf(
js,
"%s\n document.addEventListener(\"DOMContentLoaded\",function(){ globalThis.webui = new WebuiBridge({ "
"%s\n document.addEventListener(\"DOMContentLoaded\",function(){ "
"globalThis.webui = new WebuiBridge({ "
"secure: %s, token: %" PRIu32 ", port: %zu, winNum: %zu, bindList: %s, log: %s, ",
webui_javascript_bridge,
#ifdef WEBUI_TLS
@ -3441,7 +3482,11 @@ static bool _webui_browser_create_new_profile(_webui_window_t* win, size_t brows
}
#ifdef WEBUI_LOG
printf("[Core]\t\t_webui_browser_create_new_profile(%zu) -> Generating WebUI profile...\n", browser);
printf(
"[Core]\t\t_webui_browser_create_new_profile(%zu) -> Generating WebUI "
"profile...\n",
browser
);
#endif
// Temp folder
@ -3551,7 +3596,11 @@ static bool _webui_browser_create_new_profile(_webui_window_t* win, size_t brows
file = fopen(buf, "a");
if (file == NULL)
return false;
fputs("user_pref(\"toolkit.legacyUserProfileCustomizations.stylesheets\", true); ", file);
fputs(
"user_pref(\"toolkit.legacyUserProfileCustomizations.stylesheets\","
" true); ",
file
);
fputs("user_pref(\"browser.shell.checkDefaultBrowser\", false); ", file);
fputs("user_pref(\"browser.tabs.warnOnClose\", false); ", file);
fclose(file);
@ -3570,60 +3619,94 @@ static bool _webui_browser_create_new_profile(_webui_window_t* win, size_t brows
#ifdef _WIN32
fputs(
":root{--uc-toolbar-height:32px}:root:not([uidensity=\"compact\"]) "
"{--uc-toolbar-height:38px}#TabsToolbar{visibility:collapse!important}:root:not(["
"{--uc-toolbar-height:38px}#TabsToolbar{visibility:collapse!"
"important}:root:not(["
"inFullscreen]) #nav-bar{margin-top:calc(0px - "
"var(--uc-toolbar-height))}#toolbar-menubar{min-height:unset!important;height:var(--uc-"
"toolbar-height)!important;position:relative}#main-menubar{-moz-box-flex:1;background-"
"color:var(--toolbar-bgcolor,--toolbar-non-lwt-bgcolor);background-clip:padding-box;border-"
"var(--uc-toolbar-height))}#toolbar-menubar{min-height:unset!"
"important;height:var(--uc-"
"toolbar-height)!important;position:relative}#main-menubar{-moz-"
"box-flex:1;background-"
"color:var(--toolbar-bgcolor,--toolbar-non-lwt-bgcolor);background-"
"clip:padding-box;border-"
"right:30px solid transparent;border-image:linear-gradient(to "
"left,transparent,var(--toolbar-bgcolor,--toolbar-non-lwt-bgcolor) 30px) 20 / "
"30px}#toolbar-menubar:not([inactive]) {z-index:2}#toolbar-menubar[inactive] > "
"#menubar-items{opacity:0;pointer-events:none;margin-left:var(--uc-window-drag-space-width,"
"left,transparent,var(--toolbar-bgcolor,--toolbar-non-lwt-bgcolor) "
"30px) 20 / "
"30px}#toolbar-menubar:not([inactive]) "
"{z-index:2}#toolbar-menubar[inactive] > "
"#menubar-items{opacity:0;pointer-events:none;margin-left:var(--uc-"
"window-drag-space-width,"
"0px)}#nav-bar{visibility:collapse}@-moz-document "
"url(chrome://browser/content/browser.xhtml) {:root:not([sizemode=\"fullscreen\"]) > "
"head{display: block;position: fixed;width: calc(200vw - 440px);text-align: left;z-index: "
"9;pointer-events: none;}head > *{ display: none }head > title{display: "
"-moz-inline-box;padding: 4px;max-width: 50vw;overflow-x: hidden;text-overflow: "
"url(chrome://browser/content/browser.xhtml) "
"{:root:not([sizemode=\"fullscreen\"]) > "
"head{display: block;position: fixed;width: calc(200vw - "
"440px);text-align: left;z-index: "
"9;pointer-events: none;}head > *{ display: none }head > "
"title{display: "
"-moz-inline-box;padding: 4px;max-width: 50vw;overflow-x: "
"hidden;text-overflow: "
"ellipsis;}}",
file
);
#elif __APPLE__
fputs(
// ":root{--uc-toolbar-height:32px}:root:not([uidensity=\"compact\"]) "
// "{--uc-toolbar-height:38px}#TabsToolbar{visibility:collapse!important} "
// ":root{--uc-toolbar-height:32px}:root:not([uidensity=\"compact\"])
// "
// "{--uc-toolbar-height:38px}#TabsToolbar{visibility:collapse!important}
// "
":root:not([inFullscreen]) #nav-bar{margin-top:calc(0px - "
"var(--uc-toolbar-height))}#toolbar-menubar{min-height:unset!important;height:var(--uc-"
"toolbar-height)!important;position:relative}#main-menubar{-moz-box-flex:1;background-"
"color:var(--toolbar-bgcolor,--toolbar-non-lwt-bgcolor);background-clip:padding-box;border-"
"var(--uc-toolbar-height))}#toolbar-menubar{min-height:unset!"
"important;height:var(--uc-"
"toolbar-height)!important;position:relative}#main-menubar{-moz-box-"
"flex:1;background-"
"color:var(--toolbar-bgcolor,--toolbar-non-lwt-bgcolor);background-"
"clip:padding-box;border-"
"right:30px solid transparent;border-image:linear-gradient(to "
"left,transparent,var(--toolbar-bgcolor,--toolbar-non-lwt-bgcolor) 30px) 20 / "
"30px}#toolbar-menubar:not([inactive]) {z-index:2}#toolbar-menubar[inactive] > "
"#menubar-items{opacity:0;pointer-events:none;margin-left:var(--uc-window-drag-space-width,"
"left,transparent,var(--toolbar-bgcolor,--toolbar-non-lwt-bgcolor) "
"30px) 20 / "
"30px}#toolbar-menubar:not([inactive]) "
"{z-index:2}#toolbar-menubar[inactive] > "
"#menubar-items{opacity:0;pointer-events:none;margin-left:var(--uc-"
"window-drag-space-width,"
"0px)}#nav-bar{visibility:collapse}@-moz-document "
"url(chrome://browser/content/browser.xhtml) {:root:not([sizemode=\"fullscreen\"]) > "
"head{display: block;position: fixed;width: calc(200vw - 440px);text-align: left;z-index: "
"9;pointer-events: none;}head > *{ display: none }head > title{display: "
"-moz-inline-box;padding: 4px;max-width: 50vw;overflow-x: hidden;text-overflow: "
"url(chrome://browser/content/browser.xhtml) "
"{:root:not([sizemode=\"fullscreen\"]) > "
"head{display: block;position: fixed;width: calc(200vw - "
"440px);text-align: left;z-index: "
"9;pointer-events: none;}head > *{ display: none }head > "
"title{display: "
"-moz-inline-box;padding: 4px;max-width: 50vw;overflow-x: "
"hidden;text-overflow: "
"ellipsis;}}",
file
);
#else
fputs(
":root{--uc-toolbar-height:32px}:root:not([uidensity=\"compact\"]) "
"{--uc-toolbar-height:38px}#TabsToolbar{visibility:collapse!important}:root:not(["
"{--uc-toolbar-height:38px}#TabsToolbar{visibility:collapse!"
"important}:root:not(["
"inFullscreen]) #nav-bar{margin-top:calc(0px - "
"var(--uc-toolbar-height))}#toolbar-menubar{min-height:unset!important;height:var(--uc-"
"toolbar-height)!important;position:relative}#main-menubar{-moz-box-flex:1;background-"
"color:var(--toolbar-bgcolor,--toolbar-non-lwt-bgcolor);background-clip:padding-box;border-"
"var(--uc-toolbar-height))}#toolbar-menubar{min-height:unset!"
"important;height:var(--uc-"
"toolbar-height)!important;position:relative}#main-menubar{-moz-"
"box-flex:1;background-"
"color:var(--toolbar-bgcolor,--toolbar-non-lwt-bgcolor);background-"
"clip:padding-box;border-"
"right:30px solid transparent;border-image:linear-gradient(to "
"left,transparent,var(--toolbar-bgcolor,--toolbar-non-lwt-bgcolor) 30px) 20 / "
"30px}#toolbar-menubar:not([inactive]) {z-index:2}#toolbar-menubar[inactive] > "
"#menubar-items{opacity:0;pointer-events:none;margin-left:var(--uc-window-drag-space-width,"
"left,transparent,var(--toolbar-bgcolor,--toolbar-non-lwt-bgcolor) "
"30px) 20 / "
"30px}#toolbar-menubar:not([inactive]) "
"{z-index:2}#toolbar-menubar[inactive] > "
"#menubar-items{opacity:0;pointer-events:none;margin-left:var(--uc-"
"window-drag-space-width,"
"0px)}#nav-bar{visibility:collapse}@-moz-document "
"url(chrome://browser/content/browser.xhtml) {:root:not([sizemode=\"fullscreen\"]) > "
"head{display: block;position: fixed;width: calc(200vw - 440px);text-align: left;z-index: "
"9;pointer-events: none;}head > *{ display: none }head > title{display: "
"-moz-inline-box;padding: 4px;max-width: 50vw;overflow-x: hidden;text-overflow: "
"url(chrome://browser/content/browser.xhtml) "
"{:root:not([sizemode=\"fullscreen\"]) > "
"head{display: block;position: fixed;width: calc(200vw - "
"440px);text-align: left;z-index: "
"9;pointer-events: none;}head > *{ display: none }head > "
"title{display: "
"-moz-inline-box;padding: 4px;max-width: 50vw;overflow-x: "
"hidden;text-overflow: "
"ellipsis;}}",
file
);
@ -3906,9 +3989,12 @@ static bool _webui_browser_exist(_webui_window_t* win, size_t browser) {
char browser_folder[WEBUI_MAX_PATH];
// Search in `HKEY_LOCAL_MACHINE` (If Google Chrome installed for multi-user)
// Search in `HKEY_LOCAL_MACHINE` (If Google Chrome installed for
// multi-user)
if (_webui_get_windows_reg_value(
HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe",
HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows\\CurrentVer"
L"sion\\App Paths\\chrome.exe",
L"Path", browser_folder
)) {
@ -3924,7 +4010,9 @@ static bool _webui_browser_exist(_webui_window_t* win, size_t browser) {
// Search in `HKEY_CURRENT_USER` (If Google Chrome installed for one user)
if (_webui_get_windows_reg_value(
HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe",
HKEY_CURRENT_USER,
L"Software\\Microsoft\\Windows\\CurrentVer"
L"sion\\App Paths\\chrome.exe",
L"Path", browser_folder
)) {
@ -3983,8 +4071,10 @@ static bool _webui_browser_exist(_webui_window_t* win, size_t browser) {
// Search in `HKEY_LOCAL_MACHINE` (If Edge installed for multi-user)
if (_webui_get_windows_reg_value(
HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\msedge.exe", L"",
browser_fullpath
HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows\\CurrentVer"
L"sion\\App Paths\\msedge.exe",
L"", browser_fullpath
)) {
// Make sure the browser executable file exist
@ -3999,8 +4089,10 @@ static bool _webui_browser_exist(_webui_window_t* win, size_t browser) {
// Search in `HKEY_CURRENT_USER` (If Edge installed for one user)
if (_webui_get_windows_reg_value(
HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\msedge.exe", L"",
browser_fullpath
HKEY_CURRENT_USER,
L"Software\\Microsoft\\Windows\\CurrentVer"
L"sion\\App Paths\\msedge.exe",
L"", browser_fullpath
)) {
// Make sure the browser executable file exist
@ -4064,8 +4156,10 @@ static bool _webui_browser_exist(_webui_window_t* win, size_t browser) {
// Search in `HKEY_CURRENT_USER` (If Epic installed for one user)
if (_webui_get_windows_reg_value(
HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\epic.exe", L"",
browser_fullpath
HKEY_CURRENT_USER,
L"Software\\Microsoft\\Windows\\CurrentVer"
L"sion\\App Paths\\epic.exe",
L"", browser_fullpath
)) {
// Make sure the browser executable file exist
@ -4080,8 +4174,10 @@ static bool _webui_browser_exist(_webui_window_t* win, size_t browser) {
// Search in `HKEY_LOCAL_MACHINE` (If Epic installed for multi-user)
if (_webui_get_windows_reg_value(
HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\epic.exe", L"",
browser_fullpath
HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows\\CurrentVer"
L"sion\\App Paths\\epic.exe",
L"", browser_fullpath
)) {
// Make sure the browser executable file exist
@ -4133,7 +4229,9 @@ static bool _webui_browser_exist(_webui_window_t* win, size_t browser) {
// Search in `HKEY_LOCAL_MACHINE` (If Vivaldi installed for multi-user)
if (_webui_get_windows_reg_value(
HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\vivaldi.exe",
HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows\\CurrentVer"
L"sion\\App Paths\\vivaldi.exe",
L"", browser_fullpath
)) {
@ -4149,8 +4247,10 @@ static bool _webui_browser_exist(_webui_window_t* win, size_t browser) {
// Search in `HKEY_CURRENT_USER` (If Vivaldi installed for one user)
if (_webui_get_windows_reg_value(
HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\vivaldi.exe", L"",
browser_fullpath
HKEY_CURRENT_USER,
L"Software\\Microsoft\\Windows\\CurrentVer"
L"sion\\App Paths\\vivaldi.exe",
L"", browser_fullpath
)) {
// Make sure the browser executable file exist
@ -4212,8 +4312,10 @@ static bool _webui_browser_exist(_webui_window_t* win, size_t browser) {
// Search in `HKEY_LOCAL_MACHINE` (If Brave installed for multi-user)
if (_webui_get_windows_reg_value(
HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\brave.exe", L"",
browser_fullpath
HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows\\CurrentVer"
L"sion\\App Paths\\brave.exe",
L"", browser_fullpath
)) {
// Make sure the browser executable file exist
@ -4228,8 +4330,10 @@ static bool _webui_browser_exist(_webui_window_t* win, size_t browser) {
// Search in `HKEY_CURRENT_USER` (If Brave installed for one user)
if (_webui_get_windows_reg_value(
HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\brave.exe", L"",
browser_fullpath
HKEY_CURRENT_USER,
L"Software\\Microsoft\\Windows\\CurrentVer"
L"sion\\App Paths\\brave.exe",
L"", browser_fullpath
)) {
// Make sure the browser executable file exist
@ -4281,7 +4385,9 @@ static bool _webui_browser_exist(_webui_window_t* win, size_t browser) {
// Search in `HKEY_LOCAL_MACHINE` (If Firefox installed for multi-user)
if (_webui_get_windows_reg_value(
HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\firefox.exe",
HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows\\CurrentVer"
L"sion\\App Paths\\firefox.exe",
L"", browser_fullpath
)) {
@ -4297,8 +4403,10 @@ static bool _webui_browser_exist(_webui_window_t* win, size_t browser) {
// Search in `HKEY_CURRENT_USER` (If Firefox installed for one user)
if (_webui_get_windows_reg_value(
HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\firefox.exe", L"",
browser_fullpath
HKEY_CURRENT_USER,
L"Software\\Microsoft\\Windows\\CurrentVer"
L"sion\\App Paths\\firefox.exe",
L"", browser_fullpath
)) {
// Make sure the browser executable file exist
@ -4353,8 +4461,10 @@ static bool _webui_browser_exist(_webui_window_t* win, size_t browser) {
// Search in `HKEY_CURRENT_USER` (If Yandex installed for one user)
if (_webui_get_windows_reg_value(
HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\browser.exe", L"",
browser_fullpath
HKEY_CURRENT_USER,
L"Software\\Microsoft\\Windows\\CurrentVer"
L"sion\\App Paths\\browser.exe",
L"", browser_fullpath
)) {
// Make sure the browser executable file exist
@ -4369,7 +4479,9 @@ static bool _webui_browser_exist(_webui_window_t* win, size_t browser) {
// Search in `HKEY_LOCAL_MACHINE` (If Yandex installed for multi-user)
if (_webui_get_windows_reg_value(
HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\browser.exe",
HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows\\CurrentVer"
L"sion\\App Paths\\browser.exe",
L"", browser_fullpath
)) {
@ -4422,7 +4534,9 @@ static bool _webui_browser_exist(_webui_window_t* win, size_t browser) {
// Search in `HKEY_CURRENT_USER` (If Chromium installed for one user)
if (_webui_get_windows_reg_value(
HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe",
HKEY_CURRENT_USER,
L"Software\\Microsoft\\Windows\\CurrentVer"
L"sion\\App Paths\\chrome.exe",
L"Path", browser_folder
)) {
@ -4438,7 +4552,9 @@ static bool _webui_browser_exist(_webui_window_t* win, size_t browser) {
// Search in `HKEY_LOCAL_MACHINE` (If Chromium installed for multi-user)
if (_webui_get_windows_reg_value(
HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe",
HKEY_LOCAL_MACHINE,
L"Software\\Microsoft\\Windows\\CurrentVer"
L"sion\\App Paths\\chrome.exe",
L"Path", browser_folder
)) {
@ -4964,7 +5080,8 @@ static bool _webui_browser_start(_webui_window_t* win, const char* address, size
// #5 - Brave - Shows a policy notification in the first run
// #6 - Firefox - Does not support App-Mode like Chrome (Looks not great)
// #7 - Yandex - Shows a big welcome window in the first run
// #8 - Chromium - Some Anti-Malware shows a false alert when using ungoogled-chromium-binaries
// #8 - Chromium - Some Anti-Malware shows a false alert when using
// ungoogled-chromium-binaries
if (browser != AnyBrowser) {
@ -5172,7 +5289,8 @@ static size_t _webui_find_the_best_browser(_webui_window_t* win) {
// #5 - Brave - Shows a policy notification in the first run
// #6 - Firefox - Does not support App-Mode like Chrome (Looks not great)
// #7 - Yandex - Shows a big welcome window in the first run
// #8 - Chromium - Some Anti-Malware shows a false alert when using ungoogled-chromium-binaries
// #8 - Chromium - Some Anti-Malware shows a false alert when using
// ungoogled-chromium-binaries
// To save memory, let's search if a web browser is already running
@ -5303,7 +5421,8 @@ static int _webui_tls_initialization(void* ssl_ctx, void* ptr) {
}
if (SSL_CTX_use_certificate(ctx, cert) <= 0) {
#ifdef WEBUI_LOG
printf("[Core]\t\t_webui_tls_initialization() -> SSL_CTX_use_certificate failed\n");
printf("[Core]\t\t_webui_tls_initialization() -> SSL_CTX_use_certificate "
"failed\n");
#endif
_webui_panic();
return -1;
@ -5316,14 +5435,16 @@ static int _webui_tls_initialization(void* ssl_ctx, void* ptr) {
EVP_PKEY* private_key = PEM_read_bio_PrivateKey(bio_key, NULL, 0, NULL);
if (private_key == NULL) {
#ifdef WEBUI_LOG
printf("[Core]\t\t_webui_tls_initialization() -> PEM_read_bio_PrivateKey failed\n");
printf("[Core]\t\t_webui_tls_initialization() -> PEM_read_bio_PrivateKey "
"failed\n");
#endif
_webui_panic();
return -1;
}
if (SSL_CTX_use_PrivateKey(ctx, private_key) <= 0) {
#ifdef WEBUI_LOG
printf("[Core]\t\t_webui_tls_initialization() -> SSL_CTX_use_PrivateKey failed\n");
printf("[Core]\t\t_webui_tls_initialization() -> SSL_CTX_use_PrivateKey "
"failed\n");
#endif
_webui_panic();
return -1;
@ -5364,15 +5485,21 @@ static bool _webui_tls_generate_self_signed_cert(char* root_cert, char* root_key
X509_gmtime_adj(X509_get_notAfter(root_x509), (long)(WEBUI_SSL_EXPIRE));
X509_NAME* root_name = X509_get_subject_name(root_x509);
X509_NAME_add_entry_by_txt(root_name, "C", MBSTRING_ASC, "CA", -1, -1, 0); // Country
X509_NAME_add_entry_by_txt(root_name, "C", MBSTRING_ASC, "CA", -1, -1,
0); // Country
X509_NAME_add_entry_by_txt(root_name, "O", MBSTRING_ASC, "WebUI Root Authority", -1, -1, 0); // Organization
X509_NAME_add_entry_by_txt(root_name, "OU", MBSTRING_ASC, "WebUI", -1, -1, 0); // Organizational Unit
X509_NAME_add_entry_by_txt(root_name, "CN", MBSTRING_ASC, "localhost", -1, -1, 0); // Common Name
X509_NAME_add_entry_by_txt(root_name, "OU", MBSTRING_ASC, "WebUI", -1, -1,
0); // Organizational Unit
X509_NAME_add_entry_by_txt(root_name, "CN", MBSTRING_ASC, "localhost", -1, -1,
0); // Common Name
X509_NAME_add_entry_by_txt(
root_name, "subjectAltName", MBSTRING_ASC, "127.0.0.1", -1, -1, 0
); // Subject Alternative Name
X509_NAME_add_entry_by_txt(root_name, "ST", MBSTRING_ASC, "WebUI", -1, -1, 0); // State
X509_NAME_add_entry_by_txt(root_name, "L", MBSTRING_ASC, "WebUI", -1, -1, 0); // Locality
root_name, "subjectAltName", MBSTRING_ASC, "127.0.0.1", -1, -1,
0
); // Subject Alternative Name
X509_NAME_add_entry_by_txt(root_name, "ST", MBSTRING_ASC, "WebUI", -1, -1,
0); // State
X509_NAME_add_entry_by_txt(root_name, "L", MBSTRING_ASC, "WebUI", -1, -1,
0); // Locality
X509_set_issuer_name(root_x509, root_name);
X509_set_pubkey(root_x509, root_pkey);
@ -5420,15 +5547,21 @@ static bool _webui_tls_generate_self_signed_cert(char* root_cert, char* root_key
X509_gmtime_adj(X509_get_notAfter(x509), (long)(WEBUI_SSL_EXPIRE));
X509_NAME* name = X509_get_subject_name(x509);
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, "CA", -1, -1, 0); // Country
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, "WebUI", -1, -1, 0); // Organization
X509_NAME_add_entry_by_txt(name, "OU", MBSTRING_ASC, "WebUI", -1, -1, 0); // Organizational Unit
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, "localhost", -1, -1, 0); // Common Name
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, "CA", -1, -1,
0); // Country
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, "WebUI", -1, -1,
0); // Organization
X509_NAME_add_entry_by_txt(name, "OU", MBSTRING_ASC, "WebUI", -1, -1,
0); // Organizational Unit
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, "localhost", -1, -1,
0); // Common Name
X509_NAME_add_entry_by_txt(
name, "subjectAltName", MBSTRING_ASC, "127.0.0.1", -1, -1, 0
); // Subject Alternative Name
X509_NAME_add_entry_by_txt(name, "ST", MBSTRING_ASC, "WebUI", -1, -1, 0); // State
X509_NAME_add_entry_by_txt(name, "L", MBSTRING_ASC, "WebUI", -1, -1, 0); // Locality
); // Subject Alternative Name
X509_NAME_add_entry_by_txt(name, "ST", MBSTRING_ASC, "WebUI", -1, -1,
0); // State
X509_NAME_add_entry_by_txt(name, "L", MBSTRING_ASC, "WebUI", -1, -1,
0); // Locality
X509_set_issuer_name(x509, root_name);
X509_set_pubkey(x509, pkey);
@ -5480,7 +5613,8 @@ static bool _webui_show_window(_webui_window_t* win, const char* content, bool i
if (_webui_is_empty(_webui_core.ssl_cert) || _webui_is_empty(_webui_core.ssl_key)) {
#ifdef WEBUI_LOG
printf("[Core]\t\t_webui_show_window() -> Generating self-signed TLS certificate...\n");
printf("[Core]\t\t_webui_show_window() -> Generating self-signed TLS "
"certificate...\n");
#endif
// Generate SSL self-signed certificate
@ -5494,7 +5628,8 @@ static bool _webui_show_window(_webui_window_t* win, const char* content, bool i
char err_buf[1024];
ERR_error_string_n(err, err_buf, sizeof(err_buf));
printf(
"[Core]\t\t_webui_show_window() -> Generating self-signed TLS certificate failed:\n%s\n",
"[Core]\t\t_webui_show_window() -> Generating self-signed TLS "
"certificate failed:\n%s\n",
err_buf
);
#endif
@ -5512,7 +5647,8 @@ static bool _webui_show_window(_webui_window_t* win, const char* content, bool i
_webui_core.ssl_key = ssl_key;
#ifdef WEBUI_LOG
printf("[Core]\t\t_webui_show_window() -> Self-signed SSL/TLS Certificate:\nRoot:\n");
printf("[Core]\t\t_webui_show_window() -> Self-signed SSL/TLS "
"Certificate:\nRoot:\n");
printf("%s\n", (const char*)_webui_core.root_cert);
printf("%s\nServer:\n", (const char*)_webui_core.root_key);
printf("%s\n", (const char*)_webui_core.ssl_cert);
@ -5642,7 +5778,8 @@ static void _webui_window_event(
// Call user all-events cb
#ifdef WEBUI_LOG
printf("[Core]\t\t_webui_window_event() -> Calling all-events user callback...\n[Call]\n");
printf("[Core]\t\t_webui_window_event() -> Calling all-events user "
"callback...\n[Call]\n");
#endif
e.bind_id = events_cb_index;
_webui_core.cb[events_cb_index](&e);
@ -5659,7 +5796,8 @@ static void _webui_window_event(
// Call user cb
#ifdef WEBUI_LOG
printf("[Core]\t\t_webui_window_event() -> Calling user callback...\n[Call]\n");
printf("[Core]\t\t_webui_window_event() -> Calling user "
"callback...\n[Call]\n");
#endif
e.bind_id = cb_index;
_webui_core.cb[cb_index](&e);
@ -5968,7 +6106,8 @@ static int _webui_http_log(const struct mg_connection* conn, const char* message
#endif
/*
static char* _webui_inject_bridge(_webui_window_t* win, const char *user_html) {
static char* _webui_inject_bridge(_webui_window_t* win, const char
*user_html) {
#ifdef WEBUI_LOG
printf("[Core]\t\t_webui_inject_bridge()...\n");
@ -6000,8 +6139,8 @@ static int _webui_http_log(const struct mg_connection* conn, const char* message
size_t len = _webui_strlen(user_html) + 128;
char* buffer = (char*) _webui_malloc(len);
sprintf(buffer,
"<html> <script type=\"application/javascript\" src=\"webui.js\"></script>\n %s",
user_html
"<html> <script type=\"application/javascript\"
src=\"webui.js\"></script>\n %s", user_html
);
return buffer;
}
@ -6015,8 +6154,9 @@ static int _webui_http_log(const struct mg_connection* conn, const char* message
int offset = (int)(head_pos - user_html) + 6;
// Calculate the length for the new string
const char* script = "<script type=\"application/javascript\" src=\"webui.js\"></script> \n";
size_t new_len = strlen(user_html) + strlen(script) + 1;
const char* script = "<script type=\"application/javascript\"
src=\"webui.js\"></script> \n"; size_t new_len = strlen(user_html) +
strlen(script) + 1;
// Allocate memory for the new string
char* buffer = (char*) _webui_malloc(new_len);
@ -6024,7 +6164,8 @@ static int _webui_http_log(const struct mg_connection* conn, const char* message
// Construct the new HTML with script injected
strncpy(buffer, user_html, offset); // Copy up to and including <head>
strcpy(buffer + offset, script); // Copy the script
strcpy(buffer + offset + strlen(script), user_html + offset); // Copy the rest of the user HTML
strcpy(buffer + offset + strlen(script), user_html + offset); // Copy
the rest of the user HTML
return buffer;
}
@ -6103,7 +6244,8 @@ static int _webui_http_handler(struct mg_connection* conn, void* _win) {
// Forbidden 403
#ifdef WEBUI_LOG
printf("[Core]\t\t_webui_http_handler() -> Embedded Index HTML Already Handled "
printf("[Core]\t\t_webui_http_handler() -> Embedded Index HTML "
"Already Handled "
"(403)\n");
#endif
@ -6136,7 +6278,8 @@ static int _webui_http_handler(struct mg_connection* conn, void* _win) {
// Forbidden 403
#ifdef WEBUI_LOG
printf("[Core]\t\t_webui_http_handler() -> Index local file Already Handled "
printf("[Core]\t\t_webui_http_handler() -> Index local file Already "
"Handled "
"(403)\n");
#endif
@ -6240,8 +6383,8 @@ static int _webui_http_handler(struct mg_connection* conn, void* _win) {
// // Forbidden 403
// #ifdef WEBUI_LOG
// printf("[Core]\t\t_webui_http_handler() -> Local file .HTML Already Handled
// (403)\n");
// printf("[Core]\t\t_webui_http_handler() -> Local file .HTML
// Already Handled (403)\n");
// #endif
// _webui_http_send_error_page(
@ -6261,7 +6404,8 @@ static int _webui_http_handler(struct mg_connection* conn, void* _win) {
#ifdef WEBUI_LOG
printf(
"[Core]\t\t_webui_http_handler() -> Trying to interpret local file (Runtime = "
"[Core]\t\t_webui_http_handler() -> Trying to interpret local "
"file (Runtime = "
"%zu)\n",
win->runtime
);
@ -6307,7 +6451,8 @@ static int _webui_ws_connect_handler(const struct mg_connection* conn, void* _wi
// Non-authorized connection
#ifdef WEBUI_LOG
printf("[Core]\t\t_webui_ws_connect_handler() -> Non-authorized connection.\n");
printf("[Core]\t\t_webui_ws_connect_handler() -> Non-authorized "
"connection.\n");
#endif
// Block handshake
@ -6453,8 +6598,7 @@ static WEBUI_THREAD_SERVER_START {
WEBUI_SSL_EXPIRE_STR,
#endif
NULL,
NULL
};
NULL};
struct mg_callbacks http_callbacks;
struct mg_context* http_ctx;
memset(&http_callbacks, 0, sizeof(http_callbacks));
@ -6497,8 +6641,7 @@ static WEBUI_THREAD_SERVER_START {
WEBUI_SSL_EXPIRE_STR,
#endif
NULL,
NULL
};
NULL};
ws_mg_start_init_data.configuration_options = ws_server_options;
struct mg_error_data ws_mg_start_error_data = {0};
char ws_errtxtbuf[256] = {0};
@ -6763,7 +6906,8 @@ static void _webui_receive(_webui_window_t* win, int event_type, void* data, siz
// Received more data than expected
#ifdef WEBUI_LOG
printf(
"[Core]\t\t_webui_receive()... > Multi packet received more data than expected (%zu + %zu "
"[Core]\t\t_webui_receive()... > Multi packet received more data "
"than expected (%zu + %zu "
"> %zu).\n",
multi_receive, len, multi_expect
);
@ -6790,7 +6934,8 @@ static void _webui_receive(_webui_window_t* win, int event_type, void* data, siz
if (expect_len > 0 && expect_len <= WEBUI_MAX_BUF) {
#ifdef WEBUI_LOG
printf(
"[Core]\t\t_webui_receive()... > Multi packet started, Expecting %zu bytes...\n",
"[Core]\t\t_webui_receive()... > Multi packet started, "
"Expecting %zu bytes...\n",
expect_len
);
#endif
@ -6874,24 +7019,36 @@ static WEBUI_THREAD_RECEIVE {
uint16_t packet_id = _webui_get_id(packet);
#ifdef WEBUI_LOG
printf("[Core]\t\t[Thread %zu] _webui_receive_thread() -> Data received...\n", recvNum);
printf(
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Packet Size : %zu bytes\n", recvNum,
packet_len
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Data "
"received...\n",
recvNum
);
printf(
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Packet Size : "
"%zu bytes\n",
recvNum, packet_len
);
printf(
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Packet Header "
": [ ",
recvNum
);
printf("[Core]\t\t[Thread %zu] _webui_receive_thread() -> Packet Header : [ ", recvNum);
_webui_print_hex(packet, WEBUI_PROTOCOL_SIZE);
printf("]\n");
printf(
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Packet Token: 0x%08X (%" PRIu32 ")\n",
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Packet Token: "
"0x%08X (%" PRIu32 ")\n",
recvNum, packet_token, packet_token
);
printf(
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Packet ID: 0x%04X (%u)\n", recvNum,
packet_id, packet_id
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Packet ID: "
"0x%04X (%u)\n",
recvNum, packet_id, packet_id
);
printf("[Core]\t\t[Thread %zu] _webui_receive_thread() -> Packet Data: [", recvNum);
//_webui_print_ascii(&packet[WEBUI_PROTOCOL_DATA], (packet_len - WEBUI_PROTOCOL_SIZE));
//_webui_print_ascii(&packet[WEBUI_PROTOCOL_DATA], (packet_len -
// WEBUI_PROTOCOL_SIZE));
printf("]\n");
#endif
@ -6920,17 +7077,20 @@ static WEBUI_THREAD_RECEIVE {
#ifdef WEBUI_LOG
printf(
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> WEBUI_CMD_CLICK "
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> "
"WEBUI_CMD_CLICK "
"\n",
recvNum
);
printf(
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Element size: "
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Element "
"size: "
"%zu bytes \n",
recvNum, element_len
);
printf(
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Element : [%s] "
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Element "
": [%s] "
"\n",
recvNum, element
);
@ -7120,12 +7280,14 @@ static WEBUI_THREAD_RECEIVE {
recvNum
);
printf(
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Call ID: [%u] "
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Call ID: "
"[%u] "
"\n",
recvNum, packet_id
);
printf(
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Element: [%s] "
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Element: "
"[%s] "
"\n",
recvNum, element
);
@ -7272,7 +7434,8 @@ static WEBUI_THREAD_RECEIVE {
#ifdef WEBUI_LOG
else {
printf(
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Unknown command "
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Unknown "
"command "
"[0x%02x]\n",
recvNum, (unsigned char)packet[WEBUI_PROTOCOL_CMD]
);
@ -7282,7 +7445,8 @@ static WEBUI_THREAD_RECEIVE {
#ifdef WEBUI_LOG
else {
printf(
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Window disconnected.\n",
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Window "
"disconnected.\n",
recvNum
);
}
@ -7294,7 +7458,11 @@ static WEBUI_THREAD_RECEIVE {
} else {
#ifdef WEBUI_LOG
printf("[Core]\t\t[Thread %zu] _webui_receive_thread() -> Invalid Packet.\n", recvNum);
printf(
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> Invalid "
"Packet.\n",
recvNum
);
#endif
// Forced close
@ -7312,7 +7480,11 @@ static WEBUI_THREAD_RECEIVE {
win->mg_connection = conn; // send
#ifdef WEBUI_LOG
printf("[Core]\t\t[Thread %zu] _webui_receive_thread() -> WebSocket connected\n", recvNum);
printf(
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> WebSocket "
"connected\n",
recvNum
);
#endif
// New Event
@ -7353,7 +7525,11 @@ static WEBUI_THREAD_RECEIVE {
win->bridge_handled = false;
#ifdef WEBUI_LOG
printf("[Core]\t\t[Thread %zu] _webui_receive_thread() -> WebSocket Closed\n", recvNum);
printf(
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> WebSocket "
"Closed\n",
recvNum
);
#endif
// Events
@ -7389,8 +7565,9 @@ static WEBUI_THREAD_RECEIVE {
#ifdef WEBUI_LOG
else {
printf(
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> UNKNOWN EVENT TYPE (%zu)\n", recvNum,
event_type
"[Core]\t\t[Thread %zu] _webui_receive_thread() -> UNKNOWN EVENT "
"TYPE (%zu)\n",
recvNum, event_type
);
}
#endif
@ -7599,7 +7776,8 @@ static int _webui_system_win32_out(const char* cmd, char** output, bool show) {
}
/*
static BOOL CALLBACK _webui_enum_windows_proc_win32(HWND hwnd, LPARAM targetProcessId) {
static BOOL CALLBACK _webui_enum_windows_proc_win32(HWND hwnd, LPARAM
targetProcessId) {
#ifdef WEBUI_LOG
printf("[Core]\t\t_webui_enum_windows_proc_win32()...\n");
@ -7611,8 +7789,8 @@ static BOOL CALLBACK _webui_enum_windows_proc_win32(HWND hwnd, LPARAM targetProc
if (windowProcessId == targetProcessId) {
#ifdef WEBUI_LOG
printf("[Core]\t\t_webui_enum_windows_proc_win32() -> Bring the process (%lu) to the front\n",
windowProcessId); #endif
printf("[Core]\t\t_webui_enum_windows_proc_win32() -> Bring the
process (%lu) to the front\n", windowProcessId); #endif
SetFocus(hwnd);
SetForegroundWindow(hwnd);
@ -7647,9 +7825,10 @@ static int _webui_system_win32(_webui_window_t* win, char* cmd, bool show) {
// webui.js will try to close the window.
HANDLE JobObject = CreateJobObject(NULL, NULL);
JOB_OBJECT_EXTENDED_LIMIT_INFORMATION ExtendedInfo = { 0 };
ExtendedInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION |
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; SetInformationJobObject(JobObject, JobObjectExtendedLimitInformation,
&ExtendedInfo, sizeof(ExtendedInfo));
ExtendedInfo.BasicLimitInformation.LimitFlags =
JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION |
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; SetInformationJobObject(JobObject,
JobObjectExtendedLimitInformation, &ExtendedInfo, sizeof(ExtendedInfo));
*/
DWORD Return = 0;