+
+
+
+
+
+
diff --git a/testApp/resources/js/main.js b/testApp/resources/js/main.js
new file mode 100644
index 00000000..09c297fc
--- /dev/null
+++ b/testApp/resources/js/main.js
@@ -0,0 +1,99 @@
+// This is just a sample app. You can structure your Neutralinojs app code as you wish.
+// This example app is written with vanilla JavaScript and HTML.
+// Feel free to use any frontend framework you like :)
+// See more details: https://neutralino.js.org/docs/how-to/use-a-frontend-library
+
+/*
+ Function to display information about the Neutralino app.
+ This function updates the content of the 'info' element in the HTML
+ with details regarding the running Neutralino application, including
+ its ID, port, operating system, and version information.
+*/
+function showInfo() {
+ document.getElementById('info').innerHTML = `
+ ${NL_APPID} is running on port ${NL_PORT} inside ${NL_OS}
+
+ server: v${NL_VERSION} . client: v${NL_CVERSION}
+ `;
+}
+
+/*
+ Function to open the official Neutralino documentation in the default web browser.
+*/
+function openDocs() {
+ Neutralino.os.open("https://neutralino.js.org/docs");
+}
+
+/*
+ Function to open a tutorial video on Neutralino's official YouTube channel in the default web browser.
+*/
+function openTutorial() {
+ Neutralino.os.open("https://www.youtube.com/c/CodeZri");
+}
+
+/*
+ Function to set up a system tray menu with options specific to the window mode.
+ This function checks if the application is running in window mode, and if so,
+ it defines the tray menu items and sets up the tray accordingly.
+*/
+function setTray() {
+ // Tray menu is only available in window mode
+ if(NL_MODE != "window") {
+ console.log("INFO: Tray menu is only available in the window mode.");
+ return;
+ }
+
+ // Define tray menu items
+ let tray = {
+ icon: "/resources/icons/trayIcon.png",
+ menuItems: [
+ {id: "VERSION", text: "Get version"},
+ {id: "SEP", text: "-"},
+ {id: "QUIT", text: "Quit"}
+ ]
+ };
+
+ // Set the tray menu
+ Neutralino.os.setTray(tray);
+}
+
+/*
+ Function to handle click events on the tray menu items.
+ This function performs different actions based on the clicked item's ID,
+ such as displaying version information or exiting the application.
+*/
+function onTrayMenuItemClicked(event) {
+ switch(event.detail.id) {
+ case "VERSION":
+ // Display version information
+ Neutralino.os.showMessageBox("Version information",
+ `Neutralinojs server: v${NL_VERSION} | Neutralinojs client: v${NL_CVERSION}`);
+ break;
+ case "QUIT":
+ // Exit the application
+ Neutralino.app.exit();
+ break;
+ }
+}
+
+/*
+ Function to handle the window close event by gracefully exiting the Neutralino application.
+*/
+function onWindowClose() {
+ Neutralino.app.exit();
+}
+
+// Initialize Neutralino
+Neutralino.init();
+
+// Register event listeners
+Neutralino.events.on("trayMenuItemClicked", onTrayMenuItemClicked);
+Neutralino.events.on("windowClose", onWindowClose);
+
+// Conditional initialization: Set up system tray if not running on macOS
+if(NL_OS != "Darwin") { // TODO: Fix https://github.com/neutralinojs/neutralinojs/issues/615
+ setTray();
+}
+
+// Display app information
+showInfo();
diff --git a/testApp/resources/js/neutralino.d.ts b/testApp/resources/js/neutralino.d.ts
new file mode 100644
index 00000000..09d69e64
--- /dev/null
+++ b/testApp/resources/js/neutralino.d.ts
@@ -0,0 +1,531 @@
+export declare enum LoggerType {
+ WARNING = "WARNING",
+ ERROR = "ERROR",
+ INFO = "INFO"
+}
+export declare enum Icon {
+ WARNING = "WARNING",
+ ERROR = "ERROR",
+ INFO = "INFO",
+ QUESTION = "QUESTION"
+}
+export declare enum MessageBoxChoice {
+ OK = "OK",
+ OK_CANCEL = "OK_CANCEL",
+ YES_NO = "YES_NO",
+ YES_NO_CANCEL = "YES_NO_CANCEL",
+ RETRY_CANCEL = "RETRY_CANCEL",
+ ABORT_RETRY_IGNORE = "ABORT_RETRY_IGNORE"
+}
+export declare enum ClipboardFormat {
+ unknown = "unknown",
+ text = "text",
+ image = "image"
+}
+export declare enum Mode {
+ window = "window",
+ browser = "browser",
+ cloud = "cloud",
+ chrome = "chrome"
+}
+export declare enum OperatingSystem {
+ Linux = "Linux",
+ Windows = "Windows",
+ Darwin = "Darwin",
+ FreeBSD = "FreeBSD",
+ Unknown = "Unknown"
+}
+export declare enum Architecture {
+ x64 = "x64",
+ arm = "arm",
+ itanium = "itanium",
+ ia32 = "ia32",
+ unknown = "unknown"
+}
+export interface DirectoryEntry {
+ entry: string;
+ path: string;
+ type: string;
+}
+export interface FileReaderOptions {
+ pos: number;
+ size: number;
+}
+export interface DirectoryReaderOptions {
+ recursive: boolean;
+}
+export interface OpenedFile {
+ id: number;
+ eof: boolean;
+ pos: number;
+ lastRead: number;
+}
+export interface Stats {
+ size: number;
+ isFile: boolean;
+ isDirectory: boolean;
+ createdAt: number;
+ modifiedAt: number;
+}
+export interface Watcher {
+ id: number;
+ path: string;
+}
+export interface CopyOptions {
+ recursive: boolean;
+ overwrite: boolean;
+ skip: boolean;
+}
+export interface PathParts {
+ rootName: string;
+ rootDirectory: string;
+ rootPath: string;
+ relativePath: string;
+ parentPath: string;
+ filename: string;
+ stem: string;
+ extension: string;
+}
+interface Permissions$1 {
+ all: boolean;
+ ownerAll: boolean;
+ ownerRead: boolean;
+ ownerWrite: boolean;
+ ownerExec: boolean;
+ groupAll: boolean;
+ groupRead: boolean;
+ groupWrite: boolean;
+ groupExec: boolean;
+ othersAll: boolean;
+ othersRead: boolean;
+ othersWrite: boolean;
+ othersExec: boolean;
+}
+export type PermissionsMode = "ADD" | "REPLACE" | "REMOVE";
+declare function createDirectory(path: string): Promise;
+declare function remove(path: string): Promise;
+declare function writeFile(path: string, data: string): Promise;
+declare function appendFile(path: string, data: string): Promise;
+declare function writeBinaryFile(path: string, data: ArrayBuffer): Promise;
+declare function appendBinaryFile(path: string, data: ArrayBuffer): Promise;
+declare function readFile(path: string, options?: FileReaderOptions): Promise;
+declare function readBinaryFile(path: string, options?: FileReaderOptions): Promise;
+declare function openFile(path: string): Promise;
+declare function createWatcher(path: string): Promise;
+declare function removeWatcher(id: number): Promise;
+declare function getWatchers(): Promise;
+declare function updateOpenedFile(id: number, event: string, data?: any): Promise;
+declare function getOpenedFileInfo(id: number): Promise;
+declare function readDirectory(path: string, options?: DirectoryReaderOptions): Promise;
+declare function copy(source: string, destination: string, options?: CopyOptions): Promise;
+declare function move(source: string, destination: string): Promise;
+declare function getStats(path: string): Promise;
+declare function getAbsolutePath(path: string): Promise;
+declare function getRelativePath(path: string, base?: string): Promise;
+declare function getPathParts(path: string): Promise;
+declare function getPermissions(path: string): Promise;
+declare function setPermissions(path: string, permissions: Permissions$1, mode: PermissionsMode): Promise;
+declare function getJoinedPath(...paths: string[]): Promise;
+declare function getNormalizedPath(path: string): Promise;
+declare function getUnnormalizedPath(path: string): Promise;
+export interface ExecCommandOptions {
+ stdIn?: string;
+ background?: boolean;
+ cwd?: string;
+}
+export interface ExecCommandResult {
+ pid: number;
+ stdOut: string;
+ stdErr: string;
+ exitCode: number;
+}
+export interface SpawnedProcess {
+ id: number;
+ pid: number;
+}
+export interface SpawnedProcessOptions {
+ cwd?: string;
+ envs?: Record;
+}
+export interface Envs {
+ [key: string]: string;
+}
+export interface OpenDialogOptions {
+ multiSelections?: boolean;
+ filters?: Filter[];
+ defaultPath?: string;
+}
+export interface FolderDialogOptions {
+ defaultPath?: string;
+}
+export interface SaveDialogOptions {
+ forceOverwrite?: boolean;
+ filters?: Filter[];
+ defaultPath?: string;
+}
+export interface Filter {
+ name: string;
+ extensions: string[];
+}
+export interface TrayOptions {
+ icon: string;
+ menuItems: TrayMenuItem[];
+}
+export interface TrayMenuItem {
+ id?: string;
+ text: string;
+ isDisabled?: boolean;
+ isChecked?: boolean;
+}
+export type KnownPath = "config" | "data" | "cache" | "documents" | "pictures" | "music" | "video" | "downloads" | "savedGames1" | "savedGames2" | "temp";
+declare function execCommand(command: string, options?: ExecCommandOptions): Promise;
+declare function spawnProcess(command: string, options?: SpawnedProcessOptions): Promise;
+declare function updateSpawnedProcess(id: number, event: string, data?: any): Promise;
+declare function getSpawnedProcesses(): Promise;
+declare function getEnv(key: string): Promise;
+declare function getEnvs(): Promise;
+declare function showOpenDialog(title?: string, options?: OpenDialogOptions): Promise;
+declare function showFolderDialog(title?: string, options?: FolderDialogOptions): Promise;
+declare function showSaveDialog(title?: string, options?: SaveDialogOptions): Promise;
+declare function showNotification(title: string, content: string, icon?: Icon): Promise;
+declare function showMessageBox(title: string, content: string, choice?: MessageBoxChoice, icon?: Icon): Promise;
+declare function setTray(options: TrayOptions): Promise;
+declare function open$1(url: string): Promise;
+declare function getPath(name: KnownPath): Promise;
+export interface MemoryInfo {
+ physical: {
+ total: number;
+ available: number;
+ };
+ virtual: {
+ total: number;
+ available: number;
+ };
+}
+export interface KernelInfo {
+ variant: string;
+ version: string;
+}
+export interface OSInfo {
+ name: string;
+ description: string;
+ version: string;
+}
+export interface CPUInfo {
+ vendor: string;
+ model: string;
+ frequency: number;
+ architecture: string;
+ logicalThreads: number;
+ physicalCores: number;
+ physicalUnits: number;
+}
+export interface Display {
+ id: number;
+ resolution: Resolution;
+ dpi: number;
+ bpp: number;
+ refreshRate: number;
+}
+export interface Resolution {
+ width: number;
+ height: number;
+}
+export interface MousePosition {
+ x: number;
+ y: number;
+}
+declare function getMemoryInfo(): Promise;
+declare function getArch(): Promise;
+declare function getKernelInfo(): Promise;
+declare function getOSInfo(): Promise;
+declare function getCPUInfo(): Promise;
+declare function getDisplays(): Promise;
+declare function getMousePosition(): Promise;
+declare function setData(key: string, data: string | null): Promise;
+declare function getData(key: string): Promise;
+declare function removeData(key: string): Promise;
+declare function getKeys(): Promise;
+declare function clear(): Promise;
+declare function log(message: string, type?: LoggerType): Promise;
+export interface OpenActionOptions {
+ url: string;
+}
+export interface RestartOptions {
+ args: string;
+}
+declare function exit(code?: number): Promise;
+declare function killProcess(): Promise;
+declare function restartProcess(options?: RestartOptions): Promise;
+declare function getConfig(): Promise;
+declare function broadcast(event: string, data?: any): Promise;
+declare function readProcessInput(readAll?: boolean): Promise;
+declare function writeProcessOutput(data: string): Promise;
+declare function writeProcessError(data: string): Promise;
+export interface WindowOptions extends WindowSizeOptions, WindowPosOptions {
+ title?: string;
+ icon?: string;
+ fullScreen?: boolean;
+ alwaysOnTop?: boolean;
+ enableInspector?: boolean;
+ borderless?: boolean;
+ maximize?: boolean;
+ hidden?: boolean;
+ maximizable?: boolean;
+ useSavedState?: boolean;
+ exitProcessOnClose?: boolean;
+ extendUserAgentWith?: string;
+ injectGlobals?: boolean;
+ injectClientLibrary?: boolean;
+ injectScript?: string;
+ processArgs?: string;
+}
+export interface WindowSizeOptions {
+ width?: number;
+ height?: number;
+ minWidth?: number;
+ minHeight?: number;
+ maxWidth?: number;
+ maxHeight?: number;
+ resizable?: boolean;
+}
+export interface WindowPosOptions {
+ x?: number;
+ y?: number;
+ center?: boolean;
+}
+export interface WindowMenu extends Array {
+}
+export interface WindowMenuItem {
+ id?: string;
+ text: string;
+ action?: string;
+ shortcut?: string;
+ isDisabled?: boolean;
+ isChecked?: boolean;
+ menuItems?: WindowMenuItem[];
+}
+declare function setTitle(title: string): Promise;
+declare function getTitle(): Promise;
+declare function maximize(): Promise;
+declare function unmaximize(): Promise;
+declare function isMaximized(): Promise;
+declare function minimize(): Promise;
+declare function unminimize(): Promise;
+declare function isMinimized(): Promise;
+declare function setFullScreen(): Promise;
+declare function exitFullScreen(): Promise;
+declare function isFullScreen(): Promise;
+declare function show(): Promise;
+declare function hide(): Promise;
+declare function isVisible(): Promise;
+declare function focus$1(): Promise;
+declare function setIcon(icon: string): Promise;
+declare function move$1(x: number, y: number): Promise;
+declare function center(): Promise;
+declare function beginDrag(screenX?: number, screenY?: number): Promise;
+declare function setDraggableRegion(DOMElementOrId: string | HTMLElement, options?: {
+ exclude?: Array;
+}): Promise<{
+ success: true;
+ message: string;
+ exclusions: {
+ add(elements: Array): void;
+ remove(elements: Array): void;
+ removeAll(): void;
+ };
+}>;
+declare function unsetDraggableRegion(DOMElementOrId: string | HTMLElement): Promise<{
+ success: true;
+ message: string;
+}>;
+declare function setSize(options: WindowSizeOptions): Promise;
+declare function getSize(): Promise;
+declare function getPosition(): Promise;
+declare function setAlwaysOnTop(onTop: boolean): Promise;
+declare function setBorderless(borderless: boolean): Promise;
+declare function create(url: string, options?: WindowOptions): Promise;
+declare function snapshot(path: string): Promise;
+declare function setMainMenu(options: WindowMenu): Promise;
+declare function print$1(): Promise;
+interface Response$1 {
+ success: boolean;
+ message: string;
+}
+export type Builtin = "ready" | "trayMenuItemClicked" | "windowClose" | "serverOffline" | "clientConnect" | "clientDisconnect" | "appClientConnect" | "appClientDisconnect" | "extClientConnect" | "extClientDisconnect" | "extensionReady" | "neuDev_reloadApp";
+declare function on(event: string, handler: (ev: CustomEvent) => void): Promise;
+declare function off(event: string, handler: (ev: CustomEvent) => void): Promise;
+declare function dispatch(event: string, data?: any): Promise;
+declare function broadcast$1(event: string, data?: any): Promise;
+export interface ExtensionStats {
+ loaded: string[];
+ connected: string[];
+}
+declare function dispatch$1(extensionId: string, event: string, data?: any): Promise;
+declare function broadcast$2(event: string, data?: any): Promise;
+declare function getStats$1(): Promise;
+export interface Manifest {
+ applicationId: string;
+ version: string;
+ resourcesURL: string;
+}
+declare function checkForUpdates(url: string): Promise;
+declare function install(): Promise;
+export interface ClipboardImage {
+ width: number;
+ height: number;
+ bpp: number;
+ bpr: number;
+ redMask: number;
+ greenMask: number;
+ blueMask: number;
+ redShift: number;
+ greenShift: number;
+ blueShift: number;
+ data: ArrayBuffer;
+}
+declare function getFormat(): Promise;
+declare function readText(): Promise;
+declare function readImage(format?: string): Promise;
+declare function writeText(data: string): Promise;
+declare function writeImage(image: ClipboardImage): Promise;
+declare function readHTML(): Promise;
+declare function writeHTML(data: string): Promise;
+declare function clear$1(): Promise;
+interface Stats$1 {
+ size: number;
+ isFile: boolean;
+ isDirectory: boolean;
+}
+declare function getFiles(): Promise;
+declare function getStats$2(path: string): Promise;
+declare function extractFile(path: string, destination: string): Promise;
+declare function extractDirectory(path: string, destination: string): Promise;
+declare function readFile$1(path: string): Promise;
+declare function readBinaryFile$1(path: string): Promise;
+declare function mount(path: string, target: string): Promise;
+declare function unmount(path: string): Promise;
+declare function getMounts(): Promise>;
+declare function getMethods(): Promise;
+export interface InitOptions {
+ exportCustomMethods?: boolean;
+}
+export declare function init(options?: InitOptions): void;
+export type ErrorCode = "NE_FS_DIRCRER" | "NE_FS_RMDIRER" | "NE_FS_FILRDER" | "NE_FS_FILWRER" | "NE_FS_FILRMER" | "NE_FS_NOPATHE" | "NE_FS_COPYFER" | "NE_FS_MOVEFER" | "NE_OS_INVMSGA" | "NE_OS_INVKNPT" | "NE_ST_INVSTKY" | "NE_ST_STKEYWE" | "NE_RT_INVTOKN" | "NE_RT_NATPRME" | "NE_RT_APIPRME" | "NE_RT_NATRTER" | "NE_RT_NATNTIM" | "NE_CL_NSEROFF" | "NE_EX_EXTNOTC" | "NE_UP_CUPDMER" | "NE_UP_CUPDERR" | "NE_UP_UPDNOUF" | "NE_UP_UPDINER";
+interface Error$1 {
+ code: ErrorCode;
+ message: string;
+}
+declare global {
+ interface Window {
+ /** Mode of the application: window, browser, cloud, or chrome */
+ NL_MODE: Mode;
+ /** Application port */
+ NL_PORT: number;
+ /** Command-line arguments */
+ NL_ARGS: string[];
+ /** Basic authentication token */
+ NL_TOKEN: string;
+ /** Neutralinojs client version */
+ NL_CVERSION: string;
+ /** Application identifier */
+ NL_APPID: string;
+ /** Application version */
+ NL_APPVERSION: string;
+ /** Application path */
+ NL_PATH: string;
+ /** Application data path */
+ NL_DATAPATH: string;
+ /** Returns true if extensions are enabled */
+ NL_EXTENABLED: boolean;
+ /** Returns true if the client library is injected */
+ NL_GINJECTED: boolean;
+ /** Returns true if globals are injected */
+ NL_CINJECTED: boolean;
+ /** Operating system name: Linux, Windows, Darwin, FreeBSD, or Uknown */
+ NL_OS: OperatingSystem;
+ /** CPU architecture: x64, arm, itanium, ia32, or unknown */
+ NL_ARCH: Architecture;
+ /** Neutralinojs server version */
+ NL_VERSION: string;
+ /** Current working directory */
+ NL_CWD: string;
+ /** Identifier of the current process */
+ NL_PID: string;
+ /** Source of application resources: bundle or directory */
+ NL_RESMODE: string;
+ /** Release commit of the client library */
+ NL_CCOMMIT: string;
+ /** An array of custom methods */
+ NL_CMETHODS: string[];
+ }
+ /** Neutralino global object for custom methods **/
+ const Neutralino: any;
+}
+
+declare namespace custom {
+ export { getMethods };
+}
+declare namespace filesystem {
+ export { appendBinaryFile, appendFile, copy, createDirectory, createWatcher, getAbsolutePath, getJoinedPath, getNormalizedPath, getOpenedFileInfo, getPathParts, getPermissions, getRelativePath, getStats, getUnnormalizedPath, getWatchers, move, openFile, readBinaryFile, readDirectory, readFile, remove, removeWatcher, setPermissions, updateOpenedFile, writeBinaryFile, writeFile };
+}
+declare namespace os {
+ export { execCommand, getEnv, getEnvs, getPath, getSpawnedProcesses, open$1 as open, setTray, showFolderDialog, showMessageBox, showNotification, showOpenDialog, showSaveDialog, spawnProcess, updateSpawnedProcess };
+}
+declare namespace computer {
+ export { getArch, getCPUInfo, getDisplays, getKernelInfo, getMemoryInfo, getMousePosition, getOSInfo };
+}
+declare namespace storage {
+ export { clear, getData, getKeys, removeData, setData };
+}
+declare namespace debug {
+ export { log };
+}
+declare namespace app {
+ export { broadcast, exit, getConfig, killProcess, readProcessInput, restartProcess, writeProcessError, writeProcessOutput };
+}
+declare namespace window$1 {
+ export { beginDrag, center, create, exitFullScreen, focus$1 as focus, getPosition, getSize, getTitle, hide, isFullScreen, isMaximized, isMinimized, isVisible, maximize, minimize, move$1 as move, print$1 as print, setAlwaysOnTop, setBorderless, setDraggableRegion, setFullScreen, setIcon, setMainMenu, setSize, setTitle, show, snapshot, unmaximize, unminimize, unsetDraggableRegion };
+}
+declare namespace events {
+ export { broadcast$1 as broadcast, dispatch, off, on };
+}
+declare namespace extensions {
+ export { broadcast$2 as broadcast, dispatch$1 as dispatch, getStats$1 as getStats };
+}
+declare namespace updater {
+ export { checkForUpdates, install };
+}
+declare namespace clipboard {
+ export { clear$1 as clear, getFormat, readHTML, readImage, readText, writeHTML, writeImage, writeText };
+}
+declare namespace resources {
+ export { extractDirectory, extractFile, getFiles, getStats$2 as getStats, readBinaryFile$1 as readBinaryFile, readFile$1 as readFile };
+}
+declare namespace server {
+ export { getMounts, mount, unmount };
+}
+
+export {
+ Error$1 as Error,
+ Permissions$1 as Permissions,
+ Response$1 as Response,
+ app,
+ clipboard,
+ computer,
+ custom,
+ debug,
+ events,
+ extensions,
+ filesystem,
+ os,
+ resources,
+ server,
+ storage,
+ updater,
+ window$1 as window,
+};
+
+export as namespace Neutralino;
+
+export {};
diff --git a/testApp/resources/styles.css b/testApp/resources/styles.css
new file mode 100644
index 00000000..5b0e4b98
--- /dev/null
+++ b/testApp/resources/styles.css
@@ -0,0 +1,20 @@
+body {
+ background-color: white;
+}
+
+#neutralinoapp {
+ text-align: center;
+ -webkit-user-select: none;
+ user-select: none;
+ cursor: default;
+}
+
+#neutralinoapp h1{
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+ font-size: 20px;
+}
+
+#neutralinoapp > div {
+ font-size: 16px;
+ font-weight: normal;
+}