mirror of
https://github.com/taigrr/wails.git
synced 2026-04-03 05:38:56 -07:00
Compare commits
213 Commits
v2.0.0-bet
...
v2-mac-doc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a020b67f67 | ||
|
|
fa958e7a07 | ||
|
|
1a3e81a3f8 | ||
|
|
0eb7a8a771 | ||
|
|
2fa004808f | ||
|
|
cc5fd30256 | ||
|
|
c90bfc310a | ||
|
|
62d1d621aa | ||
|
|
6e8cbb8e8f | ||
|
|
32fa543164 | ||
|
|
04f93ac54e | ||
|
|
3c87d13b21 | ||
|
|
0949eab72e | ||
|
|
aab67b416f | ||
|
|
83a575e43f | ||
|
|
333949ee53 | ||
|
|
1d1238cea3 | ||
|
|
bd7b436631 | ||
|
|
c136df48b9 | ||
|
|
a090a689cf | ||
|
|
5ef2448a0c | ||
|
|
06ab4c88ad | ||
|
|
48efdea11a | ||
|
|
43cc55cb0a | ||
|
|
71f2436562 | ||
|
|
4653c77a81 | ||
|
|
72b05c6b44 | ||
|
|
b5f68e24d6 | ||
|
|
3948c8ca61 | ||
|
|
cf3a868e3a | ||
|
|
43c29abb23 | ||
|
|
7ef445f526 | ||
|
|
f6c2d4ae6b | ||
|
|
8f9fae6ad9 | ||
|
|
b45f264e2a | ||
|
|
986f8f48c7 | ||
|
|
bbc2e86286 | ||
|
|
2dc126bf19 | ||
|
|
86cbcdc089 | ||
|
|
1dd957f461 | ||
|
|
4be4946756 | ||
|
|
65979cbc75 | ||
|
|
6a7118ff6d | ||
|
|
a88b3553ba | ||
|
|
fd5348d26d | ||
|
|
569569f1fc | ||
|
|
489b9b358b | ||
|
|
71cfdfc7c8 | ||
|
|
6ebf4ed428 | ||
|
|
5be0739c5d | ||
|
|
6721e59277 | ||
|
|
77775d85ab | ||
|
|
6de0865c3e | ||
|
|
f9e559f069 | ||
|
|
9a4c603001 | ||
|
|
98a95e99a5 | ||
|
|
d19c982eed | ||
|
|
a963836e75 | ||
|
|
00e9eb4b0b | ||
|
|
262b6281e1 | ||
|
|
f66c70f0be | ||
|
|
717d373668 | ||
|
|
d29fa94aa4 | ||
|
|
01dd0cd0b2 | ||
|
|
126cc78d1a | ||
|
|
5703d465fc | ||
|
|
0c2963cf53 | ||
|
|
b61fd16936 | ||
|
|
3a8ba96cb3 | ||
|
|
3b1d74cf84 | ||
|
|
2e0a6f95a0 | ||
|
|
8470bfb26b | ||
|
|
bea0c1446a | ||
|
|
35ebbdfa12 | ||
|
|
bb25b3f42f | ||
|
|
4a11f9bb20 | ||
|
|
c1a20d0509 | ||
|
|
32c3721b1b | ||
|
|
913cc56adf | ||
|
|
38f37e817b | ||
|
|
4e68f92083 | ||
|
|
3edbda313e | ||
|
|
04cde94c96 | ||
|
|
1faa962cf5 | ||
|
|
94a74520be | ||
|
|
27dd40fd29 | ||
|
|
616ecabb41 | ||
|
|
15cd325034 | ||
|
|
450eb2e7ae | ||
|
|
84622b829c | ||
|
|
a1323ce5e9 | ||
|
|
49629f6dc6 | ||
|
|
231848cb9e | ||
|
|
a51d8bb47d | ||
|
|
e0e4c0ae11 | ||
|
|
d47b3734af | ||
|
|
26d248a4b6 | ||
|
|
6413a6fb4d | ||
|
|
5e36f4fc7f | ||
|
|
b47c278c95 | ||
|
|
81a9619fd7 | ||
|
|
ce103af77b | ||
|
|
2649c3d17d | ||
|
|
a35cc035b0 | ||
|
|
a94a720a68 | ||
|
|
995fe38ee4 | ||
|
|
7fd311f7a6 | ||
|
|
356774e3f7 | ||
|
|
5d8653be83 | ||
|
|
8b5bcdfeff | ||
|
|
f6655d019f | ||
|
|
8f31183fa8 | ||
|
|
64528b4f02 | ||
|
|
7945853294 | ||
|
|
b0df3f5c39 | ||
|
|
7caf6af91d | ||
|
|
dd7c6a3d58 | ||
|
|
cfbeb1efd1 | ||
|
|
3022b0bf3f | ||
|
|
3723c41d15 | ||
|
|
2729081f2c | ||
|
|
cad1317fc8 | ||
|
|
1368c20029 | ||
|
|
0acfdd1516 | ||
|
|
212a20626a | ||
|
|
722ecc969b | ||
|
|
078145c030 | ||
|
|
3765c8fb57 | ||
|
|
10ac38c650 | ||
|
|
a16e41f813 | ||
|
|
1bd3deb39f | ||
|
|
be5f7ceb0e | ||
|
|
6943b657c9 | ||
|
|
a148c67df0 | ||
|
|
69297667c1 | ||
|
|
1ae9469e90 | ||
|
|
d597d8e1c9 | ||
|
|
d32152ed84 | ||
|
|
d28a7e8987 | ||
|
|
ef362a746a | ||
|
|
c16c95673e | ||
|
|
d426fc46b5 | ||
|
|
0efeed4d7f | ||
|
|
a11a75fa12 | ||
|
|
2d551cd019 | ||
|
|
37259b8adb | ||
|
|
d5cfcc80f7 | ||
|
|
25564b7211 | ||
|
|
661b24cfa2 | ||
|
|
75f703465a | ||
|
|
9949420639 | ||
|
|
9e347bf71f | ||
|
|
829fd8616b | ||
|
|
ae980d48fd | ||
|
|
ba9e64f53a | ||
|
|
b15d98b555 | ||
|
|
bdda454f69 | ||
|
|
a59d01ddb9 | ||
|
|
27f8df2b31 | ||
|
|
1b28f69236 | ||
|
|
7572b64bec | ||
|
|
f6b83b0933 | ||
|
|
a51ab25e2c | ||
|
|
aeaaccb942 | ||
|
|
4bf3eb303b | ||
|
|
b5437ed1b5 | ||
|
|
e2e752dd06 | ||
|
|
9dc2caecf0 | ||
|
|
b0da974a7d | ||
|
|
b4dc8c252a | ||
|
|
afb1d12c3b | ||
|
|
7a0cb428f2 | ||
|
|
e6a89790e3 | ||
|
|
daede02c16 | ||
|
|
417895f40b | ||
|
|
6bc26aa669 | ||
|
|
a641deb388 | ||
|
|
e013ce14a1 | ||
|
|
9930ee10da | ||
|
|
de6c57771e | ||
|
|
c8359b0743 | ||
|
|
12b7cf09e6 | ||
|
|
28af34f978 | ||
|
|
49b1acc147 | ||
|
|
0ee3015c7d | ||
|
|
4aa1464b48 | ||
|
|
7b52995c86 | ||
|
|
23c1ebfac9 | ||
|
|
3de31613a1 | ||
|
|
9a54f289c4 | ||
|
|
4a740e6186 | ||
|
|
34e622455f | ||
|
|
b13d8ef9fa | ||
|
|
4898bfdf9c | ||
|
|
28ff364faa | ||
|
|
f254cb086a | ||
|
|
15615eb450 | ||
|
|
37987b3827 | ||
|
|
48cf60ac7c | ||
|
|
368195e5bd | ||
|
|
97765c77e5 | ||
|
|
962ad1ea81 | ||
|
|
eba822da0b | ||
|
|
7b052e7a2d | ||
|
|
481eaa5ade | ||
|
|
7311868636 | ||
|
|
3caa0f1438 | ||
|
|
b8ef90cb41 | ||
|
|
9efc648e3d | ||
|
|
baa96f47d8 | ||
|
|
184ce763c1 | ||
|
|
229ee95f91 | ||
|
|
ed4b74f01b |
35
.github/workflows/deploy-website-to-wails.top-mirror.yml
vendored
Normal file
35
.github/workflows/deploy-website-to-wails.top-mirror.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
name: Deploy mirror | 部署镜像
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
# pull_request:
|
||||
# branches: [ main ]
|
||||
|
||||
jobs:
|
||||
build-and-deploy:
|
||||
name: Automatic deployment | 自动部署
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'misitebao/wails'
|
||||
|
||||
steps:
|
||||
- name: Checkout | 切换到部署分支
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
ref: "master"
|
||||
submodules: true
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build Site | 构建网站
|
||||
run: |
|
||||
cd website &&
|
||||
npm install && npm run build
|
||||
|
||||
- name: Deploy to Server | 部署到服务器
|
||||
uses: hengkx/ssh-deploy@v1.0.1
|
||||
with:
|
||||
HOST: ${{ secrets.DEPLOY_HOST }}
|
||||
USERNAME: ${{ secrets.DEPLOY_HOST_USER }}
|
||||
PASSWORD: ${{ secrets.DEPLOY_HOST_PASSWORD }}
|
||||
SOURCE: "website/build"
|
||||
TARGET: "/www/wwwroot/wails.top"
|
||||
10
.github/workflows/latest-pre.yml
vendored
10
.github/workflows/latest-pre.yml
vendored
@@ -15,11 +15,11 @@ jobs:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.16
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.16
|
||||
id: go
|
||||
- name: Set up Go 1.16
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.16
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v1
|
||||
|
||||
12
.github/workflows/pr.yml
vendored
12
.github/workflows/pr.yml
vendored
@@ -13,11 +13,11 @@ jobs:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.16
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.16
|
||||
id: go
|
||||
- name: Set up Go 1.16
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.16
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v1
|
||||
@@ -29,4 +29,4 @@ jobs:
|
||||
run: go build -v ./cmd/wails
|
||||
|
||||
- name: Test
|
||||
run: ./wails version
|
||||
run: ./wails version
|
||||
|
||||
12
.github/workflows/release.yml
vendored
12
.github/workflows/release.yml
vendored
@@ -15,11 +15,11 @@ jobs:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.16
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.16
|
||||
id: go
|
||||
- name: Set up Go 1.16
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.16
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v1
|
||||
@@ -31,4 +31,4 @@ jobs:
|
||||
run: go build -v ./cmd/wails
|
||||
|
||||
- name: Test
|
||||
run: ./wails version
|
||||
run: ./wails version
|
||||
|
||||
175
README.md
175
README.md
@@ -1,5 +1,5 @@
|
||||
<p align="center" style="text-align: center">
|
||||
<img src="logo_cropped.png" width="40%"><br/>
|
||||
<img src="logo.png" width="55%"><br/>
|
||||
</p>
|
||||
<p align="center">
|
||||
Build desktop applications using Go & Web Technologies.<br/><br/>
|
||||
@@ -18,40 +18,57 @@
|
||||
|
||||
## Internationalization
|
||||
|
||||
English | [简体中文](README.zh-Hans.md)
|
||||
[English](README.md) | [简体中文](README.zh-Hans.md)
|
||||
|
||||
<span id="nav-2"></span>
|
||||
|
||||
## Table of Contents
|
||||
|
||||
<details>
|
||||
<summary>Click me to Open/Close the directory listing</summary>
|
||||
|
||||
- [1. Internationalization](#nav-1)
|
||||
- [2. Table of Contents](#nav-2)
|
||||
- [3. Introduction](#nav-3)
|
||||
- [3.1 Official Website](#nav-3-1)
|
||||
- [4. Features](#nav-4)
|
||||
- [5. Sponsors](#nav-5)
|
||||
- [6. Installation](#nav-6)
|
||||
- [6.1 MacOS](#nav-6-1)
|
||||
- [6.2 Linux](#nav-6-2)
|
||||
- [6.2.1 Debian/Ubuntu](#nav-6-2-1)
|
||||
- [6.2.2 Arch Linux / ArchLabs / Ctlos Linux](#nav-6-2-2)
|
||||
- [6.2.3 Centos](#nav-6-2-3)
|
||||
- [6.2.4 Fedora](#nav-6-2-4)
|
||||
- [6.2.5 VoidLinux & VoidLinux-musl](#nav-6-2-5)
|
||||
- [6.2.6 Gentoo](#nav-6-2-6)
|
||||
- [6.3 Windows](#nav-6-3)
|
||||
- [7. Usage](#nav-7)
|
||||
- [7.1 Next Steps](#nav-7-1)
|
||||
- [8. FAQ](#nav-8)
|
||||
- [9. Contributors](#nav-9)
|
||||
- [10. Special Mentions](#nav-10)
|
||||
- [12. Special Thanks](#nav-11)
|
||||
|
||||
</details>
|
||||
|
||||
<span id="nav-3"></span>
|
||||
|
||||
## Introductions
|
||||
|
||||
The traditional method of providing web interfaces to Go programs is via a built-in web server. Wails offers a different
|
||||
approach: it provides the ability to wrap both Go code and a web frontend into a single binary. Tools are provided to
|
||||
make this easy for you by handling project creation, compilation and bundling. All you have to do is get creative!
|
||||
|
||||
<span id="nav-3-1"></span>
|
||||
|
||||
### Official Website
|
||||
|
||||
The official docs can be found at [https://wails.app](https://wails.app).
|
||||
|
||||
<span id="nav-2"></span>
|
||||
Click [here](https://wails.io) if you are interested in trying out v2 Beta for Windows.
|
||||
|
||||
## Contents
|
||||
|
||||
- [1. Internationalization](#nav-1)
|
||||
- [2. Contents](#nav-2)
|
||||
- [3. Features](#nav-3)
|
||||
- [4. Sponsors](#nav-4)
|
||||
- [5. Installation](#nav-5)
|
||||
- [5.1 MacOS](#nav-5-1)
|
||||
- [5.2 Linux](#nav-5-2)
|
||||
- [5.2.1 Debian/Ubuntu](#nav-5-2-1)
|
||||
- [5.2.2 Arch Linux / ArchLabs / Ctlos Linux](#nav-5-2-2)
|
||||
- [5.2.3 Centos](#nav-5-2-3)
|
||||
- [5.2.4 Fedora](#nav-5-2-4)
|
||||
- [5.2.5 VoidLinux & VoidLinux-musl](#nav-5-2-5)
|
||||
- [5.2.6 Gentoo](#nav-5-2-6)
|
||||
- [5.3 Windows](#nav-5-3)
|
||||
- [6. Installation](#nav-6)
|
||||
- [7. Next Steps](#nav-7)
|
||||
- [8. FAQ](#nav-8)
|
||||
- [9. Contributors](#nav-9)
|
||||
- [10. Special Mentions](#nav-10)
|
||||
- [11. Special Thanks](#nav-11)
|
||||
|
||||
<span id="nav-3"></span>
|
||||
<span id="nav-4"></span>
|
||||
|
||||
## Features
|
||||
|
||||
@@ -65,7 +82,7 @@ The official docs can be found at [https://wails.app](https://wails.app).
|
||||
- Powerful cli tool
|
||||
- Multiplatform
|
||||
|
||||
<span id="nav-4"></span>
|
||||
<span id="nav-5"></span>
|
||||
|
||||
## Sponsors
|
||||
|
||||
@@ -77,48 +94,70 @@ This project is supported by these kind people / companies:
|
||||
<a href="https://github.com/snider" style="width:100px;">
|
||||
<img src="https://github.com/snider.png?size=100" width="100"/>
|
||||
</a>
|
||||
<a href="https://github.com/codydbentley" style="width:100px">
|
||||
<img src="https://github.com/codydbentley.png?size=100" width="100"/>
|
||||
</a>
|
||||
<br/>
|
||||
<br/>
|
||||
<a href="https://github.com/matryer" style="width:100px">
|
||||
<img src="https://github.com/matryer.png" width="100"/>
|
||||
</a>
|
||||
<a href="https://www.jetbrains.com?from=Wails" style="width:100px">
|
||||
<img src="jetbrains-grayscale.png" width="100"/>
|
||||
<img src="/img/jetbrains-grayscale.png" width="100"/>
|
||||
</a>
|
||||
<a href="https://github.com/tc-hib" style="width:55px;border-radius: 50%">
|
||||
<img src="https://github.com/tc-hib.png?size=55" width="55" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/tc-hib" style="width:55px">
|
||||
<img src="https://github.com/tc-hib.png?size=55" width="55"/>
|
||||
</a>
|
||||
<a href="https://github.com/picatz" style="width:50px;border-radius: 50%">
|
||||
<img src="https://github.com/picatz.png?size=50" width="50" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/picatz" style="width:50px">
|
||||
<img src="https://github.com/picatz.png?size=50" width="50"/>
|
||||
</a>
|
||||
<a href="https://github.com/tylertravisty" style="width:50px;border-radius: 50%">
|
||||
<img src="https://github.com/tylertravisty.png?size=50" width="50" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/tylertravisty" style="width:50px">
|
||||
<img src="https://github.com/tylertravisty.png?size=50" width="50"/>
|
||||
</a>
|
||||
<a href="https://github.com/akhudek" style="width:50px;border-radius: 50%">
|
||||
<img src="https://github.com/akhudek.png?size=50" width="50" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/akhudek" style="width:50px">
|
||||
<img src="https://github.com/akhudek.png?size=50" width="50"/>
|
||||
</a>
|
||||
<a href="https://github.com/trea" style="width:50px;border-radius: 50%">
|
||||
<img src="https://github.com/trea.png?size=50" width="50" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/trea" style="width:50px">
|
||||
<img src="https://github.com/trea.png?size=50" width="50"/>
|
||||
</a>
|
||||
<a href="https://github.com/LanguageAgnostic" style="width:55px;border-radius: 50%">
|
||||
<img src="https://github.com/LanguageAgnostic.png?size=55" width="55" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/LanguageAgnostic" style="width:55px">
|
||||
<img src="https://github.com/LanguageAgnostic.png?size=55" width="55"/>
|
||||
</a>
|
||||
<a href="https://github.com/fcjr" style="width:55px;border-radius: 50%">
|
||||
<img src="https://github.com/fcjr.png?size=55" width="55" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/fcjr" style="width:55px">
|
||||
<img src="https://github.com/fcjr.png?size=55" width="55"/>
|
||||
</a>
|
||||
<a href="https://github.com/nickarellano" style="width:60px;border-radius: 50%">
|
||||
<img src="https://github.com/nickarellano.png?size=60" width="60" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/nickarellano" style="width:60px">
|
||||
<img src="https://github.com/nickarellano.png?size=60" width="60"/>
|
||||
</a>
|
||||
<a href="https://github.com/bglw" style="width:65px;border-radius: 50%">
|
||||
<img src="https://github.com/bglw.png?size=65" width="65" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/bglw" style="width:65px">
|
||||
<img src="https://github.com/bglw.png?size=65" width="65"/>
|
||||
</a>
|
||||
<a href="https://github.com/jugglingjsons" style="width:50px;border-radius: 50%">
|
||||
<img src="https://github.com/jugglingjsons.png?size=50" width="50" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/jugglingjsons" style="width:50px">
|
||||
<img src="https://github.com/jugglingjsons.png?size=50" width="50"/>
|
||||
</a>
|
||||
<a href="https://github.com/marcus-crane" style="width:50px;border-radius: 50%">
|
||||
<img src="https://github.com/marcus-crane.png?size=50" width="50" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/marcus-crane" style="width:65px">
|
||||
<img src="https://github.com/marcus-crane.png?size=65" width="65"/>
|
||||
</a>
|
||||
<a href="https://github.com/bbergshaven" style="width:45px">
|
||||
<img src="https://github.com/bbergshaven.png?size=45" width="45"/>
|
||||
</a>
|
||||
<a href="https://github.com/Gilgames000" style="width:45px">
|
||||
<img src="https://github.com/Gilgames000.png?size=45" width="45"/>
|
||||
</a>
|
||||
<a href="https://github.com/ilgityildirim" style="width:50px">
|
||||
<img src="https://github.com/ilgityildirim.png?size=50" width="50"/>
|
||||
</a>
|
||||
<a href="https://github.com/ondoki" style="width:65px">
|
||||
<img src="https://github.com/ondoki.png?size=65" width="65"/>
|
||||
</a>
|
||||
<a href="https://github.com/questrail" style="width:50px">
|
||||
<img src="https://github.com/questrail.png?size=50" width="50"/>
|
||||
</a>
|
||||
<a href="https://github.com/DonTomato" style="width:45px">
|
||||
<img src="https://github.com/DonTomato.png?size=45" width="45"/>
|
||||
</a>
|
||||
|
||||
<span id="nav-5"></span>
|
||||
<span id="nav-6"></span>
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -128,7 +167,7 @@ an installation of Go. The basic requirements are:
|
||||
- Go 1.16
|
||||
- npm
|
||||
|
||||
<span id="nav-5-1"></span>
|
||||
<span id="nav-6-1"></span>
|
||||
|
||||
### MacOS
|
||||
|
||||
@@ -136,11 +175,11 @@ Make sure you have the xcode command line tools installed. This can be done by r
|
||||
|
||||
`xcode-select --install`
|
||||
|
||||
<span id="nav-5-2"></span>
|
||||
<span id="nav-6-2"></span>
|
||||
|
||||
### Linux
|
||||
|
||||
<span id="nav-5-2-1"></span>
|
||||
<span id="nav-6-2-1"></span>
|
||||
|
||||
#### Debian/Ubuntu
|
||||
|
||||
@@ -152,7 +191,7 @@ _Ubuntu: 16.04, 18.04, 19.04_
|
||||
|
||||
_Also succesfully tested on: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali, Neon_, Pop!\_OS
|
||||
|
||||
<span id="nav-5-2-2"></span>
|
||||
<span id="nav-6-2-2"></span>
|
||||
|
||||
#### Arch Linux / ArchLabs / Ctlos Linux
|
||||
|
||||
@@ -160,7 +199,7 @@ _Also succesfully tested on: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, K
|
||||
|
||||
_Also succesfully test on: Manjaro & ArcoLinux_
|
||||
|
||||
<span id="nav-5-2-3"></span>
|
||||
<span id="nav-6-2-3"></span>
|
||||
|
||||
#### Centos
|
||||
|
||||
@@ -168,7 +207,7 @@ _Also succesfully test on: Manjaro & ArcoLinux_
|
||||
|
||||
_CentOS 6, 7_
|
||||
|
||||
<span id="nav-5-2-4"></span>
|
||||
<span id="nav-6-2-4"></span>
|
||||
|
||||
#### Fedora
|
||||
|
||||
@@ -176,19 +215,19 @@ _CentOS 6, 7_
|
||||
|
||||
_Fedora 29, 30_
|
||||
|
||||
<span id="nav-5-2-5"></span>
|
||||
<span id="nav-6-2-5"></span>
|
||||
|
||||
#### VoidLinux & VoidLinux-musl
|
||||
|
||||
`xbps-install gtk+3-devel webkit2gtk-devel`
|
||||
|
||||
<span id="nav-5-2-6"></span>
|
||||
<span id="nav-6-2-6"></span>
|
||||
|
||||
#### Gentoo
|
||||
|
||||
`sudo emerge gtk+:3 webkit-gtk`
|
||||
|
||||
<span id="nav-5-3"></span>
|
||||
<span id="nav-6-3"></span>
|
||||
|
||||
### Windows
|
||||
|
||||
@@ -196,21 +235,21 @@ Windows requires gcc and related tooling. The recommended download is
|
||||
from [http://tdm-gcc.tdragon.net/download](http://tdm-gcc.tdragon.net/download). Once this is installed, you are good to
|
||||
go.
|
||||
|
||||
<span id="nav-6"></span>
|
||||
<span id="nav-7"></span>
|
||||
|
||||
## Installation
|
||||
## Usage
|
||||
|
||||
**Ensure Go modules are enabled: GO111MODULE=on and go/bin is in your PATH variable.**
|
||||
|
||||
Installation is as simple as running the following command:
|
||||
|
||||
<pre style='color:white'>
|
||||
```
|
||||
go get -u github.com/wailsapp/wails/cmd/wails
|
||||
</pre>
|
||||
```
|
||||
|
||||
<span id="nav-7"></span>
|
||||
<span id="nav-7-1"></span>
|
||||
|
||||
## Next Steps
|
||||
### Next Steps
|
||||
|
||||
It is recommended at this stage to read the comprehensive documentation at [https://wails.app](https://wails.app).
|
||||
|
||||
@@ -321,7 +360,7 @@ This project was mainly coded to the following albums:
|
||||
|
||||
<p align="center" style="text-align: center">
|
||||
<a href="https://pace.dev"><img src="pace.jpeg"/></a><br/>
|
||||
A <i>huge<i/> thanks to <a href="https://pace.dev">Pace</a> for sponsoring the project and helping the efforts to get Wails ported to Apple Silicon!<br/><br/>
|
||||
A <i>huge</i> thanks to <a href="https://pace.dev">Pace</a> for sponsoring the project and helping the efforts to get Wails ported to Apple Silicon!<br/><br/>
|
||||
If you are looking for a Project Management tool that's powerful but quick and easy to use, check them out!<br/><br/>
|
||||
</p>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<p align="center" style="text-align: center">
|
||||
<img src="logo_cropped.png" width="40%"><br/>
|
||||
<img src="logo.png" width="55%"><br/>
|
||||
</p>
|
||||
<p align="center">
|
||||
使用 Go 和 Web 技术构建桌面应用程序。<br/><br/>
|
||||
@@ -18,44 +18,62 @@
|
||||
|
||||
## 国际化
|
||||
|
||||
[English](README.md) | 简体中文
|
||||
|
||||
向 Go 程序提供 Web 接口的传统方法是通过内置 Web 服务器。Wails 提供了一种不同的方法:它提供了将 Go 代码和 Web
|
||||
前端都包装成单个二进制文件的能力。通过提供工具,可以很轻松的完成项目的创建、编译和打包。你所要做的就是发挥创意!
|
||||
|
||||
官方文档可以在 [https://wails.app](https://wails.app) 中找到。
|
||||
|
||||
国内镜像站点 [https://wails.top](https://wails.top)。
|
||||
[English](README.md) | [简体中文](README.zh-Hans.md)
|
||||
|
||||
<span id="nav-2"></span>
|
||||
|
||||
## 内容目录
|
||||
|
||||
<details>
|
||||
<summary>点我 打开/关闭 目录列表</summary>
|
||||
|
||||
- [1. 国际化](#nav-1)
|
||||
- [2. 内容目录](#nav-2)
|
||||
- [3. 特征](#nav-3)
|
||||
- [4. 赞助商](#nav-4)
|
||||
- [5. 安装](#nav-5)
|
||||
- [5.1 MacOS](#nav-5-1)
|
||||
- [5.2 Linux](#nav-5-2)
|
||||
- [5.2.1 Debian/Ubuntu](#nav-5-2-1)
|
||||
- [5.2.2 Arch Linux / ArchLabs / Ctlos Linux](#nav-5-2-2)
|
||||
- [5.2.3 Centos](#nav-5-2-3)
|
||||
- [5.2.4 Fedora](#nav-5-2-4)
|
||||
- [5.2.5 VoidLinux & VoidLinux-musl](#nav-5-2-5)
|
||||
- [5.2.6 Gentoo](#nav-5-2-6)
|
||||
- [5.3 Windows](#nav-5-3)
|
||||
- [3. 项目介绍](#nav-3)
|
||||
- [3.1 官方网站](#nav-3-1)
|
||||
- [4. 功能](#nav-4)
|
||||
- [5. 赞助商](#nav-5)
|
||||
- [6. 安装](#nav-6)
|
||||
- [7. 下一步](#nav-7)
|
||||
- [6.1 MacOS](#nav-6-1)
|
||||
- [6.2 Linux](#nav-6-2)
|
||||
- [6.2.1 Debian/Ubuntu](#nav-6-2-1)
|
||||
- [6.2.2 Arch Linux / ArchLabs / Ctlos Linux](#nav-6-2-2)
|
||||
- [6.2.3 Centos](#nav-6-2-3)
|
||||
- [6.2.4 Fedora](#nav-6-2-4)
|
||||
- [6.2.5 VoidLinux & VoidLinux-musl](#nav-6-2-5)
|
||||
- [6.2.6 Gentoo](#nav-6-2-6)
|
||||
- [6.3 Windows](#nav-6-3)
|
||||
- [7. 使用方法](#nav-7)
|
||||
- [7.1 下一步](#nav-7-1)
|
||||
- [8. 常见问题](#nav-8)
|
||||
- [9. 贡献者](#nav-9)
|
||||
- [10. 特别提及](#nav-10)
|
||||
- [11. 许可协议](#nav-11)
|
||||
- [12. 特别感谢](#nav-12)
|
||||
- [12. 特别感谢](#nav-11)
|
||||
|
||||
</details>
|
||||
|
||||
<span id="nav-3"></span>
|
||||
|
||||
## 特征
|
||||
## 项目介绍
|
||||
|
||||
为 Go 程序提供 Web 界面的传统方法是通过内置 Web 服务器。Wails 提供了一种不同的方法:它提供了将 Go 代码和 Web
|
||||
前端一起打包成单个二进制文件的能力。通过提供的工具,可以很轻松的完成项目的创建、编译和打包。你所要做的就是发挥想象力!
|
||||
|
||||
<span id="nav-3-1"></span>
|
||||
|
||||
### 官方网站
|
||||
|
||||
官方文档可以在 [https://wails.app](https://wails.app) 中找到。
|
||||
|
||||
如果您对适用于 Windows 的 v2 测试版感兴趣,可以点击[此处](https://wails.io)查看。
|
||||
|
||||
镜像网站:
|
||||
|
||||
- [中国大陆镜像站点 - https://wails.top](https://wails.top)
|
||||
|
||||
<span id="nav-4"></span>
|
||||
|
||||
## 功能
|
||||
|
||||
- 后端使用标准 Go
|
||||
- 使用任意前端技术构建 UI 界面
|
||||
@@ -67,56 +85,82 @@
|
||||
- 强大的命令行工具
|
||||
- 跨多个平台
|
||||
|
||||
<span id="nav-4"></span>
|
||||
<span id="nav-5"></span>
|
||||
|
||||
## 赞助商
|
||||
|
||||
这个项目由以下这些人或者公司支持:
|
||||
|
||||
<a href="https://github.com/sponsors/leaanthony" style="width:100px;">
|
||||
<img src="sponsors/bronze%20sponsor.png" width="100"/>
|
||||
</a>
|
||||
<a href="https://github.com/snider" style="width:100px;">
|
||||
<img src="https://github.com/snider.png?size=100" width="100"/>
|
||||
</a>
|
||||
<a href="https://github.com/codydbentley" style="width:100px">
|
||||
<img src="https://github.com/codydbentley.png?size=100" width="100"/>
|
||||
</a>
|
||||
<br/>
|
||||
<br/>
|
||||
<a href="https://github.com/matryer" style="width:100px">
|
||||
<img src="https://github.com/matryer.png" width="100"/>
|
||||
</a>
|
||||
<a href="https://www.jetbrains.com?from=Wails" style="width:100px">
|
||||
<img src="jetbrains-grayscale.png" width="100"/>
|
||||
<img src="/img/jetbrains-grayscale.png" width="100"/>
|
||||
</a>
|
||||
<a href="https://github.com/tc-hib" style="width:55px;border-radius: 50%">
|
||||
<img src="https://github.com/tc-hib.png?size=55" width="55" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/tc-hib" style="width:55px">
|
||||
<img src="https://github.com/tc-hib.png?size=55" width="55"/>
|
||||
</a>
|
||||
<a href="https://github.com/picatz" style="width:50px;border-radius: 50%">
|
||||
<img src="https://github.com/picatz.png?size=50" width="50" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/picatz" style="width:50px">
|
||||
<img src="https://github.com/picatz.png?size=50" width="50"/>
|
||||
</a>
|
||||
<a href="https://github.com/tylertravisty" style="width:50px;border-radius: 50%">
|
||||
<img src="https://github.com/tylertravisty.png?size=50" width="50" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/tylertravisty" style="width:50px">
|
||||
<img src="https://github.com/tylertravisty.png?size=50" width="50"/>
|
||||
</a>
|
||||
<a href="https://github.com/akhudek" style="width:50px;border-radius: 50%">
|
||||
<img src="https://github.com/akhudek.png?size=50" width="50" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/akhudek" style="width:50px">
|
||||
<img src="https://github.com/akhudek.png?size=50" width="50"/>
|
||||
</a>
|
||||
<a href="https://github.com/trea" style="width:50px;border-radius: 50%">
|
||||
<img src="https://github.com/trea.png?size=50" width="50" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/trea" style="width:50px">
|
||||
<img src="https://github.com/trea.png?size=50" width="50"/>
|
||||
</a>
|
||||
<a href="https://github.com/LanguageAgnostic" style="width:55px;border-radius: 50%">
|
||||
<img src="https://github.com/LanguageAgnostic.png?size=55" width="55" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/LanguageAgnostic" style="width:55px">
|
||||
<img src="https://github.com/LanguageAgnostic.png?size=55" width="55"/>
|
||||
</a>
|
||||
<a href="https://github.com/snider" style="width:60px;border-radius: 50%">
|
||||
<img src="https://github.com/snider.png?size=60" width="60" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/fcjr" style="width:55px">
|
||||
<img src="https://github.com/fcjr.png?size=55" width="55"/>
|
||||
</a>
|
||||
<a href="https://github.com/fcjr" style="width:55px;border-radius: 50%">
|
||||
<img src="https://github.com/fcjr.png?size=55" width="55" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/nickarellano" style="width:60px">
|
||||
<img src="https://github.com/nickarellano.png?size=60" width="60"/>
|
||||
</a>
|
||||
<a href="https://github.com/nickarellano" style="width:60px;border-radius: 50%">
|
||||
<img src="https://github.com/nickarellano.png?size=60" width="60" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/bglw" style="width:65px">
|
||||
<img src="https://github.com/bglw.png?size=65" width="65"/>
|
||||
</a>
|
||||
<a href="https://github.com/bglw" style="width:65px;border-radius: 50%">
|
||||
<img src="https://github.com/bglw.png?size=65" width="65" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/jugglingjsons" style="width:50px">
|
||||
<img src="https://github.com/jugglingjsons.png?size=50" width="50"/>
|
||||
</a>
|
||||
<a href="https://github.com/jugglingjsons" style="width:50px;border-radius: 50%">
|
||||
<img src="https://github.com/jugglingjsons.png?size=50" width="50" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/marcus-crane" style="width:65px">
|
||||
<img src="https://github.com/marcus-crane.png?size=65" width="65"/>
|
||||
</a>
|
||||
<a href="https://github.com/marcus-crane" style="width:50px;border-radius: 50%">
|
||||
<img src="https://github.com/marcus-crane.png?size=50" width="50" style="border-radius: 50%"/>
|
||||
<a href="https://github.com/bbergshaven" style="width:45px">
|
||||
<img src="https://github.com/bbergshaven.png?size=45" width="45"/>
|
||||
</a>
|
||||
<a href="https://github.com/Gilgames000" style="width:45px">
|
||||
<img src="https://github.com/Gilgames000.png?size=45" width="45"/>
|
||||
</a>
|
||||
<a href="https://github.com/ilgityildirim" style="width:50px">
|
||||
<img src="https://github.com/ilgityildirim.png?size=50" width="50"/>
|
||||
</a>
|
||||
<a href="https://github.com/ondoki" style="width:65px">
|
||||
<img src="https://github.com/ondoki.png?size=65" width="65"/>
|
||||
</a>
|
||||
<a href="https://github.com/questrail" style="width:50px">
|
||||
<img src="https://github.com/questrail.png?size=50" width="50"/>
|
||||
</a>
|
||||
<a href="https://github.com/DonTomato" style="width:45px">
|
||||
<img src="https://github.com/DonTomato.png?size=45" width="45"/>
|
||||
</a>
|
||||
|
||||
<span id="nav-5"></span>
|
||||
<span id="nav-6"></span>
|
||||
|
||||
## 安装
|
||||
|
||||
@@ -125,7 +169,7 @@ Wails 使用 cgo 与原生渲染引擎结合,因此需要依赖一些平台的
|
||||
- Go 1.16
|
||||
- npm
|
||||
|
||||
<span id="nav-5-1"></span>
|
||||
<span id="nav-6-1"></span>
|
||||
|
||||
### MacOS
|
||||
|
||||
@@ -133,11 +177,11 @@ Wails 使用 cgo 与原生渲染引擎结合,因此需要依赖一些平台的
|
||||
|
||||
`xcode-select --install`
|
||||
|
||||
<span id="nav-5-2"></span>
|
||||
<span id="nav-6-2"></span>
|
||||
|
||||
### Linux
|
||||
|
||||
<span id="nav-5-2-1"></span>
|
||||
<span id="nav-6-2-1"></span>
|
||||
|
||||
#### Debian/Ubuntu
|
||||
|
||||
@@ -149,7 +193,7 @@ _Ubuntu: 16.04, 18.04, 19.04_
|
||||
|
||||
_也成功测试了: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali, Neon_, Pop!\_OS
|
||||
|
||||
<span id="nav-5-2-2"></span>
|
||||
<span id="nav-6-2-2"></span>
|
||||
|
||||
#### Arch Linux / ArchLabs / Ctlos Linux
|
||||
|
||||
@@ -157,7 +201,7 @@ _也成功测试了: Zorin 15, Parrot 4.7, Linuxmint 19, Elementary 5, Kali, Neo
|
||||
|
||||
_也成功测试了: Manjaro & ArcoLinux_
|
||||
|
||||
<span id="nav-5-2-3"></span>
|
||||
<span id="nav-6-2-3"></span>
|
||||
|
||||
#### Centos
|
||||
|
||||
@@ -165,7 +209,7 @@ _也成功测试了: Manjaro & ArcoLinux_
|
||||
|
||||
_CentOS 6, 7_
|
||||
|
||||
<span id="nav-5-2-4"></span>
|
||||
<span id="nav-6-2-4"></span>
|
||||
|
||||
#### Fedora
|
||||
|
||||
@@ -173,39 +217,39 @@ _CentOS 6, 7_
|
||||
|
||||
_Fedora 29, 30_
|
||||
|
||||
<span id="nav-5-2-5"></span>
|
||||
<span id="nav-6-2-5"></span>
|
||||
|
||||
#### VoidLinux & VoidLinux-musl
|
||||
|
||||
`xbps-install gtk+3-devel webkit2gtk-devel`
|
||||
|
||||
<span id="nav-5-2-6"></span>
|
||||
<span id="nav-6-2-6"></span>
|
||||
|
||||
#### Gentoo
|
||||
|
||||
`sudo emerge gtk+:3 webkit-gtk`
|
||||
|
||||
<span id="nav-5-3"></span>
|
||||
<span id="nav-6-3"></span>
|
||||
|
||||
### Windows
|
||||
|
||||
Windows 需要 GCC 和相关工具。 建议从 [http://tdm-gcc.tdragon.net/download](http://tdm-gcc.tdragon.net/download) 下载, 安装完成,您就可以开始了。
|
||||
|
||||
<span id="nav-6"></span>
|
||||
<span id="nav-7"></span>
|
||||
|
||||
## 安装
|
||||
## 使用方法
|
||||
|
||||
**确保 Go modules 是开启的:GO111MODULE=on 并且 go/bin 在您的 PATH 变量中。**
|
||||
|
||||
安装很简单,运行以下命令:
|
||||
|
||||
<pre style='color:white'>
|
||||
```
|
||||
go get -u github.com/wailsapp/wails/cmd/wails
|
||||
</pre>
|
||||
```
|
||||
|
||||
<span id="nav-7"></span>
|
||||
<span id="nav-7-1"></span>
|
||||
|
||||
## 下一步
|
||||
### 下一步
|
||||
|
||||
建议在此时阅读 [https://wails.app](https://wails.app) 上面的文档.
|
||||
|
||||
@@ -217,14 +261,14 @@ go get -u github.com/wailsapp/wails/cmd/wails
|
||||
|
||||
取决于您的要求。它旨在使 Go 程序员可以轻松制作轻量级桌面应用程序或在其现有应用程序中添加前端。尽管 Wails 当前不提供对诸如菜单之类的原生元素的钩子,但将来可能会改变。
|
||||
|
||||
- 这个项目针对的是谁?
|
||||
- 这个项目针对的是哪些人?
|
||||
|
||||
希望将 HTML / JS / CSS 前端与其应用程序捆绑在一起的程序员,而不是借助创建服务并打开浏览器进行查看的方式。
|
||||
|
||||
- 名字怎么来的?
|
||||
|
||||
当我看到 WebView 时,我想"我真正想要的是围绕构建 WebView 应用程序工作,有点像 Rails 对于 Ruby"。因此,最初它是一个文字游戏(Webview on
|
||||
Rails)。碰巧也是我来自的 [国家](https://en.wikipedia.org/wiki/Wales) 的英文名字的同音。所以就是他了。
|
||||
Rails)。碰巧也是我来自的 [国家](https://en.wikipedia.org/wiki/Wales) 的英文名字的同音。所以就是它了。
|
||||
|
||||
<span id="nav-9"></span>
|
||||
|
||||
@@ -275,6 +319,7 @@ go get -u github.com/wailsapp/wails/cmd/wails
|
||||
<a href="https://github.com/Igogrek"><img src="https://github.com/Igogrek.png?size=40" width="40"/></a></a>
|
||||
<a href="https://github.com/aschey"><img src="https://github.com/aschey.png?size=40" width="40"/></a></a>
|
||||
<a href="https://github.com/akhudek"><img src="https://github.com/akhudek.png?size=40" width="40"/></a></a>
|
||||
<a href="https://github.com/s12chung"><img src="https://github.com/s12chung.png?size=40" width="40"/></a></a>
|
||||
|
||||
<span id="nav-10"></span>
|
||||
|
||||
@@ -284,9 +329,9 @@ go get -u github.com/wailsapp/wails/cmd/wails
|
||||
|
||||
- [Dustin Krysak](https://wiki.ubuntu.com/bashfulrobot) - 他的支持和反馈是巨大的。
|
||||
- [Serge Zaitsev](https://github.com/zserge) - Wails 窗口所使用的 [Webview](https://github.com/zserge/webview) 的作者。
|
||||
- [Byron](https://github.com/bh90210) - 有时,Byron 单枪匹马地保持这个项目活着。没有他令人难以置信的投入,我们永远不会得到 v1 。
|
||||
- [Byron](https://github.com/bh90210) - 有时,Byron 一个人保持这个项目活跃着。没有他令人难以置信的投入,我们永远不会得到 v1 。
|
||||
|
||||
This project was mainly coded to the following albums:
|
||||
编写项目代码时伴随着以下专辑:
|
||||
|
||||
- [Manic Street Preachers - Resistance Is Futile](https://open.spotify.com/album/1R2rsEUqXjIvAbzM0yHrxA)
|
||||
- [Manic Street Preachers - This Is My Truth, Tell Me Yours](https://open.spotify.com/album/4VzCL9kjhgGQeKCiojK1YN)
|
||||
@@ -304,17 +349,11 @@ This project was mainly coded to the following albums:
|
||||
|
||||
<span id="nav-11"></span>
|
||||
|
||||
## 许可协议
|
||||
|
||||
[](https://app.fossa.io/projects/git%2Bgithub.com%2Fwailsapp%2Fwails?ref=badge_large)
|
||||
|
||||
<span id="nav-12"></span>
|
||||
|
||||
## 特别感谢
|
||||
|
||||
<p align="center" style="text-align: center">
|
||||
<a href="https://pace.dev"><img src="pace.jpeg"/></a><br/>
|
||||
<i>非常<i/>感谢<a href="https://pace.dev">Pace</a>对项目的赞助,并帮助将 Wails 移植到 Apple Silicon !<br/><br/>
|
||||
<i>非常</i> 感谢<a href="https://pace.dev">Pace</a>对项目的赞助,并帮助将 Wails 移植到 Apple Silicon !<br/><br/>
|
||||
如果您正在寻找一个强大并且快速和易于使用的项目管理工具,可以看看他们!<br/><br/>
|
||||
</p>
|
||||
|
||||
|
||||
21
cmd/linux.go
21
cmd/linux.go
@@ -71,6 +71,11 @@ const (
|
||||
Crux
|
||||
// RHEL distribution
|
||||
RHEL
|
||||
// NixOS distribution
|
||||
NixOS
|
||||
// Artix linux distribution
|
||||
ArtixLinux
|
||||
|
||||
)
|
||||
|
||||
// DistroInfo contains all the information relating to a linux distribution
|
||||
@@ -183,6 +188,10 @@ func parseOsRelease(osRelease string) *DistroInfo {
|
||||
result.Distribution = EndeavourOS
|
||||
case "crux":
|
||||
result.Distribution = Crux
|
||||
case "nixos":
|
||||
result.Distribution = NixOS
|
||||
case "artix":
|
||||
result.Distribution = ArtixLinux
|
||||
default:
|
||||
result.Distribution = Unknown
|
||||
}
|
||||
@@ -274,6 +283,18 @@ func PrtGetInstalled(packageName string) (bool, error) {
|
||||
return exitCode == 0, nil
|
||||
}
|
||||
|
||||
// NixEnvInstalled uses nix-env to see if a package is installed
|
||||
func NixEnvInstalled(packageName string) (bool, error) {
|
||||
program := NewProgramHelper()
|
||||
nixEnv := program.FindProgram("nix-env")
|
||||
if nixEnv == nil {
|
||||
return false, fmt.Errorf("cannot check dependencies: nix-env not found")
|
||||
}
|
||||
packageName = strings.ReplaceAll(packageName, "+", `\+`)
|
||||
_, _, exitCode, _ := nixEnv.Run("-q", packageName)
|
||||
return exitCode == 0, nil
|
||||
}
|
||||
|
||||
// RequestSupportForDistribution promts the user to submit a request to support their
|
||||
// currently unsupported distribution
|
||||
func RequestSupportForDistribution(distroInfo *DistroInfo) error {
|
||||
|
||||
@@ -213,6 +213,15 @@ distributions:
|
||||
gccversioncommand: *gccdumpversion
|
||||
programs: *archdefaultprograms
|
||||
libraries: *archdefaultlibraries
|
||||
artix:
|
||||
id: artix
|
||||
releases:
|
||||
default:
|
||||
version: default
|
||||
name: Artix Linux
|
||||
gccversioncommand: *gccdumpversion
|
||||
programs: *archdefaultprograms
|
||||
libraries: *archdefaultlibraries
|
||||
ctlos:
|
||||
id: ctlos
|
||||
releases:
|
||||
@@ -345,3 +354,22 @@ distributions:
|
||||
help: Please install with `sudo prt-get depinst gtk3` and try again
|
||||
- name: webkitgtk
|
||||
help: Please install with `sudo prt-get depinst webkitgtk` and try again
|
||||
nixos:
|
||||
id: nixos
|
||||
releases:
|
||||
default:
|
||||
version: default
|
||||
name: NixOS
|
||||
gccversioncommand: *gccdumpversion
|
||||
programs:
|
||||
- name: gcc
|
||||
help: Please install with `nix-env -iA nixos.gcc`
|
||||
- name: pkg-config
|
||||
help: Please install with `nix-env -iA nixos.pkg-config`
|
||||
- name: npm
|
||||
help: Please install with `nix-env -iA nixos.nodejs`
|
||||
libraries:
|
||||
- name: gtk+3
|
||||
help: Please install with `nix-env -iA nixos.gtk3`
|
||||
- name: webkitgtk
|
||||
help: Please install with `nix-env -iA nixos.nodePackages.webkitgtk`
|
||||
|
||||
@@ -281,7 +281,7 @@ func CheckDependencies(logger *Logger) (bool, error) {
|
||||
switch distroInfo.Distribution {
|
||||
case Ubuntu, Debian, Zorin, Parrot, Linuxmint, Elementary, Kali, Neon, Deepin, Raspbian, PopOS:
|
||||
libraryChecker = DpkgInstalled
|
||||
case Arch, ArcoLinux, ArchLabs, Ctlos, Manjaro, ManjaroARM, EndeavourOS:
|
||||
case Arch, ArcoLinux, ArchLabs, Ctlos, Manjaro, ManjaroARM, EndeavourOS, ArtixLinux:
|
||||
libraryChecker = PacmanInstalled
|
||||
case CentOS, Fedora, Tumbleweed, Leap, RHEL:
|
||||
libraryChecker = RpmInstalled
|
||||
@@ -293,6 +293,8 @@ func CheckDependencies(logger *Logger) (bool, error) {
|
||||
libraryChecker = EOpkgInstalled
|
||||
case Crux:
|
||||
libraryChecker = PrtGetInstalled
|
||||
case NixOS:
|
||||
libraryChecker = NixEnvInstalled
|
||||
default:
|
||||
return false, RequestSupportForDistribution(distroInfo)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package cmd
|
||||
|
||||
// Version - Wails version
|
||||
const Version = "v1.16.5"
|
||||
const Version = "v1.16.8"
|
||||
|
||||
@@ -15,6 +15,7 @@ func init() {
|
||||
projectOptions := projectHelper.NewProjectOptions()
|
||||
commandDescription := `Generates a new Wails project using the given flags.
|
||||
Any flags that are required and not given will be prompted for.`
|
||||
build := false
|
||||
|
||||
initCommand := app.Command("init", "Initialises a new Wails project").
|
||||
LongDescription(commandDescription).
|
||||
@@ -23,7 +24,8 @@ Any flags that are required and not given will be prompted for.`
|
||||
StringFlag("template", "Template name", &projectOptions.Template).
|
||||
StringFlag("name", "Project name", &projectOptions.Name).
|
||||
StringFlag("description", "Project description", &projectOptions.Description).
|
||||
StringFlag("output", "Output binary name", &projectOptions.BinaryName)
|
||||
StringFlag("output", "Output binary name", &projectOptions.BinaryName).
|
||||
BoolFlag("build", "Build project after generating", &build)
|
||||
|
||||
initCommand.Action(func() error {
|
||||
|
||||
@@ -64,6 +66,10 @@ Any flags that are required and not given will be prompted for.`
|
||||
return err
|
||||
}
|
||||
genSpinner.Success()
|
||||
if !build {
|
||||
logger.Yellow("Project '%s' initialised. Run `wails build` to build it.", projectOptions.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Build the project
|
||||
cwd, _ := os.Getwd()
|
||||
|
||||
7
go.mod
7
go.mod
@@ -5,7 +5,7 @@ require (
|
||||
github.com/abadojack/whatlanggo v1.0.1
|
||||
github.com/fatih/color v1.7.0
|
||||
github.com/go-playground/colors v1.2.0
|
||||
github.com/gorilla/websocket v1.4.0
|
||||
github.com/gorilla/websocket v1.4.1
|
||||
github.com/jackmordaunt/icns v1.0.0
|
||||
github.com/kennygrant/sanitize v1.2.4
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
|
||||
@@ -16,12 +16,13 @@ require (
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4
|
||||
github.com/pkg/errors v0.8.1 // indirect
|
||||
github.com/sirupsen/logrus v1.4.1
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/stretchr/objx v0.1.1 // indirect
|
||||
github.com/stretchr/testify v1.3.0 // indirect
|
||||
github.com/syossan27/tebata v0.0.0-20180602121909-b283fe4bc5ba
|
||||
golang.org/x/image v0.0.0-20200430140353-33d19683fad8
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344 // indirect
|
||||
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359
|
||||
golang.org/x/text v0.3.0
|
||||
gopkg.in/AlecAivazis/survey.v1 v1.8.4
|
||||
gopkg.in/yaml.v3 v3.0.0-20190709130402-674ba3eaed22
|
||||
|
||||
9
go.sum
9
go.sum
@@ -11,8 +11,8 @@ github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/go-playground/colors v1.2.0 h1:0EdjTXKrr2g1L/LQTYtIqabeHpZuGZz1U4osS1T8+5M=
|
||||
github.com/go-playground/colors v1.2.0/go.mod h1:miw1R2JIE19cclPxsXqNdzLZsk4DP4iF+m88bRc7kfM=
|
||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ=
|
||||
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
|
||||
github.com/jackmordaunt/icns v1.0.0 h1:RYSxplerf/l/DUd09AHtITwckkv/mqjVv4DjYdPmAMQ=
|
||||
@@ -54,6 +54,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
|
||||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
@@ -76,9 +78,12 @@ golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c h1:UIcGWL6/wpCfyGuJnRFJRurA+yj8RrW7Q6x2YMCXt6c=
|
||||
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
gopkg.in/AlecAivazis/survey.v1 v1.8.4 h1:10xXXN3wgIhPheb5NI58zFgZv32Ana7P3Tl4shW+0Qc=
|
||||
|
||||
@@ -54,7 +54,7 @@ extern "C"
|
||||
int ready;
|
||||
int js_busy;
|
||||
int should_exit;
|
||||
|
||||
|
||||
int min_width;
|
||||
int min_height;
|
||||
int max_width;
|
||||
@@ -179,7 +179,7 @@ struct webview_priv
|
||||
WEBVIEW_API int webview_inject_css(struct webview *w, const char *css);
|
||||
WEBVIEW_API void webview_set_title(struct webview *w, const char *title);
|
||||
WEBVIEW_API void webview_focus(struct webview *w);
|
||||
WEBVIEW_API void webview_minsize(struct webview *w, int width, int height);
|
||||
WEBVIEW_API void webview_minsize(struct webview *w, int width, int height);
|
||||
WEBVIEW_API void webview_maxsize(struct webview *w, int width, int height);
|
||||
WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen);
|
||||
WEBVIEW_API void webview_set_color(struct webview *w, uint8_t r, uint8_t g,
|
||||
@@ -342,12 +342,12 @@ struct webview_priv
|
||||
w->priv.should_exit = 0;
|
||||
w->priv.queue = g_async_queue_new();
|
||||
w->priv.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
|
||||
|
||||
w->priv.min_width = -1;
|
||||
w->priv.min_height = -1;
|
||||
w->priv.max_width = -1;
|
||||
w->priv.max_height = -1;
|
||||
|
||||
|
||||
gtk_window_set_title(GTK_WINDOW(w->priv.window), w->title);
|
||||
|
||||
if (w->resizable)
|
||||
@@ -421,13 +421,13 @@ struct webview_priv
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_minsize(struct webview *w, int width, int height) {
|
||||
|
||||
|
||||
w->priv.min_width = width;
|
||||
w->priv.min_height = height;
|
||||
|
||||
GdkGeometry hints;
|
||||
GdkWindowHints usedHints = (GdkWindowHints) GDK_HINT_MIN_SIZE;
|
||||
|
||||
|
||||
hints.min_width = w->priv.min_width;
|
||||
hints.min_height = w->priv.min_height;
|
||||
if (w->priv.max_width != -1) {
|
||||
@@ -435,18 +435,18 @@ struct webview_priv
|
||||
hints.max_height = w->priv.max_height;
|
||||
usedHints = (GdkWindowHints)(GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE);
|
||||
}
|
||||
|
||||
|
||||
gtk_window_set_geometry_hints(GTK_WINDOW(w->priv.window), w->priv.window, &hints, usedHints);
|
||||
}
|
||||
|
||||
WEBVIEW_API void webview_maxsize(struct webview *w, int width, int height) {
|
||||
|
||||
|
||||
w->priv.max_width = width;
|
||||
w->priv.max_height = height;
|
||||
|
||||
|
||||
GdkGeometry hints;
|
||||
GdkWindowHints usedHints = (GdkWindowHints) GDK_HINT_MAX_SIZE;
|
||||
|
||||
|
||||
if (w->priv.min_width != -1) {
|
||||
hints.min_width = w->priv.min_width;
|
||||
hints.min_height = w->priv.min_height;
|
||||
@@ -454,7 +454,7 @@ struct webview_priv
|
||||
}
|
||||
hints.max_width = w->priv.max_width;
|
||||
hints.max_height = w->priv.max_height;
|
||||
|
||||
|
||||
gtk_window_set_geometry_hints(GTK_WINDOW(w->priv.window), w->priv.window, &hints, usedHints);
|
||||
}
|
||||
|
||||
@@ -514,7 +514,6 @@ struct webview_priv
|
||||
}
|
||||
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dlg), FALSE);
|
||||
gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dlg), FALSE);
|
||||
gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dlg), TRUE);
|
||||
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dlg), TRUE);
|
||||
gtk_file_chooser_set_create_folders(GTK_FILE_CHOOSER(dlg), TRUE);
|
||||
gint response = gtk_dialog_run(GTK_DIALOG(dlg));
|
||||
@@ -1398,12 +1397,12 @@ struct webview_priv
|
||||
case WM_GETMINMAXINFO:
|
||||
{
|
||||
if (w != NULL) {
|
||||
// get pixel density
|
||||
// get pixel density
|
||||
HDC hDC = GetDC(NULL);
|
||||
double DPIScaleX = GetDeviceCaps(hDC, 88)/96.0;
|
||||
double DPIScaleY = GetDeviceCaps(hDC, 90)/96.0;
|
||||
ReleaseDC(NULL, hDC);
|
||||
|
||||
|
||||
RECT rcClient, rcWind;
|
||||
POINT ptDiff;
|
||||
GetClientRect(hwnd, &rcClient);
|
||||
@@ -1413,7 +1412,7 @@ struct webview_priv
|
||||
int heightExtra = (rcWind.bottom - rcWind.top) - rcClient.bottom;
|
||||
|
||||
LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam;
|
||||
|
||||
|
||||
if (w->priv.min_width != -1) {
|
||||
lpMMI->ptMinTrackSize.x = w->priv.min_width * DPIScaleX + widthExtra;
|
||||
lpMMI->ptMinTrackSize.y = w->priv.min_height * DPIScaleY + heightExtra;
|
||||
@@ -1423,7 +1422,7 @@ struct webview_priv
|
||||
lpMMI->ptMaxTrackSize.y = w->priv.max_height * DPIScaleY + heightExtra;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
case WM_DESTROY:
|
||||
@@ -2328,14 +2327,14 @@ struct webview_priv
|
||||
{
|
||||
[w->priv.window makeKeyWindow];
|
||||
}
|
||||
|
||||
|
||||
WEBVIEW_API void webview_minsize(struct webview *w, int width, int height) {
|
||||
NSSize size;
|
||||
size.width = width;
|
||||
size.height = height;
|
||||
[w->priv.window setMinSize:size];
|
||||
}
|
||||
|
||||
|
||||
WEBVIEW_API void webview_maxsize(struct webview *w, int width, int height) {
|
||||
NSSize size;
|
||||
size.width = width;
|
||||
@@ -2346,7 +2345,7 @@ struct webview_priv
|
||||
[button performSelectorOnMainThread:@selector(setEnabled:) withObject:NO
|
||||
waitUntilDone:NO];
|
||||
}
|
||||
|
||||
|
||||
WEBVIEW_API void webview_set_fullscreen(struct webview *w, int fullscreen)
|
||||
{
|
||||
int b = ((([w->priv.window styleMask] & NSWindowStyleMaskFullScreen) ==
|
||||
@@ -2503,4 +2502,4 @@ struct webview_priv
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WEBVIEW_H */
|
||||
#endif /* WEBVIEW_H */
|
||||
|
||||
6
runtime/js/runtime/package-lock.json
generated
6
runtime/js/runtime/package-lock.json
generated
@@ -260,9 +260,9 @@
|
||||
}
|
||||
},
|
||||
"path-parse": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
|
||||
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||
"dev": true
|
||||
},
|
||||
"path-type": {
|
||||
|
||||
@@ -5,11 +5,15 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal"
|
||||
"github.com/wailsapp/wails/v2/internal/gomod"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/system"
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
@@ -42,7 +46,7 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
||||
|
||||
// Setup Platform flag
|
||||
platform := runtime.GOOS
|
||||
//command.StringFlag("platform", "Platform to target", &platform)
|
||||
command.StringFlag("platform", "Platform to target", &platform)
|
||||
|
||||
// Verbosity
|
||||
verbosity := 1
|
||||
@@ -95,14 +99,14 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
||||
"darwin/amd64",
|
||||
"darwin/arm64",
|
||||
"darwin/universal",
|
||||
"linux",
|
||||
//"linux",
|
||||
//"linux/amd64",
|
||||
//"linux/arm-7",
|
||||
"windows",
|
||||
"windows/amd64",
|
||||
})
|
||||
if !validPlatformArch.Contains(platform) {
|
||||
return fmt.Errorf("platform %s is not supported", platform)
|
||||
return fmt.Errorf("platform %s is not supported. Platforms supported: %s", platform, validPlatformArch.Join(","))
|
||||
}
|
||||
|
||||
if compress && platform == "darwin/universal" {
|
||||
@@ -117,12 +121,20 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
||||
}
|
||||
|
||||
// Tags
|
||||
experimental := false
|
||||
userTags := []string{}
|
||||
for _, tag := range strings.Split(tags, " ") {
|
||||
thisTag := strings.TrimSpace(tag)
|
||||
if thisTag != "" {
|
||||
userTags = append(userTags, thisTag)
|
||||
}
|
||||
if thisTag == "exp" {
|
||||
experimental = true
|
||||
}
|
||||
}
|
||||
|
||||
if runtime.GOOS == "linux" && !experimental {
|
||||
return fmt.Errorf("Linux version coming soon!")
|
||||
}
|
||||
|
||||
// Webview2 installer strategy (download by default)
|
||||
@@ -197,6 +209,11 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
|
||||
fmt.Fprintf(w, "\n")
|
||||
w.Flush()
|
||||
|
||||
err = checkGoModVersion(logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return doBuild(buildOptions)
|
||||
})
|
||||
}
|
||||
@@ -220,3 +237,29 @@ func doBuild(buildOptions *build.Options) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkGoModVersion(logger *clilogger.CLILogger) error {
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gomodFilename := filepath.Join(cwd, "go.mod")
|
||||
gomodData, err := os.ReadFile(gomodFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
outOfSync, err := gomod.GoModOutOfSync(gomodData, internal.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !outOfSync {
|
||||
return nil
|
||||
}
|
||||
gomodversion, err := gomod.GetWailsVersionFromModFile(gomodData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Println("Warning: go.mod is using Wails '%s' but the CLI is '%s'. Consider updating it.\n", gomodversion.String(), internal.Version)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
package dev
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
"github.com/google/shlex"
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal"
|
||||
"github.com/wailsapp/wails/v2/internal/gomod"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/project"
|
||||
|
||||
"github.com/pkg/browser"
|
||||
@@ -27,6 +33,8 @@ import (
|
||||
"github.com/wailsapp/wails/v2/pkg/commands/build"
|
||||
)
|
||||
|
||||
const defaultDevServerURL = "http://localhost:34115"
|
||||
|
||||
func LogGreen(message string, args ...interface{}) {
|
||||
text := fmt.Sprintf(message, args...)
|
||||
println(colour.Green(text))
|
||||
@@ -50,143 +58,117 @@ func sliceToMap(input []string) map[string]struct{} {
|
||||
return result
|
||||
}
|
||||
|
||||
type devFlags struct {
|
||||
ldflags string
|
||||
compilerCommand string
|
||||
assetDir string
|
||||
extensions string
|
||||
openBrowser bool
|
||||
noReload bool
|
||||
wailsjsdir string
|
||||
tags string
|
||||
verbosity int
|
||||
loglevel string
|
||||
forceBuild bool
|
||||
debounceMS int
|
||||
devServerURL string
|
||||
appargs string
|
||||
}
|
||||
|
||||
// AddSubcommand adds the `dev` command for the Wails application
|
||||
func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
|
||||
command := app.NewSubCommand("dev", "Development mode")
|
||||
|
||||
// Passthrough ldflags
|
||||
ldflags := ""
|
||||
command.StringFlag("ldflags", "optional ldflags", &ldflags)
|
||||
|
||||
// compiler command
|
||||
compilerCommand := "go"
|
||||
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &compilerCommand)
|
||||
|
||||
assetDir := ""
|
||||
command.StringFlag("assetdir", "Serve assets from the given directory", &assetDir)
|
||||
|
||||
// extensions to trigger rebuilds of application
|
||||
extensions := "go"
|
||||
command.StringFlag("e", "Extensions to trigger rebuilds (comma separated) eg go", &extensions)
|
||||
|
||||
openBrowser := false
|
||||
command.BoolFlag("browser", "Open application in browser", &openBrowser)
|
||||
|
||||
noreload := false
|
||||
command.BoolFlag("noreload", "Disable reload on asset change", &noreload)
|
||||
|
||||
wailsjsdir := ""
|
||||
command.StringFlag("wailsjsdir", "Directory to generate the Wails JS modules", &wailsjsdir)
|
||||
|
||||
// tags to pass to `go`
|
||||
tags := ""
|
||||
command.StringFlag("tags", "tags to pass to Go compiler (quoted and space separated)", &tags)
|
||||
|
||||
// Verbosity
|
||||
verbosity := 1
|
||||
command.IntFlag("v", "Verbosity level (0 - silent, 1 - standard, 2 - verbose)", &verbosity)
|
||||
|
||||
loglevel := ""
|
||||
command.StringFlag("loglevel", "Loglevel to use - Trace, Dev, Info, Warning, Error", &loglevel)
|
||||
|
||||
forceBuild := false
|
||||
command.BoolFlag("f", "Force build application", &forceBuild)
|
||||
flags := defaultDevFlags()
|
||||
command.StringFlag("ldflags", "optional ldflags", &flags.ldflags)
|
||||
command.StringFlag("compiler", "Use a different go compiler to build, eg go1.15beta1", &flags.compilerCommand)
|
||||
command.StringFlag("assetdir", "Serve assets from the given directory", &flags.assetDir)
|
||||
command.StringFlag("e", "Extensions to trigger rebuilds (comma separated) eg go", &flags.extensions)
|
||||
command.BoolFlag("browser", "Open application in browser", &flags.openBrowser)
|
||||
command.BoolFlag("noreload", "Disable reload on asset change", &flags.noReload)
|
||||
command.StringFlag("wailsjsdir", "Directory to generate the Wails JS modules", &flags.wailsjsdir)
|
||||
command.StringFlag("tags", "tags to pass to Go compiler (quoted and space separated)", &flags.tags)
|
||||
command.IntFlag("v", "Verbosity level (0 - silent, 1 - standard, 2 - verbose)", &flags.verbosity)
|
||||
command.StringFlag("loglevel", "Loglevel to use - Trace, Debug, Info, Warning, Error", &flags.loglevel)
|
||||
command.BoolFlag("f", "Force build application", &flags.forceBuild)
|
||||
command.IntFlag("debounce", "The amount of time to wait to trigger a reload on change", &flags.debounceMS)
|
||||
command.StringFlag("devserverurl", "The url of the dev server to use", &flags.devServerURL)
|
||||
command.StringFlag("appargs", "arguments to pass to the underlying app (quoted and space searated)", &flags.appargs)
|
||||
|
||||
command.Action(func() error {
|
||||
|
||||
// Create logger
|
||||
logger := clilogger.New(w)
|
||||
app.PrintBanner()
|
||||
|
||||
experimental := false
|
||||
userTags := []string{}
|
||||
for _, tag := range strings.Split(flags.tags, " ") {
|
||||
thisTag := strings.TrimSpace(tag)
|
||||
if thisTag != "" {
|
||||
userTags = append(userTags, thisTag)
|
||||
}
|
||||
if thisTag == "exp" {
|
||||
experimental = true
|
||||
}
|
||||
}
|
||||
|
||||
if runtime.GOOS == "linux" && !experimental {
|
||||
return fmt.Errorf("Linux version coming soon!")
|
||||
}
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
projectConfig, err := project.Load(cwd)
|
||||
|
||||
projectConfig, err := loadAndMergeProjectConfig(cwd, &flags)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if projectConfig.AssetDirectory == "" && assetDir == "" {
|
||||
return fmt.Errorf("No asset directory provided. Please use -assetdir to indicate which directory contains your built assets.")
|
||||
}
|
||||
|
||||
if assetDir == "" && projectConfig.AssetDirectory != "" {
|
||||
assetDir = projectConfig.AssetDirectory
|
||||
}
|
||||
|
||||
if assetDir != projectConfig.AssetDirectory {
|
||||
projectConfig.AssetDirectory = filepath.ToSlash(assetDir)
|
||||
err := projectConfig.Save()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
assetDir, err := filepath.Abs(assetDir)
|
||||
// Update go.mod to use current wails version
|
||||
err = syncGoModVersion(cwd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if wailsjsdir == "" && projectConfig.WailsJSDir != "" {
|
||||
wailsjsdir = projectConfig.WailsJSDir
|
||||
}
|
||||
|
||||
if wailsjsdir == "" {
|
||||
wailsjsdir = "./frontend"
|
||||
}
|
||||
|
||||
if wailsjsdir != projectConfig.WailsJSDir {
|
||||
projectConfig.WailsJSDir = filepath.ToSlash(wailsjsdir)
|
||||
err := projectConfig.Save()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
buildOptions := &build.Options{
|
||||
Logger: logger,
|
||||
OutputType: "dev",
|
||||
Mode: build.Dev,
|
||||
Arch: runtime.GOARCH,
|
||||
Pack: true,
|
||||
Platform: runtime.GOOS,
|
||||
LDFlags: ldflags,
|
||||
Compiler: compilerCommand,
|
||||
ForceBuild: forceBuild,
|
||||
IgnoreFrontend: false,
|
||||
Verbosity: verbosity,
|
||||
WailsJSDir: wailsjsdir,
|
||||
}
|
||||
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
// Run go mod tidy to ensure we're up to date
|
||||
err = runCommand(cwd, false, "go", "mod", "tidy")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func(watcher *fsnotify.Watcher) {
|
||||
err := watcher.Close()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}(watcher)
|
||||
|
||||
if flags.tags != "" {
|
||||
err = runCommand(cwd, true, "wails", "generate", "module", "-tags", flags.tags)
|
||||
} else {
|
||||
err = runCommand(cwd, true, "wails", "generate", "module")
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// frontend:dev server command
|
||||
if projectConfig.DevCommand != "" {
|
||||
var devCommandWaitGroup sync.WaitGroup
|
||||
closer := runFrontendDevCommand(cwd, projectConfig.DevCommand, &devCommandWaitGroup)
|
||||
defer closer(&devCommandWaitGroup)
|
||||
}
|
||||
|
||||
buildOptions := generateBuildOptions(flags)
|
||||
buildOptions.Logger = logger
|
||||
buildOptions.UserTags = internal.ParseUserTags(flags.tags)
|
||||
|
||||
var debugBinaryProcess *process.Process = nil
|
||||
var extensionsThatTriggerARebuild = sliceToMap(strings.Split(extensions, ","))
|
||||
|
||||
// Setup signal handler
|
||||
quitChannel := make(chan os.Signal, 1)
|
||||
signal.Notify(quitChannel, os.Interrupt, os.Kill, syscall.SIGTERM)
|
||||
exitCodeChannel := make(chan int, 1)
|
||||
|
||||
var passthruArgs []string
|
||||
//if len(os.Args) > 2 {
|
||||
// passthruArgs = os.Args[2:]
|
||||
//}
|
||||
|
||||
// Do initial build
|
||||
logger.Println("Building application for development...")
|
||||
newProcess, appBinary, err := restartApp(logger, buildOptions, debugBinaryProcess, loglevel, passthruArgs, assetDir, false, exitCodeChannel)
|
||||
newProcess, appBinary, err := restartApp(buildOptions, debugBinaryProcess, flags, exitCodeChannel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -195,129 +177,32 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
}
|
||||
|
||||
// open browser
|
||||
if openBrowser {
|
||||
err = browser.OpenURL("http://localhost:34115")
|
||||
if flags.openBrowser {
|
||||
url := defaultDevServerURL
|
||||
if flags.devServerURL != "" {
|
||||
url = flags.devServerURL
|
||||
}
|
||||
err = browser.OpenURL(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var newBinaryProcess *process.Process
|
||||
|
||||
// Get project dir
|
||||
projectDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get all subdirectories
|
||||
dirs, err := fs.GetSubdirectories(projectDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
LogGreen("Watching (sub)/directory: %s", projectDir)
|
||||
|
||||
// Setup a watcher for non-node_modules directories
|
||||
dirs.Each(func(dir string) {
|
||||
if strings.Contains(dir, "node_modules") {
|
||||
return
|
||||
}
|
||||
// Ignore build directory
|
||||
if strings.HasPrefix(dir, filepath.Join(projectDir, "build")) {
|
||||
return
|
||||
}
|
||||
// Ignore dot directories
|
||||
if strings.HasPrefix(dir, ".") {
|
||||
return
|
||||
}
|
||||
err = watcher.Add(dir)
|
||||
// create the project files watcher
|
||||
watcher, err := initialiseWatcher(cwd, logger.Fatal)
|
||||
defer func(watcher *fsnotify.Watcher) {
|
||||
err := watcher.Close()
|
||||
if err != nil {
|
||||
logger.Fatal(err.Error())
|
||||
}
|
||||
})
|
||||
}(watcher)
|
||||
|
||||
// Main Loop
|
||||
quit := false
|
||||
// Use 100ms debounce
|
||||
interval := 100 * time.Millisecond
|
||||
timer := time.NewTimer(interval)
|
||||
rebuild := false
|
||||
reload := false
|
||||
for quit == false {
|
||||
//reload := false
|
||||
select {
|
||||
case exitCode := <-exitCodeChannel:
|
||||
if exitCode == 0 {
|
||||
quit = true
|
||||
}
|
||||
case item := <-watcher.Events:
|
||||
// Check for file writes
|
||||
if item.Op&fsnotify.Write == fsnotify.Write {
|
||||
// Ignore directories
|
||||
if fs.DirExists(item.Name) {
|
||||
continue
|
||||
}
|
||||
LogGreen("Watching (sub)/directory: %s", cwd)
|
||||
LogGreen("Using Dev Server URL: %s", flags.devServerURL)
|
||||
LogGreen("Using reload debounce setting of %d milliseconds", flags.debounceMS)
|
||||
|
||||
// Iterate all file patterns
|
||||
ext := filepath.Ext(item.Name)
|
||||
if ext != "" {
|
||||
ext = ext[1:]
|
||||
if _, exists := extensionsThatTriggerARebuild[ext]; exists {
|
||||
rebuild = true
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(item.Name, assetDir) {
|
||||
reload = true
|
||||
}
|
||||
timer.Reset(interval)
|
||||
}
|
||||
// Check for new directories
|
||||
if item.Op&fsnotify.Create == fsnotify.Create {
|
||||
// If this is a folder, add it to our watch list
|
||||
if fs.DirExists(item.Name) {
|
||||
//node_modules is BANNED!
|
||||
if !strings.Contains(item.Name, "node_modules") {
|
||||
err := watcher.Add(item.Name)
|
||||
if err != nil {
|
||||
logger.Fatal("%s", err.Error())
|
||||
}
|
||||
LogGreen("Added new directory to watcher: %s", item.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
case <-timer.C:
|
||||
if rebuild {
|
||||
rebuild = false
|
||||
LogGreen("[Rebuild triggered] files updated")
|
||||
// Try and build the app
|
||||
newBinaryProcess, _, err = restartApp(logger, buildOptions, debugBinaryProcess, loglevel, passthruArgs, assetDir, false, exitCodeChannel)
|
||||
if err != nil {
|
||||
LogRed("Error during build: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
// If we have a new process, save it
|
||||
if newBinaryProcess != nil {
|
||||
debugBinaryProcess = newBinaryProcess
|
||||
}
|
||||
}
|
||||
if reload {
|
||||
reload = false
|
||||
_, err = http.Get("http://localhost:34115/wails/reload")
|
||||
if err != nil {
|
||||
LogRed("Error during refresh: %s", err.Error())
|
||||
}
|
||||
}
|
||||
case <-quitChannel:
|
||||
LogGreen("\nCaught quit")
|
||||
quit = true
|
||||
}
|
||||
}
|
||||
// Watch for changes and trigger restartApp()
|
||||
doWatcherLoop(buildOptions, debugBinaryProcess, flags, watcher, exitCodeChannel, quitChannel)
|
||||
|
||||
// Kill the current program if running
|
||||
if debugBinaryProcess != nil {
|
||||
@@ -337,18 +222,237 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func restartApp(logger *clilogger.CLILogger, buildOptions *build.Options, debugBinaryProcess *process.Process, loglevel string, passthruArgs []string, assetDir string, firstRun bool, exitCodeChannel chan int) (*process.Process, string, error) {
|
||||
func syncGoModVersion(cwd string) error {
|
||||
gomodFilename := filepath.Join(cwd, "go.mod")
|
||||
gomodData, err := os.ReadFile(gomodFilename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
outOfSync, err := gomod.GoModOutOfSync(gomodData, internal.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !outOfSync {
|
||||
return nil
|
||||
}
|
||||
LogGreen("Updating go.mod to use Wails '%s'", internal.Version)
|
||||
newGoData, err := gomod.UpdateGoModVersion(gomodData, internal.Version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(gomodFilename, newGoData, 0755)
|
||||
}
|
||||
|
||||
func runCommand(dir string, exitOnError bool, command string, args ...string) error {
|
||||
LogGreen("Executing: " + command + " " + strings.Join(args, " "))
|
||||
cmd := exec.Command(command, args...)
|
||||
cmd.Dir = dir
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
println(string(output))
|
||||
if exitOnError {
|
||||
os.Exit(1)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// defaultDevFlags generates devFlags with default options
|
||||
func defaultDevFlags() devFlags {
|
||||
return devFlags{
|
||||
devServerURL: defaultDevServerURL,
|
||||
compilerCommand: "go",
|
||||
verbosity: 1,
|
||||
extensions: "go",
|
||||
debounceMS: 100,
|
||||
}
|
||||
}
|
||||
|
||||
// generateBuildOptions creates a build.Options using the flags
|
||||
func generateBuildOptions(flags devFlags) *build.Options {
|
||||
result := &build.Options{
|
||||
OutputType: "dev",
|
||||
Mode: build.Dev,
|
||||
Arch: runtime.GOARCH,
|
||||
Pack: false,
|
||||
Platform: runtime.GOOS,
|
||||
LDFlags: flags.ldflags,
|
||||
Compiler: flags.compilerCommand,
|
||||
ForceBuild: flags.forceBuild,
|
||||
IgnoreFrontend: false,
|
||||
Verbosity: flags.verbosity,
|
||||
WailsJSDir: flags.wailsjsdir,
|
||||
}
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
result.Pack = false
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// loadAndMergeProjectConfig reconciles flags passed to the CLI with project config settings and updates
|
||||
// the project config if necessary
|
||||
func loadAndMergeProjectConfig(cwd string, flags *devFlags) (*project.Project, error) {
|
||||
projectConfig, err := project.Load(cwd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var shouldSaveConfig bool
|
||||
|
||||
if projectConfig.AssetDirectory == "" && flags.assetDir == "" {
|
||||
return nil, fmt.Errorf("No asset directory provided. Please use -assetdir to indicate which directory contains your built assets.")
|
||||
}
|
||||
|
||||
if flags.assetDir == "" && projectConfig.AssetDirectory != "" {
|
||||
flags.assetDir = projectConfig.AssetDirectory
|
||||
}
|
||||
|
||||
if flags.assetDir != projectConfig.AssetDirectory {
|
||||
projectConfig.AssetDirectory = filepath.ToSlash(flags.assetDir)
|
||||
}
|
||||
|
||||
flags.assetDir, err = filepath.Abs(flags.assetDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if flags.devServerURL == defaultDevServerURL && projectConfig.DevServerURL != defaultDevServerURL && projectConfig.DevServerURL != "" {
|
||||
flags.devServerURL = projectConfig.DevServerURL
|
||||
}
|
||||
|
||||
if flags.devServerURL != projectConfig.DevServerURL {
|
||||
projectConfig.DevServerURL = flags.devServerURL
|
||||
shouldSaveConfig = true
|
||||
}
|
||||
|
||||
if flags.wailsjsdir == "" && projectConfig.WailsJSDir != "" {
|
||||
flags.wailsjsdir = projectConfig.WailsJSDir
|
||||
}
|
||||
|
||||
if flags.wailsjsdir == "" {
|
||||
flags.wailsjsdir = "./frontend"
|
||||
}
|
||||
|
||||
if flags.wailsjsdir != projectConfig.WailsJSDir {
|
||||
projectConfig.WailsJSDir = filepath.ToSlash(flags.wailsjsdir)
|
||||
shouldSaveConfig = true
|
||||
}
|
||||
|
||||
if flags.debounceMS == 100 && projectConfig.DebounceMS != 100 {
|
||||
if projectConfig.DebounceMS == 0 {
|
||||
projectConfig.DebounceMS = 100
|
||||
}
|
||||
flags.debounceMS = projectConfig.DebounceMS
|
||||
}
|
||||
|
||||
if flags.debounceMS != projectConfig.DebounceMS {
|
||||
projectConfig.DebounceMS = flags.debounceMS
|
||||
shouldSaveConfig = true
|
||||
}
|
||||
|
||||
if flags.appargs == "" && projectConfig.AppArgs != "" {
|
||||
flags.appargs = projectConfig.AppArgs
|
||||
}
|
||||
|
||||
if shouldSaveConfig {
|
||||
err = projectConfig.Save()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return projectConfig, nil
|
||||
}
|
||||
|
||||
// runFrontendDevCommand will run the `frontend:dev` command if it was given, ex- `npm run dev`
|
||||
func runFrontendDevCommand(cwd string, devCommand string, wg *sync.WaitGroup) func(group *sync.WaitGroup) {
|
||||
LogGreen("Running frontend dev command: '%s'", devCommand)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
dir := filepath.Join(cwd, "frontend")
|
||||
cmdSlice := strings.Split(devCommand, " ")
|
||||
wg.Add(1)
|
||||
cmd := exec.CommandContext(ctx, cmdSlice[0], cmdSlice[1:]...)
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Dir = dir
|
||||
go func(ctx context.Context, devCommand string, cwd string, wg *sync.WaitGroup) {
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
if err.Error() != "exit status 1" {
|
||||
LogRed("Error from '%s': %s", devCommand, err.Error())
|
||||
}
|
||||
}
|
||||
LogGreen("Dev command exited!")
|
||||
wg.Done()
|
||||
}(ctx, devCommand, cwd, wg)
|
||||
|
||||
return func(wg *sync.WaitGroup) {
|
||||
if runtime.GOOS == "windows" {
|
||||
// Credit: https://stackoverflow.com/a/44551450
|
||||
// For whatever reason, killing an npm script on windows just doesn't exit properly with cancel
|
||||
if cmd != nil && cmd.Process != nil {
|
||||
kill := exec.Command("TASKKILL", "/T", "/F", "/PID", strconv.Itoa(cmd.Process.Pid))
|
||||
kill.Stderr = os.Stderr
|
||||
kill.Stdout = os.Stdout
|
||||
err := kill.Run()
|
||||
if err != nil {
|
||||
if err.Error() != "exit status 1" {
|
||||
LogRed("Error from '%s': %s", devCommand, err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cancel()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
// initialiseWatcher creates the project directory watcher that will trigger recompile
|
||||
func initialiseWatcher(cwd string, logFatal func(string, ...interface{})) (*fsnotify.Watcher, error) {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get all subdirectories
|
||||
dirs, err := fs.GetSubdirectories(cwd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Setup a watcher for non-node_modules directories
|
||||
dirs.Each(func(dir string) {
|
||||
if strings.Contains(dir, "node_modules") {
|
||||
return
|
||||
}
|
||||
// Ignore build directory
|
||||
if strings.HasPrefix(dir, filepath.Join(cwd, "build")) {
|
||||
return
|
||||
}
|
||||
// Ignore dot directories
|
||||
if strings.HasPrefix(dir, ".") {
|
||||
return
|
||||
}
|
||||
err = watcher.Add(dir)
|
||||
if err != nil {
|
||||
logFatal(err.Error())
|
||||
}
|
||||
})
|
||||
return watcher, nil
|
||||
}
|
||||
|
||||
// restartApp does the actual rebuilding of the application when files change
|
||||
func restartApp(buildOptions *build.Options, debugBinaryProcess *process.Process, flags devFlags, exitCodeChannel chan int) (*process.Process, string, error) {
|
||||
|
||||
appBinary, err := build.Build(buildOptions)
|
||||
println()
|
||||
if err != nil {
|
||||
if firstRun {
|
||||
return nil, "", err
|
||||
}
|
||||
LogRed("Build error - continuing to run current version")
|
||||
LogDarkYellow(err.Error())
|
||||
return nil, "", nil
|
||||
@@ -359,34 +463,124 @@ func restartApp(logger *clilogger.CLILogger, buildOptions *build.Options, debugB
|
||||
killError := debugBinaryProcess.Kill()
|
||||
|
||||
if killError != nil {
|
||||
logger.Fatal("Unable to kill debug binary (PID: %d)!", debugBinaryProcess.PID())
|
||||
buildOptions.Logger.Fatal("Unable to kill debug binary (PID: %d)!", debugBinaryProcess.PID())
|
||||
}
|
||||
|
||||
debugBinaryProcess = nil
|
||||
}
|
||||
|
||||
// Start up new binary with correct args
|
||||
args := slicer.StringSlicer{}
|
||||
args.Add("-loglevel", loglevel)
|
||||
if assetDir != "" {
|
||||
args.Add("-assetdir", assetDir)
|
||||
// parse appargs if any
|
||||
args, err := shlex.Split(flags.appargs)
|
||||
|
||||
if err != nil {
|
||||
buildOptions.Logger.Fatal("Unable to parse appargs: %s", err.Error())
|
||||
}
|
||||
|
||||
if len(passthruArgs) > 0 {
|
||||
args.AddSlice(passthruArgs)
|
||||
}
|
||||
newProcess := process.NewProcess(appBinary, args.AsSlice()...)
|
||||
// Set environment variables accordingly
|
||||
os.Setenv("loglevel", flags.loglevel)
|
||||
os.Setenv("assetdir", flags.assetDir)
|
||||
os.Setenv("devserverurl", flags.devServerURL)
|
||||
|
||||
// Start up new binary with correct args
|
||||
newProcess := process.NewProcess(appBinary, args...)
|
||||
err = newProcess.Start(exitCodeChannel)
|
||||
if err != nil {
|
||||
// Remove binary
|
||||
if fs.FileExists(appBinary) {
|
||||
deleteError := fs.DeleteFile(appBinary)
|
||||
if deleteError != nil {
|
||||
logger.Fatal("Unable to delete app binary: " + appBinary)
|
||||
buildOptions.Logger.Fatal("Unable to delete app binary: " + appBinary)
|
||||
}
|
||||
}
|
||||
logger.Fatal("Unable to start application: %s", err.Error())
|
||||
buildOptions.Logger.Fatal("Unable to start application: %s", err.Error())
|
||||
}
|
||||
|
||||
return newProcess, appBinary, nil
|
||||
}
|
||||
|
||||
// doWatcherLoop is the main watch loop that runs while dev is active
|
||||
func doWatcherLoop(buildOptions *build.Options, debugBinaryProcess *process.Process, flags devFlags, watcher *fsnotify.Watcher, exitCodeChannel chan int, quitChannel chan os.Signal) {
|
||||
// Main Loop
|
||||
var (
|
||||
err error
|
||||
newBinaryProcess *process.Process
|
||||
)
|
||||
var extensionsThatTriggerARebuild = sliceToMap(strings.Split(flags.extensions, ","))
|
||||
quit := false
|
||||
interval := time.Duration(flags.debounceMS) * time.Millisecond
|
||||
timer := time.NewTimer(interval)
|
||||
rebuild := false
|
||||
reload := false
|
||||
for quit == false {
|
||||
//reload := false
|
||||
select {
|
||||
case exitCode := <-exitCodeChannel:
|
||||
if exitCode == 0 {
|
||||
quit = true
|
||||
}
|
||||
case item := <-watcher.Events:
|
||||
// Check for file writes
|
||||
if item.Op&fsnotify.Write == fsnotify.Write {
|
||||
// Ignore directories
|
||||
if fs.DirExists(item.Name) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Iterate all file patterns
|
||||
ext := filepath.Ext(item.Name)
|
||||
if ext != "" {
|
||||
ext = ext[1:]
|
||||
if _, exists := extensionsThatTriggerARebuild[ext]; exists {
|
||||
rebuild = true
|
||||
timer.Reset(interval)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(item.Name, flags.assetDir) {
|
||||
reload = true
|
||||
}
|
||||
timer.Reset(interval)
|
||||
}
|
||||
// Check for new directories
|
||||
if item.Op&fsnotify.Create == fsnotify.Create {
|
||||
// If this is a folder, add it to our watch list
|
||||
if fs.DirExists(item.Name) {
|
||||
//node_modules is BANNED!
|
||||
if !strings.Contains(item.Name, "node_modules") {
|
||||
err := watcher.Add(item.Name)
|
||||
if err != nil {
|
||||
buildOptions.Logger.Fatal("%s", err.Error())
|
||||
}
|
||||
LogGreen("Added new directory to watcher: %s", item.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
case <-timer.C:
|
||||
if rebuild {
|
||||
rebuild = false
|
||||
LogGreen("[Rebuild triggered] files updated")
|
||||
// Try and build the app
|
||||
newBinaryProcess, _, err = restartApp(buildOptions, debugBinaryProcess, flags, exitCodeChannel)
|
||||
if err != nil {
|
||||
LogRed("Error during build: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
// If we have a new process, save it
|
||||
if newBinaryProcess != nil {
|
||||
debugBinaryProcess = newBinaryProcess
|
||||
}
|
||||
}
|
||||
if reload {
|
||||
reload = false
|
||||
_, err = http.Get("http://localhost:34115/wails/reload")
|
||||
if err != nil {
|
||||
LogRed("Error during refresh: %s", err.Error())
|
||||
}
|
||||
}
|
||||
case <-quitChannel:
|
||||
LogGreen("\nCaught quit")
|
||||
quit = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ import (
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal/commands/generate/template"
|
||||
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||
"github.com/wailsapp/wails/v2/pkg/parser"
|
||||
)
|
||||
|
||||
// AddSubcommand adds the `generate` command for the Wails application
|
||||
@@ -15,34 +13,11 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
|
||||
command := app.NewSubCommand("generate", "Code Generation Tools")
|
||||
|
||||
//AddModuleCommand(app, command, w)
|
||||
err := AddModuleCommand(app, command, w)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
template.AddSubCommand(app, command, w)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func logPackage(pkg *parser.Package, logger *clilogger.CLILogger) {
|
||||
|
||||
logger.Println("Processed Go package '" + pkg.Gopackage.Name + "' as '" + pkg.Name + "'")
|
||||
for _, strct := range pkg.Structs() {
|
||||
logger.Println("")
|
||||
logger.Println(" Processed struct '" + strct.Name + "'")
|
||||
if strct.IsBound {
|
||||
for _, method := range strct.Methods {
|
||||
logger.Println(" Bound method '" + method.Name + "'")
|
||||
}
|
||||
}
|
||||
if strct.IsUsedAsData {
|
||||
for _, field := range strct.Fields {
|
||||
if !field.Ignored {
|
||||
logger.Print(" Processed ")
|
||||
if field.IsOptional {
|
||||
logger.Print("optional ")
|
||||
}
|
||||
logger.Println("field '" + field.Name + "' as '" + field.JSName() + "'")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.Println("")
|
||||
}
|
||||
|
||||
@@ -1,58 +1,58 @@
|
||||
package generate
|
||||
|
||||
import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"fmt"
|
||||
"github.com/leaanthony/clir"
|
||||
"github.com/wailsapp/wails/v2/pkg/clilogger"
|
||||
"github.com/wailsapp/wails/v2/pkg/parser"
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal"
|
||||
"github.com/wailsapp/wails/v2/internal/shell"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func AddModuleCommand(app *clir.Cli, parent *clir.Command, w io.Writer) {
|
||||
// AddModuleCommand adds the `module` subcommand for the `generate` command
|
||||
func AddModuleCommand(app *clir.Cli, parent *clir.Command, w io.Writer) error {
|
||||
|
||||
// Backend API
|
||||
backendAPI := parent.NewSubCommand("module", "Generates a JS module for the frontend to interface with the backend")
|
||||
command := parent.NewSubCommand("module", "Generate wailsjs modules")
|
||||
var tags string
|
||||
command.StringFlag("tags", "tags to pass to Go compiler (quoted and space separated)", &tags)
|
||||
|
||||
// Quiet Init
|
||||
quiet := false
|
||||
backendAPI.BoolFlag("q", "Suppress output to console", &quiet)
|
||||
command.Action(func() error {
|
||||
|
||||
backendAPI.Action(func() error {
|
||||
filename := "wailsbindings"
|
||||
if runtime.GOOS == "windows" {
|
||||
filename += ".exe"
|
||||
}
|
||||
// go build -tags bindings -o bindings.exe
|
||||
tempDir := os.TempDir()
|
||||
filename = filepath.Join(tempDir, filename)
|
||||
|
||||
// Create logger
|
||||
logger := clilogger.New(w)
|
||||
logger.Mute(quiet)
|
||||
|
||||
app.PrintBanner()
|
||||
|
||||
logger.Print("Generating Javascript module for Go code...")
|
||||
|
||||
// Start Time
|
||||
start := time.Now()
|
||||
|
||||
p, err := parser.GenerateWailsFrontendPackage()
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Println("done.")
|
||||
logger.Println("")
|
||||
|
||||
elapsed := time.Since(start)
|
||||
packages := p.Packages
|
||||
|
||||
// Print report
|
||||
for _, pkg := range p.Packages {
|
||||
if pkg.ShouldGenerate() {
|
||||
logPackage(pkg, logger)
|
||||
}
|
||||
tagList := internal.ParseUserTags(tags)
|
||||
tagList = append(tagList, "bindings")
|
||||
|
||||
stdout, stderr, err := shell.RunCommand(cwd, "go", "build", "-tags", strings.Join(tagList, ","), "-o", filename)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s\n%s\n%s", stdout, stderr, err)
|
||||
}
|
||||
|
||||
logger.Println("%d packages parsed in %s.", len(packages), elapsed)
|
||||
stdout, stderr, err = shell.RunCommand(cwd, filename)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s\n%s\n%s", stdout, stderr, err)
|
||||
}
|
||||
|
||||
err = os.Remove(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ The next steps to complete the template are:
|
||||
|
||||
You can test your template by running this command:
|
||||
|
||||
`wails init -name test -t {{.TemplateDir}}`
|
||||
`wails init -n test -t {{.TemplateDir}}`
|
||||
|
||||
### Checklist
|
||||
|
||||
|
||||
@@ -12,5 +12,5 @@ To generate a platform native package, add the `-package` flag.
|
||||
## Live Development
|
||||
|
||||
To run in live development mode, run `wails dev` in the project directory. In another terminal, go into the `frontend`
|
||||
directory and run `npm run dev`. The frontend dev server will run on http://localhost:5000. Connect to this
|
||||
directory and run `npm run dev`. The frontend dev server will run on http://localhost:34115. Connect to this
|
||||
in your browser and connect to your application.
|
||||
|
||||
@@ -2,7 +2,7 @@ module changeme
|
||||
|
||||
go 1.17
|
||||
|
||||
require github.com/wailsapp/wails/v2 v2.0.0-beta.0
|
||||
require github.com/wailsapp/wails/v2 {{.WailsVersion}}
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.2 // indirect
|
||||
@@ -35,4 +35,4 @@ golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect
|
||||
)
|
||||
|
||||
// replace github.com/wailsapp/wails/v2 v2.0.0-beta.0 => {{.WailsDirectory}}
|
||||
// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}}
|
||||
@@ -81,16 +81,18 @@ func AddSubCommand(app *clir.Cli, parent *clir.Command, w io.Writer) {
|
||||
}
|
||||
|
||||
type templateData struct {
|
||||
Name string
|
||||
Description string
|
||||
TemplateDir string
|
||||
Name string
|
||||
Description string
|
||||
TemplateDir string
|
||||
WailsVersion string
|
||||
}
|
||||
|
||||
println("Extracting base template files...")
|
||||
|
||||
err = g.Extract(templateDir, &templateData{
|
||||
Name: name,
|
||||
TemplateDir: templateDir,
|
||||
Name: name,
|
||||
TemplateDir: templateDir,
|
||||
WailsVersion: app.Version(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -2,7 +2,12 @@ package initialise
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/flytam/filenamify"
|
||||
"github.com/leaanthony/slicer"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -46,8 +51,8 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
}
|
||||
|
||||
// VSCode project files
|
||||
vscode := false
|
||||
command.BoolFlag("vscode", "Generate VSCode project files", &vscode)
|
||||
ide := ""
|
||||
command.StringFlag("ide", "Generate IDE project files", &ide)
|
||||
|
||||
// List templates
|
||||
list := false
|
||||
@@ -75,6 +80,15 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate IDE option
|
||||
supportedIDEs := slicer.String([]string{"vscode", "goland"})
|
||||
ide = strings.ToLower(ide)
|
||||
if ide != "" {
|
||||
if !supportedIDEs.Contains(ide) {
|
||||
return fmt.Errorf("ide '%s' not supported. Valid values: %s", ide, supportedIDEs.Join(" "))
|
||||
}
|
||||
}
|
||||
|
||||
if !quiet {
|
||||
app.PrintBanner()
|
||||
}
|
||||
@@ -83,27 +97,47 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
|
||||
logger.Println(task)
|
||||
logger.Println(strings.Repeat("-", len(task)))
|
||||
|
||||
projectFilename, err := filenamify.Filenamify(projectName, filenamify.Options{
|
||||
Replacement: "_",
|
||||
MaxLength: 255,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
goBinary, err := exec.LookPath("go")
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to find Go compiler. Please download and install Go: https://golang.org/dl/")
|
||||
}
|
||||
|
||||
// Get base path and convert to forward slashes
|
||||
goPath := filepath.ToSlash(filepath.Dir(goBinary))
|
||||
// Trim bin directory
|
||||
goSDKPath := strings.TrimSuffix(goPath, "/bin")
|
||||
|
||||
// Create Template Options
|
||||
options := &templates.Options{
|
||||
ProjectName: projectName,
|
||||
TargetDir: projectDirectory,
|
||||
TemplateName: templateName,
|
||||
Logger: logger,
|
||||
GenerateVSCode: vscode,
|
||||
InitGit: initGit,
|
||||
ProjectName: projectName,
|
||||
TargetDir: projectDirectory,
|
||||
TemplateName: templateName,
|
||||
Logger: logger,
|
||||
IDE: ide,
|
||||
InitGit: initGit,
|
||||
ProjectNameFilename: projectFilename,
|
||||
WailsVersion: app.Version(),
|
||||
GoSDKPath: goSDKPath,
|
||||
}
|
||||
|
||||
// Try to discover author details from git config
|
||||
findAuthorDetails(options)
|
||||
|
||||
return initProject(options)
|
||||
return initProject(options, quiet)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// initProject is our main init command
|
||||
func initProject(options *templates.Options) error {
|
||||
func initProject(options *templates.Options, quiet bool) error {
|
||||
|
||||
// Start Time
|
||||
start := time.Now()
|
||||
@@ -120,6 +154,19 @@ func initProject(options *templates.Options) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Run `go mod tidy` to ensure `go.sum` is up to date
|
||||
cmd := exec.Command("go", "mod", "tidy")
|
||||
cmd.Dir = options.TargetDir
|
||||
cmd.Stderr = os.Stderr
|
||||
if !quiet {
|
||||
println("")
|
||||
cmd.Stdout = os.Stdout
|
||||
}
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if options.InitGit {
|
||||
err = initGit(options)
|
||||
if err != nil {
|
||||
@@ -127,6 +174,10 @@ func initProject(options *templates.Options) error {
|
||||
}
|
||||
}
|
||||
|
||||
if quiet {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Output stats
|
||||
elapsed := time.Since(start)
|
||||
options.Logger.Println("")
|
||||
@@ -135,9 +186,14 @@ func initProject(options *templates.Options) error {
|
||||
options.Logger.Println("Project Template: " + options.TemplateName)
|
||||
options.Logger.Println("Template Support: " + template.HelpURL)
|
||||
|
||||
if options.GenerateVSCode {
|
||||
// IDE message
|
||||
switch options.IDE {
|
||||
case "vscode":
|
||||
options.Logger.Println("VSCode config files generated.")
|
||||
case "goland":
|
||||
options.Logger.Println("Goland config files generated.")
|
||||
}
|
||||
|
||||
if options.InitGit {
|
||||
options.Logger.Println("Git repository initialised.")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/{{.ProjectNameFilename}}.iml"
|
||||
filepath="$PROJECT_DIR$/.idea/{{.ProjectNameFilename}}.iml"/>
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1 @@
|
||||
{{.ProjectName}}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git"/>
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AutoImportSettings">
|
||||
<option name="autoReloadType" value="ALL"/>
|
||||
</component>
|
||||
<component name="GOROOT" url="file://{{.GoSDKPath}}"/>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$"/>
|
||||
</component>
|
||||
<component name="GoLibraries">
|
||||
<option name="indexEntireGoPath" value="false"/>
|
||||
</component>
|
||||
<component name="ProjectId" id="wails-{{.ProjectName}}"/>
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true"/>
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true"/>
|
||||
<option name="showLibraryContents" value="true"/>
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true"/>
|
||||
<property name="RunOnceActivity.ShowReadmeOnStart" value="true"/>
|
||||
<property name="WebServerToolWindowFactoryState" value="false"/>
|
||||
<property name="com.intellij.ide.scratch.LRUPopupBuilder$1/New Scratch File" value="TEXT"/>
|
||||
<property name="go.formatter.settings.were.checked" value="true"/>
|
||||
<property name="go.import.settings.migrated" value="true"/>
|
||||
<property name="go.modules.go.list.on.any.changes.was.set" value="true"/>
|
||||
<property name="go.sdk.automatically.set" value="true"/>
|
||||
<property name="go.tried.to.enable.integration.vgo.integrator" value="true"/>
|
||||
<property name="last_opened_file_path" value="$PROJECT_DIR$"/>
|
||||
<property name="settings.editor.selected.configurable"
|
||||
value="reference.settingsdialog.IDE.editor.colors.Console Font"/>
|
||||
</component>
|
||||
<component name="RunManager" selected="Go Build.{{.ProjectName}} (dev)">>
|
||||
<configuration name="{{.ProjectName}} (dev)" type="GoApplicationRunConfiguration" factoryName="Go Application">
|
||||
<module name="{{.ProjectName}}"/>
|
||||
<working_directory value="$PROJECT_DIR$"/>
|
||||
<go_parameters value="-gcflags "all=-N -l" -tags dev -o {{.PathToDesktopBinary}}"/>
|
||||
<useCustomBuildTags value="true"/>
|
||||
<parameters value="-assetdir {{.AssetDir}}"/>
|
||||
<envs>
|
||||
<env name="CGO_ENABLED" value=""{{.CGOEnabled}}""/>
|
||||
</envs>
|
||||
<kind value="DIRECTORY"/>
|
||||
<directory value="$PROJECT_DIR$"/>
|
||||
<filePath value="$PROJECT_DIR$"/>
|
||||
<method v="2">
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration name="{{.ProjectName}} (production)" type="GoApplicationRunConfiguration"
|
||||
factoryName="Go Application">
|
||||
<module name="{{.ProjectName}}"/>
|
||||
<working_directory value="$PROJECT_DIR$"/>
|
||||
<go_parameters
|
||||
value="-ldflags "-w -s{{.WindowsFlags}}" -tags desktop,production -o {{.PathToDesktopBinary}}"/>
|
||||
<useCustomBuildTags value="true"/>
|
||||
<envs>
|
||||
<env name="CGO_ENABLED" value=""{{.CGOEnabled}}""/>
|
||||
</envs>
|
||||
<kind value="DIRECTORY"/>
|
||||
<directory value="$PROJECT_DIR$"/>
|
||||
<filePath value="$PROJECT_DIR$"/>
|
||||
<method v="2">
|
||||
</method>
|
||||
</configuration>
|
||||
|
||||
<list>
|
||||
<item itemvalue="Go Build.{{.ProjectName}} (dev)"/>
|
||||
<item itemvalue="Go Remote.Local"/>
|
||||
</list>
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0"
|
||||
DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true"/>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3"/>
|
||||
</component>
|
||||
<component name="Vcs.Log.Tabs.Properties">
|
||||
<option name="TAB_STATES">
|
||||
<map>
|
||||
<entry key="MAIN">
|
||||
<value>
|
||||
<State/>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
<option name="oldMeFiltersMigrated" value="true"/>
|
||||
</component>
|
||||
<component name="VgoProject">
|
||||
<integration-enabled>true</integration-enabled>
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
</breakpoint-manager>
|
||||
</component>
|
||||
</project>
|
||||
@@ -42,6 +42,11 @@ type Data struct {
|
||||
AuthorEmail string
|
||||
AuthorNameAndEmail string
|
||||
WailsDirectory string
|
||||
GoSDKPath string
|
||||
AssetDir string
|
||||
WindowsFlags string
|
||||
CGOEnabled string
|
||||
OutputFile string
|
||||
}
|
||||
|
||||
// Options for installing a template
|
||||
@@ -51,13 +56,19 @@ type Options struct {
|
||||
BinaryName string
|
||||
TargetDir string
|
||||
Logger *clilogger.CLILogger
|
||||
GenerateVSCode bool
|
||||
PathToDesktopBinary string
|
||||
PathToServerBinary string
|
||||
InitGit bool
|
||||
AuthorName string
|
||||
AuthorEmail string
|
||||
AssetDir string
|
||||
IDE string
|
||||
ProjectNameFilename string // The project name but as a valid filename
|
||||
WailsVersion string
|
||||
GoSDKPath string
|
||||
WindowsFlags string
|
||||
CGOEnabled string
|
||||
OutputFile string
|
||||
}
|
||||
|
||||
// Template holds data relating to a template
|
||||
@@ -241,6 +252,7 @@ func Install(options *Options) (bool, *Template, error) {
|
||||
BinaryName := filepath.Base(options.TargetDir)
|
||||
NPMProjectName := strings.ToLower(strings.ReplaceAll(BinaryName, " ", ""))
|
||||
localWailsDirectory := fs.RelativePath("../../../../../..")
|
||||
|
||||
templateData := &Data{
|
||||
ProjectName: options.ProjectName,
|
||||
BinaryName: filepath.Base(options.TargetDir),
|
||||
@@ -248,6 +260,9 @@ func Install(options *Options) (bool, *Template, error) {
|
||||
WailsDirectory: localWailsDirectory,
|
||||
AuthorEmail: options.AuthorEmail,
|
||||
AuthorName: options.AuthorName,
|
||||
WailsVersion: options.WailsVersion,
|
||||
GoSDKPath: options.GoSDKPath,
|
||||
AssetDir: options.AssetDir,
|
||||
}
|
||||
|
||||
// Create a formatted name and email combo.
|
||||
@@ -259,6 +274,10 @@ func Install(options *Options) (bool, *Template, error) {
|
||||
}
|
||||
templateData.AuthorNameAndEmail = strings.TrimSpace(templateData.AuthorNameAndEmail)
|
||||
|
||||
installer.RenameFiles(map[string]string{
|
||||
"gitignore.txt": ".gitignore",
|
||||
})
|
||||
|
||||
// Extract the template
|
||||
err = installer.Extract(options.TargetDir, templateData)
|
||||
if err != nil {
|
||||
@@ -317,17 +336,58 @@ func OutputList(logger *clilogger.CLILogger) error {
|
||||
|
||||
func generateIDEFiles(options *Options) error {
|
||||
|
||||
if options.GenerateVSCode {
|
||||
switch options.IDE {
|
||||
case "vscode":
|
||||
return generateVSCodeFiles(options)
|
||||
case "goland":
|
||||
return generateGolandFiles(options)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type ideOptions struct {
|
||||
name string
|
||||
targetDir string
|
||||
options *Options
|
||||
renameFiles map[string]string
|
||||
ignoredFiles []string
|
||||
}
|
||||
|
||||
func generateGolandFiles(options *Options) error {
|
||||
ideoptions := ideOptions{
|
||||
name: "goland",
|
||||
targetDir: filepath.Join(options.TargetDir, ".idea"),
|
||||
options: options,
|
||||
renameFiles: map[string]string{
|
||||
"projectname.iml": options.ProjectNameFilename + ".iml",
|
||||
"gitignore.txt": ".gitignore",
|
||||
"name": ".name",
|
||||
},
|
||||
}
|
||||
if !options.InitGit {
|
||||
ideoptions.ignoredFiles = []string{"vcs.xml"}
|
||||
}
|
||||
err := installIDEFiles(ideoptions)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "generating Goland IDE files")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateVSCodeFiles(options *Options) error {
|
||||
ideoptions := ideOptions{
|
||||
name: "vscode",
|
||||
targetDir: filepath.Join(options.TargetDir, ".vscode"),
|
||||
options: options,
|
||||
}
|
||||
return installIDEFiles(ideoptions)
|
||||
|
||||
targetDir := filepath.Join(options.TargetDir, ".vscode")
|
||||
source, err := debme.FS(ides, "ides/vscode")
|
||||
}
|
||||
|
||||
func installIDEFiles(o ideOptions) error {
|
||||
source, err := debme.FS(ides, "ides/"+o.name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -335,14 +395,22 @@ func generateVSCodeFiles(options *Options) error {
|
||||
// Use gosod to install the template
|
||||
installer := gosod.New(source)
|
||||
|
||||
binaryName := filepath.Base(options.TargetDir)
|
||||
if o.renameFiles != nil {
|
||||
installer.RenameFiles(o.renameFiles)
|
||||
}
|
||||
|
||||
for _, ignoreFile := range o.ignoredFiles {
|
||||
installer.IgnoreFile(ignoreFile)
|
||||
}
|
||||
|
||||
binaryName := filepath.Base(o.options.TargetDir)
|
||||
if runtime.GOOS == "windows" {
|
||||
// yay windows
|
||||
binaryName += ".exe"
|
||||
}
|
||||
|
||||
// Parse wails.json for assetdir
|
||||
wailsJSONBytes, err := os.ReadFile(filepath.Join(options.TargetDir, "wails.json"))
|
||||
wailsJSONBytes, err := os.ReadFile(filepath.Join(o.options.TargetDir, "wails.json"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -356,10 +424,16 @@ func generateVSCodeFiles(options *Options) error {
|
||||
return fmt.Errorf("Unable to find 'assetdir' in 'wails.json' ")
|
||||
}
|
||||
|
||||
options.AssetDir = assetDir.(string)
|
||||
options.PathToDesktopBinary = filepath.ToSlash(filepath.Join("build", "bin", binaryName))
|
||||
o.options.AssetDir = assetDir.(string)
|
||||
o.options.PathToDesktopBinary = filepath.ToSlash(filepath.Join("build", "bin", binaryName))
|
||||
|
||||
err = installer.Extract(targetDir, options)
|
||||
o.options.WindowsFlags = ""
|
||||
o.options.CGOEnabled = "1"
|
||||
if runtime.GOOS == "windows" {
|
||||
o.options.WindowsFlags = " -H windowsgui"
|
||||
o.options.CGOEnabled = "0"
|
||||
}
|
||||
err = installer.Extract(o.targetDir, o.options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ func (b *App) startup(ctx context.Context) {
|
||||
}
|
||||
|
||||
// domReady is called after the front-end dom has been loaded
|
||||
func (b App) domReady(ctx context.Context) {
|
||||
func (b *App) domReady(ctx context.Context) {
|
||||
// Add your action here
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
html {
|
||||
text-align: center;
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, 255);
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
@@ -13,6 +13,7 @@ body {
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overscroll-behavior: none;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Wails bin directory
|
||||
build/bin
|
||||
|
||||
# IDEs
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
# The black hole that is...
|
||||
node_modules
|
||||
@@ -2,7 +2,7 @@ module changeme
|
||||
|
||||
go 1.17
|
||||
|
||||
require github.com/wailsapp/wails/v2 v2.0.0-beta.0
|
||||
require github.com/wailsapp/wails/v2 {{.WailsVersion}}
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.2 // indirect
|
||||
@@ -35,4 +35,4 @@ golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect
|
||||
)
|
||||
|
||||
// replace github.com/wailsapp/wails/v2 v2.0.0-beta.0 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
|
||||
// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}}
|
||||
|
||||
@@ -15,6 +15,7 @@ github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab h1:9e2joQGp642w
|
||||
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab/go.mod h1:smsv/h4PBEBaU0XDTY5UwJTpZv69fQ0FfcLJr21mA6Y=
|
||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/flytam/filenamify v1.0.0/go.mod h1:Dzf9kVycwcsBlr2ATg6uxjqiFgKGH+5SKFuhdeP5zu8=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/gabriel-vasile/mimetype v1.3.1 h1:qevA6c2MtE1RorlScnixeG0VA1H4xrXyhyX3oWBynNQ=
|
||||
github.com/gabriel-vasile/mimetype v1.3.1/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
|
||||
@@ -58,8 +59,9 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 h1:pdFFlHXY9tZXmJz+tRSm1DzYEH4ebha7cffmm607bMU=
|
||||
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
@@ -75,16 +77,15 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
|
||||
github.com/leaanthony/debme v1.1.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
|
||||
github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
|
||||
github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4=
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM=
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3 h1:O0uGjKnWtdEADGrkg+TyAAbZylykMwwx/MNEXn9fp+Y=
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3/go.mod h1:TGhEc9eSJgRsupZ+iH1ZgAOnEo9zp05cRH2j08RPrF0=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934 h1:nK/JTPyJi5QRqYjVZjXgtN4/dhg2qtngoLxLDVn429k=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
|
||||
github.com/leaanthony/gosod v1.0.2/go.mod h1:W8RyeSFBXu7RpIxPGEJfW4moSyGGEjlJMLV25wEbAdU=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd h1:6m4zZ/esiByaDbzgdvDxjsOaIDgtuG1q2cyhjAi6uAg=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
|
||||
github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4=
|
||||
github.com/leaanthony/idgen v1.0.0/go.mod h1:4nBZnt8ml/f/ic/EVQuLxuj817RccT2fyrUaZFxrcVA=
|
||||
github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
|
||||
github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
|
||||
@@ -146,6 +147,8 @@ github.com/valyala/fasthttp v1.28.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfY
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
github.com/wailsapp/wails/v2 v2.0.0-beta.3 h1:8vhBbnjpYDF6cCUwKadon7J/98UjcP1nrnptUl70Tfg=
|
||||
github.com/wailsapp/wails/v2 v2.0.0-beta.3/go.mod h1:aku28riyHF2G5jmx/qtxjLWi7VwpTjhhX/HVLCptWFA=
|
||||
github.com/wzshiming/ctc v1.2.3/go.mod h1:2tVAtIY7SUyraSk0JxvwmONNPFL4ARavPuEsg5+KA28=
|
||||
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae/go.mod h1:VTAq37rkGeV+WOybvZwjXiJOicICdpLCN8ifpISjK20=
|
||||
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
|
||||
@@ -193,8 +196,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
@@ -222,4 +225,4 @@ gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
||||
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"embed"
|
||||
"log"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
@@ -13,6 +15,9 @@ import (
|
||||
//go:embed frontend/dist
|
||||
var assets embed.FS
|
||||
|
||||
//go:embed build/appicon.png
|
||||
var icon []byte
|
||||
|
||||
func main() {
|
||||
// Create an instance of the app structure
|
||||
app := NewApp()
|
||||
@@ -31,7 +36,7 @@ func main() {
|
||||
Frameless: false,
|
||||
StartHidden: false,
|
||||
HideWindowOnClose: false,
|
||||
RGBA: &options.RGBA{R: 255, G: 255, B: 255, A: 255},
|
||||
RGBA: &options.RGBA{R: 0, G: 0, B: 0, A: 0},
|
||||
Assets: assets,
|
||||
LogLevel: logger.DEBUG,
|
||||
OnStartup: app.startup,
|
||||
@@ -46,6 +51,17 @@ func main() {
|
||||
WindowIsTranslucent: false,
|
||||
DisableWindowIcon: false,
|
||||
},
|
||||
Mac: &mac.Options{
|
||||
TitleBar: mac.TitleBarHiddenInset(),
|
||||
Appearance: mac.NSAppearanceNameDarkAqua,
|
||||
WebviewIsTransparent: true,
|
||||
WindowIsTranslucent: true,
|
||||
About: &mac.AboutInfo{
|
||||
Title: "My Application",
|
||||
Message: "© 2021 Me",
|
||||
Icon: icon,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -22,7 +22,7 @@ func (b *App) startup(ctx context.Context) {
|
||||
}
|
||||
|
||||
// domReady is called after the front-end dom has been loaded
|
||||
func (b App) domReady(ctx context.Context) {
|
||||
func (b *App) domReady(ctx context.Context) {
|
||||
// Add your action here
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
html {
|
||||
background-color: rgba(33, 37, 43, 1);
|
||||
background-color: rgba(33, 37, 43, 0);
|
||||
text-align: center;
|
||||
color: white;
|
||||
}
|
||||
@@ -8,8 +8,9 @@ body {
|
||||
margin: 0;
|
||||
color: white;
|
||||
font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
|
||||
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
|
||||
sans-serif;
|
||||
overscroll-behavior: none;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Wails bin directory
|
||||
build/bin
|
||||
|
||||
# IDEs
|
||||
.idea
|
||||
.vscode
|
||||
|
||||
# The black hole that is...
|
||||
node_modules
|
||||
@@ -2,7 +2,7 @@ module changeme
|
||||
|
||||
go 1.17
|
||||
|
||||
require github.com/wailsapp/wails/v2 v2.0.0-beta.0
|
||||
require github.com/wailsapp/wails/v2 {{.WailsVersion}}
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.2 // indirect
|
||||
@@ -35,4 +35,4 @@ golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect
|
||||
)
|
||||
|
||||
// replace github.com/wailsapp/wails/v2 v2.0.0-beta.0 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
|
||||
// replace github.com/wailsapp/wails/v2 {{.WailsVersion}} => {{.WailsDirectory}}
|
||||
|
||||
@@ -15,6 +15,7 @@ github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab h1:9e2joQGp642w
|
||||
github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab/go.mod h1:smsv/h4PBEBaU0XDTY5UwJTpZv69fQ0FfcLJr21mA6Y=
|
||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/flytam/filenamify v1.0.0/go.mod h1:Dzf9kVycwcsBlr2ATg6uxjqiFgKGH+5SKFuhdeP5zu8=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/gabriel-vasile/mimetype v1.3.1 h1:qevA6c2MtE1RorlScnixeG0VA1H4xrXyhyX3oWBynNQ=
|
||||
github.com/gabriel-vasile/mimetype v1.3.1/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
|
||||
@@ -58,8 +59,9 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 h1:pdFFlHXY9tZXmJz+tRSm1DzYEH4ebha7cffmm607bMU=
|
||||
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
@@ -75,16 +77,15 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
|
||||
github.com/leaanthony/debme v1.1.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
|
||||
github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
|
||||
github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4=
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM=
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3 h1:O0uGjKnWtdEADGrkg+TyAAbZylykMwwx/MNEXn9fp+Y=
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3/go.mod h1:TGhEc9eSJgRsupZ+iH1ZgAOnEo9zp05cRH2j08RPrF0=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934 h1:nK/JTPyJi5QRqYjVZjXgtN4/dhg2qtngoLxLDVn429k=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
|
||||
github.com/leaanthony/gosod v1.0.2/go.mod h1:W8RyeSFBXu7RpIxPGEJfW4moSyGGEjlJMLV25wEbAdU=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd h1:6m4zZ/esiByaDbzgdvDxjsOaIDgtuG1q2cyhjAi6uAg=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210928094513-a94a08b538bd/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
|
||||
github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4=
|
||||
github.com/leaanthony/idgen v1.0.0/go.mod h1:4nBZnt8ml/f/ic/EVQuLxuj817RccT2fyrUaZFxrcVA=
|
||||
github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
|
||||
github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
|
||||
@@ -146,6 +147,8 @@ github.com/valyala/fasthttp v1.28.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfY
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
github.com/wailsapp/wails/v2 v2.0.0-beta.3 h1:8vhBbnjpYDF6cCUwKadon7J/98UjcP1nrnptUl70Tfg=
|
||||
github.com/wailsapp/wails/v2 v2.0.0-beta.3/go.mod h1:aku28riyHF2G5jmx/qtxjLWi7VwpTjhhX/HVLCptWFA=
|
||||
github.com/wzshiming/ctc v1.2.3/go.mod h1:2tVAtIY7SUyraSk0JxvwmONNPFL4ARavPuEsg5+KA28=
|
||||
github.com/wzshiming/winseq v0.0.0-20200112104235-db357dc107ae/go.mod h1:VTAq37rkGeV+WOybvZwjXiJOicICdpLCN8ifpISjK20=
|
||||
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
|
||||
@@ -193,8 +196,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 h1:foEbQz/B0Oz6YIqu/69kfXPYeFQAuuMYFkjaqXzl5Wo=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"embed"
|
||||
"log"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
||||
|
||||
"github.com/wailsapp/wails/v2"
|
||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
@@ -13,6 +15,9 @@ import (
|
||||
//go:embed frontend/src
|
||||
var assets embed.FS
|
||||
|
||||
//go:embed build/appicon.png
|
||||
var icon []byte
|
||||
|
||||
func main() {
|
||||
// Create an instance of the app structure
|
||||
app := NewApp()
|
||||
@@ -31,7 +36,7 @@ func main() {
|
||||
Frameless: false,
|
||||
StartHidden: false,
|
||||
HideWindowOnClose: false,
|
||||
RGBA: &options.RGBA{R: 255, G: 255, B: 255, A: 255},
|
||||
RGBA: &options.RGBA{R: 0, G: 0, B: 0, A: 0},
|
||||
Assets: assets,
|
||||
LogLevel: logger.DEBUG,
|
||||
OnStartup: app.startup,
|
||||
@@ -46,6 +51,16 @@ func main() {
|
||||
WindowIsTranslucent: false,
|
||||
DisableWindowIcon: false,
|
||||
},
|
||||
Mac: &mac.Options{
|
||||
TitleBar: mac.TitleBarHiddenInset(),
|
||||
WebviewIsTransparent: true,
|
||||
WindowIsTranslucent: true,
|
||||
About: &mac.AboutInfo{
|
||||
Title: "Vanilla Template",
|
||||
Message: "Part of the Wails projects",
|
||||
Icon: icon,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
|
||||
@@ -86,7 +86,7 @@ func updateToVersion(logger *clilogger.CLILogger, targetVersion *github.Semantic
|
||||
|
||||
// Early exit
|
||||
if targetVersionString == currentVersion {
|
||||
logger.Println("Looks like you're up to date!")
|
||||
logger.Println("\nLooks like you're up to date!")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -151,14 +151,16 @@ func updateToVersion(logger *clilogger.CLILogger, targetVersion *github.Semantic
|
||||
log.Fatal("Cannot find home directory! Please file a bug report!")
|
||||
}
|
||||
|
||||
sout, serr, err := shell.RunCommand(homeDir, "go", "get", "github.com/wailsapp/wails/v2/cmd/wails@"+desiredVersion)
|
||||
sout, serr, err := shell.RunCommand(homeDir, "go", "install", "github.com/wailsapp/wails/v2/cmd/wails@"+desiredVersion)
|
||||
if err != nil {
|
||||
logger.Println("Failed.")
|
||||
logger.Println(sout + `\n` + serr)
|
||||
return err
|
||||
}
|
||||
fmt.Println()
|
||||
logger.Println("\n")
|
||||
logger.Println("Wails CLI updated to " + desiredVersion)
|
||||
logger.Println("Make sure you update your project go.mod file to use " + desiredVersion + ":")
|
||||
logger.Println(" require github.com/wailsapp/wails/v2 " + desiredVersion)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
15
v2/cmd/wails/internal/tags.go
Normal file
15
v2/cmd/wails/internal/tags.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package internal
|
||||
|
||||
import "strings"
|
||||
|
||||
// ParseUserTags takes the string form of tags and converts to a slice of strings
|
||||
func ParseUserTags(tagString string) []string {
|
||||
userTags := make([]string, 0)
|
||||
for _, tag := range strings.Split(tagString, " ") {
|
||||
thisTag := strings.TrimSpace(tag)
|
||||
if thisTag != "" {
|
||||
userTags = append(userTags, thisTag)
|
||||
}
|
||||
}
|
||||
return userTags
|
||||
}
|
||||
3
v2/cmd/wails/internal/version.go
Normal file
3
v2/cmd/wails/internal/version.go
Normal file
@@ -0,0 +1,3 @@
|
||||
package internal
|
||||
|
||||
var Version = "v2.0.0-beta.15"
|
||||
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/wailsapp/wails/v2/cmd/wails/internal"
|
||||
"os"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/colour"
|
||||
@@ -24,7 +25,7 @@ func fatal(message string) {
|
||||
func banner(_ *clir.Cli) string {
|
||||
return fmt.Sprintf("%s %s\n",
|
||||
colour.Yellow("Wails CLI"),
|
||||
colour.DarkRed(version))
|
||||
colour.DarkRed(internal.Version))
|
||||
}
|
||||
|
||||
func printFooter() {
|
||||
@@ -35,7 +36,7 @@ func main() {
|
||||
|
||||
var err error
|
||||
|
||||
app := clir.NewCli("Wails", "Go/HTML Appkit", version)
|
||||
app := clir.NewCli("Wails", "Go/HTML Appkit", internal.Version)
|
||||
|
||||
app.SetBannerFunction(banner)
|
||||
defer printFooter()
|
||||
@@ -61,14 +62,14 @@ func main() {
|
||||
fatal(err.Error())
|
||||
}
|
||||
|
||||
err = update.AddSubcommand(app, os.Stdout, version)
|
||||
err = update.AddSubcommand(app, os.Stdout, internal.Version)
|
||||
if err != nil {
|
||||
fatal(err.Error())
|
||||
}
|
||||
|
||||
command := app.NewSubCommand("version", "The Wails CLI version")
|
||||
command.Action(func() error {
|
||||
println(version)
|
||||
println(internal.Version)
|
||||
return nil
|
||||
})
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
package main
|
||||
|
||||
var version = "v2.0.0-beta.0"
|
||||
13
v2/go.mod
13
v2/go.mod
@@ -5,6 +5,7 @@ go 1.17
|
||||
require (
|
||||
github.com/Masterminds/semver v1.5.0
|
||||
github.com/fatih/structtag v1.2.0
|
||||
github.com/flytam/filenamify v1.0.0
|
||||
github.com/fsnotify/fsnotify v1.4.9
|
||||
github.com/gabriel-vasile/mimetype v1.3.1
|
||||
github.com/go-git/go-billy/v5 v5.2.0 // indirect
|
||||
@@ -12,6 +13,7 @@ require (
|
||||
github.com/gofiber/fiber/v2 v2.17.0
|
||||
github.com/gofiber/websocket/v2 v2.0.8
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||
github.com/google/uuid v1.1.2 // indirect
|
||||
github.com/gorilla/websocket v1.4.1
|
||||
github.com/imdario/mergo v0.3.12
|
||||
@@ -20,8 +22,8 @@ require (
|
||||
github.com/leaanthony/debme v1.2.1
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934
|
||||
github.com/leaanthony/gosod v1.0.2
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20211022194343-1e4c8d4226f3
|
||||
github.com/leaanthony/gosod v1.0.3
|
||||
github.com/leaanthony/idgen v1.0.0
|
||||
github.com/leaanthony/slicer v1.5.0
|
||||
github.com/leaanthony/typescriptify-golang-structs v0.1.7
|
||||
@@ -40,9 +42,9 @@ require (
|
||||
github.com/wzshiming/ctc v1.2.3
|
||||
github.com/xyproto/xpm v1.2.1
|
||||
github.com/ztrue/tracerr v0.3.0
|
||||
golang.org/x/mod v0.4.1 // indirect
|
||||
golang.org/x/mod v0.4.1
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf
|
||||
golang.org/x/sys v0.0.0-20211020174200-9d6173849985
|
||||
golang.org/x/tools v0.1.0
|
||||
nhooyr.io/websocket v1.8.6
|
||||
)
|
||||
@@ -56,9 +58,10 @@ require (
|
||||
github.com/go-ole/go-ole v1.2.5 // indirect
|
||||
github.com/google/go-cmp v0.5.5 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 // indirect
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||
github.com/klauspost/compress v1.12.2 // indirect
|
||||
github.com/kr/pretty v0.3.0 // indirect
|
||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e // indirect
|
||||
github.com/mattn/go-runewidth v0.0.7 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
|
||||
27
v2/go.sum
27
v2/go.sum
@@ -22,6 +22,8 @@ github.com/fasthttp/websocket v0.0.0-20200320073529-1554a54587ab/go.mod h1:smsv/
|
||||
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
|
||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/flytam/filenamify v1.0.0 h1:ewx6BY2dj7U6h2zGPJmt33q/BjkSf/YsY/woQvnUNIs=
|
||||
github.com/flytam/filenamify v1.0.0/go.mod h1:Dzf9kVycwcsBlr2ATg6uxjqiFgKGH+5SKFuhdeP5zu8=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/gabriel-vasile/mimetype v1.3.1 h1:qevA6c2MtE1RorlScnixeG0VA1H4xrXyhyX3oWBynNQ=
|
||||
@@ -73,6 +75,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@@ -84,8 +88,9 @@ github.com/jackmordaunt/icns v1.0.0 h1:RYSxplerf/l/DUd09AHtITwckkv/mqjVv4DjYdPmA
|
||||
github.com/jackmordaunt/icns v1.0.0/go.mod h1:7TTQVEuGzVVfOPPlLNHJIkzA6CoV7aH1Dv9dW351oOo=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
|
||||
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5 h1:pdFFlHXY9tZXmJz+tRSm1DzYEH4ebha7cffmm607bMU=
|
||||
github.com/jchv/go-winloader v0.0.0-20200815041850-dec1ee9a7fd5/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
|
||||
github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
|
||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
@@ -98,25 +103,25 @@ github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8
|
||||
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leaanthony/clir v1.0.4 h1:Dov2y9zWJmZr7CjaCe86lKa4b5CSxskGAt2yBkoDyiU=
|
||||
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
|
||||
github.com/leaanthony/debme v1.1.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
|
||||
github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
|
||||
github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1 h1:97v6c5kYppVsbScf4r/VZdXyQ21KQIfeQOk2DgKxGG4=
|
||||
github.com/leaanthony/go-ansi-parser v1.0.1/go.mod h1:7arTzgVI47srICYhvgUV4CGd063sGEeoSlych5yeSPM=
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3 h1:O0uGjKnWtdEADGrkg+TyAAbZylykMwwx/MNEXn9fp+Y=
|
||||
github.com/leaanthony/go-common-file-dialog v1.0.3/go.mod h1:TGhEc9eSJgRsupZ+iH1ZgAOnEo9zp05cRH2j08RPrF0=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934 h1:nK/JTPyJi5QRqYjVZjXgtN4/dhg2qtngoLxLDVn429k=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20210914103035-f00aa774a934/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
|
||||
github.com/leaanthony/gosod v1.0.2 h1:LtjqaIoHuoXiQXbzMPq0isjNfltSyHKhWeiU/JbmP0w=
|
||||
github.com/leaanthony/gosod v1.0.2/go.mod h1:W8RyeSFBXu7RpIxPGEJfW4moSyGGEjlJMLV25wEbAdU=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20211022194343-1e4c8d4226f3 h1:qhgrg3MhFRAIvtaqoqI+SrT+0wDYpxDMp9e3cvcxMpI=
|
||||
github.com/leaanthony/go-webview2 v0.0.0-20211022194343-1e4c8d4226f3/go.mod h1:lS5ds4bruPk9d7lzdF/OH31Z0YCerI6MmHNFGsWoUnM=
|
||||
github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ=
|
||||
github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4=
|
||||
github.com/leaanthony/idgen v1.0.0 h1:IZreR+JGEzFV4yeVuBZA25gM0keUoFy+RDUldncQ+Jw=
|
||||
github.com/leaanthony/idgen v1.0.0/go.mod h1:4nBZnt8ml/f/ic/EVQuLxuj817RccT2fyrUaZFxrcVA=
|
||||
github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
|
||||
@@ -157,6 +162,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f h1:PgA+Olipyj258EIEYnpFFONrrCcAIWNUNoFhUfMqAGY=
|
||||
github.com/savsgio/gotils v0.0.0-20200117113501-90175b0fbe3f/go.mod h1:lHhJedqxCoHN+zMtwGNTXWmF0u9Jt363FYRhV6g0CdY=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
@@ -255,8 +262,8 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210611083646-a4fc73990273/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211020174200-9d6173849985 h1:LOlKVhfDyahgmqa97awczplwkjzNaELFg3zRIJ13RYo=
|
||||
golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -278,10 +285,12 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
|
||||
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
||||
105
v2/internal/appng/app_bindings.go
Normal file
105
v2/internal/appng/app_bindings.go
Normal file
@@ -0,0 +1,105 @@
|
||||
//go:build bindings
|
||||
// +build bindings
|
||||
|
||||
package appng
|
||||
|
||||
import (
|
||||
"github.com/leaanthony/gosod"
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
wailsRuntime "github.com/wailsapp/wails/v2/internal/frontend/runtime"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/runtime/wrapper"
|
||||
"github.com/wailsapp/wails/v2/internal/fs"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/project"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// App defines a Wails application structure
|
||||
type App struct {
|
||||
logger *logger.Logger
|
||||
appoptions *options.App
|
||||
}
|
||||
|
||||
func (a *App) Run() error {
|
||||
|
||||
// Create binding exemptions - Ugly hack. There must be a better way
|
||||
bindingExemptions := []interface{}{a.appoptions.OnStartup, a.appoptions.OnShutdown, a.appoptions.OnDomReady}
|
||||
appBindings := binding.NewBindings(a.logger, a.appoptions.Bind, bindingExemptions)
|
||||
|
||||
err := generateBindings(appBindings)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateApp creates the app!
|
||||
func CreateApp(appoptions *options.App) (*App, error) {
|
||||
// Set up logger
|
||||
myLogger := logger.New(appoptions.Logger)
|
||||
myLogger.SetLogLevel(appoptions.LogLevel)
|
||||
|
||||
result := &App{
|
||||
logger: myLogger,
|
||||
appoptions: appoptions,
|
||||
}
|
||||
|
||||
return result, nil
|
||||
|
||||
}
|
||||
|
||||
func generateBindings(bindings *binding.Bindings) error {
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
projectConfig, err := project.Load(cwd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wrapperDir := filepath.Join(projectConfig.WailsJSDir, "wailsjs", "runtime")
|
||||
_ = os.RemoveAll(wrapperDir)
|
||||
extractor := gosod.New(wrapper.RuntimeWrapper)
|
||||
err = extractor.Extract(wrapperDir, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//ipcdev.js
|
||||
err = os.WriteFile(filepath.Join(wrapperDir, "ipcdev.js"), wailsRuntime.DesktopIPC, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//runtimedev.js
|
||||
err = os.WriteFile(filepath.Join(wrapperDir, "runtimedev.js"), wailsRuntime.RuntimeDesktopJS, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
targetDir := filepath.Join(projectConfig.WailsJSDir, "wailsjs", "go")
|
||||
err = os.RemoveAll(targetDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = fs.MkDirs(targetDir)
|
||||
|
||||
modelsFile := filepath.Join(targetDir, "models.ts")
|
||||
err = bindings.WriteTS(modelsFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write backend method wrappers
|
||||
bindingsFilename := filepath.Join(targetDir, "bindings.js")
|
||||
err = bindings.GenerateBackendJS(bindingsFilename, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build darwin
|
||||
//go:build darwin && !bindings
|
||||
|
||||
package appng
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build !dev && !production && darwin
|
||||
//go:build !dev && !production && !bindings && darwin
|
||||
|
||||
package appng
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build !dev && !production && windows
|
||||
//go:build !dev && !production && !bindings && windows
|
||||
|
||||
package appng
|
||||
|
||||
@@ -24,7 +24,7 @@ Please use "wails build" or press "OK" to open the documentation on how to use "
|
||||
"Error",
|
||||
w32.MB_ICONERROR|w32.MB_OKCANCEL)
|
||||
if result == 1 {
|
||||
exec.Command("rundll32", "url.dll,FileProtocolHandler", "https://wails.io").Start()
|
||||
exec.Command("rundll32", "url.dll,FileProtocolHandler", "https://wails.io/docs/guides/manual-builds").Start()
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@ package appng
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/desktop"
|
||||
@@ -16,18 +18,14 @@ import (
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||
"github.com/wailsapp/wails/v2/internal/project"
|
||||
"github.com/wailsapp/wails/v2/internal/signal"
|
||||
pkglogger "github.com/wailsapp/wails/v2/pkg/logger"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// App defines a Wails application structure
|
||||
type App struct {
|
||||
frontend frontend.Frontend
|
||||
logger *logger.Logger
|
||||
signal *signal.Manager
|
||||
options *options.App
|
||||
|
||||
menuManager *menumanager.Manager
|
||||
@@ -60,14 +58,20 @@ func CreateApp(appoptions *options.App) (*App, error) {
|
||||
myLogger.SetLogLevel(appoptions.LogLevel)
|
||||
|
||||
// Check for CLI Flags
|
||||
assetdir := flag.String("assetdir", "", "Directory to serve assets")
|
||||
loglevel := flag.String("loglevel", "debug", "Loglevel to use - Trace, Debug, Info, Warning, Error")
|
||||
flag.Parse()
|
||||
if assetdir != nil && *assetdir != "" {
|
||||
ctx = context.WithValue(ctx, "assetdir", *assetdir)
|
||||
|
||||
assetdir := os.Getenv("assetdir")
|
||||
devServerURL := os.Getenv("devserverurl")
|
||||
loglevel := os.Getenv("loglevel")
|
||||
|
||||
if devServerURL != "" {
|
||||
ctx = context.WithValue(ctx, "devserverurl", devServerURL)
|
||||
}
|
||||
if loglevel != nil && *loglevel != "" {
|
||||
level, err := pkglogger.StringToLogLevel(*loglevel)
|
||||
if assetdir != "" {
|
||||
ctx = context.WithValue(ctx, "assetdir", assetdir)
|
||||
}
|
||||
|
||||
if loglevel != "" {
|
||||
level, err := pkglogger.StringToLogLevel(loglevel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -157,7 +161,7 @@ func generateBindings(bindings *binding.Bindings) error {
|
||||
|
||||
// Write backend method wrappers
|
||||
bindingsFilename := filepath.Join(targetDir, "bindings.js")
|
||||
err = bindings.GenerateBackendJS(bindingsFilename)
|
||||
err = bindings.GenerateBackendJS(bindingsFilename, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ package appng
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/desktop"
|
||||
@@ -12,7 +13,6 @@ import (
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/runtime"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||
"github.com/wailsapp/wails/v2/internal/signal"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
@@ -20,7 +20,6 @@ import (
|
||||
type App struct {
|
||||
frontend frontend.Frontend
|
||||
logger *logger.Logger
|
||||
signal *signal.Manager
|
||||
options *options.App
|
||||
|
||||
menuManager *menumanager.Manager
|
||||
@@ -36,9 +35,6 @@ type App struct {
|
||||
|
||||
func (a *App) Run() error {
|
||||
err := a.frontend.Run(a.ctx)
|
||||
if a.shutdownCallback != nil {
|
||||
a.shutdownCallback(a.ctx)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build windows
|
||||
//go:build windows && !bindings
|
||||
|
||||
package appng
|
||||
|
||||
|
||||
@@ -4,18 +4,19 @@ import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"github.com/wailsapp/wails/v2/internal/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/fs"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
)
|
||||
|
||||
//go:embed assets/package.json
|
||||
var packageJSON []byte
|
||||
|
||||
func (b *Bindings) GenerateBackendJS(targetfile string) error {
|
||||
func (b *Bindings) GenerateBackendJS(targetfile string, isDevBindings bool) error {
|
||||
|
||||
store := b.db.store
|
||||
var output bytes.Buffer
|
||||
@@ -23,8 +24,18 @@ func (b *Bindings) GenerateBackendJS(targetfile string) error {
|
||||
output.WriteString(`// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
`)
|
||||
|
||||
const go = {`)
|
||||
if isDevBindings {
|
||||
json, err := b.ToJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
output.WriteString("window.wailsbindings = " + json + ";")
|
||||
output.WriteString("\n")
|
||||
}
|
||||
|
||||
output.WriteString(`const go = {`)
|
||||
output.WriteString("\n")
|
||||
|
||||
var sortedPackageNames slicer.StringSlicer
|
||||
@@ -89,12 +100,10 @@ const go = {`)
|
||||
|
||||
})
|
||||
|
||||
output.WriteString(fmt.Sprintf(" }"))
|
||||
output.WriteString("\n")
|
||||
output.WriteString(" },\n")
|
||||
})
|
||||
|
||||
output.WriteString(fmt.Sprintf(" }\n"))
|
||||
output.WriteString("\n")
|
||||
output.WriteString(" },\n\n")
|
||||
})
|
||||
|
||||
output.WriteString(`};
|
||||
|
||||
@@ -1252,7 +1252,7 @@ void createDelegate(struct Application *app) {
|
||||
|
||||
app->delegate = delegate;
|
||||
|
||||
msg_id(app->application, s("setDelegate:"), delegate);
|
||||
msg_id(app->application, s("setDelegate:"), delegate);
|
||||
}
|
||||
|
||||
bool windowShouldClose(id self, SEL cmd, id sender) {
|
||||
|
||||
@@ -1 +1 @@
|
||||
The version of WebView2 used: 1.0.864.35
|
||||
The version of WebView2 SDK used: 1.0.992.28
|
||||
|
||||
@@ -7,7 +7,7 @@ set sdk_version=%1
|
||||
set native_dir="%~dp0\microsoft.web.webview2.%sdk_version%\build\native"
|
||||
copy "%native_dir%\include\*.h" .. >NUL
|
||||
copy "%native_dir%\x64\WebView2Loader.dll" "..\x64" >NUL
|
||||
@rd /S /Q "microsoft.web.webview2.%sdk_version%"
|
||||
@REM @rd /S /Q "microsoft.web.webview2.%sdk_version%"
|
||||
del /s version.txt >nul 2>&1
|
||||
echo The version of WebView2 SDK used: %sdk_version% > sdkversion.txt
|
||||
echo SDK updated to %sdk_version%
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
func doInstallationStrategy(installStatus installationStatus) error {
|
||||
confirmed, err := webview2runtime.Confirm("This application requires the WebView2 runtime. Press OK to open the download page. Minimum version required: "+minimumRuntimeVersion, "Missing Requirements")
|
||||
confirmed, err := webview2runtime.Confirm("This application requires the WebView2 runtime. Press OK to open the download page. Minimum version required: "+MinimumRuntimeVersion, "Missing Requirements")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"github.com/leaanthony/webview2runtime"
|
||||
)
|
||||
|
||||
const MinimumRuntimeVersion string = "91.0.864.48"
|
||||
const MinimumRuntimeVersion string = "91.0.992.28"
|
||||
|
||||
type installationStatus int
|
||||
|
||||
|
||||
115
v2/internal/frontend/assetserver/assetserver_browser_dev.go
Normal file
115
v2/internal/frontend/assetserver/assetserver_browser_dev.go
Normal file
@@ -0,0 +1,115 @@
|
||||
//go:build dev
|
||||
// +build dev
|
||||
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/runtime"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"golang.org/x/net/html"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
The assetserver for dev serves assets from disk.
|
||||
It injects a websocket based IPC script into `index.html`.
|
||||
|
||||
*/
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
type BrowserAssetServer struct {
|
||||
runtimeJS []byte
|
||||
assetdir string
|
||||
appOptions *options.App
|
||||
}
|
||||
|
||||
func NewBrowserAssetServer(assetdir string, bindingsJSON string, appOptions *options.App) (*BrowserAssetServer, error) {
|
||||
result := &BrowserAssetServer{
|
||||
assetdir: assetdir,
|
||||
appOptions: appOptions,
|
||||
}
|
||||
|
||||
var buffer bytes.Buffer
|
||||
buffer.WriteString(`window.wailsbindings='` + bindingsJSON + `';` + "\n")
|
||||
buffer.Write(runtime.RuntimeDesktopJS)
|
||||
result.runtimeJS = buffer.Bytes()
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (a *BrowserAssetServer) loadFileFromDisk(filename string) ([]byte, error) {
|
||||
return os.ReadFile(filepath.Join(a.assetdir, filename))
|
||||
}
|
||||
|
||||
func (a *BrowserAssetServer) processIndexHTML() ([]byte, error) {
|
||||
indexHTML, err := a.loadFileFromDisk("index.html")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
htmlNode, err := getHTMLNode(indexHTML)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = appendSpinnerToBody(htmlNode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wailsOptions, err := extractOptions(indexHTML)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if wailsOptions.disableIPCInjection == false {
|
||||
err := insertScriptInHead(htmlNode, "/wails/ipc.js")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if wailsOptions.disableRuntimeInjection == false {
|
||||
err := insertScriptInHead(htmlNode, "/wails/runtime.js")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var buffer bytes.Buffer
|
||||
err = html.Render(&buffer, htmlNode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
func (a *BrowserAssetServer) Load(filename string) ([]byte, string, error) {
|
||||
var content []byte
|
||||
var err error
|
||||
switch filename {
|
||||
case "/":
|
||||
content, err = a.processIndexHTML()
|
||||
case "/wails/runtime.js":
|
||||
content = a.runtimeJS
|
||||
case "/wails/ipc.js":
|
||||
content = runtime.WebsocketIPC
|
||||
default:
|
||||
content, err = a.loadFileFromDisk(filename)
|
||||
if strings.HasSuffix(filename, ".js") {
|
||||
var buffer bytes.Buffer
|
||||
buffer.WriteString("window.awaitIPC('" + filename + "', ()=>{")
|
||||
buffer.Write(content)
|
||||
buffer.WriteString(`
|
||||
});`)
|
||||
content = buffer.Bytes()
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
mimeType := GetMimetype(filename, content)
|
||||
return content, mimeType, nil
|
||||
}
|
||||
@@ -10,13 +10,13 @@ import (
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/runtime"
|
||||
"github.com/wailsapp/wails/v2/internal/logger"
|
||||
"io/fs"
|
||||
"log"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type DesktopAssetServer struct {
|
||||
assets debme.Debme
|
||||
indexFile []byte
|
||||
runtimeJS []byte
|
||||
assetdir string
|
||||
logger *logger.Logger
|
||||
@@ -106,27 +106,41 @@ func (a *DesktopAssetServer) init(assets embed.FS) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
indexHTML, err := a.assets.ReadFile("index.html")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.indexFile, err = injectHTML(string(indexHTML), `<script src="/wails/runtime.js"></script>`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.indexFile, err = injectHTML(string(a.indexFile), `<script src="/wails/ipc.js"></script>`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *DesktopAssetServer) processIndexHTML() ([]byte, error) {
|
||||
indexHTML, err := a.ReadFile("index.html")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wailsOptions, err := extractOptions(indexHTML)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return nil, err
|
||||
}
|
||||
if wailsOptions.disableRuntimeInjection == false {
|
||||
indexHTML, err = injectHTML(string(indexHTML), `<script src="/wails/runtime.js"></script>`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if wailsOptions.disableIPCInjection == false {
|
||||
indexHTML, err = injectHTML(string(indexHTML), `<script src="/wails/ipc.js"></script>`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return indexHTML, nil
|
||||
}
|
||||
|
||||
func (a *DesktopAssetServer) Load(filename string) ([]byte, string, error) {
|
||||
var content []byte
|
||||
var err error
|
||||
switch filename {
|
||||
case "/":
|
||||
content = a.indexFile
|
||||
content, err = a.processIndexHTML()
|
||||
case "/wails/runtime.js":
|
||||
content = a.runtimeJS
|
||||
case "/wails/ipc.js":
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
//go:build dev
|
||||
// +build dev
|
||||
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend/runtime"
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
/*
|
||||
|
||||
The assetserver for dev serves assets from disk.
|
||||
It injects a websocket based IPC script into `index.html`.
|
||||
|
||||
*/
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
type AssetServer struct {
|
||||
indexFile []byte
|
||||
runtimeJS []byte
|
||||
assetdir string
|
||||
appOptions *options.App
|
||||
}
|
||||
|
||||
func NewAssetServer(assetdir string, bindingsJSON string, appOptions *options.App) (*AssetServer, error) {
|
||||
result := &AssetServer{
|
||||
assetdir: assetdir,
|
||||
appOptions: appOptions,
|
||||
}
|
||||
|
||||
err := result.init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var buffer bytes.Buffer
|
||||
buffer.WriteString(`window.wailsbindings='` + bindingsJSON + `';` + "\n")
|
||||
buffer.Write(runtime.RuntimeDesktopJS)
|
||||
result.runtimeJS = buffer.Bytes()
|
||||
err = result.init()
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (a *AssetServer) loadFileFromDisk(filename string) ([]byte, error) {
|
||||
return os.ReadFile(filepath.Join(a.assetdir, filename))
|
||||
}
|
||||
|
||||
func (a *AssetServer) init() error {
|
||||
var err error
|
||||
a.indexFile, err = a.loadFileFromDisk("index.html")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.indexFile, err = injectHTML(string(a.indexFile), `<div id="wails-spinner"></div>`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.indexFile, err = injectHTML(string(a.indexFile), `<script src="/wails/ipc.js"></script>`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
a.indexFile, err = injectHTML(string(a.indexFile), `<script src="/wails/runtime.js"></script>`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AssetServer) Load(filename string) ([]byte, string, error) {
|
||||
var content []byte
|
||||
var err error
|
||||
switch filename {
|
||||
case "/":
|
||||
content = a.indexFile
|
||||
case "/wails/runtime.js":
|
||||
content = a.runtimeJS
|
||||
case "/wails/ipc.js":
|
||||
content = runtime.WebsocketIPC
|
||||
default:
|
||||
content, err = a.loadFileFromDisk(filename)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
mimeType := GetMimetype(filename, content)
|
||||
return content, mimeType, nil
|
||||
}
|
||||
@@ -2,20 +2,162 @@ package assetserver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"golang.org/x/net/html"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type optionType string
|
||||
|
||||
const (
|
||||
noAutoInject optionType = "noautoinject"
|
||||
noAutoInjectRuntime optionType = "noautoinjectruntime"
|
||||
noAutoInjectIPC optionType = "noautoinjectipc"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
disableRuntimeInjection bool
|
||||
disableIPCInjection bool
|
||||
}
|
||||
|
||||
func newOptions(optionString string) *Options {
|
||||
var result = &Options{}
|
||||
optionString = strings.ToLower(optionString)
|
||||
options := strings.Split(optionString, ",")
|
||||
for _, option := range options {
|
||||
switch optionType(strings.TrimSpace(option)) {
|
||||
case noAutoInject:
|
||||
result.disableRuntimeInjection = true
|
||||
result.disableIPCInjection = true
|
||||
case noAutoInjectIPC:
|
||||
result.disableIPCInjection = true
|
||||
case noAutoInjectRuntime:
|
||||
result.disableRuntimeInjection = true
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func injectHTML(input string, html string) ([]byte, error) {
|
||||
splits := strings.Split(input, "</body>")
|
||||
splits := strings.Split(input, "</head>")
|
||||
if len(splits) != 2 {
|
||||
return nil, fmt.Errorf("unable to locate a </body> tag in your html")
|
||||
return nil, fmt.Errorf("unable to locate a </head> tag in your html")
|
||||
}
|
||||
|
||||
var result bytes.Buffer
|
||||
result.WriteString(splits[0])
|
||||
result.WriteString(html)
|
||||
result.WriteString("</body>")
|
||||
result.WriteString("</head>")
|
||||
result.WriteString(splits[1])
|
||||
return result.Bytes(), nil
|
||||
}
|
||||
|
||||
func extractOptions(htmldata []byte) (*Options, error) {
|
||||
doc, err := html.Parse(bytes.NewReader(htmldata))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var extractor func(*html.Node) *Options
|
||||
extractor = func(node *html.Node) *Options {
|
||||
if node.Type == html.ElementNode && node.Data == "meta" {
|
||||
isWailsOptionsTag := false
|
||||
wailsOptions := ""
|
||||
for _, attr := range node.Attr {
|
||||
if isWailsOptionsTag && attr.Key == "content" {
|
||||
wailsOptions = attr.Val
|
||||
}
|
||||
if attr.Val == "wails-options" {
|
||||
isWailsOptionsTag = true
|
||||
}
|
||||
}
|
||||
return newOptions(wailsOptions)
|
||||
}
|
||||
for child := node.FirstChild; child != nil; child = child.NextSibling {
|
||||
result := extractor(child)
|
||||
if result != nil {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
result := extractor(doc)
|
||||
if result == nil {
|
||||
result = &Options{}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func createScriptNode(scriptName string) *html.Node {
|
||||
return &html.Node{
|
||||
Type: html.ElementNode,
|
||||
Data: "script",
|
||||
Attr: []html.Attribute{
|
||||
{
|
||||
Key: "src",
|
||||
Val: scriptName,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func createDivNode(id string) *html.Node {
|
||||
return &html.Node{
|
||||
Type: html.ElementNode,
|
||||
Data: "div",
|
||||
Attr: []html.Attribute{
|
||||
{
|
||||
Namespace: "",
|
||||
Key: "id",
|
||||
Val: id,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func insertScriptInHead(htmlNode *html.Node, scriptName string) error {
|
||||
headNode := findFirstTag(htmlNode, "head")
|
||||
if headNode == nil {
|
||||
return errors.New("cannot find head in HTML")
|
||||
}
|
||||
scriptNode := createScriptNode(scriptName)
|
||||
if headNode.FirstChild != nil {
|
||||
headNode.InsertBefore(scriptNode, headNode.FirstChild)
|
||||
} else {
|
||||
headNode.AppendChild(scriptNode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func appendSpinnerToBody(htmlNode *html.Node) error {
|
||||
bodyNode := findFirstTag(htmlNode, "body")
|
||||
if bodyNode == nil {
|
||||
return errors.New("cannot find body in HTML")
|
||||
}
|
||||
scriptNode := createDivNode("wails-spinner")
|
||||
bodyNode.AppendChild(scriptNode)
|
||||
return nil
|
||||
}
|
||||
|
||||
func getHTMLNode(htmldata []byte) (*html.Node, error) {
|
||||
return html.Parse(bytes.NewReader(htmldata))
|
||||
}
|
||||
|
||||
func findFirstTag(htmlnode *html.Node, tagName string) *html.Node {
|
||||
var extractor func(*html.Node) *html.Node
|
||||
var result *html.Node
|
||||
extractor = func(node *html.Node) *html.Node {
|
||||
if node.Type == html.ElementNode && node.Data == tagName {
|
||||
return node
|
||||
}
|
||||
for child := node.FirstChild; child != nil; child = child.NextSibling {
|
||||
result := extractor(child)
|
||||
if result != nil {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
result = extractor(htmlnode)
|
||||
return result
|
||||
}
|
||||
|
||||
70
v2/internal/frontend/assetserver/common_test.go
Normal file
70
v2/internal/frontend/assetserver/common_test.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package assetserver
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const realHTML = `<html>
|
||||
|
||||
<head>
|
||||
<title>test3</title>
|
||||
<meta name="wails-options" content="noautoinject">
|
||||
<link rel="stylesheet" href="/main.css">
|
||||
</head>
|
||||
|
||||
<body data-wails-drag>
|
||||
<div class="logo"></div>
|
||||
<div class="result" id="result">Please enter your name below <20></div>
|
||||
<div class="input-box" id="input" data-wails-no-drag>
|
||||
<input class="input" id="name" type="text" autocomplete="off">
|
||||
<button class="btn" onclick="greet()">Greet</button>
|
||||
</div>
|
||||
|
||||
<script src="/main.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
`
|
||||
|
||||
func genMeta(content string) []byte {
|
||||
return []byte("<html><head><meta name=\"wails-options\" content=\"" + content + "\"></head><body></body></html>")
|
||||
}
|
||||
|
||||
func genOptions(runtime bool, bindings bool) *Options {
|
||||
return &Options{
|
||||
disableRuntimeInjection: runtime,
|
||||
disableIPCInjection: bindings,
|
||||
}
|
||||
}
|
||||
|
||||
func Test_extractOptions(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
htmldata []byte
|
||||
want *Options
|
||||
wantError bool
|
||||
}{
|
||||
{"empty", []byte(""), &Options{}, false},
|
||||
{"bad data", []byte("<"), &Options{}, false},
|
||||
{"bad options", genMeta("noauto"), genOptions(false, false), false},
|
||||
{"realhtml", []byte(realHTML), genOptions(true, true), false},
|
||||
{"noautoinject", genMeta("noautoinject"), genOptions(true, true), false},
|
||||
{"noautoinjectipc", genMeta("noautoinjectipc"), genOptions(false, true), false},
|
||||
{"noautoinjectruntime", genMeta("noautoinjectruntime"), genOptions(true, false), false},
|
||||
{"spaces", genMeta(" noautoinjectruntime "), genOptions(true, false), false},
|
||||
{"multiple", genMeta("noautoinjectruntime,noautoinjectipc"), genOptions(true, true), false},
|
||||
{"multiple spaces", genMeta(" noautoinjectruntime, noautoinjectipc "), genOptions(true, true), false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := extractOptions(tt.htmldata)
|
||||
if !tt.wantError && err != nil {
|
||||
t.Errorf("did not want error but got it")
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("extractOptions() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,9 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/gabriel-vasile/mimetype"
|
||||
)
|
||||
import "github.com/gabriel-vasile/mimetype"
|
||||
|
||||
var (
|
||||
cache = map[string]string{}
|
||||
@@ -33,6 +34,10 @@ func GetMimetype(filename string, data []byte) string {
|
||||
result = strings.Replace(result, "text/plain", "text/css", 1)
|
||||
}
|
||||
|
||||
if filepath.Ext(filename) == ".js" && strings.HasPrefix(result, "text/plain") {
|
||||
result = strings.Replace(result, "text/plain", "text/javascript", 1)
|
||||
}
|
||||
|
||||
if result == "" {
|
||||
result = "application/octet-stream"
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ func TestGetMimetype(t *testing.T) {
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
{"css", args{"test.css", []byte("body{margin:0;padding:0;background-color:#d579b2}#app{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-align:center;color:#2c3e50;background-color:#ededed}#nav{padding:30px}#nav a{font-weight:700;color:#2c\n3e50}#nav a.router-link-exact-active{color:#42b983}.hello[data-v-4e26ad49]{margin:10px 0}")}, "text/css; charset=utf-8"},
|
||||
{"js", args{"test.js", []byte("let foo = 'bar'; console.log(foo);")}, "text/javascript; charset=utf-8"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
21
v2/internal/frontend/desktop/darwin/AppDelegate.h
Normal file
21
v2/internal/frontend/desktop/darwin/AppDelegate.h
Normal file
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// AppDelegate.h
|
||||
// test
|
||||
//
|
||||
// Created by Lea Anthony on 10/10/21.
|
||||
//
|
||||
|
||||
#ifndef AppDelegate_h
|
||||
#define AppDelegate_h
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "WailsContext.h"
|
||||
|
||||
@interface AppDelegate : NSResponder <NSTouchBarProvider>
|
||||
|
||||
@property bool alwaysOnTop;
|
||||
@property (retain) WailsWindow* mainWindow;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* AppDelegate_h */
|
||||
31
v2/internal/frontend/desktop/darwin/AppDelegate.m
Normal file
31
v2/internal/frontend/desktop/darwin/AppDelegate.m
Normal file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// AppDelegate.m
|
||||
// test
|
||||
//
|
||||
// Created by Lea Anthony on 10/10/21.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
@implementation AppDelegate
|
||||
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
|
||||
return NO;
|
||||
}
|
||||
- (void)applicationWillFinishLaunching:(NSNotification *)aNotification {
|
||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||
[self.mainWindow makeKeyAndOrderFront:self];
|
||||
if (self.alwaysOnTop) {
|
||||
[self.mainWindow setLevel:NSStatusWindowLevel];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
}
|
||||
|
||||
@synthesize touchBar;
|
||||
|
||||
@end
|
||||
61
v2/internal/frontend/desktop/darwin/Application.h
Normal file
61
v2/internal/frontend/desktop/darwin/Application.h
Normal file
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// Application.h
|
||||
// test
|
||||
//
|
||||
// Created by Lea Anthony on 10/10/21.
|
||||
//
|
||||
|
||||
#ifndef Application_h
|
||||
#define Application_h
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "WailsContext.h"
|
||||
|
||||
WailsContext* Create(const char* title, int width, int height, int frameless, int resizable, int fullscreen, int fullSizeContent, int hideTitleBar, int titlebarAppearsTransparent, int hideTitle, int useToolbar, int hideToolbarSeparator, int webviewIsTransparent, int alwaysOnTop, int hideWindowOnClose, const char *appearance, int windowIsTranslucent, int debug);
|
||||
void Run(void*);
|
||||
|
||||
void SetTitle(void* ctx, const char *title);
|
||||
void Center(void* ctx);
|
||||
void SetSize(void* ctx, int width, int height);
|
||||
void SetMinSize(void* ctx, int width, int height);
|
||||
void SetMaxSize(void* ctx, int width, int height);
|
||||
void SetPosition(void* ctx, int x, int y);
|
||||
void Fullscreen(void* ctx);
|
||||
void UnFullscreen(void* ctx);
|
||||
void Minimise(void* ctx);
|
||||
void UnMinimise(void* ctx);
|
||||
void Maximise(void* ctx);
|
||||
void UnMaximise(void* ctx);
|
||||
void Hide(void* ctx);
|
||||
void Show(void* ctx);
|
||||
void SetRGBA(void* ctx, int r, int g, int b, int a);
|
||||
void ExecJS(void* ctx, const char*);
|
||||
void Quit(void*);
|
||||
|
||||
const char* GetSize(void *ctx);
|
||||
const char* GetPos(void *ctx);
|
||||
|
||||
void ProcessURLResponse(void *inctx, const char *url, const char *contentType, void* data, int datalength);
|
||||
|
||||
/* Dialogs */
|
||||
|
||||
void MessageDialog(void *inctx, const char* dialogType, const char* title, const char* message, const char* button1, const char* button2, const char* button3, const char* button4, const char* defaultButton, const char* cancelButton, void* iconData, int iconDataLength);
|
||||
void OpenFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int allowDirectories, int allowFiles, int canCreateDirectories, int treatPackagesAsDirectories, int resolveAliases, int showHiddenFiles, int allowMultipleSelection, const char* filters);
|
||||
void SaveFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int canCreateDirectories, int treatPackagesAsDirectories, int showHiddenFiles, const char* filters);
|
||||
|
||||
/* Application Menu */
|
||||
void* NewMenu(const char* name);
|
||||
void AppendSubmenu(void* parent, void* child);
|
||||
void AppendRole(void *inctx, void *inMenu, int role);
|
||||
void SetAsApplicationMenu(void *inctx, void *inMenu);
|
||||
void UpdateApplicationMenu(void *inctx);
|
||||
|
||||
void SetAbout(void *inctx, const char* title, const char* description, void* imagedata, int datalen);
|
||||
void* AppendMenuItem(void* inctx, void* nsmenu, const char* label, const char* shortcutKey, int modifiers, int disabled, int checked, int menuItemID);
|
||||
void AppendSeparator(void* inMenu);
|
||||
void UpdateMenuItem(void* nsmenuitem, int checked);
|
||||
|
||||
NSString* safeInit(const char* input);
|
||||
|
||||
#endif /* Application_h */
|
||||
314
v2/internal/frontend/desktop/darwin/Application.m
Normal file
314
v2/internal/frontend/desktop/darwin/Application.m
Normal file
@@ -0,0 +1,314 @@
|
||||
//
|
||||
// Application.m
|
||||
//
|
||||
// Created by Lea Anthony on 10/10/21.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "WailsContext.h"
|
||||
#import "Application.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "WailsMenu.h"
|
||||
#import "WailsMenuItem.h"
|
||||
|
||||
WailsContext* Create(const char* title, int width, int height, int frameless, int resizable, int fullscreen, int fullSizeContent, int hideTitleBar, int titlebarAppearsTransparent, int hideTitle, int useToolbar, int hideToolbarSeparator, int webviewIsTransparent, int alwaysOnTop, int hideWindowOnClose, const char *appearance, int windowIsTranslucent, int debug) {
|
||||
|
||||
[NSApplication sharedApplication];
|
||||
|
||||
WailsContext *result = [WailsContext new];
|
||||
|
||||
result.debug = debug;
|
||||
|
||||
[result CreateWindow:width :height :frameless :resizable :fullscreen :fullSizeContent :hideTitleBar :titlebarAppearsTransparent :hideTitle :useToolbar :hideToolbarSeparator :webviewIsTransparent :hideWindowOnClose :safeInit(appearance) :windowIsTranslucent];
|
||||
[result SetTitle:safeInit(title)];
|
||||
[result Center];
|
||||
|
||||
result.alwaysOnTop = alwaysOnTop;
|
||||
result.hideOnClose = hideWindowOnClose;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ProcessURLResponse(void *inctx, const char *url, const char *contentType, void* data, int datalength) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
NSString *nsurl = safeInit(url);
|
||||
NSString *nsContentType = safeInit(contentType);
|
||||
NSData *nsdata = [NSData dataWithBytes:data length:datalength];
|
||||
|
||||
[ctx processURLResponse:nsurl :nsContentType :nsdata];
|
||||
}
|
||||
|
||||
void ExecJS(void* inctx, const char *script) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
NSString *nsscript = safeInit(script);
|
||||
ON_MAIN_THREAD(
|
||||
[ctx ExecJS:nsscript];
|
||||
);
|
||||
}
|
||||
|
||||
void SetTitle(void* inctx, const char *title) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
NSString *_title = safeInit(title);
|
||||
ON_MAIN_THREAD(
|
||||
[ctx SetTitle:_title];
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void SetRGBA(void *inctx, int r, int g, int b, int a) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
ON_MAIN_THREAD(
|
||||
[ctx SetRGBA:r :g :b :a];
|
||||
);
|
||||
}
|
||||
|
||||
void SetSize(void* inctx, int width, int height) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
ON_MAIN_THREAD(
|
||||
[ctx SetSize:width :height];
|
||||
);
|
||||
}
|
||||
|
||||
void SetMinSize(void* inctx, int width, int height) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
ON_MAIN_THREAD(
|
||||
[ctx SetMinSize:width :height];
|
||||
);
|
||||
}
|
||||
|
||||
void SetMaxSize(void* inctx, int width, int height) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
ON_MAIN_THREAD(
|
||||
[ctx SetMaxSize:width :height];
|
||||
);
|
||||
}
|
||||
|
||||
void SetPosition(void* inctx, int x, int y) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
ON_MAIN_THREAD(
|
||||
[ctx SetPosition:x :y];
|
||||
);
|
||||
}
|
||||
|
||||
void Center(void* inctx) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
ON_MAIN_THREAD(
|
||||
[ctx Center];
|
||||
);
|
||||
}
|
||||
|
||||
void Fullscreen(void* inctx) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
ON_MAIN_THREAD(
|
||||
[ctx Fullscreen];
|
||||
);
|
||||
}
|
||||
|
||||
void UnFullscreen(void* inctx) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
ON_MAIN_THREAD(
|
||||
[ctx UnFullscreen];
|
||||
);
|
||||
}
|
||||
|
||||
void Minimise(void* inctx) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
ON_MAIN_THREAD(
|
||||
[ctx Minimise];
|
||||
);
|
||||
}
|
||||
|
||||
void UnMinimise(void* inctx) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
ON_MAIN_THREAD(
|
||||
[ctx UnMinimise];
|
||||
);
|
||||
}
|
||||
|
||||
void Maximise(void* inctx) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
ON_MAIN_THREAD(
|
||||
[ctx Maximise];
|
||||
);
|
||||
}
|
||||
|
||||
const char* GetSize(void *inctx) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
NSRect frame = [ctx.mainWindow frame];
|
||||
NSString *result = [NSString stringWithFormat:@"%d,%d", (int)frame.size.width, (int)frame.size.height];
|
||||
return [result UTF8String];
|
||||
}
|
||||
|
||||
const char* GetPos(void *inctx) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
NSScreen* screen = [ctx getCurrentScreen];
|
||||
NSRect windowFrame = [ctx.mainWindow frame];
|
||||
NSRect screenFrame = [screen visibleFrame];
|
||||
int x = windowFrame.origin.x - screenFrame.origin.x;
|
||||
int y = windowFrame.origin.y - screenFrame.origin.y;
|
||||
y = screenFrame.size.height - y - windowFrame.size.height;
|
||||
NSString *result = [NSString stringWithFormat:@"%d,%d",x,y];
|
||||
return [result UTF8String];
|
||||
|
||||
}
|
||||
|
||||
void UnMaximise(void* inctx) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
ON_MAIN_THREAD(
|
||||
[ctx UnMaximise];
|
||||
);
|
||||
}
|
||||
|
||||
void Quit(void *inctx) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
[NSApp stop:ctx];
|
||||
}
|
||||
|
||||
void Hide(void *inctx) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
ON_MAIN_THREAD(
|
||||
[ctx Hide];
|
||||
);
|
||||
}
|
||||
|
||||
void Show(void *inctx) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
ON_MAIN_THREAD(
|
||||
[ctx Show];
|
||||
);
|
||||
}
|
||||
|
||||
NSString* safeInit(const char* input) {
|
||||
NSString *result = nil;
|
||||
if (input != nil) {
|
||||
result = [NSString stringWithUTF8String:input];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void MessageDialog(void *inctx, const char* dialogType, const char* title, const char* message, const char* button1, const char* button2, const char* button3, const char* button4, const char* defaultButton, const char* cancelButton, void* iconData, int iconDataLength) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
|
||||
NSString *_dialogType = safeInit(dialogType);
|
||||
NSString *_title = safeInit(title);
|
||||
NSString *_message = safeInit(message);
|
||||
NSString *_button1 = safeInit(button1);
|
||||
NSString *_button2 = safeInit(button2);
|
||||
NSString *_button3 = safeInit(button3);
|
||||
NSString *_button4 = safeInit(button4);
|
||||
NSString *_defaultButton = safeInit(defaultButton);
|
||||
NSString *_cancelButton = safeInit(cancelButton);
|
||||
|
||||
ON_MAIN_THREAD(
|
||||
[ctx MessageDialog:_dialogType :_title :_message :_button1 :_button2 :_button3 :_button4 :_defaultButton :_cancelButton :iconData :iconDataLength];
|
||||
)
|
||||
}
|
||||
|
||||
void OpenFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int allowDirectories, int allowFiles, int canCreateDirectories, int treatPackagesAsDirectories, int resolveAliases, int showHiddenFiles, int allowMultipleSelection, const char* filters) {
|
||||
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
NSString *_title = safeInit(title);
|
||||
NSString *_defaultFilename = safeInit(defaultFilename);
|
||||
NSString *_defaultDirectory = safeInit(defaultDirectory);
|
||||
NSString *_filters = safeInit(filters);
|
||||
|
||||
ON_MAIN_THREAD(
|
||||
[ctx OpenFileDialog:_title :_defaultFilename :_defaultDirectory :allowDirectories :allowFiles :canCreateDirectories :treatPackagesAsDirectories :resolveAliases :showHiddenFiles :allowMultipleSelection :_filters];
|
||||
)
|
||||
}
|
||||
|
||||
void SaveFileDialog(void *inctx, const char* title, const char* defaultFilename, const char* defaultDirectory, int canCreateDirectories, int treatPackagesAsDirectories, int showHiddenFiles, const char* filters) {
|
||||
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
NSString *_title = safeInit(title);
|
||||
NSString *_defaultFilename = safeInit(defaultFilename);
|
||||
NSString *_defaultDirectory = safeInit(defaultDirectory);
|
||||
NSString *_filters = safeInit(filters);
|
||||
|
||||
ON_MAIN_THREAD(
|
||||
[ctx SaveFileDialog:_title :_defaultFilename :_defaultDirectory :canCreateDirectories :treatPackagesAsDirectories :showHiddenFiles :_filters];
|
||||
)
|
||||
}
|
||||
|
||||
void AppendRole(void *inctx, void *inMenu, int role) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
WailsMenu *menu = (__bridge WailsMenu*) inMenu;
|
||||
[menu appendRole :ctx :role];
|
||||
}
|
||||
|
||||
void* NewMenu(const char *name) {
|
||||
NSString *title = @"";
|
||||
if (name != nil) {
|
||||
title = [NSString stringWithUTF8String:name];
|
||||
}
|
||||
WailsMenu *result = [[WailsMenu new] initWithNSTitle:title];
|
||||
return result;
|
||||
}
|
||||
|
||||
void AppendSubmenu(void* inparent, void* inchild) {
|
||||
WailsMenu *parent = (__bridge WailsMenu*) inparent;
|
||||
WailsMenu *child = (__bridge WailsMenu*) inchild;
|
||||
[parent appendSubmenu:child];
|
||||
}
|
||||
|
||||
void SetAsApplicationMenu(void *inctx, void *inMenu) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
WailsMenu *menu = (__bridge WailsMenu*) inMenu;
|
||||
ctx.applicationMenu = menu;
|
||||
}
|
||||
|
||||
void UpdateApplicationMenu(void *inctx) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
ON_MAIN_THREAD(
|
||||
NSApplication *app = [NSApplication sharedApplication];
|
||||
[app setMainMenu:ctx.applicationMenu];
|
||||
)
|
||||
}
|
||||
|
||||
void SetAbout(void *inctx, const char* title, const char* description, void* imagedata, int datalen) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
NSString *_title = safeInit(title);
|
||||
NSString *_description = safeInit(description);
|
||||
|
||||
[ctx SetAbout :_title :_description :imagedata :datalen];
|
||||
}
|
||||
|
||||
void* AppendMenuItem(void* inctx, void* inMenu, const char* label, const char* shortcutKey, int modifiers, int disabled, int checked, int menuItemID) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
WailsMenu *menu = (__bridge WailsMenu*) inMenu;
|
||||
NSString *_label = safeInit(label);
|
||||
NSString *_shortcutKey = safeInit(shortcutKey);
|
||||
|
||||
return [menu AppendMenuItem:ctx :_label :_shortcutKey :modifiers :disabled :checked :menuItemID];
|
||||
}
|
||||
|
||||
void UpdateMenuItem(void* nsmenuitem, int checked) {
|
||||
ON_MAIN_THREAD(
|
||||
WailsMenuItem *menuItem = (__bridge WailsMenuItem*) nsmenuitem;
|
||||
[menuItem setState:(checked == 1?NSControlStateValueOn:NSControlStateValueOff)];
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
void AppendSeparator(void* inMenu) {
|
||||
WailsMenu *menu = (__bridge WailsMenu*) inMenu;
|
||||
[menu AppendSeparator];
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Run(void *inctx) {
|
||||
WailsContext *ctx = (__bridge WailsContext*) inctx;
|
||||
NSApplication *app = [NSApplication sharedApplication];
|
||||
AppDelegate* delegate = [AppDelegate new];
|
||||
[app setDelegate:(id)delegate];
|
||||
ctx.appdelegate = delegate;
|
||||
delegate.mainWindow = ctx.mainWindow;
|
||||
delegate.alwaysOnTop = ctx.alwaysOnTop;
|
||||
|
||||
[ctx loadRequest:@"wails://wails/"];
|
||||
[app setMainMenu:ctx.applicationMenu];
|
||||
[app run];
|
||||
[ctx release];
|
||||
}
|
||||
16
v2/internal/frontend/desktop/darwin/Role.h
Normal file
16
v2/internal/frontend/desktop/darwin/Role.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Role.h
|
||||
// test
|
||||
//
|
||||
// Created by Lea Anthony on 24/10/21.
|
||||
//
|
||||
|
||||
#ifndef Role_h
|
||||
#define Role_h
|
||||
|
||||
typedef int Role;
|
||||
|
||||
static const Role AppMenu = 1;
|
||||
static const Role EditMenu = 2;
|
||||
|
||||
#endif /* Role_h */
|
||||
18
v2/internal/frontend/desktop/darwin/WailsAlert.h
Normal file
18
v2/internal/frontend/desktop/darwin/WailsAlert.h
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// WailsAlert.h
|
||||
// test
|
||||
//
|
||||
// Created by Lea Anthony on 20/10/21.
|
||||
//
|
||||
|
||||
#ifndef WailsAlert_h
|
||||
#define WailsAlert_h
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface WailsAlert : NSAlert
|
||||
- (void)addButton:(NSString*)text :(NSString*)defaultButton :(NSString*)cancelButton;
|
||||
@end
|
||||
|
||||
|
||||
#endif /* WailsAlert_h */
|
||||
30
v2/internal/frontend/desktop/darwin/WailsAlert.m
Normal file
30
v2/internal/frontend/desktop/darwin/WailsAlert.m
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// WailsAlert.m
|
||||
// test
|
||||
//
|
||||
// Created by Lea Anthony on 20/10/21.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "WailsAlert.h"
|
||||
|
||||
@implementation WailsAlert
|
||||
|
||||
- (void)addButton:(NSString*)text :(NSString*)defaultButton :(NSString*)cancelButton {
|
||||
if( text == nil ) {
|
||||
return;
|
||||
}
|
||||
NSButton *button = [self addButtonWithTitle:text];
|
||||
if( defaultButton != nil && [text isEqualToString:defaultButton]) {
|
||||
[button setKeyEquivalent:@"\r"];
|
||||
} else if( cancelButton != nil && [text isEqualToString:cancelButton]) {
|
||||
[button setKeyEquivalent:@"\033"];
|
||||
} else {
|
||||
[button setKeyEquivalent:@""];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
82
v2/internal/frontend/desktop/darwin/WailsContext.h
Normal file
82
v2/internal/frontend/desktop/darwin/WailsContext.h
Normal file
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// WailsContext.h
|
||||
// test
|
||||
//
|
||||
// Created by Lea Anthony on 10/10/21.
|
||||
//
|
||||
|
||||
#ifndef WailsContext_h
|
||||
#define WailsContext_h
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
|
||||
#define ON_MAIN_THREAD(str) dispatch_async(dispatch_get_main_queue(), ^{ str; });
|
||||
#define unicode(input) [NSString stringWithFormat:@"%C", input]
|
||||
|
||||
@interface WailsWindow : NSWindow
|
||||
- (BOOL)canBecomeKeyWindow;
|
||||
@end
|
||||
|
||||
@interface WailsContext : NSObject <WKURLSchemeHandler,WKScriptMessageHandler,WKNavigationDelegate>
|
||||
|
||||
@property (retain) WailsWindow* mainWindow;
|
||||
@property (retain) WKWebView* webview;
|
||||
@property (nonatomic, assign) id appdelegate;
|
||||
|
||||
@property bool hideOnClose;
|
||||
@property bool shuttingDown;
|
||||
|
||||
@property NSSize maxSize;
|
||||
@property NSSize minSize;
|
||||
|
||||
@property (retain) NSEvent* mouseEvent;
|
||||
|
||||
@property bool alwaysOnTop;
|
||||
|
||||
@property bool debug;
|
||||
|
||||
@property (retain) WKUserContentController* userContentController;
|
||||
@property (retain) NSMutableDictionary *urlRequests;
|
||||
|
||||
@property (retain) NSMenu* applicationMenu;
|
||||
|
||||
@property (retain) NSImage* aboutImage;
|
||||
@property (retain) NSString* aboutTitle;
|
||||
@property (retain) NSString* aboutDescription;
|
||||
|
||||
- (void) CreateWindow:(int)width :(int)height :(bool)frameless :(bool)resizable :(bool)fullscreen :(bool)fullSizeContent :(bool)hideTitleBar :(bool)titlebarAppearsTransparent :(bool)hideTitle :(bool)useToolbar :(bool)hideToolbarSeparator :(bool)webviewIsTransparent :(bool)hideWindowOnClose :(NSString *)appearance :(bool)windowIsTranslucent;
|
||||
- (void) SetSize:(int)width :(int)height;
|
||||
- (void) SetPosition:(int)x :(int) y;
|
||||
- (void) SetMinSize:(int)minWidth :(int)minHeight;
|
||||
- (void) SetMaxSize:(int)maxWidth :(int)maxHeight;
|
||||
- (void) SetTitle:(NSString*)title;
|
||||
- (void) Center;
|
||||
- (void) Fullscreen;
|
||||
- (void) UnFullscreen;
|
||||
- (void) Minimise;
|
||||
- (void) UnMinimise;
|
||||
- (void) Maximise;
|
||||
- (void) UnMaximise;
|
||||
- (void) SetRGBA:(int)r :(int)g :(int)b :(int)a;
|
||||
- (void) HideMouse;
|
||||
- (void) ShowMouse;
|
||||
- (void) Hide;
|
||||
- (void) Show;
|
||||
- (void) Quit;
|
||||
|
||||
-(void) MessageDialog :(NSString*)dialogType :(NSString*)title :(NSString*)message :(NSString*)button1 :(NSString*)button2 :(NSString*)button3 :(NSString*)button4 :(NSString*)defaultButton :(NSString*)cancelButton :(void*)iconData :(int)iconDataLength;
|
||||
- (void) OpenFileDialog :(NSString*)title :(NSString*)defaultFilename :(NSString*)defaultDirectory :(bool)allowDirectories :(bool)allowFiles :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)resolveAliases :(bool)showHiddenFiles :(bool)allowMultipleSelection :(NSString*)filters;
|
||||
- (void) SaveFileDialog :(NSString*)title :(NSString*)defaultFilename :(NSString*)defaultDirectory :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)showHiddenFiles :(NSString*)filters;
|
||||
|
||||
- (void) loadRequest:(NSString*)url;
|
||||
- (void) processURLResponse:(NSString *)url :(NSString *)contentType :(NSData*)data;
|
||||
- (void) ExecJS:(NSString*)script;
|
||||
- (NSScreen*) getCurrentScreen;
|
||||
|
||||
- (void) SetAbout :(NSString*)title :(NSString*)description :(void*)imagedata :(int)datalen;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#endif /* WailsContext_h */
|
||||
619
v2/internal/frontend/desktop/darwin/WailsContext.m
Normal file
619
v2/internal/frontend/desktop/darwin/WailsContext.m
Normal file
@@ -0,0 +1,619 @@
|
||||
//
|
||||
// WailsContext.m
|
||||
// test
|
||||
//
|
||||
// Created by Lea Anthony on 10/10/21.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <WebKit/WebKit.h>
|
||||
#import "WailsContext.h"
|
||||
#import "WailsAlert.h"
|
||||
#import "WailsMenu.h"
|
||||
#import "WindowDelegate.h"
|
||||
#import "message.h"
|
||||
#import "Role.h"
|
||||
|
||||
@implementation WailsWindow
|
||||
|
||||
- (BOOL)canBecomeKeyWindow
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation WailsContext
|
||||
|
||||
- (void) SetSize:(int)width :(int)height {
|
||||
|
||||
if (self.shuttingDown) return;
|
||||
|
||||
NSRect frame = [self.mainWindow frame];
|
||||
frame.origin.y += frame.size.height - height;
|
||||
frame.size.width = width;
|
||||
frame.size.height = height;
|
||||
ON_MAIN_THREAD([self.mainWindow setFrame:frame display:TRUE animate:FALSE];);
|
||||
}
|
||||
|
||||
- (void) SetPosition:(int)x :(int)y {
|
||||
|
||||
if (self.shuttingDown) return;
|
||||
|
||||
NSScreen* screen = [self getCurrentScreen];
|
||||
NSRect windowFrame = [self.mainWindow frame];
|
||||
NSRect screenFrame = [screen frame];
|
||||
windowFrame.origin.x = screenFrame.origin.x + (float)x;
|
||||
windowFrame.origin.y = (screenFrame.origin.y + screenFrame.size.height) - windowFrame.size.height - (float)y;
|
||||
|
||||
ON_MAIN_THREAD([self.mainWindow setFrame:windowFrame display:TRUE animate:FALSE]; );
|
||||
}
|
||||
|
||||
- (void) SetMinSize:(int)minWidth :(int)minHeight {
|
||||
|
||||
if (self.shuttingDown) return;
|
||||
|
||||
NSSize size = { minWidth, minHeight };
|
||||
|
||||
self.minSize = size;
|
||||
|
||||
ON_MAIN_THREAD(
|
||||
[self.mainWindow setMinSize:size];
|
||||
[self adjustWindowSize];
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
- (void) SetMaxSize:(int)maxWidth :(int)maxHeight {
|
||||
|
||||
if (self.shuttingDown) return;
|
||||
|
||||
NSSize size = { FLT_MAX, FLT_MAX };
|
||||
|
||||
size.width = maxWidth > 0 ? maxWidth : FLT_MAX;
|
||||
size.height = maxHeight > 0 ? maxHeight : FLT_MAX;
|
||||
|
||||
self.maxSize = size;
|
||||
|
||||
ON_MAIN_THREAD(
|
||||
[self.mainWindow setMaxSize:size];
|
||||
[self adjustWindowSize];
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
- (void) adjustWindowSize {
|
||||
|
||||
if (self.shuttingDown) return;
|
||||
|
||||
NSRect currentFrame = [self.mainWindow frame];
|
||||
|
||||
if ( currentFrame.size.width > self.maxSize.width ) currentFrame.size.width = self.maxSize.width;
|
||||
if ( currentFrame.size.width < self.minSize.width ) currentFrame.size.width = self.minSize.width;
|
||||
if ( currentFrame.size.height > self.maxSize.height ) currentFrame.size.height = self.maxSize.height;
|
||||
if ( currentFrame.size.height < self.minSize.height ) currentFrame.size.height = self.minSize.height;
|
||||
|
||||
[self.mainWindow setFrame:currentFrame display:YES animate:FALSE];
|
||||
|
||||
}
|
||||
|
||||
- (void) dealloc {
|
||||
[super dealloc];
|
||||
[self.appdelegate release];
|
||||
[self.mainWindow release];
|
||||
[self.mouseEvent release];
|
||||
[self.userContentController release];
|
||||
[self.urlRequests release];
|
||||
[self.applicationMenu release];
|
||||
}
|
||||
|
||||
- (NSScreen*) getCurrentScreen {
|
||||
NSScreen* screen = [self.mainWindow screen];
|
||||
if( screen == NULL ) {
|
||||
screen = [NSScreen mainScreen];
|
||||
}
|
||||
return screen;
|
||||
}
|
||||
|
||||
- (void) SetTitle:(NSString*)title {
|
||||
ON_MAIN_THREAD([self.mainWindow setTitle:title];)
|
||||
}
|
||||
|
||||
- (void) Center {
|
||||
ON_MAIN_THREAD( [self.mainWindow center]; );
|
||||
}
|
||||
|
||||
- (BOOL) isFullscreen {
|
||||
NSWindowStyleMask masks = [self.mainWindow styleMask];
|
||||
if ( masks & NSWindowStyleMaskFullScreen ) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void) CreateWindow:(int)width :(int)height :(bool)frameless :(bool)resizable :(bool)fullscreen :(bool)fullSizeContent :(bool)hideTitleBar :(bool)titlebarAppearsTransparent :(bool)hideTitle :(bool)useToolbar :(bool)hideToolbarSeparator :(bool)webviewIsTransparent :(bool)hideWindowOnClose :(NSString*)appearance :(bool)windowIsTranslucent {
|
||||
|
||||
self.urlRequests = [NSMutableDictionary new];
|
||||
|
||||
NSWindowStyleMask styleMask = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
|
||||
|
||||
if (frameless) {
|
||||
styleMask = NSWindowStyleMaskBorderless;
|
||||
titlebarAppearsTransparent = true;
|
||||
hideTitle = true;
|
||||
} else {
|
||||
if (!hideTitleBar) {
|
||||
styleMask |= NSWindowStyleMaskTitled;
|
||||
}
|
||||
|
||||
if (fullscreen) {
|
||||
styleMask |= NSWindowStyleMaskFullScreen;
|
||||
}
|
||||
|
||||
if( fullSizeContent || frameless || titlebarAppearsTransparent ) {
|
||||
styleMask |= NSWindowStyleMaskFullSizeContentView;
|
||||
}
|
||||
}
|
||||
|
||||
if (resizable) {
|
||||
styleMask |= NSWindowStyleMaskResizable;
|
||||
}
|
||||
|
||||
self.mainWindow = [[[WailsWindow alloc] initWithContentRect:NSMakeRect(0, 0, width, height)
|
||||
styleMask:styleMask backing:NSBackingStoreBuffered defer:NO]
|
||||
autorelease];
|
||||
|
||||
if (!frameless && useToolbar) {
|
||||
id toolbar = [[NSToolbar alloc] initWithIdentifier:@"wails.toolbar"];
|
||||
[toolbar autorelease];
|
||||
[toolbar setShowsBaselineSeparator:!hideToolbarSeparator];
|
||||
[self.mainWindow setToolbar:toolbar];
|
||||
|
||||
}
|
||||
|
||||
[self.mainWindow setTitleVisibility:hideTitle];
|
||||
[self.mainWindow setTitlebarAppearsTransparent:titlebarAppearsTransparent];
|
||||
|
||||
// [self.mainWindow canBecomeKeyWindow];
|
||||
|
||||
id contentView = [self.mainWindow contentView];
|
||||
if (windowIsTranslucent) {
|
||||
NSVisualEffectView *effectView = [NSVisualEffectView alloc];
|
||||
NSRect bounds = [contentView bounds];
|
||||
[effectView initWithFrame:bounds];
|
||||
[effectView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
|
||||
[effectView setBlendingMode:NSVisualEffectBlendingModeBehindWindow];
|
||||
[effectView setState:NSVisualEffectStateActive];
|
||||
[contentView addSubview:effectView positioned:NSWindowBelow relativeTo:nil];
|
||||
}
|
||||
|
||||
if (appearance != nil) {
|
||||
NSAppearance *nsAppearance = [NSAppearance appearanceNamed:appearance];
|
||||
[self.mainWindow setAppearance:nsAppearance];
|
||||
}
|
||||
|
||||
// Set up min/max
|
||||
NSSize maxSize = { FLT_MAX, FLT_MAX };
|
||||
self.maxSize = maxSize;
|
||||
NSSize minSize = { 0, 0 };
|
||||
self.minSize = minSize;
|
||||
[self adjustWindowSize];
|
||||
|
||||
WindowDelegate *windowDelegate = [WindowDelegate new];
|
||||
windowDelegate.hideOnClose = hideWindowOnClose;
|
||||
[self.mainWindow setDelegate:windowDelegate];
|
||||
|
||||
// Webview stuff here!
|
||||
WKWebViewConfiguration *config = [WKWebViewConfiguration new];
|
||||
config.suppressesIncrementalRendering = true;
|
||||
[config setURLSchemeHandler:self forURLScheme:@"wails"];
|
||||
|
||||
// [config.preferences setValue:[NSNumber numberWithBool:true] forKey:@"developerExtrasEnabled"];
|
||||
|
||||
WKUserContentController* userContentController = [WKUserContentController new];
|
||||
[userContentController addScriptMessageHandler:self name:@"external"];
|
||||
config.userContentController = userContentController;
|
||||
self.userContentController = userContentController;
|
||||
if (self.debug) {
|
||||
[config.preferences setValue:@YES forKey:@"developerExtrasEnabled"];
|
||||
} else {
|
||||
// Disable default context menus
|
||||
WKUserScript *initScript = [WKUserScript new];
|
||||
[initScript initWithSource:@"window.wails.flags.disableWailsDefaultContextMenu = true;"
|
||||
injectionTime:WKUserScriptInjectionTimeAtDocumentEnd
|
||||
forMainFrameOnly:false];
|
||||
[userContentController addUserScript:initScript];
|
||||
|
||||
}
|
||||
|
||||
self.webview = [WKWebView alloc];
|
||||
CGRect init = { 0,0,0,0 };
|
||||
[self.webview initWithFrame:init configuration:config];
|
||||
[contentView addSubview:self.webview];
|
||||
[self.webview setAutoresizingMask: NSViewWidthSizable|NSViewHeightSizable];
|
||||
CGRect contentViewBounds = [contentView bounds];
|
||||
[self.webview setFrame:contentViewBounds];
|
||||
|
||||
if (webviewIsTransparent) {
|
||||
[self.webview setValue:[NSNumber numberWithBool:!webviewIsTransparent] forKey:@"drawsBackground"];
|
||||
}
|
||||
|
||||
[self.webview setNavigationDelegate:self];
|
||||
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
[defaults setBool:FALSE forKey:@"NSAutomaticQuoteSubstitutionEnabled"];
|
||||
|
||||
// Mouse monitors
|
||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseDown handler:^NSEvent * _Nullable(NSEvent * _Nonnull event) {
|
||||
id window = [event window];
|
||||
if (window == self.mainWindow) {
|
||||
self.mouseEvent = event;
|
||||
}
|
||||
return event;
|
||||
}];
|
||||
|
||||
[NSEvent addLocalMonitorForEventsMatchingMask:NSEventMaskLeftMouseUp handler:^NSEvent * _Nullable(NSEvent * _Nonnull event) {
|
||||
id window = [event window];
|
||||
if (window == self.mainWindow) {
|
||||
self.mouseEvent = nil;
|
||||
[self ShowMouse];
|
||||
}
|
||||
return event;
|
||||
}];
|
||||
|
||||
self.applicationMenu = [NSMenu new];
|
||||
|
||||
}
|
||||
|
||||
- (NSMenuItem*) newMenuItem :(NSString*)title :(SEL)selector :(NSString*)key :(NSEventModifierFlags)flags {
|
||||
NSMenuItem *result = [[[NSMenuItem alloc] initWithTitle:title action:selector keyEquivalent:key] autorelease];
|
||||
if( flags != 0 ) {
|
||||
[result setKeyEquivalentModifierMask:flags];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSMenuItem*) newMenuItem :(NSString*)title :(SEL)selector :(NSString*)key {
|
||||
return [self newMenuItem :title :selector :key :0];
|
||||
}
|
||||
|
||||
- (NSMenu*) newMenu :(NSString*)title {
|
||||
WailsMenu *result = [[[WailsMenu new] initWithTitle:title] autorelease];
|
||||
[result setAutoenablesItems:NO];
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void) Quit {
|
||||
processMessage("Q");
|
||||
}
|
||||
|
||||
- (void) loadRequest :(NSString*)url {
|
||||
NSURL *wkUrl = [NSURL URLWithString:url];
|
||||
NSURLRequest *wkRequest = [NSURLRequest requestWithURL:wkUrl];
|
||||
[self.webview loadRequest:wkRequest];
|
||||
}
|
||||
|
||||
- (void) SetRGBA:(int)r :(int)g :(int)b :(int)a {
|
||||
float red = r/255;
|
||||
float green = g/255;
|
||||
float blue = b/255;
|
||||
float alpha = a/255;
|
||||
|
||||
id colour = [NSColor colorWithCalibratedRed:red green:green blue:blue alpha:alpha ];
|
||||
|
||||
ON_MAIN_THREAD([self.mainWindow setBackgroundColor:colour];);
|
||||
}
|
||||
|
||||
- (void) HideMouse {
|
||||
[NSCursor hide];
|
||||
}
|
||||
|
||||
- (void) ShowMouse {
|
||||
[NSCursor unhide];
|
||||
}
|
||||
|
||||
- (bool) isFullScreen {
|
||||
long mask = [self.mainWindow styleMask];
|
||||
return (mask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen;
|
||||
}
|
||||
|
||||
- (bool) isMaximised {
|
||||
long mask = [self.mainWindow styleMask];
|
||||
return (mask & NSWindowStyleMaskFullScreen) == NSWindowStyleMaskFullScreen;
|
||||
}
|
||||
|
||||
// Fullscreen sets the main window to be fullscreen
|
||||
- (void) Fullscreen {
|
||||
if( ! [self isFullScreen] ) {
|
||||
ON_MAIN_THREAD([self.mainWindow toggleFullScreen:nil];)
|
||||
}
|
||||
}
|
||||
|
||||
// UnFullscreen resets the main window after a fullscreen
|
||||
- (void) UnFullscreen {
|
||||
if( [self isFullScreen] ) {
|
||||
ON_MAIN_THREAD([self.mainWindow toggleFullScreen:nil];)
|
||||
}
|
||||
}
|
||||
|
||||
- (void) Minimise {
|
||||
ON_MAIN_THREAD([self.mainWindow miniaturize:nil];)
|
||||
}
|
||||
|
||||
- (void) UnMinimise {
|
||||
ON_MAIN_THREAD([self.mainWindow deminiaturize:nil];)
|
||||
}
|
||||
|
||||
- (void) Hide {
|
||||
ON_MAIN_THREAD([self.mainWindow orderOut:nil];)
|
||||
}
|
||||
|
||||
- (void) Show {
|
||||
ON_MAIN_THREAD(
|
||||
[self.mainWindow makeKeyAndOrderFront:nil];
|
||||
[NSApp activateIgnoringOtherApps:YES];
|
||||
)
|
||||
}
|
||||
|
||||
- (void) Maximise {
|
||||
if (![self.mainWindow isZoomed]) {
|
||||
ON_MAIN_THREAD([self.mainWindow zoom:nil];)
|
||||
}
|
||||
}
|
||||
|
||||
- (void) UnMaximise {
|
||||
if ([self.mainWindow isZoomed]) {
|
||||
ON_MAIN_THREAD([self.mainWindow zoom:nil];)
|
||||
}
|
||||
}
|
||||
|
||||
- (void) ExecJS:(NSString*)script {
|
||||
ON_MAIN_THREAD(
|
||||
[self.webview evaluateJavaScript:script completionHandler:nil];
|
||||
)
|
||||
}
|
||||
|
||||
- (void) processURLResponse:(NSString *)url :(NSString *)contentType :(NSData *)data {
|
||||
id<WKURLSchemeTask> urlSchemeTask = self.urlRequests[url];
|
||||
NSURL *nsurl = [NSURL URLWithString:url];
|
||||
|
||||
NSHTTPURLResponse *response = [NSHTTPURLResponse new];
|
||||
NSMutableDictionary *headerFields = [NSMutableDictionary new];
|
||||
headerFields[@"content-type"] = contentType;
|
||||
[response initWithURL:nsurl statusCode:200 HTTPVersion:@"HTTP/1.1" headerFields:headerFields];
|
||||
[urlSchemeTask didReceiveResponse:response];
|
||||
[urlSchemeTask didReceiveData:data];
|
||||
[urlSchemeTask didFinish];
|
||||
[self.urlRequests removeObjectForKey:url];
|
||||
}
|
||||
|
||||
- (void)webView:(nonnull WKWebView *)webView startURLSchemeTask:(nonnull id<WKURLSchemeTask>)urlSchemeTask {
|
||||
// Do something
|
||||
self.urlRequests[urlSchemeTask.request.URL.absoluteString] = urlSchemeTask;
|
||||
processURLRequest(self, [urlSchemeTask.request.URL.absoluteString UTF8String]);
|
||||
}
|
||||
|
||||
- (void)webView:(nonnull WKWebView *)webView stopURLSchemeTask:(nonnull id<WKURLSchemeTask>)urlSchemeTask {
|
||||
|
||||
}
|
||||
|
||||
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
|
||||
processMessage("DomReady");
|
||||
}
|
||||
|
||||
- (void)userContentController:(nonnull WKUserContentController *)userContentController didReceiveScriptMessage:(nonnull WKScriptMessage *)message {
|
||||
NSString *m = message.body;
|
||||
|
||||
// Check for drag
|
||||
if ( [m isEqualToString:@"drag"] ) {
|
||||
if( ! [self isFullScreen] ) {
|
||||
if( self.mouseEvent != nil ) {
|
||||
[self HideMouse];
|
||||
ON_MAIN_THREAD(
|
||||
[self.mainWindow performWindowDragWithEvent:self.mouseEvent];
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const char *_m = [m UTF8String];
|
||||
|
||||
processMessage(_m);
|
||||
}
|
||||
|
||||
|
||||
/***** Dialogs ******/
|
||||
-(void) MessageDialog :(NSString*)dialogType :(NSString*)title :(NSString*)message :(NSString*)button1 :(NSString*)button2 :(NSString*)button3 :(NSString*)button4 :(NSString*)defaultButton :(NSString*)cancelButton :(void*)iconData :(int)iconDataLength {
|
||||
|
||||
WailsAlert *alert = [WailsAlert new];
|
||||
|
||||
int style = NSAlertStyleInformational;
|
||||
if (dialogType != nil ) {
|
||||
if( [dialogType isEqualToString:@"warning"] ) {
|
||||
style = NSAlertStyleWarning;
|
||||
}
|
||||
if( [dialogType isEqualToString:@"error"] ) {
|
||||
style = NSAlertStyleCritical;
|
||||
}
|
||||
}
|
||||
[alert setAlertStyle:style];
|
||||
if( title != nil ) {
|
||||
[alert setMessageText:title];
|
||||
}
|
||||
if( message != nil ) {
|
||||
[alert setInformativeText:message];
|
||||
}
|
||||
|
||||
[alert addButton:button1 :defaultButton :cancelButton];
|
||||
[alert addButton:button2 :defaultButton :cancelButton];
|
||||
[alert addButton:button3 :defaultButton :cancelButton];
|
||||
[alert addButton:button4 :defaultButton :cancelButton];
|
||||
|
||||
NSImage *icon = nil;
|
||||
if (iconData != nil) {
|
||||
NSData *imageData = [NSData dataWithBytes:iconData length:iconDataLength];
|
||||
icon = [[NSImage alloc] initWithData:imageData];
|
||||
}
|
||||
ON_MAIN_THREAD(
|
||||
if( icon != nil) {
|
||||
[alert setIcon:icon];
|
||||
}
|
||||
[alert.window setLevel:NSFloatingWindowLevel];
|
||||
|
||||
long response = [alert runModal];
|
||||
int result;
|
||||
|
||||
if( response == NSAlertFirstButtonReturn ) {
|
||||
result = 0;
|
||||
}
|
||||
else if( response == NSAlertSecondButtonReturn ) {
|
||||
result = 1;
|
||||
}
|
||||
else if( response == NSAlertThirdButtonReturn ) {
|
||||
result = 2;
|
||||
} else {
|
||||
result = 3;
|
||||
}
|
||||
processMessageDialogResponse(result);
|
||||
)
|
||||
}
|
||||
|
||||
-(void) OpenFileDialog :(NSString*)title :(NSString*)defaultFilename :(NSString*)defaultDirectory :(bool)allowDirectories :(bool)allowFiles :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)resolveAliases :(bool)showHiddenFiles :(bool)allowMultipleSelection :(NSString*)filters {
|
||||
|
||||
|
||||
// Create the dialog
|
||||
NSOpenPanel *dialog = [NSOpenPanel openPanel];
|
||||
|
||||
// Valid but appears to do nothing.... :/
|
||||
if( title != nil ) {
|
||||
[dialog setTitle:title];
|
||||
}
|
||||
|
||||
// Filters - semicolon delimited list of file extensions
|
||||
if( allowFiles ) {
|
||||
if( filters != nil ) {
|
||||
filters = [filters stringByReplacingOccurrencesOfString:@"*." withString:@""];
|
||||
filters = [filters stringByReplacingOccurrencesOfString:@" " withString:@""];
|
||||
NSArray *filterList = [filters componentsSeparatedByString:@";"];
|
||||
[dialog setAllowedFileTypes:filterList];
|
||||
} else {
|
||||
[dialog setAllowsOtherFileTypes:true];
|
||||
}
|
||||
// Default Filename
|
||||
if( defaultFilename != nil ) {
|
||||
[dialog setNameFieldStringValue:defaultFilename];
|
||||
}
|
||||
|
||||
[dialog setAllowsMultipleSelection: allowMultipleSelection];
|
||||
[dialog setShowsHiddenFiles: showHiddenFiles];
|
||||
|
||||
}
|
||||
|
||||
// Default Directory
|
||||
if( defaultDirectory != nil ) {
|
||||
NSURL *url = [NSURL fileURLWithPath:defaultDirectory];
|
||||
[dialog setDirectoryURL:url];
|
||||
}
|
||||
|
||||
|
||||
// Setup Options
|
||||
[dialog setCanChooseFiles: allowFiles];
|
||||
[dialog setCanChooseDirectories: allowDirectories];
|
||||
[dialog setCanCreateDirectories: canCreateDirectories];
|
||||
[dialog setResolvesAliases: resolveAliases];
|
||||
[dialog setTreatsFilePackagesAsDirectories: treatPackagesAsDirectories];
|
||||
|
||||
// Setup callback handler
|
||||
[dialog beginSheetModalForWindow:self.mainWindow completionHandler:^(NSModalResponse returnCode) {
|
||||
NSMutableArray *arr = [NSMutableArray new];
|
||||
for (NSURL *url in [dialog URLs]) {
|
||||
[arr addObject:[url path]];
|
||||
}
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:arr options:0 error:nil];
|
||||
NSString *nsjson = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
||||
processOpenFileDialogResponse([nsjson UTF8String]);
|
||||
}];
|
||||
|
||||
ON_MAIN_THREAD([dialog runModal];)
|
||||
|
||||
}
|
||||
|
||||
|
||||
-(void) SaveFileDialog :(NSString*)title :(NSString*)defaultFilename :(NSString*)defaultDirectory :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)showHiddenFiles :(NSString*)filters; {
|
||||
|
||||
|
||||
// Create the dialog
|
||||
NSSavePanel *dialog = [NSOpenPanel savePanel];
|
||||
|
||||
// Valid but appears to do nothing.... :/
|
||||
if( title != nil ) {
|
||||
[dialog setTitle:title];
|
||||
}
|
||||
|
||||
// Filters - semicolon delimited list of file extensions
|
||||
if( filters != nil ) {
|
||||
filters = [filters stringByReplacingOccurrencesOfString:@"*." withString:@""];
|
||||
filters = [filters stringByReplacingOccurrencesOfString:@" " withString:@""];
|
||||
NSArray *filterList = [filters componentsSeparatedByString:@";"];
|
||||
[dialog setAllowedFileTypes:filterList];
|
||||
} else {
|
||||
[dialog setAllowsOtherFileTypes:true];
|
||||
}
|
||||
// Default Filename
|
||||
if( defaultFilename != nil ) {
|
||||
[dialog setNameFieldStringValue:defaultFilename];
|
||||
}
|
||||
|
||||
// Default Directory
|
||||
if( defaultDirectory != nil ) {
|
||||
NSURL *url = [NSURL fileURLWithPath:defaultDirectory];
|
||||
[dialog setDirectoryURL:url];
|
||||
}
|
||||
|
||||
// Setup Options
|
||||
[dialog setCanCreateDirectories: canCreateDirectories];
|
||||
[dialog setTreatsFilePackagesAsDirectories: treatPackagesAsDirectories];
|
||||
[dialog setShowsHiddenFiles: showHiddenFiles];
|
||||
|
||||
// Setup callback handler
|
||||
[dialog beginSheetModalForWindow:self.mainWindow completionHandler:^(NSModalResponse returnCode) {
|
||||
NSURL *url = [dialog URL];
|
||||
processSaveFileDialogResponse([url.path UTF8String]);
|
||||
}];
|
||||
|
||||
ON_MAIN_THREAD([dialog runModal];)
|
||||
|
||||
}
|
||||
|
||||
- (void) SetAbout :(NSString*)title :(NSString*)description :(void*)imagedata :(int)datalen {
|
||||
self.aboutTitle = title;
|
||||
self.aboutDescription = description;
|
||||
|
||||
NSData *imageData = [NSData dataWithBytes:imagedata length:datalen];
|
||||
self.aboutImage = [[NSImage alloc] initWithData:imageData];
|
||||
}
|
||||
|
||||
-(void) About {
|
||||
|
||||
WailsAlert *alert = [WailsAlert new];
|
||||
[alert setAlertStyle:NSAlertStyleInformational];
|
||||
if( self.aboutTitle != nil ) {
|
||||
[alert setMessageText:self.aboutTitle];
|
||||
}
|
||||
if( self.aboutDescription != nil ) {
|
||||
[alert setInformativeText:self.aboutDescription];
|
||||
}
|
||||
|
||||
|
||||
[alert.window setLevel:NSFloatingWindowLevel];
|
||||
if ( self.aboutImage != nil) {
|
||||
[alert setIcon:self.aboutImage];
|
||||
}
|
||||
|
||||
ON_MAIN_THREAD([alert runModal];)
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
30
v2/internal/frontend/desktop/darwin/WailsMenu.h
Normal file
30
v2/internal/frontend/desktop/darwin/WailsMenu.h
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// WailsMenu.h
|
||||
// test
|
||||
//
|
||||
// Created by Lea Anthony on 25/10/21.
|
||||
//
|
||||
|
||||
#ifndef WailsMenu_h
|
||||
#define WailsMenu_h
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "Role.h"
|
||||
#import "WailsMenu.h"
|
||||
#import "WailsContext.h"
|
||||
|
||||
@interface WailsMenu : NSMenu
|
||||
|
||||
//- (void) AddMenuByRole :(Role)role;
|
||||
- (WailsMenu*) initWithNSTitle :(NSString*)title;
|
||||
- (void) appendSubmenu :(WailsMenu*)child;
|
||||
- (void) appendRole :(WailsContext*)ctx :(Role)role;
|
||||
|
||||
- (NSMenuItem*) newMenuItemWithContext :(WailsContext*)ctx :(NSString*)title :(SEL)selector :(NSString*)key :(NSEventModifierFlags)flags;
|
||||
- (void*) AppendMenuItem :(WailsContext*)ctx :(NSString*)label :(NSString *)shortcutKey :(int)modifiers :(bool)disabled :(bool)checked :(int)menuItemID;
|
||||
- (void) AppendSeparator;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#endif /* WailsMenu_h */
|
||||
318
v2/internal/frontend/desktop/darwin/WailsMenu.m
Normal file
318
v2/internal/frontend/desktop/darwin/WailsMenu.m
Normal file
@@ -0,0 +1,318 @@
|
||||
//
|
||||
// WailsMenu.m
|
||||
// test
|
||||
//
|
||||
// Created by Lea Anthony on 25/10/21.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "WailsMenu.h"
|
||||
#import "WailsMenuItem.h"
|
||||
#import "Role.h"
|
||||
|
||||
@implementation WailsMenu
|
||||
|
||||
- (NSMenuItem*) newMenuItem :(NSString*)title :(SEL)selector :(NSString*)key :(NSEventModifierFlags)flags {
|
||||
NSMenuItem *result = [[[NSMenuItem alloc] initWithTitle:title action:selector keyEquivalent:key] autorelease];
|
||||
[result setKeyEquivalentModifierMask:flags];
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSMenuItem*) newMenuItemWithContext :(WailsContext*)ctx :(NSString*)title :(SEL)selector :(NSString*)key :(NSEventModifierFlags)flags {
|
||||
NSMenuItem *result = [[NSMenuItem new] autorelease];
|
||||
if ( title != nil ) {
|
||||
[result setTitle:title];
|
||||
}
|
||||
if (selector != nil) {
|
||||
[result setAction:selector];
|
||||
}
|
||||
if (key) {
|
||||
[result setKeyEquivalent:key];
|
||||
}
|
||||
if( flags != 0 ) {
|
||||
[result setKeyEquivalentModifierMask:flags];
|
||||
}
|
||||
result.target = ctx;
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSMenuItem*) newMenuItem :(NSString*)title :(SEL)selector :(NSString*)key {
|
||||
return [self newMenuItem :title :selector :key :0];
|
||||
}
|
||||
|
||||
- (WailsMenu*) initWithNSTitle:(NSString *)title {
|
||||
if( title != nil ) {
|
||||
[super initWithTitle:title];
|
||||
}
|
||||
[self setAutoenablesItems:NO];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) appendSubmenu :(WailsMenu*)child {
|
||||
NSMenuItem *childMenuItem = [[NSMenuItem new] autorelease];
|
||||
[childMenuItem setTitle:[child title]];
|
||||
[self addItem:childMenuItem];
|
||||
[childMenuItem setSubmenu:child];
|
||||
}
|
||||
|
||||
- (void) appendRole :(WailsContext*)ctx :(Role)role {
|
||||
|
||||
switch(role) {
|
||||
case AppMenu:
|
||||
{
|
||||
NSString *appName = [NSRunningApplication currentApplication].localizedName;
|
||||
if( appName == nil ) {
|
||||
appName = [[NSProcessInfo processInfo] processName];
|
||||
}
|
||||
WailsMenu *appMenu = [[WailsMenu new] initWithNSTitle:appName];
|
||||
id quitTitle = [@"Quit " stringByAppendingString:appName];
|
||||
NSMenuItem* quitMenuItem = [self newMenuItem:quitTitle :@selector(Quit) :@"q" :NSEventModifierFlagCommand];
|
||||
quitMenuItem.target = ctx;
|
||||
if (ctx.aboutTitle != nil) {
|
||||
[appMenu addItem:[self newMenuItemWithContext :ctx :[@"About " stringByAppendingString:appName] :@selector(About) :nil :0]];
|
||||
}
|
||||
[appMenu addItem:quitMenuItem];
|
||||
[self appendSubmenu:appMenu];
|
||||
break;
|
||||
}
|
||||
case EditMenu:
|
||||
{
|
||||
WailsMenu *editMenu = [[WailsMenu new] initWithNSTitle:@"Edit"];
|
||||
[editMenu addItem:[self newMenuItem:@"Undo" :@selector(undoActionName) :@"z" :NSEventModifierFlagCommand]];
|
||||
[editMenu addItem:[self newMenuItem:@"Redo" :@selector(redoActionName) :@"z" :(NSEventModifierFlagShift | NSEventModifierFlagCommand)]];
|
||||
[editMenu addItem:[NSMenuItem separatorItem]];
|
||||
[editMenu addItem:[self newMenuItem:@"Cut" :@selector(cut:) :@"x" :NSEventModifierFlagCommand]];
|
||||
[editMenu addItem:[self newMenuItem:@"Copy" :@selector(copy:) :@"c" :NSEventModifierFlagCommand]];
|
||||
[editMenu addItem:[self newMenuItem:@"Paste" :@selector(paste:) :@"v" :NSEventModifierFlagCommand]];
|
||||
[editMenu addItem:[self newMenuItem:@"Paste and Match Style" :@selector(pasteAsRichText:) :@"v" :(NSEventModifierFlagOption | NSEventModifierFlagShift | NSEventModifierFlagCommand)]];
|
||||
[editMenu addItem:[self newMenuItem:@"Delete" :@selector(delete:) :[self accel:@"backspace"] :0]];
|
||||
[editMenu addItem:[self newMenuItem:@"Select All" :@selector(selectAll:) :@"a" :NSEventModifierFlagCommand]];
|
||||
[editMenu addItem:[NSMenuItem separatorItem]];
|
||||
// NSMenuItem *speechMenuItem = [[NSMenuItem new] autorelease];
|
||||
// [speechMenuItem setTitle:@"Speech"];
|
||||
// [editMenu addItem:speechMenuItem];
|
||||
WailsMenu *speechMenu = [[WailsMenu new] initWithNSTitle:@"Speech"];
|
||||
[speechMenu addItem:[self newMenuItem:@"Start Speaking" :@selector(startSpeaking:) :@""]];
|
||||
[speechMenu addItem:[self newMenuItem:@"Stop Speaking" :@selector(stopSpeaking:) :@""]];
|
||||
[editMenu appendSubmenu:speechMenu];
|
||||
[self appendSubmenu:editMenu];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void*) AppendMenuItem :(WailsContext*)ctx :(NSString*)label :(NSString *)shortcutKey :(int)modifiers :(bool)disabled :(bool)checked :(int)menuItemID {
|
||||
|
||||
NSString *nslabel = @"";
|
||||
if (label != nil ) {
|
||||
nslabel = label;
|
||||
}
|
||||
WailsMenuItem *menuItem = [WailsMenuItem new];
|
||||
|
||||
// Label
|
||||
menuItem.title = nslabel;
|
||||
|
||||
// Process callback
|
||||
menuItem.menuItemID = menuItemID;
|
||||
menuItem.action = @selector(handleClick);
|
||||
menuItem.target = menuItem;
|
||||
|
||||
// Shortcut
|
||||
if (shortcutKey != nil) {
|
||||
[menuItem setKeyEquivalent:[self accel:shortcutKey]];
|
||||
[menuItem setKeyEquivalentModifierMask:modifiers];
|
||||
}
|
||||
|
||||
// Enabled/Disabled
|
||||
[menuItem setEnabled:!disabled];
|
||||
|
||||
// Checked
|
||||
[menuItem setState:(checked ? NSControlStateValueOn : NSControlStateValueOff)];
|
||||
|
||||
[self addItem:menuItem];
|
||||
return menuItem;
|
||||
}
|
||||
|
||||
- (void) AppendSeparator {
|
||||
[self addItem:[NSMenuItem separatorItem]];
|
||||
}
|
||||
|
||||
|
||||
- (NSString*) accel :(NSString*)key {
|
||||
|
||||
// Guard against no accelerator key
|
||||
if( key == NULL ) {
|
||||
return @"";
|
||||
}
|
||||
|
||||
if( [key isEqualToString:@"backspace"] ) {
|
||||
return unicode(0x0008);
|
||||
}
|
||||
if( [key isEqualToString:@"tab"] ) {
|
||||
return unicode(0x0009);
|
||||
}
|
||||
if( [key isEqualToString:@"return"] ) {
|
||||
return unicode(0x000d);
|
||||
}
|
||||
if( [key isEqualToString:@"enter"] ) {
|
||||
return unicode(0x000d);
|
||||
}
|
||||
if( [key isEqualToString:@"escape"] ) {
|
||||
return unicode(0x001b);
|
||||
}
|
||||
if( [key isEqualToString:@"left"] ) {
|
||||
return unicode(0x001c);
|
||||
}
|
||||
if( [key isEqualToString:@"right"] ) {
|
||||
return unicode(0x001d);
|
||||
}
|
||||
if( [key isEqualToString:@"up"] ) {
|
||||
return unicode(0x001e);
|
||||
}
|
||||
if( [key isEqualToString:@"down"] ) {
|
||||
return unicode(0x001f);
|
||||
}
|
||||
if( [key isEqualToString:@"space"] ) {
|
||||
return unicode(0x0020);
|
||||
}
|
||||
if( [key isEqualToString:@"delete"] ) {
|
||||
return unicode(0x007f);
|
||||
}
|
||||
if( [key isEqualToString:@"home"] ) {
|
||||
return unicode(0x2196);
|
||||
}
|
||||
if( [key isEqualToString:@"end"] ) {
|
||||
return unicode(0x2198);
|
||||
}
|
||||
if( [key isEqualToString:@"page up"] ) {
|
||||
return unicode(0x21de);
|
||||
}
|
||||
if( [key isEqualToString:@"page down"] ) {
|
||||
return unicode(0x21df);
|
||||
}
|
||||
if( [key isEqualToString:@"f1"] ) {
|
||||
return unicode(0xf704);
|
||||
}
|
||||
if( [key isEqualToString:@"f2"] ) {
|
||||
return unicode(0xf705);
|
||||
}
|
||||
if( [key isEqualToString:@"f3"] ) {
|
||||
return unicode(0xf706);
|
||||
}
|
||||
if( [key isEqualToString:@"f4"] ) {
|
||||
return unicode(0xf707);
|
||||
}
|
||||
if( [key isEqualToString:@"f5"] ) {
|
||||
return unicode(0xf708);
|
||||
}
|
||||
if( [key isEqualToString:@"f6"] ) {
|
||||
return unicode(0xf709);
|
||||
}
|
||||
if( [key isEqualToString:@"f7"] ) {
|
||||
return unicode(0xf70a);
|
||||
}
|
||||
if( [key isEqualToString:@"f8"] ) {
|
||||
return unicode(0xf70b);
|
||||
}
|
||||
if( [key isEqualToString:@"f9"] ) {
|
||||
return unicode(0xf70c);
|
||||
}
|
||||
if( [key isEqualToString:@"f10"] ) {
|
||||
return unicode(0xf70d);
|
||||
}
|
||||
if( [key isEqualToString:@"f11"] ) {
|
||||
return unicode(0xf70e);
|
||||
}
|
||||
if( [key isEqualToString:@"f12"] ) {
|
||||
return unicode(0xf70f);
|
||||
}
|
||||
if( [key isEqualToString:@"f13"] ) {
|
||||
return unicode(0xf710);
|
||||
}
|
||||
if( [key isEqualToString:@"f14"] ) {
|
||||
return unicode(0xf711);
|
||||
}
|
||||
if( [key isEqualToString:@"f15"] ) {
|
||||
return unicode(0xf712);
|
||||
}
|
||||
if( [key isEqualToString:@"f16"] ) {
|
||||
return unicode(0xf713);
|
||||
}
|
||||
if( [key isEqualToString:@"f17"] ) {
|
||||
return unicode(0xf714);
|
||||
}
|
||||
if( [key isEqualToString:@"f18"] ) {
|
||||
return unicode(0xf715);
|
||||
}
|
||||
if( [key isEqualToString:@"f19"] ) {
|
||||
return unicode(0xf716);
|
||||
}
|
||||
if( [key isEqualToString:@"f20"] ) {
|
||||
return unicode(0xf717);
|
||||
}
|
||||
if( [key isEqualToString:@"f21"] ) {
|
||||
return unicode(0xf718);
|
||||
}
|
||||
if( [key isEqualToString:@"f22"] ) {
|
||||
return unicode(0xf719);
|
||||
}
|
||||
if( [key isEqualToString:@"f23"] ) {
|
||||
return unicode(0xf71a);
|
||||
}
|
||||
if( [key isEqualToString:@"f24"] ) {
|
||||
return unicode(0xf71b);
|
||||
}
|
||||
if( [key isEqualToString:@"f25"] ) {
|
||||
return unicode(0xf71c);
|
||||
}
|
||||
if( [key isEqualToString:@"f26"] ) {
|
||||
return unicode(0xf71d);
|
||||
}
|
||||
if( [key isEqualToString:@"f27"] ) {
|
||||
return unicode(0xf71e);
|
||||
}
|
||||
if( [key isEqualToString:@"f28"] ) {
|
||||
return unicode(0xf71f);
|
||||
}
|
||||
if( [key isEqualToString:@"f29"] ) {
|
||||
return unicode(0xf720);
|
||||
}
|
||||
if( [key isEqualToString:@"f30"] ) {
|
||||
return unicode(0xf721);
|
||||
}
|
||||
if( [key isEqualToString:@"f31"] ) {
|
||||
return unicode(0xf722);
|
||||
}
|
||||
if( [key isEqualToString:@"f32"] ) {
|
||||
return unicode(0xf723);
|
||||
}
|
||||
if( [key isEqualToString:@"f33"] ) {
|
||||
return unicode(0xf724);
|
||||
}
|
||||
if( [key isEqualToString:@"f34"] ) {
|
||||
return unicode(0xf725);
|
||||
}
|
||||
if( [key isEqualToString:@"f35"] ) {
|
||||
return unicode(0xf726);
|
||||
}
|
||||
// if( [key isEqualToString:@"Insert"] ) {
|
||||
// return unicode(0xf727);
|
||||
// }
|
||||
// if( [key isEqualToString:@"PrintScreen"] ) {
|
||||
// return unicode(0xf72e);
|
||||
// }
|
||||
// if( [key isEqualToString:@"ScrollLock"] ) {
|
||||
// return unicode(0xf72f);
|
||||
// }
|
||||
if( [key isEqualToString:@"numLock"] ) {
|
||||
return unicode(0xf739);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
22
v2/internal/frontend/desktop/darwin/WailsMenuItem.h
Normal file
22
v2/internal/frontend/desktop/darwin/WailsMenuItem.h
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// WailsMenuItem.h
|
||||
// test
|
||||
//
|
||||
// Created by Lea Anthony on 27/10/21.
|
||||
//
|
||||
|
||||
#ifndef WailsMenuItem_h
|
||||
#define WailsMenuItem_h
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface WailsMenuItem : NSMenuItem
|
||||
|
||||
@property int menuItemID;
|
||||
|
||||
- (void) handleClick;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#endif /* WailsMenuItem_h */
|
||||
20
v2/internal/frontend/desktop/darwin/WailsMenuItem.m
Normal file
20
v2/internal/frontend/desktop/darwin/WailsMenuItem.m
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// WailsMenuItem.m
|
||||
// test
|
||||
//
|
||||
// Created by Lea Anthony on 27/10/21.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "WailsMenuItem.h"
|
||||
#include "message.h"
|
||||
|
||||
|
||||
@implementation WailsMenuItem
|
||||
|
||||
- (void) handleClick {
|
||||
processCallback(self.menuItemID);
|
||||
}
|
||||
|
||||
@end
|
||||
18
v2/internal/frontend/desktop/darwin/WindowDelegate.h
Normal file
18
v2/internal/frontend/desktop/darwin/WindowDelegate.h
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// WindowDelegate.h
|
||||
// test
|
||||
//
|
||||
// Created by Lea Anthony on 10/10/21.
|
||||
//
|
||||
|
||||
#ifndef WindowDelegate_h
|
||||
#define WindowDelegate_h
|
||||
|
||||
@interface WindowDelegate : NSObject <NSWindowDelegate>
|
||||
|
||||
@property bool hideOnClose;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#endif /* WindowDelegate_h */
|
||||
24
v2/internal/frontend/desktop/darwin/WindowDelegate.m
Normal file
24
v2/internal/frontend/desktop/darwin/WindowDelegate.m
Normal file
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// WindowDelegate.m
|
||||
// test
|
||||
//
|
||||
// Created by Lea Anthony on 10/10/21.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "WindowDelegate.h"
|
||||
#import "message.h"
|
||||
#import "WailsContext.h"
|
||||
|
||||
@implementation WindowDelegate
|
||||
|
||||
- (BOOL)windowShouldClose:(WailsWindow *)sender {
|
||||
[sender orderOut:nil];
|
||||
if( self.hideOnClose == false ) {
|
||||
processMessage("Q");
|
||||
}
|
||||
return !self.hideOnClose;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -1,3 +1,6 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package darwin
|
||||
|
||||
import (
|
||||
|
||||
51
v2/internal/frontend/desktop/darwin/callbacks.go
Normal file
51
v2/internal/frontend/desktop/darwin/callbacks.go
Normal file
@@ -0,0 +1,51 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package darwin
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -x objective-c
|
||||
#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Application.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
)
|
||||
|
||||
func (f *Frontend) handleCallback(menuItemID uint) error {
|
||||
|
||||
menuItem := getMenuItemForID(menuItemID)
|
||||
if menuItem == nil {
|
||||
return errors.New("unknown menuItem ID: " + strconv.Itoa(int(menuItemID)))
|
||||
}
|
||||
|
||||
wailsMenuItem := menuItem.wailsMenuItem
|
||||
if wailsMenuItem.Type == menu.CheckboxType {
|
||||
wailsMenuItem.Checked = !wailsMenuItem.Checked
|
||||
C.UpdateMenuItem(menuItem.nsmenuitem, bool2Cint(wailsMenuItem.Checked))
|
||||
}
|
||||
if wailsMenuItem.Type == menu.RadioType {
|
||||
// Ignore if we clicked the item that is already checked
|
||||
if !wailsMenuItem.Checked {
|
||||
for _, item := range menuItem.radioGroupMembers {
|
||||
if item.wailsMenuItem.Checked {
|
||||
item.wailsMenuItem.Checked = false
|
||||
C.UpdateMenuItem(item.nsmenuitem, C.int(0))
|
||||
}
|
||||
}
|
||||
wailsMenuItem.Checked = true
|
||||
C.UpdateMenuItem(menuItem.nsmenuitem, C.int(1))
|
||||
}
|
||||
}
|
||||
if wailsMenuItem.Click != nil {
|
||||
go wailsMenuItem.Click(&menu.CallbackData{MenuItem: wailsMenuItem})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
32
v2/internal/frontend/desktop/darwin/calloc.go
Normal file
32
v2/internal/frontend/desktop/darwin/calloc.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package darwin
|
||||
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
import "unsafe"
|
||||
|
||||
// Calloc handles alloc/dealloc of C data
|
||||
type Calloc struct {
|
||||
pool []unsafe.Pointer
|
||||
}
|
||||
|
||||
// NewCalloc creates a new allocator
|
||||
func NewCalloc() Calloc {
|
||||
return Calloc{}
|
||||
}
|
||||
|
||||
// String creates a new C string and retains a reference to it
|
||||
func (c Calloc) String(in string) *C.char {
|
||||
result := C.CString(in)
|
||||
c.pool = append(c.pool, unsafe.Pointer(result))
|
||||
return result
|
||||
}
|
||||
|
||||
// Free frees all allocated C memory
|
||||
func (c Calloc) Free() {
|
||||
for _, str := range c.pool {
|
||||
C.free(str)
|
||||
}
|
||||
c.pool = []unsafe.Pointer{}
|
||||
}
|
||||
@@ -1,33 +1,193 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package darwin
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -x objective-c
|
||||
#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Application.h"
|
||||
#import "WailsContext.h"
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
)
|
||||
|
||||
// Obj-C dialog methods send the response to this channel
|
||||
var messageDialogResponse = make(chan int)
|
||||
var openFileDialogResponse = make(chan string)
|
||||
var saveFileDialogResponse = make(chan string)
|
||||
var dialogLock sync.Mutex
|
||||
|
||||
// OpenDirectoryDialog prompts the user to select a directory
|
||||
func (f *Frontend) OpenDirectoryDialog(options frontend.OpenDialogOptions) (string, error) {
|
||||
return "", nil
|
||||
results, err := f.openDialog(&options, false, false, true)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var selected string
|
||||
if len(results) > 0 {
|
||||
selected = results[0]
|
||||
}
|
||||
return selected, nil
|
||||
}
|
||||
|
||||
func (f *Frontend) openDialog(options *frontend.OpenDialogOptions, multiple bool, allowfiles bool, allowdirectories bool) ([]string, error) {
|
||||
dialogLock.Lock()
|
||||
defer dialogLock.Unlock()
|
||||
|
||||
c := NewCalloc()
|
||||
defer c.Free()
|
||||
title := c.String(options.Title)
|
||||
defaultFilename := c.String(options.DefaultFilename)
|
||||
defaultDirectory := c.String(options.DefaultDirectory)
|
||||
allowDirectories := bool2Cint(allowdirectories)
|
||||
allowFiles := bool2Cint(allowfiles)
|
||||
canCreateDirectories := bool2Cint(options.CanCreateDirectories)
|
||||
treatPackagesAsDirectories := bool2Cint(options.TreatPackagesAsDirectories)
|
||||
resolveAliases := bool2Cint(options.ResolvesAliases)
|
||||
showHiddenFiles := bool2Cint(options.ShowHiddenFiles)
|
||||
allowMultipleFileSelection := bool2Cint(multiple)
|
||||
|
||||
var filterStrings slicer.StringSlicer
|
||||
if options.Filters != nil {
|
||||
for _, filter := range options.Filters {
|
||||
thesePatterns := strings.Split(filter.Pattern, ";")
|
||||
for _, pattern := range thesePatterns {
|
||||
pattern = strings.TrimSpace(pattern)
|
||||
if pattern != "" {
|
||||
filterStrings.Add(pattern)
|
||||
}
|
||||
}
|
||||
}
|
||||
filterStrings.Deduplicate()
|
||||
}
|
||||
filters := filterStrings.Join(";")
|
||||
C.OpenFileDialog(f.mainWindow.context, title, defaultFilename, defaultDirectory, allowDirectories, allowFiles, canCreateDirectories, treatPackagesAsDirectories, resolveAliases, showHiddenFiles, allowMultipleFileSelection, c.String(filters))
|
||||
|
||||
var result = <-openFileDialogResponse
|
||||
|
||||
var parsedResults []string
|
||||
err := json.Unmarshal([]byte(result), &parsedResults)
|
||||
|
||||
return parsedResults, err
|
||||
}
|
||||
|
||||
// OpenFileDialog prompts the user to select a file
|
||||
func (f *Frontend) OpenFileDialog(options frontend.OpenDialogOptions) (string, error) {
|
||||
return "", nil
|
||||
results, err := f.openDialog(&options, false, options.AllowFiles, options.AllowDirectories)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var selected string
|
||||
if len(results) > 0 {
|
||||
selected = results[0]
|
||||
}
|
||||
return selected, nil
|
||||
}
|
||||
|
||||
// OpenMultipleFilesDialog prompts the user to select a file
|
||||
func (f *Frontend) OpenMultipleFilesDialog(dialogOptions frontend.OpenDialogOptions) ([]string, error) {
|
||||
return []string{}, nil
|
||||
func (f *Frontend) OpenMultipleFilesDialog(options frontend.OpenDialogOptions) ([]string, error) {
|
||||
return f.openDialog(&options, true, options.AllowFiles, options.AllowDirectories)
|
||||
}
|
||||
|
||||
// SaveFileDialog prompts the user to select a file
|
||||
func (f *Frontend) SaveFileDialog(dialogOptions frontend.SaveDialogOptions) (string, error) {
|
||||
return "", nil
|
||||
func (f *Frontend) SaveFileDialog(options frontend.SaveDialogOptions) (string, error) {
|
||||
dialogLock.Lock()
|
||||
defer dialogLock.Unlock()
|
||||
|
||||
c := NewCalloc()
|
||||
defer c.Free()
|
||||
title := c.String(options.Title)
|
||||
defaultFilename := c.String(options.DefaultFilename)
|
||||
defaultDirectory := c.String(options.DefaultDirectory)
|
||||
canCreateDirectories := bool2Cint(options.CanCreateDirectories)
|
||||
treatPackagesAsDirectories := bool2Cint(options.TreatPackagesAsDirectories)
|
||||
showHiddenFiles := bool2Cint(options.ShowHiddenFiles)
|
||||
|
||||
var filterStrings slicer.StringSlicer
|
||||
if options.Filters != nil {
|
||||
for _, filter := range options.Filters {
|
||||
thesePatterns := strings.Split(filter.Pattern, ";")
|
||||
for _, pattern := range thesePatterns {
|
||||
pattern = strings.TrimSpace(pattern)
|
||||
if pattern != "" {
|
||||
filterStrings.Add(pattern)
|
||||
}
|
||||
}
|
||||
}
|
||||
filterStrings.Deduplicate()
|
||||
}
|
||||
filters := filterStrings.Join(";")
|
||||
C.SaveFileDialog(f.mainWindow.context, title, defaultFilename, defaultDirectory, canCreateDirectories, treatPackagesAsDirectories, showHiddenFiles, c.String(filters))
|
||||
|
||||
var result = <-saveFileDialogResponse
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// MessageDialog show a message dialog to the user
|
||||
func (f *Frontend) MessageDialog(options frontend.MessageDialogOptions) (string, error) {
|
||||
return "", nil
|
||||
dialogLock.Lock()
|
||||
defer dialogLock.Unlock()
|
||||
|
||||
c := NewCalloc()
|
||||
defer c.Free()
|
||||
dialogType := c.String(string(options.Type))
|
||||
title := c.String(options.Title)
|
||||
message := c.String(options.Message)
|
||||
defaultButton := c.String(options.DefaultButton)
|
||||
cancelButton := c.String(options.CancelButton)
|
||||
const MaxButtons = 4
|
||||
var buttons [MaxButtons]*C.char
|
||||
for index, buttonText := range options.Buttons {
|
||||
if index == MaxButtons {
|
||||
return "", fmt.Errorf("max %d buttons supported (%d given)", MaxButtons, len(options.Buttons))
|
||||
}
|
||||
buttons[index] = c.String(buttonText)
|
||||
}
|
||||
|
||||
var iconData unsafe.Pointer
|
||||
var iconDataLength C.int
|
||||
if options.Icon != nil {
|
||||
iconData = unsafe.Pointer(&options.Icon[0])
|
||||
iconDataLength = C.int(len(options.Icon))
|
||||
}
|
||||
|
||||
C.MessageDialog(f.mainWindow.context, dialogType, title, message, buttons[0], buttons[1], buttons[2], buttons[3], defaultButton, cancelButton, iconData, iconDataLength)
|
||||
|
||||
var result = <-messageDialogResponse
|
||||
|
||||
selectedC := buttons[result]
|
||||
var selected string
|
||||
if selectedC != nil {
|
||||
selected = options.Buttons[result]
|
||||
}
|
||||
return selected, nil
|
||||
}
|
||||
|
||||
//export processMessageDialogResponse
|
||||
func processMessageDialogResponse(selection int) {
|
||||
messageDialogResponse <- selection
|
||||
}
|
||||
|
||||
//export processOpenFileDialogResponse
|
||||
func processOpenFileDialogResponse(cselection *C.char) {
|
||||
selection := C.GoString(cselection)
|
||||
openFileDialogResponse <- selection
|
||||
}
|
||||
|
||||
//export processSaveFileDialogResponse
|
||||
func processSaveFileDialogResponse(cselection *C.char) {
|
||||
selection := C.GoString(cselection)
|
||||
saveFileDialogResponse <- selection
|
||||
}
|
||||
|
||||
@@ -1,12 +1,26 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package darwin
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -x objective-c
|
||||
#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Application.h"
|
||||
#import "WailsContext.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"html/template"
|
||||
"log"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/binding"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
@@ -15,6 +29,15 @@ import (
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
type request struct {
|
||||
url *C.char
|
||||
ctx unsafe.Pointer
|
||||
}
|
||||
|
||||
var messageBuffer = make(chan string, 100)
|
||||
var requestBuffer = make(chan *request, 100)
|
||||
var callbackBuffer = make(chan uint, 10)
|
||||
|
||||
type Frontend struct {
|
||||
|
||||
// Context
|
||||
@@ -28,7 +51,7 @@ type Frontend struct {
|
||||
assets *assetserver.DesktopAssetServer
|
||||
|
||||
// main window handle
|
||||
//mainWindow *Window
|
||||
mainWindow *Window
|
||||
minWidth, minHeight, maxWidth, maxHeight int
|
||||
bindings *binding.Bindings
|
||||
dispatcher frontend.Dispatcher
|
||||
@@ -43,10 +66,6 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.
|
||||
bindings: appBindings,
|
||||
dispatcher: dispatcher,
|
||||
ctx: ctx,
|
||||
minHeight: appoptions.MinHeight,
|
||||
minWidth: appoptions.MinWidth,
|
||||
maxHeight: appoptions.MaxHeight,
|
||||
maxWidth: appoptions.MaxWidth,
|
||||
}
|
||||
|
||||
// Check if we have been given a directory to serve assets from.
|
||||
@@ -68,9 +87,32 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.
|
||||
}
|
||||
result.assets = assets
|
||||
|
||||
go result.startMessageProcessor()
|
||||
go result.startRequestProcessor()
|
||||
go result.startCallbackProcessor()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (f *Frontend) startMessageProcessor() {
|
||||
for message := range messageBuffer {
|
||||
f.processMessage(message)
|
||||
}
|
||||
}
|
||||
func (f *Frontend) startRequestProcessor() {
|
||||
for request := range requestBuffer {
|
||||
f.processRequest(request)
|
||||
}
|
||||
}
|
||||
func (f *Frontend) startCallbackProcessor() {
|
||||
for callback := range callbackBuffer {
|
||||
err := f.handleCallback(callback)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowReload() {
|
||||
f.ExecJS("runtime.WindowReload();")
|
||||
}
|
||||
@@ -79,222 +121,104 @@ func (f *Frontend) Run(ctx context.Context) error {
|
||||
|
||||
f.ctx = context.WithValue(ctx, "frontend", f)
|
||||
|
||||
//mainWindow := NewWindow(nil, f.frontendOptions)
|
||||
//f.mainWindow = mainWindow
|
||||
//
|
||||
//var _debug = ctx.Value("debug")
|
||||
//if _debug != nil {
|
||||
// f.debug = _debug.(bool)
|
||||
//}
|
||||
//
|
||||
//f.WindowCenter()
|
||||
//f.setupChromium()
|
||||
//
|
||||
//mainWindow.OnSize().Bind(func(arg *winc.Event) {
|
||||
// f.chromium.Resize()
|
||||
//})
|
||||
//
|
||||
//mainWindow.OnClose().Bind(func(arg *winc.Event) {
|
||||
// if f.frontendOptions.HideWindowOnClose {
|
||||
// f.WindowHide()
|
||||
// } else {
|
||||
// f.Quit()
|
||||
// }
|
||||
//})
|
||||
//
|
||||
//// TODO: Move this into a callback from frontend
|
||||
//go func() {
|
||||
// if f.frontendOptions.OnStartup != nil {
|
||||
// f.frontendOptions.OnStartup(f.ctx)
|
||||
// }
|
||||
//}()
|
||||
//
|
||||
//mainWindow.Run()
|
||||
var _debug = ctx.Value("debug")
|
||||
if _debug != nil {
|
||||
f.debug = _debug.(bool)
|
||||
}
|
||||
|
||||
mainWindow := NewWindow(f.frontendOptions, f.debug)
|
||||
f.mainWindow = mainWindow
|
||||
f.mainWindow.Center()
|
||||
|
||||
go func() {
|
||||
if f.frontendOptions.OnStartup != nil {
|
||||
f.frontendOptions.OnStartup(f.ctx)
|
||||
}
|
||||
}()
|
||||
mainWindow.Run()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowCenter() {
|
||||
runtime.LockOSThread()
|
||||
//f.mainWindow.Center()
|
||||
f.mainWindow.Center()
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowSetPos(x, y int) {
|
||||
runtime.LockOSThread()
|
||||
//f.mainWindow.SetPos(x, y)
|
||||
f.mainWindow.SetPos(x, y)
|
||||
}
|
||||
func (f *Frontend) WindowGetPos() (int, int) {
|
||||
runtime.LockOSThread()
|
||||
//return f.mainWindow.Pos()
|
||||
return 0, 0
|
||||
return f.mainWindow.Pos()
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowSetSize(width, height int) {
|
||||
runtime.LockOSThread()
|
||||
//f.mainWindow.SetSize(width, height)
|
||||
f.mainWindow.SetSize(width, height)
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowGetSize() (int, int) {
|
||||
runtime.LockOSThread()
|
||||
//return f.mainWindow.Size()
|
||||
return 0, 0
|
||||
return f.mainWindow.Size()
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowSetTitle(title string) {
|
||||
runtime.LockOSThread()
|
||||
//f.mainWindow.SetText(title)
|
||||
f.mainWindow.SetTitle(title)
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowFullscreen() {
|
||||
runtime.LockOSThread()
|
||||
//f.mainWindow.SetMaxSize(0, 0)
|
||||
//f.mainWindow.SetMinSize(0, 0)
|
||||
//f.mainWindow.Fullscreen()
|
||||
f.mainWindow.SetMaxSize(0, 0)
|
||||
f.mainWindow.SetMinSize(0, 0)
|
||||
f.mainWindow.Fullscreen()
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowUnFullscreen() {
|
||||
runtime.LockOSThread()
|
||||
//f.mainWindow.UnFullscreen()
|
||||
//f.mainWindow.SetMaxSize(f.maxWidth, f.maxHeight)
|
||||
//f.mainWindow.SetMinSize(f.minWidth, f.minHeight)
|
||||
f.mainWindow.UnFullscreen()
|
||||
f.mainWindow.SetMaxSize(f.maxWidth, f.maxHeight)
|
||||
f.mainWindow.SetMinSize(f.minWidth, f.minHeight)
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowShow() {
|
||||
runtime.LockOSThread()
|
||||
//f.mainWindow.Show()
|
||||
f.mainWindow.Show()
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowHide() {
|
||||
runtime.LockOSThread()
|
||||
//f.mainWindow.Hide()
|
||||
f.mainWindow.Hide()
|
||||
}
|
||||
func (f *Frontend) WindowMaximise() {
|
||||
runtime.LockOSThread()
|
||||
//f.mainWindow.Maximise()
|
||||
f.mainWindow.Maximise()
|
||||
}
|
||||
func (f *Frontend) WindowUnmaximise() {
|
||||
runtime.LockOSThread()
|
||||
//f.mainWindow.Restore()
|
||||
f.mainWindow.UnMaximise()
|
||||
}
|
||||
func (f *Frontend) WindowMinimise() {
|
||||
runtime.LockOSThread()
|
||||
//f.mainWindow.Minimise()
|
||||
f.mainWindow.Minimise()
|
||||
}
|
||||
func (f *Frontend) WindowUnminimise() {
|
||||
runtime.LockOSThread()
|
||||
//f.mainWindow.Restore()
|
||||
f.mainWindow.UnMinimise()
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowSetMinSize(width int, height int) {
|
||||
runtime.LockOSThread()
|
||||
f.minWidth = width
|
||||
f.minHeight = height
|
||||
//f.mainWindow.SetMinSize(width, height)
|
||||
f.mainWindow.SetMinSize(width, height)
|
||||
}
|
||||
func (f *Frontend) WindowSetMaxSize(width int, height int) {
|
||||
runtime.LockOSThread()
|
||||
f.maxWidth = width
|
||||
f.maxHeight = height
|
||||
//f.mainWindow.SetMaxSize(width, height)
|
||||
f.mainWindow.SetMaxSize(width, height)
|
||||
}
|
||||
|
||||
func (f *Frontend) WindowSetRGBA(col *options.RGBA) {
|
||||
runtime.LockOSThread()
|
||||
if col == nil {
|
||||
return
|
||||
}
|
||||
/*
|
||||
|
||||
//f.mainWindow.Dispatch(func() {
|
||||
controller := f.chromium.GetController()
|
||||
controller2 := controller.GetICoreWebView2Controller2()
|
||||
|
||||
backgroundCol := edge.COREWEBVIEW2_COLOR{
|
||||
A: col.A,
|
||||
R: col.R,
|
||||
G: col.G,
|
||||
B: col.B,
|
||||
}
|
||||
|
||||
// Webview2 only has 0 and 255 as valid values.
|
||||
if backgroundCol.A > 0 && backgroundCol.A < 255 {
|
||||
backgroundCol.A = 255
|
||||
}
|
||||
|
||||
if f.frontendOptions.Windows != nil && f.frontendOptions.Windows.WebviewIsTransparent {
|
||||
backgroundCol.A = 0
|
||||
}
|
||||
|
||||
err := controller2.PutDefaultBackgroundColor(backgroundCol)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
})
|
||||
*/
|
||||
f.mainWindow.SetRGBA(col.R, col.G, col.B, col.A)
|
||||
}
|
||||
|
||||
func (f *Frontend) Quit() {
|
||||
//winc.Exit()
|
||||
f.mainWindow.Quit()
|
||||
if f.frontendOptions.OnShutdown != nil {
|
||||
f.frontendOptions.OnShutdown(f.ctx)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
const (
|
||||
ctrlZ int = 90
|
||||
ctrlX = 88
|
||||
ctrlC = 67
|
||||
ctrlV = 86
|
||||
)
|
||||
|
||||
func (f *Frontend) setupChromium() {
|
||||
chromium := edge.NewChromium()
|
||||
f.chromium = chromium
|
||||
chromium.MessageCallback = f.processMessage
|
||||
chromium.WebResourceRequestedCallback = f.processRequest
|
||||
chromium.NavigationCompletedCallback = f.navigationCompleted
|
||||
acceleratorsWebviewShouldProcess := slicer.Int([]int{ctrlV, ctrlC, ctrlX, ctrlZ})
|
||||
chromium.AcceleratorKeyCallback = func(vkey uint) bool {
|
||||
// We want webview to handle ctrl-C, ctrl-Z, ctrl-v, ctrl-x
|
||||
if acceleratorsWebviewShouldProcess.Contains(int(vkey)) {
|
||||
return false
|
||||
}
|
||||
// Post keypress
|
||||
//w32.PostMessage(f.mainWindow.Handle(), w32.WM_KEYDOWN, uintptr(vkey), 0)
|
||||
return true
|
||||
}
|
||||
chromium.Embed(f.mainWindow.Handle())
|
||||
chromium.Resize()
|
||||
settings, err := chromium.GetSettings()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = settings.PutAreDefaultContextMenusEnabled(f.debug)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = settings.PutAreDevToolsEnabled(f.debug)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = settings.PutIsZoomControlEnabled(false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = settings.PutIsStatusBarEnabled(false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = settings.PutIsStatusBarEnabled(false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Set background colour
|
||||
f.WindowSetRGBA(f.frontendOptions.RGBA)
|
||||
|
||||
chromium.AddWebResourceRequestedFilter("*", edge.COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL)
|
||||
chromium.Navigate("file://wails/")
|
||||
}
|
||||
*/
|
||||
|
||||
type EventNotify struct {
|
||||
Name string `json:"name"`
|
||||
Data []interface{} `json:"data"`
|
||||
@@ -310,50 +234,18 @@ func (f *Frontend) Notify(name string, data ...interface{}) {
|
||||
f.logger.Error(err.Error())
|
||||
return
|
||||
}
|
||||
f.ExecJS(`window.wails.EventsNotify('` + string(payload) + `');`)
|
||||
f.ExecJS(`window.wails.EventsNotify('` + template.JSEscapeString(string(payload)) + `');`)
|
||||
}
|
||||
|
||||
//func (f *Frontend) processRequest(req *edge.ICoreWebView2WebResourceRequest, args *edge.ICoreWebView2WebResourceRequestedEventArgs) {
|
||||
// //Get the request
|
||||
// uri, _ := req.GetUri()
|
||||
//
|
||||
// // Translate URI
|
||||
// uri = strings.TrimPrefix(uri, "file://wails")
|
||||
// if !strings.HasPrefix(uri, "/") {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // Load file from asset store
|
||||
// content, mimeType, err := f.assets.Load(uri)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// env := f.chromium.Environment()
|
||||
// headers := "Content-Type: " + mimeType
|
||||
// if f.servingFromDisk {
|
||||
// headers += "\nPragma: no-cache"
|
||||
// }
|
||||
// response, err := env.CreateWebResourceResponse(content, 200, "OK", headers)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// // Send response back
|
||||
// err = args.PutResponse(response)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// return
|
||||
//}
|
||||
|
||||
func (f *Frontend) processMessage(message string) {
|
||||
if message == "drag" {
|
||||
err := f.startDrag()
|
||||
if err != nil {
|
||||
f.logger.Error(err.Error())
|
||||
|
||||
if message == "DomReady" {
|
||||
if f.frontendOptions.OnDomReady != nil {
|
||||
f.frontendOptions.OnDomReady(f.ctx)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
result, err := f.dispatcher.ProcessMessage(message, f)
|
||||
if err != nil {
|
||||
f.logger.Error(err.Error())
|
||||
@@ -374,44 +266,50 @@ func (f *Frontend) processMessage(message string) {
|
||||
}
|
||||
|
||||
func (f *Frontend) Callback(message string) {
|
||||
//f.mainWindow.Dispatch(func() {
|
||||
// f.chromium.Eval(`window.wails.Callback(` + strconv.Quote(message) + `);`)
|
||||
//})
|
||||
}
|
||||
|
||||
func (f *Frontend) startDrag() error {
|
||||
//if !w32.ReleaseCapture() {
|
||||
// return fmt.Errorf("unable to release mouse capture")
|
||||
//}
|
||||
//w32.SendMessage(f.mainWindow.Handle(), w32.WM_NCLBUTTONDOWN, w32.HTCAPTION, 0)
|
||||
return nil
|
||||
f.ExecJS(`window.wails.Callback(` + strconv.Quote(message) + `);`)
|
||||
}
|
||||
|
||||
func (f *Frontend) ExecJS(js string) {
|
||||
//f.mainWindow.Dispatch(func() {
|
||||
// f.chromium.Eval(js)
|
||||
//})
|
||||
f.mainWindow.ExecJS(js)
|
||||
}
|
||||
|
||||
//func (f *Frontend) navigationCompleted(sender *edge.ICoreWebView2, args *edge.ICoreWebView2NavigationCompletedEventArgs) {
|
||||
// if f.frontendOptions.OnDomReady != nil {
|
||||
// go f.frontendOptions.OnDomReady(f.ctx)
|
||||
// }
|
||||
//
|
||||
// // If you want to start hidden, return
|
||||
// if f.frontendOptions.StartHidden {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // Hack to make it visible: https://github.com/MicrosoftEdge/WebView2Feedback/issues/1077#issuecomment-825375026
|
||||
// err := f.chromium.Hide()
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
// err = f.chromium.Show()
|
||||
// if err != nil {
|
||||
// log.Fatal(err)
|
||||
// }
|
||||
// f.mainWindow.Show()
|
||||
//
|
||||
//}
|
||||
func (f *Frontend) processRequest(r *request) {
|
||||
url := C.GoString(r.url)
|
||||
url = strings.TrimPrefix(url, "wails://wails")
|
||||
if !strings.HasPrefix(url, "/") {
|
||||
return
|
||||
}
|
||||
_contents, _mimetype, err := f.assets.Load(url)
|
||||
if err != nil {
|
||||
f.logger.Error(err.Error())
|
||||
//TODO: Handle errors
|
||||
return
|
||||
}
|
||||
var data unsafe.Pointer
|
||||
if _contents != nil {
|
||||
data = unsafe.Pointer(&_contents[0])
|
||||
}
|
||||
mimetype := C.CString(_mimetype)
|
||||
defer C.free(unsafe.Pointer(mimetype))
|
||||
|
||||
C.ProcessURLResponse(r.ctx, r.url, mimetype, data, C.int(len(_contents)))
|
||||
}
|
||||
|
||||
//export processMessage
|
||||
func processMessage(message *C.char) {
|
||||
goMessage := C.GoString(message)
|
||||
messageBuffer <- goMessage
|
||||
}
|
||||
|
||||
//export processURLRequest
|
||||
func processURLRequest(ctx unsafe.Pointer, url *C.char) {
|
||||
requestBuffer <- &request{
|
||||
url: url,
|
||||
ctx: ctx,
|
||||
}
|
||||
}
|
||||
|
||||
//export processCallback
|
||||
func processCallback(callbackID uint) {
|
||||
callbackBuffer <- callbackID
|
||||
}
|
||||
|
||||
237
v2/internal/frontend/desktop/darwin/main.m
Normal file
237
v2/internal/frontend/desktop/darwin/main.m
Normal file
@@ -0,0 +1,237 @@
|
||||
//go:build ignore
|
||||
// main.m
|
||||
// test
|
||||
//
|
||||
// Created by Lea Anthony on 10/10/21.
|
||||
//
|
||||
|
||||
// ****** This file is used for testing purposes only ******
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Application.h"
|
||||
|
||||
void processMessage(const char*t) {
|
||||
NSLog(@"processMessage called");
|
||||
}
|
||||
|
||||
void processMessageDialogResponse(int t) {
|
||||
NSLog(@"processMessage called");
|
||||
}
|
||||
|
||||
void processOpenFileDialogResponse(const char *t) {
|
||||
NSLog(@"processMessage called %s", t);
|
||||
}
|
||||
void processSaveFileDialogResponse(const char *t) {
|
||||
NSLog(@"processMessage called %s", t);
|
||||
}
|
||||
|
||||
void processCallback(int callbackID) {
|
||||
NSLog(@"Process callback %d", callbackID);
|
||||
}
|
||||
|
||||
void processURLRequest(void *ctx, const char* url) {
|
||||
NSLog(@"processURLRequest called");
|
||||
const char myByteArray[] = { 0x3c,0x68,0x31,0x3e,0x48,0x65,0x6c,0x6c,0x6f,0x20,0x57,0x6f,0x72,0x6c,0x64,0x21,0x3c,0x2f,0x68,0x31,0x3e };
|
||||
ProcessURLResponse(ctx, url, "text/html", (void*)myByteArray, 21);
|
||||
}
|
||||
|
||||
unsigned char _Users_username_Pictures_SaltBae_png[] = {
|
||||
|
||||
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d,
|
||||
0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14,
|
||||
0x08, 0x06, 0x00, 0x00, 0x00, 0x8d, 0x89, 0x1d, 0x0d, 0x00, 0x00, 0x00,
|
||||
0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00, 0xb1, 0x8f, 0x0b, 0xfc, 0x61,
|
||||
0x05, 0x00, 0x00, 0x00, 0x20, 0x63, 0x48, 0x52, 0x4d, 0x00, 0x00, 0x7a,
|
||||
0x26, 0x00, 0x00, 0x80, 0x84, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x80,
|
||||
0xe8, 0x00, 0x00, 0x75, 0x30, 0x00, 0x00, 0xea, 0x60, 0x00, 0x00, 0x3a,
|
||||
0x98, 0x00, 0x00, 0x17, 0x70, 0x9c, 0xba, 0x51, 0x3c, 0x00, 0x00, 0x00,
|
||||
0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00, 0x0b,
|
||||
0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x01, 0xd5, 0x69, 0x54,
|
||||
0x58, 0x74, 0x58, 0x4d, 0x4c, 0x3a, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x64,
|
||||
0x6f, 0x62, 0x65, 0x2e, 0x78, 0x6d, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x3c, 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x78,
|
||||
0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x3d, 0x22, 0x61, 0x64, 0x6f, 0x62,
|
||||
0x65, 0x3a, 0x6e, 0x73, 0x3a, 0x6d, 0x65, 0x74, 0x61, 0x2f, 0x22, 0x20,
|
||||
0x78, 0x3a, 0x78, 0x6d, 0x70, 0x74, 0x6b, 0x3d, 0x22, 0x58, 0x4d, 0x50,
|
||||
0x20, 0x43, 0x6f, 0x72, 0x65, 0x20, 0x35, 0x2e, 0x34, 0x2e, 0x30, 0x22,
|
||||
0x3e, 0x0a, 0x20, 0x20, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44,
|
||||
0x46, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x72, 0x64, 0x66, 0x3d,
|
||||
0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e,
|
||||
0x77, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x31, 0x39, 0x39, 0x39, 0x2f,
|
||||
0x30, 0x32, 0x2f, 0x32, 0x32, 0x2d, 0x72, 0x64, 0x66, 0x2d, 0x73, 0x79,
|
||||
0x6e, 0x74, 0x61, 0x78, 0x2d, 0x6e, 0x73, 0x23, 0x22, 0x3e, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65,
|
||||
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x64,
|
||||
0x66, 0x3a, 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x22, 0x22, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x78,
|
||||
0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x74, 0x69, 0x66, 0x66, 0x3d, 0x22, 0x68,
|
||||
0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f,
|
||||
0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x69, 0x66, 0x66, 0x2f,
|
||||
0x31, 0x2e, 0x30, 0x2f, 0x22, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x43, 0x6f,
|
||||
0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x3e, 0x31, 0x3c,
|
||||
0x2f, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65,
|
||||
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x4f, 0x72,
|
||||
0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x31, 0x3c,
|
||||
0x2f, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74,
|
||||
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x3c, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x50, 0x68,
|
||||
0x6f, 0x74, 0x6f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x49, 0x6e, 0x74,
|
||||
0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e,
|
||||
0x32, 0x3c, 0x2f, 0x74, 0x69, 0x66, 0x66, 0x3a, 0x50, 0x68, 0x6f, 0x74,
|
||||
0x6f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x49, 0x6e, 0x74, 0x65, 0x72,
|
||||
0x70, 0x72, 0x65, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a, 0x20,
|
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44,
|
||||
0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x0a,
|
||||
0x20, 0x20, 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x52, 0x44, 0x46,
|
||||
0x3e, 0x0a, 0x3c, 0x2f, 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x6d, 0x65, 0x74,
|
||||
0x61, 0x3e, 0x0a, 0x02, 0xd8, 0x80, 0x05, 0x00, 0x00, 0x04, 0xdc, 0x49,
|
||||
0x44, 0x41, 0x54, 0x38, 0x11, 0x1d, 0x94, 0x49, 0x6c, 0x1b, 0x65, 0x18,
|
||||
0x86, 0x9f, 0x99, 0xf9, 0x67, 0xc6, 0x6b, 0xbc, 0x26, 0xce, 0xda, 0xa4,
|
||||
0x25, 0x69, 0x0b, 0x2d, 0x28, 0x34, 0x2c, 0x95, 0x00, 0x89, 0x45, 0x08,
|
||||
0x5a, 0x95, 0x03, 0x08, 0x09, 0x21, 0xe0, 0x80, 0x38, 0xc3, 0x85, 0x03,
|
||||
0xe2, 0x00, 0x47, 0xc4, 0x1d, 0x38, 0x70, 0xe3, 0xc6, 0x01, 0x01, 0x42,
|
||||
0x20, 0x54, 0x7a, 0x2a, 0x6b, 0x0b, 0x94, 0xd2, 0xd2, 0x25, 0x69, 0x9b,
|
||||
0xa4, 0x0d, 0x2d, 0xa9, 0xb3, 0x78, 0x89, 0x9d, 0xf1, 0x2c, 0x9e, 0x85,
|
||||
0x2f, 0xb5, 0x35, 0xb6, 0x35, 0x96, 0xde, 0x79, 0xdf, 0xef, 0x7f, 0x9f,
|
||||
0x4f, 0xfb, 0xe0, 0xad, 0x37, 0x12, 0xfd, 0xf0, 0xb3, 0x9c, 0xfb, 0xb7,
|
||||
0xc5, 0x8d, 0x46, 0x9b, 0x71, 0x5b, 0xf1, 0xd0, 0xf4, 0x18, 0xdb, 0xeb,
|
||||
0x4b, 0x1c, 0xff, 0xf1, 0x57, 0x98, 0xdc, 0x87, 0x72, 0x3a, 0x8c, 0x3a,
|
||||
0xcb, 0x8c, 0xea, 0x31, 0x35, 0xb7, 0xc3, 0x99, 0xba, 0xc3, 0xd7, 0xab,
|
||||
0x3e, 0x87, 0x2a, 0x8a, 0xb3, 0xff, 0xdc, 0xe0, 0x9b, 0x8f, 0x5f, 0xa2,
|
||||
0x1c, 0xc5, 0xfc, 0x72, 0xc9, 0x41, 0x99, 0x71, 0x48, 0xca, 0x84, 0x3c,
|
||||
0x3e, 0xda, 0xd2, 0x05, 0x9a, 0xb1, 0xc7, 0x35, 0x67, 0x1c, 0xdd, 0x4c,
|
||||
0x68, 0xeb, 0x26, 0xd9, 0x30, 0x26, 0x09, 0x23, 0x5c, 0x3f, 0xc2, 0xd3,
|
||||
0x43, 0xc2, 0x24, 0x21, 0x4e, 0x34, 0x40, 0x27, 0x89, 0x13, 0xf9, 0x1e,
|
||||
0x22, 0x6e, 0xd5, 0x45, 0x43, 0x63, 0xc6, 0xd2, 0x50, 0xa9, 0xc4, 0x67,
|
||||
0x24, 0x15, 0x72, 0xa9, 0x7e, 0x95, 0xfa, 0x4f, 0x27, 0x78, 0x64, 0x76,
|
||||
0x86, 0x23, 0x61, 0xc0, 0xf0, 0x58, 0x15, 0xc3, 0x29, 0x71, 0x06, 0x45,
|
||||
0x2e, 0xa5, 0x48, 0xbb, 0x0a, 0x3d, 0x89, 0xa0, 0x8f, 0x08, 0x8a, 0x8e,
|
||||
0x08, 0xbb, 0xc1, 0x8e, 0xb0, 0x8d, 0xdd, 0x0f, 0xc9, 0x84, 0x06, 0x65,
|
||||
0x34, 0xf4, 0xed, 0x8d, 0xff, 0x58, 0xbd, 0xfc, 0x27, 0x17, 0x2f, 0x9e,
|
||||
0xe3, 0xf0, 0x81, 0x49, 0x5e, 0xde, 0x5f, 0xe1, 0x9e, 0x82, 0xcd, 0xdc,
|
||||
0x78, 0x8d, 0xd9, 0xb2, 0xc9, 0x56, 0x12, 0x32, 0x94, 0x4f, 0x91, 0xcb,
|
||||
0x88, 0x68, 0xda, 0x42, 0x13, 0x77, 0x11, 0xa2, 0xa8, 0xc3, 0x5a, 0x5f,
|
||||
0x46, 0x30, 0x65, 0x52, 0x29, 0xe4, 0x24, 0x4d, 0x8e, 0xcc, 0x68, 0x19,
|
||||
0xe5, 0x76, 0xbb, 0xac, 0x5c, 0x98, 0xa7, 0xb3, 0xed, 0xd0, 0x37, 0x62,
|
||||
0xa2, 0xb0, 0xc7, 0x89, 0xe5, 0x2e, 0x03, 0x0d, 0x97, 0x95, 0x46, 0x8f,
|
||||
0x31, 0xd7, 0xa6, 0x63, 0x81, 0x65, 0x25, 0x84, 0xba, 0x45, 0x5f, 0x65,
|
||||
0x31, 0x2c, 0x71, 0x6b, 0x77, 0x69, 0xf5, 0x7a, 0xbc, 0xb0, 0x3b, 0xcd,
|
||||
0xf9, 0xa5, 0x90, 0xd1, 0xb0, 0xcd, 0xd4, 0xb0, 0xdc, 0xd7, 0xc4, 0xfa,
|
||||
0xf0, 0x78, 0x95, 0x7b, 0x27, 0xab, 0x5c, 0x5e, 0x6e, 0xd2, 0xee, 0x05,
|
||||
0xdc, 0xd8, 0xea, 0xf1, 0xf7, 0xe2, 0x1a, 0xc7, 0xee, 0x1a, 0x62, 0x2e,
|
||||
0x1f, 0xe3, 0xe8, 0xb6, 0xc4, 0x4c, 0xd3, 0x6d, 0x6e, 0xd0, 0x6b, 0xfc,
|
||||
0x4c, 0xe3, 0xd4, 0x1f, 0xc4, 0x4b, 0xf3, 0x1c, 0x2c, 0x65, 0x29, 0x67,
|
||||
0x4d, 0xbe, 0xfb, 0xad, 0x45, 0x65, 0x0c, 0xea, 0x7e, 0x1f, 0x15, 0x6b,
|
||||
0x09, 0x0b, 0x8b, 0xb7, 0x19, 0xc9, 0xa5, 0x78, 0x75, 0x6e, 0x18, 0xdf,
|
||||
0xf5, 0x79, 0x72, 0xd0, 0xa2, 0x2d, 0xb3, 0x3a, 0xbb, 0xb4, 0x41, 0x3e,
|
||||
0x53, 0xe6, 0xf4, 0xca, 0x3c, 0xa5, 0x7c, 0x86, 0xe9, 0xfd, 0x47, 0x18,
|
||||
0x2e, 0xbd, 0xce, 0xd1, 0x97, 0x26, 0x78, 0xbc, 0x7e, 0x1d, 0xff, 0xcc,
|
||||
0xa7, 0x5c, 0x71, 0x74, 0x16, 0xe3, 0x18, 0xd7, 0x1e, 0x23, 0xe8, 0xac,
|
||||
0xa3, 0x0c, 0xcd, 0x60, 0x22, 0x6f, 0x43, 0x36, 0x43, 0x3b, 0x19, 0xc6,
|
||||
0x08, 0x7a, 0xe0, 0x6c, 0xe3, 0x27, 0x8a, 0xdb, 0x4e, 0xc0, 0xd4, 0xa0,
|
||||
0xcd, 0x27, 0xaf, 0xbd, 0xcb, 0x86, 0x36, 0xc6, 0xcc, 0xfe, 0x59, 0xd2,
|
||||
0xca, 0x90, 0x93, 0x36, 0x70, 0xaf, 0x9c, 0xe4, 0xcb, 0x6f, 0x65, 0x54,
|
||||
0xd9, 0x47, 0x59, 0x70, 0xbb, 0x74, 0x1b, 0x0e, 0x89, 0xe7, 0xa3, 0xc7,
|
||||
0x12, 0x39, 0x63, 0xea, 0x68, 0x12, 0x6b, 0x53, 0x5c, 0x9e, 0xef, 0x76,
|
||||
0xf0, 0x55, 0x86, 0x0d, 0x17, 0x56, 0x9a, 0x4d, 0x94, 0x95, 0x65, 0xe6,
|
||||
0xbe, 0x67, 0x98, 0xbe, 0xfb, 0x21, 0x52, 0xd2, 0x43, 0xaf, 0x5d, 0x47,
|
||||
0x6b, 0x5c, 0xa3, 0x59, 0xbf, 0xc2, 0x62, 0xdd, 0x26, 0xa5, 0x12, 0x6a,
|
||||
0x41, 0x44, 0xdf, 0xbd, 0xcd, 0x92, 0x17, 0xa0, 0xb6, 0x03, 0x43, 0xba,
|
||||
0x66, 0x91, 0xe9, 0xdc, 0xc2, 0xce, 0xed, 0xa1, 0xfc, 0xc0, 0x2b, 0x14,
|
||||
0xff, 0xfd, 0x1e, 0x4b, 0xb3, 0xa9, 0x29, 0x87, 0x81, 0xd2, 0x04, 0x8e,
|
||||
0x66, 0x89, 0x58, 0x00, 0x7e, 0x07, 0xaf, 0xdb, 0xa4, 0xbb, 0xb5, 0x49,
|
||||
0xb9, 0xaa, 0x18, 0xb9, 0x77, 0x8e, 0xcd, 0xdb, 0x6d, 0x1e, 0x1c, 0xb5,
|
||||
0x38, 0x7d, 0xa5, 0xcf, 0xaa, 0x08, 0xeb, 0x77, 0x3f, 0x35, 0xc7, 0xda,
|
||||
0xfc, 0x02, 0xaa, 0xf6, 0x1c, 0xbb, 0x9f, 0x78, 0x9f, 0x89, 0x43, 0x47,
|
||||
0xa4, 0x6f, 0x3d, 0x06, 0xed, 0x90, 0x92, 0x79, 0x95, 0xd4, 0xe4, 0xfd,
|
||||
0x98, 0x66, 0x4a, 0x6a, 0xd7, 0xc7, 0x0b, 0x62, 0xa4, 0xe3, 0x8c, 0x4d,
|
||||
0xc4, 0xe8, 0x85, 0x98, 0xe5, 0x46, 0x44, 0x26, 0x97, 0x21, 0xe9, 0xf7,
|
||||
0xf9, 0x61, 0xc5, 0xe3, 0xd4, 0x66, 0x84, 0xd2, 0x70, 0xc9, 0xee, 0x79,
|
||||
0x98, 0x43, 0xc7, 0x5e, 0x27, 0xb6, 0x8a, 0xd2, 0x5a, 0x1f, 0xf3, 0xa9,
|
||||
0xf7, 0x88, 0xce, 0x7d, 0x85, 0x71, 0xe0, 0x79, 0x98, 0x7a, 0x90, 0x9e,
|
||||
0x1b, 0xd0, 0x13, 0x52, 0x4a, 0x66, 0x97, 0x7d, 0x33, 0x1e, 0xed, 0xae,
|
||||
0xc7, 0x87, 0x1f, 0x7d, 0xce, 0xc2, 0xd5, 0x3a, 0xe6, 0xde, 0x02, 0xcb,
|
||||
0xdb, 0x3e, 0xbe, 0xa6, 0x91, 0x95, 0x62, 0x6b, 0x2f, 0xce, 0x90, 0x3c,
|
||||
0xfd, 0xce, 0x71, 0x0e, 0xcc, 0x3e, 0x82, 0x13, 0xf4, 0x09, 0xd5, 0x00,
|
||||
0x16, 0x82, 0x98, 0xb3, 0x49, 0x24, 0xb1, 0x83, 0xc8, 0xc0, 0xd6, 0x3a,
|
||||
0x54, 0x33, 0xab, 0x14, 0x8c, 0x16, 0x4e, 0x38, 0xcc, 0xe5, 0xeb, 0x4d,
|
||||
0x5e, 0x7b, 0xfb, 0x4d, 0xaa, 0x79, 0xa1, 0x45, 0x1c, 0x9b, 0xd2, 0x94,
|
||||
0xcc, 0x0e, 0x8c, 0x52, 0x7a, 0x65, 0x17, 0xc7, 0xa9, 0x0c, 0x8e, 0xe2,
|
||||
0xf7, 0xba, 0xa8, 0xc8, 0x13, 0x87, 0x32, 0x87, 0x0b, 0x27, 0x30, 0x36,
|
||||
0x57, 0xe8, 0xea, 0x15, 0xce, 0x06, 0x65, 0x5e, 0x3d, 0x5a, 0x94, 0x53,
|
||||
0xb7, 0x59, 0x58, 0xdf, 0x25, 0xc4, 0xe4, 0xc9, 0x65, 0x3d, 0xb4, 0xb4,
|
||||
0x4e, 0x37, 0x0c, 0x29, 0x98, 0x4a, 0xe8, 0x11, 0xde, 0x85, 0x42, 0x43,
|
||||
0x1c, 0xaa, 0x38, 0x55, 0xc4, 0xb4, 0x2c, 0x22, 0x3d, 0xcd, 0xfa, 0xea,
|
||||
0x0d, 0xf4, 0x8d, 0x1f, 0xc9, 0x5f, 0xfa, 0x82, 0x6d, 0xc7, 0xe1, 0xa6,
|
||||
0x57, 0xe3, 0x56, 0x6e, 0x96, 0xbf, 0x16, 0x1f, 0xa3, 0x54, 0xaa, 0x91,
|
||||
0x16, 0x5a, 0xb2, 0xa9, 0x04, 0xaf, 0x67, 0xc9, 0xac, 0x6c, 0xfa, 0x32,
|
||||
0x9e, 0x48, 0xea, 0xa5, 0x0b, 0x89, 0x3b, 0x54, 0x47, 0xf2, 0xa1, 0xf2,
|
||||
0x2a, 0x4d, 0xeb, 0xf4, 0x17, 0xdc, 0xd4, 0x72, 0x6c, 0xb5, 0x36, 0x28,
|
||||
0xb6, 0x7e, 0x17, 0x04, 0xd3, 0xac, 0x7a, 0x42, 0xc1, 0xf4, 0x6e, 0x9e,
|
||||
0xbf, 0x6b, 0xb7, 0x3c, 0x3a, 0x21, 0x67, 0xcb, 0x41, 0x48, 0x07, 0x91,
|
||||
0xde, 0x1a, 0xe2, 0xaa, 0x9c, 0xb1, 0x59, 0xdb, 0x12, 0x25, 0xc1, 0x32,
|
||||
0x92, 0xea, 0xc9, 0xaf, 0x3b, 0x97, 0xca, 0xca, 0xfe, 0x5b, 0xfe, 0xe5,
|
||||
0x33, 0x29, 0xeb, 0x16, 0x95, 0xd2, 0x24, 0xeb, 0xda, 0x30, 0xeb, 0x95,
|
||||
0x1a, 0xd3, 0xf7, 0x0f, 0x51, 0x1c, 0xd9, 0x0b, 0x99, 0x12, 0x7a, 0x4a,
|
||||
0xd0, 0xd3, 0x25, 0x9a, 0x88, 0x45, 0xb1, 0x04, 0x33, 0x2c, 0x8a, 0x99,
|
||||
0x34, 0x6b, 0x75, 0x19, 0x91, 0x9d, 0x92, 0x29, 0x89, 0xa0, 0x2c, 0x8b,
|
||||
0x9d, 0xd8, 0x7a, 0x5e, 0x04, 0x07, 0x87, 0x66, 0x28, 0x56, 0x67, 0xb9,
|
||||
0xd6, 0xd2, 0x39, 0xd9, 0xec, 0x33, 0x30, 0xb2, 0x8b, 0xea, 0xae, 0x83,
|
||||
0x18, 0xb9, 0x31, 0x34, 0xbb, 0x42, 0x22, 0x0b, 0x21, 0x96, 0x3c, 0x61,
|
||||
0xac, 0xcb, 0x95, 0x60, 0x2a, 0xe9, 0x68, 0x79, 0x08, 0x36, 0x56, 0x65,
|
||||
0x27, 0x4a, 0xd9, 0x83, 0x00, 0xcf, 0x0b, 0xf1, 0xfc, 0x10, 0x15, 0x0a,
|
||||
0x6a, 0x75, 0x77, 0x8b, 0x86, 0xdc, 0x58, 0x57, 0x45, 0x52, 0xe9, 0x84,
|
||||
0x81, 0x7c, 0x91, 0x28, 0x55, 0x23, 0x96, 0x13, 0xd7, 0x24, 0xbe, 0xac,
|
||||
0x17, 0xfa, 0xf2, 0x78, 0x63, 0xc7, 0x82, 0x08, 0xda, 0xa6, 0xc5, 0x50,
|
||||
0x55, 0x04, 0xe5, 0x65, 0x5b, 0x06, 0xde, 0xce, 0xf0, 0x24, 0xf3, 0x4e,
|
||||
0x70, 0xb5, 0x15, 0x6a, 0x34, 0x7b, 0x11, 0x9d, 0xbe, 0x10, 0x53, 0xd0,
|
||||
0xa8, 0x86, 0x2e, 0x76, 0xb6, 0x2a, 0x9d, 0x2c, 0x48, 0x3c, 0x5b, 0xa2,
|
||||
0xc8, 0x3a, 0x37, 0xd4, 0x9d, 0xed, 0x6c, 0x4a, 0xab, 0x95, 0x6e, 0x08,
|
||||
0x66, 0x3d, 0x5a, 0xad, 0x4d, 0x18, 0xc8, 0xca, 0xfa, 0xd5, 0x85, 0x6f,
|
||||
0xf9, 0x5f, 0xde, 0x02, 0x30, 0xff, 0x03, 0x8c, 0x47, 0x35, 0xad, 0xbc,
|
||||
0xbf, 0x26, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
|
||||
0x42, 0x60, 0x82
|
||||
|
||||
};
|
||||
|
||||
unsigned int _Users_username_Pictures_SaltBae_png_len = 1863;
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
// insert code here...
|
||||
int frameless = 1;
|
||||
int resizable = 0;
|
||||
int fullscreen = 0;
|
||||
int fullSizeContent = 1;
|
||||
int hideTitleBar = 0;
|
||||
int titlebarAppearsTransparent = 0;
|
||||
int hideTitle = 0;
|
||||
int useToolbar = 0;
|
||||
int hideToolbarSeparator = 0;
|
||||
int webviewIsTransparent = 1;
|
||||
int alwaysOnTop = 0;
|
||||
int hideWindowOnClose = 0;
|
||||
const char* appearance = "NSAppearanceNameDarkAqua";
|
||||
int windowIsTranslucent = 1;
|
||||
int debug = 1;
|
||||
WailsContext *result = Create("OI OI!",400,400, frameless, resizable, fullscreen, fullSizeContent, hideTitleBar, titlebarAppearsTransparent, hideTitle, useToolbar, hideToolbarSeparator, webviewIsTransparent, alwaysOnTop, hideWindowOnClose, appearance, windowIsTranslucent, debug);
|
||||
SetRGBA(result, 255, 0, 0, 255);
|
||||
void *m = NewMenu("");
|
||||
SetAbout(result, "Fake title", "I am a description", _Users_username_Pictures_SaltBae_png, _Users_username_Pictures_SaltBae_png_len);
|
||||
// AddMenuByRole(result, 1);
|
||||
|
||||
AppendRole(result, m, 1);
|
||||
AppendRole(result, m, 2);
|
||||
void* submenu = NewMenu("test");
|
||||
void* menuITem = AppendMenuItem(result, submenu, "Woohoo", "p", 0, 0, 0, 470);
|
||||
AppendSubmenu(m, submenu);
|
||||
UpdateMenuItem(menuITem, 1);
|
||||
SetAsApplicationMenu(result, m);
|
||||
SetPosition(result, 100, 100);
|
||||
|
||||
|
||||
|
||||
Run((void*)CFBridgingRetain(result));
|
||||
return 0;
|
||||
}
|
||||
@@ -1,97 +1,135 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package darwin
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -x objective-c
|
||||
#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Application.h"
|
||||
#import "WailsContext.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
"github.com/wailsapp/wails/v2/pkg/menu/keys"
|
||||
)
|
||||
|
||||
type NSMenu struct {
|
||||
context unsafe.Pointer
|
||||
nsmenu unsafe.Pointer
|
||||
}
|
||||
|
||||
func NewNSMenu(context unsafe.Pointer, name string) *NSMenu {
|
||||
c := NewCalloc()
|
||||
defer c.Free()
|
||||
title := c.String(name)
|
||||
nsmenu := C.NewMenu(title)
|
||||
return &NSMenu{
|
||||
context: context,
|
||||
nsmenu: nsmenu,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *NSMenu) AddSubMenu(label string) *NSMenu {
|
||||
result := NewNSMenu(m.context, label)
|
||||
C.AppendSubmenu(m.nsmenu, result.nsmenu)
|
||||
return result
|
||||
}
|
||||
|
||||
func (m *NSMenu) AppendRole(role menu.Role) {
|
||||
C.AppendRole(m.context, m.nsmenu, C.int(role))
|
||||
}
|
||||
|
||||
type MenuItem struct {
|
||||
id uint
|
||||
nsmenuitem unsafe.Pointer
|
||||
wailsMenuItem *menu.MenuItem
|
||||
radioGroupMembers []*MenuItem
|
||||
}
|
||||
|
||||
func (m *NSMenu) AddMenuItem(menuItem *menu.MenuItem) *MenuItem {
|
||||
c := NewCalloc()
|
||||
defer c.Free()
|
||||
var modifier C.int
|
||||
var key *C.char
|
||||
if menuItem.Accelerator != nil {
|
||||
modifier = C.int(keys.ToMacModifier(menuItem.Accelerator))
|
||||
key = c.String(menuItem.Accelerator.Key)
|
||||
}
|
||||
|
||||
result := &MenuItem{
|
||||
wailsMenuItem: menuItem,
|
||||
}
|
||||
|
||||
result.id = createMenuItemID(result)
|
||||
result.nsmenuitem = C.AppendMenuItem(m.context, m.nsmenu, c.String(menuItem.Label), key, modifier, bool2Cint(menuItem.Disabled), bool2Cint(menuItem.Checked), C.int(result.id))
|
||||
return result
|
||||
}
|
||||
|
||||
//func (w *Window) SetApplicationMenu(menu *menu.Menu) {
|
||||
//w.applicationMenu = menu
|
||||
//processMenu(w, menu)
|
||||
//}
|
||||
|
||||
//func processMenu(window *Window, menu *menu.Menu) {
|
||||
//mainMenu := window.NewMenu()
|
||||
//for _, menuItem := range menu.Items {
|
||||
// submenu := mainMenu.AddSubMenu(menuItem.Label)
|
||||
// for _, menuItem := range menuItem.SubMenu.Items {
|
||||
// processMenuItem(submenu, menuItem)
|
||||
// }
|
||||
//}
|
||||
//mainMenu.Show()
|
||||
//}
|
||||
func processMenu(parent *NSMenu, wailsMenu *menu.Menu) {
|
||||
var radioGroups []*MenuItem
|
||||
|
||||
//func processMenuItem(parent *winc.MenuItem, menuItem *menu.MenuItem) {
|
||||
// if menuItem.Hidden {
|
||||
// return
|
||||
// }
|
||||
// switch menuItem.Type {
|
||||
// case menu.SeparatorType:
|
||||
// parent.AddSeparator()
|
||||
// case menu.TextType:
|
||||
// shortcut := acceleratorToWincShortcut(menuItem.Accelerator)
|
||||
// newItem := parent.AddItem(menuItem.Label, shortcut)
|
||||
// if menuItem.Tooltip != "" {
|
||||
// newItem.SetToolTip(menuItem.Tooltip)
|
||||
// }
|
||||
// if menuItem.Click != nil {
|
||||
// newItem.OnClick().Bind(func(e *winc.Event) {
|
||||
// menuItem.Click(&menu.CallbackData{
|
||||
// MenuItem: menuItem,
|
||||
// })
|
||||
// })
|
||||
// }
|
||||
// newItem.SetEnabled(!menuItem.Disabled)
|
||||
//
|
||||
// case menu.CheckboxType:
|
||||
// shortcut := acceleratorToWincShortcut(menuItem.Accelerator)
|
||||
// newItem := parent.AddItem(menuItem.Label, shortcut)
|
||||
// newItem.SetCheckable(true)
|
||||
// newItem.SetChecked(menuItem.Checked)
|
||||
// if menuItem.Tooltip != "" {
|
||||
// newItem.SetToolTip(menuItem.Tooltip)
|
||||
// }
|
||||
// if menuItem.Click != nil {
|
||||
// newItem.OnClick().Bind(func(e *winc.Event) {
|
||||
// toggleCheckBox(menuItem)
|
||||
// menuItem.Click(&menu.CallbackData{
|
||||
// MenuItem: menuItem,
|
||||
// })
|
||||
// })
|
||||
// }
|
||||
// newItem.SetEnabled(!menuItem.Disabled)
|
||||
// addCheckBoxToMap(menuItem, newItem)
|
||||
// case menu.RadioType:
|
||||
// shortcut := acceleratorToWincShortcut(menuItem.Accelerator)
|
||||
// newItem := parent.AddItemRadio(menuItem.Label, shortcut)
|
||||
// newItem.SetCheckable(true)
|
||||
// newItem.SetChecked(menuItem.Checked)
|
||||
// if menuItem.Tooltip != "" {
|
||||
// newItem.SetToolTip(menuItem.Tooltip)
|
||||
// }
|
||||
// if menuItem.Click != nil {
|
||||
// newItem.OnClick().Bind(func(e *winc.Event) {
|
||||
// toggleRadioItem(menuItem)
|
||||
// menuItem.Click(&menu.CallbackData{
|
||||
// MenuItem: menuItem,
|
||||
// })
|
||||
// })
|
||||
// }
|
||||
// newItem.SetEnabled(!menuItem.Disabled)
|
||||
// addRadioItemToMap(menuItem, newItem)
|
||||
// case menu.SubmenuType:
|
||||
// submenu := parent.AddSubMenu(menuItem.Label)
|
||||
// for _, menuItem := range menuItem.SubMenu.Items {
|
||||
// processMenuItem(submenu, menuItem)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
for _, menuItem := range wailsMenu.Items {
|
||||
if menuItem.SubMenu != nil {
|
||||
if len(radioGroups) > 0 {
|
||||
processRadioGroups(radioGroups)
|
||||
radioGroups = []*MenuItem{}
|
||||
}
|
||||
submenu := parent.AddSubMenu(menuItem.Label)
|
||||
processMenu(submenu, menuItem.SubMenu)
|
||||
} else {
|
||||
lastMenuItem := processMenuItem(parent, menuItem)
|
||||
if menuItem.Type == menu.RadioType {
|
||||
radioGroups = append(radioGroups, lastMenuItem)
|
||||
} else {
|
||||
if len(radioGroups) > 0 {
|
||||
processRadioGroups(radioGroups)
|
||||
radioGroups = []*MenuItem{}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func processRadioGroups(groups []*MenuItem) {
|
||||
for _, item := range groups {
|
||||
item.radioGroupMembers = groups
|
||||
}
|
||||
}
|
||||
|
||||
func processMenuItem(parent *NSMenu, menuItem *menu.MenuItem) *MenuItem {
|
||||
if menuItem.Hidden {
|
||||
return nil
|
||||
}
|
||||
if menuItem.Role != 0 {
|
||||
parent.AppendRole(menuItem.Role)
|
||||
return nil
|
||||
}
|
||||
if menuItem.Type == menu.SeparatorType {
|
||||
C.AppendSeparator(parent.nsmenu)
|
||||
return nil
|
||||
}
|
||||
|
||||
return parent.AddMenuItem(menuItem)
|
||||
|
||||
}
|
||||
|
||||
func (f *Frontend) MenuSetApplicationMenu(menu *menu.Menu) {
|
||||
//f.mainWindow.SetApplicationMenu(menu)
|
||||
f.mainWindow.SetApplicationMenu(menu)
|
||||
}
|
||||
|
||||
func (f *Frontend) MenuUpdateApplicationMenu() {
|
||||
//processMenu(f.mainWindow, f.mainWindow.applicationMenu)
|
||||
f.MenuSetApplicationMenu(f.frontendOptions.Menu)
|
||||
f.mainWindow.UpdateApplicationMenu()
|
||||
}
|
||||
|
||||
51
v2/internal/frontend/desktop/darwin/menuitem.go
Normal file
51
v2/internal/frontend/desktop/darwin/menuitem.go
Normal file
@@ -0,0 +1,51 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package darwin
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -x objective-c
|
||||
#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Application.h"
|
||||
#import "WailsContext.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"log"
|
||||
"math"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var menuItemToID = make(map[*MenuItem]uint)
|
||||
var idToMenuItem = make(map[uint]*MenuItem)
|
||||
var menuItemLock sync.Mutex
|
||||
var menuItemIDCounter uint = 0
|
||||
|
||||
func createMenuItemID(item *MenuItem) uint {
|
||||
menuItemLock.Lock()
|
||||
defer menuItemLock.Unlock()
|
||||
counter := 0
|
||||
for {
|
||||
menuItemIDCounter++
|
||||
value := idToMenuItem[menuItemIDCounter]
|
||||
if value == nil {
|
||||
break
|
||||
}
|
||||
counter++
|
||||
if counter == math.MaxInt {
|
||||
log.Fatal("insane amounts of menuitems detected! Aborting before the collapse of the world!")
|
||||
}
|
||||
}
|
||||
idToMenuItem[menuItemIDCounter] = item
|
||||
menuItemToID[item] = menuItemIDCounter
|
||||
return menuItemIDCounter
|
||||
}
|
||||
|
||||
func getMenuItemForID(id uint) *MenuItem {
|
||||
menuItemLock.Lock()
|
||||
defer menuItemLock.Unlock()
|
||||
return idToMenuItem[id]
|
||||
}
|
||||
29
v2/internal/frontend/desktop/darwin/message.h
Normal file
29
v2/internal/frontend/desktop/darwin/message.h
Normal file
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// message.h
|
||||
// test
|
||||
//
|
||||
// Created by Lea Anthony on 14/10/21.
|
||||
//
|
||||
|
||||
#ifndef export_h
|
||||
#define export_h
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void processMessage(const char *);
|
||||
void processURLRequest(void*, const char *);
|
||||
void processMessageDialogResponse(int);
|
||||
void processOpenFileDialogResponse(const char*);
|
||||
void processSaveFileDialogResponse(const char*);
|
||||
void processCallback(int);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* export_h */
|
||||
226
v2/internal/frontend/desktop/darwin/window.go
Normal file
226
v2/internal/frontend/desktop/darwin/window.go
Normal file
@@ -0,0 +1,226 @@
|
||||
package darwin
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -x objective-c
|
||||
#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Application.h"
|
||||
#import "WailsContext.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"log"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/options"
|
||||
)
|
||||
|
||||
func init() {
|
||||
runtime.LockOSThread()
|
||||
}
|
||||
|
||||
type Window struct {
|
||||
context unsafe.Pointer
|
||||
}
|
||||
|
||||
func bool2Cint(value bool) C.int {
|
||||
if value {
|
||||
return C.int(1)
|
||||
}
|
||||
return C.int(0)
|
||||
}
|
||||
|
||||
func NewWindow(frontendOptions *options.App, debugMode bool) *Window {
|
||||
|
||||
c := NewCalloc()
|
||||
defer c.Free()
|
||||
|
||||
frameless := bool2Cint(frontendOptions.Frameless)
|
||||
resizable := bool2Cint(!frontendOptions.DisableResize)
|
||||
fullscreen := bool2Cint(frontendOptions.Fullscreen)
|
||||
alwaysOnTop := bool2Cint(frontendOptions.AlwaysOnTop)
|
||||
hideWindowOnClose := bool2Cint(frontendOptions.HideWindowOnClose)
|
||||
debug := bool2Cint(debugMode)
|
||||
|
||||
var fullSizeContent, hideTitleBar, hideTitle, useToolbar, webviewIsTransparent C.int
|
||||
var titlebarAppearsTransparent, hideToolbarSeparator, windowIsTranslucent C.int
|
||||
var appearance, title *C.char
|
||||
|
||||
width := C.int(frontendOptions.Width)
|
||||
height := C.int(frontendOptions.Height)
|
||||
|
||||
title = c.String(frontendOptions.Title)
|
||||
|
||||
if frontendOptions.Mac != nil {
|
||||
mac := frontendOptions.Mac
|
||||
if mac.TitleBar != nil {
|
||||
fullSizeContent = bool2Cint(mac.TitleBar.FullSizeContent)
|
||||
hideTitleBar = bool2Cint(mac.TitleBar.HideTitleBar)
|
||||
hideTitle = bool2Cint(mac.TitleBar.HideTitle)
|
||||
useToolbar = bool2Cint(mac.TitleBar.UseToolbar)
|
||||
titlebarAppearsTransparent = bool2Cint(mac.TitleBar.TitlebarAppearsTransparent)
|
||||
hideToolbarSeparator = bool2Cint(mac.TitleBar.HideToolbarSeparator)
|
||||
}
|
||||
windowIsTranslucent = bool2Cint(mac.WindowIsTranslucent)
|
||||
webviewIsTransparent = bool2Cint(mac.WebviewIsTransparent)
|
||||
|
||||
appearance = c.String(string(mac.Appearance))
|
||||
}
|
||||
var context *C.WailsContext = C.Create(title, width, height, frameless, resizable, fullscreen, fullSizeContent,
|
||||
hideTitleBar, titlebarAppearsTransparent, hideTitle, useToolbar, hideToolbarSeparator, webviewIsTransparent,
|
||||
alwaysOnTop, hideWindowOnClose, appearance, windowIsTranslucent, debug)
|
||||
|
||||
// Create menu
|
||||
result := &Window{
|
||||
context: unsafe.Pointer(context),
|
||||
}
|
||||
|
||||
if frontendOptions.RGBA != nil {
|
||||
result.SetRGBA(frontendOptions.RGBA.R, frontendOptions.RGBA.G, frontendOptions.RGBA.B, frontendOptions.RGBA.A)
|
||||
}
|
||||
|
||||
if frontendOptions.Mac != nil && frontendOptions.Mac.About != nil {
|
||||
title := c.String(frontendOptions.Mac.About.Title)
|
||||
description := c.String(frontendOptions.Mac.About.Message)
|
||||
var icon unsafe.Pointer
|
||||
var length C.int
|
||||
if frontendOptions.Mac.About.Icon != nil {
|
||||
icon = unsafe.Pointer(&frontendOptions.Mac.About.Icon[0])
|
||||
length = C.int(len(frontendOptions.Mac.About.Icon))
|
||||
}
|
||||
C.SetAbout(result.context, title, description, icon, length)
|
||||
}
|
||||
|
||||
if frontendOptions.Menu != nil {
|
||||
result.SetApplicationMenu(frontendOptions.Menu)
|
||||
}
|
||||
|
||||
result.SetMinSize(frontendOptions.MinWidth, frontendOptions.MinHeight)
|
||||
result.SetMaxSize(frontendOptions.MaxWidth, frontendOptions.MaxHeight)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (w *Window) Center() {
|
||||
C.Center(w.context)
|
||||
}
|
||||
|
||||
func (w *Window) Run() {
|
||||
C.Run(w.context)
|
||||
}
|
||||
|
||||
func (w *Window) Quit() {
|
||||
C.Quit(w.context)
|
||||
}
|
||||
|
||||
func (w *Window) SetRGBA(r uint8, g uint8, b uint8, a uint8) {
|
||||
C.SetRGBA(w.context, C.int(r), C.int(g), C.int(b), C.int(a))
|
||||
}
|
||||
|
||||
func (w *Window) ExecJS(js string) {
|
||||
_js := C.CString(js)
|
||||
C.ExecJS(w.context, _js)
|
||||
C.free(unsafe.Pointer(_js))
|
||||
}
|
||||
|
||||
func (w *Window) SetPos(x int, y int) {
|
||||
C.SetPosition(w.context, C.int(x), C.int(y))
|
||||
}
|
||||
|
||||
func (w *Window) SetSize(width int, height int) {
|
||||
C.SetSize(w.context, C.int(width), C.int(height))
|
||||
}
|
||||
|
||||
func (w *Window) SetTitle(title string) {
|
||||
t := C.CString(title)
|
||||
C.SetTitle(w.context, t)
|
||||
C.free(unsafe.Pointer(t))
|
||||
}
|
||||
|
||||
func (w *Window) Maximise() {
|
||||
C.Maximise(w.context)
|
||||
}
|
||||
|
||||
func (w *Window) UnMaximise() {
|
||||
C.UnMaximise(w.context)
|
||||
}
|
||||
|
||||
func (w *Window) Minimise() {
|
||||
C.Minimise(w.context)
|
||||
}
|
||||
|
||||
func (w *Window) UnMinimise() {
|
||||
C.UnMinimise(w.context)
|
||||
}
|
||||
|
||||
func (w *Window) SetMinSize(width int, height int) {
|
||||
if width == 0 && height == 0 {
|
||||
return
|
||||
}
|
||||
C.SetMinSize(w.context, C.int(width), C.int(height))
|
||||
}
|
||||
|
||||
func (w *Window) SetMaxSize(width int, height int) {
|
||||
if width == 0 && height == 0 {
|
||||
return
|
||||
}
|
||||
C.SetMaxSize(w.context, C.int(width), C.int(height))
|
||||
}
|
||||
|
||||
func (w *Window) Fullscreen() {
|
||||
C.Fullscreen(w.context)
|
||||
}
|
||||
|
||||
func (w *Window) UnFullscreen() {
|
||||
C.UnFullscreen(w.context)
|
||||
}
|
||||
|
||||
func (w *Window) Show() {
|
||||
C.Show(w.context)
|
||||
}
|
||||
|
||||
func (w *Window) Hide() {
|
||||
C.Hide(w.context)
|
||||
}
|
||||
|
||||
func parseIntDuo(temp string) (int, int) {
|
||||
split := strings.Split(temp, ",")
|
||||
x, err := strconv.Atoi(split[0])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
y, err := strconv.Atoi(split[1])
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return x, y
|
||||
}
|
||||
|
||||
func (w *Window) Pos() (int, int) {
|
||||
var _result *C.char = C.GetPos(w.context)
|
||||
temp := C.GoString(_result)
|
||||
return parseIntDuo(temp)
|
||||
}
|
||||
|
||||
func (w *Window) Size() (int, int) {
|
||||
var _result *C.char = C.GetSize(w.context)
|
||||
temp := C.GoString(_result)
|
||||
return parseIntDuo(temp)
|
||||
}
|
||||
|
||||
func (w *Window) SetApplicationMenu(inMenu *menu.Menu) {
|
||||
mainMenu := NewNSMenu(w.context, "")
|
||||
processMenu(mainMenu, inMenu)
|
||||
C.SetAsApplicationMenu(w.context, mainMenu.nsmenu)
|
||||
}
|
||||
|
||||
func (w *Window) UpdateApplicationMenu() {
|
||||
C.UpdateApplicationMenu(w.context)
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package windows
|
||||
|
||||
import (
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
package windows
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"github.com/leaanthony/go-common-file-dialog/cfd"
|
||||
"github.com/wailsapp/wails/v2/internal/frontend"
|
||||
|
||||
@@ -11,8 +11,7 @@ import (
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
"text/template"
|
||||
|
||||
"github.com/leaanthony/go-webview2/pkg/edge"
|
||||
"github.com/leaanthony/winc"
|
||||
@@ -35,7 +34,8 @@ type Frontend struct {
|
||||
debug bool
|
||||
|
||||
// Assets
|
||||
assets *assetserver.DesktopAssetServer
|
||||
assets *assetserver.DesktopAssetServer
|
||||
startURL string
|
||||
|
||||
// main window handle
|
||||
mainWindow *Window
|
||||
@@ -57,21 +57,33 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.
|
||||
minWidth: appoptions.MinWidth,
|
||||
maxHeight: appoptions.MaxHeight,
|
||||
maxWidth: appoptions.MaxWidth,
|
||||
}
|
||||
|
||||
// Check if we have been given a directory to serve assets from.
|
||||
// If so, this means we are in dev mode and are serving assets off disk.
|
||||
// We indicate this through the `servingFromDisk` flag to ensure requests
|
||||
// aren't cached by WebView2 in dev mode
|
||||
_assetdir := ctx.Value("assetdir")
|
||||
if _assetdir != nil {
|
||||
result.servingFromDisk = true
|
||||
startURL: "file://wails/",
|
||||
}
|
||||
|
||||
bindingsJSON, err := appBindings.ToJSON()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
_devServerURL := ctx.Value("devserverurl")
|
||||
if _devServerURL != nil {
|
||||
devServerURL := _devServerURL.(string)
|
||||
if len(devServerURL) > 0 && devServerURL != "http://localhost:34115" {
|
||||
result.startURL = devServerURL
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we have been given a directory to serve assets from.
|
||||
// If so, this means we are in dev mode and are serving assets off disk.
|
||||
// We indicate this through the `servingFromDisk` flag to ensure requests
|
||||
// aren't cached by WebView2 in dev mode
|
||||
|
||||
_assetdir := ctx.Value("assetdir")
|
||||
if _assetdir != nil {
|
||||
result.servingFromDisk = true
|
||||
}
|
||||
|
||||
assets, err := assetserver.NewDesktopAssetServer(ctx, appoptions.Assets, bindingsJSON)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@@ -123,6 +135,7 @@ func (f *Frontend) Run(ctx context.Context) error {
|
||||
}
|
||||
|
||||
mainWindow.Run()
|
||||
mainWindow.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -245,35 +258,15 @@ func (f *Frontend) Quit() {
|
||||
winc.Exit()
|
||||
}
|
||||
|
||||
const (
|
||||
ctrlZ int = 90
|
||||
ctrlX = 88
|
||||
ctrlC = 67
|
||||
ctrlV = 86
|
||||
ctrlA = 65
|
||||
arrowUp = 38
|
||||
arrowDown = 40
|
||||
arrowRight = 39
|
||||
arrowLeft = 37
|
||||
keyDel = 46
|
||||
)
|
||||
|
||||
func (f *Frontend) setupChromium() {
|
||||
chromium := edge.NewChromium()
|
||||
f.chromium = chromium
|
||||
chromium.MessageCallback = f.processMessage
|
||||
chromium.WebResourceRequestedCallback = f.processRequest
|
||||
chromium.NavigationCompletedCallback = f.navigationCompleted
|
||||
acceleratorsWebviewShouldProcess := slicer.Int([]int{ctrlV, ctrlC, ctrlX, ctrlZ, ctrlA, arrowLeft, arrowRight, arrowUp, arrowDown, keyDel})
|
||||
|
||||
chromium.AcceleratorKeyCallback = func(vkey uint) bool {
|
||||
// We want webview to handle ctrl-C, ctrl-Z, ctrl-v, ctrl-x
|
||||
if acceleratorsWebviewShouldProcess.Contains(int(vkey)) {
|
||||
return false
|
||||
}
|
||||
// Post keypress
|
||||
w32.PostMessage(f.mainWindow.Handle(), w32.WM_KEYDOWN, uintptr(vkey), 0)
|
||||
return true
|
||||
return false
|
||||
}
|
||||
chromium.Embed(f.mainWindow.Handle())
|
||||
chromium.Resize()
|
||||
@@ -297,7 +290,11 @@ func (f *Frontend) setupChromium() {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = settings.PutIsStatusBarEnabled(false)
|
||||
err = settings.PutAreBrowserAcceleratorKeysEnabled(false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
err = settings.PutIsSwipeNavigationEnabled(false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -305,8 +302,9 @@ func (f *Frontend) setupChromium() {
|
||||
// Set background colour
|
||||
f.WindowSetRGBA(f.frontendOptions.RGBA)
|
||||
|
||||
chromium.SetGlobalPermission(edge.CoreWebView2PermissionStateAllow)
|
||||
chromium.AddWebResourceRequestedFilter("*", edge.COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL)
|
||||
chromium.Navigate("file://wails/")
|
||||
chromium.Navigate(f.startURL)
|
||||
}
|
||||
|
||||
type EventNotify struct {
|
||||
@@ -324,7 +322,7 @@ func (f *Frontend) Notify(name string, data ...interface{}) {
|
||||
f.logger.Error(err.Error())
|
||||
return
|
||||
}
|
||||
f.ExecJS(`window.wails.EventsNotify('` + string(payload) + `');`)
|
||||
f.ExecJS(`window.wails.EventsNotify('` + template.JSEscapeString(string(payload)) + `');`)
|
||||
}
|
||||
|
||||
func (f *Frontend) processRequest(req *edge.ICoreWebView2WebResourceRequest, args *edge.ICoreWebView2WebResourceRequestedEventArgs) {
|
||||
|
||||
@@ -30,6 +30,9 @@ func NewWindow(parent winc.Controller, options *options.App) *Window {
|
||||
exStyle |= w32.WS_EX_NOREDIRECTIONBITMAP
|
||||
}
|
||||
}
|
||||
if options.AlwaysOnTop {
|
||||
exStyle |= w32.WS_EX_TOPMOST
|
||||
}
|
||||
|
||||
var dwStyle = w32.WS_OVERLAPPEDWINDOW
|
||||
if options.Frameless {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user