#include <sys/time.h>
#include <sys/types.h>
#include <termios.h>
+#include <time.h>
#include <unistd.h>
#include <wchar.h>
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"
;
{ "\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" },
{ 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;
}
+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();
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) {
*/
int newtInit(void) {
char * MonoValue, * MonoEnv = "NEWT_MONO";
+ char * NoFlowCtrlValue, * NoFlowCtrlEnv = "NEWT_NOFLOWCTRL";
const char *lang;
int ret;
if (strstr (lang, ".euc") != NULL)
trashScreen = 1;
- (void) strlen(ident);
-
SLutf8_enable(-1);
SLtt_get_terminfo();
SLtt_get_screen_size();
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();
currentHelpline = NULL;
}
+ freeKeymap();
+
SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
newtCursorOn();
SLsmg_refresh();
}
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;
*/
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;
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);
}
}
/* 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. */
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;
*fromcopy = malloc(sizeof(struct kmap_trie_entry));
if (*fromcopy) {
**fromcopy = *to ;
+ (*fromcopy)->alloced = 1;
(*fromcopy)->next = 0 ;
}
}
}
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;
if (currentWindow == NULL)
return;
- row = col = 0;
-
row = currentWindow->top - 1;
col = currentWindow->left - 2;
if (row < 0)
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. */
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;
}
/**
* @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,
}
SLsmg_gotorc(SLtt_Screen_Rows - 1, 0);
SLsmg_write_string(buf);
+ SLsmg_gotorc(cursorRow, cursorCol);
}
void newtPushHelpLine(const char * text) {
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;
+}