1 /* Public Domain Curses */
5 RCSID("$Id: pdcscrn.c,v 1.89 2008/07/13 16:08:17 wmcbrine Exp $")
10 # define PDC_OFFSET 32
15 /* COLOR_PAIR to attribute encoding table. */
17 unsigned char *pdc_atrtab
= (unsigned char *)NULL
;
19 int pdc_adapter
; /* screen type */
20 int pdc_scrnmode
; /* default screen mode */
21 int pdc_font
; /* default font size */
22 bool pdc_direct_video
; /* allow direct screen memory writes */
23 bool pdc_bogus_adapter
; /* TRUE if adapter has insane values */
24 unsigned pdc_video_seg
; /* video base segment */
25 unsigned pdc_video_ofs
; /* video base offset */
27 static short curstoreal
[16], realtocurs
[16] =
29 COLOR_BLACK
, COLOR_BLUE
, COLOR_GREEN
, COLOR_CYAN
, COLOR_RED
,
30 COLOR_MAGENTA
, COLOR_YELLOW
, COLOR_WHITE
, COLOR_BLACK
+ 8,
31 COLOR_BLUE
+ 8, COLOR_GREEN
+ 8, COLOR_CYAN
+ 8, COLOR_RED
+ 8,
32 COLOR_MAGENTA
+ 8, COLOR_YELLOW
+ 8, COLOR_WHITE
+ 8
35 static bool sizeable
= FALSE
; /* TRUE if adapter is resizeable */
37 static unsigned short *saved_screen
= NULL
;
38 static int saved_lines
= 0;
39 static int saved_cols
= 0;
41 static int saved_scrnmode
[3];
42 static int saved_font
[3];
44 /* Thanks to Jeff Duntemann, K16RA for providing the impetus
45 (through the Dr. Dobbs Journal, March 1989 issue) for getting
46 the routines below merged into Bjorn Larsson's PDCurses 1.3...
47 -- frotz@dri.com 900730 */
49 /* _get_font() - Get the current font size */
51 static int _get_font(void)
55 retval
= getdosmemword(0x485);
57 /* Assume the MDS Genius is in 66 line mode. */
59 if ((retval
== 0) && (pdc_adapter
== _MDS_GENIUS
))
65 retval
= 10; /* POINTS is not certain on MDA/Hercules */
87 /* _set_font() - Sets the current font size, if the adapter allows such a
88 change. It is an error to attempt to change the font size on a
89 "bogus" adapter. The reason for this is that we have a known video
90 adapter identity problem. e.g. Two adapters report the same identifying
93 static void _set_font(int size
)
97 if (pdc_bogus_adapter
)
111 if (sizeable
&& (pdc_font
!= size
))
130 if (sizeable
&& (pdc_font
!= size
))
152 curs_set(SP
->visibility
);
154 pdc_font
= _get_font();
157 /* _set_80x25() - force a known screen state: 80x25 text mode. Forces the
158 appropriate 80x25 alpha mode given the display adapter. */
160 static void _set_80x25(void)
184 /* _get_scrn_mode() - Return the current BIOS video mode */
186 static int _get_scrn_mode(void)
193 return (int)regs
.h
.al
;
196 /* _set_scrn_mode() - Sets the BIOS Video Mode Number only if it is
197 different from the current video mode. */
199 static void _set_scrn_mode(int new_mode
)
203 if (_get_scrn_mode() != new_mode
)
206 regs
.h
.al
= (unsigned char) new_mode
;
210 pdc_font
= _get_font();
211 pdc_scrnmode
= new_mode
;
212 LINES
= PDC_get_rows();
213 COLS
= PDC_get_columns();
216 /* _sanity_check() - A video adapter identification sanity check. This
217 routine will force sane values for various control flags. */
219 static int _sanity_check(int adapter
)
221 int fontsize
= _get_font();
222 int rows
= PDC_get_rows();
224 PDC_LOG(("_sanity_check() - called: Adapter %d\n", adapter
));
236 pdc_bogus_adapter
= TRUE
;
245 pdc_bogus_adapter
= TRUE
;
262 pdc_bogus_adapter
= TRUE
;
267 pdc_bogus_adapter
= TRUE
;
270 if (pdc_bogus_adapter
)
273 pdc_direct_video
= FALSE
;
279 /* _query_adapter_type() - Determine PC video adapter type. */
281 static int _query_adapter_type(void)
286 /* thanks to paganini@ax.apc.org for the GO32 fix */
288 #if !defined(__DJGPP__) && !defined(__WATCOMC__)
291 short video_base
= getdosmemword(0x463);
293 PDC_LOG(("_query_adapter_type() - called\n"));
295 /* attempt to call VGA Identify Adapter Function */
300 if ((regs
.h
.al
== 0x1a) && (retval
== _NONE
))
302 /* We know that the PS/2 video BIOS is alive and well. */
322 case 26: /* ...alt. VGA BIOS... */
343 /* No VGA BIOS, check for an EGA BIOS by selecting an
344 Alternate Function Service...
346 bx == 0x0010 --> return EGA information */
352 if ((regs
.h
.bl
!= 0x10) && (retval
== _NONE
))
354 /* An EGA BIOS exists */
365 else if (retval
== _NONE
)
367 /* Now we know we only have CGA or MDA */
371 switch (regs
.h
.al
& 0x30)
386 if (video_base
== 0x3d4)
388 pdc_video_seg
= 0xb800;
399 if (video_base
== 0x3b4)
401 pdc_video_seg
= 0xb000;
412 if ((retval
== _NONE
)
417 pdc_direct_video
= FALSE
;
419 if ((unsigned)pdc_video_seg
== 0xb000)
424 /* Check for DESQview shadow buffer
425 thanks to paganini@ax.apc.org for the GO32 fix */
430 regs
.x
.di
= pdc_video_ofs
;
432 regs
.x
.es
= pdc_video_seg
;
433 __dpmi_int(0x10, ®s
);
434 pdc_video_seg
= regs
.x
.es
;
436 segs
.es
= pdc_video_seg
;
437 int86x(0x10, ®s
, ®s
, &segs
);
438 pdc_video_seg
= segs
.es
;
440 pdc_video_ofs
= regs
.x
.di
;
443 pdc_adapter
= retval
;
445 return _sanity_check(retval
);
448 /* close the physical screen -- may restore the screen to its state
449 before PDC_scr_open(); miscellaneous cleanup */
451 void PDC_scr_close(void)
455 struct SREGS segregs
;
459 PDC_LOG(("PDC_scr_close() - called\n"));
461 if (getenv("PDC_RESTORE_SCREEN") && saved_screen
)
464 dosmemput(saved_screen
, saved_lines
* saved_cols
* 2,
465 (unsigned long)_FAR_POINTER(pdc_video_seg
,
468 # if (SMALL || MEDIUM)
470 ds
= FP_SEG((void far
*)saved_screen
);
475 movedata(ds
, (int)saved_screen
, pdc_video_seg
, pdc_video_ofs
,
476 (saved_lines
* saved_cols
* 2));
478 memcpy((void *)_FAR_POINTER(pdc_video_seg
, pdc_video_ofs
),
479 (void *)saved_screen
, (saved_lines
* saved_cols
* 2));
488 if (SP
->visibility
!= 1)
491 /* Position cursor to the bottom left of the screen. */
493 PDC_gotoyx(PDC_get_rows() - 2, 0);
496 void PDC_scr_free(void)
503 pdc_atrtab
= (unsigned char *)NULL
;
506 /* open the physical screen -- allocate SP, miscellaneous intialization,
507 and may save the existing screen for later restoration */
509 int PDC_scr_open(int argc
, char **argv
)
513 struct SREGS segregs
;
519 PDC_LOG(("PDC_scr_open() - called\n"));
521 SP
= calloc(1, sizeof(SCREEN
));
522 pdc_atrtab
= calloc(PDC_COLOR_PAIRS
* PDC_OFFSET
, 1);
524 if (!SP
|| !pdc_atrtab
)
527 for (i
= 0; i
< 16; i
++)
528 curstoreal
[realtocurs
[i
]] = i
;
530 SP
->orig_attr
= FALSE
;
532 pdc_direct_video
= TRUE
; /* Assume that we can */
533 pdc_video_seg
= 0xb000; /* Base screen segment addr */
534 pdc_video_ofs
= 0x0; /* Base screen segment ofs */
536 pdc_adapter
= _query_adapter_type();
537 pdc_scrnmode
= _get_scrn_mode();
538 pdc_font
= _get_font();
540 SP
->lines
= PDC_get_rows();
541 SP
->cols
= PDC_get_columns();
543 SP
->mouse_wait
= PDC_CLICK_PERIOD
;
546 /* If the environment variable PDCURSES_BIOS is set, the DOS int10()
547 BIOS calls are used in place of direct video memory access. */
549 if (getenv("PDCURSES_BIOS"))
550 pdc_direct_video
= FALSE
;
552 /* This code for preserving the current screen. */
554 if (getenv("PDC_RESTORE_SCREEN"))
556 saved_lines
= SP
->lines
;
557 saved_cols
= SP
->cols
;
559 saved_screen
= malloc(saved_lines
* saved_cols
* 2);
563 SP
->_preserve
= FALSE
;
567 dosmemget((unsigned long)_FAR_POINTER(pdc_video_seg
, pdc_video_ofs
),
568 saved_lines
* saved_cols
* 2, saved_screen
);
572 ds
= FP_SEG((void far
*) saved_screen
);
577 movedata(pdc_video_seg
, pdc_video_ofs
, ds
, (int)saved_screen
,
578 (saved_lines
* saved_cols
* 2));
580 memcpy((void *)saved_screen
,
581 (void *)_FAR_POINTER(pdc_video_seg
, pdc_video_ofs
),
582 (saved_lines
* saved_cols
* 2));
587 SP
->_preserve
= (getenv("PDC_PRESERVE_SCREEN") != NULL
);
592 /* the core of resize_term() */
594 int PDC_resize_screen(int nlines
, int ncols
)
596 PDC_LOG(("PDC_resize_screen() - called. Lines: %d Cols: %d\n",
599 /* Trash the stored value of orig_cursor -- it's only good if the
600 video mode doesn't change */
602 SP
->orig_cursor
= 0x0607;
623 PDC_set_blink(COLORS
== 8);
628 void PDC_reset_prog_mode(void)
630 PDC_LOG(("PDC_reset_prog_mode() - called.\n"));
633 void PDC_reset_shell_mode(void)
635 PDC_LOG(("PDC_reset_shell_mode() - called.\n"));
638 void PDC_restore_screen_mode(int i
)
640 if (i
>= 0 && i
<= 2)
642 pdc_font
= _get_font();
643 _set_font(saved_font
[i
]);
645 if (_get_scrn_mode() != saved_scrnmode
[i
])
646 _set_scrn_mode(saved_scrnmode
[i
]);
650 void PDC_save_screen_mode(int i
)
652 if (i
>= 0 && i
<= 2)
654 saved_font
[i
] = pdc_font
;
655 saved_scrnmode
[i
] = pdc_scrnmode
;
659 void PDC_init_pair(short pair
, short fg
, short bg
)
661 unsigned char att
, temp_bg
;
667 for (i
= 0; i
< PDC_OFFSET
; i
++)
669 att
= fg
| (bg
<< 4);
671 if (i
& (A_REVERSE
>> PDC_ATTR_SHIFT
))
672 att
= bg
| (fg
<< 4);
673 if (i
& (A_UNDERLINE
>> PDC_ATTR_SHIFT
))
675 if (i
& (A_INVIS
>> PDC_ATTR_SHIFT
))
678 att
= temp_bg
<< 4 | temp_bg
;
680 if (i
& (A_BOLD
>> PDC_ATTR_SHIFT
))
682 if (i
& (A_BLINK
>> PDC_ATTR_SHIFT
))
685 pdc_atrtab
[pair
* PDC_OFFSET
+ i
] = att
;
689 int PDC_pair_content(short pair
, short *fg
, short *bg
)
691 *fg
= realtocurs
[pdc_atrtab
[pair
* PDC_OFFSET
] & 0x0F];
692 *bg
= realtocurs
[(pdc_atrtab
[pair
* PDC_OFFSET
] & 0xF0) >> 4];
697 /* _egapal() - Find the EGA palette value (0-63) for the color (0-15).
698 On VGA, this is an index into the DAC. */
700 static short _egapal(short color
)
705 regs
.h
.bl
= curstoreal
[color
];
712 bool PDC_can_change_color(void)
714 return (pdc_adapter
== _VGACOLOR
);
717 /* These are only valid when pdc_adapter == _VGACOLOR */
719 int PDC_color_content(short color
, short *red
, short *green
, short *blue
)
723 /* Read single DAC register */
726 regs
.h
.bl
= _egapal(color
);
730 /* Scale and store */
732 *red
= DIVROUND((unsigned)(regs
.h
.dh
) * 1000, 63);
733 *green
= DIVROUND((unsigned)(regs
.h
.ch
) * 1000, 63);
734 *blue
= DIVROUND((unsigned)(regs
.h
.cl
) * 1000, 63);
739 int PDC_init_color(short color
, short red
, short green
, short blue
)
745 regs
.h
.dh
= DIVROUND((unsigned)red
* 63, 1000);
746 regs
.h
.ch
= DIVROUND((unsigned)green
* 63, 1000);
747 regs
.h
.cl
= DIVROUND((unsigned)blue
* 63, 1000);
749 /* Set single DAC register */
752 regs
.W
.bx
= _egapal(color
);