/* Public Domain Curses */ #include "pdcdos.h" RCSID("$Id: pdcscrn.c,v 1.89 2008/07/13 16:08:17 wmcbrine Exp $") #include <stdlib.h> #ifdef CHTYPE_LONG # define PDC_OFFSET 32 #else # define PDC_OFFSET 8 #endif /* COLOR_PAIR to attribute encoding table. */ unsigned char *pdc_atrtab = (unsigned char *)NULL; int pdc_adapter; /* screen type */ int pdc_scrnmode; /* default screen mode */ int pdc_font; /* default font size */ bool pdc_direct_video; /* allow direct screen memory writes */ bool pdc_bogus_adapter; /* TRUE if adapter has insane values */ unsigned pdc_video_seg; /* video base segment */ unsigned pdc_video_ofs; /* video base offset */ static short curstoreal[16], realtocurs[16] = { COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE, COLOR_BLACK + 8, COLOR_BLUE + 8, COLOR_GREEN + 8, COLOR_CYAN + 8, COLOR_RED + 8, COLOR_MAGENTA + 8, COLOR_YELLOW + 8, COLOR_WHITE + 8 }; static bool sizeable = FALSE; /* TRUE if adapter is resizeable */ static unsigned short *saved_screen = NULL; static int saved_lines = 0; static int saved_cols = 0; static int saved_scrnmode[3]; static int saved_font[3]; /* Thanks to Jeff Duntemann, K16RA for providing the impetus (through the Dr. Dobbs Journal, March 1989 issue) for getting the routines below merged into Bjorn Larsson's PDCurses 1.3... -- frotz@dri.com 900730 */ /* _get_font() - Get the current font size */ static int _get_font(void) { int retval; retval = getdosmemword(0x485); /* Assume the MDS Genius is in 66 line mode. */ if ((retval == 0) && (pdc_adapter == _MDS_GENIUS)) retval = _FONT15; switch (pdc_adapter) { case _MDA: retval = 10; /* POINTS is not certain on MDA/Hercules */ break; case _EGACOLOR: case _EGAMONO: switch (retval) { case _FONT8: case _FONT14: break; default: retval = _FONT14; } break; case _CGA: retval = _FONT8; } return retval; } /* _set_font() - Sets the current font size, if the adapter allows such a change. It is an error to attempt to change the font size on a "bogus" adapter. The reason for this is that we have a known video adapter identity problem. e.g. Two adapters report the same identifying characteristics. */ static void _set_font(int size) { PDCREGS regs; if (pdc_bogus_adapter) return; switch (pdc_adapter) { case _CGA: case _MDA: case _MCGACOLOR: case _MCGAMONO: case _MDS_GENIUS: break; case _EGACOLOR: case _EGAMONO: if (sizeable && (pdc_font != size)) { switch (size) { case _FONT8: regs.W.ax = 0x1112; regs.h.bl = 0x00; PDCINT(0x10, regs); break; case _FONT14: regs.W.ax = 0x1111; regs.h.bl = 0x00; PDCINT(0x10, regs); } } break; case _VGACOLOR: case _VGAMONO: if (sizeable && (pdc_font != size)) { switch (size) { case _FONT8: regs.W.ax = 0x1112; regs.h.bl = 0x00; PDCINT(0x10, regs); break; case _FONT14: regs.W.ax = 0x1111; regs.h.bl = 0x00; PDCINT(0x10, regs); break; case _FONT16: regs.W.ax = 0x1114; regs.h.bl = 0x00; PDCINT(0x10, regs); } } } curs_set(SP->visibility); pdc_font = _get_font(); } /* _set_80x25() - force a known screen state: 80x25 text mode. Forces the appropriate 80x25 alpha mode given the display adapter. */ static void _set_80x25(void) { PDCREGS regs; switch (pdc_adapter) { case _CGA: case _EGACOLOR: case _EGAMONO: case _VGACOLOR: case _VGAMONO: case _MCGACOLOR: case _MCGAMONO: regs.h.ah = 0x00; regs.h.al = 0x03; PDCINT(0x10, regs); break; case _MDA: regs.h.ah = 0x00; regs.h.al = 0x07; PDCINT(0x10, regs); } } /* _get_scrn_mode() - Return the current BIOS video mode */ static int _get_scrn_mode(void) { PDCREGS regs; regs.h.ah = 0x0f; PDCINT(0x10, regs); return (int)regs.h.al; } /* _set_scrn_mode() - Sets the BIOS Video Mode Number only if it is different from the current video mode. */ static void _set_scrn_mode(int new_mode) { PDCREGS regs; if (_get_scrn_mode() != new_mode) { regs.h.ah = 0; regs.h.al = (unsigned char) new_mode; PDCINT(0x10, regs); } pdc_font = _get_font(); pdc_scrnmode = new_mode; LINES = PDC_get_rows(); COLS = PDC_get_columns(); } /* _sanity_check() - A video adapter identification sanity check. This routine will force sane values for various control flags. */ static int _sanity_check(int adapter) { int fontsize = _get_font(); int rows = PDC_get_rows(); PDC_LOG(("_sanity_check() - called: Adapter %d\n", adapter)); switch (adapter) { case _EGACOLOR: case _EGAMONO: switch (rows) { case 25: case 43: break; default: pdc_bogus_adapter = TRUE; } switch (fontsize) { case _FONT8: case _FONT14: break; default: pdc_bogus_adapter = TRUE; } break; case _VGACOLOR: case _VGAMONO: break; case _CGA: case _MDA: case _MCGACOLOR: case _MCGAMONO: switch (rows) { case 25: break; default: pdc_bogus_adapter = TRUE; } break; default: pdc_bogus_adapter = TRUE; } if (pdc_bogus_adapter) { sizeable = FALSE; pdc_direct_video = FALSE; } return adapter; } /* _query_adapter_type() - Determine PC video adapter type. */ static int _query_adapter_type(void) { PDCREGS regs; int retval = _NONE; /* thanks to paganini@ax.apc.org for the GO32 fix */ #if !defined(__DJGPP__) && !defined(__WATCOMC__) struct SREGS segs; #endif short video_base = getdosmemword(0x463); PDC_LOG(("_query_adapter_type() - called\n")); /* attempt to call VGA Identify Adapter Function */ regs.W.ax = 0x1a00; PDCINT(0x10, regs); if ((regs.h.al == 0x1a) && (retval == _NONE)) { /* We know that the PS/2 video BIOS is alive and well. */ switch (regs.h.al) { case 0: retval = _NONE; break; case 1: retval = _MDA; break; case 2: retval = _CGA; break; case 4: retval = _EGACOLOR; sizeable = TRUE; break; case 5: retval = _EGAMONO; break; case 26: /* ...alt. VGA BIOS... */ case 7: retval = _VGACOLOR; sizeable = TRUE; break; case 8: retval = _VGAMONO; break; case 10: case 13: retval = _MCGACOLOR; break; case 12: retval = _MCGAMONO; break; default: retval = _CGA; } } else { /* No VGA BIOS, check for an EGA BIOS by selecting an Alternate Function Service... bx == 0x0010 --> return EGA information */ regs.h.ah = 0x12; regs.W.bx = 0x10; PDCINT(0x10, regs); if ((regs.h.bl != 0x10) && (retval == _NONE)) { /* An EGA BIOS exists */ regs.h.ah = 0x12; regs.h.bl = 0x10; PDCINT(0x10, regs); if (regs.h.bh == 0) retval = _EGACOLOR; else retval = _EGAMONO; } else if (retval == _NONE) { /* Now we know we only have CGA or MDA */ PDCINT(0x11, regs); switch (regs.h.al & 0x30) { case 0x10: case 0x20: retval = _CGA; break; case 0x30: retval = _MDA; break; default: retval = _NONE; } } } if (video_base == 0x3d4) { pdc_video_seg = 0xb800; switch (retval) { case _EGAMONO: retval = _EGACOLOR; break; case _VGAMONO: retval = _VGACOLOR; } } if (video_base == 0x3b4) { pdc_video_seg = 0xb000; switch (retval) { case _EGACOLOR: retval = _EGAMONO; break; case _VGACOLOR: retval = _VGAMONO; } } if ((retval == _NONE) #ifndef CGA_DIRECT || (retval == _CGA) #endif ) pdc_direct_video = FALSE; if ((unsigned)pdc_video_seg == 0xb000) SP->mono = TRUE; else SP->mono = FALSE; /* Check for DESQview shadow buffer thanks to paganini@ax.apc.org for the GO32 fix */ #ifndef __WATCOMC__ regs.h.ah = 0xfe; regs.h.al = 0; regs.x.di = pdc_video_ofs; # ifdef __DJGPP__ regs.x.es = pdc_video_seg; __dpmi_int(0x10, ®s); pdc_video_seg = regs.x.es; # else segs.es = pdc_video_seg; int86x(0x10, ®s, ®s, &segs); pdc_video_seg = segs.es; # endif pdc_video_ofs = regs.x.di; #endif if (!pdc_adapter) pdc_adapter = retval; return _sanity_check(retval); } /* close the physical screen -- may restore the screen to its state before PDC_scr_open(); miscellaneous cleanup */ void PDC_scr_close(void) { #if SMALL || MEDIUM # ifndef __PACIFIC__ struct SREGS segregs; # endif int ds; #endif PDC_LOG(("PDC_scr_close() - called\n")); if (getenv("PDC_RESTORE_SCREEN") && saved_screen) { #ifdef __DJGPP__ dosmemput(saved_screen, saved_lines * saved_cols * 2, (unsigned long)_FAR_POINTER(pdc_video_seg, pdc_video_ofs)); #else # if (SMALL || MEDIUM) # ifdef __PACIFIC__ ds = FP_SEG((void far *)saved_screen); # else segread(&segregs); ds = segregs.ds; # endif movedata(ds, (int)saved_screen, pdc_video_seg, pdc_video_ofs, (saved_lines * saved_cols * 2)); # else memcpy((void *)_FAR_POINTER(pdc_video_seg, pdc_video_ofs), (void *)saved_screen, (saved_lines * saved_cols * 2)); # endif #endif free(saved_screen); saved_screen = NULL; } reset_shell_mode(); if (SP->visibility != 1) curs_set(1); /* Position cursor to the bottom left of the screen. */ PDC_gotoyx(PDC_get_rows() - 2, 0); } void PDC_scr_free(void) { if (SP) free(SP); if (pdc_atrtab) free(pdc_atrtab); pdc_atrtab = (unsigned char *)NULL; } /* open the physical screen -- allocate SP, miscellaneous intialization, and may save the existing screen for later restoration */ int PDC_scr_open(int argc, char **argv) { #if SMALL || MEDIUM # ifndef __PACIFIC__ struct SREGS segregs; # endif int ds; #endif int i; PDC_LOG(("PDC_scr_open() - called\n")); SP = calloc(1, sizeof(SCREEN)); pdc_atrtab = calloc(PDC_COLOR_PAIRS * PDC_OFFSET, 1); if (!SP || !pdc_atrtab) return ERR; for (i = 0; i < 16; i++) curstoreal[realtocurs[i]] = i; SP->orig_attr = FALSE; pdc_direct_video = TRUE; /* Assume that we can */ pdc_video_seg = 0xb000; /* Base screen segment addr */ pdc_video_ofs = 0x0; /* Base screen segment ofs */ pdc_adapter = _query_adapter_type(); pdc_scrnmode = _get_scrn_mode(); pdc_font = _get_font(); SP->lines = PDC_get_rows(); SP->cols = PDC_get_columns(); SP->mouse_wait = PDC_CLICK_PERIOD; SP->audible = TRUE; /* If the environment variable PDCURSES_BIOS is set, the DOS int10() BIOS calls are used in place of direct video memory access. */ if (getenv("PDCURSES_BIOS")) pdc_direct_video = FALSE; /* This code for preserving the current screen. */ if (getenv("PDC_RESTORE_SCREEN")) { saved_lines = SP->lines; saved_cols = SP->cols; saved_screen = malloc(saved_lines * saved_cols * 2); if (!saved_screen) { SP->_preserve = FALSE; return OK; } #ifdef __DJGPP__ dosmemget((unsigned long)_FAR_POINTER(pdc_video_seg, pdc_video_ofs), saved_lines * saved_cols * 2, saved_screen); #else # if SMALL || MEDIUM # ifdef __PACIFIC__ ds = FP_SEG((void far *) saved_screen); # else segread(&segregs); ds = segregs.ds; # endif movedata(pdc_video_seg, pdc_video_ofs, ds, (int)saved_screen, (saved_lines * saved_cols * 2)); # else memcpy((void *)saved_screen, (void *)_FAR_POINTER(pdc_video_seg, pdc_video_ofs), (saved_lines * saved_cols * 2)); # endif #endif } SP->_preserve = (getenv("PDC_PRESERVE_SCREEN") != NULL); return OK; } /* the core of resize_term() */ int PDC_resize_screen(int nlines, int ncols) { PDC_LOG(("PDC_resize_screen() - called. Lines: %d Cols: %d\n", nlines, ncols)); /* Trash the stored value of orig_cursor -- it's only good if the video mode doesn't change */ SP->orig_cursor = 0x0607; switch (pdc_adapter) { case _EGACOLOR: if (nlines >= 43) _set_font(_FONT8); else _set_80x25(); break; case _VGACOLOR: if (nlines > 28) _set_font(_FONT8); else if (nlines > 25) _set_font(_FONT14); else _set_80x25(); } PDC_set_blink(COLORS == 8); return OK; } void PDC_reset_prog_mode(void) { PDC_LOG(("PDC_reset_prog_mode() - called.\n")); } void PDC_reset_shell_mode(void) { PDC_LOG(("PDC_reset_shell_mode() - called.\n")); } void PDC_restore_screen_mode(int i) { if (i >= 0 && i <= 2) { pdc_font = _get_font(); _set_font(saved_font[i]); if (_get_scrn_mode() != saved_scrnmode[i]) _set_scrn_mode(saved_scrnmode[i]); } } void PDC_save_screen_mode(int i) { if (i >= 0 && i <= 2) { saved_font[i] = pdc_font; saved_scrnmode[i] = pdc_scrnmode; } } void PDC_init_pair(short pair, short fg, short bg) { unsigned char att, temp_bg; chtype i; fg = curstoreal[fg]; bg = curstoreal[bg]; for (i = 0; i < PDC_OFFSET; i++) { att = fg | (bg << 4); if (i & (A_REVERSE >> PDC_ATTR_SHIFT)) att = bg | (fg << 4); if (i & (A_UNDERLINE >> PDC_ATTR_SHIFT)) att = 1; if (i & (A_INVIS >> PDC_ATTR_SHIFT)) { temp_bg = att >> 4; att = temp_bg << 4 | temp_bg; } if (i & (A_BOLD >> PDC_ATTR_SHIFT)) att |= 8; if (i & (A_BLINK >> PDC_ATTR_SHIFT)) att |= 128; pdc_atrtab[pair * PDC_OFFSET + i] = att; } } int PDC_pair_content(short pair, short *fg, short *bg) { *fg = realtocurs[pdc_atrtab[pair * PDC_OFFSET] & 0x0F]; *bg = realtocurs[(pdc_atrtab[pair * PDC_OFFSET] & 0xF0) >> 4]; return OK; } /* _egapal() - Find the EGA palette value (0-63) for the color (0-15). On VGA, this is an index into the DAC. */ static short _egapal(short color) { PDCREGS regs; regs.W.ax = 0x1007; regs.h.bl = curstoreal[color]; PDCINT(0x10, regs); return regs.h.bh; } bool PDC_can_change_color(void) { return (pdc_adapter == _VGACOLOR); } /* These are only valid when pdc_adapter == _VGACOLOR */ int PDC_color_content(short color, short *red, short *green, short *blue) { PDCREGS regs; /* Read single DAC register */ regs.W.ax = 0x1015; regs.h.bl = _egapal(color); PDCINT(0x10, regs); /* Scale and store */ *red = DIVROUND((unsigned)(regs.h.dh) * 1000, 63); *green = DIVROUND((unsigned)(regs.h.ch) * 1000, 63); *blue = DIVROUND((unsigned)(regs.h.cl) * 1000, 63); return OK; } int PDC_init_color(short color, short red, short green, short blue) { PDCREGS regs; /* Scale */ regs.h.dh = DIVROUND((unsigned)red * 63, 1000); regs.h.ch = DIVROUND((unsigned)green * 63, 1000); regs.h.cl = DIVROUND((unsigned)blue * 63, 1000); /* Set single DAC register */ regs.W.ax = 0x1010; regs.W.bx = _egapal(color); PDCINT(0x10, regs); return OK; }