
;--- handling DC stuff

		.386
if ?FLAT
		.MODEL FLAT, stdcall
else
		.MODEL SMALL, stdcall
endif
		option casemap:none
        option proc:private

		include winbase.inc
		include winuser.inc
        include wingdi.inc
        include duser32.inc
        include macros.inc


?DCITEMS	equ 5

DCCACHEITEM struct
hDC		dd ?
hwnd	dd ?
bUsed	db ?
DCCACHEITEM ends

		.DATA

		public g_dwOldRealizePalette

g_dwOldRealizePalette dd 0
if ?AUTOINIT
g_hxlib	dd 0
endif

g_dccache	DCCACHEITEM ?DCITEMS dup (<0,0>)

g_bInit	db 0

		.CODE

BeginPaint proc public hWnd:HWND, lpPS:ptr PAINTSTRUCT

        invoke GetDC, hWnd
        mov ecx, lpPS
        mov [ecx].PAINTSTRUCT.hdc, eax
        mov [ecx].PAINTSTRUCT.fErase, 1
        push eax
        invoke GetClientRect, hWnd, addr [ecx].PAINTSTRUCT.rcPaint
        pop eax
		mov ecx, hWnd
        .if ([ecx].WNDOBJ.bErase)
        	push eax
        	invoke SendMessage, ecx, WM_ERASEBKGND, eax, 0
            .if (eax)
            	mov ecx, hWnd
                mov [ecx].WNDOBJ.bErase, 0
            .endif
            pop eax
        .endif
		@strace	<"BeginPaint(", hWnd, ", ", lpPS, ")=", eax>
		ret
        align 4
BeginPaint endp

EndPaint proc public hWnd:HWND, lpPS:ptr PAINTSTRUCT
        mov ecx, lpPS
        invoke ReleaseDC, hWnd, [ecx].PAINTSTRUCT.hdc
        mov ecx, hWnd
        mov [ecx].WNDOBJ.bUpdate, 0
		@strace	<"EndPaint(", hWnd, ", ", lpPS, ")=", eax>
		ret
        align 4
EndPaint endp

_ClearDCCache proc public uses ebx
		mov ebx, offset g_dccache
        mov ecx, ?DCITEMS
        .while (ecx)
			.if (([ebx].DCCACHEITEM.hDC) && ([ebx].DCCACHEITEM.bUsed == FALSE))
            	push ecx
                xor eax, eax
                xchg eax, [ebx].DCCACHEITEM.hDC
			    invoke DeleteDC, eax
                pop ecx
            .endif
            add ebx, sizeof DCCACHEITEM
            dec ecx
        .endw
		@strace	<"_ClearDCCache">
        ret
        align 4
_ClearDCCache endp

DeinitDC proc uses ebx 

		invoke _ClearDCCache
if ?AUTOINIT        
        .if (g_hxlib)
        	invoke FreeLibrary, g_hxlib
        .endif
endif        
		@strace	<"DeinitDC">
		ret
        align 4
DeinitDC endp

if ?AUTOINIT

InGraphicsMode proc
		push edx
        mov dx, 3ceh
        in al, dx		;save index register
        mov ah, al
        mov al, 6
        out dx, al
        inc dx
        in al, dx
        xchg ah, al
        dec dx
        out dx, al		;restore index register
        pop edx
        and ah,1
        movzx eax,ah
        ret
	    align 4
InGraphicsMode endp        

InitGfx proc public

        test g_bInit, 2
        jnz @F
       	or  g_bInit, 2
		invoke InGraphicsMode
        .if (!eax)
           	invoke LoadLibrary, CStr("HXGUIHLP")
            mov g_hxlib, eax
        .endif
@@:
        ret
InitGfx endp

endif

InitDC proc public
		invoke GetModuleHandle, CStr("GDI32")
        .if (eax)
		   	invoke GetProcAddress, eax, CStr("pfnRealizePalette")
			.if (eax)
				mov ecx, [eax]
				mov g_dwOldRealizePalette, ecx
				mov [eax], offset UserRealizePalette
			.endif
		.endif
        invoke atexit, offset DeinitDC
		@strace	<"InitDC">
		ret
        align 4
InitDC endp

;--- create a DC for the DC cache

_CreateDC proc

        test g_bInit, 1
        jnz @F
       	or  g_bInit, 1
        invoke InitDC
@@:        
        invoke CreateDCA, CStr("DISPLAY"), 0, 0, 0
		@strace	<"_CreateDC">
		ret
        align 4
_CreateDC endp

SetDCOrgEx proto :DWORD, :DWORD, :DWORD

GetDC proc public uses ebx hWnd:DWORD

		mov ebx, offset g_dccache
        mov ecx, ?DCITEMS
        .while (ecx)
;			@strace	<"GetDC: cache entry ", ebx, " hdc=", [ebx].DCCACHEITEM.hDC, " hwnd=", [ebx].DCCACHEITEM.hwnd>
        	.if (![ebx].DCCACHEITEM.bUsed)
            	mov [ebx].DCCACHEITEM.bUsed, TRUE
ifdef _DEBUG
				sub ecx, ?DCITEMS
                neg ecx
endif
;				@strace	<"GetDC(", hWnd, "): cache entry ", ecx, " used">
                .if (![ebx].DCCACHEITEM.hDC)
                	invoke _CreateDC		;fill the cache
                    .if (!eax)
                    	mov [ebx].DCCACHEITEM.bUsed, FALSE
                        jmp exit
                    .endif
                    mov [ebx].DCCACHEITEM.hDC, eax
                .endif
                mov edx, hWnd
                mov [ebx].DCCACHEITEM.hwnd, edx
                mov eax, [ebx].DCCACHEITEM.hDC
                jmp found
            .endif
            add ebx, sizeof DCCACHEITEM
            dec ecx
        .endw
        invoke _CreateDC
        and eax, eax
        jz exit
found:
		mov ebx, eax
		mov ecx, hWnd
		.if (ecx && ([ecx].WNDOBJ.dwType == USER_TYPE_HWND) && (!([ecx].WNDOBJ.dwStyle & WS_MAXIMIZE)))
			mov eax, [ecx].WNDOBJ.rc.left
			mov edx, [ecx].WNDOBJ.rc.top
		.else
			xor eax, eax
			xor edx, edx
		.endif
		invoke SetDCOrgEx, ebx, eax, edx
        
		invoke SetViewportOrgEx, ebx, 0,0,0
		invoke SetWindowOrgEx, ebx, 0,0,0
        
		mov ecx, hWnd
		.if (ecx)
			mov eax,[ecx].WNDOBJ.pWndClass
			mov eax, [eax].WNDCLASSEX.hbrBackground
		.else
			invoke GetStockObject, WHITE_BRUSH
		.endif
		.if (eax)
			invoke SelectObject, ebx, eax
		.endif
        invoke SetSystemPaletteUse, ebx, SYSPAL_STATIC
        mov eax, ebx
exit:        
		@strace	<"GetDC(", hWnd, ")=", eax>
		ret
        align 4
GetDC endp

;--- there is currently no no-client area in hx's user32 emulation

GetWindowDC proc public hWnd:DWORD

		invoke GetDC, hWnd
		@strace	<"GetWindowDC(", hWnd, ")=", eax>
		ret
        align 4
GetWindowDC endp

ReleaseDC proc public uses ebx hWnd:DWORD, hdc:DWORD

		xor eax, eax
        mov edx, hWnd
        mov ecx, hdc
        and ecx, ecx
        jz exit
        and edx, edx
        jz @F
        cmp [edx].WNDOBJ.dwType, USER_TYPE_HWND
        jnz exit
@@:
		mov eax, ecx
		mov ebx, offset g_dccache
        mov ecx, ?DCITEMS
        .while (ecx)
        	.if (([ebx].DCCACHEITEM.bUsed) && (eax == [ebx].DCCACHEITEM.hDC))
            	mov [ebx].DCCACHEITEM.bUsed, FALSE
                mov [ebx].DCCACHEITEM.hwnd, 0
                @mov eax, 1
                jmp exit
            .endif
            add ebx, sizeof DCCACHEITEM
            dec ecx
        .endw
		invoke DeleteDC, eax
exit:        
		@strace	<"ReleaseDC(", hWnd, ", ", hdc, ")=", eax>
		ret
        align 4
ReleaseDC endp

FillRect proc public hdc:DWORD, prect:ptr RECT, hBrush:DWORD

        invoke SelectObject, hdc, hBrush
        push eax
        mov ecx, prect
        mov edx, [ecx].RECT.right
        sub edx, [ecx].RECT.left
        mov eax, [ecx].RECT.bottom
        sub eax, [ecx].RECT.top
        invoke PatBlt, hdc, [ecx].RECT.left, [ecx].RECT.top, edx, eax, PATCOPY
        pop eax
        invoke SelectObject, hdc, eax
        @mov eax, 1
exit:        
ifdef _DEBUG
		mov ecx, prect
endif
		@strace	<"FillRect(", hdc, ", ", prect, "[", [ecx].RECT.left, " ", [ecx].RECT.top, " ", [ecx].RECT.right, " ", [ecx].RECT.bottom, "], ", hBrush, ")=", eax>
		ret
        align 4
FillRect endp

DrawFocusRect proc public hDC:dword, lpRect:ptr RECT
		xor eax, eax
		@strace	<"DrawFocusRect(", hDC, ", ", lpRect, ")=", eax>
        ret
        align 4
DrawFocusRect endp

TabbedTextOutA proc public hDC:dword, X:dword, Y:dword, lpString:ptr BYTE,
		nCount:DWORD, nTabPositions:DWORD, lpnTabPositions:ptr DWORD, nTabOrigin:DWORD

local	size_:SIZE_

        mov edx, nTabPositions
		.if (edx < 2)
        	push ebx
            push esi
            push edi
            mov edi,X
        	mov ebx,8
        	.if (edx)
				mov ecx, lpnTabPositions
    	    	mov ebx, [ecx]
            .endif
            mov ecx, nCount
            mov esi, lpString
            mov edx, esi
            .while (ecx)
            	lodsb
                .if (al == 9)
                	push ecx
                    mov ecx, esi
                    sub ecx, edx
                    dec ecx
                    push edx
                    push ecx
                    invoke GetTextExtentPoint32A, hDC, edx, ecx, addr size_
                    pop ecx
                    pop edx
			 		invoke TextOutA, hDC, edi, Y, edx, ecx
                    add edi, size_.cx_
                    add edi, 8
                    mov eax, ebx
                    shl eax,3
                    add edi, eax
                    dec eax
                    not eax
                    and edi, eax
                    
                    pop ecx
                    mov edx, esi
                .endif
                dec ecx
            .endw
            mov ecx, esi
            sub ecx, edx
            .if (ecx)
		 		invoke TextOutA, hDC, edi, Y, edx, ecx
            .endif
            pop edi
            pop esi
            pop ebx
        .else
			invoke TextOutA, hDC, X, Y, lpString, nCount
        .endif
		@strace	<"TabbedTextOutA(", hDC, ", ", X, ", ", Y, ", ", lpString, ", ", nCount, ", ", nTabPositions, ", ", lpnTabPositions, ", ", nTabOrigin, ")=", eax>
        ret
        align 4
TabbedTextOutA endp

DrawTextA proc public uses ebx hdc:dword, lpString:ptr BYTE, nCount:dword, lpRect:ptr RECT, uFormat:dword

local	size_:SIZE_

		cmp nCount,-1
        jnz @F
        invoke lstrlen, lpString
        mov nCount, eax
@@:        
        test uFormat, DT_CENTER or DT_VCENTER
        jz @F
        invoke GetTextExtentPoint32A, hdc, lpString, nCount, addr size_
@@:     
		mov ebx, lpRect
        mov edx, [ebx].RECT.left
        test uFormat, DT_CENTER
        jz @F
        mov eax, [ebx].RECT.right
        sub eax, edx
        sub eax, size_.cx_
        and eax, eax
        js @F
        shr eax, 1
        add edx, eax
@@:        
        mov eax, [ebx].RECT.top
        test uFormat, DT_VCENTER
        jz @F
        mov ecx, [ebx].RECT.bottom
        sub ecx, eax
        sub ecx, size_.cy
        and ecx, ecx
        js @F
        shr ecx, 1
        add eax, ecx
@@:        
		invoke ExtTextOutA, hdc, edx, eax, 0, 0, lpString, nCount, 0
		@strace	<"DrawTextA(", hdc, ", ", lpString, ", ", nCount, ", ", lpRect, ", ", nCount, ", ", uFormat, ")=", eax>
		ret
        align 4
DrawTextA endp

GrayStringA proc public hdc:dword, hBrush:dword, lpOutputFunc:ptr, lpData:DWORD, nCount:dword, x:dword, y:dword, nWidth:dword, nHeight:dword
		xor eax, eax
		@strace	<"GrayStringA(", hdc, ", ", hBrush, ", ", lpOutputFunc, ", ", lpData, ", ", nCount, ", ", x, ", ", y, ", ", nWidth, ", ", nHeight, ")=", eax>
		ret
        align 4
GrayStringA endp

UserRealizePalette proc public hdc:dword

		push hdc
		call g_dwOldRealizePalette
        .if (edx)		;edx==number of entries which have changed
        	push eax
        	invoke WindowFromDC, hdc
            .if (eax)		;NULL is HWND_TOP
            	invoke SendMessage, HWND_BROADCAST, WM_PALETTECHANGED, eax, 0
            .endif
            pop eax
        .endif
		@strace	<"UserRealizePalette(", hdc, ")=", eax>
		ret
        align 4
        
UserRealizePalette endp

;--- get window

WindowFromDC proc public uses ebx hdc:DWORD

local	pt:POINT

        mov eax, hdc
        and eax, eax
        jz exit
		@serialize_enter
		mov ebx, offset g_dccache
        mov ecx, ?DCITEMS
        xor edx, edx
        .while (ecx)
        	.if (([ebx].DCCACHEITEM.bUsed) && (eax == [ebx].DCCACHEITEM.hDC))
                mov edx, [ebx].DCCACHEITEM.hwnd
                .break
            .endif
            add ebx, sizeof DCCACHEITEM
            dec ecx
        .endw
		mov eax, edx
        @serialize_exit
exit:        
		@strace	<"WindowFromDC(", hdc, ")=", eax>
		ret
        align 4
WindowFromDC endp

DrawIcon proc public hdc:dword, X:dword, Y:dword, hIcon:ptr
		xor eax, eax
		@strace	<"DrawIcon(", hdc, ", ", X, ", ", Y, ", ", hIcon, ")=", eax>
		ret
        align 4
DrawIcon endp

DrawIconEx proc public hdc:DWORD, nLeft:dword, nTop:dword, hIcon:DWORD, cxWidth:dword, cyWidth:dword, iStepIfAniCur:dword, hbrFlickerFreeDraw:DWORD, diFlags:DWORD
		xor eax, eax
		@strace	<"DrawIconEx(", hdc, ", ", nLeft, ", ", nTop, ", ", hIcon, ", ", cxWidth, ", ", cyWidth, " ...)=", eax, " *** unsupp ***">
		ret
        align 4
DrawIconEx endp

	end

