mirror of
https://gitea.nishi.boats/pyrite-dev/milsko
synced 2026-01-15 22:03:29 +00:00
778 lines
19 KiB
C
778 lines
19 KiB
C
#include <Mw/Milsko.h>
|
|
|
|
typedef struct userdata {
|
|
MwLL ll;
|
|
POINT min;
|
|
POINT max;
|
|
int min_set;
|
|
int max_set;
|
|
} userdata_t;
|
|
|
|
static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
|
|
userdata_t* u = (userdata_t*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
|
|
if(u == NULL) return DefWindowProc(hWnd, msg, wp, lp);
|
|
|
|
if(msg == WM_PAINT) {
|
|
PAINTSTRUCT ps;
|
|
RECT rc;
|
|
HBITMAP hbmp;
|
|
HDC dc, hbdc;
|
|
|
|
u->ll->gdi.force_render = 0;
|
|
|
|
if(u->ll->common.copy_buffer) {
|
|
GetClientRect(hWnd, &rc);
|
|
|
|
dc = GetDC(hWnd);
|
|
hbmp = CreateCompatibleBitmap(dc, rc.right - rc.left, rc.bottom - rc.top);
|
|
hbdc = CreateCompatibleDC(dc);
|
|
SelectObject(hbdc, hbmp);
|
|
ReleaseDC(hWnd, dc);
|
|
|
|
u->ll->gdi.hDC = hbdc;
|
|
MwLLDispatch(u->ll, draw, NULL);
|
|
|
|
dc = BeginPaint(hWnd, &ps);
|
|
StretchBlt(dc, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hbdc, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SRCCOPY);
|
|
EndPaint(hWnd, &ps);
|
|
|
|
DeleteDC(hbdc);
|
|
DeleteObject(hbmp);
|
|
} else {
|
|
u->ll->gdi.hDC = BeginPaint(hWnd, &ps);
|
|
MwLLDispatch(u->ll, draw, NULL);
|
|
EndPaint(hWnd, &ps);
|
|
}
|
|
} else if(msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN || msg == WM_RBUTTONDOWN) {
|
|
MwLLMouse p;
|
|
p.point.x = LOWORD(lp);
|
|
p.point.y = HIWORD(lp);
|
|
if(msg == WM_LBUTTONDOWN) {
|
|
p.button = MwLLMouseLeft;
|
|
} else if(msg == WM_MBUTTONDOWN) {
|
|
p.button = MwLLMouseMiddle;
|
|
} else if(msg == WM_RBUTTONDOWN) {
|
|
p.button = MwLLMouseRight;
|
|
}
|
|
|
|
SetCapture(hWnd);
|
|
SetFocus(hWnd);
|
|
MwLLDispatch(u->ll, down, &p);
|
|
} else if(msg == WM_LBUTTONUP || msg == WM_MBUTTONUP || msg == WM_RBUTTONUP) {
|
|
MwLLMouse p;
|
|
p.point.x = LOWORD(lp);
|
|
p.point.y = HIWORD(lp);
|
|
if(msg == WM_LBUTTONUP) {
|
|
p.button = MwLLMouseLeft;
|
|
} else if(msg == WM_MBUTTONUP) {
|
|
p.button = MwLLMouseMiddle;
|
|
} else if(msg == WM_RBUTTONUP) {
|
|
p.button = MwLLMouseRight;
|
|
}
|
|
|
|
SetCapture(NULL);
|
|
MwLLDispatch(u->ll, up, &p);
|
|
} else if(msg == WM_MOUSEWHEEL) {
|
|
int d = GET_WHEEL_DELTA_WPARAM(wp);
|
|
MwLLMouse p;
|
|
p.point.x = LOWORD(lp);
|
|
p.point.y = HIWORD(lp);
|
|
|
|
if(d > 0) {
|
|
p.button = MwLLMouseWheelUp;
|
|
} else if(d < 0) {
|
|
p.button = MwLLMouseWheelDown;
|
|
}
|
|
|
|
MwLLDispatch(u->ll, down, &p);
|
|
MwLLDispatch(u->ll, up, &p);
|
|
} else if(msg == WM_MOUSEMOVE) {
|
|
MwPoint p;
|
|
p.x = LOWORD(lp);
|
|
p.y = HIWORD(lp);
|
|
|
|
if(u->ll->gdi.grabbed) {
|
|
RECT rc;
|
|
|
|
GetClientRect(hWnd, &rc);
|
|
p.x -= (rc.right - rc.left) / 2;
|
|
p.y -= (rc.bottom - rc.top) / 2;
|
|
}
|
|
|
|
MwLLDispatch(u->ll, move, &p);
|
|
|
|
if(u->ll->gdi.grabbed && (p.x != 0 || p.y != 0)) {
|
|
RECT rc;
|
|
POINT p;
|
|
|
|
GetClientRect(hWnd, &rc);
|
|
|
|
p.x = (rc.right - rc.left) / 2;
|
|
p.y = (rc.bottom - rc.top) / 2;
|
|
|
|
MapWindowPoints(hWnd, HWND_DESKTOP, &p, 1);
|
|
|
|
SetCursorPos(p.x, p.y);
|
|
}
|
|
} else if(msg == WM_SIZE) {
|
|
MwLLDispatch(u->ll, resize, NULL);
|
|
} else if(msg == WM_ERASEBKGND) {
|
|
return 1;
|
|
} else if(msg == WM_NCHITTEST) {
|
|
LPARAM style = GetWindowLongPtr(hWnd, GWL_STYLE);
|
|
if(style & WS_CHILD) return HTCLIENT;
|
|
return DefWindowProc(hWnd, msg, wp, lp);
|
|
} else if(msg == WM_DESTROY) {
|
|
PostQuitMessage(0);
|
|
} else if(msg == WM_CLOSE) {
|
|
MwLLDispatch(u->ll, close, NULL);
|
|
} else if(msg == WM_CHAR || msg == WM_SYSCHAR) {
|
|
int n = wp;
|
|
const int base = 'A' - 1;
|
|
|
|
if(n != 0x1b && n <= 0x1f) {
|
|
n = (n + base) | MwLLControlMask;
|
|
if(!(GetKeyState(VK_LSHIFT) || GetKeyState(VK_RSHIFT))) n += 0x20;
|
|
}
|
|
if(HIBYTE(VkKeyScan(wp)) & 2) n |= MwLLControlMask;
|
|
if(msg == WM_SYSCHAR) n |= MwLLAltMask;
|
|
|
|
if((0x20 <= n && n <= 0x7f) || (n & MwLLKeyMask)) MwLLDispatch(u->ll, key, &n);
|
|
} else if(msg == WM_SETFOCUS) {
|
|
MwLLDispatch(u->ll, focus_in, NULL);
|
|
} else if(msg == WM_KILLFOCUS) {
|
|
MwLLDispatch(u->ll, focus_out, NULL);
|
|
} else if(msg == WM_KEYDOWN || msg == WM_KEYUP || msg == WM_SYSKEYDOWN || msg == WM_SYSKEYUP) {
|
|
int n = -1;
|
|
if(wp == VK_MENU && msg == WM_KEYUP) return 0;
|
|
if(wp == VK_LEFT) n = MwLLKeyLeft;
|
|
if(wp == VK_RIGHT) n = MwLLKeyRight;
|
|
if(wp == VK_UP) n = MwLLKeyUp;
|
|
if(wp == VK_DOWN) n = MwLLKeyDown;
|
|
if(wp == VK_RETURN) n = MwLLKeyEnter;
|
|
if(wp == VK_BACK) n = MwLLKeyBackSpace;
|
|
if(wp == VK_ESCAPE) n = MwLLKeyEscape;
|
|
if(wp == VK_LSHIFT) n = MwLLKeyLeftShift;
|
|
if(wp == VK_RSHIFT) n = MwLLKeyRightShift;
|
|
if(wp == VK_MENU) n = MwLLKeyAlt;
|
|
if(wp == VK_CONTROL) n = MwLLKeyControl;
|
|
|
|
if((msg == WM_SYSKEYDOWN || msg == WM_SYSKEYUP) && n != -1 && wp != VK_MENU) {
|
|
n |= MwLLAltMask;
|
|
}
|
|
if(n != -1) {
|
|
if(msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN) {
|
|
MwLLDispatch(u->ll, key, &n);
|
|
} else {
|
|
MwLLDispatch(u->ll, key_released, &n);
|
|
}
|
|
}
|
|
} else if(msg == WM_GETMINMAXINFO) {
|
|
if(u->min_set || u->max_set) {
|
|
LPARAM style = GetWindowLongPtr(hWnd, GWL_STYLE);
|
|
MINMAXINFO* mmi = (MINMAXINFO*)lp;
|
|
if(u->min_set) {
|
|
RECT rc;
|
|
|
|
rc.left = 0;
|
|
rc.top = 0;
|
|
rc.right = u->min.x;
|
|
rc.bottom = u->min.y;
|
|
AdjustWindowRect(&rc, style, FALSE);
|
|
|
|
mmi->ptMinTrackSize.x = rc.right - rc.left;
|
|
mmi->ptMinTrackSize.y = rc.bottom - rc.top;
|
|
}
|
|
if(u->max_set) {
|
|
RECT rc;
|
|
|
|
rc.left = 0;
|
|
rc.top = 0;
|
|
rc.right = u->min.x;
|
|
rc.bottom = u->min.y;
|
|
AdjustWindowRect(&rc, style, FALSE);
|
|
|
|
mmi->ptMaxTrackSize.x = rc.right - rc.left;
|
|
mmi->ptMaxTrackSize.y = rc.bottom - rc.top;
|
|
}
|
|
} else {
|
|
return DefWindowProc(hWnd, msg, wp, lp);
|
|
}
|
|
} else if(msg == WM_SETCURSOR) {
|
|
if(LOWORD(lp) != HTCLIENT) return DefWindowProc(hWnd, msg, wp, lp);
|
|
if(u->ll->gdi.cursor != NULL) SetCursor(u->ll->gdi.cursor);
|
|
} else if(msg == WM_USER) {
|
|
InvalidateRect(hWnd, NULL, FALSE);
|
|
UpdateWindow(hWnd);
|
|
} else {
|
|
return DefWindowProc(hWnd, msg, wp, lp);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) {
|
|
MwLL r = malloc(sizeof(*r));
|
|
userdata_t* u = malloc(sizeof(*u));
|
|
WNDCLASSEX wc;
|
|
|
|
memset(&wc, 0, sizeof(wc));
|
|
wc.cbSize = sizeof(WNDCLASSEX);
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
wc.lpfnWndProc = wndproc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = (HINSTANCE)GetModuleHandle(NULL);
|
|
wc.lpszClassName = "milsko";
|
|
wc.lpszMenuName = NULL;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = GetSysColorBrush(COLOR_MENU);
|
|
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
|
|
wc.hIconSm = NULL;
|
|
|
|
MwLLCreateCommon(r);
|
|
|
|
RegisterClassEx(&wc);
|
|
|
|
r->common.copy_buffer = 1;
|
|
r->common.type = MwLLBackendGDI;
|
|
|
|
r->gdi.get_clipboard = 1;
|
|
r->gdi.force_render = 0;
|
|
r->gdi.grabbed = 0;
|
|
r->gdi.hWnd = CreateWindow("milsko", "Milsko", parent == NULL ? (WS_OVERLAPPEDWINDOW) : (WS_CHILD | WS_VISIBLE), x == MwDEFAULT ? CW_USEDEFAULT : x, y == MwDEFAULT ? CW_USEDEFAULT : y, width, height, parent == NULL ? NULL : parent->gdi.hWnd, 0, wc.hInstance, NULL);
|
|
r->gdi.hInstance = wc.hInstance;
|
|
r->gdi.cursor = NULL;
|
|
r->gdi.icon = NULL;
|
|
|
|
u->ll = r;
|
|
u->min_set = 0;
|
|
u->max_set = 0;
|
|
SetWindowLongPtr(r->gdi.hWnd, GWLP_USERDATA, (LPARAM)u);
|
|
|
|
if(parent == NULL) {
|
|
RECT rc;
|
|
|
|
rc.left = 0;
|
|
rc.top = 0;
|
|
rc.right = width;
|
|
rc.bottom = height;
|
|
AdjustWindowRect(&rc, GetWindowLongPtr(r->gdi.hWnd, GWL_STYLE), FALSE);
|
|
SetWindowPos(r->gdi.hWnd, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, SWP_NOMOVE);
|
|
|
|
ShowWindow(r->gdi.hWnd, SW_NORMAL);
|
|
UpdateWindow(r->gdi.hWnd);
|
|
|
|
InvalidateRect(r->gdi.hWnd, NULL, FALSE);
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
static void MwLLDestroyImpl(MwLL handle) {
|
|
MwLLDestroyCommon(handle);
|
|
|
|
/* for safety */
|
|
SetWindowLongPtr(handle->gdi.hWnd, GWLP_USERDATA, (LPARAM)NULL);
|
|
DestroyWindow(handle->gdi.hWnd);
|
|
|
|
if(handle->gdi.cursor != NULL) DestroyCursor(handle->gdi.cursor);
|
|
|
|
free(handle);
|
|
}
|
|
|
|
static void MwLLBeginDrawImpl(MwLL handle) {
|
|
(void)handle;
|
|
}
|
|
|
|
static void MwLLEndDrawImpl(MwLL handle) {
|
|
(void)handle;
|
|
}
|
|
|
|
static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) {
|
|
POINT* p = malloc(sizeof(*p) * points_count);
|
|
HPEN pen = CreatePen(PS_NULL, 0, RGB(0, 0, 0));
|
|
int i;
|
|
|
|
for(i = 0; i < points_count; i++) {
|
|
p[i].x = points[i].x;
|
|
p[i].y = points[i].y;
|
|
}
|
|
SelectObject(handle->gdi.hDC, color->gdi.brush);
|
|
SelectObject(handle->gdi.hDC, pen);
|
|
SetPolyFillMode(handle->gdi.hDC, ALTERNATE);
|
|
Polygon(handle->gdi.hDC, p, points_count);
|
|
|
|
DeleteObject(pen);
|
|
|
|
free(p);
|
|
}
|
|
|
|
static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) {
|
|
HPEN pen = CreatePen(PS_SOLID, 1, RGB(color->common.red, color->common.green, color->common.blue));
|
|
|
|
SelectObject(handle->gdi.hDC, pen);
|
|
MoveToEx(handle->gdi.hDC, points[0].x, points[0].y, NULL);
|
|
LineTo(handle->gdi.hDC, points[1].x, points[1].y);
|
|
|
|
DeleteObject(pen);
|
|
}
|
|
|
|
static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) {
|
|
MwLLColor c = malloc(sizeof(*c));
|
|
|
|
c->gdi.brush = NULL;
|
|
|
|
MwLLColorUpdate(handle, c, r, g, b);
|
|
|
|
return c;
|
|
}
|
|
|
|
static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) {
|
|
HDC dc = GetDC(handle->gdi.hWnd);
|
|
|
|
if(r > 255) r = 255;
|
|
if(g > 255) g = 255;
|
|
if(b > 255) b = 255;
|
|
if(r < 0) r = 0;
|
|
if(g < 0) g = 0;
|
|
if(b < 0) b = 0;
|
|
|
|
if(c->gdi.brush != NULL) DeleteObject(c->gdi.brush);
|
|
c->gdi.brush = CreateSolidBrush(GetNearestColor(dc, RGB(r, g, b)));
|
|
c->common.red = r;
|
|
c->common.green = g;
|
|
c->common.blue = b;
|
|
|
|
ReleaseDC(handle->gdi.hWnd, dc);
|
|
}
|
|
|
|
static void MwLLFreeColorImpl(MwLLColor color) {
|
|
DeleteObject(color->gdi.brush);
|
|
|
|
free(color);
|
|
}
|
|
|
|
static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) {
|
|
RECT rc;
|
|
|
|
GetClientRect(handle->gdi.hWnd, &rc);
|
|
MapWindowPoints(handle->gdi.hWnd, GetParent(handle->gdi.hWnd), (LPPOINT)&rc, 2);
|
|
|
|
*x = rc.left;
|
|
*y = rc.top;
|
|
*w = rc.right - rc.left;
|
|
*h = rc.bottom - rc.top;
|
|
}
|
|
|
|
static void MwLLSetXYImpl(MwLL handle, int x, int y) {
|
|
SetWindowPos(handle->gdi.hWnd, NULL, x, y, 0, 0, SWP_NOSIZE);
|
|
InvalidateRect(handle->gdi.hWnd, NULL, FALSE);
|
|
}
|
|
|
|
static void MwLLSetWHImpl(MwLL handle, int w, int h) {
|
|
SetWindowPos(handle->gdi.hWnd, NULL, 0, 0, w, h, SWP_NOMOVE);
|
|
InvalidateRect(handle->gdi.hWnd, NULL, FALSE);
|
|
}
|
|
|
|
static void MwLLSetTitleImpl(MwLL handle, const char* title) {
|
|
SetWindowText(handle->gdi.hWnd, title);
|
|
}
|
|
|
|
static int MwLLPendingImpl(MwLL handle) {
|
|
MSG msg;
|
|
|
|
(void)handle;
|
|
|
|
if(handle->gdi.get_clipboard) return 1;
|
|
return PeekMessage(&msg, handle->gdi.hWnd, 0, 0, PM_NOREMOVE) ? 1 : 0;
|
|
}
|
|
|
|
static void MwLLNextEventImpl(MwLL handle) {
|
|
MSG msg;
|
|
|
|
(void)handle;
|
|
|
|
if(handle->gdi.get_clipboard) {
|
|
HGLOBAL hg;
|
|
if(OpenClipboard(handle->gdi.hWnd) != 0 && (hg = GetClipboardData(CF_TEXT)) != NULL) {
|
|
char* txt = malloc(GlobalSize(hg));
|
|
char* clp = GlobalLock(hg);
|
|
|
|
strcpy(txt, clp);
|
|
|
|
GlobalUnlock(hg);
|
|
CloseClipboard();
|
|
|
|
MwLLDispatch(handle, clipboard, txt);
|
|
|
|
free(txt);
|
|
}
|
|
|
|
handle->gdi.get_clipboard = 0;
|
|
}
|
|
while(PeekMessage(&msg, handle->gdi.hWnd, 0, 0, PM_NOREMOVE)) {
|
|
GetMessage(&msg, handle->gdi.hWnd, 0, 0);
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) {
|
|
MwLLPixmap r = malloc(sizeof(*r));
|
|
HDC dc = GetDC(handle->gdi.hWnd);
|
|
BITMAPINFOHEADER bmih;
|
|
|
|
r->common.raw = malloc(width * height * 4);
|
|
memcpy(r->common.raw, data, 4 * width * height);
|
|
|
|
r->common.width = width;
|
|
r->common.height = height;
|
|
|
|
bmih.biSize = sizeof(bmih);
|
|
bmih.biWidth = width;
|
|
bmih.biHeight = -(LONG)height;
|
|
bmih.biPlanes = 1;
|
|
bmih.biBitCount = 32;
|
|
bmih.biCompression = BI_RGB;
|
|
bmih.biSizeImage = 0;
|
|
bmih.biXPelsPerMeter = 0;
|
|
bmih.biYPelsPerMeter = 0;
|
|
bmih.biClrUsed = 0;
|
|
bmih.biClrImportant = 0;
|
|
|
|
r->gdi.hBitmap = CreateDIBSection(dc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, (void**)&r->gdi.quad, NULL, (DWORD)0);
|
|
|
|
r->gdi.hMask = NULL;
|
|
r->gdi.hMask2 = NULL;
|
|
|
|
ReleaseDC(handle->gdi.hWnd, dc);
|
|
|
|
MwLLPixmapUpdate(r);
|
|
|
|
return r;
|
|
}
|
|
|
|
static void MwLLPixmapUpdateImpl(MwLLPixmap r) {
|
|
int y, x;
|
|
int w = (r->common.width + (16 - (r->common.width % 16))) / 8;
|
|
WORD* words;
|
|
WORD* words2;
|
|
|
|
if(16 * (r->common.width / 16) == r->common.width) w -= 2;
|
|
|
|
words = malloc(w * r->common.height);
|
|
words2 = malloc(w * r->common.height);
|
|
memset(words, 0, w * r->common.height);
|
|
memset(words2, 0, w * r->common.height);
|
|
for(y = 0; y < r->common.height; y++) {
|
|
BYTE* l = (BYTE*)&words[y * (w / 2)];
|
|
BYTE* l2 = (BYTE*)&words2[y * (w / 2)];
|
|
for(x = 0; x < r->common.width; x++) {
|
|
RGBQUAD* q = &r->gdi.quad[y * r->common.width + x];
|
|
unsigned char* px = &r->common.raw[(y * r->common.width + x) * 4];
|
|
|
|
q->rgbRed = px[0];
|
|
q->rgbGreen = px[1];
|
|
q->rgbBlue = px[2];
|
|
|
|
if(px[3]) {
|
|
l[x / 8] |= 1 << (7 - (x % 8));
|
|
} else {
|
|
l2[x / 8] |= 1 << (7 - (x % 8));
|
|
}
|
|
}
|
|
}
|
|
|
|
if(r->gdi.hMask != NULL) DeleteObject(r->gdi.hMask);
|
|
if(r->gdi.hMask2 != NULL) DeleteObject(r->gdi.hMask2);
|
|
|
|
r->gdi.hMask = CreateBitmap(r->common.width, r->common.height, 1, 1, words);
|
|
r->gdi.hMask2 = CreateBitmap(r->common.width, r->common.height, 1, 1, words2);
|
|
|
|
free(words);
|
|
free(words2);
|
|
}
|
|
|
|
static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) {
|
|
free(pixmap->common.raw);
|
|
DeleteObject(pixmap->gdi.hMask);
|
|
DeleteObject(pixmap->gdi.hMask2);
|
|
DeleteObject(pixmap->gdi.hBitmap);
|
|
|
|
free(pixmap);
|
|
}
|
|
|
|
static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) {
|
|
HDC hmdc = CreateCompatibleDC(handle->gdi.hDC);
|
|
POINT p[3];
|
|
|
|
p[0].x = rect->x;
|
|
p[0].y = rect->y;
|
|
|
|
p[1].x = rect->x + rect->width;
|
|
p[1].y = rect->y;
|
|
|
|
p[2].x = rect->x;
|
|
p[2].y = rect->y + rect->height;
|
|
|
|
SelectObject(hmdc, pixmap->gdi.hBitmap);
|
|
|
|
SetStretchBltMode(handle->gdi.hDC, HALFTONE);
|
|
PlgBlt(handle->gdi.hDC, p, hmdc, 0, 0, pixmap->common.width, pixmap->common.height, pixmap->gdi.hMask, 0, 0);
|
|
|
|
DeleteDC(hmdc);
|
|
}
|
|
|
|
static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) {
|
|
ICONINFO ii;
|
|
|
|
memset(&ii, 0, sizeof(ii));
|
|
ii.fIcon = TRUE;
|
|
ii.xHotspot = 0;
|
|
ii.yHotspot = 0;
|
|
ii.hbmMask = pixmap->gdi.hMask2;
|
|
ii.hbmColor = pixmap->gdi.hBitmap;
|
|
|
|
if(handle->gdi.icon != NULL) DestroyIcon(handle->gdi.icon);
|
|
handle->gdi.icon = CreateIconIndirect(&ii);
|
|
SendMessage(handle->gdi.hWnd, WM_SETICON, ICON_SMALL, (LPARAM)handle->gdi.icon);
|
|
SendMessage(handle->gdi.hWnd, WM_SETICON, ICON_BIG, (LPARAM)handle->gdi.icon);
|
|
}
|
|
|
|
static void MwLLForceRenderImpl(MwLL handle) {
|
|
if(!handle->gdi.force_render) {
|
|
PostMessage(handle->gdi.hWnd, WM_USER, 0, 0);
|
|
|
|
handle->gdi.force_render = 1;
|
|
}
|
|
}
|
|
|
|
HCURSOR MwLLGDICreateCursor(MwCursor* image, MwCursor* mask) {
|
|
HCURSOR cursor;
|
|
BYTE* dmask = malloc((MwCursorDataHeight / 8) * MwCursorDataHeight);
|
|
BYTE* dimage = malloc((MwCursorDataHeight / 8) * MwCursorDataHeight);
|
|
int y, x, ys, xs;
|
|
|
|
xs = -mask->x + image->x;
|
|
ys = MwCursorDataHeight + mask->y;
|
|
ys = MwCursorDataHeight + image->y - ys;
|
|
|
|
memset(dmask, 0xff, (MwCursorDataHeight / 8) * MwCursorDataHeight);
|
|
memset(dimage, 0, (MwCursorDataHeight / 8) * MwCursorDataHeight);
|
|
|
|
for(y = 0; y < mask->height; y++) {
|
|
BYTE* l = &dmask[y * (MwCursorDataHeight / 8)];
|
|
unsigned int n = mask->data[y];
|
|
for(x = mask->width - 1; x >= 0; x--) {
|
|
l[x / 8] = l[x / 8] >> 1;
|
|
if(!(n & 1)) {
|
|
l[x / 8] |= 1 << 7;
|
|
}
|
|
|
|
n = n >> 1;
|
|
}
|
|
}
|
|
|
|
for(y = 0; y < image->height; y++) {
|
|
BYTE* l = &dimage[(y + ys) * (MwCursorDataHeight / 8)];
|
|
unsigned int n = image->data[y];
|
|
|
|
for(x = image->width - 1; x >= 0; x--) {
|
|
if(n & 1) {
|
|
l[(x + xs) / 8] |= (1 << (7 - ((x + xs) % 8)));
|
|
}
|
|
|
|
n = n >> 1;
|
|
}
|
|
}
|
|
|
|
cursor = CreateCursor(GetModuleHandle(NULL), xs, ys, MwCursorDataHeight, MwCursorDataHeight, dmask, dimage);
|
|
|
|
free(dimage);
|
|
free(dmask);
|
|
|
|
return cursor;
|
|
}
|
|
|
|
static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) {
|
|
HCURSOR cursor = MwLLGDICreateCursor(image, mask);
|
|
|
|
if(handle->gdi.cursor != NULL) DestroyCursor(handle->gdi.cursor);
|
|
if(handle->gdi.icon != NULL) DestroyIcon(handle->gdi.icon);
|
|
handle->gdi.cursor = cursor;
|
|
}
|
|
|
|
static void MwLLDetachImpl(MwLL handle, MwPoint* point) {
|
|
RECT rc, rc2;
|
|
LPARAM lp = GetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE);
|
|
LPARAM lp2 = GetWindowLongPtr(handle->gdi.hWnd, GWL_EXSTYLE);
|
|
|
|
lp &= WS_VISIBLE;
|
|
|
|
GetWindowRect(GetParent(handle->gdi.hWnd), &rc);
|
|
|
|
GetClientRect(handle->gdi.hWnd, &rc2);
|
|
|
|
if(lp2 & WS_EX_TOOLWINDOW) {
|
|
SetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE, (LPARAM)lp);
|
|
} else {
|
|
SetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE, (LPARAM)WS_OVERLAPPEDWINDOW | lp);
|
|
}
|
|
SetParent(handle->gdi.hWnd, NULL);
|
|
|
|
rc.left += point->x;
|
|
rc.top += point->y;
|
|
|
|
AdjustWindowRect(&rc2, GetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE), FALSE);
|
|
rc2.right -= rc2.left;
|
|
rc2.bottom -= rc2.top;
|
|
|
|
SetWindowPos(handle->gdi.hWnd, HWND_TOPMOST, rc.left, rc.top, rc2.right == 0 ? 1 : rc2.right, rc2.bottom == 0 ? 1 : rc2.bottom, SWP_FRAMECHANGED | SWP_NOACTIVATE);
|
|
}
|
|
|
|
static void MwLLShowImpl(MwLL handle, int show) {
|
|
ShowWindow(handle->gdi.hWnd, show ? SW_NORMAL : SW_HIDE);
|
|
if(show) SetFocus(handle->gdi.hWnd);
|
|
}
|
|
|
|
static void MwLLMakePopupImpl(MwLL handle, MwLL parent) {
|
|
(void)handle;
|
|
(void)parent;
|
|
/* TODO */
|
|
}
|
|
|
|
static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) {
|
|
userdata_t* u = (userdata_t*)GetWindowLongPtr(handle->gdi.hWnd, GWLP_USERDATA);
|
|
|
|
u->min_set = u->max_set = 1;
|
|
u->min.x = minx;
|
|
u->min.y = miny;
|
|
u->max.x = maxx;
|
|
u->max.y = maxy;
|
|
}
|
|
|
|
static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) {
|
|
LPARAM lp = GetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE);
|
|
|
|
if(toggle) {
|
|
lp &= ~WS_CAPTION;
|
|
} else {
|
|
lp |= WS_CAPTION;
|
|
}
|
|
|
|
SetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE, lp);
|
|
|
|
SetWindowPos(handle->gdi.hWnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
|
|
}
|
|
|
|
static void MwLLFocusImpl(MwLL handle) {
|
|
SetFocus(handle->gdi.hWnd);
|
|
}
|
|
|
|
static void MwLLGrabPointerImpl(MwLL handle, int toggle) {
|
|
if(toggle) {
|
|
POINT p;
|
|
RECT rc;
|
|
|
|
GetClientRect(handle->gdi.hWnd, &rc);
|
|
|
|
rc.right -= rc.left;
|
|
rc.bottom -= rc.top;
|
|
|
|
p.x = (rc.right - rc.left) / 2;
|
|
p.y = (rc.bottom - rc.top) / 2;
|
|
|
|
MapWindowPoints(handle->gdi.hWnd, HWND_DESKTOP, &p, 1);
|
|
|
|
handle->gdi.grabbed = 1;
|
|
|
|
SetFocus(handle->gdi.hWnd);
|
|
|
|
GetWindowRect(handle->gdi.hWnd, &rc);
|
|
ClipCursor(&rc);
|
|
|
|
SetCursorPos(p.x, p.y);
|
|
} else {
|
|
handle->gdi.grabbed = 0;
|
|
ClipCursor(NULL);
|
|
}
|
|
}
|
|
|
|
static void MwLLSetClipboardImpl(MwLL handle, const char* text) {
|
|
HGLOBAL hg;
|
|
if(OpenClipboard(handle->gdi.hWnd) != 0) {
|
|
char* lock;
|
|
|
|
EmptyClipboard();
|
|
hg = GlobalAlloc(GHND | GMEM_SHARE, strlen(text) + 1);
|
|
|
|
lock = GlobalLock(hg);
|
|
strcpy(lock, text);
|
|
GlobalUnlock(hg);
|
|
|
|
SetClipboardData(CF_TEXT, hg);
|
|
|
|
CloseClipboard();
|
|
}
|
|
}
|
|
|
|
static void MwLLGetClipboardImpl(MwLL handle) {
|
|
handle->gdi.get_clipboard = 1; /* nishi: we do this to make clipboard api work similar to other backends */
|
|
}
|
|
|
|
static void MwLLMakeToolWindowImpl(MwLL handle) {
|
|
LPARAM lp = GetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE) & (WS_VISIBLE | WS_CHILD);
|
|
RECT rc;
|
|
int w, h;
|
|
|
|
SetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE, (LPARAM)lp);
|
|
SetWindowLongPtr(handle->gdi.hWnd, GWL_EXSTYLE, (LPARAM)WS_EX_TOOLWINDOW);
|
|
|
|
GetClientRect(handle->gdi.hWnd, &rc);
|
|
|
|
w = rc.right - rc.left;
|
|
h = rc.bottom - rc.top;
|
|
|
|
SetWindowPos(handle->gdi.hWnd, NULL, 0, 0, w, h, SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER);
|
|
}
|
|
|
|
static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) {
|
|
POINT p;
|
|
|
|
(void)handle;
|
|
|
|
GetCursorPos(&p);
|
|
|
|
point->x = p.x;
|
|
point->y = p.y;
|
|
}
|
|
|
|
static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) {
|
|
RECT rc;
|
|
|
|
(void)handle;
|
|
|
|
GetClientRect(GetDesktopWindow(), &rc);
|
|
|
|
rect->x = rect->y = 0;
|
|
rect->width = rc.right - rc.left;
|
|
rect->height = rc.bottom - rc.top;
|
|
}
|
|
|
|
static void MwLLBeginStateChangeImpl(MwLL handle) {
|
|
(void)handle;
|
|
}
|
|
|
|
static void MwLLEndStateChangeImpl(MwLL handle) {
|
|
(void)handle;
|
|
}
|
|
|
|
static int MwLLGDICallInitImpl(void) {
|
|
/* TODO: check properly */
|
|
return 0;
|
|
}
|
|
|
|
#include "call.c"
|
|
CALL(GDI);
|