Logo Search packages:      
Sourcecode: vile version File versions

ibmpc.c

/*
 * The routines in this file provide support for the IBM-PC family
 * of machines, and their typical display cards:  mono, cga, ega, vga.
 * It goes directly to the graphics RAM to do screen output.
 *
 * Modified by Pete Ruczynski (pjr) for auto-sensing and selection of
 * display type.
 *
 * $Header: /usr/build/vile/vile/RCS/ibmpc.c,v 1.97 2002/12/06 23:32:48 tom Exp $
 *
 */

#include    "estruct.h"
#include    "edef.h"

#if DISP_BORLAND || !DISP_IBMPC
#error misconfigured:  DISP_IBMPC should be defined if using ibmpc.c
#error (and DISP_BORLAND should not be defined)
#endif

#if CC_DJGPP
#include <pc.h>
#define min(a,b) (((a) < (b)) ? (a) : (b))
#define max(a,b) (((a) > (b)) ? (a) : (b))
#define outp(p,v) outportb(p,v)
#define inp(p) inportb(p)
#define far
#include <io.h> /* for setmode() */
#include <fcntl.h> /* for O_BINARY */
#include <dpmi.h> /* for the register struct */
#include <go32.h>
#endif

#define NROW      50                /* Max Screen size.           */
#define NCOL      80                /* Edit if you want to.       */
#define     NPAUSE      200               /* # times thru update to pause */
#define     SPACE 32                /* space character            */

#if CC_WATCOM
#define     MONOADDR    (0xb000 << 4)     /* MONO screen memory */
#define     OTHERADDR   (0xb800 << 4)     /* CGA,EGA,VGA screen memory */
#endif

#if CC_DJGPP
#define FAR_POINTER(s,o) (0xe0000000 + s*16 + o)
#define FP_SEG(a) ((ULONG)(a) >> 4L)
#define FP_OFF(a) ((ULONG)(a) & 0x0fL)
#define     MONOADDR    0xb000            /* MONO screen memory */
#define     OTHERADDR   0xb800            /* CGA,EGA,VGA screen memory */
#endif

#ifndef OTHERADDR
#define     MONOADDR    0xb0000000L /* MONO screen memory */
#define     OTHERADDR   0xb8000000L /* CGA,EGA,VGA screen memory */
#endif

#ifndef FAR_POINTER
#define FAR_POINTER(s,o) (s)
#endif

#define     MONOSCR     0
#define     CGASCR      1
#define     EGASCR      2
#define     VGASCR      3

static      const long  ScreenAddress[] = {
            MONOADDR,   /* MONOSCR: Monochrome adapter */
            OTHERADDR,  /* CGASCR: Color graphics adapter */
            OTHERADDR,  /* EGASCR: Enhanced graphics adapter */
            OTHERADDR   /* VGASCR: VGA adapter */
      };


#if CC_WATCOM
#ifdef __386__
#define     INTX86(a,b,c)           int386(a, b, c)
#define     INTX86X(a,b,c,d)  int386x(a, b, c, d)
#else
#define     INTX86(a,b,c)           int86(a, b, c)
#define     INTX86X(a,b,c,d)  int86x(a, b, c, d)
#endif
#define     _AX_        eax
#define     _BX_        ebx
#define     _CX_        ecx
#define     _DX_        edx
#define     _DI_        edi
#else
#define     INTX86(a,b,c)     int86(a, b, c)
#define     INTX86X(a,b,c,d)  int86x(a, b, c, d)
#define     _AX_        ax
#define     _BX_        bx
#define     _CX_        cx
#define     _DX_        dx
#define     _DI_        di
#endif

#define     ColorDisplay()    (dtype != MONOSCR && !monochrome)
#define     AttrColor(b,f)    (((ctrans[b] & 7) << 4) | (ctrans[f] & 15))
#define     Black(n)    ((n) ? 0 : 7)
#define     White(n)    ((n) ? 7 : 0)
#define     AttrMono(f) (((Black(f) & 7) << 4) | (White(f) & 15))

#if OPT_MS_MOUSE
      static      int   ms_crsr2inx  ( int, int );
      static      void  ms_deinstall (void);
      static      void  ms_hidecrsr  (void);
      static      void  ms_install   (void);
      static      void  ms_setvrange ( int, int );
      static      void  ms_showcrsr  (void);
#else
# define ms_deinstall()
# define ms_install()
#endif

static      int   dtype = -1; /* current display type       */
#if CC_DJGPP
#define PACKED __attribute__ ((packed))
#else
#define PACKED
#endif

      /* mode-independent VGA-BIOS status information */
typedef     struct {
      UCHAR video_modes[3] PACKED;  /* 00 Supported video-modes */
      UCHAR reserved[4] PACKED;     /* 03 */
      UCHAR text_scanlines PACKED;  /* 07 Number of pixel rows in text mode */
      UCHAR num_charsets PACKED;    /* 08 Number of character sets that can be displayed */
      UCHAR num_loadable PACKED;    /* 09 Number of character sets loadable into video RAM */
      UCHAR capability PACKED;      /* 0A VGA-BIOS capability info */
      UCHAR more_info PACKED; /* 0B More VGA-BIOS capability info */
      UCHAR reserved2[4] PACKED;    /* 0C */
      } static_VGA_info PACKED;

      /* mode-dependent VGA-BIOS status information */
typedef     struct {
      static_VGA_info *static_info PACKED; /* 00 Address of table containing static info */
      UCHAR code_number PACKED;     /* 04 Code number of current video mode */
      USHORT      num_columns PACKED;     /* 05 Number of displayed screen or pixel cols */
      USHORT      page_length PACKED;     /* 07 Length of display page in video RAM */
      USHORT      curr_page PACKED; /* 09 Starting address of current display-page in video RAM */
      UCHAR crsr_pos[8][2] PACKED;  /* 0B Cursor positions in display-pages in col/row order */
      UCHAR crsr_end PACKED;  /* 1B Ending row of cursor (pixel) row */
      UCHAR crsr_start PACKED;      /* 1C Starting row of cursor (pixel) row */
      UCHAR curr_page_num PACKED;   /* 1D Number of current display page */
      USHORT      port_crt PACKED;  /* 1E Port address of the CRT controller address register */
      UCHAR curr_crtc PACKED; /* 20 Current contents of CRTC control registers */
      UCHAR curr_color_sel PACKED;  /* 21 Current color selection register contents */
      UCHAR num_rows PACKED;  /* 22 Number of screen rows displayed */
      USHORT      char_height PACKED;     /* 23 Height of characters in pixel rows */
      UCHAR code_active PACKED;     /* 25 Code number of active video adapter */
      UCHAR code_inactive PACKED;   /* 26 Code number of inactive video adapter */
      USHORT      num_colors PACKED;      /* 27 Number of displayable colors (0=monochrome) */
      UCHAR num_pages PACKED; /* 29 Number of screen pages */
      UCHAR num_pixel_rows PACKED;  /* 2A Number of displayed pixel rows (RES_200, etc.) */
      UCHAR num_cset0 PACKED; /* 2B Number of char-table used with chars whose 3rd attr bit is 0 */
      UCHAR num_cset1 PACKED; /* 2C Number of char-table used with chars whose 3rd attr bit is 1 */
      UCHAR misc_info PACKED; /* 2D Miscellaneous information */
      UCHAR reserved[3] PACKED;     /* 2E */
      UCHAR size_of_ram PACKED;     /* 31 Size of available video RAM (0=64k, 1=128k, 2=192k, 3=256k) */
      UCHAR reserved2[14] PACKED;   /* 32 */
      } dynamic_VGA_info PACKED;    /* length == 64 bytes */

      /* scan-line resolution codes */
#define     RES_200     0
#define     RES_350     1
#define     RES_400     2
#define RES_480 3

      /* character-size codes */
#define     C8x8  0x12
#define     C8x14 0x11
#define     C8x16 0x14

      /* character-size in pixels, for mouse-positioning */
static      int   chr_wide = 8;
static      int   chr_high = 8;

typedef     struct      {
      char  *name;
      UCHAR type;
      UCHAR mode;
      UCHAR vchr; /* code for setting character-height */
      UCHAR rows;
      UCHAR cols;
      UCHAR vres; /* required scan-lines, RES_200, ... */
      } DRIVERS;

#define ORIGTYPE  0     /* store original info in this slot.
                     (these values should all (?) get replaced
                     at open time) */

/* order this table so that more higher resolution entries for the same
 *  name come first.  remember -- synonyms take only 10 bytes, plus the
 *  name itself.
 */
static      DRIVERS drivers[] = {
            {"default",ORIGTYPE,    3,      C8x8,   25,  80, RES_200},
            {"2",      VGASCR,      3,    C8x16,      25,  80, RES_400},
            {"25",     VGASCR,      3,    C8x16,      25,  80, RES_400},
            {"2",      CGASCR,      3,    C8x8, 25,  80, RES_200},
            {"25",     CGASCR,      3,    C8x8, 25,  80, RES_200},
            {"CGA",    CGASCR,      3,    C8x8, 25,  80, RES_200},
            {"MONO",   MONOSCR,     3,    C8x8, 25,  80, RES_200},
            {"80x25",  VGASCR,      3,    C8x16,      25,  80, RES_400},
            {"80x28",  VGASCR,      3,    C8x14,  28,  80, RES_400},
            {"EGA",    EGASCR,      3,    C8x8, 43,  80, RES_350},
            {"4",      EGASCR,      3,    C8x8, 43,  80, RES_350},
            {"43",     EGASCR,      3,    C8x8, 43,  80, RES_350},
            {"80x43",  VGASCR,      3,    C8x8,   43,  80, RES_350},
            {"5",      VGASCR,      3,    C8x8, 50,  80, RES_400},
            {"50",     VGASCR,      3,    C8x8, 50,  80, RES_400},
            {"VGA",    VGASCR,      3,    C8x8, 50,  80, RES_400},
            {"80x50",  VGASCR,      3,    C8x8, 50,  80, RES_400},
            {"80x14",  VGASCR,      3,    C8x14,  14,  80, RES_200},
            {"40x12",  VGASCR,      1,    C8x16,      12,  40, RES_200},
            {"40x21",  VGASCR,      1,    C8x16,      21,  40, RES_350},
            {"40x25",  VGASCR,      1,    C8x16,      25,  40, RES_400},
            {"40x28",  VGASCR,      1,    C8x14,  28,  40, RES_400},
            {"40x50",  VGASCR,      1,    C8x8,   50,  40, RES_400},

      };

/*  the following should be sized dynamically, but it may not be worth it,
      if we come up in the biggest size anyway, since we never shrink
      but only grow */
static USHORT *screen_lines[NROW];  /* pointer to screen lines    */
static USHORT *screen2_lines[NROW]; /* pointer to page-1 lines    */


static      int   ibm_opened,
            original_page,    /* display-page (we use 0)    */
            allowed_vres,     /* possible scan-lines, 1 bit per value */
            original_curs,    /* start/stop scan lines      */
            monochrome  = FALSE;

extern  void      ibmmove   (int,int);
extern  void      ibmeeol   (void);
extern  void      ibmeeop   (void);
extern  void      ibmbeep   (void);
extern  void    ibmopen   (void);
extern      void  ibmrev    (UINT);
extern      int   ibmcres   (const char *);
extern      void  ibmclose  (void);
extern      void  ibmputc   (int);
extern      void  ibmkopen  (void);
extern      void  ibmkclose (void);

#if   OPT_COLOR
extern      void  ibmfcol   (int);
extern      void  ibmbcol   (int);

int   cfcolor = -1;           /* current forground color */
int   cbcolor = -1;           /* current background color */
static      const char *initpalettestr = "0 4 2 6 1 5 3 7 8 12 10 14 9 13 11 15";
/* black, red, green, yellow, blue, magenta, cyan, white   */
#endif
extern      void  ibmscroll (int,int,int);

static      int   screen_init(int);
static      int   identify_adapter(void);
static      int   blank_attr(void);

static      const struct {
      char  *seq;
      int   code;
} keyseqs[] = {   /* use 'Z' in place of leading 0, so these can be C-strings */
      /* Arrow keys */
      {"Z\110",     KEY_Up},
      {"Z\120",     KEY_Down},
      {"Z\115",     KEY_Right},
      {"Z\113",     KEY_Left},
      /* page scroll */
      {"Z\121",     KEY_Next},
      {"Z\111",     KEY_Prior},
      {"Z\107",     KEY_Home},
      {"Z\117",     KEY_End},
      /* editing */
      {"ZR",            KEY_Insert},
      {"Z\123",     KEY_Delete},
      /* function keys */
      {"Z;",          KEY_F1},
      {"Z<",      KEY_F2},
      {"Z=",      KEY_F3},
      {"Z>",      KEY_F4},
      {"Z?",      KEY_F5},
      {"Z@",      KEY_F6},
      {"ZA",      KEY_F7},
      {"ZB",      KEY_F8},
      {"ZC",      KEY_F9},
      {"ZD",          KEY_F10},
};

static int current_ibmtype;

/*
 * Standard terminal interface dispatch table. Most of the fields point into
 * "termio" code.
 */
TERM    term    = {
      NROW,
      NROW,
      NCOL,
      NCOL,
      NPAUSE,
      ibmopen,
      ibmclose,
      ibmkopen,
      ibmkclose,
      ttgetc,
      ibmputc,
      tttypahead,
      ttflush,
      ibmmove,
      ibmeeol,
      ibmeeop,
      ibmbeep,
      ibmrev,
      ibmcres,
#if   OPT_COLOR
      ibmfcol,
      ibmbcol,
      set_ctrans,
#else
      nullterm_setfore,
      nullterm_setback,
      nullterm_setpal,
#endif
      nullterm_setccol,
      ibmscroll,
      nullterm_pflush,
      nullterm_icursor,
      nullterm_settitle,
      nullterm_watchfd,
      nullterm_unwatchfd,
      nullterm_cursorvis,
};

#if CC_DJGPP
_go32_dpmi_seginfo vgainfo;
#endif

static int
get_vga_bios_info(dynamic_VGA_info *buffer)
{
# if CC_DJGPP
      _go32_dpmi_registers regs;
      vgainfo.size = (sizeof (dynamic_VGA_info)+15) / 16;
      if (_go32_dpmi_allocate_dos_memory(&vgainfo) != 0) {
            fprintf(stderr,"Couldn't allocate vgainfo memory\n");
            exit(BADEXIT);
      }

      regs.x.ax = 0x1b00;
      regs.x.bx = 0;
      regs.x.ss = regs.x.sp = 0;
      regs.x.es = vgainfo.rm_segment;
      regs.x.di = 0;
      _go32_dpmi_simulate_int(0x10, &regs);

      dosmemget( vgainfo.rm_segment*16, sizeof (dynamic_VGA_info), buffer);

      _go32_dpmi_free_dos_memory(&vgainfo);

      return (regs.h.al == 0x1b);
#else
      struct SREGS segs;
      union REGS regs;

#if CC_WATCOM
      segread(&segs);
#else
      segs.es   = FP_SEG(buffer);
#endif
      regs.x._DI_ = FP_OFF(buffer);
      regs.x._AX_ = 0x1b00;
      regs.x._BX_ = 0;
      INTX86X(0x10, &regs, &regs, &segs); /* Get VGA-BIOS status */

      return (regs.h.al == 0x1b);
#endif
}

static void
set_display (int mode)
{
      union REGS regs;
      regs.h.ah = 0;
      regs.h.al = mode;
      INTX86(0x10, &regs, &regs);
}

static void
set_page (int page)
{
      union REGS regs;
      regs.h.ah = 5;
      regs.h.al = page;
      INTX86(0x10, &regs, &regs);
}

#ifdef MUCK_WITH_KBD_RATE
/* this code turned off because there's currently no facility
 * to reset to the original rate when we quit.  i _hate_ programs
 * that don't put the world back they way they found it.
 */
/*  set the keyboard rate to max */
static void
maxkbdrate (void)
{
      union REGS regs;
      regs.h.ah = 0x3;
      regs.h.al = 0x5;
      regs.h.bh = 0x0;
      regs.h.bl = 0x0;
      INTX86(0x16, &regs, &regs);
}
#endif

static void
set_char_size(int code)
{
      union REGS regs;
      switch (code) {
      case C8x8:  chr_wide = 8;     chr_high = 8;     break;
      case C8x14: chr_wide = 8;     chr_high = 14;    break;
      case C8x16: chr_wide = 8;     chr_high = 16;    break;
      default:    return;           /* cannot set this one! */
      }
      regs.h.ah = 0x11;       /* set char. generator function code      */
      regs.h.al = code;       /*  to specified ROM                */
      regs.h.bl = 0;          /* Character table 0                */
      INTX86(0x10, &regs, &regs);   /* VIDEO - TEXT-MODE CHARACTER GENERATOR FUNCTIONS */
}

static void
set_cursor(int start_stop)
{
      union REGS regs;
      regs.h.ah = 1;          /* set cursor size function code */
      regs.x._CX_ = (drivers[ORIGTYPE].mode <= 3) ?
            start_stop & 0x707 : start_stop;
      INTX86(0x10, &regs, &regs);   /* VIDEO - SET TEXT-MODE CURSOR SHAPE */
}

static int
get_cursor(void)
{
      union REGS regs;
      regs.h.ah = 3;
      regs.h.bh = 0;
      INTX86(0x10, &regs, &regs);   /* VIDEO - GET CURSOR POSITION */
      return regs.x._CX_;
}

static void
set_vertical_resolution(int code)
{
      union REGS regs;
      regs.h.ah = 0x12;
      regs.h.al = code;
      regs.h.bl = 0x30;
      INTX86(0x10, &regs, &regs);   /* VIDEO - SELECT VERTICAL RESOLUTION */
      if (code == RES_200)
            delay(50);  /* patch: timing problem? */
}

/*--------------------------------------------------------------------------*/

#if   OPT_COLOR
void
ibmfcol(          /* set the current output color */
int color)        /* color to set */
{
      if (color < 0)
            color = C_WHITE;
      cfcolor = ctrans[color];
}

void
ibmbcol(          /* set the current background color */
int color)        /* color to set */
{
      if (color < 0)
            color = C_BLACK;
      cbcolor = ctrans[color];
}
#endif

void
ibmmove(int row, int col)
{
      union REGS regs;
      regs.h.ah = 2;          /* set cursor position function code */
      regs.h.dl = col;
      regs.h.dh = row;
      regs.h.bh = 0;          /* set screen page number */
      INTX86(0x10, &regs, &regs);
}

/* erase to the end of the line */
void
ibmeeol(void)
{
      int ccol,crow;    /* current column,row for cursor */
      union REGS regs;

      /* find the current cursor position */
      regs.h.ah = 3;          /* read cursor position function code */
      regs.h.bh = 0;          /* current video page */
      INTX86(0x10, &regs, &regs);

      ccol = regs.h.dl;       /* record current column */
      crow = regs.h.dh;       /* and row */

      scwrite(crow, ccol, term.cols-ccol, NULL, NULL, gfcolor, gbcolor);

}

/* put a character at the current position in the current colors */
void
ibmputc(int ch)
{
      union REGS regs;
      regs.h.ah = 14;         /* write char to screen with current attrs */
      regs.h.al = ch;
#if   OPT_COLOR
      regs.h.bl = ColorDisplay() ? cfcolor : White(TRUE);
#else
      regs.h.bl = White(TRUE);
#endif
      regs.h.bh = 0;          /* current video page */
      INTX86(0x10, &regs, &regs);
}

void
ibmeeop(void)
{
      union REGS regs;
      regs.h.ah = 6;          /* scroll page up function code */
      regs.h.al = 0;          /* # lines to scroll (clear it) */
      regs.x._CX_ = 0;        /* upper left corner of scroll */
      regs.h.dh = term.rows - 1; /* lower right corner of scroll */
      regs.h.dl = term.cols - 1;
      regs.h.bh = blank_attr();
      INTX86(0x10, &regs, &regs);
}

void
ibmrev(           /* change reverse video state */
UINT state) /* TRUE = reverse, FALSE = normal */
{
      /* This never gets used under the IBM-PC driver */
}

/* change screen properties */
int
ibmcres(
const char *res)  /* name for new "resolution" */
{
      int i;
      int status = FALSE;

      if (!res || !strcmp(res, "?"))      /* find the default configuration */
            res = "default";

      /* look up the driver by name, initialize screen */
      for (i = 0; i < TABLESIZE(drivers); i++) {
            if (strcmp(res, drivers[i].name) == 0) {
                  if ((status = screen_init(i)) == TRUE) {
                        strcpy(current_res_name, res);
                        break;
                  }
            }
      }
      return status;
}

#if OPT_MS_MOUSE || OPT_FLASH
extern VIDEO **vscreen; /* patch: edef.h */

static      int   vp2attr ( VIDEO *, int );
static      void  move2nd ( int, int );
static      void  copy2nd ( int );

static int
vp2attr(VIDEO *vp, int inverted)
{
      int   attr;
#if   OPT_COLOR
      if (ColorDisplay())
            attr = AttrColor(
                  inverted ? ReqFcolor(vp) : ReqBcolor(vp),
                  inverted ? ReqBcolor(vp) : ReqFcolor(vp));
      else
#endif
       attr = AttrMono(!inverted);
      return (attr << 8);
}

static void
move2nd(int row, int col)
{
      union REGS regs;
      regs.h.ah = 0x02;
      regs.h.bh = 1;
      regs.h.dh = row;
      regs.h.dl = col;
      INTX86(0x10, &regs, &regs);
}

static void
copy2nd(int inverted)
{
      WINDOW      *wp;
      VIDEO *vp;
      USHORT *lp;
      char *tt;
      register int      row, col, attr;

      for_each_visible_window(wp) {
            for (row = wp->w_toprow; row <= mode_row(wp); row++) {
                  vp = vscreen[row];
                  lp = screen2_lines[row];
                  tt = vp->v_text;
                  attr = vp2attr(vp, inverted ^ (row == mode_row(wp)));
                  for (col = 0; col < term.cols; col++) {
                        lp[col] = (attr | tt[col]);
                  }
            }
      }

      /* fill in the message line */
      lp = screen2_lines[term.rows-1];
      attr = blank_attr() << 8;
      for (col = 0; col < term.cols; col++)
            lp[col] = attr | SPACE;
      move2nd(ttrow, ttcol);
}
#endif

/*
 * Reading back from display memory does not work properly when using a mouse,
 * because the portion of the display line beginning with the mouse cursor is
 * altered (by the mouse driver, apparently).  Flash the display by building an
 * inverted copy of the screen in the second display-page and toggling
 * momentarily to that copy.
 *
 * Note: there's no window from which to copy the message line.
 */
#if OPT_FLASH
void
flash_display (void)
{
      copy2nd(TRUE);
      set_page(1);
      catnap(100,FALSE); /* if we don't wait, we cannot see the flash */
      set_page(0);
}
#endif      /* OPT_FLASH */

void
ibmbeep(void)
{
#if   OPT_FLASH
      if (global_g_val(GMDFLASH) && ibm_opened) {
            flash_display();
            return;
      }
#endif
      bdos(6, BEL, 0);  /* annoying!! */
}

void
ibmopen(void)
{
      register DRIVERS *driver = &drivers[ORIGTYPE];
      int i;
      union REGS regs;

      if (sizeof(dynamic_VGA_info) != 64) {
            printf("DOS vile build error -- dynamic_VGA_info struct"
                  " must be packed (ibmpc.c)\n");
            exit(BADEXIT);
      }

      regs.h.ah = 0xf;
      INTX86(0x10,&regs, &regs);    /* VIDEO - GET DISPLAY MODE */

      driver->vchr  = C8x8;
      driver->vres  = RES_200;
      driver->rows  = 25;
      driver->cols  = regs.h.ah;
      driver->mode  = regs.h.al;
      original_page = regs.h.bh;
      driver->type  = identify_adapter();
      allowed_vres  = (1<<RES_200); /* assume only 200 scan-lines */

      if (driver->type == VGASCR) { /* we can determine original rows */
            dynamic_VGA_info buffer;

            if (get_vga_bios_info(&buffer)) {
#undef TESTIT
#ifdef TESTIT
                  printf ("call succeeded\n");
                  printf ("static_info is 0x%x\n", buffer.static_info);
                  printf ("code_number is 0x%x\n", buffer.code_number);
                  printf ("num_columns is 0x%x\n", buffer.num_columns);
                  printf ("page_length is 0x%x\n", buffer.page_length);
                  printf ("curr_page is 0x%x\n", buffer.curr_page);
                  printf ("num_rows is 0x%x\n", buffer.num_rows);
#endif
                  switch (buffer.char_height) {
                  case 8:           driver->vchr = C8x8;    break;
                  case 14:    driver->vchr = C8x14;   break;
                  case 16:    driver->vchr = C8x16;   break;
                  }
                  driver->rows = buffer.num_rows;
#if CC_DJGPP
                  { ULONG staticinfop;
                  static_VGA_info static_info;
                  staticinfop = ((ULONG)buffer.static_info & 0xffffL);
                  staticinfop += (((ULONG)buffer.static_info >> 12) &
                                    0xffff0L);
                  dosmemget( staticinfop, sizeof(static_info),
                              &static_info);
                  allowed_vres = static_info.text_scanlines;
                  }
#elif CC_WATCOM
                  {
                  static_VGA_info __far *staticinfop;
                  staticinfop = MK_FP (
                        ((ULONG)(buffer.static_info) >> 16) & 0xffffL,
                        ((ULONG)(buffer.static_info)      ) & 0xffffL
                        );
                  allowed_vres = staticinfop->text_scanlines;
                  }
#else
                  allowed_vres = buffer.static_info->text_scanlines;
#endif
                  driver->vres = buffer.num_pixel_rows;
            }
      } else if (driver->type == EGASCR) {
            allowed_vres |= (1<<RES_350);
      }

      original_curs = get_cursor();

#ifdef PVGA
      set_display(10);  /* set graphic 640x350 mode */
      regs.x._AX_ = 0x007F;
      regs.h.bh = 0x01;       /* set non-VGA mode */
      INTX86(0x10,&regs, &regs);
      set_display(7);         /* set Hercule mode */
      current_res_name = "25";
#endif

#if   OPT_COLOR
      set_palette(initpalettestr);
#endif
      if (!ibmcres(current_res_name))
            (void)screen_init(ORIGTYPE);
      revexist = TRUE;
      ttopen();

#ifdef MUCK_WITH_KBD_RATE
      maxkbdrate();   /* set the keyboard rate to max */
#endif
      for (i = TABLESIZE(keyseqs); i--; ) {
            int len = strlen(keyseqs[i].seq);
            if (keyseqs[i].seq[0] == 'Z') {
                  keyseqs[i].seq[0] = '\0';
            }
            addtosysmap(keyseqs[i].seq, len, keyseqs[i].code);
      }

      ibm_opened = TRUE;      /* now safe to use 'flash', etc. */
}

void
ibmclose(void)
{
      int   ctype = current_ibmtype;

      if (current_ibmtype != ORIGTYPE)
            (void)screen_init(ORIGTYPE);
      if (original_page != 0)
            set_page(original_page);
      set_cursor(original_curs);

      current_ibmtype = ctype; /* ...so subsequent term.open restores us */

      dtype = MONOSCR;        /* ...force monochrome */
      kbd_erase_to_end(0);    /* ...force colors _off_ */
      kbd_flush();
}

/* "keyboard" open and close */
void
ibmkopen(void)
{
      ms_install();
#if CC_DJGPP
      setmode(0,O_BINARY);
#endif
}

void
ibmkclose(void)
{
#if CC_DJGPP
      setmode(0,O_TEXT);
#endif
      ms_deinstall();
}

static int
screen_init(                  /* initialize the pointers to video memory */
int newtype)                  /* type of graphics adapter to initialize */
{
      dynamic_VGA_info buffer;
      union REGS regs;
      union {
            long laddr; /* long form of address */
            USHORT *paddr;    /* pointer form of address */
      } addr;
      long pagesize;
      register DRIVERS *driver;
      register int i;
      int        type, rows, cols;

      driver = &drivers[newtype];

      /* check to see if we're allowed this many scan-lines */
      if ((allowed_vres & (1 << (driver->vres))) == 0)
            return FALSE;

      type = driver->type;
      rows = driver->rows;
      cols = driver->cols;

      /* and set up the various parameters as needed */
      set_vertical_resolution(driver->vres);

      set_display(driver->mode);
      set_vertical_resolution(driver->vres);
      set_char_size(driver->vchr);

      /* reset the original cursor -- it gets changed above somewhere */
      set_cursor(original_curs);

      /*
       * Install an alternative hardcopy routine which prints as many lines
       * as are displayed on the screen. The normal BIOS routine always
       * prints 25 lines.
       */
      if (rows > 25) {
            regs.h.ah = 0x12; /* alternate select function code    */
            regs.h.bl = 0x20;       /* alt. print screen routine       */
            INTX86(0x10, &regs, &regs);   /* VIDEO - SELECT ALTERNATE PRTSCRN  */
      }

      if (driver->type == EGASCR) {
            outp(0x3d4, 10);  /* video bios bug workaround */
            outp(0x3d5, 6);
      }

      /* set the $sres environment var. to the name of the driver in use */
      (void)strcpy(screen_desc, driver->name);

      if ((type == MONOSCR) != (dtype == MONOSCR))
            sgarbf = TRUE;
      dtype = type;
      current_ibmtype = newtype;

      /* initialize the screen pointer array */
      if (monochrome)
            addr.laddr = FAR_POINTER(ScreenAddress[MONOSCR],0x0000);
      else if (type == MONOSCR)
            addr.laddr = FAR_POINTER(ScreenAddress[CGASCR],0x0000);
      else
            addr.laddr = FAR_POINTER(ScreenAddress[type],0x0000);

      for (i = 0; i < rows; i++)
            screen_lines[i] = addr.paddr + (cols * i);

#if OPT_FLASH || OPT_MS_MOUSE
      /* Build row-indices for display page #1, to use it in screen flashing
       * or for mouse highlighting.
       */
      if ((type == VGASCR) && get_vga_bios_info(&buffer)) {
            /*
             * Setting page-1 seems to make Window 3.1 "aware" that we're
             * going to write to that page.  Otherwise, the "flash" mode
             * doesn't write to the correct address.
             */
            set_page(1);
            get_vga_bios_info(&buffer);
            pagesize = (long)buffer.page_length; /* also, page-1 offset */
            set_page(0);
      } else {
            /*
             * This was tested for all of the VGA combinations running
             * with MSDOS, but isn't general -- dickey@software.org
             */
            pagesize = (rows * cols);
            switch (cols) {
            case 40:    pagesize += ((4*cols) - 32);  break;
            case 80:    pagesize += ((2*cols) - 32);  break;
            }
            pagesize <<= 1;
      }
      addr.laddr += pagesize;
      for (i = 0; i < rows; i++)
            screen2_lines[i] = addr.paddr + (cols * i);
#endif
      /* changing the screen-size forces an update, so we do this last */
      newscreensize(rows, cols);
#if OPT_MS_MOUSE
      if (ms_exists()) {
            ms_deinstall();
            ms_install();
      }
#endif
      return TRUE;
}


int identify_adapter(void)
{
      union REGS regs;
      monochrome = FALSE;

      /* check for VGA or MCGA */
      regs.x._AX_ = 0x1a00;
      regs.h.bl = 0x00;
      INTX86(0x10,&regs, &regs); /* GET DISPLAY COMB. CODE (PS,VGA,MCGA) */

      if (regs.h.al == 0x1a) {      /* function succeeded */
            switch (regs.h.bl) {
            case 0x01:  monochrome = TRUE;
                        return MONOSCR;

            case 0x02:  return CGASCR;

            case 0x05:  monochrome = TRUE;      /* FALLTHRU */
            case 0x04:  return EGASCR;

            case 0x07:  monochrome = TRUE;      /* FALLTHRU */
            case 0x08:  return VGASCR;

            case 0x0b:  monochrome = TRUE;      /* FALLTHRU */
            case 0x0a:                    /* FALLTHRU */
            case 0x0c:  return CGASCR;    /* MCGA */
            }
      }

      /*
       * Check for MONO board
       */
      INTX86(0x11, &regs, &regs);   /* BIOS - GET EQUIPMENT LIST */

      /* Bits 4-5 in ax are:
       *    00 EGA, VGA or PGA
       *    01 40x25 color
       *    10 80x25 color
       *    11 80x25 monochrome
       */
      if ((regs.x._AX_ & 0x30) == 0x30) {
            monochrome = TRUE;
            return MONOSCR;
      }

      /*
       * Check for EGA board
       */
      regs.h.ah = 0x12;
      regs.h.bl = 0x10;
      INTX86(0x10, &regs, &regs);   /* VIDEO - GET EGA INFO */

      if (regs.h.bl != 0x10)
            return EGASCR;

      return CGASCR;
}

/* write a line out*/
void
scwrite(int row, int col,     /* where */
      int nchar,        /* length of outstr and attrstr */
      const char *outstr,     /* string to write */
      VIDEO_ATTR *attrstr,    /* attributes to write out */
      int forg,         /* foreground color to write */
      int bacg)         /* background color to write */
{
      register USHORT *lnptr;
      register int i;

      if (row > term.rows-1)
            return;

      lnptr = screen_lines[row]+col;

      if (attrstr) {
            register USHORT attrnorm;
            register USHORT attrrev;
#if   OPT_COLOR
            if (ColorDisplay()) {
                  attrnorm = AttrColor(bacg,forg) << 8;
                  attrrev = AttrColor(forg,bacg) << 8;
            } else
#endif
            {
            attrnorm = AttrMono(bacg < forg) << 8;
            attrrev = AttrMono(forg < bacg) << 8;
            }
            for (i = 0; i < nchar; i++) {
                  *lnptr++ = ((outstr != 0)
                        ? (outstr[i+col] & 0xff)
                        : SPACE) | ((attrstr[i+col] & (VAREV|VASEL))
                              ? attrrev
                              : attrnorm);
            }
      } else {
            register USHORT attr; /* temporary place to store attribute byte */
            /* build the attribute byte and setup the screen pointer */
#if   OPT_COLOR
            attr = ColorDisplay() ? AttrColor(bacg,forg) :
                              AttrMono(bacg < forg);
#else
            attr = AttrMono(bacg < forg);
#endif
            attr <<= 8;
            for (i = 0; i < nchar; i++) {
                  *lnptr++ = ((outstr != 0)
                        ? (outstr[i+col] & 0xff)
                        : SPACE) | attr;
            }
      }

}

/* reads back a line into a VIDEO struct, used in line-update computation */
VIDEO *
scread(VIDEO *vp, int row)
{
      register int      i;
      USHORT *slp;            /* screen line image          */

      if (row > term.rows-1)
            return 0;

      if (vp == 0) {
            static      VIDEO *mine;
            if (video_alloc(&mine))
                  vp = mine;
            else
                  tidy_exit(BADEXIT);
      }

      slp = &screen_lines[row];
      for (i = 0; i < term.cols; i++)
            vp->v_text[i] = slp[i];

      return vp;
}

/* returns attribute for blank/empty space */
static int
blank_attr(void)
{
      register int attr;
#if   OPT_COLOR
      attr = ColorDisplay() ? AttrColor(gbcolor,gfcolor) : AttrMono(TRUE);
#else
      attr = AttrMono(TRUE);
#endif
      return attr;
}

/*
 * Move 'n' lines starting at 'from' to 'to'
 *
 * OPT_PRETTIER_SCROLL is prettier but slower -- it scrolls a line at a time
 *    instead of all at once.
 */
void
ibmscroll(int from, int to, int n)
{
      union REGS regs;
#if OPT_PRETTIER_SCROLL
      if (absol(from-to) > 1) {
            ibmscroll(from, (from < to) ? to-1 : to+1, n);
            if (from < to)
                  from = to-1;
            else
                  from = to+1;
      }
#endif
      if (from > to) {
            regs.h.ah = 0x06; /* scroll window up */
            regs.h.al = from - to;  /* number of lines to scroll */
            regs.h.ch = to;         /* upper window row */
            regs.h.dh = from + n - 1;     /* lower window row */
      } else {
            regs.h.ah = 0x07; /* scroll window down */
            regs.h.al = to - from;  /* number of lines to scroll */
            regs.h.ch = from; /* upper window row */
            regs.h.dh = to + n - 1; /* lower window row */
      }
      regs.h.bh = blank_attr();     /* attribute to use for line-fill */
      regs.h.cl = 0;                /* left window column */
      regs.h.dl = term.cols - 1;    /* lower window column */
      INTX86(0x10, &regs, &regs);
}


/*--------------------------------------------------------------------------*/

#if OPT_MS_MOUSE

/* Define translations between mouse (pixels) and chars (row/col).
 * patch: why does 8 by 8 work, not chr_high by chr_wide?
 */
#define MS_CHAR_WIDE    ((term.cols == 80) ? 8 : 16)
#define MS_CHAR_HIGH    8

#define     pixels2col(x)   ((x)/MS_CHAR_WIDE)
#define pixels2row(y)   ((y)/MS_CHAR_HIGH)

#define col2pixels(x)   ((x)*MS_CHAR_WIDE)
#define row2pixels(y)   ((y)*MS_CHAR_HIGH)

/* Define a macro for calling mouse services */
#define MouseCall INTX86(0x33, &regs, &regs)

#define MS_MOVEMENT     iBIT(0)     /* mouse cursor movement */
#define     MS_BTN1_PRESS   iBIT(1) /* left button */
#define MS_BTN1_RELEASE iBIT(2)
#define MS_BTN2_PRESS   iBIT(3)     /* right button */
#define MS_BTN2_RELEASE iBIT(4)
#define MS_BTN3_PRESS   iBIT(5)     /* center button */
#define MS_BTN3_RELEASE iBIT(6)

#define BLINK 0x8000

      /* These have to be "far", otherwise TurboC doesn't force the
       * segment register to be specified from 'ms_event_handler()'
       */
int   far   button_pending;   /* 0=none, 1=pressed, 2=released */
int   far   button_number;    /* 1=left, 2=right, 3=center */
int   far   button_press_x;
int   far   button_press_y;
int   far   button_relsd_x;
int   far   button_relsd_y;
int         rodent_exists;
int         rodent_cursor_display;

#if CC_TURBO
#define     MsButtonPending() button_pending
#endif

/*
 * If we're using a DPMI configuration, we'll not be able to use the mouse
 * event handler, since it relies on a call rather than an interrupt.  We can
 * do polling instead.
 */
#if !CC_TURBO
static int
MsButtonPending(void)
{
      union REGS regs;
      regs.x._AX_ = 3;  /* query the mouse */
      MouseCall;

      if (regs.x._BX_ & 7) {
            if (regs.x._BX_ & 1)
                  button_number = 1;
            else if (regs.x._BX_ & 2)
                  button_number = 2;
            else if (regs.x._BX_ & 4)
                  button_number = 3;

            button_press_x = button_relsd_x = regs.x._CX_;
            button_press_y = button_relsd_y = regs.x._DX_;
            button_pending = 1;

      } else {
            if (button_pending)
                  button_pending = 2;
            button_relsd_x = regs.x._CX_;
            button_relsd_y = regs.x._DX_;
      }
      return button_pending;
}
#endif

int
ms_exists (void)
{
      return rodent_exists;
}

void
ms_processing (void)
{
      WINDOW      *wp;
      int   copied = FALSE,
            invert, normal,
            first, first_x = ttcol, first_y = ttrow,
            last,  last_x  = ttcol,  last_y = ttrow,
            that,  that_x,  that_y,
            attr, delta;
      USHORT *s2page = screen2_lines[0];

      ms_showcrsr();
      while (MsButtonPending()) {
            if (button_pending == 2) {    /* released? */
                  button_pending = 0;
                  break;
            } else {    /* selection */

#if CC_TURBO
                  disable();
                  that_x = button_relsd_x;
                  that_y = button_relsd_y;
                  enable();
#else
                  that_x = button_relsd_x;
                  that_y = button_relsd_y;
#endif

                  if (!copied) {
                        int x = pixels2col(button_press_x);
                        int y = pixels2row(button_press_y);
                        wp = row2window(y);
                        /* Set the dot-location if button 1 was pressed
                         * in a window.
                         */
                        if (wp != 0
                         && ttrow != term.rows - 1
                         && setcursor(y, x)) {
                              (void)update(TRUE);
                              ms_setvrange(wp->w_toprow,
                                         mode_row(wp) - 1);
                        } else {    /* cannot reposition */
                              kbd_alarm();
                              while (MsButtonPending() != 2)
                                    ;
                              continue;
                        }
                        first_x = last_x = col2pixels(ttcol);
                        first_y = last_y = row2pixels(ttrow);
                        first = ms_crsr2inx(first_x, first_y);

                        copy2nd(FALSE);
                        set_page(1);
                        copied = TRUE;

                        invert = vp2attr(vscreen[ttrow],TRUE);
                        normal = vp2attr(vscreen[ttrow],FALSE);
                  }

                  that  = ms_crsr2inx(that_x, that_y);
                  last  = ms_crsr2inx(last_x, last_y);
                  delta = (last < that) ? 1 : -1;

                  if (that != last) {
                        register int j;
                        if (((last < that) && (last <= first))
                         || ((last > that) && (last >= first))) {
                              attr = normal;
                        } else {
                              attr = invert;
                        }
#define HiLite(n,attr) s2page[n] = attr | (s2page[n] & 0xff)

                        for (j = last; j != that; j += delta) {
                              if (j == first) {
                                    if (attr == normal) {
                                          attr = invert;
                                    } else {
                                          attr = normal;
                                    }
                              }
                              HiLite(j,attr);
                        }
                        HiLite(that,invert|BLINK);
                  }
                  last_x = that_x;
                  last_y = that_y;
            }
      }

      /*
       * If we've been highlighting the selection, finish it off.
       */
      if (copied) {
            set_page(0);
            ms_setvrange(0, term.rows-1);
            mlerase();
            setwmark(pixels2row(last_y), pixels2col(last_x));
            if (DOT.l != MK.l
             || DOT.o != MK.o) {
                  regionshape = EXACT;
                  (void)yankregion();
                  (void)update(TRUE);
            }
            movecursor(pixels2row(first_y), pixels2col(first_x));
      }
}

/* translate cursor position (pixels) to array-index of the text-position */
static int
ms_crsr2inx(int x, int y)
{
      return pixels2col(x) + (pixels2row(y) * term.cols);
}

static void
ms_deinstall(void)
{
      union REGS regs;
      ms_hidecrsr();
      regs.x._AX_ = 0;  /* reset the mouse */
      MouseCall;
      rodent_exists = FALSE;
}

      /* This event-handler cannot do I/O; tracing it can be tricky...
       */
#if CC_TURBO
void far
ms_event_handler (void)
{
      UINT  ms_event  = _AX;
/*    UINT  ms_button = _BX;*/
      UINT  ms_horz   = _CX;
      UINT  ms_vert   = _DX;

      if (ms_event & MS_BTN1_PRESS) {
            button_pending = 1;
            button_number  = 1;
            button_press_x = button_relsd_x = ms_horz;
            button_press_y = button_relsd_y = ms_vert;
      } else {    /* movement or release */
            if (ms_event & MS_BTN1_RELEASE)
                  button_pending = 2;
            button_relsd_x = ms_horz;
            button_relsd_y = ms_vert;
      }
      return;
}
#endif

static void
ms_hidecrsr(void)
{
      union REGS regs;
      /* Hides the mouse cursor if it is displayed */
      if (rodent_cursor_display) {
            rodent_cursor_display = FALSE;
            regs.x._AX_ = 0x02;
            MouseCall;
      }
} /* End of ms_hidecrsr() */

static void
ms_install(void)
{
      union REGS regs;
      if (rodent_exists)
            return;

      /* If a mouse is installed, initializes the mouse and
       * sets rodent_exists to 1. If no mouse is installed,
       * sets rodent_exists to 0.
       */
      regs.x._AX_ = 0;
      MouseCall;
      rodent_exists = regs.x._AX_;
      rodent_cursor_display = FALSE; /* safest assumption */
      if (ms_exists()) {
            struct SREGS segs;

            memset(&regs, 0, sizeof(regs));
            memset(&segs, 0, sizeof(segs));

            regs.x._AX_ = 0x4;      /* set mouse position */
            regs.x._CX_ = 0;
            regs.x._DX_ = 0;
            MouseCall;

#if CC_TURBO
            regs.x._AX_ = 0xc;      /* define event handler */
            regs.x._CX_ = MS_MOVEMENT | MS_BTN1_PRESS | MS_BTN1_RELEASE;
            regs.x._DX_ = FP_OFF(ms_event_handler);
            segs.es = FP_SEG(ms_event_handler);
            INTX86X(0x33, &regs, &regs, &segs);
#endif
      }
}

static void
ms_setvrange(int upperrow, int lowerrow)
{
      union REGS regs;
      /* Restricts vertical cursor movement to the screen region
       * between upperrow and lowerrow.  If the cursor is outside the range,
       * it is moved inside.
       */
      regs.x._AX_ = 0x08;
      regs.x._CX_ = row2pixels(upperrow);
      regs.x._DX_ = row2pixels(lowerrow);
      MouseCall;
} /* End of ms_setvrange() */


static void
ms_showcrsr(void)
{
      union REGS regs;
      /* Displays the mouse cursor */
      int counter;

      /* Call Int 33H Function 2AH to get the value of the display counter */
      regs.x._AX_ = 0x2A;
      MouseCall;
      counter = regs.x._AX_;

      /* Call Int 33H Function 01H as many times as needed to display */
      /* the mouse cursor */
      while (counter-- > 0) {
            regs.x._AX_ = 0x01;
            MouseCall;
      }
      rodent_cursor_display = TRUE;
} /* End of ms_showcrsr() */
#endif /* OPT_MS_MOUSE */

Generated by  Doxygen 1.6.0   Back to index