5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-05 23:30:10 +08:00
wails/v3/pkg/application/webview_window_windows.go

481 lines
11 KiB
Go

//go:build windows
package application
import (
"errors"
"fmt"
"github.com/wailsapp/wails/v3/internal/w32"
"github.com/wailsapp/wails/v3/pkg/events"
"syscall"
"unsafe"
"github.com/samber/lo"
)
var showDevTools = func(window unsafe.Pointer) {}
type windowsWebviewWindow struct {
windowImpl unsafe.Pointer
parent *WebviewWindow
hwnd w32.HWND
}
func (w *windowsWebviewWindow) setTitle(title string) {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) setSize(width, height int) {
x, y := w.position()
w32.MoveWindow(w.hwnd, x, y, width, height, true)
}
func (w *windowsWebviewWindow) setAlwaysOnTop(alwaysOnTop bool) {
globalApplication.dispatchOnMainThread(func() {
position := w32.HWND_NOTOPMOST
if alwaysOnTop {
position = w32.HWND_TOPMOST
}
w32.SetWindowPos(w.hwnd, position, 0, 0, 0, 0, uint(w32.SWP_NOMOVE|w32.SWP_NOSIZE))
})
}
func (w *windowsWebviewWindow) setURL(url string) {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) setResizable(resizable bool) {
globalApplication.dispatchOnMainThread(func() {
w.setStyle(resizable, w32.WS_THICKFRAME)
})
}
func (w *windowsWebviewWindow) setMinSize(width, height int) {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) setMaxSize(width, height int) {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) execJS(js string) {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) restore() {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) setBackgroundColour(color RGBA) {
w32.SetBackgroundColour(w.hwnd, color.Red, color.Green, color.Blue)
}
func (w *windowsWebviewWindow) run() {
globalApplication.dispatchOnMainThread(w._run)
}
func (w *windowsWebviewWindow) _run() {
var exStyle uint
options := w.parent.options
exStyle = w32.WS_EX_CONTROLPARENT | w32.WS_EX_APPWINDOW
if options.BackgroundType != BackgroundTypeSolid {
exStyle |= w32.WS_EX_NOREDIRECTIONBITMAP
}
if options.AlwaysOnTop {
exStyle |= w32.WS_EX_TOPMOST
}
w.hwnd = w32.CreateWindowEx(
exStyle,
windowClassName,
lo.Must(syscall.UTF16PtrFromString(options.Title)),
w32.WS_OVERLAPPEDWINDOW,
w32.CW_USEDEFAULT,
w32.CW_USEDEFAULT,
options.Width,
options.Height,
0,
0,
w32.GetModuleHandle(""),
nil)
if w.hwnd == 0 {
panic("Unable to create window")
}
// Register the window with the application
windowsApp := globalApplication.impl.(*windowsApp)
windowsApp.registerWindow(w)
if options.DisableResize {
w.setResizable(false)
}
// Icon
if !options.Windows.DisableIcon {
// App icon ID is 3
icon, err := NewIconFromResource(w32.GetModuleHandle(""), uint16(3))
if err == nil {
w.setIcon(icon)
}
} else {
w.disableIcon()
}
switch options.BackgroundType {
case BackgroundTypeSolid:
w.setBackgroundColour(options.BackgroundColour)
case BackgroundTypeTransparent:
case BackgroundTypeTranslucent:
w.setBackdropType(options.Windows.BackdropType)
}
w.setForeground()
// Process the theme
switch options.Windows.Theme {
case SystemDefault:
w.updateTheme(w32.IsCurrentlyDarkMode())
globalApplication.On(events.Windows.SystemThemeChanged, func() {
w.updateTheme(w32.IsCurrentlyDarkMode())
})
case Light:
w.updateTheme(false)
case Dark:
w.updateTheme(true)
}
if !options.Hidden {
w.show()
w.update()
}
}
func (w *windowsWebviewWindow) center() {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) size() (int, int) {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) setForeground() {
w32.SetForegroundWindow(w.hwnd)
}
func (w *windowsWebviewWindow) update() {
w32.UpdateWindow(w.hwnd)
}
func (w *windowsWebviewWindow) width() int {
rect := w32.GetWindowRect(w.hwnd)
return int(rect.Right - rect.Left)
}
func (w *windowsWebviewWindow) height() int {
rect := w32.GetWindowRect(w.hwnd)
return int(rect.Bottom - rect.Top)
}
func (w *windowsWebviewWindow) position() (int, int) {
rect := w32.GetWindowRect(w.hwnd)
return int(rect.Left), int(rect.Right)
}
func (w *windowsWebviewWindow) destroy() {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) reload() {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) forceReload() {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) toggleDevTools() {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) zoomReset() {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) zoomIn() {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) zoomOut() {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) getZoom() float64 {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) setZoom(zoom float64) {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) close() {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) zoom() {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) setHTML(html string) {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) setPosition(x int, y int) {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) on(eventID uint) {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) minimise() {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) unminimise() {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) maximise() {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) unmaximise() {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) fullscreen() {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) unfullscreen() {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) isMinimised() bool {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) isMaximised() bool {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) isFullscreen() bool {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) disableSizeConstraints() {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) setFullscreenButtonEnabled(enabled bool) {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) show() {
w32.ShowWindow(w.hwnd, w32.SW_SHOW)
}
func (w *windowsWebviewWindow) hide() {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) getScreen() (*Screen, error) {
//TODO implement me
panic("implement me")
}
func (w *windowsWebviewWindow) setFrameless(b bool) {
//TODO implement me
panic("implement me")
}
func newWindowImpl(parent *WebviewWindow) *windowsWebviewWindow {
result := &windowsWebviewWindow{
parent: parent,
}
return result
}
func (w *windowsWebviewWindow) openContextMenu(menu *Menu, data *ContextMenuData) {
// Create the menu
thisMenu := newMenuImpl(menu)
thisMenu.update()
//C.windowShowMenu(w.nsWindow, thisMenu.nsMenu, C.int(data.X), C.int(data.Y))
}
func (w *windowsWebviewWindow) setStyle(b bool, style int) {
currentStyle := int(w32.GetWindowLongPtr(w.hwnd, w32.GWL_STYLE))
if currentStyle != 0 {
if b {
currentStyle |= style
} else {
currentStyle &^= style
}
w32.SetWindowLongPtr(w.hwnd, w32.GWL_STYLE, uintptr(currentStyle))
}
}
func (w *windowsWebviewWindow) setExStyle(b bool, style int) {
currentStyle := int(w32.GetWindowLongPtr(w.hwnd, w32.GWL_EXSTYLE))
if currentStyle != 0 {
if b {
currentStyle |= style
} else {
currentStyle &^= style
}
w32.SetWindowLongPtr(w.hwnd, w32.GWL_EXSTYLE, uintptr(currentStyle))
}
}
func (w *windowsWebviewWindow) setBackdropType(backdropType BackdropType) {
if !w32.IsWindowsVersionAtLeast(10, 0, 22621) {
var accent = w32.ACCENT_POLICY{
AccentState: w32.ACCENT_ENABLE_BLURBEHIND,
}
var data w32.WINDOWCOMPOSITIONATTRIBDATA
data.Attrib = w32.WCA_ACCENT_POLICY
data.PvData = w32.PVOID(&accent)
data.CbData = w32.SIZE_T(unsafe.Sizeof(accent))
w32.SetWindowCompositionAttribute(w.hwnd, &data)
} else {
backdropValue := backdropType
// We default to None, but in w32 None = 1 and Auto = 0
// So we check if the value given was Auto and set it to 0
if backdropType == Auto {
backdropValue = None
}
w32.DwmSetWindowAttribute(w.hwnd, w32.DwmwaSystemBackdropType, w32.LPCVOID(&backdropValue), uint32(unsafe.Sizeof(backdropValue)))
}
}
func (w *windowsWebviewWindow) setIcon(icon w32.HICON) {
w32.SendMessage(w.hwnd, w32.BM_SETIMAGE, w32.IMAGE_ICON, uintptr(icon))
}
func (w *windowsWebviewWindow) disableIcon() {
// TODO: If frameless, return
exStyle := w32.GetWindowLong(w.hwnd, w32.GWL_EXSTYLE)
w32.SetWindowLong(w.hwnd, w32.GWL_EXSTYLE, uint32(exStyle|w32.WS_EX_DLGMODALFRAME))
w32.SetWindowPos(w.hwnd, 0, 0, 0, 0, 0,
uint(
w32.SWP_FRAMECHANGED|
w32.SWP_NOMOVE|
w32.SWP_NOSIZE|
w32.SWP_NOZORDER),
)
}
func (w *windowsWebviewWindow) updateTheme(isDarkMode bool) {
if w32.IsCurrentlyHighContrastMode() {
return
}
if !w32.SupportsThemes() {
return
}
w32.SetTheme(w.hwnd, isDarkMode)
// Custom theme processing
customTheme := w.parent.options.Windows.CustomTheme
// Custom theme
if w32.SupportsCustomThemes() && customTheme != nil {
if w.isActive() {
if isDarkMode {
w32.SetTitleBarColour(w.hwnd, customTheme.DarkModeTitleBar)
w32.SetTitleTextColour(w.hwnd, customTheme.DarkModeTitleText)
w32.SetBorderColour(w.hwnd, customTheme.DarkModeBorder)
} else {
w32.SetTitleBarColour(w.hwnd, customTheme.LightModeTitleBar)
w32.SetTitleTextColour(w.hwnd, customTheme.LightModeTitleText)
w32.SetBorderColour(w.hwnd, customTheme.LightModeBorder)
}
} else {
if isDarkMode {
w32.SetTitleBarColour(w.hwnd, customTheme.DarkModeTitleBarInactive)
w32.SetTitleTextColour(w.hwnd, customTheme.DarkModeTitleTextInactive)
w32.SetBorderColour(w.hwnd, customTheme.DarkModeBorderInactive)
} else {
w32.SetTitleBarColour(w.hwnd, customTheme.LightModeTitleBarInactive)
w32.SetTitleTextColour(w.hwnd, customTheme.LightModeTitleTextInactive)
w32.SetBorderColour(w.hwnd, customTheme.LightModeBorderInactive)
}
}
}
}
func (w *windowsWebviewWindow) isActive() bool {
return w32.GetForegroundWindow() == w.hwnd
}
func (w *windowsWebviewWindow) WndProc(msg uint32, wparam, lparam uintptr) uintptr {
switch msg {
case w32.WM_SIZE:
return 0
case w32.WM_CLOSE:
w32.PostMessage(w.hwnd, w32.WM_QUIT, 0, 0)
// Unregister the window with the application
windowsApp := globalApplication.impl.(*windowsApp)
windowsApp.unregisterWindow(w)
return 0
default:
return w32.DefWindowProc(w.hwnd, msg, wparam, lparam)
}
}
func NewIconFromResource(instance w32.HINSTANCE, resId uint16) (w32.HICON, error) {
var err error
var result w32.HICON
if result = w32.LoadIconWithResourceID(instance, resId); result == 0 {
err = errors.New(fmt.Sprintf("Cannot load icon from resource with id %v", resId))
}
return result, err
}