├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .vscode └── extensions.json ├── CMakeLists.txt ├── README.md ├── asserts └── moonbit-webview.png ├── lib ├── libwebview.0.12.0.dylib ├── libwebview.0.12.dylib ├── libwebview.dylib ├── webview.dll └── webview.lib ├── moon.mod.json ├── scripts ├── build.sh ├── env.bat └── env.sh └── src ├── binding.mbt ├── examples ├── 01_run │ ├── main.mbt │ └── moon.pkg.json ├── 02_local │ ├── main.mbt │ └── moon.pkg.json ├── 03_remote │ ├── main.mbt │ └── moon.pkg.json ├── 04_user_agent │ ├── main.mbt │ └── moon.pkg.json ├── 05_alert │ ├── main.mbt │ └── moon.pkg.json ├── 06_onload │ ├── main.mbt │ └── moon.pkg.json ├── 07_inject_js │ ├── main.mbt │ └── moon.pkg.json ├── 08_eval │ ├── main.mbt │ └── moon.pkg.json ├── 09_dispatch │ ├── main.mbt │ └── moon.pkg.json ├── 10_bind │ ├── main.mbt │ └── moon.pkg.json ├── 11_multi_window │ ├── main.mbt │ └── moon.pkg.json ├── 12_embed │ ├── hello.html │ ├── hello.mbt │ ├── main.mbt │ └── moon.pkg.json ├── 13_todo │ ├── Readme.md │ ├── bundle.html │ ├── bundle.mbt │ ├── main.mbt │ └── moon.pkg.json └── Readme.md ├── moon.pkg.json ├── stub.c ├── webview.mbt └── webview_test.mbt /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | stable: 7 | strategy: 8 | matrix: 9 | os: 10 | # - ubuntu-latest 11 | - macos-latest 12 | # - macos-13 13 | - windows-latest 14 | fail-fast: false 15 | runs-on: ${{ matrix.os }} 16 | continue-on-error: false 17 | steps: 18 | - uses: actions/checkout@v4 19 | 20 | - name: install 21 | if: ${{ matrix.os != 'windows-latest' }} 22 | run: | 23 | curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash 24 | echo "$HOME/.moon/bin" >> $GITHUB_PATH 25 | 26 | - name: install on windows 27 | if: ${{ matrix.os == 'windows-latest' }} 28 | run: | 29 | Set-ExecutionPolicy RemoteSigned -Scope CurrentUser; irm https://cli.moonbitlang.com/install/powershell.ps1 | iex 30 | "C:\Users\runneradmin\.moon\bin" | Out-File -FilePath $env:GITHUB_PATH -Append 31 | 32 | - name: moon version 33 | run: | 34 | moon version --all 35 | 36 | - name: moon install 37 | run: | 38 | moon update 39 | moon install 40 | 41 | - name: moon check 42 | run: moon check --target native --deny-warn 43 | 44 | - name: format diff 45 | run: | 46 | moon fmt --check 47 | 48 | - name: Setup MSVC 49 | if: ${{ matrix.os == 'windows-latest' }} 50 | uses: ilammy/msvc-dev-cmd@v1 51 | 52 | - name: Run moon test (windows) 53 | if: ${{ matrix.os == 'windows-latest' }} 54 | env: 55 | _CL_: /link /LIBPATH:lib webview.lib /DEBUG 56 | PATH: lib;${{ env.PATH }} 57 | run: | 58 | moon test --target native 59 | 60 | # - name: Run moon test (non-windows) 61 | # if: ${{ matrix.os != 'windows-latest' }} 62 | # env: 63 | # DYLD_LIBRARY_PATH: lib 64 | # run: | 65 | # moon test --target native 66 | 67 | - name: moon test --doc (windows) 68 | if: ${{ matrix.os == 'windows-latest' }} 69 | env: 70 | _CL_: /link /LIBPATH:lib webview.lib /DEBUG 71 | PATH: lib;${{ env.PATH }} 72 | run: | 73 | moon test --target native --doc 74 | 75 | # - name: moon test --doc (non-windows) 76 | # if: ${{ matrix.os != 'windows-latest' }} 77 | # env: 78 | # DYLD_LIBRARY_PATH: lib 79 | # run: | 80 | # moon test --target native --doc 81 | 82 | - name: moon build (windows) 83 | if: ${{ matrix.os == 'windows-latest' }} 84 | env: 85 | _CL_: /link /LIBPATH:lib webview.lib /DEBUG 86 | PATH: lib;${{ env.PATH }} 87 | run: | 88 | moon build --target native 89 | 90 | - name: moon build (non-windows) 91 | if: ${{ matrix.os != 'windows-latest' }} 92 | env: 93 | DYLD_LIBRARY_PATH: lib 94 | run: | 95 | moon build --target native 96 | 97 | - name: check exe size 98 | if: ${{ matrix.os != 'windows-latest' }} 99 | run: find ./target -name '*.exe' | xargs ls -lh 100 | 101 | - name: check core size on windows 102 | if: ${{ matrix.os == 'windows-latest' }} 103 | run: Get-ChildItem -Path ".\target" -Recurse -Filter "*.exe" | ForEach-Object { "{0} ({1} bytes)" -f $_.FullName, $_.Length } 104 | 105 | bleeding: 106 | strategy: 107 | matrix: 108 | os: 109 | # - ubuntu-latest 110 | - macos-latest 111 | # - macos-13 112 | - windows-latest 113 | continue-on-error: false 114 | runs-on: ${{ matrix.os }} 115 | steps: 116 | - uses: actions/checkout@v4 117 | 118 | - name: install 119 | if: ${{ matrix.os != 'windows-latest' }} 120 | run: | 121 | curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash -s bleeding 122 | echo "$HOME/.moon/bin" >> $GITHUB_PATH 123 | 124 | - name: install on windows 125 | if: ${{ matrix.os == 'windows-latest' }} 126 | env: 127 | MOONBIT_INSTALL_VERSION: bleeding 128 | run: | 129 | Set-ExecutionPolicy RemoteSigned -Scope CurrentUser; irm https://cli.moonbitlang.com/install/powershell.ps1 | iex 130 | "C:\Users\runneradmin\.moon\bin" | Out-File -FilePath $env:GITHUB_PATH -Append 131 | 132 | - name: moon version 133 | run: | 134 | moon version --all 135 | 136 | - name: moon install 137 | run: | 138 | moon update 139 | moon install 140 | 141 | - name: Setup MSVC 142 | if: ${{ matrix.os == 'windows-latest' }} 143 | uses: ilammy/msvc-dev-cmd@v1 144 | 145 | - name: Run moon test (windows) 146 | if: ${{ matrix.os == 'windows-latest' }} 147 | env: 148 | _CL_: /link /LIBPATH:lib webview.lib /DEBUG 149 | PATH: lib;${{ env.PATH }} 150 | run: | 151 | moon test --target native 152 | 153 | # - name: Run moon test (non-windows) 154 | # if: ${{ matrix.os != 'windows-latest' }} 155 | # env: 156 | # DYLD_LIBRARY_PATH: lib 157 | # run: | 158 | # moon test --target native 159 | 160 | - name: moon test --doc (windows) 161 | if: ${{ matrix.os == 'windows-latest' }} 162 | env: 163 | _CL_: /link /LIBPATH:lib webview.lib /DEBUG 164 | PATH: lib;${{ env.PATH }} 165 | run: | 166 | moon test --target native --doc 167 | 168 | # - name: moon test --doc (non-windows) 169 | # if: ${{ matrix.os != 'windows-latest' }} 170 | # env: 171 | # DYLD_LIBRARY_PATH: lib 172 | # run: | 173 | # moon test --target native --doc 174 | 175 | - name: moon check 176 | run: moon check --target native --deny-warn 177 | 178 | - name: format diff 179 | run: | 180 | moon fmt --check 181 | 182 | - name: moon build (windows) 183 | if: ${{ matrix.os == 'windows-latest' }} 184 | env: 185 | _CL_: /link /LIBPATH:lib webview.lib /DEBUG 186 | PATH: lib;${{ env.PATH }} 187 | run: | 188 | moon build --target native 189 | 190 | - name: moon build (non-windows) 191 | if: ${{ matrix.os != 'windows-latest' }} 192 | env: 193 | DYLD_LIBRARY_PATH: lib 194 | run: | 195 | moon build --target native 196 | 197 | - name: check exe size 198 | run: find ./target -name '*.exe' | xargs ls -lh 199 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | build/ 3 | .mooncakes/ 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "moonbit.moonbit-lang" 4 | ] 5 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | project(webview-builder LANGUAGES C CXX) 3 | 4 | if(NOT CMAKE_BUILD_TYPE) 5 | message(STATUS "No CMAKE_BUILD_TYPE specified, defaulting to Debug") 6 | set(CMAKE_BUILD_TYPE Debug CACHE STRING "Build type" FORCE) 7 | endif() 8 | 9 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin") 10 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib") 11 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib") 12 | 13 | include(FetchContent) 14 | 15 | set(WEBVIEW_BUILD_TESTS OFF CACHE BOOL "" FORCE) 16 | set(WEBVIEW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) 17 | set(WEBVIEW_USE_CLANG_TOOLS OFF CACHE BOOL "" FORCE) 18 | set(WEBVIEW_ENABLE_CHECKS OFF CACHE BOOL "" FORCE) 19 | set(WEBVIEW_USE_CLANG_TIDY OFF CACHE BOOL "" FORCE) 20 | set(WEBVIEW_BUILD_DOCS OFF CACHE BOOL "" FORCE) 21 | set(WEBVIEW_USE_CLANG_FORMAT OFF CACHE BOOL "" FORCE) 22 | set(WEBVIEW_BUILD_SHARED_LIBRARY ON CACHE BOOL "" FORCE) 23 | set(WEBVIEW_BUILD_STATIC_LIBRARY OFF CACHE BOOL "" FORCE) 24 | set(WEBVIEW_PACKAGE_HEADERS ON CACHE BOOL "" FORCE) 25 | set(WEBVIEW_INSTALL_TARGETS ON CACHE BOOL "" FORCE) 26 | 27 | FetchContent_Declare( 28 | webview 29 | GIT_REPOSITORY https://github.com/webview/webview 30 | GIT_TAG master) 31 | 32 | FetchContent_MakeAvailable(webview) 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # justjavac/webview 2 | 3 | MoonBit bindings for webview, a tiny library for creating web-based desktop 4 | GUIs. 5 | 6 | > ⚠️ This project is still in development. 7 | 8 | ![moonbit webview demo](asserts/moonbit-webview.png) 9 | 10 | ## Installation 11 | 12 | Add `justjavac/webview` to your dependencies: 13 | 14 | ```shell 15 | moon update 16 | moon add justjavac/webview 17 | ``` 18 | 19 | ## Config 20 | 21 | Config your `moon.pkg.json` file: 22 | 23 | ```json 24 | { 25 | "is-main": true, 26 | "link": { 27 | "native": { 28 | "cc-flags": "-fwrapv -fsanitize=address -fsanitize=undefined", 29 | "cc-link-flags": "-L .mooncakes/justjavac/webview/lib -lwebview" 30 | } 31 | } 32 | } 33 | ``` 34 | 35 | ## Setup Env 36 | 37 | On macOS, you need to tell the dynamic linker where to find your compiled `.dylib` files. From the project root, run: 38 | 39 | ```shell 40 | export DYLD_LIBRARY_PATH="$(pwd)/.mooncakes/justjavac/webview/lib" 41 | ``` 42 | 43 | On Windows, you need to set the `PATH` environment variable to include the directory where the `webview.dll` is located. 44 | 45 | ```bat 46 | set PATH=%PATH%;.mooncakes\justjavac\webview\lib 47 | ``` 48 | 49 | ## Usage 50 | 51 | ```moonbit 52 | let html = 53 | #| 54 | #| 55 | #| Hello, Moonbit! 56 | #| 57 | #| 58 | 59 | fn main { 60 | @webview.Webview::new(debug=1) 61 | ..set_title("Moonbit Webview Example") 62 | ..set_size(800, 600, @webview.SizeHint::None) 63 | ..set_html(html) 64 | ..run() 65 | } 66 | ``` 67 | 68 | ## Development 69 | 70 | Build and test: 71 | 72 | ```shell 73 | cmake -G Ninja -B build -S . -D CMAKE_BUILD_TYPE=Release 74 | cmake --build build 75 | scripts/env.sh # Or `scripts/env.bat` on Windows 76 | 77 | moon update 78 | moon install 79 | moon run --target native src/examples/02_local 80 | ``` 81 | 82 | ## License 83 | 84 | MIT © justjavac 85 | -------------------------------------------------------------------------------- /asserts/moonbit-webview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justjavac/moonbit-webview/a43a38d04efe66a27bc950b33dd6d0b32bf8fd8c/asserts/moonbit-webview.png -------------------------------------------------------------------------------- /lib/libwebview.0.12.0.dylib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justjavac/moonbit-webview/a43a38d04efe66a27bc950b33dd6d0b32bf8fd8c/lib/libwebview.0.12.0.dylib -------------------------------------------------------------------------------- /lib/libwebview.0.12.dylib: -------------------------------------------------------------------------------- 1 | libwebview.0.12.0.dylib -------------------------------------------------------------------------------- /lib/libwebview.dylib: -------------------------------------------------------------------------------- 1 | libwebview.0.12.dylib -------------------------------------------------------------------------------- /lib/webview.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justjavac/moonbit-webview/a43a38d04efe66a27bc950b33dd6d0b32bf8fd8c/lib/webview.dll -------------------------------------------------------------------------------- /lib/webview.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/justjavac/moonbit-webview/a43a38d04efe66a27bc950b33dd6d0b32bf8fd8c/lib/webview.lib -------------------------------------------------------------------------------- /moon.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "justjavac/webview", 3 | "version": "0.1.6", 4 | "deps": { 5 | "justjavac/ffi": "0.1.5" 6 | }, 7 | "readme": "README.md", 8 | "repository": "https://github.com/justjavac/moonbit-webview", 9 | "license": "MIT", 10 | "keywords": [ 11 | "webview", 12 | "webui", 13 | "gui", 14 | "web", 15 | "desktop-app" 16 | ], 17 | "description": "MoonBit bindings for webview, a tiny library for creating web-based desktop GUIs.", 18 | "source": "src", 19 | "warn-list": "" 20 | } -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | cmake -G Ninja -B build -S . -D CMAKE_BUILD_TYPE=Release 2 | cmake --build build 3 | -------------------------------------------------------------------------------- /scripts/env.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set _CL_=/link /LIBPATH:lib webview.lib /DEBUG 3 | set PATH=lib;%PATH% 4 | -------------------------------------------------------------------------------- /scripts/env.sh: -------------------------------------------------------------------------------- 1 | export DYLD_LIBRARY_PATH="$(pwd)/lib" 2 | -------------------------------------------------------------------------------- /src/binding.mbt: -------------------------------------------------------------------------------- 1 | /// This module provides the FFI (Foreign Function Interface) for the webview library. 2 | /// It allows the main application to call functions defined in the webview library. 3 | /// 4 | /// see: https://github.com/webview/webview/blob/f1a9d6b6fb8bcc2e266057224887a3d628f30f90/webview.i 5 | 6 | ///| typedef void *webview_t; 7 | pub extern type Webview_t 8 | 9 | ///| extern webview_t webview_create(int debug, void *window); 10 | pub extern "C" fn webview_create(debug : Int, window : Int64) -> Webview_t = "webview_create" 11 | 12 | ///| extern void webview_destroy(webview_t w); 13 | pub extern "C" fn webview_destroy(webview : Webview_t) -> Int = "webview_destroy" 14 | 15 | ///| extern void webview_run(webview_t w); 16 | pub extern "C" fn webview_run(webview : Webview_t) -> Int = "webview_run" 17 | 18 | ///| extern void webview_terminate(webview_t w); 19 | pub extern "C" fn webview_terminate(webview : Webview_t) -> Int = "webview_terminate" 20 | 21 | ///| extern void webview_dispatch(webview_t w, void (*fn)(webview_t w, void *arg), void *arg); 22 | pub extern "C" fn webview_dispatch( 23 | webview : Webview_t, 24 | call_closure : FuncRef[(Webview_t, (Webview_t) -> Unit) -> Unit], 25 | closure : () -> Unit 26 | ) -> Int = "webview_dispatch" 27 | 28 | ///| extern void *webview_get_window(webview_t w); 29 | pub extern "C" fn webview_get_window(webview : Webview_t) -> Int64 = "webview_get_window" 30 | 31 | ///| extern void *webview_get_native_handle(webview_t w, webview_native_handle_kind_t kind); 32 | pub extern "C" fn webview_get_native_handle( 33 | webview : Webview_t, 34 | kind : NativeHandleKind 35 | ) -> Int64 = "webview_get_native_handle" 36 | 37 | ///| extern void webview_set_title(webview_t w, const char *title); 38 | pub extern "C" fn webview_set_title(webview : Webview_t, title : Bytes) -> Int = "webview_set_title" 39 | 40 | ///| extern void webview_set_size(webview_t w, int width, int height, webview_hint_t hints); 41 | pub extern "C" fn webview_set_size( 42 | webview : Webview_t, 43 | width : Int, 44 | height : Int, 45 | hint : SizeHint 46 | ) -> Int = "webview_set_size" 47 | 48 | ///| extern void webview_navigate(webview_t w, const char *url); 49 | pub extern "C" fn webview_navigate(webview : Webview_t, html : Bytes) -> Int = "webview_navigate" 50 | 51 | ///| extern void webview_set_html(webview_t w, const char *html); 52 | pub extern "C" fn webview_set_html(webview : Webview_t, html : Bytes) -> Int = "webview_set_html" 53 | 54 | ///| extern void webview_init(webview_t w, const char *js); 55 | pub extern "C" fn webview_init(webview : Webview_t, js : Bytes) -> Int = "webview_init" 56 | 57 | ///| extern void webview_eval(webview_t w, const char *js); 58 | pub extern "C" fn webview_eval(webview : Webview_t, js : Bytes) -> Int = "webview_eval" 59 | 60 | ///| extern void webview_bind(webview_t w, const char *name, void (*fn)(const char *id, const char *req, void *arg), void *arg); 61 | pub extern "C" fn webview_bind( 62 | webview : Webview_t, 63 | name : Bytes, 64 | call_closure : FuncRef[(Bytes, Bytes, (Bytes, Bytes) -> Unit) -> Unit], 65 | closure : (Bytes, Bytes) -> Unit 66 | ) -> Int = "webview_bind" 67 | 68 | ///| extern void webview_unbind(webview_t w, const char *name); 69 | pub extern "C" fn webview_unbind(webview : Webview_t, name : Bytes) -> Int = "webview_unbind" 70 | 71 | ///| extern void webview_return(webview_t w, const char *seq, int status, const char *result); 72 | pub extern "C" fn webview_return( 73 | webview : Webview_t, 74 | seq : Bytes, 75 | status : Int, 76 | result : Bytes 77 | ) -> Int = "webview_return" 78 | -------------------------------------------------------------------------------- /src/examples/01_run/main.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// Creates and runs a webview window with debug mode enabled. 3 | /// 4 | /// Sets up a webview window with the following configurations: 5 | /// 6 | /// * Debug mode is enabled 7 | /// * Window size is set to 800x600 pixels 8 | /// * No size hint constraints 9 | fn main { 10 | @webview.Webview::new(debug=1) 11 | ..set_size(800, 600, @webview.SizeHint::None) 12 | ..run() 13 | } 14 | -------------------------------------------------------------------------------- /src/examples/01_run/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "is-main": true, 3 | "import": [ 4 | { 5 | "path": "justjavac/webview", 6 | "alias": "webview" 7 | } 8 | ], 9 | "supported-targets": ["native"], 10 | "targets": { 11 | "main.mbt": ["native"] 12 | }, 13 | "link": { 14 | "native": { 15 | "cc-flags": "-fwrapv -fsanitize=address -fsanitize=undefined", 16 | "cc-link-flags": "-Llib -lwebview" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/examples/02_local/main.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// Defines the HTML template for the local webview example. Contains a centered 3 | /// "Hello, Moonbit!" message with custom styling. 4 | let html = 5 | #| 6 | #| 7 | #| 18 | #| 19 | #| 20 | #| Hello, Moonbit! 21 | #| 22 | #| 23 | 24 | ///| 25 | /// Creates and runs a webview window displaying a local HTML content with a 26 | /// "Hello, Moonbit!" message. 27 | /// 28 | /// The webview window is configured with: 29 | /// 30 | /// * Debug mode enabled 31 | /// * Custom title "Moonbit Webview Example" 32 | /// * Window size of 800x600 pixels 33 | /// * Centered text content with custom styling 34 | fn main { 35 | @webview.Webview::new(debug=1) 36 | ..set_title("Moonbit Webview Example") 37 | ..set_size(800, 600, @webview.SizeHint::None) 38 | ..set_html(html) 39 | ..run() 40 | } 41 | -------------------------------------------------------------------------------- /src/examples/02_local/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "is-main": true, 3 | "import": [ 4 | { 5 | "path": "justjavac/webview", 6 | "alias": "webview" 7 | } 8 | ], 9 | "supported-targets": ["native"], 10 | "targets": { 11 | "main.mbt": ["native"] 12 | }, 13 | "link": { 14 | "native": { 15 | "cc-flags": "-fwrapv -fsanitize=address -fsanitize=undefined", 16 | "cc-link-flags": "-Llib -lwebview" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/examples/03_remote/main.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// Creates and runs a webview window that navigates to the MoonBit homepage. 3 | fn main { 4 | @webview.Webview::new(debug=1) 5 | ..set_title("Moonbit Webview Example") 6 | ..set_size(800, 600, @webview.SizeHint::None) 7 | ..navigate("https://www.moonbitlang.com") 8 | ..run() 9 | } 10 | -------------------------------------------------------------------------------- /src/examples/03_remote/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "is-main": true, 3 | "import": [ 4 | { 5 | "path": "justjavac/webview", 6 | "alias": "webview" 7 | } 8 | ], 9 | "supported-targets": ["native"], 10 | "targets": { 11 | "main.mbt": ["native"] 12 | }, 13 | "link": { 14 | "native": { 15 | "cc-flags": "-fwrapv -fsanitize=address -fsanitize=undefined", 16 | "cc-link-flags": "-Llib -lwebview" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/examples/04_user_agent/main.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// Defines an HTML template that displays the user agent string of the browser. 3 | /// 4 | /// This example demonstrates how to create a simple webview application that 5 | /// displays the user agent string of the browser in a styled HTML document. 6 | let html = 7 | #| 8 | #| 9 | #| 14 | #| 15 | #| 16 | #| 17 | #| 18 | #| 19 | 20 | ///| 21 | /// Creates and runs a webview window that displays the user agent string of the 22 | /// browser. 23 | fn main { 24 | @webview.Webview::new(debug=1) 25 | ..set_title("Moonbit Webview Example") 26 | ..set_size(800, 600, @webview.SizeHint::None) 27 | ..set_html(html) 28 | ..run() 29 | } 30 | -------------------------------------------------------------------------------- /src/examples/04_user_agent/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "is-main": true, 3 | "import": [ 4 | { 5 | "path": "justjavac/webview", 6 | "alias": "webview" 7 | } 8 | ], 9 | "supported-targets": ["native"], 10 | "targets": { 11 | "main.mbt": ["native"] 12 | }, 13 | "link": { 14 | "native": { 15 | "cc-flags": "-fwrapv -fsanitize=address -fsanitize=undefined", 16 | "cc-link-flags": "-Llib -lwebview" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/examples/05_alert/main.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// Defines an HTML string containing a simple webpage with a JavaScript alert. 3 | /// 4 | /// Contains a minimal HTML document structure with a script tag that displays an 5 | /// alert message "Hello Moonbit!" when loaded. 6 | let html = 7 | #| 8 | #| 9 | #| 10 | #| 11 | #| 12 | 13 | ///| 14 | /// Creates and runs a webview window that displays a simple HTML page with a 15 | /// JavaScript alert. 16 | fn main { 17 | @webview.Webview::new(debug=1) 18 | ..set_title("Moonbit Webview Example") 19 | ..set_size(800, 600, @webview.SizeHint::None) 20 | ..set_html(html) 21 | ..run() 22 | } 23 | -------------------------------------------------------------------------------- /src/examples/05_alert/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "is-main": true, 3 | "import": [ 4 | { 5 | "path": "justjavac/webview", 6 | "alias": "webview" 7 | } 8 | ], 9 | "supported-targets": ["native"], 10 | "targets": { 11 | "main.mbt": ["native"] 12 | }, 13 | "link": { 14 | "native": { 15 | "cc-flags": "-fwrapv -fsanitize=address -fsanitize=undefined", 16 | "cc-link-flags": "-Llib -lwebview" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/examples/06_onload/main.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// Defines an HTML template that displays "Hello, Moonbit!" in the center of the 3 | /// window. 4 | let html = 5 | #| 6 | #| 7 | #| 18 | #| 19 | #| 20 | #| 25 | #| 26 | #| 27 | 28 | ///| 29 | /// Creates a window with "Hello, Moonbit!" displayed in the center using a 30 | /// customized HTML template. 31 | /// 32 | /// The text is rendered after the DOM content is loaded using JavaScript. 33 | fn main { 34 | @webview.Webview::new(debug=1) 35 | ..set_title("Moonbit Webview Example") 36 | ..set_size(800, 600, @webview.SizeHint::None) 37 | ..set_html(html) 38 | ..run() 39 | } 40 | -------------------------------------------------------------------------------- /src/examples/06_onload/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "is-main": true, 3 | "import": [ 4 | { 5 | "path": "justjavac/webview", 6 | "alias": "webview" 7 | } 8 | ], 9 | "supported-targets": ["native"], 10 | "targets": { 11 | "main.mbt": ["native"] 12 | }, 13 | "link": { 14 | "native": { 15 | "cc-flags": "-fwrapv -fsanitize=address -fsanitize=undefined", 16 | "cc-link-flags": "-Llib -lwebview" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/examples/07_inject_js/main.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// Defines an HTML template that displays a simple message in the webview. 3 | let html = 4 | #| 5 | #| 6 | #| 7 | #| 8 | #| 9 | 10 | ///| 11 | /// Creates and runs a webview window that displays a message and injects JavaScript 12 | /// to set a global variable. 13 | fn main { 14 | @webview.Webview::new(debug=1) 15 | ..set_title("Moonbit Webview Example") 16 | ..set_size(800, 600, @webview.SizeHint::None) 17 | ..init("(window.foo = 'bar')") 18 | ..set_html(html) 19 | ..run() 20 | } 21 | -------------------------------------------------------------------------------- /src/examples/07_inject_js/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "is-main": true, 3 | "import": [ 4 | { 5 | "path": "justjavac/webview", 6 | "alias": "webview" 7 | } 8 | ], 9 | "supported-targets": ["native"], 10 | "targets": { 11 | "main.mbt": ["native"] 12 | }, 13 | "link": { 14 | "native": { 15 | "cc-flags": "-fwrapv -fsanitize=address -fsanitize=undefined", 16 | "cc-link-flags": "-Llib -lwebview" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/examples/08_eval/main.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// Defines an HTML template that displays a simple message by executing JavaScript 3 | let html = 4 | #| 5 | #| 6 | #| 11 | #| 12 | #| 13 | 14 | ///| 15 | /// Creates and runs a webview window that evaluates JavaScript 16 | fn main { 17 | @webview.Webview::new(debug=1) 18 | ..set_title("Moonbit Webview Example") 19 | ..set_size(800, 600, @webview.SizeHint::None) 20 | ..set_html(html) 21 | ..eval("foo('Hello from Moonbit!');") 22 | ..run() 23 | } 24 | -------------------------------------------------------------------------------- /src/examples/08_eval/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "is-main": true, 3 | "import": [ 4 | { 5 | "path": "justjavac/webview", 6 | "alias": "webview" 7 | } 8 | ], 9 | "supported-targets": ["native"], 10 | "targets": { 11 | "main.mbt": ["native"] 12 | }, 13 | "link": { 14 | "native": { 15 | "cc-flags": "-fwrapv -fsanitize=address -fsanitize=undefined", 16 | "cc-link-flags": "-Llib -lwebview" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/examples/09_dispatch/main.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// Defines an HTML template that displays a simple message in the webview. 3 | let html = 4 | #| 5 | #| 6 | #| 11 | #| 12 | #| 13 | 14 | ///| 15 | /// Creates and runs a webview window that displays a message and injects JavaScript 16 | /// to set a global variable. 17 | fn main { 18 | let webview = @webview.Webview::new(debug=1) 19 | webview.set_title("Moonbit Webview Example") 20 | webview.set_size(800, 600, @webview.SizeHint::None) 21 | webview.set_html(html) 22 | webview.dispatch(fn() { webview.terminate() }) 23 | webview.run() 24 | } 25 | -------------------------------------------------------------------------------- /src/examples/09_dispatch/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "is-main": true, 3 | "import": [ 4 | { 5 | "path": "justjavac/webview", 6 | "alias": "webview" 7 | } 8 | ], 9 | "supported-targets": ["native"], 10 | "targets": { 11 | "main.mbt": ["native"] 12 | }, 13 | "link": { 14 | "native": { 15 | "cc-flags": "-fwrapv -fsanitize=address -fsanitize=undefined", 16 | "cc-link-flags": "-Llib -lwebview" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/examples/10_bind/main.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// Defines the HTML template for the bind example. 3 | /// 4 | /// This HTML includes a button that, when pressed, calls a JavaScript function 5 | /// `press` with a message, a number, and the current date. 6 | let html = 7 | #| 8 | #| 9 | #| 29 | #| 30 | #| 31 | #|

Hello, Moonbit!

32 | #| 35 | #| 36 | #| 37 | 38 | ///| 39 | /// Creates and runs a webview window that displays a button. 40 | /// When the button is pressed, it calls the `press` function with a message, 41 | /// a number, and the current date. 42 | fn main { 43 | let mut counter = 0 44 | @webview.Webview::new(debug=1) 45 | ..set_title("Moonbit Webview Example") 46 | ..set_size(800, 600, @webview.SizeHint::None) 47 | ..bind("press", fn(id, req) { 48 | counter += 1 49 | println(id) 50 | println(req) 51 | println(counter) 52 | }) 53 | ..set_html(html) 54 | ..run() 55 | } 56 | -------------------------------------------------------------------------------- /src/examples/10_bind/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "is-main": true, 3 | "import": [ 4 | { 5 | "path": "justjavac/webview", 6 | "alias": "webview" 7 | } 8 | ], 9 | "supported-targets": ["native"], 10 | "targets": { 11 | "main.mbt": ["native"] 12 | }, 13 | "link": { 14 | "native": { 15 | "cc-flags": "-fwrapv -fsanitize=address -fsanitize=undefined", 16 | "cc-link-flags": "-Llib -lwebview" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/examples/11_multi_window/main.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// Defines the HTML template for the local webview example. Contains a centered 3 | /// "Hello, Moonbit!" message with custom styling. 4 | let html = 5 | #| 6 | #| 7 | #| 18 | #| 19 | #| 20 | #| Hello, Moonbit! 21 | #| 22 | #| 23 | 24 | ///| 25 | /// Creates and runs two webview windows displaying a local HTML content with a 26 | /// "Hello, Moonbit!" message. 27 | fn main { 28 | let webview1 = @webview.Webview::new(debug=1) 29 | webview1.set_title("Moonbit Webview Example") 30 | webview1.set_size(800, 600, @webview.SizeHint::None) 31 | webview1.set_html(html) 32 | let webview2 = @webview.Webview::new(debug=1) 33 | webview2.set_title("Moonbit Webview Example") 34 | webview2.set_size(800, 600, @webview.SizeHint::None) 35 | webview2.set_html(html) 36 | webview1.run() 37 | webview2.run() 38 | } 39 | -------------------------------------------------------------------------------- /src/examples/11_multi_window/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "is-main": true, 3 | "import": [ 4 | { 5 | "path": "justjavac/webview", 6 | "alias": "webview" 7 | } 8 | ], 9 | "supported-targets": ["native"], 10 | "targets": { 11 | "main.mbt": ["native"] 12 | }, 13 | "link": { 14 | "native": { 15 | "cc-flags": "-fwrapv -fsanitize=address -fsanitize=undefined", 16 | "cc-link-flags": "-Llib -lwebview" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/examples/12_embed/hello.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | 17 | 18 | Hello, Moonbit! 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/examples/12_embed/hello.mbt: -------------------------------------------------------------------------------- 1 | // Generated by `moon tool embed --text`, do not edit. 2 | 3 | ///| 4 | let resource : String = 5 | #| 6 | #| 7 | #| 8 | #| 19 | #| 20 | #| 21 | #| 22 | #| Hello, Moonbit! 23 | #| 24 | #| 25 | #| 26 | -------------------------------------------------------------------------------- /src/examples/12_embed/main.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// Creates and runs a webview window displaying a local HTML content with a 3 | /// "Hello, Moonbit!" message. 4 | /// 5 | /// The webview window is configured with: 6 | /// 7 | /// * Debug mode enabled 8 | /// * Custom title "Moonbit Webview Example" 9 | /// * Window size of 800x600 pixels 10 | /// * Centered text content with custom styling 11 | fn main { 12 | @webview.Webview::new(debug=1) 13 | ..set_title("Moonbit Webview Example") 14 | ..set_size(800, 600, @webview.SizeHint::None) 15 | ..set_html(resource) 16 | ..run() 17 | } 18 | -------------------------------------------------------------------------------- /src/examples/12_embed/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "is-main": true, 3 | "import": [ 4 | { 5 | "path": "justjavac/webview", 6 | "alias": "webview" 7 | } 8 | ], 9 | "supported-targets": ["native"], 10 | "targets": { 11 | "main.mbt": ["native"] 12 | }, 13 | "link": { 14 | "native": { 15 | "cc-flags": "-fwrapv -fsanitize=address -fsanitize=undefined", 16 | "cc-link-flags": "-Llib -lwebview" 17 | } 18 | }, 19 | "pre-build": [ 20 | { 21 | "input": "hello.html", 22 | "output": "hello.mbt", 23 | "command": ":embed -i $input -o $output" 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/examples/13_todo/Readme.md: -------------------------------------------------------------------------------- 1 | copy from https://github.com/Boscop/web-view/blob/82d7cbce6228b1a964673cc0f22944ad808eab42/webview-examples/examples/todo-ps/dist/bundle.html 2 | 3 | MIT License 4 | -------------------------------------------------------------------------------- /src/examples/13_todo/bundle.html: -------------------------------------------------------------------------------- 1 | Rust / PureScript - Todo App -------------------------------------------------------------------------------- /src/examples/13_todo/main.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// Creates and runs a webview window displaying a local HTML content with a 3 | /// "Hello, Moonbit!" message. 4 | /// 5 | /// The webview window is configured with: 6 | /// 7 | /// * Debug mode enabled 8 | /// * Custom title "Moonbit Webview Example" 9 | /// * Window size of 800x600 pixels 10 | /// * Centered text content with custom styling 11 | fn main { 12 | @webview.Webview::new(debug=1) 13 | ..set_title("Moonbit Webview Example") 14 | ..set_size(800, 600, @webview.SizeHint::None) 15 | ..set_html(resource) 16 | ..run() 17 | } 18 | -------------------------------------------------------------------------------- /src/examples/13_todo/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "is-main": true, 3 | "import": [ 4 | { 5 | "path": "justjavac/webview", 6 | "alias": "webview" 7 | } 8 | ], 9 | "supported-targets": ["native"], 10 | "targets": { 11 | "main.mbt": ["native"] 12 | }, 13 | "link": { 14 | "native": { 15 | "cc-flags": "-fwrapv -fsanitize=address -fsanitize=undefined", 16 | "cc-link-flags": "-Llib -lwebview" 17 | } 18 | }, 19 | "pre-build": [ 20 | { 21 | "input": "bundle.html", 22 | "output": "bundle.mbt", 23 | "command": ":embed -i $input -o $output" 24 | } 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/examples/Readme.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | | Name | Status | Note | 4 | | --------------- | ------ | --------------------------------------- | 5 | | 01_run | ✓ | | 6 | | 02_local | ✓ | | 7 | | 03_remote | ✓ | | 8 | | 04_user_agent | ✓ | | 9 | | 05_alert | * | Works on Windows, no response on Mac OS | 10 | | 06_onload | ✓ | | 11 | | 07_inject_js | ✓ | | 12 | | 08_eval | ✓ | | 13 | | 09_dispatch | ✓ | | 14 | | 10_bind | 💥 | | 15 | | 11_multi_window | ✓ | | 16 | | 12_embed | ✓ | | 17 | | 13_todo | ✓ | | 18 | -------------------------------------------------------------------------------- /src/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "import": [ 3 | "justjavac/ffi" 4 | ], 5 | "supported-targets": ["native"], 6 | "targets": { 7 | "binding.mbt": ["native"], 8 | "webview.mbt": ["native"] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/stub.c: -------------------------------------------------------------------------------- 1 | #include "webview/webview.h" 2 | 3 | webview_t moonbit_webview_create(int debug, void *window) { 4 | return webview_create(debug, window); 5 | } 6 | 7 | void moonbit_webview_destroy(webview_t w) { 8 | webview_destroy(w); 9 | } 10 | 11 | // void webview_run(webview_t w); 12 | void moonbit_webview_run(webview_t w) { 13 | webview_run(w); 14 | } 15 | 16 | // void webview_terminate(webview_t w); 17 | void moonbit_webview_terminate(webview_t w) { 18 | webview_terminate(w); 19 | } 20 | 21 | // void webview_dispatch(webview_t w, void (*fn)(webview_t w, void *arg), void *arg); 22 | void moonbit_webview_dispatch(webview_t w, void (*fn)(webview_t w, void *arg), void *arg) { 23 | webview_dispatch(w, fn, arg); 24 | } 25 | 26 | // void *webview_get_window(webview_t w); 27 | void *moonbit_webview_get_window(webview_t w) { 28 | return webview_get_window(w); 29 | } 30 | 31 | // void *webview_get_native_handle(webview_t w, webview_native_handle_kind_t kind); 32 | void *moonbit_webview_get_native_handle(webview_t w, webview_native_handle_kind_t kind) { 33 | return webview_get_native_handle(w, kind); 34 | } 35 | 36 | // void webview_set_title(webview_t w, const char *title); 37 | void moonbit_webview_set_title(webview_t w, const char *title) { 38 | webview_set_title(w, title); 39 | } 40 | 41 | // void webview_set_size(webview_t w, int width, int height, webview_hint_t hints); 42 | void moonbit_webview_set_size(webview_t w, int width, int height, webview_hint_t hints) { 43 | webview_set_size(w, width, height, hints); 44 | } 45 | 46 | // void webview_navigate(webview_t w, const char *url); 47 | void moonbit_webview_navigate(webview_t w, const char *url) { 48 | webview_navigate(w, url); 49 | } 50 | 51 | // void webview_set_html(webview_t w, const char *html); 52 | void moonbit_webview_set_html(webview_t w, const char *html) { 53 | webview_set_html(w, html); 54 | } 55 | 56 | // void webview_init(webview_t w, const char *js); 57 | void moonbit_webview_init(webview_t w, const char *js) { 58 | webview_init(w, js); 59 | } 60 | 61 | // void webview_eval(webview_t w, const char *js); 62 | void moonbit_webview_eval(webview_t w, const char *js) { 63 | webview_eval(w, js); 64 | } 65 | 66 | // void webview_bind(webview_t w, const char *name, void (*fn)(const char *seq, const char *req, void *arg), void *arg); 67 | void moonbit_webview_bind(webview_t w, const char *name, void (*fn)(const char *seq, const char *req, void *arg), void *arg) { 68 | webview_bind(w, name, fn, arg); 69 | } 70 | 71 | // void webview_unbind(webview_t w, const char *name); 72 | void moonbit_webview_unbind(webview_t w, const char *name) { 73 | webview_unbind(w, name); 74 | } 75 | 76 | // void webview_return(webview_t w, const char *seq, int status, const char *result); 77 | void moonbit_webview_return(webview_t w, const char *seq, int status, const char *result) { 78 | webview_return(w, seq, status, result); 79 | } -------------------------------------------------------------------------------- /src/webview.mbt: -------------------------------------------------------------------------------- 1 | ///| Native handle kind. The actual type depends on the backend. 2 | pub(all) enum NativeHandleKind { 3 | /// Top-level window. `GtkWindow` pointer (GTK), `NSWindow` pointer (Cocoa) or `HWND` (Win32). 4 | Window = 0 5 | /// Browser widget. `GtkWidget` pointer (GTK), `NSView` pointer (Cocoa) or `HWND` (Win32). 6 | Widget = 1 7 | /// Browser controller. `WebKitWebView` pointer (WebKitGTK), `WKWebView` 8 | /// pointer (Cocoa/WebKit) or `ICoreWebView2Controller` pointer (Win32/WebView2). 9 | Browser = 2 10 | } derive(Show) 11 | 12 | ///| Window size hints 13 | pub(all) enum SizeHint { 14 | /// Width and height are default size. 15 | None = 0 16 | /// Width and height are minimum bounds. 17 | Min = 1 18 | /// Width and height are maximum bounds. 19 | Max = 2 20 | /// Window size can not be changed by a user. 21 | Fixed = 3 22 | } derive(Show) 23 | 24 | ///| An instance of a webview window. 25 | /// 26 | /// Example: 27 | /// 28 | /// ```moonbit 29 | /// let webview = @webview.Webview::new(debug=1) 30 | /// webview.set_title("My Webview") 31 | /// webview.set_size(800, 600, @webview.SizeHint::None) 32 | /// webview.set_html("

Hello, World!

") 33 | /// webview.dispatch(fn() { webview.terminate() }) 34 | /// webview.run() 35 | /// ``` 36 | struct Webview { 37 | handle : Webview_t 38 | callbacks : Map[String, (Bytes, Bytes) -> Unit] 39 | } 40 | 41 | ///| Creates a new webview instance from a webview handle. 42 | /// 43 | /// Parameters: 44 | /// - `debug` - If set to 1, enables debugging mode which provides additional logging. 45 | pub fn Webview::new(debug~ : Int = 0) -> Webview { 46 | let window : Int64 = 0 47 | let webview = Webview::{ 48 | handle: webview_create(debug, window), 49 | callbacks: {}, 50 | } 51 | webview 52 | } 53 | 54 | ///| Stops the main loop. It is safe to call this function from another other 55 | /// background thread. 56 | pub fn Webview::destroy(self : Webview) -> Unit { 57 | for name, _callback in self.callbacks { 58 | let _ = self.unbind(name) 59 | 60 | } 61 | let _ = webview_terminate(self.handle) 62 | let _ = webview_destroy(self.handle) 63 | 64 | } 65 | 66 | ///| Schedules a function to be invoked on the thread with the run/event loop. 67 | /// 68 | /// Since library functions generally do not have thread safety guarantees, 69 | /// this function can be used to schedule code to execute on the main/GUI 70 | /// thread and thereby make that execution safe in multi-threaded applications. 71 | /// 72 | /// Parameters: 73 | /// - `callback` - The function to be invoked. 74 | /// - `arg` - An optional argument passed along to the callback function. 75 | pub fn Webview::dispatch(self : Webview, callback : () -> Unit) -> Unit { 76 | let _ = webview_dispatch(self.handle, fn(w, f) { f(w) }, callback) 77 | 78 | } 79 | 80 | ///| Stops the main loop. It is safe to call this function from another 81 | /// background thread. 82 | pub fn Webview::terminate(self : Webview) -> Unit { 83 | let _ = webview_terminate(self.handle) 84 | 85 | } 86 | 87 | ///| Binds a function pointer to a new global JavaScript function. 88 | /// 89 | /// Internally, JS glue code is injected to create the JS function by the 90 | /// given name. The callback function is passed a request identifier, 91 | /// a request string and a user-provided argument. The request string is 92 | /// a JSON array of the arguments passed to the JS function. 93 | /// 94 | /// Parameters: 95 | /// - `name` - The name of the JavaScript function to bind. 96 | /// - `callback` - The function to be invoked when the JS function is called. 97 | /// - `arg` - An optional user-provided argument passed to the callback function. 98 | /// 99 | /// Returns: 100 | /// - `WEBVIEW_ERROR_DUPLICATE` - A binding already exists with the specified name. 101 | pub fn Webview::bind( 102 | self : Webview, 103 | name : String, 104 | callback : (Bytes, Bytes) -> Unit 105 | ) -> Unit { 106 | self.callbacks.set(name, callback) 107 | let _ = webview_bind( 108 | self.handle, 109 | @ffi.to_cstr(name), 110 | fn(id, req, f) { f(id, req) }, 111 | callback, 112 | ) 113 | 114 | } 115 | 116 | ///| Removes a binding created with `webview.bind()`. 117 | /// 118 | /// Parameters: 119 | /// - `name` - The name of the JavaScript function to unbind. 120 | /// 121 | /// Returns: 122 | /// - `WEBVIEW_ERROR_NOT_FOUND` - No binding exists with the specified name. 123 | pub fn Webview::unbind(self : Webview, name : String) -> Unit { 124 | self.callbacks.remove(name) 125 | let _ = webview_unbind(self.handle, @ffi.to_cstr(name)) 126 | 127 | } 128 | 129 | ///| Updates the title of the native window. 130 | /// 131 | /// Parameters: 132 | /// - `title` - The new title. 133 | pub fn Webview::set_title(self : Webview, title : String) -> Unit { 134 | let _ = webview_set_title(self.handle, @ffi.to_cstr(title)) 135 | 136 | } 137 | 138 | ///| Load HTML content into the webview. 139 | /// 140 | /// Parameters: 141 | /// - `html` - The HTML content to load. 142 | /// 143 | /// Example: 144 | /// ```moonbit 145 | /// let webview = @webview.Webview::new() 146 | /// webview.set_html("

Hello, World!

") 147 | /// webview.dispatch(fn() { webview.terminate() }) 148 | /// webview.run() 149 | /// ``` 150 | pub fn Webview::set_html(self : Webview, html : String) -> Unit { 151 | let _ = webview_set_html(self.handle, @ffi.to_cstr(html)) 152 | 153 | } 154 | 155 | ///| Navigates webview to the given URL. URL may be a properly encoded data URI. 156 | /// 157 | /// Parameters: 158 | /// - `url` - The URL to navigate to. 159 | /// 160 | /// Example: 161 | /// ```moonbit 162 | /// let webview = @webview.Webview::new() 163 | /// webview.navigate("https://www.example.com") 164 | /// webview.navigate("data:text/html,

Hello, World!

") 165 | /// webview.navigate("data:text/html;base64,PGgxPkhlbGxvPC9oMT4=") 166 | /// webview.dispatch(fn() { webview.terminate() }) 167 | /// webview.run() 168 | /// ``` 169 | pub fn Webview::navigate(self : Webview, url : String) -> Unit { 170 | let url = url.to_array() 171 | url.push('\u{0000}') 172 | let url = url.map(fn(c) { c.to_int().to_byte() }) |> Bytes::from_array 173 | let _ = webview_navigate(self.handle, url) 174 | 175 | } 176 | 177 | ///| Returns the native handle of the window associated with the webview instance. 178 | /// The handle can be a `GtkWindow` pointer (GTK), `NSWindow` pointer (Cocoa) 179 | /// or `HWND` (Win32). 180 | pub fn Webview::get_window(self : Webview) -> Int64 { 181 | webview_get_window(self.handle) 182 | } 183 | 184 | ///| Get a native handle of choice. 185 | /// 186 | /// Parameters: 187 | /// - `kind` - The kind of handle to retrieve. 188 | pub fn Webview::get_native_handle( 189 | self : Webview, 190 | kind : NativeHandleKind 191 | ) -> Int64 { 192 | webview_get_native_handle(self.handle, kind) 193 | } 194 | 195 | ///| 196 | /// Returns the internal webview handle of the webview instance. This handle is 197 | /// the raw pointer used by the underlying webview library. 198 | pub fn Webview::get_handle(self : Webview) -> Webview_t { 199 | self.handle 200 | } 201 | 202 | ///| Evaluates arbitrary JavaScript code. 203 | /// 204 | /// Use bindings if you need to communicate the result of the evaluation. 205 | /// 206 | /// Parameters: 207 | /// - `js` - The JavaScript code to evaluate. 208 | pub fn Webview::eval(self : Webview, js : String) -> Unit { 209 | let _ = webview_eval(self.handle, @ffi.to_cstr(js)) 210 | 211 | } 212 | 213 | ///| Injects JavaScript code to be executed immediately upon loading a page. 214 | /// The code will be executed before `window.onload`. 215 | /// 216 | /// Parameters: 217 | /// - `js` - The JavaScript code to inject. 218 | pub fn Webview::init(self : Webview, js : String) -> Unit { 219 | let _ = webview_init(self.handle, @ffi.to_cstr(js)) 220 | 221 | } 222 | 223 | ///| Responds to a binding call from the JS side. 224 | /// 225 | /// This function is safe to call from another thread. 226 | /// 227 | /// Parameters: 228 | /// - `id` - The identifier of the binding call. Pass along the value received 229 | /// in the binding handler (see `webview.bind()`). 230 | /// - `status` - A status of zero tells the JS side that the binding call was 231 | /// successful; any other value indicates an error. 232 | /// - `result` - The result of the binding call to be returned to the JS side. 233 | /// This must either be a valid JSON value or an empty string for 234 | /// the primitive JS value `undefined`. 235 | pub fn Webview::response( 236 | self : Webview, 237 | id : String, 238 | status : Int, 239 | result : String 240 | ) -> Unit { 241 | let _ = webview_return( 242 | self.handle, 243 | @ffi.to_cstr(id), 244 | status, 245 | @ffi.to_cstr(result), 246 | ) 247 | 248 | } 249 | 250 | ///| Updates the size of the native window. 251 | /// 252 | /// Remarks: 253 | /// - Using `WEBVIEW_HINT_MAX` for setting the maximum window size is not 254 | /// supported with GTK 4 because X11-specific functions such as 255 | /// `gtk_window_set_geometry_hints` were removed. This option has no effect 256 | /// when using GTK 4. 257 | /// - GTK 4 can set a default/initial window size if done early enough; 258 | /// otherwise, this function has no effect. GTK 4 (unlike 3) can't resize 259 | /// a window after it has been set up. 260 | /// 261 | /// Parameters: 262 | /// - `width` - The new width of the window. 263 | /// - `height` - The new height of the window. 264 | /// - `hints` - Hints for the window size. 265 | pub fn Webview::set_size( 266 | self : Webview, 267 | width : Int, 268 | height : Int, 269 | hints : SizeHint 270 | ) -> Unit { 271 | let _ = webview_set_size(self.handle, width, height, hints) 272 | 273 | } 274 | 275 | ///| Runs the main loop until it's terminated. 276 | pub fn Webview::run(self : Webview) -> Unit { 277 | let _ = webview_run(self.handle) 278 | self.destroy() 279 | } 280 | -------------------------------------------------------------------------------- /src/webview_test.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | test "Start app loop and terminate it" { 3 | let webview = @webview.Webview::new() 4 | webview.dispatch(fn() { webview.terminate() }) 5 | webview.run() 6 | assert_eq!(1 + 1, 2) 7 | assert_eq!(2 + 2, 4) 8 | } 9 | 10 | ///| 11 | test "Create a window, run app and terminate it" { 12 | let webview = @webview.Webview::new() 13 | webview.set_title("Test") 14 | webview.set_size(480, 320, @webview.SizeHint::None) 15 | webview.set_html("set_html ok") 16 | webview.navigate("data:text/plain,navigate%20ok") 17 | webview.dispatch(fn() { }) 18 | webview.dispatch(fn() { webview.terminate() }) 19 | webview.run() 20 | webview.destroy() 21 | } 22 | --------------------------------------------------------------------------------