From 67be25fbe43274340de89049fec7098cdf998b47 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Thu, 10 Apr 2014 01:09:35 +0300 Subject: Basic working bemenu with curses backend --- lib/draw/curses.c | 258 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 255 insertions(+), 3 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index c873496..48a146a 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -2,8 +2,260 @@ * @file curses.c */ -/* - * code goes here - */ +#include "../internal.h" +#include +#include +#include +#include +#include +#include +#include + +/* ncurses.h likes to define stuff for us. + * This unforunately mangles with our struct. */ +#undef erase +#undef refresh +#undef mvprintw +#undef move +#undef init_pair +#undef attroff +#undef attron +#undef getmaxx +#undef getmaxy +#undef timeout + +static struct curses { + void *handle; + WINDOW *stdscr; + WINDOW* (*initscr)(void); + int (*endwin)(void); + int (*refresh)(void); + int (*erase)(void); + int (*get_wch)(wint_t *wch); + int (*mvprintw)(int x, int y, const char *fmt, ...); + int (*move)(int x, int y); + int (*init_pair)(short color, short f, short b); + int (*attroff)(int attrs); + int (*attron)(int attrs); + int (*start_color)(void); + int (*getmaxx)(WINDOW *win); + int (*getmaxy)(WINDOW *win); + int (*keypad)(WINDOW *win, bool bf); + int *ESCDELAY; +} curses; + +static void _bmDrawCursesDrawLine(int pair, int y, const char *format, ...) +{ + static int ncols = 0; + static char *buffer = NULL; + int new_ncols = curses.getmaxx(curses.stdscr); + + if (new_ncols <= 0) + return; + + if (!buffer || new_ncols > ncols) { + if (buffer) + free(buffer); + + ncols = new_ncols; + + if (!(buffer = calloc(1, ncols + 1))) + return; + } + + va_list args; + va_start(args, format); + int tlen = vsnprintf(NULL, 0, format, args) + 1; + if (tlen > ncols) + tlen = ncols; + va_end(args); + + va_start(args, format); + vsnprintf(buffer, tlen, format, args); + va_end(args); + + memset(buffer + tlen - 1, ' ', ncols - tlen + 1); + + if (pair > 0) + curses.attron(COLOR_PAIR(pair)); + + curses.mvprintw(y, 0, buffer); + + if (pair > 0) + curses.attroff(COLOR_PAIR(pair)); +} + +static void _bmDrawCursesRender(const bmMenu *menu) +{ + if (!curses.stdscr) { + freopen("/dev/tty", "rw", stdin); + setlocale(LC_CTYPE, ""); + if ((curses.stdscr = curses.initscr()) == NULL) + return; + + *curses.ESCDELAY = 25; + curses.keypad(curses.stdscr, true); + + curses.start_color(); + curses.init_pair(1, COLOR_BLACK, COLOR_RED); + curses.init_pair(2, COLOR_RED, COLOR_BLACK); + } + + const unsigned int lines = curses.getmaxy(curses.stdscr); + curses.erase(); + + size_t titleLen = (menu->title ? strlen(menu->title) + 1 : 0); + + _bmDrawCursesDrawLine(0, 0, "%*s%s", titleLen, "", menu->filter); + + if (menu->title) { + curses.attron(COLOR_PAIR(1)); + curses.mvprintw(0, 0, menu->title); + curses.attroff(COLOR_PAIR(1)); + } + + unsigned int i, cl = 1; + unsigned int itemsCount; + bmItem **items = bmMenuGetFilteredItems(menu, &itemsCount); + for (i = (menu->index / (lines - 1)) * (lines - 1); i < itemsCount && cl < lines; ++i) { + int selected = (items[i] == bmMenuGetSelectedItem(menu)); + _bmDrawCursesDrawLine((selected ? 2 : 0), cl++, "%s%s", (selected ? ">> " : " "), items[i]->text); + } + + curses.move(0, titleLen + menu->cursesCursor); + curses.refresh(); +} + +static void _bmDrawCursesEndWin(void) +{ + if (curses.endwin) + curses.endwin(); + + curses.stdscr = NULL; +} + +static bmKey _bmDrawCursesGetKey(unsigned int *unicode) +{ + assert(unicode != NULL); + *unicode = 0; + + if (!curses.stdscr) + return BM_KEY_NONE; + + curses.get_wch(unicode); + switch (*unicode) { + case 16: /* C-p */ + case KEY_UP: return BM_KEY_UP; + + case 14: /* C-n */ + case KEY_DOWN: return BM_KEY_DOWN; + + case 2: /* C-b */ + case KEY_LEFT: return BM_KEY_LEFT; + + case 6: /* C-f */ + case KEY_RIGHT: return BM_KEY_RIGHT; + + case 1: /* C-a */ + case KEY_HOME: return BM_KEY_HOME; + + case 5: /* C-e */ + case KEY_END: return BM_KEY_END; + + case KEY_PPAGE: return BM_KEY_PAGE_UP; + case KEY_NPAGE: return BM_KEY_PAGE_DOWN; + + case 8: /* C-h */ + case KEY_BACKSPACE: return BM_KEY_BACKSPACE; + + case 4: /* C-d */ + case KEY_DC: return BM_KEY_DELETE; + + case 21: return BM_KEY_LINE_DELETE_LEFT; /* C-u */ + case 11: return BM_KEY_LINE_DELETE_RIGHT; /* C-k */ + case 23: return BM_KEY_WORD_DELETE; /* C-w */ + + case 9: return BM_KEY_TAB; /* Tab */ + + case 10: /* Return */ + _bmDrawCursesEndWin(); + return BM_KEY_RETURN; + + case 7: /* C-g */ + case 27: /* Escape */ + _bmDrawCursesEndWin(); + return BM_KEY_ESCAPE; + + default: break; + } + + return BM_KEY_UNICODE; +} + +static void _bmDrawCursesFree(void) +{ + _bmDrawCursesEndWin(); + + if (curses.handle) + dlclose(curses.handle); + + memset(&curses, 0, sizeof(curses)); +} + +int _bmDrawCursesInit(struct _bmRenderApi *api) +{ + memset(&curses, 0, sizeof(curses)); + + /* FIXME: hardcoded and not cross-platform */ + curses.handle = dlopen("/usr/lib/libncursesw.so.5", RTLD_LAZY); + + if (!curses.handle) + return 0; + +#define bmLoadFunction(x) (curses.x = dlsym(curses.handle, #x)) + + if (!bmLoadFunction(initscr)) + goto function_pointer_exception; + if (!bmLoadFunction(endwin)) + goto function_pointer_exception; + if (!bmLoadFunction(refresh)) + goto function_pointer_exception; + if (!bmLoadFunction(get_wch)) + goto function_pointer_exception; + if (!bmLoadFunction(erase)) + goto function_pointer_exception; + if (!bmLoadFunction(mvprintw)) + goto function_pointer_exception; + if (!bmLoadFunction(move)) + goto function_pointer_exception; + if (!bmLoadFunction(init_pair)) + goto function_pointer_exception; + if (!bmLoadFunction(attroff)) + goto function_pointer_exception; + if (!bmLoadFunction(attron)) + goto function_pointer_exception; + if (!bmLoadFunction(start_color)) + goto function_pointer_exception; + if (!bmLoadFunction(getmaxx)) + goto function_pointer_exception; + if (!bmLoadFunction(getmaxy)) + goto function_pointer_exception; + if (!bmLoadFunction(keypad)) + goto function_pointer_exception; + if (!bmLoadFunction(ESCDELAY)) + goto function_pointer_exception; + +#undef bmLoadFunction + + api->getKey = _bmDrawCursesGetKey; + api->render = _bmDrawCursesRender; + api->free = _bmDrawCursesFree; + + return 1; + +function_pointer_exception: + _bmDrawCursesFree(); + return 0; +} /* vim: set ts=8 sw=4 tw=0 :*/ -- cgit v1.2.3-70-g09d2 From cff1f37f970adafce1ac3a982ea1d338e609cfed Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Thu, 10 Apr 2014 01:31:22 +0300 Subject: Do curses refresh before endwin. --- lib/draw/curses.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 48a146a..5c6ff4a 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -128,6 +128,9 @@ static void _bmDrawCursesRender(const bmMenu *menu) static void _bmDrawCursesEndWin(void) { + if (curses.refresh) + curses.refresh(); + if (curses.endwin) curses.endwin(); -- cgit v1.2.3-70-g09d2 From 4d920ad9e4aa344c1600e7419f75f6adb647b1b0 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Thu, 10 Apr 2014 01:41:32 +0300 Subject: Make asserts and ifs more consistent. --- client/client.c | 10 +++++----- lib/draw/curses.c | 2 +- lib/filter.c | 12 ++++++------ lib/item.c | 6 +++--- lib/menu.c | 42 +++++++++++++++++++++--------------------- lib/util.c | 19 +++++++++++-------- test/bmMenuNew.c | 2 +- 7 files changed, 48 insertions(+), 45 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/client/client.c b/client/client.c index df56511..973e57a 100644 --- a/client/client.c +++ b/client/client.c @@ -17,22 +17,22 @@ static ptrdiff_t getLine(char **outLine, size_t *outAllocated, FILE *stream) size_t len = 0, allocated; char *s, *buffer; - assert(outLine != NULL); - assert(outAllocated != NULL); + assert(outLine); + assert(outAllocated); - if (stream == NULL || feof(stream) || ferror(stream)) + if (!stream || feof(stream) || ferror(stream)) return -1; allocated = *outAllocated; buffer = *outLine; - if (buffer == NULL || allocated == 0) { + if (!buffer || allocated == 0) { if (!(buffer = calloc(1, (allocated = 1024) + 1))) return -1; } for (s = buffer;;) { - if (fgets(s, allocated - (s - buffer), stream) == NULL) { + if (!fgets(s, allocated - (s - buffer), stream)) { *outAllocated = allocated; *outLine = buffer; return -1; diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 5c6ff4a..3582be5 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -139,7 +139,7 @@ static void _bmDrawCursesEndWin(void) static bmKey _bmDrawCursesGetKey(unsigned int *unicode) { - assert(unicode != NULL); + assert(unicode); *unicode = 0; if (!curses.stdscr) diff --git a/lib/filter.c b/lib/filter.c index b1cf668..d301415 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -17,9 +17,9 @@ */ bmItem** _bmFilterDmenu(bmMenu *menu, unsigned int *count, unsigned int *selected) { - assert(menu != NULL); - assert(count != NULL); - assert(selected != NULL); + assert(menu); + assert(count); + assert(selected); *count = *selected = 0; /* FIXME: not real dmenu like filtering at all */ @@ -51,9 +51,9 @@ bmItem** _bmFilterDmenu(bmMenu *menu, unsigned int *count, unsigned int *selecte */ bmItem** _bmFilterDmenuCaseInsensitive(bmMenu *menu, unsigned int *count, unsigned int *selected) { - assert(menu != NULL); - assert(count != NULL); - assert(selected != NULL); + assert(menu); + assert(count); + assert(selected); *count = *selected = 0; /* FIXME: stub */ diff --git a/lib/item.c b/lib/item.c index 40ebb52..beca6ed 100644 --- a/lib/item.c +++ b/lib/item.c @@ -31,7 +31,7 @@ bmItem* bmItemNew(const char *text) */ void bmItemFree(bmItem *item) { - assert(item != NULL); + assert(item); if (item->text) free(item->text); @@ -47,7 +47,7 @@ void bmItemFree(bmItem *item) */ int bmItemSetText(bmItem *item, const char *text) { - assert(item != NULL); + assert(item); char *copy = NULL; if (text && !(copy = _bmStrdup(text))) @@ -68,7 +68,7 @@ int bmItemSetText(bmItem *item, const char *text) */ const char* bmItemGetText(const bmItem *item) { - assert(item != NULL); + assert(item); return item->text; } diff --git a/lib/menu.c b/lib/menu.c index 5ea046a..ccdbf0d 100644 --- a/lib/menu.c +++ b/lib/menu.c @@ -15,7 +15,7 @@ static bmItem** (*filterFunc[BM_FILTER_MODE_LAST])(bmMenu *menu, unsigned int *c static void _bmMenuFilter(bmMenu *menu) { - assert(menu != NULL); + assert(menu); if (menu->filteredItems) free(menu->filteredItems); @@ -90,7 +90,7 @@ bmMenu* bmMenuNew(bmDrawMode drawMode) */ void bmMenuFree(bmMenu *menu) { - assert(menu != NULL); + assert(menu); if (menu->renderApi.free) menu->renderApi.free(); @@ -112,7 +112,7 @@ void bmMenuFree(bmMenu *menu) */ void bmMenuFreeItems(bmMenu *menu) { - assert(menu != NULL); + assert(menu); unsigned int i; for (i = 0; i < menu->itemsCount; ++i) @@ -131,7 +131,7 @@ void bmMenuFreeItems(bmMenu *menu) */ void bmMenuSetFilterMode(bmMenu *menu, bmFilterMode mode) { - assert(menu != NULL); + assert(menu); bmFilterMode oldMode = mode; menu->filterMode = (mode >= BM_FILTER_MODE_LAST ? BM_FILTER_MODE_DMENU : mode); @@ -148,7 +148,7 @@ void bmMenuSetFilterMode(bmMenu *menu, bmFilterMode mode) */ bmFilterMode bmMenuGetFilterMode(const bmMenu *menu) { - assert(menu != NULL); + assert(menu); return menu->filterMode; } @@ -160,7 +160,7 @@ bmFilterMode bmMenuGetFilterMode(const bmMenu *menu) */ int bmMenuSetTitle(bmMenu *menu, const char *title) { - assert(menu != NULL); + assert(menu); char *copy = NULL; if (title && !(copy = _bmStrdup(title))) @@ -181,7 +181,7 @@ int bmMenuSetTitle(bmMenu *menu, const char *title) */ const char* bmMenuGetTitle(const bmMenu *menu) { - assert(menu != NULL); + assert(menu); return menu->title; } @@ -195,8 +195,8 @@ const char* bmMenuGetTitle(const bmMenu *menu) */ int bmMenuAddItemAt(bmMenu *menu, bmItem *item, unsigned int index) { - assert(menu != NULL); - assert(item != NULL); + assert(menu); + assert(item); if (menu->itemsCount >= menu->allocatedCount && !_bmMenuGrowItems(menu)) return 0; @@ -232,7 +232,7 @@ int bmMenuAddItem(bmMenu *menu, bmItem *item) */ int bmMenuRemoveItemAt(bmMenu *menu, unsigned int index) { - assert(menu != NULL); + assert(menu); unsigned int i = index; if (i >= menu->itemsCount) @@ -251,8 +251,8 @@ int bmMenuRemoveItemAt(bmMenu *menu, unsigned int index) */ int bmMenuRemoveItem(bmMenu *menu, bmItem *item) { - assert(menu != NULL); - assert(item != NULL); + assert(menu); + assert(item); unsigned int i; for (i = 0; i < menu->itemsCount && menu->items[i] != item; ++i); @@ -267,7 +267,7 @@ int bmMenuRemoveItem(bmMenu *menu, bmItem *item) */ bmItem* bmMenuGetSelectedItem(const bmMenu *menu) { - assert(menu != NULL); + assert(menu); unsigned int count; bmItem **items = bmMenuGetFilteredItems(menu, &count); @@ -287,7 +287,7 @@ bmItem* bmMenuGetSelectedItem(const bmMenu *menu) */ bmItem** bmMenuGetItems(const bmMenu *menu, unsigned int *nmemb) { - assert(menu != NULL); + assert(menu); if (nmemb) *nmemb = menu->itemsCount; @@ -307,7 +307,7 @@ bmItem** bmMenuGetItems(const bmMenu *menu, unsigned int *nmemb) */ bmItem** bmMenuGetFilteredItems(const bmMenu *menu, unsigned int *nmemb) { - assert(menu != NULL); + assert(menu); if (nmemb) *nmemb = (menu->filteredItems ? menu->filteredCount : menu->itemsCount); @@ -326,9 +326,9 @@ bmItem** bmMenuGetFilteredItems(const bmMenu *menu, unsigned int *nmemb) */ int bmMenuSetItems(bmMenu *menu, const bmItem **items, unsigned int nmemb) { - assert(menu != NULL); + assert(menu); - if (items == NULL || nmemb == 0) { + if (!items || nmemb == 0) { bmMenuFreeItems(menu); return 1; } @@ -353,7 +353,7 @@ int bmMenuSetItems(bmMenu *menu, const bmItem **items, unsigned int nmemb) */ void bmMenuRender(const bmMenu *menu) { - assert(menu != NULL); + assert(menu); if (menu->renderApi.render) menu->renderApi.render(menu); @@ -370,8 +370,8 @@ void bmMenuRender(const bmMenu *menu) */ bmKey bmMenuGetKey(bmMenu *menu, unsigned int *unicode) { - assert(menu != NULL); - assert(unicode != NULL); + assert(menu); + assert(unicode); *unicode = 0; bmKey key = BM_KEY_NONE; @@ -390,7 +390,7 @@ bmKey bmMenuGetKey(bmMenu *menu, unsigned int *unicode) */ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode) { - assert(menu != NULL); + assert(menu); char *oldFilter = _bmStrdup(menu->filter); unsigned int itemsCount = (menu->filteredItems ? menu->filteredCount : menu->itemsCount); diff --git a/lib/util.c b/lib/util.c index 8c9bc0f..d948b05 100644 --- a/lib/util.c +++ b/lib/util.c @@ -18,6 +18,8 @@ */ char* _bmStrdup(const char *string) { + assert(string); + size_t len = strlen(string); if (len == 0) return NULL; @@ -41,6 +43,8 @@ char* _bmStrdup(const char *string) */ bmItem** _bmShrinkItemList(bmItem ***list, size_t osize, size_t nsize) { + assert(list); + if (nsize >= osize) return *list; @@ -62,8 +66,7 @@ bmItem** _bmShrinkItemList(bmItem ***list, size_t osize, size_t nsize) */ int _bmUtf8StringScreenWidth(const char *string) { - if (!string) - return 0; + assert(string); int num_char = mbstowcs(NULL, string, 0) + 1; wchar_t *wstring = malloc((num_char + 1) * sizeof (wstring[0])); @@ -87,7 +90,7 @@ int _bmUtf8StringScreenWidth(const char *string) */ size_t _bmUtf8RuneNext(const char *string, size_t start) { - assert(string != NULL); + assert(string); size_t len = strlen(string), i = start; if (len == 0 || len <= i || !*string) @@ -106,7 +109,7 @@ size_t _bmUtf8RuneNext(const char *string, size_t start) */ size_t _bmUtf8RunePrev(const char *string, size_t start) { - assert(string != NULL); + assert(string); size_t len = strlen(string), i = start; if (i == 0 || len < start || !*string) @@ -125,7 +128,7 @@ size_t _bmUtf8RunePrev(const char *string, size_t start) */ size_t _bmUtf8RuneWidth(const char *rune, unsigned int u8len) { - assert(rune != NULL); + assert(rune); char mb[5] = { 0, 0, 0, 0, 0 }; memcpy(mb, rune, (u8len > 4 ? 4 : u8len)); return _bmUtf8StringScreenWidth(mb); @@ -141,7 +144,7 @@ size_t _bmUtf8RuneWidth(const char *rune, unsigned int u8len) */ size_t _bmUtf8RuneRemove(char *string, size_t start, size_t *runeWidth) { - assert(string != NULL); + assert(string); if (runeWidth) *runeWidth = 0; @@ -173,7 +176,7 @@ size_t _bmUtf8RuneRemove(char *string, size_t start, size_t *runeWidth) */ size_t _bmUtf8RuneInsert(char *string, size_t bufSize, size_t start, const char *rune, unsigned int u8len, size_t *runeWidth) { - assert(string != NULL); + assert(string); if (runeWidth) *runeWidth = 0; @@ -206,7 +209,7 @@ size_t _bmUtf8RuneInsert(char *string, size_t bufSize, size_t start, const char */ size_t _bmUnicodeInsert(char *string, size_t bufSize, size_t start, unsigned int unicode, size_t *runeWidth) { - assert(string != NULL); + assert(string); char u8len = ((unicode < 0x80) ? 1 : ((unicode < 0x800) ? 2 : ((unicode < 0x10000) ? 3 : 4))); char mb[5] = { 0, 0, 0, 0 }; diff --git a/test/bmMenuNew.c b/test/bmMenuNew.c index e1b6161..ccb572d 100644 --- a/test/bmMenuNew.c +++ b/test/bmMenuNew.c @@ -11,7 +11,7 @@ int main(int argc, char **argv) bmDrawMode i; for (i = 0; i < BM_DRAW_MODE_LAST; ++i) { bmMenu *menu = bmMenuNew(i); - assert(menu != NULL); + assert(menu); bmMenuRender(menu); bmMenuFree(menu); } -- cgit v1.2.3-70-g09d2 From 956494767c5f2fef7b5672ba60532224ea608d39 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Thu, 10 Apr 2014 10:56:38 +0300 Subject: lolCase variables --- lib/draw/curses.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 3582be5..3afd9bc 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -48,16 +48,16 @@ static void _bmDrawCursesDrawLine(int pair, int y, const char *format, ...) { static int ncols = 0; static char *buffer = NULL; - int new_ncols = curses.getmaxx(curses.stdscr); + int newNcols = curses.getmaxx(curses.stdscr); - if (new_ncols <= 0) + if (newNcols <= 0) return; - if (!buffer || new_ncols > ncols) { + if (!buffer || newNcols > ncols) { if (buffer) free(buffer); - ncols = new_ncols; + ncols = newNcols; if (!(buffer = calloc(1, ncols + 1))) return; -- cgit v1.2.3-70-g09d2 From efc5781aec94563871d56638d3ba92475b43e58b Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Thu, 10 Apr 2014 10:57:37 +0300 Subject: Consistency --- lib/draw/curses.c | 45 +++++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 14 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 3afd9bc..eecfcba 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -148,37 +148,54 @@ static bmKey _bmDrawCursesGetKey(unsigned int *unicode) curses.get_wch(unicode); switch (*unicode) { case 16: /* C-p */ - case KEY_UP: return BM_KEY_UP; + case KEY_UP: + return BM_KEY_UP; case 14: /* C-n */ - case KEY_DOWN: return BM_KEY_DOWN; + case KEY_DOWN: + return BM_KEY_DOWN; case 2: /* C-b */ - case KEY_LEFT: return BM_KEY_LEFT; + case KEY_LEFT: + return BM_KEY_LEFT; case 6: /* C-f */ - case KEY_RIGHT: return BM_KEY_RIGHT; + case KEY_RIGHT: + return BM_KEY_RIGHT; case 1: /* C-a */ - case KEY_HOME: return BM_KEY_HOME; + case KEY_HOME: + return BM_KEY_HOME; case 5: /* C-e */ - case KEY_END: return BM_KEY_END; + case KEY_END: + return BM_KEY_END; - case KEY_PPAGE: return BM_KEY_PAGE_UP; - case KEY_NPAGE: return BM_KEY_PAGE_DOWN; + case KEY_PPAGE: /* PAGE UP */ + return BM_KEY_PAGE_UP; + + case KEY_NPAGE: /* PAGE DOWN */ + return BM_KEY_PAGE_DOWN; case 8: /* C-h */ - case KEY_BACKSPACE: return BM_KEY_BACKSPACE; + case KEY_BACKSPACE: + return BM_KEY_BACKSPACE; case 4: /* C-d */ - case KEY_DC: return BM_KEY_DELETE; + case KEY_DC: + return BM_KEY_DELETE; + + case 21: /* C-u */ + return BM_KEY_LINE_DELETE_LEFT; + + case 11: /* C-k */ + return BM_KEY_LINE_DELETE_RIGHT; - case 21: return BM_KEY_LINE_DELETE_LEFT; /* C-u */ - case 11: return BM_KEY_LINE_DELETE_RIGHT; /* C-k */ - case 23: return BM_KEY_WORD_DELETE; /* C-w */ + case 23: /* C-w */ + return BM_KEY_WORD_DELETE; - case 9: return BM_KEY_TAB; /* Tab */ + case 9: /* Tab */ + return BM_KEY_TAB; case 10: /* Return */ _bmDrawCursesEndWin(); -- cgit v1.2.3-70-g09d2 From ff8ad3a804459ddc4e407b688b093b6f4543cf53 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Thu, 10 Apr 2014 11:08:10 +0300 Subject: Remove @file from non-public library files. --- lib/draw/curses.c | 4 ---- lib/filter.c | 4 ---- lib/internal.h | 4 ---- lib/item.c | 4 ---- lib/menu.c | 4 ---- lib/util.c | 4 ---- 6 files changed, 24 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index eecfcba..a0f5351 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -1,7 +1,3 @@ -/** - * @file curses.c - */ - #include "../internal.h" #include #include diff --git a/lib/filter.c b/lib/filter.c index d301415..92e5683 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -1,7 +1,3 @@ -/** - * @file filter.c - */ - #include "internal.h" #include #include diff --git a/lib/internal.h b/lib/internal.h index 786e082..2220333 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -1,7 +1,3 @@ -/** - * @file internal.h - */ - #include "bemenu.h" #ifndef size_t diff --git a/lib/item.c b/lib/item.c index beca6ed..8320b9b 100644 --- a/lib/item.c +++ b/lib/item.c @@ -1,7 +1,3 @@ -/** - * @file item.c - */ - #include "internal.h" #include #include diff --git a/lib/menu.c b/lib/menu.c index 184c976..4ccb94a 100644 --- a/lib/menu.c +++ b/lib/menu.c @@ -1,7 +1,3 @@ -/** - * @file bemenu.c - */ - #include "internal.h" #include #include diff --git a/lib/util.c b/lib/util.c index d948b05..ae230c8 100644 --- a/lib/util.c +++ b/lib/util.c @@ -1,7 +1,3 @@ -/** - * @file util.c - */ - #include "internal.h" #define _XOPEN_SOURCE 700 #include -- cgit v1.2.3-70-g09d2 From 9a04c4a9a7ff424741f3b6f9b0e34a6f998da7b2 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Thu, 10 Apr 2014 13:23:03 +0300 Subject: Document curses struct --- lib/draw/curses.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index a0f5351..c1bb013 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -20,6 +20,9 @@ #undef getmaxy #undef timeout +/** + * Dynamically loaded curses API. + */ static struct curses { void *handle; WINDOW *stdscr; -- cgit v1.2.3-70-g09d2 From e874818889ed799c8f4e4db2adf77dd19013c878 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Thu, 10 Apr 2014 20:01:34 +0300 Subject: Cleanup curses better. --- lib/draw/curses.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index c1bb013..0e19538 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -1,10 +1,12 @@ #include "../internal.h" +#define _XOPEN_SOURCE 700 #include #include #include #include #include #include +#include #include /* ncurses.h likes to define stuff for us. @@ -24,6 +26,7 @@ * Dynamically loaded curses API. */ static struct curses { + struct sigaction action; void *handle; WINDOW *stdscr; WINDOW* (*initscr)(void); @@ -87,7 +90,7 @@ static void _bmDrawCursesDrawLine(int pair, int y, const char *format, ...) static void _bmDrawCursesRender(const bmMenu *menu) { if (!curses.stdscr) { - freopen("/dev/tty", "rw", stdin); + freopen("/dev/tty", "r", stdin); setlocale(LC_CTYPE, ""); if ((curses.stdscr = curses.initscr()) == NULL) return; @@ -134,6 +137,7 @@ static void _bmDrawCursesEndWin(void) curses.endwin(); curses.stdscr = NULL; + freopen("/dev/tty", "w", stdout); } static bmKey _bmDrawCursesGetKey(unsigned int *unicode) @@ -218,9 +222,17 @@ static void _bmDrawCursesFree(void) if (curses.handle) dlclose(curses.handle); + sigaction(SIGABRT, &curses.action, NULL); + sigaction(SIGSEGV, &curses.action, NULL); memset(&curses, 0, sizeof(curses)); } +static void _bmDrawCursesCrashHandler(int sig) +{ + (void)sig; + _bmDrawCursesFree(); +} + int _bmDrawCursesInit(struct _bmRenderApi *api) { memset(&curses, 0, sizeof(curses)); @@ -270,6 +282,11 @@ int _bmDrawCursesInit(struct _bmRenderApi *api) api->render = _bmDrawCursesRender; api->free = _bmDrawCursesFree; + struct sigaction action; + memset(&action, 0, sizeof(struct sigaction)); + action.sa_handler = _bmDrawCursesCrashHandler; + sigaction(SIGABRT, &action, &curses.action); + sigaction(SIGSEGV, &action, &curses.action); return 1; function_pointer_exception: -- cgit v1.2.3-70-g09d2 From a6d0413b972580f3bbfde8750090270b0d8d463e Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Thu, 10 Apr 2014 20:04:06 +0300 Subject: Implement list structure, and feature for multiple selections. --- client/client.c | 8 +- lib/CMakeLists.txt | 1 + lib/bemenu.h | 56 ++++++++++++-- lib/draw/curses.c | 8 +- lib/filter.c | 28 +++---- lib/internal.h | 64 ++++++++++----- lib/list.c | 135 ++++++++++++++++++++++++++++++++ lib/menu.c | 223 ++++++++++++++++++++++++++++++++--------------------- 8 files changed, 386 insertions(+), 137 deletions(-) create mode 100644 lib/list.c (limited to 'lib/draw/curses.c') diff --git a/client/client.c b/client/client.c index 4bdfdc6..ecaed25 100644 --- a/client/client.c +++ b/client/client.c @@ -101,10 +101,10 @@ int main(int argc, char **argv) } while ((status = bmMenuRunWithKey(menu, key, unicode)) == BM_RUN_RESULT_RUNNING); if (status == BM_RUN_RESULT_SELECTED) { - bmItem *item = bmMenuGetSelectedItem(menu); - - if (item) - printf("%s\n", bmItemGetText(item)); + unsigned int i, count; + bmItem **items = bmMenuGetSelectedItems(menu, &count); + for (i = 0; i < count; ++i) + printf("%s\n", bmItemGetText(items[i])); } bmMenuFree(menu); diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index e669ef5..f53dfc6 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -3,6 +3,7 @@ SET(BEMENU_SOURCE menu.c item.c filter.c + list.c util.c draw/curses.c ) diff --git a/lib/bemenu.h b/lib/bemenu.h index f2f0372..250ad53 100644 --- a/lib/bemenu.h +++ b/lib/bemenu.h @@ -85,6 +85,7 @@ typedef enum bmKey { BM_KEY_TAB, BM_KEY_ESCAPE, BM_KEY_RETURN, + BM_KEY_SHIFT_RETURN, BM_KEY_UNICODE, BM_KEY_LAST } bmKey; @@ -200,24 +201,52 @@ int bmMenuRemoveItemAt(bmMenu *menu, unsigned int index); */ int bmMenuRemoveItem(bmMenu *menu, bmItem *item); + /** - * Get selected item from bmMenu instance. + * Get highlighted item from bmMenu instance. * - * @param menu bmMenu instance from where to get selected item. - * @return Selected bmItem instance, **NULL** if none selected. + * @param menu bmMenu instance from where to get highlighted item. + * @return Selected bmItem instance, **NULL** if none highlighted. */ -bmItem* bmMenuGetSelectedItem(const bmMenu *menu); +bmItem* bmMenuGetHighlightedItem(const bmMenu *menu); /** - * Get items from bmMenu instance. + * Highlight item in menu by index. * - * @warning The pointer returned by this function may be invalid after removing or adding new items. + * @param menu bmMenu instance from where to highlight item. + * @return 1 on successful highlight, 0 on failure. + */ +int bmMenuSetHighlightedIndex(bmMenu *menu, unsigned int index); + +/** + * Highlight item in menu. * - * @param menu bmMenu instance from where to get items. + * @param menu bmMenu instance from where to highlight item. + * @param item bmItem instance to highlight. + * @return 1 on successful highlight, 0 on failure. + */ +int bmMenuSetHighlighted(bmMenu *menu, bmItem *item); + +/** + * Get selected items from bmMenu instance. + * + * @param menu bmMenu instance from where to get selected items. * @param outNmemb Reference to unsigned int where total count of returned items will be stored. * @return Pointer to array of bmItem pointers. */ -bmItem** bmMenuGetItems(const bmMenu *menu, unsigned int *outNmemb); +bmItem** bmMenuGetSelectedItems(const bmMenu *menu, unsigned int *outNmemb); + +/** + * Set selected items to bmMenu instance. + * + * @warning The list won't be copied. + * + * @param menu bmMenu instance where items will be set. + * @param items Array of bmItem pointers to set. + * @param nmemb Total count of items in array. + * @return 1 on successful set, 0 on failure. + */ +int bmMenuSetSelectedItems(bmMenu *menu, bmItem **items, unsigned int nmemb); /** * Get filtered (displayed) items from bmMenu instance. @@ -231,6 +260,17 @@ bmItem** bmMenuGetItems(const bmMenu *menu, unsigned int *outNmemb); */ bmItem** bmMenuGetFilteredItems(const bmMenu *menu, unsigned int *outNmemb); +/** + * Get items from bmMenu instance. + * + * @warning The pointer returned by this function may be invalid after removing or adding new items. + * + * @param menu bmMenu instance from where to get items. + * @param outNmemb Reference to unsigned int where total count of returned items will be stored. + * @return Pointer to array of bmItem pointers. + */ +bmItem** bmMenuGetItems(const bmMenu *menu, unsigned int *outNmemb); + /** * Set items to bmMenu instance. * Will replace all the old items on bmMenu instance. diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 0e19538..336b21d 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -120,8 +120,9 @@ static void _bmDrawCursesRender(const bmMenu *menu) unsigned int itemsCount; bmItem **items = bmMenuGetFilteredItems(menu, &itemsCount); for (i = (menu->index / (lines - 1)) * (lines - 1); i < itemsCount && cl < lines; ++i) { - int selected = (items[i] == bmMenuGetSelectedItem(menu)); - _bmDrawCursesDrawLine((selected ? 2 : 0), cl++, "%s%s", (selected ? ">> " : " "), items[i]->text); + int highlighted = (items[i] == bmMenuGetHighlightedItem(menu)); + int color = (highlighted ? 2 : (_bmMenuItemIsSelected(menu, items[i]) ? 1 : 0)); + _bmDrawCursesDrawLine(color, cl++, "%s%s", (highlighted ? ">> " : " "), items[i]->text); } curses.move(0, titleLen + menu->cursesCursor); @@ -200,6 +201,9 @@ static bmKey _bmDrawCursesGetKey(unsigned int *unicode) case 9: /* Tab */ return BM_KEY_TAB; + case 18: /* C-r */ + return BM_KEY_SHIFT_RETURN; + case 10: /* Return */ _bmDrawCursesEndWin(); return BM_KEY_RETURN; diff --git a/lib/filter.c b/lib/filter.c index 33126c0..4677e73 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -8,33 +8,33 @@ * * @param menu bmMenu instance to filter. * @param outNmemb unsigned int reference to filtered items outNmemb. - * @param outSelected unsigned int reference to new outSelected item index. + * @param outHighlighted unsigned int reference to new outHighlighted item index. * @return Pointer to array of bmItem pointers. */ -bmItem** _bmFilterDmenu(bmMenu *menu, unsigned int *outNmemb, unsigned int *outSelected) +bmItem** _bmFilterDmenu(bmMenu *menu, unsigned int *outNmemb, unsigned int *outHighlighted) { assert(menu); assert(outNmemb); - assert(outSelected); - *outNmemb = *outSelected = 0; + assert(outHighlighted); + *outNmemb = *outHighlighted = 0; /* FIXME: not real dmenu like filtering at all */ - bmItem **filtered = calloc(menu->itemsCount, sizeof(bmItem*)); + bmItem **filtered = calloc(menu->items.count, sizeof(bmItem*)); if (!filtered) return NULL; unsigned int i, f; - for (f = i = 0; i < menu->itemsCount; ++i) { - bmItem *item = menu->items[i]; + for (f = i = 0; i < menu->items.count; ++i) { + bmItem *item = menu->items.list[i]; if (item->text && strstr(item->text, menu->filter)) { - if (f == 0 || item == bmMenuGetSelectedItem(menu)) - *outSelected = f; + if (f == 0 || item == bmMenuGetHighlightedItem(menu)) + *outHighlighted = f; filtered[f++] = item; } } - return _bmShrinkItemList(&filtered, menu->itemsCount, (*outNmemb = f)); + return _bmShrinkItemList(&filtered, menu->items.count, (*outNmemb = f)); } /** @@ -42,15 +42,15 @@ bmItem** _bmFilterDmenu(bmMenu *menu, unsigned int *outNmemb, unsigned int *outS * * @param menu bmMenu instance to filter. * @param outNmemb unsigned int reference to filtered items outNmemb. - * @param outSelected unsigned int reference to new outSelected item index. + * @param outHighlighted unsigned int reference to new outHighlighted item index. * @return Pointer to array of bmItem pointers. */ -bmItem** _bmFilterDmenuCaseInsensitive(bmMenu *menu, unsigned int *outNmemb, unsigned int *outSelected) +bmItem** _bmFilterDmenuCaseInsensitive(bmMenu *menu, unsigned int *outNmemb, unsigned int *outHighlighted) { assert(menu); assert(outNmemb); - assert(outSelected); - *outNmemb = *outSelected = 0; + assert(outHighlighted); + *outNmemb = *outHighlighted = 0; /* FIXME: stub */ diff --git a/lib/internal.h b/lib/internal.h index 66eabbc..d0a9848 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -38,6 +38,23 @@ struct _bmRenderApi { void (*free)(void); }; +struct _bmItemList { + /** + * Items in the list. + */ + struct _bmItem **list; + + /** + * Number of items. + */ + unsigned int count; + + /** + * Number of allocated items. + */ + unsigned int allocated; +}; + /** * Internal bmMenu struct that is not exposed to public. */ @@ -48,14 +65,19 @@ struct _bmMenu { struct _bmRenderApi renderApi; /** - * All items contained in menu instance. + * Items contained in menu instance. */ - struct _bmItem **items; + struct _bmItemList items; /** * Filtered/displayed items contained in menu instance. */ - struct _bmItem **filteredItems; + struct _bmItemList filtered; + + /** + * Selected items. + */ + struct _bmItemList selection; /** * Menu instance title. @@ -79,22 +101,7 @@ struct _bmMenu { unsigned int cursesCursor; /** - * Number of items in menu instance. - */ - unsigned int itemsCount; - - /** - * Number of filtered items in menu instance. - */ - unsigned int filteredCount; - - /** - * Number of allocated items in menu instance. - */ - unsigned int allocatedCount; - - /** - * Current filtered item index in menu instance. + * Current filtered/highlighted item index in menu instance. * This index is valid for the list returned by bmMenuGetFilteredItems. */ unsigned int index; @@ -113,9 +120,24 @@ struct _bmMenu { /* draw/curses.c */ int _bmDrawCursesInit(struct _bmRenderApi *api); +/* menu.c */ +int _bmMenuItemIsSelected(const bmMenu *menu, const bmItem *item); + /* filter.c */ -bmItem** _bmFilterDmenu(bmMenu *menu, unsigned int *outNmemb, unsigned int *outSelected); -bmItem** _bmFilterDmenuCaseInsensitive(bmMenu *menu, unsigned int *outNmemb, unsigned int *outSelected); +bmItem** _bmFilterDmenu(bmMenu *menu, unsigned int *outNmemb, unsigned int *outHighlighted); +bmItem** _bmFilterDmenuCaseInsensitive(bmMenu *menu, unsigned int *outNmemb, unsigned int *outHighlighted); + +/* list.c */ +void _bmItemListFreeList(struct _bmItemList *list); +void _bmItemListFreeItems(struct _bmItemList *list); +bmItem** _bmItemListGetItems(const struct _bmItemList *list, unsigned int *outNmemb); +int _bmItemListSetItemsNoCopy(struct _bmItemList *list, bmItem **items, unsigned int nmemb); +int _bmItemListSetItems(struct _bmItemList *list, const bmItem **items, unsigned int nmemb); +int _bmItemListGrow(struct _bmItemList *list, unsigned int step); +int _bmItemListAddItemAt(struct _bmItemList *list, bmItem *item, unsigned int index); +int _bmItemListAddItem(struct _bmItemList *list, bmItem *item); +int _bmItemListRemoveItemAt(struct _bmItemList *list, unsigned int index); +int _bmItemListRemoveItem(struct _bmItemList *list, const bmItem *item); /* util.c */ char* _bmStrdup(const char *s); diff --git a/lib/list.c b/lib/list.c new file mode 100644 index 0000000..2123818 --- /dev/null +++ b/lib/list.c @@ -0,0 +1,135 @@ +#include "internal.h" +#include +#include +#include + +void _bmItemListFreeList(struct _bmItemList *list) +{ + assert(list); + + if (list->list) + free(list->list); + + list->allocated = list->count = 0; + list->list = NULL; +} + +void _bmItemListFreeItems(struct _bmItemList *list) +{ + assert(list); + + unsigned int i; + for (i = 0; i < list->count; ++i) + bmItemFree(list->list[i]); + + _bmItemListFreeList(list); +} + +bmItem** _bmItemListGetItems(const struct _bmItemList *list, unsigned int *outNmemb) +{ + assert(list); + + if (outNmemb) + *outNmemb = list->count; + + return list->list; +} + +int _bmItemListSetItemsNoCopy(struct _bmItemList *list, bmItem **items, unsigned int nmemb) +{ + assert(list); + + _bmItemListFreeList(list); + + if (!items || nmemb == 0) { + items = NULL; + nmemb = 0; + } + + list->list = items; + list->allocated = list->count = nmemb; + return 1; +} + +int _bmItemListSetItems(struct _bmItemList *list, const bmItem **items, unsigned int nmemb) +{ + assert(list); + + if (!items || nmemb == 0) { + _bmItemListFreeItems(list); + return 1; + } + + bmItem **newItems; + if (!(newItems = calloc(sizeof(bmItem*), nmemb))) + return 0; + + memcpy(newItems, items, sizeof(bmItem*) * nmemb); + return _bmItemListSetItemsNoCopy(list, newItems, nmemb); +} + +int _bmItemListGrow(struct _bmItemList *list, unsigned int step) +{ + assert(list); + + void *tmp; + unsigned int nsize = sizeof(bmItem*) * (list->allocated + step); + + if (!list->list || !(tmp = realloc(list->list, nsize))) { + if (!(tmp = malloc(nsize))) + return 0; + + if (list->list) + memcpy(tmp, list->list, sizeof(bmItem*) * list->allocated); + } + + list->list = tmp; + list->allocated += step; + memset(&list->list[list->count], 0, sizeof(bmItem*) * (list->allocated - list->count)); + return 1; +} + +int _bmItemListAddItemAt(struct _bmItemList *list, bmItem *item, unsigned int index) +{ + assert(list); + assert(item); + + if ((!list->list || list->allocated <= list->count) && !_bmItemListGrow(list, 32)) + return 0; + + if (index + 1 != list->count) { + unsigned int i = index; + memmove(&list->list[i + 1], &list->list[i], sizeof(bmItem*) * (list->count - i)); + } + + list->list[index] = item; + list->count++; + return 1; +} + +int _bmItemListAddItem(struct _bmItemList *list, bmItem *item) +{ + assert(list); + return _bmItemListAddItemAt(list, item, list->count); +} + +int _bmItemListRemoveItemAt(struct _bmItemList *list, unsigned int index) +{ + assert(list); + + unsigned int i = index; + if (!list->list || list->count <= i) + return 0; + + memmove(&list->list[i], &list->list[i], sizeof(bmItem*) * (list->count - i)); + return 1; +} + +int _bmItemListRemoveItem(struct _bmItemList *list, const bmItem *item) +{ + unsigned int i; + for (i = 0; i < list->count && list->list[i] != item; ++i); + return _bmItemListRemoveItemAt(list, i); +} + +/* vim: set ts=8 sw=4 tw=0 :*/ diff --git a/lib/menu.c b/lib/menu.c index 3d41121..6274fe3 100644 --- a/lib/menu.c +++ b/lib/menu.c @@ -7,7 +7,7 @@ /** * Filter function map. */ -static bmItem** (*filterFunc[BM_FILTER_MODE_LAST])(bmMenu *menu, unsigned int *outNmemb, unsigned int *outSelected) = { +static bmItem** (*filterFunc[BM_FILTER_MODE_LAST])(bmMenu *menu, unsigned int *outNmemb, unsigned int *outHighlighted) = { _bmFilterDmenu, /* BM_FILTER_DMENU */ _bmFilterDmenuCaseInsensitive /* BM_FILTER_DMENU_CASE_INSENSITIVE */ }; @@ -16,37 +16,22 @@ static void _bmMenuFilter(bmMenu *menu) { assert(menu); - if (menu->filteredItems) - free(menu->filteredItems); - - menu->filteredCount = 0; - menu->filteredItems = NULL; - unsigned int count, selected; bmItem **filtered = filterFunc[menu->filterMode](menu, &count, &selected); - menu->filteredItems = filtered; - menu->filteredCount = count; + _bmItemListSetItemsNoCopy(&menu->filtered, filtered, count); menu->index = selected; } -static int _bmMenuGrowItems(bmMenu *menu) +int _bmMenuItemIsSelected(const bmMenu *menu, const bmItem *item) { - void *tmp; - static const unsigned int step = 32; - unsigned int nsize = sizeof(bmItem*) * (menu->allocatedCount + step); - - if (!(tmp = realloc(menu->items, nsize))) { - if (!(tmp = malloc(nsize))) - return 0; - - memcpy(tmp, menu->items, sizeof(bmItem*) * menu->allocatedCount); - } + assert(menu); + assert(item); - menu->items = tmp; - menu->allocatedCount += step; - memset(&menu->items[menu->itemsCount], 0, sizeof(bmItem*) * (menu->allocatedCount - menu->itemsCount)); - return 1; + unsigned int i, count; + bmItem **items = bmMenuGetSelectedItems(menu, &count); + for (i = 0; i < count && items[i] != item; ++i); + return (i < count); } /** @@ -97,8 +82,8 @@ void bmMenuFree(bmMenu *menu) if (menu->title) free(menu->title); - if (menu->filteredItems) - free(menu->filteredItems); + if (menu->filtered.list) + free(menu->filtered.list); bmMenuFreeItems(menu); free(menu); @@ -112,14 +97,9 @@ void bmMenuFree(bmMenu *menu) void bmMenuFreeItems(bmMenu *menu) { assert(menu); - - unsigned int i; - for (i = 0; i < menu->itemsCount; ++i) - bmItemFree(menu->items[i]); - - free(menu->items); - menu->allocatedCount = menu->itemsCount = 0; - menu->items = NULL; + _bmItemListFreeList(&menu->selection); + _bmItemListFreeList(&menu->filtered); + _bmItemListFreeItems(&menu->items); } /** @@ -195,19 +175,7 @@ const char* bmMenuGetTitle(const bmMenu *menu) int bmMenuAddItemAt(bmMenu *menu, bmItem *item, unsigned int index) { assert(menu); - assert(item); - - if (menu->itemsCount >= menu->allocatedCount && !_bmMenuGrowItems(menu)) - return 0; - - if (index + 1 != menu->itemsCount) { - unsigned int i = index; - memmove(&menu->items[i + 1], &menu->items[i], sizeof(bmItem*) * (menu->itemsCount - i)); - } - - menu->items[index] = item; - menu->itemsCount++; - return 1; + return _bmItemListAddItemAt(&menu->items, item, index);; } /** @@ -219,7 +187,7 @@ int bmMenuAddItemAt(bmMenu *menu, bmItem *item, unsigned int index) */ int bmMenuAddItem(bmMenu *menu, bmItem *item) { - return bmMenuAddItemAt(menu, item, menu->itemsCount); + return _bmItemListAddItem(&menu->items, item); } /** @@ -235,12 +203,18 @@ int bmMenuRemoveItemAt(bmMenu *menu, unsigned int index) { assert(menu); - unsigned int i = index; - if (i >= menu->itemsCount) + if (!menu->items.list || menu->items.count <= index) return 0; - memmove(&menu->items[i], &menu->items[i], sizeof(bmItem*) * (menu->itemsCount - i)); - return 1; + bmItem *item = menu->items.list[index]; + int ret = _bmItemListRemoveItemAt(&menu->items, index); + + if (ret) { + _bmItemListRemoveItem(&menu->selection, item); + _bmItemListRemoveItem(&menu->filtered, item); + } + + return ret; } /** @@ -255,20 +229,24 @@ int bmMenuRemoveItemAt(bmMenu *menu, unsigned int index) int bmMenuRemoveItem(bmMenu *menu, bmItem *item) { assert(menu); - assert(item); - unsigned int i; - for (i = 0; i < menu->itemsCount && menu->items[i] != item; ++i); - return bmMenuRemoveItemAt(menu, i); + int ret = _bmItemListRemoveItem(&menu->items, item); + + if (ret) { + _bmItemListRemoveItem(&menu->selection, item); + _bmItemListRemoveItem(&menu->filtered, item); + } + + return ret; } /** - * Get selected item from bmMenu instance. + * Get highlighted item from bmMenu instance. * - * @param menu bmMenu instance from where to get selected item. - * @return Selected bmItem instance, **NULL** if none selected. + * @param menu bmMenu instance from where to get highlighted item. + * @return Selected bmItem instance, **NULL** if none highlighted. */ -bmItem* bmMenuGetSelectedItem(const bmMenu *menu) +bmItem* bmMenuGetHighlightedItem(const bmMenu *menu) { assert(menu); @@ -282,22 +260,70 @@ bmItem* bmMenuGetSelectedItem(const bmMenu *menu) } /** - * Get items from bmMenu instance. + * Highlight item in menu by index. * - * @warning The pointer returned by this function may be invalid after removing or adding new items. + * @param menu bmMenu instance from where to highlight item. + * @return 1 on successful highlight, 0 on failure. + */ +int bmMenuSetHighlightedIndex(bmMenu *menu, unsigned int index) +{ + assert(menu); + unsigned int itemsCount = (menu->filtered.list ? menu->filtered.count : menu->items.count); + + if (itemsCount <= index) + return 0; + + return (menu->index = index); +} + +/** + * Highlight item in menu. * - * @param menu bmMenu instance from where to get items. + * @param menu bmMenu instance from where to highlight item. + * @param item bmItem instance to highlight. + * @return 1 on successful highlight, 0 on failure. + */ +int bmMenuSetHighlighted(bmMenu *menu, bmItem *item) +{ + assert(menu); + + unsigned int i, itemsCount; + bmItem **items = bmMenuGetFilteredItems(menu, &itemsCount); + for (i = 0; i < itemsCount && items[i] != item; ++i); + + if (itemsCount <= i) + return 0; + + return (menu->index = i); +} + +/** + * Get selected items from bmMenu instance. + * + * @param menu bmMenu instance from where to get selected items. * @param outNmemb Reference to unsigned int where total count of returned items will be stored. * @return Pointer to array of bmItem pointers. */ -bmItem** bmMenuGetItems(const bmMenu *menu, unsigned int *outNmemb) +bmItem** bmMenuGetSelectedItems(const bmMenu *menu, unsigned int *outNmemb) { assert(menu); + return _bmItemListGetItems(&menu->selection, outNmemb); +} - if (outNmemb) - *outNmemb = menu->itemsCount; - - return menu->items; +/** + * Set selected items to bmMenu instance. + * + * @warning The list won't be copied. + * + * @param menu bmMenu instance where items will be set. + * @param items Array of bmItem pointers to set. + * @param nmemb Total count of items in array. + * @return 1 on successful set, 0 on failure. + */ +int bmMenuSetSelectedItems(bmMenu *menu, bmItem **items, unsigned int nmemb) +{ + assert(menu); + return _bmItemListSetItemsNoCopy(&menu->selection, items, nmemb); } /** @@ -314,10 +340,25 @@ bmItem** bmMenuGetFilteredItems(const bmMenu *menu, unsigned int *outNmemb) { assert(menu); - if (outNmemb) - *outNmemb = (menu->filteredItems ? menu->filteredCount : menu->itemsCount); + if (menu->filtered.list) + return _bmItemListGetItems(&menu->filtered, outNmemb); - return (menu->filteredItems ? menu->filteredItems : menu->items); + return _bmItemListGetItems(&menu->items, outNmemb); +} + +/** + * Get items from bmMenu instance. + * + * @warning The pointer returned by this function may be invalid after removing or adding new items. + * + * @param menu bmMenu instance from where to get items. + * @param outNmemb Reference to unsigned int where total count of returned items will be stored. + * @return Pointer to array of bmItem pointers. + */ +bmItem** bmMenuGetItems(const bmMenu *menu, unsigned int *outNmemb) +{ + assert(menu); + return _bmItemListGetItems(&menu->items, outNmemb); } /** @@ -335,21 +376,14 @@ int bmMenuSetItems(bmMenu *menu, const bmItem **items, unsigned int nmemb) { assert(menu); - if (!items || nmemb == 0) { - bmMenuFreeItems(menu); - return 1; - } + int ret = _bmItemListSetItems(&menu->items, items, nmemb); - bmItem **newItems; - if (!(newItems = calloc(sizeof(bmItem*), nmemb))) - return 0; - - memcpy(newItems, items, sizeof(bmItem*) * nmemb); - bmMenuFreeItems(menu); + if (ret) { + _bmItemListFreeList(&menu->selection); + _bmItemListFreeList(&menu->filtered); + } - menu->items = newItems; - menu->allocatedCount = menu->itemsCount = nmemb; - return 1; + return ret; } /** @@ -400,7 +434,7 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode) { assert(menu); char *oldFilter = _bmStrdup(menu->filter); - unsigned int itemsCount = (menu->filteredItems ? menu->filteredCount : menu->itemsCount); + unsigned int itemsCount = (menu->filtered.list ? menu->filtered.count : menu->items.count); switch (key) { case BM_KEY_LEFT: @@ -502,9 +536,9 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode) case BM_KEY_TAB: { - bmItem *selected = bmMenuGetSelectedItem(menu); - if (selected && bmItemGetText(selected)) { - const char *text = bmItemGetText(selected); + bmItem *highlighted = bmMenuGetHighlightedItem(menu); + if (highlighted && bmItemGetText(highlighted)) { + const char *text = bmItemGetText(highlighted); size_t len = strlen(text); if (len > sizeof(menu->filter) - 1) @@ -518,6 +552,19 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode) } break; + case BM_KEY_SHIFT_RETURN: + case BM_KEY_RETURN: + { + bmItem *highlighted = bmMenuGetHighlightedItem(menu); + if (highlighted && !_bmMenuItemIsSelected(menu, highlighted)) + _bmItemListAddItem(&menu->selection, highlighted); + } + break; + + case BM_KEY_ESCAPE: + _bmItemListFreeList(&menu->selection); + break; + default: break; } -- cgit v1.2.3-70-g09d2 From 590c5d9f857d594af4146fb6e019228b874b368a Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Thu, 10 Apr 2014 23:50:55 +0300 Subject: Undef get_wch --- lib/draw/curses.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 336b21d..a58dd3b 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -12,6 +12,7 @@ /* ncurses.h likes to define stuff for us. * This unforunately mangles with our struct. */ #undef erase +#undef get_wch #undef refresh #undef mvprintw #undef move -- cgit v1.2.3-70-g09d2 From cc93ff905ff9cf8bcb71a088a16529167511b8ad Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Fri, 11 Apr 2014 01:59:50 +0300 Subject: Draw lines properly. --- lib/draw/curses.c | 75 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 19 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index a58dd3b..22abfd9 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -47,37 +47,73 @@ static struct curses { int *ESCDELAY; } curses; -static void _bmDrawCursesDrawLine(int pair, int y, const char *format, ...) +static int _bmDrawCursesResizeBuffer(char **buffer, size_t osize, size_t nsize) { - static int ncols = 0; - static char *buffer = NULL; - int newNcols = curses.getmaxx(curses.stdscr); - - if (newNcols <= 0) - return; + assert(buffer); + assert(nsize); - if (!buffer || newNcols > ncols) { - if (buffer) - free(buffer); + if (nsize == 0 || nsize < osize) + return 0; - ncols = newNcols; + void *tmp; + if (!*buffer || !(tmp = realloc(*buffer, nsize))) { + if (!(tmp = malloc(nsize))) + return 0; - if (!(buffer = calloc(1, ncols + 1))) - return; + if (*buffer) { + memcpy(tmp, *buffer, osize); + free(*buffer); + } } + *buffer = tmp; + memset(*buffer + osize, ' ', (nsize - osize)); + (*buffer)[nsize - 1] = 0; + return 1; +} + +static void _bmDrawCursesDrawLine(int pair, int y, const char *format, ...) +{ + static int blen = 0; + static char *buffer = NULL; + + int ncols = curses.getmaxx(curses.stdscr); + if (ncols <= 0) + return; + va_list args; va_start(args, format); - int tlen = vsnprintf(NULL, 0, format, args) + 1; - if (tlen > ncols) - tlen = ncols; + int nlen = vsnprintf(NULL, 0, format, args) + 1; + if (nlen < ncols) + nlen = ncols; va_end(args); + if ((!buffer || nlen > blen) && !_bmDrawCursesResizeBuffer(&buffer, blen, nlen)) + return; + + blen = nlen; va_start(args, format); - vsnprintf(buffer, tlen, format, args); + int slen = vsnprintf(buffer, blen - 1, format, args); + memset(buffer + slen, ' ', (blen - slen)); + buffer[blen - 1] = 0; va_end(args); - memset(buffer + tlen - 1, ' ', ncols - tlen + 1); + int dw = 0, i = 0; + while (dw < ncols && i < blen) { + if (buffer[i] == '\t') buffer[i] = ' '; + int next = _bmUtf8RuneNext(buffer, i); + dw += _bmUtf8RuneWidth(buffer + i, next); + i += (next ? next : 1); + } + + if (dw < ncols) { + if (!_bmDrawCursesResizeBuffer(&buffer, blen - 1, blen + (ncols - dw) + 1)) + return; + } else if (i < blen) { + int cc = dw - (dw - ncols); + memset(buffer + i - (dw - ncols), ' ', (ncols - cc) + 1); + buffer[i - (dw - ncols) + (ncols - cc) + 1] = 0; + } if (pair > 0) curses.attron(COLOR_PAIR(pair)); @@ -126,7 +162,8 @@ static void _bmDrawCursesRender(const bmMenu *menu) _bmDrawCursesDrawLine(color, cl++, "%s%s", (highlighted ? ">> " : " "), items[i]->text); } - curses.move(0, titleLen + menu->cursesCursor); + unsigned int ncols = curses.getmaxx(curses.stdscr) - titleLen - 1; + curses.move(0, titleLen + (ncols < menu->cursesCursor ? ncols : menu->cursesCursor)); curses.refresh(); } -- cgit v1.2.3-70-g09d2 From 48cf42f0c9f9850659e739602b7e27b614266364 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Fri, 11 Apr 2014 02:02:11 +0300 Subject: Buffer grown too much. --- lib/draw/curses.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 22abfd9..034ed6f 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -107,7 +107,7 @@ static void _bmDrawCursesDrawLine(int pair, int y, const char *format, ...) } if (dw < ncols) { - if (!_bmDrawCursesResizeBuffer(&buffer, blen - 1, blen + (ncols - dw) + 1)) + if (!_bmDrawCursesResizeBuffer(&buffer, blen - 1, blen + (ncols - dw))) return; } else if (i < blen) { int cc = dw - (dw - ncols); -- cgit v1.2.3-70-g09d2 From c82ebb768c39d19df084a61b6d4332f66fd341b9 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Fri, 11 Apr 2014 23:09:01 +0300 Subject: Support mac, duplicate stdin/stdout to make piping possible. --- lib/draw/curses.c | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 034ed6f..83a039b 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -8,6 +8,21 @@ #include #include #include +#include + +#if _WIN32 +static const char *TTY = "CON"; +#else +static const char *TTY = "/dev/tty"; +#endif + +#if __APPLE__ + const char *DL_PATH = "libncurses.5.dylib"; +#elif _WIN32 +# error FIXME: Compile with windows... or use relative path? +#else + const char *DL_PATH = "libncursesw.so.5"; +#endif /* ncurses.h likes to define stuff for us. * This unforunately mangles with our struct. */ @@ -45,6 +60,8 @@ static struct curses { int (*getmaxy)(WINDOW *win); int (*keypad)(WINDOW *win, bool bf); int *ESCDELAY; + int oldStdin; + int oldStdout; } curses; static int _bmDrawCursesResizeBuffer(char **buffer, size_t osize, size_t nsize) @@ -127,8 +144,14 @@ static void _bmDrawCursesDrawLine(int pair, int y, const char *format, ...) static void _bmDrawCursesRender(const bmMenu *menu) { if (!curses.stdscr) { - freopen("/dev/tty", "r", stdin); + curses.oldStdin = dup(STDIN_FILENO); + curses.oldStdout = dup(STDOUT_FILENO); + + freopen(TTY, "w", stdout); + freopen(TTY, "r", stdin); + setlocale(LC_CTYPE, ""); + if ((curses.stdscr = curses.initscr()) == NULL) return; @@ -169,14 +192,22 @@ static void _bmDrawCursesRender(const bmMenu *menu) static void _bmDrawCursesEndWin(void) { + freopen(TTY, "w", stdout); + if (curses.refresh) curses.refresh(); if (curses.endwin) curses.endwin(); + if (curses.stdscr) { + dup2(curses.oldStdin, STDIN_FILENO); + dup2(curses.oldStdout, STDOUT_FILENO); + close(curses.oldStdin); + close(curses.oldStdout); + } + curses.stdscr = NULL; - freopen("/dev/tty", "w", stdout); } static bmKey _bmDrawCursesGetKey(unsigned int *unicode) @@ -278,9 +309,7 @@ static void _bmDrawCursesCrashHandler(int sig) int _bmDrawCursesInit(struct _bmRenderApi *api) { memset(&curses, 0, sizeof(curses)); - - /* FIXME: hardcoded and not cross-platform */ - curses.handle = dlopen("/usr/lib/libncursesw.so.5", RTLD_LAZY); + curses.handle = dlopen(DL_PATH, RTLD_LAZY); if (!curses.handle) return 0; -- cgit v1.2.3-70-g09d2 From 28a44b9e410f16ad6f532187b99299ec8536d449 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Fri, 11 Apr 2014 23:11:54 +0300 Subject: Add cast for conversion when type isn't unsigned. --- lib/draw/curses.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 83a039b..b3bed81 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -218,7 +218,7 @@ static bmKey _bmDrawCursesGetKey(unsigned int *unicode) if (!curses.stdscr) return BM_KEY_NONE; - curses.get_wch(unicode); + curses.get_wch((wint_t*)unicode); switch (*unicode) { case 16: /* C-p */ case KEY_UP: -- cgit v1.2.3-70-g09d2 From 46486abc64fc84a7439edc59e0f5b8b5459b3f99 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sat, 12 Apr 2014 00:00:39 +0300 Subject: Delete is emitted on mac terminal. --- lib/draw/curses.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index b3bed81..3b0e610 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -251,6 +251,7 @@ static bmKey _bmDrawCursesGetKey(unsigned int *unicode) return BM_KEY_PAGE_DOWN; case 8: /* C-h */ + case 127: /* Delete */ case KEY_BACKSPACE: return BM_KEY_BACKSPACE; -- cgit v1.2.3-70-g09d2 From 29c34b0861ff1e5b16831f9093863934cd429e7a Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sat, 12 Apr 2014 00:01:06 +0300 Subject: Consistency. --- lib/draw/curses.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 3b0e610..30bbd8f 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -244,10 +244,10 @@ static bmKey _bmDrawCursesGetKey(unsigned int *unicode) case KEY_END: return BM_KEY_END; - case KEY_PPAGE: /* PAGE UP */ + case KEY_PPAGE: /* Page up */ return BM_KEY_PAGE_UP; - case KEY_NPAGE: /* PAGE DOWN */ + case KEY_NPAGE: /* Page down */ return BM_KEY_PAGE_DOWN; case 8: /* C-h */ -- cgit v1.2.3-70-g09d2 From 058d8a98edb99caa538a922ac13f0f9fab5fb7fb Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sat, 12 Apr 2014 11:15:22 +0300 Subject: Try ncursesw and then ncruses as fallback. --- lib/draw/curses.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 30bbd8f..cb1d204 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -17,11 +17,19 @@ static const char *TTY = "/dev/tty"; #endif #if __APPLE__ - const char *DL_PATH = "libncurses.5.dylib"; + const char *DL_PATH[] = { + "libncursesw.5.dylib", + "libncurses.5.dylib", + NULL + }; #elif _WIN32 # error FIXME: Compile with windows... or use relative path? #else - const char *DL_PATH = "libncursesw.so.5"; + const char *DL_PATH[] = { + "libncursesw.so.5", + "libncurses.so.5", + NULL + }; #endif /* ncurses.h likes to define stuff for us. @@ -310,7 +318,10 @@ static void _bmDrawCursesCrashHandler(int sig) int _bmDrawCursesInit(struct _bmRenderApi *api) { memset(&curses, 0, sizeof(curses)); - curses.handle = dlopen(DL_PATH, RTLD_LAZY); + + unsigned int i; + for (i = 0; DL_PATH[i] && !curses.handle; ++i) + curses.handle = dlopen(DL_PATH[i], RTLD_LAZY); if (!curses.handle) return 0; -- cgit v1.2.3-70-g09d2 From f2608c3c64cb72e1e315142076a7c356facad7de Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sat, 12 Apr 2014 14:15:37 +0300 Subject: Handle empty items. --- client/client.c | 6 ++++-- lib/draw/curses.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/client/client.c b/client/client.c index ecaed25..ff32d1b 100644 --- a/client/client.c +++ b/client/client.c @@ -103,8 +103,10 @@ int main(int argc, char **argv) if (status == BM_RUN_RESULT_SELECTED) { unsigned int i, count; bmItem **items = bmMenuGetSelectedItems(menu, &count); - for (i = 0; i < count; ++i) - printf("%s\n", bmItemGetText(items[i])); + for (i = 0; i < count; ++i) { + const char *text = bmItemGetText(items[i]); + printf("%s\n", (text ? text : "")); + } } bmMenuFree(menu); diff --git a/lib/draw/curses.c b/lib/draw/curses.c index cb1d204..653a07d 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -190,7 +190,7 @@ static void _bmDrawCursesRender(const bmMenu *menu) for (i = (menu->index / (lines - 1)) * (lines - 1); i < itemsCount && cl < lines; ++i) { int highlighted = (items[i] == bmMenuGetHighlightedItem(menu)); int color = (highlighted ? 2 : (_bmMenuItemIsSelected(menu, items[i]) ? 1 : 0)); - _bmDrawCursesDrawLine(color, cl++, "%s%s", (highlighted ? ">> " : " "), items[i]->text); + _bmDrawCursesDrawLine(color, cl++, "%s%s", (highlighted ? ">> " : " "), (items[i]->text ? items[i]->text : "(null)")); } unsigned int ncols = curses.getmaxx(curses.stdscr) - titleLen - 1; -- cgit v1.2.3-70-g09d2 From ad4e0425a6860803e5f31a08c349cd99e02e2847 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sat, 12 Apr 2014 18:42:30 +0300 Subject: Make page scrolling work like it should. (Shfit+pgup/pgdwn for old behaviour) --- lib/bemenu.h | 2 ++ lib/draw/curses.c | 13 +++++++++++++ lib/internal.h | 5 +++++ lib/menu.c | 17 ++++++++++++++++- 4 files changed, 36 insertions(+), 1 deletion(-) (limited to 'lib/draw/curses.c') diff --git a/lib/bemenu.h b/lib/bemenu.h index d348ffa..0b0769d 100644 --- a/lib/bemenu.h +++ b/lib/bemenu.h @@ -77,6 +77,8 @@ typedef enum bmKey { BM_KEY_END, BM_KEY_PAGE_UP, BM_KEY_PAGE_DOWN, + BM_KEY_SHIFT_PAGE_UP, + BM_KEY_SHIFT_PAGE_DOWN, BM_KEY_BACKSPACE, BM_KEY_DELETE, BM_KEY_LINE_DELETE_LEFT, diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 653a07d..b54693f 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -198,6 +198,12 @@ static void _bmDrawCursesRender(const bmMenu *menu) curses.refresh(); } +static unsigned int _bmDrawCursesDisplayedCount(const bmMenu *menu) +{ + (void)menu; + return (curses.stdscr ? curses.getmaxy(curses.stdscr) : 0); +} + static void _bmDrawCursesEndWin(void) { freopen(TTY, "w", stdout); @@ -258,6 +264,12 @@ static bmKey _bmDrawCursesGetKey(unsigned int *unicode) case KEY_NPAGE: /* Page down */ return BM_KEY_PAGE_DOWN; + case 398: /* S-Page up */ + return BM_KEY_SHIFT_PAGE_UP; + + case 396: /* S-Page down */ + return BM_KEY_SHIFT_PAGE_DOWN; + case 8: /* C-h */ case 127: /* Delete */ case KEY_BACKSPACE: @@ -361,6 +373,7 @@ int _bmDrawCursesInit(struct _bmRenderApi *api) #undef bmLoadFunction + api->displayedCount = _bmDrawCursesDisplayedCount; api->getKey = _bmDrawCursesGetKey; api->render = _bmDrawCursesRender; api->free = _bmDrawCursesFree; diff --git a/lib/internal.h b/lib/internal.h index 2acd6f5..b3ca87c 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -27,6 +27,11 @@ struct _bmItem { * Renderers should be able to fill this one as they see fit. */ struct _bmRenderApi { + /** + * Get count of displayed items by the underlying renderer. + */ + unsigned int (*displayedCount)(const bmMenu *menu); + /** * If the underlying renderer is a UI toolkit. (curses, etc...) * There might be possibility to get user input, and this should be thus implemented. diff --git a/lib/menu.c b/lib/menu.c index 0457da8..e819dd5 100644 --- a/lib/menu.c +++ b/lib/menu.c @@ -532,6 +532,13 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode) unsigned int itemsCount; bmMenuGetFilteredItems(menu, &itemsCount); + unsigned int displayed = 0; + if (menu->renderApi.displayedCount) + displayed = menu->renderApi.displayedCount(menu); + + if (!displayed) + displayed = itemsCount; + switch (key) { case BM_KEY_LEFT: { @@ -569,10 +576,18 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode) break; case BM_KEY_PAGE_UP: - menu->index = 0; + menu->index = (menu->index < displayed ? 0 : menu->index - (displayed - 1)); break; case BM_KEY_PAGE_DOWN: + menu->index = (menu->index + displayed >= itemsCount ? itemsCount - 1 : menu->index + (displayed - 1)); + break; + + case BM_KEY_SHIFT_PAGE_UP: + menu->index = 0; + break; + + case BM_KEY_SHIFT_PAGE_DOWN: menu->index = itemsCount - 1; break; -- cgit v1.2.3-70-g09d2 From 3ad042c625d931b7043a857bb49cb0660258f343 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sat, 12 Apr 2014 18:44:03 +0300 Subject: S-Return (C-t, insert in curses) should return input, C-Return is mark. (C-r, C-space in curses) --- lib/bemenu.h | 1 + lib/draw/curses.c | 6 ++++++ lib/menu.c | 4 +++- 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'lib/draw/curses.c') diff --git a/lib/bemenu.h b/lib/bemenu.h index 0b0769d..9ef684f 100644 --- a/lib/bemenu.h +++ b/lib/bemenu.h @@ -88,6 +88,7 @@ typedef enum bmKey { BM_KEY_ESCAPE, BM_KEY_RETURN, BM_KEY_SHIFT_RETURN, + BM_KEY_CONTROL_RETURN, BM_KEY_UNICODE, BM_KEY_LAST } bmKey; diff --git a/lib/draw/curses.c b/lib/draw/curses.c index b54693f..4b467f6 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -291,7 +291,13 @@ static bmKey _bmDrawCursesGetKey(unsigned int *unicode) case 9: /* Tab */ return BM_KEY_TAB; + case 0: /* C-Space */ case 18: /* C-r */ + return BM_KEY_CONTROL_RETURN; + + case 20: /* C-t */ + case 331: /* Insert */ + _bmDrawCursesEndWin(); return BM_KEY_SHIFT_RETURN; case 10: /* Return */ diff --git a/lib/menu.c b/lib/menu.c index e819dd5..a53451d 100644 --- a/lib/menu.c +++ b/lib/menu.c @@ -663,7 +663,7 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode) } break; - case BM_KEY_SHIFT_RETURN: + case BM_KEY_CONTROL_RETURN: case BM_KEY_RETURN: { bmItem *highlighted = bmMenuGetHighlightedItem(menu); @@ -672,6 +672,7 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode) } break; + case BM_KEY_SHIFT_RETURN: case BM_KEY_ESCAPE: _bmItemListFreeList(&menu->selection); break; @@ -682,6 +683,7 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode) bmMenuFilter(menu); switch (key) { + case BM_KEY_SHIFT_RETURN: case BM_KEY_RETURN: return BM_RUN_RESULT_SELECTED; case BM_KEY_ESCAPE: return BM_RUN_RESULT_CANCEL; default: break; -- cgit v1.2.3-70-g09d2 From 042448798d9d2b95ce5ab9ce718b9a16ef0a5fc1 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sat, 12 Apr 2014 18:44:52 +0300 Subject: Add more keybindings to curses interface. --- lib/draw/curses.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 4b467f6..26754be 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -251,10 +251,12 @@ static bmKey _bmDrawCursesGetKey(unsigned int *unicode) return BM_KEY_RIGHT; case 1: /* C-a */ + case 391: /* S-Home */ case KEY_HOME: return BM_KEY_HOME; case 5: /* C-e */ + case 386: /* S-End */ case KEY_END: return BM_KEY_END; @@ -279,6 +281,7 @@ static bmKey _bmDrawCursesGetKey(unsigned int *unicode) case KEY_DC: return BM_KEY_DELETE; + case 383: /* S-Del */ case 21: /* C-u */ return BM_KEY_LINE_DELETE_LEFT; -- cgit v1.2.3-70-g09d2 From 311e4b36768a0d4e113ccf6d2256ca95c6621508 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sat, 12 Apr 2014 19:59:21 +0300 Subject: Use strcspn instead of strtok --- client/client.c | 7 +++++-- lib/draw/curses.c | 10 +++++++--- lib/filter.c | 9 +++++++-- lib/internal.h | 1 + lib/util.c | 13 +++++++++++++ 5 files changed, 33 insertions(+), 7 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/client/client.c b/client/client.c index c031c0b..8e670b1 100644 --- a/client/client.c +++ b/client/client.c @@ -26,13 +26,16 @@ static void readItemsToMenuFromStdin(bmMenu *menu) } buffer[allocated - step + read - 1] = 0; - char *s; - for (s = strtok(buffer, "\n"); s; s = strtok(NULL, "\n")) { + size_t pos; + char *s = buffer; + while ((pos = strcspn(s, "\n")) != 0) { + s[pos] = 0; bmItem *item = bmItemNew(s); if (!item) break; bmMenuAddItem(menu, item); + s += pos + 1; } free(buffer); diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 26754be..3b99cd9 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -1,14 +1,18 @@ #include "../internal.h" -#define _XOPEN_SOURCE 700 + +#define _XOPEN_SOURCE 500 +#include /* sigaction */ +#include /* vsnprintf */ +#undef _XOPEN_SOURCE + #include +#include #include #include #include #include #include -#include #include -#include #if _WIN32 static const char *TTY = "CON"; diff --git a/lib/filter.c b/lib/filter.c index 836ad83..811451b 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -54,12 +54,17 @@ static char* _bmFilterTokenize(bmMenu *menu, char ***outTokv, unsigned int *outT if (!(buffer = _bmStrdup(menu->filter))) goto fail; - char *s, **tmp = NULL; + size_t pos = 0; unsigned int tokc = 0, tokn = 0; - for (s = strtok(buffer, " "); s; tmp[tokc - 1] = s, s = strtok(NULL, " "), tokv = tmp) + char *s = buffer, **tmp = NULL; + while ((pos = _bmStripToken(s, " ")) != 0) { if (++tokc > tokn && !(tmp = realloc(tmp, ++tokn * sizeof(char*)))) goto fail; + tmp[tokc - 1] = s; + s += pos + 1; + } + *outTokv = tmp; *outTokc = tokc; return buffer; diff --git a/lib/internal.h b/lib/internal.h index b3ca87c..1ed13b4 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -163,6 +163,7 @@ int _bmItemListRemoveItem(struct _bmItemList *list, const bmItem *item); /* util.c */ char* _bmStrdup(const char *s); +size_t _bmStripToken(char *string, const char *token); int _bmStrupcmp(const char *hay, const char *needle); int _bmStrnupcmp(const char *hay, const char *needle, size_t len); char* _bmStrupstr(const char *hay, const char *needle); diff --git a/lib/util.c b/lib/util.c index a77e2ff..49f9175 100644 --- a/lib/util.c +++ b/lib/util.c @@ -27,6 +27,19 @@ char* _bmStrdup(const char *string) return (char *)memcpy(copy, string, len); } +/** + * Replaces next token in string with '\0' and returns position for the replaced token. + * + * @param string C "string" where token will be replaced. + * @return Position of the replaced token. + */ +size_t _bmStripToken(char *string, const char *token) +{ + size_t len = strcspn(string, token); + string[len] = 0; + return len; +} + /** * Portable case-insensitive strcmp. * -- cgit v1.2.3-70-g09d2 From bfc53136c8fbea59f116d8d0de92b2711f7804c0 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sat, 12 Apr 2014 20:21:40 +0300 Subject: Add print attribute and fix warning it catched. --- lib/draw/curses.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 3b99cd9..656e47d 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -101,6 +101,9 @@ static int _bmDrawCursesResizeBuffer(char **buffer, size_t osize, size_t nsize) return 1; } +#if __GNUC__ +__attribute__((format(printf, 3, 4))) +#endif static void _bmDrawCursesDrawLine(int pair, int y, const char *format, ...) { static int blen = 0; @@ -178,8 +181,7 @@ static void _bmDrawCursesRender(const bmMenu *menu) const unsigned int lines = curses.getmaxy(curses.stdscr); curses.erase(); - size_t titleLen = (menu->title ? strlen(menu->title) + 1 : 0); - + int titleLen = (menu->title ? strlen(menu->title) + 1 : 0); _bmDrawCursesDrawLine(0, 0, "%*s%s", titleLen, "", menu->filter); if (menu->title) { -- cgit v1.2.3-70-g09d2 From 6692f73c5c3e34baa5b5d8e2fdfa524291979317 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sat, 12 Apr 2014 20:51:32 +0300 Subject: Meh, no (null) it's empty if it's empty. --- lib/draw/curses.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 656e47d..946275e 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -196,7 +196,7 @@ static void _bmDrawCursesRender(const bmMenu *menu) for (i = (menu->index / (lines - 1)) * (lines - 1); i < itemsCount && cl < lines; ++i) { int highlighted = (items[i] == bmMenuGetHighlightedItem(menu)); int color = (highlighted ? 2 : (_bmMenuItemIsSelected(menu, items[i]) ? 1 : 0)); - _bmDrawCursesDrawLine(color, cl++, "%s%s", (highlighted ? ">> " : " "), (items[i]->text ? items[i]->text : "(null)")); + _bmDrawCursesDrawLine(color, cl++, "%s%s", (highlighted ? ">> " : " "), (items[i]->text ? items[i]->text : "")); } unsigned int ncols = curses.getmaxx(curses.stdscr) - titleLen - 1; -- cgit v1.2.3-70-g09d2 From f03e03cdd9c267b9f3c171ba57799d876d80d819 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sat, 12 Apr 2014 20:52:29 +0300 Subject: Make filter to pointer. --- lib/draw/curses.c | 2 +- lib/internal.h | 12 ++++++++---- lib/menu.c | 40 ++++++++++++++++++---------------------- lib/util.c | 41 +++++++++++++++++++++++++++++------------ 4 files changed, 56 insertions(+), 39 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 946275e..3d7871e 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -182,7 +182,7 @@ static void _bmDrawCursesRender(const bmMenu *menu) curses.erase(); int titleLen = (menu->title ? strlen(menu->title) + 1 : 0); - _bmDrawCursesDrawLine(0, 0, "%*s%s", titleLen, "", menu->filter); + _bmDrawCursesDrawLine(0, 0, "%*s%s", titleLen, "", (menu->filter ? menu->filter : "")); if (menu->title) { curses.attron(COLOR_PAIR(1)); diff --git a/lib/internal.h b/lib/internal.h index 6d116a0..4f6afbe 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -103,15 +103,19 @@ struct _bmMenu { /** * Text used to filter matches. - * XXX: Change this to a pointer? */ - char filter[1024]; + char *filter; /** * Used as optimization. */ char *oldFilter; + /** + * Size of filter buffer + */ + size_t filterSize; + /** * Current byte offset on filter text. */ @@ -173,7 +177,7 @@ size_t _bmUtf8RuneNext(const char *string, size_t start); size_t _bmUtf8RunePrev(const char *string, size_t start); size_t _bmUtf8RuneWidth(const char *rune, unsigned int u8len); size_t _bmUtf8RuneRemove(char *string, size_t start, size_t *outRuneWidth); -size_t _bmUtf8RuneInsert(char *string, size_t bufSize, size_t start, const char *rune, unsigned int u8len, size_t *outRuneWidth); -size_t _bmUnicodeInsert(char *string, size_t bufSize, size_t start, unsigned int unicode, size_t *outRuneWidth); +size_t _bmUtf8RuneInsert(char **string, size_t *bufSize, size_t start, const char *rune, unsigned int u8len, size_t *outRuneWidth); +size_t _bmUnicodeInsert(char **string, size_t *bufSize, size_t start, unsigned int unicode, size_t *outRuneWidth); /* vim: set ts=8 sw=4 tw=0 :*/ diff --git a/lib/menu.c b/lib/menu.c index a53451d..f414772 100644 --- a/lib/menu.c +++ b/lib/menu.c @@ -71,6 +71,9 @@ void bmMenuFree(bmMenu *menu) if (menu->title) free(menu->title); + if (menu->filter) + free(menu->filter); + if (menu->oldFilter) free(menu->oldFilter); @@ -126,12 +129,11 @@ void bmMenuSetFilter(bmMenu *menu, const char *filter) { assert(menu); - if (!filter) { - memset(menu->filter, 0, sizeof(menu->filter)); - return; - } + if (menu->filter) + free(menu->filter); - strncpy(menu->filter, filter, sizeof(menu->filter)); + menu->filter = (filter ? _bmStrdup(filter) : NULL); + menu->filterSize = (filter ? strlen(filter) : 0); } /** @@ -426,7 +428,7 @@ bmItem** bmMenuGetFilteredItems(const bmMenu *menu, unsigned int *outNmemb) { assert(menu); - if (strlen(menu->filter)) + if (menu->filter && strlen(menu->filter)) return _bmItemListGetItems(&menu->filtered, outNmemb); return _bmItemListGetItems(&menu->items, outNmemb); @@ -459,7 +461,7 @@ void bmMenuFilter(bmMenu *menu) assert(menu); char addition = 0; - size_t len = strlen(menu->filter); + size_t len = (menu->filter ? strlen(menu->filter) : 0); if (!len || !menu->items.list || menu->items.count <= 0) { _bmItemListFreeList(&menu->filtered); @@ -561,7 +563,7 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode) break; case BM_KEY_END: - menu->cursor = strlen(menu->filter); + menu->cursor = (menu->filter ? strlen(menu->filter) : 0); menu->cursesCursor = _bmUtf8StringScreenWidth(menu->filter); break; @@ -619,17 +621,17 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode) case BM_KEY_WORD_DELETE: { - while (menu->cursor < strlen(menu->filter) && !isspace(menu->filter[menu->cursor])) { + while (menu->cursor < (menu->filter ? strlen(menu->filter) : 0) && !isspace(menu->filter[menu->cursor])) { unsigned int oldCursor = menu->cursor; menu->cursor += _bmUtf8RuneNext(menu->filter, menu->cursor); menu->cursesCursor += _bmUtf8RuneWidth(menu->filter + oldCursor, menu->cursor - oldCursor); } - while (menu->cursor > 0 && isspace(menu->filter[menu->cursor - 1])) { + while (menu->cursor > 0 && menu->filter && isspace(menu->filter[menu->cursor - 1])) { unsigned int oldCursor = menu->cursor; menu->cursor -= _bmUtf8RunePrev(menu->filter, menu->cursor); menu->cursesCursor -= _bmUtf8RuneWidth(menu->filter + menu->cursor, oldCursor - menu->cursor); } - while (menu->cursor > 0 && !isspace(menu->filter[menu->cursor - 1])) { + while (menu->cursor > 0 && menu->filter && !isspace(menu->filter[menu->cursor - 1])) { size_t width; menu->cursor -= _bmUtf8RuneRemove(menu->filter, menu->cursor, &width); menu->cursesCursor -= width; @@ -640,24 +642,18 @@ bmRunResult bmMenuRunWithKey(bmMenu *menu, bmKey key, unsigned int unicode) case BM_KEY_UNICODE: { size_t width; - menu->cursor += _bmUnicodeInsert(menu->filter, sizeof(menu->filter) - 1, menu->cursor, unicode, &width); + menu->cursor += _bmUnicodeInsert(&menu->filter, &menu->filterSize, menu->cursor, unicode, &width); menu->cursesCursor += width; } break; case BM_KEY_TAB: { + const char *text; bmItem *highlighted = bmMenuGetHighlightedItem(menu); - if (highlighted && bmItemGetText(highlighted)) { - const char *text = bmItemGetText(highlighted); - size_t len = strlen(text); - - if (len > sizeof(menu->filter) - 1) - len = sizeof(menu->filter) - 1; - - memset(menu->filter, 0, strlen(menu->filter)); - memcpy(menu->filter, text, len); - menu->cursor = strlen(menu->filter); + if (highlighted && (text = bmItemGetText(highlighted))) { + bmMenuSetFilter(menu, text); + menu->cursor = (menu->filter ? strlen(menu->filter) : 0); menu->cursesCursor = _bmUtf8StringScreenWidth(menu->filter); } } diff --git a/lib/util.c b/lib/util.c index bcb27cb..ca00514 100644 --- a/lib/util.c +++ b/lib/util.c @@ -228,29 +228,45 @@ size_t _bmUtf8RuneRemove(char *string, size_t start, size_t *outRuneWidth) /** * Insert UTF8 rune to buffer. * - * @param string Null terminated C "string". - * @param bufSize Size of the buffer. + * @param inOutString Reference to buffer. + * @param inOutBufSize Reference to size of the buffer. * @param start Start offset where to insert to. (cursor) * @param rune Buffer to insert to string. * @param u8len Byte length of the rune. * @param outRuneWidth Reference to size_t, return number of columns for inserted rune, or -1 on failure. * @return Number of bytes inserted to buffer. */ -size_t _bmUtf8RuneInsert(char *string, size_t bufSize, size_t start, const char *rune, unsigned int u8len, size_t *outRuneWidth) +size_t _bmUtf8RuneInsert(char **inOutString, size_t *inOutBufSize, size_t start, const char *rune, unsigned int u8len, size_t *outRuneWidth) { - assert(string); + assert(inOutString); + assert(inOutBufSize); if (outRuneWidth) *outRuneWidth = 0; - size_t len = strlen(string); - if (len + u8len >= bufSize) + size_t len = (*inOutString ? strlen(*inOutString) : 0); + if (!*inOutString && !(*inOutString = calloc(1, (*inOutBufSize = u8len + 1)))) return 0; + if (len + u8len >= *inOutBufSize) { + void *tmp; + if (!(tmp = realloc(*inOutString, (*inOutBufSize * 2)))) { + if (!(tmp = malloc((*inOutBufSize * 2)))) + return 0; + + memcpy(tmp, *inOutString, *inOutBufSize); + free(*inOutString); + } + + memset(tmp + *inOutBufSize, 0, *inOutBufSize); + *inOutString = tmp; + *inOutBufSize *= 2; + } + if (u8len == 1 && !isprint(*rune)) return 0; - char *str = string + start; + char *str = *inOutString + start; memmove(str + u8len, str, len - start); memcpy(str, rune, u8len); @@ -262,16 +278,17 @@ size_t _bmUtf8RuneInsert(char *string, size_t bufSize, size_t start, const char /** * Insert unicode character to UTF8 buffer. * - * @param string Null terminated C "string". - * @param bufSize Size of the buffer. + * @param inOutString Reference to buffer. + * @param inOutBufSize Reference to size of the buffer. * @param start Start offset where to insert to. (cursor) * @param unicode Unicode character to insert. * @param outRuneWidth Reference to size_t, return number of columns for inserted rune, or -1 on failure. * @return Number of bytes inserted to buffer. */ -size_t _bmUnicodeInsert(char *string, size_t bufSize, size_t start, unsigned int unicode, size_t *outRuneWidth) +size_t _bmUnicodeInsert(char **inOutString, size_t *inOutBufSize, size_t start, unsigned int unicode, size_t *outRuneWidth) { - assert(string); + assert(inOutString); + assert(inOutBufSize); char u8len = ((unicode < 0x80) ? 1 : ((unicode < 0x800) ? 2 : ((unicode < 0x10000) ? 3 : 4))); char mb[5] = { 0, 0, 0, 0 }; @@ -285,7 +302,7 @@ size_t _bmUnicodeInsert(char *string, size_t bufSize, size_t start, unsigned int mb[0] |= (unicode >> (i * 6 - 6)); } - return _bmUtf8RuneInsert(string, bufSize, start, mb, u8len, outRuneWidth); + return _bmUtf8RuneInsert(inOutString, inOutBufSize, start, mb, u8len, outRuneWidth); } /* vim: set ts=8 sw=4 tw=0 :*/ -- cgit v1.2.3-70-g09d2 From f722f247fcd2d53c346cc99bba15c0d20a16c652 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sat, 12 Apr 2014 23:20:53 +0300 Subject: Xterm does not feed S+pgup/pgdown but does so for Ctrl combination --- lib/draw/curses.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 3d7871e..17089af 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -272,9 +272,11 @@ static bmKey _bmDrawCursesGetKey(unsigned int *unicode) case KEY_NPAGE: /* Page down */ return BM_KEY_PAGE_DOWN; + case 550: /* C-Page up */ case 398: /* S-Page up */ return BM_KEY_SHIFT_PAGE_UP; + case 545: /* C-Page down */ case 396: /* S-Page down */ return BM_KEY_SHIFT_PAGE_DOWN; -- cgit v1.2.3-70-g09d2 From 7da3ebe4239675b18560ab642abd1a100801da66 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sat, 12 Apr 2014 23:58:01 +0300 Subject: Scrollable curses input \o/ --- lib/draw/curses.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 17089af..9e8502b 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -181,8 +181,18 @@ static void _bmDrawCursesRender(const bmMenu *menu) const unsigned int lines = curses.getmaxy(curses.stdscr); curses.erase(); - int titleLen = (menu->title ? strlen(menu->title) + 1 : 0); - _bmDrawCursesDrawLine(0, 0, "%*s%s", titleLen, "", (menu->filter ? menu->filter : "")); + unsigned int titleLen = (menu->title ? strlen(menu->title) + 1 : 0); + unsigned int ncols = curses.getmaxx(curses.stdscr); + unsigned int ccols = ncols - titleLen - 1; + unsigned int doffset = (menu->cursesCursor < ccols ? 0 : menu->cursesCursor - ccols); + + if (doffset > 0) { + /* find offset where we won't break the UTF8 string */ + doffset += _bmUtf8RuneNext(menu->filter, doffset); + doffset -= _bmUtf8RunePrev(menu->filter, doffset); + } + + _bmDrawCursesDrawLine(0, 0, "%*s%s", titleLen, "", (menu->filter ? menu->filter + doffset : "")); if (menu->title) { curses.attron(COLOR_PAIR(1)); @@ -199,8 +209,7 @@ static void _bmDrawCursesRender(const bmMenu *menu) _bmDrawCursesDrawLine(color, cl++, "%s%s", (highlighted ? ">> " : " "), (items[i]->text ? items[i]->text : "")); } - unsigned int ncols = curses.getmaxx(curses.stdscr) - titleLen - 1; - curses.move(0, titleLen + (ncols < menu->cursesCursor ? ncols : menu->cursesCursor)); + curses.move(0, titleLen + (menu->cursesCursor < ccols ? menu->cursesCursor : ccols)); curses.refresh(); } -- cgit v1.2.3-70-g09d2 From fc6539c1013d8187ed5a0dc3dfce65f3f626bf79 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sun, 13 Apr 2014 01:22:49 +0300 Subject: Buffer as format is dangerous, this functions seems to be VA one. --- lib/draw/curses.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 9e8502b..f05db01 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -150,7 +150,7 @@ static void _bmDrawCursesDrawLine(int pair, int y, const char *format, ...) if (pair > 0) curses.attron(COLOR_PAIR(pair)); - curses.mvprintw(y, 0, buffer); + curses.mvprintw(y, 0, "%s", buffer); if (pair > 0) curses.attroff(COLOR_PAIR(pair)); -- cgit v1.2.3-70-g09d2 From 60c1ab88cc4ee7b5d4f87c7867059464757666bb Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sun, 13 Apr 2014 01:39:31 +0300 Subject: Store old actions to seperate actions. --- lib/draw/curses.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index f05db01..3b160a9 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -54,7 +54,8 @@ static const char *TTY = "/dev/tty"; * Dynamically loaded curses API. */ static struct curses { - struct sigaction action; + struct sigaction abrtAction; + struct sigaction segvAction; void *handle; WINDOW *stdscr; WINDOW* (*initscr)(void); @@ -342,8 +343,8 @@ static void _bmDrawCursesFree(void) if (curses.handle) dlclose(curses.handle); - sigaction(SIGABRT, &curses.action, NULL); - sigaction(SIGSEGV, &curses.action, NULL); + sigaction(SIGABRT, &curses.abrtAction, NULL); + sigaction(SIGSEGV, &curses.segvAction, NULL); memset(&curses, 0, sizeof(curses)); } @@ -407,8 +408,8 @@ int _bmDrawCursesInit(struct _bmRenderApi *api) struct sigaction action; memset(&action, 0, sizeof(struct sigaction)); action.sa_handler = _bmDrawCursesCrashHandler; - sigaction(SIGABRT, &action, &curses.action); - sigaction(SIGSEGV, &action, &curses.action); + sigaction(SIGABRT, &action, &curses.abrtAction); + sigaction(SIGSEGV, &action, &curses.segvAction); return 1; function_pointer_exception: -- cgit v1.2.3-70-g09d2 From 9c0b25f6a9f7e0a0c2f8b6a4608aab68e5e6a909 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sun, 13 Apr 2014 02:47:54 +0300 Subject: Enable noecho and raw mode. --- lib/draw/curses.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 3b160a9..7d91d36 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -72,6 +72,8 @@ static struct curses { int (*getmaxx)(WINDOW *win); int (*getmaxy)(WINDOW *win); int (*keypad)(WINDOW *win, bool bf); + int (*noecho)(void); + int (*raw)(void); int *ESCDELAY; int oldStdin; int oldStdout; @@ -173,6 +175,8 @@ static void _bmDrawCursesRender(const bmMenu *menu) *curses.ESCDELAY = 25; curses.keypad(curses.stdscr, true); + curses.noecho(); + curses.raw(); curses.start_color(); curses.init_pair(1, COLOR_BLACK, COLOR_RED); @@ -395,6 +399,10 @@ int _bmDrawCursesInit(struct _bmRenderApi *api) goto function_pointer_exception; if (!bmLoadFunction(keypad)) goto function_pointer_exception; + if (!bmLoadFunction(noecho)) + goto function_pointer_exception; + if (!bmLoadFunction(raw)) + goto function_pointer_exception; if (!bmLoadFunction(ESCDELAY)) goto function_pointer_exception; -- cgit v1.2.3-70-g09d2 From c2bed7689d1d97e7bfc0ab52e028e290ee0b3f0e Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sun, 13 Apr 2014 03:00:34 +0300 Subject: Enable cursor (hidden when launched by vim) --- lib/draw/curses.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 7d91d36..0304dd5 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -72,6 +72,7 @@ static struct curses { int (*getmaxx)(WINDOW *win); int (*getmaxy)(WINDOW *win); int (*keypad)(WINDOW *win, bool bf); + int (*curs_set)(int visibility); int (*noecho)(void); int (*raw)(void); int *ESCDELAY; @@ -175,6 +176,7 @@ static void _bmDrawCursesRender(const bmMenu *menu) *curses.ESCDELAY = 25; curses.keypad(curses.stdscr, true); + curses.curs_set(1); curses.noecho(); curses.raw(); @@ -399,6 +401,8 @@ int _bmDrawCursesInit(struct _bmRenderApi *api) goto function_pointer_exception; if (!bmLoadFunction(keypad)) goto function_pointer_exception; + if (!bmLoadFunction(curs_set)) + goto function_pointer_exception; if (!bmLoadFunction(noecho)) goto function_pointer_exception; if (!bmLoadFunction(raw)) -- cgit v1.2.3-70-g09d2 From 66a6f08c8a9a90fd8c176a4c6b1f5aa6094233c4 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sun, 13 Apr 2014 03:23:11 +0300 Subject: vsnprintf is not on same headers on darwin. --- lib/draw/curses.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 0304dd5..6ebfb45 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -1,5 +1,11 @@ #include "../internal.h" +#if __APPLE__ +# define _C99_SOURCE +# include /* vsnprintf */ +# undef _C99_SOURCE +#endif + #define _XOPEN_SOURCE 500 #include /* sigaction */ #include /* vsnprintf */ -- cgit v1.2.3-70-g09d2 From 850a8335d5c35cc81ba576cd4636460ea1684223 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Sun, 13 Apr 2014 04:16:23 +0300 Subject: Flush input buffer after showing menu first time. --- lib/draw/curses.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 6ebfb45..9a123df 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -79,6 +79,7 @@ static struct curses { int (*getmaxy)(WINDOW *win); int (*keypad)(WINDOW *win, bool bf); int (*curs_set)(int visibility); + int (*flushinp)(void); int (*noecho)(void); int (*raw)(void); int *ESCDELAY; @@ -181,6 +182,7 @@ static void _bmDrawCursesRender(const bmMenu *menu) return; *curses.ESCDELAY = 25; + curses.flushinp(); curses.keypad(curses.stdscr, true); curses.curs_set(1); curses.noecho(); @@ -409,6 +411,8 @@ int _bmDrawCursesInit(struct _bmRenderApi *api) goto function_pointer_exception; if (!bmLoadFunction(curs_set)) goto function_pointer_exception; + if (!bmLoadFunction(flushinp)) + goto function_pointer_exception; if (!bmLoadFunction(noecho)) goto function_pointer_exception; if (!bmLoadFunction(raw)) -- cgit v1.2.3-70-g09d2 From 066c5c2e61d1b91f04564115ec061968a0716533 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Mon, 14 Apr 2014 19:00:03 +0300 Subject: Make sure text fits tightly terminal + simplified logic --- lib/draw/curses.c | 53 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 22 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 9a123df..5cd1335 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -87,12 +87,12 @@ static struct curses { int oldStdout; } curses; -static int _bmDrawCursesResizeBuffer(char **buffer, size_t osize, size_t nsize) +static int _bmDrawCursesResizeBuffer(char **buffer, size_t *osize, size_t nsize) { assert(buffer); - assert(nsize); + assert(osize); - if (nsize == 0 || nsize < osize) + if (nsize == 0 || nsize <= *osize) return 0; void *tmp; @@ -101,14 +101,13 @@ static int _bmDrawCursesResizeBuffer(char **buffer, size_t osize, size_t nsize) return 0; if (*buffer) { - memcpy(tmp, *buffer, osize); + memcpy(tmp, *buffer, *osize); free(*buffer); } } *buffer = tmp; - memset(*buffer + osize, ' ', (nsize - osize)); - (*buffer)[nsize - 1] = 0; + *osize = nsize; return 1; } @@ -117,32 +116,27 @@ __attribute__((format(printf, 3, 4))) #endif static void _bmDrawCursesDrawLine(int pair, int y, const char *format, ...) { - static int blen = 0; + static size_t blen = 0; static char *buffer = NULL; - int ncols = curses.getmaxx(curses.stdscr); + size_t ncols = curses.getmaxx(curses.stdscr); if (ncols <= 0) return; va_list args; va_start(args, format); - int nlen = vsnprintf(NULL, 0, format, args) + 1; - if (nlen < ncols) - nlen = ncols; + size_t nlen = vsnprintf(NULL, 0, format, args); va_end(args); - if ((!buffer || nlen > blen) && !_bmDrawCursesResizeBuffer(&buffer, blen, nlen)) + if ((!buffer || nlen > blen) && !_bmDrawCursesResizeBuffer(&buffer, &blen, nlen + 1)) return; - blen = nlen; va_start(args, format); - int slen = vsnprintf(buffer, blen - 1, format, args); - memset(buffer + slen, ' ', (blen - slen)); - buffer[blen - 1] = 0; + vsnprintf(buffer, blen - 1, format, args); va_end(args); - int dw = 0, i = 0; - while (dw < ncols && i < blen) { + size_t dw = 0, i = 0; + while (dw < ncols && i < nlen) { if (buffer[i] == '\t') buffer[i] = ' '; int next = _bmUtf8RuneNext(buffer, i); dw += _bmUtf8RuneWidth(buffer + i, next); @@ -150,12 +144,27 @@ static void _bmDrawCursesDrawLine(int pair, int y, const char *format, ...) } if (dw < ncols) { - if (!_bmDrawCursesResizeBuffer(&buffer, blen - 1, blen + (ncols - dw))) - return; + /* line is too short, widen it */ + size_t offset = i + (ncols - dw); + if (blen <= offset && !_bmDrawCursesResizeBuffer(&buffer, &blen, offset + 1)) + return; + + memset(buffer + nlen, ' ', offset - nlen); + buffer[offset] = 0; } else if (i < blen) { - int cc = dw - (dw - ncols); + /* line is too long, shorten it */ + i -= _bmUtf8RunePrev(buffer, i - (dw - ncols)) - 1; + size_t cc = dw - (dw - ncols); + + size_t offset = i - (dw - ncols) + (ncols - cc) + 1; + if (blen <= offset) { + int diff = offset - blen + 1; + if (!_bmDrawCursesResizeBuffer(&buffer, &blen, blen + diff)) + return; + } + memset(buffer + i - (dw - ncols), ' ', (ncols - cc) + 1); - buffer[i - (dw - ncols) + (ncols - cc) + 1] = 0; + buffer[offset] = 0; } if (pair > 0) -- cgit v1.2.3-70-g09d2 From 5b873de2ded661416d64dc589c1d10bde2c5dfc0 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Mon, 14 Apr 2014 19:00:15 +0300 Subject: Better input scroll logic. --- lib/draw/curses.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 5cd1335..4ae63d7 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -208,12 +208,12 @@ static void _bmDrawCursesRender(const bmMenu *menu) unsigned int titleLen = (menu->title ? strlen(menu->title) + 1 : 0); unsigned int ncols = curses.getmaxx(curses.stdscr); unsigned int ccols = ncols - titleLen - 1; - unsigned int doffset = (menu->cursesCursor < ccols ? 0 : menu->cursesCursor - ccols); + unsigned int dcols = 0, doffset = menu->cursor; - if (doffset > 0) { - /* find offset where we won't break the UTF8 string */ - doffset += _bmUtf8RuneNext(menu->filter, doffset); - doffset -= _bmUtf8RunePrev(menu->filter, doffset); + while (doffset > 0 && dcols < ccols) { + int prev = _bmUtf8RunePrev(menu->filter, doffset); + dcols += _bmUtf8RuneWidth(menu->filter + doffset - prev, prev); + doffset -= (prev ? prev : 1); } _bmDrawCursesDrawLine(0, 0, "%*s%s", titleLen, "", (menu->filter ? menu->filter + doffset : "")); -- cgit v1.2.3-70-g09d2 From 9df8716cb8787110aedf5d9ad9c27b4eb3bade39 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Mon, 14 Apr 2014 19:11:26 +0300 Subject: Handle window resize. --- lib/draw/curses.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 4ae63d7..5673c90 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -62,6 +62,7 @@ static const char *TTY = "/dev/tty"; static struct curses { struct sigaction abrtAction; struct sigaction segvAction; + struct sigaction winchAction; void *handle; WINDOW *stdscr; WINDOW* (*initscr)(void); @@ -273,6 +274,11 @@ static bmKey _bmDrawCursesGetKey(unsigned int *unicode) curses.get_wch((wint_t*)unicode); switch (*unicode) { +#if KEY_RESIZE + case KEY_RESIZE: + return BM_KEY_NONE; +#endif + case 16: /* C-p */ case KEY_UP: return BM_KEY_UP; @@ -335,7 +341,6 @@ static bmKey _bmDrawCursesGetKey(unsigned int *unicode) case 9: /* Tab */ return BM_KEY_TAB; - case 0: /* C-Space */ case 18: /* C-r */ return BM_KEY_CONTROL_RETURN; @@ -368,6 +373,7 @@ static void _bmDrawCursesFree(void) sigaction(SIGABRT, &curses.abrtAction, NULL); sigaction(SIGSEGV, &curses.segvAction, NULL); + sigaction(SIGWINCH, &curses.winchAction, NULL); memset(&curses, 0, sizeof(curses)); } @@ -377,6 +383,16 @@ static void _bmDrawCursesCrashHandler(int sig) _bmDrawCursesFree(); } +static void _bmDrawCursesResizeHandler(int sig) +{ + (void)sig; + if (!curses.stdscr) + return; + + curses.endwin(); + curses.refresh(); +} + int _bmDrawCursesInit(struct _bmRenderApi *api) { memset(&curses, 0, sizeof(curses)); @@ -441,6 +457,9 @@ int _bmDrawCursesInit(struct _bmRenderApi *api) action.sa_handler = _bmDrawCursesCrashHandler; sigaction(SIGABRT, &action, &curses.abrtAction); sigaction(SIGSEGV, &action, &curses.segvAction); + + action.sa_handler = _bmDrawCursesResizeHandler; + sigaction(SIGWINCH, &action, &curses.winchAction); return 1; function_pointer_exception: -- cgit v1.2.3-70-g09d2 From bcda5404011714622ec22a37c4b7837defe4377e Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Mon, 14 Apr 2014 19:14:30 +0300 Subject: Hide title if more than NCOLS --- lib/draw/curses.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 5673c90..2cc84af 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -206,8 +206,12 @@ static void _bmDrawCursesRender(const bmMenu *menu) const unsigned int lines = curses.getmaxy(curses.stdscr); curses.erase(); - unsigned int titleLen = (menu->title ? strlen(menu->title) + 1 : 0); unsigned int ncols = curses.getmaxx(curses.stdscr); + unsigned int titleLen = (menu->title ? strlen(menu->title) + 1 : 0); + + if (titleLen >= ncols) + titleLen = 0; + unsigned int ccols = ncols - titleLen - 1; unsigned int dcols = 0, doffset = menu->cursor; @@ -219,7 +223,7 @@ static void _bmDrawCursesRender(const bmMenu *menu) _bmDrawCursesDrawLine(0, 0, "%*s%s", titleLen, "", (menu->filter ? menu->filter + doffset : "")); - if (menu->title) { + if (menu->title && titleLen > 0) { curses.attron(COLOR_PAIR(1)); curses.mvprintw(0, 0, menu->title); curses.attroff(COLOR_PAIR(1)); -- cgit v1.2.3-70-g09d2 From 7533cebfe531f2264b10903a5d1b8a0d60b9fcae Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Mon, 14 Apr 2014 19:33:50 +0300 Subject: Tell curses to use terminal default colors --- lib/draw/curses.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 2cc84af..f8137b8 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -76,6 +76,7 @@ static struct curses { int (*attroff)(int attrs); int (*attron)(int attrs); int (*start_color)(void); + int (*use_default_colors)(void); int (*getmaxx)(WINDOW *win); int (*getmaxy)(WINDOW *win); int (*keypad)(WINDOW *win, bool bf); @@ -199,8 +200,9 @@ static void _bmDrawCursesRender(const bmMenu *menu) curses.raw(); curses.start_color(); + curses.use_default_colors(); curses.init_pair(1, COLOR_BLACK, COLOR_RED); - curses.init_pair(2, COLOR_RED, COLOR_BLACK); + curses.init_pair(2, COLOR_RED, -1); } const unsigned int lines = curses.getmaxy(curses.stdscr); @@ -432,6 +434,8 @@ int _bmDrawCursesInit(struct _bmRenderApi *api) goto function_pointer_exception; if (!bmLoadFunction(start_color)) goto function_pointer_exception; + if (!bmLoadFunction(use_default_colors)) + goto function_pointer_exception; if (!bmLoadFunction(getmaxx)) goto function_pointer_exception; if (!bmLoadFunction(getmaxy)) -- cgit v1.2.3-70-g09d2 From cf27013c1d1790e0d5239aa6fc34999e0f173f30 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Tue, 15 Apr 2014 20:06:51 +0300 Subject: Print the missing function and from what library in case of exception. --- lib/draw/curses.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index f8137b8..afe0a98 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -410,7 +410,8 @@ int _bmDrawCursesInit(struct _bmRenderApi *api) if (!curses.handle) return 0; -#define bmLoadFunction(x) (curses.x = dlsym(curses.handle, #x)) + char *func = NULL; +#define bmLoadFunction(x) (curses.x = dlsym(curses.handle, (func = #x))) if (!bmLoadFunction(initscr)) goto function_pointer_exception; @@ -471,6 +472,7 @@ int _bmDrawCursesInit(struct _bmRenderApi *api) return 1; function_pointer_exception: + fprintf(stderr, "-!- Could not load function '%s' from '%s'\n", func, DL_PATH[i]); _bmDrawCursesFree(); return 0; } -- cgit v1.2.3-70-g09d2 From f77ae857b181ace139cc702f2a997db6ade86b8c Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Tue, 15 Apr 2014 20:07:47 +0300 Subject: It's better to guard whole function. --- lib/draw/curses.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index afe0a98..0f6fdd2 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -252,6 +252,9 @@ static unsigned int _bmDrawCursesDisplayedCount(const bmMenu *menu) static void _bmDrawCursesEndWin(void) { + if (!curses.stdscr) + return; + freopen(TTY, "w", stdout); if (curses.refresh) @@ -260,12 +263,10 @@ static void _bmDrawCursesEndWin(void) if (curses.endwin) curses.endwin(); - if (curses.stdscr) { - dup2(curses.oldStdin, STDIN_FILENO); - dup2(curses.oldStdout, STDOUT_FILENO); - close(curses.oldStdin); - close(curses.oldStdout); - } + dup2(curses.oldStdin, STDIN_FILENO); + dup2(curses.oldStdout, STDOUT_FILENO); + close(curses.oldStdin); + close(curses.oldStdout); curses.stdscr = NULL; } -- cgit v1.2.3-70-g09d2 From 88590ddcfefdb94f2900282ec8b7a9573b53d37f Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Tue, 15 Apr 2014 20:14:42 +0300 Subject: Don't use the enumerator variable. --- lib/draw/curses.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 0f6fdd2..82fd194 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -403,15 +403,15 @@ static void _bmDrawCursesResizeHandler(int sig) int _bmDrawCursesInit(struct _bmRenderApi *api) { memset(&curses, 0, sizeof(curses)); + const char *lib = NULL, *func = NULL; unsigned int i; for (i = 0; DL_PATH[i] && !curses.handle; ++i) - curses.handle = dlopen(DL_PATH[i], RTLD_LAZY); + curses.handle = dlopen((lib = DL_PATH[i]), RTLD_LAZY); if (!curses.handle) return 0; - char *func = NULL; #define bmLoadFunction(x) (curses.x = dlsym(curses.handle, (func = #x))) if (!bmLoadFunction(initscr)) @@ -473,7 +473,7 @@ int _bmDrawCursesInit(struct _bmRenderApi *api) return 1; function_pointer_exception: - fprintf(stderr, "-!- Could not load function '%s' from '%s'\n", func, DL_PATH[i]); + fprintf(stderr, "-!- Could not load function '%s' from '%s'\n", func, lib); _bmDrawCursesFree(); return 0; } -- cgit v1.2.3-70-g09d2 From 8e415197d248560b359bace7ef8f7ffe0f445099 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Tue, 15 Apr 2014 20:31:10 +0300 Subject: This is not used --- lib/draw/curses.c | 1 - 1 file changed, 1 deletion(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index 82fd194..c4e323a 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -54,7 +54,6 @@ static const char *TTY = "/dev/tty"; #undef attron #undef getmaxx #undef getmaxy -#undef timeout /** * Dynamically loaded curses API. -- cgit v1.2.3-70-g09d2 From 953c61f4ad12d2a711d0c91e24e37cae871dcdc3 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Tue, 15 Apr 2014 20:34:21 +0300 Subject: Support older ncurses. --- lib/draw/curses.c | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'lib/draw/curses.c') diff --git a/lib/draw/curses.c b/lib/draw/curses.c index c4e323a..a1f23ef 100644 --- a/lib/draw/curses.c +++ b/lib/draw/curses.c @@ -42,9 +42,16 @@ static const char *TTY = "/dev/tty"; }; #endif +/* these are implemented as macros in older curses */ +#ifndef NCURSES_OPAQUE +static int wrap_getmaxx(WINDOW *win) { return getmaxx(win); } +static int wrap_getmaxy(WINDOW *win) { return getmaxy(win); } +#endif + /* ncurses.h likes to define stuff for us. * This unforunately mangles with our struct. */ #undef erase +#undef getch #undef get_wch #undef refresh #undef mvprintw @@ -68,6 +75,7 @@ static struct curses { int (*endwin)(void); int (*refresh)(void); int (*erase)(void); + int (*getch)(void); int (*get_wch)(wint_t *wch); int (*mvprintw)(int x, int y, const char *fmt, ...); int (*move)(int x, int y); @@ -278,7 +286,11 @@ static bmKey _bmDrawCursesGetKey(unsigned int *unicode) if (!curses.stdscr) return BM_KEY_NONE; - curses.get_wch((wint_t*)unicode); + if (curses.get_wch) + curses.get_wch((wint_t*)unicode); + else if (curses.getch) + *unicode = curses.getch(); + switch (*unicode) { #if KEY_RESIZE case KEY_RESIZE: @@ -419,7 +431,7 @@ int _bmDrawCursesInit(struct _bmRenderApi *api) goto function_pointer_exception; if (!bmLoadFunction(refresh)) goto function_pointer_exception; - if (!bmLoadFunction(get_wch)) + if (!bmLoadFunction(get_wch) && !bmLoadFunction(getch)) goto function_pointer_exception; if (!bmLoadFunction(erase)) goto function_pointer_exception; @@ -437,10 +449,6 @@ int _bmDrawCursesInit(struct _bmRenderApi *api) goto function_pointer_exception; if (!bmLoadFunction(use_default_colors)) goto function_pointer_exception; - if (!bmLoadFunction(getmaxx)) - goto function_pointer_exception; - if (!bmLoadFunction(getmaxy)) - goto function_pointer_exception; if (!bmLoadFunction(keypad)) goto function_pointer_exception; if (!bmLoadFunction(curs_set)) @@ -454,6 +462,16 @@ int _bmDrawCursesInit(struct _bmRenderApi *api) if (!bmLoadFunction(ESCDELAY)) goto function_pointer_exception; +#ifndef NCURSES_OPAQUE + curses.getmaxx = wrap_getmaxx; + curses.getmaxy = wrap_getmaxy; +#else + if (!bmLoadFunction(getmaxx)) + goto function_pointer_exception; + if (!bmLoadFunction(getmaxy)) + goto function_pointer_exception; +#endif + #undef bmLoadFunction api->displayedCount = _bmDrawCursesDisplayedCount; -- cgit v1.2.3-70-g09d2