├── upload_requirements.txt ├── win32material ├── __init__.py └── win32material.py ├── setup.py ├── LICENSE ├── .github └── workflows │ └── python-publish.yml └── README.md /upload_requirements.txt: -------------------------------------------------------------------------------- 1 | setuptools 2 | twine 3 | wheel 4 | build 5 | -------------------------------------------------------------------------------- /win32material/__init__.py: -------------------------------------------------------------------------------- 1 | """Load functions""" 2 | 3 | from platform import platform 4 | 5 | if not platform().startswith("Windows-10") and not platform().startswith("Windows-11"): 6 | raise ImportError("To use this package, you need to use Windows 10 or above") 7 | 8 | from .win32material import (BORDERTYPE, MICAMODE, MICATHEME, ApplyAcrylic, 9 | ApplyDarkMode, ApplyMica, SetBorderColor, 10 | SetTitlebarColor, SetTitleColor, SetWindowBorder) 11 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """Setup for win32material""" 2 | 3 | from distutils.core import setup 4 | 5 | with open("README.md", "r") as file: 6 | long_description = file.read() 7 | 8 | setup( 9 | name="win32material", 10 | version="1.0.7", 11 | description="Apply some window effects to the Win32 Applications", 12 | long_description=long_description, 13 | long_description_content_type="text/markdown", 14 | author="littlewhitecloud", 15 | url="https://github.com/littlewhitecloud/win32material", 16 | packages=["win32material"], 17 | ) 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023-2025 小白云 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will upload a Python Package using Twine when a release is created 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries 3 | 4 | # This workflow uses actions that are not certified by GitHub. 5 | # They are provided by a third-party and are governed by 6 | # separate terms of service, privacy policy, and support 7 | # documentation. 8 | 9 | name: Upload Python Package 10 | 11 | on: 12 | release: 13 | types: [published] 14 | 15 | permissions: 16 | contents: read 17 | 18 | jobs: 19 | deploy: 20 | 21 | runs-on: ubuntu-latest 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | - name: Set up Python 26 | uses: actions/setup-python@v3 27 | with: 28 | python-version: '3.x' 29 | - name: Install dependencies 30 | run: | 31 | python -m pip install --upgrade pip 32 | pip install build 33 | - name: Build package 34 | run: python -m build 35 | - name: Publish package 36 | uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 37 | with: 38 | user: __token__ 39 | password: ${{ secrets.PYPI_API_TOKEN }} 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # win32material 2 | Apply some window effects like `mica` `micaalt` `acrylic` to the Win32 Applications. 3 | Can also change the window's titlebar color, border type and so on. (Windows 11 only) 4 | 5 | ## Installation 6 | ```console 7 | pip install win32material --user 8 | ``` 9 | 10 | ## Help 11 | How to get the hwnd of the window? 12 | ```python 13 | from ctypes import windll, c_char_p 14 | hwnd = windll.user32.FindWindowW(c_char_p(None), "{Your window name}") 15 | ``` 16 | 17 | ## Gallery 18 | ![image](https://github.com/littlewhitecloud/win32material/assets/71159641/ffcea60c-718a-4315-9069-c1e4abc3f4cd) 19 | ![image](https://github.com/littlewhitecloud/win32material/assets/71159641/c9e522c5-d8c5-4563-a0e5-7fef39366a1d) 20 | ![image](https://github.com/littlewhitecloud/win32style/assets/71159641/760b5195-354e-428c-9f48-781e7a4dc3ae) 21 | ```python 22 | from win32material import ApplyMica, ApplyAcrylic 23 | 24 | # ApplyMica(hwnd, theme, micaalt) 25 | # ApplyAcrylic(hwnd, extend) 26 | ``` 27 | 28 | ```python 29 | ChangeTitlebarColor(hwnd, "#111111") 30 | ``` 31 | ![image](https://github.com/littlewhitecloud/win32style/assets/71159641/bc179e80-fcb0-48e4-92f0-8ab9e465ef1e) 32 | 33 | ```python 34 | ChangeBorderColor(hwnd, "#114514") 35 | ``` 36 | ![image](https://github.com/littlewhitecloud/win32style/assets/71159641/7c3b035d-4a40-4026-aa5f-fbaf27846e43) 37 | 38 | 39 | ```python 40 | ChangeTitleColor(hwnd, "#745616") 41 | ``` 42 | ![image](https://github.com/littlewhitecloud/win32style/assets/71159641/f3521d0b-3483-4138-bcda-b2d742079385) 43 | 44 | ```python 45 | SetBorderType(hwnd, BORDERTYPE.RECTANGULAR) 46 | ``` 47 | ![image](https://github.com/littlewhitecloud/win32style/assets/71159641/2a609226-5021-47f5-a80e-0e9250701140) 48 | 49 | ```python 50 | SetBorderType(hwnd, BORDERTYPE.ROUND) 51 | ``` 52 | ![image](https://github.com/littlewhitecloud/win32style/assets/71159641/5648f581-3a92-4a3c-bd74-853d5f38677a) 53 | 54 | ```python 55 | SetBorderType(hwnd, BORDERTYPE.SMALLROUND) 56 | ``` 57 | ![image](https://github.com/littlewhitecloud/win32style/assets/71159641/f06c4917-757f-48c5-b411-ed243f8fdf1c) 58 | 59 | ### Thanks 60 | Get the idea of applying mica from [https://github.com/marticliment/win32mica/](https://github.com/marticliment/win32mica/) 61 | And some other ideas from [https://github.com/Akascape/py-win-styles](https://github.com/Akascape/py-window-styles) 62 | -------------------------------------------------------------------------------- /win32material/win32material.py: -------------------------------------------------------------------------------- 1 | """Define different materials and functions for win32 applications""" 2 | 3 | from __future__ import annotations 4 | 5 | from ctypes import POINTER, Structure, byref, c_int, pointer, sizeof, windll 6 | from ctypes.wintypes import DWORD, HWND, ULONG 7 | from functools import partial 8 | from sys import getwindowsversion 9 | 10 | dwmapi = windll.dwmapi 11 | user32 = windll.user32 12 | 13 | 14 | class MICATHEME: 15 | LIGHT: bool = False 16 | DARK: bool = True 17 | 18 | 19 | class MICAMODE: 20 | DEFAULT: bool = False 21 | ALT: bool = True 22 | 23 | 24 | class BORDERTYPE: 25 | RECTANGULAR: int = 1 26 | ROUND: int = 2 27 | SMALLROUND: int = 3 28 | 29 | 30 | class AccentPolicy(Structure): 31 | _fields_ = [ 32 | ("AccentState", DWORD), 33 | ("AccentFlags", DWORD), 34 | ("GradientColor", DWORD), 35 | ("AnimationId", DWORD), 36 | ] 37 | 38 | 39 | class WindowCompositionAttributeData(Structure): 40 | _fields_ = [ 41 | ("Attribute", DWORD), 42 | ("Data", POINTER(AccentPolicy)), 43 | ("SizeOfData", ULONG), 44 | ] 45 | 46 | 47 | class MARGINS(Structure): 48 | _fields_ = [ 49 | ("cxLeftWidth", c_int), 50 | ("cxRightWidth", c_int), 51 | ("cyTopHeight", c_int), 52 | ("cyBottomHeight", c_int), 53 | ] 54 | 55 | 56 | def strtohex(_: str) -> int: 57 | return int(f"{_[5:7]}{_[3:5]}{_[1:3]}", base=16) 58 | 59 | 60 | def ExtendFrameIntoClientArea(hwnd: HWND) -> None: 61 | margins = MARGINS(-1, -1, -1, -1) 62 | dwmapi.DwmExtendFrameIntoClientArea(hwnd, byref(margins)) 63 | 64 | 65 | def ApplyDarkMode(hwnd: HWND) -> None: 66 | dwmapi.DwmSetWindowAttribute(hwnd, 20, byref(DWORD(True)), sizeof(DWORD)) 67 | 68 | 69 | # https://github.com/marticliment/win32mica/ 70 | def ApplyMica( 71 | hwnd: HWND, theme: bool = False, micaalt: bool = True, extend: bool = True 72 | ) -> None: 73 | UNDOCUMENTED_MICA_VALUE = 0x04 if micaalt else 0x02 74 | DOCUMENTED_MICA_VALUE = 0x01 if micaalt else 0x04 75 | UNDOCUMENTED_MICA_ENTRY = 1029 76 | DOCUMENTED_MICA_ENTRY = 38 77 | 78 | flag: bool = False if getwindowsversion().build < 22523 else True 79 | value: int = UNDOCUMENTED_MICA_VALUE if flag else DOCUMENTED_MICA_VALUE 80 | 81 | entry: int = DOCUMENTED_MICA_ENTRY if flag else UNDOCUMENTED_MICA_ENTRY 82 | 83 | if extend: 84 | ExtendFrameIntoClientArea(hwnd) 85 | 86 | # Set the theme of the window 87 | if theme: 88 | ApplyDarkMode(hwnd) 89 | 90 | # Set the window's backdrop 91 | dwmapi.DwmSetWindowAttribute(hwnd, entry, byref(DWORD(value)), sizeof(DWORD)) 92 | 93 | 94 | def ApplyAcrylic( 95 | hwnd: HWND, theme: bool = False, extend: bool = False, hexcolor: str | None = None 96 | ) -> None: 97 | if theme: 98 | ApplyDarkMode(hwnd) 99 | 100 | if extend: 101 | ExtendFrameIntoClientArea(hwnd) 102 | 103 | accentpolicy: AccentPolicy = AccentPolicy() 104 | data: WindowCompositionAttributeData = WindowCompositionAttributeData() 105 | data.Attribute = 30 106 | data.SizeOfData = sizeof(accentpolicy) 107 | data.Data = pointer(accentpolicy) 108 | 109 | accentpolicy.AccentState = 3 110 | 111 | if hexcolor: 112 | accentpolicy.GradientColor = DWORD(strtohex(hexcolor)) 113 | 114 | user32.SetWindowCompositionAttribute(hwnd, pointer(data)) 115 | 116 | 117 | def SetWindowAttribute(hwnd: HWND, entry: int, hexcolor: str): 118 | dwmapi.DwmSetWindowAttribute( 119 | hwnd, entry, byref(DWORD(strtohex(hexcolor))), sizeof(DWORD) 120 | ) 121 | 122 | 123 | def SetWindowBorder(hwnd: HWND, type: BORDERTYPE | int) -> None: 124 | dwmapi.DwmSetWindowAttribute(hwnd, 33, byref(DWORD(type)), sizeof(DWORD)) 125 | 126 | 127 | SetBorderColor = partial(SetWindowAttribute, entry=34) 128 | SetTitlebarColor = partial(SetWindowAttribute, entry=35) 129 | SetTitleColor = partial(SetWindowAttribute, entry=36) 130 | --------------------------------------------------------------------------------