/*
**  FUNCTIONS WHICH ALLOW TURBO C 1.5 VIDEO TEXT OUTPUT
**  ROUTINES TO RUN IN A TOPVIEW, DESQVIEW OR MICROSOFT
**  WINDOWS WINDOW, EVEN WHEN DIRECTVIDEO = 1.
*/

#include <conio.h>
#include <dos.h>

#define VIDEOINT    0x10    /* video BIOS interrupt */

extern struct _VIDEO {      /* UNDOCUMENTED VIDEO INFORMATION STRUCTURE */
    unsigned char winleft;      /* left window coordinate (0 relative) */
    unsigned char wintop;       /* top window coordinate (0 relative) */
    unsigned char winright;     /* right window coordinate (0 relative) */
    unsigned char winbottom;    /* bottom window coordinate (0 relative) */
    unsigned char attribute;    /* text attribute */
    unsigned char normattr;     /* normal attribute */
    unsigned char currmode;     /* current video text mode */
    unsigned char screenheight; /* bottom - top */
    unsigned char screenwidth;  /* right - left */
    unsigned char graphics;     /* mode type (0: text; 1: graphics) */
    unsigned char needcgasync;  /* cga sync to prevent "snow" (1: yes) */
    char far *videobuffer;      /* pointer to video buffer */
} _video;

char TopViewActive;         /* NON-ZERO IF TOPVIEW WINDOWING IS ACTIVE */

/*
**  SETUP FOR TOPVIEW/DESQVIEW VIDEO
**  call at startup and whenever the video mode is changed.
**  installs the shadow buffer address and sets TopViewActive.
*/
void SetupTopView(void)
{
    union REGS reg;
    struct SREGS sreg;

    if (_video.graphics) {                  /* if in a graphic mode */
        TopViewActive = 0;                  /* TopView cannot be active */
        return;
    }
    reg.h.ah = 0xFE;                        /* Get Video Buffer */
    sreg.es = FP_SEG(_video.videobuffer);   /* assumed buffer address */
    reg.x.di = FP_OFF(_video.videobuffer);
    int86x(VIDEOINT, &reg, &reg, &sreg);    /* call video BIOS */
    TopViewActive = (_video.videobuffer != MK_FP(sreg.es, reg.x.di));
    if (TopViewActive)                      /* if under TopView */
        _video.needcgasync = 0;             /* CGA sync is never needed */
    _video.videobuffer = MK_FP(sreg.es, reg.x.di);  /* shadow buffer addr */
}

/*
**  UPDATE SCREEN FROM TOPVIEW VIDEO BUFFER
**  (not required for DESQview)
*/
void UpdateTopView(void)
{
    union REGS reg;
    struct SREGS sreg;

    if (_video.graphics || !TopViewActive)  /* if graphic or not active */
        return;                             /* TopView cannot be active */
    reg.h.ah = 0xFF;                        /* update video buffer */
    reg.x.cx = _video.screenheight * _video.screenwidth;    /* all of it */
    sreg.es = FP_SEG(_video.videobuffer);   /* buffer address */
    reg.x.di = FP_OFF(_video.videobuffer);
    int86x(VIDEOINT, &reg, &reg, &sreg);    /* call video BIOS */
    kbhit();                                /* yield Windows control */
}

/*
**  Test the TopView Video Functions.
*/

int main()
{
    int i;

    SetupTopView();
    cputs("This will run fine under DOS,"
        " as well as in a TopView/DESQview/Windows window!\n");
    UpdateTopView();
    for (i=1; i<=25; ++i) {
        sleep(1);
        cprintf("line %2d: %s\n", i,
            "ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz");
        UpdateTopView();
    }
    return 0;
}
