]> 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 d6f8e0a82aaef0561235322fbb0d57d40c6c4011..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>
 
@@ -38,10 +39,11 @@ static char ** currentHelpline = NULL;
 
 static int cursorRow, cursorCol;
 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"
 ;
 
@@ -92,6 +94,7 @@ static const struct keymap keymap[] = {
        { "\033[2~",            NEWT_KEY_INSERT,        "kI" },
 
        { "\033\t",             NEWT_KEY_UNTAB,         "kB" },
+       { "\033[Z",             NEWT_KEY_UNTAB,         NULL },
 
        { "\033[5~",            NEWT_KEY_PGUP,          "kP" },
        { "\033[6~",            NEWT_KEY_PGDN,          "kN" },
@@ -131,11 +134,7 @@ static const struct keymap keymap[] = {
        { 0 },  /* LEAVE this one */
 };
 static void initKeymap();
-
-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 freeKeymap();
 
 static newtSuspendCallback suspendCallback = NULL;
 static void * suspendCallbackData = NULL;
@@ -221,6 +220,111 @@ static int getkey() {
 
 }
 
+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();
@@ -248,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) {
@@ -279,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;
 
@@ -291,8 +396,6 @@ int newtInit(void) {
     if (strstr (lang, ".euc") != NULL)
        trashScreen = 1;
 
-    (void) strlen(ident);
-
     SLutf8_enable(-1);
     SLtt_get_terminfo();
     SLtt_get_screen_size();
@@ -301,12 +404,16 @@ int newtInit(void) {
     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();
 
@@ -335,6 +442,8 @@ int newtFinished(void) {
        currentHelpline = NULL;
     }
 
+    freeKeymap();
+
     SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
     newtCursorOn();
     SLsmg_refresh();
@@ -413,7 +522,8 @@ void newtSetColors(struct newtColors colors) {
 }
 
 void newtSetColor(int colorset, char *fg, char *bg) {
-    if (colorset < NEWT_COLORSET_ROOT || colorset > NEWT_COLORSET_SELLISTBOX ||
+    if (colorset < NEWT_COLORSET_ROOT ||
+        (colorset > NEWT_COLORSET_SELLISTBOX && colorset < NEWT_COLORSET_CUSTOM(0)) ||
            !SLtt_Use_Ansi_Colors)
        return;
 
@@ -425,17 +535,14 @@ void newtSetColor(int colorset, char *fg, char *bg) {
  */
 
 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 */
 };
-/* Here are some static entries that will help in handling esc O foo and
-   esc [ foo as variants of each other: */
-static struct kmap_trie_entry
-    kmap_trie_escO     = { 'O', 0, 0, 0 },
-    kmap_trie_escBrack = { '[', 0, 0, &kmap_trie_escO },
-    kmap_trie_root     = { '\033', 0, &kmap_trie_escBrack, 0 };
+
+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;
@@ -473,7 +580,7 @@ static void dumpkeys_recursive(struct kmap_trie_entry *curr, int i, FILE *f) {
 static void dump_keymap(void) {
     FILE *f = fopen("newt.keydump","wt");
     if (f) {
-        dumpkeys_recursive(&kmap_trie_root,0,f);
+        dumpkeys_recursive(kmap_trie_root, 0, f);
         fclose(f);
     }
 }
@@ -481,7 +588,7 @@ static void dump_keymap(void) {
 
 /* 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 *root = kmap_trie_root ;
     struct kmap_trie_entry **curptr = &root ;
 
     /* Try to make sure the common matching buffer is long enough. */
@@ -505,6 +612,7 @@ static void newtBindKey(char *keyseq, int meaning) {
             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;
@@ -545,6 +653,7 @@ static void kmap_trie_fallback(struct kmap_trie_entry *to,
             *fromcopy = malloc(sizeof(struct kmap_trie_entry));
             if (*fromcopy) {
                 **fromcopy = *to ;
+               (*fromcopy)->alloced = 1;
                 (*fromcopy)->next = 0 ;
             }
         }
@@ -552,32 +661,30 @@ static void kmap_trie_fallback(struct kmap_trie_entry *to,
 }
 
 int newtGetKey(void) {
-    int key;
+    int key, lastcode, errors = 0;
     unsigned char *chptr = keyreader_buf, *lastmatch;
-    int lastcode;
-    struct kmap_trie_entry *curr = &kmap_trie_root;
+    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);
+    } while (key == NEWT_KEY_SUSPEND || key == SLANG_GETKEY_ERROR);
 
     /* Read more characters, matching against the trie as we go */
     lastcode = *chptr = key;
@@ -760,8 +867,6 @@ void newtPopWindowNoRefresh(void) {
     if (currentWindow == NULL)
        return;
 
-    row = col = 0;
-
     row = currentWindow->top - 1;
     col = currentWindow->left - 2;
     if (row < 0)
@@ -843,6 +948,22 @@ void newtClearBox(int left, int top, int width, int height) {
 
 static void initKeymap(void) {
     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. */
@@ -870,8 +991,33 @@ static void initKeymap(void) {
        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);
+    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);
+
+    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;
 }
 
 /**
@@ -879,7 +1025,9 @@ static void initKeymap(void) {
  * @param int - number of usecs to wait for.
  */
 void newtDelay(unsigned int usecs) {
-    usleep(usecs);
+    struct timespec t = { usecs / 1000000, (usecs % 1000000) * 1000 };
+
+    nanosleep(&t, NULL);
 }
 
 struct eventResult newtDefaultEventHandler(newtComponent c,
@@ -915,6 +1063,7 @@ void newtRedrawHelpLine(void) {
     }
     SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
     SLsmg_write_string(buf);
+    SLsmg_gotorc(cursorRow, cursorCol);
 }
 
 void newtPushHelpLine(const char * text) {
@@ -1012,3 +1161,12 @@ void newtTrashScreen(void) {
        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;
+}