We already delay the freeing of a pane until it cannot be in use.
But we also sometimes need the ->data to hang around a bit beyond
close too.
So introduce a new "Free" callback to tell a pane to free its
data, and call that just before the pane is freed.
Signed-off-by: NeilBrown <neil@brown.name>
Core features
-------------
-- [ ] pane_close() can be called at awkward times. We need to do some initial
+- [X] pane_close() can be called at awkward times. We need to do some initial
processing so that it looks closed, but so that code can continue to
run, then schedule proper close for later.
..Hmm... I already do this, since before I added this item to the todo list.
mark_free(dd->point);
mark_free(dd->mark);
call("doc:closed", dd->doc);
- free(dd);
- ci->home->data = safe_cast NULL;
return 1;
}
key_add(doc_handle_cmd, "Refresh", &doc_refresh);
key_add(doc_handle_cmd, "Clone", &doc_clone);
key_add(doc_handle_cmd, "Close", &doc_close);
+ key_add(doc_handle_cmd, "Free", &edlib_do_free);
key_add(doc_handle_cmd, "doc:dup-point", &doc_dup_point);
key_add(doc_handle_cmd, "Replace", &doc_replace);
key_add(doc_handle_cmd, "get-attr", &doc_handle_get_attr);
while (ei->freelist) {
struct pane *p = ei->freelist;
ei->freelist = p->focus;
+ p->focus = NULL;
+
+ p->damaged &= ~DAMAGED_DEAD;
+ pane_call(p, "Free", p);
command_put(p->handle);
p->handle = NULL;
attr_free(&p->attrs);
return 0;
}
+DEF_EXTERN_CMD(edlib_do_free)
+{
+ free(ci->home->data);
+ ci->home->data= safe_cast NULL;
+ return 1;
+}
+
DEF_CMD(editor_on_idle)
{
/* register comm2 to be called when next idle. */
DEF_CMD(editor_close)
{
-
stat_free();
return 0;
}
+DEF_CMD(editor_free)
+{
+ /* Freeing the ed_info here mustn't happen. It must be
+ * done much later
+ */
+ return 1;
+}
+
void * safe memsave(struct pane *p safe, char *buf, int len)
{
struct ed_info *ei;
{
struct ed_info *ei = ed->data;
if (!ei) {
+ p->damaged &= ~DAMAGED_DEAD;
+ pane_call(p, "Free", p);
command_put(p->handle);
p->handle = NULL;
attr_free(&p->attrs);
key_add_prefix(ed_map, "editor:notify:",
&editor_send_notify);
key_add(ed_map, "Close", &editor_close);
+ key_add(ed_map, "Free", &editor_free);
}
ei->map = key_alloc();
key_add(ei->map, "on_idle-clean_up", &editor_clean_up);
/* If a child has not yet had "Close" called, we need to leave
* ->parent in place so a full range of commands are available.
*/
- // p->parent = p;
- p->damaged |= DAMAGED_DEAD;
- if (ed != p)
+ if (ed != p) {
+ p->damaged |= DAMAGED_DEAD;
editor_delayed_free(ed, p);
- else {
+ } else {
+ pane_call(p, "Free", p);
command_put(p->handle);
p->handle = NULL;
attr_free(&p->attrs);
static int _name ## _func(const struct cmd_info *ci safe)
#define REDEF_CMD(_name) \
static int _name ## _func(const struct cmd_info *ci safe)
+#define DEF_EXTERN_CMD(_name) \
+ static int _name ## _func(const struct cmd_info *ci safe); \
+ struct command _name = CMD(_name); \
+ static int _name ## _func(const struct cmd_info *ci safe)
+#define DECL_EXTERN_CMD(_name) \
+ extern struct command _name;
+
#define DEF_LOOKUP_CMD(_name, _map) \
static struct lookup_cmd _name = { { key_lookup_cmd_func, 0, NULL }, \
&_map};
+DECL_EXTERN_CMD(edlib_do_free);
+
int key_lookup_cmd_func(const struct cmd_info *ci safe);
struct pfx_cmd {
struct display_data *dd = p->data;
ncurses_end(p);
hash_free(dd);
- free(dd);
- p->data = safe_cast NULL;
return 1;
}
key_add(nc_map, "Display:close", &nc_close_display);
key_add(nc_map, "Display:set-noclose", &nc_set_noclose);
key_add(nc_map, "Close", &nc_close);
+ key_add(nc_map, "Free", &edlib_do_free);
key_add(nc_map, "pane-clear", &nc_clear);
key_add(nc_map, "text-size", &nc_text_size);
key_add(nc_map, "Draw:text", &nc_draw_text);
if (dr->rendering)
pane_close(dr->rendering);
doc_free(d);
- free(dr);
return 1;
}
key_add(doc_map, "get-attr", &dir_get_attr);
key_add(doc_map, "Notify:Close", &dir_notify_close);
key_add(doc_map, "Close", &dir_destroy);
+ key_add(doc_map, "Free", &edlib_do_free);
}
key_add(docs_map, "Notify:Close", &docs_notify_close);
key_add(docs_map, "get-attr", &docs_get_attr);
+ key_add(docs_map, "Free", &edlib_do_free);
key_add(docs_aux_map, "doc:revisit", &doc_revisit);
key_add(docs_aux_map, "doc:status-changed", &doc_damage);
struct email_info *ei = ci->home->data;
// ??? ;
call("doc:closed", ei->spacer);
- free(ei);
return 1;
}
char *invis safe;
};
-DEF_CMD(email_view_close)
+DEF_CMD(email_view_free)
{
struct email_view *evi = ci->home->data;
{
email_map = key_alloc();
key_add(email_map, "Close", &email_close);
+ key_add(email_map, "Free", &edlib_do_free);
key_add(email_map, "doc:email:render-spacer", &email_spacer);
key_add(email_map, "doc:email:select", &email_select);
key_add(email_map, "doc:get-attr", &email_get_attr);
email_view_map = key_alloc();
- key_add(email_view_map, "Close", &email_view_close);
+ key_add(email_view_map, "Free", &email_view_free);
key_add(email_view_map, "doc:step", &email_step);
key_add(email_view_map, "doc:set-ref", &email_set_ref);
key_add(email_view_map, "doc:set-attr", &email_view_set_attr);
for (i = 0; i < mpi->nparts; i++)
call("doc:closed", mpi->parts[i].pane);
doc_free(&mpi->doc);
+ return 1;
+}
+
+DEF_CMD(mp_free)
+{
+ struct mp_info *mpi = ci->home->data;
+
free(mpi->parts);
free(mpi);
return 1;
key_add(mp_map, "doc:set-attr", &mp_set_attr);
key_add(mp_map, "doc:step-part", &mp_step_part);
key_add(mp_map, "Close", &mp_close);
+ key_add(mp_map, "Free", &mp_free);
key_add(mp_map, "Notify:Close", &mp_notify_close);
key_add(mp_map, "doc:notify-viewers", &mp_notify_viewers);
key_add(mp_map, "multipart-add", &mp_add);
if (p)
home_call(p, "doc:del-view", ci->home, dri->vnum);
doc_free(d);
- free(dri);
- ci->home->data = safe_cast NULL;
return 1;
}
key_add(dr_map, "doc:set-ref", &dr_set_ref);
key_add(dr_map, "doc:step", &dr_step);
key_add(dr_map, "Close", &dr_close);
+ key_add(dr_map, "Free", &edlib_do_free);
key_add(dr_map, "doc:notify-viewers", &dr_notify_viewers);
key_add(dr_map, "doc:replaced", &dr_notify_replace);
key_add(dr_map, "Notify:Close", &dr_notify_close);
struct text *t = container_of(d, struct text, doc);
text_cleanout(t);
- free(t->fname);
doc_free(d);
+ return 1;
+}
+
+DEF_CMD(text_free)
+{
+ struct doc *d = ci->home->data;
+ struct text *t = container_of(d, struct text, doc);
+
+ free(t->fname);
free(t);
return 1;
}
key_add(text_map, "doc:revisit", &text_revisited);
key_add(text_map, "Close", &text_destroy);
+ key_add(text_map, "Free", &text_free);
key_add(text_map, "get-attr", &text_get_attr);
}
mark_free(n->m);
free(n);
}
- free(esi);
return 1;
}
key_add(es_map, "C-Chr-C", &search_add);
key_add(es_map, "C-Chr-R", &search_forward);
key_add(es_map, "Close", &search_close);
+ key_add(es_map, "Free", &edlib_do_free);
key_add(es_map, "Enter", &search_done);
key_add(es_map, "search:done", &search_done);
key_add(es_map, "doc:replaced", &search_again);
}
mark_free(hi->start);
mark_free(hi->end);
- free(hi);
+ hi->start = NULL;
+ hi->end = NULL;
return 0;
}
DEF_CMD(emacs_search_done)
key_add(m, "map-attr", &emacs_hl_attrs);
key_add(m, "Draw:text", &highlight_draw);
key_add(m, "Close", &emacs_highlight_close);
+ key_add(m, "Free", &edlib_do_free);
key_add(m, "Abort", &emacs_highlight_abort);
key_add(m, "Notify:clip", &emacs_highlight_clip);
key_add(m, "highlight:set-popup", &emacs_highlight_set_popup);
while ((m = vmark_first(ci->home, bi->view, ci->home)) != NULL)
mark_free(m);
call("doc:del-view", ci->home, bi->view);
- free(bi);
return 1;
}
key_add(b64_map, "doc:step", &base64_step);
key_add(b64_map, "Close", &b64_close);
+ key_add(b64_map, "Free", &edlib_do_free);
key_add(b64_map, "Notify:clip", &b64_clip);
call_comm("global-set-command", ed, &b64_attach, 0, NULL, "attach-base64");
free(t);
}
-DEF_CMD(copy_close)
+DEF_CMD(copy_free)
{
struct copy_info *cyi = ci->home->data;
if (!copy_map) {
copy_map = key_alloc();
- key_add(copy_map, "Close", ©_close);
+ key_add(copy_map, "Free", ©_free);
}
cyi->pane = pane_register(ed, 0, ©_handle.c, cyi);
mark_free(cd->start);
mark_free(cd->end);
- free(cd);
return 1;
}
crop_map = key_alloc();
key_add_prefix(crop_map, "doc:", &crop_generic);
key_add(crop_map, "Close", &crop_close);
+ key_add(crop_map, "Free", &edlib_do_free);
key_add(crop_map, "doc:write_file", &crop_write);
key_add(crop_map, "doc:step", &crop_step);
key_add(crop_map, "Notify:clip", &crop_clip);
if (hi->history)
pane_close(hi->history);
+ return 1;
+}
+
+DEF_CMD(history_free)
+{
+ struct history_info *hi = ci->home->data;
+
free(hi->search.b);
free(hi->saved);
free(hi);
ci->home->data = safe_cast NULL;
+ /* handle was in 'hi' */
+ ci->home->handle = NULL;
return 1;
}
history_map = key_alloc();
key_add(history_map, "Close", &history_close);
+ key_add(history_map, "Free", &history_free);
key_add(history_map, "Notify:Close", &history_notify_close);
key_add(history_map, "doc:replaced", &history_notify_replace);
key_add(history_map, "M-Chr-p", &history_move);
key_add(im_map, "Notify:Close", &close_focus);
key_add_prefix(im_map, "window:request:", &request_notify);
key_add_prefix(im_map, "window:notify:", &send_notify);
+ key_add(im_map, "Free", &edlib_do_free);
}
DEF_LOOKUP_CMD(input_handle, im_map);
command_put(kd->cmds[i]);
free(kd->cmds);
}
+ return 1;
+ }
+ if (strcmp(ci->key, "Free") == 0) {
free(kd);
+ ci->home->data = safe_cast NULL;
return 1;
}
if (strcmp(ci->key, "Clone") == 0) {
return;
libevent_map = key_alloc();
key_add(libevent_map, "Notify:Close", &libevent_notify);
+ key_add(libevent_map, "Free", &edlib_do_free);
}
while ((m = vmark_first(d, cli->view_num, ci->home)) != NULL)
mark_free(m);
home_call(d, "doc:del-view", ci->home, cli->view_num);
- free(cli);
- ci->home->data = safe_cast NULL;
pane_close(ci->home);
return 1;
}
key_add(linecount_map, "doc:CountLines", &linecount_notify_count);
key_add(linecount_map, "doc:GotoLine", &linecount_notify_goto);
key_add(linecount_map, "Notify:clip", &linecount_clip);
+ key_add(linecount_map, "Free", &edlib_do_free);
}
return;
messageline_map = key_alloc();
key_add(messageline_map, "Clone", &messageline_clone);
+ key_add(messageline_map, "Free", &edlib_do_free);
key_add(messageline_map, "Display:border", &messageline_border);
key_add(messageline_map, "Message", &messageline_msg);
key_add(messageline_map, "Message:modal", &messageline_msg);
DEF_CMD(popup_close)
{
struct popup_info *ppi = ci->home->data;
+
command_put(ppi->done);
+ ppi->done = NULL;
+ return 1;
+}
+
+DEF_CMD(popup_free)
+{
+ struct popup_info *ppi = ci->home->data;
+
free(ppi->style);
free(ppi);
return 1;
popup_map = key_alloc();
key_add(popup_map, "Close", &popup_close);
+ key_add(popup_map, "Free", &popup_free);
key_add(popup_map, "Notify:Close", &popup_notify_close);
key_add(popup_map, "Abort", &popup_abort);
key_add(popup_map, "popup:style", &popup_style);
qp_map = key_alloc();
key_add(qp_map, "doc:step", &qp_step);
+ key_add(qp_map, "Free", &edlib_do_free);
call_comm("global-set-command", ed, &qp_attach, 0, NULL, "attach-quoted_printable");
call_comm("global-set-command", ed, &qp_attach, 0, NULL, "attach-qprint");
while ((m = vmark_first(p, rl->view, p)) != NULL)
mark_free(m);
call("doc:del-view", p, rl->view);
- free(rl);
- p->data = safe_cast NULL;
- p->handle = NULL;
return 0;
}
key_add(rl_map, "doc:render-line-prev", &render_prev);
key_add(rl_map, "Clone", &rl_clone);
key_add(rl_map, "Close", &rl_close);
+ key_add(rl_map, "Free", &edlib_do_free);
key_add(rl_map, "Notify:clip", &rl_clip);
call_comm("global-set-command", ed, &renderline_attach, 0, NULL, "attach-renderline");
while ((m = vmark_first(p, hi->vnum, p)) != NULL)
mark_free(m);
call("doc:del-view", p, hi->vnum);
- p->data = safe_cast NULL;
- free(hi);
return 1;
}
{
header_map = key_alloc();
key_add(header_map, "Close", &header_close);
+ key_add(header_map, "Free", &edlib_do_free);
key_add(header_map, "get-header", &header_get);
key_add(header_map, "Notify:clip", &header_clip);
}
return 0;
}
+DEF_CMD(tile_free)
+{
+ struct tileinfo *ti = ci->home->data;
+
+ free(ti->name);
+ free(ti);
+ return 1;
+}
+
DEF_CMD(tile_refresh_size)
{
struct pane *p = ci->home;
if (ti->direction == Neither) {
/* Children have already been destroyed, just clean up */
- free(ti->group);
free(ti->name);
- free(ti);
return 1;
}
if (p->parent == p) {
/* subsumed husk being destroyed */
- free(ti->name);
- free(ti);
return 1;
}
tile_adjust(prev);
}
list_del(&ti->tiles);
- free(ti->name);
- free(ti);
if (remaining == 1 && remain->parent != remain) {
struct tileinfo *ti2;
enum dir tmp;
key_add(tile_map, "ChildRegistered", &tile_child_registered);
key_add(tile_map, "ChildReplaced", &tile_child_replaced);
key_add(tile_map, "Close", &tile_close);
+ key_add(tile_map, "Free", &tile_free);
key_add(tile_map, "Refresh:size", &tile_refresh_size);
call_comm("global-set-command", ed, &tile_attach, 0, NULL, "attach-tile");
if (vd->viewpoint)
mark_free(vd->viewpoint);
- free(vd);
return 1;
}
key_add(view_map, "Window:border", &view_border);
key_add(view_map, "Refresh:view", &view_refresh_view);
key_add(view_map, "Close", &view_close);
+ key_add(view_map, "Free", &edlib_do_free);
key_add(view_map, "Clone", &view_clone);
key_add(view_map, "ChildRegistered", &view_child_registered);
key_add(view_map, "Refresh:size", &view_refresh_size);
mark_free(ws->mymark);
ws->mymark = NULL;
- free(ws);
- ci->home->data = safe_cast NULL;
return 1;
}
key_add(ws_map, "map-attr", &ws_attrs);
key_add(ws_map, "Close", &ws_close);
+ key_add(ws_map, "Free", &edlib_do_free);
key_add(ws_map, "Clone", &ws_clone);
call_comm("global-set-command", ed, &whitespace_attach,
0, NULL, "attach-whitespace");
return do_render_complete_prev(cd, ci->mark, ci->home->parent, ci->num, NULL);
}
-DEF_CMD(complete_close)
+DEF_CMD(complete_free)
{
struct complete_data *cd = ci->home->data;
key_add(rc_map, "doc:render-line", &render_complete_line);
key_add(rc_map, "doc:render-line-prev", &render_complete_prev);
- key_add(rc_map, "Close", &complete_close);
+ key_add(rc_map, "Free", &complete_free);
key_add(rc_map, "Clone", &complete_clone);
key_add(rc_map, "Replace", &complete_ignore_replace);
return 1;
}
-DEF_CMD(format_close)
-{
- struct rf_data *rl = ci->home->data;
- free(rl);
- return 1;
-}
-
static struct pane *do_render_format_attach(struct pane *parent, int nolines);
DEF_CMD(format_clone)
{
key_add(rf_map, "doc:render-line", &render_line);
key_add(rf_map, "doc:render-line-prev", &render_line_prev);
- key_add(rf_map, "Close", &format_close);
key_add(rf_map, "Clone", &format_clone);
key_add(rf_map, "doc:get-attr", &format_get_attr);
key_add(rf_map, "doc:content", &format_content);
+ key_add(rf_map, "Free", &edlib_do_free);
}
DEF_LOOKUP_CMD(render_format_handle, rf_map);
struct he_data *he = p->data;
he->pane = NULL;
- p->data = safe_cast NULL;
- p->handle = NULL;
- free(he);
return 1;
}
key_add(he_map, "doc:render-line", &render_line);
key_add(he_map, "Close", &render_hex_close);
+ key_add(he_map, "Free", &edlib_do_free);
key_add(he_map, "Clone", &render_hex_clone);
key_add(he_map, "doc:replaced", &render_hex_notify_replace);
}
call("doc:del-view", p, rl->typenum);
mark_free(rl->old_point);
- p->data = safe_cast NULL;
- p->handle = NULL;
- free(rl);
return 0;
}
key_add(rl_map, "Abort", &render_lines_abort);
key_add(rl_map, "Close", &render_lines_close);
+ key_add(rl_map, "Free", &edlib_do_free);
key_add(rl_map, "Clone", &render_lines_clone);
key_add(rl_map, "Refresh", &render_lines_refresh);
key_add(rl_map, "Refresh:view", &render_lines_refresh_view);