574 lines
17 KiB
Go
574 lines
17 KiB
Go
|
//go:build windows
|
||
|
// +build windows
|
||
|
|
||
|
package edge
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"log"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"strings"
|
||
|
"sync/atomic"
|
||
|
"syscall"
|
||
|
"unsafe"
|
||
|
|
||
|
"github.com/wailsapp/go-webview2/internal/w32"
|
||
|
"github.com/wailsapp/go-webview2/webviewloader"
|
||
|
"golang.org/x/sys/windows"
|
||
|
)
|
||
|
|
||
|
type Rect = w32.Rect
|
||
|
|
||
|
type Chromium struct {
|
||
|
hwnd uintptr
|
||
|
controller *ICoreWebView2Controller
|
||
|
webview *ICoreWebView2
|
||
|
inited uintptr
|
||
|
envCompleted *iCoreWebView2CreateCoreWebView2EnvironmentCompletedHandler
|
||
|
controllerCompleted *iCoreWebView2CreateCoreWebView2ControllerCompletedHandler
|
||
|
webMessageReceived *iCoreWebView2WebMessageReceivedEventHandler
|
||
|
containsFullScreenElementChanged *ICoreWebView2ContainsFullScreenElementChangedEventHandler
|
||
|
permissionRequested *iCoreWebView2PermissionRequestedEventHandler
|
||
|
webResourceRequested *iCoreWebView2WebResourceRequestedEventHandler
|
||
|
acceleratorKeyPressed *ICoreWebView2AcceleratorKeyPressedEventHandler
|
||
|
navigationCompleted *ICoreWebView2NavigationCompletedEventHandler
|
||
|
processFailed *ICoreWebView2ProcessFailedEventHandler
|
||
|
|
||
|
environment *ICoreWebView2Environment
|
||
|
padding Rect
|
||
|
webview2RuntimeVersion string
|
||
|
|
||
|
// Settings
|
||
|
Debug bool
|
||
|
DataPath string
|
||
|
BrowserPath string
|
||
|
AdditionalBrowserArgs []string
|
||
|
|
||
|
// permissions
|
||
|
permissions map[CoreWebView2PermissionKind]CoreWebView2PermissionState
|
||
|
globalPermission *CoreWebView2PermissionState
|
||
|
|
||
|
// Callbacks
|
||
|
MessageCallback func(string)
|
||
|
MessageWithAdditionalObjectsCallback func(message string, sender *ICoreWebView2, args *ICoreWebView2WebMessageReceivedEventArgs)
|
||
|
WebResourceRequestedCallback func(request *ICoreWebView2WebResourceRequest, args *ICoreWebView2WebResourceRequestedEventArgs)
|
||
|
NavigationCompletedCallback func(sender *ICoreWebView2, args *ICoreWebView2NavigationCompletedEventArgs)
|
||
|
ProcessFailedCallback func(sender *ICoreWebView2, args *ICoreWebView2ProcessFailedEventArgs)
|
||
|
ContainsFullScreenElementChangedCallback func(sender *ICoreWebView2, args *ICoreWebView2ContainsFullScreenElementChangedEventArgs)
|
||
|
AcceleratorKeyCallback func(uint) bool
|
||
|
}
|
||
|
|
||
|
func NewChromium() *Chromium {
|
||
|
e := &Chromium{}
|
||
|
/*
|
||
|
All these handlers are passed to native code through syscalls with 'uintptr(unsafe.Pointer(handler))' and we know
|
||
|
that a pointer to those will be kept in the native code. Furthermore these handlers als contain pointer to other Go
|
||
|
structs like the vtable.
|
||
|
This violates the unsafe.Pointer rule '(4) Conversion of a Pointer to a uintptr when calling syscall.Syscall.' because
|
||
|
theres no guarantee that Go doesn't move these objects.
|
||
|
AFAIK currently the Go runtime doesn't move HEAP objects, so we should be safe with these handlers. But they don't
|
||
|
guarantee it, because in the future Go might use a compacting GC.
|
||
|
There's a proposal to add a runtime.Pin function, to prevent moving pinned objects, which would allow to easily fix
|
||
|
this issue by just pinning the handlers. The https://go-review.googlesource.com/c/go/+/367296/ should land in Go 1.19.
|
||
|
*/
|
||
|
e.envCompleted = newICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler(e)
|
||
|
e.controllerCompleted = newICoreWebView2CreateCoreWebView2ControllerCompletedHandler(e)
|
||
|
e.webMessageReceived = newICoreWebView2WebMessageReceivedEventHandler(e)
|
||
|
e.permissionRequested = newICoreWebView2PermissionRequestedEventHandler(e)
|
||
|
e.webResourceRequested = newICoreWebView2WebResourceRequestedEventHandler(e)
|
||
|
e.acceleratorKeyPressed = newICoreWebView2AcceleratorKeyPressedEventHandler(e)
|
||
|
e.navigationCompleted = newICoreWebView2NavigationCompletedEventHandler(e)
|
||
|
e.processFailed = newICoreWebView2ProcessFailedEventHandler(e)
|
||
|
e.containsFullScreenElementChanged = newICoreWebView2ContainsFullScreenElementChangedEventHandler(e)
|
||
|
/*
|
||
|
// Pinner seems to panic in some cases as reported on Discord, maybe during shutdown when GC detects pinned objects
|
||
|
// to be released that have not been unpinned.
|
||
|
// It would also be better to use our ComBridge for this event handlers implementation instead of pinning them.
|
||
|
// So all COM Implementations on the go-side use the same code.
|
||
|
var pinner runtime.Pinner
|
||
|
pinner.Pin(e.envCompleted)
|
||
|
pinner.Pin(e.controllerCompleted)
|
||
|
pinner.Pin(e.webMessageReceived)
|
||
|
pinner.Pin(e.permissionRequested)
|
||
|
pinner.Pin(e.webResourceRequested)
|
||
|
pinner.Pin(e.acceleratorKeyPressed)
|
||
|
pinner.Pin(e.navigationCompleted)
|
||
|
pinner.Pin(e.processFailed)
|
||
|
pinner.Pin(e.containsFullScreenElementChanged)
|
||
|
*/
|
||
|
e.permissions = make(map[CoreWebView2PermissionKind]CoreWebView2PermissionState)
|
||
|
|
||
|
return e
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) Embed(hwnd uintptr) bool {
|
||
|
|
||
|
var err error
|
||
|
|
||
|
e.hwnd = hwnd
|
||
|
|
||
|
dataPath := e.DataPath
|
||
|
if dataPath == "" {
|
||
|
currentExePath := make([]uint16, windows.MAX_PATH)
|
||
|
_, err := windows.GetModuleFileName(windows.Handle(0), ¤tExePath[0], windows.MAX_PATH)
|
||
|
if err != nil {
|
||
|
// What to do here?
|
||
|
return false
|
||
|
}
|
||
|
currentExeName := filepath.Base(windows.UTF16ToString(currentExePath))
|
||
|
dataPath = filepath.Join(os.Getenv("AppData"), currentExeName)
|
||
|
}
|
||
|
|
||
|
if e.BrowserPath != "" {
|
||
|
if _, err := os.Stat(e.BrowserPath); errors.Is(err, os.ErrNotExist) {
|
||
|
log.Printf("Browser path %s does not exist", e.BrowserPath)
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
browserArgs := strings.Join(e.AdditionalBrowserArgs, " ")
|
||
|
if err := createCoreWebView2EnvironmentWithOptions(e.BrowserPath, dataPath, e.envCompleted, browserArgs); err != nil {
|
||
|
log.Printf("Error calling Webview2Loader: %v", err)
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
e.webview2RuntimeVersion, err = webviewloader.GetAvailableCoreWebView2BrowserVersionString(e.BrowserPath)
|
||
|
if err != nil {
|
||
|
log.Printf("Error getting Webview2 runtime version: %v", err)
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
var msg w32.Msg
|
||
|
for {
|
||
|
if atomic.LoadUintptr(&e.inited) != 0 {
|
||
|
break
|
||
|
}
|
||
|
r, _, _ := w32.User32GetMessageW.Call(
|
||
|
uintptr(unsafe.Pointer(&msg)),
|
||
|
0,
|
||
|
0,
|
||
|
0,
|
||
|
)
|
||
|
if r == 0 {
|
||
|
break
|
||
|
}
|
||
|
w32.User32TranslateMessage.Call(uintptr(unsafe.Pointer(&msg)))
|
||
|
w32.User32DispatchMessageW.Call(uintptr(unsafe.Pointer(&msg)))
|
||
|
}
|
||
|
e.Init("window.external={invoke:s=>window.chrome.webview.postMessage(s)}")
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) SetPadding(padding Rect) {
|
||
|
if e.padding.Top == padding.Top && e.padding.Bottom == padding.Bottom &&
|
||
|
e.padding.Left == padding.Left && e.padding.Right == padding.Right {
|
||
|
|
||
|
return
|
||
|
}
|
||
|
|
||
|
e.padding = padding
|
||
|
e.Resize()
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) Resize() {
|
||
|
if e.hwnd == 0 {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
var bounds w32.Rect
|
||
|
w32.User32GetClientRect.Call(e.hwnd, uintptr(unsafe.Pointer(&bounds)))
|
||
|
|
||
|
bounds.Top += e.padding.Top
|
||
|
bounds.Bottom -= e.padding.Bottom
|
||
|
bounds.Left += e.padding.Left
|
||
|
bounds.Right -= e.padding.Right
|
||
|
|
||
|
e.SetSize(bounds)
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) Navigate(url string) {
|
||
|
e.webview.vtbl.Navigate.Call(
|
||
|
uintptr(unsafe.Pointer(e.webview)),
|
||
|
uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(url))),
|
||
|
)
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) NavigateToString(content string) {
|
||
|
e.webview.vtbl.NavigateToString.Call(
|
||
|
uintptr(unsafe.Pointer(e.webview)),
|
||
|
uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(content))),
|
||
|
)
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) Init(script string) {
|
||
|
e.webview.vtbl.AddScriptToExecuteOnDocumentCreated.Call(
|
||
|
uintptr(unsafe.Pointer(e.webview)),
|
||
|
uintptr(unsafe.Pointer(windows.StringToUTF16Ptr(script))),
|
||
|
0,
|
||
|
)
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) Eval(script string) {
|
||
|
|
||
|
if e.webview == nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
_script, err := windows.UTF16PtrFromString(script)
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
|
||
|
e.webview.vtbl.ExecuteScript.Call(
|
||
|
uintptr(unsafe.Pointer(e.webview)),
|
||
|
uintptr(unsafe.Pointer(_script)),
|
||
|
0,
|
||
|
)
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) Show() error {
|
||
|
return e.controller.PutIsVisible(true)
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) Hide() error {
|
||
|
return e.controller.PutIsVisible(false)
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) QueryInterface(_, _ uintptr) uintptr {
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) AddRef() uintptr {
|
||
|
return 1
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) Release() uintptr {
|
||
|
return 1
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) EnvironmentCompleted(res uintptr, env *ICoreWebView2Environment) uintptr {
|
||
|
if int32(res) < 0 {
|
||
|
log.Fatalf("Creating environment failed with %08x: %s", res, syscall.Errno(res))
|
||
|
}
|
||
|
env.vtbl.AddRef.Call(uintptr(unsafe.Pointer(env)))
|
||
|
e.environment = env
|
||
|
|
||
|
env.vtbl.CreateCoreWebView2Controller.Call(
|
||
|
uintptr(unsafe.Pointer(env)),
|
||
|
e.hwnd,
|
||
|
uintptr(unsafe.Pointer(e.controllerCompleted)),
|
||
|
)
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) CreateCoreWebView2ControllerCompleted(res uintptr, controller *ICoreWebView2Controller) uintptr {
|
||
|
if int32(res) < 0 {
|
||
|
log.Fatalf("Creating controller failed with %08x: %s", res, syscall.Errno(res))
|
||
|
}
|
||
|
controller.vtbl.AddRef.Call(uintptr(unsafe.Pointer(controller)))
|
||
|
e.controller = controller
|
||
|
|
||
|
var token _EventRegistrationToken
|
||
|
controller.vtbl.GetCoreWebView2.Call(
|
||
|
uintptr(unsafe.Pointer(controller)),
|
||
|
uintptr(unsafe.Pointer(&e.webview)),
|
||
|
)
|
||
|
e.webview.vtbl.AddRef.Call(
|
||
|
uintptr(unsafe.Pointer(e.webview)),
|
||
|
)
|
||
|
e.webview.vtbl.AddWebMessageReceived.Call(
|
||
|
uintptr(unsafe.Pointer(e.webview)),
|
||
|
uintptr(unsafe.Pointer(e.webMessageReceived)),
|
||
|
uintptr(unsafe.Pointer(&token)),
|
||
|
)
|
||
|
e.webview.vtbl.AddPermissionRequested.Call(
|
||
|
uintptr(unsafe.Pointer(e.webview)),
|
||
|
uintptr(unsafe.Pointer(e.permissionRequested)),
|
||
|
uintptr(unsafe.Pointer(&token)),
|
||
|
)
|
||
|
e.webview.vtbl.AddWebResourceRequested.Call(
|
||
|
uintptr(unsafe.Pointer(e.webview)),
|
||
|
uintptr(unsafe.Pointer(e.webResourceRequested)),
|
||
|
uintptr(unsafe.Pointer(&token)),
|
||
|
)
|
||
|
e.webview.vtbl.AddNavigationCompleted.Call(
|
||
|
uintptr(unsafe.Pointer(e.webview)),
|
||
|
uintptr(unsafe.Pointer(e.navigationCompleted)),
|
||
|
uintptr(unsafe.Pointer(&token)),
|
||
|
)
|
||
|
e.webview.vtbl.AddProcessFailed.Call(
|
||
|
uintptr(unsafe.Pointer(e.webview)),
|
||
|
uintptr(unsafe.Pointer(e.processFailed)),
|
||
|
uintptr(unsafe.Pointer(&token)),
|
||
|
)
|
||
|
e.webview.vtbl.AddContainsFullScreenElementChanged.Call(
|
||
|
uintptr(unsafe.Pointer(e.webview)),
|
||
|
uintptr(unsafe.Pointer(e.containsFullScreenElementChanged)),
|
||
|
uintptr(unsafe.Pointer(&token)),
|
||
|
)
|
||
|
|
||
|
e.controller.AddAcceleratorKeyPressed(e.acceleratorKeyPressed, &token)
|
||
|
|
||
|
atomic.StoreUintptr(&e.inited, 1)
|
||
|
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) ContainsFullScreenElementChanged(sender *ICoreWebView2, args *ICoreWebView2ContainsFullScreenElementChangedEventArgs) uintptr {
|
||
|
if e.ContainsFullScreenElementChangedCallback != nil {
|
||
|
e.ContainsFullScreenElementChangedCallback(sender, args)
|
||
|
}
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) MessageReceived(sender *ICoreWebView2, args *ICoreWebView2WebMessageReceivedEventArgs) uintptr {
|
||
|
var _message *uint16
|
||
|
args.vtbl.TryGetWebMessageAsString.Call(
|
||
|
uintptr(unsafe.Pointer(args)),
|
||
|
uintptr(unsafe.Pointer(&_message)),
|
||
|
)
|
||
|
|
||
|
message := w32.Utf16PtrToString(_message)
|
||
|
|
||
|
if hasCapability(e.webview2RuntimeVersion, GetAdditionalObjects) {
|
||
|
obj, err := args.GetAdditionalObjects()
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
|
||
|
if obj != nil && e.MessageWithAdditionalObjectsCallback != nil {
|
||
|
defer obj.Release()
|
||
|
e.MessageWithAdditionalObjectsCallback(message, sender, args)
|
||
|
} else if e.MessageCallback != nil {
|
||
|
e.MessageCallback(message)
|
||
|
}
|
||
|
} else if e.MessageCallback != nil {
|
||
|
e.MessageCallback(message)
|
||
|
}
|
||
|
|
||
|
sender.vtbl.PostWebMessageAsString.Call(
|
||
|
uintptr(unsafe.Pointer(sender)),
|
||
|
uintptr(unsafe.Pointer(_message)),
|
||
|
)
|
||
|
windows.CoTaskMemFree(unsafe.Pointer(_message))
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) SetPermission(kind CoreWebView2PermissionKind, state CoreWebView2PermissionState) {
|
||
|
e.permissions[kind] = state
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) SetBackgroundColour(R, G, B, A uint8) {
|
||
|
controller := e.GetController()
|
||
|
controller2 := controller.GetICoreWebView2Controller2()
|
||
|
|
||
|
backgroundCol := COREWEBVIEW2_COLOR{
|
||
|
A: A,
|
||
|
R: R,
|
||
|
G: G,
|
||
|
B: B,
|
||
|
}
|
||
|
|
||
|
// WebView2 only has 0 and 255 as valid values.
|
||
|
if backgroundCol.A > 0 && backgroundCol.A < 255 {
|
||
|
backgroundCol.A = 255
|
||
|
}
|
||
|
|
||
|
err := controller2.PutDefaultBackgroundColor(backgroundCol)
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) SetGlobalPermission(state CoreWebView2PermissionState) {
|
||
|
e.globalPermission = &state
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) PermissionRequested(_ *ICoreWebView2, args *iCoreWebView2PermissionRequestedEventArgs) uintptr {
|
||
|
var kind CoreWebView2PermissionKind
|
||
|
args.vtbl.GetPermissionKind.Call(
|
||
|
uintptr(unsafe.Pointer(args)),
|
||
|
uintptr(kind),
|
||
|
)
|
||
|
var result CoreWebView2PermissionState
|
||
|
if e.globalPermission != nil {
|
||
|
result = *e.globalPermission
|
||
|
} else {
|
||
|
var ok bool
|
||
|
result, ok = e.permissions[kind]
|
||
|
if !ok {
|
||
|
result = CoreWebView2PermissionStateDefault
|
||
|
}
|
||
|
}
|
||
|
args.vtbl.PutState.Call(
|
||
|
uintptr(unsafe.Pointer(args)),
|
||
|
uintptr(result),
|
||
|
)
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) WebResourceRequested(sender *ICoreWebView2, args *ICoreWebView2WebResourceRequestedEventArgs) uintptr {
|
||
|
req, err := args.GetRequest()
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
defer req.Release()
|
||
|
|
||
|
if e.WebResourceRequestedCallback != nil {
|
||
|
e.WebResourceRequestedCallback(req, args)
|
||
|
}
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) AddWebResourceRequestedFilter(filter string, ctx COREWEBVIEW2_WEB_RESOURCE_CONTEXT) {
|
||
|
err := e.webview.AddWebResourceRequestedFilter(filter, ctx)
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) Environment() *ICoreWebView2Environment {
|
||
|
return e.environment
|
||
|
}
|
||
|
|
||
|
// AcceleratorKeyPressed is called when an accelerator key is pressed.
|
||
|
// If the AcceleratorKeyCallback method has been set, it will defer handling of the keypress
|
||
|
// to the callback. That callback returns a bool indicating if the event was handled.
|
||
|
func (e *Chromium) AcceleratorKeyPressed(sender *ICoreWebView2Controller, args *ICoreWebView2AcceleratorKeyPressedEventArgs) uintptr {
|
||
|
if e.AcceleratorKeyCallback == nil {
|
||
|
return 0
|
||
|
}
|
||
|
eventKind, _ := args.GetKeyEventKind()
|
||
|
if eventKind == COREWEBVIEW2_KEY_EVENT_KIND_KEY_DOWN ||
|
||
|
eventKind == COREWEBVIEW2_KEY_EVENT_KIND_SYSTEM_KEY_DOWN {
|
||
|
virtualKey, _ := args.GetVirtualKey()
|
||
|
status, _ := args.GetPhysicalKeyStatus()
|
||
|
if !status.WasKeyDown {
|
||
|
args.PutHandled(e.AcceleratorKeyCallback(virtualKey))
|
||
|
return 0
|
||
|
}
|
||
|
}
|
||
|
args.PutHandled(false)
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) GetSettings() (*ICoreWebViewSettings, error) {
|
||
|
return e.webview.GetSettings()
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) GetController() *ICoreWebView2Controller {
|
||
|
return e.controller
|
||
|
}
|
||
|
|
||
|
func boolToInt(input bool) int {
|
||
|
if input {
|
||
|
return 1
|
||
|
}
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) NavigationCompleted(sender *ICoreWebView2, args *ICoreWebView2NavigationCompletedEventArgs) uintptr {
|
||
|
if e.NavigationCompletedCallback != nil {
|
||
|
e.NavigationCompletedCallback(sender, args)
|
||
|
}
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) ProcessFailed(sender *ICoreWebView2, args *ICoreWebView2ProcessFailedEventArgs) uintptr {
|
||
|
if e.ProcessFailedCallback != nil {
|
||
|
e.ProcessFailedCallback(sender, args)
|
||
|
}
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) NotifyParentWindowPositionChanged() error {
|
||
|
//It looks like the wndproc function is called before the controller initialization is complete.
|
||
|
//Because of this the controller is nil
|
||
|
if e.controller == nil {
|
||
|
return nil
|
||
|
}
|
||
|
return e.controller.NotifyParentWindowPositionChanged()
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) Focus() {
|
||
|
err := e.controller.MoveFocus(COREWEBVIEW2_MOVE_FOCUS_REASON_PROGRAMMATIC)
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) PutZoomFactor(zoomFactor float64) {
|
||
|
err := e.controller.PutZoomFactor(zoomFactor)
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) OpenDevToolsWindow() {
|
||
|
e.webview.OpenDevToolsWindow()
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) HasCapability(c Capability) bool {
|
||
|
return hasCapability(e.webview2RuntimeVersion, c)
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) GetIsSwipeNavigationEnabled() (bool, error) {
|
||
|
if !hasCapability(e.webview2RuntimeVersion, SwipeNavigation) {
|
||
|
return false, UnsupportedCapabilityError
|
||
|
}
|
||
|
webview2Settings, err := e.webview.GetSettings()
|
||
|
if err != nil {
|
||
|
return false, err
|
||
|
}
|
||
|
webview2Settings6 := webview2Settings.GetICoreWebView2Settings6()
|
||
|
var result bool
|
||
|
result, err = webview2Settings6.GetIsSwipeNavigationEnabled()
|
||
|
if err != windows.DS_S_SUCCESS {
|
||
|
return false, err
|
||
|
}
|
||
|
return result, nil
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) PutIsSwipeNavigationEnabled(enabled bool) error {
|
||
|
if !hasCapability(e.webview2RuntimeVersion, SwipeNavigation) {
|
||
|
return UnsupportedCapabilityError
|
||
|
}
|
||
|
webview2Settings, err := e.webview.GetSettings()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
webview2Settings6 := webview2Settings.GetICoreWebView2Settings6()
|
||
|
err = webview2Settings6.PutIsSwipeNavigationEnabled(enabled)
|
||
|
if err != windows.DS_S_SUCCESS {
|
||
|
return err
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) AllowExternalDrag(allow bool) error {
|
||
|
if !hasCapability(e.webview2RuntimeVersion, AllowExternalDrop) {
|
||
|
return UnsupportedCapabilityError
|
||
|
}
|
||
|
controller := e.GetController()
|
||
|
controller4 := controller.GetICoreWebView2Controller4()
|
||
|
err := controller4.PutAllowExternalDrop(allow)
|
||
|
if err != windows.DS_S_SUCCESS {
|
||
|
return err
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (e *Chromium) GetAllowExternalDrag() (bool, error) {
|
||
|
if !hasCapability(e.webview2RuntimeVersion, AllowExternalDrop) {
|
||
|
return false, UnsupportedCapabilityError
|
||
|
}
|
||
|
controller := e.GetController()
|
||
|
controller4 := controller.GetICoreWebView2Controller4()
|
||
|
result, err := controller4.GetAllowExternalDrop()
|
||
|
if err != windows.DS_S_SUCCESS {
|
||
|
return false, err
|
||
|
}
|
||
|
return result, nil
|
||
|
}
|