7 #include <sys/signal.h>
23 int height
, width
, top
, left
;
24 SLsmg_Char_Type
* buffer
;
34 static struct Window windowStack
[20];
35 static struct Window
* currentWindow
= NULL
;
37 static char * helplineStack
[20];
38 static char ** currentHelpline
= NULL
;
40 static int cursorRow
, cursorCol
;
41 static int cursorOn
= 1;
42 static int noFlowCtrl
= 0;
43 static int trashScreen
= 0;
44 extern int needResize
;
46 static const char * const defaultHelpLine
=
47 " <Tab>/<Alt-Tab> between elements | <Space> selects | <F12> next screen"
50 const struct newtColors newtDefaultColorPalette
= {
51 "white", "blue", /* root fg, bg */
52 "black", "lightgray", /* border fg, bg */
53 "black", "lightgray", /* window fg, bg */
54 "white", "black", /* shadow fg, bg */
55 "red", "lightgray", /* title fg, bg */
56 "lightgray", "red", /* button fg, bg */
57 "red", "lightgray", /* active button fg, bg */
58 "lightgray", "blue", /* checkbox fg, bg */
59 "lightgray", "red", /* active checkbox fg, bg */
60 "lightgray", "blue", /* entry box fg, bg */
61 "blue", "lightgray", /* label fg, bg */
62 "black", "lightgray", /* listbox fg, bg */
63 "lightgray", "blue", /* active listbox fg, bg */
64 "black", "lightgray", /* textbox fg, bg */
65 "lightgray", "red", /* active textbox fg, bg */
66 "white", "blue", /* help line */
67 "lightgray", "blue", /* root text */
68 "blue", /* scale full */
69 "red", /* scale empty */
70 "blue", "lightgray", /* disabled entry fg, bg */
71 "black", "lightgray", /* compact button fg, bg */
72 "lightgray", "red", /* active & sel listbox */
73 "black", "brown" /* selected listbox */
76 static const struct keymap keymap
[] = {
77 { "\033OA", NEWT_KEY_UP
, "ku" },
78 { "\020", NEWT_KEY_UP
, NULL
}, /* emacs ^P */
79 { "\033OB", NEWT_KEY_DOWN
, "kd" },
80 { "\016", NEWT_KEY_DOWN
, NULL
}, /* emacs ^N */
81 { "\033OC", NEWT_KEY_RIGHT
, "kr" },
82 { "\006", NEWT_KEY_RIGHT
, NULL
}, /* emacs ^F */
83 { "\033OD", NEWT_KEY_LEFT
, "kl" },
84 { "\002", NEWT_KEY_LEFT
, NULL
}, /* emacs ^B */
85 { "\033OH", NEWT_KEY_HOME
, "kh" },
86 { "\033[1~", NEWT_KEY_HOME
, NULL
},
87 { "\001", NEWT_KEY_HOME
, NULL
}, /* emacs ^A */
88 { "\033Ow", NEWT_KEY_END
, "kH" },
89 { "\033[4~", NEWT_KEY_END
, "@7" },
90 { "\005", NEWT_KEY_END
, NULL
}, /* emacs ^E */
92 { "\033[3~", NEWT_KEY_DELETE
, "kD" },
93 { "\004", NEWT_KEY_DELETE
, NULL
}, /* emacs ^D */
94 { "\033[2~", NEWT_KEY_INSERT
, "kI" },
96 { "\033\t", NEWT_KEY_UNTAB
, "kB" },
97 { "\033[Z", NEWT_KEY_UNTAB
, NULL
},
99 { "\033[5~", NEWT_KEY_PGUP
, "kP" },
100 { "\033[6~", NEWT_KEY_PGDN
, "kN" },
101 { "\033V", NEWT_KEY_PGUP
, NULL
},
102 { "\033v", NEWT_KEY_PGUP
, NULL
},
103 { "\026", NEWT_KEY_PGDN
, NULL
},
105 { "\033[[A", NEWT_KEY_F1
, NULL
},
106 { "\033[[B", NEWT_KEY_F2
, NULL
},
107 { "\033[[C", NEWT_KEY_F3
, NULL
},
108 { "\033[[D", NEWT_KEY_F4
, NULL
},
109 { "\033[[E", NEWT_KEY_F5
, NULL
},
111 { "\033OP", NEWT_KEY_F1
, NULL
},
112 { "\033OQ", NEWT_KEY_F2
, NULL
},
113 { "\033OR", NEWT_KEY_F3
, NULL
},
114 { "\033OS", NEWT_KEY_F4
, NULL
},
116 { "\033[11~", NEWT_KEY_F1
, "k1" },
117 { "\033[12~", NEWT_KEY_F2
, "k2" },
118 { "\033[13~", NEWT_KEY_F3
, "k3" },
119 { "\033[14~", NEWT_KEY_F4
, "k4" },
120 { "\033[15~", NEWT_KEY_F5
, "k5" },
121 { "\033[17~", NEWT_KEY_F6
, "k6" },
122 { "\033[18~", NEWT_KEY_F7
, "k7" },
123 { "\033[19~", NEWT_KEY_F8
, "k8" },
124 { "\033[20~", NEWT_KEY_F9
, "k9" },
125 { "\033[21~", NEWT_KEY_F10
, "k;" },
126 { "\033[23~", NEWT_KEY_F11
, "F1" },
127 { "\033[24~", NEWT_KEY_F12
, "F2" },
128 { "\033", NEWT_KEY_ESCAPE
, "@2" },
129 { "\033", NEWT_KEY_ESCAPE
, "@9" },
131 { "\177", NEWT_KEY_BKSPC
, NULL
},
132 { "\010", NEWT_KEY_BKSPC
, NULL
},
134 { 0 }, /* LEAVE this one */
136 static void initKeymap();
137 static void freeKeymap();
139 static newtSuspendCallback suspendCallback
= NULL
;
140 static void * suspendCallbackData
= NULL
;
142 void newtSetSuspendCallback(newtSuspendCallback cb
, void * data
) {
143 suspendCallback
= cb
;
144 suspendCallbackData
= data
;
147 static void handleSigwinch(int signum
) {
151 static int getkeyInterruptHook(void) {
155 int _newt_wstrlen(const char *str
, int len
) {
162 if (len
< 0) len
= strlen(str
);
163 memset(&ps
,0,sizeof(mbstate_t));
167 x
= mbrtowc(&tmp
,str
,len
,&ps
);
179 /** Trim a string to fit
180 * @param title - string. NULL will be inserted if necessary
181 * @param chrs - available space. (character cells)
183 void trim_string(char *title
, int chrs
)
191 memset(&ps
, 0, sizeof(ps
));
195 x
= mbrtowc(&tmp
, p
, ln
, &ps
);
196 if (x
< 0) { // error
212 static int getkey() {
215 while ((c
= SLang_getkey()) == '\xC') { /* if Ctrl-L redraw whole screen */
216 SLsmg_touch_lines(0, SLtt_Screen_Rows
);
223 static void updateColorset(char *fg
, char *bg
, char **fg_p
, char **bg_p
)
231 /* parse color specifications (e.g. root=,black:border=red,blue)
232 * and update the palette
234 static void parseColors(char *s
, struct newtColors
*palette
)
236 char *name
, *str
, *fg
, *bg
;
238 for (str
= s
; (s
= strtok(str
, ";:\n\r\t ")); str
= NULL
) {
240 if (!(s
= strchr(s
, '=')) || !*s
)
244 if (!(s
= strchr(s
, ',')) || !*s
)
249 if (!strcmp(name
, "root"))
250 updateColorset(fg
, bg
, &palette
->rootFg
, &palette
->rootBg
);
251 else if (!strcmp(name
, "border"))
252 updateColorset(fg
, bg
, &palette
->borderFg
, &palette
->borderBg
);
253 else if (!strcmp(name
, "window"))
254 updateColorset(fg
, bg
, &palette
->windowFg
, &palette
->windowBg
);
255 else if (!strcmp(name
, "shadow"))
256 updateColorset(fg
, bg
, &palette
->shadowFg
, &palette
->shadowBg
);
257 else if (!strcmp(name
, "title"))
258 updateColorset(fg
, bg
, &palette
->titleFg
, &palette
->titleBg
);
259 else if (!strcmp(name
, "button"))
260 updateColorset(fg
, bg
, &palette
->buttonFg
, &palette
->buttonBg
);
261 else if (!strcmp(name
, "actbutton"))
262 updateColorset(fg
, bg
, &palette
->actButtonFg
, &palette
->actButtonBg
);
263 else if (!strcmp(name
, "checkbox"))
264 updateColorset(fg
, bg
, &palette
->checkboxFg
, &palette
->checkboxBg
);
265 else if (!strcmp(name
, "actcheckbox"))
266 updateColorset(fg
, bg
, &palette
->actCheckboxFg
, &palette
->actCheckboxBg
);
267 else if (!strcmp(name
, "entry"))
268 updateColorset(fg
, bg
, &palette
->entryFg
, &palette
->entryBg
);
269 else if (!strcmp(name
, "label"))
270 updateColorset(fg
, bg
, &palette
->labelFg
, &palette
->labelBg
);
271 else if (!strcmp(name
, "listbox"))
272 updateColorset(fg
, bg
, &palette
->listboxFg
, &palette
->listboxBg
);
273 else if (!strcmp(name
, "actlistbox"))
274 updateColorset(fg
, bg
, &palette
->actListboxFg
, &palette
->actListboxBg
);
275 else if (!strcmp(name
, "textbox"))
276 updateColorset(fg
, bg
, &palette
->textboxFg
, &palette
->textboxBg
);
277 else if (!strcmp(name
, "acttextbox"))
278 updateColorset(fg
, bg
, &palette
->actTextboxFg
, &palette
->actTextboxBg
);
279 else if (!strcmp(name
, "helpline"))
280 updateColorset(fg
, bg
, &palette
->helpLineFg
, &palette
->helpLineBg
);
281 else if (!strcmp(name
, "roottext"))
282 updateColorset(fg
, bg
, &palette
->rootTextFg
, &palette
->rootTextBg
);
283 else if (!strcmp(name
, "emptyscale"))
284 updateColorset(fg
, bg
, NULL
, &palette
->emptyScale
);
285 else if (!strcmp(name
, "fullscale"))
286 updateColorset(fg
, bg
, NULL
, &palette
->fullScale
);
287 else if (!strcmp(name
, "disentry"))
288 updateColorset(fg
, bg
, &palette
->disabledEntryFg
, &palette
->disabledEntryBg
);
289 else if (!strcmp(name
, "compactbutton"))
290 updateColorset(fg
, bg
, &palette
->compactButtonFg
, &palette
->compactButtonBg
);
291 else if (!strcmp(name
, "actsellistbox"))
292 updateColorset(fg
, bg
, &palette
->actSelListboxFg
, &palette
->actSelListboxBg
);
293 else if (!strcmp(name
, "sellistbox"))
294 updateColorset(fg
, bg
, &palette
->selListboxFg
, &palette
->selListboxBg
);
298 static void initColors(void)
300 char *colors
, *colors_file
, buf
[16384];
302 struct newtColors palette
;
304 palette
= newtDefaultColorPalette
;
306 colors_file
= getenv("NEWT_COLORS_FILE");
307 #ifdef NEWT_COLORS_FILE
308 if (colors_file
== NULL
)
309 colors_file
= NEWT_COLORS_FILE
;
312 if ((colors
= getenv("NEWT_COLORS"))) {
313 strncpy(buf
, colors
, sizeof (buf
));
314 buf
[sizeof (buf
) - 1] = '\0';
315 parseColors(buf
, &palette
);
316 } else if (colors_file
&& *colors_file
&& (f
= fopen(colors_file
, "r"))) {
318 if ((r
= fread(buf
, 1, sizeof (buf
) - 1, f
)) > 0) {
320 parseColors(buf
, &palette
);
325 newtSetColors(palette
);
328 void newtFlushInput(void) {
329 while (SLang_input_pending(0)) {
335 * @brief Refresh the screen
337 void newtRefresh(void) {
341 void newtSuspend(void) {
342 SLtt_set_cursor_visibility (1);
345 SLtt_set_cursor_visibility (cursorOn
);
349 * @brief Return after suspension.
350 * @return 0 on success.
352 int newtResume(void) {
355 return SLang_init_tty(0, noFlowCtrl
, 0);
359 SLsmg_set_color(NEWT_COLORSET_ROOT
);
367 * @brief Resize the screen
368 * @param redraw - boolean - should we redraw the screen?
370 void newtResizeScreen(int redraw
) {
371 /* we can't redraw from scratch, just redisplay SLang screen */
372 SLtt_get_screen_size();
373 /* SLsmg_reinit_smg(); */
375 SLsmg_touch_lines(0, SLtt_Screen_Rows
);
381 * @brief Initialize the newt library
382 * @return int - 0 for success, else < 0
385 char * MonoValue
, * MonoEnv
= "NEWT_MONO";
386 char * NoFlowCtrlValue
, * NoFlowCtrlEnv
= "NEWT_NOFLOWCTRL";
390 if ((lang
= getenv("LC_ALL")) == NULL
)
391 if ((lang
= getenv("LC_CTYPE")) == NULL
)
392 if ((lang
= getenv("LANG")) == NULL
)
394 /* slang doesn't support multibyte encodings except UTF-8,
395 avoid character corruption by redrawing the screen */
396 if (strstr (lang
, ".euc") != NULL
)
401 SLtt_get_screen_size();
403 MonoValue
= getenv(MonoEnv
);
404 if ( MonoValue
!= NULL
)
405 SLtt_Use_Ansi_Colors
= 0;
407 NoFlowCtrlValue
= getenv(NoFlowCtrlEnv
);
408 if ( NoFlowCtrlValue
!= NULL
)
411 if ((ret
= SLsmg_init_smg()) < 0)
413 if ((ret
= SLang_init_tty(0, noFlowCtrl
, 0)) < 0)
420 SLsignal_intr(SIGWINCH
, handleSigwinch
);
421 SLang_getkey_intr_hook
= getkeyInterruptHook
;
427 * @brief Closedown the newt library, tidying screen.
428 * @returns int , 0. (no errors reported)
430 int newtFinished(void) {
432 for (; currentWindow
>= windowStack
; currentWindow
--) {
433 free(currentWindow
->buffer
);
434 free(currentWindow
->title
);
436 currentWindow
= NULL
;
439 if (currentHelpline
) {
440 for (; currentHelpline
>= helplineStack
; currentHelpline
--)
441 free(*currentHelpline
);
442 currentHelpline
= NULL
;
447 SLsmg_gotorc(SLtt_Screen_Rows
- 1, 0);
457 * @brief Set the colors used.
458 * @param colors - newtColor struct used.
460 void newtSetColors(struct newtColors colors
) {
461 if (!SLtt_Use_Ansi_Colors
) {
464 for (i
= 2; i
< 25; i
++)
465 SLtt_set_mono(i
, NULL
, 0);
467 SLtt_set_mono(NEWT_COLORSET_SELLISTBOX
, NULL
, SLTT_BOLD_MASK
);
469 SLtt_set_mono(NEWT_COLORSET_ACTBUTTON
, NULL
, SLTT_REV_MASK
);
470 SLtt_set_mono(NEWT_COLORSET_ACTCHECKBOX
, NULL
, SLTT_REV_MASK
);
471 SLtt_set_mono(NEWT_COLORSET_ACTLISTBOX
, NULL
, SLTT_REV_MASK
);
472 SLtt_set_mono(NEWT_COLORSET_ACTTEXTBOX
, NULL
, SLTT_REV_MASK
);
474 SLtt_set_mono(NEWT_COLORSET_ACTSELLISTBOX
, NULL
, SLTT_REV_MASK
| SLTT_BOLD_MASK
);
476 SLtt_set_mono(NEWT_COLORSET_DISENTRY
, NULL
, 0); // FIXME
477 SLtt_set_mono(NEWT_COLORSET_FULLSCALE
, NULL
, SLTT_ULINE_MASK
| SLTT_REV_MASK
);
478 SLtt_set_mono(NEWT_COLORSET_EMPTYSCALE
, NULL
, SLTT_ULINE_MASK
);
481 SLtt_set_color(NEWT_COLORSET_ROOT
, "", colors
.rootFg
, colors
.rootBg
);
482 SLtt_set_color(NEWT_COLORSET_BORDER
, "", colors
.borderFg
, colors
.borderBg
);
483 SLtt_set_color(NEWT_COLORSET_WINDOW
, "", colors
.windowFg
, colors
.windowBg
);
484 SLtt_set_color(NEWT_COLORSET_SHADOW
, "", colors
.shadowFg
, colors
.shadowBg
);
485 SLtt_set_color(NEWT_COLORSET_TITLE
, "", colors
.titleFg
, colors
.titleBg
);
486 SLtt_set_color(NEWT_COLORSET_BUTTON
, "", colors
.buttonFg
, colors
.buttonBg
);
487 SLtt_set_color(NEWT_COLORSET_ACTBUTTON
, "", colors
.actButtonFg
,
489 SLtt_set_color(NEWT_COLORSET_CHECKBOX
, "", colors
.checkboxFg
,
491 SLtt_set_color(NEWT_COLORSET_ACTCHECKBOX
, "", colors
.actCheckboxFg
,
492 colors
.actCheckboxBg
);
493 SLtt_set_color(NEWT_COLORSET_ENTRY
, "", colors
.entryFg
, colors
.entryBg
);
494 SLtt_set_color(NEWT_COLORSET_LABEL
, "", colors
.labelFg
, colors
.labelBg
);
495 SLtt_set_color(NEWT_COLORSET_LISTBOX
, "", colors
.listboxFg
,
497 SLtt_set_color(NEWT_COLORSET_ACTLISTBOX
, "", colors
.actListboxFg
,
498 colors
.actListboxBg
);
499 SLtt_set_color(NEWT_COLORSET_TEXTBOX
, "", colors
.textboxFg
,
501 SLtt_set_color(NEWT_COLORSET_ACTTEXTBOX
, "", colors
.actTextboxFg
,
502 colors
.actTextboxBg
);
503 SLtt_set_color(NEWT_COLORSET_HELPLINE
, "", colors
.helpLineFg
,
505 SLtt_set_color(NEWT_COLORSET_ROOTTEXT
, "", colors
.rootTextFg
,
508 SLtt_set_color(NEWT_COLORSET_EMPTYSCALE
, "", "white",
510 SLtt_set_color(NEWT_COLORSET_FULLSCALE
, "", "white",
512 SLtt_set_color(NEWT_COLORSET_DISENTRY
, "", colors
.disabledEntryFg
,
513 colors
.disabledEntryBg
);
515 SLtt_set_color(NEWT_COLORSET_COMPACTBUTTON
, "", colors
.compactButtonFg
,
516 colors
.compactButtonBg
);
518 SLtt_set_color(NEWT_COLORSET_ACTSELLISTBOX
, "", colors
.actSelListboxFg
,
519 colors
.actSelListboxBg
);
520 SLtt_set_color(NEWT_COLORSET_SELLISTBOX
, "", colors
.selListboxFg
,
521 colors
.selListboxBg
);
524 void newtSetColor(int colorset
, char *fg
, char *bg
) {
525 if (colorset
< NEWT_COLORSET_ROOT
||
526 (colorset
> NEWT_COLORSET_SELLISTBOX
&& colorset
< NEWT_COLORSET_CUSTOM(0)) ||
527 !SLtt_Use_Ansi_Colors
)
530 SLtt_set_color(colorset
, "", fg
, bg
);
533 /* Keymap handling - rewritten by Henning Makholm <henning@makholm.net>,
537 struct kmap_trie_entry
{
538 char alloced
; /* alloced/not first element in array */
539 char c
; /* character got from terminal */
540 int code
; /* newt key, or 0 if c does not make a complete sequence */
541 struct kmap_trie_entry
*contseq
; /* sub-trie for character following c */
542 struct kmap_trie_entry
*next
; /* try this if char received != c */
545 static struct kmap_trie_entry
*kmap_trie_root
= NULL
;
546 static int keyreader_buf_len
= 10 ;
547 static unsigned char default_keyreader_buf
[10];
548 static unsigned char *keyreader_buf
= default_keyreader_buf
;
550 #if 0 /* for testing of the keymap manipulation code */
551 static void dumpkeys_recursive(struct kmap_trie_entry
*curr
, int i
, FILE *f
) {
554 if( curr
&& i
>= keyreader_buf_len
) {
555 fprintf(f
,"ARGH! Too long sequence!\n") ;
558 for(;curr
;curr
=curr
->next
) {
559 keyreader_buf
[i
] = curr
->c
;
560 ps
= seen
[(unsigned char)curr
->c
]++ ;
561 if( ps
|| curr
->code
|| (!curr
->code
&& !curr
->contseq
) ) {
563 if( keyreader_buf
[j
] > 32 && keyreader_buf
[j
]<127 &&
564 keyreader_buf
[j
] != '^' && keyreader_buf
[j
] != '\\' )
565 fprintf(f
,"%c",keyreader_buf
[j
]);
566 else if( keyreader_buf
[j
] > 0 && keyreader_buf
[j
]<=32 )
567 fprintf(f
,"^%c",keyreader_buf
[j
] + 0x40);
570 (unsigned)(unsigned char)keyreader_buf
[j
]);
573 fprintf(f
,": 0x%X\n",curr
->code
);
575 fprintf(f
,": (just keymap)\n");
577 dumpkeys_recursive(curr
->contseq
,i
+1,f
);
580 static void dump_keymap(void) {
581 FILE *f
= fopen("newt.keydump","wt");
583 dumpkeys_recursive(kmap_trie_root
, 0, f
);
589 /* newtBindKey may overwrite a binding that is there already */
590 static void newtBindKey(char *keyseq
, int meaning
) {
591 struct kmap_trie_entry
*root
= kmap_trie_root
;
592 struct kmap_trie_entry
**curptr
= &root
;
594 /* Try to make sure the common matching buffer is long enough. */
595 if( strlen(keyseq
) > keyreader_buf_len
) {
596 int i
= strlen(keyseq
)+10;
597 unsigned char *newbuf
= malloc(i
);
599 if (keyreader_buf
!= default_keyreader_buf
)
601 keyreader_buf
= newbuf
;
602 keyreader_buf_len
= i
;
606 if (*keyseq
== 0) return; /* binding the empty sequence is meaningless */
609 while ((*curptr
) && (*curptr
)->c
!= *keyseq
)
610 curptr
= &(*curptr
)->next
;
612 struct kmap_trie_entry
* fresh
613 = calloc(strlen(keyseq
),sizeof(struct kmap_trie_entry
));
614 if (fresh
== 0) return; /* despair! */
618 fresh
->contseq
= fresh
+1;
619 (fresh
++)->c
= *(keyseq
++);
622 fresh
->code
= meaning
;
626 (*curptr
)->code
= meaning
;
629 curptr
= &(*curptr
)->contseq
;
635 /* This function recursively inserts all entries in the "to" trie into
636 corresponding positions in the "from" trie, except positions that
637 are already defined in the "from" trie. */
638 static void kmap_trie_fallback(struct kmap_trie_entry
*to
,
639 struct kmap_trie_entry
**from
) {
644 for (;to
!=NULL
;to
=to
->next
) {
645 struct kmap_trie_entry
**fromcopy
= from
;
646 while ((*fromcopy
) && (*fromcopy
)->c
!= to
->c
)
647 fromcopy
= &(*fromcopy
)->next
;
649 if ((*fromcopy
)->code
== 0)
650 (*fromcopy
)->code
= to
->code
;
651 kmap_trie_fallback(to
->contseq
, &(*fromcopy
)->contseq
);
653 *fromcopy
= malloc(sizeof(struct kmap_trie_entry
));
656 (*fromcopy
)->alloced
= 1;
657 (*fromcopy
)->next
= 0 ;
663 int newtGetKey(void) {
664 int key
, lastcode
, errors
= 0;
665 unsigned char *chptr
= keyreader_buf
, *lastmatch
;
666 struct kmap_trie_entry
*curr
= kmap_trie_root
;
670 if (key
== SLANG_GETKEY_ERROR
) {
673 return NEWT_KEY_RESIZE
;
676 /* Ignore other signals, but assume that stdin disappeared (the
677 * parent terminal was proably closed) if the error persists.
680 return NEWT_KEY_ERROR
;
685 if (key
== NEWT_KEY_SUSPEND
&& suspendCallback
)
686 suspendCallback(suspendCallbackData
);
687 } while (key
== NEWT_KEY_SUSPEND
|| key
== SLANG_GETKEY_ERROR
);
689 /* Read more characters, matching against the trie as we go */
690 lastcode
= *chptr
= key
;
693 while (curr
->c
!= key
) {
695 if (curr
==NULL
) goto break2levels
;
698 lastcode
= curr
->code
;
701 curr
= curr
->contseq
;
702 if (curr
==NULL
) break;
704 if (SLang_input_pending(5) <= 0)
707 if (chptr
==keyreader_buf
+keyreader_buf_len
-1) break;
708 *++chptr
= key
= getkey();
712 /* The last time the trie matched was at position lastmatch. Back
713 * up if we have read too many characters. */
714 while (chptr
> lastmatch
)
715 SLang_ungetkey(*chptr
--);
721 * @brief Wait for a keystroke
723 void newtWaitForKey(void) {
727 newtClearKeyBuffer();
731 * @brief Clear the keybuffer
733 void newtClearKeyBuffer(void) {
734 while (SLang_input_pending(1)) {
741 * @param left. int Size; _not_ including border
742 * @param top: int size, _not_ including border
743 * @param width unsigned int
744 * @param height unsigned int
745 * @param title - title string
746 * @return zero on success
748 int newtOpenWindow(int left
, int top
,
749 unsigned int width
, unsigned int height
,
750 const char * title
) {
757 if (currentWindow
&& currentWindow
- windowStack
+ 1
758 >= sizeof (windowStack
) / sizeof (struct Window
))
761 if (!currentWindow
) {
762 currentWindow
= windowStack
;
767 currentWindow
->left
= left
;
768 currentWindow
->top
= top
;
769 currentWindow
->width
= width
;
770 currentWindow
->height
= height
;
771 currentWindow
->title
= title
? strdup(title
) : NULL
;
773 currentWindow
->buffer
= malloc(sizeof(SLsmg_Char_Type
) * (width
+ 5) * (height
+ 3));
777 /* clip to the current screen bounds - msw */
782 if (left
+ width
> SLtt_Screen_Cols
)
783 width
= SLtt_Screen_Cols
- left
;
784 if (top
+ height
> SLtt_Screen_Rows
)
785 height
= SLtt_Screen_Rows
- top
;
787 for (j
= 0; j
< height
+ 3; j
++, row
++) {
788 SLsmg_gotorc(row
, col
);
789 SLsmg_read_raw(currentWindow
->buffer
+ n
,
790 currentWindow
->width
+ 5);
791 n
+= currentWindow
->width
+ 5;
796 SLsmg_set_color(NEWT_COLORSET_BORDER
);
797 SLsmg_set_char_set(1);
798 SLsmg_draw_box(top
- 1, left
- 1, height
+ 2, width
+ 2);
799 SLsmg_set_char_set(0);
801 if (currentWindow
->title
) {
802 trim_string (currentWindow
->title
, width
-4);
803 i
= wstrlen(currentWindow
->title
,-1) + 4;
804 i
= ((width
- i
) / 2) + left
;
805 SLsmg_gotorc(top
- 1, i
);
806 SLsmg_set_char_set(1);
807 SLsmg_write_char(SLSMG_RTEE_CHAR
);
808 SLsmg_set_char_set(0);
809 SLsmg_write_char(' ');
810 SLsmg_set_color(NEWT_COLORSET_TITLE
);
811 SLsmg_write_string((char *)currentWindow
->title
);
812 SLsmg_set_color(NEWT_COLORSET_BORDER
);
813 SLsmg_write_char(' ');
814 SLsmg_set_char_set(1);
815 SLsmg_write_char(SLSMG_LTEE_CHAR
);
816 SLsmg_set_char_set(0);
819 SLsmg_set_color(NEWT_COLORSET_WINDOW
);
820 SLsmg_fill_region(top
, left
, height
, width
, ' ');
822 SLsmg_set_color(NEWT_COLORSET_SHADOW
);
823 SLsmg_fill_region(top
+ height
+ 1, left
, 1, width
+ 2, ' ');
824 SLsmg_fill_region(top
, left
+ width
+ 1, height
+ 1, 1, ' ');
826 for (i
= top
; i
< (top
+ height
+ 1); i
++) {
827 SLsmg_gotorc(i
, left
+ width
+ 1);
828 SLsmg_write_string(" ");
835 * @brief Draw a centered window.
836 * @param width - width in char cells
837 * @param height - no. of char cells.
838 * @param title - fixed title
839 * @returns zero on success
841 int newtCenteredWindow(unsigned int width
,unsigned int height
,
842 const char * title
) {
845 top
= (int)(SLtt_Screen_Rows
- height
) / 2;
847 /* I don't know why, but this seems to look better */
848 if ((SLtt_Screen_Rows
% 2) && (top
% 2)) top
--;
850 left
= (int)(SLtt_Screen_Cols
- width
) / 2;
852 return newtOpenWindow(left
, top
, width
, height
, title
);
856 * @brief Remove the top window
858 void newtPopWindow(void) {
859 newtPopWindowNoRefresh();
863 void newtPopWindowNoRefresh(void) {
867 if (currentWindow
== NULL
)
870 row
= currentWindow
->top
- 1;
871 col
= currentWindow
->left
- 2;
876 for (j
= 0; j
< currentWindow
->height
+ 3; j
++, row
++) {
877 SLsmg_gotorc(row
, col
);
878 SLsmg_write_raw(currentWindow
->buffer
+ n
,
879 currentWindow
->width
+ 5);
880 n
+= currentWindow
->width
+ 5;
883 free(currentWindow
->buffer
);
884 free(currentWindow
->title
);
886 if (currentWindow
== windowStack
)
887 currentWindow
= NULL
;
891 SLsmg_set_char_set(0);
896 void newtGetWindowPos(int * x
, int * y
) {
898 *x
= currentWindow
->left
;
899 *y
= currentWindow
->top
;
904 void newtGetrc(int * row
, int * col
) {
909 *row
-= currentWindow
->top
;
910 *col
-= currentWindow
->left
;
914 void newtGotorc(int newRow
, int newCol
) {
916 newRow
+= currentWindow
->top
;
917 newCol
+= currentWindow
->left
;
922 SLsmg_gotorc(cursorRow
, cursorCol
);
925 void newtDrawBox(int left
, int top
, int width
, int height
, int shadow
) {
927 top
+= currentWindow
->top
;
928 left
+= currentWindow
->left
;
931 SLsmg_draw_box(top
, left
, height
, width
);
934 SLsmg_set_color(NEWT_COLORSET_SHADOW
);
935 SLsmg_fill_region(top
+ height
, left
+ 1, 1, width
- 1, ' ');
936 SLsmg_fill_region(top
+ 1, left
+ width
, height
, 1, ' ');
940 void newtClearBox(int left
, int top
, int width
, int height
) {
942 top
+= currentWindow
->top
;
943 left
+= currentWindow
->left
;
946 SLsmg_fill_region(top
, left
, height
, width
, ' ');
949 static void initKeymap(void) {
950 const struct keymap
* curr
;
951 struct kmap_trie_entry
*kmap_trie_escBrack
, *kmap_trie_escO
;
953 /* Here are some entries that will help in handling esc O foo and
954 esc [ foo as variants of each other. */
955 kmap_trie_root
= calloc(3, sizeof (struct kmap_trie_entry
));
956 kmap_trie_escBrack
= kmap_trie_root
+ 1;
957 kmap_trie_escO
= kmap_trie_root
+ 2;
959 kmap_trie_root
->alloced
= 1;
960 kmap_trie_root
->c
= '\033';
961 kmap_trie_root
->contseq
= kmap_trie_escBrack
;
963 kmap_trie_escBrack
->c
= '[';
964 kmap_trie_escBrack
->next
= kmap_trie_escO
;
966 kmap_trie_escO
->c
= 'O';
968 /* First bind built-in default bindings. They may be shadowed by
969 the termcap entries that get bound later. */
970 for (curr
= keymap
; curr
->code
; curr
++) {
972 newtBindKey(curr
->str
,curr
->code
);
975 /* Then bind strings from termcap entries */
976 for (curr
= keymap
; curr
->code
; curr
++) {
978 char *pc
= SLtt_tgetstr(curr
->tc
);
980 newtBindKey(pc
,curr
->code
);
985 /* Finally, invent lowest-priority keybindings that correspond to
986 searching for esc-O-foo if esc-[-foo was not found and vice
987 versa. That is needed because of strong confusion among
988 different emulators of VTxxx terminals; some terminfo/termcap
989 descriptions are apparently written by people who were not
990 aware of the differences between "applicataion" and "terminal"
991 keypad modes. Or perhaps they were, but tried to make their
992 description work with a program that puts the keyboard in the
993 wrong emulation mode. In short, one needs this: */
994 kmap_trie_fallback(kmap_trie_escO
->contseq
, &kmap_trie_escBrack
->contseq
);
995 kmap_trie_fallback(kmap_trie_escBrack
->contseq
, &kmap_trie_escO
->contseq
);
998 static void free_keys(struct kmap_trie_entry
*kmap
, struct kmap_trie_entry
*parent
, int prepare
) {
1002 free_keys(kmap
->contseq
, kmap
, prepare
);
1003 free_keys(kmap
->next
, kmap
, prepare
);
1005 if (!kmap
->alloced
&& kmap
- parent
== 1)
1008 /* find first element in array */
1009 while (!kmap
->alloced
)
1012 kmap
->alloced
+= prepare
? 1 : -1;
1013 if (!prepare
&& kmap
->alloced
== 1)
1017 static void freeKeymap() {
1018 free_keys(kmap_trie_root
, NULL
, 1);
1019 free_keys(kmap_trie_root
, NULL
, 0);
1020 kmap_trie_root
= NULL
;
1024 * @brief Delay for a specified number of usecs
1025 * @param int - number of usecs to wait for.
1027 void newtDelay(unsigned int usecs
) {
1028 struct timespec t
= { usecs
/ 1000000, (usecs
% 1000000) * 1000 };
1030 nanosleep(&t
, NULL
);
1033 struct eventResult
newtDefaultEventHandler(newtComponent c
,
1035 struct eventResult er
;
1037 er
.result
= ER_IGNORED
;
1041 void newtRedrawHelpLine(void) {
1044 SLsmg_set_color(NEWT_COLORSET_HELPLINE
);
1046 if (currentHelpline
) {
1047 /* buffer size needs to be wide enough to hold all the multibyte
1048 currentHelpline + all the single byte ' ' to fill the line */
1049 int wlen
= wstrlen(*currentHelpline
, -1);
1052 if (wlen
> SLtt_Screen_Cols
)
1053 wlen
= SLtt_Screen_Cols
;
1054 len
= strlen(*currentHelpline
) + (SLtt_Screen_Cols
- wlen
);
1055 buf
= alloca(len
+ 1);
1056 memset(buf
, ' ', len
);
1057 memcpy(buf
, *currentHelpline
, strlen(*currentHelpline
));
1060 buf
= alloca(SLtt_Screen_Cols
+ 1);
1061 memset(buf
, ' ', SLtt_Screen_Cols
);
1062 buf
[SLtt_Screen_Cols
] = '\0';
1064 SLsmg_gotorc(SLtt_Screen_Rows
- 1, 0);
1065 SLsmg_write_string(buf
);
1066 SLsmg_gotorc(cursorRow
, cursorCol
);
1069 void newtPushHelpLine(const char * text
) {
1070 if (currentHelpline
&& currentHelpline
- helplineStack
+ 1
1071 >= sizeof (helplineStack
) / sizeof (char *))
1075 text
= defaultHelpLine
;
1077 if (currentHelpline
)
1078 (*(++currentHelpline
)) = strdup(text
);
1080 currentHelpline
= helplineStack
;
1081 *currentHelpline
= strdup(text
);
1084 newtRedrawHelpLine();
1087 void newtPopHelpLine(void) {
1088 if (!currentHelpline
) return;
1090 free(*currentHelpline
);
1091 if (currentHelpline
== helplineStack
)
1092 currentHelpline
= NULL
;
1096 newtRedrawHelpLine();
1099 void newtDrawRootText(int col
, int row
, const char * text
) {
1100 SLsmg_set_color(NEWT_COLORSET_ROOTTEXT
);
1103 col
= SLtt_Screen_Cols
+ col
;
1107 row
= SLtt_Screen_Rows
+ row
;
1110 SLsmg_gotorc(row
, col
);
1111 SLsmg_write_string((char *)text
);
1114 int newtSetFlags(int oldFlags
, int newFlags
, enum newtFlagsSense sense
) {
1116 case NEWT_FLAGS_SET
:
1117 return oldFlags
| newFlags
;
1119 case NEWT_FLAGS_RESET
:
1120 return oldFlags
& (~newFlags
);
1122 case NEWT_FLAGS_TOGGLE
:
1123 return oldFlags
^ newFlags
;
1135 void newtGetScreenSize(int * cols
, int * rows
) {
1136 if (rows
) *rows
= SLtt_Screen_Rows
;
1137 if (cols
) *cols
= SLtt_Screen_Cols
;
1140 void newtDefaultPlaceHandler(newtComponent c
, int newLeft
, int newTop
) {
1145 void newtDefaultMappedHandler(newtComponent c
, int isMapped
) {
1146 c
->isMapped
= isMapped
;
1149 void newtCursorOff(void) {
1151 SLtt_set_cursor_visibility (cursorOn
);
1154 void newtCursorOn(void) {
1156 SLtt_set_cursor_visibility (cursorOn
);
1159 void newtTrashScreen(void) {
1161 SLsmg_touch_lines(0, SLtt_Screen_Rows
);
1164 void newtComponentGetPosition(newtComponent co
, int * left
, int * top
) {
1165 if (left
) *left
= co
->left
;
1166 if (top
) *top
= co
->top
;
1169 void newtComponentGetSize(newtComponent co
, int * width
, int * height
) {
1170 if (width
) *width
= co
->width
;
1171 if (height
) *height
= co
->height
;