Why AWM is not compatible with OpenGlass Legacy
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.
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?
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.
Then I inserted a piece of code into AWM to output symbols with an offset value of zero.
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.
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.
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.
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 🙏
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.
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)
With just OpenGlass alone the text works fine:
@ImSwordQueen I compiled your fork and it works fine, except for a problem with vertical text alignment when the window is maximized.
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.
Ok, I have found a solution and updated the instructions.