OpenGlass icon indicating copy to clipboard operation
OpenGlass copied to clipboard

Why AWM is not compatible with OpenGlass Legacy

Open ALTaleX531 opened this issue 7 months ago • 7 comments

Description

Since the release of OpenGlass Legacy v2, a lot of feedback has been given that running with AWM leads to complete transparency/opaqueness, or crashes.

Investigation

Almost everyone thinks it's an OpenGlass issue because it almost never happened before. To be honest, I'm a little sad that I've done my best to minimize destructive changes in order to avoid incompatibility. So I tried compiling AWM myself and tried to reproduce the above problems, and I got the following results.

Image If I run OpenGlass before running AWM, then I get full transparency as shown above.

https://github.com/Dulappy/aero-window-manager/blob/fc44618f507e5a39c3d4ef7f66eaef61dbd01858/awmdll/awmdll.cpp#L1003-L1131 https://github.com/ALTaleX531/OpenGlass/blob/65b441d1e32eb680f7655c488e65c063b3222607/OpenGlass/GlassFrameHandler.cpp#L518-L528 Check out the code above. AWM in fact overwrites OpenGlass's colors with its own and blocks OpenGlass's efforts to convert normal draw geometry commands to draw glass commands.

But what if I run AWM first? Image Image

Well, I got a crash, caused by a fast failure exception, which also meant that OpenGlass didn't get a chance to generate a memory dump. Obviously, udwm's PE file header was f*cked up, and that's why the GetFileVersionInfoSizeW function thought it was not a correct dll image. So, my experience tells me that AWM was parsing out a symbol with an offset of 0, so write attempts to memory at udwm+offset screwed up the PE header.

Image Then I inserted a piece of code into AWM to output symbols with an offset value of zero.

Image Looks like AWM got the name of a symbol wrong because the correct name is private: virtual void * __cdecl CText::`scalar deleting destructor'(unsigned int). https://github.com/Dulappy/aero-window-manager/blob/fc44618f507e5a39c3d4ef7f66eaef61dbd01858/awmdll/awmdll.cpp#L1492-L1503 AWM hooked this function to ensure that allocated TEXTEX objects are properly freed. However, AWM didn't successfully hook up when it actually ran, which means that a memory leak occurred but nobody knew.

The system I tested with was Windows 10 22H2, but this could still be successfully reproduced in 1809. There are many other weird issues, most of which are due to improper memory management of TEXTEX objects.

Possible Solution

For Dulappy, I think you should refactor AWM and provide the option to disable some of the hooks. For general developers, the solution is to remove all unnecessary hooks or fork OpenGlass to integrate AWM's features, which will solve all the problems once and for all. For average users, use other branches of AWM that have fixed this issue, or use the windhawk mods that existed as predecessors to AWM.

ALTaleX531 avatar May 28 '25 06:05 ALTaleX531

For those that need a compatible build of AWM, here's a build that I use as of Legacy 2.0.5 provided by ImSwordQueen.

awm.zip

DAPOPOBEFASTONYOAZZ avatar May 28 '25 13:05 DAPOPOBEFASTONYOAZZ

For anyone who just wants the Windows Vista/7 look and wants to compile their own AWM but doesn't know how to modify it, here's a simple guide.

Retain only the following hooks, comment/remove other hook operations.

rv = funchook_prepare(funchook, (void**)&CTLW_UpdateNCAreaPositionsAndSizes_orig, CTLW_UpdateNCAreaPositionsAndSizes_Hook);
if (rv) {
    return ERR_FH_INIT;
}
rv = funchook_prepare(funchook, (void**)&CButton_SetVisualStates_orig, CButton_SetVisualStates_Hook);
if (rv) {
    return ERR_FH_INIT;
}

Replace the implementation of long CTLW_UpdateNCAreaPositionsAndSizes_Hook(BYTE* pThis) with the following code.

long CTLW_UpdateNCAreaPositionsAndSizes_Hook(BYTE* pThis) {
    CTLW_UpdateNCAreaPositionsAndSizes_orig(pThis);

    int XBOffsetNor = awmsettings.xBtnOffsetNormal;
    int XBOffsetMax = awmsettings.xBtnOffsetMaximized;
    MARGINS clientMargins = *(MARGINS*)(pThis + CTLW_ClientMargins);

    bool isMaximized = *(pThis + wState1) & STATE_MAXIMIZED;
    bool isTool = *(pThis + wState2) & TYPE_TOOL;

    BYTE* windowVisual = *(BYTE**)(pThis + CTLW_WindowVisual);
    int DPIValue = *(int*)(windowVisual + CVis_DPI);

    if (*(long long *)(pThis + CTLW_ClientArea)) {
        BYTE* clientVisual = *(BYTE **)(pThis + CTLW_ClientVisual);
        CVisual_SetInsetFromParentLeft(clientVisual, clientMargins.cxLeftWidth);
        CVisual_SetInsetFromParentRight(clientVisual, clientMargins.cxRightWidth);
        CVisual_SetInsetFromParentTop(clientVisual, clientMargins.cyTopHeight);
        CVisual_SetInsetFromParentBottom(clientVisual, clientMargins.cyBottomHeight);

        // seems unused, included here anyway just in case
        BYTE* clientBlur = *(BYTE **)(pThis + CTLW_ClientBlur);
        if (clientBlur) {
            CVisual_SetInsetFromParent(clientBlur, (struct _MARGINS*)(clientVisual + CVis_InsetFromParent));
        }
    }

    MARGINS* borderSizes;
    if (isMaximized) {
        borderSizes = (MARGINS*)(pThis + CTLW_BorderSizesMax);
    }
    else {
        borderSizes = (MARGINS*)(pThis + CTLW_BorderSizesNormal);
    }

    // left inset calculations for icon and text
    int insetLeft = awmsettings.insetLeftAddNormal + awmsettings.insetLeftMulNormal * clientMargins.cxLeftWidth;
    if (isMaximized) {
        insetLeft = awmsettings.insetLeftAddMaximized + awmsettings.insetLeftMulMaximized * clientMargins.cxLeftWidth;
    }

    // right inset calculations for buttons
    // might add some more options here later
    int insetRight = clientMargins.cxRightWidth;
    if (insetRight <= 0) {
        insetRight = *(int*)(windowVisual + CVis_BorderWidth);
    }

    if (isMaximized) {
        insetRight = borderSizes->cxRightWidth + XBOffsetMax;
    }
    else {
        insetRight += XBOffsetNor;
    }

    int insetTop = borderSizes->cyTopHeight;

    if (isTool) {
        int TBHeight = GetSystemMetricsForDpi(53, DPIValue);
        int fullTBHeight = TBHeight + *(DWORD*)(windowVisual + CVis_BorderWidth) + 1;
        int btnHeight = floor(TBHeight * (double)(awmsettings.xBtnHeightPalette / awmsettings.targetTBHeightPalette) + 0.5);

        switch (awmsettings.tbBtnAlignPalette) {
        case AWM_BTN_ALIGN_TOP:
            insetTop += awmsettings.xBtnInsetDirectionalPalette;
            break;
        case AWM_BTN_ALIGN_CENTER:
            insetTop += (fullTBHeight - btnHeight - insetTop) / 2;
            break;
        case AWM_BTN_ALIGN_TBCENTER:
            insetTop = fullTBHeight - TBHeight - 1;
            insetTop += (TBHeight - btnHeight)/2;
            break;
        case AWM_BTN_ALIGN_BOTTOM:
            insetTop = fullTBHeight - btnHeight - awmsettings.xBtnInsetDirectionalPalette;
            break;
        }
        insetRight+=awmsettings.xBtnOffsetPalette;
    }

    CTopLevelWindow_UpdateNCAreaButton(pThis, 3, insetTop, &insetRight, DPIValue);
    CTopLevelWindow_UpdateNCAreaButton(pThis, 2, insetTop, &insetRight, DPIValue);
    CTopLevelWindow_UpdateNCAreaButton(pThis, 1, insetTop, &insetRight, DPIValue);
    CTopLevelWindow_UpdateNCAreaButton(pThis, 0, insetTop, &insetRight, DPIValue);

    BYTE* iconVisual = *(BYTE**)(pThis + CTLW_IconVisual);
    if (iconVisual) {
        tagSIZE size = { 0 };
        if (*(int*)(windowVisual + CVis_InsetTop) || *(int*)(windowVisual + CVis_InsetBottom) || (*(DWORD*)(pThis + wState2) & 0x10000) == 0) {
            size.cx = GetSystemMetricsForDpi(SM_CXSMICON, DPIValue);
            size.cy = GetSystemMetricsForDpi(SM_CYSMICON, DPIValue);
        }
        CVisual_SetSize(iconVisual, &size);

        if (awmsettings.iconTextVerticalAlign == AWM_TEXT_VALIGN_CENTER) {
            insetTop = borderSizes->cyTopHeight + (clientMargins.cyTopHeight - size.cx - borderSizes->cyTopHeight) / 2;
        }
        else {
            int borderSize = *(DWORD*)(windowVisual + CVis_BorderWidth);
            insetTop = borderSize + (clientMargins.cyTopHeight - size.cx - borderSize - 1) / 2;
        }
        CVisual_SetInsetFromParentLeft(iconVisual, insetLeft);
        CVisual_SetInsetFromParentTop(iconVisual, insetTop);

        if (size.cx > 0) {
            insetLeft += size.cx + awmsettings.textInset;
        }
    }

    BYTE* textVisual = *(BYTE**)(pThis + CTLW_TextVisual);
    if (textVisual) {
        int borderSize;
        if (awmsettings.iconTextVerticalAlign == AWM_TEXT_VALIGN_CENTER)
            borderSize = borderSizes->cyTopHeight;
        else
            borderSize = *(DWORD*)(windowVisual + CVis_BorderWidth);

        tagSIZE size = { 0, clientMargins.cyTopHeight - borderSize - 2 };

        CVisual_SetInsetFromParentTop(textVisual, borderSize + 1);
        CVisual_SetInsetFromParentLeft(textVisual, insetLeft);
        CVisual_SetSize(textVisual, &size);
    }

    return 0;
}

This way, you don't need to care about the order in which AWM and OpenGlass run, and most of the features are now implemented by OpenGlass.

ALTaleX531 avatar May 28 '25 17:05 ALTaleX531

For those that need a compatible build of AWM, here's a build that I use as of Legacy 2.0.5 provided by ImSwordQueen.

removed

Please link the main repo instead of linking a possibly outdated build 🙏

ImSwordQueen avatar May 28 '25 17:05 ImSwordQueen

Please link the main repo instead of linking a possibly outdated build 🙏

Oops - I apologize. I did not know a most recent build was compiled that is compatible and was easy for everybody to download.

DAPOPOBEFASTONYOAZZ avatar May 28 '25 18:05 DAPOPOBEFASTONYOAZZ

For anyone who just wants the Windows Vista/7 look and wants to compile their own AWM but doesn't know how to modify it, here's a simple guide.

Retain only the following hooks, comment/remove other hook operations.

...

This way, you don't need to care about the order in which AWM and OpenGlass run, and most of the features are now implemented by OpenGlass.

I tried the instructions you gave to patch AWM just to allow the bare minimum hooks and the text vanishes entirely in my end. (https://github.com/ImSwordQueen/aero-window-manager-OPL-2.0/commit/04941a9f4ac3ff7bb035b94909a27a2504e91004)

Image

With just OpenGlass alone the text works fine:

Image

ImSwordQueen avatar May 28 '25 18:05 ImSwordQueen

@ImSwordQueen I compiled your fork and it works fine, except for a problem with vertical text alignment when the window is maximized.

Image Image

Edit: I seem to have reproduced your problem, there is not much of a problem for everything that exists before AWM runs, but for windows created afterward the text disappears.

ALTaleX531 avatar May 28 '25 19:05 ALTaleX531

Ok, I have found a solution and updated the instructions.

ALTaleX531 avatar May 28 '25 19:05 ALTaleX531