/* * 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 #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 /* for setmode() */ #include /* for O_BINARY */ #include /* for the register struct */ #include #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, ®s); 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, ®s, ®s, &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, ®s, ®s); } static void set_page (int page) { union REGS regs; regs.h.ah = 5; regs.h.al = page; INTX86(0x10, ®s, ®s); } #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, ®s, ®s); } #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, ®s, ®s); /* 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, ®s, ®s); /* VIDEO - SET TEXT-MODE CURSOR SHAPE */ } static int get_cursor(void) { union REGS regs; regs.h.ah = 3; regs.h.bh = 0; INTX86(0x10, ®s, ®s); /* 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, ®s, ®s); /* 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, ®s, ®s); } /* 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, ®s, ®s); 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, ®s, ®s); } 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, ®s, ®s); } 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, ®s, ®s); } 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,®s, ®s); /* 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<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<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, ®s, ®s); /* 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,®s, ®s); /* 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, ®s, ®s); /* 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, ®s, ®s); /* 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, ®s, ®s); } /*--------------------------------------------------------------------------*/ #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, ®s, ®s) #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(®s, 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, ®s, ®s, &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 */