diff --git a/csi.c b/csi.c index 2d0f3c62..42f19a91 100644 --- a/csi.c +++ b/csi.c @@ -2048,6 +2048,82 @@ csi_dispatch(struct terminal *term, uint8_t final) break; /* private[0] == ‘$’ */ } + case '#': { + switch (final) { + case 'P': { /* XTPUSHCOLORS */ + int slot = vt_param_get(term, 0, 0); + + /* Pm == 0, "push" (what xterm does is take take the + *current* slot + 1, even if that's in the middle of the + stack, and overwrites whatever is already in that + slot) */ + if (slot == 0) + slot = term->color_stack.idx + 1; + + if (term->color_stack.size < slot) { + const size_t new_size = slot; + term->color_stack.stack = xrealloc( + term->color_stack.stack, + new_size * sizeof(term->color_stack.stack[0])); + + /* Initialize new slots (except the selected slot, + which is done below) */ + xassert(new_size > 0); + for (size_t i = term->color_stack.size; i < new_size - 1; i++) { + memcpy(&term->color_stack.stack[i], &term->colors, + sizeof(term->colors)); + } + term->color_stack.size = new_size; + } + + xassert(slot > 0); + xassert(slot <= term->color_stack.size); + term->color_stack.idx = slot; + memcpy(&term->color_stack.stack[slot - 1], &term->colors, + sizeof(term->colors)); + break; + } + + case 'Q': { /* XTPOPCOLORS */ + int slot = vt_param_get(term, 0, 0); + + /* Pm == 0, "pop" (what xterm does is copy colors from the + *current* slot, *and* decrease the current slot index, + even if that's in the middle of the stack) */ + if (slot == 0) + slot = term->color_stack.idx; + + if (slot > 0 && slot <= term->color_stack.size) { + memcpy(&term->colors, &term->color_stack.stack[slot - 1], + sizeof(term->colors)); + term->color_stack.idx = slot - 1; + + /* TODO: we _could_ iterate all cells and only dirty + those that are affected by the palette change... */ + term_damage_view(term); + } else if (slot == 0) { + LOG_ERR("XTPOPCOLORS: cannot pop beyond the first element"); + } else { + LOG_ERR( + "XTPOPCOLORS: invalid color slot: %d " + "(stack has %zu slots, current slot is %zu)", + vt_param_get(term, 0, 0), + term->color_stack.size, term->color_stack.idx); + } + break; + } + + case 'R': { /* XTREPORTCOLORS */ + char reply[64]; + int n = xsnprintf(reply, sizeof(reply), "\033[?%zu;%zu#Q", + term->color_stack.idx, term->color_stack.size); + term_to_slave(term, reply, n); + break; + } + } + break; /* private[0] == '#' */ + } + case 0x243f: /* ?$ */ switch (final) { case 'p': { diff --git a/terminal.c b/terminal.c index caa8aa5a..ca3d2bc1 100644 --- a/terminal.c +++ b/terminal.c @@ -1227,6 +1227,11 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper, .selection_bg = conf->colors.selection_bg, .use_custom_selection = conf->colors.use_custom.selection, }, + .color_stack = { + .stack = NULL, + .size = 0, + .idx = 0, + }, .origin = ORIGIN_ABSOLUTE, .cursor_style = conf->cursor.style, .cursor_blink = { @@ -1823,6 +1828,7 @@ term_destroy(struct terminal *term) free(term->foot_exe); free(term->cwd); free(term->mouse_user_cursor); + free(term->color_stack.stack); int ret = EXIT_SUCCESS; @@ -2040,6 +2046,10 @@ term_reset(struct terminal *term, bool hard) term->colors.use_custom_selection = term->conf->colors.use_custom.selection; memcpy(term->colors.table, term->conf->colors.table, sizeof(term->colors.table)); + free(term->color_stack.stack); + term->color_stack.stack = NULL; + term->color_stack.size = 0; + term->color_stack.idx = 0; term->origin = ORIGIN_ABSOLUTE; term->normal.cursor.lcf = false; term->alt.cursor.lcf = false; diff --git a/terminal.h b/terminal.h index 9fce2396..4d628661 100644 --- a/terminal.h +++ b/terminal.h @@ -393,6 +393,19 @@ struct url { }; typedef tll(struct url) url_list_t; + +struct colors { + uint32_t fg; + uint32_t bg; + uint32_t table[256]; + uint16_t alpha; + uint32_t cursor_fg; /* Text color */ + uint32_t cursor_bg; /* cursor color */ + uint32_t selection_fg; + uint32_t selection_bg; + bool use_custom_selection; +}; + struct terminal { struct fdm *fdm; struct reaper *reaper; @@ -563,17 +576,13 @@ struct terminal { int cell_width; /* pixels per cell, x-wise */ int cell_height; /* pixels per cell, y-wise */ + struct colors colors; + struct { - uint32_t fg; - uint32_t bg; - uint32_t table[256]; - uint16_t alpha; - uint32_t cursor_fg; /* Text color */ - uint32_t cursor_bg; /* cursor color */ - uint32_t selection_fg; - uint32_t selection_bg; - bool use_custom_selection; - } colors; + struct colors *stack; + size_t idx; + size_t size; + } color_stack; enum cursor_style cursor_style; struct {