mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-04 21:00:31 +08:00
225 lines
5.5 KiB
Go
225 lines
5.5 KiB
Go
//go:build windows
|
|
|
|
package application
|
|
|
|
import (
|
|
"github.com/wailsapp/wails/v3/pkg/events"
|
|
"github.com/wailsapp/wails/v3/pkg/w32"
|
|
"syscall"
|
|
"unsafe"
|
|
|
|
"github.com/samber/lo"
|
|
)
|
|
|
|
var windowClassName = lo.Must(syscall.UTF16PtrFromString("WailsWebviewWindow"))
|
|
|
|
type windowsApp struct {
|
|
parent *App
|
|
|
|
instance w32.HINSTANCE
|
|
|
|
windowMap map[w32.HWND]*windowsWebviewWindow
|
|
|
|
mainThreadID w32.HANDLE
|
|
mainThreadWindowHWND w32.HWND
|
|
|
|
// Windows hidden by application.Hide()
|
|
hiddenWindows []*windowsWebviewWindow
|
|
focusedWindow w32.HWND
|
|
|
|
// system theme
|
|
isDarkMode bool
|
|
}
|
|
|
|
func (m *windowsApp) getPrimaryScreen() (*Screen, error) {
|
|
//TODO implement me
|
|
panic("implement me")
|
|
}
|
|
|
|
func (m *windowsApp) getScreens() ([]*Screen, error) {
|
|
//TODO implement me
|
|
panic("implement me")
|
|
}
|
|
|
|
func (m *windowsApp) hide() {
|
|
// Get the current focussed window
|
|
m.focusedWindow = w32.GetForegroundWindow()
|
|
|
|
// Iterate over all windows and hide them if they aren't already hidden
|
|
for _, window := range m.windowMap {
|
|
if window.isVisible() {
|
|
// Add to hidden windows
|
|
m.hiddenWindows = append(m.hiddenWindows, window)
|
|
window.hide()
|
|
}
|
|
}
|
|
// Switch focus to the next application
|
|
hwndNext := w32.GetWindow(m.mainThreadWindowHWND, w32.GW_HWNDNEXT)
|
|
w32.SetForegroundWindow(hwndNext)
|
|
}
|
|
|
|
func (m *windowsApp) show() {
|
|
// Iterate over all windows and show them if they were previously hidden
|
|
for _, window := range m.hiddenWindows {
|
|
window.show()
|
|
}
|
|
// Show the foreground window
|
|
w32.SetForegroundWindow(m.focusedWindow)
|
|
}
|
|
|
|
func (m *windowsApp) on(eventID uint) {
|
|
//C.registerListener(C.uint(eventID))
|
|
}
|
|
|
|
func (m *windowsApp) setIcon(icon []byte) {
|
|
//C.setApplicationIcon(unsafe.Pointer(&icon[0]), C.int(len(icon)))
|
|
}
|
|
|
|
func (m *windowsApp) name() string {
|
|
//appName := C.getAppName()
|
|
//defer C.free(unsafe.Pointer(appName))
|
|
//return C.GoString(appName)
|
|
return ""
|
|
}
|
|
|
|
func (m *windowsApp) getCurrentWindowID() uint {
|
|
//return uint(C.getCurrentWindowID())
|
|
return uint(0)
|
|
}
|
|
|
|
func (m *windowsApp) setApplicationMenu(menu *Menu) {
|
|
if menu == nil {
|
|
// Create a default menu for mac
|
|
menu = defaultApplicationMenu()
|
|
}
|
|
menu.Update()
|
|
|
|
// Convert impl to macosMenu object
|
|
//m.applicationMenu = (menu.impl).(*macosMenu).nsMenu
|
|
//C.setApplicationMenu(m.applicationMenu)
|
|
}
|
|
|
|
func (m *windowsApp) run() error {
|
|
// Add a hook to the ApplicationDidFinishLaunching event
|
|
//m.parent.On(events.Mac.ApplicationDidFinishLaunching, func() {
|
|
// C.setApplicationShouldTerminateAfterLastWindowClosed(C.bool(m.parent.options.Mac.ApplicationShouldTerminateAfterLastWindowClosed))
|
|
// C.setActivationPolicy(C.int(m.parent.options.Mac.ActivationPolicy))
|
|
// C.activateIgnoringOtherApps()
|
|
//})
|
|
// setup event listeners
|
|
for eventID := range m.parent.applicationEventListeners {
|
|
m.on(eventID)
|
|
}
|
|
|
|
_ = m.runMainLoop()
|
|
|
|
//C.run()
|
|
return nil
|
|
}
|
|
|
|
func (m *windowsApp) destroy() {
|
|
//C.destroyApp()
|
|
}
|
|
|
|
func (m *windowsApp) init() {
|
|
// Register the window class
|
|
|
|
icon := w32.LoadIconWithResourceID(m.instance, w32.IDI_APPLICATION)
|
|
|
|
var wc w32.WNDCLASSEX
|
|
wc.Size = uint32(unsafe.Sizeof(wc))
|
|
wc.Style = w32.CS_HREDRAW | w32.CS_VREDRAW
|
|
wc.WndProc = syscall.NewCallback(m.wndProc)
|
|
wc.Instance = m.instance
|
|
wc.Background = w32.COLOR_BTNFACE + 1
|
|
wc.Icon = icon
|
|
wc.Cursor = w32.LoadCursorWithResourceID(0, w32.IDC_ARROW)
|
|
wc.ClassName = windowClassName
|
|
wc.MenuName = nil
|
|
wc.IconSm = icon
|
|
|
|
if ret := w32.RegisterClassEx(&wc); ret == 0 {
|
|
panic(syscall.GetLastError())
|
|
}
|
|
|
|
m.isDarkMode = w32.IsCurrentlyDarkMode()
|
|
}
|
|
|
|
func (m *windowsApp) wndProc(hwnd w32.HWND, msg uint32, wParam, lParam uintptr) uintptr {
|
|
|
|
// Handle the invoke callback
|
|
if msg == wmInvokeCallback {
|
|
m.invokeCallback(wParam, lParam)
|
|
return 0
|
|
}
|
|
|
|
// If the WndProcInterceptor is set in options, pass the message on
|
|
if m.parent.options.Windows.WndProcInterceptor != nil {
|
|
returnValue, shouldReturn := m.parent.options.Windows.WndProcInterceptor(hwnd, msg, wParam, lParam)
|
|
if shouldReturn {
|
|
return returnValue
|
|
}
|
|
}
|
|
|
|
switch msg {
|
|
case w32.WM_SETTINGCHANGE:
|
|
settingChanged := w32.UTF16PtrToString((*uint16)(unsafe.Pointer(lParam)))
|
|
if settingChanged == "ImmersiveColorSet" {
|
|
isDarkMode := w32.IsCurrentlyDarkMode()
|
|
if isDarkMode != m.isDarkMode {
|
|
applicationEvents <- uint(events.Windows.SystemThemeChanged)
|
|
m.isDarkMode = isDarkMode
|
|
}
|
|
}
|
|
return 0
|
|
case w32.WM_POWERBROADCAST:
|
|
switch wParam {
|
|
case w32.PBT_APMPOWERSTATUSCHANGE:
|
|
applicationEvents <- uint(events.Windows.APMPowerStatusChange)
|
|
case w32.PBT_APMSUSPEND:
|
|
applicationEvents <- uint(events.Windows.APMSuspend)
|
|
case w32.PBT_APMRESUMEAUTOMATIC:
|
|
applicationEvents <- uint(events.Windows.APMResumeAutomatic)
|
|
case w32.PBT_APMRESUMESUSPEND:
|
|
applicationEvents <- uint(events.Windows.APMResumeSuspend)
|
|
case w32.PBT_POWERSETTINGCHANGE:
|
|
applicationEvents <- uint(events.Windows.APMPowerSettingChange)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
if window, ok := m.windowMap[hwnd]; ok {
|
|
return window.WndProc(msg, wParam, lParam)
|
|
}
|
|
|
|
// Dispatch the message to the appropriate window
|
|
|
|
return w32.DefWindowProc(hwnd, msg, wParam, lParam)
|
|
}
|
|
|
|
func (m *windowsApp) registerWindow(result *windowsWebviewWindow) {
|
|
m.windowMap[result.hwnd] = result
|
|
}
|
|
|
|
func (m *windowsApp) unregisterWindow(w *windowsWebviewWindow) {
|
|
delete(m.windowMap, w.hwnd)
|
|
|
|
// If this was the last window...
|
|
if len(m.windowMap) == 0 {
|
|
w32.PostQuitMessage(0)
|
|
}
|
|
}
|
|
|
|
func newPlatformApp(app *App) *windowsApp {
|
|
result := &windowsApp{
|
|
parent: app,
|
|
instance: w32.GetModuleHandle(""),
|
|
windowMap: make(map[w32.HWND]*windowsWebviewWindow),
|
|
}
|
|
|
|
result.init()
|
|
result.initMainLoop()
|
|
|
|
return result
|
|
}
|