diff --git a/docs/src/content/docs/guides/custom-protocol-association.mdx b/docs/src/content/docs/guides/custom-protocol-association.mdx new file mode 100644 index 000000000..4d5bf1eca --- /dev/null +++ b/docs/src/content/docs/guides/custom-protocol-association.mdx @@ -0,0 +1,167 @@ +--- +title: Custom Protocol Schemes (Deep Linking) +description: Guide to implementing custom URL schemes for deep linking in Wails applications across macOS, Windows, and Linux. +--- + +import { Aside } from '@astrojs/starlight/components'; + +# Custom Protocol Schemes (Deep Linking) + +Custom protocol schemes (also known as custom URL schemes or deep linking) allow your Wails application to be launched or brought to the foreground by clicking a URL with a scheme you define (e.g., `myapp://some/data`). This is useful for various purposes, such as: + +- OAuth authentication flows. +- Inter-application communication. +- Launching your app with a specific context or to perform a particular action. + +Wails provides a unified way to handle these custom URL invocations across macOS, Windows, and Linux through the `events.Common.ApplicationLaunchedWithUrl` event. + +## Defining Your Protocols + +First, you need to define the custom protocol schemes your application will use. This is done in your `wails.json` project configuration file. Wails reads this file during the build process (`wails build`) to configure the necessary platform-specific assets like `Info.plist` for macOS, NSIS installer scripts for Windows, and `.desktop` files for Linux. + +**Example: `wails.json`** + +```json title="wails.json" +{ + "name": "My App", + "description": "An amazing Wails app!", + "info": { + "companyName": "My Company", + "productName": "My Product", + // ... other info fields ... + "protocols": [ + { + "scheme": "myapp", + "description": "My Application Custom Protocol" + }, + { + "scheme": "anotherprotocol", + "description": "Another protocol for specific actions" + } + ] + } + // ... other wails.json fields ... +} +``` + +This `info.protocols` array is what Wails uses to generate the necessary entries in platform-specific files. For example, in template files, you might access this via a path like `{{.Info.Protocols}}`. + + + +## Handling the Event in Your Application + +When your application is launched or activated via a custom URL, Wails emits an `events.Common.ApplicationLaunchedWithUrl` event. You can listen for this event and retrieve the URL that triggered the launch. + +```go title="main.go" +import ( + "log" + "github.com/wailsapp/wails/v3/pkg/application" + "github.com/wailsapp/wails/v3/pkg/events" +) + +func main() { + app := application.New(application.Options{ + Name: "My App", // Ensure this matches relevant info from wails.json if needed + Description: "An amazing Wails app!", + // ... other runtime options ... + }) + + app.OnApplicationEvent(events.Common.ApplicationLaunchedWithUrl, func(e *application.ApplicationEvent) { + launchedURL := e.Context().URL() // Retrieve the URL from the event context + log.Printf("Application launched with URL: %s", launchedURL) + + // TODO: Process the URL (e.g., navigate, perform action, etc.) + // Example: app.EmitEvent("frontend:ShowURL", launchedURL) + }) + + // ... rest of your main function ... + err := app.Run() + if err != nil { + log.Fatal(err) + } +} +``` + + + +## Platform-Specific Setup and Behavior + +While Wails aims for a unified event, the underlying mechanism for custom protocol registration and URL delivery varies by operating system. + +### macOS + +- **Setup:** Wails automatically configures your application's `Info.plist` file during the build process. It adds `CFBundleURLTypes` entries based on the `info.protocols` defined in your `wails.json` file. + ```xml title="Info.plist (excerpt generated by Wails)" + CFBundleURLTypes + + + CFBundleURLName + My Application Custom Protocol + CFBundleURLSchemes + + myapp + + + + + ``` +- **How it Works:** When a URL like `myapp://` is opened, macOS uses LaunchServices to find the application registered for that scheme and sends it an Apple Event (`kAEGetURL`). Wails intercepts this event and translates it into the common `events.Common.ApplicationLaunchedWithUrl` Wails event, providing the URL via `e.Context().URL()`. + +### Windows + +- **Setup:** Custom protocol schemes on Windows are registered in the Windows Registry. Wails facilitates this through its NSIS installer template. + - When you build your application with the `-nsis` flag, Wails uses the `v3/internal/commands/updatable_build_assets/windows/nsis/wails_tools.nsh.tmpl` file. + - This template contains macros like `CUSTOM_PROTOCOL_ASSOCIATE` and `wails.associateCustomProtocols` which use the `info.protocols` from your `wails.json` (passed as `{{.Info.Protocols}}` to the template) to create the necessary registry entries during installation. + ```nsis title="wails_tools.nsh.tmpl (excerpt)" + !macro wails.associateCustomProtocols + ; Create custom protocols associations + {{range .Info.Protocols}} + !insertmacro CUSTOM_PROTOCOL_ASSOCIATE "{{.Scheme}}" "{{.Description}}" "$INSTDIR\${PRODUCT_EXECUTABLE},0" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\"" + {{end}} + !macroend + ``` +- **How it Works:** The installer registers your application executable to be called with the URL as a command-line argument (`%1`). For example, `your_app.exe "myapp://some/data"`. + - The Wails runtime for Windows (`v3/pkg/application/application_windows.go`) has been updated to check `os.Args` upon startup. If it detects an argument that looks like a URL (e.g., `os.Args[1]` contains `"://"`), it now emits the `events.Common.ApplicationLaunchedWithUrl` event with this URL. + + + +### Linux + +- **Setup:** On Linux, custom protocol handling is typically managed via `.desktop` files and the MIME type system. + - Wails uses a `.desktop` file template (e.g., `v3/internal/commands/updatable_build_assets/linux/desktop.tmpl`) which is populated during the build using information from `wails.json`. + ```desktop title="desktop.tmpl (excerpt)" + [Desktop Entry] + Name={{.ProductName}} + Exec=/usr/local/bin/{{.BinaryName}} %u + MimeType={{range $index, $protocol := .Info.Protocols}}x-scheme-handler/{{$protocol.Scheme}};{{end}} + ``` + The `Exec` line uses `%u` which gets replaced by the URL. The `MimeType` line registers your application as a handler for `x-scheme-handler/your-scheme` for each protocol defined in `wails.json` (via `{{.Info.Protocols}}`). + - When packaging for Linux (e.g., using `nfpm`), this `.desktop` file is installed to `/usr/share/applications/`. + - A `postinstall.sh` script (e.g., `v3/internal/commands/build_assets/linux/nfpm/scripts/postinstall.sh`) is used to update the system's application and MIME databases: + ```sh title="postinstall.sh (excerpt)" + #!/bin/sh + update-desktop-database -q /usr/share/applications + update-mime-database -n /usr/share/mime + ``` +- **How it Works:** When a URL like `myapp://` is opened, the desktop environment uses the MIME database to find the associated `.desktop` file and executes the command specified in its `Exec` line, substituting `%u` with the URL. Your application receives this URL as a command-line argument. + - The Wails runtime for Linux (`v3/pkg/application/application_linux.go`) checks `os.Args` on startup. If it detects an argument that looks like a URL, it emits the `events.Common.ApplicationLaunchedWithUrl` event. + +## Testing Your Custom Protocols + +- **macOS:** Open Terminal and type `open "your-scheme://your/data"`. +- **Linux:** Open a terminal and type `xdg-open "your-scheme://your/data"` (requires `xdg-utils` to be installed and the app to be properly packaged and registered). +- **Windows:** After installation via NSIS: + - You can try running `start your-scheme://your/data` from Command Prompt or PowerShell. + - Create a simple HTML file with a link `Test Link` and open it in a browser. + + + +By following this guide, you can effectively use custom protocol schemes to enhance your Wails application's interactivity and integration with other applications or web services. diff --git a/v3/examples/custom-protocol-example/.gitignore b/v3/examples/custom-protocol-example/.gitignore new file mode 100644 index 000000000..ba8194ab6 --- /dev/null +++ b/v3/examples/custom-protocol-example/.gitignore @@ -0,0 +1,6 @@ +.task +bin +frontend/dist +frontend/node_modules +build/linux/appimage/build +build/windows/nsis/MicrosoftEdgeWebview2Setup.exe \ No newline at end of file diff --git a/v3/examples/custom-protocol-example/README.md b/v3/examples/custom-protocol-example/README.md new file mode 100644 index 000000000..ad12c3f40 --- /dev/null +++ b/v3/examples/custom-protocol-example/README.md @@ -0,0 +1,59 @@ +# Welcome to Your New Wails3 Project! + +Congratulations on generating your Wails3 application! This README will guide you through the next steps to get your project up and running. + +## Getting Started + +1. Navigate to your project directory in the terminal. + +2. To run your application in development mode, use the following command: + + ``` + wails3 dev + ``` + + This will start your application and enable hot-reloading for both frontend and backend changes. + +3. To build your application for production, use: + + ``` + wails3 build + ``` + + This will create a production-ready executable in the `build` directory. + +## Exploring Wails3 Features + +Now that you have your project set up, it's time to explore the features that Wails3 offers: + +1. **Check out the examples**: The best way to learn is by example. Visit the `examples` directory in the `v3/examples` directory to see various sample applications. + +2. **Run an example**: To run any of the examples, navigate to the example's directory and use: + + ``` + go run . + ``` + + Note: Some examples may be under development during the alpha phase. + +3. **Explore the documentation**: Visit the [Wails3 documentation](https://v3.wails.io/) for in-depth guides and API references. + +4. **Join the community**: Have questions or want to share your progress? Join the [Wails Discord](https://discord.gg/JDdSxwjhGf) or visit the [Wails discussions on GitHub](https://github.com/wailsapp/wails/discussions). + +## Project Structure + +Take a moment to familiarize yourself with your project structure: + +- `frontend/`: Contains your frontend code (HTML, CSS, JavaScript/TypeScript) +- `main.go`: The entry point of your Go backend +- `app.go`: Define your application structure and methods here +- `wails.json`: Configuration file for your Wails project + +## Next Steps + +1. Modify the frontend in the `frontend/` directory to create your desired UI. +2. Add backend functionality in `main.go`. +3. Use `wails3 dev` to see your changes in real-time. +4. When ready, build your application with `wails3 build`. + +Happy coding with Wails3! If you encounter any issues or have questions, don't hesitate to consult the documentation or reach out to the Wails community. diff --git a/v3/examples/custom-protocol-example/Taskfile.yml b/v3/examples/custom-protocol-example/Taskfile.yml new file mode 100644 index 000000000..572db59ac --- /dev/null +++ b/v3/examples/custom-protocol-example/Taskfile.yml @@ -0,0 +1,33 @@ +version: '3' + +includes: + common: ./build/Taskfile.yml + windows: ./build/windows/Taskfile.yml + darwin: ./build/darwin/Taskfile.yml + linux: ./build/linux/Taskfile.yml + +vars: + APP_NAME: "custom-protocol-example" + BIN_DIR: "bin" + +tasks: + build: + summary: Builds the application + cmds: + - task: "{{OS}}:build" + + package: + summary: Packages a production build of the application + cmds: + - task: "{{OS}}:package" + + run: + summary: Runs the application + cmds: + - task: "{{OS}}:run" + + dev: + summary: Runs the application in development mode + cmds: + - wails3 dev -config ./build/config.yml + diff --git a/v3/examples/custom-protocol-example/build/Taskfile.yml b/v3/examples/custom-protocol-example/build/Taskfile.yml new file mode 100644 index 000000000..ba497b5b6 --- /dev/null +++ b/v3/examples/custom-protocol-example/build/Taskfile.yml @@ -0,0 +1,85 @@ +version: '3' + +tasks: + go:mod:tidy: + summary: Runs `go mod tidy` + internal: true + cmds: + - go mod tidy + + install:frontend:deps: + summary: Install frontend dependencies + dir: frontend + sources: + - package.json + - package-lock.json + generates: + - node_modules/* + preconditions: + - sh: npm version + cmds: + - echo "Skipping frontend dependencies installation" + + build:frontend: + label: build:frontend (PRODUCTION={{.PRODUCTION}}) + summary: Build the frontend project + dir: frontend + sources: + - "**/*" + generates: + - dist/**/* + deps: + - task: install:frontend:deps + - task: generate:bindings + vars: + BUILD_FLAGS: + ref: .BUILD_FLAGS + cmds: + - npm run {{.BUILD_COMMAND}} -q + env: + PRODUCTION: '{{.PRODUCTION | default "false"}}' + vars: + BUILD_COMMAND: '{{if eq .PRODUCTION "true"}}build{{else}}build{{end}}' + + + generate:bindings: + label: generate:bindings (BUILD_FLAGS={{.BUILD_FLAGS}}) + summary: Generates bindings for the frontend + deps: + - task: go:mod:tidy + sources: + - "**/*.[jt]s" + - exclude: frontend/**/* + - frontend/bindings/**/* # Rerun when switching between dev/production mode causes changes in output + - "**/*.go" + - go.mod + - go.sum + generates: + - frontend/bindings/**/* + cmds: + - wails3 generate bindings -f '{{.BUILD_FLAGS}}' -clean=true + + generate:icons: + summary: Generates Windows `.ico` and Mac `.icns` files from an image + dir: build + sources: + - "appicon.png" + generates: + - "darwin/icons.icns" + - "windows/icon.ico" + cmds: + - wails3 generate icons -input appicon.png -macfilename darwin/icons.icns -windowsfilename windows/icon.ico + + dev:frontend: + summary: Runs the frontend in development mode + dir: frontend + deps: + - task: install:frontend:deps + cmds: + - echo "Skipping frontend development mode" + + update:build-assets: + summary: Updates the build assets + dir: build + cmds: + - wails3 update build-assets -name "{{.APP_NAME}}" -binaryname "{{.APP_NAME}}" -config config.yml -dir . diff --git a/v3/examples/custom-protocol-example/build/appicon.png b/v3/examples/custom-protocol-example/build/appicon.png new file mode 100644 index 000000000..63617fe4f Binary files /dev/null and b/v3/examples/custom-protocol-example/build/appicon.png differ diff --git a/v3/examples/custom-protocol-example/build/config.yml b/v3/examples/custom-protocol-example/build/config.yml new file mode 100644 index 000000000..8f2cb0348 --- /dev/null +++ b/v3/examples/custom-protocol-example/build/config.yml @@ -0,0 +1,67 @@ +# This file contains the configuration for this project. +# When you update `info` or `fileAssociations`, run `wails3 task common:update:build-assets` to update the assets. +# Note that this will overwrite any changes you have made to the assets. +version: '3' + +# This information is used to generate the build assets. +info: + companyName: "My Company" # The name of the company + productName: "My Product" # The name of the application + productIdentifier: "com.mycompany.myproduct" # The unique product identifier + description: "A program that does X" # The application description + copyright: "(c) 2025, My Company" # Copyright text + comments: "Some Product Comments" # Comments + version: "0.0.1" # The application version + +# Dev mode configuration +dev_mode: + root_path: . + log_level: warn + debounce: 1000 + ignore: + dir: + - .git + - node_modules + - frontend + - bin + file: + - .DS_Store + - .gitignore + - .gitkeep + watched_extension: + - "*.go" + git_ignore: true + executes: + - cmd: wails3 task common:install:frontend:deps + type: once + - cmd: wails3 task common:dev:frontend + type: background + - cmd: go mod tidy + type: blocking + - cmd: wails3 task build + type: blocking + - cmd: wails3 task run + type: primary + +# File Associations +# More information at: https://v3.wails.io/noit/done/yet +fileAssociations: +# - ext: wails +# name: Wails +# description: Wails Application File +# iconName: wailsFileIcon +# role: Editor +# - ext: jpg +# name: JPEG +# description: Image File +# iconName: jpegFileIcon +# role: Editor +# mimeType: image/jpeg # (optional) + +protocols: + - scheme: wailsexample + description: Wails Example Application Custom Protocol + +# Other data +other: + - name: My Other Data \ No newline at end of file diff --git a/v3/examples/custom-protocol-example/build/darwin/Info.dev.plist b/v3/examples/custom-protocol-example/build/darwin/Info.dev.plist new file mode 100644 index 000000000..a46aa82d9 --- /dev/null +++ b/v3/examples/custom-protocol-example/build/darwin/Info.dev.plist @@ -0,0 +1,43 @@ + + + + CFBundlePackageType + APPL + CFBundleName + My Product + CFBundleExecutable + custom-protocol-example + CFBundleIdentifier + com.mycompany.myproduct + CFBundleVersion + 0.0.1 + CFBundleGetInfoString + Some Product Comments + CFBundleShortVersionString + 0.0.1 + CFBundleIconFile + icons + LSMinimumSystemVersion + 10.15.0 + NSHighResolutionCapable + true + NSHumanReadableCopyright + (c) 2025, My Company + NSAppTransportSecurity + + NSAllowsLocalNetworking + + + CFBundleURLTypes + + + CFBundleURLName + wails.com.wailsexample + CFBundleURLSchemes + + wailsexample + + + + + \ No newline at end of file diff --git a/v3/examples/custom-protocol-example/build/darwin/Info.plist b/v3/examples/custom-protocol-example/build/darwin/Info.plist new file mode 100644 index 000000000..d88fd1030 --- /dev/null +++ b/v3/examples/custom-protocol-example/build/darwin/Info.plist @@ -0,0 +1,38 @@ + + + + CFBundlePackageType + APPL + CFBundleName + My Product + CFBundleExecutable + custom-protocol-example + CFBundleIdentifier + com.mycompany.myproduct + CFBundleVersion + 0.0.1 + CFBundleGetInfoString + Some Product Comments + CFBundleShortVersionString + 0.0.1 + CFBundleIconFile + icons + LSMinimumSystemVersion + 10.15.0 + NSHighResolutionCapable + true + NSHumanReadableCopyright + (c) 2025, My Company + CFBundleURLTypes + + + CFBundleURLName + wails.com.wailsexample + CFBundleURLSchemes + + wailsexample + + + + + \ No newline at end of file diff --git a/v3/examples/custom-protocol-example/build/darwin/Taskfile.yml b/v3/examples/custom-protocol-example/build/darwin/Taskfile.yml new file mode 100644 index 000000000..e456dbad5 --- /dev/null +++ b/v3/examples/custom-protocol-example/build/darwin/Taskfile.yml @@ -0,0 +1,76 @@ +version: '3' + +includes: + common: ../Taskfile.yml + +tasks: + build: + summary: Creates a production build of the application + deps: + - task: common:go:mod:tidy + - task: common:generate:icons + - task: common:build:frontend + cmds: + - go build {{.BUILD_FLAGS}} -o {{.OUTPUT}} + vars: + BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-buildvcs=false -gcflags=all="-l"{{end}}' + DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}' + OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}' + env: + GOOS: darwin + CGO_ENABLED: 1 + GOARCH: '{{.ARCH | default ARCH}}' + CGO_CFLAGS: "-mmacosx-version-min=10.15" + CGO_LDFLAGS: "-mmacosx-version-min=10.15" + MACOSX_DEPLOYMENT_TARGET: "10.15" + PRODUCTION: '{{.PRODUCTION | default "false"}}' + + build:universal: + summary: Builds darwin universal binary (arm64 + amd64) + deps: + - task: build + vars: + ARCH: amd64 + OUTPUT: "{{.BIN_DIR}}/{{.APP_NAME}}-amd64" + - task: build + vars: + ARCH: arm64 + OUTPUT: "{{.BIN_DIR}}/{{.APP_NAME}}-arm64" + cmds: + - lipo -create -output "{{.BIN_DIR}}/{{.APP_NAME}}" "{{.BIN_DIR}}/{{.APP_NAME}}-amd64" "{{.BIN_DIR}}/{{.APP_NAME}}-arm64" + - rm "{{.BIN_DIR}}/{{.APP_NAME}}-amd64" "{{.BIN_DIR}}/{{.APP_NAME}}-arm64" + + package: + summary: Packages a production build of the application into a `.app` bundle + deps: + - task: build + vars: + PRODUCTION: "false" + cmds: + - task: create:app:bundle + + package:universal: + summary: Packages darwin universal binary (arm64 + amd64) + deps: + - task: build:universal + cmds: + - task: create:app:bundle + + + create:app:bundle: + summary: Creates an `.app` bundle + cmds: + - mkdir -p {{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/{MacOS,Resources} + - cp build/darwin/icons.icns {{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/Resources + - cp {{.BIN_DIR}}/{{.APP_NAME}} {{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/MacOS + - cp build/darwin/Info.plist {{.BIN_DIR}}/{{.APP_NAME}}.app/Contents + - codesign --force --deep --sign - {{.BIN_DIR}}/{{.APP_NAME}}.app + + run: + cmds: + - mkdir -p {{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/{MacOS,Resources} + - cp build/darwin/icons.icns {{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/Resources + - cp {{.BIN_DIR}}/{{.APP_NAME}} {{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/MacOS + - cp build/darwin/Info.dev.plist {{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/Info.plist + - codesign --force --deep --sign - {{.BIN_DIR}}/{{.APP_NAME}}.dev.app + - '{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/MacOS/{{.APP_NAME}}' diff --git a/v3/examples/custom-protocol-example/build/darwin/icons.icns b/v3/examples/custom-protocol-example/build/darwin/icons.icns new file mode 100644 index 000000000..1b5bd4c86 Binary files /dev/null and b/v3/examples/custom-protocol-example/build/darwin/icons.icns differ diff --git a/v3/examples/custom-protocol-example/build/linux/Taskfile.yml b/v3/examples/custom-protocol-example/build/linux/Taskfile.yml new file mode 100644 index 000000000..a6115574a --- /dev/null +++ b/v3/examples/custom-protocol-example/build/linux/Taskfile.yml @@ -0,0 +1,113 @@ +version: '3' + +includes: + common: ../Taskfile.yml + +tasks: + build: + summary: Builds the application for Linux + deps: + - task: common:go:mod:tidy + - task: common:generate:icons + cmds: + - go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}} + vars: + BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-buildvcs=false -gcflags=all="-l"{{end}}' + env: + GOOS: linux + CGO_ENABLED: 1 + GOARCH: '{{.ARCH | default ARCH}}' + PRODUCTION: '{{.PRODUCTION | default "false"}}' + + package: + summary: Packages a production build of the application for Linux + deps: + - task: build + vars: + PRODUCTION: "true" + cmds: + - task: create:appimage + - task: create:deb + - task: create:rpm + - task: create:aur + + create:appimage: + summary: Creates an AppImage + dir: build/linux/appimage + deps: + - task: build + vars: + PRODUCTION: "true" + - task: generate:dotdesktop + cmds: + - cp {{.APP_BINARY}} {{.APP_NAME}} + - cp ../../appicon.png appicon.png + - wails3 generate appimage -binary {{.APP_NAME}} -icon {{.ICON}} -desktopfile {{.DESKTOP_FILE}} -outputdir {{.OUTPUT_DIR}} -builddir {{.ROOT_DIR}}/build/linux/appimage/build + vars: + APP_NAME: '{{.APP_NAME}}' + APP_BINARY: '../../../bin/{{.APP_NAME}}' + ICON: '../../appicon.png' + DESKTOP_FILE: '../{{.APP_NAME}}.desktop' + OUTPUT_DIR: '../../../bin' + + create:deb: + summary: Creates a deb package + deps: + - task: build + vars: + PRODUCTION: "true" + cmds: + - task: generate:dotdesktop + - task: generate:deb + + create:rpm: + summary: Creates a rpm package + deps: + - task: build + vars: + PRODUCTION: "true" + cmds: + - task: generate:dotdesktop + - task: generate:rpm + + create:aur: + summary: Creates a arch linux packager package + deps: + - task: build + vars: + PRODUCTION: "true" + cmds: + - task: generate:dotdesktop + - task: generate:aur + + generate:deb: + summary: Creates a deb package + cmds: + - wails3 tool package -name {{.APP_NAME}} -format deb -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin + + generate:rpm: + summary: Creates a rpm package + cmds: + - wails3 tool package -name {{.APP_NAME}} -format rpm -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin + + generate:aur: + summary: Creates a arch linux packager package + cmds: + - wails3 tool package -name {{.APP_NAME}} -format archlinux -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin + + generate:dotdesktop: + summary: Generates a `.desktop` file + dir: build + cmds: + - mkdir -p {{.ROOT_DIR}}/build/linux/appimage + - wails3 generate .desktop -name "{{.APP_NAME}}" -exec "{{.EXEC}}" -icon "{{.ICON}}" -outputfile {{.ROOT_DIR}}/build/linux/{{.APP_NAME}}.desktop -categories "{{.CATEGORIES}}" + vars: + APP_NAME: '{{.APP_NAME}}' + EXEC: '{{.APP_NAME}}' + ICON: 'appicon' + CATEGORIES: 'Development;' + OUTPUTFILE: '{{.ROOT_DIR}}/build/linux/{{.APP_NAME}}.desktop' + + run: + cmds: + - '{{.BIN_DIR}}/{{.APP_NAME}}' diff --git a/v3/examples/custom-protocol-example/build/linux/appimage/build.sh b/v3/examples/custom-protocol-example/build/linux/appimage/build.sh new file mode 100644 index 000000000..85901c34e --- /dev/null +++ b/v3/examples/custom-protocol-example/build/linux/appimage/build.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# Copyright (c) 2018-Present Lea Anthony +# SPDX-License-Identifier: MIT + +# Fail script on any error +set -euxo pipefail + +# Define variables +APP_DIR="${APP_NAME}.AppDir" + +# Create AppDir structure +mkdir -p "${APP_DIR}/usr/bin" +cp -r "${APP_BINARY}" "${APP_DIR}/usr/bin/" +cp "${ICON_PATH}" "${APP_DIR}/" +cp "${DESKTOP_FILE}" "${APP_DIR}/" + +if [[ $(uname -m) == *x86_64* ]]; then + # Download linuxdeploy and make it executable + wget -q -4 -N https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage + chmod +x linuxdeploy-x86_64.AppImage + + # Run linuxdeploy to bundle the application + ./linuxdeploy-x86_64.AppImage --appdir "${APP_DIR}" --output appimage +else + # Download linuxdeploy and make it executable (arm64) + wget -q -4 -N https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-aarch64.AppImage + chmod +x linuxdeploy-aarch64.AppImage + + # Run linuxdeploy to bundle the application (arm64) + ./linuxdeploy-aarch64.AppImage --appdir "${APP_DIR}" --output appimage +fi + +# Rename the generated AppImage +mv "${APP_NAME}*.AppImage" "${APP_NAME}.AppImage" + diff --git a/v3/examples/custom-protocol-example/build/linux/nfpm/nfpm.yaml b/v3/examples/custom-protocol-example/build/linux/nfpm/nfpm.yaml new file mode 100644 index 000000000..7356f2992 --- /dev/null +++ b/v3/examples/custom-protocol-example/build/linux/nfpm/nfpm.yaml @@ -0,0 +1,50 @@ +# Feel free to remove those if you don't want/need to use them. +# Make sure to check the documentation at https://nfpm.goreleaser.com +# +# The lines below are called `modelines`. See `:help modeline` + +name: "custom-protocol-example" +arch: ${GOARCH} +platform: "linux" +version: "0.0.1" +section: "default" +priority: "extra" +maintainer: ${GIT_COMMITTER_NAME} <${GIT_COMMITTER_EMAIL}> +description: "A program that does X" +vendor: "My Company" +homepage: "https://wails.io" +license: "MIT" +release: "1" + +contents: + - src: "./bin/custom-protocol-example" + dst: "/usr/local/bin/custom-protocol-example" + - src: "./build/appicon.png" + dst: "/usr/share/icons/hicolor/128x128/apps/custom-protocol-example.png" + - src: "./build/linux/custom-protocol-example.desktop" + dst: "/usr/share/applications/custom-protocol-example.desktop" + +depends: + - gtk3 + - libwebkit2gtk + +# replaces: +# - foobar +# provides: +# - bar +# depends: +# - gtk3 +# - libwebkit2gtk +# recommends: +# - whatever +# suggests: +# - something-else +# conflicts: +# - not-foo +# - not-bar +# changelog: "changelog.yaml" +# scripts: +# preinstall: ./build/linux/nfpm/scripts/preinstall.sh +# postinstall: ./build/linux/nfpm/scripts/postinstall.sh +# preremove: ./build/linux/nfpm/scripts/preremove.sh +# postremove: ./build/linux/nfpm/scripts/postremove.sh diff --git a/v3/examples/custom-protocol-example/build/linux/nfpm/scripts/postinstall.sh b/v3/examples/custom-protocol-example/build/linux/nfpm/scripts/postinstall.sh new file mode 100644 index 000000000..a9bf588e2 --- /dev/null +++ b/v3/examples/custom-protocol-example/build/linux/nfpm/scripts/postinstall.sh @@ -0,0 +1 @@ +#!/bin/bash diff --git a/v3/examples/custom-protocol-example/build/linux/nfpm/scripts/postremove.sh b/v3/examples/custom-protocol-example/build/linux/nfpm/scripts/postremove.sh new file mode 100644 index 000000000..a9bf588e2 --- /dev/null +++ b/v3/examples/custom-protocol-example/build/linux/nfpm/scripts/postremove.sh @@ -0,0 +1 @@ +#!/bin/bash diff --git a/v3/examples/custom-protocol-example/build/linux/nfpm/scripts/preinstall.sh b/v3/examples/custom-protocol-example/build/linux/nfpm/scripts/preinstall.sh new file mode 100644 index 000000000..a9bf588e2 --- /dev/null +++ b/v3/examples/custom-protocol-example/build/linux/nfpm/scripts/preinstall.sh @@ -0,0 +1 @@ +#!/bin/bash diff --git a/v3/examples/custom-protocol-example/build/linux/nfpm/scripts/preremove.sh b/v3/examples/custom-protocol-example/build/linux/nfpm/scripts/preremove.sh new file mode 100644 index 000000000..a9bf588e2 --- /dev/null +++ b/v3/examples/custom-protocol-example/build/linux/nfpm/scripts/preremove.sh @@ -0,0 +1 @@ +#!/bin/bash diff --git a/v3/examples/custom-protocol-example/build/windows/Taskfile.yml b/v3/examples/custom-protocol-example/build/windows/Taskfile.yml new file mode 100644 index 000000000..805c1aa7f --- /dev/null +++ b/v3/examples/custom-protocol-example/build/windows/Taskfile.yml @@ -0,0 +1,57 @@ +version: '3' + +includes: + common: ../Taskfile.yml + +tasks: + build: + summary: Builds the application for Windows + deps: + - task: common:go:mod:tidy + - task: common:generate:icons + cmds: + - task: generate:syso + - go build {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}.exe + - cmd: powershell Remove-item *.syso + platforms: [windows] + - cmd: rm -f *.syso + platforms: [linux, darwin] + vars: + BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production -trimpath -buildvcs=false -ldflags="-w -s -H windowsgui"{{else}}-buildvcs=false -gcflags=all="-l"{{end}}' + env: + GOOS: windows + CGO_ENABLED: 0 + GOARCH: '{{.ARCH | default ARCH}}' + PRODUCTION: '{{.PRODUCTION | default "false"}}' + + package: + summary: Packages a production build of the application into a `.exe` bundle + cmds: + - task: create:nsis:installer + + generate:syso: + summary: Generates Windows `.syso` file + dir: build + cmds: + - wails3 generate syso -arch {{.ARCH}} -icon windows/icon.ico -manifest windows/wails.exe.manifest -info windows/info.json -out ../wails_windows_{{.ARCH}}.syso + vars: + ARCH: '{{.ARCH | default ARCH}}' + + create:nsis:installer: + summary: Creates an NSIS installer + dir: build/windows/nsis + deps: + - task: build + vars: + PRODUCTION: "true" + cmds: + # Create the Microsoft WebView2 bootstrapper if it doesn't exist + - wails3 generate webview2bootstrapper -dir "{{.ROOT_DIR}}/build/windows/nsis" + - makensis -DARG_WAILS_{{.ARG_FLAG}}_BINARY="{{.ROOT_DIR}}/{{.BIN_DIR}}/{{.APP_NAME}}.exe" project.nsi + vars: + ARCH: '{{.ARCH | default ARCH}}' + ARG_FLAG: '{{if eq .ARCH "amd64"}}AMD64{{else}}ARM64{{end}}' + + run: + cmds: + - '{{.BIN_DIR}}/{{.APP_NAME}}.exe' diff --git a/v3/examples/custom-protocol-example/build/windows/icon.ico b/v3/examples/custom-protocol-example/build/windows/icon.ico new file mode 100644 index 000000000..bfa0690b7 Binary files /dev/null and b/v3/examples/custom-protocol-example/build/windows/icon.ico differ diff --git a/v3/examples/custom-protocol-example/build/windows/info.json b/v3/examples/custom-protocol-example/build/windows/info.json new file mode 100644 index 000000000..71dfd6d99 --- /dev/null +++ b/v3/examples/custom-protocol-example/build/windows/info.json @@ -0,0 +1,15 @@ +{ + "fixed": { + "file_version": "0.0.1" + }, + "info": { + "0000": { + "ProductVersion": "0.0.1", + "CompanyName": "My Company", + "FileDescription": "A program that does X", + "LegalCopyright": "(c) 2025, My Company", + "ProductName": "My Product", + "Comments": "Some Product Comments" + } + } +} \ No newline at end of file diff --git a/v3/examples/custom-protocol-example/build/windows/nsis/project.nsi b/v3/examples/custom-protocol-example/build/windows/nsis/project.nsi new file mode 100644 index 000000000..5ff2eb085 --- /dev/null +++ b/v3/examples/custom-protocol-example/build/windows/nsis/project.nsi @@ -0,0 +1,112 @@ +Unicode true + +#### +## Please note: Template replacements don't work in this file. They are provided with default defines like +## mentioned underneath. +## If the keyword is not defined, "wails_tools.nsh" will populate them. +## If they are defined here, "wails_tools.nsh" will not touch them. This allows you to use this project.nsi manually +## from outside of Wails for debugging and development of the installer. +## +## For development first make a wails nsis build to populate the "wails_tools.nsh": +## > wails build --target windows/amd64 --nsis +## Then you can call makensis on this file with specifying the path to your binary: +## For a AMD64 only installer: +## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app.exe +## For a ARM64 only installer: +## > makensis -DARG_WAILS_ARM64_BINARY=..\..\bin\app.exe +## For a installer with both architectures: +## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app-amd64.exe -DARG_WAILS_ARM64_BINARY=..\..\bin\app-arm64.exe +#### +## The following information is taken from the wails_tools.nsh file, but they can be overwritten here. +#### +## !define INFO_PROJECTNAME "my-project" # Default "custom-protocol-example" +## !define INFO_COMPANYNAME "My Company" # Default "My Company" +## !define INFO_PRODUCTNAME "My Product Name" # Default "My Product" +## !define INFO_PRODUCTVERSION "1.0.0" # Default "0.1.0" +## !define INFO_COPYRIGHT "(c) Now, My Company" # Default "© now, My Company" +### +## !define PRODUCT_EXECUTABLE "Application.exe" # Default "${INFO_PROJECTNAME}.exe" +## !define UNINST_KEY_NAME "UninstKeyInRegistry" # Default "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}" +#### +## !define REQUEST_EXECUTION_LEVEL "admin" # Default "admin" see also https://nsis.sourceforge.io/Docs/Chapter4.html +#### +## Include the wails tools +#### +!include "wails_tools.nsh" + +# The version information for this two must consist of 4 parts +VIProductVersion "${INFO_PRODUCTVERSION}.0" +VIFileVersion "${INFO_PRODUCTVERSION}.0" + +VIAddVersionKey "CompanyName" "${INFO_COMPANYNAME}" +VIAddVersionKey "FileDescription" "${INFO_PRODUCTNAME} Installer" +VIAddVersionKey "ProductVersion" "${INFO_PRODUCTVERSION}" +VIAddVersionKey "FileVersion" "${INFO_PRODUCTVERSION}" +VIAddVersionKey "LegalCopyright" "${INFO_COPYRIGHT}" +VIAddVersionKey "ProductName" "${INFO_PRODUCTNAME}" + +# Enable HiDPI support. https://nsis.sourceforge.io/Reference/ManifestDPIAware +ManifestDPIAware true + +!include "MUI.nsh" + +!define MUI_ICON "..\icon.ico" +!define MUI_UNICON "..\icon.ico" +# !define MUI_WELCOMEFINISHPAGE_BITMAP "resources\leftimage.bmp" #Include this to add a bitmap on the left side of the Welcome Page. Must be a size of 164x314 +!define MUI_FINISHPAGE_NOAUTOCLOSE # Wait on the INSTFILES page so the user can take a look into the details of the installation steps +!define MUI_ABORTWARNING # This will warn the user if they exit from the installer. + +!insertmacro MUI_PAGE_WELCOME # Welcome to the installer page. +# !insertmacro MUI_PAGE_LICENSE "resources\eula.txt" # Adds a EULA page to the installer +!insertmacro MUI_PAGE_DIRECTORY # In which folder install page. +!insertmacro MUI_PAGE_INSTFILES # Installing page. +!insertmacro MUI_PAGE_FINISH # Finished installation page. + +!insertmacro MUI_UNPAGE_INSTFILES # Uninstalling page + +!insertmacro MUI_LANGUAGE "English" # Set the Language of the installer + +## The following two statements can be used to sign the installer and the uninstaller. The path to the binaries are provided in %1 +#!uninstfinalize 'signtool --file "%1"' +#!finalize 'signtool --file "%1"' + +Name "${INFO_PRODUCTNAME}" +OutFile "..\..\..\bin\${INFO_PROJECTNAME}-${ARCH}-installer.exe" # Name of the installer's file. +InstallDir "$PROGRAMFILES64\${INFO_COMPANYNAME}\${INFO_PRODUCTNAME}" # Default installing folder ($PROGRAMFILES is Program Files folder). +ShowInstDetails show # This will always show the installation details. + +Function .onInit + !insertmacro wails.checkArchitecture +FunctionEnd + +Section + !insertmacro wails.setShellContext + + !insertmacro wails.webview2runtime + + SetOutPath $INSTDIR + + !insertmacro wails.files + + CreateShortcut "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" + CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}" + + !insertmacro wails.associateFiles + + !insertmacro wails.writeUninstaller +SectionEnd + +Section "uninstall" + !insertmacro wails.setShellContext + + RMDir /r "$AppData\${PRODUCT_EXECUTABLE}" # Remove the WebView2 DataPath + + RMDir /r $INSTDIR + + Delete "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" + Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk" + + !insertmacro wails.unassociateFiles + + !insertmacro wails.deleteUninstaller +SectionEnd diff --git a/v3/examples/custom-protocol-example/build/windows/nsis/wails_tools.nsh b/v3/examples/custom-protocol-example/build/windows/nsis/wails_tools.nsh new file mode 100644 index 000000000..607fc4e85 --- /dev/null +++ b/v3/examples/custom-protocol-example/build/windows/nsis/wails_tools.nsh @@ -0,0 +1,212 @@ +# DO NOT EDIT - Generated automatically by `wails build` + +!include "x64.nsh" +!include "WinVer.nsh" +!include "FileFunc.nsh" + +!ifndef INFO_PROJECTNAME + !define INFO_PROJECTNAME "custom-protocol-example" +!endif +!ifndef INFO_COMPANYNAME + !define INFO_COMPANYNAME "My Company" +!endif +!ifndef INFO_PRODUCTNAME + !define INFO_PRODUCTNAME "My Product" +!endif +!ifndef INFO_PRODUCTVERSION + !define INFO_PRODUCTVERSION "0.0.1" +!endif +!ifndef INFO_COPYRIGHT + !define INFO_COPYRIGHT "(c) 2025, My Company" +!endif +!ifndef PRODUCT_EXECUTABLE + !define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe" +!endif +!ifndef UNINST_KEY_NAME + !define UNINST_KEY_NAME "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}" +!endif +!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINST_KEY_NAME}" + +!ifndef REQUEST_EXECUTION_LEVEL + !define REQUEST_EXECUTION_LEVEL "admin" +!endif + +RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}" + +!ifdef ARG_WAILS_AMD64_BINARY + !define SUPPORTS_AMD64 +!endif + +!ifdef ARG_WAILS_ARM64_BINARY + !define SUPPORTS_ARM64 +!endif + +!ifdef SUPPORTS_AMD64 + !ifdef SUPPORTS_ARM64 + !define ARCH "amd64_arm64" + !else + !define ARCH "amd64" + !endif +!else + !ifdef SUPPORTS_ARM64 + !define ARCH "arm64" + !else + !error "Wails: Undefined ARCH, please provide at least one of ARG_WAILS_AMD64_BINARY or ARG_WAILS_ARM64_BINARY" + !endif +!endif + +!macro wails.checkArchitecture + !ifndef WAILS_WIN10_REQUIRED + !define WAILS_WIN10_REQUIRED "This product is only supported on Windows 10 (Server 2016) and later." + !endif + + !ifndef WAILS_ARCHITECTURE_NOT_SUPPORTED + !define WAILS_ARCHITECTURE_NOT_SUPPORTED "This product can't be installed on the current Windows architecture. Supports: ${ARCH}" + !endif + + ${If} ${AtLeastWin10} + !ifdef SUPPORTS_AMD64 + ${if} ${IsNativeAMD64} + Goto ok + ${EndIf} + !endif + + !ifdef SUPPORTS_ARM64 + ${if} ${IsNativeARM64} + Goto ok + ${EndIf} + !endif + + IfSilent silentArch notSilentArch + silentArch: + SetErrorLevel 65 + Abort + notSilentArch: + MessageBox MB_OK "${WAILS_ARCHITECTURE_NOT_SUPPORTED}" + Quit + ${else} + IfSilent silentWin notSilentWin + silentWin: + SetErrorLevel 64 + Abort + notSilentWin: + MessageBox MB_OK "${WAILS_WIN10_REQUIRED}" + Quit + ${EndIf} + + ok: +!macroend + +!macro wails.files + !ifdef SUPPORTS_AMD64 + ${if} ${IsNativeAMD64} + File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_AMD64_BINARY}" + ${EndIf} + !endif + + !ifdef SUPPORTS_ARM64 + ${if} ${IsNativeARM64} + File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_ARM64_BINARY}" + ${EndIf} + !endif +!macroend + +!macro wails.writeUninstaller + WriteUninstaller "$INSTDIR\uninstall.exe" + + SetRegView 64 + WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}" + WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}" + WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}" + WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}" + WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\"" + WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S" + + ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 + IntFmt $0 "0x%08X" $0 + WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0" +!macroend + +!macro wails.deleteUninstaller + Delete "$INSTDIR\uninstall.exe" + + SetRegView 64 + DeleteRegKey HKLM "${UNINST_KEY}" +!macroend + +!macro wails.setShellContext + ${If} ${REQUEST_EXECUTION_LEVEL} == "admin" + SetShellVarContext all + ${else} + SetShellVarContext current + ${EndIf} +!macroend + +# Install webview2 by launching the bootstrapper +# See https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#online-only-deployment +!macro wails.webview2runtime + !ifndef WAILS_INSTALL_WEBVIEW_DETAILPRINT + !define WAILS_INSTALL_WEBVIEW_DETAILPRINT "Installing: WebView2 Runtime" + !endif + + SetRegView 64 + # If the admin key exists and is not empty then webview2 is already installed + ReadRegStr $0 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" + ${If} $0 != "" + Goto ok + ${EndIf} + + ${If} ${REQUEST_EXECUTION_LEVEL} == "user" + # If the installer is run in user level, check the user specific key exists and is not empty then webview2 is already installed + ReadRegStr $0 HKCU "Software\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv" + ${If} $0 != "" + Goto ok + ${EndIf} + ${EndIf} + + SetDetailsPrint both + DetailPrint "${WAILS_INSTALL_WEBVIEW_DETAILPRINT}" + SetDetailsPrint listonly + + InitPluginsDir + CreateDirectory "$pluginsdir\webview2bootstrapper" + SetOutPath "$pluginsdir\webview2bootstrapper" + File "MicrosoftEdgeWebview2Setup.exe" + ExecWait '"$pluginsdir\webview2bootstrapper\MicrosoftEdgeWebview2Setup.exe" /silent /install' + + SetDetailsPrint both + ok: +!macroend + +# Copy of APP_ASSOCIATE and APP_UNASSOCIATE macros from here https://gist.github.com/nikku/281d0ef126dbc215dd58bfd5b3a5cd5b +!macro APP_ASSOCIATE EXT FILECLASS DESCRIPTION ICON COMMANDTEXT COMMAND + ; Backup the previously associated file class + ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" "" + WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "${FILECLASS}_backup" "$R0" + + WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "${FILECLASS}" + + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}" "" `${DESCRIPTION}` + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\DefaultIcon" "" `${ICON}` + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell" "" "open" + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open" "" `${COMMANDTEXT}` + WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open\command" "" `${COMMAND}` +!macroend + +!macro APP_UNASSOCIATE EXT FILECLASS + ; Backup the previously associated file class + ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" `${FILECLASS}_backup` + WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "$R0" + + DeleteRegKey SHELL_CONTEXT `Software\Classes\${FILECLASS}` +!macroend + +!macro wails.associateFiles + ; Create file associations + +!macroend + +!macro wails.unassociateFiles + ; Delete app associations + +!macroend \ No newline at end of file diff --git a/v3/examples/custom-protocol-example/build/windows/wails.exe.manifest b/v3/examples/custom-protocol-example/build/windows/wails.exe.manifest new file mode 100644 index 000000000..21af92674 --- /dev/null +++ b/v3/examples/custom-protocol-example/build/windows/wails.exe.manifest @@ -0,0 +1,15 @@ + + + + + + + + + + + true/pm + permonitorv2,permonitor + + + \ No newline at end of file diff --git a/v3/examples/custom-protocol-example/frontend/.gitignore b/v3/examples/custom-protocol-example/frontend/.gitignore new file mode 100644 index 000000000..a547bf36d --- /dev/null +++ b/v3/examples/custom-protocol-example/frontend/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/v3/examples/custom-protocol-example/frontend/bindings/github.com/wailsapp/wails/v3/examples/custom-protocol-example/greetservice.js b/v3/examples/custom-protocol-example/frontend/bindings/github.com/wailsapp/wails/v3/examples/custom-protocol-example/greetservice.js new file mode 100644 index 000000000..0b93e6d75 --- /dev/null +++ b/v3/examples/custom-protocol-example/frontend/bindings/github.com/wailsapp/wails/v3/examples/custom-protocol-example/greetservice.js @@ -0,0 +1,15 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore: Unused imports +import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime"; + +/** + * @param {string} name + * @returns {$CancellablePromise} + */ +export function Greet(name) { + return $Call.ByID(1411160069, name); +} diff --git a/v3/examples/custom-protocol-example/frontend/bindings/github.com/wailsapp/wails/v3/examples/custom-protocol-example/index.js b/v3/examples/custom-protocol-example/frontend/bindings/github.com/wailsapp/wails/v3/examples/custom-protocol-example/index.js new file mode 100644 index 000000000..fdf1ff435 --- /dev/null +++ b/v3/examples/custom-protocol-example/frontend/bindings/github.com/wailsapp/wails/v3/examples/custom-protocol-example/index.js @@ -0,0 +1,8 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +import * as GreetService from "./greetservice.js"; +export { + GreetService +}; diff --git a/v3/examples/custom-protocol-example/frontend/dist/assets/index-BS9x21Y4.js b/v3/examples/custom-protocol-example/frontend/dist/assets/index-BS9x21Y4.js new file mode 100644 index 000000000..4f1023c59 --- /dev/null +++ b/v3/examples/custom-protocol-example/frontend/dist/assets/index-BS9x21Y4.js @@ -0,0 +1,24 @@ +(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))o(i);new MutationObserver(i=>{for(const r of i)if(r.type==="childList")for(const s of r.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&o(s)}).observe(document,{childList:!0,subtree:!0});function n(i){const r={};return i.integrity&&(r.integrity=i.integrity),i.referrerPolicy&&(r.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?r.credentials="include":i.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function o(i){if(i.ep)return;i.ep=!0;const r=n(i);fetch(i.href,r)}})();const S="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";function R(e=21){let t="",n=e|0;for(;n--;)t+=S[Math.random()*64|0];return t}const U=window.location.origin+"/wails/runtime",_=Object.freeze({Call:0,Clipboard:1,Application:2,Events:3,ContextMenu:4,Dialog:5,Window:6,Screens:7,System:8,Browser:9,CancelCall:10});let T=R();function k(e,t=""){return function(n,o=null){return I(e,n,t,o)}}async function I(e,t,n,o){var i,r;let s=new URL(U);s.searchParams.append("object",e.toString()),s.searchParams.append("method",t.toString()),o&&s.searchParams.append("args",JSON.stringify(o));let c={"x-wails-client-id":T};n&&(c["x-wails-window-name"]=n);let a=await fetch(s,{headers:c});if(!a.ok)throw new Error(await a.text());return((r=(i=a.headers.get("Content-Type"))===null||i===void 0?void 0:i.indexOf("application/json"))!==null&&r!==void 0?r:-1)!==-1?a.json():a.text()}k(_.System);const z=function(){var e,t,n,o,i;try{if(!((t=(e=window.chrome)===null||e===void 0?void 0:e.webview)===null||t===void 0)&&t.postMessage)return window.chrome.webview.postMessage.bind(window.chrome.webview);if(!((i=(o=(n=window.webkit)===null||n===void 0?void 0:n.messageHandlers)===null||o===void 0?void 0:o.external)===null||i===void 0)&&i.postMessage)return window.webkit.messageHandlers.external.postMessage.bind(window.webkit.messageHandlers.external)}catch{}return console.warn(` +%c⚠️ Browser Environment Detected %c + +%cOnly UI previews are available in the browser. For full functionality, please run the application in desktop mode. +More information at: https://v3.wails.io/learn/build/#using-a-browser-for-development +`,"background: #ffffff; color: #000000; font-weight: bold; padding: 4px 8px; border-radius: 4px; border: 2px solid #000000;","background: transparent;","color: #ffffff; font-style: italic; font-weight: bold;"),null}();function h(e){z==null||z(e)}function H(){return window._wails.environment.OS==="windows"}function W(){return!!window._wails.environment.Debug}function B(){return new MouseEvent("mousedown").buttons===0}function P(e){var t;return e.target instanceof HTMLElement?e.target:!(e.target instanceof HTMLElement)&&e.target instanceof Node&&(t=e.target.parentElement)!==null&&t!==void 0?t:document.body}document.addEventListener("DOMContentLoaded",()=>{});window.addEventListener("contextmenu",X);const N=k(_.ContextMenu),j=0;function F(e,t,n,o){N(j,{id:e,x:t,y:n,data:o})}function X(e){const t=P(e),n=window.getComputedStyle(t).getPropertyValue("--custom-contextmenu").trim();if(n){e.preventDefault();const o=window.getComputedStyle(t).getPropertyValue("--custom-contextmenu-data");F(n,e.clientX,e.clientY,o)}else Y(e,t)}function Y(e,t){if(W())return;switch(window.getComputedStyle(t).getPropertyValue("--default-contextmenu").trim()){case"show":return;case"hide":e.preventDefault();return}if(t.isContentEditable)return;const n=window.getSelection(),o=n&&n.toString().length>0;if(o)for(let i=0;i{M=e,M||(w=p=!1,l())};window.addEventListener("mousedown",D,{capture:!0});window.addEventListener("mousemove",D,{capture:!0});window.addEventListener("mouseup",D,{capture:!0});for(const e of["click","contextmenu","dblclick"])window.addEventListener(e,A,{capture:!0});function A(e){(g||p)&&(e.stopImmediatePropagation(),e.stopPropagation(),e.preventDefault())}const C=0,V=1,L=2;function D(e){let t,n=e.buttons;switch(e.type){case"mousedown":t=C,E||(n=f|1<n!==e),t.length===0?d.delete(e.eventName):d.set(e.eventName,t))}window._wails=window._wails||{};window._wails.dispatchWailsEvent=ee;k(_.Events);class ${constructor(t,n=null){this.name=t,this.data=n}}function ee(e){let t=d.get(e.name);if(!t)return;let n=new $(e.name,e.data);"sender"in e&&(n.sender=e.sender),t=t.filter(o=>!o.dispatch(n)),t.length===0?d.delete(e.name):d.set(e.name,t)}function te(e,t,n){let o=d.get(e)||[];const i=new Q(e,t,n);return o.push(i),d.set(e,o),()=>Z(i)}function ne(e,t){return te(e,t,-1)}window._wails=window._wails||{};window._wails.invoke=h;h("wails:runtime:ready");document.addEventListener("DOMContentLoaded",()=>{const e=document.getElementById("app");e?e.innerHTML=` +
+

Custom Protocol / Deep Link Test

+

+ This page demonstrates handling custom URL schemes (deep links). +

+

+ Example Link: + Try opening this URL (e.g., by pasting it into your browser's address bar or using open your-app-scheme://... in terminal): +
+ wailsexample://test/path?value=123&message=hello +

+ +
+ Received URL: +
Waiting for application to be opened via a custom URL...
+
+
+ `:console.error('Element with ID "app" not found.')});ne("frontend:ShowURL",e=>{console.log("frontend:ShowURL event received, data:",e),displayUrl(e.data)});window.displayUrl=function(e){const t=document.getElementById("received-url");t?t.textContent=e||"No URL received or an error occurred.":console.error("Element with ID 'received-url' not found in displayUrl.")}; diff --git a/v3/examples/custom-protocol-example/frontend/dist/assets/index-uDrhEpT0.css b/v3/examples/custom-protocol-example/frontend/dist/assets/index-uDrhEpT0.css new file mode 100644 index 000000000..37a5c205c --- /dev/null +++ b/v3/examples/custom-protocol-example/frontend/dist/assets/index-uDrhEpT0.css @@ -0,0 +1 @@ +:root{font-family:system-ui,Avenir,Helvetica,Arial,sans-serif;line-height:1.5;font-weight:400;color-scheme:light dark;color:#ffffffde;background-color:#242424;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}a{font-weight:500;color:#646cff;text-decoration:inherit}a:hover{color:#535bf2}body{font-family:system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif;margin:0;background-color:#f7f7f7;color:#333;display:flex;justify-content:center;align-items:center;min-height:100vh;padding:20px;box-sizing:border-box}h1{color:#0056b3;font-size:1.8em;margin-bottom:.8em}#app{width:100%;max-width:600px;margin:auto}.container{background-color:#fff;padding:25px 30px;border-radius:8px;box-shadow:0 2px 10px #0000001a;text-align:left}p{line-height:1.6;font-size:1em;margin-bottom:1em}a{color:#007bff;text-decoration:none}a:hover{text-decoration:underline}.url-display{margin-top:25px;padding:15px;background-color:#e9ecef;border:1px solid #ced4da;border-radius:4px;font-family:Courier New,Courier,monospace;font-size:.95em;word-break:break-all}.label{font-weight:700;display:block;margin-bottom:8px;color:#495057}.logo{height:6em;padding:1.5em;will-change:filter;transition:filter .3s}.logo:hover{filter:drop-shadow(0 0 2em #646cffaa)}.logo.vanilla:hover{filter:drop-shadow(0 0 2em #f7df1eaa)}.card{padding:2em}.read-the-docs{color:#888}button{border-radius:8px;border:1px solid transparent;padding:.6em 1.2em;font-size:1em;font-weight:500;font-family:inherit;background-color:#1a1a1a;cursor:pointer;transition:border-color .25s}button:hover{border-color:#646cff}button:focus,button:focus-visible{outline:4px auto -webkit-focus-ring-color}@media (prefers-color-scheme: light){:root{color:#213547;background-color:#fff}a:hover{color:#747bff}button{background-color:#f9f9f9}} diff --git a/v3/examples/custom-protocol-example/frontend/dist/index.html b/v3/examples/custom-protocol-example/frontend/dist/index.html new file mode 100644 index 000000000..126962c69 --- /dev/null +++ b/v3/examples/custom-protocol-example/frontend/dist/index.html @@ -0,0 +1,14 @@ + + + + + + + Vite App + + + + +
+ + diff --git a/v3/examples/custom-protocol-example/frontend/dist/vite.svg b/v3/examples/custom-protocol-example/frontend/dist/vite.svg new file mode 100644 index 000000000..e7b8dfb1b --- /dev/null +++ b/v3/examples/custom-protocol-example/frontend/dist/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/v3/examples/custom-protocol-example/frontend/index.html b/v3/examples/custom-protocol-example/frontend/index.html new file mode 100644 index 000000000..72ba3a8b3 --- /dev/null +++ b/v3/examples/custom-protocol-example/frontend/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/v3/examples/custom-protocol-example/frontend/package-lock.json b/v3/examples/custom-protocol-example/frontend/package-lock.json new file mode 100644 index 000000000..2b2b28cc5 --- /dev/null +++ b/v3/examples/custom-protocol-example/frontend/package-lock.json @@ -0,0 +1,1017 @@ +{ + "name": "frontend", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "0.0.0", + "dependencies": { + "@wailsio/runtime": "^3.0.0-alpha.66" + }, + "devDependencies": { + "vite": "^6.3.5" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", + "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz", + "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", + "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz", + "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", + "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", + "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", + "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", + "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", + "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", + "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", + "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", + "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", + "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", + "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", + "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", + "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", + "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", + "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", + "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", + "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", + "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", + "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", + "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", + "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", + "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.0.tgz", + "integrity": "sha512-KxN+zCjOYHGwCl4UCtSfZ6jrq/qi88JDUtiEFk8LELEHq2Egfc/FgW+jItZiOLRuQfb/3xJSgFuNPC9jzggX+A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.0.tgz", + "integrity": "sha512-yDvqx3lWlcugozax3DItKJI5j05B0d4Kvnjx+5mwiUpWramVvmAByYigMplaoAQ3pvdprGCTCE03eduqE/8mPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.0.tgz", + "integrity": "sha512-2KOU574vD3gzcPSjxO0eyR5iWlnxxtmW1F5CkNOHmMlueKNCQkxR6+ekgWyVnz6zaZihpUNkGxjsYrkTJKhkaw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.0.tgz", + "integrity": "sha512-gE5ACNSxHcEZyP2BA9TuTakfZvULEW4YAOtxl/A/YDbIir/wPKukde0BNPlnBiP88ecaN4BJI2TtAd+HKuZPQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.0.tgz", + "integrity": "sha512-GSxU6r5HnWij7FoSo7cZg3l5GPg4HFLkzsFFh0N/b16q5buW1NAWuCJ+HMtIdUEi6XF0qH+hN0TEd78laRp7Dg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.0.tgz", + "integrity": "sha512-KGiGKGDg8qLRyOWmk6IeiHJzsN/OYxO6nSbT0Vj4MwjS2XQy/5emsmtoqLAabqrohbgLWJ5GV3s/ljdrIr8Qjg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.0.tgz", + "integrity": "sha512-46OzWeqEVQyX3N2/QdiU/CMXYDH/lSHpgfBkuhl3igpZiaB3ZIfSjKuOnybFVBQzjsLwkus2mjaESy8H41SzvA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.0.tgz", + "integrity": "sha512-lfgW3KtQP4YauqdPpcUZHPcqQXmTmH4nYU0cplNeW583CMkAGjtImw4PKli09NFi2iQgChk4e9erkwlfYem6Lg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.0.tgz", + "integrity": "sha512-nn8mEyzMbdEJzT7cwxgObuwviMx6kPRxzYiOl6o/o+ChQq23gfdlZcUNnt89lPhhz3BYsZ72rp0rxNqBSfqlqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.0.tgz", + "integrity": "sha512-l+QK99je2zUKGd31Gh+45c4pGDAqZSuWQiuRFCdHYC2CSiO47qUWsCcenrI6p22hvHZrDje9QjwSMAFL3iwXwQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.0.tgz", + "integrity": "sha512-WbnJaxPv1gPIm6S8O/Wg+wfE/OzGSXlBMbOe4ie+zMyykMOeqmgD1BhPxZQuDqwUN+0T/xOFtL2RUWBspnZj3w==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.0.tgz", + "integrity": "sha512-eRDWR5t67/b2g8Q/S8XPi0YdbKcCs4WQ8vklNnUYLaSWF+Cbv2axZsp4jni6/j7eKvMLYCYdcsv8dcU+a6QNFg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.0.tgz", + "integrity": "sha512-TWrZb6GF5jsEKG7T1IHwlLMDRy2f3DPqYldmIhnA2DVqvvhY2Ai184vZGgahRrg8k9UBWoSlHv+suRfTN7Ua4A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.0.tgz", + "integrity": "sha512-ieQljaZKuJpmWvd8gW87ZmSFwid6AxMDk5bhONJ57U8zT77zpZ/TPKkU9HpnnFrM4zsgr4kiGuzbIbZTGi7u9A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.0.tgz", + "integrity": "sha512-/L3pW48SxrWAlVsKCN0dGLB2bi8Nv8pr5S5ocSM+S0XCn5RCVCXqi8GVtHFsOBBCSeR+u9brV2zno5+mg3S4Aw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.0.tgz", + "integrity": "sha512-XMLeKjyH8NsEDCRptf6LO8lJk23o9wvB+dJwcXMaH6ZQbbkHu2dbGIUindbMtRN6ux1xKi16iXWu6q9mu7gDhQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.0.tgz", + "integrity": "sha512-m/P7LycHZTvSQeXhFmgmdqEiTqSV80zn6xHaQ1JSqwCtD1YGtwEK515Qmy9DcB2HK4dOUVypQxvhVSy06cJPEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.0.tgz", + "integrity": "sha512-4yodtcOrFHpbomJGVEqZ8fzD4kfBeCbpsUy5Pqk4RluXOdsWdjLnjhiKy2w3qzcASWd04fp52Xz7JKarVJ5BTg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.0.tgz", + "integrity": "sha512-tmazCrAsKzdkXssEc65zIE1oC6xPHwfy9d5Ta25SRCDOZS+I6RypVVShWALNuU9bxIfGA0aqrmzlzoM5wO5SPQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.0.tgz", + "integrity": "sha512-h1J+Yzjo/X+0EAvR2kIXJDuTuyT7drc+t2ALY0nIcGPbTatNOf0VWdhEA2Z4AAjv6X1NJV7SYo5oCTYRJhSlVA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@wailsio/runtime": { + "version": "3.0.0-alpha.66", + "resolved": "https://registry.npmjs.org/@wailsio/runtime/-/runtime-3.0.0-alpha.66.tgz", + "integrity": "sha512-ENLu8rn1griL1gFHJqkq1i+BVxrrA0JPJHYneUJYuf/s54kjuQViW0RKDEe/WTDo56ABpfykrd/T8OYpPUyXUw==", + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", + "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.4", + "@esbuild/android-arm": "0.25.4", + "@esbuild/android-arm64": "0.25.4", + "@esbuild/android-x64": "0.25.4", + "@esbuild/darwin-arm64": "0.25.4", + "@esbuild/darwin-x64": "0.25.4", + "@esbuild/freebsd-arm64": "0.25.4", + "@esbuild/freebsd-x64": "0.25.4", + "@esbuild/linux-arm": "0.25.4", + "@esbuild/linux-arm64": "0.25.4", + "@esbuild/linux-ia32": "0.25.4", + "@esbuild/linux-loong64": "0.25.4", + "@esbuild/linux-mips64el": "0.25.4", + "@esbuild/linux-ppc64": "0.25.4", + "@esbuild/linux-riscv64": "0.25.4", + "@esbuild/linux-s390x": "0.25.4", + "@esbuild/linux-x64": "0.25.4", + "@esbuild/netbsd-arm64": "0.25.4", + "@esbuild/netbsd-x64": "0.25.4", + "@esbuild/openbsd-arm64": "0.25.4", + "@esbuild/openbsd-x64": "0.25.4", + "@esbuild/sunos-x64": "0.25.4", + "@esbuild/win32-arm64": "0.25.4", + "@esbuild/win32-ia32": "0.25.4", + "@esbuild/win32-x64": "0.25.4" + } + }, + "node_modules/fdir": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.0.tgz", + "integrity": "sha512-HqMFpUbWlf/tvcxBFNKnJyzc7Lk+XO3FGc3pbNBLqEbOz0gPLRgcrlS3UF4MfUrVlstOaP/q0kM6GVvi+LrLRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.7" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.41.0", + "@rollup/rollup-android-arm64": "4.41.0", + "@rollup/rollup-darwin-arm64": "4.41.0", + "@rollup/rollup-darwin-x64": "4.41.0", + "@rollup/rollup-freebsd-arm64": "4.41.0", + "@rollup/rollup-freebsd-x64": "4.41.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.41.0", + "@rollup/rollup-linux-arm-musleabihf": "4.41.0", + "@rollup/rollup-linux-arm64-gnu": "4.41.0", + "@rollup/rollup-linux-arm64-musl": "4.41.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.41.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.41.0", + "@rollup/rollup-linux-riscv64-gnu": "4.41.0", + "@rollup/rollup-linux-riscv64-musl": "4.41.0", + "@rollup/rollup-linux-s390x-gnu": "4.41.0", + "@rollup/rollup-linux-x64-gnu": "4.41.0", + "@rollup/rollup-linux-x64-musl": "4.41.0", + "@rollup/rollup-win32-arm64-msvc": "4.41.0", + "@rollup/rollup-win32-ia32-msvc": "4.41.0", + "@rollup/rollup-win32-x64-msvc": "4.41.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", + "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/vite": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + } + } +} diff --git a/v3/examples/custom-protocol-example/frontend/package.json b/v3/examples/custom-protocol-example/frontend/package.json new file mode 100644 index 000000000..64d7435a8 --- /dev/null +++ b/v3/examples/custom-protocol-example/frontend/package.json @@ -0,0 +1,17 @@ +{ + "name": "frontend", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "devDependencies": { + "vite": "^6.3.5" + }, + "dependencies": { + "@wailsio/runtime": "^3.0.0-alpha.66" + } +} diff --git a/v3/examples/custom-protocol-example/frontend/public/vite.svg b/v3/examples/custom-protocol-example/frontend/public/vite.svg new file mode 100644 index 000000000..e7b8dfb1b --- /dev/null +++ b/v3/examples/custom-protocol-example/frontend/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/v3/examples/custom-protocol-example/frontend/src/counter.js b/v3/examples/custom-protocol-example/frontend/src/counter.js new file mode 100644 index 000000000..881e2d7ad --- /dev/null +++ b/v3/examples/custom-protocol-example/frontend/src/counter.js @@ -0,0 +1,9 @@ +export function setupCounter(element) { + let counter = 0 + const setCounter = (count) => { + counter = count + element.innerHTML = `count is ${counter}` + } + element.addEventListener('click', () => setCounter(counter + 1)) + setCounter(0) +} diff --git a/v3/examples/custom-protocol-example/frontend/src/javascript.svg b/v3/examples/custom-protocol-example/frontend/src/javascript.svg new file mode 100644 index 000000000..f9abb2b72 --- /dev/null +++ b/v3/examples/custom-protocol-example/frontend/src/javascript.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/v3/examples/custom-protocol-example/frontend/src/main.js b/v3/examples/custom-protocol-example/frontend/src/main.js new file mode 100644 index 000000000..fd11d82fa --- /dev/null +++ b/v3/examples/custom-protocol-example/frontend/src/main.js @@ -0,0 +1,45 @@ +import './style.css' +import { Events } from '@wailsio/runtime' + +document.addEventListener('DOMContentLoaded', () => { + const appDiv = document.getElementById('app'); + if (appDiv) { + appDiv.innerHTML = ` +
+

Custom Protocol / Deep Link Test

+

+ This page demonstrates handling custom URL schemes (deep links). +

+

+ Example Link: + Try opening this URL (e.g., by pasting it into your browser's address bar or using open your-app-scheme://... in terminal): +
+ wailsexample://test/path?value=123&message=hello +

+ +
+ Received URL: +
Waiting for application to be opened via a custom URL...
+
+
+ `; + } else { + console.error('Element with ID "app" not found.'); + } +}); + +// Listen for the event from Go +Events.On('frontend:ShowURL', (e) => { + console.log('frontend:ShowURL event received, data:', e); + displayUrl(e.data); +}); + +// Make displayUrl available globally just in case, though direct call from event is better +window.displayUrl = function(url) { + const urlElement = document.getElementById('received-url'); + if (urlElement) { + urlElement.textContent = url || "No URL received or an error occurred."; + } else { + console.error("Element with ID 'received-url' not found in displayUrl."); + } +} diff --git a/v3/examples/custom-protocol-example/frontend/src/style.css b/v3/examples/custom-protocol-example/frontend/src/style.css new file mode 100644 index 000000000..0fb047c33 --- /dev/null +++ b/v3/examples/custom-protocol-example/frontend/src/style.css @@ -0,0 +1,142 @@ +:root { + font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; + margin: 0; /* Reset default margin */ + background-color: #f7f7f7; + color: #333; + display: flex; /* Use flexbox to center content */ + justify-content: center; /* Center horizontally */ + align-items: center; /* Center vertically */ + min-height: 100vh; /* Full viewport height */ + padding: 20px; /* Add some padding around the content */ + box-sizing: border-box; /* Ensure padding doesn't expand body beyond viewport */ +} + +h1 { + color: #0056b3; + font-size: 1.8em; + margin-bottom: 0.8em; +} + +#app { + width: 100%; + max-width: 600px; + margin: auto; /* This also helps in centering if body flex isn't enough or overridden */ +} + +.container { + background-color: #fff; + padding: 25px 30px; + border-radius: 8px; + box-shadow: 0 2px 10px rgba(0,0,0,0.1); + text-align: left; +} + +p { + line-height: 1.6; + font-size: 1em; + margin-bottom: 1em; +} + +a { + color: #007bff; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +.url-display { + margin-top: 25px; + padding: 15px; + background-color: #e9ecef; + border: 1px solid #ced4da; + border-radius: 4px; + font-family: 'Courier New', Courier, monospace; + font-size: 0.95em; + word-break: break-all; +} + +.label { + font-weight: bold; + display: block; + margin-bottom: 8px; + color: #495057; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: filter 300ms; +} +.logo:hover { + filter: drop-shadow(0 0 2em #646cffaa); +} +.logo.vanilla:hover { + filter: drop-shadow(0 0 2em #f7df1eaa); +} + +.card { + padding: 2em; +} + +.read-the-docs { + color: #888; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/v3/examples/custom-protocol-example/greetservice.go b/v3/examples/custom-protocol-example/greetservice.go new file mode 100644 index 000000000..8972c39cd --- /dev/null +++ b/v3/examples/custom-protocol-example/greetservice.go @@ -0,0 +1,7 @@ +package main + +type GreetService struct{} + +func (g *GreetService) Greet(name string) string { + return "Hello " + name + "!" +} diff --git a/v3/examples/custom-protocol-example/main.go b/v3/examples/custom-protocol-example/main.go new file mode 100644 index 000000000..f5c5db38b --- /dev/null +++ b/v3/examples/custom-protocol-example/main.go @@ -0,0 +1,82 @@ +package main + +import ( + "embed" + _ "embed" + "log" + "time" + + "github.com/wailsapp/wails/v3/pkg/application" + "github.com/wailsapp/wails/v3/pkg/events" +) + +// Wails uses Go's `embed` package to embed the frontend files into the binary. +// Any files in the frontend/dist folder will be embedded into the binary and +// made available to the frontend. +// See https://pkg.go.dev/embed for more information. + +//go:embed all:frontend/dist +var assets embed.FS + +// main function serves as the application's entry point. It initializes the application, creates a window, +// and starts a goroutine that emits a time-based event every second. It subsequently runs the application and +// logs any error that might occur. +func main() { + // Create a new Wails application by providing the necessary options. + // Variables 'Name' and 'Description' are for application metadata. + // 'Assets' configures the asset server with the 'FS' variable pointing to the frontend files. + // 'Bind' is a list of Go struct instances. The frontend has access to the methods of these instances. + // 'Mac' options tailor the application when running an macOS. + app := application.New(application.Options{ + Name: "custom-protocol-example", + Description: "A demo of using raw HTML & CSS", + Services: []application.Service{ + application.NewService(&GreetService{}), + }, + Assets: application.AssetOptions{ + Handler: application.AssetFileServerFS(assets), + }, + Mac: application.MacOptions{ + ApplicationShouldTerminateAfterLastWindowClosed: true, + }, + }) + + // Listen for the system event indicating the app was launched with a URL + app.Event.OnApplicationEvent(events.Common.ApplicationLaunchedWithUrl, func(e *application.ApplicationEvent) { + app.Event.Emit("frontend:ShowURL", e.Context().URL()) + }) + + // Create a new window with the necessary options. + // 'Title' is the title of the window. + // 'Mac' options tailor the window when running on macOS. + // 'BackgroundColour' is the background colour of the window. + // 'URL' is the URL that will be loaded into the webview. + _ = app.Window.NewWithOptions(application.WebviewWindowOptions{ + Title: "Window 1", + Mac: application.MacWindow{ + InvisibleTitleBarHeight: 50, + Backdrop: application.MacBackdropTranslucent, + TitleBar: application.MacTitleBarHiddenInset, + }, + BackgroundColour: application.NewRGB(27, 38, 54), + URL: "/", + }) + + // Create a goroutine that emits an event containing the current time every second. + // The frontend can listen to this event and update the UI accordingly. + go func() { + for { + now := time.Now().Format(time.RFC1123) + app.Event.Emit("time", now) + time.Sleep(time.Second) + } + }() + + // Run the application. This blocks until the application has been exited. + err := app.Run() + + // If an error occurred while running the application, log it and exit. + if err != nil { + log.Fatal(err) + } +} diff --git a/v3/internal/commands/build-assets.go b/v3/internal/commands/build-assets.go index b9a6283c9..e3dbaa128 100644 --- a/v3/internal/commands/build-assets.go +++ b/v3/internal/commands/build-assets.go @@ -21,8 +21,17 @@ var buildAssets embed.FS //go:embed updatable_build_assets var updatableBuildAssets embed.FS +// ProtocolConfig defines the structure for a custom protocol in wails.json/wails.yaml +type ProtocolConfig struct { + Scheme string `yaml:"scheme" json:"scheme"` + Description string `yaml:"description,omitempty" json:"description,omitempty"` + // Future platform-specific fields can be added here if needed by templates. + // E.g., for macOS: CFBundleURLName string `yaml:"cfBundleURLName,omitempty" json:"cfBundleURLName,omitempty"` +} + +// BuildAssetsOptions defines the options for generating build assets. type BuildAssetsOptions struct { - Dir string `description:"The directory to generate the files into" default:"."` + Dir string `description:"The directory to generate the files into" default:"."` Name string `description:"The name of the project"` BinaryName string `description:"The name of the binary"` ProductName string `description:"The name of the product" default:"My Product"` @@ -42,26 +51,30 @@ type BuildAssetsOptions struct { Typescript bool `description:"Use typescript" default:"false"` } +// BuildConfig defines the configuration for generating build assets. type BuildConfig struct { BuildAssetsOptions FileAssociations []FileAssociation `yaml:"fileAssociations"` + Protocols []ProtocolConfig `yaml:"protocols,omitempty"` } +// UpdateBuildAssetsOptions defines the options for updating build assets. type UpdateBuildAssetsOptions struct { - Dir string `description:"The directory to generate the files into" default:"build"` + Dir string `description:"The directory to generate the files into" default:"build"` Name string `description:"The name of the project"` BinaryName string `description:"The name of the binary"` - ProductName string `description:"The name of the product" default:"My Product"` - ProductDescription string `description:"The description of the product" default:"My Product Description"` - ProductVersion string `description:"The version of the product" default:"0.1.0"` - ProductCompany string `description:"The company of the product" default:"My Company"` - ProductCopyright string `description:"The copyright notice" default:"\u00a9 now, My Company"` - ProductComments string `description:"Comments to add to the generated files" default:"This is a comment"` + ProductName string `description:"The name of the product" default:"My Product"` + ProductDescription string `description:"The description of the product" default:"My Product Description"` + ProductVersion string `description:"The version of the product" default:"0.1.0"` + ProductCompany string `description:"The company of the product" default:"My Company"` + ProductCopyright string `description:"The copyright notice" default:"© now, My Company"` + ProductComments string `description:"Comments to add to the generated files" default:"This is a comment"` ProductIdentifier string `description:"The product identifier, e.g com.mycompany.myproduct"` Config string `description:"The path to the config file"` Silent bool `description:"Suppress output to console"` } +// GenerateBuildAssets generates the build assets for the project. func GenerateBuildAssets(options *BuildAssetsOptions) error { DisableFooter = true @@ -144,6 +157,7 @@ func GenerateBuildAssets(options *BuildAssetsOptions) error { return nil } +// FileAssociation defines the structure for a file association. type FileAssociation struct { Ext string `yaml:"ext"` Name string `yaml:"name"` @@ -153,11 +167,14 @@ type FileAssociation struct { MimeType string `yaml:"mimeType"` } +// UpdateConfig defines the configuration for updating build assets. type UpdateConfig struct { UpdateBuildAssetsOptions FileAssociations []FileAssociation `yaml:"fileAssociations"` + Protocols []ProtocolConfig `yaml:"protocols,omitempty"` } +// WailsConfig defines the structure for a Wails configuration. type WailsConfig struct { Info struct { CompanyName string `yaml:"companyName"` @@ -168,9 +185,11 @@ type WailsConfig struct { Comments string `yaml:"comments"` Version string `yaml:"version"` } `yaml:"info"` - FileAssociations []FileAssociation `yaml:"fileAssociations"` + FileAssociations []FileAssociation `yaml:"fileAssociations,omitempty"` + Protocols []ProtocolConfig `yaml:"protocols,omitempty"` } +// UpdateBuildAssets updates the build assets for the project. func UpdateBuildAssets(options *UpdateBuildAssetsOptions) error { DisableFooter = true @@ -200,6 +219,7 @@ func UpdateBuildAssets(options *UpdateBuildAssetsOptions) error { options.ProductComments = wailsConfig.Info.Comments options.ProductVersion = wailsConfig.Info.Version config.FileAssociations = wailsConfig.FileAssociations + config.Protocols = wailsConfig.Protocols } config.UpdateBuildAssetsOptions = *options diff --git a/v3/internal/commands/build_assets/linux/nfpm/scripts/postinstall.sh b/v3/internal/commands/build_assets/linux/nfpm/scripts/postinstall.sh index a9bf588e2..4bbb815a3 100644 --- a/v3/internal/commands/build_assets/linux/nfpm/scripts/postinstall.sh +++ b/v3/internal/commands/build_assets/linux/nfpm/scripts/postinstall.sh @@ -1 +1,21 @@ -#!/bin/bash +#!/bin/sh + +# Update desktop database for .desktop file changes +# This makes the application appear in application menus and registers its capabilities. +if command -v update-desktop-database >/dev/null 2>&1; then + echo "Updating desktop database..." + update-desktop-database -q /usr/share/applications +else + echo "Warning: update-desktop-database command not found. Desktop file may not be immediately recognized." >&2 +fi + +# Update MIME database for custom URL schemes (x-scheme-handler) +# This ensures the system knows how to handle your custom protocols. +if command -v update-mime-database >/dev/null 2>&1; then + echo "Updating MIME database..." + update-mime-database -n /usr/share/mime +else + echo "Warning: update-mime-database command not found. Custom URL schemes may not be immediately recognized." >&2 +fi + +exit 0 diff --git a/v3/internal/commands/updatable_build_assets/darwin/Info.dev.plist.tmpl b/v3/internal/commands/updatable_build_assets/darwin/Info.dev.plist.tmpl index e44a679d2..b68a8f1f7 100644 --- a/v3/internal/commands/updatable_build_assets/darwin/Info.dev.plist.tmpl +++ b/v3/internal/commands/updatable_build_assets/darwin/Info.dev.plist.tmpl @@ -51,5 +51,20 @@ NSAllowsLocalNetworking + {{- if .Protocols}} + CFBundleURLTypes + + {{- range .Protocols}} + + CFBundleURLName + wails.com.{{.Scheme}} + CFBundleURLSchemes + + {{.Scheme}} + + + {{- end}} + + {{- end}} \ No newline at end of file diff --git a/v3/internal/commands/updatable_build_assets/darwin/Info.plist.tmpl b/v3/internal/commands/updatable_build_assets/darwin/Info.plist.tmpl index c20032556..2767128ff 100644 --- a/v3/internal/commands/updatable_build_assets/darwin/Info.plist.tmpl +++ b/v3/internal/commands/updatable_build_assets/darwin/Info.plist.tmpl @@ -46,5 +46,20 @@ {{- end}} {{- end}} + {{- if .Protocols}} + CFBundleURLTypes + + {{- range .Protocols}} + + CFBundleURLName + wails.com.{{.Scheme}} + CFBundleURLSchemes + + {{.Scheme}} + + + {{- end}} + + {{- end}} \ No newline at end of file diff --git a/v3/internal/commands/updatable_build_assets/linux/desktop.tmpl b/v3/internal/commands/updatable_build_assets/linux/desktop.tmpl new file mode 100644 index 000000000..06f42314f --- /dev/null +++ b/v3/internal/commands/updatable_build_assets/linux/desktop.tmpl @@ -0,0 +1,15 @@ +[Desktop Entry] +Version=1.0 +Name={{.ProductName}} +Comment={{.ProductDescription}} +# The Exec line includes %u to pass the URL to the application +Exec=/usr/local/bin/{{.BinaryName}} %u +Terminal=false +Type=Application +Icon={{.BinaryName}} +Categories=Utility; +StartupWMClass={{.BinaryName}} + +{{if .Protocols -}} +MimeType={{range $index, $protocol := .Info.Protocols}}x-scheme-handler/{{$protocol.Scheme}};{{end}} +{{- end}} diff --git a/v3/internal/commands/updatable_build_assets/linux/nfpm/nfpm.yaml.tmpl b/v3/internal/commands/updatable_build_assets/linux/nfpm/nfpm.yaml.tmpl index a1b93c5c3..f3766c761 100644 --- a/v3/internal/commands/updatable_build_assets/linux/nfpm/nfpm.yaml.tmpl +++ b/v3/internal/commands/updatable_build_assets/linux/nfpm/nfpm.yaml.tmpl @@ -49,6 +49,13 @@ overrides: - base-devel - pkgconf +# scripts section to ensure desktop database is updated after install +scripts: + postinstall: "./build/linux/nfpm/scripts/postinstall.sh" + # You can also add preremove, postremove if needed + # preremove: "./build/linux/nfpm/scripts/preremove.sh" + # postremove: "./build/linux/nfpm/scripts/postremove.sh" + # replaces: # - foobar # provides: @@ -63,9 +70,4 @@ overrides: # conflicts: # - not-foo # - not-bar -# changelog: "changelog.yaml" -# scripts: -# preinstall: ./build/linux/nfpm/scripts/preinstall.sh -# postinstall: ./build/linux/nfpm/scripts/postinstall.sh -# preremove: ./build/linux/nfpm/scripts/preremove.sh -# postremove: ./build/linux/nfpm/scripts/postremove.sh +# changelog: "changelog.yaml" \ No newline at end of file diff --git a/v3/internal/runtime/desktop/@wailsio/runtime/src/event_types.ts b/v3/internal/runtime/desktop/@wailsio/runtime/src/event_types.ts index 9e5a8f1c6..9360224da 100644 --- a/v3/internal/runtime/desktop/@wailsio/runtime/src/event_types.ts +++ b/v3/internal/runtime/desktop/@wailsio/runtime/src/event_types.ts @@ -205,6 +205,7 @@ export const Types = Object.freeze({ Common: Object.freeze({ ApplicationOpenedWithFile: "common:ApplicationOpenedWithFile", ApplicationStarted: "common:ApplicationStarted", + ApplicationLaunchedWithUrl: "common:ApplicationLaunchedWithUrl", ThemeChanged: "common:ThemeChanged", WindowClosing: "common:WindowClosing", WindowDidMove: "common:WindowDidMove", diff --git a/v3/pkg/application/application_darwin.go b/v3/pkg/application/application_darwin.go index aea15e98a..cb38f7e70 100644 --- a/v3/pkg/application/application_darwin.go +++ b/v3/pkg/application/application_darwin.go @@ -57,6 +57,8 @@ static void init(void) { NSDistributedNotificationCenter *center = [NSDistributedNotificationCenter defaultCenter]; [center addObserver:appDelegate selector:@selector(themeChanged:) name:@"AppleInterfaceThemeChangedNotification" object:nil]; + // Register the custom URL scheme handler + StartCustomProtocolHandler(); } static bool isDarkMode(void) { @@ -428,3 +430,16 @@ func HandleOpenFile(filePath *C.char) { ctx: eventContext, } } + +//export HandleCustomProtocol +func HandleCustomProtocol(urlCString *C.char) { + urlString := C.GoString(urlCString) + eventContext := newApplicationEventContext() + eventContext.setURL(urlString) + + // Emit the standard event with the URL string as data + applicationEvents <- &ApplicationEvent{ + Id: uint(events.Common.ApplicationLaunchedWithUrl), + ctx: eventContext, + } +} diff --git a/v3/pkg/application/application_darwin_delegate.h b/v3/pkg/application/application_darwin_delegate.h index 1523356b2..77c30898b 100644 --- a/v3/pkg/application/application_darwin_delegate.h +++ b/v3/pkg/application/application_darwin_delegate.h @@ -13,4 +13,13 @@ extern void HandleOpenFile(char *); -#endif +// Declarations for Apple Event based custom URL handling +extern void HandleCustomProtocol(char*); + +@interface CustomProtocolSchemeHandler : NSObject ++ (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent; +@end + +void StartCustomProtocolHandler(void); + +#endif /* appdelegate_h */ diff --git a/v3/pkg/application/application_darwin_delegate.m b/v3/pkg/application/application_darwin_delegate.m index 117968d0a..87504e62b 100644 --- a/v3/pkg/application/application_darwin_delegate.m +++ b/v3/pkg/application/application_darwin_delegate.m @@ -1,6 +1,7 @@ //go:build darwin #import "application_darwin_delegate.h" #import "../events/events_darwin.h" +#import // For Apple Event constants extern bool hasListeners(unsigned int); extern bool shouldQuitApplication(); extern void cleanup(); @@ -41,7 +42,7 @@ extern void handleSecondInstanceData(char * message); return YES; } - (BOOL)applicationShouldHandleReopen:(NSNotification *)notification - hasVisibleWindows:(BOOL)flag { + hasVisibleWindows:(BOOL)flag { // Changed from NSApplication to NSNotification if( hasListeners(EventApplicationShouldHandleReopen) ) { processApplicationEvent(EventApplicationShouldHandleReopen, @{@"hasVisibleWindows": @(flag)}); } @@ -179,3 +180,19 @@ extern void handleSecondInstanceData(char * message); // GENERATED EVENTS END @end +// Implementation for Apple Event based custom URL handling +@implementation CustomProtocolSchemeHandler ++ (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent { + NSString *urlStr = [[event paramDescriptorForKeyword:keyDirectObject] stringValue]; + if (urlStr) { + HandleCustomProtocol((char*)[urlStr UTF8String]); + } +} +@end +void StartCustomProtocolHandler(void) { + NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager]; + [appleEventManager setEventHandler:[CustomProtocolSchemeHandler class] + andSelector:@selector(handleGetURLEvent:withReplyEvent:) + forEventClass:kInternetEventClass + andEventID: kAEGetURL]; +} diff --git a/v3/pkg/application/application_linux.go b/v3/pkg/application/application_linux.go index a61088ea9..b92c2c6aa 100644 --- a/v3/pkg/application/application_linux.go +++ b/v3/pkg/application/application_linux.go @@ -16,9 +16,12 @@ import "C" import ( "fmt" "os" + "slices" "strings" "sync" + "path/filepath" + "github.com/godbus/dbus/v5" "github.com/wailsapp/wails/v3/internal/operatingsystem" "github.com/wailsapp/wails/v3/pkg/events" @@ -27,7 +30,8 @@ import ( func init() { // FIXME: This should be handled appropriately in the individual files most likely. // Set GDK_BACKEND=x11 if currently unset and XDG_SESSION_TYPE is unset, unspecified or x11 to prevent warnings - if os.Getenv("GDK_BACKEND") == "" && (os.Getenv("XDG_SESSION_TYPE") == "" || os.Getenv("XDG_SESSION_TYPE") == "unspecified" || os.Getenv("XDG_SESSION_TYPE") == "x11") { + if os.Getenv("GDK_BACKEND") == "" && + (os.Getenv("XDG_SESSION_TYPE") == "" || os.Getenv("XDG_SESSION_TYPE") == "unspecified" || os.Getenv("XDG_SESSION_TYPE") == "x11") { _ = os.Setenv("GDK_BACKEND", "x11") } } @@ -94,6 +98,39 @@ func (a *linuxApp) setApplicationMenu(menu *Menu) { func (a *linuxApp) run() error { + if len(os.Args) == 2 { // Case: program + 1 argument + arg1 := os.Args[1] + // Check if the argument is likely a URL from a custom protocol invocation + if strings.Contains(arg1, "://") { + a.parent.info("Application launched with argument, potentially a URL from custom protocol", "url", arg1) + eventContext := newApplicationEventContext() + eventContext.setURL(arg1) + applicationEvents <- &ApplicationEvent{ + Id: uint(events.Common.ApplicationLaunchedWithUrl), + ctx: eventContext, + } + } else { + // Check if the argument matches any file associations + if a.parent.options.FileAssociations != nil { + ext := filepath.Ext(arg1) + if slices.Contains(a.parent.options.FileAssociations, ext) { + a.parent.info("File opened via file association", "file", arg1, "extension", ext) + eventContext := newApplicationEventContext() + eventContext.setOpenedWithFile(arg1) + applicationEvents <- &ApplicationEvent{ + Id: uint(events.Common.ApplicationOpenedWithFile), + ctx: eventContext, + } + return nil + } + } + a.parent.info("Application launched with single argument (not a URL), potential file open?", "arg", arg1) + } + } else if len(os.Args) > 2 { + // Log if multiple arguments are passed + a.parent.info("Application launched with multiple arguments", "args", os.Args[1:]) + } + a.parent.Event.OnApplicationEvent(events.Linux.ApplicationStartup, func(evt *ApplicationEvent) { // TODO: What should happen here? }) @@ -147,7 +184,10 @@ func (a *linuxApp) monitorThemeChanges() { defer handlePanic() conn, err := dbus.ConnectSessionBus() if err != nil { - a.parent.info("[WARNING] Failed to connect to session bus; monitoring for theme changes will not function:", err) + a.parent.info( + "[WARNING] Failed to connect to session bus; monitoring for theme changes will not function:", + err, + ) return } defer conn.Close() diff --git a/v3/pkg/application/application_windows.go b/v3/pkg/application/application_windows.go index b3b2d9bdd..7caf4f5c4 100644 --- a/v3/pkg/application/application_windows.go +++ b/v3/pkg/application/application_windows.go @@ -7,6 +7,7 @@ import ( "os" "path/filepath" "slices" + "strings" "sync" "sync/atomic" "syscall" @@ -150,20 +151,35 @@ func (m *windowsApp) run() error { ctx: blankApplicationEventContext, } - // Check if there is 1 parameter passed to the application - // and if the extension matches the options.FileAssociations string - if len(os.Args) == 2 { - arg := os.Args[1] - ext := filepath.Ext(arg) - if slices.Contains(m.parent.options.FileAssociations, ext) { + if len(os.Args) == 2 { // Case: program + 1 argument + arg1 := os.Args[1] + // Check if the argument is likely a URL from a custom protocol invocation + if strings.Contains(arg1, "://") { + m.parent.info("Application launched with argument, potentially a URL from custom protocol", "url", arg1) eventContext := newApplicationEventContext() - eventContext.setOpenedWithFile(arg) - // EmitEvent application started event + eventContext.setURL(arg1) applicationEvents <- &ApplicationEvent{ - Id: uint(events.Common.ApplicationOpenedWithFile), + Id: uint(events.Common.ApplicationLaunchedWithUrl), ctx: eventContext, } + } else { + // If not a URL-like string, check for file association + if m.parent.options.FileAssociations != nil { + ext := filepath.Ext(arg1) + if slices.Contains(m.parent.options.FileAssociations, ext) { + m.parent.info("Application launched with file via file association", "file", arg1) + eventContext := newApplicationEventContext() + eventContext.setOpenedWithFile(arg1) + applicationEvents <- &ApplicationEvent{ + Id: uint(events.Common.ApplicationOpenedWithFile), + ctx: eventContext, + } + } + } } + } else if len(os.Args) > 2 { + // Log if multiple arguments are passed, though typical protocol/file launch is a single arg. + m.parent.info("Application launched with multiple arguments", "args", os.Args[1:]) } _ = m.runMainLoop() @@ -383,7 +399,9 @@ func newPlatformApp(app *App) *windowsApp { func (a *App) logPlatformInfo() { var args []any args = append(args, "Go-WebView2Loader", webviewloader.UsingGoWebview2Loader) - webviewVersion, err := webviewloader.GetAvailableCoreWebView2BrowserVersionString(a.options.Windows.WebviewBrowserPath) + webviewVersion, err := webviewloader.GetAvailableCoreWebView2BrowserVersionString( + a.options.Windows.WebviewBrowserPath, + ) if err != nil { args = append(args, "WebView2", "Error: "+err.Error()) } else { @@ -398,7 +416,9 @@ func (a *App) logPlatformInfo() { func (a *App) platformEnvironment() map[string]any { result := map[string]any{} - webviewVersion, _ := webviewloader.GetAvailableCoreWebView2BrowserVersionString(a.options.Windows.WebviewBrowserPath) + webviewVersion, _ := webviewloader.GetAvailableCoreWebView2BrowserVersionString( + a.options.Windows.WebviewBrowserPath, + ) result["Go-WebView2Loader"] = webviewloader.UsingGoWebview2Loader result["WebView2"] = webviewVersion return result diff --git a/v3/pkg/application/context_application_event.go b/v3/pkg/application/context_application_event.go index 468634f22..32f392455 100644 --- a/v3/pkg/application/context_application_event.go +++ b/v3/pkg/application/context_application_event.go @@ -1,19 +1,24 @@ package application +import "log" + var blankApplicationEventContext = &ApplicationEventContext{} const ( - openedFiles = "openedFiles" - filename = "filename" + CONTEXT_OPENED_FILES = "openedFiles" + CONTEXT_FILENAME = "filename" + CONTEXT_URL = "url" ) +// ApplicationEventContext is the context of an application event type ApplicationEventContext struct { // contains filtered or unexported fields data map[string]any } +// OpenedFiles returns the opened files from the event context if it was set func (c ApplicationEventContext) OpenedFiles() []string { - files, ok := c.data[openedFiles] + files, ok := c.data[CONTEXT_OPENED_FILES] if !ok { return nil } @@ -25,7 +30,7 @@ func (c ApplicationEventContext) OpenedFiles() []string { } func (c ApplicationEventContext) setOpenedFiles(files []string) { - c.data[openedFiles] = files + c.data[CONTEXT_OPENED_FILES] = files } func (c ApplicationEventContext) setIsDarkMode(mode bool) { @@ -44,24 +49,31 @@ func (c ApplicationEventContext) getBool(key string) bool { return result } +// IsDarkMode returns true if the event context has a dark mode func (c ApplicationEventContext) IsDarkMode() bool { return c.getBool("isDarkMode") } +// HasVisibleWindows returns true if the event context has a visible window func (c ApplicationEventContext) HasVisibleWindows() bool { return c.getBool("hasVisibleWindows") } -func (c ApplicationEventContext) setData(data map[string]any) { +func (c *ApplicationEventContext) setData(data map[string]any) { c.data = data } -func (c ApplicationEventContext) setOpenedWithFile(filepath string) { - c.data[filename] = filepath +func (c *ApplicationEventContext) setOpenedWithFile(filepath string) { + c.data[CONTEXT_FILENAME] = filepath } +func (c *ApplicationEventContext) setURL(openedWithURL string) { + c.data[CONTEXT_URL] = openedWithURL +} + +// Filename returns the filename from the event context if it was set func (c ApplicationEventContext) Filename() string { - filename, ok := c.data[filename] + filename, ok := c.data[CONTEXT_FILENAME] if !ok { return "" } @@ -72,6 +84,21 @@ func (c ApplicationEventContext) Filename() string { return result } +// URL returns the URL from the event context if it was set +func (c ApplicationEventContext) URL() string { + url, ok := c.data[CONTEXT_URL] + if !ok { + log.Println("URL not found in event context") + return "" + } + result, ok := url.(string) + if !ok { + log.Println("URL not a string in event context") + return "" + } + return result +} + func newApplicationEventContext() *ApplicationEventContext { return &ApplicationEventContext{ data: make(map[string]any), diff --git a/v3/pkg/events/events.go b/v3/pkg/events/events.go index c09b7e8e5..c0d200103 100644 --- a/v3/pkg/events/events.go +++ b/v3/pkg/events/events.go @@ -1,13 +1,14 @@ package events type ApplicationEventType uint -type WindowEventType uint +type WindowEventType uint var Common = newCommonEvents() type commonEvents struct { ApplicationOpenedWithFile ApplicationEventType ApplicationStarted ApplicationEventType + ApplicationLaunchedWithUrl ApplicationEventType ThemeChanged ApplicationEventType WindowClosing WindowEventType WindowDidMove WindowEventType @@ -20,7 +21,6 @@ type commonEvents struct { WindowLostFocus WindowEventType WindowMaximise WindowEventType WindowMinimise WindowEventType - WindowToggleFrameless WindowEventType WindowRestore WindowEventType WindowRuntimeReady WindowEventType WindowShow WindowEventType @@ -37,19 +37,19 @@ func newCommonEvents() commonEvents { return commonEvents{ ApplicationOpenedWithFile: 1024, ApplicationStarted: 1025, - ThemeChanged: 1026, - WindowClosing: 1027, - WindowDidMove: 1028, - WindowDidResize: 1029, - WindowDPIChanged: 1030, - WindowFilesDropped: 1031, - WindowFocus: 1032, - WindowFullscreen: 1033, - WindowHide: 1034, - WindowLostFocus: 1035, - WindowMaximise: 1036, - WindowMinimise: 1037, - WindowToggleFrameless: 1038, + ApplicationLaunchedWithUrl: 1026, + ThemeChanged: 1027, + WindowClosing: 1028, + WindowDidMove: 1029, + WindowDidResize: 1030, + WindowDPIChanged: 1031, + WindowFilesDropped: 1032, + WindowFocus: 1033, + WindowFullscreen: 1034, + WindowHide: 1035, + WindowLostFocus: 1036, + WindowMaximise: 1037, + WindowMinimise: 1038, WindowRestore: 1039, WindowRuntimeReady: 1040, WindowShow: 1041, @@ -68,12 +68,12 @@ var Linux = newLinuxEvents() type linuxEvents struct { ApplicationStartup ApplicationEventType SystemThemeChanged ApplicationEventType - WindowDeleteEvent WindowEventType - WindowDidMove WindowEventType - WindowDidResize WindowEventType - WindowFocusIn WindowEventType - WindowFocusOut WindowEventType - WindowLoadChanged WindowEventType + WindowDeleteEvent WindowEventType + WindowDidMove WindowEventType + WindowDidResize WindowEventType + WindowFocusIn WindowEventType + WindowFocusOut WindowEventType + WindowLoadChanged WindowEventType } func newLinuxEvents() linuxEvents { @@ -92,138 +92,138 @@ func newLinuxEvents() linuxEvents { var Mac = newMacEvents() type macEvents struct { - ApplicationDidBecomeActive ApplicationEventType - ApplicationDidChangeBackingProperties ApplicationEventType - ApplicationDidChangeEffectiveAppearance ApplicationEventType - ApplicationDidChangeIcon ApplicationEventType - ApplicationDidChangeOcclusionState ApplicationEventType - ApplicationDidChangeScreenParameters ApplicationEventType - ApplicationDidChangeStatusBarFrame ApplicationEventType - ApplicationDidChangeStatusBarOrientation ApplicationEventType - ApplicationDidChangeTheme ApplicationEventType - ApplicationDidFinishLaunching ApplicationEventType - ApplicationDidHide ApplicationEventType - ApplicationDidResignActive ApplicationEventType - ApplicationDidUnhide ApplicationEventType - ApplicationDidUpdate ApplicationEventType - ApplicationShouldHandleReopen ApplicationEventType - ApplicationWillBecomeActive ApplicationEventType - ApplicationWillFinishLaunching ApplicationEventType - ApplicationWillHide ApplicationEventType - ApplicationWillResignActive ApplicationEventType - ApplicationWillTerminate ApplicationEventType - ApplicationWillUnhide ApplicationEventType - ApplicationWillUpdate ApplicationEventType - MenuDidAddItem ApplicationEventType - MenuDidBeginTracking ApplicationEventType - MenuDidClose ApplicationEventType - MenuDidDisplayItem ApplicationEventType - MenuDidEndTracking ApplicationEventType - MenuDidHighlightItem ApplicationEventType - MenuDidOpen ApplicationEventType - MenuDidPopUp ApplicationEventType - MenuDidRemoveItem ApplicationEventType - MenuDidSendAction ApplicationEventType - MenuDidSendActionToItem ApplicationEventType - MenuDidUpdate ApplicationEventType - MenuWillAddItem ApplicationEventType - MenuWillBeginTracking ApplicationEventType - MenuWillDisplayItem ApplicationEventType - MenuWillEndTracking ApplicationEventType - MenuWillHighlightItem ApplicationEventType - MenuWillOpen ApplicationEventType - MenuWillPopUp ApplicationEventType - MenuWillRemoveItem ApplicationEventType - MenuWillSendAction ApplicationEventType - MenuWillSendActionToItem ApplicationEventType - MenuWillUpdate ApplicationEventType - WebViewDidCommitNavigation WindowEventType - WebViewDidFinishNavigation WindowEventType + ApplicationDidBecomeActive ApplicationEventType + ApplicationDidChangeBackingProperties ApplicationEventType + ApplicationDidChangeEffectiveAppearance ApplicationEventType + ApplicationDidChangeIcon ApplicationEventType + ApplicationDidChangeOcclusionState ApplicationEventType + ApplicationDidChangeScreenParameters ApplicationEventType + ApplicationDidChangeStatusBarFrame ApplicationEventType + ApplicationDidChangeStatusBarOrientation ApplicationEventType + ApplicationDidChangeTheme ApplicationEventType + ApplicationDidFinishLaunching ApplicationEventType + ApplicationDidHide ApplicationEventType + ApplicationDidResignActive ApplicationEventType + ApplicationDidUnhide ApplicationEventType + ApplicationDidUpdate ApplicationEventType + ApplicationShouldHandleReopen ApplicationEventType + ApplicationWillBecomeActive ApplicationEventType + ApplicationWillFinishLaunching ApplicationEventType + ApplicationWillHide ApplicationEventType + ApplicationWillResignActive ApplicationEventType + ApplicationWillTerminate ApplicationEventType + ApplicationWillUnhide ApplicationEventType + ApplicationWillUpdate ApplicationEventType + MenuDidAddItem ApplicationEventType + MenuDidBeginTracking ApplicationEventType + MenuDidClose ApplicationEventType + MenuDidDisplayItem ApplicationEventType + MenuDidEndTracking ApplicationEventType + MenuDidHighlightItem ApplicationEventType + MenuDidOpen ApplicationEventType + MenuDidPopUp ApplicationEventType + MenuDidRemoveItem ApplicationEventType + MenuDidSendAction ApplicationEventType + MenuDidSendActionToItem ApplicationEventType + MenuDidUpdate ApplicationEventType + MenuWillAddItem ApplicationEventType + MenuWillBeginTracking ApplicationEventType + MenuWillDisplayItem ApplicationEventType + MenuWillEndTracking ApplicationEventType + MenuWillHighlightItem ApplicationEventType + MenuWillOpen ApplicationEventType + MenuWillPopUp ApplicationEventType + MenuWillRemoveItem ApplicationEventType + MenuWillSendAction ApplicationEventType + MenuWillSendActionToItem ApplicationEventType + MenuWillUpdate ApplicationEventType + WebViewDidCommitNavigation WindowEventType + WebViewDidFinishNavigation WindowEventType WebViewDidReceiveServerRedirectForProvisionalNavigation WindowEventType - WebViewDidStartProvisionalNavigation WindowEventType - WindowDidBecomeKey WindowEventType - WindowDidBecomeMain WindowEventType - WindowDidBeginSheet WindowEventType - WindowDidChangeAlpha WindowEventType - WindowDidChangeBackingLocation WindowEventType - WindowDidChangeBackingProperties WindowEventType - WindowDidChangeCollectionBehavior WindowEventType - WindowDidChangeEffectiveAppearance WindowEventType - WindowDidChangeOcclusionState WindowEventType - WindowDidChangeOrderingMode WindowEventType - WindowDidChangeScreen WindowEventType - WindowDidChangeScreenParameters WindowEventType - WindowDidChangeScreenProfile WindowEventType - WindowDidChangeScreenSpace WindowEventType - WindowDidChangeScreenSpaceProperties WindowEventType - WindowDidChangeSharingType WindowEventType - WindowDidChangeSpace WindowEventType - WindowDidChangeSpaceOrderingMode WindowEventType - WindowDidChangeTitle WindowEventType - WindowDidChangeToolbar WindowEventType - WindowDidDeminiaturize WindowEventType - WindowDidEndSheet WindowEventType - WindowDidEnterFullScreen WindowEventType - WindowDidEnterVersionBrowser WindowEventType - WindowDidExitFullScreen WindowEventType - WindowDidExitVersionBrowser WindowEventType - WindowDidExpose WindowEventType - WindowDidFocus WindowEventType - WindowDidMiniaturize WindowEventType - WindowDidMove WindowEventType - WindowDidOrderOffScreen WindowEventType - WindowDidOrderOnScreen WindowEventType - WindowDidResignKey WindowEventType - WindowDidResignMain WindowEventType - WindowDidResize WindowEventType - WindowDidUpdate WindowEventType - WindowDidUpdateAlpha WindowEventType - WindowDidUpdateCollectionBehavior WindowEventType - WindowDidUpdateCollectionProperties WindowEventType - WindowDidUpdateShadow WindowEventType - WindowDidUpdateTitle WindowEventType - WindowDidUpdateToolbar WindowEventType - WindowDidZoom WindowEventType - WindowFileDraggingEntered WindowEventType - WindowFileDraggingExited WindowEventType - WindowFileDraggingPerformed WindowEventType - WindowHide WindowEventType - WindowMaximise WindowEventType - WindowUnMaximise WindowEventType - WindowMinimise WindowEventType - WindowUnMinimise WindowEventType - WindowShouldClose WindowEventType - WindowShow WindowEventType - WindowWillBecomeKey WindowEventType - WindowWillBecomeMain WindowEventType - WindowWillBeginSheet WindowEventType - WindowWillChangeOrderingMode WindowEventType - WindowWillClose WindowEventType - WindowWillDeminiaturize WindowEventType - WindowWillEnterFullScreen WindowEventType - WindowWillEnterVersionBrowser WindowEventType - WindowWillExitFullScreen WindowEventType - WindowWillExitVersionBrowser WindowEventType - WindowWillFocus WindowEventType - WindowWillMiniaturize WindowEventType - WindowWillMove WindowEventType - WindowWillOrderOffScreen WindowEventType - WindowWillOrderOnScreen WindowEventType - WindowWillResignMain WindowEventType - WindowWillResize WindowEventType - WindowWillUnfocus WindowEventType - WindowWillUpdate WindowEventType - WindowWillUpdateAlpha WindowEventType - WindowWillUpdateCollectionBehavior WindowEventType - WindowWillUpdateCollectionProperties WindowEventType - WindowWillUpdateShadow WindowEventType - WindowWillUpdateTitle WindowEventType - WindowWillUpdateToolbar WindowEventType - WindowWillUpdateVisibility WindowEventType - WindowWillUseStandardFrame WindowEventType - WindowZoomIn WindowEventType - WindowZoomOut WindowEventType - WindowZoomReset WindowEventType + WebViewDidStartProvisionalNavigation WindowEventType + WindowDidBecomeKey WindowEventType + WindowDidBecomeMain WindowEventType + WindowDidBeginSheet WindowEventType + WindowDidChangeAlpha WindowEventType + WindowDidChangeBackingLocation WindowEventType + WindowDidChangeBackingProperties WindowEventType + WindowDidChangeCollectionBehavior WindowEventType + WindowDidChangeEffectiveAppearance WindowEventType + WindowDidChangeOcclusionState WindowEventType + WindowDidChangeOrderingMode WindowEventType + WindowDidChangeScreen WindowEventType + WindowDidChangeScreenParameters WindowEventType + WindowDidChangeScreenProfile WindowEventType + WindowDidChangeScreenSpace WindowEventType + WindowDidChangeScreenSpaceProperties WindowEventType + WindowDidChangeSharingType WindowEventType + WindowDidChangeSpace WindowEventType + WindowDidChangeSpaceOrderingMode WindowEventType + WindowDidChangeTitle WindowEventType + WindowDidChangeToolbar WindowEventType + WindowDidDeminiaturize WindowEventType + WindowDidEndSheet WindowEventType + WindowDidEnterFullScreen WindowEventType + WindowDidEnterVersionBrowser WindowEventType + WindowDidExitFullScreen WindowEventType + WindowDidExitVersionBrowser WindowEventType + WindowDidExpose WindowEventType + WindowDidFocus WindowEventType + WindowDidMiniaturize WindowEventType + WindowDidMove WindowEventType + WindowDidOrderOffScreen WindowEventType + WindowDidOrderOnScreen WindowEventType + WindowDidResignKey WindowEventType + WindowDidResignMain WindowEventType + WindowDidResize WindowEventType + WindowDidUpdate WindowEventType + WindowDidUpdateAlpha WindowEventType + WindowDidUpdateCollectionBehavior WindowEventType + WindowDidUpdateCollectionProperties WindowEventType + WindowDidUpdateShadow WindowEventType + WindowDidUpdateTitle WindowEventType + WindowDidUpdateToolbar WindowEventType + WindowDidZoom WindowEventType + WindowFileDraggingEntered WindowEventType + WindowFileDraggingExited WindowEventType + WindowFileDraggingPerformed WindowEventType + WindowHide WindowEventType + WindowMaximise WindowEventType + WindowUnMaximise WindowEventType + WindowMinimise WindowEventType + WindowUnMinimise WindowEventType + WindowShouldClose WindowEventType + WindowShow WindowEventType + WindowWillBecomeKey WindowEventType + WindowWillBecomeMain WindowEventType + WindowWillBeginSheet WindowEventType + WindowWillChangeOrderingMode WindowEventType + WindowWillClose WindowEventType + WindowWillDeminiaturize WindowEventType + WindowWillEnterFullScreen WindowEventType + WindowWillEnterVersionBrowser WindowEventType + WindowWillExitFullScreen WindowEventType + WindowWillExitVersionBrowser WindowEventType + WindowWillFocus WindowEventType + WindowWillMiniaturize WindowEventType + WindowWillMove WindowEventType + WindowWillOrderOffScreen WindowEventType + WindowWillOrderOnScreen WindowEventType + WindowWillResignMain WindowEventType + WindowWillResize WindowEventType + WindowWillUnfocus WindowEventType + WindowWillUpdate WindowEventType + WindowWillUpdateAlpha WindowEventType + WindowWillUpdateCollectionBehavior WindowEventType + WindowWillUpdateCollectionProperties WindowEventType + WindowWillUpdateShadow WindowEventType + WindowWillUpdateTitle WindowEventType + WindowWillUpdateToolbar WindowEventType + WindowWillUpdateVisibility WindowEventType + WindowWillUseStandardFrame WindowEventType + WindowZoomIn WindowEventType + WindowZoomOut WindowEventType + WindowZoomReset WindowEventType } func newMacEvents() macEvents { @@ -366,50 +366,50 @@ func newMacEvents() macEvents { var Windows = newWindowsEvents() type windowsEvents struct { - APMPowerSettingChange ApplicationEventType - APMPowerStatusChange ApplicationEventType - APMResumeAutomatic ApplicationEventType - APMResumeSuspend ApplicationEventType - APMSuspend ApplicationEventType - ApplicationStarted ApplicationEventType - SystemThemeChanged ApplicationEventType + APMPowerSettingChange ApplicationEventType + APMPowerStatusChange ApplicationEventType + APMResumeAutomatic ApplicationEventType + APMResumeSuspend ApplicationEventType + APMSuspend ApplicationEventType + ApplicationStarted ApplicationEventType + SystemThemeChanged ApplicationEventType WebViewNavigationCompleted WindowEventType - WindowActive WindowEventType - WindowBackgroundErase WindowEventType - WindowClickActive WindowEventType - WindowClosing WindowEventType - WindowDidMove WindowEventType - WindowDidResize WindowEventType - WindowDPIChanged WindowEventType - WindowDragDrop WindowEventType - WindowDragEnter WindowEventType - WindowDragLeave WindowEventType - WindowDragOver WindowEventType - WindowEndMove WindowEventType - WindowEndResize WindowEventType - WindowFullscreen WindowEventType - WindowHide WindowEventType - WindowInactive WindowEventType - WindowKeyDown WindowEventType - WindowKeyUp WindowEventType - WindowKillFocus WindowEventType - WindowNonClientHit WindowEventType - WindowNonClientMouseDown WindowEventType - WindowNonClientMouseLeave WindowEventType - WindowNonClientMouseMove WindowEventType - WindowNonClientMouseUp WindowEventType - WindowPaint WindowEventType - WindowRestore WindowEventType - WindowSetFocus WindowEventType - WindowShow WindowEventType - WindowStartMove WindowEventType - WindowStartResize WindowEventType - WindowUnFullscreen WindowEventType - WindowZOrderChanged WindowEventType - WindowMinimise WindowEventType - WindowUnMinimise WindowEventType - WindowMaximise WindowEventType - WindowUnMaximise WindowEventType + WindowActive WindowEventType + WindowBackgroundErase WindowEventType + WindowClickActive WindowEventType + WindowClosing WindowEventType + WindowDidMove WindowEventType + WindowDidResize WindowEventType + WindowDPIChanged WindowEventType + WindowDragDrop WindowEventType + WindowDragEnter WindowEventType + WindowDragLeave WindowEventType + WindowDragOver WindowEventType + WindowEndMove WindowEventType + WindowEndResize WindowEventType + WindowFullscreen WindowEventType + WindowHide WindowEventType + WindowInactive WindowEventType + WindowKeyDown WindowEventType + WindowKeyUp WindowEventType + WindowKillFocus WindowEventType + WindowNonClientHit WindowEventType + WindowNonClientMouseDown WindowEventType + WindowNonClientMouseLeave WindowEventType + WindowNonClientMouseMove WindowEventType + WindowNonClientMouseUp WindowEventType + WindowPaint WindowEventType + WindowRestore WindowEventType + WindowSetFocus WindowEventType + WindowShow WindowEventType + WindowStartMove WindowEventType + WindowStartResize WindowEventType + WindowUnFullscreen WindowEventType + WindowZOrderChanged WindowEventType + WindowMinimise WindowEventType + WindowUnMinimise WindowEventType + WindowMaximise WindowEventType + WindowUnMaximise WindowEventType } func newWindowsEvents() windowsEvents { @@ -458,7 +458,6 @@ func newWindowsEvents() windowsEvents { WindowUnMinimise: 1230, WindowMaximise: 1231, WindowUnMaximise: 1232, - } } @@ -467,213 +466,214 @@ func JSEvent(event uint) string { } var eventToJS = map[uint]string{ - 1024: "common:ApplicationOpenedWithFile", - 1025: "common:ApplicationStarted", - 1026: "common:ThemeChanged", - 1027: "common:WindowClosing", - 1028: "common:WindowDidMove", - 1029: "common:WindowDidResize", - 1030: "common:WindowDPIChanged", - 1031: "common:WindowFilesDropped", - 1032: "common:WindowFocus", - 1033: "common:WindowFullscreen", - 1034: "common:WindowHide", - 1035: "common:WindowLostFocus", - 1036: "common:WindowMaximise", - 1037: "common:WindowMinimise", - 1038: "common:WindowToggleFrameless", - 1039: "common:WindowRestore", - 1040: "common:WindowRuntimeReady", - 1041: "common:WindowShow", - 1042: "common:WindowUnFullscreen", - 1043: "common:WindowUnMaximise", - 1044: "common:WindowUnMinimise", - 1045: "common:WindowZoom", - 1046: "common:WindowZoomIn", - 1047: "common:WindowZoomOut", - 1048: "common:WindowZoomReset", - 1049: "linux:ApplicationStartup", - 1050: "linux:SystemThemeChanged", - 1051: "linux:WindowDeleteEvent", - 1052: "linux:WindowDidMove", - 1053: "linux:WindowDidResize", - 1054: "linux:WindowFocusIn", - 1055: "linux:WindowFocusOut", - 1056: "linux:WindowLoadChanged", - 1057: "mac:ApplicationDidBecomeActive", - 1058: "mac:ApplicationDidChangeBackingProperties", - 1059: "mac:ApplicationDidChangeEffectiveAppearance", - 1060: "mac:ApplicationDidChangeIcon", - 1061: "mac:ApplicationDidChangeOcclusionState", - 1062: "mac:ApplicationDidChangeScreenParameters", - 1063: "mac:ApplicationDidChangeStatusBarFrame", - 1064: "mac:ApplicationDidChangeStatusBarOrientation", - 1065: "mac:ApplicationDidChangeTheme", - 1066: "mac:ApplicationDidFinishLaunching", - 1067: "mac:ApplicationDidHide", - 1068: "mac:ApplicationDidResignActive", - 1069: "mac:ApplicationDidUnhide", - 1070: "mac:ApplicationDidUpdate", - 1071: "mac:ApplicationShouldHandleReopen", - 1072: "mac:ApplicationWillBecomeActive", - 1073: "mac:ApplicationWillFinishLaunching", - 1074: "mac:ApplicationWillHide", - 1075: "mac:ApplicationWillResignActive", - 1076: "mac:ApplicationWillTerminate", - 1077: "mac:ApplicationWillUnhide", - 1078: "mac:ApplicationWillUpdate", - 1079: "mac:MenuDidAddItem", - 1080: "mac:MenuDidBeginTracking", - 1081: "mac:MenuDidClose", - 1082: "mac:MenuDidDisplayItem", - 1083: "mac:MenuDidEndTracking", - 1084: "mac:MenuDidHighlightItem", - 1085: "mac:MenuDidOpen", - 1086: "mac:MenuDidPopUp", - 1087: "mac:MenuDidRemoveItem", - 1088: "mac:MenuDidSendAction", - 1089: "mac:MenuDidSendActionToItem", - 1090: "mac:MenuDidUpdate", - 1091: "mac:MenuWillAddItem", - 1092: "mac:MenuWillBeginTracking", - 1093: "mac:MenuWillDisplayItem", - 1094: "mac:MenuWillEndTracking", - 1095: "mac:MenuWillHighlightItem", - 1096: "mac:MenuWillOpen", - 1097: "mac:MenuWillPopUp", - 1098: "mac:MenuWillRemoveItem", - 1099: "mac:MenuWillSendAction", - 1100: "mac:MenuWillSendActionToItem", - 1101: "mac:MenuWillUpdate", - 1102: "mac:WebViewDidCommitNavigation", - 1103: "mac:WebViewDidFinishNavigation", - 1104: "mac:WebViewDidReceiveServerRedirectForProvisionalNavigation", - 1105: "mac:WebViewDidStartProvisionalNavigation", - 1106: "mac:WindowDidBecomeKey", - 1107: "mac:WindowDidBecomeMain", - 1108: "mac:WindowDidBeginSheet", - 1109: "mac:WindowDidChangeAlpha", - 1110: "mac:WindowDidChangeBackingLocation", - 1111: "mac:WindowDidChangeBackingProperties", - 1112: "mac:WindowDidChangeCollectionBehavior", - 1113: "mac:WindowDidChangeEffectiveAppearance", - 1114: "mac:WindowDidChangeOcclusionState", - 1115: "mac:WindowDidChangeOrderingMode", - 1116: "mac:WindowDidChangeScreen", - 1117: "mac:WindowDidChangeScreenParameters", - 1118: "mac:WindowDidChangeScreenProfile", - 1119: "mac:WindowDidChangeScreenSpace", - 1120: "mac:WindowDidChangeScreenSpaceProperties", - 1121: "mac:WindowDidChangeSharingType", - 1122: "mac:WindowDidChangeSpace", - 1123: "mac:WindowDidChangeSpaceOrderingMode", - 1124: "mac:WindowDidChangeTitle", - 1125: "mac:WindowDidChangeToolbar", - 1126: "mac:WindowDidDeminiaturize", - 1127: "mac:WindowDidEndSheet", - 1128: "mac:WindowDidEnterFullScreen", - 1129: "mac:WindowDidEnterVersionBrowser", - 1130: "mac:WindowDidExitFullScreen", - 1131: "mac:WindowDidExitVersionBrowser", - 1132: "mac:WindowDidExpose", - 1133: "mac:WindowDidFocus", - 1134: "mac:WindowDidMiniaturize", - 1135: "mac:WindowDidMove", - 1136: "mac:WindowDidOrderOffScreen", - 1137: "mac:WindowDidOrderOnScreen", - 1138: "mac:WindowDidResignKey", - 1139: "mac:WindowDidResignMain", - 1140: "mac:WindowDidResize", - 1141: "mac:WindowDidUpdate", - 1142: "mac:WindowDidUpdateAlpha", - 1143: "mac:WindowDidUpdateCollectionBehavior", - 1144: "mac:WindowDidUpdateCollectionProperties", - 1145: "mac:WindowDidUpdateShadow", - 1146: "mac:WindowDidUpdateTitle", - 1147: "mac:WindowDidUpdateToolbar", - 1148: "mac:WindowDidZoom", - 1149: "mac:WindowFileDraggingEntered", - 1150: "mac:WindowFileDraggingExited", - 1151: "mac:WindowFileDraggingPerformed", - 1152: "mac:WindowHide", - 1153: "mac:WindowMaximise", - 1154: "mac:WindowUnMaximise", - 1155: "mac:WindowMinimise", - 1156: "mac:WindowUnMinimise", - 1157: "mac:WindowShouldClose", - 1158: "mac:WindowShow", - 1159: "mac:WindowWillBecomeKey", - 1160: "mac:WindowWillBecomeMain", - 1161: "mac:WindowWillBeginSheet", - 1162: "mac:WindowWillChangeOrderingMode", - 1163: "mac:WindowWillClose", - 1164: "mac:WindowWillDeminiaturize", - 1165: "mac:WindowWillEnterFullScreen", - 1166: "mac:WindowWillEnterVersionBrowser", - 1167: "mac:WindowWillExitFullScreen", - 1168: "mac:WindowWillExitVersionBrowser", - 1169: "mac:WindowWillFocus", - 1170: "mac:WindowWillMiniaturize", - 1171: "mac:WindowWillMove", - 1172: "mac:WindowWillOrderOffScreen", - 1173: "mac:WindowWillOrderOnScreen", - 1174: "mac:WindowWillResignMain", - 1175: "mac:WindowWillResize", - 1176: "mac:WindowWillUnfocus", - 1177: "mac:WindowWillUpdate", - 1178: "mac:WindowWillUpdateAlpha", - 1179: "mac:WindowWillUpdateCollectionBehavior", - 1180: "mac:WindowWillUpdateCollectionProperties", - 1181: "mac:WindowWillUpdateShadow", - 1182: "mac:WindowWillUpdateTitle", - 1183: "mac:WindowWillUpdateToolbar", - 1184: "mac:WindowWillUpdateVisibility", - 1185: "mac:WindowWillUseStandardFrame", - 1186: "mac:WindowZoomIn", - 1187: "mac:WindowZoomOut", - 1188: "mac:WindowZoomReset", - 1189: "windows:APMPowerSettingChange", - 1190: "windows:APMPowerStatusChange", - 1191: "windows:APMResumeAutomatic", - 1192: "windows:APMResumeSuspend", - 1193: "windows:APMSuspend", - 1194: "windows:ApplicationStarted", - 1195: "windows:SystemThemeChanged", - 1196: "windows:WebViewNavigationCompleted", - 1197: "windows:WindowActive", - 1198: "windows:WindowBackgroundErase", - 1199: "windows:WindowClickActive", - 1200: "windows:WindowClosing", - 1201: "windows:WindowDidMove", - 1202: "windows:WindowDidResize", - 1203: "windows:WindowDPIChanged", - 1204: "windows:WindowDragDrop", - 1205: "windows:WindowDragEnter", - 1206: "windows:WindowDragLeave", - 1207: "windows:WindowDragOver", - 1208: "windows:WindowEndMove", - 1209: "windows:WindowEndResize", - 1210: "windows:WindowFullscreen", - 1211: "windows:WindowHide", - 1212: "windows:WindowInactive", - 1213: "windows:WindowKeyDown", - 1214: "windows:WindowKeyUp", - 1215: "windows:WindowKillFocus", - 1216: "windows:WindowNonClientHit", - 1217: "windows:WindowNonClientMouseDown", - 1218: "windows:WindowNonClientMouseLeave", - 1219: "windows:WindowNonClientMouseMove", - 1220: "windows:WindowNonClientMouseUp", - 1221: "windows:WindowPaint", - 1222: "windows:WindowRestore", - 1223: "windows:WindowSetFocus", - 1224: "windows:WindowShow", - 1225: "windows:WindowStartMove", - 1226: "windows:WindowStartResize", - 1227: "windows:WindowUnFullscreen", - 1228: "windows:WindowZOrderChanged", - 1229: "windows:WindowMinimise", - 1230: "windows:WindowUnMinimise", - 1231: "windows:WindowMaximise", - 1232: "windows:WindowUnMaximise", + 1024: "ApplicationOpenedWithFile", + 1025: "ApplicationStarted", + 1026: "ApplicationLaunchedWithUrl", + 1027: "ThemeChanged", + 1028: "WindowClosing", + 1029: "WindowDidMove", + 1030: "WindowDidResize", + 1031: "WindowDPIChanged", + 1032: "WindowFilesDropped", + 1033: "WindowFocus", + 1034: "WindowFullscreen", + 1035: "WindowHide", + 1036: "WindowLostFocus", + 1037: "WindowMaximise", + 1038: "WindowMinimise", + 1039: "WindowRestore", + 1040: "WindowRuntimeReady", + 1041: "WindowShow", + 1042: "WindowUnFullscreen", + 1043: "WindowUnMaximise", + 1044: "WindowUnMinimise", + 1045: "WindowZoom", + 1046: "WindowZoomIn", + 1047: "WindowZoomOut", + 1048: "WindowZoomReset", + 1049: "ApplicationStartup", + 1050: "SystemThemeChanged", + 1051: "WindowDeleteEvent", + 1052: "WindowDidMove", + 1053: "WindowDidResize", + 1054: "WindowFocusIn", + 1055: "WindowFocusOut", + 1056: "WindowLoadChanged", + 1057: "ApplicationDidBecomeActive", + 1058: "ApplicationDidChangeBackingProperties", + 1059: "ApplicationDidChangeEffectiveAppearance", + 1060: "ApplicationDidChangeIcon", + 1061: "ApplicationDidChangeOcclusionState", + 1062: "ApplicationDidChangeScreenParameters", + 1063: "ApplicationDidChangeStatusBarFrame", + 1064: "ApplicationDidChangeStatusBarOrientation", + 1065: "ApplicationDidChangeTheme", + 1066: "ApplicationDidFinishLaunching", + 1067: "ApplicationDidHide", + 1068: "ApplicationDidResignActive", + 1069: "ApplicationDidUnhide", + 1070: "ApplicationDidUpdate", + 1071: "ApplicationShouldHandleReopen", + 1072: "ApplicationWillBecomeActive", + 1073: "ApplicationWillFinishLaunching", + 1074: "ApplicationWillHide", + 1075: "ApplicationWillResignActive", + 1076: "ApplicationWillTerminate", + 1077: "ApplicationWillUnhide", + 1078: "ApplicationWillUpdate", + 1079: "MenuDidAddItem", + 1080: "MenuDidBeginTracking", + 1081: "MenuDidClose", + 1082: "MenuDidDisplayItem", + 1083: "MenuDidEndTracking", + 1084: "MenuDidHighlightItem", + 1085: "MenuDidOpen", + 1086: "MenuDidPopUp", + 1087: "MenuDidRemoveItem", + 1088: "MenuDidSendAction", + 1089: "MenuDidSendActionToItem", + 1090: "MenuDidUpdate", + 1091: "MenuWillAddItem", + 1092: "MenuWillBeginTracking", + 1093: "MenuWillDisplayItem", + 1094: "MenuWillEndTracking", + 1095: "MenuWillHighlightItem", + 1096: "MenuWillOpen", + 1097: "MenuWillPopUp", + 1098: "MenuWillRemoveItem", + 1099: "MenuWillSendAction", + 1100: "MenuWillSendActionToItem", + 1101: "MenuWillUpdate", + 1102: "WebViewDidCommitNavigation", + 1103: "WebViewDidFinishNavigation", + 1104: "WebViewDidReceiveServerRedirectForProvisionalNavigation", + 1105: "WebViewDidStartProvisionalNavigation", + 1106: "WindowDidBecomeKey", + 1107: "WindowDidBecomeMain", + 1108: "WindowDidBeginSheet", + 1109: "WindowDidChangeAlpha", + 1110: "WindowDidChangeBackingLocation", + 1111: "WindowDidChangeBackingProperties", + 1112: "WindowDidChangeCollectionBehavior", + 1113: "WindowDidChangeEffectiveAppearance", + 1114: "WindowDidChangeOcclusionState", + 1115: "WindowDidChangeOrderingMode", + 1116: "WindowDidChangeScreen", + 1117: "WindowDidChangeScreenParameters", + 1118: "WindowDidChangeScreenProfile", + 1119: "WindowDidChangeScreenSpace", + 1120: "WindowDidChangeScreenSpaceProperties", + 1121: "WindowDidChangeSharingType", + 1122: "WindowDidChangeSpace", + 1123: "WindowDidChangeSpaceOrderingMode", + 1124: "WindowDidChangeTitle", + 1125: "WindowDidChangeToolbar", + 1126: "WindowDidDeminiaturize", + 1127: "WindowDidEndSheet", + 1128: "WindowDidEnterFullScreen", + 1129: "WindowDidEnterVersionBrowser", + 1130: "WindowDidExitFullScreen", + 1131: "WindowDidExitVersionBrowser", + 1132: "WindowDidExpose", + 1133: "WindowDidFocus", + 1134: "WindowDidMiniaturize", + 1135: "WindowDidMove", + 1136: "WindowDidOrderOffScreen", + 1137: "WindowDidOrderOnScreen", + 1138: "WindowDidResignKey", + 1139: "WindowDidResignMain", + 1140: "WindowDidResize", + 1141: "WindowDidUpdate", + 1142: "WindowDidUpdateAlpha", + 1143: "WindowDidUpdateCollectionBehavior", + 1144: "WindowDidUpdateCollectionProperties", + 1145: "WindowDidUpdateShadow", + 1146: "WindowDidUpdateTitle", + 1147: "WindowDidUpdateToolbar", + 1148: "WindowDidZoom", + 1149: "WindowFileDraggingEntered", + 1150: "WindowFileDraggingExited", + 1151: "WindowFileDraggingPerformed", + 1152: "WindowHide", + 1153: "WindowMaximise", + 1154: "WindowUnMaximise", + 1155: "WindowMinimise", + 1156: "WindowUnMinimise", + 1157: "WindowShouldClose", + 1158: "WindowShow", + 1159: "WindowWillBecomeKey", + 1160: "WindowWillBecomeMain", + 1161: "WindowWillBeginSheet", + 1162: "WindowWillChangeOrderingMode", + 1163: "WindowWillClose", + 1164: "WindowWillDeminiaturize", + 1165: "WindowWillEnterFullScreen", + 1166: "WindowWillEnterVersionBrowser", + 1167: "WindowWillExitFullScreen", + 1168: "WindowWillExitVersionBrowser", + 1169: "WindowWillFocus", + 1170: "WindowWillMiniaturize", + 1171: "WindowWillMove", + 1172: "WindowWillOrderOffScreen", + 1173: "WindowWillOrderOnScreen", + 1174: "WindowWillResignMain", + 1175: "WindowWillResize", + 1176: "WindowWillUnfocus", + 1177: "WindowWillUpdate", + 1178: "WindowWillUpdateAlpha", + 1179: "WindowWillUpdateCollectionBehavior", + 1180: "WindowWillUpdateCollectionProperties", + 1181: "WindowWillUpdateShadow", + 1182: "WindowWillUpdateTitle", + 1183: "WindowWillUpdateToolbar", + 1184: "WindowWillUpdateVisibility", + 1185: "WindowWillUseStandardFrame", + 1186: "WindowZoomIn", + 1187: "WindowZoomOut", + 1188: "WindowZoomReset", + 1189: "APMPowerSettingChange", + 1190: "APMPowerStatusChange", + 1191: "APMResumeAutomatic", + 1192: "APMResumeSuspend", + 1193: "APMSuspend", + 1194: "ApplicationStarted", + 1195: "SystemThemeChanged", + 1196: "WebViewNavigationCompleted", + 1197: "WindowActive", + 1198: "WindowBackgroundErase", + 1199: "WindowClickActive", + 1200: "WindowClosing", + 1201: "WindowDidMove", + 1202: "WindowDidResize", + 1203: "WindowDPIChanged", + 1204: "WindowDragDrop", + 1205: "WindowDragEnter", + 1206: "WindowDragLeave", + 1207: "WindowDragOver", + 1208: "WindowEndMove", + 1209: "WindowEndResize", + 1210: "WindowFullscreen", + 1211: "WindowHide", + 1212: "WindowInactive", + 1213: "WindowKeyDown", + 1214: "WindowKeyUp", + 1215: "WindowKillFocus", + 1216: "WindowNonClientHit", + 1217: "WindowNonClientMouseDown", + 1218: "WindowNonClientMouseLeave", + 1219: "WindowNonClientMouseMove", + 1220: "WindowNonClientMouseUp", + 1221: "WindowPaint", + 1222: "WindowRestore", + 1223: "WindowSetFocus", + 1224: "WindowShow", + 1225: "WindowStartMove", + 1226: "WindowStartResize", + 1227: "WindowUnFullscreen", + 1228: "WindowZOrderChanged", + 1229: "WindowMinimise", + 1230: "WindowUnMinimise", + 1231: "WindowMaximise", + 1232: "WindowUnMaximise", } + diff --git a/v3/pkg/events/events.txt b/v3/pkg/events/events.txt index 91c39ba0c..3478d3838 100644 --- a/v3/pkg/events/events.txt +++ b/v3/pkg/events/events.txt @@ -1,5 +1,6 @@ common:ApplicationOpenedWithFile common:ApplicationStarted +common:ApplicationLaunchedWithUrl common:ThemeChanged common:WindowClosing common:WindowDidMove