Merge branch 'obsd-master'

This commit is contained in:
Thomas Adam
2026-02-17 08:51:05 +00:00
5 changed files with 155 additions and 100 deletions

View File

@@ -57,14 +57,12 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
{ {
struct args *args = cmd_get_args(self); struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item); struct client *tc = cmdq_get_target_client(item);
struct paste_buffer *pb; struct paste_buffer *pb = NULL;
char *bufname, *bufdata = NULL, *cause = NULL; char *bufname = NULL, *bufdata = NULL, *cause = NULL;
const char *olddata; const char *olddata;
size_t bufsize = 0, newsize; size_t bufsize = 0, newsize;
if (args_get(args, 'b') == NULL) if (args_get(args, 'b') != NULL) {
pb = NULL;
else {
bufname = xstrdup(args_get(args, 'b')); bufname = xstrdup(args_get(args, 'b'));
pb = paste_get_name(bufname); pb = paste_get_name(bufname);
} }

View File

@@ -51,29 +51,24 @@ control_notify_window_layout_changed(struct window *w)
template = "%layout-change #{window_id} #{window_layout} " template = "%layout-change #{window_id} #{window_layout} "
"#{window_visible_layout} #{window_raw_flags}"; "#{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) { TAILQ_FOREACH(c, &clients, entry) {
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL) if (!CONTROL_SHOULD_NOTIFY_CLIENT(c) || c->session == NULL)
continue; continue;
s = c->session; s = c->session;
if (winlink_find_by_window_id(&s->windows, w->id) != NULL)
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);
control_write(c, "%s", cp); control_write(c, "%s", cp);
free(cp);
}
} }
free(cp);
} }
void void

190
control.c
View File

@@ -846,15 +846,13 @@ control_stop(struct client *c)
/* Check session subscription. */ /* Check session subscription. */
static void 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 session *s = c->session;
struct format_tree *ft;
char *value; char *value;
ft = format_create_defaults(NULL, c, s, NULL, NULL);
value = format_expand(ft, csub->format); value = format_expand(ft, csub->format);
format_free(ft);
if (csub->last != NULL && strcmp(value, csub->last) == 0) { if (csub->last != NULL && strcmp(value, csub->last) == 0) {
free(value); 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 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 session *s = c->session;
struct window_pane *wp; struct window *w = wl->window;
struct window *w;
struct winlink *wl;
struct format_tree *ft;
char *value; char *value;
struct control_sub_pane *csp, find; struct control_sub_pane *csp, find;
RB_FOREACH(wl, winlinks, &s->windows) { value = format_expand(ft, csub->format);
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);
find.pane = wp->id; find.pane = wp->id;
find.idx = wl->idx; find.idx = wl->idx;
csp = RB_FIND(control_sub_panes, &csub->panes, &find); csp = RB_FIND(control_sub_panes, &csub->panes, &find);
if (csp == NULL) { if (csp == NULL) {
csp = xcalloc(1, sizeof *csp); csp = xcalloc(1, sizeof *csp);
csp->pane = wp->id; csp->pane = wp->id;
csp->idx = wl->idx; csp->idx = wl->idx;
RB_INSERT(control_sub_panes, &csub->panes, csp); 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;
}
} }
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. */ /* 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 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 session *s = c->session;
struct window *w; struct window *w = wl->window;
struct winlink *wl;
struct format_tree *ft;
char *value; char *value;
struct control_sub_window *csw, find; struct control_sub_window *csw, find;
RB_FOREACH(wl, winlinks, &s->windows) { value = format_expand(ft, csub->format);
w = wl->window;
ft = format_create_defaults(NULL, c, s, wl, NULL); find.window = w->id;
value = format_expand(ft, csub->format); find.idx = wl->idx;
format_free(ft);
find.window = w->id; csw = RB_FIND(control_sub_windows, &csub->windows, &find);
find.idx = wl->idx; if (csw == NULL) {
csw = xcalloc(1, sizeof *csw);
csw = RB_FIND(control_sub_windows, &csub->windows, &find); csw->window = w->id;
if (csw == NULL) { csw->idx = wl->idx;
csw = xcalloc(1, sizeof *csw); RB_INSERT(control_sub_windows, &csub->windows, 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;
} }
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. */ /* Check subscriptions timer. */
@@ -1053,30 +1034,91 @@ control_check_subs_timer(__unused int fd, __unused short events, void *data)
struct client *c = data; struct client *c = data;
struct control_state *cs = c->control_state; struct control_state *cs = c->control_state;
struct control_sub *csub, *csub1; 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 }; 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__); log_debug("%s: timer fired", __func__);
evtimer_add(&cs->subs_timer, &tv); 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) { switch (csub->type) {
case CONTROL_SUB_SESSION: case CONTROL_SUB_SESSION:
control_check_subs_session(c, csub); have_session = 1;
break;
case CONTROL_SUB_PANE:
control_check_subs_pane(c, csub);
break; break;
case CONTROL_SUB_ALL_PANES: 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; break;
case CONTROL_SUB_WINDOW: case CONTROL_SUB_WINDOW:
control_check_subs_window(c, csub); control_check_subs_window(c, csub);
break; break;
case CONTROL_SUB_SESSION:
case CONTROL_SUB_ALL_PANES:
case CONTROL_SUB_ALL_WINDOWS: case CONTROL_SUB_ALL_WINDOWS:
control_check_subs_all_windows(c, csub);
break; 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. */ /* Add a subscription. */

14
grid.c
View File

@@ -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_line *gl = &gd->linedata[py];
struct grid_cell_entry *gce = &gl->celldata[px]; struct grid_cell_entry *gce = &gl->celldata[px];
struct grid_extd_entry *gee; 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); memcpy(gce, &grid_cleared_entry, sizeof *gce);
if (bg != 8) { if (bg != 8) {
if (bg & COLOUR_FLAG_RGB) { 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 = grid_extended_cell(gl, gce, &grid_cleared_cell);
gee->bg = bg; gee->bg = bg;
} else { } else {
@@ -1089,12 +1095,16 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx,
off = 0; off = 0;
gl = grid_peek_line(gd, py); gl = grid_peek_line(gd, py);
if (gl == NULL) {
buf[0] = '\0';
return (buf);
}
if (flags & GRID_STRING_EMPTY_CELLS) if (flags & GRID_STRING_EMPTY_CELLS)
end = gl->cellsize; end = gl->cellsize;
else else
end = gl->cellused; end = gl->cellused;
for (xx = px; xx < px + nx; xx++) { for (xx = px; xx < px + nx; xx++) {
if (gl == NULL || xx >= end) if (xx >= end)
break; break;
grid_get_cell(gd, xx, py, &gc); grid_get_cell(gd, xx, py, &gc);
if (gc.flags & GRID_FLAG_PADDING) if (gc.flags & GRID_FLAG_PADDING)

View File

@@ -355,7 +355,7 @@ window_copy_clone_screen(struct screen *src, struct screen *hint, u_int *cx,
if (trim) { if (trim) {
while (sy > screen_hsize(src)) { while (sy > screen_hsize(src)) {
gl = grid_peek_line(src->grid, sy - 1); gl = grid_peek_line(src->grid, sy - 1);
if (gl->cellused != 0) if (gl == NULL || gl->cellused != 0)
break; break;
sy--; sy--;
} }
@@ -3625,6 +3625,10 @@ window_copy_stringify(struct grid *gd, u_int py, u_int first, u_int last,
buf = xrealloc(buf, bufsize); buf = xrealloc(buf, bufsize);
gl = grid_peek_line(gd, py); gl = grid_peek_line(gd, py);
if (gl == NULL) {
buf[*size - 1] = '\0';
return (buf);
}
bx = *size - 1; bx = *size - 1;
for (ax = first; ax < last; ax++) { for (ax = first; ax < last; ax++) {
d = window_copy_cellstring(gl, ax, &dlen, &allocated); 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; px = *ppx;
pywrap = *ppy; pywrap = *ppy;
gl = grid_peek_line(gd, pywrap); gl = grid_peek_line(gd, pywrap);
if (gl == NULL) {
free(cells);
return;
}
while (cell < ncells) { while (cell < ncells) {
cells[cell].d = window_copy_cellstring(gl, px, cells[cell].d = window_copy_cellstring(gl, px,
&cells[cell].dlen, &cells[cell].allocated); &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; px = 0;
pywrap++; pywrap++;
gl = grid_peek_line(gd, 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)--) { for (*start = gd->hsize - data->oy; *start > 0; (*start)--) {
gl = grid_peek_line(gd, (*start) - 1); gl = grid_peek_line(gd, (*start) - 1);
if (~gl->flags & GRID_LINE_WRAPPED) if (gl == NULL || ~gl->flags & GRID_LINE_WRAPPED)
break; break;
} }
*end = gd->hsize - data->oy + gd->sy; *end = gd->hsize - data->oy + gd->sy;