391 lines
9.4 KiB
C++
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);
|
||
|
}
|