mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-06 13:13:16 +08:00
165 lines
4.5 KiB
Go
165 lines
4.5 KiB
Go
//go:build windows
|
|
package w32
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/samber/lo"
|
|
"log"
|
|
"strconv"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
const (
|
|
GCLP_HBRBACKGROUND int32 = -10
|
|
)
|
|
|
|
func ExtendFrameIntoClientArea(hwnd uintptr, extend bool) {
|
|
// -1: Adds the default frame styling (aero shadow and e.g. rounded corners on Windows 11)
|
|
// Also shows the caption buttons if transparent ant translucent but they don't work.
|
|
// 0: Adds the default frame styling but no aero shadow, does not show the caption buttons.
|
|
// 1: Adds the default frame styling (aero shadow and e.g. rounded corners on Windows 11) but no caption buttons
|
|
// are shown if transparent ant translucent.
|
|
var margins MARGINS
|
|
if extend {
|
|
margins = MARGINS{1, 1, 1, 1} // Only extend 1 pixel to have the default frame styling but no caption buttons
|
|
}
|
|
if err := dwmExtendFrameIntoClientArea(hwnd, &margins); err != nil {
|
|
log.Fatal(fmt.Errorf("DwmExtendFrameIntoClientArea failed: %s", err))
|
|
}
|
|
}
|
|
|
|
func IsVisible(hwnd uintptr) bool {
|
|
ret, _, _ := procIsWindowVisible.Call(hwnd)
|
|
return ret != 0
|
|
}
|
|
|
|
func IsWindowFullScreen(hwnd uintptr) bool {
|
|
wRect := GetWindowRect(hwnd)
|
|
m := MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)
|
|
var mi MONITORINFO
|
|
mi.CbSize = uint32(unsafe.Sizeof(mi))
|
|
if !GetMonitorInfo(m, &mi) {
|
|
return false
|
|
}
|
|
return wRect.Left == mi.RcMonitor.Left &&
|
|
wRect.Top == mi.RcMonitor.Top &&
|
|
wRect.Right == mi.RcMonitor.Right &&
|
|
wRect.Bottom == mi.RcMonitor.Bottom
|
|
}
|
|
|
|
func IsWindowMaximised(hwnd uintptr) bool {
|
|
style := uint32(getWindowLong(hwnd, GWL_STYLE))
|
|
return style&WS_MAXIMIZE != 0
|
|
}
|
|
func IsWindowMinimised(hwnd uintptr) bool {
|
|
style := uint32(getWindowLong(hwnd, GWL_STYLE))
|
|
return style&WS_MINIMIZE != 0
|
|
}
|
|
|
|
func RestoreWindow(hwnd uintptr) {
|
|
showWindow(hwnd, SW_RESTORE)
|
|
}
|
|
|
|
func ShowWindowMaximised(hwnd uintptr) {
|
|
showWindow(hwnd, SW_MAXIMIZE)
|
|
}
|
|
func ShowWindowMinimised(hwnd uintptr) {
|
|
showWindow(hwnd, SW_MINIMIZE)
|
|
}
|
|
|
|
func SetBackgroundColour(hwnd uintptr, r, g, b uint8) {
|
|
col := uint32(r) | uint32(g)<<8 | uint32(b)<<16
|
|
hbrush, _, _ := procCreateSolidBrush.Call(uintptr(col))
|
|
setClassLongPtr(hwnd, GCLP_HBRBACKGROUND, hbrush)
|
|
}
|
|
|
|
func IsWindowNormal(hwnd uintptr) bool {
|
|
return !IsWindowMaximised(hwnd) && !IsWindowMinimised(hwnd) && !IsWindowFullScreen(hwnd)
|
|
}
|
|
|
|
func setClassLongPtr(hwnd uintptr, param int32, val uintptr) bool {
|
|
proc := procSetClassLongPtr
|
|
if strconv.IntSize == 32 {
|
|
/*
|
|
https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setclasslongptrw
|
|
Note: To write code that is compatible with both 32-bit and 64-bit Windows, use SetClassLongPtr.
|
|
When compiling for 32-bit Windows, SetClassLongPtr is defined as a call to the SetClassLong function
|
|
|
|
=> We have to do this dynamically when directly calling the DLL procedures
|
|
*/
|
|
proc = procSetClassLong
|
|
}
|
|
|
|
ret, _, _ := proc.Call(
|
|
hwnd,
|
|
uintptr(param),
|
|
val,
|
|
)
|
|
return ret != 0
|
|
}
|
|
|
|
func getWindowLong(hwnd uintptr, index int) int32 {
|
|
ret, _, _ := procGetWindowLong.Call(
|
|
hwnd,
|
|
uintptr(index))
|
|
|
|
return int32(ret)
|
|
}
|
|
|
|
func showWindow(hwnd uintptr, cmdshow int) bool {
|
|
ret, _, _ := procShowWindow.Call(
|
|
hwnd,
|
|
uintptr(cmdshow))
|
|
return ret != 0
|
|
}
|
|
|
|
func MustStringToUTF16Ptr(input string) *uint16 {
|
|
return lo.Must(syscall.UTF16PtrFromString(input))
|
|
}
|
|
|
|
func MustStringToUTF16uintptr(input string) uintptr {
|
|
ret := lo.Must(syscall.UTF16PtrFromString(input))
|
|
return uintptr(unsafe.Pointer(ret))
|
|
}
|
|
|
|
func MustStringToUTF16(input string) []uint16 {
|
|
return lo.Must(syscall.UTF16FromString(input))
|
|
}
|
|
|
|
func CenterWindow(hwnd HWND) {
|
|
windowInfo := getWindowInfo(hwnd)
|
|
frameless := windowInfo.IsPopup()
|
|
|
|
info := GetMonitorInfoForWindow(hwnd)
|
|
workRect := info.RcWork
|
|
screenMiddleW := workRect.Left + (workRect.Right-workRect.Left)/2
|
|
screenMiddleH := workRect.Top + (workRect.Bottom-workRect.Top)/2
|
|
var winRect *RECT
|
|
if !frameless {
|
|
winRect = GetWindowRect(hwnd)
|
|
} else {
|
|
winRect = GetClientRect(hwnd)
|
|
}
|
|
winWidth := winRect.Right - winRect.Left
|
|
winHeight := winRect.Bottom - winRect.Top
|
|
windowX := screenMiddleW - (winWidth / 2)
|
|
windowY := screenMiddleH - (winHeight / 2)
|
|
SetWindowPos(hwnd, HWND_TOP, int(windowX), int(windowY), int(winWidth), int(winHeight), SWP_NOSIZE)
|
|
}
|
|
|
|
func getWindowInfo(hwnd HWND) *WINDOWINFO {
|
|
var info WINDOWINFO
|
|
info.CbSize = uint32(unsafe.Sizeof(info))
|
|
GetWindowInfo(hwnd, &info)
|
|
return &info
|
|
}
|
|
|
|
func GetMonitorInfoForWindow(hwnd HWND) *MONITORINFO {
|
|
currentMonitor := MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST)
|
|
var info MONITORINFO
|
|
info.CbSize = uint32(unsafe.Sizeof(info))
|
|
GetMonitorInfo(currentMonitor, &info)
|
|
return &info
|
|
}
|