diff --git a/cmd-set-buffer.c b/cmd-set-buffer.c index 0b0ec3a2..eef2978e 100644 --- a/cmd-set-buffer.c +++ b/cmd-set-buffer.c @@ -57,30 +57,30 @@ 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 *bufdata, *cause; - const char *bufname, *olddata; - size_t bufsize, newsize; + struct paste_buffer *pb = NULL; + char *bufname = NULL, *bufdata = NULL, *cause = NULL; + const char *olddata; + size_t bufsize = 0, newsize; - bufname = args_get(args, 'b'); - if (bufname == NULL) - pb = NULL; - else + if (args_get(args, 'b') != NULL) { + bufname = xstrdup(args_get(args, 'b')); pb = paste_get_name(bufname); + } if (cmd_get_entry(self) == &cmd_delete_buffer_entry) { if (pb == NULL) { if (bufname != NULL) { cmdq_error(item, "unknown buffer: %s", bufname); - return (CMD_RETURN_ERROR); + goto fail; } pb = paste_get_top(&bufname); } if (pb == NULL) { cmdq_error(item, "no buffer"); - return (CMD_RETURN_ERROR); + goto fail; } paste_free(pb); + free(bufname); return (CMD_RETURN_NORMAL); } @@ -88,32 +88,28 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item) if (pb == NULL) { if (bufname != NULL) { cmdq_error(item, "unknown buffer: %s", bufname); - return (CMD_RETURN_ERROR); + goto fail; } pb = paste_get_top(&bufname); } if (pb == NULL) { cmdq_error(item, "no buffer"); - return (CMD_RETURN_ERROR); + goto fail; } if (paste_rename(bufname, args_get(args, 'n'), &cause) != 0) { cmdq_error(item, "%s", cause); - free(cause); - return (CMD_RETURN_ERROR); + goto fail; } return (CMD_RETURN_NORMAL); } if (args_count(args) != 1) { cmdq_error(item, "no data specified"); - return (CMD_RETURN_ERROR); + goto fail; } if ((newsize = strlen(args_string(args, 0))) == 0) return (CMD_RETURN_NORMAL); - bufsize = 0; - bufdata = NULL; - if (args_has(args, 'a') && pb != NULL) { olddata = paste_buffer_data(pb, &bufsize); bufdata = xmalloc(bufsize); @@ -126,12 +122,16 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item) if (paste_set(bufdata, bufsize, bufname, &cause) != 0) { cmdq_error(item, "%s", cause); - free(bufdata); - free(cause); - return (CMD_RETURN_ERROR); + goto fail; } if (args_has(args, 'w') && tc != NULL) tty_set_selection(&tc->tty, "", bufdata, bufsize); return (CMD_RETURN_NORMAL); + +fail: + free(bufdata); + free(bufname); + free(cause); + return (CMD_RETURN_ERROR); } 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 578d04cb..35f960d2 100644 --- a/control.c +++ b/control.c @@ -610,7 +610,7 @@ control_append_data(struct client *c, struct control_pane *cp, uint64_t age, struct evbuffer *message, struct window_pane *wp, size_t size) { u_char *new_data; - size_t new_size; + size_t new_size, start; u_int i; if (message == NULL) { @@ -629,10 +629,16 @@ control_append_data(struct client *c, struct control_pane *cp, uint64_t age, if (new_size < size) fatalx("not enough data: %zu < %zu", new_size, size); for (i = 0; i < size; i++) { - if (new_data[i] < ' ' || new_data[i] == '\\') + if (new_data[i] < ' ' || new_data[i] == '\\') { evbuffer_add_printf(message, "\\%03o", new_data[i]); - else - evbuffer_add_printf(message, "%c", new_data[i]); + } else { + start = i; + while (i + 1 < size && + new_data[i + 1] >= ' ' && + new_data[i + 1] != '\\') + i++; + evbuffer_add(message, new_data + start, i - start + 1); + } } window_pane_update_used_data(wp, &cp->offset, size); return (message); @@ -840,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); @@ -909,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. */ @@ -999,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. */ @@ -1047,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/format.c b/format.c index d955e982..223f624b 100644 --- a/format.c +++ b/format.c @@ -2012,8 +2012,10 @@ format_cb_pane_bottom(struct format_tree *ft) static void * format_cb_pane_dead(struct format_tree *ft) { - if (ft->wp != NULL) { - if (ft->wp->fd == -1) + struct window_pane *wp = ft->wp; + + if (wp != NULL) { + if (wp->fd == -1 && (wp->flags & PANE_STATUSREADY)) return (xstrdup("1")); return (xstrdup("0")); } 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/input.c b/input.c index 0dbc0b2f..a248e6b3 100644 --- a/input.c +++ b/input.c @@ -101,6 +101,7 @@ struct input_ctx { struct bufferevent *event; struct screen_write_ctx ctx; struct colour_palette *palette; + struct client *c; struct input_cell cell; struct input_cell old_cell; @@ -854,7 +855,7 @@ input_restore_state(struct input_ctx *ictx) /* Initialise input parser. */ struct input_ctx * input_init(struct window_pane *wp, struct bufferevent *bev, - struct colour_palette *palette) + struct colour_palette *palette, struct client *c) { struct input_ctx *ictx; @@ -862,6 +863,7 @@ input_init(struct window_pane *wp, struct bufferevent *bev, ictx->wp = wp; ictx->event = bev; ictx->palette = palette; + ictx->c = c; ictx->input_space = INPUT_BUF_START; ictx->input_buf = xmalloc(INPUT_BUF_START); @@ -3110,31 +3112,28 @@ input_osc_52_reply(struct input_ctx *ictx) input_add_request(ictx, INPUT_REQUEST_CLIPBOARD, ictx->input_end); } -/* Handle the OSC 52 sequence for setting the clipboard. */ -static void -input_osc_52(struct input_ctx *ictx, const char *p) +/* + * Parse and decode OSC 52 clipboard data. Returns 0 on failure or if handled + * as a query. On success, returns 1 and sets *out, *outlen, and *flags (caller + * must free *out). + */ +static int +input_osc_52_parse(struct input_ctx *ictx, const char *p, u_char **out, + int *outlen, char *flags) { - struct window_pane *wp = ictx->wp; - size_t len; - char *end; - u_char *out; - int outlen, state; - struct screen_write_ctx ctx; - const char* allow = "cpqs01234567"; - char flags[sizeof "cpqs01234567"] = ""; - u_int i, j = 0; + char *end; + size_t len; + const char *allow = "cpqs01234567"; + u_int i, j = 0; - if (wp == NULL) - return; - state = options_get_number(global_options, "set-clipboard"); - if (state != 2) - return; + if (options_get_number(global_options, "set-clipboard") != 2) + return (0); if ((end = strchr(p, ';')) == NULL) - return; + return (0); end++; if (*end == '\0') - return; + return (0); log_debug("%s: %s", __func__, end); for (i = 0; p + i != end; i++) { @@ -3145,25 +3144,53 @@ input_osc_52(struct input_ctx *ictx, const char *p) if (strcmp(end, "?") == 0) { input_osc_52_reply(ictx); - return; + return (0); } len = (strlen(end) / 4) * 3; if (len == 0) - return; + return (0); - out = xmalloc(len); - if ((outlen = b64_pton(end, out, len)) == -1) { - free(out); - return; + *out = xmalloc(len); + if ((*outlen = b64_pton(end, *out, len)) == -1) { + free(*out); + *out = NULL; + return (0); } - screen_write_start_pane(&ctx, wp, NULL); - screen_write_setselection(&ctx, flags, out, outlen); - screen_write_stop(&ctx); - notify_pane("pane-set-clipboard", wp); + return (1); +} - paste_add(NULL, out, outlen); +/* Handle the OSC 52 sequence for setting the clipboard. */ +static void +input_osc_52(struct input_ctx *ictx, const char *p) +{ + struct window_pane *wp = ictx->wp; + struct screen_write_ctx ctx; + u_char *out; + int outlen; + char flags[sizeof "cpqs01234567"] = ""; + + if (!input_osc_52_parse(ictx, p, &out, &outlen, flags)) + return; + + if (wp == NULL) { + /* Popup window. */ + if (ictx->c == NULL) { + free(out); + return; + } + tty_set_selection(&ictx->c->tty, flags, out, outlen); + paste_add(NULL, out, outlen); + } else { + /* Normal window. */ + screen_write_start_pane(&ctx, wp, NULL); + screen_write_setselection(&ctx, flags, out, outlen); + screen_write_stop(&ctx); + notify_pane("pane-set-clipboard", wp); + paste_add(NULL, out, outlen); + } + free(out); } /* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */ @@ -3434,7 +3461,7 @@ input_cancel_requests(struct client *c) { struct input_request *ir, *ir1; - TAILQ_FOREACH_SAFE(ir, &c->input_requests, entry, ir1) + TAILQ_FOREACH_SAFE(ir, &c->input_requests, centry, ir1) input_free_request(ir); } diff --git a/key-bindings.c b/key-bindings.c index 1fa568f3..3bcef706 100644 --- a/key-bindings.c +++ b/key-bindings.c @@ -297,12 +297,12 @@ key_bindings_remove_table(const char *name) table = key_bindings_get_table(name, 0); if (table != NULL) { RB_REMOVE(key_tables, &key_tables, table); + TAILQ_FOREACH(c, &clients, entry) { + if (c->keytable == table) + server_client_set_key_table(c, NULL); + } key_bindings_unref_table(table); } - TAILQ_FOREACH(c, &clients, entry) { - if (c->keytable == table) - server_client_set_key_table(c, NULL); - } } void diff --git a/paste.c b/paste.c index ff73aaa8..7eda6ada 100644 --- a/paste.c +++ b/paste.c @@ -106,7 +106,7 @@ paste_is_empty(void) /* Get the most recent automatic buffer. */ struct paste_buffer * -paste_get_top(const char **name) +paste_get_top(char **name) { struct paste_buffer *pb; @@ -116,7 +116,7 @@ paste_get_top(const char **name) if (pb == NULL) return (NULL); if (name != NULL) - *name = pb->name; + *name = xstrdup(pb->name); return (pb); } diff --git a/popup.c b/popup.c index ff9b07c1..d4100998 100644 --- a/popup.c +++ b/popup.c @@ -850,7 +850,7 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px, pd->job = job_run(shellcmd, argc, argv, env, s, cwd, popup_job_update_cb, popup_job_complete_cb, NULL, pd, JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE|JOB_DEFAULTSHELL, jx, jy); - pd->ictx = input_init(NULL, job_get_event(pd->job), &pd->palette); + pd->ictx = input_init(NULL, job_get_event(pd->job), &pd->palette, c); server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb, popup_draw_cb, popup_key_cb, popup_free_cb, popup_resize_cb, pd); diff --git a/resize.c b/resize.c index 9a61c300..6cbc938d 100644 --- a/resize.c +++ b/resize.c @@ -250,7 +250,7 @@ skip: /* Return whether a suitable size was found. */ if (type == WINDOW_SIZE_MANUAL) { log_debug("%s: type is manual", __func__); - return (1); + return (w != NULL); } if (type == WINDOW_SIZE_LARGEST) { log_debug("%s: type is largest", __func__); diff --git a/server-client.c b/server-client.c index ab5bb346..bf6c5fb9 100644 --- a/server-client.c +++ b/server-client.c @@ -2743,18 +2743,31 @@ server_client_handle_key(struct client *c, struct key_event *event) void server_client_loop(void) { - struct client *c; - struct window *w; - struct window_pane *wp; + struct client *c; + struct window *w; + struct window_pane *wp; + struct window_mode_entry *wme; /* Check for window resize. This is done before redrawing. */ RB_FOREACH(w, windows, &windows) server_client_check_window_resize(w); + /* Notify modes that pane styles may have changed. */ + RB_FOREACH(w, windows, &windows) { + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->flags & PANE_STYLECHANGED) { + wme = TAILQ_FIRST(&wp->modes); + if (wme != NULL && + wme->mode->style_changed != NULL) + wme->mode->style_changed(wme); + } + } + } + /* Check clients. */ TAILQ_FOREACH(c, &clients, entry) { server_client_check_exit(c); - if (c->session != NULL) { + if (c->session != NULL && c->session->curw != NULL) { server_client_check_modes(c); server_client_check_redraw(c); server_client_reset_state(c); diff --git a/sort.c b/sort.c index a1d85891..fb3f89ee 100644 --- a/sort.c +++ b/sort.c @@ -197,23 +197,25 @@ sort_pane_cmp(const void *a0, const void *b0) case SORT_CREATION: result = a->id - b->id; break; - case SORT_INDEX: - case SORT_NAME: - case SORT_ORDER: case SORT_SIZE: - case SORT_END: + result = a->sx * a->sy - b->sx * b->sy; break; - } - if (result == 0) { - /* - * Panes don't have names, so use number order for any other - * sort field. - */ + case SORT_INDEX: window_pane_index(a, &ai); window_pane_index(b, &bi); result = ai - bi; + break; + case SORT_NAME: + result = strcmp(a->screen->title, b->screen->title); + break; + case SORT_ORDER: + case SORT_END: + break; } + if (result == 0) + result = strcmp(a->screen->title, b->screen->title); + if (sort_crit->reversed) result = -result; return (result); @@ -235,6 +237,16 @@ sort_winlink_cmp(const void *a0, const void *b0) case SORT_INDEX: result = wla->idx - wlb->idx; break; + case SORT_CREATION: + if (timercmp(&wa->creation_time, &wb->creation_time, >)) { + result = -1; + break; + } + if (timercmp(&wa->creation_time, &wb->creation_time, <)) { + result = 1; + break; + } + break; case SORT_ACTIVITY: if (timercmp(&wa->activity_time, &wb->activity_time, >)) { result = -1; @@ -248,9 +260,10 @@ sort_winlink_cmp(const void *a0, const void *b0) case SORT_NAME: result = strcmp(wa->name, wb->name); break; - case SORT_CREATION: - case SORT_ORDER: case SORT_SIZE: + result = wa->sx * wa->sy - wb->sx * wb->sy; + break; + case SORT_ORDER: case SORT_END: break; } @@ -295,7 +308,8 @@ sort_order_from_string(const char* order) return (SORT_CREATION); if (strcasecmp(order, "index") == 0) return (SORT_INDEX); - if (strcasecmp(order, "name") == 0) + if (strcasecmp(order, "name") == 0 || + strcasecmp(order, "title") == 0) return (SORT_NAME); if (strcasecmp(order, "order") == 0) return (SORT_ORDER); diff --git a/tmux.1 b/tmux.1 index d4de7654..d70f884a 100644 --- a/tmux.1 +++ b/tmux.1 @@ -3092,7 +3092,11 @@ See the section. .Fl O specifies the sort order: one of -.Ql name , +.Ql name +(title), +.Ql index , +.Ql size +(area), .Ql creation (time), or .Ql activity @@ -3125,6 +3129,10 @@ section. specifies the sort order: one of .Ql index , .Ql name , +.Ql size +(area), +.Ql creation +(time), or .Ql activity (time). diff --git a/tmux.h b/tmux.h index 3913c157..2c7a4376 100644 --- a/tmux.h +++ b/tmux.h @@ -1101,6 +1101,7 @@ struct window_mode { void (*free)(struct window_mode_entry *); void (*resize)(struct window_mode_entry *, u_int, u_int); void (*update)(struct window_mode_entry *); + void (*style_changed)(struct window_mode_entry *); void (*key)(struct window_mode_entry *, struct client *, struct session *, struct winlink *, key_code, struct mouse_event *); @@ -1305,6 +1306,7 @@ struct window { struct event offset_timer; struct timeval activity_time; + struct timeval creation_time; struct window_pane *active; struct window_panes last_panes; @@ -2363,7 +2365,7 @@ time_t paste_buffer_created(struct paste_buffer *); const char *paste_buffer_data(struct paste_buffer *, size_t *); struct paste_buffer *paste_walk(struct paste_buffer *); int paste_is_empty(void); -struct paste_buffer *paste_get_top(const char **); +struct paste_buffer *paste_get_top(char **); struct paste_buffer *paste_get_name(const char *); void paste_free(struct paste_buffer *); void paste_add(const char *, char *, size_t); @@ -3065,7 +3067,7 @@ void recalculate_sizes_now(int); /* input.c */ #define INPUT_BUF_DEFAULT_SIZE 1048576 struct input_ctx *input_init(struct window_pane *, struct bufferevent *, - struct colour_palette *); + struct colour_palette *, struct client *); void input_free(struct input_ctx *); void input_reset(struct input_ctx *, int); struct evbuffer *input_pending(struct input_ctx *); diff --git a/tty-draw.c b/tty-draw.c index 97e15dcc..080ea42b 100644 --- a/tty-draw.c +++ b/tty-draw.c @@ -262,10 +262,12 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, else next_state = TTY_DRAW_LINE_NEW1; } - log_debug("%s: cell %u empty %u, bg %u; state: current %s, " - "next %s", __func__, px + i, empty, gcp->bg, - tty_draw_line_states[current_state], - tty_draw_line_states[next_state]); + if (log_get_level() != 0) { + log_debug("%s: cell %u empty %u, bg %u; state: " + "current %s, next %s", __func__, px + i, empty, + gcp->bg, tty_draw_line_states[current_state], + tty_draw_line_states[next_state]); + } /* If the state has changed, flush any collected data. */ if (next_state != current_state) { diff --git a/tty-keys.c b/tty-keys.c index e3e20eec..361de3df 100644 --- a/tty-keys.c +++ b/tty-keys.c @@ -1377,6 +1377,10 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size) /* Convert from base64. */ needed = (end / 4) * 3; + if (needed == 0) { + free(copy); + return (0); + } out = xmalloc(needed); if ((outlen = b64_pton(copy, out, len)) == -1) { free(out); @@ -1612,8 +1616,10 @@ tty_keys_extended_device_attributes(struct tty *tty, const char *buf, } if (i == (sizeof tmp) - 1) return (-1); - tmp[i - 1] = '\0'; *size = 5 + i; + if (i == 0) + return (0); + tmp[i - 1] = '\0'; /* Add terminal features. */ if (strncmp(tmp, "iTerm2 ", 7) == 0) @@ -1686,11 +1692,13 @@ tty_keys_colours(struct tty *tty, const char *buf, size_t len, size_t *size, } if (i == (sizeof tmp) - 1) return (-1); + *size = 6 + i; + if (i == 0) + return (0); if (tmp[i - 1] == '\033') tmp[i - 1] = '\0'; else tmp[i] = '\0'; - *size = 6 + i; /* Work out the colour. */ n = colour_parseX11(tmp); @@ -1755,11 +1763,13 @@ tty_keys_palette(struct tty *tty, const char *buf, size_t len, size_t *size) } if (i == (sizeof tmp) - 1) return (-1); + *size = 5 + i; + if (i == 0) + return (0); if (tmp[i - 1] == '\033') tmp[i - 1] = '\0'; else tmp[i] = '\0'; - *size = 5 + i; /* Parse index. */ idx = strtol(tmp, &endptr, 10); diff --git a/tty.c b/tty.c index 878575c4..f969f46d 100644 --- a/tty.c +++ b/tty.c @@ -633,7 +633,8 @@ tty_add(struct tty *tty, const char *buf, size_t len) if (tty_log_fd != -1) write(tty_log_fd, buf, len); - if (tty->flags & TTY_STARTED) + if ((tty->flags & TTY_STARTED) && + !event_pending(&tty->event_out, EV_WRITE, NULL)) event_add(&tty->event_out, NULL); } @@ -2289,7 +2290,6 @@ tty_cell(struct tty *tty, const struct grid_cell *gc, /* If it is a single character, write with putc to handle ACS. */ if (gcp->data.size == 1) { - tty_attributes(tty, gcp, defaults, palette, hl); if (*gcp->data.data < 0x20 || *gcp->data.data == 0x7f) return; tty_putc(tty, *gcp->data.data); diff --git a/window-copy.c b/window-copy.c index c575a1f9..2f28355a 100644 --- a/window-copy.c +++ b/window-copy.c @@ -51,6 +51,7 @@ static void window_copy_redraw_selection(struct window_mode_entry *, u_int); static void window_copy_redraw_lines(struct window_mode_entry *, u_int, u_int); static void window_copy_redraw_screen(struct window_mode_entry *); +static void window_copy_style_changed(struct window_mode_entry *); static void window_copy_write_line(struct window_mode_entry *, struct screen_write_ctx *, u_int); static void window_copy_write_lines(struct window_mode_entry *, @@ -158,6 +159,7 @@ const struct window_mode window_copy_mode = { .init = window_copy_init, .free = window_copy_free, .resize = window_copy_resize, + .style_changed = window_copy_style_changed, .key_table = window_copy_key_table, .command = window_copy_command, .formats = window_copy_formats, @@ -170,6 +172,7 @@ const struct window_mode window_view_mode = { .init = window_copy_view_init, .free = window_copy_free, .resize = window_copy_resize, + .style_changed = window_copy_style_changed, .key_table = window_copy_key_table, .command = window_copy_command, .formats = window_copy_formats, @@ -352,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--; } @@ -491,7 +494,7 @@ window_copy_view_init(struct window_mode_entry *wme, data->backing = xmalloc(sizeof *data->backing); screen_init(data->backing, sx, screen_size_y(base), UINT_MAX); - data->ictx = input_init(NULL, NULL, NULL); + data->ictx = input_init(NULL, NULL, NULL, NULL); data->mx = data->cx; data->my = screen_hsize(data->backing) + data->cy - data->oy; data->showmark = 0; @@ -3622,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); @@ -3667,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); @@ -3676,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; } } @@ -4077,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; @@ -4268,6 +4281,9 @@ window_copy_clear_marks(struct window_mode_entry *wme) { struct window_copy_mode_data *data = wme->data; + data->searchcount = -1; + data->searchmore = 0; + free(data->searchmark); data->searchmark = NULL; } @@ -4595,6 +4611,16 @@ window_copy_redraw_screen(struct window_mode_entry *wme) window_copy_redraw_lines(wme, 0, screen_size_y(&data->screen)); } +static void +window_copy_style_changed(struct window_mode_entry *wme) +{ + struct window_copy_mode_data *data = wme->data; + + if (data->screen.sel != NULL) + window_copy_set_selection(wme, 0, 1); + window_copy_redraw_screen(wme); +} + static void window_copy_synchronize_cursor_end(struct window_mode_entry *wme, int begin, int no_reset) @@ -5036,9 +5062,9 @@ static void window_copy_append_selection(struct window_mode_entry *wme) { struct window_pane *wp = wme->wp; - char *buf; + char *buf, *bufname = NULL; struct paste_buffer *pb; - const char *bufdata, *bufname = NULL; + const char *bufdata; size_t len, bufsize; struct screen_write_ctx ctx; @@ -5063,6 +5089,7 @@ window_copy_append_selection(struct window_mode_entry *wme) } if (paste_set(buf, len, bufname, NULL) != 0) free(buf); + free(bufname); } static void diff --git a/window.c b/window.c index b43d3cce..d1a2219e 100644 --- a/window.c +++ b/window.c @@ -329,6 +329,9 @@ window_create(u_int sx, u_int sy, u_int xpixel, u_int ypixel) RB_INSERT(windows, &windows, w); window_set_fill_character(w); + + if (gettimeofday(&w->creation_time, NULL) != 0) + fatal("gettimeofday failed"); window_update_activity(w); log_debug("%s: @%u create %ux%u (%ux%u)", __func__, w->id, sx, sy, @@ -1171,7 +1174,7 @@ window_pane_set_event(struct window_pane *wp) NULL, window_pane_error_callback, wp); if (wp->event == NULL) fatalx("out of memory"); - wp->ictx = input_init(wp, wp->event, &wp->palette); + wp->ictx = input_init(wp, wp->event, &wp->palette, NULL); bufferevent_enable(wp->event, EV_READ|EV_WRITE); }