diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c index 5b66dbee..eef2978e 100644 --- a/cmd-set-buffer.c +++ b/cmd-set-buffer.c @@ -57,14 +57,12 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item) { struct args *args = cmd_get_args(self); struct client *tc = cmdq_get_target_client(item); - struct paste_buffer *pb; - char *bufname, *bufdata = NULL, *cause = NULL; + struct paste_buffer *pb = NULL; + char *bufname = NULL, *bufdata = NULL, *cause = NULL; const char *olddata; size_t bufsize = 0, newsize; - if (args_get(args, 'b') == NULL) - pb = NULL; - else { + if (args_get(args, 'b') != NULL) { bufname = xstrdup(args_get(args, 'b')); pb = paste_get_name(bufname); } diff --git a/control-notify.c b/control-notify.c index 30f94194..ba6a8355 100644 --- a/control-notify.c +++ b/control-notify.c @@ -51,29 +51,24 @@ control_notify_window_layout_changed(struct window *w) template = "%layout-change #{window_id} #{window_layout} " "#{window_visible_layout} #{window_raw_flags}"; + /* + * When the last pane in a window is closed it won't have a layout root + * and we don't need to inform the client about the layout change + * because the whole window will go away soon. + */ + wl = TAILQ_FIRST(&w->winlinks); + if (wl == NULL || w->layout_root == NULL) + return; + cp = format_single(NULL, template, NULL, NULL, wl, NULL); + TAILQ_FOREACH(c, &clients, entry) { if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) continue; s = c->session; - - if (winlink_find_by_window_id(&s->windows, w->id) == NULL) - continue; - - /* - * When the last pane in a window is closed it won't have a - * layout root and we don't need to inform the client about the - * layout change because the whole window will go away soon. - */ - if (w->layout_root == NULL) - continue; - - wl = winlink_find_by_window(&s->windows, w); - if (wl != NULL) { - cp = format_single(NULL, template, c, NULL, wl, NULL); + if (winlink_find_by_window_id(&s->windows, w->id) != NULL) control_write(c, "%s", cp); - free(cp); - } } + free(cp); } void diff --git a/control.c b/control.c index c3bedde8..35f960d2 100644 --- a/control.c +++ b/control.c @@ -846,15 +846,13 @@ control_stop(struct client *c) /* Check session subscription. */ static void -control_check_subs_session(struct client *c, struct control_sub *csub) +control_check_subs_session(struct client *c, struct control_sub *csub, + struct format_tree *ft) { struct session *s = c->session; - struct format_tree *ft; char *value; - ft = format_create_defaults(NULL, c, s, NULL, NULL); value = format_expand(ft, csub->format); - format_free(ft); if (csub->last != NULL && strcmp(value, csub->last) == 0) { free(value); @@ -915,48 +913,38 @@ control_check_subs_pane(struct client *c, struct control_sub *csub) } } -/* Check all panes subscription. */ +/* Check all-panes subscription for a pane. */ static void -control_check_subs_all_panes(struct client *c, struct control_sub *csub) +control_check_subs_all_panes_one(struct client *c, struct control_sub *csub, + struct format_tree *ft, struct winlink *wl, struct window_pane *wp) { struct session *s = c->session; - struct window_pane *wp; - struct window *w; - struct winlink *wl; - struct format_tree *ft; + struct window *w = wl->window; char *value; struct control_sub_pane *csp, find; - RB_FOREACH(wl, winlinks, &s->windows) { - w = wl->window; - TAILQ_FOREACH(wp, &w->panes, entry) { - ft = format_create_defaults(NULL, c, s, wl, wp); - value = format_expand(ft, csub->format); - format_free(ft); + value = format_expand(ft, csub->format); - find.pane = wp->id; - find.idx = wl->idx; + find.pane = wp->id; + find.idx = wl->idx; - csp = RB_FIND(control_sub_panes, &csub->panes, &find); - if (csp == NULL) { - csp = xcalloc(1, sizeof *csp); - csp->pane = wp->id; - csp->idx = wl->idx; - RB_INSERT(control_sub_panes, &csub->panes, csp); - } - - if (csp->last != NULL && - strcmp(value, csp->last) == 0) { - free(value); - continue; - } - control_write(c, - "%%subscription-changed %s $%u @%u %u %%%u : %s", - csub->name, s->id, w->id, wl->idx, wp->id, value); - free(csp->last); - csp->last = value; - } + csp = RB_FIND(control_sub_panes, &csub->panes, &find); + if (csp == NULL) { + csp = xcalloc(1, sizeof *csp); + csp->pane = wp->id; + csp->idx = wl->idx; + RB_INSERT(control_sub_panes, &csub->panes, csp); } + + if (csp->last != NULL && strcmp(value, csp->last) == 0) { + free(value); + return; + } + control_write(c, + "%%subscription-changed %s $%u @%u %u %%%u : %s", + csub->name, s->id, w->id, wl->idx, wp->id, value); + free(csp->last); + csp->last = value; } /* Check window subscription. */ @@ -1005,45 +993,38 @@ control_check_subs_window(struct client *c, struct control_sub *csub) } } -/* Check all windows subscription. */ +/* Check all-windows subscription for a window. */ static void -control_check_subs_all_windows(struct client *c, struct control_sub *csub) +control_check_subs_all_windows_one(struct client *c, struct control_sub *csub, + struct format_tree *ft, struct winlink *wl) { struct session *s = c->session; - struct window *w; - struct winlink *wl; - struct format_tree *ft; + struct window *w = wl->window; char *value; struct control_sub_window *csw, find; - RB_FOREACH(wl, winlinks, &s->windows) { - w = wl->window; + value = format_expand(ft, csub->format); - ft = format_create_defaults(NULL, c, s, wl, NULL); - value = format_expand(ft, csub->format); - format_free(ft); + find.window = w->id; + find.idx = wl->idx; - find.window = w->id; - find.idx = wl->idx; - - csw = RB_FIND(control_sub_windows, &csub->windows, &find); - if (csw == NULL) { - csw = xcalloc(1, sizeof *csw); - csw->window = w->id; - csw->idx = wl->idx; - RB_INSERT(control_sub_windows, &csub->windows, csw); - } - - if (csw->last != NULL && strcmp(value, csw->last) == 0) { - free(value); - continue; - } - control_write(c, - "%%subscription-changed %s $%u @%u %u - : %s", - csub->name, s->id, w->id, wl->idx, value); - free(csw->last); - csw->last = value; + csw = RB_FIND(control_sub_windows, &csub->windows, &find); + if (csw == NULL) { + csw = xcalloc(1, sizeof *csw); + csw->window = w->id; + csw->idx = wl->idx; + RB_INSERT(control_sub_windows, &csub->windows, csw); } + + if (csw->last != NULL && strcmp(value, csw->last) == 0) { + free(value); + return; + } + control_write(c, + "%%subscription-changed %s $%u @%u %u - : %s", + csub->name, s->id, w->id, wl->idx, value); + free(csw->last); + csw->last = value; } /* Check subscriptions timer. */ @@ -1053,30 +1034,91 @@ control_check_subs_timer(__unused int fd, __unused short events, void *data) struct client *c = data; struct control_state *cs = c->control_state; struct control_sub *csub, *csub1; + struct session *s = c->session; + struct format_tree *ft; + struct winlink *wl; + struct window_pane *wp; struct timeval tv = { .tv_sec = 1 }; + int have_session = 0, have_all_panes = 0; + int have_all_windows = 0; log_debug("%s: timer fired", __func__); evtimer_add(&cs->subs_timer, &tv); - RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1) { + /* Find which subscription types are present. */ + RB_FOREACH(csub, control_subs, &cs->subs) { switch (csub->type) { case CONTROL_SUB_SESSION: - control_check_subs_session(c, csub); - break; - case CONTROL_SUB_PANE: - control_check_subs_pane(c, csub); + have_session = 1; break; case CONTROL_SUB_ALL_PANES: - control_check_subs_all_panes(c, csub); + have_all_panes = 1; + break; + case CONTROL_SUB_ALL_WINDOWS: + have_all_windows = 1; + break; + default: + break; + } + } + + /* Check session subscriptions. */ + if (have_session) { + ft = format_create_defaults(NULL, c, s, NULL, NULL); + RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1) { + if (csub->type == CONTROL_SUB_SESSION) + control_check_subs_session(c, csub, ft); + } + format_free(ft); + } + + /* Check pane and window subscriptions. */ + RB_FOREACH_SAFE(csub, control_subs, &cs->subs, csub1) { + switch (csub->type) { + case CONTROL_SUB_PANE: + control_check_subs_pane(c, csub); break; case CONTROL_SUB_WINDOW: control_check_subs_window(c, csub); break; + case CONTROL_SUB_SESSION: + case CONTROL_SUB_ALL_PANES: case CONTROL_SUB_ALL_WINDOWS: - control_check_subs_all_windows(c, csub); break; } } + + /* Check all-panes subscriptions. */ + if (have_all_panes) { + RB_FOREACH(wl, winlinks, &s->windows) { + TAILQ_FOREACH(wp, &wl->window->panes, entry) { + ft = format_create_defaults(NULL, c, s, wl, wp); + RB_FOREACH_SAFE(csub, control_subs, &cs->subs, + csub1) { + if (csub->type != CONTROL_SUB_ALL_PANES) + continue; + control_check_subs_all_panes_one(c, + csub, ft, wl, wp); + } + format_free(ft); + } + } + } + + /* Check all-windows subscriptions. */ + if (have_all_windows) { + RB_FOREACH(wl, winlinks, &s->windows) { + ft = format_create_defaults(NULL, c, s, wl, NULL); + RB_FOREACH_SAFE(csub, control_subs, &cs->subs, + csub1) { + if (csub->type != CONTROL_SUB_ALL_WINDOWS) + continue; + control_check_subs_all_windows_one(c, csub, ft, + wl); + } + format_free(ft); + } + } } /* Add a subscription. */ diff --git a/grid.c b/grid.c index c783f7b7..28a15d77 100644 --- a/grid.c +++ b/grid.c @@ -205,11 +205,17 @@ grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg) struct grid_line *gl = &gd->linedata[py]; struct grid_cell_entry *gce = &gl->celldata[px]; struct grid_extd_entry *gee; + u_int old_offset = gce->offset; + int had_extd = (gce->flags & GRID_FLAG_EXTENDED); memcpy(gce, &grid_cleared_entry, sizeof *gce); if (bg != 8) { if (bg & COLOUR_FLAG_RGB) { - grid_get_extended_cell(gl, gce, gce->flags); + if (had_extd && old_offset < gl->extdsize) { + gce->flags |= GRID_FLAG_EXTENDED; + gce->offset = old_offset; + } else + grid_get_extended_cell(gl, gce, gce->flags); gee = grid_extended_cell(gl, gce, &grid_cleared_cell); gee->bg = bg; } else { @@ -1089,12 +1095,16 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, off = 0; gl = grid_peek_line(gd, py); + if (gl == NULL) { + buf[0] = '\0'; + return (buf); + } if (flags & GRID_STRING_EMPTY_CELLS) end = gl->cellsize; else end = gl->cellused; for (xx = px; xx < px + nx; xx++) { - if (gl == NULL || xx >= end) + if (xx >= end) break; grid_get_cell(gd, xx, py, &gc); if (gc.flags & GRID_FLAG_PADDING) diff --git a/window-copy.c b/window-copy.c index f3a8507d..c4f10b37 100644 --- a/window-copy.c +++ b/window-copy.c @@ -355,7 +355,7 @@ window_copy_clone_screen(struct screen *src, struct screen *hint, u_int *cx, if (trim) { while (sy > screen_hsize(src)) { gl = grid_peek_line(src->grid, sy - 1); - if (gl->cellused != 0) + if (gl == NULL || gl->cellused != 0) break; sy--; } @@ -3625,6 +3625,10 @@ window_copy_stringify(struct grid *gd, u_int py, u_int first, u_int last, buf = xrealloc(buf, bufsize); gl = grid_peek_line(gd, py); + if (gl == NULL) { + buf[*size - 1] = '\0'; + return (buf); + } bx = *size - 1; for (ax = first; ax < last; ax++) { d = window_copy_cellstring(gl, ax, &dlen, &allocated); @@ -3670,6 +3674,10 @@ window_copy_cstrtocellpos(struct grid *gd, u_int ncells, u_int *ppx, u_int *ppy, px = *ppx; pywrap = *ppy; gl = grid_peek_line(gd, pywrap); + if (gl == NULL) { + free(cells); + return; + } while (cell < ncells) { cells[cell].d = window_copy_cellstring(gl, px, &cells[cell].dlen, &cells[cell].allocated); @@ -3679,6 +3687,8 @@ window_copy_cstrtocellpos(struct grid *gd, u_int ncells, u_int *ppx, u_int *ppy, px = 0; pywrap++; gl = grid_peek_line(gd, pywrap); + if (gl == NULL) + break; } } @@ -4080,7 +4090,7 @@ window_copy_visible_lines(struct window_copy_mode_data *data, u_int *start, for (*start = gd->hsize - data->oy; *start > 0; (*start)--) { gl = grid_peek_line(gd, (*start) - 1); - if (~gl->flags & GRID_LINE_WRAPPED) + if (gl == NULL || ~gl->flags & GRID_LINE_WRAPPED) break; } *end = gd->hsize - data->oy + gd->sy;