diff --git a/v3/STATUS.md b/v3/STATUS.md index 74f7116b..e5eeaaf4 100644 --- a/v3/STATUS.md +++ b/v3/STATUS.md @@ -183,6 +183,8 @@ An 'X' indicates that the option is not supported by the platform. | Hidden | Y | | | | | EnableFraudulentWebsiteWarnings | | | | | | Zoom | | | | | +| ZoomControlEnabled | | | | | +| OpenInspectorOnStartup | | | | | | EnableDragAndDrop | | | | | | Windows | Y | - | - | | | Focused | Y | | | | @@ -286,15 +288,14 @@ Built-in plugin support: ### Mac Options -| Feature | Default | Notes | -|-------------------|-------------------|------------------------------------------------------| -| Backdrop | MacBackdropNormal | Standard solid window | -| DisableShadow | false | | -| TitleBar | | Standard window decorations by default | -| Appearance | DefaultAppearance | | +| Feature | Default | Notes | +|-------------------------|-------------------|------------------------------------------------------| +| Backdrop | MacBackdropNormal | Standard solid window | +| DisableShadow | false | | +| TitleBar | | Standard window decorations by default | +| Appearance | DefaultAppearance | | | InvisibleTitleBarHeight | 0 | Creates an invisible title bar for frameless windows | - ## Windows Specific - [x] Translucency @@ -311,6 +312,4 @@ Built-in plugin support: | DisableFramelessWindowDecorations | | | | WindowMask | nil | Makes the window the contents of the bitmap | - - ## Linux Specific diff --git a/v3/examples/binding/go.mod b/v3/examples/binding/go.mod index 3dbff5f9..6e43aef5 100644 --- a/v3/examples/binding/go.mod +++ b/v3/examples/binding/go.mod @@ -5,16 +5,20 @@ go 1.20 require github.com/wailsapp/wails/v3 v3.0.0-alpha.0 require ( + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/leaanthony/slicer v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/samber/lo v1.37.0 // indirect + github.com/wailsapp/go-webview2 v1.0.1 // indirect github.com/wailsapp/mimetype v1.4.1 // indirect github.com/wailsapp/wails/v2 v2.3.2-0.20230117193915-45c3a501d9e6 // indirect golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 // indirect golang.org/x/net v0.7.0 // indirect - golang.org/x/sys v0.7.0 // indirect + golang.org/x/sys v0.8.0 // indirect ) replace github.com/wailsapp/wails/v3 => ../.. diff --git a/v3/examples/binding/go.sum b/v3/examples/binding/go.sum index 5266584f..56af9c50 100644 --- a/v3/examples/binding/go.sum +++ b/v3/examples/binding/go.sum @@ -1,7 +1,13 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= +github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= +github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY= @@ -18,6 +24,8 @@ github.com/samber/lo v1.37.0/go.mod h1:9vaz2O4o8oOnK23pd2TrXufcbdbJIa3b6cstBWKpo github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/wailsapp/go-webview2 v1.0.1 h1:dEJIeEApW/MhO2tTMISZBFZPuW7kwrFA1NtgFB1z1II= +github.com/wailsapp/go-webview2 v1.0.1/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo= github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs= github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 h1:RjggHMcaTVp0LOVZcW0bo8alwHrOaCrGUDgfWUHhnN4= @@ -25,10 +33,12 @@ golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9/go.mod h1:cyybsKvd6eL0RnXn6p golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/v3/examples/window/main.go b/v3/examples/window/main.go index e44d722e..c9de5fde 100644 --- a/v3/examples/window/main.go +++ b/v3/examples/window/main.go @@ -2,14 +2,8 @@ package main import ( _ "embed" - "fmt" - "log" - "math/rand" - "runtime" - "strconv" - "time" - "github.com/wailsapp/wails/v3/pkg/events" + "log" "github.com/wailsapp/wails/v3/pkg/application" ) @@ -25,261 +19,261 @@ func main() { app.On(events.Mac.ApplicationDidFinishLaunching, func() { log.Println("ApplicationDidFinishLaunching") }) - - currentWindow := func(fn func(window *application.WebviewWindow)) { - if app.CurrentWindow() != nil { - fn(app.CurrentWindow()) - } else { - println("Current WebviewWindow is nil") - } - } - - // Create a custom menu - menu := app.NewMenu() - menu.AddRole(application.AppMenu) - - windowCounter := 1 - - // Let's make a "Demo" menu - myMenu := menu.AddSubmenu("New") - - myMenu.Add("New WebviewWindow"). - SetAccelerator("CmdOrCtrl+N"). - OnClick(func(ctx *application.Context) { - app.NewWebviewWindow(). - SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)). - SetPosition(rand.Intn(1000), rand.Intn(800)). - SetURL("https://wails.io"). - Show() - windowCounter++ - }) - myMenu.Add("New WebviewWindow (Hide on Close"). - SetAccelerator("CmdOrCtrl+H"). - OnClick(func(ctx *application.Context) { - app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{HideOnClose: true}). - SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)). - SetPosition(rand.Intn(1000), rand.Intn(800)). - SetURL("https://wails.io"). - Show() - windowCounter++ - }) - myMenu.Add("New Frameless WebviewWindow"). - SetAccelerator("CmdOrCtrl+F"). - OnClick(func(ctx *application.Context) { - app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{ - X: rand.Intn(1000), - Y: rand.Intn(800), - Frameless: true, - Mac: application.MacWindow{ - InvisibleTitleBarHeight: 50, - }, - }).Show() - windowCounter++ - }) - if runtime.GOOS == "darwin" { - myMenu.Add("New WebviewWindow (MacTitleBarHiddenInset)"). - OnClick(func(ctx *application.Context) { - app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{ - Mac: application.MacWindow{ - TitleBar: application.MacTitleBarHiddenInset, - InvisibleTitleBarHeight: 25, - }, - }). - SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)). - SetPosition(rand.Intn(1000), rand.Intn(800)). - SetHTML("

A MacTitleBarHiddenInset WebviewWindow example

"). - Show() - windowCounter++ - }) - myMenu.Add("New WebviewWindow (MacTitleBarHiddenInsetUnified)"). - OnClick(func(ctx *application.Context) { - app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{ - Mac: application.MacWindow{ - TitleBar: application.MacTitleBarHiddenInsetUnified, - InvisibleTitleBarHeight: 50, - }, - }). - SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)). - SetPosition(rand.Intn(1000), rand.Intn(800)). - SetHTML("

A MacTitleBarHiddenInsetUnified WebviewWindow example

"). - Show() - windowCounter++ - }) - myMenu.Add("New WebviewWindow (MacTitleBarHidden)"). - OnClick(func(ctx *application.Context) { - app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{ - Mac: application.MacWindow{ - TitleBar: application.MacTitleBarHidden, - InvisibleTitleBarHeight: 25, - }, - }). - SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)). - SetPosition(rand.Intn(1000), rand.Intn(800)). - SetHTML("

A MacTitleBarHidden WebviewWindow example

"). - Show() - windowCounter++ - }) - } - - sizeMenu := menu.AddSubmenu("Size") - sizeMenu.Add("Set Size (800,600)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - w.SetSize(800, 600) - }) - }) - - sizeMenu.Add("Set Size (Random)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - w.SetSize(rand.Intn(800)+200, rand.Intn(600)+200) - }) - }) - sizeMenu.Add("Set Min Size (200,200)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - w.SetMinSize(200, 200) - }) - }) - sizeMenu.Add("Set Max Size (600,600)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - w.SetFullscreenButtonEnabled(false) - w.SetMaxSize(600, 600) - }) - }) - sizeMenu.Add("Get Current WebviewWindow Size").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - width, height := w.Size() - app.InfoDialog().SetTitle("Current WebviewWindow Size").SetMessage("Width: " + strconv.Itoa(width) + " Height: " + strconv.Itoa(height)).Show() - }) - }) - - sizeMenu.Add("Reset Min Size").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - w.SetMinSize(0, 0) - }) - }) - - sizeMenu.Add("Reset Max Size").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - w.SetMaxSize(0, 0) - w.SetFullscreenButtonEnabled(true) - }) - }) - positionMenu := menu.AddSubmenu("Position") - positionMenu.Add("Set Position (0,0)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - w.SetPosition(0, 0) - }) - }) - positionMenu.Add("Set Position (Random)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - w.SetPosition(rand.Intn(1000), rand.Intn(800)) - }) - }) - - positionMenu.Add("Get Position").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - x, y := w.Position() - app.InfoDialog().SetTitle("Current WebviewWindow Position").SetMessage("X: " + strconv.Itoa(x) + " Y: " + strconv.Itoa(y)).Show() - }) - }) - - positionMenu.Add("Center").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - w.Center() - }) - }) - stateMenu := menu.AddSubmenu("State") - stateMenu.Add("Minimise (for 2 secs)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - w.Minimise() - time.Sleep(2 * time.Second) - w.Restore() - }) - }) - stateMenu.Add("Maximise").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - w.Maximise() - }) - }) - stateMenu.Add("Fullscreen").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - w.Fullscreen() - }) - }) - stateMenu.Add("UnFullscreen").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - w.UnFullscreen() - }) - }) - stateMenu.Add("Restore").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - w.Restore() - }) - }) - stateMenu.Add("Hide (for 2 seconds)").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - w.Hide() - time.Sleep(2 * time.Second) - w.Show() - }) - }) - stateMenu.Add("Always on Top").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - w.SetAlwaysOnTop(true) - }) - }) - stateMenu.Add("Not always on Top").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - w.SetAlwaysOnTop(false) - }) - }) - stateMenu.Add("Google.com").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - w.SetURL("https://google.com") - }) - }) - stateMenu.Add("wails.io").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - w.SetURL("https://wails.io") - }) - }) - stateMenu.Add("Get Primary Screen").OnClick(func(ctx *application.Context) { - screen, err := app.GetPrimaryScreen() - if err != nil { - app.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show() - return - } - msg := fmt.Sprintf("Screen: %+v", screen) - app.InfoDialog().SetTitle("Primary Screen").SetMessage(msg).Show() - }) - stateMenu.Add("Get Screens").OnClick(func(ctx *application.Context) { - screens, err := app.GetScreens() - if err != nil { - app.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show() - return - } - for _, screen := range screens { - msg := fmt.Sprintf("Screen: %+v", screen) - app.InfoDialog().SetTitle(fmt.Sprintf("Screen %s", screen.ID)).SetMessage(msg).Show() - } - }) - stateMenu.Add("Get Screen for WebviewWindow").OnClick(func(ctx *application.Context) { - currentWindow(func(w *application.WebviewWindow) { - screen, err := w.GetScreen() - if err != nil { - app.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show() - return - } - msg := fmt.Sprintf("Screen: %+v", screen) - app.InfoDialog().SetTitle(fmt.Sprintf("Screen %s", screen.ID)).SetMessage(msg).Show() - }) - }) + // + //currentWindow := func(fn func(window *application.WebviewWindow)) { + // if app.CurrentWindow() != nil { + // fn(app.CurrentWindow()) + // } else { + // println("Current WebviewWindow is nil") + // } + //} + // + //// Create a custom menu + //menu := app.NewMenu() + //menu.AddRole(application.AppMenu) + // + //windowCounter := 1 + // + //// Let's make a "Demo" menu + //myMenu := menu.AddSubmenu("New") + // + //myMenu.Add("New WebviewWindow"). + // SetAccelerator("CmdOrCtrl+N"). + // OnClick(func(ctx *application.Context) { + // app.NewWebviewWindow(). + // SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)). + // SetPosition(rand.Intn(1000), rand.Intn(800)). + // SetURL("https://wails.io"). + // Show() + // windowCounter++ + // }) + //myMenu.Add("New WebviewWindow (Hide on Close"). + // SetAccelerator("CmdOrCtrl+H"). + // OnClick(func(ctx *application.Context) { + // app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{HideOnClose: true}). + // SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)). + // SetPosition(rand.Intn(1000), rand.Intn(800)). + // SetURL("https://wails.io"). + // Show() + // windowCounter++ + // }) + //myMenu.Add("New Frameless WebviewWindow"). + // SetAccelerator("CmdOrCtrl+F"). + // OnClick(func(ctx *application.Context) { + // app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{ + // X: rand.Intn(1000), + // Y: rand.Intn(800), + // Frameless: true, + // Mac: application.MacWindow{ + // InvisibleTitleBarHeight: 50, + // }, + // }).Show() + // windowCounter++ + // }) + //if runtime.GOOS == "darwin" { + // myMenu.Add("New WebviewWindow (MacTitleBarHiddenInset)"). + // OnClick(func(ctx *application.Context) { + // app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{ + // Mac: application.MacWindow{ + // TitleBar: application.MacTitleBarHiddenInset, + // InvisibleTitleBarHeight: 25, + // }, + // }). + // SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)). + // SetPosition(rand.Intn(1000), rand.Intn(800)). + // SetHTML("

A MacTitleBarHiddenInset WebviewWindow example

"). + // Show() + // windowCounter++ + // }) + // myMenu.Add("New WebviewWindow (MacTitleBarHiddenInsetUnified)"). + // OnClick(func(ctx *application.Context) { + // app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{ + // Mac: application.MacWindow{ + // TitleBar: application.MacTitleBarHiddenInsetUnified, + // InvisibleTitleBarHeight: 50, + // }, + // }). + // SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)). + // SetPosition(rand.Intn(1000), rand.Intn(800)). + // SetHTML("

A MacTitleBarHiddenInsetUnified WebviewWindow example

"). + // Show() + // windowCounter++ + // }) + // myMenu.Add("New WebviewWindow (MacTitleBarHidden)"). + // OnClick(func(ctx *application.Context) { + // app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{ + // Mac: application.MacWindow{ + // TitleBar: application.MacTitleBarHidden, + // InvisibleTitleBarHeight: 25, + // }, + // }). + // SetTitle("WebviewWindow "+strconv.Itoa(windowCounter)). + // SetPosition(rand.Intn(1000), rand.Intn(800)). + // SetHTML("

A MacTitleBarHidden WebviewWindow example

"). + // Show() + // windowCounter++ + // }) + //} + // + //sizeMenu := menu.AddSubmenu("Size") + //sizeMenu.Add("Set Size (800,600)").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // w.SetSize(800, 600) + // }) + //}) + // + //sizeMenu.Add("Set Size (Random)").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // w.SetSize(rand.Intn(800)+200, rand.Intn(600)+200) + // }) + //}) + //sizeMenu.Add("Set Min Size (200,200)").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // w.SetMinSize(200, 200) + // }) + //}) + //sizeMenu.Add("Set Max Size (600,600)").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // w.SetFullscreenButtonEnabled(false) + // w.SetMaxSize(600, 600) + // }) + //}) + //sizeMenu.Add("Get Current WebviewWindow Size").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // width, height := w.Size() + // app.InfoDialog().SetTitle("Current WebviewWindow Size").SetMessage("Width: " + strconv.Itoa(width) + " Height: " + strconv.Itoa(height)).Show() + // }) + //}) + // + //sizeMenu.Add("Reset Min Size").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // w.SetMinSize(0, 0) + // }) + //}) + // + //sizeMenu.Add("Reset Max Size").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // w.SetMaxSize(0, 0) + // w.SetFullscreenButtonEnabled(true) + // }) + //}) + //positionMenu := menu.AddSubmenu("Position") + //positionMenu.Add("Set Position (0,0)").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // w.SetPosition(0, 0) + // }) + //}) + //positionMenu.Add("Set Position (Random)").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // w.SetPosition(rand.Intn(1000), rand.Intn(800)) + // }) + //}) + // + //positionMenu.Add("Get Position").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // x, y := w.Position() + // app.InfoDialog().SetTitle("Current WebviewWindow Position").SetMessage("X: " + strconv.Itoa(x) + " Y: " + strconv.Itoa(y)).Show() + // }) + //}) + // + //positionMenu.Add("Center").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // w.Center() + // }) + //}) + //stateMenu := menu.AddSubmenu("State") + //stateMenu.Add("Minimise (for 2 secs)").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // w.Minimise() + // time.Sleep(2 * time.Second) + // w.Restore() + // }) + //}) + //stateMenu.Add("Maximise").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // w.Maximise() + // }) + //}) + //stateMenu.Add("Fullscreen").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // w.Fullscreen() + // }) + //}) + //stateMenu.Add("UnFullscreen").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // w.UnFullscreen() + // }) + //}) + //stateMenu.Add("Restore").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // w.Restore() + // }) + //}) + //stateMenu.Add("Hide (for 2 seconds)").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // w.Hide() + // time.Sleep(2 * time.Second) + // w.Show() + // }) + //}) + //stateMenu.Add("Always on Top").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // w.SetAlwaysOnTop(true) + // }) + //}) + //stateMenu.Add("Not always on Top").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // w.SetAlwaysOnTop(false) + // }) + //}) + //stateMenu.Add("Google.com").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // w.SetURL("https://google.com") + // }) + //}) + //stateMenu.Add("wails.io").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // w.SetURL("https://wails.io") + // }) + //}) + //stateMenu.Add("Get Primary Screen").OnClick(func(ctx *application.Context) { + // screen, err := app.GetPrimaryScreen() + // if err != nil { + // app.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show() + // return + // } + // msg := fmt.Sprintf("Screen: %+v", screen) + // app.InfoDialog().SetTitle("Primary Screen").SetMessage(msg).Show() + //}) + //stateMenu.Add("Get Screens").OnClick(func(ctx *application.Context) { + // screens, err := app.GetScreens() + // if err != nil { + // app.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show() + // return + // } + // for _, screen := range screens { + // msg := fmt.Sprintf("Screen: %+v", screen) + // app.InfoDialog().SetTitle(fmt.Sprintf("Screen %s", screen.ID)).SetMessage(msg).Show() + // } + //}) + //stateMenu.Add("Get Screen for WebviewWindow").OnClick(func(ctx *application.Context) { + // currentWindow(func(w *application.WebviewWindow) { + // screen, err := w.GetScreen() + // if err != nil { + // app.ErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show() + // return + // } + // msg := fmt.Sprintf("Screen: %+v", screen) + // app.InfoDialog().SetTitle(fmt.Sprintf("Screen %s", screen.ID)).SetMessage(msg).Show() + // }) + //}) app.NewWebviewWindowWithOptions(application.WebviewWindowOptions{ Mac: application.MacWindow{ DisableShadow: true, }, }) - app.SetMenu(menu) + //app.SetMenu(menu) err := app.Run() if err != nil { diff --git a/v3/go.mod b/v3/go.mod index a2b7cfdb..a664f784 100644 --- a/v3/go.mod +++ b/v3/go.mod @@ -18,8 +18,9 @@ require ( github.com/pterm/pterm v0.12.51 github.com/samber/lo v1.37.0 github.com/tc-hib/winres v0.1.6 + github.com/wailsapp/go-webview2 v1.0.1 github.com/wailsapp/wails/v2 v2.3.2-0.20230117193915-45c3a501d9e6 - golang.org/x/sys v0.7.0 + golang.org/x/sys v0.8.0 modernc.org/sqlite v1.21.0 ) @@ -31,6 +32,7 @@ require ( github.com/fatih/color v1.13.0 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/gookit/color v1.5.2 // indirect + github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect github.com/joho/godotenv v1.4.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/leaanthony/slicer v1.5.0 // indirect diff --git a/v3/go.sum b/v3/go.sum index 4d563491..3057c2cf 100644 --- a/v3/go.sum +++ b/v3/go.sum @@ -41,6 +41,8 @@ github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI= github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg= github.com/jackmordaunt/icns/v2 v2.2.1 h1:MGklwYP2yohKn2Bw7XxlF69LZe98S1vUfl5OvAulPwg= github.com/jackmordaunt/icns/v2 v2.2.1/go.mod h1:6aYIB9eSzyfHHMKqDf17Xrs1zetQPReAkiUSHzdw4cI= +github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= +github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= github.com/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= @@ -140,6 +142,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/tc-hib/winres v0.1.6 h1:qgsYHze+BxQPEYilxIz/KCQGaClvI2+yLBAZs+3+0B8= github.com/tc-hib/winres v0.1.6/go.mod h1:pe6dOR40VOrGz8PkzreVKNvEKnlE8t4yR8A8naL+t7A= +github.com/wailsapp/go-webview2 v1.0.1 h1:dEJIeEApW/MhO2tTMISZBFZPuW7kwrFA1NtgFB1z1II= +github.com/wailsapp/go-webview2 v1.0.1/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo= github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs= github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= @@ -172,6 +176,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -185,8 +190,8 @@ golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/v3/pkg/application/application.go b/v3/pkg/application/application.go index 9278fdd0..7508afda 100644 --- a/v3/pkg/application/application.go +++ b/v3/pkg/application/application.go @@ -23,6 +23,9 @@ import ( var globalApplication *App +// isDebugMode is true if the application is running in debug mode +var isDebugMode func() bool + func init() { runtime.LockOSThread() } @@ -53,6 +56,13 @@ func New(appOptions Options) *App { result.log.AddOutput(&logger.Console{}) } + // Patch isDebug if we aren't in prod mode + if isDebugMode == nil { + isDebugMode = func() bool { + return true + } + } + result.Events = NewWailsEventProcessor(result.dispatchEventToWindows) opts := assetserveroptions.Options{ @@ -206,7 +216,8 @@ type App struct { contextMenus map[string]*Menu contextMenusLock sync.Mutex - assets *assetserver.AssetServer + assets *assetserver.AssetServer + startURL string // Hooks windowCreatedCallbacks []func(window *WebviewWindow) diff --git a/v3/pkg/application/application_production.go b/v3/pkg/application/application_production.go new file mode 100644 index 00000000..14be48cb --- /dev/null +++ b/v3/pkg/application/application_production.go @@ -0,0 +1,10 @@ +//go:build production + +package application + +// We use this to patch the application to production mode. +func init() { + isDebugMode = func() bool { + return false + } +} diff --git a/v3/pkg/application/options_webview_window.go b/v3/pkg/application/options_webview_window.go index 0855a289..3367ccd2 100644 --- a/v3/pkg/application/options_webview_window.go +++ b/v3/pkg/application/options_webview_window.go @@ -36,7 +36,9 @@ type WebviewWindowOptions struct { Hidden bool EnableFraudulentWebsiteWarnings bool Zoom float64 + ZoomControlEnabled bool EnableDragAndDrop bool + OpenInspectorOnStartup bool Mac MacWindow Windows WindowsWindow Focused bool diff --git a/v3/pkg/application/options_win.go b/v3/pkg/application/options_win.go index 25003fde..c4842f63 100644 --- a/v3/pkg/application/options_win.go +++ b/v3/pkg/application/options_win.go @@ -38,6 +38,16 @@ type WindowsWindow struct { // WindowMask is used to set the window shape. Use a PNG with an alpha channel to create a custom shape. WindowMask []byte WindowMaskDraggable bool + + // Path where the WebView2 stores the user data. If empty %APPDATA%\[BinaryName.exe] will be used. + // If the path is not valid, a messagebox will be displayed with the error and the app will exit with error code. + WebviewUserDataPath string + + // Path to the directory with WebView2 executables. If empty WebView2 installed in the system will be used. + WebviewBrowserPath string + + // WebviewGpuIsDisabled is used to enable / disable GPU acceleration for the webview + WebviewGpuIsDisabled bool } type Theme int diff --git a/v3/pkg/application/webview_window_darwin.go b/v3/pkg/application/webview_window_darwin.go index d5b316d9..6acf5e44 100644 --- a/v3/pkg/application/webview_window_darwin.go +++ b/v3/pkg/application/webview_window_darwin.go @@ -1111,7 +1111,9 @@ func (w *macosWebviewWindow) run() { w.setMaxSize(w.parent.options.MaxWidth, w.parent.options.MaxHeight) } //w.setZoom(w.parent.options.Zoom) - w.enableDevTools() + if isDebugMode() { + w.enableDevTools() + } w.setBackgroundColour(w.parent.options.BackgroundColour) macOptions := w.parent.options.Mac diff --git a/v3/pkg/application/webview_window_windows.go b/v3/pkg/application/webview_window_windows.go index 314bd62a..b07c4993 100644 --- a/v3/pkg/application/webview_window_windows.go +++ b/v3/pkg/application/webview_window_windows.go @@ -5,12 +5,19 @@ package application import ( "errors" "fmt" + "github.com/wailsapp/wails/v2/pkg/assetserver" + "io" + "net/http" + "net/http/httptest" + "net/url" "strconv" + "strings" "unicode/utf16" "unsafe" "github.com/samber/lo" + "github.com/wailsapp/go-webview2/pkg/edge" "github.com/wailsapp/wails/v3/pkg/events" "github.com/wailsapp/wails/v3/pkg/w32" ) @@ -27,6 +34,10 @@ type windowsWebviewWindow struct { previousWindowStyle uint32 previousWindowExStyle uint32 previousWindowPlacement w32.WINDOWPLACEMENT + + // Webview + chromium *edge.Chromium + hasStarted bool } func (w *windowsWebviewWindow) nativeWindowHandle() uintptr { @@ -89,6 +100,8 @@ func (w *windowsWebviewWindow) run() { options := w.parent.options + w.chromium = edge.NewChromium() + var exStyle uint exStyle = w32.WS_EX_CONTROLPARENT | w32.WS_EX_APPWINDOW if options.BackgroundType != BackgroundTypeSolid { @@ -197,6 +210,8 @@ func (w *windowsWebviewWindow) run() { w.Focus() } + w.setupChromium() + if !options.Hidden { w.show() w.update() @@ -622,6 +637,10 @@ func (w *windowsWebviewWindow) WndProc(msg uint32, wparam, lparam uintptr) uintp // Unregister the window with the application windowsApp := globalApplication.impl.(*windowsApp) windowsApp.unregisterWindow(w) + case w32.WM_NCLBUTTONDOWN: + w32.SetFocus(w.hwnd) + case w32.WM_MOVE, w32.WM_MOVING: + _ = w.chromium.NotifyParentWindowPositionChanged() case w32.WM_GETMINMAXINFO: mmi := (*w32.MINMAXINFO)(unsafe.Pointer(lparam)) hasConstraints := false @@ -742,7 +761,7 @@ func (w *windowsWebviewWindow) WndProc(msg uint32, wparam, lparam uintptr) uintp // In Full-Screen mode we don't need to adjust anything // It essential we have the flag here, that is set before SetWindowPos in fullscreen/unfullscreen // because the native size might not yet reflect we are in fullscreen during this event! - // TODO: w.chromium.SetPadding(edge.Rect{}) + w.chromium.SetPadding(edge.Rect{}) } else if w.isMaximised() { // If the window is maximized we must adjust the client area to the work area of the monitor. Otherwise // some content goes beyond the visible part of the monitor. @@ -773,7 +792,7 @@ func (w *windowsWebviewWindow) WndProc(msg uint32, wparam, lparam uintptr) uintp } } } - // TODO: w.chromium.SetPadding(edge.Rect{}) + w.chromium.SetPadding(edge.Rect{}) } else { // This is needed to workaround the resize flickering in frameless mode with WindowDecorations // See: https://stackoverflow.com/a/6558508 @@ -782,7 +801,7 @@ func (w *windowsWebviewWindow) WndProc(msg uint32, wparam, lparam uintptr) uintp // Increasing the bottom also worksaround the flickering but we would loose 1px of the WebView content // therefore let's pad the content with 1px at the bottom. rgrc.Bottom += 1 - // TODO: w.chromium.SetPadding(edge.Rect{Bottom: 1}) + w.chromium.SetPadding(edge.Rect{Bottom: 1}) } return 0 } @@ -878,6 +897,304 @@ func (w *windowsWebviewWindow) isAlwaysOnTop() bool { return w32.GetWindowLong(w.hwnd, w32.GWL_EXSTYLE)&w32.WS_EX_TOPMOST != 0 } +// processMessage is given a message sent from JS via the postMessage API +// We put it on the global window message buffer to be processed centrally +func (w *windowsWebviewWindow) processMessage(message string) { + // We send all messages to the centralised window message buffer + windowMessageBuffer <- &windowMessage{ + windowId: w.parent.id, + message: message, + } +} + +func coreWebview2RequestToHttpRequest(coreReq *edge.ICoreWebView2WebResourceRequest) func() (*http.Request, error) { + return func() (r *http.Request, err error) { + header := http.Header{} + headers, err := coreReq.GetHeaders() + if err != nil { + return nil, fmt.Errorf("GetHeaders Error: %s", err) + } + defer headers.Release() + + headersIt, err := headers.GetIterator() + if err != nil { + return nil, fmt.Errorf("GetIterator Error: %s", err) + } + defer headersIt.Release() + + for { + has, err := headersIt.HasCurrentHeader() + if err != nil { + return nil, fmt.Errorf("HasCurrentHeader Error: %s", err) + } + if !has { + break + } + + name, value, err := headersIt.GetCurrentHeader() + if err != nil { + return nil, fmt.Errorf("GetCurrentHeader Error: %s", err) + } + + header.Set(name, value) + if _, err := headersIt.MoveNext(); err != nil { + return nil, fmt.Errorf("MoveNext Error: %s", err) + } + } + + method, err := coreReq.GetMethod() + if err != nil { + return nil, fmt.Errorf("GetMethod Error: %s", err) + } + + uri, err := coreReq.GetUri() + if err != nil { + return nil, fmt.Errorf("GetUri Error: %s", err) + } + + var body io.ReadCloser + if content, err := coreReq.GetContent(); err != nil { + return nil, fmt.Errorf("GetContent Error: %s", err) + } else if content != nil { + body = &iStreamReleaseCloser{stream: content} + } + + req, err := http.NewRequest(method, uri, body) + if err != nil { + if body != nil { + body.Close() + } + return nil, err + } + req.Header = header + return req, nil + } +} + +type iStreamReleaseCloser struct { + stream *edge.IStream + closed bool +} + +func (i *iStreamReleaseCloser) Read(p []byte) (int, error) { + if i.closed { + return 0, io.ErrClosedPipe + } + return i.stream.Read(p) +} + +func (i *iStreamReleaseCloser) Close() error { + if i.closed { + return nil + } + i.closed = true + return i.stream.Release() +} + +func (w *windowsWebviewWindow) processRequest(req *edge.ICoreWebView2WebResourceRequest, args *edge.ICoreWebView2WebResourceRequestedEventArgs) { + /* + webviewRequests <- &webViewAssetRequest{ + Request: webview.NewRequest(wkUrlSchemeTask), + windowId: uint(windowID), + windowName: globalApplication.getWindowForID(uint(windowID)).Name(), + } + */ + // Setting the UserAgent on the CoreWebView2Settings clears the whole default UserAgent of the Edge browser, but + // we want to just append our ApplicationIdentifier. So we adjust the UserAgent for every request. + if reqHeaders, err := req.GetHeaders(); err == nil { + useragent, _ := reqHeaders.GetHeader(assetserver.HeaderUserAgent) + useragent = strings.Join([]string{useragent, assetserver.WailsUserAgentValue}, " ") + reqHeaders.SetHeader(assetserver.HeaderUserAgent, useragent) + reqHeaders.Release() + } + + if globalApplication.assets == nil { + // We are using the devServer let the WebView2 handle the request with its default handler + return + } + + //Get the request + uri, _ := req.GetUri() + reqUri, err := url.ParseRequestURI(uri) + if err != nil { + globalApplication.error("Unable to parse request uri %s: %s", uri, err) + return + } + + if reqUri.Scheme != "http" { + // Let the WebView2 handle the request with its default handler + return + } else if reqUri.Host != "wails.localhost" { + // Let the WebView2 handle the request with its default handler + return + } + + rw := httptest.NewRecorder() + globalApplication.assets.ProcessHTTPRequestLegacy(rw, coreWebview2RequestToHttpRequest(req)) + + headers := []string{} + for k, v := range rw.Header() { + headers = append(headers, fmt.Sprintf("%s: %s", k, strings.Join(v, ","))) + } + + env := w.chromium.Environment() + response, err := env.CreateWebResourceResponse(rw.Body.Bytes(), rw.Code, http.StatusText(rw.Code), strings.Join(headers, "\n")) + if err != nil { + globalApplication.error("CreateWebResourceResponse Error: %s", err) + return + } + defer response.Release() + + // Send response back + err = args.PutResponse(response) + if err != nil { + globalApplication.error("PutResponse Error: %s", err) + return + } +} + +func (w *windowsWebviewWindow) setupChromium() { + chromium := w.chromium + debugMode := isDebugMode() + + disableFeatues := []string{} + + if !w.parent.options.EnableFraudulentWebsiteWarnings { + disableFeatues = append(disableFeatues, "msSmartScreenProtection") + } + + opts := w.parent.options.Windows + chromium.DataPath = opts.WebviewUserDataPath + chromium.BrowserPath = opts.WebviewBrowserPath + + if opts.WebviewGpuIsDisabled { + chromium.AdditionalBrowserArgs = append(chromium.AdditionalBrowserArgs, "--disable-gpu") + } + + if len(disableFeatues) > 0 { + arg := fmt.Sprintf("--disable-features=%s", strings.Join(disableFeatues, ",")) + chromium.AdditionalBrowserArgs = append(chromium.AdditionalBrowserArgs, arg) + } + + chromium.MessageCallback = w.processMessage + chromium.WebResourceRequestedCallback = w.processRequest + chromium.NavigationCompletedCallback = w.navigationCompleted + chromium.AcceleratorKeyCallback = func(vkey uint) bool { + w32.PostMessage(w.hwnd, w32.WM_KEYDOWN, uintptr(vkey), 0) + return false + } + + chromium.Embed(w.hwnd) + chromium.Resize() + settings, err := chromium.GetSettings() + if err != nil { + globalApplication.fatal(err.Error()) + } + err = settings.PutAreDefaultContextMenusEnabled(debugMode) + if err != nil { + globalApplication.fatal(err.Error()) + } + err = settings.PutAreDevToolsEnabled(debugMode) + if err != nil { + globalApplication.fatal(err.Error()) + } + + if w.parent.options.Zoom > 0.0 { + chromium.PutZoomFactor(w.parent.options.Zoom) + } + err = settings.PutIsZoomControlEnabled(w.parent.options.ZoomControlEnabled) + if err != nil { + globalApplication.fatal(err.Error()) + } + + err = settings.PutIsStatusBarEnabled(false) + if err != nil { + globalApplication.fatal(err.Error()) + } + err = settings.PutAreBrowserAcceleratorKeysEnabled(false) + if err != nil { + globalApplication.fatal(err.Error()) + } + err = settings.PutIsSwipeNavigationEnabled(false) + if err != nil { + globalApplication.fatal(err.Error()) + } + + if debugMode && w.parent.options.OpenInspectorOnStartup { + chromium.OpenDevToolsWindow() + } + + //TODO: Setup focus event handler + //onFocus := f.mainWindow.OnSetFocus() + //onFocus.Bind(f.onFocus) + + // Set background colour + w.setBackgroundColour(w.parent.options.BackgroundColour) + + chromium.SetGlobalPermission(edge.CoreWebView2PermissionStateAllow) + chromium.AddWebResourceRequestedFilter("*", edge.COREWEBVIEW2_WEB_RESOURCE_CONTEXT_ALL) + chromium.Navigate("http://wails.localhost") + +} + +func (w *windowsWebviewWindow) navigationCompleted(sender *edge.ICoreWebView2, args *edge.ICoreWebView2NavigationCompletedEventArgs) { + + // TODO: DomReady Event + + // Todo: Resize hacks + /* + if f.frontendOptions.Frameless && f.frontendOptions.DisableResize == false { + f.ExecJS("window.wails.flags.enableResize = true;") + } + */ + + // TODO: Work out why we need this + //if w.hasStarted { + // return + //} + //w.hasStarted = true + + // Hack to make it visible: https://github.com/MicrosoftEdge/WebView2Feedback/issues/1077#issuecomment-825375026 + err := w.chromium.Hide() + if err != nil { + globalApplication.fatal(err.Error()) + } + if w.parent.options.Hidden { + return + } + err = w.chromium.Show() + if err != nil { + globalApplication.fatal(err.Error()) + + } + + //if w.parent.options.Hidden { + // return + //} + + //switch f.frontendOptions.WindowStartState { + //case options.Maximised: + // if !f.frontendOptions.DisableResize { + // win32.ShowWindowMaximised(f.mainWindow.Handle()) + // } else { + // win32.ShowWindow(f.mainWindow.Handle()) + // } + //case options.Minimised: + // win32.ShowWindowMinimised(f.mainWindow.Handle()) + //case options.Fullscreen: + // f.mainWindow.Fullscreen() + // win32.ShowWindow(f.mainWindow.Handle()) + //default: + // if f.frontendOptions.Fullscreen { + // f.mainWindow.Fullscreen() + // } + // win32.ShowWindow(f.mainWindow.Handle()) + //} + // + //f.mainWindow.hasBeenShown = true + +} + func ScaleWithDPI(pixels int, dpi uint) int { return (pixels * int(dpi)) / 96 }