1 /* Public Domain Curses */
2
3 #include "pdcdos.h"
4
5 RCSID("$Id: pdcscrn.c,v 1.89 2008/07/13 16:08:17 wmcbrine Exp $")
6
7 #include <stdlib.h>
8
9 #ifdef CHTYPE_LONG
10 # define PDC_OFFSET 32
11 #else
12 # define PDC_OFFSET 8
13 #endif
14
15 /* COLOR_PAIR to attribute encoding table. */
16
17 unsigned char *pdc_atrtab = (unsigned char *)NULL;
18
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 */
26
27 static short curstoreal[16], realtocurs[16] =
28 {
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
33 };
34
35 static bool sizeable = FALSE; /* TRUE if adapter is resizeable */
36
37 static unsigned short *saved_screen = NULL;
38 static int saved_lines = 0;
39 static int saved_cols = 0;
40
41 static int saved_scrnmode[3];
42 static int saved_font[3];
43
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 -- [email protected] 900730 */
48
49 /* _get_font() - Get the current font size */
50
_get_font(void)51 static int _get_font(void)
52 {
53 int retval;
54
55 retval = getdosmemword(0x485);
56
57 /* Assume the MDS Genius is in 66 line mode. */
58
59 if ((retval == 0) && (pdc_adapter == _MDS_GENIUS))
60 retval = _FONT15;
61
62 switch (pdc_adapter)
63 {
64 case _MDA:
65 retval = 10; /* POINTS is not certain on MDA/Hercules */
66 break;
67
68 case _EGACOLOR:
69 case _EGAMONO:
70 switch (retval)
71 {
72 case _FONT8:
73 case _FONT14:
74 break;
75 default:
76 retval = _FONT14;
77 }
78 break;
79
80 case _CGA:
81 retval = _FONT8;
82 }
83
84 return retval;
85 }
86
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
91 characteristics. */
92
_set_font(int size)93 static void _set_font(int size)
94 {
95 PDCREGS regs;
96
97 if (pdc_bogus_adapter)
98 return;
99
100 switch (pdc_adapter)
101 {
102 case _CGA:
103 case _MDA:
104 case _MCGACOLOR:
105 case _MCGAMONO:
106 case _MDS_GENIUS:
107 break;
108
109 case _EGACOLOR:
110 case _EGAMONO:
111 if (sizeable && (pdc_font != size))
112 {
113 switch (size)
114 {
115 case _FONT8:
116 regs.W.ax = 0x1112;
117 regs.h.bl = 0x00;
118 PDCINT(0x10, regs);
119 break;
120 case _FONT14:
121 regs.W.ax = 0x1111;
122 regs.h.bl = 0x00;
123 PDCINT(0x10, regs);
124 }
125 }
126 break;
127
128 case _VGACOLOR:
129 case _VGAMONO:
130 if (sizeable && (pdc_font != size))
131 {
132 switch (size)
133 {
134 case _FONT8:
135 regs.W.ax = 0x1112;
136 regs.h.bl = 0x00;
137 PDCINT(0x10, regs);
138 break;
139 case _FONT14:
140 regs.W.ax = 0x1111;
141 regs.h.bl = 0x00;
142 PDCINT(0x10, regs);
143 break;
144 case _FONT16:
145 regs.W.ax = 0x1114;
146 regs.h.bl = 0x00;
147 PDCINT(0x10, regs);
148 }
149 }
150 }
151
152 curs_set(SP->visibility);
153
154 pdc_font = _get_font();
155 }
156
157 /* _set_80x25() - force a known screen state: 80x25 text mode. Forces the
158 appropriate 80x25 alpha mode given the display adapter. */
159
_set_80x25(void)160 static void _set_80x25(void)
161 {
162 PDCREGS regs;
163
164 switch (pdc_adapter)
165 {
166 case _CGA:
167 case _EGACOLOR:
168 case _EGAMONO:
169 case _VGACOLOR:
170 case _VGAMONO:
171 case _MCGACOLOR:
172 case _MCGAMONO:
173 regs.h.ah = 0x00;
174 regs.h.al = 0x03;
175 PDCINT(0x10, regs);
176 break;
177 case _MDA:
178 regs.h.ah = 0x00;
179 regs.h.al = 0x07;
180 PDCINT(0x10, regs);
181 }
182 }
183
184 /* _get_scrn_mode() - Return the current BIOS video mode */
185
_get_scrn_mode(void)186 static int _get_scrn_mode(void)
187 {
188 PDCREGS regs;
189
190 regs.h.ah = 0x0f;
191 PDCINT(0x10, regs);
192
193 return (int)regs.h.al;
194 }
195
196 /* _set_scrn_mode() - Sets the BIOS Video Mode Number only if it is
197 different from the current video mode. */
198
_set_scrn_mode(int new_mode)199 static void _set_scrn_mode(int new_mode)
200 {
201 PDCREGS regs;
202
203 if (_get_scrn_mode() != new_mode)
204 {
205 regs.h.ah = 0;
206 regs.h.al = (unsigned char) new_mode;
207 PDCINT(0x10, regs);
208 }
209
210 pdc_font = _get_font();
211 pdc_scrnmode = new_mode;
212 LINES = PDC_get_rows();
213 COLS = PDC_get_columns();
214 }
215
216 /* _sanity_check() - A video adapter identification sanity check. This
217 routine will force sane values for various control flags. */
218
_sanity_check(int adapter)219 static int _sanity_check(int adapter)
220 {
221 int fontsize = _get_font();
222 int rows = PDC_get_rows();
223
224 PDC_LOG(("_sanity_check() - called: Adapter %d\n", adapter));
225
226 switch (adapter)
227 {
228 case _EGACOLOR:
229 case _EGAMONO:
230 switch (rows)
231 {
232 case 25:
233 case 43:
234 break;
235 default:
236 pdc_bogus_adapter = TRUE;
237 }
238
239 switch (fontsize)
240 {
241 case _FONT8:
242 case _FONT14:
243 break;
244 default:
245 pdc_bogus_adapter = TRUE;
246 }
247 break;
248
249 case _VGACOLOR:
250 case _VGAMONO:
251 break;
252
253 case _CGA:
254 case _MDA:
255 case _MCGACOLOR:
256 case _MCGAMONO:
257 switch (rows)
258 {
259 case 25:
260 break;
261 default:
262 pdc_bogus_adapter = TRUE;
263 }
264 break;
265
266 default:
267 pdc_bogus_adapter = TRUE;
268 }
269
270 if (pdc_bogus_adapter)
271 {
272 sizeable = FALSE;
273 pdc_direct_video = FALSE;
274 }
275
276 return adapter;
277 }
278
279 /* _query_adapter_type() - Determine PC video adapter type. */
280
_query_adapter_type(void)281 static int _query_adapter_type(void)
282 {
283 PDCREGS regs;
284 int retval = _NONE;
285
286 /* thanks to [email protected] for the GO32 fix */
287
288 #if !defined(__DJGPP__) && !defined(__WATCOMC__)
289 struct SREGS segs;
290 #endif
291 short video_base = getdosmemword(0x463);
292
293 PDC_LOG(("_query_adapter_type() - called\n"));
294
295 /* attempt to call VGA Identify Adapter Function */
296
297 regs.W.ax = 0x1a00;
298 PDCINT(0x10, regs);
299
300 if ((regs.h.al == 0x1a) && (retval == _NONE))
301 {
302 /* We know that the PS/2 video BIOS is alive and well. */
303
304 switch (regs.h.al)
305 {
306 case 0:
307 retval = _NONE;
308 break;
309 case 1:
310 retval = _MDA;
311 break;
312 case 2:
313 retval = _CGA;
314 break;
315 case 4:
316 retval = _EGACOLOR;
317 sizeable = TRUE;
318 break;
319 case 5:
320 retval = _EGAMONO;
321 break;
322 case 26: /* ...alt. VGA BIOS... */
323 case 7:
324 retval = _VGACOLOR;
325 sizeable = TRUE;
326 break;
327 case 8:
328 retval = _VGAMONO;
329 break;
330 case 10:
331 case 13:
332 retval = _MCGACOLOR;
333 break;
334 case 12:
335 retval = _MCGAMONO;
336 break;
337 default:
338 retval = _CGA;
339 }
340 }
341 else
342 {
343 /* No VGA BIOS, check for an EGA BIOS by selecting an
344 Alternate Function Service...
345
346 bx == 0x0010 --> return EGA information */
347
348 regs.h.ah = 0x12;
349 regs.W.bx = 0x10;
350 PDCINT(0x10, regs);
351
352 if ((regs.h.bl != 0x10) && (retval == _NONE))
353 {
354 /* An EGA BIOS exists */
355
356 regs.h.ah = 0x12;
357 regs.h.bl = 0x10;
358 PDCINT(0x10, regs);
359
360 if (regs.h.bh == 0)
361 retval = _EGACOLOR;
362 else
363 retval = _EGAMONO;
364 }
365 else if (retval == _NONE)
366 {
367 /* Now we know we only have CGA or MDA */
368
369 PDCINT(0x11, regs);
370
371 switch (regs.h.al & 0x30)
372 {
373 case 0x10:
374 case 0x20:
375 retval = _CGA;
376 break;
377 case 0x30:
378 retval = _MDA;
379 break;
380 default:
381 retval = _NONE;
382 }
383 }
384 }
385
386 if (video_base == 0x3d4)
387 {
388 pdc_video_seg = 0xb800;
389 switch (retval)
390 {
391 case _EGAMONO:
392 retval = _EGACOLOR;
393 break;
394 case _VGAMONO:
395 retval = _VGACOLOR;
396 }
397 }
398
399 if (video_base == 0x3b4)
400 {
401 pdc_video_seg = 0xb000;
402 switch (retval)
403 {
404 case _EGACOLOR:
405 retval = _EGAMONO;
406 break;
407 case _VGACOLOR:
408 retval = _VGAMONO;
409 }
410 }
411
412 if ((retval == _NONE)
413 #ifndef CGA_DIRECT
414 || (retval == _CGA)
415 #endif
416 )
417 pdc_direct_video = FALSE;
418
419 if ((unsigned)pdc_video_seg == 0xb000)
420 SP->mono = TRUE;
421 else
422 SP->mono = FALSE;
423
424 /* Check for DESQview shadow buffer
425 thanks to [email protected] for the GO32 fix */
426
427 #ifndef __WATCOMC__
428 regs.h.ah = 0xfe;
429 regs.h.al = 0;
430 regs.x.di = pdc_video_ofs;
431 # ifdef __DJGPP__
432 regs.x.es = pdc_video_seg;
433 __dpmi_int(0x10, ®s);
434 pdc_video_seg = regs.x.es;
435 # else
436 segs.es = pdc_video_seg;
437 int86x(0x10, ®s, ®s, &segs);
438 pdc_video_seg = segs.es;
439 # endif
440 pdc_video_ofs = regs.x.di;
441 #endif
442 if (!pdc_adapter)
443 pdc_adapter = retval;
444
445 return _sanity_check(retval);
446 }
447
448 /* close the physical screen -- may restore the screen to its state
449 before PDC_scr_open(); miscellaneous cleanup */
450
PDC_scr_close(void)451 void PDC_scr_close(void)
452 {
453 #if SMALL || MEDIUM
454 # ifndef __PACIFIC__
455 struct SREGS segregs;
456 # endif
457 int ds;
458 #endif
459 PDC_LOG(("PDC_scr_close() - called\n"));
460
461 if (getenv("PDC_RESTORE_SCREEN") && saved_screen)
462 {
463 #ifdef __DJGPP__
464 dosmemput(saved_screen, saved_lines * saved_cols * 2,
465 (unsigned long)_FAR_POINTER(pdc_video_seg,
466 pdc_video_ofs));
467 #else
468 # if (SMALL || MEDIUM)
469 # ifdef __PACIFIC__
470 ds = FP_SEG((void far *)saved_screen);
471 # else
472 segread(&segregs);
473 ds = segregs.ds;
474 # endif
475 movedata(ds, (int)saved_screen, pdc_video_seg, pdc_video_ofs,
476 (saved_lines * saved_cols * 2));
477 # else
478 memcpy((void *)_FAR_POINTER(pdc_video_seg, pdc_video_ofs),
479 (void *)saved_screen, (saved_lines * saved_cols * 2));
480 # endif
481 #endif
482 free(saved_screen);
483 saved_screen = NULL;
484 }
485
486 reset_shell_mode();
487
488 if (SP->visibility != 1)
489 curs_set(1);
490
491 /* Position cursor to the bottom left of the screen. */
492
493 PDC_gotoyx(PDC_get_rows() - 2, 0);
494 }
495
PDC_scr_free(void)496 void PDC_scr_free(void)
497 {
498 if (SP)
499 free(SP);
500 if (pdc_atrtab)
501 free(pdc_atrtab);
502
503 pdc_atrtab = (unsigned char *)NULL;
504 }
505
506 /* open the physical screen -- allocate SP, miscellaneous intialization,
507 and may save the existing screen for later restoration */
508
PDC_scr_open(int argc,char ** argv)509 int PDC_scr_open(int argc, char **argv)
510 {
511 #if SMALL || MEDIUM
512 # ifndef __PACIFIC__
513 struct SREGS segregs;
514 # endif
515 int ds;
516 #endif
517 int i;
518
519 PDC_LOG(("PDC_scr_open() - called\n"));
520
521 SP = calloc(1, sizeof(SCREEN));
522 pdc_atrtab = calloc(PDC_COLOR_PAIRS * PDC_OFFSET, 1);
523
524 if (!SP || !pdc_atrtab)
525 return ERR;
526
527 for (i = 0; i < 16; i++)
528 curstoreal[realtocurs[i]] = i;
529
530 SP->orig_attr = FALSE;
531
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 */
535
536 pdc_adapter = _query_adapter_type();
537 pdc_scrnmode = _get_scrn_mode();
538 pdc_font = _get_font();
539
540 SP->lines = PDC_get_rows();
541 SP->cols = PDC_get_columns();
542
543 SP->mouse_wait = PDC_CLICK_PERIOD;
544 SP->audible = TRUE;
545
546 /* If the environment variable PDCURSES_BIOS is set, the DOS int10()
547 BIOS calls are used in place of direct video memory access. */
548
549 if (getenv("PDCURSES_BIOS"))
550 pdc_direct_video = FALSE;
551
552 /* This code for preserving the current screen. */
553
554 if (getenv("PDC_RESTORE_SCREEN"))
555 {
556 saved_lines = SP->lines;
557 saved_cols = SP->cols;
558
559 saved_screen = malloc(saved_lines * saved_cols * 2);
560
561 if (!saved_screen)
562 {
563 SP->_preserve = FALSE;
564 return OK;
565 }
566 #ifdef __DJGPP__
567 dosmemget((unsigned long)_FAR_POINTER(pdc_video_seg, pdc_video_ofs),
568 saved_lines * saved_cols * 2, saved_screen);
569 #else
570 # if SMALL || MEDIUM
571 # ifdef __PACIFIC__
572 ds = FP_SEG((void far *) saved_screen);
573 # else
574 segread(&segregs);
575 ds = segregs.ds;
576 # endif
577 movedata(pdc_video_seg, pdc_video_ofs, ds, (int)saved_screen,
578 (saved_lines * saved_cols * 2));
579 # else
580 memcpy((void *)saved_screen,
581 (void *)_FAR_POINTER(pdc_video_seg, pdc_video_ofs),
582 (saved_lines * saved_cols * 2));
583 # endif
584 #endif
585 }
586
587 SP->_preserve = (getenv("PDC_PRESERVE_SCREEN") != NULL);
588
589 return OK;
590 }
591
592 /* the core of resize_term() */
593
PDC_resize_screen(int nlines,int ncols)594 int PDC_resize_screen(int nlines, int ncols)
595 {
596 PDC_LOG(("PDC_resize_screen() - called. Lines: %d Cols: %d\n",
597 nlines, ncols));
598
599 /* Trash the stored value of orig_cursor -- it's only good if the
600 video mode doesn't change */
601
602 SP->orig_cursor = 0x0607;
603
604 switch (pdc_adapter)
605 {
606 case _EGACOLOR:
607 if (nlines >= 43)
608 _set_font(_FONT8);
609 else
610 _set_80x25();
611 break;
612
613 case _VGACOLOR:
614 if (nlines > 28)
615 _set_font(_FONT8);
616 else
617 if (nlines > 25)
618 _set_font(_FONT14);
619 else
620 _set_80x25();
621 }
622
623 PDC_set_blink(COLORS == 8);
624
625 return OK;
626 }
627
PDC_reset_prog_mode(void)628 void PDC_reset_prog_mode(void)
629 {
630 PDC_LOG(("PDC_reset_prog_mode() - called.\n"));
631 }
632
PDC_reset_shell_mode(void)633 void PDC_reset_shell_mode(void)
634 {
635 PDC_LOG(("PDC_reset_shell_mode() - called.\n"));
636 }
637
PDC_restore_screen_mode(int i)638 void PDC_restore_screen_mode(int i)
639 {
640 if (i >= 0 && i <= 2)
641 {
642 pdc_font = _get_font();
643 _set_font(saved_font[i]);
644
645 if (_get_scrn_mode() != saved_scrnmode[i])
646 _set_scrn_mode(saved_scrnmode[i]);
647 }
648 }
649
PDC_save_screen_mode(int i)650 void PDC_save_screen_mode(int i)
651 {
652 if (i >= 0 && i <= 2)
653 {
654 saved_font[i] = pdc_font;
655 saved_scrnmode[i] = pdc_scrnmode;
656 }
657 }
658
PDC_init_pair(short pair,short fg,short bg)659 void PDC_init_pair(short pair, short fg, short bg)
660 {
661 unsigned char att, temp_bg;
662 chtype i;
663
664 fg = curstoreal[fg];
665 bg = curstoreal[bg];
666
667 for (i = 0; i < PDC_OFFSET; i++)
668 {
669 att = fg | (bg << 4);
670
671 if (i & (A_REVERSE >> PDC_ATTR_SHIFT))
672 att = bg | (fg << 4);
673 if (i & (A_UNDERLINE >> PDC_ATTR_SHIFT))
674 att = 1;
675 if (i & (A_INVIS >> PDC_ATTR_SHIFT))
676 {
677 temp_bg = att >> 4;
678 att = temp_bg << 4 | temp_bg;
679 }
680 if (i & (A_BOLD >> PDC_ATTR_SHIFT))
681 att |= 8;
682 if (i & (A_BLINK >> PDC_ATTR_SHIFT))
683 att |= 128;
684
685 pdc_atrtab[pair * PDC_OFFSET + i] = att;
686 }
687 }
688
PDC_pair_content(short pair,short * fg,short * bg)689 int PDC_pair_content(short pair, short *fg, short *bg)
690 {
691 *fg = realtocurs[pdc_atrtab[pair * PDC_OFFSET] & 0x0F];
692 *bg = realtocurs[(pdc_atrtab[pair * PDC_OFFSET] & 0xF0) >> 4];
693
694 return OK;
695 }
696
697 /* _egapal() - Find the EGA palette value (0-63) for the color (0-15).
698 On VGA, this is an index into the DAC. */
699
_egapal(short color)700 static short _egapal(short color)
701 {
702 PDCREGS regs;
703
704 regs.W.ax = 0x1007;
705 regs.h.bl = curstoreal[color];
706
707 PDCINT(0x10, regs);
708
709 return regs.h.bh;
710 }
711
PDC_can_change_color(void)712 bool PDC_can_change_color(void)
713 {
714 return (pdc_adapter == _VGACOLOR);
715 }
716
717 /* These are only valid when pdc_adapter == _VGACOLOR */
718
PDC_color_content(short color,short * red,short * green,short * blue)719 int PDC_color_content(short color, short *red, short *green, short *blue)
720 {
721 PDCREGS regs;
722
723 /* Read single DAC register */
724
725 regs.W.ax = 0x1015;
726 regs.h.bl = _egapal(color);
727
728 PDCINT(0x10, regs);
729
730 /* Scale and store */
731
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);
735
736 return OK;
737 }
738
PDC_init_color(short color,short red,short green,short blue)739 int PDC_init_color(short color, short red, short green, short blue)
740 {
741 PDCREGS regs;
742
743 /* Scale */
744
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);
748
749 /* Set single DAC register */
750
751 regs.W.ax = 0x1010;
752 regs.W.bx = _egapal(color);
753
754 PDCINT(0x10, regs);
755
756 return OK;
757 }
758