5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-02 02:49:29 +08:00

Initial implementation of runtime over http

This commit is contained in:
Lea Anthony 2023-01-27 21:05:53 +11:00
parent 8534b32a9f
commit 14b201bb65
No known key found for this signature in database
GPG Key ID: 33DAF7BB90A58405
22 changed files with 629 additions and 262 deletions

6
go.work Normal file
View File

@ -0,0 +1,6 @@
go 1.19
use (
v2
v3
)

View File

@ -6,16 +6,19 @@ github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keL
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/renameio/v2 v2.0.0 h1:UifI23ZTGY8Tt29JbYFiuyIU3eX+RNFtUwefq9qAhxg=
github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc=
github.com/klauspost/cpuid/v2 v2.2.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/sftp v1.10.1 h1:VasscCm72135zRysgrJDKsntdmPN+OuU3+nnHYA9wyc=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=

View File

@ -14,6 +14,7 @@ import (
const (
runtimeJSPath = "/wails/runtime.js"
ipcJSPath = "/wails/ipc.js"
runtimePath = "/wails/runtime"
)
type RuntimeAssets interface {
@ -22,6 +23,10 @@ type RuntimeAssets interface {
RuntimeDesktopJS() []byte
}
type RuntimeHandler interface {
HandleRuntimeCall(w http.ResponseWriter, r *http.Request)
}
type AssetServer struct {
handler http.Handler
wsHandler http.Handler
@ -34,6 +39,9 @@ type AssetServer struct {
servingFromDisk bool
appendSpinnerToBody bool
// Use http based runtime
runtimeHandler RuntimeHandler
assetServerWebView
}
@ -77,6 +85,10 @@ func NewAssetServerWithHandler(handler http.Handler, bindingsJSON string, servin
return result, nil
}
func (d *AssetServer) UseRuntimeHandler(handler RuntimeHandler) {
d.runtimeHandler = handler
}
func (d *AssetServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if isWebSocket(req) {
// Forward WebSockets to the distinct websocket handler if it exists
@ -122,6 +134,13 @@ func (d *AssetServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
case runtimeJSPath:
d.writeBlob(rw, path, d.runtimeJS)
case runtimePath:
if d.runtimeHandler != nil {
d.runtimeHandler.HandleRuntimeCall(rw, req)
} else {
d.handler.ServeHTTP(rw, req)
}
case ipcJSPath:
content := d.runtime.DesktopIPC()
if d.ipcJS != nil {

View File

@ -5,6 +5,7 @@ go 1.19
require (
github.com/go-task/task/v3 v3.20.0
github.com/jackmordaunt/icns/v2 v2.2.1
github.com/json-iterator/go v1.1.12
github.com/leaanthony/clir v1.6.0
github.com/leaanthony/gosod v1.0.3
github.com/leaanthony/winicon v1.0.0
@ -33,6 +34,8 @@ require (
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mattn/go-zglob v0.0.4 // indirect
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect

View File

@ -26,6 +26,7 @@ github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg78
github.com/go-task/task/v3 v3.20.0 h1:pTavuhP+AiEpKLzh5I6Lja9Ux7ypYO5QMsEPTbhYEDc=
github.com/go-task/task/v3 v3.20.0/go.mod h1:y7rWakbLR5gFElGgo6rA2dyr6vU/zNIDVfn3S4Of6OI=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI=
@ -36,6 +37,8 @@ github.com/jackmordaunt/icns/v2 v2.2.1 h1:MGklwYP2yohKn2Bw7XxlF69LZe98S1vUfl5OvA
github.com/jackmordaunt/icns/v2 v2.2.1/go.mod h1:6aYIB9eSzyfHHMKqDf17Xrs1zetQPReAkiUSHzdw4cI=
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
@ -74,6 +77,10 @@ github.com/mattn/go-zglob v0.0.4 h1:LQi2iOm0/fGgu80AioIJ/1j9w9Oh+9DZ39J4VAGzHQM=
github.com/mattn/go-zglob v0.0.4/go.mod h1:MxxjyoXXnMxfIpxTK2GAkw1w8glPsQILx3N5wrKakiY=
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
@ -107,6 +114,7 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=

View File

@ -10,46 +10,61 @@ The electron alternative for Go
/* jshint esversion: 9 */
const runtimeURL = window.location.origin + "/wails/runtime";
import {Call} from "./calls";
import {invoke} from "./ipc";
function runtimeCall(method, args) {
let url = new URL(runtimeURL);
url.searchParams.append("method", method);
if (args) {
for (let key in args) {
url.searchParams.append(key, args[key]);
}
}
return new Promise((resolve, reject) => {
fetch(url)
.then(response => {
if (response.ok) {
return response.json();
}
reject(Error(response.statusText));
})
.then(data => resolve(data))
.catch(error => reject(error));
});
}
export function newWindow(id) {
let call = function(method, args) {
if (id !== -1) {
args["windowID"] = id;
}
return runtimeCall("window." + method, args);
}
return {
// Reload: () => invoke('WR', id),
// ReloadApp: () => invoke('WR', id),
// SetSystemDefaultTheme: () => invoke('WASDT', id),
// SetLightTheme: () => invoke('WALT', id),
// SetDarkTheme: () => invoke('WADT', id),
Center: () => invoke('Wc', id),
SetTitle: (title) => invoke('WT' + title, id),
Fullscreen: () => invoke('WF', id),
UnFullscreen: () => invoke('Wf', id),
SetSize: (width, height) => invoke('WS' + width + ',' + height, id),
GetSize: () => {
return Call(":wails:WindowGetSize")
},
SetMaxSize: (width, height) => invoke('WZ:' + width + ':' + height, id),
SetMinSize: (width, height) => invoke('Wz:' + width + ':' + height, id),
SetAlwaysOnTop: (b) => invoke('WATP:' + (b ? '1' : '0'), id),
SetPosition: (x, y) => invoke('Wp:' + x + ':' + y, id),
GetPosition: () => {
return Call(":wails:WindowGetPos")
},
Hide: () => invoke('WH', id),
Maximise: () => invoke('WM', id),
Show: () => invoke('WS', id),
ToggleMaximise: () => invoke('Wt', id),
UnMaximise: () => invoke('WU', id),
Minimise: () => invoke('Wm', id),
UnMinimise: () => invoke('Wu', id),
SetBackgroundColour: (R, G, B, A) =>
invoke('Wr:' + JSON.stringify({
r: R || 0,
g: G || 0,
b: B || 0,
a: A || 255}, id)
),
// Reload: () => call('WR'),
// ReloadApp: () => call('WR'),
// SetSystemDefaultTheme: () => call('WASDT'),
// SetLightTheme: () => call('WALT'),
// SetDarkTheme: () => call('WADT'),
Center: () => call('Center'),
SetTitle: (title) => call('SetTitle', {title}),
Fullscreen: () => call('Fullscreen'),
UnFullscreen: () => call('UnFullscreen'),
SetSize: (width, height) => call('SetSize', {width,height}),
GetSize: () => { return call('GetSize') },
SetMaxSize: (width, height) => call('SetMaxSize', {width,height}),
SetMinSize: (width, height) => call('SetMinSize', {width,height}),
SetAlwaysOnTop: (b) => call('SetAlwaysOnTop', {alwaysOnTop:b}),
SetPosition: (x, y) => call('SetPosition', {x,y}),
GetPosition: () => { return call('GetPosition') },
Hide: () => call('Hide'),
Maximise: () => call('Maximise'),
Show: () => call('Show'),
ToggleMaximise: () => call('ToggleMaximise'),
UnMaximise: () => call('UnMaximise'),
Minimise: () => call('Minimise'),
UnMinimise: () => call('UnMinimise'),
SetBackgroundColour: (r, g, b, a) => call('SetBackgroundColour', {R, G, B, A}),
}
}

View File

@ -1 +1 @@
(()=>{var o=null;(function(){let s=function(e){for(var n=window[e.shift()];n&&e.length;)n=n[e.shift()];return n},t=s(["chrome","webview","postMessage"]),i=s(["webkit","messageHandlers","external","postMessage"]);if(!t&&!i){console.error("Unsupported Platform");return}t&&(o=e=>window.chrome.webview.postMessage(e)),i&&(o=e=>window.webkit.messageHandlers.external.postMessage(e))})();function r(s,t){o(t&&t!==-1?"WINDOWID:"+t+":"+s:s)}})();
(()=>{var o=null;(function(){let s=function(e){let n=window[e.shift()];for(;n&&e.length;)n=n[e.shift()];return n},t=s(["chrome","webview","postMessage"]),i=s(["webkit","messageHandlers","external","postMessage"]);if(!t&&!i){console.error("Unsupported Platform");return}t&&(o=e=>window.chrome.webview.postMessage(e)),i&&(o=e=>window.webkit.messageHandlers.external.postMessage(e))})();function l(s,t){o(t&&t!==-1?"WINDOWID:"+t+":"+s:s)}})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
(()=>{var u=null;(function(){let e=function(n){for(var r=window[n.shift()];r&&n.length;)r=r[n.shift()];return r},t=e(["chrome","webview","postMessage"]),o=e(["webkit","messageHandlers","external","postMessage"]);if(!t&&!o){console.error("Unsupported Platform");return}t&&(u=n=>window.chrome.webview.postMessage(n)),o&&(u=n=>window.webkit.messageHandlers.external.postMessage(n))})();function i(e,t){u(t&&t!==-1?"WINDOWID:"+t+":"+e:e)}var c={};function y(){var e=new Uint32Array(1);return window.crypto.getRandomValues(e)[0]}function W(){return Math.random()*9007199254740991}var d;window.crypto?d=y:d=W;function f(e,t,o){o==null&&(o=0);let n=window.wails.window.ID();return new Promise(function(r,l){var s;do s=e+"-"+d();while(c[s]);var w;o>0&&(w=setTimeout(function(){l(Error("Call to "+e+" timed out. Request ID: "+s))},o)),c[s]={timeoutHandle:w,reject:l,resolve:r};try{let m={name:e,args:t,callbackID:s,windowID:n};window.WailsInvoke("C"+JSON.stringify(m))}catch(m){console.error(m)}})}window.ObfuscatedCall=(e,t,o)=>(o==null&&(o=0),new Promise(function(n,r){var l;do l=e+"-"+d();while(c[l]);var s;o>0&&(s=setTimeout(function(){r(Error("Call to method "+e+" timed out. Request ID: "+l))},o)),c[l]={timeoutHandle:s,reject:r,resolve:n};try{let w={id:e,args:t,callbackID:l,windowID:window.wails.window.ID()};window.WailsInvoke("c"+JSON.stringify(w))}catch(w){console.error(w)}}));function p(e){let t;try{t=JSON.parse(e)}catch(r){let l=`Invalid JSON passed to callback: ${r.message}. Message: ${e}`;throw runtime.LogDebug(l),new Error(l)}let o=t.callbackid,n=c[o];if(!n){let r=`Callback '${o}' not registered!!!`;throw console.error(r),new Error(r)}clearTimeout(n.timeoutHandle),delete c[o],t.error?n.reject(t.error):n.resolve(t.result)}var a={};function b(e){let t=e.name;if(a[t]){let o=a[t].slice();for(let n=0;n<a[t].length;n+=1){let r=a[t][n],l=e.data;r.Callback(l)&&o.splice(n,1)}o.length===0?S(t):a[t]=o}}function h(e){let t;try{t=JSON.parse(e)}catch{let n="Invalid JSON passed to Notify: "+e;throw new Error(n)}b(t)}function S(e){delete a[e],window.WailsInvoke("EX"+e)}window.go={};function v(e){try{e=JSON.parse(e)}catch(t){console.error(t)}window.go=window.go||{},Object.keys(e).forEach(t=>{window.go[t]=window.go[t]||{},Object.keys(e[t]).forEach(o=>{window.go[t][o]=window.go[t][o]||{},Object.keys(e[t][o]).forEach(n=>{window.go[t][o][n]=function(){let r=0;function l(){let s=[].slice.call(arguments);return f([t,o,n].join("."),s,r)}return l.setTimeout=function(s){r=s},l.getTimeout=function(){return r},l}()})})})}function g(e){return{Center:()=>i("Wc",e),SetTitle:t=>i("WT"+t,e),Fullscreen:()=>i("WF",e),UnFullscreen:()=>i("Wf",e),SetSize:(t,o)=>i("WS"+t+","+o,e),GetSize:()=>f(":wails:WindowGetSize"),SetMaxSize:(t,o)=>i("WZ:"+t+":"+o,e),SetMinSize:(t,o)=>i("Wz:"+t+":"+o,e),SetAlwaysOnTop:t=>i("WATP:"+(t?"1":"0"),e),SetPosition:(t,o)=>i("Wp:"+t+":"+o,e),GetPosition:()=>f(":wails:WindowGetPos"),Hide:()=>i("WH",e),Maximise:()=>i("WM",e),Show:()=>i("WS",e),ToggleMaximise:()=>i("Wt",e),UnMaximise:()=>i("WU",e),Minimise:()=>i("Wm",e),UnMinimise:()=>i("Wu",e),SetBackgroundColour:(t,o,n,r)=>i("Wr:"+JSON.stringify({r:t||0,g:o||0,b:n||0,a:r||255},e))}}window.wails={Callback:p,callbacks:c,EventsNotify:h,eventListeners:a,SetBindings:v};function x(e){return{Window:g(e),Show:()=>i("S"),Hide:()=>i("H"),Quit:()=>i("Q")}}window.runtime=x(-1);console.log("Wails v3.0.0 Debug Mode Enabled");})();
(()=>{var w=null;(function(){let o=function(n){let r=window[n.shift()];for(;r&&n.length;)r=r[n.shift()];return r},e=o(["chrome","webview","postMessage"]),t=o(["webkit","messageHandlers","external","postMessage"]);if(!e&&!t){console.error("Unsupported Platform");return}e&&(w=n=>window.chrome.webview.postMessage(n)),t&&(w=n=>window.webkit.messageHandlers.external.postMessage(n))})();function u(o,e){w(e&&e!==-1?"WINDOWID:"+e+":"+o:o)}var s={};function x(){let o=new Uint32Array(1);return window.crypto.getRandomValues(o)[0]}function g(){return Math.random()*9007199254740991}var f;window.crypto?f=x:f=g;function m(o,e,t){t==null&&(t=0);let n=window.wails.window.ID();return new Promise(function(r,i){let l;do l=o+"-"+f();while(s[l]);let a;t>0&&(a=setTimeout(function(){i(Error("Call to "+o+" timed out. Request ID: "+l))},t)),s[l]={timeoutHandle:a,reject:i,resolve:r};try{let d={name:o,args:e,callbackID:l,windowID:n};window.WailsInvoke("C"+JSON.stringify(d))}catch(d){console.error(d)}})}window.ObfuscatedCall=(o,e,t)=>(t==null&&(t=0),new Promise(function(n,r){let i;do i=o+"-"+f();while(s[i]);let l;t>0&&(l=setTimeout(function(){r(Error("Call to method "+o+" timed out. Request ID: "+i))},t)),s[i]={timeoutHandle:l,reject:r,resolve:n};try{let a={id:o,args:e,callbackID:i,windowID:window.wails.window.ID()};window.WailsInvoke("c"+JSON.stringify(a))}catch(a){console.error(a)}}));function h(o){let e;try{e=JSON.parse(o)}catch(r){let i=`Invalid JSON passed to callback: ${r.message}. Message: ${o}`;throw runtime.LogDebug(i),new Error(i)}let t=e.callbackid,n=s[t];if(!n){let r=`Callback '${t}' not registered!!!`;throw console.error(r),new Error(r)}clearTimeout(n.timeoutHandle),delete s[t],e.error?n.reject(e.error):n.resolve(e.result)}var c={};function b(o){let e=o.name;if(c[e]){let t=c[e].slice();for(let n=0;n<c[e].length;n+=1){let r=c[e][n],i=o.data;r.Callback(i)&&t.splice(n,1)}t.length===0?k(e):c[e]=t}}function p(o){let e;try{e=JSON.parse(o)}catch{let n="Invalid JSON passed to Notify: "+o;throw new Error(n)}b(e)}function k(o){delete c[o],window.WailsInvoke("EX"+o)}window.go={};function S(o){try{o=JSON.parse(o)}catch(e){console.error(e)}window.go=window.go||{},Object.keys(o).forEach(e=>{window.go[e]=window.go[e]||{},Object.keys(o[e]).forEach(t=>{window.go[e][t]=window.go[e][t]||{},Object.keys(o[e][t]).forEach(n=>{window.go[e][t][n]=function(){let r=0;function i(){let l=[].slice.call(arguments);return m([e,t,n].join("."),l,r)}return i.setTimeout=function(l){r=l},i.getTimeout=function(){return r},i}()})})})}var v=window.location.origin+"/wails/runtime";function E(o,e){let t=new URL(v);if(t.searchParams.append("method",o),e)for(let n in e)t.searchParams.append(n,e[n]);return new Promise((n,r)=>{fetch(t).then(i=>{if(i.ok)return i.json();r(Error(i.statusText))}).then(i=>n(i)).catch(i=>r(i))})}function y(o){let e=function(t,n){return o!==-1&&(n.windowID=o),E("window."+t,n)};return{Center:()=>e("Center"),SetTitle:t=>e("SetTitle",{title:t}),Fullscreen:()=>e("Fullscreen"),UnFullscreen:()=>e("UnFullscreen"),SetSize:(t,n)=>e("SetSize",{width:t,height:n}),GetSize:()=>e("GetSize"),SetMaxSize:(t,n)=>e("SetMaxSize",{width:t,height:n}),SetMinSize:(t,n)=>e("SetMinSize",{width:t,height:n}),SetAlwaysOnTop:t=>e("SetAlwaysOnTop",{alwaysOnTop:t}),SetPosition:(t,n)=>e("SetPosition",{x:t,y:n}),GetPosition:()=>e("GetPosition"),Hide:()=>e("Hide"),Maximise:()=>e("Maximise"),Show:()=>e("Show"),ToggleMaximise:()=>e("ToggleMaximise"),UnMaximise:()=>e("UnMaximise"),Minimise:()=>e("Minimise"),UnMinimise:()=>e("UnMinimise"),SetBackgroundColour:(t,n,r,i)=>e("SetBackgroundColour",{R,G,B,A})}}window.wails={Callback:h,callbacks:s,EventsNotify:p,eventListeners:c,SetBindings:S};function O(o){return{Window:y(o),Show:()=>u("S"),Hide:()=>u("H"),Quit:()=>u("Q")}}window.runtime=O(-1);console.log("Wails v3.0.0 Debug Mode Enabled");})();

View File

@ -1 +1 @@
(()=>{var u=null;(function(){let e=function(n){for(var r=window[n.shift()];r&&n.length;)r=r[n.shift()];return r},t=e(["chrome","webview","postMessage"]),o=e(["webkit","messageHandlers","external","postMessage"]);if(!t&&!o){console.error("Unsupported Platform");return}t&&(u=n=>window.chrome.webview.postMessage(n)),o&&(u=n=>window.webkit.messageHandlers.external.postMessage(n))})();function i(e,t){u(t&&t!==-1?"WINDOWID:"+t+":"+e:e)}var c={};function y(){var e=new Uint32Array(1);return window.crypto.getRandomValues(e)[0]}function W(){return Math.random()*9007199254740991}var d;window.crypto?d=y:d=W;function f(e,t,o){o==null&&(o=0);let n=window.wails.window.ID();return new Promise(function(r,l){var s;do s=e+"-"+d();while(c[s]);var w;o>0&&(w=setTimeout(function(){l(Error("Call to "+e+" timed out. Request ID: "+s))},o)),c[s]={timeoutHandle:w,reject:l,resolve:r};try{let m={name:e,args:t,callbackID:s,windowID:n};window.WailsInvoke("C"+JSON.stringify(m))}catch(m){console.error(m)}})}window.ObfuscatedCall=(e,t,o)=>(o==null&&(o=0),new Promise(function(n,r){var l;do l=e+"-"+d();while(c[l]);var s;o>0&&(s=setTimeout(function(){r(Error("Call to method "+e+" timed out. Request ID: "+l))},o)),c[l]={timeoutHandle:s,reject:r,resolve:n};try{let w={id:e,args:t,callbackID:l,windowID:window.wails.window.ID()};window.WailsInvoke("c"+JSON.stringify(w))}catch(w){console.error(w)}}));function p(e){let t;try{t=JSON.parse(e)}catch(r){let l=`Invalid JSON passed to callback: ${r.message}. Message: ${e}`;throw runtime.LogDebug(l),new Error(l)}let o=t.callbackid,n=c[o];if(!n){let r=`Callback '${o}' not registered!!!`;throw console.error(r),new Error(r)}clearTimeout(n.timeoutHandle),delete c[o],t.error?n.reject(t.error):n.resolve(t.result)}var a={};function b(e){let t=e.name;if(a[t]){let o=a[t].slice();for(let n=0;n<a[t].length;n+=1){let r=a[t][n],l=e.data;r.Callback(l)&&o.splice(n,1)}o.length===0?S(t):a[t]=o}}function h(e){let t;try{t=JSON.parse(e)}catch{let n="Invalid JSON passed to Notify: "+e;throw new Error(n)}b(t)}function S(e){delete a[e],window.WailsInvoke("EX"+e)}window.go={};function v(e){try{e=JSON.parse(e)}catch(t){console.error(t)}window.go=window.go||{},Object.keys(e).forEach(t=>{window.go[t]=window.go[t]||{},Object.keys(e[t]).forEach(o=>{window.go[t][o]=window.go[t][o]||{},Object.keys(e[t][o]).forEach(n=>{window.go[t][o][n]=function(){let r=0;function l(){let s=[].slice.call(arguments);return f([t,o,n].join("."),s,r)}return l.setTimeout=function(s){r=s},l.getTimeout=function(){return r},l}()})})})}function g(e){return{Center:()=>i("Wc",e),SetTitle:t=>i("WT"+t,e),Fullscreen:()=>i("WF",e),UnFullscreen:()=>i("Wf",e),SetSize:(t,o)=>i("WS"+t+","+o,e),GetSize:()=>f(":wails:WindowGetSize"),SetMaxSize:(t,o)=>i("WZ:"+t+":"+o,e),SetMinSize:(t,o)=>i("Wz:"+t+":"+o,e),SetAlwaysOnTop:t=>i("WATP:"+(t?"1":"0"),e),SetPosition:(t,o)=>i("Wp:"+t+":"+o,e),GetPosition:()=>f(":wails:WindowGetPos"),Hide:()=>i("WH",e),Maximise:()=>i("WM",e),Show:()=>i("WS",e),ToggleMaximise:()=>i("Wt",e),UnMaximise:()=>i("WU",e),Minimise:()=>i("Wm",e),UnMinimise:()=>i("Wu",e),SetBackgroundColour:(t,o,n,r)=>i("Wr:"+JSON.stringify({r:t||0,g:o||0,b:n||0,a:r||255},e))}}window.wails={Callback:p,callbacks:c,EventsNotify:h,eventListeners:a,SetBindings:v};function x(e){return{Window:g(e),Show:()=>i("S"),Hide:()=>i("H"),Quit:()=>i("Q")}}window.runtime=x(-1);console.log("Wails v3.0.0 Debug Mode Enabled");})();
(()=>{var w=null;(function(){let o=function(n){let r=window[n.shift()];for(;r&&n.length;)r=r[n.shift()];return r},e=o(["chrome","webview","postMessage"]),t=o(["webkit","messageHandlers","external","postMessage"]);if(!e&&!t){console.error("Unsupported Platform");return}e&&(w=n=>window.chrome.webview.postMessage(n)),t&&(w=n=>window.webkit.messageHandlers.external.postMessage(n))})();function u(o,e){w(e&&e!==-1?"WINDOWID:"+e+":"+o:o)}var s={};function x(){let o=new Uint32Array(1);return window.crypto.getRandomValues(o)[0]}function g(){return Math.random()*9007199254740991}var f;window.crypto?f=x:f=g;function m(o,e,t){t==null&&(t=0);let n=window.wails.window.ID();return new Promise(function(r,i){let l;do l=o+"-"+f();while(s[l]);let a;t>0&&(a=setTimeout(function(){i(Error("Call to "+o+" timed out. Request ID: "+l))},t)),s[l]={timeoutHandle:a,reject:i,resolve:r};try{let d={name:o,args:e,callbackID:l,windowID:n};window.WailsInvoke("C"+JSON.stringify(d))}catch(d){console.error(d)}})}window.ObfuscatedCall=(o,e,t)=>(t==null&&(t=0),new Promise(function(n,r){let i;do i=o+"-"+f();while(s[i]);let l;t>0&&(l=setTimeout(function(){r(Error("Call to method "+o+" timed out. Request ID: "+i))},t)),s[i]={timeoutHandle:l,reject:r,resolve:n};try{let a={id:o,args:e,callbackID:i,windowID:window.wails.window.ID()};window.WailsInvoke("c"+JSON.stringify(a))}catch(a){console.error(a)}}));function h(o){let e;try{e=JSON.parse(o)}catch(r){let i=`Invalid JSON passed to callback: ${r.message}. Message: ${o}`;throw runtime.LogDebug(i),new Error(i)}let t=e.callbackid,n=s[t];if(!n){let r=`Callback '${t}' not registered!!!`;throw console.error(r),new Error(r)}clearTimeout(n.timeoutHandle),delete s[t],e.error?n.reject(e.error):n.resolve(e.result)}var c={};function b(o){let e=o.name;if(c[e]){let t=c[e].slice();for(let n=0;n<c[e].length;n+=1){let r=c[e][n],i=o.data;r.Callback(i)&&t.splice(n,1)}t.length===0?k(e):c[e]=t}}function p(o){let e;try{e=JSON.parse(o)}catch{let n="Invalid JSON passed to Notify: "+o;throw new Error(n)}b(e)}function k(o){delete c[o],window.WailsInvoke("EX"+o)}window.go={};function S(o){try{o=JSON.parse(o)}catch(e){console.error(e)}window.go=window.go||{},Object.keys(o).forEach(e=>{window.go[e]=window.go[e]||{},Object.keys(o[e]).forEach(t=>{window.go[e][t]=window.go[e][t]||{},Object.keys(o[e][t]).forEach(n=>{window.go[e][t][n]=function(){let r=0;function i(){let l=[].slice.call(arguments);return m([e,t,n].join("."),l,r)}return i.setTimeout=function(l){r=l},i.getTimeout=function(){return r},i}()})})})}var v=window.location.origin+"/wails/runtime";function E(o,e){let t=new URL(v);if(t.searchParams.append("method",o),e)for(let n in e)t.searchParams.append(n,e[n]);return new Promise((n,r)=>{fetch(t).then(i=>{if(i.ok)return i.json();r(Error(i.statusText))}).then(i=>n(i)).catch(i=>r(i))})}function y(o){let e=function(t,n){return o!==-1&&(n.windowID=o),E("window."+t,n)};return{Center:()=>e("Center"),SetTitle:t=>e("SetTitle",{title:t}),Fullscreen:()=>e("Fullscreen"),UnFullscreen:()=>e("UnFullscreen"),SetSize:(t,n)=>e("SetSize",{width:t,height:n}),GetSize:()=>e("GetSize"),SetMaxSize:(t,n)=>e("SetMaxSize",{width:t,height:n}),SetMinSize:(t,n)=>e("SetMinSize",{width:t,height:n}),SetAlwaysOnTop:t=>e("SetAlwaysOnTop",{alwaysOnTop:t}),SetPosition:(t,n)=>e("SetPosition",{x:t,y:n}),GetPosition:()=>e("GetPosition"),Hide:()=>e("Hide"),Maximise:()=>e("Maximise"),Show:()=>e("Show"),ToggleMaximise:()=>e("ToggleMaximise"),UnMaximise:()=>e("UnMaximise"),Minimise:()=>e("Minimise"),UnMinimise:()=>e("UnMinimise"),SetBackgroundColour:(t,n,r,i)=>e("SetBackgroundColour",{R,G,B,A})}}window.wails={Callback:h,callbacks:s,EventsNotify:p,eventListeners:c,SetBindings:S};function O(o){return{Window:y(o),Show:()=>u("S"),Hide:()=>u("H"),Quit:()=>u("Q")}}window.runtime=O(-1);console.log("Wails v3.0.0 Debug Mode Enabled");})();

View File

@ -1 +1 @@
(()=>{var u=null;(function(){let e=function(n){for(var r=window[n.shift()];r&&n.length;)r=r[n.shift()];return r},t=e(["chrome","webview","postMessage"]),o=e(["webkit","messageHandlers","external","postMessage"]);if(!t&&!o){console.error("Unsupported Platform");return}t&&(u=n=>window.chrome.webview.postMessage(n)),o&&(u=n=>window.webkit.messageHandlers.external.postMessage(n))})();function i(e,t){u(t&&t!==-1?"WINDOWID:"+t+":"+e:e)}var c={};function y(){var e=new Uint32Array(1);return window.crypto.getRandomValues(e)[0]}function W(){return Math.random()*9007199254740991}var d;window.crypto?d=y:d=W;function f(e,t,o){o==null&&(o=0);let n=window.wails.window.ID();return new Promise(function(r,l){var s;do s=e+"-"+d();while(c[s]);var w;o>0&&(w=setTimeout(function(){l(Error("Call to "+e+" timed out. Request ID: "+s))},o)),c[s]={timeoutHandle:w,reject:l,resolve:r};try{let m={name:e,args:t,callbackID:s,windowID:n};window.WailsInvoke("C"+JSON.stringify(m))}catch(m){console.error(m)}})}window.ObfuscatedCall=(e,t,o)=>(o==null&&(o=0),new Promise(function(n,r){var l;do l=e+"-"+d();while(c[l]);var s;o>0&&(s=setTimeout(function(){r(Error("Call to method "+e+" timed out. Request ID: "+l))},o)),c[l]={timeoutHandle:s,reject:r,resolve:n};try{let w={id:e,args:t,callbackID:l,windowID:window.wails.window.ID()};window.WailsInvoke("c"+JSON.stringify(w))}catch(w){console.error(w)}}));function p(e){let t;try{t=JSON.parse(e)}catch(r){let l=`Invalid JSON passed to callback: ${r.message}. Message: ${e}`;throw runtime.LogDebug(l),new Error(l)}let o=t.callbackid,n=c[o];if(!n){let r=`Callback '${o}' not registered!!!`;throw console.error(r),new Error(r)}clearTimeout(n.timeoutHandle),delete c[o],t.error?n.reject(t.error):n.resolve(t.result)}var a={};function b(e){let t=e.name;if(a[t]){let o=a[t].slice();for(let n=0;n<a[t].length;n+=1){let r=a[t][n],l=e.data;r.Callback(l)&&o.splice(n,1)}o.length===0?S(t):a[t]=o}}function h(e){let t;try{t=JSON.parse(e)}catch{let n="Invalid JSON passed to Notify: "+e;throw new Error(n)}b(t)}function S(e){delete a[e],window.WailsInvoke("EX"+e)}window.go={};function v(e){try{e=JSON.parse(e)}catch(t){console.error(t)}window.go=window.go||{},Object.keys(e).forEach(t=>{window.go[t]=window.go[t]||{},Object.keys(e[t]).forEach(o=>{window.go[t][o]=window.go[t][o]||{},Object.keys(e[t][o]).forEach(n=>{window.go[t][o][n]=function(){let r=0;function l(){let s=[].slice.call(arguments);return f([t,o,n].join("."),s,r)}return l.setTimeout=function(s){r=s},l.getTimeout=function(){return r},l}()})})})}function g(e){return{Center:()=>i("Wc",e),SetTitle:t=>i("WT"+t,e),Fullscreen:()=>i("WF",e),UnFullscreen:()=>i("Wf",e),SetSize:(t,o)=>i("WS"+t+","+o,e),GetSize:()=>f(":wails:WindowGetSize"),SetMaxSize:(t,o)=>i("WZ:"+t+":"+o,e),SetMinSize:(t,o)=>i("Wz:"+t+":"+o,e),SetAlwaysOnTop:t=>i("WATP:"+(t?"1":"0"),e),SetPosition:(t,o)=>i("Wp:"+t+":"+o,e),GetPosition:()=>f(":wails:WindowGetPos"),Hide:()=>i("WH",e),Maximise:()=>i("WM",e),Show:()=>i("WS",e),ToggleMaximise:()=>i("Wt",e),UnMaximise:()=>i("WU",e),Minimise:()=>i("Wm",e),UnMinimise:()=>i("Wu",e),SetBackgroundColour:(t,o,n,r)=>i("Wr:"+JSON.stringify({r:t||0,g:o||0,b:n||0,a:r||255},e))}}window.wails={Callback:p,callbacks:c,EventsNotify:h,eventListeners:a,SetBindings:v};function x(e){return{Window:g(e),Show:()=>i("S"),Hide:()=>i("H"),Quit:()=>i("Q")}}window.runtime=x(-1);console.log("Wails v3.0.0 Debug Mode Enabled");})();
(()=>{var w=null;(function(){let o=function(n){let r=window[n.shift()];for(;r&&n.length;)r=r[n.shift()];return r},e=o(["chrome","webview","postMessage"]),t=o(["webkit","messageHandlers","external","postMessage"]);if(!e&&!t){console.error("Unsupported Platform");return}e&&(w=n=>window.chrome.webview.postMessage(n)),t&&(w=n=>window.webkit.messageHandlers.external.postMessage(n))})();function u(o,e){w(e&&e!==-1?"WINDOWID:"+e+":"+o:o)}var s={};function x(){let o=new Uint32Array(1);return window.crypto.getRandomValues(o)[0]}function g(){return Math.random()*9007199254740991}var f;window.crypto?f=x:f=g;function m(o,e,t){t==null&&(t=0);let n=window.wails.window.ID();return new Promise(function(r,i){let l;do l=o+"-"+f();while(s[l]);let a;t>0&&(a=setTimeout(function(){i(Error("Call to "+o+" timed out. Request ID: "+l))},t)),s[l]={timeoutHandle:a,reject:i,resolve:r};try{let d={name:o,args:e,callbackID:l,windowID:n};window.WailsInvoke("C"+JSON.stringify(d))}catch(d){console.error(d)}})}window.ObfuscatedCall=(o,e,t)=>(t==null&&(t=0),new Promise(function(n,r){let i;do i=o+"-"+f();while(s[i]);let l;t>0&&(l=setTimeout(function(){r(Error("Call to method "+o+" timed out. Request ID: "+i))},t)),s[i]={timeoutHandle:l,reject:r,resolve:n};try{let a={id:o,args:e,callbackID:i,windowID:window.wails.window.ID()};window.WailsInvoke("c"+JSON.stringify(a))}catch(a){console.error(a)}}));function h(o){let e;try{e=JSON.parse(o)}catch(r){let i=`Invalid JSON passed to callback: ${r.message}. Message: ${o}`;throw runtime.LogDebug(i),new Error(i)}let t=e.callbackid,n=s[t];if(!n){let r=`Callback '${t}' not registered!!!`;throw console.error(r),new Error(r)}clearTimeout(n.timeoutHandle),delete s[t],e.error?n.reject(e.error):n.resolve(e.result)}var c={};function b(o){let e=o.name;if(c[e]){let t=c[e].slice();for(let n=0;n<c[e].length;n+=1){let r=c[e][n],i=o.data;r.Callback(i)&&t.splice(n,1)}t.length===0?k(e):c[e]=t}}function p(o){let e;try{e=JSON.parse(o)}catch{let n="Invalid JSON passed to Notify: "+o;throw new Error(n)}b(e)}function k(o){delete c[o],window.WailsInvoke("EX"+o)}window.go={};function S(o){try{o=JSON.parse(o)}catch(e){console.error(e)}window.go=window.go||{},Object.keys(o).forEach(e=>{window.go[e]=window.go[e]||{},Object.keys(o[e]).forEach(t=>{window.go[e][t]=window.go[e][t]||{},Object.keys(o[e][t]).forEach(n=>{window.go[e][t][n]=function(){let r=0;function i(){let l=[].slice.call(arguments);return m([e,t,n].join("."),l,r)}return i.setTimeout=function(l){r=l},i.getTimeout=function(){return r},i}()})})})}var v=window.location.origin+"/wails/runtime";function E(o,e){let t=new URL(v);if(t.searchParams.append("method",o),e)for(let n in e)t.searchParams.append(n,e[n]);return new Promise((n,r)=>{fetch(t).then(i=>{if(i.ok)return i.json();r(Error(i.statusText))}).then(i=>n(i)).catch(i=>r(i))})}function y(o){let e=function(t,n){return o!==-1&&(n.windowID=o),E("window."+t,n)};return{Center:()=>e("Center"),SetTitle:t=>e("SetTitle",{title:t}),Fullscreen:()=>e("Fullscreen"),UnFullscreen:()=>e("UnFullscreen"),SetSize:(t,n)=>e("SetSize",{width:t,height:n}),GetSize:()=>e("GetSize"),SetMaxSize:(t,n)=>e("SetMaxSize",{width:t,height:n}),SetMinSize:(t,n)=>e("SetMinSize",{width:t,height:n}),SetAlwaysOnTop:t=>e("SetAlwaysOnTop",{alwaysOnTop:t}),SetPosition:(t,n)=>e("SetPosition",{x:t,y:n}),GetPosition:()=>e("GetPosition"),Hide:()=>e("Hide"),Maximise:()=>e("Maximise"),Show:()=>e("Show"),ToggleMaximise:()=>e("ToggleMaximise"),UnMaximise:()=>e("UnMaximise"),Minimise:()=>e("Minimise"),UnMinimise:()=>e("UnMinimise"),SetBackgroundColour:(t,n,r,i)=>e("SetBackgroundColour",{R,G,B,A})}}window.wails={Callback:h,callbacks:s,EventsNotify:p,eventListeners:c,SetBindings:S};function O(o){return{Window:y(o),Show:()=>u("S"),Hide:()=>u("H"),Quit:()=>u("Q")}}window.runtime=O(-1);console.log("Wails v3.0.0 Debug Mode Enabled");})();

View File

@ -114,6 +114,13 @@ func (a *App) getSystemTrayID() uint {
a.systemTrayID++
return a.systemTrayID
}
func (a *App) getWindowForID(id uint) *WebviewWindow {
a.windowsLock.Lock()
defer a.windowsLock.Unlock()
return a.windows[id]
}
func (a *App) On(eventType events.ApplicationEventType, callback func()) {
eventID := uint(eventType)
a.applicationEventListenersLock.Lock()

View File

@ -163,7 +163,7 @@ func newRole(role Role) *MenuItem {
case ToggleDevTools:
return newToggleDevToolsMenuItem()
case ResetZoom:
return newResetZoomMenuItem()
return newZoomResetMenuItem()
case ZoomIn:
return newZoomInMenuItem()
case ZoomOut:

View File

@ -564,14 +564,14 @@ func newToggleDevToolsMenuItem() *MenuItem {
})
}
func newResetZoomMenuItem() *MenuItem {
func newZoomResetMenuItem() *MenuItem {
// reset zoom menu item
return newMenuItem("Actual Size").
SetAccelerator("CmdOrCtrl+0").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.CurrentWindow()
if currentWindow != nil {
currentWindow.ResetZoom()
currentWindow.ZoomReset()
}
})
}

View File

@ -2,7 +2,10 @@ package application
import (
"fmt"
"net/http"
"strings"
jsoniter "github.com/json-iterator/go"
)
type MessageProcessor struct {
@ -15,46 +18,41 @@ func NewMessageProcessor(w *WebviewWindow) *MessageProcessor {
}
}
func (m *MessageProcessor) ProcessMessage(message string) {
func (m *MessageProcessor) httpError(rw http.ResponseWriter, message string, args ...any) {
m.Error(message, args...)
rw.WriteHeader(http.StatusBadRequest)
rw.Write([]byte(message))
}
// TODO: Implement calls to other windows
// Check for prefix "WINDOWID"
// If prefix exists, get window ID by parsing: "WINDOWID:12:MESSAGE"
if strings.HasPrefix(message, "WINDOWID") {
m.Error("Window ID prefix not yet implemented")
func (m *MessageProcessor) HandleRuntimeCall(rw http.ResponseWriter, r *http.Request) {
m.Info("Processing runtime call")
// Read "method" from query string
method := r.URL.Query().Get("method")
if method == "" {
m.httpError(rw, "No method specified")
return
}
window := m.window
if message == "" {
m.Error("Blank message received")
splitMethod := strings.Split(method, ".")
if len(splitMethod) != 2 {
m.httpError(rw, "Invalid method format")
return
}
m.Info("Processing message: %s", message)
switch message[0] {
//case 'L':
// m.processLogMessage(message)
//case 'E':
// return m.processEventMessage(message)
//case 'C':
// return m.processCallMessage(message)
//case 'c':
// return m.processSecureCallMessage(message)
case 'W':
m.processWindowMessage(message, window)
//case 'B':
// return m.processBrowserMessage(message)
case 'Q':
globalApplication.Quit()
case 'S':
//globalApplication.Show()
case 'H':
//globalApplication.Hide()
// Get the object
object := splitMethod[0]
// Get the method
method = splitMethod[1]
switch object {
case "window":
m.processWindowMethod(method, rw, r)
default:
m.Error("Unknown message from front end:", message)
m.httpError(rw, "Unknown runtime call: %s", object)
}
}
func (m *MessageProcessor) ProcessMessage(message string) {
m.Info("ProcessMessage from front end:", message)
}
func (m *MessageProcessor) Error(message string, args ...any) {
@ -64,3 +62,23 @@ func (m *MessageProcessor) Error(message string, args ...any) {
func (m *MessageProcessor) Info(message string, args ...any) {
fmt.Printf("[MessageProcessor] Info: "+message, args...)
}
func (m *MessageProcessor) json(rw http.ResponseWriter, data any) {
// convert data to json
var jsonPayload = []byte("{}")
var err error
if data != nil {
jsonPayload, err = jsoniter.Marshal(data)
if err != nil {
m.Error("Unable to convert data to JSON. Please report this to the Wails team! Error: %s", err)
return
}
}
_, err = rw.Write(jsonPayload)
if err != nil {
m.Error("Unable to write json payload. Please report this to the Wails team! Error: %s", err)
return
}
rw.WriteHeader(http.StatusOK)
rw.Header().Set("Content-Type", "application/json")
}

View File

@ -0,0 +1,95 @@
package application
import "strconv"
type QueryParams map[string][]string
func (qp QueryParams) String(key string) *string {
if qp == nil {
return nil
}
values := qp[key]
if len(values) == 0 {
return nil
}
return &values[0]
}
func (qp QueryParams) Int(key string) *int {
val := qp.String(key)
if val == nil {
return nil
}
result, err := strconv.Atoi(*val)
if err != nil {
return nil
}
return &result
}
func (qp QueryParams) UInt8(key string) *uint8 {
val := qp.String(key)
if val == nil {
return nil
}
intResult, err := strconv.Atoi(*val)
if err != nil {
return nil
}
if intResult < 0 {
intResult = 0
}
if intResult > 255 {
intResult = 255
}
var result = uint8(intResult)
return &result
}
func (qp QueryParams) UInt(key string) *uint {
val := qp.String(key)
if val == nil {
return nil
}
intResult, err := strconv.Atoi(*val)
if err != nil {
return nil
}
if intResult < 0 {
intResult = 0
}
if intResult > 255 {
intResult = 255
}
var result = uint(intResult)
return &result
}
func (qp QueryParams) Bool(key string) *bool {
val := qp.String(key)
if val == nil {
return nil
}
result, err := strconv.ParseBool(*val)
if err != nil {
return nil
}
return &result
}
func (qp QueryParams) Float64(key string) *float64 {
val := qp.String(key)
if val == nil {
return nil
}
result, err := strconv.ParseFloat(*val, 64)
if err != nil {
return nil
}
return &result
}

View File

@ -1,95 +1,191 @@
package application
import (
"encoding/json"
"strconv"
"strings"
"net/http"
"github.com/wailsapp/wails/v3/pkg/options"
)
func (m *MessageProcessor) mustAtoI(input string) int {
result, err := strconv.Atoi(input)
if err != nil {
m.Error("cannot convert %s to integer!", input)
}
return result
}
func (m *MessageProcessor) processWindowMethod(method string, rw http.ResponseWriter, r *http.Request) {
func (m *MessageProcessor) processWindowMessage(message string, window *WebviewWindow) {
if len(message) < 2 {
m.Error("Invalid Window Message: " + message)
params := QueryParams(r.URL.Query())
var targetWindow = m.window
windowID := params.UInt("windowID")
if windowID != nil {
// Get window for ID
targetWindow = globalApplication.getWindowForID(*windowID)
if targetWindow == nil {
m.Error("Window ID %s not found", *windowID)
return
}
}
switch message[1] {
case 'A':
switch message[2:] {
//case "SDT":
// go window.WindowSetSystemDefaultTheme()
//case "LT":
// go window.SetLightTheme()
//case "DT":
// go window.SetDarkTheme()
case "TP:0", "TP:1":
if message[2:] == "TP:0" {
go window.SetAlwaysOnTop(false)
} else if message[2:] == "TP:1" {
go window.SetAlwaysOnTop(true)
}
switch method {
case "SetTitle":
title := params.String("title")
if title == nil {
m.Error("SetTitle: title is required")
return
}
case 'c':
go window.Center()
case 'T':
title := message[2:]
go window.SetTitle(title)
case 'F':
go window.Fullscreen()
case 'f':
go window.UnFullscreen()
case 's':
parts := strings.Split(message[3:], ":")
w := m.mustAtoI(parts[0])
h := m.mustAtoI(parts[1])
go window.SetSize(w, h)
case 'p':
parts := strings.Split(message[3:], ":")
x := m.mustAtoI(parts[0])
y := m.mustAtoI(parts[1])
go window.SetPosition(x, y)
case 'H':
go window.Hide()
case 'S':
go window.Show()
//case 'R':
// go window.ReloadApp()
case 'r':
var rgba options.RGBA
err := json.Unmarshal([]byte(message[3:]), &rgba)
if err != nil {
m.Error("Invalid RGBA Message: %s", err.Error())
targetWindow.SetTitle(*title)
m.json(rw, nil)
case "SetSize":
width := params.Int("width")
height := params.Int("height")
if width == nil || height == nil {
m.Error("Invalid SetSize message")
return
}
go window.SetBackgroundColour(&rgba)
case 'M':
go window.Maximise()
//case 't':
// go window.ToggleMaximise()
case 'U':
go window.UnMaximise()
case 'm':
go window.Minimise()
case 'u':
go window.UnMinimise()
case 'Z':
parts := strings.Split(message[3:], ":")
w := m.mustAtoI(parts[0])
h := m.mustAtoI(parts[1])
go window.SetMaxSize(w, h)
case 'z':
parts := strings.Split(message[3:], ":")
w := m.mustAtoI(parts[0])
h := m.mustAtoI(parts[1])
go window.SetMinSize(w, h)
targetWindow.SetSize(*width, *height)
m.json(rw, nil)
case "SetPosition":
x := params.Int("x")
y := params.Int("y")
if x == nil || y == nil {
m.Error("Invalid SetPosition message")
return
}
targetWindow.SetPosition(*x, *y)
m.json(rw, nil)
case "Fullscreen":
targetWindow.Fullscreen()
m.json(rw, nil)
case "UnFullscreen":
targetWindow.UnFullscreen()
m.json(rw, nil)
case "Minimise":
targetWindow.Minimize()
m.json(rw, nil)
case "UnMinimise":
targetWindow.UnMinimise()
m.json(rw, nil)
case "Maximise":
targetWindow.Maximise()
m.json(rw, nil)
case "UnMaximise":
targetWindow.UnMaximise()
m.json(rw, nil)
case "Show":
targetWindow.Show()
m.json(rw, nil)
case "Hide":
targetWindow.Hide()
m.json(rw, nil)
case "Close":
targetWindow.Close()
m.json(rw, nil)
case "Center":
targetWindow.Center()
m.json(rw, nil)
case "Size":
width, height := targetWindow.Size()
m.json(rw, map[string]interface{}{
"width": width,
"height": height,
})
case "Position":
x, y := targetWindow.Position()
m.json(rw, map[string]interface{}{
"x": x,
"y": y,
})
case "SetBackgroundColour":
r := params.UInt8("r")
if r == nil {
m.Error("Invalid SetBackgroundColour message: 'r' value required")
return
}
g := params.UInt8("g")
if g == nil {
m.Error("Invalid SetBackgroundColour message: 'g' value required")
return
}
b := params.UInt8("b")
if b == nil {
m.Error("Invalid SetBackgroundColour message: 'b' value required")
return
}
a := params.UInt8("a")
if a == nil {
m.Error("Invalid SetBackgroundColour message: 'a' value required")
return
}
targetWindow.SetBackgroundColour(&options.RGBA{
Red: *r,
Green: *g,
Blue: *b,
Alpha: *a,
})
m.json(rw, nil)
case "SetAlwaysOnTop":
alwaysOnTop := params.Bool("alwaysOnTop")
if alwaysOnTop == nil {
m.Error("Invalid SetAlwaysOnTop message: 'alwaysOnTop' value required")
return
}
targetWindow.SetAlwaysOnTop(*alwaysOnTop)
m.json(rw, nil)
case "SetResizable":
resizable := params.Bool("resizable")
if resizable == nil {
m.Error("Invalid SetResizable message: 'resizable' value required")
return
}
targetWindow.SetResizable(*resizable)
m.json(rw, nil)
case "SetMinSize":
width := params.Int("width")
height := params.Int("height")
if width == nil || height == nil {
m.Error("Invalid SetMinSize message")
return
}
targetWindow.SetMinSize(*width, *height)
m.json(rw, nil)
case "SetMaxSize":
width := params.Int("width")
height := params.Int("height")
if width == nil || height == nil {
m.Error("Invalid SetMaxSize message")
return
}
targetWindow.SetMaxSize(*width, *height)
m.json(rw, nil)
case "Width":
width := targetWindow.Width()
m.json(rw, map[string]interface{}{
"width": width,
})
case "Height":
height := targetWindow.Height()
m.json(rw, map[string]interface{}{
"height": height,
})
case "ZoomIn":
targetWindow.ZoomIn()
m.json(rw, nil)
case "ZoomOut":
targetWindow.ZoomOut()
m.json(rw, nil)
case "ZoomReset":
targetWindow.ZoomReset()
m.json(rw, nil)
case "GetZoom":
zoomLevel := targetWindow.GetZoom()
m.json(rw, map[string]interface{}{
"zoomLevel": zoomLevel,
})
case "SetZoom":
zoomLevel := params.Float64("zoomLevel")
if zoomLevel == nil {
m.Error("Invalid SetZoom message: invalid 'zoomLevel' value")
return
}
targetWindow.SetZoom(*zoomLevel)
m.json(rw, nil)
default:
m.Error("unknown Window message: %s", message)
m.httpError(rw, "Unknown window method: %s", method)
}
}

View File

@ -34,9 +34,11 @@ type (
reload()
forceReload()
toggleDevTools()
resetZoom()
zoomReset()
zoomIn()
zoomOut()
getZoom() float64
setZoom(zoom float64)
close()
zoom()
minimize()
@ -112,6 +114,7 @@ func NewWindow(options *options.WebviewWindow) *WebviewWindow {
}
result.messageProcessor = NewMessageProcessor(result)
srv.UseRuntimeHandler(result.messageProcessor)
return result
}
@ -211,6 +214,21 @@ func (w *WebviewWindow) SetURL(s string) *WebviewWindow {
return w
}
func (w *WebviewWindow) SetZoom(magnification float64) *WebviewWindow {
w.options.Zoom = magnification
if w.impl != nil {
w.impl.setZoom(magnification)
}
return w
}
func (w *WebviewWindow) GetZoom() float64 {
if w.impl != nil {
return w.impl.getZoom()
}
return 1
}
func (w *WebviewWindow) SetResizable(b bool) *WebviewWindow {
w.options.DisableResize = !b
if w.impl != nil {
@ -449,9 +467,9 @@ func (w *WebviewWindow) ToggleDevTools() {
w.impl.toggleDevTools()
}
func (w *WebviewWindow) ResetZoom() *WebviewWindow {
func (w *WebviewWindow) ZoomReset() *WebviewWindow {
if w.impl != nil {
w.impl.resetZoom()
w.impl.zoomReset()
}
return w

View File

@ -251,8 +251,8 @@ void windowEnableDevTools(void* nsWindow) {
});
}
// windowResetZoom
void windowResetZoom(void* nsWindow) {
// windowZoomReset
void windowZoomReset(void* nsWindow) {
// Reset zoom on main thread
dispatch_async(dispatch_get_main_queue(), ^{
// Get window delegate
@ -262,6 +262,24 @@ void windowResetZoom(void* nsWindow) {
});
}
// windowZoomSet
void windowZoomSet(void* nsWindow, double zoom) {
// Reset zoom on main thread
dispatch_async(dispatch_get_main_queue(), ^{
// Get window delegate
WebviewWindowDelegate* delegate = (WebviewWindowDelegate*)[(WebviewWindow*)nsWindow delegate];
// Reset zoom
[delegate.webView setMagnification:zoom];
});
}
// windowZoomGet
float windowZoomGet(void* nsWindow) {
// Get zoom
WebviewWindowDelegate* delegate = (WebviewWindowDelegate*)[(WebviewWindow*)nsWindow delegate];
return [delegate.webView magnification];
}
// windowZoomIn
void windowZoomIn(void* nsWindow) {
// Zoom in on main thread
@ -762,6 +780,14 @@ type macosWebviewWindow struct {
parent *WebviewWindow
}
func (w *macosWebviewWindow) getZoom() float64 {
return float64(C.windowZoomGet(w.nsWindow))
}
func (w *macosWebviewWindow) setZoom(zoom float64) {
C.windowZoomSet(w.nsWindow, C.double(zoom))
}
func (w *macosWebviewWindow) setFrameless(frameless bool) {
C.windowSetFrameless(w.nsWindow, C.bool(frameless))
if frameless {
@ -848,8 +874,8 @@ func (w *macosWebviewWindow) zoomOut() {
C.windowZoomOut(w.nsWindow)
}
func (w *macosWebviewWindow) resetZoom() {
C.windowResetZoom(w.nsWindow)
func (w *macosWebviewWindow) zoomReset() {
C.windowZoomReset(w.nsWindow)
}
func (w *macosWebviewWindow) toggleDevTools() {
@ -1017,6 +1043,7 @@ func (w *macosWebviewWindow) run() {
if w.parent.options.MaxWidth != 0 || w.parent.options.MaxHeight != 0 {
w.setMaxSize(w.parent.options.MaxWidth, w.parent.options.MaxHeight)
}
//w.setZoom(w.parent.options.Zoom)
w.enableDevTools()
w.setBackgroundColour(w.parent.options.BackgroundColour)

View File

@ -39,6 +39,7 @@ type WebviewWindow struct {
FullscreenButtonEnabled bool
Hidden bool
EnableFraudulentWebsiteWarnings bool
Zoom float64
}
var WindowDefaults = &WebviewWindow{