7 #include <sys/signal.h>
21 #if defined(HAVE_FRIBIDI_FRIBIDI_H) && defined(HAVE_DLFCN_H)
22 #include <fribidi/fribidi.h>
25 /* No sense in enabling shaping if we don't have BIDI support. */
36 #define ARABIC_BASE 0x621
37 #define ARABIC_END 0x64A
39 static const arabic_char_node arabic_shaping_table
[] = {
40 /* 0x621 */ { TRUE
, 0xFE80, 0x0000, 0x0000, 0x0000},
41 /* 0x622 */ { TRUE
, 0xFE81, 0x0000, 0x0000, 0xFE82},
42 /* 0x623 */ { TRUE
, 0xFE83, 0x0000, 0x0000, 0xFE84},
43 /* 0x624 */ { TRUE
, 0xFE85, 0x0000, 0x0000, 0xFE86},
44 /* 0x625 */ { TRUE
, 0xFE87, 0x0000, 0x0000, 0xFE88},
45 /* 0x626 */ { TRUE
, 0xFE89, 0xFE8B, 0xFE8C, 0xFE8A},
46 /* 0x627 */ { TRUE
, 0xFE8D, 0x0000, 0x0000, 0xFE8E},
47 /* 0x628 */ { TRUE
, 0xFE8F, 0xFE91, 0xFE92, 0xFE90},
48 /* 0x629 */ { TRUE
, 0xFE93, 0x0000, 0x0000, 0xFE94},
49 /* 0x62A */ { TRUE
, 0xFE95, 0xFE97, 0xFE98, 0xFE96},
50 /* 0x62B */ { TRUE
, 0xFE99, 0xFE9B, 0xFE9C, 0xFE9A},
51 /* 0x62C */ { TRUE
, 0xFE9D, 0xFE9F, 0xFEA0, 0xFE9E},
52 /* 0x62D */ { TRUE
, 0xFEA1, 0xFEA3, 0xFEA4, 0xFEA2},
53 /* 0x62E */ { TRUE
, 0xFEA5, 0xFEA7, 0xFEA8, 0xFEA6},
54 /* 0x62F */ { TRUE
, 0xFEA9, 0x0000, 0x0000, 0xFEAA},
55 /* 0x630 */ { TRUE
, 0xFEAB, 0x0000, 0x0000, 0xFEAC},
56 /* 0x631 */ { TRUE
, 0xFEAD, 0x0000, 0x0000, 0xFEAE},
57 /* 0x632 */ { TRUE
, 0xFEAF, 0x0000, 0x0000, 0xFEB0},
58 /* 0x633 */ { TRUE
, 0xFEB1, 0xFEB3, 0xFEB4, 0xFEB2},
59 /* 0x634 */ { TRUE
, 0xFEB5, 0xFEB7, 0xFEB8, 0xFEB6},
60 /* 0x635 */ { TRUE
, 0xFEB9, 0xFEBB, 0xFEBC, 0xFEBA},
61 /* 0x636 */ { TRUE
, 0xFEBD, 0xFEBF, 0xFEC0, 0xFEBE},
62 /* 0x637 */ { TRUE
, 0xFEC1, 0xFEC3, 0xFEC4, 0xFEC2},
63 /* 0x638 */ { TRUE
, 0xFEC5, 0xFEC7, 0xFEC8, 0xFEC6},
64 /* 0x639 */ { TRUE
, 0xFEC9, 0xFECB, 0xFECC, 0xFECA},
65 /* 0x63A */ { TRUE
, 0xFECD, 0xFECF, 0xFED0, 0xFECE},
66 /* 0x63B */ { FALSE
, 0x0000, 0x0000, 0x0000, 0x0000},
67 /* 0x63C */ { FALSE
, 0x0000, 0x0000, 0x0000, 0x0000},
68 /* 0x63D */ { FALSE
, 0x0000, 0x0000, 0x0000, 0x0000},
69 /* 0x63E */ { FALSE
, 0x0000, 0x0000, 0x0000, 0x0000},
70 /* 0x63F */ { FALSE
, 0x0000, 0x0000, 0x0000, 0x0000},
71 /* 0x640 */ { TRUE
, 0x0640, 0x0640, 0x0640, 0x0640},
72 /* 0x641 */ { TRUE
, 0xFED1, 0xFED3, 0xFED4, 0xFED2},
73 /* 0x642 */ { TRUE
, 0xFED5, 0xFED7, 0xFED8, 0xFED6},
74 /* 0x643 */ { TRUE
, 0xFED9, 0xFEDB, 0xFEDC, 0xFEDA},
75 /* 0x644 */ { TRUE
, 0xFEDD, 0xFEDF, 0xFEE0, 0xFEDE},
76 /* 0x645 */ { TRUE
, 0xFEE1, 0xFEE3, 0xFEE4, 0xFEE2},
77 /* 0x646 */ { TRUE
, 0xFEE5, 0xFEE7, 0xFEE8, 0xFEE6},
78 /* 0x647 */ { TRUE
, 0xFEE9, 0xFEEB, 0xFEEC, 0xFEEA},
79 /* 0x648 */ { TRUE
, 0xFEED, 0x0000, 0x0000, 0xFEEE},
80 /* 0x649 */ { TRUE
, 0xFEEF, 0x0000, 0x0000, 0xFEF0},
81 /* 0x64A */ { TRUE
, 0xFEF1, 0xFEF3, 0xFEF4, 0xFEF2}
86 arabic_char_node ar_node
;
90 #define EXTRA_BASE 0x67E
91 #define EXTRA_END 0x6CC
92 static const extra_char_node extra_shaping_table
[] = {
93 {0x067E, {TRUE
, 0xFB56, 0xFB58, 0xFB59, 0xFB57}},
94 {0x0686, {TRUE
, 0xFB7A, 0xFB7C, 0xFB7D, 0xFB7B}},
95 {0x0698, {TRUE
, 0xFB8A, 0x0000, 0x0000, 0xFB8B}},
96 {0x06A9, {TRUE
, 0xFB8E, 0xFB90, 0xFB91, 0xFB8F}},
97 {0x06AF, {TRUE
, 0xFB92, 0xFB94, 0xFB95, 0xFB93}},
98 {0x06CC, {TRUE
, 0xFBFC, 0xFBFE, 0xFBFF, 0xFBFD}},
99 {0x0000, {FALSE
, 0x0000, 0x0000, 0x0000, 0x0000}},
102 static const arabic_char_node
*get_char_node(wchar_t w
)
104 if (w
>= ARABIC_BASE
&& w
<= ARABIC_END
)
105 return &arabic_shaping_table
[w
- ARABIC_BASE
];
106 else if (w
>= EXTRA_BASE
&& w
<= EXTRA_END
) {
107 const extra_char_node
*node
= extra_shaping_table
;
111 return &node
->ar_node
;
119 static int do_shaping(wchar_t *buf
, int len
) {
127 newbuf
= (wchar_t *)malloc(sizeof(wchar_t)*len
);
129 for (i
= 0, j
= 0; i
< len
; i
++, j
++) {
130 int have_previous
= FALSE
, have_next
= FALSE
;
131 const arabic_char_node
*node
, *node1
;
137 /* If it is non-joiner, ignore it */
138 if (buf
[i
] == 0x200C) {
145 /* If it's not in our range, skip it. */
146 node
= get_char_node(buf
[i
]);
152 /* The character wasn't included in the unicode shaping table. */
153 if (!node
->is_shaped
)
158 for (prev
= i
- 1; prev
>= 0; prev
--)
159 if (wcwidth(buf
[prev
]) || buf
[prev
] == 0x200C)
162 if (prev
>= 0 && (node1
= get_char_node(buf
[prev
]))
163 && ( node1
->initial
|| node1
->medial
))
165 have_previous
= TRUE
;
168 for (next
= i
+ 1; next
< len
; next
++)
169 if (wcwidth(buf
[next
]) || buf
[next
] == 0x200C)
172 if (next
< len
&& (node1
= get_char_node(buf
[next
]))
173 && (node1
->medial
|| node1
->final
))
179 * FIXME: do not make ligature if there are combining
180 * characters between two parts.
182 if (buf
[i
] == 0x644 && have_next
&& next
== i
+ 1)
187 newbuf
[j
] = 0xFEF5 + (have_previous
? 1 : 0);
191 newbuf
[j
] = 0xFEF7 + (have_previous
? 1 : 0);
195 newbuf
[j
] = 0xFEF9 + (have_previous
? 1 : 0);
199 newbuf
[j
] = 0xFEFB + (have_previous
? 1 : 0);
208 if (have_previous
&& have_next
&& node
->medial
)
210 newbuf
[j
] = node
->medial
;
214 else if (have_previous
&& node
->final
)
216 newbuf
[j
] = node
->final
;
220 else if (have_next
&& node
->initial
)
222 newbuf
[j
] = node
->initial
;
226 else if (node
->isolated
)
228 newbuf
[j
] = node
->isolated
;
231 for (i
= 0; i
< len
&& i
< j
; i
++) {
242 /* Converts bidi wchar text {in} to visual wchar text which is displayable
243 * in text mode. Uses {base_dir} as default base direction.
244 * Returns malloc'ed converted text or NULL in case of error or if {need_out} is
245 * not set. Modifies {base_dir} to reflect actual direction.
247 static wchar_t* wchar_to_textmod_visual(wchar_t *in
,unsigned int len
,FriBidiCharType
*base_dir
, int need_out
)
249 FriBidiChar
*out
= NULL
;
250 static void *handle
= NULL
;
252 fribidi_boolean (*func_ptr
) (FriBidiChar
*, FriBidiStrIndex
,
253 FriBidiCharType
*, FriBidiChar
*,
254 FriBidiStrIndex
*, FriBidiStrIndex
*,
258 handle
= dlopen("/usr/lib/libfribidi.so.0", RTLD_LAZY
| RTLD_GLOBAL
);
260 handle
= dlopen("/lib/libfribidi.so.0", RTLD_LAZY
| RTLD_GLOBAL
);
264 func_ptr
= dlsym(handle
, "fribidi_log2vis");
272 out
= (FriBidiChar
*)malloc(sizeof(FriBidiChar
)*(len
+1));
277 return (wchar_t *) out
;
281 len
= wcsnlen(in
, len
);
283 (*func_ptr
)(in
, len
, base_dir
, out
, NULL
, NULL
, NULL
);
285 return (wchar_t *) out
;
289 * Converts text given in {str} from logical order to visual order.
290 * Uses {dir} as base direction ('N', 'R', 'L').
291 * Returns malloc'ed converted string. Modifies {dir} to reflect actual
294 static char *_newt_log2vis(const char *str
, char *dir
)
298 int len
= strlen(str
);
300 FriBidiCharType basedir
;
304 case 'R': basedir
= FRIBIDI_TYPE_R
;
306 case 'L': basedir
= FRIBIDI_TYPE_L
;
308 default: basedir
= FRIBIDI_TYPE_ON
;
316 wcs
= malloc(sizeof(*wcs
) * (len
+ 1));
319 ret
= mbstowcs(wcs
, str
, len
+ 1);
324 owcs
= wchar_to_textmod_visual(wcs
, ret
, &basedir
, 1);
325 if (FRIBIDI_DIR_TO_LEVEL(basedir
))
334 newlen
= wcstombs(NULL
, owcs
, 0);
339 rstr
= malloc(newlen
+ 1);
344 ret
= wcstombs(rstr
, owcs
, newlen
+ 1);
354 /* Returns base direction of text given in {str}.
356 char get_text_direction(const char *str
)
358 int len
= strlen(str
);
363 FriBidiCharType basedir
= FRIBIDI_TYPE_ON
;
366 wcs
= malloc(sizeof(*wcs
) * (len
+ 1));
369 ret
= mbstowcs(wcs
, str
, len
+ 1);
374 wchar_to_textmod_visual(wcs
, ret
, &basedir
, 1);
376 if (FRIBIDI_DIR_TO_LEVEL(basedir
))
384 /* If width of string {str} is less then {width} adds
385 * final spaces to make it {width} position wide.
386 * Returns malloc'ed padded string or NULL in case of errors
387 * or if string does not need padding.
389 static char *pad_line(const char *str
, int width
)
391 int len
= strlen(str
);
392 int w
= _newt_wstrlen(str
, len
);
395 char *newstr
= malloc(len
+ 1 + (width
- w
));
398 memcpy(newstr
, str
, len
);
399 memset(newstr
+ len
, ' ', width
- w
);
400 newstr
[len
+width
-w
] = '\0';
407 * Writes string {str}. Uses {dir} as default direction.
408 * Returns direction of the string in {dir}.
410 void write_string_int(const char *str
, char *dir
)
420 tmpstr
= _newt_log2vis(str
, dir
);
423 SLsmg_write_string(str
);
428 /* Writes at most {n} positions of the string {str}.
429 * Adds final (logical) spaces if string width is less than {n}.
430 * Uses {dir} as default direction.
431 * Returns direction of the string in {dir}
433 void write_nstring_int(const char *str
, int n
, char *dir
)
436 char *tmpstr
, *tmpstr1
;
443 tmpstr1
= pad_line(str
, n
);
446 tmpstr
= _newt_log2vis(str
, dir
);
451 SLsmg_write_nstring(str
, n
);
458 void write_string_int(const char *str
, char *dir
)
460 SLsmg_write_string(str
);
463 void write_nstring_int(const char *str
, int w
, char *dir
)
465 SLsmg_write_nstring(str
, w
);
468 char get_text_direction(const char *str
)
475 int height
, width
, top
, left
;
476 SLsmg_Char_Type
* buffer
;
486 static struct Window windowStack
[20];
487 static struct Window
* currentWindow
= NULL
;
489 static char * helplineStack
[20];
490 static char ** currentHelpline
= NULL
;
492 static int cursorRow
, cursorCol
;
493 static int needResize
= 0;
494 static int cursorOn
= 1;
495 static int trashScreen
= 0;
497 static const char * defaultHelpLine
=
498 " <Tab>/<Alt-Tab> between elements | <Space> selects | <F12> next screen"
501 const struct newtColors newtDefaultColorPalette
= {
502 "white", "blue", /* root fg, bg */
503 "black", "lightgray", /* border fg, bg */
504 "black", "lightgray", /* window fg, bg */
505 "white", "black", /* shadow fg, bg */
506 "red", "lightgray", /* title fg, bg */
507 "lightgray", "red", /* button fg, bg */
508 "red", "lightgray", /* active button fg, bg */
509 "yellow", "blue", /* checkbox fg, bg */
510 "blue", "brown", /* active checkbox fg, bg */
511 "yellow", "blue", /* entry box fg, bg */
512 "blue", "lightgray", /* label fg, bg */
513 "black", "lightgray", /* listbox fg, bg */
514 "yellow", "blue", /* active listbox fg, bg */
515 "black", "lightgray", /* textbox fg, bg */
516 "lightgray", "black", /* active textbox fg, bg */
517 "white", "blue", /* help line */
518 "yellow", "blue", /* root text */
519 "blue", /* scale full */
520 "red", /* scale empty */
521 "blue", "lightgray", /* disabled entry fg, bg */
522 "black", "lightgray", /* compact button fg, bg */
523 "yellow", "red", /* active & sel listbox */
524 "black", "brown" /* selected listbox */
527 static const struct keymap keymap
[] = {
528 { "\033OA", NEWT_KEY_UP
, "ku" },
529 { "\020", NEWT_KEY_UP
, NULL
}, /* emacs ^P */
530 { "\033OB", NEWT_KEY_DOWN
, "kd" },
531 { "\016", NEWT_KEY_DOWN
, NULL
}, /* emacs ^N */
532 { "\033OC", NEWT_KEY_RIGHT
, "kr" },
533 { "\006", NEWT_KEY_RIGHT
, NULL
}, /* emacs ^F */
534 { "\033OD", NEWT_KEY_LEFT
, "kl" },
535 { "\002", NEWT_KEY_LEFT
, NULL
}, /* emacs ^B */
536 { "\033OH", NEWT_KEY_HOME
, "kh" },
537 { "\033[1~", NEWT_KEY_HOME
, NULL
},
538 { "\001", NEWT_KEY_HOME
, NULL
}, /* emacs ^A */
539 { "\033Ow", NEWT_KEY_END
, "kH" },
540 { "\033[4~", NEWT_KEY_END
, "@7" },
541 { "\005", NEWT_KEY_END
, NULL
}, /* emacs ^E */
543 { "\033[3~", NEWT_KEY_DELETE
, "kD" },
544 { "\004", NEWT_KEY_DELETE
, NULL
}, /* emacs ^D */
545 { "\033[2~", NEWT_KEY_INSERT
, "kI" },
547 { "\033\t", NEWT_KEY_UNTAB
, "kB" },
549 { "\033[5~", NEWT_KEY_PGUP
, "kP" },
550 { "\033[6~", NEWT_KEY_PGDN
, "kN" },
551 { "\033V", NEWT_KEY_PGUP
, NULL
},
552 { "\033v", NEWT_KEY_PGUP
, NULL
},
553 { "\026", NEWT_KEY_PGDN
, NULL
},
555 { "\033[[A", NEWT_KEY_F1
, NULL
},
556 { "\033[[B", NEWT_KEY_F2
, NULL
},
557 { "\033[[C", NEWT_KEY_F3
, NULL
},
558 { "\033[[D", NEWT_KEY_F4
, NULL
},
559 { "\033[[E", NEWT_KEY_F5
, NULL
},
561 { "\033OP", NEWT_KEY_F1
, NULL
},
562 { "\033OQ", NEWT_KEY_F2
, NULL
},
563 { "\033OR", NEWT_KEY_F3
, NULL
},
564 { "\033OS", NEWT_KEY_F4
, NULL
},
566 { "\033[11~", NEWT_KEY_F1
, "k1" },
567 { "\033[12~", NEWT_KEY_F2
, "k2" },
568 { "\033[13~", NEWT_KEY_F3
, "k3" },
569 { "\033[14~", NEWT_KEY_F4
, "k4" },
570 { "\033[15~", NEWT_KEY_F5
, "k5" },
571 { "\033[17~", NEWT_KEY_F6
, "k6" },
572 { "\033[18~", NEWT_KEY_F7
, "k7" },
573 { "\033[19~", NEWT_KEY_F8
, "k8" },
574 { "\033[20~", NEWT_KEY_F9
, "k9" },
575 { "\033[21~", NEWT_KEY_F10
, "k;" },
576 { "\033[23~", NEWT_KEY_F11
, "F1" },
577 { "\033[24~", NEWT_KEY_F12
, "F2" },
578 { "\033", NEWT_KEY_ESCAPE
, "@2" },
579 { "\033", NEWT_KEY_ESCAPE
, "@9" },
581 { "\177", NEWT_KEY_BKSPC
, NULL
},
582 { "\010", NEWT_KEY_BKSPC
, NULL
},
584 { 0 }, /* LEAVE this one */
586 static void initKeymap();
588 static const char ident
[] = // ident friendly
589 "$Version: Newt windowing library v" VERSION
" $"
590 "$Copyright: (C) 1996-2003 Red Hat, Inc. Written by Erik Troan $"
591 "$License: Lesser GNU Public License. $";
593 static newtSuspendCallback suspendCallback
= NULL
;
594 static void * suspendCallbackData
= NULL
;
596 void newtSetSuspendCallback(newtSuspendCallback cb
, void * data
) {
597 suspendCallback
= cb
;
598 suspendCallbackData
= data
;
601 static void handleSigwinch(int signum
) {
605 static int getkeyInterruptHook(void) {
609 int _newt_wstrlen(const char *str
, int len
) {
616 if (len
< 0) len
= strlen(str
);
617 memset(&ps
,0,sizeof(mbstate_t));
621 x
= mbrtowc(&tmp
,str
,len
,&ps
);
633 /** Trim a string to fit
634 * @param title - string. NULL will be inserted if necessary
635 * @param chrs - available space. (character cells)
637 void trim_string(char *title
, int chrs
)
645 memset(&ps
, 0, sizeof(ps
));
648 x
= mbrtowc(&tmp
, p
, ln
, &ps
);
649 if (x
< 0) { // error
664 static int getkey() {
667 while ((c
= SLang_getkey()) == '\xC') { /* if Ctrl-L redraw whole screen */
668 SLsmg_touch_lines (0, SLtt_Screen_Rows
- 1);
675 void newtFlushInput(void) {
676 while (SLang_input_pending(0)) {
682 * @brief Refresh the screen
684 void newtRefresh(void) {
688 void newtSuspend(void) {
689 SLtt_set_cursor_visibility (1);
692 SLtt_set_cursor_visibility (cursorOn
);
696 * @brief Return after suspension.
697 * @return 0 on success.
699 int newtResume(void) {
702 return SLang_init_tty(0, 0, 0);
706 SLsmg_set_color(NEWT_COLORSET_ROOT
);
714 * @brief Resize the screen
715 * @param redraw - boolean - should we redraw the screen?
717 void newtResizeScreen(int redraw
) {
718 SLtt_get_screen_size();
721 SLsmg_touch_lines (0, SLtt_Screen_Rows
- 1);
727 * @brief Initialize the newt library
728 * @return int - 0 for success, else < 0
731 char * MonoValue
, * MonoEnv
= "NEWT_MONO";
735 if ((lang
= getenv("LC_ALL")) == NULL
)
736 if ((lang
= getenv("LC_CTYPE")) == NULL
)
737 if ((lang
= getenv("LANG")) == NULL
)
739 if (strstr (lang
, ".euc") != NULL
)
742 (void) strlen(ident
);
745 SLtt_get_screen_size();
746 // there is no such function in slang?!
747 // SLutf8_enable(-1); /* init. utf8 according to locale */
749 MonoValue
= getenv(MonoEnv
);
750 if ( MonoValue
== NULL
) {
751 SLtt_Use_Ansi_Colors
= 1;
753 SLtt_Use_Ansi_Colors
= 0;
756 if ((ret
= SLsmg_init_smg()) < 0)
758 if ((ret
= SLang_init_tty(0, 0, 0)) < 0)
761 newtSetColors(newtDefaultColorPalette
);
765 /*memset(&sa, 0, sizeof(sa));
766 sa.sa_handler = handleSigwinch;
767 sigaction(SIGWINCH, &sa, NULL);*/
769 SLsignal_intr(SIGWINCH
, handleSigwinch
);
770 SLang_getkey_intr_hook
= getkeyInterruptHook
;
776 * @brief Closedown the newt library, tidying screen.
777 * @returns int , 0. (no errors reported)
779 int newtFinished(void) {
780 SLsmg_gotorc(SLtt_Screen_Rows
- 1, 0);
790 * @brief Set the colors used.
791 * @param colors - newtColor struct used.
793 void newtSetColors(struct newtColors colors
) {
794 if (!SLtt_Use_Ansi_Colors
) {
797 for (i
= 2; i
< 25; i
++)
798 SLtt_set_mono(i
, NULL
, 0);
800 SLtt_set_mono(NEWT_COLORSET_SELLISTBOX
, NULL
, SLTT_BOLD_MASK
);
802 SLtt_set_mono(NEWT_COLORSET_ACTBUTTON
, NULL
, SLTT_REV_MASK
);
803 SLtt_set_mono(NEWT_COLORSET_ACTCHECKBOX
, NULL
, SLTT_REV_MASK
);
804 SLtt_set_mono(NEWT_COLORSET_ACTLISTBOX
, NULL
, SLTT_REV_MASK
);
805 SLtt_set_mono(NEWT_COLORSET_ACTTEXTBOX
, NULL
, SLTT_REV_MASK
);
807 SLtt_set_mono(NEWT_COLORSET_ACTSELLISTBOX
, NULL
, SLTT_REV_MASK
| SLTT_BOLD_MASK
);
809 SLtt_set_mono(NEWT_COLORSET_DISENTRY
, NULL
, 0); // FIXME
810 SLtt_set_mono(NEWT_COLORSET_FULLSCALE
, NULL
, SLTT_ULINE_MASK
| SLTT_REV_MASK
);
811 SLtt_set_mono(NEWT_COLORSET_EMPTYSCALE
, NULL
, SLTT_ULINE_MASK
);
814 SLtt_set_color(NEWT_COLORSET_ROOT
, "", colors
.rootFg
, colors
.rootBg
);
815 SLtt_set_color(NEWT_COLORSET_BORDER
, "", colors
.borderFg
, colors
.borderBg
);
816 SLtt_set_color(NEWT_COLORSET_WINDOW
, "", colors
.windowFg
, colors
.windowBg
);
817 SLtt_set_color(NEWT_COLORSET_SHADOW
, "", colors
.shadowFg
, colors
.shadowBg
);
818 SLtt_set_color(NEWT_COLORSET_TITLE
, "", colors
.titleFg
, colors
.titleBg
);
819 SLtt_set_color(NEWT_COLORSET_BUTTON
, "", colors
.buttonFg
, colors
.buttonBg
);
820 SLtt_set_color(NEWT_COLORSET_ACTBUTTON
, "", colors
.actButtonFg
,
822 SLtt_set_color(NEWT_COLORSET_CHECKBOX
, "", colors
.checkboxFg
,
824 SLtt_set_color(NEWT_COLORSET_ACTCHECKBOX
, "", colors
.actCheckboxFg
,
825 colors
.actCheckboxBg
);
826 SLtt_set_color(NEWT_COLORSET_ENTRY
, "", colors
.entryFg
, colors
.entryBg
);
827 SLtt_set_color(NEWT_COLORSET_LABEL
, "", colors
.labelFg
, colors
.labelBg
);
828 SLtt_set_color(NEWT_COLORSET_LISTBOX
, "", colors
.listboxFg
,
830 SLtt_set_color(NEWT_COLORSET_ACTLISTBOX
, "", colors
.actListboxFg
,
831 colors
.actListboxBg
);
832 SLtt_set_color(NEWT_COLORSET_TEXTBOX
, "", colors
.textboxFg
,
834 SLtt_set_color(NEWT_COLORSET_ACTTEXTBOX
, "", colors
.actTextboxFg
,
835 colors
.actTextboxBg
);
836 SLtt_set_color(NEWT_COLORSET_HELPLINE
, "", colors
.helpLineFg
,
838 SLtt_set_color(NEWT_COLORSET_ROOTTEXT
, "", colors
.rootTextFg
,
841 SLtt_set_color(NEWT_COLORSET_EMPTYSCALE
, "", "white",
843 SLtt_set_color(NEWT_COLORSET_FULLSCALE
, "", "white",
845 SLtt_set_color(NEWT_COLORSET_DISENTRY
, "", colors
.disabledEntryFg
,
846 colors
.disabledEntryBg
);
848 SLtt_set_color(NEWT_COLORSET_COMPACTBUTTON
, "", colors
.compactButtonFg
,
849 colors
.compactButtonBg
);
851 SLtt_set_color(NEWT_COLORSET_ACTSELLISTBOX
, "", colors
.actSelListboxFg
,
852 colors
.actSelListboxBg
);
853 SLtt_set_color(NEWT_COLORSET_SELLISTBOX
, "", colors
.selListboxFg
,
854 colors
.selListboxBg
);
857 /* Keymap handling - rewritten by Henning Makholm <henning@makholm.net>,
861 struct kmap_trie_entry
{
862 char c
; /* character got from terminal */
863 int code
; /* newt key, or 0 if c does not make a complete sequence */
864 struct kmap_trie_entry
*contseq
; /* sub-trie for character following c */
865 struct kmap_trie_entry
*next
; /* try this if char received != c */
867 /* Here are some static entries that will help in handling esc O foo and
868 esc [ foo as variants of each other: */
869 static struct kmap_trie_entry
870 kmap_trie_escO
= { 'O', 0, 0, 0 },
871 kmap_trie_escBrack
= { '[', 0, 0, &kmap_trie_escO
},
872 kmap_trie_root
= { '\033', 0, &kmap_trie_escBrack
, 0 };
873 static int keyreader_buf_len
= 10 ;
874 static unsigned char default_keyreader_buf
[10];
875 static unsigned char *keyreader_buf
= default_keyreader_buf
;
877 #if 0 /* for testing of the keymap manipulation code */
878 static void dumpkeys_recursive(struct kmap_trie_entry
*curr
, int i
, FILE *f
) {
881 if( curr
&& i
>= keyreader_buf_len
) {
882 fprintf(f
,"ARGH! Too long sequence!\n") ;
885 for(;curr
;curr
=curr
->next
) {
886 keyreader_buf
[i
] = curr
->c
;
887 ps
= seen
[(unsigned char)curr
->c
]++ ;
888 if( ps
|| curr
->code
|| (!curr
->code
&& !curr
->contseq
) ) {
890 if( keyreader_buf
[j
] > 32 && keyreader_buf
[j
]<127 &&
891 keyreader_buf
[j
] != '^' && keyreader_buf
[j
] != '\\' )
892 fprintf(f
,"%c",keyreader_buf
[j
]);
893 else if( keyreader_buf
[j
] > 0 && keyreader_buf
[j
]<=32 )
894 fprintf(f
,"^%c",keyreader_buf
[j
] + 0x40);
897 (unsigned)(unsigned char)keyreader_buf
[j
]);
900 fprintf(f
,": 0x%X\n",curr
->code
);
902 fprintf(f
,": (just keymap)\n");
904 dumpkeys_recursive(curr
->contseq
,i
+1,f
);
907 static void dump_keymap(void) {
908 FILE *f
= fopen("newt.keydump","wt");
910 dumpkeys_recursive(&kmap_trie_root
,0,f
);
916 /* newtBindKey may overwrite a binding that is there already */
917 static void newtBindKey(char *keyseq
, int meaning
) {
918 struct kmap_trie_entry
*root
= &kmap_trie_root
;
919 struct kmap_trie_entry
**curptr
= &root
;
921 /* Try to make sure the common matching buffer is long enough. */
922 if( strlen(keyseq
) > keyreader_buf_len
) {
923 int i
= strlen(keyseq
)+10;
924 unsigned char *newbuf
= malloc(i
);
926 if (keyreader_buf
!= default_keyreader_buf
)
928 keyreader_buf
= newbuf
;
929 keyreader_buf_len
= i
;
933 if (*keyseq
== 0) return; /* binding the empty sequence is meaningless */
936 while ((*curptr
) && (*curptr
)->c
!= *keyseq
)
937 curptr
= &(*curptr
)->next
;
939 struct kmap_trie_entry
* fresh
940 = calloc(strlen(keyseq
),sizeof(struct kmap_trie_entry
));
941 if (fresh
== 0) return; /* despair! */
944 fresh
->contseq
= fresh
+1;
945 (fresh
++)->c
= *(keyseq
++);
948 fresh
->code
= meaning
;
952 (*curptr
)->code
= meaning
;
955 curptr
= &(*curptr
)->contseq
;
961 /* This function recursively inserts all entries in the "to" trie into
962 corresponding positions in the "from" trie, except positions that
963 are already defined in the "from" trie. */
964 static void kmap_trie_fallback(struct kmap_trie_entry
*to
,
965 struct kmap_trie_entry
**from
) {
970 for (;to
!=NULL
;to
=to
->next
) {
971 struct kmap_trie_entry
**fromcopy
= from
;
972 while ((*fromcopy
) && (*fromcopy
)->c
!= to
->c
)
973 fromcopy
= &(*fromcopy
)->next
;
975 if ((*fromcopy
)->code
== 0)
976 (*fromcopy
)->code
= to
->code
;
977 kmap_trie_fallback(to
->contseq
, &(*fromcopy
)->contseq
);
979 *fromcopy
= malloc(sizeof(struct kmap_trie_entry
));
982 (*fromcopy
)->next
= 0 ;
988 int newtGetKey(void) {
990 unsigned char *chptr
= keyreader_buf
, *lastmatch
;
992 struct kmap_trie_entry
*curr
= &kmap_trie_root
;
996 if (key
== SLANG_GETKEY_ERROR
) {
997 /* Either garbage was read, or stdin disappeared
998 * (the parent terminal was proably closed)
999 * if the latter, die.
1005 return NEWT_KEY_RESIZE
;
1008 /* ignore other signals */
1012 if (key
== NEWT_KEY_SUSPEND
&& suspendCallback
)
1013 suspendCallback(suspendCallbackData
);
1014 } while (key
== NEWT_KEY_SUSPEND
);
1016 /* Read more characters, matching against the trie as we go */
1017 lastcode
= *chptr
= key
;
1020 while (curr
->c
!= key
) {
1022 if (curr
==NULL
) goto break2levels
;
1025 lastcode
= curr
->code
;
1028 curr
= curr
->contseq
;
1029 if (curr
==NULL
) break;
1031 if (SLang_input_pending(5) <= 0)
1034 if (chptr
==keyreader_buf
+keyreader_buf_len
-1) break;
1035 *++chptr
= key
= getkey();
1039 /* The last time the trie matched was at position lastmatch. Back
1040 * up if we have read too many characters. */
1041 while (chptr
> lastmatch
)
1042 SLang_ungetkey(*chptr
--);
1048 * @brief Wait for a keystroke
1050 void newtWaitForKey(void) {
1054 newtClearKeyBuffer();
1058 * @brief Clear the keybuffer
1060 void newtClearKeyBuffer(void) {
1061 while (SLang_input_pending(1)) {
1067 * Open a new window.
1068 * @param left. unsigned int Size; _not_ including border
1069 * @param top: unsigned int size, _not_ including border
1070 * @param width unsigned int
1071 * @param height unsigned int
1072 * @param title - title string
1073 * @return zero on success (currently no errors reported)
1075 int newtOpenWindow(unsigned int left
, unsigned int top
,
1076 unsigned int width
, unsigned int height
,
1077 const char * title
) {
1084 if (!currentWindow
) {
1085 currentWindow
= windowStack
;
1090 currentWindow
->left
= left
;
1091 currentWindow
->top
= top
;
1092 currentWindow
->width
= width
;
1093 currentWindow
->height
= height
;
1094 currentWindow
->title
= title
? strdup(title
) : NULL
;
1096 currentWindow
->buffer
= malloc(sizeof(SLsmg_Char_Type
) * (width
+ 3) * (height
+ 3));
1100 /* clip to the current screen bounds - msw */
1105 if (left
+ width
> SLtt_Screen_Cols
)
1106 width
= SLtt_Screen_Cols
- left
;
1107 if (top
+ height
> SLtt_Screen_Rows
)
1108 height
= SLtt_Screen_Rows
- top
;
1110 for (j
= 0; j
< height
+ 3; j
++, row
++) {
1111 SLsmg_gotorc(row
, col
);
1112 SLsmg_read_raw(currentWindow
->buffer
+ n
,
1113 currentWindow
->width
+ 3);
1114 n
+= currentWindow
->width
+ 3;
1119 SLsmg_set_color(NEWT_COLORSET_BORDER
);
1120 SLsmg_set_char_set(1);
1121 SLsmg_draw_box(top
- 1, left
- 1, height
+ 2, width
+ 2);
1122 SLsmg_set_char_set(0);
1124 if (currentWindow
->title
) {
1125 trim_string (currentWindow
->title
, width
-4);
1126 i
= wstrlen(currentWindow
->title
,-1) + 4;
1127 i
= ((width
- i
) / 2) + left
;
1128 SLsmg_gotorc(top
- 1, i
);
1129 SLsmg_set_char_set(1);
1130 SLsmg_write_char(SLSMG_RTEE_CHAR
);
1131 SLsmg_set_char_set(0);
1132 SLsmg_write_char(' ');
1133 SLsmg_set_color(NEWT_COLORSET_TITLE
);
1134 write_string_int((char *)currentWindow
->title
, NULL
);
1135 SLsmg_set_color(NEWT_COLORSET_BORDER
);
1136 SLsmg_write_char(' ');
1137 SLsmg_set_char_set(1);
1138 SLsmg_write_char(SLSMG_LTEE_CHAR
);
1139 SLsmg_set_char_set(0);
1142 SLsmg_set_color(NEWT_COLORSET_WINDOW
);
1143 SLsmg_fill_region(top
, left
, height
, width
, ' ');
1145 SLsmg_set_color(NEWT_COLORSET_SHADOW
);
1146 SLsmg_fill_region(top
+ height
+ 1, left
, 1, width
+ 2, ' ');
1147 SLsmg_fill_region(top
, left
+ width
+ 1, height
+ 1, 1, ' ');
1149 for (i
= top
; i
< (top
+ height
+ 1); i
++) {
1150 SLsmg_gotorc(i
, left
+ width
+ 1);
1151 SLsmg_write_string(" ");
1158 * @brief Draw a centered window.
1159 * @param width - width in char cells
1160 * @param height - no. of char cells.
1161 * @param title - fixed title
1162 * @returns 0. No errors reported
1164 int newtCenteredWindow(unsigned int width
,unsigned int height
,
1165 const char * title
) {
1166 unsigned int top
, left
;
1168 top
= (SLtt_Screen_Rows
- height
) / 2;
1170 /* I don't know why, but this seems to look better */
1171 if ((SLtt_Screen_Rows
% 2) && (top
% 2)) top
--;
1173 left
= (SLtt_Screen_Cols
- width
) / 2;
1175 newtOpenWindow(left
, top
, width
, height
, title
);
1181 * @brief Remove the top window
1183 void newtPopWindow(void) {
1189 row
= currentWindow
->top
- 1;
1190 col
= currentWindow
->left
- 1;
1195 for (j
= 0; j
< currentWindow
->height
+ 3; j
++, row
++) {
1196 SLsmg_gotorc(row
, col
);
1197 SLsmg_write_raw(currentWindow
->buffer
+ n
,
1198 currentWindow
->width
+ 3);
1199 n
+= currentWindow
->width
+ 3;
1202 free(currentWindow
->buffer
);
1203 free(currentWindow
->title
);
1205 if (currentWindow
== windowStack
)
1206 currentWindow
= NULL
;
1210 SLsmg_set_char_set(0);
1217 void newtGetWindowPos(int * x
, int * y
) {
1218 if (currentWindow
) {
1219 *x
= currentWindow
->left
;
1220 *y
= currentWindow
->top
;
1225 void newtGetrc(int * row
, int * col
) {
1230 void newtGotorc(int newRow
, int newCol
) {
1231 if (currentWindow
) {
1232 newRow
+= currentWindow
->top
;
1233 newCol
+= currentWindow
->left
;
1238 SLsmg_gotorc(cursorRow
, cursorCol
);
1241 void newtDrawBox(int left
, int top
, int width
, int height
, int shadow
) {
1242 if (currentWindow
) {
1243 top
+= currentWindow
->top
;
1244 left
+= currentWindow
->left
;
1247 SLsmg_draw_box(top
, left
, height
, width
);
1250 SLsmg_set_color(NEWT_COLORSET_SHADOW
);
1251 SLsmg_fill_region(top
+ height
, left
+ 1, 1, width
- 1, ' ');
1252 SLsmg_fill_region(top
+ 1, left
+ width
, height
, 1, ' ');
1256 void newtClearBox(int left
, int top
, int width
, int height
) {
1257 if (currentWindow
) {
1258 top
+= currentWindow
->top
;
1259 left
+= currentWindow
->left
;
1262 SLsmg_fill_region(top
, left
, height
, width
, ' ');
1265 static void initKeymap(void) {
1266 const struct keymap
* curr
;
1268 /* First bind built-in default bindings. They may be shadowed by
1269 the termcap entries that get bound later. */
1270 for (curr
= keymap
; curr
->code
; curr
++) {
1272 newtBindKey(curr
->str
,curr
->code
);
1275 /* Then bind strings from termcap entries */
1276 for (curr
= keymap
; curr
->code
; curr
++) {
1278 char *pc
= SLtt_tgetstr(curr
->tc
);
1280 newtBindKey(pc
,curr
->code
);
1285 /* Finally, invent lowest-priority keybindings that correspond to
1286 searching for esc-O-foo if esc-[-foo was not found and vice
1287 versa. That is needed because of strong confusion among
1288 different emulators of VTxxx terminals; some terminfo/termcap
1289 descriptions are apparently written by people who were not
1290 aware of the differences between "applicataion" and "terminal"
1291 keypad modes. Or perhaps they were, but tried to make their
1292 description work with a program that puts the keyboard in the
1293 wrong emulation mode. In short, one needs this: */
1294 kmap_trie_fallback(kmap_trie_escO
.contseq
, &kmap_trie_escBrack
.contseq
);
1295 kmap_trie_fallback(kmap_trie_escBrack
.contseq
, &kmap_trie_escO
.contseq
);
1299 * @brief Delay for a specified number of usecs
1300 * @param int - number of usecs to wait for.
1302 void newtDelay(unsigned int usecs
) {
1308 tv
.tv_sec
= usecs
/ 1000000;
1309 tv
.tv_usec
= usecs
% 1000000;
1311 select(0, &set
, &set
, &set
, &tv
);
1314 struct eventResult
newtDefaultEventHandler(newtComponent c
,
1316 struct eventResult er
;
1318 er
.result
= ER_IGNORED
;
1322 void newtRedrawHelpLine(void) {
1325 SLsmg_set_color(NEWT_COLORSET_HELPLINE
);
1327 if (currentHelpline
) {
1328 /* buffer size needs to be wide enough to hold all the multibyte
1329 currentHelpline + all the single byte ' ' to fill the line */
1330 int wlen
= wstrlen(*currentHelpline
, -1);
1333 if (wlen
> SLtt_Screen_Cols
)
1334 wlen
= SLtt_Screen_Cols
;
1335 len
= strlen(*currentHelpline
) + (SLtt_Screen_Cols
- wlen
);
1336 buf
= alloca(len
+ 1);
1337 memset(buf
, ' ', len
);
1338 memcpy(buf
, *currentHelpline
, strlen(*currentHelpline
));
1341 buf
= alloca(SLtt_Screen_Cols
+ 1);
1342 memset(buf
, ' ', SLtt_Screen_Cols
);
1343 buf
[SLtt_Screen_Cols
] = '\0';
1345 SLsmg_gotorc(SLtt_Screen_Rows
- 1, 0);
1346 write_string_int(buf
, NULL
);
1349 void newtPushHelpLine(const char * text
) {
1351 text
= defaultHelpLine
;
1353 if (currentHelpline
)
1354 (*(++currentHelpline
)) = strdup(text
);
1356 currentHelpline
= helplineStack
;
1357 *currentHelpline
= strdup(text
);
1360 newtRedrawHelpLine();
1363 void newtPopHelpLine(void) {
1364 if (!currentHelpline
) return;
1366 free(*currentHelpline
);
1367 if (currentHelpline
== helplineStack
)
1368 currentHelpline
= NULL
;
1372 newtRedrawHelpLine();
1375 void newtDrawRootText(int col
, int row
, const char * text
) {
1376 SLsmg_set_color(NEWT_COLORSET_ROOTTEXT
);
1379 col
= SLtt_Screen_Cols
+ col
;
1383 row
= SLtt_Screen_Rows
+ row
;
1386 SLsmg_gotorc(row
, col
);
1387 write_string_int((char *)text
, NULL
);
1390 int newtSetFlags(int oldFlags
, int newFlags
, enum newtFlagsSense sense
) {
1392 case NEWT_FLAGS_SET
:
1393 return oldFlags
| newFlags
;
1395 case NEWT_FLAGS_RESET
:
1396 return oldFlags
& (~newFlags
);
1398 case NEWT_FLAGS_TOGGLE
:
1399 return oldFlags
^ newFlags
;
1411 void newtGetScreenSize(int * cols
, int * rows
) {
1412 if (rows
) *rows
= SLtt_Screen_Rows
;
1413 if (cols
) *cols
= SLtt_Screen_Cols
;
1416 void newtDefaultPlaceHandler(newtComponent c
, int newLeft
, int newTop
) {
1421 void newtDefaultMappedHandler(newtComponent c
, int isMapped
) {
1422 c
->isMapped
= isMapped
;
1425 void newtCursorOff(void) {
1427 SLtt_set_cursor_visibility (cursorOn
);
1430 void newtCursorOn(void) {
1432 SLtt_set_cursor_visibility (cursorOn
);
1435 void newtTrashScreen(void) {
1437 SLsmg_touch_lines (0, SLtt_Screen_Rows
- 1);