
--proc/windows/class: WNDCLASSEX API
--Written by Cosmin Apreutesei. Public Domain.

setfenv(1, require'winapi')
require'winapi.winuser'

--register/unregister

ffi.cdef[[
typedef struct tagWNDCLASSEXW {
	 UINT        cbSize;
	 UINT        _style;
	 WNDPROC     proc;
	 int         cbClsExtra;
	 int         cbWndExtra;
	 HINSTANCE   hInstance;
	 HICON       icon;
	 HCURSOR     cursor;
	 HBRUSH      background;
	 LPCWSTR     lpszMenuName;
	 LPCWSTR     lpszClassName;
	 HICON       small_icon;
} WNDCLASSEXW, *PWNDCLASSEXW,  *NPWNDCLASSEXW,  *LPWNDCLASSEXW;

ATOM RegisterClassExW(const WNDCLASSEXW *);

BOOL UnregisterClassW(
     LPCWSTR lpClassName,
     HINSTANCE hInstance);

]]

CS_VREDRAW = 0x0001
CS_HREDRAW = 0x0002
CS_DBLCLKS = 0x0008
CS_OWNDC = 0x0020
CS_CLASSDC = 0x0040
CS_PARENTDC = 0x0080
CS_NOCLOSE = 0x0200
CS_SAVEBITS = 0x0800
CS_BYTEALIGNCLIENT = 0x1000
CS_BYTEALIGNWINDOW = 0x2000
CS_GLOBALCLASS = 0x4000
CS_IME = 0x00010000
CS_DROPSHADOW = 0x00020000

WNDCLASSEXW = struct{
	ctype = 'WNDCLASSEXW', size = 'cbSize',
	fields = sfields{
		'name', 'lpszClassName', wcs, mbs,
		'style', '_style', flags, pass,
	}
}

function RegisterClass(info)
	assert(info.proc ~= nil, 'proc is required') --or you'll get a crash
	return checknz(C.RegisterClassExW(WNDCLASSEXW(info)))
end

function UnregisterClass(class)
	if not class then return end
	checknz(C.UnregisterClassW(ffi.cast('LPCWSTR', wcs(MAKEINTRESOURCE(class))), nil))
end

--set/get class long

GCL_MENUNAME        = -8
GCL_HBRBACKGROUND   = -10
GCL_HCURSOR         = -12
GCL_HICON           = -14
GCL_HMODULE         = -16
GCL_CBWNDEXTRA      = -18
GCL_CBCLSEXTRA      = -20
GCL_WNDPROC         = -24
GCL_STYLE           = -26
GCW_ATOM            = -32
GCL_HICONSM         = -34

if ffi.abi'64bit' then
	ffi.cdef[[
	LONG_PTR SetClassLongPtrW(HWND hWnd, int nIndex, LONG_PTR dwNewLong);
	LONG_PTR GetClassLongPtrW(HWND hWnd, int nIndex);
	]]
	SetClassLongW = C.SetClassLongPtrW
	GetClassLongW = C.GetClassLongPtrW
else --32bit
	ffi.cdef[[
	LONG SetClassLongW(HWND hWnd, int nIndex, LONG dwNewLong);
	LONG GetClassLongW(HWND hWnd, int nIndex);
	]]
	SetClassLongW = C.SetClassLongW
	GetClassLongW = C.GetClassLongW
end

function SetClassLong(hwnd, GCL, long)
	callnz2(SetClassLongW, hwnd, flags(GCL), ffi.cast('LONG', long))
end

function GetClassLong(hwnd, GCL) return GetClassLongW(hwnd, flags(GCL)) end

-- Get/SetClassLong wrappers (don't look them up in the docs)

function GetClassStyle(hwnd) return tonumber(GetClassLong(hwnd, GCL_STYLE)) end
function SetClassStyle(hwnd, style) SetClassLong(hwnd, GCL_STYLE, flags(style)) end

function GetClassIcon(hwnd) return ptr(ffi.cast('HICON', GetClassLong(hwnd, GCL_HICON))) end
function SetClassIcon(hwnd, icon) SetClassLong(hwnd, GCL_HICON, icon) end

function GetClassSmallIcon(hwnd) return ptr(ffi.cast('HICON', GetClassLong(hwnd, GCL_HICONSM))) end
function SetClassSmallIcon(hwnd, icon) SetClassLong(hwnd, GCL_HICONSM, icon) end

function GetClassCursor(hwnd) return ptr(ffi.cast('HCURSOR', GetClassLong(hwnd, GCL_HCURSOR))) end
function SetClassCursor(hwnd, cursor) SetClassLong(hwnd, GCL_HCURSOR, cursor) end

function GetClassBackground(hwnd) return ptr(ffi.cast('HBRUSH', GetClassLong(hwnd, GCL_HBRBACKGROUND))) end
function SetClassBackground(hwnd, bg) SetClassLong(hwnd, GCL_HBRBACKGROUND, bg) end

--showcase

if not ... then
package.loaded['winapi.windowclasses'] = true --prevent double-loading by winapi.window
require'winapi.color'
require'winapi.cursor'
require'winapi.window' --for DefWindowProc
local class = print(RegisterClass{
	name='MyClass',
	style = bit.bor(CS_HREDRAW, CS_VREDRAW),
	background = COLOR_WINDOW,
	cursor = LoadCursor(IDC_ARROW),
	proc = DefWindowProc,
})
UnregisterClass(class)
end

