Compare commits

..

56 Commits

Author SHA1 Message Date
Lea Anthony
c64b7bb79c [v2] v2.0.0-beta.16 2021-11-08 19:15:07 +11:00
Lea Anthony
e72b438ad2 [website] Fix blog 2021-11-08 19:13:54 +11:00
Lea Anthony
3e4a112a3d Merge pull request #922 from wailsapp/v2-mac-docs
V2 Mac updates
2021-11-08 08:12:07 +00:00
Lea Anthony
a020b67f67 [website] Fix desktop icon 2021-11-08 19:10:31 +11:00
Lea Anthony
fa958e7a07 [website] assetdir clarification 2021-11-08 17:38:30 +11:00
Lea Anthony
1a3e81a3f8 [website] Misc updates 2021-11-08 17:36:08 +11:00
Lea Anthony
0eb7a8a771 [v2] Update svelte template 2021-11-08 07:00:01 +11:00
Lea Anthony
2fa004808f [website] Update options example 2021-11-08 06:31:34 +11:00
Lea Anthony
cc5fd30256 [v2] Update vanilla template 2021-11-08 06:31:13 +11:00
Lea Anthony
c90bfc310a [mac] Fix lifecycle hooks 2021-11-06 10:40:02 +11:00
Lea Anthony
62d1d621aa [mac] Tidy up 2021-11-04 20:58:08 +11:00
Lea Anthony
6e8cbb8e8f [mac] Ensure minimum osx version 2021-11-04 20:45:22 +11:00
Lea Anthony
32fa543164 [website] Update docs 2021-11-03 19:25:42 +11:00
Lea Anthony
04f93ac54e [v2] Update go.mod 2021-11-03 19:24:12 +11:00
Lea Anthony
3c87d13b21 [mac] Fix fullscreen 2021-11-03 19:23:23 +11:00
Lea Anthony
0949eab72e [linux] add flag 2021-11-03 19:22:59 +11:00
Lea Anthony
aab67b416f [mac] add default menu 2021-11-03 19:22:38 +11:00
Lea Anthony
83a575e43f [v2] warn if wails version out of sync during build 2021-11-02 22:33:34 +11:00
Lea Anthony
333949ee53 [mac] better output text on build 2021-11-02 22:20:44 +11:00
Lea Anthony
1d1238cea3 [website] add cross compile 2021-11-02 22:19:59 +11:00
Lea Anthony
bd7b436631 [mac] Add fallback for app name 2021-11-02 22:05:42 +11:00
Lea Anthony
c136df48b9 [mac] Fix App Name in app menu 2021-11-02 22:04:06 +11:00
Lea Anthony
a090a689cf [mac] Fix plist generation 2021-11-02 21:56:35 +11:00
Lea Anthony
5ef2448a0c [website] updates 2021-11-02 21:00:56 +11:00
Lea Anthony
06ab4c88ad [website] updates 2021-11-02 20:54:42 +11:00
Lea Anthony
48efdea11a [website] updates 2021-11-02 20:54:13 +11:00
Lea Anthony
43cc55cb0a [mac] Small tweaks 2021-11-02 20:06:59 +11:00
Lea Anthony
71f2436562 [website] Add Mac options 2021-11-02 08:31:21 +11:00
Lea Anthony
4653c77a81 Merge branch 'master' into v2-mac-docs 2021-11-02 08:20:20 +11:00
Lea Anthony
72b05c6b44 Merge pull request #907 from phoenix147/appargs
Appargs
2021-11-02 07:23:00 +11:00
Lukas Crepaz
b5f68e24d6 added appargs for application arguments in dev mode 2021-11-01 08:57:10 +01:00
Lukas Crepaz
3948c8ca61 use environment variables to supply the development binary with flags to support CLI arguments in the app 2021-10-31 09:12:22 +01:00
Lea Anthony
cf3a868e3a [mac] Support MenuUpdateApplicationMenu 2021-10-31 15:09:50 +11:00
Lea Anthony
43c29abb23 Merge pull request #901 from misitebao/synchronize-chinese-documents
docs: synchronize chinese documents
2021-10-31 08:55:22 +11:00
Lea Anthony
7ef445f526 [mac] Improve string/memory handling, dialog icon -> []byte 2021-10-31 08:50:14 +11:00
misitebao
f6c2d4ae6b docs: synchronize all chinese documents 2021-10-31 04:32:38 +08:00
misitebao
8f9fae6ad9 docs: synchronize chinese readme logo size 2021-10-31 03:02:00 +08:00
misitebao
b45f264e2a docs: synchronize chinese readme 2021-10-31 02:55:01 +08:00
misitebao
986f8f48c7 docs: organize the readme 2021-10-31 02:54:22 +08:00
misitebao
bbc2e86286 docs: update chinese readme 2021-10-31 02:27:47 +08:00
Lea Anthony
2dc126bf19 [mac] Fix ExecJS 2021-10-30 19:28:25 +11:00
Lea Anthony
86cbcdc089 [mac] Move ops to main thread 2021-10-30 17:19:58 +11:00
Lea Anthony
1dd957f461 [mac] Fix SetPosition 2021-10-30 16:31:06 +11:00
Lea Anthony
4be4946756 [mac] Fix SetMaxSize 2021-10-30 11:07:07 +11:00
Lea Anthony
65979cbc75 Merge pull request #900 from misitebao/synchronize-chinese-documents
docs: synchronize chinese documents
2021-10-30 10:57:05 +11:00
Lea Anthony
6a7118ff6d [mac] Support cross compiling to windows 2021-10-30 10:44:22 +11:00
Lea Anthony
a88b3553ba [mac] Support min/max 2021-10-30 10:34:55 +11:00
Lea Anthony
fd5348d26d [v2] Fix build output 2021-10-30 10:33:30 +11:00
Lea Anthony
569569f1fc [mac] support amd/arm/universal 2021-10-30 10:19:49 +11:00
Lea Anthony
489b9b358b [mac] menu support 2021-10-30 09:51:46 +11:00
misitebao
71cfdfc7c8 feat: increase synchronized content 2021-10-29 03:15:42 +08:00
misitebao
6ebf4ed428 feat: synchronize some chinese documents 2021-10-29 03:15:04 +08:00
misitebao
5be0739c5d feat(website): synchronize chinese credits 2021-10-28 18:45:45 +08:00
Lea Anthony
6721e59277 [v2] Fix build command for dev mode 2021-10-28 19:24:05 +11:00
Lea Anthony
77775d85ab v1.16.8 2021-10-26 19:38:53 +11:00
Lea Anthony
6de0865c3e Merge pull request #896 from wailsapp/develop
Develop
2021-10-26 19:36:48 +11:00
92 changed files with 2614 additions and 932 deletions

105
README.md
View File

@@ -18,42 +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).
Click [here](https://wails.io) if you are interested in trying out v2 Beta for Windows.
<span id="nav-2"></span>
## 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
@@ -67,7 +82,7 @@ Click [here](https://wails.io) if you are interested in trying out v2 Beta for W
- Powerful cli tool
- Multiplatform
<span id="nav-4"></span>
<span id="nav-5"></span>
## Sponsors
@@ -142,7 +157,7 @@ This project is supported by these kind people / companies:
<img src="https://github.com/DonTomato.png?size=45" width="45"/>
</a>
<span id="nav-5"></span>
<span id="nav-6"></span>
## Installation
@@ -152,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
@@ -160,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
@@ -176,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
@@ -184,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
@@ -192,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
@@ -200,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
@@ -220,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).
@@ -345,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>

View File

@@ -1,5 +1,5 @@
<p align="center" style="text-align: center">
<img src="logo.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,13 +85,12 @@
- 强大的命令行工具
- 跨多个平台
<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>
@@ -143,7 +160,7 @@
<img src="https://github.com/DonTomato.png?size=45" width="45"/>
</a>
<span id="nav-5"></span>
<span id="nav-6"></span>
## 安装
@@ -152,7 +169,7 @@ Wails 使用 cgo 与原生渲染引擎结合,因此需要依赖一些平台的
- Go 1.16
- npm
<span id="nav-5-1"></span>
<span id="nav-6-1"></span>
### MacOS
@@ -160,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
@@ -176,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
@@ -184,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
@@ -192,7 +209,7 @@ _也成功测试了: Manjaro & ArcoLinux_
_CentOS 6, 7_
<span id="nav-5-2-4"></span>
<span id="nav-6-2-4"></span>
#### Fedora
@@ -200,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) 上面的文档.
@@ -244,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>
@@ -302,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>
@@ -311,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)
@@ -331,17 +349,11 @@ This project was mainly coded to the following albums:
<span id="nav-11"></span>
## 许可协议
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fwailsapp%2Fwails.svg?type=large)](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>

View File

@@ -1,4 +1,4 @@
package cmd
// Version - Wails version
const Version = "v1.16.7"
const Version = "v1.16.8"

View File

@@ -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" {
@@ -129,8 +133,8 @@ func AddBuildSubcommand(app *clir.Cli, w io.Writer) {
}
}
if runtime.GOOS == "darwin" && !experimental {
return fmt.Errorf("MacOS version coming soon!")
if runtime.GOOS == "linux" && !experimental {
return fmt.Errorf("Linux version coming soon!")
}
// Webview2 installer strategy (download by default)
@@ -205,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)
})
}
@@ -228,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
}

View File

@@ -16,10 +16,10 @@ import (
"syscall"
"time"
"github.com/google/shlex"
"github.com/wailsapp/wails/v2/cmd/wails/internal"
"github.com/wailsapp/wails/v2/internal/gomod"
"github.com/leaanthony/slicer"
"github.com/wailsapp/wails/v2/internal/project"
"github.com/pkg/browser"
@@ -72,6 +72,7 @@ type devFlags struct {
forceBuild bool
debounceMS int
devServerURL string
appargs string
}
// AddSubcommand adds the `dev` command for the Wails application
@@ -93,6 +94,7 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
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
@@ -111,8 +113,8 @@ func AddSubcommand(app *clir.Cli, w io.Writer) error {
}
}
if runtime.GOOS == "darwin" && !experimental {
return fmt.Errorf("MacOS version coming soon!")
if runtime.GOOS == "linux" && !experimental {
return fmt.Errorf("Linux version coming soon!")
}
cwd, err := os.Getwd()
@@ -353,6 +355,10 @@ func loadAndMergeProjectConfig(cwd string, flags *devFlags) (*project.Project, e
shouldSaveConfig = true
}
if flags.appargs == "" && projectConfig.AppArgs != "" {
flags.appargs = projectConfig.AppArgs
}
if shouldSaveConfig {
err = projectConfig.Save()
if err != nil {
@@ -463,16 +469,20 @@ func restartApp(buildOptions *build.Options, debugBinaryProcess *process.Process
debugBinaryProcess = nil
}
// parse appargs if any
args, err := shlex.Split(flags.appargs)
if err != nil {
buildOptions.Logger.Fatal("Unable to parse appargs: %s", err.Error())
}
// 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
args := slicer.StringSlicer{}
args.Add("-loglevel", flags.loglevel)
if flags.assetDir != "" {
args.Add("-assetdir", flags.assetDir)
}
if flags.devServerURL != "" {
args.Add("-devserverurl", flags.devServerURL)
}
newProcess := process.NewProcess(appBinary, args.AsSlice()...)
newProcess := process.NewProcess(appBinary, args...)
err = newProcess.Start(exitCodeChannel)
if err != nil {
// Remove binary

View File

@@ -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%;
}

View File

@@ -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 {

View File

@@ -1,5 +1,5 @@
html {
background-color: rgba(33, 37, 43, 1);
background-color: rgba(33, 37, 43, 0);
text-align: center;
color: white;
}

View File

@@ -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 {

View File

@@ -1,3 +1,3 @@
package internal
var Version = "v2.0.0-beta.15"
var Version = "v2.0.0-beta.16"

View File

@@ -13,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
@@ -60,6 +61,7 @@ require (
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

View File

@@ -75,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=
@@ -101,8 +103,9 @@ 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=
@@ -159,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=
@@ -280,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=

View File

@@ -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,19 +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")
devServerURL := flag.String("devserverurl", "", "URL of development server")
loglevel := flag.String("loglevel", "debug", "Loglevel to use - Trace, Debug, Info, Warning, Error")
flag.Parse()
if devServerURL != nil && *devServerURL != "" {
ctx = context.WithValue(ctx, "devserverurl", *devServerURL)
assetdir := os.Getenv("assetdir")
devServerURL := os.Getenv("devserverurl")
loglevel := os.Getenv("loglevel")
if devServerURL != "" {
ctx = context.WithValue(ctx, "devserverurl", devServerURL)
}
if assetdir != nil && *assetdir != "" {
ctx = context.WithValue(ctx, "assetdir", *assetdir)
if assetdir != "" {
ctx = context.WithValue(ctx, "assetdir", assetdir)
}
if loglevel != nil && *loglevel != "" {
level, err := pkglogger.StringToLogLevel(*loglevel)
if loglevel != "" {
level, err := pkglogger.StringToLogLevel(loglevel)
if err != nil {
return nil, err
}

View File

@@ -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
}

View File

@@ -9,11 +9,12 @@
#define AppDelegate_h
#import <Cocoa/Cocoa.h>
#import "WailsContext.h"
@interface AppDelegate : NSResponder <NSTouchBarProvider>
@property bool alwaysOnTop;
@property (retain) NSWindow* mainWindow;
@property (retain) WailsWindow* mainWindow;
@end

View File

@@ -25,28 +25,6 @@
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[NSApp activateIgnoringOtherApps:YES];
}
//
//- (void) CreateMenu {
// [NSApplication sharedApplication];
// menubar = [[NSMenu new] autorelease];
// id appMenuItem = [[NSMenuItem new] autorelease];
// [menubar addItem:appMenuItem];
// [NSApp setMainMenu:menubar];
// id appMenu = [[NSMenu new] autorelease];
// id appName = [[NSProcessInfo processInfo] processName];
// id quitTitle = [@"Quit " stringByAppendingString:appName];
// id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:quitTitle
// action:@selector(terminate:) keyEquivalent:@"q"]
// autorelease];
// [appMenu addItem:quitMenuItem];
// [appMenuItem setSubmenu:appMenu];
//}
//
//- (void) dealloc {
// [super dealloc];
// window = nil;
// menubar = nil;
//}
@synthesize touchBar;

View File

@@ -36,9 +36,26 @@ void Quit(void*);
const char* GetSize(void *ctx);
const char* GetPos(void *ctx);
void ProcessURLResponse(void *inctx, const char *url, const char *contentType, const char *data, int datalength);
void ProcessURLResponse(void *inctx, const char *url, const char *contentType, void* data, int datalength);
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);
/* 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 */

View File

@@ -9,27 +9,31 @@
#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 :appearance :windowIsTranslucent];
[result SetTitle:title];
[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, const char* data, int datalength) {
void ProcessURLResponse(void *inctx, const char *url, const char *contentType, void* data, int datalength) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
NSString *nsurl = [[NSString alloc] initWithUTF8String:url];
NSString *nsContentType = [[NSString alloc] initWithUTF8String:contentType];
NSString *nsurl = safeInit(url);
NSString *nsContentType = safeInit(contentType);
NSData *nsdata = [NSData dataWithBytes:data length:datalength];
[ctx processURLResponse:nsurl :nsContentType :nsdata];
@@ -37,15 +41,17 @@ void ProcessURLResponse(void *inctx, const char *url, const char *contentType, c
void ExecJS(void* inctx, const char *script) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
NSString *nsscript = safeInit(script);
ON_MAIN_THREAD(
[ctx ExecJS:script];
[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];
[ctx SetTitle:_title];
);
}
@@ -81,7 +87,7 @@ void SetMaxSize(void* inctx, int width, int height) {
void SetPosition(void* inctx, int x, int y) {
WailsContext *ctx = (__bridge WailsContext*) inctx;
ON_MAIN_THREAD(
[ctx SetSize:x :y];
[ctx SetPosition:x :y];
);
}
@@ -173,42 +179,136 @@ void Show(void *inctx) {
);
}
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) {
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];
[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];
[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];
[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 sharedApplication];
NSApplication *app = [NSApplication sharedApplication];
AppDelegate* delegate = [AppDelegate new];
[NSApp setDelegate:(id)delegate];
[app setDelegate:(id)delegate];
ctx.appdelegate = delegate;
delegate.mainWindow = ctx.mainWindow;
delegate.alwaysOnTop = ctx.alwaysOnTop;
[ctx loadRequest:@"wails://wails/"];
[NSApp run];
[app setMainMenu:ctx.applicationMenu];
[app run];
[ctx release];
NSLog(@"Here");
}

View 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 */

View File

@@ -11,7 +11,7 @@
#import <Cocoa/Cocoa.h>
@interface WailsAlert : NSAlert
- (void)addButton:(const char*)text :(const char*)defaultButton :(const char*)cancelButton;
- (void)addButton:(NSString*)text :(NSString*)defaultButton :(NSString*)cancelButton;
@end

View File

@@ -11,14 +11,14 @@
@implementation WailsAlert
- (void)addButton:(const char*)text :(const char*)defaultButton :(const char*)cancelButton {
- (void)addButton:(NSString*)text :(NSString*)defaultButton :(NSString*)cancelButton {
if( text == nil ) {
return;
}
NSButton *button = [self addButtonWithTitle:[NSString stringWithUTF8String:text]];
if( defaultButton != nil && strcmp(text, defaultButton) == 0) {
NSButton *button = [self addButtonWithTitle:text];
if( defaultButton != nil && [text isEqualToString:defaultButton]) {
[button setKeyEquivalent:@"\r"];
} else if( cancelButton != nil && strcmp(text, cancelButton) == 0) {
} else if( cancelButton != nil && [text isEqualToString:cancelButton]) {
[button setKeyEquivalent:@"\033"];
} else {
[button setKeyEquivalent:@""];

View File

@@ -12,12 +12,13 @@
#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>
@interface WailsContext : NSObject <WKURLSchemeHandler,WKScriptMessageHandler,WKNavigationDelegate>
@property (retain) WailsWindow* mainWindow;
@property (retain) WKWebView* webview;
@@ -32,20 +33,24 @@
@property (retain) NSEvent* mouseEvent;
@property bool alwaysOnTop;
@property bool maximised;
@property bool debug;
@property (retain) WKUserContentController* userContentController;
@property (retain) NSMutableDictionary *urlRequests;
- (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 :(const char *)appearance :(bool)windowIsTranslucent;
@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:(const char*)title;
- (void) SetTitle:(NSString*)title;
- (void) Center;
- (void) Fullscreen;
- (void) UnFullscreen;
@@ -58,16 +63,19 @@
- (void) ShowMouse;
- (void) Hide;
- (void) Show;
- (void) Quit;
-(void) MessageDialog :(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) OpenFileDialog :(const char*)title :(const char*)defaultFilename :(const char*)defaultDirectory :(bool)allowDirectories :(bool)allowFiles :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)resolveAliases :(bool)showHiddenFiles :(bool)allowMultipleSelection :(const char*)filters;
-(void) SaveFileDialog :(const char*)title :(const char*)defaultFilename :(const char*)defaultDirectory :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)showHiddenFiles :(const char*)filters;
-(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:(const char*)script;
- (void) ExecJS:(NSString*)script;
- (NSScreen*) getCurrentScreen;
- (void) SetAbout :(NSString*)title :(NSString*)description :(void*)imagedata :(int)datalen;
@end

View File

@@ -9,8 +9,10 @@
#import <WebKit/WebKit.h>
#import "WailsContext.h"
#import "WailsAlert.h"
#import "WailsMenu.h"
#import "WindowDelegate.h"
#import "message.h"
#import "Role.h"
@implementation WailsWindow
@@ -31,7 +33,7 @@
frame.origin.y += frame.size.height - height;
frame.size.width = width;
frame.size.height = height;
[self.mainWindow setFrame:frame display:TRUE animate:FALSE];
ON_MAIN_THREAD([self.mainWindow setFrame:frame display:TRUE animate:FALSE];);
}
- (void) SetPosition:(int)x :(int)y {
@@ -40,11 +42,11 @@
NSScreen* screen = [self getCurrentScreen];
NSRect windowFrame = [self.mainWindow frame];
NSRect screenFrame = [screen visibleFrame];
windowFrame.origin.x += screenFrame.origin.x + (float)x;
windowFrame.origin.y += (screenFrame.origin.y + screenFrame.size.height) - windowFrame.size.height - (float)y;
[self.mainWindow setFrame:windowFrame display:TRUE animate:FALSE];
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 {
@@ -54,10 +56,11 @@
NSSize size = { minWidth, minHeight };
self.minSize = size;
[self.mainWindow setMinSize:size];
[self adjustWindowSize];
ON_MAIN_THREAD(
[self.mainWindow setMinSize:size];
[self adjustWindowSize];
);
}
@@ -71,10 +74,11 @@
size.height = maxHeight > 0 ? maxHeight : FLT_MAX;
self.maxSize = size;
[self.mainWindow setMinSize:size];
[self adjustWindowSize];
ON_MAIN_THREAD(
[self.mainWindow setMaxSize:size];
[self adjustWindowSize];
);
}
@@ -88,8 +92,8 @@
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:TRUE animate:FALSE];
[self.mainWindow setFrame:currentFrame display:YES animate:FALSE];
}
@@ -100,6 +104,7 @@
[self.mouseEvent release];
[self.userContentController release];
[self.urlRequests release];
[self.applicationMenu release];
}
- (NSScreen*) getCurrentScreen {
@@ -110,55 +115,66 @@
return screen;
}
- (void) SetTitle:(const char *)title {
NSString *_title = [NSString stringWithUTF8String:title];
[self.mainWindow setTitle:_title];
- (void) SetTitle:(NSString*)title {
ON_MAIN_THREAD([self.mainWindow setTitle:title];)
}
- (void) Center {
[self.mainWindow center];
ON_MAIN_THREAD( [self.mainWindow center]; );
}
- (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 :(const char *)appearance :(bool)windowIsTranslucent {
- (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 = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
NSWindowStyleMask styleMask = NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
if (frameless) {
styleMask = NSWindowStyleMaskBorderless;
titlebarAppearsTransparent = true;
hideTitle = true;
} else {
if (resizable) {
styleMask |= NSWindowStyleMaskResizable;
if (!hideTitleBar) {
styleMask |= NSWindowStyleMaskTitled;
}
if (fullscreen) {
styleMask |= NSWindowStyleMaskFullScreen;
}
if( fullSizeContent || frameless || titlebarAppearsTransparent ) {
styleMask |= NSWindowStyleMaskFullSizeContentView;
}
}
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) {
return;
}
if (useToolbar) {
NSLog(@"Using Toolbar");
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];
// [self.mainWindow canBecomeKeyWindow];
id contentView = [self.mainWindow contentView];
if (windowIsTranslucent) {
@@ -172,8 +188,7 @@
}
if (appearance != nil) {
NSString *name = [NSString stringWithUTF8String:appearance];
NSAppearance *nsAppearance = [NSAppearance appearanceNamed:name];
NSAppearance *nsAppearance = [NSAppearance appearanceNamed:appearance];
[self.mainWindow setAppearance:nsAppearance];
}
@@ -193,7 +208,7 @@
config.suppressesIncrementalRendering = true;
[config setURLSchemeHandler:self forURLScheme:@"wails"];
[config.preferences setValue:[NSNumber numberWithBool:true] forKey:@"developerExtrasEnabled"];
// [config.preferences setValue:[NSNumber numberWithBool:true] forKey:@"developerExtrasEnabled"];
WKUserContentController* userContentController = [WKUserContentController new];
[userContentController addScriptMessageHandler:self name:@"external"];
@@ -223,6 +238,8 @@
[self.webview setValue:[NSNumber numberWithBool:!webviewIsTransparent] forKey:@"drawsBackground"];
}
[self.webview setNavigationDelegate:self];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:FALSE forKey:@"NSAutomaticQuoteSubstitutionEnabled"];
@@ -244,6 +261,30 @@
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 {
@@ -260,7 +301,7 @@
id colour = [NSColor colorWithCalibratedRed:red green:green blue:blue alpha:alpha ];
[self.mainWindow setBackgroundColor:colour];
ON_MAIN_THREAD([self.mainWindow setBackgroundColor:colour];);
}
- (void) HideMouse {
@@ -276,52 +317,60 @@
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] ) {
[self.mainWindow toggleFullScreen:nil];
ON_MAIN_THREAD([self.mainWindow toggleFullScreen:nil];)
}
}
// UnFullscreen resets the main window after a fullscreen
- (void) UnFullscreen {
if( [self isFullScreen] ) {
[self.mainWindow toggleFullScreen:nil];
ON_MAIN_THREAD([self.mainWindow toggleFullScreen:nil];)
}
}
- (void) Minimise {
[self.mainWindow miniaturize:nil];
ON_MAIN_THREAD([self.mainWindow miniaturize:nil];)
}
- (void) UnMinimise {
[self.mainWindow deminiaturize:nil];
ON_MAIN_THREAD([self.mainWindow deminiaturize:nil];)
}
- (void) Hide {
[self.mainWindow orderOut:nil];
ON_MAIN_THREAD([self.mainWindow orderOut:nil];)
}
- (void) Show {
[self.mainWindow makeKeyAndOrderFront:nil];
[NSApp activateIgnoringOtherApps:YES];
ON_MAIN_THREAD(
[self.mainWindow makeKeyAndOrderFront:nil];
[NSApp activateIgnoringOtherApps:YES];
)
}
- (void) Maximise {
if (! self.maximised) {
[self.mainWindow zoom:nil];
if (![self.mainWindow isZoomed]) {
ON_MAIN_THREAD([self.mainWindow zoom:nil];)
}
}
- (void) UnMaximise {
if (self.maximised) {
[self.mainWindow zoom:nil];
if ([self.mainWindow isZoomed]) {
ON_MAIN_THREAD([self.mainWindow zoom:nil];)
}
}
- (void) ExecJS:(const char*)script {
NSString *nsscript = [NSString stringWithUTF8String:script];
[self.webview evaluateJavaScript:nsscript completionHandler:nil];
- (void) ExecJS:(NSString*)script {
ON_MAIN_THREAD(
[self.webview evaluateJavaScript:script completionHandler:nil];
)
}
- (void) processURLResponse:(NSString *)url :(NSString *)contentType :(NSData *)data {
@@ -348,6 +397,10 @@
}
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
processMessage("DomReady");
}
- (void)userContentController:(nonnull WKUserContentController *)userContentController didReceiveScriptMessage:(nonnull WKScriptMessage *)message {
NSString *m = message.body;
@@ -371,25 +424,25 @@
/***** Dialogs ******/
-(void) MessageDialog :(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) 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( strcmp(dialogType, "warning") == 0 ) {
if( [dialogType isEqualToString:@"warning"] ) {
style = NSAlertStyleWarning;
}
if( strcmp(dialogType, "error") == 0) {
if( [dialogType isEqualToString:@"error"] ) {
style = NSAlertStyleCritical;
}
}
[alert setAlertStyle:style];
if( strlen(title) > 0 ) {
[alert setMessageText:[NSString stringWithUTF8String:title]];
if( title != nil ) {
[alert setMessageText:title];
}
if( strlen(message) > 0 ) {
[alert setInformativeText:[NSString stringWithUTF8String:message]];
if( message != nil ) {
[alert setInformativeText:message];
}
[alert addButton:button1 :defaultButton :cancelButton];
@@ -397,47 +450,59 @@
[alert addButton:button3 :defaultButton :cancelButton];
[alert addButton:button4 :defaultButton :cancelButton];
long response = [alert runModal];
int result;
if( response == NSAlertFirstButtonReturn ) {
result = 0;
NSImage *icon = nil;
if (iconData != nil) {
NSData *imageData = [NSData dataWithBytes:iconData length:iconDataLength];
icon = [[NSImage alloc] initWithData:imageData];
}
else if( response == NSAlertSecondButtonReturn ) {
result = 1;
}
else if( response == NSAlertThirdButtonReturn ) {
result = 2;
} else {
result = 3;
}
processMessageDialogResponse(result);
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 :(const char*)title :(const char*)defaultFilename :(const char*)defaultDirectory :(bool)allowDirectories :(bool)allowFiles :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)resolveAliases :(bool)showHiddenFiles :(bool)allowMultipleSelection :(const char*)filters {
-(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( strlen(title) > 0 ) {
[dialog setTitle:[NSString stringWithUTF8String:title]];
if( title != nil ) {
[dialog setTitle:title];
}
// Filters - semicolon delimited list of file extensions
if( allowFiles ) {
if( filters != nil && strlen(filters) > 0) {
NSString *filterString = [[NSString stringWithUTF8String:filters] stringByReplacingOccurrencesOfString:@"*." withString:@""];
filterString = [filterString stringByReplacingOccurrencesOfString:@" " withString:@""];
NSArray *filterList = [filterString componentsSeparatedByString:@";"];
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 != NULL && strlen(defaultFilename) > 0 ) {
[dialog setNameFieldStringValue:[NSString stringWithUTF8String:defaultFilename]];
if( defaultFilename != nil ) {
[dialog setNameFieldStringValue:defaultFilename];
}
[dialog setAllowsMultipleSelection: allowMultipleSelection];
@@ -446,8 +511,8 @@
}
// Default Directory
if( defaultDirectory != NULL && strlen(defaultDirectory) > 0 ) {
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:defaultDirectory]];
if( defaultDirectory != nil ) {
NSURL *url = [NSURL fileURLWithPath:defaultDirectory];
[dialog setDirectoryURL:url];
}
@@ -470,40 +535,39 @@
processOpenFileDialogResponse([nsjson UTF8String]);
}];
[dialog runModal];
ON_MAIN_THREAD([dialog runModal];)
}
-(void) SaveFileDialog :(const char*)title :(const char*)defaultFilename :(const char*)defaultDirectory :(bool)canCreateDirectories :(bool)treatPackagesAsDirectories :(bool)showHiddenFiles :(const char*)filters; {
-(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( strlen(title) > 0 ) {
[dialog setTitle:[NSString stringWithUTF8String:title]];
if( title != nil ) {
[dialog setTitle:title];
}
// Filters - semicolon delimited list of file extensions
if( filters != nil && strlen(filters) > 0) {
NSString *filterString = [[NSString stringWithUTF8String:filters] stringByReplacingOccurrencesOfString:@"*." withString:@""];
filterString = [filterString stringByReplacingOccurrencesOfString:@" " withString:@""];
NSArray *filterList = [filterString componentsSeparatedByString:@";"];
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 != NULL && strlen(defaultFilename) > 0 ) {
[dialog setNameFieldStringValue:[NSString stringWithUTF8String:defaultFilename]];
if( defaultFilename != nil ) {
[dialog setNameFieldStringValue:defaultFilename];
}
// Default Directory
if( defaultDirectory != NULL && strlen(defaultDirectory) > 0 ) {
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithUTF8String:defaultDirectory]];
if( defaultDirectory != nil ) {
NSURL *url = [NSURL fileURLWithPath:defaultDirectory];
[dialog setDirectoryURL:url];
}
@@ -518,10 +582,38 @@
processSaveFileDialogResponse([url.path UTF8String]);
}];
[dialog runModal];
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

View 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 */

View 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

View 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 */

View 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

View File

@@ -9,10 +9,11 @@
#import <Cocoa/Cocoa.h>
#import "WindowDelegate.h"
#import "message.h"
#import "WailsContext.h"
@implementation WindowDelegate
- (BOOL)windowShouldClose:(NSWindow *)sender {
- (BOOL)windowShouldClose:(WailsWindow *)sender {
[sender orderOut:nil];
if( self.hideOnClose == false ) {
processMessage("Q");

View 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
}

View File

@@ -16,6 +16,7 @@ import (
"fmt"
"strings"
"sync"
"unsafe"
"github.com/leaanthony/slicer"
"github.com/wailsapp/wails/v2/internal/frontend"
@@ -155,7 +156,14 @@ func (f *Frontend) MessageDialog(options frontend.MessageDialogOptions) (string,
buttons[index] = c.String(buttonText)
}
C.MessageDialog(f.mainWindow.context, dialogType, title, message, buttons[0], buttons[1], buttons[2], buttons[3], defaultButton, cancelButton)
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

View File

@@ -36,6 +36,7 @@ type request struct {
var messageBuffer = make(chan string, 100)
var requestBuffer = make(chan *request, 100)
var callbackBuffer = make(chan uint, 10)
type Frontend struct {
@@ -65,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.
@@ -92,6 +89,7 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.
go result.startMessageProcessor()
go result.startRequestProcessor()
go result.startCallbackProcessor()
return result
}
@@ -106,6 +104,14 @@ func (f *Frontend) startRequestProcessor() {
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();")
@@ -208,6 +214,9 @@ func (f *Frontend) WindowSetRGBA(col *options.RGBA) {
func (f *Frontend) Quit() {
f.mainWindow.Quit()
if f.frontendOptions.OnShutdown != nil {
f.frontendOptions.OnShutdown(f.ctx)
}
}
type EventNotify struct {
@@ -229,13 +238,14 @@ func (f *Frontend) Notify(name string, data ...interface{}) {
}
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())
@@ -259,14 +269,6 @@ func (f *Frontend) Callback(message string) {
f.ExecJS(`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
}
func (f *Frontend) ExecJS(js string) {
f.mainWindow.ExecJS(js)
}
@@ -283,8 +285,10 @@ func (f *Frontend) processRequest(r *request) {
//TODO: Handle errors
return
}
data := C.CString(string(_contents))
defer C.free(unsafe.Pointer(data))
var data unsafe.Pointer
if _contents != nil {
data = unsafe.Pointer(&_contents[0])
}
mimetype := C.CString(_mimetype)
defer C.free(unsafe.Pointer(mimetype))
@@ -304,3 +308,8 @@ func processURLRequest(ctx unsafe.Pointer, url *C.char) {
ctx: ctx,
}
}
//export processCallback
func processCallback(callbackID uint) {
callbackBuffer <- callbackID
}

View File

@@ -12,7 +12,6 @@
void processMessage(const char*t) {
NSLog(@"processMessage called");
}
void processMessageDialogResponse(int t) {
@@ -22,33 +21,215 @@ void processMessageDialogResponse(int t) {
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", myByteArray, 21);
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 = 0;
int resizable = 1;
int frameless = 1;
int resizable = 0;
int fullscreen = 0;
int fullSizeContent = 1;
int hideTitleBar = 0;
int titlebarAppearsTransparent = 1;
int titlebarAppearsTransparent = 0;
int hideTitle = 0;
int useToolbar = 1;
int hideToolbarSeparator = 1;
int webviewIsTransparent = 0;
int alwaysOnTop = 1;
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));

View File

@@ -3,96 +3,133 @@
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()
}

View 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]
}

View File

@@ -19,6 +19,7 @@ void processURLRequest(void*, const char *);
void processMessageDialogResponse(int);
void processOpenFileDialogResponse(const char*);
void processSaveFileDialogResponse(const char*);
void processCallback(int);
#ifdef __cplusplus
}

View File

@@ -17,6 +17,8 @@ import (
"strings"
"unsafe"
"github.com/wailsapp/wails/v2/pkg/menu"
"github.com/wailsapp/wails/v2/pkg/options"
)
@@ -46,10 +48,6 @@ func NewWindow(frontendOptions *options.App, debugMode bool) *Window {
alwaysOnTop := bool2Cint(frontendOptions.AlwaysOnTop)
hideWindowOnClose := bool2Cint(frontendOptions.HideWindowOnClose)
debug := bool2Cint(debugMode)
alpha := C.int(frontendOptions.RGBA.A)
red := C.int(frontendOptions.RGBA.R)
green := C.int(frontendOptions.RGBA.G)
blue := C.int(frontendOptions.RGBA.B)
var fullSizeContent, hideTitleBar, hideTitle, useToolbar, webviewIsTransparent C.int
var titlebarAppearsTransparent, hideToolbarSeparator, windowIsTranslucent C.int
@@ -75,13 +73,39 @@ func NewWindow(frontendOptions *options.App, debugMode bool) *Window {
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)
var context *C.WailsContext = C.Create(title, width, height, frameless, resizable, fullscreen, fullSizeContent,
hideTitleBar, titlebarAppearsTransparent, hideTitle, useToolbar, hideToolbarSeparator, webviewIsTransparent,
alwaysOnTop, hideWindowOnClose, appearance, windowIsTranslucent, debug)
C.SetRGBA(unsafe.Pointer(context), red, green, blue, alpha)
return &Window{
// 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() {
@@ -90,7 +114,6 @@ func (w *Window) Center() {
func (w *Window) Run() {
C.Run(w.context)
println("I exited!")
}
func (w *Window) Quit() {
@@ -138,10 +161,16 @@ func (w *Window) UnMinimise() {
}
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))
}
@@ -185,3 +214,13 @@ func (w *Window) Size() (int, int) {
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)
}

View File

@@ -55,7 +55,7 @@ type MessageDialogOptions struct {
Buttons []string
DefaultButton string
CancelButton string
Icon string
Icon []byte
}
type Frontend interface {

View File

@@ -1,10 +1,11 @@
package gomod
import (
"github.com/Masterminds/semver"
"github.com/matryer/is"
"reflect"
"testing"
"github.com/Masterminds/semver"
"github.com/matryer/is"
)
const basic string = `module changeme
@@ -75,7 +76,7 @@ const basicUpdated string = `module changeme
go 1.17
require github.com/wailsapp/wails/v2 v2.0.0-beta.15
require github.com/wailsapp/wails/v2 v2.0.0-beta.16
require (
github.com/andybalholm/brotli v1.0.2 // indirect
@@ -330,7 +331,7 @@ const multilineRequireUpdated = `module changeme
go 1.17
require (
github.com/wailsapp/wails/v2 v2.0.0-beta.15
github.com/wailsapp/wails/v2 v2.0.0-beta.16
)
require (
@@ -381,12 +382,12 @@ func TestUpdateGoModVersion(t *testing.T) {
want []byte
wantErr bool
}{
{"basic", args{[]byte(basic), "v2.0.0-beta.15"}, []byte(basicUpdated), false},
{"basicmultiline", args{[]byte(multilineRequire), "v2.0.0-beta.15"}, []byte(multilineRequireUpdated), false},
{"basicmultilinereplace", args{[]byte(multilineReplace), "v2.0.0-beta.15"}, []byte(multilineReplaceUpdated), false},
{"basicmultilinereplaceblock", args{[]byte(multilineReplaceBlock), "v2.0.0-beta.15"}, []byte(multilineReplaceBlockUpdated), false},
{"basicmultilinereplacenoversion", args{[]byte(multilineReplaceNoVersion), "v2.0.0-beta.15"}, []byte(multilineReplaceNoVersionUpdated), false},
{"basicmultilinereplacenoversionblock", args{[]byte(multilineReplaceNoVersionBlock), "v2.0.0-beta.15"}, []byte(multilineReplaceNoVersionBlockUpdated), false},
{"basic", args{[]byte(basic), "v2.0.0-beta.16"}, []byte(basicUpdated), false},
{"basicmultiline", args{[]byte(multilineRequire), "v2.0.0-beta.16"}, []byte(multilineRequireUpdated), false},
{"basicmultilinereplace", args{[]byte(multilineReplace), "v2.0.0-beta.16"}, []byte(multilineReplaceUpdated), false},
{"basicmultilinereplaceblock", args{[]byte(multilineReplaceBlock), "v2.0.0-beta.16"}, []byte(multilineReplaceBlockUpdated), false},
{"basicmultilinereplacenoversion", args{[]byte(multilineReplaceNoVersion), "v2.0.0-beta.16"}, []byte(multilineReplaceNoVersionUpdated), false},
{"basicmultilinereplacenoversionblock", args{[]byte(multilineReplaceNoVersionBlock), "v2.0.0-beta.16"}, []byte(multilineReplaceNoVersionBlockUpdated), false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@@ -413,8 +414,8 @@ func TestGoModOutOfSync(t *testing.T) {
want bool
wantErr bool
}{
{"basic", args{[]byte(basic), "v2.0.0-beta.15"}, true, false},
{"basicmultiline", args{[]byte(multilineRequire), "v2.0.0-beta.15"}, true, false},
{"basic", args{[]byte(basic), "v2.0.0-beta.16"}, true, false},
{"basicmultiline", args{[]byte(multilineRequire), "v2.0.0-beta.16"}, true, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@@ -433,7 +434,7 @@ const multilineReplaceUpdated = `module changeme
go 1.17
require (
github.com/wailsapp/wails/v2 v2.0.0-beta.15
github.com/wailsapp/wails/v2 v2.0.0-beta.16
)
require (
@@ -468,14 +469,14 @@ require (
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6 // indirect
)
replace github.com/wailsapp/wails/v2 v2.0.0-beta.15 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
replace github.com/wailsapp/wails/v2 v2.0.0-beta.16 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
`
const multilineReplaceNoVersionUpdated = `module changeme
go 1.17
require (
github.com/wailsapp/wails/v2 v2.0.0-beta.15
github.com/wailsapp/wails/v2 v2.0.0-beta.16
)
require (
@@ -517,7 +518,7 @@ const multilineReplaceNoVersionBlockUpdated = `module changeme
go 1.17
require (
github.com/wailsapp/wails/v2 v2.0.0-beta.15
github.com/wailsapp/wails/v2 v2.0.0-beta.16
)
require (
@@ -562,7 +563,7 @@ const multilineReplaceBlockUpdated = `module changeme
go 1.17
require (
github.com/wailsapp/wails/v2 v2.0.0-beta.15
github.com/wailsapp/wails/v2 v2.0.0-beta.16
)
require (
@@ -598,6 +599,6 @@ require (
)
replace (
github.com/wailsapp/wails/v2 v2.0.0-beta.15 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
github.com/wailsapp/wails/v2 v2.0.0-beta.16 => C:\Users\leaan\Documents\wails-v2-beta\wails\v2
)
`

View File

@@ -3,6 +3,7 @@ package menumanager
import (
"encoding/json"
"fmt"
"github.com/wailsapp/wails/v2/pkg/menu"
)

View File

@@ -53,6 +53,9 @@ type Project struct {
// The url to use to server assets. Default "https://localhost:34115"
DevServerURL string `json:"devserverurl"`
// Arguments that are forwared to the application in dev mode
AppArgs string `json:"appargs"`
}
func (p *Project) Save() error {

View File

@@ -35,7 +35,7 @@ func NewManager(ctx context.Context, cancel context.CancelFunc, bus *servicebus.
result := &Manager{
bus: bus,
logger: logger.CustomLogger("Event Manager"),
logger: logger.CustomLogger("Signal Manager"),
signalchannel: make(chan os.Signal, 2),
ctx: ctx,
cancel: cancel,
@@ -49,7 +49,7 @@ func NewManager(ctx context.Context, cancel context.CancelFunc, bus *servicebus.
func (m *Manager) Start() {
// Hook into interrupts
gosignal.Notify(m.signalchannel, os.Interrupt, syscall.SIGTERM)
gosignal.Notify(m.signalchannel, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)
m.wg.Add(1)

View File

@@ -2,10 +2,11 @@ package buildassets
import (
"embed"
"github.com/leaanthony/debme"
"github.com/leaanthony/gosod"
"os"
"path/filepath"
"github.com/leaanthony/debme"
"github.com/leaanthony/gosod"
)
//go:embed build
@@ -50,3 +51,17 @@ func RegenerateAppIcon(target string) error {
}
return a.CopyFile("appicon.png", target, 0644)
}
func RegeneratePlist(targetDir string, projectName string) error {
darwinAssets, err := debme.FS(assets, "build/darwin")
if err != nil {
return err
}
templateDir := gosod.New(darwinAssets)
err = templateDir.Extract(targetDir, &assetData{Name: projectName})
if err != nil {
return err
}
return nil
}

View File

@@ -3,9 +3,6 @@ package build
import (
"bytes"
"fmt"
"github.com/leaanthony/gosod"
wailsRuntime "github.com/wailsapp/wails/v2/internal/frontend/runtime"
"github.com/wailsapp/wails/v2/internal/frontend/runtime/wrapper"
"io/ioutil"
"os"
"os/exec"
@@ -13,6 +10,10 @@ import (
"runtime"
"strings"
"github.com/leaanthony/gosod"
wailsRuntime "github.com/wailsapp/wails/v2/internal/frontend/runtime"
"github.com/wailsapp/wails/v2/internal/frontend/runtime/wrapper"
"github.com/pkg/errors"
"github.com/leaanthony/slicer"
@@ -215,8 +216,6 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
commands.Add(`"all=-N -l"`)
}
//commands.Add("-a")
var tags slicer.StringSlicer
tags.Add(options.OutputType)
tags.AddSlice(options.UserTags)
@@ -299,7 +298,7 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
if v != "" {
v += " "
}
v += "-I" + buildBaseDir
v += "-mmacosx-version-min=10.13"
return v
})
// Use upsertEnv so we don't overwrite user's CGO_CXXFLAGS
@@ -314,6 +313,17 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
cmd.Env = upsertEnv(cmd.Env, "CGO_ENABLED", func(v string) string {
return "1"
})
if runtime.GOOS == "darwin" {
// Set the minimum Mac SDK to 10.13
cmd.Env = upsertEnv(cmd.Env, "CGO_LDFLAGS", func(v string) string {
if v != "" {
v += " "
}
v += "-mmacosx-version-min=10.13"
return v
})
}
}
cmd.Env = upsertEnv(cmd.Env, "GOOS", func(v string) string {
@@ -337,8 +347,6 @@ func (b *BaseBuilder) CompileProject(options *Options) error {
return err
}
println("Done.")
if !options.Compress {
return nil
}
@@ -534,10 +542,10 @@ func (b *BaseBuilder) BuildFrontend(outputLogger *clilogger.CLILogger) error {
}
outputLogger.Print("Compiling frontend: ")
cmd := strings.Split(b.projectData.BuildCommand, " ")
cmd := strings.Split(buildCommand, " ")
if verbose {
outputLogger.Println("")
outputLogger.Println(" Build command: '" + strings.Join(cmd, " ") + "'")
outputLogger.Println(" Build command: '" + buildCommand + "'")
}
stdout, stderr, err := shell.RunCommand(frontendDir, cmd[0], cmd[1:]...)
if verbose || err != nil {

View File

@@ -6,6 +6,7 @@ import (
"os"
"path/filepath"
"runtime"
"strings"
"github.com/wailsapp/wails/v2/internal/fs"
@@ -111,17 +112,11 @@ func Build(options *Options) (string, error) {
}
}
// Build the base assets
//err = builder.BuildAssets(options)
//if err != nil {
// return "", err
//}
// If we are building for windows, we will need to generate the asset bundle before
// compilation. This will be a .syso file in the project root
if options.Pack && options.Platform == "windows" {
outputLogger.Print("Generating bundle assets: ")
err := packageApplication(options)
err := packageApplicationForWindows(options)
if err != nil {
return "", err
}
@@ -149,10 +144,10 @@ func Build(options *Options) (string, error) {
options.OutputFile = amd64Filename
options.CleanBuildDirectory = false
if options.Verbosity == VERBOSE {
println()
println(" Building AMD64 Target:", filepath.Join(options.BuildDirectory, options.OutputFile))
outputLogger.Println("\nBuilding AMD64 Target:", filepath.Join(options.BuildDirectory, options.OutputFile))
}
err = builder.CompileProject(options)
if err != nil {
return "", err
}
@@ -161,15 +156,16 @@ func Build(options *Options) (string, error) {
options.OutputFile = arm64Filename
options.CleanBuildDirectory = false
if options.Verbosity == VERBOSE {
println(" Building ARM64 Target:", filepath.Join(options.BuildDirectory, options.OutputFile))
outputLogger.Println("Building ARM64 Target:", filepath.Join(options.BuildDirectory, options.OutputFile))
}
err = builder.CompileProject(options)
if err != nil {
return "", err
}
// Run lipo
if options.Verbosity == VERBOSE {
println(" Running lipo: ", "lipo", "-create", "-output", outputFile, amd64Filename, arm64Filename)
outputLogger.Println(" Running lipo: ", "lipo", "-create", "-output", outputFile, amd64Filename, arm64Filename)
}
_, stderr, err := shell.RunCommand(options.BuildDirectory, "lipo", "-create", "-output", outputFile, amd64Filename, arm64Filename)
if err != nil {
@@ -193,6 +189,8 @@ func Build(options *Options) (string, error) {
}
}
outputLogger.Println("Done.")
// Do we need to pack the app for non-windows?
if options.Pack && options.Platform != "windows" {
@@ -212,6 +210,18 @@ func Build(options *Options) (string, error) {
return "", err
}
return options.CompiledBinary, nil
result := options.CompiledBinary
if options.Pack && options.Platform == "darwin" {
sr := strings.Split(result, "/")
for i := len(sr) - 1; i >= 0; i-- {
if strings.Contains(sr[i], ".app") {
result = strings.Join(sr[:i+1], "/")
break
}
}
}
return result, nil
}

View File

@@ -2,10 +2,19 @@ package build
import (
"fmt"
"image"
"os"
"path"
"path/filepath"
"runtime"
"github.com/leaanthony/winicon"
"github.com/tc-hib/winres"
"github.com/jackmordaunt/icns"
"github.com/pkg/errors"
"github.com/wailsapp/wails/v2/pkg/buildassets"
"github.com/wailsapp/wails/v2/internal/fs"
)
@@ -14,8 +23,10 @@ func packageProject(options *Options, platform string) error {
var err error
switch platform {
case "darwin", "windows":
err = packageApplication(options)
case "darwin":
err = packageApplicationForDarwin(options)
case "windows":
err = packageApplicationForWindows(options)
default:
err = fmt.Errorf("packing not supported for %s yet", platform)
}
@@ -65,3 +76,225 @@ func getBuildBaseDirectory(options *Options) (string, error) {
func getPackageAssetsDirectory() string {
return fs.RelativePath("internal/packager", runtime.GOOS)
}
func packageApplicationForDarwin(options *Options) error {
var err error
// Create directory structure
bundlename := options.ProjectData.Name + ".app"
contentsDirectory := filepath.Join(options.BuildDirectory, bundlename, "/Contents")
exeDir := filepath.Join(contentsDirectory, "/MacOS")
err = fs.MkDirs(exeDir, 0755)
if err != nil {
return err
}
resourceDir := filepath.Join(contentsDirectory, "/Resources")
err = fs.MkDirs(resourceDir, 0755)
if err != nil {
return err
}
// Copy binary
packedBinaryPath := filepath.Join(exeDir, options.ProjectData.Name)
err = fs.MoveFile(options.CompiledBinary, packedBinaryPath)
if err != nil {
return errors.Wrap(err, "Cannot move file: "+options.ProjectData.OutputFilename)
}
// Generate Info.plist
err = processPList(options, contentsDirectory)
if err != nil {
return err
}
// Generate Icons
err = processApplicationIcon(resourceDir, options.ProjectData.Path)
if err != nil {
return err
}
options.CompiledBinary = packedBinaryPath
return nil
}
func processPList(options *Options, contentsDirectory string) error {
// Check if plist already exists in project dir
plistFileDir := filepath.Join(options.ProjectData.Path, "build", "darwin")
plistFile := filepath.Join(plistFileDir, "Info.plist")
// If the file doesn't exist, generate it
if !fs.FileExists(plistFile) {
err := buildassets.RegeneratePlist(plistFileDir, options.ProjectData.Name)
if err != nil {
return err
}
}
// Copy it to the contents directory
targetFile := filepath.Join(contentsDirectory, "Info.plist")
return fs.CopyFile(plistFile, targetFile)
}
func processApplicationIcon(resourceDir string, iconsDir string) (err error) {
appIcon := filepath.Join(iconsDir, "appicon.png")
// Install default icon if one doesn't exist
if !fs.FileExists(appIcon) {
// No - Install default icon
err = buildassets.RegenerateAppIcon(appIcon)
if err != nil {
return
}
}
tgtBundle := path.Join(resourceDir, "iconfile.icns")
imageFile, err := os.Open(appIcon)
if err != nil {
return err
}
defer func() {
err = imageFile.Close()
if err == nil {
return
}
}()
srcImg, _, err := image.Decode(imageFile)
if err != nil {
return err
}
dest, err := os.Create(tgtBundle)
if err != nil {
return err
}
defer func() {
err = dest.Close()
if err == nil {
return
}
}()
return icns.Encode(dest, srcImg)
}
func packageApplicationForWindows(options *Options) error {
// Generate icon
var err error
err = generateIcoFile(options)
if err != nil {
return err
}
// Ensure Manifest is present
err = generateManifest(options)
if err != nil {
return err
}
// Create syso file
err = compileResources(options)
if err != nil {
return err
}
return nil
}
func generateManifest(options *Options) error {
filename := options.ProjectData.Name + ".exe.manifest"
manifestFile := filepath.Join(options.ProjectData.Path, "build", "windows", filename)
if !fs.FileExists(manifestFile) {
return buildassets.RegenerateManifest(manifestFile)
}
return nil
}
func generateIcoFile(options *Options) error {
// Check ico file exists already
icoFile := filepath.Join(options.ProjectData.Path, "build", "windows", "icon.ico")
if !fs.FileExists(icoFile) {
// Check icon exists
appicon := filepath.Join(options.ProjectData.Path, "build", "appicon.png")
if !fs.FileExists(appicon) {
return fmt.Errorf("application icon missing: %s", appicon)
}
// Load icon
input, err := os.Open(appicon)
if err != nil {
return err
}
output, err := os.OpenFile(icoFile, os.O_CREATE, 0644)
if err != nil {
return err
}
err = winicon.GenerateIcon(input, output, []int{256, 128, 64, 48, 32, 16})
if err != nil {
return err
}
}
return nil
}
func compileResources(options *Options) error {
currentDir, err := os.Getwd()
if err != nil {
return err
}
defer func() {
os.Chdir(currentDir)
}()
windowsDir := filepath.Join(options.ProjectData.Path, "build", "windows")
err = os.Chdir(windowsDir)
if err != nil {
return err
}
rs := winres.ResourceSet{}
icon := filepath.Join(windowsDir, "icon.ico")
iconFile, err := os.Open(icon)
if err != nil {
return err
}
defer iconFile.Close()
ico, err := winres.LoadICO(iconFile)
if err != nil {
return err
}
err = rs.SetIcon(winres.RT_ICON, ico)
if err != nil {
return err
}
ManifestFilename := options.ProjectData.Name + ".exe.manifest"
manifestData, err := os.ReadFile(ManifestFilename)
xmlData, err := winres.AppManifestFromXML(manifestData)
if err != nil {
return err
}
rs.SetManifest(xmlData)
targetFile := filepath.Join(options.ProjectData.Path, options.ProjectData.Name+"-res.syso")
fout, err := os.Create(targetFile)
if err != nil {
return err
}
defer fout.Close()
archs := map[string]winres.Arch{
"amd64": winres.ArchAMD64,
}
targetArch, supported := archs[options.Arch]
if !supported {
return fmt.Errorf("arch '%s' not supported", options.Arch)
}
err = rs.WriteObject(fout, targetArch)
if err != nil {
return err
}
return nil
}

View File

@@ -1,181 +0,0 @@
package build
import (
"bytes"
"image"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"text/template"
"github.com/wailsapp/wails/v2/pkg/buildassets"
"github.com/jackmordaunt/icns"
"github.com/pkg/errors"
"github.com/wailsapp/wails/v2/internal/fs"
)
func packageApplication(options *Options) error {
var err error
// Create directory structure
bundlename := options.ProjectData.Name + ".app"
contentsDirectory := filepath.Join(options.BuildDirectory, bundlename, "/Contents")
exeDir := filepath.Join(contentsDirectory, "/MacOS")
err = fs.MkDirs(exeDir, 0755)
if err != nil {
return err
}
resourceDir := filepath.Join(contentsDirectory, "/Resources")
err = fs.MkDirs(resourceDir, 0755)
if err != nil {
return err
}
// Copy binary
packedBinaryPath := filepath.Join(exeDir, options.ProjectData.Name)
err = fs.MoveFile(options.CompiledBinary, packedBinaryPath)
if err != nil {
return errors.Wrap(err, "Cannot move file: "+options.ProjectData.OutputFilename)
}
// Generate Info.plist
err = processPList(options, contentsDirectory)
if err != nil {
return err
}
// Generate Icons
err = processApplicationIcon(resourceDir, options.ProjectData.BuildDir)
if err != nil {
return err
}
options.CompiledBinary = packedBinaryPath
return nil
}
func processPList(options *Options, contentsDirectory string) error {
// Check if plist already exists in project dir
plistFile := filepath.Join(options.ProjectData.BuildDir, "darwin", "Info.plist")
// If the file doesn't exist, generate it
if !fs.FileExists(plistFile) {
err := generateDefaultPlist(options, plistFile)
if err != nil {
return err
}
}
// Copy it to the contents directory
targetFile := filepath.Join(contentsDirectory, "Info.plist")
return fs.CopyFile(plistFile, targetFile)
}
func generateDefaultPlist(options *Options, targetPlistFile string) error {
name := defaultString(options.ProjectData.Name, "WailsTest")
exe := defaultString(options.OutputFile, name)
version := "1.0.0"
author := defaultString(options.ProjectData.Author.Name, "Anonymous")
packageID := strings.Join([]string{"wails", name}, ".")
plistData := newPlistData(name, exe, packageID, version, author)
tmpl := template.New("infoPlist")
plistTemplate := fs.RelativePath("./internal/packager/darwin/Info.plist")
infoPlist, err := ioutil.ReadFile(plistTemplate)
if err != nil {
return errors.Wrap(err, "Cannot open plist template")
}
_, err = tmpl.Parse(string(infoPlist))
if err != nil {
return err
}
// Write the template to a buffer
var tpl bytes.Buffer
err = tmpl.Execute(&tpl, plistData)
if err != nil {
return err
}
// Create the directory if it doesn't exist
err = fs.MkDirs(filepath.Dir(targetPlistFile))
if err != nil {
return err
}
// Save the file
return ioutil.WriteFile(targetPlistFile, tpl.Bytes(), 0644)
}
func defaultString(val string, defaultVal string) string {
if val != "" {
return val
}
return defaultVal
}
type plistData struct {
Title string
Exe string
PackageID string
Version string
Author string
}
func newPlistData(title, exe, packageID, version, author string) *plistData {
return &plistData{
Title: title,
Exe: exe,
Version: version,
PackageID: packageID,
Author: author,
}
}
func processApplicationIcon(resourceDir string, iconsDir string) (err error) {
appIcon := filepath.Join(iconsDir, "appicon.png")
// Install default icon if one doesn't exist
if !fs.FileExists(appIcon) {
// No - Install default icon
err = buildassets.RegenerateAppIcon(appIcon)
if err != nil {
return
}
}
tgtBundle := path.Join(resourceDir, "iconfile.icns")
imageFile, err := os.Open(appIcon)
if err != nil {
return err
}
defer func() {
err = imageFile.Close()
if err == nil {
return
}
}()
srcImg, _, err := image.Decode(imageFile)
if err != nil {
return err
}
dest, err := os.Create(tgtBundle)
if err != nil {
return err
}
defer func() {
err = dest.Close()
if err == nil {
return
}
}()
return icns.Encode(dest, srcImg)
}

View File

@@ -1,129 +0,0 @@
package build
import (
"fmt"
"github.com/leaanthony/winicon"
"github.com/tc-hib/winres"
"github.com/wailsapp/wails/v2/internal/fs"
"github.com/wailsapp/wails/v2/pkg/buildassets"
"os"
"path/filepath"
)
func packageApplication(options *Options) error {
// Generate icon
var err error
err = generateIcoFile(options)
if err != nil {
return err
}
// Ensure Manifest is present
err = generateManifest(options)
if err != nil {
return err
}
// Create syso file
err = compileResources(options)
if err != nil {
return err
}
return nil
}
func generateManifest(options *Options) error {
filename := options.ProjectData.Name + ".exe.manifest"
manifestFile := filepath.Join(options.ProjectData.Path, "build", "windows", filename)
if !fs.FileExists(manifestFile) {
return buildassets.RegenerateManifest(manifestFile)
}
return nil
}
func generateIcoFile(options *Options) error {
// Check ico file exists already
icoFile := filepath.Join(options.ProjectData.Path, "build", "windows", "icon.ico")
if !fs.FileExists(icoFile) {
// Check icon exists
appicon := filepath.Join(options.ProjectData.Path, "build", "appicon.png")
if !fs.FileExists(appicon) {
return fmt.Errorf("application icon missing: %s", appicon)
}
// Load icon
input, err := os.Open(appicon)
if err != nil {
return err
}
output, err := os.OpenFile(icoFile, os.O_CREATE, 0644)
if err != nil {
return err
}
err = winicon.GenerateIcon(input, output, []int{256, 128, 64, 48, 32, 16})
if err != nil {
return err
}
}
return nil
}
func compileResources(options *Options) error {
currentDir, err := os.Getwd()
if err != nil {
return err
}
defer func() {
os.Chdir(currentDir)
}()
windowsDir := filepath.Join(options.ProjectData.Path, "build", "windows")
err = os.Chdir(windowsDir)
if err != nil {
return err
}
rs := winres.ResourceSet{}
icon := filepath.Join(windowsDir, "icon.ico")
iconFile, err := os.Open(icon)
if err != nil {
return err
}
defer iconFile.Close()
ico, err := winres.LoadICO(iconFile)
if err != nil {
return err
}
err = rs.SetIcon(winres.RT_ICON, ico)
if err != nil {
return err
}
ManifestFilename := options.ProjectData.Name + ".exe.manifest"
manifestData, err := os.ReadFile(ManifestFilename)
xmlData, err := winres.AppManifestFromXML(manifestData)
if err != nil {
return err
}
rs.SetManifest(xmlData)
targetFile := filepath.Join(options.ProjectData.Path, options.ProjectData.Name+"-res.syso")
fout, err := os.Create(targetFile)
if err != nil {
return err
}
defer fout.Close()
archs := map[string]winres.Arch{
"amd64": winres.ArchAMD64,
}
targetArch, supported := archs[options.Arch]
if !supported {
return fmt.Errorf("arch '%s' not supported", options.Arch)
}
err = rs.WriteObject(fout, targetArch)
if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,26 @@
package keys
const (
NSEventModifierFlagShift = 1 << 17 // Set if Shift key is pressed.
NSEventModifierFlagControl = 1 << 18 // Set if Control key is pressed.
NSEventModifierFlagOption = 1 << 19 // Set if Option or Alternate key is pressed.
NSEventModifierFlagCommand = 1 << 20 // Set if Command key is pressed.
)
var macModifierMap = map[Modifier]int{
CmdOrCtrlKey: NSEventModifierFlagCommand,
ControlKey: NSEventModifierFlagControl,
OptionOrAltKey: NSEventModifierFlagOption,
ShiftKey: NSEventModifierFlagShift,
}
func ToMacModifier(accelerator *Accelerator) int {
if accelerator == nil {
return 0
}
result := 0
for _, modifier := range accelerator.Modifiers {
result |= macModifierMap[modifier]
}
return result
}

View File

@@ -0,0 +1,31 @@
package keys
import "testing"
func TestToMacModifier(t *testing.T) {
tests := []struct {
name string
accelerator *Accelerator
want int
}{
// TODO: Add test cases.
{"nil", nil, 0},
{"empty", &Accelerator{}, 0},
{"key", &Accelerator{Key: "p"}, 0},
{"cmd", CmdOrCtrl(""), NSEventModifierFlagCommand},
{"ctrl", Control(""), NSEventModifierFlagControl},
{"shift", Shift(""), NSEventModifierFlagShift},
{"option", OptionOrAlt(""), NSEventModifierFlagOption},
{"cmd+ctrl", Combo("", CmdOrCtrlKey, ControlKey), NSEventModifierFlagCommand | NSEventModifierFlagControl},
{"cmd+ctrl+shift", Combo("", CmdOrCtrlKey, ControlKey, ShiftKey), NSEventModifierFlagCommand | NSEventModifierFlagControl | NSEventModifierFlagShift},
{"cmd+ctrl+shift+option", Combo("", CmdOrCtrlKey, ControlKey, ShiftKey, OptionOrAltKey), NSEventModifierFlagCommand | NSEventModifierFlagControl | NSEventModifierFlagShift | NSEventModifierFlagOption},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ToMacModifier(tt.accelerator); got != tt.want {
t.Errorf("ToMacModifier() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -11,9 +11,9 @@ type MenuItem struct {
// Label is what appears as the menu text
Label string
// Role is a predefined menu type
//Role Role `json:"Role,omitempty"`
Role Role
// Accelerator holds a representation of a key binding
Accelerator *keys.Accelerator `json:"Accelerator,omitempty"`
Accelerator *keys.Accelerator
// Type of MenuItem, EG: Checkbox, Text, Separator, Radio, Submenu
Type Type
// Disabled makes the item unselectable
@@ -24,10 +24,10 @@ type MenuItem struct {
Checked bool
// Submenu contains a list of menu items that will be shown as a submenu
//SubMenu []*MenuItem `json:"SubMenu,omitempty"`
SubMenu *Menu `json:"SubMenu,omitempty"`
SubMenu *Menu
// Callback function when menu clicked
Click Callback `json:"-"`
Click Callback
/*
// Text Colour
RGBA string
@@ -267,16 +267,3 @@ func SubMenu(label string, menu *Menu) *MenuItem {
return result
}
// SubMenuWithID is a helper to create Submenus with an ID
func SubMenuWithID(label string, menu *Menu) *MenuItem {
result := &MenuItem{
Label: label,
SubMenu: menu,
Type: SubmenuType,
}
menu.setParent(result)
return result
}

View File

@@ -3,37 +3,39 @@
// Electron License: https://github.com/electron/electron/blob/master/LICENSE
package menu
/*
type Role string
// Role is a type to identify menu roles
type Role int
// These constants need to be kept in sync with `v2/internal/frontend/desktop/darwin/Role.h`
const (
AboutRole Role = "about"
UndoRole Role = "undo"
RedoRole Role = "redo"
CutRole Role = "cut"
CopyRole Role = "copy"
PasteRole Role = "paste"
PasteAndMatchStyleRole Role = "pasteAndMatchStyle"
SelectAllRole Role = "selectAll"
DeleteRole Role = "delete"
MinimizeRole Role = "minimize"
QuitRole Role = "quit"
TogglefullscreenRole Role = "togglefullscreen"
FileMenuRole Role = "fileMenu"
EditMenuRole Role = "editMenu"
ViewMenuRole Role = "viewMenu"
WindowMenuRole Role = "windowMenu"
AppMenuRole Role = "appMenu"
HideRole Role = "hide"
HideOthersRole Role = "hideOthers"
UnhideRole Role = "unhide"
FrontRole Role = "front"
ZoomRole Role = "zoom"
WindowSubMenuRole Role = "windowSubMenu"
HelpSubMenuRole Role = "helpSubMenu"
SeparatorItemRole Role = "separatorItem"
AppMenuRole Role = 1
EditMenuRole = 2
//AboutRole Role = "about"
//UndoRole Role = "undo"
//RedoRole Role = "redo"
//CutRole Role = "cut"
//CopyRole Role = "copy"
//PasteRole Role = "paste"
//PasteAndMatchStyleRole Role = "pasteAndMatchStyle"
//SelectAllRole Role = "selectAll"
//DeleteRole Role = "delete"
//MinimizeRole Role = "minimize"
//QuitRole Role = "quit"
//TogglefullscreenRole Role = "togglefullscreen"
//FileMenuRole Role = "fileMenu"
//ViewMenuRole Role = "viewMenu"
//WindowMenuRole Role = "windowMenu"
//HideRole Role = "hide"
//HideOthersRole Role = "hideOthers"
//UnhideRole Role = "unhide"
//FrontRole Role = "front"
//ZoomRole Role = "zoom"
//WindowSubMenuRole Role = "windowSubMenu"
//HelpSubMenuRole Role = "helpSubMenu"
//SeparatorItemRole Role = "separatorItem"
)
/*
// About provides a MenuItem with the About role
func About() *MenuItem {
return &MenuItem{
@@ -111,8 +113,8 @@ func Quit() *MenuItem {
}
}
// Togglefullscreen provides a MenuItem with the Togglefullscreen role
func Togglefullscreen() *MenuItem {
// ToggleFullscreen provides a MenuItem with the ToggleFullscreen role
func ToggleFullscreen() *MenuItem {
return &MenuItem{
Role: TogglefullscreenRole,
}
@@ -124,6 +126,7 @@ func FileMenu() *MenuItem {
Role: FileMenuRole,
}
}
*/
// EditMenu provides a MenuItem with the whole default "Edit" menu (Undo, Copy, etc.).
func EditMenu() *MenuItem {
@@ -132,6 +135,7 @@ func EditMenu() *MenuItem {
}
}
/*
// ViewMenu provides a MenuItem with the whole default "View" menu (Reload, Toggle Developer Tools, etc.)
func ViewMenu() *MenuItem {
return &MenuItem{
@@ -145,7 +149,7 @@ func WindowMenu() *MenuItem {
Role: WindowMenuRole,
}
}
*/
// These roles are Mac only
// AppMenu provides a MenuItem with the whole default "App" menu (About, Services, etc.)
@@ -155,6 +159,7 @@ func AppMenu() *MenuItem {
}
}
/*
// Hide provides a MenuItem that maps to the hide action.
func Hide() *MenuItem {
return &MenuItem{
@@ -169,8 +174,8 @@ func HideOthers() *MenuItem {
}
}
// Unhide provides a MenuItem that maps to the unhideAllApplications action.
func Unhide() *MenuItem {
// UnHide provides a MenuItem that maps to the unHideAllApplications action.
func UnHide() *MenuItem {
return &MenuItem{
Role: UnhideRole,
}

View File

@@ -2,6 +2,7 @@ package options
import (
"github.com/wailsapp/wails/v2/pkg/logger"
"github.com/wailsapp/wails/v2/pkg/menu"
)
// Default options for creating the App
@@ -11,3 +12,8 @@ var Default = &App{
Logger: logger.NewDefaultLogger(),
LogLevel: logger.INFO,
}
var defaultMacMenu = menu.NewMenuFromItems(
menu.AppMenu(),
menu.EditMenu(),
)

View File

@@ -1,12 +1,18 @@
package mac
type ActivationPolicy int
//type ActivationPolicy int
//
//const (
// NSApplicationActivationPolicyRegular ActivationPolicy = 0
// NSApplicationActivationPolicyAccessory ActivationPolicy = 1
// NSApplicationActivationPolicyProhibited ActivationPolicy = 2
//)
const (
NSApplicationActivationPolicyRegular ActivationPolicy = 0
NSApplicationActivationPolicyAccessory ActivationPolicy = 1
NSApplicationActivationPolicyProhibited ActivationPolicy = 2
)
type AboutInfo struct {
Title string
Message string
Icon []byte
}
// Options are options specific to Mac
type Options struct {
@@ -14,6 +20,7 @@ type Options struct {
Appearance AppearanceType
WebviewIsTransparent bool
WindowIsTranslucent bool
ActivationPolicy ActivationPolicy
//ActivationPolicy ActivationPolicy
About *AboutInfo
//URLHandlers map[string]func(string)
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"embed"
"log"
"runtime"
"github.com/wailsapp/wails/v2/pkg/options/mac"
"github.com/wailsapp/wails/v2/pkg/options/windows"
@@ -94,4 +95,11 @@ func MergeDefaults(appoptions *App) {
appoptions.Height = appoptions.MaxHeight
}
switch runtime.GOOS {
case "darwin":
if appoptions.Menu == nil {
appoptions.Menu = defaultMacMenu
}
}
}

View File

@@ -0,0 +1,161 @@
---
slug: wails-v2-beta-for-mac
title: Wails v2 Beta for MacOS
authors: [leaanthony]
tags: [wails, v2]
---
<div class="text--center">
<img src="/img/wails-mac.png" width="60%" style={{"box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px"}}/>
</div>
<br/>
Today marks the first beta release of Wails v2 for Mac! It's taken quite a while to get to this point and I'm hoping
that today's release will give you something that's reasonably useful. There have been a number of twists and turns
to get to this point and I'm hoping, with your help, to iron out the crinkles and get the Mac port polished for the
final v2 release.
You mean this isn't ready for production? For your use case, it may well be ready, but there are still a number of
known issues so keep your eye on [this project board](https://github.com/wailsapp/wails/projects/7) and if you would
like to contribute, you'd be very welcome!
So what's new for Wails v2 for Mac vs v1? Hint: It's pretty similar to the Windows Beta :wink:
### New Features
<div class="text--center">
<img src="/img/wails-menus-mac.png" width="80%" style={{"box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px"}}/>
</div>
<br/>
There were a lot of requests for native menu support. Wails has finally got you covered. Application menus are now available
and include support for most native menu features. This includes standard menu items, checkboxes, radio groups, submenus
and separators.
There were a huge number of requests in v1 for the ability to have greater control of the window itself.
I'm happy to announce that there's new runtime APIs specifically for this.
It's feature-rich and supports multi-monitor configurations. There is also an improved dialogs API: Now, you can have modern, native
dialogs with rich configuration to cater for all your dialog needs.
### Mac Specific Options
In addition to the normal application options, Wails v2 for Mac also brings some Mac extras:
- Make your window all funky and translucent, like all the pretty swift apps!
- Highly customisable titlebar
- We support the NSAppearance options for the application
- Simple config to auto-create an "About" menu
### No requirement to bundle assets
A huge pain-point of v1 was the need to condense your entire application down to single JS & CSS files. I'm happy to
announce that for v2, there is no requirement to bundle assets, in any way, shape or form. Want to load a local image? Use an
`<img>` tag with a local src path. Want to use a cool font? Copy it in and add the path to it in your CSS.
> Wow, that sounds like a webserver...
Yes, it works just like a webserver, except it isn't.
> So how do I include my assets?
You just pass a single `embed.FS` that contains all your assets into your application configuration.
They don't even need to be in the top directory - Wails will just work it out for you.
### New Development Experience
Now that assets don't need to be bundled, it's enabled a whole new development experience. The new `wails dev`
command will build and run your application, but instead of using the assets in the `embed.FS`, it loads them directly
from disk.
It also provides the additional features:
- Hot reload - Any changes to frontend assets will trigger and auto reload of the application frontend
- Auto rebuild - Any changes to your Go code will rebuild and relaunch your application
In addition to this, a webserver will start on port 34115. This will serve your application to any browser that
connects to it. All connected web browsers will respond to system events like hot reload on asset change.
In Go, we are used to dealing with structs in our applications. It's often useful to send structs to our frontend
and use them as state in our application. In v1, this was a very manual process and a bit of a burden on the
developer. I'm happy to announce that in v2, any application run in dev mode will automatically generate Typescript
models for all structs that are input or output parameters to bound methods. This enables seamless interchange of data
models between the two worlds.
In addition to this, another JS module is dynamically generated wrapping all your bound methods. This provides
JSDoc for your methods, providing code completion and hinting in your IDE. It's really cool when you get data models
auto-imported when hitting tab in an auto-generated module wrapping your Go code!
### Remote Templates
<div class="text--center">
<img src="/img/remote-mac.png" width="80%" style={{"box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px"}}/>
</div>
<br/>
Getting an application up and running quickly was always a key goal for the Wails project. When we launched, we tried
to cover a lot of the modern frameworks at the time: react, vue and angular. The world of frontend development is very
opinionated, fast moving and hard to keep on top of! As a result, we found our base templates getting out of date pretty
quickly and this caused a maintenance headache. It also meant that we didn't have cool modern templates for the latest
and greatest tech stacks.
With v2, I wanted to empower the community by giving you the ability to create and host templates yourselves, rather
than rely on the Wails project. So now you can create projects using community supported templates! I hope this will
inspire developers to create a vibrant ecosystem of project templates. I'm really quite excited about what our developer
community can create!
### Native M1 Support
Thanks to the amazing support of [Mat Ryer](https://github.com/matryer/), the Wails project now supports M1 native
builds:
<div class="text--center">
<img src="/img/build-darwin-arm.png" width="80%" style={{"box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px"}}/>
</div>
<br/>
You can also specify `darwin/amd64` as a target too:
<div class="text--center">
<img src="/img/build-darwin-amd.png" width="80%" style={{"box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px"}}/>
</div>
<br/>
Oh, I almost forgot.... you can also do `darwin/universal`.... :wink:
<div class="text--center">
<img src="/img/build-darwin-universal.png" width="80%" style={{"box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px"}}/>
</div>
<br/>
### Cross Compilation to Windows
Because Wails v2 for Windows is pure Go, you can target Windows builds without docker.
<div class="text--center">
<img src="/img/build-cross-windows.png" width="80%" style={{"box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px"}}/>
</div>
<br/>
### WKWebView Renderer
V1 relied on a (now deprecated) WebView component. V2 uses the most recent WKWebKit component so expect the latest and greatest from Apple.
### In Conclusion
As I'd said in the Windows release notes, Wails v2 represents a new foundation for the project.
The aim of this release is to get feedback on the new approach, and to iron out any bugs before a full release.
Your input would be most welcome! Please direct any feedback to the [v2 Beta](https://github.com/wailsapp/wails/discussions/828)
discussion board.
And finally, I'd like to give a special thank you to all the [project sponsors](/docs/credits#sponsors), including [JetBrains](https://www.jetbrains.com?from=Wails),
whose support drive the project in many ways behind the scenes.
I look forward to seeing what people build with Wails in this next exciting phase of the project!
Lea.
PS: Linux users, you're next!
PPS: If you or your company find Wails useful, please consider [sponsoring the project](https://github.com/sponsors/leaanthony). Thanks!

View File

@@ -7,8 +7,9 @@ sidebar_position: 1
## Supported Platforms
- Windows 10
- MacOS x64 & arm64 (due October '21)
- Linux (due December '21)
- MacOS 10.13+ (amd64)
- MacOS 11.0+ (arm64)
- Linux (due Jan '22)
## Dependencies
@@ -47,7 +48,11 @@ import TabItem from "@theme/TabItem";
{ label: "Linux", value: "Linux" },
]}
>
<TabItem value="MacOS">Coming Soon...</TabItem>
<TabItem value="MacOS">
Wails requires that the xcode command line tools are installed. This can be done by running:<br/>
<code>xcode-select --install</code>
</TabItem>
<TabItem value="Windows">
Wails requires that the <a href="https://developer.microsoft.com/en-us/microsoft-edge/webview2/">WebView2</a>{" "}
runtime is installed. Some Windows installations will already have this installed. You can check using the{" "}
@@ -62,7 +67,7 @@ import TabItem from "@theme/TabItem";
## Installing Wails
Run `go install github.com/wailsapp/wails/v2/cmd/wails@v2.0.0-beta.15` to install the Wails CLI.
Run `go install github.com/wailsapp/wails/v2/cmd/wails@v2.0.0-beta.16` to install the Wails CLI.
## System Check

View File

@@ -199,7 +199,7 @@ The format of the file is slightly different. Here is a comparison:
| frontend / serve | | Removed |
| tags | | Removed |
| | wailsjsdir | The directory to generate wailsjs modules |
| | assetdir | The directory of the frontend assets for `dev` mode |
| | assetdir | The directory of the compiled frontend assets for `dev` mode |
</p>

View File

@@ -74,6 +74,12 @@ Example:
`wails build -clean -o myproject.exe`
:::info UPX on Apple Silicon
There are [issues](https://github.com/upx/upx/issues/446) with using UPX with Apple Silicon.
:::
## doctor
`wails doctor` will run diagnostics to ensure that your system is ready for development.
@@ -134,6 +140,8 @@ Your system is ready for Wails development!
| -wailsjsdir | The directory to generate the generated Wails JS modules | Value in `wails.json` |
| -debounce | The time to wait for reload after an asset change is detected | 100 (milliseconds) |
| -devserverurl "url" | Use 3rd party dev server url, EG Vite | "http://localhost:34115" |
| -appargs "args" | Arguments passed to the application in shell style | |
| -platform "platform" | Platform/Arch to target | `runtime.GOOS` |
If the `assetdir`, `wailsjsdir`, `debounce` or `devserverurl` flags are provided on the command line, they are saved in
`wails.json`, and become the defaults for subsequent invocations.

View File

@@ -5,7 +5,7 @@ sidebar_position: 4
# Menus
It is possible to add an application menu to Wails projects. This is achieved by defining a [Menu](#menu) struct and
calling the runtime method [MenuSetApplicationMenu](/docs/reference/runtime/menu#menusetapplicationmenu).
setting the [`Menu`](/docs/reference/options#menu) option, or by calling the runtime method [MenuSetApplicationMenu](/docs/reference/runtime/menu#menusetapplicationmenu).
It is also possible to dynamically update the menu, by updating the menu struct and calling
[MenuUpdateApplicationMenu](/docs/reference/runtime/menu#menuupdateapplicationmenu).
@@ -79,6 +79,7 @@ type MenuItem struct {
| Checked | bool | Adds check to item (Checkbox & Radio types) |
| SubMenu | [\*Menu](#menu) | Sets the submenu |
| Click | [Callback](#callback) | Callback function when menu clicked |
| Role | string | Defines a [role](#roles) for this menu item. Mac only for now. |
### Accelerator
@@ -231,3 +232,19 @@ type CallbackData struct {
The function is given a `CallbackData` struct which indicates which menu item triggered the callback. This is useful when
using radio groups that may share a callback.
### Role
:::info Roles
Roles are currently supported on Mac only.
:::
A menu item may have a role, which is essentially a pre-defined menu item. We currently support the following roles:
| Role | Description |
| ---- | ----------- |
| AppMenuRole | The standard Mac application menu. Can be created using `menu.AppMenu()` |
| EditMenuRole | The standard Mac edit menu. Can be created using `menu.EditMenu()` |

View File

@@ -28,6 +28,7 @@ func main() {
StartHidden: false,
HideWindowOnClose: false,
RGBA: &options.RGBA{R: 0, G: 0, B: 0, A: 255},
AlwaysOnTop: false,
Assets: assets,
Menu: app.applicationMenu(),
Logger: nil,
@@ -43,6 +44,24 @@ func main() {
WindowIsTranslucent: false,
DisableWindowIcon: false,
},
Mac: &mac.Options{
TitleBar: &mac.TitleBar{
TitlebarAppearsTransparent: true,
HideTitle: false,
HideTitleBar: false,
FullSizeContent: false,
UseToolbar: false,
HideToolbarSeparator: true,
},
Appearance: mac.NSAppearanceNameDarkAqua,
WebviewIsTransparent: true,
WindowIsTranslucent: false,
About: &mac.AboutInfo{
Title: "My Application",
Message: "© 2021 Me",
Icon: icon,
},
},
})
if err != nil {
log.Fatal(err)
@@ -192,6 +211,8 @@ Type: \*menu.Menu
The menu to be used by the application. More details about Menus in the [Menu Reference](/docs/reference/runtime/menu).
NOTE: On Mac, if no menu is specified, a default menu will be created.
### Logger
Name: Logger
@@ -281,3 +302,153 @@ Name: DisableWindowIcon
Type: bool
Setting this to true will remove the icon in the top left corner of the title bar.
## Mac Specific Options
### TitleBar
Name: TitleBar
Type: [*mac.TitleBar](#titlebar-struct)
The TitleBar struct provides the ability to configure the look and feel of the title bar.
### Appearance
Name: Appearance
Type: [AppearanceType](#appearance-type)
Appearance is used to set the style of your app in accordance with Apple's [NSAppearance](https://developer.apple.com/documentation/appkit/nsappearancename?language=objc) names.
### WebviewIsTransparent
Name: WebviewIsTransparent
Type: bool
Setting this to `true` will make the webview background transparent when an alpha value of `0` is used.
This means that if you use `rgba(0,0,0,0)`, the host window will show through.
Often combined with [WindowIsTranslucent](#WindowIsTranslucent) to make frosty-looking applications.
### WindowIsTranslucent
Name: WindowIsTranslucent
Type: bool
Setting this to `true` will make the window background translucent. Often combined
with [WebviewIsTransparent](#WebviewIsTransparent) to make frosty-looking applications.
### About
Name: About
Type: [About](#about-struct)
This configuration lets you set the title, message and icon for the "About" menu item in the app menu created by the "AppMenu" role.
#### Titlebar struct
The titlebar of the application can be customised by using the TitleBar options:
```go
type TitleBar struct {
TitlebarAppearsTransparent bool
HideTitle bool
HideTitleBar bool
FullSizeContent bool
UseToolbar bool
HideToolbarSeparator bool
}
```
| Name | Description |
| ---- | ----------- |
| TitlebarAppearsTransparent | Makes the titlebar transparent. [Apple Docs](https://developer.apple.com/documentation/appkit/nswindow/1419167-titlebarappearstransparent?language=objc) |
| HideTitle | Hides the title of the window. [Apple Docs](https://developer.apple.com/documentation/appkit/nswindowtitlevisibility?language=objc) |
| HideTitleBar | Removes [NSWindowStyleMaskTitled](https://developer.apple.com/documentation/appkit/nswindowstylemask/nswindowstylemasktitled/) from the style mask |
| FullSizeContent | Makes the webview fill the entire window. [Apple Docs](https://developer.apple.com/documentation/appkit/nswindowstylemask/nswindowstylemaskfullsizecontentview)|
| UseToolbar | Adds a default toolbar to the window. [Apple Docs](https://developer.apple.com/documentation/appkit/nstoolbar?language=objc) |
| HideToolbarSeparator | Removes the line beneath the toolbar. [Apple Docs](https://developer.apple.com/documentation/appkit/nstoolbar/1516954-showsbaselineseparator?language=objc) |
Preconfigured titlebar settings are available:
| Setting | Example |
| ------- | ------- |
|`mac.TitleBarDefault()` | ![](/img/reference/titlebar-default.png) |
|`mac.TitleBarHidden()` | ![](/img/reference/titlebar-hidden.png) |
|`mac.TitleBarHiddenInset()` | ![](/img/reference/titlebar-hidden-inset.png) |
Example:
```go
Mac: &mac.Options{
TitleBar: mac.TitleBarHiddenInset(),
}
```
Click [here](https://github.com/lukakerr/NSWindowStyles) for some inspiration on customising the titlebar.
#### Appearance type
You can specify the application's [appearance](https://developer.apple.com/documentation/appkit/nsappearance?language=objc).
| Value | Description |
| --------------- | ------------------ |
| DefaultAppearance | DefaultAppearance uses the default system value |
| NSAppearanceNameAqua | The standard light system appearance |
| NSAppearanceNameDarkAqua | The standard dark system appearance |
| NSAppearanceNameVibrantLight | The light vibrant appearance |
| NSAppearanceNameAccessibilityHighContrastAqua | A high-contrast version of the standard light system appearance |
| NSAppearanceNameAccessibilityHighContrastDarkAqua | A high-contrast version of the standard dark system appearance |
| NSAppearanceNameAccessibilityHighContrastVibrantLight | A high-contrast version of the light vibrant appearance |
| NSAppearanceNameAccessibilityHighContrastVibrantDark | A high-contrast version of the dark vibrant appearance |
Example:
```go
Mac: &mac.Options{
Appearance: mac.NSAppearanceNameDarkAqua,
}
```
#### About struct
```go
type AboutInfo struct {
Title string
Message string
Icon []byte
}
```
If these settings are provided, an "About" menu item will appear in the app menu (when using the `AppMenu` role).
Given this configuration:
```go
//go:embed build/appicon.png
var icon []byte
func main() {
err := wails.Run(&options.App{
...
Mac: &mac.Options{
About: &mac.AboutInfo{
Title: "My Application",
Message: "© 2021 Me",
Icon: icon,
},
},
})
```
The "About" menu item will appear in the app menu:
<div class="text--center">
<img src="/img/reference/about-menu.png" style={{"box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px"}}/>
</div>
<br/>
When clicked, that will open an about message box:
<div class="text--center">
<img src="/img/reference/about-dialog.png" width="40%" style={{"box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px"}}/>
</div>
<br/>

View File

@@ -9,7 +9,7 @@ The project config resides in the `wails.json` file in the project directory. Th
```json
{
"name": "[The project name]",
"assetdir": "[Relative path to your assets directory]",
"assetdir": "[Relative path to the directory containing the compiled assets]",
"frontend:install": "[The command to install node dependencies, run in the frontend directory - often `npm install`]",
"frontend:build": "[The command to build the assets, run in the frontend directory - often `npm run build`]",
"frontend:dev": "[This command is run in a separate process on `wails dev`. Useful for 3rd party watchers]",
@@ -17,7 +17,9 @@ The project config resides in the `wails.json` file in the project directory. Th
"version": "[Project config version]",
"outputfilename": "[The name of the binary]",
"debounceMS": 100, // The default time the dev server waits to reload when it detects a vhange in assets
"devserverurl": "[URL to the dev server serving local assets. Default: http://localhost:34115]"
"devserverurl": "[URL to the dev server serving local assets. Default: http://localhost:34115]",
"appargs": "[Arguments passed to the application in shell style when in dev mode]"
}
```

View File

@@ -63,7 +63,7 @@ const darkCodeTheme = require('prism-react-renderer/themes/palenight');
({
announcementBar: {
id: 'beta-message',
content: 'Wails v2 is currently Beta for Windows. Mac & Linux in progress.',
content: 'Wails v2 is currently Beta for Windows & Mac. Linux in progress.',
backgroundColor: '#b00',
textColor: '#FFF',
isCloseable: false,

View File

@@ -10,7 +10,7 @@ sidebar_position: 1
Wails 是一个可让您使用 Go 和 Web 技术编写桌面应用的项目。
将它看作为轻量快速的 Electron for Go”。 您可以使用 Go 的灵活性和强大功能,结合丰富的现代前端,轻松的构建应用程序。
将它看作为 Go 的轻量级和快速的 Electron 替代品。 您可以使用 Go 的灵活性和强大功能,结合丰富的现代前端,轻松的构建应用程序。
Wails 一点也不弱!这是 [xbar](https://xbarapp.com) - 一个使用 Wails 编写的 MacOS 桌面应用。它使用 Mac 的系统原生菜单,支持浅色和深色桌面主题,主窗口使用半透明,使其具有原生应用的
“冰霜” 效果。
@@ -31,13 +31,13 @@ Wails 自动使您的 Go 方法可用于 Javascript因此您可以从前端
## 运行时库
Wails 为 Go 和 Javascript 提供了一个运行时库,可以处理现代应用程序需要的很多东西,比如事件、日志记录、对话框等。
Wails 为 Go 和 Javascript 提供了一个运行时库,可以处理现代应用程序需要的很多东西,比如事件、日志、对话框等。
## 实时开发体验
### 自动重新构建
当您在“dev模式下运行您的应用程序时Wails 会将您的应用程序构建为原生桌面应用程序,但会从磁盘读取您的资源。它将检测您的 Go 代码的任何更改,并自动重新构建和重新启动您的应用程序。
当您在“dev模式下运行您的应用程序时Wails 会将您的应用程序构建为原生桌面应用程序,但会从磁盘读取您的资源。它将检测您的 Go 代码的任何更改,并自动重新构建和重新启动您的应用程序。
### 自动重新加载
@@ -47,7 +47,7 @@ Wails 为 Go 和 Javascript 提供了一个运行时库,可以处理现代应
如果您更喜欢在浏览器中调试和开发,那么 Wails 可以满足您的需求。正在运行的应用程序还有一个网络服务器,它将在连接到它的任何浏览器中运行您的应用程序。当您的资源在磁盘上发生变化时,它会刷新。
## 生成原生二进制文件
## 可用于生产的原生二进制文件
当您准备好完成应用程序的最终构建时CLI 会将其编译为单个可执行文件,并将所有资源打包到其中。在 Windows 和 MacOS
可以创建用于分发的原生包。使用打包工具后生成的资源图标、info.plist、清单文件等是您项目的一部分可以自定义让您完全控制应用程序的构建方式。

View File

@@ -11,7 +11,7 @@ sidebar_position: 2
- [Gophers Slack Channel](https://gophers.slack.com/messages/CJ4P9F7MZ/)
- [Gophers Slack Channel Invite](https://invite.slack.golangbridge.org/)
- [Github Issues](https://github.com/wailsapp/wails/issues)
- [v2 Beta Discussion Board](https://github.com/wailsapp/wails/discussions/828)
- [v2 测试版讨论板](https://github.com/wailsapp/wails/discussions/828)
## 社交媒体

View File

@@ -23,3 +23,7 @@ sidebar_position: 1
- [wails-template-vue](https://github.com/misitebao/wails-template-vue) - 基于 Vue 和 Vue-Router 的 Wails 模板
- [wails-vite-vue-ts](https://github.com/codydbentley/wails-vite-vue-ts) - 使用 Vite 的 Vue 3 TypeScript(以及添加功能的说明)
- [wails-vite-vue-the-works](https://github.com/codydbentley/wails-vite-vue-the-works) - 使用 Vite, Vuex, Vue Router, Sass, 和 ESLint + Prettier 的 Vue 3 TypeScript
## Angular
- [wails-angular-template](https://github.com/TAINCER/wails-angular-template) - 带有 TypeScript, Sass, 热重载, 代码拆分和 i18n 的 Angular

View File

@@ -20,6 +20,9 @@ sidebar_position: 99
<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">
@@ -58,15 +61,27 @@ sidebar_position: 99
<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">
<img src="https://github.com/marcus-crane.png?size=50" width="50"/>
</a>
<a href="https://github.com/codydbentley" style="width:65px">
<img src="https://github.com/codydbentley.png?size=65" width="65"/>
<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>
`,
}}
/>

View File

@@ -46,6 +46,6 @@ Wails 项目具有以下布局:
`frontend`目录没有特定于 Wails 的内容,可以是您选择的任何前端项目。
`build`目录在构建过程中使用。这些文件可以更新以自定义您的构建。如果文件从构建目录中删除,将重新生成默认版本。
`build`目录在构建过程中使用。这些文件可以修改以自定义您的构建。如果文件从构建目录中删除,将重新生成默认版本。
`go.mod`中的默认模块名称是“changeme”。您应该将其更改为更合适的内容。

View File

@@ -30,7 +30,7 @@ Wails 有许多安装前需要的常见依赖项:
从[Node 下载页面](https://nodejs.org/en/download/)下载 Npm。最好使用最新版本因为这是我们通常会测试的版本。
运行 `npm --version` 进行验。
运行 `npm --version` 进行验
## 平台指定依赖关系
@@ -63,7 +63,7 @@ import TabItem from "@theme/TabItem";
## 安装 Wails
运行 `go install github.com/wailsapp/wails/v2/cmd/wails@v2.0.0-beta.15` 安装 Wails CLI。
运行 `go install github.com/wailsapp/wails/v2/cmd/wails@v2.0.0-beta.16` 安装 Wails CLI。
## 系统检查

View File

@@ -146,3 +146,20 @@ Wails v2 处理资源的方式的伟大之处在于它没有!您唯一需要
第一个,如果有给定,将在`frontend`目录中执行以安装 node 模块。第二个,如果有给定,将在`frontend`目录中执行以构建前端项目。
如果没有给出这两个字段,那么 Wails 不会对前端做任何操作。它仅仅被用作`embed.FS`。
## 内置开发服务器
运行`wails dev`将启动内置的开发服务器,它将在您的项目目录中启动一个文件监听器。
默认情况下如果有任何文件更改wails 会检查它是否是应用程序文件(默认:.go可使用`-e`标志配置)。如果是,那么它将重新构建您的应用程序并重新启动它。如果更改的文件在`assetdir`目录中,它会在很短的时间后重新加载。
开发服务器使用一种称为“防抖”的技术,这意味着它不会立即重新加载,因为可能会在短时间内更改多个文件。当触发发生时,它会在发出重新加载之前等待一定的时间。
如果发生另一个触发,它会再次重置为等待时间。默认情况下,此值为 100ms。如果此值不适用于您的项目则可以使用`-debounce`标志进行配置。如果使用,此值将保存到您的项目配置中并成为默认值。
## 外部开发服务器
一些框架带有自己的实时重新加载服务器,但是它们将无法利用 Wails Go 绑定。在这种情况下最好运行一个监听脚本将项目重新构建到构建目录中Wails 将监视该目录。
有关示例,请参阅使用[rollup](https://rollupjs.org/guide/en/)的默认 svelte 模板。对于[create-react-app](https://create-react-app.dev/),可以使用[此脚本](https://gist.github.com/int128/e0cdec598c5b3db728ff35758abdbafd)来实现类似的结果。
## Go 模块
默认的 Wails 模板会生成一个包含模块名称“changeme”的`go.mod`文件。您应该在项目生成后将其更改为更合适的内容。

View File

@@ -25,3 +25,7 @@ Wails 为拖动窗口提供了一个简单的解决方案任何具有“data-
</body>
</html>
```
:::info 全屏
如果您允许应用程序全屏显示,则此拖动功能将被禁用。
:::

View File

@@ -0,0 +1,9 @@
# 滚动超出
[Overscroll](https://developer.mozilla.org/zh-CN/docs/Web/CSS/overscroll-behavior) 是当您滚动超出页面内容边界时有时会获得的“弹跳效果”。这在移动应用程序中很常见。这可以使用 CSS 禁用:
```css
body {
overscroll-behavior: none;
}
```

View File

@@ -89,3 +89,4 @@ Renaming package-lock.json -> package-lock.tmpl.json...
- 确保`template.json`完整,尤其是`helpurl`
- 将文件推送到 GitHub
- 在[社区模板](/docs/community/templates)页面上创建 PR
- 在[模板公告](https://github.com/wailsapp/wails/discussions/825)讨论板上发布模板

View File

@@ -9,10 +9,10 @@
通过在构建时使用`-webview2`标志,您可以决定在未检测到合适的运行时的时候(包括安装的运行时是否太旧)应用程序将执行的操作。四个选项是:
1. 下载
2. 内嵌
3. 浏览器
4. 错误
1. Download下载
2. Embed内嵌
3. Browser浏览器
4. Error错误
### 下载

View File

@@ -17,7 +17,7 @@ Wails 应用程序是一个带有一个 webkit 前端的标准的 Go 应用程
### 概述
主应用程序由对`wails.Run()`的调用组成. 它接受描述应用程序窗口大小、窗口标题、要使用的资源等应用程序配置。基本应用程序可能如下所示:
主应用程序由对`wails.Run()`的调用组成. 它接受描述应用程序窗口大小、窗口标题、要使用的资源等应用程序配置。基本应用程序可能如下所示:
```go title="main.go"
package main
@@ -85,7 +85,7 @@ func (b *App) Greet(name string) string {
#### 资源
`Assets` 选项是必须的,因为您不能拥有没有前端资源的 Wails 应用程序。这些资源可以是您希望在 Web 应用程序中找到的任何文件 - html、js、css、svg、png 等。
**不需要生成资源包**- 纯文件即可。当应用程序启动时,它将尝试从您的资源中加载`index.html`,并且那时起前端基本上将作为浏览器工作。值得注意的是 embed.FS
**不需要生成资源包**- 纯文件即可。当应用程序启动时,它将尝试从您的资源中加载`index.html`,并且那时起前端基本上将作为浏览器工作。值得注意的是`embed.FS`
文件所在的位置没有要求。嵌入路径很可能使用了相对于您的主应用程序代码的嵌套目录,例如 `frontend/dist`
```go title="main.go"
@@ -95,10 +95,12 @@ var assets embed.FS
启动时Wails 将遍历嵌入的文件,寻找包含的`index.html`. 所有其他资源将相对于该目录加载。
由于生产二进制文件使用包含在`embed.FS`的文件,因此应用程序不需要附带任何外部文件。
由于可用于生产二进制文件使用包含在`embed.FS`的文件,因此应用程序不需要附带任何外部文件。
当使用`wails dev`命令在”dev“模式下资源从磁盘加载任何更改都会导致“实时重新加载”。资源的位置需要使用`-assetdir`传递给`wails dev`命令,并且很可能与嵌入路径相同。
希望`embed.FS`将来我们可以从它本身计算出来。更多细节可以在[应用程序开发指南](/docs/guides/application-development)中找到
希望将来我们可以从`embed.FS`本身计算出来
更多细节可以在[应用程序开发指南](/docs/guides/application-development)中找到。
#### 应用程序生命周期回调

View File

@@ -13,25 +13,27 @@ Wails CLI 有许多用于管理项目的命令。所有命令都以此方式运
`wails init` 用于生成项目。
| 标志 | 描述 | 默认 |
| :----------------- | :------------------------------------------------------------------ | :------ |
| -n "project name" | 项目名. **强制必填**. | |
| -d "project dir" | 要创建的项目目录 | 项目名 |
| -g | 初始化 git 存储库 | |
| -l | 可用项目模板列表 | |
| -q | 禁止输出到控制台 | |
| -t "template name" | 要使用的项目模板。这可能是在 github 上托管的远程模板的 URL 的名称。 | vanilla |
| -ide | 生成 IDE 项目文件 | |
| -f | 强制构建应用 | false |
| 标志 | 描述 | 默认 |
| :----------------- | :---------------------------------------------------------------------------------- | :------ |
| -n "project name" | 项目名. **强制必填**. | |
| -d "project dir" | 要创建的项目目录 | 项目名 |
| -g | 初始化 git 存储库 | |
| -l | 可用项目模板列表 | |
| -q | 禁止输出到控制台 | |
| -t "template name" | 要使用的项目模板。这可能是默认模板的名称或在 github 上托管的远程模板的 URL 的名称。 | vanilla |
| -ide | 生成 IDE 项目文件 | |
| -f | 强制构建应用 | false |
示例:
`wails init -n test -d mytestproject -g -ide vscode -q`
这将在 "mytestproject" 目录生成一个名为 "test" 的项目,初始化 git生成 vscode 项目文件并静默执行。
可以在[此处](/docs/guides/ides)找到有关在 Wails 中使用 IDE 的更多信息。
### 远程模板
支持远程模板(托管在 GitHub 上)并且可以使用模板项目 URL 进行安装。
支持远程模板(托管在 GitHub 上)并且可以使用模板项目 URL 进行安装。
示例: `wails init -n test -t https://github.com/leaanthony/testtemplate`
@@ -66,6 +68,10 @@ Wails CLI 有许多用于管理项目的命令。所有命令都以此方式运
如果您更喜欢使用标准 Go 工具进行构建,请参阅[手动构建](/docs/guides/manual-builds)指南。
示例:
`wails build -clean -o myproject.exe`
## 诊断检查
`wails doctor` 将运行诊断程序以确保您的系统已准备好进行开发。
@@ -111,23 +117,25 @@ Your system is ready for Wails development!
- 所有应用程序资源都从磁盘加载。如果它们被更改,应用程序将自动重新加载(而不是重新构建)。所有连接的浏览器也将重新加载
- 生成的 JS 模块提供以下内容:
- 带有自动生成的 JSDoc 的 Go 方法的 Javascript 包装器,提供代码提示
- 的 Go 结构体的 TypeScript 版本,可以构造并传递给您的后端方法
- 的 Go 结构体的 TypeScript 版本,可以构造并传递给您的 Go 方法
- 生成第二个 JS 模块,为运行时提供包装器 + TS 声明
| 标志 | 描述 | 默认 |
| :--------------------------- | :---------------------------------------------------- | :-------------------------- |
| -assetdir "./path/to/assets" | 编译资源的路径 | Value in `wails.json` |
| -browser | `http://localhost:34115`在启动时打开浏览器 | |
| -compiler "compiler" | 使用不同的 go 编译器来构建,例如 go1.15beta1 | go |
| -e | 触发重建的扩展(逗号分隔) | go |
| -ldflags "flags" | 传递给编译器的额外 ldflags | |
| -tags "extra tags" | 构建标签以传递给编译器(引号和空格分隔) | |
| -loglevel "loglevel" | 要使用的日志级别 - Trace, Debug, Info, Warning, Error | Debug |
| -noreload | 资源更改时禁用自动重新加载 | |
| -v | 详细级别 (0 - silent, 1 - standard, 2 - verbose) | 1 |
| -wailsjsdir | 生成生成的 Wails JS 模块的目录 | Value store in `wails.json` |
| 标志 | 描述 | 默认 |
| :--------------------------- | :---------------------------------------------------- | :----------------------- |
| -assetdir "./path/to/assets" | 编译资源的路径 | `wails.json`中的值 |
| -browser | 在启动时打开浏览器到`http://localhost:34115` | |
| -compiler "compiler" | 使用不同的 go 编译器来构建,例如 go1.15beta1 | go |
| -e | 触发重新构建的扩展(逗号分隔) | go |
| -ldflags "flags" | 传递给编译器的额外 ldflags | |
| -tags "extra tags" | 构建标签以传递给编译器(引号和空格分隔) | |
| -loglevel "loglevel" | 要使用的日志级别 - Trace, Debug, Info, Warning, Error | Debug |
| -noreload | 资源更改时禁用自动重新加载 | |
| -v | 详细级别 (0 - silent, 1 - standard, 2 - verbose) | 1 |
| -wailsjsdir | 生成生成的 Wails JS 模块的目录 | `wails.json`中的值 |
| -debounce | 检测到资源更改后等待重新加载的时间 | 100 (毫秒) |
| -devserverurl "url" | 使用第 3 方开发服务器 url, 例如 Vite | "http://localhost:34115" |
如果在命令行上提供了`-assetdir``-wailsjsdir`标志,它们将保存在`wails.json`中,并成为后续调用的默认值。
如果在命令行上提供了`-assetdir``-wailsjsdir``debounce`或`devserverurl`标志,它们将保存在`wails.json`中,并成为后续调用的默认值。
示例:
@@ -136,10 +144,12 @@ Your system is ready for Wails development!
此命令将执行以下操作:
- 构建应用程序并运行它(更多细节在[这里](/docs/guides/manual-builds)
- 生成 Wails JS 模块 ``./frontend/src`
- 注意文件的更新`./frontend/dist`并在任何更改时重新加载
- `./frontend/src`中生成 Wails JS 模块
- 监听`./frontend/dist`中文件的更新并在更改时重新加载
- 打开浏览器并连接到应用程序
[此处](/docs/guides/application-development)提供了有关将此功能与现有框架脚本一起使用的更多信息。
## 生成
### 模板

View File

@@ -155,6 +155,14 @@ func main() {
该值是默认设置窗口的 RGBA 值。默认值0xFFFFFFFF。
### 窗口固定在最顶层
名称AlwaysOnTop
类型bool
窗口在失去焦点时应保持在其他窗口之上。
### 资源
名称Assets
@@ -219,7 +227,7 @@ func main() {
定义需要绑定到前端的方法的一部分结构实例。
### 窗口
### Windows
名称Windows
@@ -235,7 +243,7 @@ func main() {
类型bool
将此设置为 true 将使 webview 背景透明,其中没有其他颜色呈现。通常与[窗口半透明](#窗口半透明)结合使用 以制作外观现代的应用程序。
当 alpha 值为 0 时,设置为 true 将使 WebView 背景透明。这意味着如果你使用`rgba(0,0,0,0)`,主窗口将显示。通常与[窗口半透明](#窗口半透明)结合使用以制作冰霜效果的应用程序。
### 窗口半透明
@@ -243,7 +251,7 @@ func main() {
类型bool
将此设置为 true 将使窗口半透明。通常与[网页透明](#网页透明) 结合使用以制作外观现代的应用程序。
将此设置为 true 将使窗口半透明。通常与[网页透明](#网页透明) 结合使用以制作冰霜效果的应用程序。
### 禁用窗口图标

View File

@@ -11,13 +11,16 @@ sidebar_position: 5
"name": "[项目名称]",
"assetdir": "[资源目录的相对路径]",
"frontend:install": "[安装node依赖的命令在frontend目录下运行 - 通常是 `npm install`]",
"frontend:dev": "[此命令在“Wails dev”上的单独进程中运行。适用于第三方观察者]",
"frontend:build": "[构建资源的命令在frontend目录下运行 - 通常是 `npm run build`]",
"wailsjsdir": "[自动生成的JS模块将被创建的目录的相对路径]",
"version": "[项目配置版本]",
"outputfilename": "[二进制文件的名称]"
"outputfilename": "[二进制文件的名称]",
"debounceMS": 100, // 在检测到资源更改时,开发服务器等待重新加载的时间
"devserverurl": "[用于服务本地资源的开发服务器URL。默认http://localhost:34115]"
}
```
该文件将在运行`wails build`或`wails dev`时,由 Wails CLI 读取。
`wails build/dev`命令中的`assetdir``wailsjsdir`标志将覆盖项目配置并作为后续运行的默认值。
`wails build/dev`命令中的`assetdir`,`wailsjsdir`,`debounceMS`和`devserverurl`标志将覆盖项目配置并作为后续运行的默认值。

View File

@@ -15,44 +15,44 @@ JS 运行时当前不支持 Dialog。
### 打开选择目录对话框
打开一个对话框,提示用户选择目录。可以使用 [打开选择文件对话框参数选项](#打开选择文件对话框参数选项)进行自定义。
Go 方法签名: `OpenDirectoryDialog(ctx context.Context, dialogOptions OpenDialogOptions) (string, error)`
返回值: 所选目录(如果用户取消则为空白)或错误
打开一个对话框,提示用户选择目录。可以使用 [打开选择文件对话框参数选项](#打开选择文件对话框参数选项)进行自定义。
### 打开选择文件对话框
打开一个对话框,提示用户选择文件。可以使用[打开选择文件对话框参数选项](#打开选择文件对话框参数选项)进行自定义。
Go 方法签名: `OpenFileDialog(ctx context.Context, dialogOptions OpenDialogOptions) (string, error)`
返回值: 所选文件(如果用户取消则为空白)或错误
打开一个对话框,提示用户选择文件。可以使用[打开选择文件对话框参数选项](#打开选择文件对话框参数选项)进行自定义。
### 打开选择多个文件对话框
打开一个对话框,提示用户选择多个文件。可以使用[打开选择文件对话框参数选项](#打开选择文件对话框参数选项)进行自定义。
Go 方法签名: `OpenMultipleFilesDialog(ctx context.Context, dialogOptions OpenDialogOptions) ([]string, error)`
返回值: 选定的文件(如果用户取消则为零)或错误
打开一个对话框,提示用户选择多个文件。可以使用[打开选择文件对话框参数选项](#打开选择文件对话框参数选项)进行自定义。
### 保存文件对话框
打开一个对话框,提示用户选择文件名以进行保存。可以使用[保存文件对话框参数选项](#保存文件对话框参数选项)自定义。
Go 方法签名: `SaveFileDialog(ctx context.Context, dialogOptions SaveDialogOptions) (string, error)`
返回值: 所选文件(如果用户取消则为空白)或错误
打开一个对话框,提示用户选择文件名以进行保存。可以使用[保存文件对话框参数选项](#保存文件对话框参数选项)自定义。
### 消息对话框
使用消息对话框显示消息。可以使用[消息对话框参数选项](#消息对话框参数选项)进行自定义。
Go 方法签名: `MessageDialog(ctx context.Context, dialogOptions MessageDialogOptions) (string, error)`
返回值: 所选按钮的文本或错误
使用消息对话框显示消息。可以使用[消息对话框参数选项](#消息对话框参数选项)进行自定义。
## 参数选项
### 打开选择文件对话框参数选项
@@ -63,15 +63,28 @@ type OpenDialogOptions struct {
DefaultFilename string
Title string
Filters []FileFilter
AllowFiles bool // Mac Only
AllowDirectories bool // Mac Only
ShowHiddenFiles bool // Mac Only
CanCreateDirectories bool // Mac Only
ResolvesAliases bool // Mac Only
TreatPackagesAsDirectories bool // Mac Only
AllowFiles bool
AllowDirectories bool
ShowHiddenFiles bool
CanCreateDirectories bool
ResolvesAliases bool
TreatPackagesAsDirectories bool
}
```
| 字段 | 描述 | Win | Mac |
| -------------------------- | --------------------------------- | --- | --- |
| DefaultDirectory | 对话框打开时显示的目录 | ✅ | ✅ |
| DefaultFilename | 默认文件名 | ✅ | ✅ |
| Title | 对话框的标题 | ✅ | ✅ |
| [Filters](#文件过滤) | 文件过滤器列表 | ✅ | ✅ |
| AllowFiles | 允许选择文件 | | ✅ |
| AllowDirectories | 允许选择目录 | | ✅ |
| ShowHiddenFiles | 显示系统隐藏的文件 | | ✅ |
| CanCreateDirectories | 允许用户创建目录 | | ✅ |
| ResolvesAliases | 如果为 true则返回文件而不是别名 | | ✅ |
| TreatPackagesAsDirectories | 允许导航到包 | | ✅ |
### 保存文件对话框参数选项
```go
@@ -80,12 +93,22 @@ type SaveDialogOptions struct {
DefaultFilename string
Title string
Filters []FileFilter
ShowHiddenFiles bool // Mac Only
CanCreateDirectories bool // Mac Only
TreatPackagesAsDirectories bool // Mac Only
ShowHiddenFiles bool
CanCreateDirectories bool
TreatPackagesAsDirectories bool
}
```
| 字段 | 描述 | Win | Mac |
| -------------------------- | ---------------------- | --- | --- |
| DefaultDirectory | 对话框打开时显示的目录 | ✅ | ✅ |
| DefaultFilename | 默认文件名 | ✅ | ✅ |
| Title | 对话框的标题 | ✅ | ✅ |
| [Filters](#文件过滤) | 文件过滤器列表 | ✅ | ✅ |
| ShowHiddenFiles | 显示系统隐藏的文件 | | ✅ |
| CanCreateDirectories | 允许用户创建目录 | | ✅ |
| TreatPackagesAsDirectories | 允许导航到包 | | ✅ |
### 消息对话框参数选项
```go
@@ -94,30 +117,96 @@ type MessageDialogOptions struct {
Title string
Message string
Buttons []string
DefaultButton string // Mac Only
CancelButton string // Mac Only
Icon string // Mac Only
DefaultButton string
CancelButton string
}
```
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
| 字段 | 描述 | Win | Mac |
| ------------- | ---------------------------------------------------- | --- | --- |
| Type | 消息对话框的类型,例如问题、信息... | ✅ | ✅ |
| Title | 对话框的标题 | ✅ | ✅ |
| Message | 向用户显示的消息 | ✅ | ✅ |
| Buttons | 按钮标题列表 | | ✅ |
| DefaultButton | 带有此文本的按钮应被视为默认按钮。 Bound to `return` | | ✅ |
| CancelButton | 带有此文本的按钮应被视为取消。Bound to `escape` | | ✅ |
<Tabs
defaultValue="Windows"
values={[
{ label: "Windows", value: "Windows" },
{ label: "MacOS", value: "MacOS" },
{ label: "Linux", value: "Linux" },
]}
>
<TabItem value="Windows">
Windows
具有标准对话框类型并且按钮不可定制。返回的值将是以下之一:“确定”、“取消”、“中止”、“重试”、“忽略”、“是”、“否”、“再试一次”或“继续”
</TabItem>
<TabItem value="MacOS">“DefaultButton”和“CancelButton”都应与“Buttons”中的值匹配。</TabItem>
<TabItem value="Linux">即将推出...</TabItem>
</Tabs>
#### Windows
Windows 具有标准对话框类型,其中的按钮不可自定义。
返回的值将是以下之一:"Ok", "Cancel", "Abort", "Retry", "Ignore", "Yes", "No", "Try Again" or "Continue"
#### Mac
Mac 上的消息对话框最多可以指定 4 个按钮。如果没有`DefaultButton`或`CancelButton`给出,第一个按钮被认为是默认的并绑定到`return`键。
对于以下代码:
```go
selection, err := runtime.MessageDialog(b.ctx, runtime.MessageDialogOptions{
Title: "It's your turn!",
Message: "Select a number",
Buttons: []string{"one", "two", "three", "four"},
})
```
第一个按钮显示为默认值:
<div class="text--center">
<img
src="/img/runtime/dialog_no_defaults.png"
width="30%"
style={{ "box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px" }}
/>
</div>
<br />
如果我们指定`DefaultButton`为“two”
```go
selection, err := runtime.MessageDialog(b.ctx, runtime.MessageDialogOptions{
Title: "It's your turn!",
Message: "Select a number",
Buttons: []string{"one", "two", "three", "four"},
DefaultButton: "two",
})
```
第二个按钮显示为默认值。当 `return` 被按下时则返回数值“two”。
<div class="text--center">
<img
src="/img/runtime/dialog_default_button.png"
width="30%"
style={{ "box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px" }}
/>
</div>
<br />
如果我们现在指定`CancelButton`为“three”
```go
selection, err := runtime.MessageDialog(b.ctx, runtime.MessageDialogOptions{
Title: "It's your turn!",
Message: "Select a number",
Buttons: []string{"one", "two", "three", "four"},
DefaultButton: "two",
CancelButton: "three",
})
```
带有“three”的按钮显示在对话框的底部。当`escape`被按下时则返回值“three”
<div class="text--center">
<img
src="/img/runtime/dialog_default_cancel.png"
width="30%"
style={{ "box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px" }}
/>
</div>
<br />
<br />
<br />
#### 对话框类型
@@ -138,3 +227,41 @@ type FileFilter struct {
Pattern string // semi-colon separated list of extensions, EG: "*.jpg;*.png"
}
```
#### Windows
Windows 允许您在对话框中使用多个文件过滤器。每个 FileFilter 将在对话框中显示为一个单独的条目:
<div class="text--center">
<img
src="/img/runtime/dialog_win_filters.png"
width="50%"
style={{ "box-shadow": "rgb(255 255 255 / 20%) 0px 4px 8px 0px, rgb(104 104 104) 0px 6px 20px 0px" }}
/>
</div>
<br />
<br />
<br />
#### Mac
Mac 对话框只有一组模式来过滤文件的概念。如果提供了多个 FileFiltersWails 将使用所有定义的模式。
示例:
```go
selection, err := runtime.OpenFileDialog(b.ctx, runtime.OpenDialogOptions{
Title: "Select File",
Filters: []runtime.FileFilter{
{
DisplayName: "Images (*.png;*.jpg)",
Pattern: "*.png;*.jpg",
}, {
DisplayName: "Videos (*.mov;*.mp4)",
Pattern: "*.mov;*.mp4",
},
},
})
```
这将导致使用`*.png,*.jpg,*.mov,*.mp4`作为过滤器打开文件对话框。

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="50%" height="50%" viewBox="0 0 150 124" version="1.1" xmlns="http://www.w3.org/2000/svg"
<svg width="50%" height="50%" viewBox="0 0 150 150" version="1.1" xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1.2207,0,0,1.21688,0,0)">

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="50%" height="50%" viewBox="0 0 150 125" version="1.1" xmlns="http://www.w3.org/2000/svg"
<svg width="50%" height="50%" viewBox="0 0 150 150" version="1.1" xmlns="http://www.w3.org/2000/svg"
xml:space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<g transform="matrix(1.2207,0,0,1.21688,0,0)">

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 514 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB