]> git.ipfire.org Git - thirdparty/newt.git/blobdiff - newt.c
install python modules to purelib and platlib
[thirdparty/newt.git] / newt.c
diff --git a/newt.c b/newt.c
index 4cc22d0507eca8084136aacbe7f3213e4af45f11..7b58f1709bf61cf97c6fd710a3b8e0d11792411f 100644 (file)
--- a/newt.c
+++ b/newt.c
@@ -8,6 +8,7 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <termios.h>
+#include <time.h>
 #include <unistd.h>
 #include <wchar.h>
 
@@ -37,11 +38,12 @@ static char * helplineStack[20];
 static char ** currentHelpline = NULL;
 
 static int cursorRow, cursorCol;
-static int needResize = 0;
 static int cursorOn = 1;
+static int noFlowCtrl = 0;
 static int trashScreen = 0;
+extern int needResize;
 
-static const char * defaultHelpLine =
+static const char * const defaultHelpLine =
 "  <Tab>/<Alt-Tab> between elements   |  <Space> selects   |  <F12> next screen"
 ;
 
@@ -53,47 +55,52 @@ const struct newtColors newtDefaultColorPalette = {
        "red", "lightgray",                     /* title fg, bg */
        "lightgray", "red",                     /* button fg, bg */
        "red", "lightgray",                     /* active button fg, bg */
-       "yellow", "blue",                       /* checkbox fg, bg */
-       "blue", "brown",                        /* active checkbox fg, bg */
-       "yellow", "blue",                       /* entry box fg, bg */
+       "lightgray", "blue",                    /* checkbox fg, bg */
+       "lightgray", "red",                     /* active checkbox fg, bg */
+       "lightgray", "blue",                    /* entry box fg, bg */
        "blue", "lightgray",                    /* label fg, bg */
        "black", "lightgray",                   /* listbox fg, bg */
-       "yellow", "blue",                       /* active listbox fg, bg */
+       "lightgray", "blue",                    /* active listbox fg, bg */
        "black", "lightgray",                   /* textbox fg, bg */
-       "lightgray", "black",                   /* active textbox fg, bg */
+       "lightgray", "red",                     /* active textbox fg, bg */
        "white", "blue",                        /* help line */
-       "yellow", "blue",                       /* root text */
+       "lightgray", "blue",                    /* root text */
        "blue",                                 /* scale full */
        "red",                                  /* scale empty */
        "blue", "lightgray",                    /* disabled entry fg, bg */
-       "white", "blue",                        /* compact button fg, bg */
-       "yellow", "red",                        /* active & sel listbox */
+       "black", "lightgray",                   /* compact button fg, bg */
+       "lightgray", "red",                     /* active & sel listbox */
        "black", "brown"                        /* selected listbox */
 };
 
 static const struct keymap keymap[] = {
-       { "\033OA",             NEWT_KEY_UP,            "kh" },
-       { "\033[A",             NEWT_KEY_UP,            "ku" },
+       { "\033OA",             NEWT_KEY_UP,            "ku" },
+       { "\020",               NEWT_KEY_UP,            NULL }, /* emacs ^P */
        { "\033OB",             NEWT_KEY_DOWN,          "kd" },
-       { "\033[B",             NEWT_KEY_DOWN,          "kd" },
-       { "\033[C",             NEWT_KEY_RIGHT,         "kr" },
+       { "\016",               NEWT_KEY_DOWN,          NULL }, /* emacs ^N */
        { "\033OC",             NEWT_KEY_RIGHT,         "kr" },
-       { "\033[D",             NEWT_KEY_LEFT,          "kl" },
+       { "\006",               NEWT_KEY_RIGHT,         NULL }, /* emacs ^F */
        { "\033OD",             NEWT_KEY_LEFT,          "kl" },
-       { "\033[H",             NEWT_KEY_HOME,          "kh" },
-       { "\033[1~",            NEWT_KEY_HOME,          "kh" },
+       { "\002",               NEWT_KEY_LEFT,          NULL }, /* emacs ^B */
+       { "\033OH",             NEWT_KEY_HOME,          "kh" },
+       { "\033[1~",            NEWT_KEY_HOME,          NULL },
+       { "\001",               NEWT_KEY_HOME,          NULL }, /* emacs ^A */
        { "\033Ow",             NEWT_KEY_END,           "kH" },
-       { "\033[4~",            NEWT_KEY_END,           "kH" },
+        { "\033[4~",           NEWT_KEY_END,           "@7" },
+        { "\005",              NEWT_KEY_END,           NULL }, /* emacs ^E */
 
-       { "\033[3~",            NEWT_KEY_DELETE,        "kl" },
-       { "\033[2~",            NEWT_KEY_INSERT,        NULL },
+       { "\033[3~",            NEWT_KEY_DELETE,        "kD" },
+       { "\004",               NEWT_KEY_DELETE,        NULL }, /* emacs ^D */
+       { "\033[2~",            NEWT_KEY_INSERT,        "kI" },
 
-       { "\033\t",             NEWT_KEY_UNTAB,         NULL },
+       { "\033\t",             NEWT_KEY_UNTAB,         "kB" },
+       { "\033[Z",             NEWT_KEY_UNTAB,         NULL },
 
-       { "\033[5~",            NEWT_KEY_PGUP,          NULL },
-       { "\033[6~",            NEWT_KEY_PGDN,          NULL },
-       { "\033V",              NEWT_KEY_PGUP,          "kH" },
-       { "\033v",              NEWT_KEY_PGUP,          "kH" },
+       { "\033[5~",            NEWT_KEY_PGUP,          "kP" },
+       { "\033[6~",            NEWT_KEY_PGDN,          "kN" },
+       { "\033V",              NEWT_KEY_PGUP,          NULL },
+       { "\033v",              NEWT_KEY_PGUP,          NULL },
+        { "\026",              NEWT_KEY_PGDN,          NULL },
 
        { "\033[[A",            NEWT_KEY_F1,            NULL },
        { "\033[[B",            NEWT_KEY_F2,            NULL },
@@ -106,28 +113,28 @@ static const struct keymap keymap[] = {
        { "\033OR",             NEWT_KEY_F3,            NULL },
        { "\033OS",             NEWT_KEY_F4,            NULL },
 
-       { "\033[11~",           NEWT_KEY_F1,            NULL },
-       { "\033[12~",           NEWT_KEY_F2,            NULL },
-       { "\033[13~",           NEWT_KEY_F3,            NULL },
-       { "\033[14~",           NEWT_KEY_F4,            NULL },
-       { "\033[15~",           NEWT_KEY_F5,            NULL },
-       { "\033[17~",           NEWT_KEY_F6,            NULL },
-       { "\033[18~",           NEWT_KEY_F7,            NULL },
-       { "\033[19~",           NEWT_KEY_F8,            NULL },
-       { "\033[20~",           NEWT_KEY_F9,            NULL },
-       { "\033[21~",           NEWT_KEY_F10,           NULL },
-       { "\033[23~",           NEWT_KEY_F11,           NULL },
-       { "\033[24~",           NEWT_KEY_F12,           NULL },
-       { "\033",               NEWT_KEY_ESCAPE,        NULL },
-
+       { "\033[11~",           NEWT_KEY_F1,            "k1" },
+       { "\033[12~",           NEWT_KEY_F2,            "k2" },
+       { "\033[13~",           NEWT_KEY_F3,            "k3" },
+       { "\033[14~",           NEWT_KEY_F4,            "k4" },
+       { "\033[15~",           NEWT_KEY_F5,            "k5" },
+       { "\033[17~",           NEWT_KEY_F6,            "k6" },
+       { "\033[18~",           NEWT_KEY_F7,            "k7" },
+       { "\033[19~",           NEWT_KEY_F8,            "k8" },
+       { "\033[20~",           NEWT_KEY_F9,            "k9" },
+       { "\033[21~",           NEWT_KEY_F10,           "k;" },
+       { "\033[23~",           NEWT_KEY_F11,           "F1" },
+       { "\033[24~",           NEWT_KEY_F12,           "F2" },
+       { "\033",               NEWT_KEY_ESCAPE,        "@2" },
+        { "\033",              NEWT_KEY_ESCAPE,        "@9" },
+
+        { "\177",              NEWT_KEY_BKSPC,         NULL },
+        { "\010",              NEWT_KEY_BKSPC,         NULL },
+        
        { 0 },  /* LEAVE this one */
 };
-static char keyPrefix = '\033';
-
-static const char ident[] = // ident friendly
-    "$Version: Newt windowing library v" VERSION " $"
-    "$Copyright: (C) 1996-2003 Red Hat, Inc. Written by Erik Troan $"
-    "$License: Lesser GNU Public License. $";
+static void initKeymap();
+static void freeKeymap();
 
 static newtSuspendCallback suspendCallback = NULL;
 static void * suspendCallbackData = NULL;
@@ -145,7 +152,7 @@ static int getkeyInterruptHook(void) {
     return -1;
 }
 
-int wstrlen(const char *str, int len) {
+int _newt_wstrlen(const char *str, int len) {
        mbstate_t ps;
        wchar_t tmp;
        int nchars = 0;
@@ -169,17 +176,155 @@ int wstrlen(const char *str, int len) {
        return nchars;
 }
 
+/** Trim a string to fit 
+ * @param title - string. NULL will be inserted if necessary
+ * @param chrs  - available space. (character cells)
+ */
+void trim_string(char *title, int chrs)
+{
+       char *p = title;
+       int ln;
+       int x = 0,y = 0;
+       wchar_t tmp;
+       mbstate_t ps;
+
+       memset(&ps, 0, sizeof(ps));
+       ln = strlen(title);
+
+       while (*p) {
+               x = mbrtowc(&tmp, p, ln, &ps);
+               if (x < 0) { // error
+                       *p = '\0';
+                       return;
+               }
+               y = wcwidth(tmp);
+               if (y > chrs) {
+                       *p = '\0';
+                       return;
+               } else {
+                       p += x;
+                       ln -= x;
+                       chrs -= y;
+               }
+       }       
+}
+
 static int getkey() {
     int c;
 
     while ((c = SLang_getkey()) == '\xC') { /* if Ctrl-L redraw whole screen */
-        SLsmg_touch_lines (0, SLtt_Screen_Rows - 1);
+        SLsmg_touch_lines(0, SLtt_Screen_Rows);
         SLsmg_refresh();
     }
     return c;
 
 }
 
+static void updateColorset(char *fg, char *bg, char **fg_p, char **bg_p)
+{
+    if (*fg && fg_p)
+       *fg_p = fg;
+    if (*bg && bg_p)
+       *bg_p = bg;
+}
+
+/* parse color specifications (e.g. root=,black:border=red,blue)
+ * and update the palette
+ */
+static void parseColors(char *s, struct newtColors *palette)
+{
+    char *name, *str, *fg, *bg;
+
+    for (str = s; (s = strtok(str, ";:\n\r\t ")); str = NULL) {
+       name = s;
+       if (!(s = strchr(s, '=')) || !*s)
+           continue;
+       *s = '\0';
+       fg = ++s;
+       if (!(s = strchr(s, ',')) || !*s)
+           continue;
+       *s = '\0';
+       bg = ++s;
+
+       if (!strcmp(name, "root"))
+           updateColorset(fg, bg, &palette->rootFg, &palette->rootBg);
+       else if (!strcmp(name, "border"))
+           updateColorset(fg, bg, &palette->borderFg, &palette->borderBg);
+       else if (!strcmp(name, "window"))
+           updateColorset(fg, bg, &palette->windowFg, &palette->windowBg);
+       else if (!strcmp(name, "shadow"))
+           updateColorset(fg, bg, &palette->shadowFg, &palette->shadowBg);
+       else if (!strcmp(name, "title"))
+           updateColorset(fg, bg, &palette->titleFg, &palette->titleBg);
+       else if (!strcmp(name, "button"))
+           updateColorset(fg, bg, &palette->buttonFg, &palette->buttonBg);
+       else if (!strcmp(name, "actbutton"))
+           updateColorset(fg, bg, &palette->actButtonFg, &palette->actButtonBg);
+       else if (!strcmp(name, "checkbox"))
+           updateColorset(fg, bg, &palette->checkboxFg, &palette->checkboxBg);
+       else if (!strcmp(name, "actcheckbox"))
+           updateColorset(fg, bg, &palette->actCheckboxFg, &palette->actCheckboxBg);
+       else if (!strcmp(name, "entry"))
+           updateColorset(fg, bg, &palette->entryFg, &palette->entryBg);
+       else if (!strcmp(name, "label"))
+           updateColorset(fg, bg, &palette->labelFg, &palette->labelBg);
+       else if (!strcmp(name, "listbox"))
+           updateColorset(fg, bg, &palette->listboxFg, &palette->listboxBg);
+       else if (!strcmp(name, "actlistbox"))
+           updateColorset(fg, bg, &palette->actListboxFg, &palette->actListboxBg);
+       else if (!strcmp(name, "textbox"))
+           updateColorset(fg, bg, &palette->textboxFg, &palette->textboxBg);
+       else if (!strcmp(name, "acttextbox"))
+           updateColorset(fg, bg, &palette->actTextboxFg, &palette->actTextboxBg);
+       else if (!strcmp(name, "helpline"))
+           updateColorset(fg, bg, &palette->helpLineFg, &palette->helpLineBg);
+       else if (!strcmp(name, "roottext"))
+           updateColorset(fg, bg, &palette->rootTextFg, &palette->rootTextBg);
+       else if (!strcmp(name, "emptyscale"))
+           updateColorset(fg, bg, NULL, &palette->emptyScale);
+       else if (!strcmp(name, "fullscale"))
+           updateColorset(fg, bg, NULL, &palette->fullScale);
+       else if (!strcmp(name, "disentry"))
+           updateColorset(fg, bg, &palette->disabledEntryFg, &palette->disabledEntryBg);
+       else if (!strcmp(name, "compactbutton"))
+           updateColorset(fg, bg, &palette->compactButtonFg, &palette->compactButtonBg);
+       else if (!strcmp(name, "actsellistbox"))
+           updateColorset(fg, bg, &palette->actSelListboxFg, &palette->actSelListboxBg);
+       else if (!strcmp(name, "sellistbox"))
+           updateColorset(fg, bg, &palette->selListboxFg, &palette->selListboxBg);
+    }
+}
+
+static void initColors(void)
+{
+    char *colors, *colors_file, buf[16384];
+    FILE *f;
+    struct newtColors palette;
+
+    palette = newtDefaultColorPalette;
+
+    colors_file = getenv("NEWT_COLORS_FILE");
+#ifdef NEWT_COLORS_FILE
+    if (colors_file == NULL)
+       colors_file = NEWT_COLORS_FILE;
+#endif
+
+    if ((colors = getenv("NEWT_COLORS"))) {
+       strncpy(buf, colors, sizeof (buf));
+       buf[sizeof (buf) - 1] = '\0';
+       parseColors(buf, &palette);
+    } else if (colors_file && *colors_file && (f = fopen(colors_file, "r"))) {
+       size_t r;
+       if ((r = fread(buf, 1, sizeof (buf) - 1, f)) > 0) {
+           buf[r] = '\0';
+           parseColors(buf, &palette);
+       }
+       fclose(f);
+    }
+
+    newtSetColors(palette);
+}
+
 void newtFlushInput(void) {
     while (SLang_input_pending(0)) {
        getkey();
@@ -207,7 +352,7 @@ void newtSuspend(void) {
 int newtResume(void) {
     SLsmg_resume_smg ();
     SLsmg_refresh();
-    return SLang_init_tty(0, 0, 0);
+    return SLang_init_tty(0, noFlowCtrl, 0);
 }
 
 void newtCls(void) {
@@ -223,10 +368,11 @@ void newtCls(void) {
  * @param redraw - boolean - should we redraw the screen?
  */
 void newtResizeScreen(int redraw) {
+    /* we can't redraw from scratch, just redisplay SLang screen */
     SLtt_get_screen_size();
-    SLsmg_reinit_smg();
+    /* SLsmg_reinit_smg(); */
     if (redraw) {
-        SLsmg_touch_lines (0, SLtt_Screen_Rows - 1);
+        SLsmg_touch_lines(0, SLtt_Screen_Rows);
         newtRefresh();
     }
 }
@@ -237,6 +383,7 @@ void newtResizeScreen(int redraw) {
  */
 int newtInit(void) {
     char * MonoValue, * MonoEnv = "NEWT_MONO";
+    char * NoFlowCtrlValue, * NoFlowCtrlEnv = "NEWT_NOFLOWCTRL";
     const char *lang;
     int ret;
 
@@ -244,33 +391,31 @@ int newtInit(void) {
         if ((lang = getenv("LC_CTYPE")) == NULL)
             if ((lang = getenv("LANG")) == NULL)
                 lang = "";
+    /* slang doesn't support multibyte encodings except UTF-8,
+       avoid character corruption by redrawing the screen */
     if (strstr (lang, ".euc") != NULL)
        trashScreen = 1;
 
-    (void) strlen(ident);
-
+    SLutf8_enable(-1);
     SLtt_get_terminfo();
     SLtt_get_screen_size();
 
     MonoValue = getenv(MonoEnv);
-    if ( MonoValue == NULL ) {
-       SLtt_Use_Ansi_Colors = 1;
-    } else {
+    if ( MonoValue != NULL )
        SLtt_Use_Ansi_Colors = 0;
-    }
+
+    NoFlowCtrlValue = getenv(NoFlowCtrlEnv);
+    if ( NoFlowCtrlValue != NULL )
+        noFlowCtrl = 1;
 
     if ((ret = SLsmg_init_smg()) < 0)
        return ret;
-    if ((ret = SLang_init_tty(0, 0, 0)) < 0)
+    if ((ret = SLang_init_tty(0, noFlowCtrl, 0)) < 0)
        return ret;
 
-    newtSetColors(newtDefaultColorPalette);
+    initColors();
     newtCursorOff();
-    /*initKeymap();*/
-
-    /*memset(&sa, 0, sizeof(sa));
-    sa.sa_handler = handleSigwinch;
-    sigaction(SIGWINCH, &sa, NULL);*/
+    initKeymap();
 
     SLsignal_intr(SIGWINCH, handleSigwinch);
     SLang_getkey_intr_hook = getkeyInterruptHook;
@@ -283,6 +428,22 @@ int newtInit(void) {
  * @returns int , 0. (no errors reported)
  */
 int newtFinished(void) {
+    if (currentWindow) {
+       for (; currentWindow >= windowStack; currentWindow--) {
+           free(currentWindow->buffer);
+           free(currentWindow->title);
+       }
+       currentWindow = NULL;
+    }
+
+    if (currentHelpline) {
+       for (; currentHelpline >= helplineStack; currentHelpline--)
+           free(*currentHelpline);
+       currentHelpline = NULL;
+    }
+
+    freeKeymap();
+
     SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
     newtCursorOn();
     SLsmg_refresh();
@@ -360,93 +521,200 @@ void newtSetColors(struct newtColors colors) {
                   colors.selListboxBg);
 }
 
+void newtSetColor(int colorset, char *fg, char *bg) {
+    if (colorset < NEWT_COLORSET_ROOT ||
+        (colorset > NEWT_COLORSET_SELLISTBOX && colorset < NEWT_COLORSET_CUSTOM(0)) ||
+           !SLtt_Use_Ansi_Colors)
+       return;
+
+    SLtt_set_color(colorset, "", fg, bg);
+}
+
+/* Keymap handling - rewritten by Henning Makholm <henning@makholm.net>,
+ * November 2003.
+ */
+
+struct kmap_trie_entry {
+    char alloced; /* alloced/not first element in array */
+    char c ;   /* character got from terminal */
+    int code;  /* newt key, or 0 if c does not make a complete sequence */
+    struct kmap_trie_entry *contseq; /* sub-trie for character following c */
+    struct kmap_trie_entry *next;    /* try this if char received != c */
+};
+
+static struct kmap_trie_entry *kmap_trie_root = NULL;
+static int keyreader_buf_len = 10 ;
+static unsigned char default_keyreader_buf[10];
+static unsigned char *keyreader_buf = default_keyreader_buf;
+
+#if 0 /* for testing of the keymap manipulation code */
+static void dumpkeys_recursive(struct kmap_trie_entry *curr, int i, FILE *f) {
+    int j, ps ;
+    char seen[256]={0};
+    if( curr && i >= keyreader_buf_len ) {
+        fprintf(f,"ARGH! Too long sequence!\n") ;
+        return ;
+    }
+    for(;curr;curr=curr->next) {
+        keyreader_buf[i] = curr->c ;
+        ps = seen[(unsigned char)curr->c]++ ;
+        if( ps || curr->code || (!curr->code && !curr->contseq) ) {
+            for(j=0;j<=i;j++) {
+                if( keyreader_buf[j] > 32 && keyreader_buf[j]<127 &&
+                    keyreader_buf[j] != '^' && keyreader_buf[j] != '\\' )
+                    fprintf(f,"%c",keyreader_buf[j]);
+                else if( keyreader_buf[j] > 0 && keyreader_buf[j]<=32 )
+                    fprintf(f,"^%c",keyreader_buf[j] + 0x40);
+                else
+                    fprintf(f,"\\%03o",
+                            (unsigned)(unsigned char)keyreader_buf[j]);
+            }
+            if( curr->code )
+                fprintf(f,": 0x%X\n",curr->code);
+            else
+                fprintf(f,": (just keymap)\n");
+        }
+        dumpkeys_recursive(curr->contseq,i+1,f);
+    }
+}
+static void dump_keymap(void) {
+    FILE *f = fopen("newt.keydump","wt");
+    if (f) {
+        dumpkeys_recursive(kmap_trie_root, 0, f);
+        fclose(f);
+    }
+}
+#endif
+
+/* newtBindKey may overwrite a binding that is there already */
+static void newtBindKey(char *keyseq, int meaning) {
+    struct kmap_trie_entry *root = kmap_trie_root ;
+    struct kmap_trie_entry **curptr = &root ;
+
+    /* Try to make sure the common matching buffer is long enough. */
+    if( strlen(keyseq) > keyreader_buf_len ) {
+        int i = strlen(keyseq)+10;
+        unsigned char *newbuf = malloc(i);
+        if (newbuf) {
+            if (keyreader_buf != default_keyreader_buf)
+                free(keyreader_buf);
+            keyreader_buf = newbuf;
+            keyreader_buf_len = i;
+        }
+    }
+    
+    if (*keyseq == 0) return; /* binding the empty sequence is meaningless */
+    
+    while(1) {
+        while ((*curptr) && (*curptr)->c != *keyseq)
+            curptr = &(*curptr)->next;
+        if ((*curptr)==0) {
+            struct kmap_trie_entry* fresh
+                =  calloc(strlen(keyseq),sizeof(struct kmap_trie_entry));
+            if (fresh == 0) return; /* despair! */
+           fresh->alloced = 1;
+            *curptr = fresh;
+            while (keyseq[1]) {
+                fresh->contseq = fresh+1;
+                (fresh++)->c = *(keyseq++);
+            }
+            fresh->c = *keyseq;
+            fresh->code = meaning;
+            return;
+        }
+        if (keyseq[1]==0) {
+            (*curptr)->code = meaning;
+            return;
+        } else {
+            curptr = &(*curptr)->contseq;
+            keyseq++;
+        }
+    }      
+}
+
+/* This function recursively inserts all entries in the "to" trie into
+   corresponding positions in the "from" trie, except positions that
+   are already defined in the "from" trie. */
+static void kmap_trie_fallback(struct kmap_trie_entry *to,
+                               struct kmap_trie_entry **from) {
+    if (*from == NULL)
+        *from = to ;
+    if (*from == to)
+        return ;
+    for (;to!=NULL;to=to->next) {
+        struct kmap_trie_entry **fromcopy = from ;
+        while ((*fromcopy) && (*fromcopy)->c != to->c)
+            fromcopy = &(*fromcopy)->next ;
+        if (*fromcopy) {
+            if ((*fromcopy)->code == 0)
+                (*fromcopy)->code = to->code;
+            kmap_trie_fallback(to->contseq, &(*fromcopy)->contseq);
+        } else {
+            *fromcopy = malloc(sizeof(struct kmap_trie_entry));
+            if (*fromcopy) {
+                **fromcopy = *to ;
+               (*fromcopy)->alloced = 1;
+                (*fromcopy)->next = 0 ;
+            }
+        }
+    }
+}
+
 int newtGetKey(void) {
-    int key;
-    char buf[10], * chptr = buf;
-    const struct keymap * curr;
+    int key, lastcode, errors = 0;
+    unsigned char *chptr = keyreader_buf, *lastmatch;
+    struct kmap_trie_entry *curr = kmap_trie_root;
 
     do {
        key = getkey();
        if (key == SLANG_GETKEY_ERROR) {
-           /* Either garbage was read, or stdin disappeared
-            * (the parent terminal was proably closed)
-            * if the latter, die.
-            */
-           if (feof(stdin))
-                   exit(1);
            if (needResize) {
                 needResize = 0;
                return NEWT_KEY_RESIZE;
             }
 
-           /* ignore other signals */
+           /* Ignore other signals, but assume that stdin disappeared (the
+            * parent terminal was proably closed) if the error persists.
+            */
+           if (errors++ > 10)
+               return NEWT_KEY_ERROR;
+
            continue;
        }
 
        if (key == NEWT_KEY_SUSPEND && suspendCallback)
            suspendCallback(suspendCallbackData);
-    } while (key == NEWT_KEY_SUSPEND);
-
-    switch (key) {
-      case 'v' | 0x80:
-      case 'V' | 0x80:
-       return NEWT_KEY_PGUP;
-
-      case 22:
-       return NEWT_KEY_PGDN;
-
-       return NEWT_KEY_BKSPC;
-      case 0x7f:
-       return NEWT_KEY_BKSPC;
-
-      case 0x08:
-       return NEWT_KEY_BKSPC;
-
-      default:
-       if (key != keyPrefix) return key;
+    } while (key == NEWT_KEY_SUSPEND || key == SLANG_GETKEY_ERROR);
+
+    /* Read more characters, matching against the trie as we go */
+    lastcode = *chptr = key;
+    lastmatch = chptr ;
+    while(1) {
+         while (curr->c != key) {
+             curr = curr->next ;
+             if (curr==NULL) goto break2levels;
+         }
+         if (curr->code) {
+             lastcode = curr->code;
+             lastmatch = chptr;
+         }
+         curr = curr->contseq;
+         if (curr==NULL) break;
+
+         if (SLang_input_pending(5) <= 0)
+             break;
+
+         if (chptr==keyreader_buf+keyreader_buf_len-1) break;
+         *++chptr = key = getkey();
     }
-
-    memset(buf, 0, sizeof(buf));
-
-    *chptr++ = key;
-    while (SLang_input_pending(5)) {
-       key = getkey();
-       if (key == keyPrefix) {
-           /* he hit unknown keys too many times -- start over */
-           memset(buf, 0, sizeof(buf));
-           chptr = buf;
-       }
-
-       *chptr++ = key;
-
-       /* this search should use bsearch(), but when we only look through
-          a list of 20 (or so) keymappings, it's probably faster just to
-          do a inline linear search */
-
-       for (curr = keymap; curr->code; curr++) {
-           if (curr->str) {
-               if (!strcmp(curr->str, buf))
-                   return curr->code;
-           }
-       }
-    }
-
-    for (curr = keymap; curr->code; curr++) {
-       if (curr->str) {
-           if (!strcmp(curr->str, buf))
-               return curr->code;
-       }
-    }
-
-    /* Looks like we were a bit overzealous in reading characters. Return
-       just the first character, and put everything else back in the buffer
-       for later */
-
-    chptr--;
-    while (chptr > buf)
-       SLang_ungetkey(*chptr--);
-
-    return *chptr;
+   break2levels:
+
+      /* The last time the trie matched was at position lastmatch. Back
+       * up if we have read too many characters. */
+      while (chptr > lastmatch)
+          SLang_ungetkey(*chptr--);
+    
+      return lastcode;
 }
 
 /**
@@ -470,14 +738,15 @@ void newtClearKeyBuffer(void) {
 
 /**
  * Open a new window.
- * @param left. unsigned int Size; _not_ including border
- * @param top: unsigned int size, _not_ including border
+ * @param left. int Size; _not_ including border
+ * @param top: int size, _not_ including border
  * @param width unsigned int
  * @param height unsigned int
  * @param title - title string
- * @return zero on success (currently no errors reported)
+ * @return zero on success
  */
-int newtOpenWindow(unsigned left, unsigned top, unsigned width, unsigned height,
+int newtOpenWindow(int left, int top, 
+                   unsigned int width, unsigned int height,
                          const char * title) {
     int j, row, col;
     int n;
@@ -485,6 +754,10 @@ int newtOpenWindow(unsigned left, unsigned top, unsigned width, unsigned height,
 
     newtFlushInput();
 
+    if (currentWindow && currentWindow - windowStack + 1
+           >= sizeof (windowStack) / sizeof (struct Window))
+       return 1;
+
     if (!currentWindow) {
        currentWindow = windowStack;
     } else {
@@ -497,10 +770,10 @@ int newtOpenWindow(unsigned left, unsigned top, unsigned width, unsigned height,
     currentWindow->height = height;
     currentWindow->title = title ? strdup(title) : NULL;
 
-    currentWindow->buffer = malloc(sizeof(SLsmg_Char_Type) * (width + 3) * (height + 3));
+    currentWindow->buffer = malloc(sizeof(SLsmg_Char_Type) * (width + 5) * (height + 3));
 
     row = top - 1;
-    col = left - 1;
+    col = left - 2;
     /* clip to the current screen bounds - msw */
     if (row < 0)
        row = 0;
@@ -514,16 +787,19 @@ int newtOpenWindow(unsigned left, unsigned top, unsigned width, unsigned height,
     for (j = 0; j < height + 3; j++, row++) {
        SLsmg_gotorc(row, col);
        SLsmg_read_raw(currentWindow->buffer + n,
-                      currentWindow->width + 3);
-       n += currentWindow->width + 3;
+                      currentWindow->width + 5);
+       n += currentWindow->width + 5;
     }
 
     newtTrashScreen();
 
     SLsmg_set_color(NEWT_COLORSET_BORDER);
+    SLsmg_set_char_set(1);
     SLsmg_draw_box(top - 1, left - 1, height + 2, width + 2);
+    SLsmg_set_char_set(0);
 
     if (currentWindow->title) {
+       trim_string (currentWindow->title, width-4);
        i = wstrlen(currentWindow->title,-1) + 4;
        i = ((width - i) / 2) + left;
        SLsmg_gotorc(top - 1, i);
@@ -560,34 +836,39 @@ int newtOpenWindow(unsigned left, unsigned top, unsigned width, unsigned height,
  * @param width - width in char cells
  * @param height - no. of char cells.
  * @param title - fixed title
- * @returns 0. No errors reported
+ * @returns zero on success
  */
-int newtCenteredWindow(unsigned width, unsigned height, const char * title) {
-    unsigned top, left;
+int newtCenteredWindow(unsigned int width,unsigned int height, 
+                       const char * title) {
+    int top, left;
 
-    top = (SLtt_Screen_Rows - height) / 2;
+    top = (int)(SLtt_Screen_Rows - height) / 2;
 
     /* I don't know why, but this seems to look better */
     if ((SLtt_Screen_Rows % 2) && (top % 2)) top--;
 
-    left = (SLtt_Screen_Cols - width) / 2;
+    left = (int)(SLtt_Screen_Cols - width) / 2;
 
-    newtOpenWindow(left, top, width, height, title);
-
-    return 0;
+    return newtOpenWindow(left, top, width, height, title);
 }
 
 /**
  * @brief Remove the top window
  */
 void newtPopWindow(void) {
+    newtPopWindowNoRefresh();
+    newtRefresh();
+}
+
+void newtPopWindowNoRefresh(void) {
     int j, row, col;
     int n = 0;
 
-    row = col = 0;
+    if (currentWindow == NULL)
+       return;
 
     row = currentWindow->top - 1;
-    col = currentWindow->left - 1;
+    col = currentWindow->left - 2;
     if (row < 0)
        row = 0;
     if (col < 0)
@@ -595,8 +876,8 @@ void newtPopWindow(void) {
     for (j = 0; j < currentWindow->height + 3; j++, row++) {
        SLsmg_gotorc(row, col);
        SLsmg_write_raw(currentWindow->buffer + n,
-                       currentWindow->width + 3);
-       n += currentWindow->width + 3;
+                       currentWindow->width + 5);
+       n += currentWindow->width + 5;
     }
 
     free(currentWindow->buffer);
@@ -610,8 +891,6 @@ void newtPopWindow(void) {
     SLsmg_set_char_set(0);
 
     newtTrashScreen();
-
-    newtRefresh();
 }
 
 void newtGetWindowPos(int * x, int * y) {
@@ -623,8 +902,13 @@ void newtGetWindowPos(int * x, int * y) {
 }
 
 void newtGetrc(int * row, int * col) {
-   *row = cursorRow;
-   *col = cursorCol;
+    *row = cursorRow;
+    *col = cursorCol;
+
+    if (currentWindow) {
+       *row -= currentWindow->top;
+       *col -= currentWindow->left;
+    }
 }
 
 void newtGotorc(int newRow, int newCol) {
@@ -662,41 +946,88 @@ void newtClearBox(int left, int top, int width, int height) {
     SLsmg_fill_region(top, left, height, width, ' ');
 }
 
-#if 0
-/* This doesn't seem to work quite right. I don't know why not, but when
-   I rsh from an rxvt into a box and run this code, the machine returns
-   console key's (\033[B) rather then xterm ones (\033OB). */
 static void initKeymap(void) {
-    struct keymap * curr;
+    const struct keymap * curr;
+    struct kmap_trie_entry *kmap_trie_escBrack, *kmap_trie_escO;
+
+    /* Here are some entries that will help in handling esc O foo and
+       esc [ foo as variants of each other. */
+    kmap_trie_root = calloc(3, sizeof (struct kmap_trie_entry));
+    kmap_trie_escBrack = kmap_trie_root + 1;
+    kmap_trie_escO = kmap_trie_root + 2;
+
+    kmap_trie_root->alloced = 1;
+    kmap_trie_root->c = '\033';
+    kmap_trie_root->contseq = kmap_trie_escBrack;
+
+    kmap_trie_escBrack->c = '[';
+    kmap_trie_escBrack->next = kmap_trie_escO;
+
+    kmap_trie_escO->c = 'O';
+
+    /* First bind built-in default bindings. They may be shadowed by
+       the termcap entries that get bound later. */
+    for (curr = keymap; curr->code; curr++) {
+        if (curr->str)
+            newtBindKey(curr->str,curr->code);
+    }
 
+    /* Then bind strings from termcap entries */
     for (curr = keymap; curr->code; curr++) {
-       if (!curr->str)
-           curr->str = SLtt_tgetstr(curr->tc);
+       if (curr->tc) {
+            char *pc = SLtt_tgetstr(curr->tc);
+            if (pc) {
+                newtBindKey(pc,curr->code);
+            }
+        }
     }
 
-    /* Newt's keymap handling is a bit broken. It assumes that any extended
-       keystrokes begin with ESC. If you're using a homebrek terminal you
-       will probably need to fix this, or just yell at me and I'll be so
-       ashamed of myself for doing it this way I'll fix it */
+    /* Finally, invent lowest-priority keybindings that correspond to
+       searching for esc-O-foo if esc-[-foo was not found and vice
+       versa.  That is needed because of strong confusion among
+       different emulators of VTxxx terminals; some terminfo/termcap
+       descriptions are apparently written by people who were not
+       aware of the differences between "applicataion" and "terminal"
+       keypad modes. Or perhaps they were, but tried to make their
+       description work with a program that puts the keyboard in the
+       wrong emulation mode. In short, one needs this: */
+    kmap_trie_fallback(kmap_trie_escO->contseq, &kmap_trie_escBrack->contseq);
+    kmap_trie_fallback(kmap_trie_escBrack->contseq, &kmap_trie_escO->contseq);
+}
+
+static void free_keys(struct kmap_trie_entry *kmap, struct kmap_trie_entry *parent, int prepare) {
+    if (kmap == NULL)
+       return;
+
+    free_keys(kmap->contseq, kmap, prepare);
+    free_keys(kmap->next, kmap, prepare);
 
-    keyPrefix = 0x1b;          /* ESC */
+    if (!kmap->alloced && kmap - parent == 1)
+           return;
+
+    /* find first element in array */
+    while (!kmap->alloced)
+       kmap--;
+
+    kmap->alloced += prepare ? 1 : -1;
+    if (!prepare && kmap->alloced == 1)
+       free(kmap);
+}
+
+static void freeKeymap() {
+    free_keys(kmap_trie_root, NULL, 1);
+    free_keys(kmap_trie_root, NULL, 0);
+    kmap_trie_root = NULL;
 }
-#endif
 
 /**
  * @brief Delay for a specified number of usecs
  * @param int - number of usecs to wait for.
  */
-void newtDelay(unsigned usecs) {
-    fd_set set;
-    struct timeval tv;
-
-    FD_ZERO(&set);
+void newtDelay(unsigned int usecs) {
+    struct timespec t = { usecs / 1000000, (usecs % 1000000) * 1000 };
 
-    tv.tv_sec = usecs / 1000000;
-    tv.tv_usec = usecs % 1000000;
-
-    select(0, &set, &set, &set, &tv);
+    nanosleep(&t, NULL);
 }
 
 struct eventResult newtDefaultEventHandler(newtComponent c,
@@ -732,9 +1063,14 @@ void newtRedrawHelpLine(void) {
     }
     SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
     SLsmg_write_string(buf);
+    SLsmg_gotorc(cursorRow, cursorCol);
 }
 
 void newtPushHelpLine(const char * text) {
+    if (currentHelpline && currentHelpline - helplineStack + 1
+           >= sizeof (helplineStack) / sizeof (char *))
+       return;
+
     if (!text)
        text = defaultHelpLine;
 
@@ -822,6 +1158,15 @@ void newtCursorOn(void) {
 
 void newtTrashScreen(void) {
     if (trashScreen)
-       SLsmg_touch_lines (0, SLtt_Screen_Rows - 1);
+       SLsmg_touch_lines(0, SLtt_Screen_Rows);
 }
      
+void newtComponentGetPosition(newtComponent co, int * left, int * top) {
+    if (left) *left = co->left;
+    if (top) *top = co->top;
+}
+
+void newtComponentGetSize(newtComponent co, int * width, int * height) {
+    if (width) *width = co->width;
+    if (height) *height = co->height;
+}