7 #include <sys/signal.h>
22 int height
, width
, top
, left
;
23 SLsmg_Char_Type
* buffer
;
33 static struct Window windowStack
[20];
34 static struct Window
* currentWindow
= NULL
;
36 static char * helplineStack
[20];
37 static char ** currentHelpline
= NULL
;
39 static int cursorRow
, cursorCol
;
40 static int cursorOn
= 1;
41 static int trashScreen
= 0;
42 extern int needResize
;
44 static const char * const defaultHelpLine
=
45 " <Tab>/<Alt-Tab> between elements | <Space> selects | <F12> next screen"
48 const struct newtColors newtDefaultColorPalette
= {
49 "white", "blue", /* root fg, bg */
50 "black", "lightgray", /* border fg, bg */
51 "black", "lightgray", /* window fg, bg */
52 "white", "black", /* shadow fg, bg */
53 "red", "lightgray", /* title fg, bg */
54 "lightgray", "red", /* button fg, bg */
55 "red", "lightgray", /* active button fg, bg */
56 "lightgray", "blue", /* checkbox fg, bg */
57 "lightgray", "red", /* active checkbox fg, bg */
58 "lightgray", "blue", /* entry box fg, bg */
59 "blue", "lightgray", /* label fg, bg */
60 "black", "lightgray", /* listbox fg, bg */
61 "lightgray", "blue", /* active listbox fg, bg */
62 "black", "lightgray", /* textbox fg, bg */
63 "lightgray", "red", /* active textbox fg, bg */
64 "white", "blue", /* help line */
65 "lightgray", "blue", /* root text */
66 "blue", /* scale full */
67 "red", /* scale empty */
68 "blue", "lightgray", /* disabled entry fg, bg */
69 "black", "lightgray", /* compact button fg, bg */
70 "lightgray", "red", /* active & sel listbox */
71 "black", "brown" /* selected listbox */
74 static const struct keymap keymap
[] = {
75 { "\033OA", NEWT_KEY_UP
, "ku" },
76 { "\020", NEWT_KEY_UP
, NULL
}, /* emacs ^P */
77 { "\033OB", NEWT_KEY_DOWN
, "kd" },
78 { "\016", NEWT_KEY_DOWN
, NULL
}, /* emacs ^N */
79 { "\033OC", NEWT_KEY_RIGHT
, "kr" },
80 { "\006", NEWT_KEY_RIGHT
, NULL
}, /* emacs ^F */
81 { "\033OD", NEWT_KEY_LEFT
, "kl" },
82 { "\002", NEWT_KEY_LEFT
, NULL
}, /* emacs ^B */
83 { "\033OH", NEWT_KEY_HOME
, "kh" },
84 { "\033[1~", NEWT_KEY_HOME
, NULL
},
85 { "\001", NEWT_KEY_HOME
, NULL
}, /* emacs ^A */
86 { "\033Ow", NEWT_KEY_END
, "kH" },
87 { "\033[4~", NEWT_KEY_END
, "@7" },
88 { "\005", NEWT_KEY_END
, NULL
}, /* emacs ^E */
90 { "\033[3~", NEWT_KEY_DELETE
, "kD" },
91 { "\004", NEWT_KEY_DELETE
, NULL
}, /* emacs ^D */
92 { "\033[2~", NEWT_KEY_INSERT
, "kI" },
94 { "\033\t", NEWT_KEY_UNTAB
, "kB" },
95 { "\033[Z", NEWT_KEY_UNTAB
, NULL
},
97 { "\033[5~", NEWT_KEY_PGUP
, "kP" },
98 { "\033[6~", NEWT_KEY_PGDN
, "kN" },
99 { "\033V", NEWT_KEY_PGUP
, NULL
},
100 { "\033v", NEWT_KEY_PGUP
, NULL
},
101 { "\026", NEWT_KEY_PGDN
, NULL
},
103 { "\033[[A", NEWT_KEY_F1
, NULL
},
104 { "\033[[B", NEWT_KEY_F2
, NULL
},
105 { "\033[[C", NEWT_KEY_F3
, NULL
},
106 { "\033[[D", NEWT_KEY_F4
, NULL
},
107 { "\033[[E", NEWT_KEY_F5
, NULL
},
109 { "\033OP", NEWT_KEY_F1
, NULL
},
110 { "\033OQ", NEWT_KEY_F2
, NULL
},
111 { "\033OR", NEWT_KEY_F3
, NULL
},
112 { "\033OS", NEWT_KEY_F4
, NULL
},
114 { "\033[11~", NEWT_KEY_F1
, "k1" },
115 { "\033[12~", NEWT_KEY_F2
, "k2" },
116 { "\033[13~", NEWT_KEY_F3
, "k3" },
117 { "\033[14~", NEWT_KEY_F4
, "k4" },
118 { "\033[15~", NEWT_KEY_F5
, "k5" },
119 { "\033[17~", NEWT_KEY_F6
, "k6" },
120 { "\033[18~", NEWT_KEY_F7
, "k7" },
121 { "\033[19~", NEWT_KEY_F8
, "k8" },
122 { "\033[20~", NEWT_KEY_F9
, "k9" },
123 { "\033[21~", NEWT_KEY_F10
, "k;" },
124 { "\033[23~", NEWT_KEY_F11
, "F1" },
125 { "\033[24~", NEWT_KEY_F12
, "F2" },
126 { "\033", NEWT_KEY_ESCAPE
, "@2" },
127 { "\033", NEWT_KEY_ESCAPE
, "@9" },
129 { "\177", NEWT_KEY_BKSPC
, NULL
},
130 { "\010", NEWT_KEY_BKSPC
, NULL
},
132 { 0 }, /* LEAVE this one */
134 static void initKeymap();
135 static void freeKeymap();
137 static const char ident
[] = // ident friendly
138 "$Version: Newt windowing library v" VERSION
" $"
139 "$Copyright: (C) 1996-2003 Red Hat, Inc. Written by Erik Troan $"
140 "$License: Lesser GNU Public License. $";
142 static newtSuspendCallback suspendCallback
= NULL
;
143 static void * suspendCallbackData
= NULL
;
145 void newtSetSuspendCallback(newtSuspendCallback cb
, void * data
) {
146 suspendCallback
= cb
;
147 suspendCallbackData
= data
;
150 static void handleSigwinch(int signum
) {
154 static int getkeyInterruptHook(void) {
158 int _newt_wstrlen(const char *str
, int len
) {
165 if (len
< 0) len
= strlen(str
);
166 memset(&ps
,0,sizeof(mbstate_t));
170 x
= mbrtowc(&tmp
,str
,len
,&ps
);
182 /** Trim a string to fit
183 * @param title - string. NULL will be inserted if necessary
184 * @param chrs - available space. (character cells)
186 void trim_string(char *title
, int chrs
)
194 memset(&ps
, 0, sizeof(ps
));
198 x
= mbrtowc(&tmp
, p
, ln
, &ps
);
199 if (x
< 0) { // error
215 static int getkey() {
218 while ((c
= SLang_getkey()) == '\xC') { /* if Ctrl-L redraw whole screen */
219 SLsmg_touch_lines(0, SLtt_Screen_Rows
);
226 static void updateColorset(char *fg
, char *bg
, char **fg_p
, char **bg_p
)
234 /* parse color specifications (e.g. root=,black:border=red,blue)
235 * and update the palette
237 static void parseColors(char *s
, struct newtColors
*palette
)
239 char *name
, *str
, *fg
, *bg
;
241 for (str
= s
; (s
= strtok(str
, ";:\n\r\t ")); str
= NULL
) {
243 if (!(s
= strchr(s
, '=')) || !*s
)
247 if (!(s
= strchr(s
, ',')) || !*s
)
252 if (!strcmp(name
, "root"))
253 updateColorset(fg
, bg
, &palette
->rootFg
, &palette
->rootBg
);
254 else if (!strcmp(name
, "border"))
255 updateColorset(fg
, bg
, &palette
->borderFg
, &palette
->borderBg
);
256 else if (!strcmp(name
, "window"))
257 updateColorset(fg
, bg
, &palette
->windowFg
, &palette
->windowBg
);
258 else if (!strcmp(name
, "shadow"))
259 updateColorset(fg
, bg
, &palette
->shadowFg
, &palette
->shadowBg
);
260 else if (!strcmp(name
, "title"))
261 updateColorset(fg
, bg
, &palette
->titleFg
, &palette
->titleBg
);
262 else if (!strcmp(name
, "button"))
263 updateColorset(fg
, bg
, &palette
->buttonFg
, &palette
->buttonBg
);
264 else if (!strcmp(name
, "actbutton"))
265 updateColorset(fg
, bg
, &palette
->actButtonFg
, &palette
->actButtonBg
);
266 else if (!strcmp(name
, "checkbox"))
267 updateColorset(fg
, bg
, &palette
->checkboxFg
, &palette
->checkboxBg
);
268 else if (!strcmp(name
, "actcheckbox"))
269 updateColorset(fg
, bg
, &palette
->actCheckboxFg
, &palette
->actCheckboxBg
);
270 else if (!strcmp(name
, "entry"))
271 updateColorset(fg
, bg
, &palette
->entryFg
, &palette
->entryBg
);
272 else if (!strcmp(name
, "label"))
273 updateColorset(fg
, bg
, &palette
->labelFg
, &palette
->labelBg
);
274 else if (!strcmp(name
, "listbox"))
275 updateColorset(fg
, bg
, &palette
->listboxFg
, &palette
->listboxBg
);
276 else if (!strcmp(name
, "actlistbox"))
277 updateColorset(fg
, bg
, &palette
->actListboxFg
, &palette
->actListboxBg
);
278 else if (!strcmp(name
, "textbox"))
279 updateColorset(fg
, bg
, &palette
->textboxFg
, &palette
->textboxBg
);
280 else if (!strcmp(name
, "acttextbox"))
281 updateColorset(fg
, bg
, &palette
->actTextboxFg
, &palette
->actTextboxBg
);
282 else if (!strcmp(name
, "helpline"))
283 updateColorset(fg
, bg
, &palette
->helpLineFg
, &palette
->helpLineBg
);
284 else if (!strcmp(name
, "roottext"))
285 updateColorset(fg
, bg
, &palette
->rootTextFg
, &palette
->rootTextBg
);
286 else if (!strcmp(name
, "emptyscale"))
287 updateColorset(fg
, bg
, NULL
, &palette
->emptyScale
);
288 else if (!strcmp(name
, "fullscale"))
289 updateColorset(fg
, bg
, NULL
, &palette
->fullScale
);
290 else if (!strcmp(name
, "disentry"))
291 updateColorset(fg
, bg
, &palette
->disabledEntryFg
, &palette
->disabledEntryBg
);
292 else if (!strcmp(name
, "compactbutton"))
293 updateColorset(fg
, bg
, &palette
->compactButtonFg
, &palette
->compactButtonBg
);
294 else if (!strcmp(name
, "actsellistbox"))
295 updateColorset(fg
, bg
, &palette
->actSelListboxFg
, &palette
->actSelListboxBg
);
296 else if (!strcmp(name
, "sellistbox"))
297 updateColorset(fg
, bg
, &palette
->selListboxFg
, &palette
->selListboxBg
);
301 static void initColors(void)
303 char *colors
, *colors_file
, buf
[16384];
305 struct newtColors palette
;
307 palette
= newtDefaultColorPalette
;
309 colors_file
= getenv("NEWT_COLORS_FILE");
310 #ifdef NEWT_COLORS_FILE
311 if (colors_file
== NULL
)
312 colors_file
= NEWT_COLORS_FILE
;
315 if ((colors
= getenv("NEWT_COLORS"))) {
316 strncpy(buf
, colors
, sizeof (buf
));
317 buf
[sizeof (buf
) - 1] = '\0';
318 parseColors(buf
, &palette
);
319 } else if (colors_file
&& *colors_file
&& (f
= fopen(colors_file
, "r"))) {
321 if ((r
= fread(buf
, 1, sizeof (buf
) - 1, f
)) > 0) {
323 parseColors(buf
, &palette
);
328 newtSetColors(palette
);
331 void newtFlushInput(void) {
332 while (SLang_input_pending(0)) {
338 * @brief Refresh the screen
340 void newtRefresh(void) {
344 void newtSuspend(void) {
345 SLtt_set_cursor_visibility (1);
348 SLtt_set_cursor_visibility (cursorOn
);
352 * @brief Return after suspension.
353 * @return 0 on success.
355 int newtResume(void) {
358 return SLang_init_tty(0, 0, 0);
362 SLsmg_set_color(NEWT_COLORSET_ROOT
);
370 * @brief Resize the screen
371 * @param redraw - boolean - should we redraw the screen?
373 void newtResizeScreen(int redraw
) {
374 /* we can't redraw from scratch, just redisplay SLang screen */
375 SLtt_get_screen_size();
376 /* SLsmg_reinit_smg(); */
378 SLsmg_touch_lines(0, SLtt_Screen_Rows
);
384 * @brief Initialize the newt library
385 * @return int - 0 for success, else < 0
388 char * MonoValue
, * MonoEnv
= "NEWT_MONO";
392 if ((lang
= getenv("LC_ALL")) == NULL
)
393 if ((lang
= getenv("LC_CTYPE")) == NULL
)
394 if ((lang
= getenv("LANG")) == NULL
)
396 /* slang doesn't support multibyte encodings except UTF-8,
397 avoid character corruption by redrawing the screen */
398 if (strstr (lang
, ".euc") != NULL
)
401 (void) strlen(ident
);
405 SLtt_get_screen_size();
407 MonoValue
= getenv(MonoEnv
);
408 if ( MonoValue
!= NULL
)
409 SLtt_Use_Ansi_Colors
= 0;
411 if ((ret
= SLsmg_init_smg()) < 0)
413 if ((ret
= SLang_init_tty(0, 0, 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
)
872 row
= currentWindow
->top
- 1;
873 col
= currentWindow
->left
- 2;
878 for (j
= 0; j
< currentWindow
->height
+ 3; j
++, row
++) {
879 SLsmg_gotorc(row
, col
);
880 SLsmg_write_raw(currentWindow
->buffer
+ n
,
881 currentWindow
->width
+ 5);
882 n
+= currentWindow
->width
+ 5;
885 free(currentWindow
->buffer
);
886 free(currentWindow
->title
);
888 if (currentWindow
== windowStack
)
889 currentWindow
= NULL
;
893 SLsmg_set_char_set(0);
898 void newtGetWindowPos(int * x
, int * y
) {
900 *x
= currentWindow
->left
;
901 *y
= currentWindow
->top
;
906 void newtGetrc(int * row
, int * col
) {
911 *row
-= currentWindow
->top
;
912 *col
-= currentWindow
->left
;
916 void newtGotorc(int newRow
, int newCol
) {
918 newRow
+= currentWindow
->top
;
919 newCol
+= currentWindow
->left
;
924 SLsmg_gotorc(cursorRow
, cursorCol
);
927 void newtDrawBox(int left
, int top
, int width
, int height
, int shadow
) {
929 top
+= currentWindow
->top
;
930 left
+= currentWindow
->left
;
933 SLsmg_draw_box(top
, left
, height
, width
);
936 SLsmg_set_color(NEWT_COLORSET_SHADOW
);
937 SLsmg_fill_region(top
+ height
, left
+ 1, 1, width
- 1, ' ');
938 SLsmg_fill_region(top
+ 1, left
+ width
, height
, 1, ' ');
942 void newtClearBox(int left
, int top
, int width
, int height
) {
944 top
+= currentWindow
->top
;
945 left
+= currentWindow
->left
;
948 SLsmg_fill_region(top
, left
, height
, width
, ' ');
951 static void initKeymap(void) {
952 const struct keymap
* curr
;
953 struct kmap_trie_entry
*kmap_trie_escBrack
, *kmap_trie_escO
;
955 /* Here are some entries that will help in handling esc O foo and
956 esc [ foo as variants of each other. */
957 kmap_trie_root
= calloc(3, sizeof (struct kmap_trie_entry
));
958 kmap_trie_escBrack
= kmap_trie_root
+ 1;
959 kmap_trie_escO
= kmap_trie_root
+ 2;
961 kmap_trie_root
->alloced
= 1;
962 kmap_trie_root
->c
= '\033';
963 kmap_trie_root
->contseq
= kmap_trie_escBrack
;
965 kmap_trie_escBrack
->c
= '[';
966 kmap_trie_escBrack
->next
= kmap_trie_escO
;
968 kmap_trie_escO
->c
= 'O';
970 /* First bind built-in default bindings. They may be shadowed by
971 the termcap entries that get bound later. */
972 for (curr
= keymap
; curr
->code
; curr
++) {
974 newtBindKey(curr
->str
,curr
->code
);
977 /* Then bind strings from termcap entries */
978 for (curr
= keymap
; curr
->code
; curr
++) {
980 char *pc
= SLtt_tgetstr(curr
->tc
);
982 newtBindKey(pc
,curr
->code
);
987 /* Finally, invent lowest-priority keybindings that correspond to
988 searching for esc-O-foo if esc-[-foo was not found and vice
989 versa. That is needed because of strong confusion among
990 different emulators of VTxxx terminals; some terminfo/termcap
991 descriptions are apparently written by people who were not
992 aware of the differences between "applicataion" and "terminal"
993 keypad modes. Or perhaps they were, but tried to make their
994 description work with a program that puts the keyboard in the
995 wrong emulation mode. In short, one needs this: */
996 kmap_trie_fallback(kmap_trie_escO
->contseq
, &kmap_trie_escBrack
->contseq
);
997 kmap_trie_fallback(kmap_trie_escBrack
->contseq
, &kmap_trie_escO
->contseq
);
1000 static void free_keys(struct kmap_trie_entry
*kmap
, struct kmap_trie_entry
*parent
, int prepare
) {
1004 free_keys(kmap
->contseq
, kmap
, prepare
);
1005 free_keys(kmap
->next
, kmap
, prepare
);
1007 if (!kmap
->alloced
&& kmap
- parent
== 1)
1010 /* find first element in array */
1011 while (!kmap
->alloced
)
1014 kmap
->alloced
+= prepare
? 1 : -1;
1015 if (!prepare
&& kmap
->alloced
== 1)
1019 static void freeKeymap() {
1020 free_keys(kmap_trie_root
, NULL
, 1);
1021 free_keys(kmap_trie_root
, NULL
, 0);
1022 kmap_trie_root
= NULL
;
1026 * @brief Delay for a specified number of usecs
1027 * @param int - number of usecs to wait for.
1029 void newtDelay(unsigned int usecs
) {
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
;