github.com/secoba/wails/v2@v2.6.4/internal/frontend/desktop/windows/win32/window.go (about)

     1  //go:build windows
     2  
     3  package win32
     4  
     5  import (
     6  	"fmt"
     7  	"log"
     8  	"strconv"
     9  	"syscall"
    10  	"unsafe"
    11  
    12  	"github.com/secoba/wails/v2/internal/frontend/desktop/windows/winc"
    13  )
    14  
    15  const (
    16  	WS_MAXIMIZE = 0x01000000
    17  	WS_MINIMIZE = 0x20000000
    18  
    19  	GWL_STYLE = -16
    20  
    21  	MONITOR_DEFAULTTOPRIMARY = 0x00000001
    22  )
    23  
    24  const (
    25  	SW_HIDE            = 0
    26  	SW_NORMAL          = 1
    27  	SW_SHOWNORMAL      = 1
    28  	SW_SHOWMINIMIZED   = 2
    29  	SW_MAXIMIZE        = 3
    30  	SW_SHOWMAXIMIZED   = 3
    31  	SW_SHOWNOACTIVATE  = 4
    32  	SW_SHOW            = 5
    33  	SW_MINIMIZE        = 6
    34  	SW_SHOWMINNOACTIVE = 7
    35  	SW_SHOWNA          = 8
    36  	SW_RESTORE         = 9
    37  	SW_SHOWDEFAULT     = 10
    38  	SW_FORCEMINIMIZE   = 11
    39  )
    40  
    41  const (
    42  	GCLP_HBRBACKGROUND int32 = -10
    43  )
    44  
    45  // Power
    46  const (
    47  	// WM_POWERBROADCAST - Notifies applications that a power-management event has occurred.
    48  	WM_POWERBROADCAST = 536
    49  
    50  	// PBT_APMPOWERSTATUSCHANGE - Power status has changed.
    51  	PBT_APMPOWERSTATUSCHANGE = 10
    52  
    53  	// PBT_APMRESUMEAUTOMATIC -Operation is resuming automatically from a low-power state. This message is sent every time the system resumes.
    54  	PBT_APMRESUMEAUTOMATIC = 18
    55  
    56  	// PBT_APMRESUMESUSPEND - Operation is resuming from a low-power state. This message is sent after PBT_APMRESUMEAUTOMATIC if the resume is triggered by user input, such as pressing a key.
    57  	PBT_APMRESUMESUSPEND = 7
    58  
    59  	// PBT_APMSUSPEND - System is suspending operation.
    60  	PBT_APMSUSPEND = 4
    61  
    62  	// PBT_POWERSETTINGCHANGE - A power setting change event has been received.
    63  	PBT_POWERSETTINGCHANGE = 32787
    64  )
    65  
    66  // http://msdn.microsoft.com/en-us/library/windows/desktop/bb773244.aspx
    67  type MARGINS struct {
    68  	CxLeftWidth, CxRightWidth, CyTopHeight, CyBottomHeight int32
    69  }
    70  
    71  // http://msdn.microsoft.com/en-us/library/windows/desktop/dd162897.aspx
    72  type RECT struct {
    73  	Left, Top, Right, Bottom int32
    74  }
    75  
    76  // http://msdn.microsoft.com/en-us/library/windows/desktop/dd145065.aspx
    77  type MONITORINFO struct {
    78  	CbSize    uint32
    79  	RcMonitor RECT
    80  	RcWork    RECT
    81  	DwFlags   uint32
    82  }
    83  
    84  func ExtendFrameIntoClientArea(hwnd uintptr, extend bool) {
    85  	// -1: Adds the default frame styling (aero shadow and e.g. rounded corners on Windows 11)
    86  	//     Also shows the caption buttons if transparent ant translucent but they don't work.
    87  	//  0: Adds the default frame styling but no aero shadow, does not show the caption buttons.
    88  	//  1: Adds the default frame styling (aero shadow and e.g. rounded corners on Windows 11) but no caption buttons
    89  	//     are shown if transparent ant translucent.
    90  	var margins MARGINS
    91  	if extend {
    92  		margins = MARGINS{1, 1, 1, 1} // Only extend 1 pixel to have the default frame styling but no caption buttons
    93  	}
    94  	if err := dwmExtendFrameIntoClientArea(hwnd, &margins); err != nil {
    95  		log.Fatal(fmt.Errorf("DwmExtendFrameIntoClientArea failed: %s", err))
    96  	}
    97  }
    98  
    99  func IsVisible(hwnd uintptr) bool {
   100  	ret, _, _ := procIsWindowVisible.Call(hwnd)
   101  	return ret != 0
   102  }
   103  
   104  func IsWindowFullScreen(hwnd uintptr) bool {
   105  	wRect := GetWindowRect(hwnd)
   106  	m := MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY)
   107  	var mi MONITORINFO
   108  	mi.CbSize = uint32(unsafe.Sizeof(mi))
   109  	if !GetMonitorInfo(m, &mi) {
   110  		return false
   111  	}
   112  	return wRect.Left == mi.RcMonitor.Left &&
   113  		wRect.Top == mi.RcMonitor.Top &&
   114  		wRect.Right == mi.RcMonitor.Right &&
   115  		wRect.Bottom == mi.RcMonitor.Bottom
   116  }
   117  
   118  func IsWindowMaximised(hwnd uintptr) bool {
   119  	style := uint32(getWindowLong(hwnd, GWL_STYLE))
   120  	return style&WS_MAXIMIZE != 0
   121  }
   122  func IsWindowMinimised(hwnd uintptr) bool {
   123  	style := uint32(getWindowLong(hwnd, GWL_STYLE))
   124  	return style&WS_MINIMIZE != 0
   125  }
   126  
   127  func RestoreWindow(hwnd uintptr) {
   128  	showWindow(hwnd, SW_RESTORE)
   129  }
   130  
   131  func ShowWindow(hwnd uintptr) {
   132  	showWindow(hwnd, SW_SHOW)
   133  }
   134  
   135  func ShowWindowMaximised(hwnd uintptr) {
   136  	showWindow(hwnd, SW_MAXIMIZE)
   137  }
   138  func ShowWindowMinimised(hwnd uintptr) {
   139  	showWindow(hwnd, SW_MINIMIZE)
   140  }
   141  
   142  func SetBackgroundColour(hwnd uintptr, r, g, b uint8) {
   143  	col := winc.RGB(r, g, b)
   144  	hbrush, _, _ := procCreateSolidBrush.Call(uintptr(col))
   145  	setClassLongPtr(hwnd, GCLP_HBRBACKGROUND, hbrush)
   146  }
   147  
   148  func IsWindowNormal(hwnd uintptr) bool {
   149  	return !IsWindowMaximised(hwnd) && !IsWindowMinimised(hwnd) && !IsWindowFullScreen(hwnd)
   150  }
   151  
   152  func dwmExtendFrameIntoClientArea(hwnd uintptr, margins *MARGINS) error {
   153  	ret, _, _ := procDwmExtendFrameIntoClientArea.Call(
   154  		hwnd,
   155  		uintptr(unsafe.Pointer(margins)))
   156  
   157  	if ret != 0 {
   158  		return syscall.GetLastError()
   159  	}
   160  
   161  	return nil
   162  }
   163  
   164  func setClassLongPtr(hwnd uintptr, param int32, val uintptr) bool {
   165  	proc := procSetClassLongPtr
   166  	if strconv.IntSize == 32 {
   167  		/*
   168  			https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setclasslongptrw
   169  			Note: 	To write code that is compatible with both 32-bit and 64-bit Windows, use SetClassLongPtr.
   170  					When compiling for 32-bit Windows, SetClassLongPtr is defined as a call to the SetClassLong function
   171  
   172  			=> We have to do this dynamically when directly calling the DLL procedures
   173  		*/
   174  		proc = procSetClassLong
   175  	}
   176  
   177  	ret, _, _ := proc.Call(
   178  		hwnd,
   179  		uintptr(param),
   180  		val,
   181  	)
   182  	return ret != 0
   183  }
   184  
   185  func getWindowLong(hwnd uintptr, index int) int32 {
   186  	ret, _, _ := procGetWindowLong.Call(
   187  		hwnd,
   188  		uintptr(index))
   189  
   190  	return int32(ret)
   191  }
   192  
   193  func showWindow(hwnd uintptr, cmdshow int) bool {
   194  	ret, _, _ := procShowWindow.Call(
   195  		hwnd,
   196  		uintptr(cmdshow))
   197  	return ret != 0
   198  }
   199  
   200  func GetWindowRect(hwnd uintptr) *RECT {
   201  	var rect RECT
   202  	procGetWindowRect.Call(
   203  		hwnd,
   204  		uintptr(unsafe.Pointer(&rect)))
   205  
   206  	return &rect
   207  }
   208  
   209  func MonitorFromWindow(hwnd uintptr, dwFlags uint32) HMONITOR {
   210  	ret, _, _ := procMonitorFromWindow.Call(
   211  		hwnd,
   212  		uintptr(dwFlags),
   213  	)
   214  	return HMONITOR(ret)
   215  }
   216  
   217  func GetMonitorInfo(hMonitor HMONITOR, lmpi *MONITORINFO) bool {
   218  	ret, _, _ := procGetMonitorInfo.Call(
   219  		uintptr(hMonitor),
   220  		uintptr(unsafe.Pointer(lmpi)),
   221  	)
   222  	return ret != 0
   223  }