marticliment / win32mica

Win32mica: a simple module to add the Mica effect on legacy python windows.
https://pypi.org/project/win32mica
MIT License
95 stars 5 forks source link

suggestion: Support win10 acrylic and win7 ground glass #16

Open Puiching-Memory opened 1 year ago

Puiching-Memory commented 1 year ago

Tips:I'm using translation software

I have tried to add advanced effects to win32 forms, and here are some of my ideas.

  1. Import enum and ctypes modules and related classes to handle Windows API calls and data types.
  2. Define the required enumerations and structs
  3. Use the WindowEffect class to encapsulate the methods and data used to achieve the windowing effect.
  4. Set the AccentState attribute of the accentPolicy structure to the value corresponding to the Aero effect.
  5. Call SetWindowCompositionAttribute function, handle to the window and winCompAttrData structure passed to it.

I will submit my code as an attachment. It contains the simplest way to achieve both effects and was tested on my computer. Unfortunately, it still has a lot of bugs, but I don't have time to fix it. So I'm giving it to you, hoping to provide you with some reference and inspiration. TEST7.zip

This is the simplest way to call code: TEST7.WindowEffect().setAeroEffect(HWND)

This is the win7 ground glass effect reference

{639B83E5-A016-47a6-9791-4102BFA0E8FF} {C8CB7B29-0A63-4950-BD40-07290C2FC08A}

It is important to note that these effects are not directly achieved by a single line of code. I also adjusted the color of the controls. In the ground glass effect, the closer the color is to black, the higher the transparency.

At the same time, you can also see that some controls are still white. Also, the buttons in the title bar have become transparent.

This is Windows 10 acrylic effect

{039DEF37-6A3C-4c5d-B9CC-044714E4E2A4}

It is puzzling that this effect has a huge lag in the Windows 10 environment, but not in the Windows 11 environment

littlewhitecloud commented 1 year ago

呃,其实这个库只包含mica和mica alt效果,并不支持其他的效果。 如果你想使用acrylic aero效果的话,请使用BlurWindow库(pip install) 如果你也想用win7样式的边框,请上网搜索,是有方法的,善用搜索引擎是很重要的。 @Puiching-Memory

Puiching-Memory commented 1 year ago

感谢你的提醒。我重新思考了我的请求,win32mica应该专注于“mica”的实现,要求支持win7的效果是有点不合理的。或许你已经注意到我的第一条消息中有一条zip下载链接。里面包含了一些python代码,能实现所谓的亚克力和磨砂玻璃效果。这些代码已经在win11上测试,我使用的库是wxpython。

wxpython默认使用GDI+模式,这种模式不支持GPU加速,理论上不能实现复杂的背景混合效果。 这与许多经典win32 GUI库相同。

我选择提交为issue而不是commit是因为我没有时间完善这些测试代码。 仅分享为一种思路 @littlewhitecloud

littlewhitecloud commented 1 year ago

这个代码没有问题,有人测试过了

marticliment commented 1 year ago

I will have this in mind, and give it a try as MicaStyle.FLUENT and MicaStyle.GLASSY

littlewhitecloud commented 1 year ago

I made a c++ version to apply Acrylic effect.

#include <Windows.h>
#include "win32acrylic.h"

void ApplyAcrylic(const HWND hwnd, const bool theme)
{ // Windows 10 & 11
    pfnSetWindowCompositionAttribute setWindowCompositionAttribute = (pfnSetWindowCompositionAttribute)GetProcAddress(GetModuleHandle("user32.dll"), "SetWindowCompositionAttribute");

    ACCENT_POLICY accentpolicy = {ACCENT_INVALID_STATE, theme, theme ? 1074926098 : 0, 0};

    WINDOWCOMPOSITIONATTRIBDATA data;
    data.Attrib = WCA_ACCENT_POLICY;
    data.pvData = &accentpolicy;
    data.cbData = sizeof(accentpolicy);

    DwmSetWindowAttribute(hwnd, 20, &theme, sizeof(int));
    setWindowCompositionAttribute(hwnd, &data);
}
#pragma once

typedef enum _WINDOWCOMPOSITIONATTRIB
{
    WCA_UNDEFINED = 0,
    WCA_NCRENDERING_ENABLED = 1,
    WCA_NCRENDERING_POLICY = 2,
    WCA_TRANSITIONS_FORCEDISABLED = 3,
    WCA_ALLOW_NCPAINT = 4,
    WCA_CAPTION_BUTTON_BOUNDS = 5,
    WCA_NONCLIENT_RTL_LAYOUT = 6,
    WCA_FORCE_ICONIC_REPRESENTATION = 7,
    WCA_EXTENDED_FRAME_BOUNDS = 8,
    WCA_HAS_ICONIC_BITMAP = 9,
    WCA_THEME_ATTRIBUTES = 10,
    WCA_NCRENDERING_EXILED = 11,
    WCA_NCADORNMENTINFO = 12,
    WCA_EXCLUDED_FROM_LIVEPREVIEW = 13,
    WCA_VIDEO_OVERLAY_ACTIVE = 14,
    WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15,
    WCA_DISALLOW_PEEK = 16,
    WCA_CLOAK = 17,
    WCA_CLOAKED = 18,
    WCA_ACCENT_POLICY = 19,
    WCA_FREEZE_REPRESENTATION = 20,
    WCA_EVER_UNCLOAKED = 21,
    WCA_VISUAL_OWNER = 22,
    WCA_LAST = 23
} WINDOWCOMPOSITIONATTRIB;

typedef struct _WINDOWCOMPOSITIONATTRIBDATA
{
    WINDOWCOMPOSITIONATTRIB Attrib;
    PVOID pvData;
    SIZE_T cbData;
} WINDOWCOMPOSITIONATTRIBDATA;

typedef enum _ACCENT_STATE
{
    ACCENT_DISABLED = 0,
    ACCENT_ENABLE_GRADIENT = 1,
    ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
    ACCENT_ENABLE_BLURBEHIND = 3,
    ACCENT_INVALID_STATE = 4,
} ACCENT_STATE;

typedef struct _ACCENT_POLICY
{
    ACCENT_STATE AccentState;
    DWORD AccentFlags;
    DWORD GradientColor;
    DWORD AnimationId;
} ACCENT_POLICY;

WINUSERAPI BOOL WINAPI SetWindowCompositionAttribute(
    _In_ HWND hWnd,
    _Inout_ WINDOWCOMPOSITIONATTRIBDATA *pAttrData);

typedef BOOL(WINAPI *pfnSetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONATTRIBDATA *);

As for python... I find a pip package named BlurWindow does that well.

littlewhitecloud commented 1 year ago

Think we can use c++ instead of python. C++ can do the same but more easier.

#pragma once

#ifdef APPLYMICA_EXPORTS
#define DLLEXPORT __declspec(dllexport)
#else
#define DLLEXPORT __declspec(dllimport)
#endif

extern "C" {
    DLLEXPORT void ApplyAcrylic(const HWND hwnd, const bool theme);
    DLLEXPORT void ApplyDocumentMica(const HWND hwnd, const bool theme, const bool micaalt, const bool extend);
    DLLEXPORT void ApplyUndocumentMica(const HWND hwnd, const bool theme, const bool micaalt, const bool extend);
}
// win32mica.cpp - Apply mica and acrylic for win32 applications
#include <Windows.h>
#include <Dwmapi.h>

#include "win32mica.h"

#pragma comment(lib, "Dwmapi.lib")

static void ExtendFrameIntoClientArea(const HWND hwnd)
{
    const MARGINS margins = {-1, -1, -1, -1};
    DwmExtendFrameIntoClientArea(hwnd, &margins);
}

void ApplyDocumentMica(const HWND hwnd, const bool theme, const bool micaalt, const bool extend)
{ // Windows 11 23523+
    const int value = micaalt ? 0x04 : 0x02;

    if (extend)
        ExtendFrameIntoClientArea(hwnd);

    // Set the window's theme
    DwmSetWindowAttribute(hwnd, 20, &theme, sizeof(int));
    // Set the window's backdrop
    DwmSetWindowAttribute(hwnd, 38, &value, sizeof(int));
}

void ApplyUndocumentMica(const HWND hwnd, const bool theme, const bool micaalt, const bool extend)
{ // Windows 11 23523-
    const int value = micaalt ? 0x04 : 0x01;

    if (extend)
        ExtendFrameIntoClientArea(hwnd);

    // Set the window's theme
    DwmSetWindowAttribute(hwnd, 20, &theme, sizeof(int));
    // Set the window's backdrop
    DwmSetWindowAttribute(hwnd, 1029, &value, sizeof(int));
}
LIBRARY win32mica.dll
EXPORTS
    ApplyDocumentMica @1
    ApplyUndocumentMica @2
        ApplyAcrylic @3

After write done these, and do

cl /LD /DEF: win32mica.def win32mica.cpp

We can use c++ to call it and also can use python to call the dll file.

from ctypes import windll
from pathlib import Path
from sys import getwindowsversion

if getwindowsversion().build < 22000:
    raise OSError("Use Windows 11 to apply mica effect to the win32 application")

plugin = windll.LoadLibrary(str(Path(__file__).parent / "win32mica.dll"))

class MICATHEME:
    LIGHT: bool = False
    DARK: bool = True

class MICAMODE:
    DEFAULT: bool = False
    ALT: bool = True

def ApplyMica(hwnd: int = 0, theme: bool = True, micaalt: bool = True, extend: bool = True) -> None:
    """Apply mica effect for Win32 Applications
    Args:
        hwnd(int): The target window's hwnd
        theme(bool):
            false -> light
            true -> dark
        micaalt(bool):
            false -> default
            true -> alt
        extend(bool):
            false -> only apply to titlebar
            true -> extend to the window
    """
    if getwindowsversion().build < 22523:
        plugin.ApplyUndocumentMica(hwnd, theme, micaalt, extend)
    else:
        plugin.ApplyDocumentMica(hwnd, theme, micaalt, extend)

That's quite easy and we can use any of the languages to call the dll file to apply the effect.

Feel free to see my version of win32mica(www.github.com/littlewhitecloud/win32mica) (Does this out of topic?)

marticliment commented 1 year ago

I will study that

littlewhitecloud commented 1 year ago

I will study that

Thanks! This new repo include acrylic and mica effect, feel free to see it : https://github.com/littlewhitecloud/win32style