winamp/Src/Plugins/General/gen_ml/skinnedwnd.cpp
2024-09-24 14:54:57 +02:00

569 lines
14 KiB
C++

#include "./skinnedwnd.h"
#include "../winamp/wa_dlg.h"
#include "../nu/trace.h"
#include "./mldwm.h"
#include "../nu/CGlobalAtom.h"
static CGlobalAtom WNDDATAPROPW(L"SWDATA");
static UINT WINAMP_WM_DIRECT_MOUSE_WHEEL = WM_NULL;
#ifndef LONGX86
#ifdef _WIN64
#define LONGX86 LONG_PTR
#else /*_WIN64*/
#define LONGX86 LONG
#endif /*_WIN64*/
#endif // LONGX86
#define SWS_ATTACHED 0x00010000 // window attached
#define SWS_UNICODE 0x00020000 // winodow is unicode
#define SWS_THEMED 0x00040000 // was themed before
#define SWS_REFLECT 0x00080000 // support message reflection
#define SWS_DIALOG 0x00100000 // treat this as dialog
#define BORDER_WIDTH 1
extern HRESULT(WINAPI *SetWindowTheme)(HWND hwnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList); //xp theme shit
extern BOOL (__stdcall *IsAppThemed)(void);
#define DWM_COMPOSITION_CHECK ((UINT)-1)
#define DWM_COMPOSITION_DISABLED ((UINT)0)
#define DWM_COMPOSITION_ENABLED ((UINT)1)
static UINT dwmCompositionEnabled = DWM_COMPOSITION_CHECK;
static BOOL CALLBACK SkinChangedNotifyCB(HWND hwnd, LPARAM param)
{
SendMessageW(hwnd, (UINT)WM_ML_IPC, MAKEWPARAM(TRUE, param), (LPARAM)ML_IPC_SKINNEDWND_SKINCHANGED);
return TRUE;
}
SkinnedWnd *SkinnedWnd::GetFromHWND(HWND hwndSkinned)
{
return (hwndSkinned && IsWindow(hwndSkinned)) ? (SkinnedWnd*)GetPropW(hwndSkinned, WNDDATAPROPW) : NULL;
}
BOOL SkinnedWnd::IsDwmCompositionEnabled()
{
if (DWM_COMPOSITION_CHECK == dwmCompositionEnabled)
{
dwmCompositionEnabled = DWM_COMPOSITION_DISABLED;
BOOL bEnabled;
if (S_OK == MlDwm_LoadLibrary() && S_OK == MlDwm_IsCompositionEnabled(&bEnabled) && bEnabled)
dwmCompositionEnabled = DWM_COMPOSITION_ENABLED;
}
return (DWM_COMPOSITION_ENABLED == dwmCompositionEnabled);
}
SkinnedWnd::SkinnedWnd(BOOL bIsDialog)
: hwnd(NULL), style(SWS_NORMAL), uiState(NULL), redrawLock(0),
fnWndProc(NULL), wnddata(SKINNEDWND_TYPE_WINDOW | ((bIsDialog) ? SWS_DIALOG : 0))
{
minSize.cx = 0;
minSize.cy = 0;
maxSize.cx = 0;
maxSize.cy = 0;
if (WM_NULL == WINAMP_WM_DIRECT_MOUSE_WHEEL)
WINAMP_WM_DIRECT_MOUSE_WHEEL = RegisterWindowMessageW(L"WINAMP_WM_DIRECT_MOUSE_WHEEL");
}
SkinnedWnd::~SkinnedWnd(void)
{
if (!hwnd || !IsWindow(hwnd)) return;
RemovePropW(hwnd, WNDDATAPROPW);
if (fnWndProc)
{
INT index;
index = (SWS_DIALOG & wnddata) ? DWLP_DLGPROC : GWLP_WNDPROC;
(SWS_UNICODE & wnddata) ? SetWindowLongPtrW(hwnd, index, (LONGX86)(LONG_PTR)fnWndProc) : SetWindowLongPtrA(hwnd, index, (LONGX86)(LONG_PTR)fnWndProc);
}
if ((SWS_THEMED & wnddata) && IsAppThemed && IsAppThemed() && SetWindowTheme) SetWindowTheme(hwnd, NULL, NULL);
}
BOOL SkinnedWnd::IsUnicode(void)
{
return ( 0 != (SWS_UNICODE & wnddata));
}
BOOL SkinnedWnd::IsAttached(void)
{
return ( 0 != (SWS_ATTACHED & wnddata));
}
BOOL SkinnedWnd::Attach(HWND hwndToSkin)
{
INT index;
if (hwnd) return FALSE;
hwnd = hwndToSkin;
if(!hwnd || GetPropW(hwnd, WNDDATAPROPW)) return FALSE;
wnddata &= (SKINNEDWND_TYPE_WINDOW | SWS_DIALOG);
if(IsWindowUnicode(hwnd)) wnddata |= SWS_UNICODE;
index = (SWS_DIALOG & wnddata) ? DWLP_DLGPROC : GWLP_WNDPROC;
fnWndProc= (WNDPROC)(LONG_PTR)((SWS_UNICODE & wnddata) ? SetWindowLongPtrW(hwnd, index, (LONGX86)(LONG_PTR)WindowProcReal) : SetWindowLongPtrA(hwnd, index, (LONGX86)(LONG_PTR)WindowProcReal));
if (!fnWndProc || !SetPropW(hwnd, WNDDATAPROPW, this)) return FALSE;
RemoveReflector(hwnd); // we will use this refelector
wnddata |= (SWS_ATTACHED | SWS_REFLECT);
if (S_OK == MlDwm_LoadLibrary())
{
DWMNCRENDERINGPOLICY ncrp = DWMNCRP_DISABLED;
DWORD allow = FALSE;
MlDwm_SetWindowAttribute(hwnd, DWMWA_NCRENDERING_POLICY, &ncrp, sizeof(ncrp));
MlDwm_SetWindowAttribute(hwnd, DWMWA_ALLOW_NCPAINT, &allow, sizeof(allow));
}
if (IsAppThemed && IsAppThemed() && SetWindowTheme)
{
SetWindowTheme(hwnd, NULL, L"");
wnddata |= SWS_THEMED;
}
uiState =(WORD)SendMessageW(hwnd, WM_QUERYUISTATE, 0, 0L);
return TRUE;
}
LRESULT SkinnedWnd::CallPrevWndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return (SWS_UNICODE & wnddata) ? CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam) : CallWindowProcA(fnWndProc, hwnd, uMsg, wParam, lParam);
}
LRESULT SkinnedWnd::CallDefWndProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
return (SWS_UNICODE & wnddata) ? DefWindowProcW(hwnd, uMsg, wParam, lParam) : DefWindowProcA(hwnd, uMsg, wParam, lParam);
}
void SkinnedWnd::OnSkinChanged(BOOL bNotifyChildren, BOOL bRedraw)
{
if (SWS_USESKINFONT & style)
{
HFONT skinFont;
skinFont = (HFONT)MlStockObjects_Get(SKIN_FONT);
if (NULL == skinFont)
skinFont = (HFONT)MlStockObjects_Get(DEFAULT_FONT);
if (NULL != skinFont)
{
HFONT windowFont = (HFONT)CallPrevWndProc(WM_GETFONT, 0, 0L);
if (skinFont != windowFont)
{
DisableRedraw();
SendMessageW(hwnd, WM_SETFONT, (WPARAM)skinFont, MAKELPARAM(0, bRedraw));
if (FALSE != bRedraw)
{
SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE |
SWP_FRAMECHANGED | SWP_NOREDRAW);
}
EnableRedraw(SWR_NONE);
}
}
}
if (bNotifyChildren)
EnumChildWindows(hwnd, SkinChangedNotifyCB, bRedraw);
SendMessageW(hwnd, (UINT)WM_ML_IPC,
MAKEWPARAM(bNotifyChildren, bRedraw),
(LPARAM)ML_IPC_SKINNEDWND_SKINUPDATED);
if (bRedraw)
InvalidateRect(hwnd, NULL, TRUE);
}
void SkinnedWnd::OnSkinUpdated(BOOL bNotifyChildren, BOOL bRedraw)
{
}
void SkinnedWnd::SkinChanged(BOOL bNotifyChildren, BOOL bRedraw)
{
OnSkinChanged(bNotifyChildren, bRedraw);
}
void SkinnedWnd::EnableReflection(BOOL bEnable)
{
wnddata = (wnddata & ~SWS_REFLECT) | ((bEnable) ? SWS_REFLECT : 0);
}
BOOL SkinnedWnd::SetStyle(UINT newStyle, BOOL bRedraw)
{
style = newStyle;
if (NULL != hwnd)
SkinChanged(FALSE, bRedraw);
return TRUE;
}
void SkinnedWnd::SetMinMaxInfo(MLSKINNEDMINMAXINFO *minMax)
{
if (NULL != minMax)
{
minSize.cx = minMax->min.cx;
if (minSize.cx < 0)
minSize.cx = 0;
minSize.cy = minMax->min.cy;
if (minSize.cy < 0)
minSize.cy = 0;
maxSize.cx = minMax->max.cx;
if (maxSize.cx < 0)
maxSize.cx = 0;
maxSize.cy = minMax->max.cy;
if (maxSize.cy < 0)
maxSize.cy = 0;
}
else
{
memset(&minSize, 0, sizeof(minSize));
memset(&maxSize, 0, sizeof(maxSize));
}
}
BOOL SkinnedWnd::OnMediaLibraryIPC(INT msg, INT_PTR param, LRESULT *pResult)
{
switch(msg)
{
case ML_IPC_SKINNEDWND_ISSKINNED: *pResult = IsAttached(); return TRUE;
case ML_IPC_SKINNEDWND_SKINCHANGED: SkinChanged(LOWORD(param), HIWORD(param)); *pResult = 1; return TRUE;
case ML_IPC_SKINNEDWND_SKINUPDATED: OnSkinUpdated(LOWORD(param), HIWORD(param)); break;
case ML_IPC_SKINNEDWND_GETTYPE: *pResult = GetType(); return TRUE;
case ML_IPC_SKINNEDWND_ENABLEREFLECTION: EnableReflection((BOOL)param); *pResult = 1; return TRUE;
case ML_IPC_SKINNEDWND_GETPREVWNDPROC:
if (param) *((BOOL*)param) = (SWS_UNICODE & wnddata);
*pResult = (INT_PTR)fnWndProc;
return TRUE;
case ML_IPC_SKINNEDWND_SETSTYLE: *pResult = style; style = (UINT)param; return TRUE;
case ML_IPC_SKINNEDWND_GETSTYLE: *pResult = style; return TRUE;
case ML_IPC_SKINNEDWND_SETMINMAXINFO:
SetMinMaxInfo((MLSKINNEDMINMAXINFO*)param);
*pResult = TRUE;
return TRUE;
}
return FALSE;
}
INT SkinnedWnd::OnNcHitTest(POINTS pts)
{
return (INT)CallPrevWndProc(WM_NCHITTEST, 0, *(LPARAM*)&pts);
}
void SkinnedWnd::DrawBorder(HDC hdc, RECT *prc, UINT type, HPEN pen)
{
HPEN penOld;
INT o = (BORDER_WIDTH/2) + ((BORDER_WIDTH%2) ? 1 : 0);
switch(type)
{
case BORDER_SUNKEN:
case BORDER_FLAT:
penOld = (HPEN)SelectObject(hdc, pen);
MoveToEx(hdc, prc->right - o, prc->top, NULL);
LineTo(hdc, prc->right - o, prc->bottom);
MoveToEx(hdc, prc->right - BORDER_WIDTH, prc->bottom - o, NULL);
LineTo(hdc, prc->left - 1, prc->bottom - o);
if (BORDER_FLAT == type)
{
MoveToEx(hdc, prc->left + BORDER_WIDTH/2, prc->bottom - BORDER_WIDTH, NULL);
LineTo(hdc, prc->left + BORDER_WIDTH/2, prc->top);
MoveToEx(hdc, prc->left, prc->top + BORDER_WIDTH/2, NULL);
LineTo(hdc, prc->right - BORDER_WIDTH, prc->top + BORDER_WIDTH/2);
}
SelectObject(hdc, penOld);
break;
}
}
UINT SkinnedWnd::GetBorderType(void)
{
DWORD ws = (DWORD)GetWindowLongPtrW(hwnd, GWL_EXSTYLE);
if (WS_EX_STATICEDGE & ws) return BORDER_FLAT;
else if (WS_EX_CLIENTEDGE & ws) return BORDER_SUNKEN;
ws = (DWORD)GetWindowLongPtrW(hwnd, GWL_STYLE);
return (WS_BORDER & ws) ? BORDER_FLAT : BORDER_NONE;
}
void SkinnedWnd::DrawBorder(HDC hdc)
{
UINT borderType = GetBorderType();
if (BORDER_NONE != borderType)
{
RECT rc;
GetWindowRect(hwnd, &rc);
OffsetRect(&rc, -rc.left, -rc.top);
DrawBorder(hdc, &rc, borderType, GetBorderPen());
}
}
void SkinnedWnd::OnNcPaint(HRGN rgnUpdate)
{
UINT borderType = GetBorderType();
if (BORDER_NONE == borderType) return;
UINT flags = DCX_PARENTCLIP | DCX_CACHE | DCX_WINDOW | DCX_CLIPSIBLINGS |
DCX_INTERSECTUPDATE | DCX_VALIDATE;
HDC hdc = GetDCEx(hwnd, ((HRGN)NULLREGION != rgnUpdate) ? rgnUpdate : NULL, flags);
if (NULL == hdc) return;
DrawBorder(hdc);
ReleaseDC(hwnd, hdc);
}
INT SkinnedWnd::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS *pncsp)
{
UINT borderType = GetBorderType();
switch(borderType)
{
case BORDER_SUNKEN:
case BORDER_FLAT:
if (bCalcValidRects)
{
SetRect(&pncsp->rgrc[0],
pncsp->lppos->x, pncsp->lppos->y,
pncsp->lppos->x + pncsp->lppos->cx - BORDER_WIDTH, pncsp->lppos->y + pncsp->lppos->cy - BORDER_WIDTH);
}
else
{
GetWindowRect(hwnd, &pncsp->rgrc[0]);
pncsp->rgrc[0].right -= BORDER_WIDTH;
pncsp->rgrc[0].bottom -= BORDER_WIDTH;
}
if (BORDER_FLAT == borderType)
{
pncsp->rgrc[0].left += BORDER_WIDTH;
pncsp->rgrc[0].top += BORDER_WIDTH;
}
break;
}
return 0;
}
void SkinnedWnd::OnPrint(HDC hdc, UINT options)
{
if ((PRF_CHECKVISIBLE & options) && !IsWindowVisible(hwnd)) return;
if (PRF_NONCLIENT & options) DrawBorder(hdc);
if (PRF_CLIENT & options)
{
CallPrevWndProc(WM_PRINT, (WPARAM)hdc, (LPARAM)(~(PRF_NONCLIENT | PRF_CHECKVISIBLE) & options));
}
}
HPEN SkinnedWnd::GetBorderPen(void)
{
return (HPEN)MlStockObjects_Get(HILITE_PEN);
}
void SkinnedWnd::OnUpdateUIState(UINT uAction, UINT uState)
{
CallPrevWndProc(WM_UPDATEUISTATE, MAKEWPARAM(uAction, uState), 0L);
uiState =(WORD)SendMessageW(hwnd, WM_QUERYUISTATE, 0, 0L);
}
void SkinnedWnd::OnStyleChanged(INT styleType, STYLESTRUCT *pss)
{
if (0 != redrawLock)
{
if (0 != (GWL_STYLE & styleType) &&
(WS_VISIBLE & pss->styleOld) != (WS_VISIBLE & pss->styleNew))
{
redrawLock = 0;
}
}
CallPrevWndProc(WM_STYLECHANGED, (WPARAM)styleType, (LPARAM)pss);
}
void SkinnedWnd::OnDwmCompositionChanged(void)
{
dwmCompositionEnabled = DWM_COMPOSITION_CHECK;
}
void SkinnedWnd::DisableRedraw()
{
if (0 == redrawLock)
{
UINT windowStyle = (UINT)GetWindowLongPtrW(hwnd, GWL_STYLE);
if (0 == (WS_VISIBLE & windowStyle))
return;
CallDefWndProc(WM_SETREDRAW, FALSE, 0L);
}
redrawLock++;
}
void SkinnedWnd::EnableRedraw(SkinnedWndRedraw redrawFlags)
{
UINT rdwFlags(0);
if (0 == redrawLock)
return;
redrawLock--;
if (0 != redrawLock)
return;
CallDefWndProc(WM_SETREDRAW, TRUE, 0L);
if (0 != (SWR_INVALIDATE & redrawFlags))
{
rdwFlags |= RDW_INVALIDATE;
if (0 != (SWR_UPDATE & redrawFlags))
rdwFlags |= RDW_UPDATENOW;
}
if (0 != (SWR_ERASE & redrawFlags))
{
rdwFlags |= RDW_ERASE;
if (0 != (SWR_UPDATE & redrawFlags))
rdwFlags |= RDW_ERASENOW;
}
if (0 != rdwFlags)
{
if (0 != (SWR_ALLCHILDREN & redrawFlags))
rdwFlags |= RDW_ALLCHILDREN;
RedrawWindow(hwnd, NULL, NULL, rdwFlags);
}
}
BOOL SkinnedWnd::OnDirectMouseWheel(INT delta, UINT vtKey, POINTS pts)
{
SendMessageW(hwnd, WM_MOUSEWHEEL, MAKEWPARAM(vtKey, delta), *((LPARAM*)&pts));
return TRUE;
}
void SkinnedWnd::OnGetMinMaxInfo(MINMAXINFO *minMax)
{
if (NULL == minMax)
return;
CallPrevWndProc(WM_GETMINMAXINFO, 0, (LPARAM)minMax);
if (0 != minSize.cx)
minMax->ptMinTrackSize.x = minSize.cx;
if (0 != minSize.cy)
minMax->ptMinTrackSize.y = minSize.cy;
if (0 != maxSize.cx)
minMax->ptMaxTrackSize.x = maxSize.cx;
if (0 != maxSize.cy)
minMax->ptMaxTrackSize.y = maxSize.cy;
}
LRESULT SkinnedWnd::WindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_NCHITTEST: return OnNcHitTest(MAKEPOINTS(lParam));
case WM_NCPAINT: OnNcPaint((HRGN)wParam); return 0;
case WM_NCCALCSIZE: return OnNcCalcSize((BOOL)wParam, (NCCALCSIZE_PARAMS*)lParam);
case WM_PRINT: OnPrint((HDC)wParam, (UINT)lParam); return 0;
case WM_UPDATEUISTATE: OnUpdateUIState(LOWORD(wParam), HIWORD(wParam)); return 0;
case WM_STYLECHANGED: OnStyleChanged((INT)wParam, (STYLESTRUCT*)lParam); return 0;
case WM_SUPPORTREFLECT:
{
BOOL reflectionSupported = (0 != (SWS_REFLECT & wnddata) && CanReflect((UINT)wParam));
if (0 != (SWS_DIALOG & wnddata))
{
SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, reflectionSupported);
return TRUE;
}
return reflectionSupported;
}
case WM_ML_IPC:
{
LRESULT result;
if (OnMediaLibraryIPC((INT)lParam, (INT_PTR)wParam, &result))
{
if (SWS_DIALOG & wnddata)
{
SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, (LONGX86)result);
return TRUE;
}
return result;
}
break;
}
case WM_DWMCOMPOSITIONCHANGED: OnDwmCompositionChanged(); return 0;
case WM_GETMINMAXINFO: OnGetMinMaxInfo((MINMAXINFO*)lParam); return 0;
}
// Reflection
if (0 != (SWS_REFLECT & wnddata))
{
LRESULT result;
if (ReflectMessage(hwnd, uMsg, wParam, lParam, (0 != (SWS_DIALOG & wnddata)), &result))
return result;
}
if ( 0 == (SWS_NO_DIRECT_MOUSE_WHEEL & style) &&
WINAMP_WM_DIRECT_MOUSE_WHEEL == uMsg &&
WM_NULL != WINAMP_WM_DIRECT_MOUSE_WHEEL &&
FALSE != OnDirectMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam), GET_KEYSTATE_WPARAM(wParam), MAKEPOINTS(lParam)))
{
if (0 != (SWS_DIALOG & wnddata))
SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, TRUE);
return TRUE;
}
return CallPrevWndProc(uMsg, wParam, lParam);
}
LRESULT WINAPI SkinnedWnd::WindowProcReal(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
SkinnedWnd *pWnd = (SkinnedWnd*)GetPropW(hwnd, WNDDATAPROPW);
if (!pWnd)
return (IsWindowUnicode(hwnd)) ? DefWindowProcW(hwnd, uMsg, wParam, lParam) : DefWindowProcA(hwnd, uMsg, wParam, lParam);
switch(uMsg)
{
case WM_NCDESTROY:
{
WNDPROC fnWndProc = pWnd->fnWndProc;
delete(pWnd);
return IsWindowUnicode(hwnd) ? CallWindowProcW(fnWndProc, hwnd, uMsg, wParam, lParam) : CallWindowProcA(fnWndProc, hwnd, uMsg, wParam, lParam);
}
break;
}
return pWnd->WindowProc(uMsg, wParam, lParam);
}