You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			223 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			223 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			Python
		
	
| # coding:utf-8
 | |
| import sys
 | |
| 
 | |
| from ctypes import POINTER, c_bool, c_int, pointer, sizeof, WinDLL, byref
 | |
| from ctypes.wintypes import DWORD, LONG, LPCVOID
 | |
| 
 | |
| from win32 import win32api, win32gui
 | |
| from win32.lib import win32con
 | |
| 
 | |
| from .c_structures import (
 | |
|     ACCENT_POLICY,
 | |
|     ACCENT_STATE,
 | |
|     MARGINS,
 | |
|     DWMNCRENDERINGPOLICY,
 | |
|     DWMWINDOWATTRIBUTE,
 | |
|     WINDOWCOMPOSITIONATTRIB,
 | |
|     WINDOWCOMPOSITIONATTRIBDATA,
 | |
| )
 | |
| 
 | |
| 
 | |
| class WindowEffect:
 | |
|     """ A class that calls Windows API to realize window effect """
 | |
| 
 | |
|     def __init__(self):
 | |
|         # Declare the function signature of the API
 | |
|         self.user32 = WinDLL("user32")
 | |
|         self.dwmapi = WinDLL("dwmapi")
 | |
|         self.SetWindowCompositionAttribute = self.user32.SetWindowCompositionAttribute
 | |
|         self.DwmExtendFrameIntoClientArea = self.dwmapi.DwmExtendFrameIntoClientArea
 | |
|         self.DwmSetWindowAttribute = self.dwmapi.DwmSetWindowAttribute
 | |
|         self.SetWindowCompositionAttribute.restype = c_bool
 | |
|         self.DwmExtendFrameIntoClientArea.restype = LONG
 | |
|         self.DwmSetWindowAttribute.restype = LONG
 | |
|         self.SetWindowCompositionAttribute.argtypes = [
 | |
|             c_int,
 | |
|             POINTER(WINDOWCOMPOSITIONATTRIBDATA),
 | |
|         ]
 | |
|         self.DwmSetWindowAttribute.argtypes = [c_int, DWORD, LPCVOID, DWORD]
 | |
|         self.DwmExtendFrameIntoClientArea.argtypes = [c_int, POINTER(MARGINS)]
 | |
| 
 | |
|         # Initialize structure
 | |
|         self.accentPolicy = ACCENT_POLICY()
 | |
|         self.winCompAttrData = WINDOWCOMPOSITIONATTRIBDATA()
 | |
|         self.winCompAttrData.Attribute = WINDOWCOMPOSITIONATTRIB.WCA_ACCENT_POLICY.value
 | |
|         self.winCompAttrData.SizeOfData = sizeof(self.accentPolicy)
 | |
|         self.winCompAttrData.Data = pointer(self.accentPolicy)
 | |
| 
 | |
|     def setAcrylicEffect(self, hWnd, gradientColor: str = "F2F2F299", isEnableShadow: bool = True, animationId: int = 0):
 | |
|         """ Add the acrylic effect to the window
 | |
| 
 | |
|         Parameters
 | |
|         ----------
 | |
|         hWnd: int or `sip.voidptr`
 | |
|             Window handle
 | |
| 
 | |
|         gradientColor: str
 | |
|             Hexadecimal acrylic mixed color, corresponding to four RGBA channels
 | |
| 
 | |
|         isEnableShadow: bool
 | |
|             Enable window shadows
 | |
| 
 | |
|         animationId: int
 | |
|             Turn on matte animation
 | |
|         """
 | |
|         hWnd = int(hWnd)
 | |
|         # Acrylic mixed color
 | |
|         gradientColor = (
 | |
|             gradientColor[6:]
 | |
|             + gradientColor[4:6]
 | |
|             + gradientColor[2:4]
 | |
|             + gradientColor[:2]
 | |
|         )
 | |
|         gradientColor = DWORD(int(gradientColor, base=16))
 | |
|         # matte animation
 | |
|         animationId = DWORD(animationId)
 | |
|         # window shadow
 | |
|         accentFlags = DWORD(0x20 | 0x40 | 0x80 |
 | |
|                             0x100) if isEnableShadow else DWORD(0)
 | |
|         self.accentPolicy.AccentState = ACCENT_STATE.ACCENT_ENABLE_ACRYLICBLURBEHIND.value
 | |
|         self.accentPolicy.GradientColor = gradientColor
 | |
|         self.accentPolicy.AccentFlags = accentFlags
 | |
|         self.accentPolicy.AnimationId = animationId
 | |
|         # enable acrylic effect
 | |
|         self.SetWindowCompositionAttribute(hWnd, pointer(self.winCompAttrData))
 | |
| 
 | |
|     def setMicaEffect(self, hWnd):
 | |
|         """ Add the mica effect to the window (Win11 only)
 | |
| 
 | |
|         Parameters
 | |
|         ----------
 | |
|         hWnd: int or `sip.voidptr`
 | |
|             Window handle
 | |
|         """
 | |
|         if sys.getwindowsversion().build < 22000:
 | |
|             raise Exception("The mica effect is only available on Win11")
 | |
| 
 | |
|         hWnd = int(hWnd)
 | |
|         margins = MARGINS(-1, -1, -1, -1)
 | |
|         self.DwmExtendFrameIntoClientArea(hWnd, byref(margins))
 | |
|         self.DwmSetWindowAttribute(hWnd, 1029, byref(c_int(1)), 4)
 | |
|         self.accentPolicy.AccentState = ACCENT_STATE.ACCENT_ENABLE_HOSTBACKDROP.value
 | |
|         self.SetWindowCompositionAttribute(hWnd, pointer(self.winCompAttrData))
 | |
| 
 | |
|     def setAeroEffect(self, hWnd):
 | |
|         """ Add the aero effect to the window
 | |
| 
 | |
|         Parameters
 | |
|         ----------
 | |
|         hWnd: int or `sip.voidptr`
 | |
|             Window handle
 | |
|         """
 | |
|         hWnd = int(hWnd)
 | |
|         self.accentPolicy.AccentState = ACCENT_STATE.ACCENT_ENABLE_BLURBEHIND.value
 | |
|         self.SetWindowCompositionAttribute(hWnd, pointer(self.winCompAttrData))
 | |
| 
 | |
|     def removeBackgroundEffect(self, hWnd):
 | |
|         """ Remove background effect
 | |
| 
 | |
|         Parameters
 | |
|         ----------
 | |
|         hWnd: int or `sip.voidptr`
 | |
|             Window handle
 | |
|         """
 | |
|         hWnd = int(hWnd)
 | |
|         self.accentPolicy.AccentState = ACCENT_STATE.ACCENT_DISABLED.value
 | |
|         self.SetWindowCompositionAttribute(hWnd, pointer(self.winCompAttrData))
 | |
| 
 | |
|     @staticmethod
 | |
|     def moveWindow(hWnd):
 | |
|         """ Move the window
 | |
| 
 | |
|         Parameters
 | |
|         ----------
 | |
|         hWnd: int or `sip.voidptr`
 | |
|             Window handle
 | |
|         """
 | |
|         hWnd = int(hWnd)
 | |
|         win32gui.ReleaseCapture()
 | |
|         win32api.SendMessage(
 | |
|             hWnd, win32con.WM_SYSCOMMAND, win32con.SC_MOVE + win32con.HTCAPTION, 0
 | |
|         )
 | |
| 
 | |
|     def addShadowEffect(self, hWnd):
 | |
|         """ Add DWM shadow to window
 | |
| 
 | |
|         Parameters
 | |
|         ----------
 | |
|         hWnd: int or `sip.voidptr`
 | |
|             Window handle
 | |
|         """
 | |
|         hWnd = int(hWnd)
 | |
|         margins = MARGINS(-1, -1, -1, -1)
 | |
|         self.DwmExtendFrameIntoClientArea(hWnd, byref(margins))
 | |
| 
 | |
|     def addMenuShadowEffect(self, hWnd):
 | |
|         """ Add DWM shadow to menu
 | |
| 
 | |
|         Parameters
 | |
|         ----------
 | |
|         hWnd: int or `sip.voidptr`
 | |
|             Window handle
 | |
|         """
 | |
|         hWnd = int(hWnd)
 | |
|         self.DwmSetWindowAttribute(
 | |
|             hWnd,
 | |
|             DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY.value,
 | |
|             byref(c_int(DWMNCRENDERINGPOLICY.DWMNCRP_ENABLED.value)),
 | |
|             4,
 | |
|         )
 | |
|         margins = MARGINS(-1, -1, -1, -1)
 | |
|         self.DwmExtendFrameIntoClientArea(hWnd, byref(margins))
 | |
| 
 | |
|     def removeShadowEffect(self, hWnd):
 | |
|         """ Remove DWM shadow from the window
 | |
| 
 | |
|         Parameters
 | |
|         ----------
 | |
|         hWnd: int or `sip.voidptr`
 | |
|             Window handle
 | |
|         """
 | |
|         hWnd = int(hWnd)
 | |
|         self.DwmSetWindowAttribute(
 | |
|             hWnd,
 | |
|             DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY.value,
 | |
|             byref(c_int(DWMNCRENDERINGPOLICY.DWMNCRP_DISABLED.value)),
 | |
|             4,
 | |
|         )
 | |
| 
 | |
|     @staticmethod
 | |
|     def removeMenuShadowEffect(hWnd):
 | |
|         """ Remove shadow from pop-up menu
 | |
| 
 | |
|         Parameters
 | |
|         ----------
 | |
|         hWnd: int or `sip.voidptr`
 | |
|             Window handle
 | |
|         """
 | |
|         hWnd = int(hWnd)
 | |
|         style = win32gui.GetClassLong(hWnd, win32con.GCL_STYLE)
 | |
|         style &= ~0x00020000  # CS_DROPSHADOW
 | |
|         win32api.SetClassLong(hWnd, win32con.GCL_STYLE, style)
 | |
| 
 | |
|     @staticmethod
 | |
|     def addWindowAnimation(hWnd):
 | |
|         """ Enables the maximize and minimize animation of the window
 | |
| 
 | |
|         Parameters
 | |
|         ----------
 | |
|         hWnd : int or `sip.voidptr`
 | |
|             Window handle
 | |
|         """
 | |
|         hWnd = int(hWnd)
 | |
|         style = win32gui.GetWindowLong(hWnd, win32con.GWL_STYLE)
 | |
|         win32gui.SetWindowLong(
 | |
|             hWnd,
 | |
|             win32con.GWL_STYLE,
 | |
|             style
 | |
|             | win32con.WS_MAXIMIZEBOX
 | |
|             | win32con.WS_CAPTION
 | |
|             | win32con.CS_DBLCLKS
 | |
|             | win32con.WS_THICKFRAME,
 | |
|         )
 |