;*DDK*************************************************************************/
;
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
ifdef DCAF
        PAGE    ,132
        TITLE   SCRAREA.ASM
;/*****************************************************************************
;*
;* SOURCE FILE NAME = SCRAREA.ASM
;*
;* DESCRIPTIVE NAME = DCAF Screen Change Area functions
;*
;*
;* VERSION      V2.0
;*
;* DATE         04/28/92
;*
;* DESCRIPTION  Contains Driver Entry Points to create, query and
;*              delete Screen Change Areas.
;*
;* FUNCTIONS
;*              OpenScreenChangeArea
;*              CloseScreenChangeArea
;*              GetScreenChangeArea
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   04/10/92                     Created for DCAF 1.3
;*   07/06/92                     Ported to 32-bit for DCAF 2.0
;*
;*****************************************************************************/

        .386p
        .xlist
INCL_ERROR              equ     1
INCL_DDICOMFLAGS        equ     1
INCL_GRE_REGIONS        equ     1
INCL_GPIREGIONS         equ     1
INCL_GRE_DCS            equ     1
DINCL_ENABLE            equ     1
DINCL_BITMAP            equ     1
INCL_SHLERRORS          equ     1
        include pmgre.inc
        include driver.inc
        include protos.inc
        include extern.inc
        .list

        .MODEL  FLAT
        ASSUME  CS:FLAT, SS:FLAT, DS:FLAT, ES:FLAT
        .DATA


public  pStartSCA
pStartSCA DWORD  0              ; Points at the SCA linked list

        ; Define a global variable that we use to pass COM flags
        ; (of which we are only interested in COM_SCR_BOUNDS)
        ; into the enumerate_clip_rects function.
        ; We cannot pass this value into enumerate_clip_rects
        ; by adding an extra parameter because the interface to
        ; enumerate_clip_rects is fixed.
public  ulGlobalCOMFlags
ulGlobalCOMFlags DWORD  0

        .CODE

        InnerGre32Entry5  PROTO @Gre32Entry5


page
;--------------------------Exported-Routine-----------------------------;
;/*********************************************************************
;* OpenScreenChangeArea                                               *
;*                                                                    *
;* This routine will allocate a data area internal to the display     *
;* driver in which the driver will accumulate screen changes.  It     *
;* returns a 32 bit handle which is required to identify the area in  *
;* GetScreenChangeArea and CloseScreenChangeArea calls.               *
;*                                                                    *
;**********************************************************************
;*
;* Entry:
;*       None
;* Returns:
;*       DX:AX = 32 bit handle (pointer) to the ScreenChangeArea
;* Error Returns:
;*       DX:AX = GPI_ERROR
;*       Error logged
;* Registers Preserved:
;*       SI,DI,BP,DS
;* Registers Destroyed:
;*       AX,BX,CX,DX,ES,FLAGS
;* History:
;*
;* Mon  6-Jul-1992       -by-    John Batty
;*     Changed for MASM 6.0 and optimised 32-bit code.
;* Fri 10-Apr-1992       -by-    Mark Berry
;*     Wrote it.
;*********************************************************************/

ALIGN 4
OpenScreenChangeArea PROC SYSCALL USES EBX ESI EDI,
        hdc    :HDC,
        hddc   :PVOID,
        FunN   :ULONG

;/*
;** Grab the driver semaphore etc.
;*/
        cld
        mov     esi,hddc                ; ESI --> ddc
        mov     edx,esi
        call    enter_driver
        mov     eax, GPI_ERROR
        jc      osca_exit_no_lock       ; EAX = GPI_ERROR on an error


;/*
;** Check that DCAF is enabled.
;*/
        cmp     fDCAFEnabled,TRUE
        je      @F
        mov     eax, PMERR_FUNCTION_NOT_SUPPORTED
        save_error_code
        jmp     osca_error
@@:

;/*
;** Try allocating the memory we need
;*/
        mov     eax, size SCA
        INVOKE  AllocMem
        or      ecx,ecx                 ; Zero ecx return means an error
        jz      osca_error

;/*
;** We have a valid address for this ScreenChangeArea - now link
;** it to the start of our linked list of areas
;*/
        mov     ebx,eax                 ; This is the newly created SCA
        ASSUME  EBX:PTR SCA
        mov     eax, pStartSCA          ; Get the old list start

;/*
;** The old list start is now in eax.
;** If this is NULL then this is the first SCA area to be created,
;** so we must turn on SCREEN bounds accumulation.
;*/
        mov     ecx,eax

        mov     [ebx].sca_next, eax     ; link the new to the old start
        mov     pStartSCA, ebx          ; save the new start of the list

;/*
;** Initialize the new SCA to empty
;*/
        mov     [ebx].sca_cRects, 0; no rectangles accumulated

;/*
;** Now we turn on SCREEN bounds accumulation if this was the first
;** SCA to be created.
;*/
        or      ecx,ecx
        jnz     accumulation_on

        push    ebx                     ; save the handle

        INVOKE  InnerGre32Entry5,
                hdc,
                COM_SCR_BOUND,
                COM_SCR_BOUND,
                hddc,
                NGreSetProcessControl

        pop     ebx                     ; restore the handle
accumulation_on:

;/*
;** Return the address as the handle
;*/
        mov     eax, ebx
        jmp     osca_exit

osca_error:
        mov     eax, GPI_ERROR

osca_exit:
;/*
;** Release the driver semaphore
;*/
        call    leave_driver
osca_exit_no_lock:
        fw_zero <ecx>
        ret

OpenScreenChangeArea ENDP

;--------------------------Exported-Routine-----------------------------;
;/*********************************************************************
;* CloseScreenChangeArea                                              *
;*                                                                    *
;* This routine frees the data area internal to the display driver,   *
;* identified by the SCA handle, which was accumulating screen        *
;* changes.  It returns a boolean indicating success or failure.      *
;*                                                                    *
;* NB. Error conditions are not obvious here, but we will return TRUE *
;*     if passed a handle we recognise, and false in all other cases. *
;**********************************************************************
;*
;* Entry:
;*       None
;* Returns:
;*       DX:AX = TRUE (1)
;* Error Returns:
;*       DX:AX = FALSE (0)
;*       Error logged
;* Registers Preserved:
;*       SI,DI,BP,DS
;* Registers Destroyed:
;*       AX,BX,CX,DX,ES,FLAGS
;* History:
;*
;* Mon  6-Jul-1992       -by-    John Batty
;*     Changed for MASM 6.0 and optimised 32-bit code.
;* Fri 10-Apr-1992       -by-    Mark Berry
;*     Wrote it.
;*********************************************************************/

ALIGN 4
CloseScreenChangeArea PROC SYSCALL USES EBX EDI ESI,
        hdc    :HDC,
        hsca   :PVOID,
        hddc   :PVOID,
        FunN   :ULONG

;/*
;** Grab the driver semaphore etc.
;*/
        cld
        mov     esi,hddc                ; ESI --> ddc
        mov     edx,esi
        call    enter_driver
        jc      csca_exit_no_lock       ; EAX = 0 on an error

;/*
;** Check that DCAF is enabled.
;*/
        cmp     fDCAFEnabled,TRUE
        je      @F
        mov     eax, PMERR_FUNCTION_NOT_SUPPORTED
        save_error_code
        jmp     csca_error
@@:

;/*
;** Get the passed HSCA and check it is non NULL
;*/
        mov     eax, hsca
        or      eax, eax
        jnz     non_null

no_match_found:
        mov     eax, PMERR_NO_HANDLE
        save_error_code
        xor     eax,eax
        jmp     csca_error

non_null:
;/*
;** Handle deleting the initial link first
;*/
        mov     ebx, pStartSCA          ; get the start of the list
        ASSUME  EBX:PTR SCA
        cmp     ebx, eax                ; is the start the one to delete ?
        jnz     search_list             ; jump if not to search the list

;/*
;** We are deleting the start of the list
;*/
        mov     ebx, [ebx].sca_next     ; get the second entry
        mov     pStartSCA, ebx          ; this is the new list start
        jmp     free_the_memory

search_list:
;/*
;** Search the linked list for the passed handle.
;** The current entry is in ebx.
;*/
        xor     edx,edx                 ; initialize back pointer to NULL

list_loop:
        and     ebx,ebx                 ; have we reached the NULL terminator?
        jz      no_match_found

        mov     edx,ebx                 ; this is the new back pointer
        mov     ebx, [ebx].sca_next     ; move down the list

        cmp     ebx, eax                ; have we found the match?
        jne     list_loop               ; loop back along the list

;/*
;** To get here we must have found a match which is not at the
;** start of the list
;*/
        mov     ebx, [ebx].sca_next     ; get the link to the next entry
        xchg    ebx,edx
        mov     [ebx].sca_next, edx     ; link the last entry to the next entry

free_the_memory:
;/*
;** The address of the memory block to be freed is in EAX
;*/
        INVOKE  FreeMem

;/*
;** If the list is now NULL then we turn off the SCREEN bounds
;** accumulation bit.
;*/
        mov     eax,pStartSCA
        or      eax,eax
        jnz     accumulation_checked

        INVOKE  InnerGre32Entry5,
                hdc,
                COM_SCR_BOUND,
                0,
                hddc,
                NGreSetProcessControl

accumulation_checked:
        mov     eax,1

csca_error:

;/*
;** Release the driver semaphore
;*/
        call    leave_driver

csca_exit_no_lock:
        fw_zero <ecx>
        ret

CloseScreenChangeArea ENDP

;--------------------------Exported-Routine-----------------------------;
;/*********************************************************************
;* GetScreenChangeArea                                                *
;*                                                                    *
;* This routine takes a screen change area handle, and for the Screen *
;* Change Area identified merges its rectangles with the supplied     *
;* region.                                                            *
;*                                                                    *
;* The SCA is reset as a result of this call.                         *
;*                                                                    *
;**********************************************************************
;*
;* Entry:
;*       None
;* Returns:
;*       DX:AX = TRUE (1)
;* Error Returns:
;*       DX:AX = FALSE (0)
;*       Error logged
;* Registers Preserved:
;*       SI,DI,BP,DS
;* Registers Destroyed:
;*       AX,BX,CX,DX,ES,FLAGS
;* History:
;*
;* Mon  6-Jul-1992       -by-    John Batty
;*     Changed for MASM 6.0 and optimised 32-bit code.
;* Mon 13-Apr-1992       -by-    Mark Berry
;*     Wrote it.
;*********************************************************************/

ALIGN 4
GetScreenChangeArea PROC SYSCALL USES EBX EDI ESI,
        hdc    :HDC,
        hsca   :PVOID,
        phrgn  :PVOID,
        hddc   :PVOID,
        FunN   :ULONG


;/*
;** Grab the driver semaphore etc.
;*/
        cld
        mov     esi,hddc                ; ESI --> ddc
        mov     edx,esi
        call    enter_driver
        jc      gsca_exit_no_lock       ; EAX = 0 on an error

;/*
;** Check that DCAF is enabled.
;*/
        cmp     fDCAFEnabled,TRUE
        je      @F
        mov     eax,PMERR_FUNCTION_NOT_SUPPORTED
        save_error_code
        xor     eax,eax
        jmp     gsca_error
@@:

;/*
;** Merge any Seamless rectangles with the global (application)
;** SCAs.
;*/
        INVOKE  MergeSeamlessSCAWithGlobalSCAs

;/*
;** Get the passed HSCA and check it is non NULL
;*/
        mov     eax, hsca
        and     eax, eax
        jnz     gsca_non_null

gsca_no_match_found:
        mov     eax, PMERR_NO_HANDLE
        save_error_code
        xor     eax,eax
        jmp     gsca_error

gsca_non_null:
;/*
;** Search for this SCA in the linked list.
;*/
        mov     ebx, pStartSCA          ; get the start of the list
        ASSUME  EBX:PTR SCA

next_SCA:
        cmp     ebx, eax                ; have we found the right one ?
        jz      found_it

        and     ebx,ebx                 ; have we reached the NULL terminator
        jz      gsca_no_match_found

        mov     ebx, [ebx].sca_next     ; move down the list

        jmp     next_SCA

found_it:
        mov     ecx,[ebx].sca_cRects    ; get the number of rectangles
        lea     ebx,[ebx].sca_rect[0]   ; get the start of the rectangles

        mov     esi, phrgn
        ASSUME  ESI:PTR DWORD
        mov     eax, [esi]
        xor     esi,esi                 ; need a zero high word !

ifdef SETREGION
;/*
;** This code sets the region to be just the rectangles returned.
;*/
        INVOKE  PFNDefSetRectRegion PTR pfnSetRectRegion,
                hdc,
                eax,    ; hrgn
                ebx,    ; prcl
                ecx,    ; cRect
                hddc,
                NGreSetRectRegion

        and     eax,eax
        jnz     clear_and_return
else ; SETREGION
;/*
;** This code combines the rectangle returned with whatever is
;** already in the region.
;*/

;/*
;** Nothing to do if there are no rectangles in the ScreenChangeArea
;*/
        jecxz    good_return

combine_each_rect:
        push    ecx              ; save rectangle count
        push    ebx              ; save rectangle pointer
        push    eax              ; save region handle
        push    edx              ; save region handle

        INVOKE  PFNDefCombineRectRegion PTR pfnDefCombineRectRegion,
                hdc,     ; hdc
                eax,     ; hrgn
                ebx,     ; prcl
                eax,     ; hrgn
                CRGN_OR, ; ulMode
                hddc,
                NGreCombineRectRegion

        .errnz  RGN_ERROR
        and     eax,eax         ; set the flag for a jump after the pops

        ; pops dont affect the flags !
        pop     edx             ; restore region handle
        pop     eax             ; restore region handle
        pop     ebx             ; restore rectangle count
        pop     ecx             ; restore rectangle pointer

        jz      an_error_occured

        add     ebx, size RECTL

        loop    combine_each_rect

        jmp     clear_and_return
an_error_occured:
endif ; SETREGION

;/*
;** Oh dear - we got an error from the engine when we tried to
;** pass them our rectangles.
;** We assume the error occured because we somehow got some bad
;** rectangles stored in our ScreenChangeArea structure.
;** To avoid getting this error ad infinitum, we will set the
;** stored data in the SCA to be a single rectangle the size of the
;** screen, so that any data we may have missed will be picked up
;** next time we are called.
;** We still return an error for logging purposes.
;*/
        mov     ebx, hsca
        ASSUME  EBX:PTR SCA
        mov     [ebx].sca_cRects, 1
        lea     ebx,[ebx].sca_rect[0]   ; get the start of the rectangles
        ASSUME  EBX:PTR RECTL
        xor     eax,eax                 ; zeros are very useful
        mov     [ebx].rcl_xLeft, eax
        mov     [ebx].rcl_yBottom, eax
        mov     [ebx].rcl_xRight, SCREEN_CX
        mov     [ebx].rcl_yTop, SCREEN_CY

        mov     eax, FALSE
        jmp     gsca_error

clear_and_return:
;/*
;** We set the region, so clear our count of used rectangles.
;*/
        mov     ebx, hsca
        ASSUME  EBX:PTR SCA
        mov     [ebx].sca_cRects, 0

good_return:
        mov     eax,TRUE

gsca_error:

;/*
;** Release the driver semaphore
;*/
        call    leave_driver

gsca_exit_no_lock:
        fw_zero <ecx>
        ret

GetScreenChangeArea ENDP


ALIGN 4
GetScreenBitsStub  PROC SYSCALL,
        hdc       :HDC,
        hrgn      :ULONG,
        pDest     :PVOID,
        pulLength :PVOID,
        flCmd     :ULONG,
        hddc      :PVOID,
        FunN      :ULONG

        ; Check whether DCAF is enabled.
        cmp     fDCAFEnabled,TRUE
        jne     gsb_disabled

        ; Indirectly invoke the function.
        INVOKE  PFNGetScreenBits PTR pfnGetScreenBits,
                     hdc, hrgn, pDest, pulLength, flCmd, hddc, FunN
        ret

gsb_disabled:
        ; DCAF is not enabled.
        ; Log a suitable error and exit.
        mov     eax, PMERR_FUNCTION_NOT_SUPPORTED
        save_error_code

        ; Return zero to indicate error.
        xor     eax,eax
        ret

GetScreenBitsStub ENDP

ALIGN 4
SetScreenBitsStub PROC SYSCALL,
        hdc       :HDC,
        pBuffer   :PVOID,
        cBytes    :ULONG,
        hrgn      :ULONG,
        hddc      :PVOID,
        FunN      :ULONG

        ; Check whether DCAF is enabled.
        cmp     fDCAFEnabled,TRUE
        jne     ssb_disabled

        ; Indirectly invoke the function.
        INVOKE  PFNSetScreenBits PTR pfnSetScreenBits,
                                  hdc, pBuffer, cBytes, hrgn, hddc, FunN
        ret

ssb_disabled:
        ; DCAF is not enabled.
        ; Log a suitable error and exit.
        mov     eax, PMERR_FUNCTION_NOT_SUPPORTED
        save_error_code

        ; Return zero to indicate error.
        xor     eax,eax
        ret

SetScreenBitsStub ENDP

endif ; DCAF

end
