;       SCCSID = @(#)sswsave.asm        6.2 91/08/28
       PAGE    60,132
; ****************************************************************************
; *                                                                          *
; *                       IBM/Microsoft Confidential                         *
; *                                                                          *
; *                 Copyright (c) IBM Corporation  1987, 1990                *
; *                 Copyright (c) Microsoft Corp.  1987, 1990                *
; *                           All Rights Reserved                            *
; *                                                                          *
; ****************************************************************************

;***************************************************************************
;
; Source File Name:     SSWSAVE.ASM
;
; Subroutine Name:      DOSSGSAVE
;
; Descriptive Name:     Screen Switcher save function
;
; Function:     Causes saving of specified screen group screen
;               and hardware state information.
;
; Notes:
;       Dependencies:   None.
;
;       Restrictions:   Only the Shell may call this routine.
;
;       Change History:
;
;       @TL6 - 03/01/90 - DCR 704 - Merge SMG/SSW instance data into
;                         OS2CHAR
;       @GDW   08/26/91   PTR B725436 Fix to allow semaphore loop on INTERUPT
;       MDLL   01/10/94   BJN Page Tune segments for Merged DLL.
;
;
; Entry Point:
;       Linkage:  EXTRN DOSSGSAVE : FAR
;                       PUSH    WORD   ACTION
;                       PUSH    WORD   SGID        ; In coming SG #
;                       CALL    DOSSGSAVE
;
; Input:
;       WORD     SGID           screen group number
;
; Exit Normal:
;       AX      ReturnCode   Value = 0
;
; Exit Error:
;       AX      error_sgs_not_session_mgr
;       AX      error_vio_lock_freeze
;
; Effects:      All other registers preserved.
;
; Internal References:
;          Data:
;          Routines:    SSLOCKCHECK
;                       SSPIDCHECK
;
; External References:
;          Routines:    DOSGETINFOSEG
;                       DOSSEMSET
;                       DOSSEMWAIT
;                       DOSSEMCLEAR
;                       VIOSAVE
;                       DOSSEMREQUEST
; #                     DOSSMNOTIFYDD
;
;***************************************************************************
;
;       DOSGETINFOSEG(Determine caller's screen group #)
;       IF (AX e no_error)
;          IF (LIS_CurProcID ne ssmgr_pid)
;             AX = error_scs_not_session_mgr
;          ELSE
;             SSFINDSG(get pointer to sgcb)
;             IF (AX e error_scs_sg_notfound)
;                SSMEMMAP(Locate a lot in sgcb)
;                IF (AX e no_error)
;                   SSCBSETUP(Setup sgcb)
;                   IF (AX e no_error)
;                      SSSEMSETUP(Setup sgcb semaphores)
;                   ENDIF
;                ENDIF
;             ENDIF
;             WHILE (kbdowner ne 0)
;                DOSSLEEP(Wait for screen lock)
;             ENDWHILE
;             DOSSEMREQUEST(Wait for savelocksem)
;             IF (AX e no_error) OR
;             IF (AX e error_sem_timeout)
;                Set savelockflag
;                Register savelockowner
;                DOSSEMSET(Block any undo calls until SAVE is finished)
;                IF (AX e no_error) OR
;                IF (AX e error_sem_owner_died)
;                   Indicate screen group is background
;                   Clear timedouterror
;                   IF (Popup Save)
;                      IF (action e 5> AND
;                      IF (modeactionflag ne NULL) OR
;                      IF (scrnactionflag ne NULL)
;                         AX = error_vio_transparent_popup
;                      ELSE
;                         IF (sglockineffect ne 0)
;                            SSLOCKCHECK(Time and freeze the owning process)
;                         ENDIF
;                         IF (modeactionflag e 1)
; #                          DOSSMNOTIFYDD(Presave notification)
;                            IF (freezefunction e process_frozen) AND
;                            IF (savemodepid e sgprocessfrozen)
;                               VIOSAVE(Save everything)
;                            ELSE
;                               PROC1(Release the save mode thread)
;                               IF (AX e no_error)
;                                  VIOSAVE(Save everything except mode)
;                               ENDIF
;                            ENDIF
;                         ELSE
;                            VIOSAVE(Save everything)
;                         ENDIF
;                      ENDIF
;                   ELSEIF (scrnactionflag e 0)
;                      IF (sglockineffect ne 0)
;                         SSLOCKCHECK(Time and freeze the owning process)
;                         IF (freezefunction e process_frozen) AND
;                         IF (savemodepid e sgprocessfrozen)
; #                          DOSSMNOTIFYDD(Presave notification)
;                            VIOSAVE(Save everything)
;                         ELSE
;                            Clear AX
;                         ENDIF
;                      ENDIF
;                   ENDIF
;                   IF (sgprocessfrozen ne saverestpid)
;                      DOSSEMSET(Block any undo calls until SAVE is finished)
;                      IF (AX e no_error)
;                         DOSSEMSET(Set saveredrawsem)
;                         IF (AX e no_error) OR
;                         IF (AX e error_sem_owner_died)
;                            DOSSEMCLEAR(Release savelocksem)
;                            IF (AX e no_error) OR
;                            IF (AX e error_sem_owner_died)
;                               Update saverestflags
;                               DOSSEMCLEAR(Release saveresthreadsem)
;                               IF (AX e no_error)
;                                  DOSSEMWAIT(Wait for saveredrawsem)
;                                  IF (AX e no_error)
;                                     DOSSEMCLEAR(Relase saveundosem)
;                                     IF (AX e no_error)
;                                        IF (DOSEXITLIST cleanup)
;                                           Set saverestflags
;                                        ELSE
;                                           VIOSCROLLDN(Clear screen)
;                                           IF (AX e no_error)
; #                                            DOSSMNOTIFYDD(Presave notif.)
;                                              VIOSAVE(Save everything)
;                                              IF (AX e no_error)
;                                                 Clear saverestflags
;                                              ENDIF
;                                           ENDIF
;                                        ENDIF
;                                        Indicate screen group is background
;                                        Clear saverestflgs
;                                     ENDIF
;                                  ENDIF
;                               ENDIF
;                            ENDIF
;                         ENDIF
;                      ENDIF
;                   ENDIF
;                ELSEIF (scrnactionflag e 1)
;                   IF (sglockineffect ne 0)
;                      SSLOCKCHECK
;                      Clear screenlocksgid
;                      Clear AX
;                   ENDIF
;                ELSEIF (scrnactionflag e NULL)
;                   IF (sglockineffect ne 0)
;                      SSLOCKCHECK
;                      Clear screenlocksgid
;                      Clear AX
;                   ENDIF
;                   IF (AX e no_error)
; #                    DOSSMNOTIFYDD(Presave notification)
;                      VIOSAVE(Save everything)
;                   ENDIF
;                ENDIF
;             ENDIF
;          ENDIF
;       ENDIF
;       IF (savelockflag e 1)
;          DOSSEMCLEAR(Release savelocksem)
;       ENDIF
;       DOSSEMCLEAR(Release saveundosem)
;
;***************************************************************************



EXTRN   ssmgr_pid          : WORD
EXTRN   savelocksem        : BYTE
EXTRN   savelockflag       : BYTE
EXTRN   saveundoflag       : WORD
EXTRN   timedouterror      : WORD
EXTRN   savelockowner      : WORD
EXTRN   saveundosem        : DWORD
EXTRN   modeaction         : WORD
EXTRN   scrnaction         : WORD
EXTRN   screenlocksgid     : WORD
EXTRN   blank              : BYTE
EXTRN   DOSSLEEP           : FAR
EXTRN   DOSFSRAMSEMREQUEST : FAR
EXTRN   DOSFSRAMSEMCLEAR   : FAR

.xlist
INCLUDE SSWINC.INC
INCLUDE INFOSEG.INC
INCLUDE SSWEXTR3.INC
INCLUDE SMREXTRN.INC                   ; Device Driver Notification EQUs
INCLUDE DC1SEGS.INC                                                     ;MDLL
.list

.386P

CODE    SEGMENT WORD PUBLIC 'CODE' USE16                                ;@TL6

        ASSUME  CS:CONFORM16,DS:NOTHING,SS:NOTHING,ES:NOTHING           ;MDLL

;---------------------------------------------------------------------------
PROC1           PROC    NEAR            ; Release save mode thread
                                        ; Procedure added 1/30/87

.IF <zero ax>                                                           ;@TL6
;mov     cx,di                                                          ;@TL6
 lea     cx,[di].savemodesem                                            ;@TL6
 push    ds                 ; Set a sem which we
 push    cx                 ; will wait on for thd to clear
 call    DOSSEMSET
 .IF <zero ax>              ; 1/27/87 Clear the global ram              ;@TL6
  push    ds                ; semaphore to allow the save
  push    offset savelocksem ; mode to take place
  mov     savelockflag,al                                               ;@TL6
  call    DOSFSRAMSEMCLEAR
  .IF <zero ax>                                                         ;@TL6
   or      [di].savemodeflags,savemodereq
   mov     modeaction,1                 ; Tells thread to save
;  mov     cx,di                        ; mode                          ;@TL6
   lea     ax,[di].savemodethreadsem                                    ;@TL6
   push    ds                           ; Release the thread
   push    ax                           ; to perform the mode           ;@TL6
   call    DOSSEMCLEAR
   .IF <zero ax>                                                        ;@TL6
;   mov     cx,di                                                       ;@TL6
;   add     cx,offset savemodesem                                       ;@TL6
    push    ds                         ; Now wait on the
    push    cx                         ; previously set sem
    push    dword ptr timeout                                           ;CJ10
;   push    timeout                                                     ;CJ10
    call    DOSSEMWAIT
   .ENDIF
  .ENDIF
 .ENDIF
.ENDIF
                RET
PROC1           ENDP

CODE    ENDS                                                            ;@TL6

;---------------------------------------------------------------------------


CODE_TUNE4    SEGMENT WORD PUBLIC 'CODE' USE16                          ;MDLL

        ASSUME  CS:CONFORM16,DS:NOTHING,SS:NOTHING,ES:NOTHING           ;MDLL

 PUBLIC  DOSSGSAVE

DOSSGSAVE      PROC    FAR

 push    bp
 mov     bp,sp

 push    bx
 push    cx
 push    dx
 push    es
 push    ds
 push    si
 push    di

;push    ax                             ; Need to store 2 words         ;@TL6
;mov     bx,sp                          ; which will be used to         ;@TL6
;push    ax                             ; store the globalsg            ;@TL6
;mov     cx,sp                          ; and the localsg               ;@TL6
;push    ss                                                             ;@TL6
;push    bx                                                             ;@TL6
;push    ss                                                             ;@TL6
;push    cx                                                             ;@TL6

;call    DOSGETINFOSEG                  ; Determine caller's            ;@TL6
;pop     es                             ; Get localsg into es           ;@TL6
;pop     bx                                                             ;@TL6
;.IF <zero ax> near                                                     ;@TL6
   mov     ax,stdatasg                  ; We can access our
   mov     ds,ax                        ; static data area
   mov     es,localsg                   ; Setup local infoseg           ;@TL6
   mov     bx,es:lis_curprocid          ; Get current pid#
   .IF <bx ne ssmgr_pid>
     mov     ax,error_scs_not_session_mgr  ; Session Manager,
   .ELSE near
;***************************************************************************
; The following code was added on 7/16/87 to correct a window opened
; during rapid screen switching
;***************************************************************************
;;;    push   bx                        ; Save curprocid
       mov    bx,ss:[bp].sgid           ; SG# into bx
       xor    bh,bh                     ; Shave off process-type
       call SSFINDSG                    ; See if we have sgcb
;;;    pop    bx                        ; Restore curprocid
       .IF <ax e error_scs_sg_notfound>  ; If new sg# then
         call SSMEMMAP                  ; check mem for location
         .IF <zero ax>                  ; for new sgcb Sgpointeroff     ;@TL6
                                        ; points to sgcb spot in memory
                                        ; DI also points to spot
           call SSCBSETUP               ; Setup the cb
           .IF <zero ax>                                                ;@TL6
             call SSSEMSETUP            ; DI should point to
           .ENDIF                       ; sgcb
         .ENDIF
       .ENDIF
       .WHILE <[di].kbdowner ne 0>      ; We cool our heels waiting for
;CJ10   push   0                        ; a sg just made foreground and
        push   DWORD PTR 10             ; which has not yet gotten a    ;CJ10
        call   DOSSLEEP                 ; requested screen lock. This is
       .ENDWHILE                        ; to prevent unnecessarily freezing
                                        ; a sg which does not really have
                                        ; the screen locked.
;***************************************************************************
     .repeat                                                            ;@GDW
       push    ds                       ; Get the global semaphore
       push    offset savelocksem
       push    dword ptr timeout                                        ;CJ10
;      push    timeout                                                  ;CJ10
       call    DOSFSRAMSEMREQUEST
     .until  <ax ne ERROR_INTERRUPT>                                    ;@GDW

     .IF <zero ax> OR                                                   ;@TL6
     .IF <ax e error_sem_timeout> near
       mov    savelockflag,1            ; Indicate we set semaphore
;---------------------------------------------------------------------------
; The following code was added on 3/25/87 to handle the possible case of
; undo calls executing simultaneously with modewait or savredraw calls when
; they are later released by freeing the global ram semaphore
;---------------------------------------------------------------------------

       push    ds                       ; Now we block any undo calls
       push    offset saveundosem       ; until we finish the save
       call    DOSSEMSET
       .IF <zero ax> near OR            ; If no error or                ;@TL6
       .IF <ax e error_sem_owner_died> near
         or      [di].sgflags,in_backgrnd  ; Sg is backgrnd
         mov     timedouterror,0        ; For error return
         .IF <ss:[bp].action ne 0> near  ; If pop-up save, then
;---------------------------------------------------------------------------
;         The following code takes care of transparent popups
;---------------------------------------------------------------------------
          .IF <ss:[bp].action e 5> AND
          .IF <[di].modeactionflag ne null> OR
          .IF <[di].scrnactionflag ne null>
            mov     ax,error_vio_transparent_popup
            and     [di].sgflags, in_foregrnd      ; Sg is NOT backgrnd
          .ELSE near                                                    ;@TL6
;---------------------------------------------------------------------------
           .IF <[di].sglockineffect ne 0>  ; if sg has lock on
            call    SSLOCKCHECK            ; time it and freeze it
            mov     timedouterror,ax       ; save any error returned
           .ENDIF

;          ******************************
;          *  Notify Registered Device  *
;          *  Drivers of SG switch.     *
;          ******************************
;          PUSH   Pre_Save_Notification  ; Not. Type
;          PUSH   0                      ; No telling of incoming SG
;          PUSH   SS:[BP].SGID           ; SG being saved
;          CALL   DosSMNotifyDD

           .IF <[di].modeactionflag e 1> near  ; If sg saves mode
            .IF <ax e freezefunction> AND  ; If we froze the process
             mov     ax,[di].sgprocessfrozen ; which does the save
            .IF <[di].savemodepid e ax>
              push    ss:[bp].sgid    ; Tell VIO to save everything
              push    ss:[bp].action
              call    VIOSAVE
            .ELSE                    ; If we did not freeze the owner
             call    PROC1           ; Release the save mode thread
             .IF <zero ax>                                              ;@TL6
                push    ss:[bp].sgid    ; Tell VIO to save everything
                mov     ax,ss:[bp].action ; except mode
                add     ax,2
                push    ax
                call    VIOSAVE
             .ENDIF
            .ENDIF
           .ELSE                       ; If sg does not save mode
             push    ss:[bp].sgid    ; Tell VIO to save everything
             push    ss:[bp].action
             call    VIOSAVE
           .ENDIF
          .ENDIF
;---------------------------------------------------------------------------
;        This ends the modified section of code from 2/18/87
;---------------------------------------------------------------------------
         .ELSEIF <[di].scrnactionflag e 0> NEAR ; If normal save and
                                                ; sg has save thread

;---------------------------------------------------------------------------
;        The following 15 lines of code were added 12/3/86
;---------------------------------------------------------------------------
           .IF <[di].sglockineffect ne 0>
           call    SSLOCKCHECK
            .IF <ax e freezefunction>         ; ax is changed in call
            mov     ax,[di].saverestpid
            .IF <[di].sgprocessfrozen e ax>   ; If we froze the process
                                              ; which does save/restore

;           ******************************
;           *  Notify Registered Device  *
;           *  Drivers of SG switch.     *
;           ******************************
;           PUSH   Pre_Save_Notification  ; Not. Type
;           PUSH   0                      ; No telling of incoming SG
;           PUSH   SS:[BP].SGID           ; SG being saved
;           CALL   DosSMNotifyDD

            push    ss:[bp].sgid    ; Tell VIO to save everything
            push    ss:[bp].action  ; and hope for the best
            call    VIOSAVE
           .ELSE
            xor     ax,ax
           .ENDIF
          .ENDIF
         .ENDIF

;---------------------------------------------------------------------------

           mov     cx,[di].saverestpid
          .IF <[di].sgprocessfrozen ne cx> near   ; changed 12/15/86
           push    ds                 ; Now we block any undo calls
           push    offset saveundosem ; until we finish the save
           call    DOSSEMSET
           .IF <zero ax> near                                           ;@TL6
;@TL6       mov     cx,di
            lea     cx,[di].saveredrawsem                               ;@TL6
            push    ds
            push    cx                   ; cleared by thread
            call    DOSSEMSET
            .IF <zero ax> OR             ; If no error or               ;@TL6
            .IF <ax e error_sem_owner_died> near
              push    ds
              push    offset savelocksem
              mov     savelockflag,0
              call    DOSFSRAMSEMCLEAR
             .IF <zero ax> OR                                           ;@TL6
             .IF <ax e error_sem_owner_died> near
               and     [di].saverestflags,0FFFEH ; Turn off dosexitlist flg
               or      [di].saverestflags,savescrnreq
               mov     scrnaction,savescrn  ; = 0

;              ******************************
;              *  Notify Registered Device  *
;              *  Drivers of SG switch.     *
;              ******************************
;              PUSH   Pre_Save_Notification  ; Not. Type
;              PUSH   0                      ; No telling of incoming SG
;              PUSH   SS:[BP].SGID           ; SG being saved
;              CALL   DosSMNotifyDD

;@TL6          mov     cx,di
               lea     ax,[di].saveresthreadsem                         ;@TL6
               push    ds
               push    ax                                               ;@TL6
               call    DOSSEMCLEAR      ; thread
              .IF <zero ax>            ; If no error                    ;@TL6
;@TL6           mov     cx,di
;@TL6           add     cx,offset saveredrawsem
                push    ds
                push    cx
                push    dword ptr timeout       ; until cleared by      ;CJ10
;CJ10           push    timeout
                call    DOSSEMWAIT     ; save thread
               .IF <zero ax>          ; If no error                     ;@TL6
                push    ds                 ; Now we clear any undo calls
                push    offset saveundosem
                call    DOSSEMCLEAR
                .IF <zero ax>          ; If no error                    ;@TL6
                  test    [di].saverestflags,1  ; check for dosexitlist cleanup
                 .IF z                ; 8/14/86
                   and     [di].saverestflags,savescrncomp
                 .ELSE                ; 8/14/86
                  cwde                 ; 8/14/86                   ;@TL6,CJ10
                  push    eax          ; 8/14/86                        ;@TL6
                  push    24           ; 8/14/86
                  push    79           ; 8/14/86
                  push    -1           ; 8/14/86
                  push    ds           ; 8/14/86
                  push    offset blank ; 8/14/86
                  push    ax           ; 8/14/86                        ;@TL6
                  call    VIOSCROLLDN  ; 8/14/86
                  .IF <zero ax>                                         ;@TL6

;                  ******************************
;                  *  Notify Registered Device  *
;                  *  Drivers of SG switch.     *
;                  ******************************
;                  PUSH   Pre_Save_Notification  ; Not. Type
;                  PUSH   0                      ; No telling of incoming SG
;                  PUSH   SS:[BP].SGID           ; SG being saved
;                  CALL   DosSMNotifyDD

                   push    ss:[bp].sgid  ; Tell VIO to save all
                   push    ss:[bp].action  ; 8/14/86
                   call    VIOSAVE    ; 8/14/86
                   .IF <zero ax>        ; 8/14/86                       ;@TL6
                    mov     [di].saverestflags,0  ; 8/14/86
                   .ENDIF
                  .ENDIF
                 .ENDIF
                 or      [di].sgflags,in_backgrnd
                 mov     screenlocksgid,0
                .ENDIF
               .ENDIF
              .ENDIF
             .ENDIF
            .ENDIF
           .ENDIF
          .ENDIF                            ; added 12/3/86
;---------------------------------------------------------------------------
         .ELSEIF <[di].scrnactionflag e 1>  ; If normal save and the sg
           .IF <[di].sglockineffect ne 0>
             call    SSLOCKCHECK        ; will do its own restore but no
                                        ; save
;---------------------------------------------------------------------------
             mov     screenlocksgid,0
             mov     timedouterror,ax
             xor     ax,ax
           .ENDIF
;---------------------------------------------------------------------------
         .ELSEIF <[di].scrnactionflag e null>  ; If normal save and
           .IF <[di].sglockineffect ne 0>  ; we do the save, check for lock
;---------------------------------------------------------------------------
             call    SSLOCKCHECK        ; and time it
             mov     screenlocksgid,0
             mov     timedouterror,ax
             xor     ax,ax
           .ENDIF
           .IF <zero ax>                                                ;@TL6

;            ******************************
;            *  Notify Registered Device  *
;            *  Drivers of SG switch.     *
;            ******************************
;            PUSH   Pre_Save_Notification  ; Not. Type
;            PUSH   0                      ; No telling of incoming SG
;            PUSH   SS:[BP].SGID           ; SG being saved
;            CALL   DosSMNotifyDD

             push    ss:[bp].sgid       ; Tell VIO to save all
             push    ss:[bp].action
             call    VIOSAVE
           .ENDIF
         .ENDIF
       .ENDIF                            ; 3/25/87
;     .ENDIF                             ; ES7/16/87
     .ENDIF
   .ENDIF
;.ENDIF                                                                 ;@TL6

 .IF <savelockflag e 1>
   mov     savelockflag,0
   push    ax
   push    ds
   push    offset savelocksem
   call    DOSFSRAMSEMCLEAR     ; 12-12-88 @GA1
   pop     ax
 .ENDIF                                                                 ;@TL6
;----------------------------------------------------------------------------
;      We added the following on 3/25/87 to clear any undo calls
;----------------------------------------------------------------------------
   push    ax
   push    ds                 ; Now we clear any undo calls
   push    offset saveundosem
   call    DOSSEMCLEAR
   pop     ax
;----------------------------------------------------------------------------

 pop     di
 pop     si
 pop     ds
 pop     es
 pop     dx
 pop     cx
 pop     bx
 pop     bp
 ret     4
DOSSGSAVE      ENDP

CODE_TUNE4    ENDS                                                      ;MDLL
 END
