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