]> git.ipfire.org Git - thirdparty/newt.git/blob - newt.c
- add newtPopWindowNoRefresh()
[thirdparty/newt.git] / newt.c
1 #include "config.h"
2
3 #include <slang.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <sys/signal.h>
8 #include <sys/time.h>
9 #include <sys/types.h>
10 #include <termios.h>
11 #include <unistd.h>
12 #include <wchar.h>
13
14 #ifdef HAVE_ALLOCA_H
15 #include <alloca.h>
16 #endif
17
18 #include "newt.h"
19 #include "newt_pr.h"
20
21 struct Window {
22 int height, width, top, left;
23 SLsmg_Char_Type * buffer;
24 char * title;
25 };
26
27 struct keymap {
28 char * str;
29 int code;
30 char * tc;
31 };
32
33 static struct Window windowStack[20];
34 static struct Window * currentWindow = NULL;
35
36 static char * helplineStack[20];
37 static char ** currentHelpline = NULL;
38
39 static int cursorRow, cursorCol;
40 static int needResize = 0;
41 static int cursorOn = 1;
42 static int trashScreen = 0;
43
44 static const char * defaultHelpLine =
45 " <Tab>/<Alt-Tab> between elements | <Space> selects | <F12> next screen"
46 ;
47
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 */
72 };
73
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 */
89
90 { "\033[3~", NEWT_KEY_DELETE, "kD" },
91 { "\004", NEWT_KEY_DELETE, NULL }, /* emacs ^D */
92 { "\033[2~", NEWT_KEY_INSERT, "kI" },
93
94 { "\033\t", NEWT_KEY_UNTAB, "kB" },
95
96 { "\033[5~", NEWT_KEY_PGUP, "kP" },
97 { "\033[6~", NEWT_KEY_PGDN, "kN" },
98 { "\033V", NEWT_KEY_PGUP, NULL },
99 { "\033v", NEWT_KEY_PGUP, NULL },
100 { "\026", NEWT_KEY_PGDN, NULL },
101
102 { "\033[[A", NEWT_KEY_F1, NULL },
103 { "\033[[B", NEWT_KEY_F2, NULL },
104 { "\033[[C", NEWT_KEY_F3, NULL },
105 { "\033[[D", NEWT_KEY_F4, NULL },
106 { "\033[[E", NEWT_KEY_F5, NULL },
107
108 { "\033OP", NEWT_KEY_F1, NULL },
109 { "\033OQ", NEWT_KEY_F2, NULL },
110 { "\033OR", NEWT_KEY_F3, NULL },
111 { "\033OS", NEWT_KEY_F4, NULL },
112
113 { "\033[11~", NEWT_KEY_F1, "k1" },
114 { "\033[12~", NEWT_KEY_F2, "k2" },
115 { "\033[13~", NEWT_KEY_F3, "k3" },
116 { "\033[14~", NEWT_KEY_F4, "k4" },
117 { "\033[15~", NEWT_KEY_F5, "k5" },
118 { "\033[17~", NEWT_KEY_F6, "k6" },
119 { "\033[18~", NEWT_KEY_F7, "k7" },
120 { "\033[19~", NEWT_KEY_F8, "k8" },
121 { "\033[20~", NEWT_KEY_F9, "k9" },
122 { "\033[21~", NEWT_KEY_F10, "k;" },
123 { "\033[23~", NEWT_KEY_F11, "F1" },
124 { "\033[24~", NEWT_KEY_F12, "F2" },
125 { "\033", NEWT_KEY_ESCAPE, "@2" },
126 { "\033", NEWT_KEY_ESCAPE, "@9" },
127
128 { "\177", NEWT_KEY_BKSPC, NULL },
129 { "\010", NEWT_KEY_BKSPC, NULL },
130
131 { 0 }, /* LEAVE this one */
132 };
133 static void initKeymap();
134
135 static const char ident[] = // ident friendly
136 "$Version: Newt windowing library v" VERSION " $"
137 "$Copyright: (C) 1996-2003 Red Hat, Inc. Written by Erik Troan $"
138 "$License: Lesser GNU Public License. $";
139
140 static newtSuspendCallback suspendCallback = NULL;
141 static void * suspendCallbackData = NULL;
142
143 void newtSetSuspendCallback(newtSuspendCallback cb, void * data) {
144 suspendCallback = cb;
145 suspendCallbackData = data;
146 }
147
148 static void handleSigwinch(int signum) {
149 needResize = 1;
150 }
151
152 static int getkeyInterruptHook(void) {
153 return -1;
154 }
155
156 int _newt_wstrlen(const char *str, int len) {
157 mbstate_t ps;
158 wchar_t tmp;
159 int nchars = 0;
160
161 if (!str) return 0;
162 if (!len) return 0;
163 if (len < 0) len = strlen(str);
164 memset(&ps,0,sizeof(mbstate_t));
165 while (len > 0) {
166 int x,y;
167
168 x = mbrtowc(&tmp,str,len,&ps);
169 if (x >0) {
170 str += x;
171 len -= x;
172 y = wcwidth(tmp);
173 if (y>0)
174 nchars+=y;
175 } else break;
176 }
177 return nchars;
178 }
179
180 /** Trim a string to fit
181 * @param title - string. NULL will be inserted if necessary
182 * @param chrs - available space. (character cells)
183 */
184 void trim_string(char *title, int chrs)
185 {
186 char *p = title;
187 int ln;
188 int x = 0,y = 0;
189 wchar_t tmp;
190 mbstate_t ps;
191
192 memset(&ps, 0, sizeof(ps));
193 ln = strlen(title);
194
195 while (*p) {
196 x = mbrtowc(&tmp, p, ln, &ps);
197 if (x < 0) { // error
198 *p = '\0';
199 return;
200 }
201 y = wcwidth(tmp);
202 if (y > chrs) {
203 *p = '\0';
204 return;
205 } else {
206 p += x;
207 ln -= x;
208 chrs -= y;
209 }
210 }
211 }
212
213 static int getkey() {
214 int c;
215
216 while ((c = SLang_getkey()) == '\xC') { /* if Ctrl-L redraw whole screen */
217 SLsmg_touch_lines (0, SLtt_Screen_Rows - 1);
218 SLsmg_refresh();
219 }
220 return c;
221
222 }
223
224 void newtFlushInput(void) {
225 while (SLang_input_pending(0)) {
226 getkey();
227 }
228 }
229
230 /**
231 * @brief Refresh the screen
232 */
233 void newtRefresh(void) {
234 SLsmg_refresh();
235 }
236
237 void newtSuspend(void) {
238 SLtt_set_cursor_visibility (1);
239 SLsmg_suspend_smg();
240 SLang_reset_tty();
241 SLtt_set_cursor_visibility (cursorOn);
242 }
243
244 /**
245 * @brief Return after suspension.
246 * @return 0 on success.
247 */
248 int newtResume(void) {
249 SLsmg_resume_smg ();
250 SLsmg_refresh();
251 return SLang_init_tty(0, 0, 0);
252 }
253
254 void newtCls(void) {
255 SLsmg_set_color(NEWT_COLORSET_ROOT);
256 SLsmg_gotorc(0, 0);
257 SLsmg_erase_eos();
258
259 newtRefresh();
260 }
261
262 /**
263 * @brief Resize the screen
264 * @param redraw - boolean - should we redraw the screen?
265 */
266 void newtResizeScreen(int redraw) {
267 SLtt_get_screen_size();
268 SLsmg_reinit_smg();
269 if (redraw) {
270 SLsmg_touch_lines (0, SLtt_Screen_Rows - 1);
271 newtRefresh();
272 }
273 }
274
275 /**
276 * @brief Initialize the newt library
277 * @return int - 0 for success, else < 0
278 */
279 int newtInit(void) {
280 char * MonoValue, * MonoEnv = "NEWT_MONO";
281 const char *lang;
282 int ret;
283
284 if ((lang = getenv("LC_ALL")) == NULL)
285 if ((lang = getenv("LC_CTYPE")) == NULL)
286 if ((lang = getenv("LANG")) == NULL)
287 lang = "";
288 if (strstr (lang, ".euc") != NULL)
289 trashScreen = 1;
290
291 (void) strlen(ident);
292
293 SLtt_get_terminfo();
294 SLtt_get_screen_size();
295
296 MonoValue = getenv(MonoEnv);
297 if ( MonoValue != NULL )
298 SLtt_Use_Ansi_Colors = 0;
299
300 if ((ret = SLsmg_init_smg()) < 0)
301 return ret;
302 if ((ret = SLang_init_tty(0, 0, 0)) < 0)
303 return ret;
304
305 newtSetColors(newtDefaultColorPalette);
306 newtCursorOff();
307 initKeymap();
308
309 /*memset(&sa, 0, sizeof(sa));
310 sa.sa_handler = handleSigwinch;
311 sigaction(SIGWINCH, &sa, NULL);*/
312
313 SLsignal_intr(SIGWINCH, handleSigwinch);
314 SLang_getkey_intr_hook = getkeyInterruptHook;
315
316 return 0;
317 }
318
319 /**
320 * @brief Closedown the newt library, tidying screen.
321 * @returns int , 0. (no errors reported)
322 */
323 int newtFinished(void) {
324 SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
325 newtCursorOn();
326 SLsmg_refresh();
327 SLsmg_reset_smg();
328 SLang_reset_tty();
329
330 return 0;
331 }
332
333 /**
334 * @brief Set the colors used.
335 * @param colors - newtColor struct used.
336 */
337 void newtSetColors(struct newtColors colors) {
338 if (!SLtt_Use_Ansi_Colors) {
339 int i;
340
341 for (i = 2; i < 25; i++)
342 SLtt_set_mono(i, NULL, 0);
343
344 SLtt_set_mono(NEWT_COLORSET_SELLISTBOX, NULL, SLTT_BOLD_MASK);
345
346 SLtt_set_mono(NEWT_COLORSET_ACTBUTTON, NULL, SLTT_REV_MASK);
347 SLtt_set_mono(NEWT_COLORSET_ACTCHECKBOX, NULL, SLTT_REV_MASK);
348 SLtt_set_mono(NEWT_COLORSET_ACTLISTBOX, NULL, SLTT_REV_MASK);
349 SLtt_set_mono(NEWT_COLORSET_ACTTEXTBOX, NULL, SLTT_REV_MASK);
350
351 SLtt_set_mono(NEWT_COLORSET_ACTSELLISTBOX, NULL, SLTT_REV_MASK | SLTT_BOLD_MASK);
352
353 SLtt_set_mono(NEWT_COLORSET_DISENTRY, NULL, 0); // FIXME
354 SLtt_set_mono(NEWT_COLORSET_FULLSCALE, NULL, SLTT_ULINE_MASK | SLTT_REV_MASK);
355 SLtt_set_mono(NEWT_COLORSET_EMPTYSCALE, NULL, SLTT_ULINE_MASK);
356 return;
357 }
358 SLtt_set_color(NEWT_COLORSET_ROOT, "", colors.rootFg, colors.rootBg);
359 SLtt_set_color(NEWT_COLORSET_BORDER, "", colors.borderFg, colors.borderBg);
360 SLtt_set_color(NEWT_COLORSET_WINDOW, "", colors.windowFg, colors.windowBg);
361 SLtt_set_color(NEWT_COLORSET_SHADOW, "", colors.shadowFg, colors.shadowBg);
362 SLtt_set_color(NEWT_COLORSET_TITLE, "", colors.titleFg, colors.titleBg);
363 SLtt_set_color(NEWT_COLORSET_BUTTON, "", colors.buttonFg, colors.buttonBg);
364 SLtt_set_color(NEWT_COLORSET_ACTBUTTON, "", colors.actButtonFg,
365 colors.actButtonBg);
366 SLtt_set_color(NEWT_COLORSET_CHECKBOX, "", colors.checkboxFg,
367 colors.checkboxBg);
368 SLtt_set_color(NEWT_COLORSET_ACTCHECKBOX, "", colors.actCheckboxFg,
369 colors.actCheckboxBg);
370 SLtt_set_color(NEWT_COLORSET_ENTRY, "", colors.entryFg, colors.entryBg);
371 SLtt_set_color(NEWT_COLORSET_LABEL, "", colors.labelFg, colors.labelBg);
372 SLtt_set_color(NEWT_COLORSET_LISTBOX, "", colors.listboxFg,
373 colors.listboxBg);
374 SLtt_set_color(NEWT_COLORSET_ACTLISTBOX, "", colors.actListboxFg,
375 colors.actListboxBg);
376 SLtt_set_color(NEWT_COLORSET_TEXTBOX, "", colors.textboxFg,
377 colors.textboxBg);
378 SLtt_set_color(NEWT_COLORSET_ACTTEXTBOX, "", colors.actTextboxFg,
379 colors.actTextboxBg);
380 SLtt_set_color(NEWT_COLORSET_HELPLINE, "", colors.helpLineFg,
381 colors.helpLineBg);
382 SLtt_set_color(NEWT_COLORSET_ROOTTEXT, "", colors.rootTextFg,
383 colors.rootTextBg);
384
385 SLtt_set_color(NEWT_COLORSET_EMPTYSCALE, "", "white",
386 colors.emptyScale);
387 SLtt_set_color(NEWT_COLORSET_FULLSCALE, "", "white",
388 colors.fullScale);
389 SLtt_set_color(NEWT_COLORSET_DISENTRY, "", colors.disabledEntryFg,
390 colors.disabledEntryBg);
391
392 SLtt_set_color(NEWT_COLORSET_COMPACTBUTTON, "", colors.compactButtonFg,
393 colors.compactButtonBg);
394
395 SLtt_set_color(NEWT_COLORSET_ACTSELLISTBOX, "", colors.actSelListboxFg,
396 colors.actSelListboxBg);
397 SLtt_set_color(NEWT_COLORSET_SELLISTBOX, "", colors.selListboxFg,
398 colors.selListboxBg);
399 }
400
401 /* Keymap handling - rewritten by Henning Makholm <henning@makholm.net>,
402 * November 2003.
403 */
404
405 struct kmap_trie_entry {
406 char c ; /* character got from terminal */
407 int code; /* newt key, or 0 if c does not make a complete sequence */
408 struct kmap_trie_entry *contseq; /* sub-trie for character following c */
409 struct kmap_trie_entry *next; /* try this if char received != c */
410 };
411 /* Here are some static entries that will help in handling esc O foo and
412 esc [ foo as variants of each other: */
413 static struct kmap_trie_entry
414 kmap_trie_escO = { 'O', 0, 0, 0 },
415 kmap_trie_escBrack = { '[', 0, 0, &kmap_trie_escO },
416 kmap_trie_root = { '\033', 0, &kmap_trie_escBrack, 0 };
417 static int keyreader_buf_len = 10 ;
418 static unsigned char default_keyreader_buf[10];
419 static unsigned char *keyreader_buf = default_keyreader_buf;
420
421 #if 0 /* for testing of the keymap manipulation code */
422 static void dumpkeys_recursive(struct kmap_trie_entry *curr, int i, FILE *f) {
423 int j, ps ;
424 char seen[256]={0};
425 if( curr && i >= keyreader_buf_len ) {
426 fprintf(f,"ARGH! Too long sequence!\n") ;
427 return ;
428 }
429 for(;curr;curr=curr->next) {
430 keyreader_buf[i] = curr->c ;
431 ps = seen[(unsigned char)curr->c]++ ;
432 if( ps || curr->code || (!curr->code && !curr->contseq) ) {
433 for(j=0;j<=i;j++) {
434 if( keyreader_buf[j] > 32 && keyreader_buf[j]<127 &&
435 keyreader_buf[j] != '^' && keyreader_buf[j] != '\\' )
436 fprintf(f,"%c",keyreader_buf[j]);
437 else if( keyreader_buf[j] > 0 && keyreader_buf[j]<=32 )
438 fprintf(f,"^%c",keyreader_buf[j] + 0x40);
439 else
440 fprintf(f,"\\%03o",
441 (unsigned)(unsigned char)keyreader_buf[j]);
442 }
443 if( curr->code )
444 fprintf(f,": 0x%X\n",curr->code);
445 else
446 fprintf(f,": (just keymap)\n");
447 }
448 dumpkeys_recursive(curr->contseq,i+1,f);
449 }
450 }
451 static void dump_keymap(void) {
452 FILE *f = fopen("newt.keydump","wt");
453 if (f) {
454 dumpkeys_recursive(&kmap_trie_root,0,f);
455 fclose(f);
456 }
457 }
458 #endif
459
460 /* newtBindKey may overwrite a binding that is there already */
461 static void newtBindKey(char *keyseq, int meaning) {
462 struct kmap_trie_entry *root = &kmap_trie_root ;
463 struct kmap_trie_entry **curptr = &root ;
464
465 /* Try to make sure the common matching buffer is long enough. */
466 if( strlen(keyseq) > keyreader_buf_len ) {
467 int i = strlen(keyseq)+10;
468 unsigned char *newbuf = malloc(i);
469 if (newbuf) {
470 if (keyreader_buf != default_keyreader_buf)
471 free(keyreader_buf);
472 keyreader_buf = newbuf;
473 keyreader_buf_len = i;
474 }
475 }
476
477 if (*keyseq == 0) return; /* binding the empty sequence is meaningless */
478
479 while(1) {
480 while ((*curptr) && (*curptr)->c != *keyseq)
481 curptr = &(*curptr)->next;
482 if ((*curptr)==0) {
483 struct kmap_trie_entry* fresh
484 = calloc(strlen(keyseq),sizeof(struct kmap_trie_entry));
485 if (fresh == 0) return; /* despair! */
486 *curptr = fresh;
487 while (keyseq[1]) {
488 fresh->contseq = fresh+1;
489 (fresh++)->c = *(keyseq++);
490 }
491 fresh->c = *keyseq;
492 fresh->code = meaning;
493 return;
494 }
495 if (keyseq[1]==0) {
496 (*curptr)->code = meaning;
497 return;
498 } else {
499 curptr = &(*curptr)->contseq;
500 keyseq++;
501 }
502 }
503 }
504
505 /* This function recursively inserts all entries in the "to" trie into
506 corresponding positions in the "from" trie, except positions that
507 are already defined in the "from" trie. */
508 static void kmap_trie_fallback(struct kmap_trie_entry *to,
509 struct kmap_trie_entry **from) {
510 if (*from == NULL)
511 *from = to ;
512 if (*from == to)
513 return ;
514 for (;to!=NULL;to=to->next) {
515 struct kmap_trie_entry **fromcopy = from ;
516 while ((*fromcopy) && (*fromcopy)->c != to->c)
517 fromcopy = &(*fromcopy)->next ;
518 if (*fromcopy) {
519 if ((*fromcopy)->code == 0)
520 (*fromcopy)->code = to->code;
521 kmap_trie_fallback(to->contseq, &(*fromcopy)->contseq);
522 } else {
523 *fromcopy = malloc(sizeof(struct kmap_trie_entry));
524 if (*fromcopy) {
525 **fromcopy = *to ;
526 (*fromcopy)->next = 0 ;
527 }
528 }
529 }
530 }
531
532 int newtGetKey(void) {
533 int key;
534 unsigned char *chptr = keyreader_buf, *lastmatch;
535 int lastcode;
536 struct kmap_trie_entry *curr = &kmap_trie_root;
537
538 do {
539 key = getkey();
540 if (key == SLANG_GETKEY_ERROR) {
541 /* Either garbage was read, or stdin disappeared
542 * (the parent terminal was proably closed)
543 * if the latter, die.
544 */
545 if (feof(stdin))
546 exit(1);
547 if (needResize) {
548 needResize = 0;
549 return NEWT_KEY_RESIZE;
550 }
551
552 /* ignore other signals */
553 continue;
554 }
555
556 if (key == NEWT_KEY_SUSPEND && suspendCallback)
557 suspendCallback(suspendCallbackData);
558 } while (key == NEWT_KEY_SUSPEND);
559
560 /* Read more characters, matching against the trie as we go */
561 lastcode = *chptr = key;
562 lastmatch = chptr ;
563 while(1) {
564 while (curr->c != key) {
565 curr = curr->next ;
566 if (curr==NULL) goto break2levels;
567 }
568 if (curr->code) {
569 lastcode = curr->code;
570 lastmatch = chptr;
571 }
572 curr = curr->contseq;
573 if (curr==NULL) break;
574
575 if (SLang_input_pending(5) <= 0)
576 break;
577
578 if (chptr==keyreader_buf+keyreader_buf_len-1) break;
579 *++chptr = key = getkey();
580 }
581 break2levels:
582
583 /* The last time the trie matched was at position lastmatch. Back
584 * up if we have read too many characters. */
585 while (chptr > lastmatch)
586 SLang_ungetkey(*chptr--);
587
588 return lastcode;
589 }
590
591 /**
592 * @brief Wait for a keystroke
593 */
594 void newtWaitForKey(void) {
595 newtRefresh();
596
597 getkey();
598 newtClearKeyBuffer();
599 }
600
601 /**
602 * @brief Clear the keybuffer
603 */
604 void newtClearKeyBuffer(void) {
605 while (SLang_input_pending(1)) {
606 getkey();
607 }
608 }
609
610 /**
611 * Open a new window.
612 * @param left. int Size; _not_ including border
613 * @param top: int size, _not_ including border
614 * @param width unsigned int
615 * @param height unsigned int
616 * @param title - title string
617 * @return zero on success (currently no errors reported)
618 */
619 int newtOpenWindow(int left, int top,
620 unsigned int width, unsigned int height,
621 const char * title) {
622 int j, row, col;
623 int n;
624 int i;
625
626 newtFlushInput();
627
628 if (!currentWindow) {
629 currentWindow = windowStack;
630 } else {
631 currentWindow++;
632 }
633
634 currentWindow->left = left;
635 currentWindow->top = top;
636 currentWindow->width = width;
637 currentWindow->height = height;
638 currentWindow->title = title ? strdup(title) : NULL;
639
640 currentWindow->buffer = malloc(sizeof(SLsmg_Char_Type) * (width + 5) * (height + 3));
641
642 row = top - 1;
643 col = left - 2;
644 /* clip to the current screen bounds - msw */
645 if (row < 0)
646 row = 0;
647 if (col < 0)
648 col = 0;
649 if (left + width > SLtt_Screen_Cols)
650 width = SLtt_Screen_Cols - left;
651 if (top + height > SLtt_Screen_Rows)
652 height = SLtt_Screen_Rows - top;
653 n = 0;
654 for (j = 0; j < height + 3; j++, row++) {
655 SLsmg_gotorc(row, col);
656 SLsmg_read_raw(currentWindow->buffer + n,
657 currentWindow->width + 5);
658 n += currentWindow->width + 5;
659 }
660
661 newtTrashScreen();
662
663 SLsmg_set_color(NEWT_COLORSET_BORDER);
664 SLsmg_set_char_set(1);
665 SLsmg_draw_box(top - 1, left - 1, height + 2, width + 2);
666 SLsmg_set_char_set(0);
667
668 if (currentWindow->title) {
669 trim_string (currentWindow->title, width-4);
670 i = wstrlen(currentWindow->title,-1) + 4;
671 i = ((width - i) / 2) + left;
672 SLsmg_gotorc(top - 1, i);
673 SLsmg_set_char_set(1);
674 SLsmg_write_char(SLSMG_RTEE_CHAR);
675 SLsmg_set_char_set(0);
676 SLsmg_write_char(' ');
677 SLsmg_set_color(NEWT_COLORSET_TITLE);
678 SLsmg_write_string((char *)currentWindow->title);
679 SLsmg_set_color(NEWT_COLORSET_BORDER);
680 SLsmg_write_char(' ');
681 SLsmg_set_char_set(1);
682 SLsmg_write_char(SLSMG_LTEE_CHAR);
683 SLsmg_set_char_set(0);
684 }
685
686 SLsmg_set_color(NEWT_COLORSET_WINDOW);
687 SLsmg_fill_region(top, left, height, width, ' ');
688
689 SLsmg_set_color(NEWT_COLORSET_SHADOW);
690 SLsmg_fill_region(top + height + 1, left, 1, width + 2, ' ');
691 SLsmg_fill_region(top, left + width + 1, height + 1, 1, ' ');
692
693 for (i = top; i < (top + height + 1); i++) {
694 SLsmg_gotorc(i, left + width + 1);
695 SLsmg_write_string(" ");
696 }
697
698 return 0;
699 }
700
701 /**
702 * @brief Draw a centered window.
703 * @param width - width in char cells
704 * @param height - no. of char cells.
705 * @param title - fixed title
706 * @returns 0. No errors reported
707 */
708 int newtCenteredWindow(unsigned int width,unsigned int height,
709 const char * title) {
710 int top, left;
711
712 top = (int)(SLtt_Screen_Rows - height) / 2;
713
714 /* I don't know why, but this seems to look better */
715 if ((SLtt_Screen_Rows % 2) && (top % 2)) top--;
716
717 left = (int)(SLtt_Screen_Cols - width) / 2;
718
719 newtOpenWindow(left, top, width, height, title);
720
721 return 0;
722 }
723
724 /**
725 * @brief Remove the top window
726 */
727 void newtPopWindow(void) {
728 newtPopWindowNoRefresh();
729 newtRefresh();
730 }
731
732 void newtPopWindowNoRefresh(void) {
733 int j, row, col;
734 int n = 0;
735
736 row = col = 0;
737
738 row = currentWindow->top - 1;
739 col = currentWindow->left - 2;
740 if (row < 0)
741 row = 0;
742 if (col < 0)
743 col = 0;
744 for (j = 0; j < currentWindow->height + 3; j++, row++) {
745 SLsmg_gotorc(row, col);
746 SLsmg_write_raw(currentWindow->buffer + n,
747 currentWindow->width + 5);
748 n += currentWindow->width + 5;
749 }
750
751 free(currentWindow->buffer);
752 free(currentWindow->title);
753
754 if (currentWindow == windowStack)
755 currentWindow = NULL;
756 else
757 currentWindow--;
758
759 SLsmg_set_char_set(0);
760
761 newtTrashScreen();
762 }
763
764 void newtGetWindowPos(int * x, int * y) {
765 if (currentWindow) {
766 *x = currentWindow->left;
767 *y = currentWindow->top;
768 } else
769 *x = *y = 0;
770 }
771
772 void newtGetrc(int * row, int * col) {
773 *row = cursorRow;
774 *col = cursorCol;
775 }
776
777 void newtGotorc(int newRow, int newCol) {
778 if (currentWindow) {
779 newRow += currentWindow->top;
780 newCol += currentWindow->left;
781 }
782
783 cursorRow = newRow;
784 cursorCol = newCol;
785 SLsmg_gotorc(cursorRow, cursorCol);
786 }
787
788 void newtDrawBox(int left, int top, int width, int height, int shadow) {
789 if (currentWindow) {
790 top += currentWindow->top;
791 left += currentWindow->left;
792 }
793
794 SLsmg_draw_box(top, left, height, width);
795
796 if (shadow) {
797 SLsmg_set_color(NEWT_COLORSET_SHADOW);
798 SLsmg_fill_region(top + height, left + 1, 1, width - 1, ' ');
799 SLsmg_fill_region(top + 1, left + width, height, 1, ' ');
800 }
801 }
802
803 void newtClearBox(int left, int top, int width, int height) {
804 if (currentWindow) {
805 top += currentWindow->top;
806 left += currentWindow->left;
807 }
808
809 SLsmg_fill_region(top, left, height, width, ' ');
810 }
811
812 static void initKeymap(void) {
813 const struct keymap * curr;
814
815 /* First bind built-in default bindings. They may be shadowed by
816 the termcap entries that get bound later. */
817 for (curr = keymap; curr->code; curr++) {
818 if (curr->str)
819 newtBindKey(curr->str,curr->code);
820 }
821
822 /* Then bind strings from termcap entries */
823 for (curr = keymap; curr->code; curr++) {
824 if (curr->tc) {
825 char *pc = SLtt_tgetstr(curr->tc);
826 if (pc) {
827 newtBindKey(pc,curr->code);
828 }
829 }
830 }
831
832 /* Finally, invent lowest-priority keybindings that correspond to
833 searching for esc-O-foo if esc-[-foo was not found and vice
834 versa. That is needed because of strong confusion among
835 different emulators of VTxxx terminals; some terminfo/termcap
836 descriptions are apparently written by people who were not
837 aware of the differences between "applicataion" and "terminal"
838 keypad modes. Or perhaps they were, but tried to make their
839 description work with a program that puts the keyboard in the
840 wrong emulation mode. In short, one needs this: */
841 kmap_trie_fallback(kmap_trie_escO.contseq, &kmap_trie_escBrack.contseq);
842 kmap_trie_fallback(kmap_trie_escBrack.contseq, &kmap_trie_escO.contseq);
843 }
844
845 /**
846 * @brief Delay for a specified number of usecs
847 * @param int - number of usecs to wait for.
848 */
849 void newtDelay(unsigned int usecs) {
850 fd_set set;
851 struct timeval tv;
852
853 FD_ZERO(&set);
854
855 tv.tv_sec = usecs / 1000000;
856 tv.tv_usec = usecs % 1000000;
857
858 select(0, &set, &set, &set, &tv);
859 }
860
861 struct eventResult newtDefaultEventHandler(newtComponent c,
862 struct event ev) {
863 struct eventResult er;
864
865 er.result = ER_IGNORED;
866 return er;
867 }
868
869 void newtRedrawHelpLine(void) {
870 char * buf;
871
872 SLsmg_set_color(NEWT_COLORSET_HELPLINE);
873
874 if (currentHelpline) {
875 /* buffer size needs to be wide enough to hold all the multibyte
876 currentHelpline + all the single byte ' ' to fill the line */
877 int wlen = wstrlen(*currentHelpline, -1);
878 int len;
879
880 if (wlen > SLtt_Screen_Cols)
881 wlen = SLtt_Screen_Cols;
882 len = strlen(*currentHelpline) + (SLtt_Screen_Cols - wlen);
883 buf = alloca(len + 1);
884 memset(buf, ' ', len);
885 memcpy(buf, *currentHelpline, strlen(*currentHelpline));
886 buf[len] = '\0';
887 } else {
888 buf = alloca(SLtt_Screen_Cols + 1);
889 memset(buf, ' ', SLtt_Screen_Cols);
890 buf[SLtt_Screen_Cols] = '\0';
891 }
892 SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
893 SLsmg_write_string(buf);
894 }
895
896 void newtPushHelpLine(const char * text) {
897 if (!text)
898 text = defaultHelpLine;
899
900 if (currentHelpline)
901 (*(++currentHelpline)) = strdup(text);
902 else {
903 currentHelpline = helplineStack;
904 *currentHelpline = strdup(text);
905 }
906
907 newtRedrawHelpLine();
908 }
909
910 void newtPopHelpLine(void) {
911 if (!currentHelpline) return;
912
913 free(*currentHelpline);
914 if (currentHelpline == helplineStack)
915 currentHelpline = NULL;
916 else
917 currentHelpline--;
918
919 newtRedrawHelpLine();
920 }
921
922 void newtDrawRootText(int col, int row, const char * text) {
923 SLsmg_set_color(NEWT_COLORSET_ROOTTEXT);
924
925 if (col < 0) {
926 col = SLtt_Screen_Cols + col;
927 }
928
929 if (row < 0) {
930 row = SLtt_Screen_Rows + row;
931 }
932
933 SLsmg_gotorc(row, col);
934 SLsmg_write_string((char *)text);
935 }
936
937 int newtSetFlags(int oldFlags, int newFlags, enum newtFlagsSense sense) {
938 switch (sense) {
939 case NEWT_FLAGS_SET:
940 return oldFlags | newFlags;
941
942 case NEWT_FLAGS_RESET:
943 return oldFlags & (~newFlags);
944
945 case NEWT_FLAGS_TOGGLE:
946 return oldFlags ^ newFlags;
947
948 default:
949 return oldFlags;
950 }
951 }
952
953 void newtBell(void)
954 {
955 SLtt_beep();
956 }
957
958 void newtGetScreenSize(int * cols, int * rows) {
959 if (rows) *rows = SLtt_Screen_Rows;
960 if (cols) *cols = SLtt_Screen_Cols;
961 }
962
963 void newtDefaultPlaceHandler(newtComponent c, int newLeft, int newTop) {
964 c->left = newLeft;
965 c->top = newTop;
966 }
967
968 void newtDefaultMappedHandler(newtComponent c, int isMapped) {
969 c->isMapped = isMapped;
970 }
971
972 void newtCursorOff(void) {
973 cursorOn = 0;
974 SLtt_set_cursor_visibility (cursorOn);
975 }
976
977 void newtCursorOn(void) {
978 cursorOn = 1;
979 SLtt_set_cursor_visibility (cursorOn);
980 }
981
982 void newtTrashScreen(void) {
983 if (trashScreen)
984 SLsmg_touch_lines (0, SLtt_Screen_Rows - 1);
985 }
986