github.com/AlpineAIO/wails/v2@v2.0.0-beta.32.0.20240505041856-1047a8fa5fef/internal/platform/win32/theme.go (about)

     1  //go:build windows
     2  
     3  package win32
     4  
     5  import (
     6  	"golang.org/x/sys/windows/registry"
     7  	"unsafe"
     8  )
     9  
    10  type DWMWINDOWATTRIBUTE int32
    11  
    12  const DwmwaUseImmersiveDarkModeBefore20h1 DWMWINDOWATTRIBUTE = 19
    13  const DwmwaUseImmersiveDarkMode DWMWINDOWATTRIBUTE = 20
    14  const DwmwaBorderColor DWMWINDOWATTRIBUTE = 34
    15  const DwmwaCaptionColor DWMWINDOWATTRIBUTE = 35
    16  const DwmwaTextColor DWMWINDOWATTRIBUTE = 36
    17  const DwmwaSystemBackdropType DWMWINDOWATTRIBUTE = 38
    18  
    19  const SPI_GETHIGHCONTRAST = 0x0042
    20  const HCF_HIGHCONTRASTON = 0x00000001
    21  const WCA_ACCENT_POLICY WINDOWCOMPOSITIONATTRIB = 19
    22  
    23  type ACCENT_STATE DWORD
    24  
    25  const (
    26  	ACCENT_DISABLED                   ACCENT_STATE = 0
    27  	ACCENT_ENABLE_GRADIENT            ACCENT_STATE = 1
    28  	ACCENT_ENABLE_TRANSPARENTGRADIENT ACCENT_STATE = 2
    29  	ACCENT_ENABLE_BLURBEHIND          ACCENT_STATE = 3
    30  	ACCENT_ENABLE_ACRYLICBLURBEHIND   ACCENT_STATE = 4 // RS4 1803
    31  	ACCENT_ENABLE_HOSTBACKDROP        ACCENT_STATE = 5 // RS5 1809
    32  	ACCENT_INVALID_STATE              ACCENT_STATE = 6
    33  )
    34  
    35  type ACCENT_POLICY struct {
    36  	AccentState   ACCENT_STATE
    37  	AccentFlags   DWORD
    38  	GradientColor DWORD
    39  	AnimationId   DWORD
    40  }
    41  
    42  type WINDOWCOMPOSITIONATTRIBDATA struct {
    43  	Attrib WINDOWCOMPOSITIONATTRIB
    44  	PvData unsafe.Pointer
    45  	CbData uintptr
    46  }
    47  
    48  type WINDOWCOMPOSITIONATTRIB DWORD
    49  
    50  // BackdropType defines the type of translucency we wish to use
    51  type BackdropType int32
    52  
    53  const (
    54  	BackdropTypeAuto    BackdropType = 0
    55  	BackdropTypeNone    BackdropType = 1
    56  	BackdropTypeMica    BackdropType = 2
    57  	BackdropTypeAcrylic BackdropType = 3
    58  	BackdropTypeTabbed  BackdropType = 4
    59  )
    60  
    61  func dwmSetWindowAttribute(hwnd HWND, dwAttribute DWMWINDOWATTRIBUTE, pvAttribute unsafe.Pointer, cbAttribute uintptr) {
    62  	ret, _, err := procDwmSetWindowAttribute.Call(
    63  		uintptr(hwnd),
    64  		uintptr(dwAttribute),
    65  		uintptr(pvAttribute),
    66  		cbAttribute)
    67  	if ret != 0 {
    68  		_ = err
    69  		// println(err.Error())
    70  	}
    71  }
    72  
    73  func SupportsThemes() bool {
    74  	// We can't support Windows versions before 17763
    75  	return IsWindowsVersionAtLeast(10, 0, 17763)
    76  }
    77  
    78  func SupportsCustomThemes() bool {
    79  	return IsWindowsVersionAtLeast(10, 0, 17763)
    80  }
    81  
    82  func SupportsBackdropTypes() bool {
    83  	return IsWindowsVersionAtLeast(10, 0, 22621)
    84  }
    85  
    86  func SupportsImmersiveDarkMode() bool {
    87  	return IsWindowsVersionAtLeast(10, 0, 18985)
    88  }
    89  
    90  func SetTheme(hwnd HWND, useDarkMode bool) {
    91  	if SupportsThemes() {
    92  		attr := DwmwaUseImmersiveDarkModeBefore20h1
    93  		if SupportsImmersiveDarkMode() {
    94  			attr = DwmwaUseImmersiveDarkMode
    95  		}
    96  		var winDark int32
    97  		if useDarkMode {
    98  			winDark = 1
    99  		}
   100  		dwmSetWindowAttribute(hwnd, attr, unsafe.Pointer(&winDark), unsafe.Sizeof(winDark))
   101  	}
   102  }
   103  
   104  func EnableBlurBehind(hwnd HWND) {
   105  	var accent = ACCENT_POLICY{
   106  		AccentState: ACCENT_ENABLE_ACRYLICBLURBEHIND,
   107  		AccentFlags: 0x2,
   108  	}
   109  	var data WINDOWCOMPOSITIONATTRIBDATA
   110  	data.Attrib = WCA_ACCENT_POLICY
   111  	data.PvData = unsafe.Pointer(&accent)
   112  	data.CbData = unsafe.Sizeof(accent)
   113  
   114  	SetWindowCompositionAttribute(hwnd, &data)
   115  }
   116  
   117  func SetWindowCompositionAttribute(hwnd HWND, data *WINDOWCOMPOSITIONATTRIBDATA) bool {
   118  	if procSetWindowCompositionAttribute != nil {
   119  		ret, _, _ := procSetWindowCompositionAttribute.Call(
   120  			uintptr(hwnd),
   121  			uintptr(unsafe.Pointer(data)),
   122  		)
   123  		return ret != 0
   124  	}
   125  	return false
   126  }
   127  
   128  func EnableTranslucency(hwnd HWND, backdrop BackdropType) {
   129  	if SupportsBackdropTypes() {
   130  		dwmSetWindowAttribute(hwnd, DwmwaSystemBackdropType, unsafe.Pointer(&backdrop), unsafe.Sizeof(backdrop))
   131  	} else {
   132  		println("Warning: Translucency type unavailable on Windows < 22621")
   133  	}
   134  }
   135  
   136  func SetTitleBarColour(hwnd HWND, titleBarColour int32) {
   137  	dwmSetWindowAttribute(hwnd, DwmwaCaptionColor, unsafe.Pointer(&titleBarColour), unsafe.Sizeof(titleBarColour))
   138  }
   139  
   140  func SetTitleTextColour(hwnd HWND, titleTextColour int32) {
   141  	dwmSetWindowAttribute(hwnd, DwmwaTextColor, unsafe.Pointer(&titleTextColour), unsafe.Sizeof(titleTextColour))
   142  }
   143  
   144  func SetBorderColour(hwnd HWND, titleBorderColour int32) {
   145  	dwmSetWindowAttribute(hwnd, DwmwaBorderColor, unsafe.Pointer(&titleBorderColour), unsafe.Sizeof(titleBorderColour))
   146  }
   147  
   148  func SetWindowTheme(hwnd HWND, appName string, subIdList string) uintptr {
   149  	var subID uintptr
   150  	if subIdList != "" {
   151  		subID = MustStringToUTF16uintptr(subIdList)
   152  	}
   153  	ret, _, _ := procSetWindowTheme.Call(
   154  		uintptr(hwnd),
   155  		MustStringToUTF16uintptr(appName),
   156  		subID,
   157  	)
   158  
   159  	return ret
   160  }
   161  func IsCurrentlyDarkMode() bool {
   162  	key, err := registry.OpenKey(registry.CURRENT_USER, `SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize`, registry.QUERY_VALUE)
   163  	if err != nil {
   164  		return false
   165  	}
   166  	defer key.Close()
   167  
   168  	AppsUseLightTheme, _, err := key.GetIntegerValue("AppsUseLightTheme")
   169  	if err != nil {
   170  		return false
   171  	}
   172  	return AppsUseLightTheme == 0
   173  }
   174  
   175  type highContrast struct {
   176  	CbSize            uint32
   177  	DwFlags           uint32
   178  	LpszDefaultScheme *int16
   179  }
   180  
   181  func IsCurrentlyHighContrastMode() bool {
   182  	var result highContrast
   183  	result.CbSize = uint32(unsafe.Sizeof(result))
   184  	res, _, err := procSystemParametersInfo.Call(SPI_GETHIGHCONTRAST, uintptr(result.CbSize), uintptr(unsafe.Pointer(&result)), 0)
   185  	if res == 0 {
   186  		_ = err
   187  		return false
   188  	}
   189  	r := result.DwFlags&HCF_HIGHCONTRASTON == HCF_HIGHCONTRASTON
   190  	return r
   191  }