diff --git a/doc/man/man3/notcurses_selector.3.md b/doc/man/man3/notcurses_selector.3.md index 528d14dbd..44a1fe0eb 100644 --- a/doc/man/man3/notcurses_selector.3.md +++ b/doc/man/man3/notcurses_selector.3.md @@ -55,7 +55,7 @@ typedef struct ncselector_options { **bool ncselector_offer_input(struct ncselector* ***n***, const ncinput* ***nc***);** -**void ncselector_destroy(struct ncselector* ***n***);** +**void ncselector_destroy(struct ncselector* ***n***, char** ***item***);** # DESCRIPTION diff --git a/include/ncpp/Selector.hh b/include/ncpp/Selector.hh index e63f0e41f..342c6fb44 100644 --- a/include/ncpp/Selector.hh +++ b/include/ncpp/Selector.hh @@ -38,7 +38,7 @@ namespace ncpp ~Selector () { if (!is_notcurses_stopped ()) - ncselector_destroy (selector); + ncselector_destroy (selector, nullptr); } int additem (const ncselector_item *item) const NOEXCEPT_MAYBE diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index 0db32f303..fde08460c 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -3609,7 +3609,7 @@ API bool ncselector_offer_input(struct ncselector* n, const ncinput* nc) __attribute__ ((nonnull (1, 2))); // Destroy the ncselector. -API void ncselector_destroy(struct ncselector* n); +API void ncselector_destroy(struct ncselector* n, char** item); struct ncmselector_item { const char* option; diff --git a/src/demo/zoo.c b/src/demo/zoo.c index 93c991271..39883b66e 100644 --- a/src/demo/zoo.c +++ b/src/demo/zoo.c @@ -429,7 +429,7 @@ reader_demo(struct notcurses* nc){ } done: - ncselector_destroy(selector); + ncselector_destroy(selector, NULL); ncmultiselector_destroy(mselector); ncplane_destroy(rp); return ret; diff --git a/src/lib/reader.c b/src/lib/reader.c index 57f4e8659..4e34fa35e 100644 --- a/src/lib/reader.c +++ b/src/lib/reader.c @@ -1,5 +1,26 @@ #include "internal.h" +static void +ncreader_destroy_internal(ncreader* n){ + if(n){ + if(n->manage_cursor){ + notcurses_cursor_disable(ncplane_notcurses(n->ncp)); + } + ncplane_destroy(n->textarea); + ncplane_destroy(n->ncp); + free(n); + } +} + +void ncreader_destroy(ncreader* n, char** contents){ + if(n){ + if(contents){ + *contents = ncreader_contents(n); + } + ncreader_destroy_internal(n); + } +} + ncreader* ncreader_create(ncplane* n, const ncreader_options* opts){ ncreader_options zeroed = {}; if(!opts){ @@ -37,6 +58,12 @@ ncreader* ncreader_create(ncplane* n, const ncreader_options* opts){ nr->manage_cursor = opts->flags & NCREADER_OPTION_CURSOR; ncplane_set_channels(nr->ncp, opts->tchannels); ncplane_set_styles(nr->ncp, opts->tattrword); + if(ncplane_set_widget(n, nr, (void(*)(void*))ncreader_destroy_internal)){ + ncplane_destroy(nr->textarea); + ncplane_destroy(nr->ncp); + free(nr); + return NULL; + } return nr; } @@ -383,17 +410,3 @@ bool ncreader_offer_input(ncreader* n, const ncinput* ni){ char* ncreader_contents(const ncreader* n){ return ncplane_contents(n->ncp, 0, 0, 0, 0); } - -void ncreader_destroy(ncreader* n, char** contents){ - if(n){ - if(contents){ - *contents = ncreader_contents(n); - } - if(n->manage_cursor){ - notcurses_cursor_disable(ncplane_notcurses(n->ncp)); - } - ncplane_destroy(n->textarea); - ncplane_destroy(n->ncp); - free(n); - } -} diff --git a/src/lib/selector.c b/src/lib/selector.c index 2d5aa8aee..999a801b9 100644 --- a/src/lib/selector.c +++ b/src/lib/selector.c @@ -249,6 +249,34 @@ ncselector_dim_yx(const ncselector* n, unsigned* ncdimy, unsigned* ncdimx){ *ncdimx = cols; } +static void +ncselector_destroy_internal(ncselector* n){ + if(n){ + while(n->itemcount--){ + free(n->items[n->itemcount].option); + free(n->items[n->itemcount].desc); + } + if(ncplane_set_widget(n->ncp, NULL, NULL) == 0){ + ncplane_destroy(n->ncp); + } + free(n->items); + free(n->title); + free(n->secondary); + free(n->footer); + free(n); + } +} + +void ncselector_destroy(ncselector* n, char** item){ + if(n){ + if(item){ + *item = n->items[n->selected].option; + n->items[n->selected].option = NULL; + } + ncselector_destroy_internal(n); + } +} + ncselector* ncselector_create(ncplane* n, const ncselector_options* opts){ if(n == notcurses_stdplane(ncplane_notcurses(n))){ logerror("won't use the standard plane\n"); // would fail later on resize @@ -269,13 +297,11 @@ ncselector* ncselector_create(ncplane* n, const ncselector_options* opts){ } ncselector* ns = malloc(sizeof(*ns)); if(ns == NULL){ -fprintf(stderr, "SHIT -3\n"); return NULL; } memset(ns, 0, sizeof(*ns)); if(opts->defidx && opts->defidx >= itemcount){ logerror("default index %u too large (%u items)\n", opts->defidx, itemcount); -fprintf(stderr, "SHIT -2\n"); goto freeitems; } ns->title = opts->title ? strdup(opts->title) : NULL; @@ -305,7 +331,6 @@ fprintf(stderr, "SHIT -2\n"); ns->darrowy = ns->uarrowy = ns->arrowx = -1; if(itemcount){ if(!(ns->items = malloc(sizeof(*ns->items) * itemcount))){ -fprintf(stderr, "SHIT -1\n"); goto freeitems; } }else{ @@ -315,7 +340,6 @@ fprintf(stderr, "SHIT -1\n"); const struct ncselector_item* src = &opts->items[ns->itemcount]; int unsafe = ncstrwidth(src->option); if(unsafe < 0){ -fprintf(stderr, "SHIT 0\n"); goto freeitems; } unsigned cols = unsafe; @@ -326,7 +350,6 @@ fprintf(stderr, "SHIT 0\n"); const char *desc = src->desc ? src->desc : ""; unsafe = ncstrwidth(desc); if(unsafe < 0){ -fprintf(stderr, "SHIT 1\n"); goto freeitems; } cols = unsafe; @@ -337,7 +360,6 @@ fprintf(stderr, "SHIT 1\n"); ns->items[ns->itemcount].option = strdup(src->option); ns->items[ns->itemcount].desc = strdup(desc); if(!(ns->items[ns->itemcount].desc && ns->items[ns->itemcount].option)){ -fprintf(stderr, "SHIT 2\n"); free(ns->items[ns->itemcount].option); free(ns->items[ns->itemcount].desc); goto freeitems; @@ -347,15 +369,12 @@ fprintf(stderr, "SHIT 2\n"); ns->ncp = n; ncselector_dim_yx(ns, &dimy, &dimx); if(ncplane_resize_simple(n, dimy, dimx)){ -fprintf(stderr, "SHIT 3\n"); goto freeitems; } - if(ncplane_set_widget(ns->ncp, ns, (void(*)(void*))ncselector_destroy)){ -fprintf(stderr, "SHIT 4\n"); + if(ncplane_set_widget(ns->ncp, ns, (void(*)(void*))ncselector_destroy_internal)){ goto freeitems; } ncselector_draw(ns); // deal with error here? -fprintf(stderr, "RETURNING %p\n", ns); return ns; freeitems: @@ -367,7 +386,6 @@ freeitems: free(ns->title); free(ns->secondary); free(ns->footer); free(ns); ncplane_destroy(n); -fprintf(stderr, "RETURNING %p\n", NULL); return NULL; } @@ -565,23 +583,6 @@ bool ncselector_offer_input(ncselector* n, const ncinput* nc){ return false; } -void ncselector_destroy(ncselector* n){ - if(n){ - while(n->itemcount--){ - free(n->items[n->itemcount].option); - free(n->items[n->itemcount].desc); - } - if(ncplane_set_widget(n->ncp, NULL, NULL) == 0){ - ncplane_destroy(n->ncp); - } - free(n->items); - free(n->title); - free(n->secondary); - free(n->footer); - free(n); - } -} - ncplane* ncmultiselector_plane(ncmultiselector* n){ return n->ncp; } diff --git a/src/poc/selector.c b/src/poc/selector.c index 1f14b236c..138ce7750 100644 --- a/src/poc/selector.c +++ b/src/poc/selector.c @@ -39,8 +39,8 @@ run_selector(struct notcurses* nc, struct ncselector* ns){ continue; } switch(keypress){ - case NCKEY_ENTER: ncselector_destroy(ns); return; - case 'M': case 'J': if(ni.ctrl){ ncselector_destroy(ns); return; } + case NCKEY_ENTER: ncselector_destroy(ns, NULL); return; + case 'M': case 'J': if(ni.ctrl){ ncselector_destroy(ns, NULL); return; } } if(keypress == 'q'){ break; @@ -48,7 +48,7 @@ run_selector(struct notcurses* nc, struct ncselector* ns){ } notcurses_render(nc); } - ncselector_destroy(ns); + ncselector_destroy(ns, NULL); } int main(void){ diff --git a/src/tests/selector.cpp b/src/tests/selector.cpp index f86c0d6fc..46a1da3e3 100644 --- a/src/tests/selector.cpp +++ b/src/tests/selector.cpp @@ -65,7 +65,7 @@ TEST_CASE("Selectors") { ncplane_dim_yx(ncsp, &dimy, &dimx); CHECK(4 == dimy); CHECK(5 == dimx); - ncselector_destroy(ncs); + ncselector_destroy(ncs, nullptr); } SUBCASE("TitledSelector") { @@ -86,7 +86,7 @@ TEST_CASE("Selectors") { ncplane_dim_yx(ncsp, &dimy, &dimx); CHECK(6 == dimy); CHECK(strlen(opts.title) + 4 == dimx); - ncselector_destroy(ncs); + ncselector_destroy(ncs, nullptr); } SUBCASE("SecondarySelector") { @@ -107,7 +107,7 @@ TEST_CASE("Selectors") { ncplane_dim_yx(ncsp, &dimy, &dimx); CHECK(4 == dimy); CHECK(strlen(opts.secondary) + 2 == dimx); - ncselector_destroy(ncs); + ncselector_destroy(ncs, nullptr); } SUBCASE("FooterSelector") { @@ -128,7 +128,7 @@ TEST_CASE("Selectors") { ncplane_dim_yx(ncsp, &dimy, &dimx); CHECK(4 == dimy); CHECK(strlen(opts.footer) + 2 == dimx); - ncselector_destroy(ncs); + ncselector_destroy(ncs, nullptr); } SUBCASE("PopulatedSelector") { @@ -136,7 +136,7 @@ TEST_CASE("Selectors") { { "op1", "this is option 1", }, { "2ndop", "this is option #2", }, { "tres", "option the third", }, - { NULL, NULL, }, + { nullptr, nullptr, }, }; struct ncselector_options opts{}; opts.items = items; @@ -154,7 +154,7 @@ TEST_CASE("Selectors") { ncplane_dim_yx(ncsp, &dimy, &dimx); CHECK(7 == dimy); CHECK(15 < dimx); - ncselector_destroy(ncs); + ncselector_destroy(ncs, nullptr); } SUBCASE("EmptySelectorMovement") { @@ -175,7 +175,7 @@ TEST_CASE("Selectors") { sel = ncselector_previtem(ncs); REQUIRE(nullptr == sel); CHECK(0 == notcurses_render(nc_)); - ncselector_destroy(ncs); + ncselector_destroy(ncs, nullptr); } SUBCASE("SelectorMovement") { @@ -183,7 +183,7 @@ TEST_CASE("Selectors") { { "op1", "this is option 1", }, { "2ndop", "this is option #2", }, { "tres", "option the third", }, - { NULL, NULL, }, + { nullptr, nullptr, }, }; struct ncselector_options opts{}; opts.items = items; @@ -216,7 +216,7 @@ TEST_CASE("Selectors") { REQUIRE(nullptr != sel); CHECK(0 == strcmp(sel, items[0].option)); CHECK(0 == notcurses_render(nc_)); - ncselector_destroy(ncs); + ncselector_destroy(ncs, nullptr); } // Provide three items, limited to 1 shown at a time @@ -225,7 +225,7 @@ TEST_CASE("Selectors") { { "op1", "this is option 1", }, { "2ndop", "this is option #2", }, { "tres", "option the third", }, - { NULL, NULL, }, + { nullptr, nullptr, }, }; struct ncselector_options opts{}; opts.maxdisplay = 1; @@ -264,7 +264,7 @@ TEST_CASE("Selectors") { unsigned dimy, dimx; ncplane_dim_yx(ncsp, &dimy, &dimx); CHECK(5 == dimy); - ncselector_destroy(ncs); + ncselector_destroy(ncs, nullptr); } // Provide three items, limited to 2 shown at a time @@ -273,7 +273,7 @@ TEST_CASE("Selectors") { { "op1", "this is option 1", }, { "2ndop", "this is option #2", }, { "tres", "option the third", }, - { NULL, NULL, }, + { nullptr, nullptr, }, }; struct ncselector_options opts{}; opts.maxdisplay = 2; @@ -311,7 +311,7 @@ TEST_CASE("Selectors") { unsigned dimy, dimx; ncplane_dim_yx(ncsp, &dimy, &dimx); CHECK(6 == dimy); - ncselector_destroy(ncs); + ncselector_destroy(ncs, nullptr); } CHECK(0 == notcurses_stop(nc_));