| /* 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; |
| } |