]> git.ipfire.org Git - thirdparty/newt.git/blob - newt.c
clean up asian patches
[thirdparty/newt.git] / newt.c
1 #include <slang.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <sys/signal.h>
6 #include <sys/time.h>
7 #include <sys/types.h>
8 #include <termios.h>
9 #include <unistd.h>
10 #include <locale.h>
11
12 #include "newt.h"
13 #include "newt_pr.h"
14
15 struct Window {
16 int height, width, top, left;
17 short * buffer;
18 char * title;
19 };
20
21 struct keymap {
22 char * str;
23 int code;
24 char * tc;
25 };
26
27 static struct Window windowStack[20];
28 static struct Window * currentWindow = NULL;
29
30 static char * helplineStack[20];
31 static char ** currentHelpline = NULL;
32
33 static int cursorRow, cursorCol;
34 static int needResize;
35 static int cursorOn = 1;
36
37 static const char * defaultHelpLine =
38 " <Tab>/<Alt-Tab> between elements | <Space> selects | <F12> next screen"
39 ;
40
41 const struct newtColors newtDefaultColorPalette = {
42 "white", "blue", /* root fg, bg */
43 "black", "lightgray", /* border fg, bg */
44 "black", "lightgray", /* window fg, bg */
45 "white", "black", /* shadow fg, bg */
46 "red", "lightgray", /* title fg, bg */
47 "lightgray", "red", /* button fg, bg */
48 "red", "lightgray", /* active button fg, bg */
49 "yellow", "blue", /* checkbox fg, bg */
50 "blue", "brown", /* active checkbox fg, bg */
51 "yellow", "blue", /* entry box fg, bg */
52 "blue", "lightgray", /* label fg, bg */
53 "black", "lightgray", /* listbox fg, bg */
54 "yellow", "blue", /* active listbox fg, bg */
55 "black", "lightgray", /* textbox fg, bg */
56 "lightgray", "black", /* active textbox fg, bg */
57 "white", "blue", /* help line */
58 "yellow", "blue", /* root text */
59 "blue", /* scale full */
60 "red", /* scale empty */
61 "blue", "lightgray", /* disabled entry fg, bg */
62 "white", "blue", /* compact button fg, bg */
63 "yellow", "red", /* active & sel listbox */
64 "black", "brown" /* selected listbox */
65 };
66
67 static const struct keymap keymap[] = {
68 { "\033OA", NEWT_KEY_UP, "kh" },
69 { "\033[A", NEWT_KEY_UP, "ku" },
70 { "\033OB", NEWT_KEY_DOWN, "kd" },
71 { "\033[B", NEWT_KEY_DOWN, "kd" },
72 { "\033[C", NEWT_KEY_RIGHT, "kr" },
73 { "\033OC", NEWT_KEY_RIGHT, "kr" },
74 { "\033[D", NEWT_KEY_LEFT, "kl" },
75 { "\033OD", NEWT_KEY_LEFT, "kl" },
76 { "\033[H", NEWT_KEY_HOME, "kh" },
77 { "\033[1~", NEWT_KEY_HOME, "kh" },
78 { "\033Ow", NEWT_KEY_END, "kH" },
79 { "\033[4~", NEWT_KEY_END, "kH" },
80
81 { "\033[3~", NEWT_KEY_DELETE, "kl" },
82 { "\033[2~", NEWT_KEY_INSERT, NULL },
83
84 { "\033\t", NEWT_KEY_UNTAB, NULL },
85
86 { "\033[5~", NEWT_KEY_PGUP, NULL },
87 { "\033[6~", NEWT_KEY_PGDN, NULL },
88 { "\033V", NEWT_KEY_PGUP, "kH" },
89 { "\033v", NEWT_KEY_PGUP, "kH" },
90
91 { "\033[[A", NEWT_KEY_F1, NULL },
92 { "\033[[B", NEWT_KEY_F2, NULL },
93 { "\033[[C", NEWT_KEY_F3, NULL },
94 { "\033[[D", NEWT_KEY_F4, NULL },
95 { "\033[[E", NEWT_KEY_F5, NULL },
96
97 { "\033OP", NEWT_KEY_F1, NULL },
98 { "\033OQ", NEWT_KEY_F2, NULL },
99 { "\033OR", NEWT_KEY_F3, NULL },
100 { "\033OS", NEWT_KEY_F4, NULL },
101
102 { "\033[11~", NEWT_KEY_F1, NULL },
103 { "\033[12~", NEWT_KEY_F2, NULL },
104 { "\033[13~", NEWT_KEY_F3, NULL },
105 { "\033[14~", NEWT_KEY_F4, NULL },
106 { "\033[15~", NEWT_KEY_F5, NULL },
107 { "\033[17~", NEWT_KEY_F6, NULL },
108 { "\033[18~", NEWT_KEY_F7, NULL },
109 { "\033[19~", NEWT_KEY_F8, NULL },
110 { "\033[20~", NEWT_KEY_F9, NULL },
111 { "\033[21~", NEWT_KEY_F10, NULL },
112 { "\033[23~", NEWT_KEY_F11, NULL },
113 { "\033[24~", NEWT_KEY_F12, NULL },
114
115 { NULL, 0, NULL }, /* LEAVE this one */
116 };
117 static char keyPrefix = '\033';
118
119 static const char * version = "Newt windowing library version " VERSION
120 " - (C) 1996-2000 Red Hat Software. "
121 "Redistributable under the term of the Library "
122 "GNU Public License. "
123 "Written by Erik Troan\n";
124
125 static newtSuspendCallback suspendCallback = NULL;
126 static void * suspendCallbackData = NULL;
127
128 void newtSetSuspendCallback(newtSuspendCallback cb, void * data) {
129 suspendCallback = cb;
130 suspendCallbackData = data;
131 }
132
133 static void handleSigwinch(int signum) {
134 needResize = 1;
135 }
136
137 static int getkeyInterruptHook(void) {
138 return -1;
139 }
140
141 void newtFlushInput(void) {
142 while (SLang_input_pending(0)) {
143 SLang_getkey();
144 }
145 }
146
147 void newtRefresh(void) {
148 SLsmg_refresh();
149 }
150
151 void newtSuspend(void) {
152 SLtt_set_cursor_visibility (1);
153 SLsmg_suspend_smg();
154 SLang_reset_tty();
155 SLtt_set_cursor_visibility (cursorOn);
156 }
157
158 void newtResume(void) {
159 SLsmg_resume_smg ();
160 SLsmg_refresh();
161 SLang_init_tty(0, 0, 0);
162 }
163
164 void newtCls(void) {
165 SLsmg_set_color(NEWT_COLORSET_ROOT);
166 SLsmg_gotorc(0, 0);
167 SLsmg_erase_eos();
168
169 newtRefresh();
170 }
171
172 void newtResizeScreen(int redraw) {
173 newtPushHelpLine("");
174
175 SLtt_get_screen_size();
176 SLang_init_tty(0, 0, 0);
177
178 SLsmg_touch_lines (0, SLtt_Screen_Rows - 1);
179
180 /* I don't know why I need this */
181 SLsmg_refresh();
182
183 newtPopHelpLine();
184
185 if (redraw)
186 SLsmg_refresh();
187 }
188
189 int newtInit(void) {
190 char * MonoValue, * MonoEnv = "NEWT_MONO";
191
192 /* initialize locale */
193 setlocale (LC_ALL, "");
194
195 /* use the version variable just to be sure it gets included */
196 strlen(version);
197
198 SLtt_get_terminfo();
199 SLtt_get_screen_size();
200
201 MonoValue = getenv(MonoEnv);
202 if ( MonoValue == NULL ) {
203 SLtt_Use_Ansi_Colors = 1;
204 } else {
205 SLtt_Use_Ansi_Colors = 0;
206 }
207
208 SLsmg_init_smg();
209 SLang_init_tty(0, 0, 0);
210
211 newtSetColors(newtDefaultColorPalette);
212 newtCursorOff();
213 /*initKeymap();*/
214
215 /*memset(&sa, 0, sizeof(sa));
216 sa.sa_handler = handleSigwinch;
217 sigaction(SIGWINCH, &sa, NULL);*/
218
219 SLsignal_intr(SIGWINCH, handleSigwinch);
220 SLang_getkey_intr_hook = getkeyInterruptHook;
221
222
223
224 return 0;
225 }
226
227 int newtFinished(void) {
228 SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
229 newtCursorOn();
230 SLsmg_refresh();
231 SLsmg_reset_smg();
232 SLang_reset_tty();
233
234 return 0;
235 }
236
237 void newtSetColors(struct newtColors colors) {
238 SLtt_set_color(NEWT_COLORSET_ROOT, "", colors.rootFg, colors.rootBg);
239 SLtt_set_color(NEWT_COLORSET_BORDER, "", colors.borderFg, colors.borderBg);
240 SLtt_set_color(NEWT_COLORSET_WINDOW, "", colors.windowFg, colors.windowBg);
241 SLtt_set_color(NEWT_COLORSET_SHADOW, "", colors.shadowFg, colors.shadowBg);
242 SLtt_set_color(NEWT_COLORSET_TITLE, "", colors.titleFg, colors.titleBg);
243 SLtt_set_color(NEWT_COLORSET_BUTTON, "", colors.buttonFg, colors.buttonBg);
244 SLtt_set_color(NEWT_COLORSET_ACTBUTTON, "", colors.actButtonFg,
245 colors.actButtonBg);
246 SLtt_set_color(NEWT_COLORSET_CHECKBOX, "", colors.checkboxFg,
247 colors.checkboxBg);
248 SLtt_set_color(NEWT_COLORSET_ACTCHECKBOX, "", colors.actCheckboxFg,
249 colors.actCheckboxBg);
250 SLtt_set_color(NEWT_COLORSET_ENTRY, "", colors.entryFg, colors.entryBg);
251 SLtt_set_color(NEWT_COLORSET_LABEL, "", colors.labelFg, colors.labelBg);
252 SLtt_set_color(NEWT_COLORSET_LISTBOX, "", colors.listboxFg,
253 colors.listboxBg);
254 SLtt_set_color(NEWT_COLORSET_ACTLISTBOX, "", colors.actListboxFg,
255 colors.actListboxBg);
256 SLtt_set_color(NEWT_COLORSET_TEXTBOX, "", colors.textboxFg,
257 colors.textboxBg);
258 SLtt_set_color(NEWT_COLORSET_ACTTEXTBOX, "", colors.actTextboxFg,
259 colors.actTextboxBg);
260 SLtt_set_color(NEWT_COLORSET_HELPLINE, "", colors.helpLineFg,
261 colors.helpLineBg);
262 SLtt_set_color(NEWT_COLORSET_ROOTTEXT, "", colors.rootTextFg,
263 colors.rootTextBg);
264
265 SLtt_set_color(NEWT_COLORSET_EMPTYSCALE, "", "black",
266 colors.emptyScale);
267 SLtt_set_color(NEWT_COLORSET_FULLSCALE, "", "black",
268 colors.fullScale);
269 SLtt_set_color(NEWT_COLORSET_DISENTRY, "", colors.disabledEntryFg,
270 colors.disabledEntryBg);
271
272 SLtt_set_color(NEWT_COLORSET_COMPACTBUTTON, "", colors.compactButtonFg,
273 colors.compactButtonBg);
274
275 SLtt_set_color(NEWT_COLORSET_ACTSELLISTBOX, "", colors.actSelListboxFg,
276 colors.actSelListboxBg);
277 SLtt_set_color(NEWT_COLORSET_SELLISTBOX, "", colors.selListboxFg,
278 colors.selListboxBg);
279 }
280
281 int newtGetKey(void) {
282 int key;
283 char buf[10], * chptr = buf;
284 const struct keymap * curr;
285
286 do {
287 key = SLang_getkey();
288 if (key == 0xFFFF) {
289 if (needResize)
290 return NEWT_KEY_RESIZE;
291
292 /* ignore other signals */
293 continue;
294 }
295
296 if (key == NEWT_KEY_SUSPEND && suspendCallback)
297 suspendCallback(suspendCallbackData);
298 } while (key == NEWT_KEY_SUSPEND);
299
300 switch (key) {
301 case 'v' | 0x80:
302 case 'V' | 0x80:
303 return NEWT_KEY_PGUP;
304
305 case 22:
306 return NEWT_KEY_PGDN;
307
308 return NEWT_KEY_BKSPC;
309 case 0x7f:
310 return NEWT_KEY_BKSPC;
311
312 case 0x08:
313 return NEWT_KEY_BKSPC;
314
315 default:
316 if (key != keyPrefix) return key;
317 }
318
319 memset(buf, 0, sizeof(buf));
320
321 *chptr++ = key;
322 while (SLang_input_pending(5)) {
323 key = SLang_getkey();
324 if (key == keyPrefix) {
325 /* he hit unknown keys too many times -- start over */
326 memset(buf, 0, sizeof(buf));
327 chptr = buf;
328 }
329
330 *chptr++ = key;
331
332 /* this search should use bsearch(), but when we only look through
333 a list of 20 (or so) keymappings, it's probably faster just to
334 do a inline linear search */
335
336 for (curr = keymap; curr->code; curr++) {
337 if (curr->str) {
338 if (!strcmp(curr->str, buf))
339 return curr->code;
340 }
341 }
342 }
343
344 for (curr = keymap; curr->code; curr++) {
345 if (curr->str) {
346 if (!strcmp(curr->str, buf))
347 return curr->code;
348 }
349 }
350
351 /* Looks like we were a bit overzealous in reading characters. Return
352 just the first character, and put everything else back in the buffer
353 for later */
354
355 chptr--;
356 while (chptr > buf)
357 SLang_ungetkey(*chptr--);
358
359 return *chptr;
360 }
361
362 void newtWaitForKey(void) {
363 newtRefresh();
364
365 SLang_getkey();
366 newtClearKeyBuffer();
367 }
368
369 void newtClearKeyBuffer(void) {
370 while (SLang_input_pending(1)) {
371 SLang_getkey();
372 }
373 }
374
375 int newtOpenWindow(int left, int top, int width, int height,
376 const char * title) {
377 int j, row, col;
378 int n;
379 int i;
380
381 newtFlushInput();
382
383 if (!currentWindow) {
384 currentWindow = windowStack;
385 } else {
386 currentWindow++;
387 }
388
389 currentWindow->left = left;
390 currentWindow->top = top;
391 currentWindow->width = width;
392 currentWindow->height = height;
393 currentWindow->title = title ? strdup(title) : NULL;
394
395 currentWindow->buffer = malloc(sizeof(short) * (width + 3) * (height + 3));
396
397 row = top - 1;
398 col = left - 1;
399 n = 0;
400 for (j = 0; j < height + 3; j++, row++) {
401 SLsmg_gotorc(row, col);
402 SLsmg_read_raw(currentWindow->buffer + n,
403 currentWindow->width + 3);
404 n += currentWindow->width + 3;
405 }
406
407 SLsmg_set_color(NEWT_COLORSET_BORDER);
408 SLsmg_draw_box(top - 1, left - 1, height + 2, width + 2);
409
410 if (currentWindow->title) {
411 i = strlen(currentWindow->title) + 4;
412 i = ((width - i) / 2) + left;
413 SLsmg_gotorc(top - 1, i);
414 SLsmg_set_char_set(1);
415 SLsmg_write_char(SLSMG_RTEE_CHAR);
416 SLsmg_set_char_set(0);
417 SLsmg_write_char(' ');
418 SLsmg_set_color(NEWT_COLORSET_TITLE);
419 SLsmg_write_string((char *)currentWindow->title);
420 SLsmg_set_color(NEWT_COLORSET_BORDER);
421 SLsmg_write_char(' ');
422 SLsmg_set_char_set(1);
423 SLsmg_write_char(SLSMG_LTEE_CHAR);
424 SLsmg_set_char_set(0);
425 }
426
427 SLsmg_set_color(NEWT_COLORSET_WINDOW);
428 SLsmg_fill_region(top, left, height, width, ' ');
429
430 SLsmg_set_color(NEWT_COLORSET_SHADOW);
431 SLsmg_fill_region(top + height + 1, left, 1, width + 2, ' ');
432 SLsmg_fill_region(top, left + width + 1, height + 1, 1, ' ');
433
434 for (i = top; i < (top + height + 1); i++) {
435 SLsmg_gotorc(i, left + width + 1);
436 SLsmg_write_string(" ");
437 }
438
439 return 0;
440 }
441
442 int newtCenteredWindow(int width, int height, const char * title) {
443 int top, left;
444
445 top = (SLtt_Screen_Rows - height) / 2;
446
447 /* I don't know why, but this seems to look better */
448 if ((SLtt_Screen_Rows % 2) && (top % 2)) top--;
449
450 left = (SLtt_Screen_Cols - width) / 2;
451
452 newtOpenWindow(left, top, width, height, title);
453
454 return 0;
455 }
456
457 void newtPopWindow(void) {
458 int j, row, col;
459 int n = 0;
460
461 row = col = 0;
462
463 row = currentWindow->top - 1;
464 col = currentWindow->left - 1;
465 for (j = 0; j < currentWindow->height + 3; j++, row++) {
466 SLsmg_gotorc(row, col);
467 SLsmg_write_raw(currentWindow->buffer + n,
468 currentWindow->width + 3);
469 n += currentWindow->width + 3;
470 }
471
472 free(currentWindow->buffer);
473 free(currentWindow->title);
474
475 if (currentWindow == windowStack)
476 currentWindow = NULL;
477 else
478 currentWindow--;
479
480 SLsmg_set_char_set(0);
481
482 newtRefresh();
483 }
484
485 void newtGetWindowPos(int * x, int * y) {
486 if (currentWindow) {
487 *x = currentWindow->left;
488 *y = currentWindow->top;
489 } else
490 *x = *y = 0;
491 }
492
493 void newtGetrc(int * row, int * col) {
494 *row = cursorRow;
495 *col = cursorCol;
496 }
497
498 void newtGotorc(int newRow, int newCol) {
499 if (currentWindow) {
500 newRow += currentWindow->top;
501 newCol += currentWindow->left;
502 }
503
504 cursorRow = newRow;
505 cursorCol = newCol;
506 SLsmg_gotorc(cursorRow, cursorCol);
507 }
508
509 void newtDrawBox(int left, int top, int width, int height, int shadow) {
510 if (currentWindow) {
511 top += currentWindow->top;
512 left += currentWindow->left;
513 }
514
515 SLsmg_draw_box(top, left, height, width);
516
517 if (shadow) {
518 SLsmg_set_color(NEWT_COLORSET_SHADOW);
519 SLsmg_fill_region(top + height, left + 1, 1, width - 1, ' ');
520 SLsmg_fill_region(top + 1, left + width, height, 1, ' ');
521 }
522 }
523
524 void newtClearBox(int left, int top, int width, int height) {
525 if (currentWindow) {
526 top += currentWindow->top;
527 left += currentWindow->left;
528 }
529
530 SLsmg_fill_region(top, left, height, width, ' ');
531 }
532
533 #if 0
534 /* This doesn't seem to work quite right. I don't know why not, but when
535 I rsh from an rxvt into a box and run this code, the machine returns
536 console key's (\033[B) rather then xterm ones (\033OB). */
537 static void initKeymap(void) {
538 struct keymap * curr;
539
540 for (curr = keymap; curr->code; curr++) {
541 if (!curr->str)
542 curr->str = SLtt_tgetstr(curr->tc);
543 }
544
545 /* Newt's keymap handling is a bit broken. It assumes that any extended
546 keystrokes begin with ESC. If you're using a homebrek terminal you
547 will probably need to fix this, or just yell at me and I'll be so
548 ashamed of myself for doing it this way I'll fix it */
549
550 keyPrefix = 0x1b; /* ESC */
551 }
552 #endif
553
554 void newtDelay(int usecs) {
555 fd_set set;
556 struct timeval tv;
557
558 FD_ZERO(&set);
559
560 tv.tv_sec = usecs / 1000000;
561 tv.tv_usec = usecs % 1000000;
562
563 select(0, &set, &set, &set, &tv);
564 }
565
566 struct eventResult newtDefaultEventHandler(newtComponent c,
567 struct event ev) {
568 struct eventResult er;
569
570 er.result = ER_IGNORED;
571 return er;
572 }
573
574 void newtRedrawHelpLine(void) {
575 char * buf;
576
577 SLsmg_set_color(NEWT_COLORSET_HELPLINE);
578
579 buf = alloca(SLtt_Screen_Cols + 1);
580 memset(buf, ' ', SLtt_Screen_Cols);
581 buf[SLtt_Screen_Cols] = '\0';
582
583 if (currentHelpline)
584 memcpy(buf, *currentHelpline, strlen(*currentHelpline));
585
586 SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
587 SLsmg_write_string(buf);
588 }
589
590 void newtPushHelpLine(const char * text) {
591 if (!text)
592 text = defaultHelpLine;
593
594 if (currentHelpline)
595 (*(++currentHelpline)) = strdup(text);
596 else {
597 currentHelpline = helplineStack;
598 *currentHelpline = strdup(text);
599 }
600
601 newtRedrawHelpLine();
602 }
603
604 void newtPopHelpLine(void) {
605 if (!currentHelpline) return;
606
607 free(*currentHelpline);
608 if (currentHelpline == helplineStack)
609 currentHelpline = NULL;
610 else
611 currentHelpline--;
612
613 newtRedrawHelpLine();
614 }
615
616 void newtDrawRootText(int col, int row, const char * text) {
617 SLsmg_set_color(NEWT_COLORSET_ROOTTEXT);
618
619 if (col < 0) {
620 col = SLtt_Screen_Cols + col;
621 }
622
623 if (row < 0) {
624 row = SLtt_Screen_Rows + row;
625 }
626
627 SLsmg_gotorc(row, col);
628 SLsmg_write_string((char *)text);
629 }
630
631 int newtSetFlags(int oldFlags, int newFlags, enum newtFlagsSense sense) {
632 switch (sense) {
633 case NEWT_FLAGS_SET:
634 return oldFlags | newFlags;
635
636 case NEWT_FLAGS_RESET:
637 return oldFlags & (~newFlags);
638
639 case NEWT_FLAGS_TOGGLE:
640 return oldFlags ^ newFlags;
641
642 default:
643 return oldFlags;
644 }
645 }
646
647 void newtBell(void)
648 {
649 SLtt_beep();
650 }
651
652 void newtGetScreenSize(int * cols, int * rows) {
653 if (rows) *rows = SLtt_Screen_Rows;
654 if (cols) *cols = SLtt_Screen_Cols;
655 }
656
657 void newtDefaultPlaceHandler(newtComponent c, int newLeft, int newTop) {
658 c->left = newLeft;
659 c->top = newTop;
660 }
661
662 void newtDefaultMappedHandler(newtComponent c, int isMapped) {
663 c->isMapped = isMapped;
664 }
665
666 void newtCursorOff(void) {
667 cursorOn = 0;
668 SLtt_set_cursor_visibility (cursorOn);
669 }
670
671 void newtCursorOn(void) {
672 cursorOn = 1;
673 SLtt_set_cursor_visibility (cursorOn);
674 }