winamp/Src/Plugins/Library/ml_devices/widgetHost.cpp
2024-09-24 14:54:57 +02:00

391 lines
9.4 KiB
C++

#include "main.h"
#include "./widgetHost.h"
#define WIDGETHOST_WINDOW_CLASS L"NullsoftDevicesWidgetHost"
#define WIDGETHOST_WIDGET_ID 1000
typedef
enum WidgetHostState
{
WIDGETHOST_STATE_FROZEN_UI = (1 << 0),
} WidgetHostState;
DEFINE_ENUM_FLAG_OPERATORS(WidgetHostState);
typedef struct WidgetHost
{
WidgetHostState state;
WidgetStyle widgetStyle;
HFONT font;
HRGN updateRegion;
POINT updateOffset;
} WidgetHost;
typedef struct WidgetHostCreateParam
{
WidgetCreateProc widgetCreate;
void *widgetCreateParam;
} WidgetHostCreateParam;
#define WIDGETHOST(_hwnd) ((WidgetHost*)(LONGX86)GetWindowLongPtrW((_hwnd), 0))
#define WIDGETHOST_RET_VOID(_self, _hwnd) {(_self) = WIDGETHOST((_hwnd)); if (NULL == (_self)) return;}
#define WIDGETHOST_RET_VAL(_self, _hwnd, _error) {(_self) = WIDGETHOST((_hwnd)); if (NULL == (_self)) return (_error);}
#define WIDGETHOST_WIDGET(_hostWindow) (GetDlgItem((_hostWindow), WIDGETHOST_WIDGET_ID))
#define WIDGETHOST_IS_FROZEN(_self) (0 != (WIDGETHOST_STATE_FROZEN_UI & (_self)->state))
#define WIDGETHOST_FREEZE(_self) (((_self)->state) |= WIDGETHOST_STATE_FROZEN_UI)
#define WIDGETHOST_THAW(_self) (((_self)->state) &= ~WIDGETHOST_STATE_FROZEN_UI)
static LRESULT CALLBACK
WidgetHost_WindowProc(HWND hwnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam);
static ATOM
WidgetHost_GetClassAtom(HINSTANCE instance)
{
WNDCLASSEXW klass;
ATOM klassAtom;
klassAtom = (ATOM)GetClassInfoExW(instance, WIDGETHOST_WINDOW_CLASS, &klass);
if (0 != klassAtom)
return klassAtom;
memset(&klass, 0, sizeof(klass));
klass.cbSize = sizeof(klass);
klass.style = CS_DBLCLKS;
klass.lpfnWndProc = WidgetHost_WindowProc;
klass.cbClsExtra = 0;
klass.cbWndExtra = sizeof(WidgetHost*);
klass.hInstance = instance;
klass.hIcon = NULL;
klass.hCursor = LoadCursorW(NULL, (LPCWSTR)IDC_ARROW);
klass.hbrBackground = NULL;
klass.lpszMenuName = NULL;
klass.lpszClassName = WIDGETHOST_WINDOW_CLASS;
klass.hIconSm = NULL;
klassAtom = RegisterClassExW(&klass);
return klassAtom;
}
HWND
WidgetHost_Create(unsigned int windowStyle, int x, int y, int width, int height,
HWND parentWindow, WidgetCreateProc createProc, void *createParam)
{
HINSTANCE instance;
ATOM klassAtom;
HWND hwnd;
WidgetHostCreateParam hostParam;
if (NULL == createProc)
return NULL;
instance = GetModuleHandleW(NULL);
klassAtom = WidgetHost_GetClassAtom(instance);
if (0 == klassAtom)
return NULL;
hostParam.widgetCreate = createProc;
hostParam.widgetCreateParam = createParam;
hwnd = CreateWindowExW(WS_EX_NOPARENTNOTIFY |WS_EX_CONTROLPARENT,
(LPCWSTR)MAKEINTATOM(klassAtom), NULL,
WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | windowStyle,
x, y, width, height,
parentWindow, NULL, instance, &hostParam);
return hwnd;
}
static void
WidgetHost_Layout(HWND hwnd, BOOL redraw)
{
WidgetHost *self;
RECT rect;
WIDGETHOST_RET_VOID(self, hwnd);
if (FALSE == GetClientRect(hwnd, &rect))
return;
HWND widgetWindow = WIDGETHOST_WIDGET(hwnd);
if (NULL != widgetWindow)
{
unsigned int flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER;
if (FALSE == redraw)
flags |= SWP_NOREDRAW;
SetWindowPos(widgetWindow, NULL, 0, 0, RECTWIDTH(rect), RECTHEIGHT(rect), flags);
}
}
static void
WidgetHost_Paint(HWND hwnd, HDC hdc, const RECT *paintRect, BOOL erase)
{
if (FALSE != erase)
{
COLORREF backColor, prevBackColor;
backColor = Graphics_GetSkinColor(WADLG_WNDBG);
prevBackColor = SetBkColor(hdc, backColor);
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, paintRect, NULL, 0, NULL);
SetBkColor(hdc, prevBackColor);
}
}
static void
WidgetHost_UpdateSkin(HWND hwnd)
{
WidgetHost *self;
WIDGETHOST_RET_VOID(self, hwnd);
BOOL styleChanged = FALSE;
if (FALSE != WidgetStyle_UpdateDefaultColors(&self->widgetStyle))
styleChanged = TRUE;
if (FALSE != styleChanged)
{
HWND widgetWindow = WIDGETHOST_WIDGET(hwnd);
if (NULL != widgetWindow)
{
WIDGET_STYLE_COLOR_CHANGED(widgetWindow);
InvalidateRect(widgetWindow, NULL, TRUE);
}
}
}
static void
WidgetHost_UpdateFont(HWND hwnd, BOOL redraw)
{
WidgetHost *self;
BOOL styleChanged = FALSE;
long unitWidth, unitHeight;
WIDGETHOST_RET_VOID(self, hwnd);
if (FALSE == Graphics_GetWindowBaseUnits(hwnd, &unitWidth, &unitHeight))
{
unitWidth = 6;
unitHeight = 13;
}
if (FALSE != WidgetStyle_UpdateDefaultFonts(&self->widgetStyle, self->font, unitWidth, unitHeight))
styleChanged = TRUE;
if (FALSE != styleChanged)
{
HWND widgetWindow = WIDGETHOST_WIDGET(hwnd);
if (NULL != widgetWindow)
{
WIDGET_STYLE_COLOR_CHANGED(widgetWindow);
InvalidateRect(widgetWindow, NULL, TRUE);
}
}
}
static LRESULT
WidgetHost_OnCreate(HWND hwnd, CREATESTRUCT *createStruct)
{
WidgetHost *self;
HWND widgetWindow;
WidgetHostCreateParam *createParam;
if (NULL == createStruct)
return -1;
createParam = (WidgetHostCreateParam*)createStruct->lpCreateParams;
if (NULL == createParam)
return -1;
self = (WidgetHost*)malloc(sizeof(WidgetHost));
if (NULL == self)
return -1;
SetLastError(ERROR_SUCCESS);
if (!SetWindowLongPtr(hwnd, 0, (LONGX86)self) && ERROR_SUCCESS != GetLastError())
return -1;
memset(self, 0, sizeof(WidgetHost));
WIDGETHOST_FREEZE(self);
MLSkinWindow2(Plugin_GetLibraryWindow(), hwnd, SKINNEDWND_TYPE_WINDOW,
SWS_USESKINFONT | SWS_USESKINCOLORS | SWS_USESKINCURSORS);
WidgetHost_UpdateFont(hwnd, FALSE);
WidgetHost_UpdateSkin(hwnd);
widgetWindow = NULL;
if (NULL != createParam->widgetCreate)
widgetWindow = createParam->widgetCreate(hwnd, createParam->widgetCreateParam);
if (NULL == widgetWindow)
return -1;
SetWindowLongPtrW(widgetWindow, GWLP_ID, WIDGETHOST_WIDGET_ID);
WIDGET_SET_STYLE(widgetWindow, &self->widgetStyle);
SetWindowPos(widgetWindow, NULL, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW | SWP_FRAMECHANGED);
ShowWindow(widgetWindow, SW_SHOWNA);
SetWindowPos(widgetWindow, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
WIDGETHOST_THAW(self);
SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
return 0;
}
static void
WidgetHost_OnDestroy(HWND hwnd)
{
WidgetHost *self;
self = WIDGETHOST(hwnd);
SetWindowLongPtr(hwnd, 0, 0);
if (NULL == self)
return;
WIDGETHOST_FREEZE(self);
WidgetStyle_Free(&self->widgetStyle);
free(self);
}
static void
WidgetHost_OnPaint(HWND hwnd)
{
PAINTSTRUCT ps;
if (NULL != BeginPaint(hwnd, &ps))
{
WidgetHost_Paint(hwnd, ps.hdc, &ps.rcPaint, ps.fErase);
EndPaint(hwnd, &ps);
}
}
static void
WidgetHost_OnPrintClient(HWND hwnd, HDC hdc, UINT options)
{
RECT clientRect;
if (GetClientRect(hwnd, &clientRect))
{
WidgetHost_Paint(hwnd, hdc, &clientRect, TRUE);
}
}
static void
WidgetHost_OnWindowPosChanged(HWND hwnd, WINDOWPOS *windowPos)
{
if ((SWP_NOSIZE | SWP_NOMOVE) != ((SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED) & windowPos->flags))
{
WidgetHost *self;
WIDGETHOST_RET_VOID(self, hwnd);
if (FALSE != WIDGETHOST_IS_FROZEN(self))
return;
WidgetHost_Layout(hwnd, 0 == (SWP_NOREDRAW & windowPos->flags));
}
}
static void
WidgetHost_OnDisplayChanged(HWND hwnd, INT bpp, INT dpi_x, INT dpi_y)
{
WidgetHost *self;
WIDGETHOST_RET_VOID(self, hwnd);
if (FALSE != WIDGETHOST_IS_FROZEN(self))
return;
WidgetHost_UpdateSkin(hwnd);
InvalidateRect(hwnd, NULL, TRUE);
}
static void
WidgetHost_OnSetFont(HWND hwnd, HFONT font, BOOL redraw)
{
WidgetHost *self;
LOGFONTW prevFont, newFont;
WIDGETHOST_RET_VOID(self, hwnd);
if (NULL == self->font ||
sizeof(LOGFONTW) != GetObjectW(self->font, sizeof(prevFont), &prevFont))
{
ZeroMemory(&prevFont, sizeof(prevFont));
}
self->font = font;
if (NULL == self->font ||
sizeof(newFont) != GetObjectW(self->font, sizeof(newFont), &newFont))
{
ZeroMemory(&newFont, sizeof(newFont));
}
if (0 != memcmp(&prevFont, &newFont, sizeof(prevFont)) &&
FALSE == WIDGETHOST_IS_FROZEN(self))
{
WidgetHost_UpdateFont(hwnd, redraw);
}
}
static HFONT
WidgetHost_OnGetFont(HWND hwnd)
{
WidgetHost *self;
WIDGETHOST_RET_VAL(self, hwnd, NULL);
return self->font;
}
static void
WidgetHost_OnSetUpdateRegion(HWND hwnd, HRGN updateRegion, POINTS regionOffset)
{
WidgetHost *self;
WIDGETHOST_RET_VOID(self, hwnd);
self->updateRegion = updateRegion;
self->updateOffset.x = regionOffset.x;
self->updateOffset.y = regionOffset.y;
}
static LRESULT CALLBACK
WidgetHost_WindowProc(HWND hwnd, unsigned int uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_CREATE: return WidgetHost_OnCreate(hwnd, (CREATESTRUCT*)lParam);
case WM_DESTROY: WidgetHost_OnDestroy(hwnd); return 0;
case WM_PAINT: WidgetHost_OnPaint(hwnd); return 0;
case WM_PRINTCLIENT: WidgetHost_OnPrintClient(hwnd, (HDC)wParam, (UINT)lParam); return 0;
case WM_PRINT: return 0;
case WM_ERASEBKGND: return 0;
case WM_WINDOWPOSCHANGED: WidgetHost_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return 0;
case WM_SIZE: return 0;
case WM_MOVE: return 0;
case WM_DISPLAYCHANGE: WidgetHost_OnDisplayChanged(hwnd, (INT)wParam, LOWORD(lParam), HIWORD(lParam)); return 0;
case WM_SETFONT: WidgetHost_OnSetFont(hwnd, (HFONT)wParam, LOWORD(lParam)); return 0;
case WM_GETFONT: return (LRESULT)WidgetHost_OnGetFont(hwnd);
// gen_ml flickerless drawing
case WM_USER + 0x200: return 1;
case WM_USER + 0x201: WidgetHost_OnSetUpdateRegion(hwnd, (HRGN)lParam, MAKEPOINTS(wParam)); return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}