diff --git a/csi.c b/csi.c index ea2b97e6..9b00c3ef 100644 --- a/csi.c +++ b/csi.c @@ -791,19 +791,10 @@ csi_dispatch(struct terminal *term, uint8_t final) case 24: LOG_WARN("unimplemented: resize window (DECSLPP)"); break; case 14: { /* report window size in pixels */ - const int x_margin = term->x_margin; - const int y_margin = term->y_margin; - const int cell_width = term->cols * term->cell_width; - const int cell_height = term->rows * term->cell_height; - - /* right+bottom margins */ - const int r_margin = term->width - cell_width - x_margin; - const int b_margin = term->height - cell_height - y_margin; - char reply[64]; snprintf(reply, sizeof(reply), "\033[4;%d;%dt", - term->height - y_margin - b_margin, - term->width - x_margin - r_margin); + term->height - term->margins.top - term->margins.bottom, + term->width - term->margins.left - term->margins.right); term_to_slave(term, reply, strlen(reply)); break; } diff --git a/input.c b/input.c index c8f920b3..d04b228d 100644 --- a/input.c +++ b/input.c @@ -687,8 +687,8 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, int x = wl_fixed_to_int(surface_x) * term->scale; int y = wl_fixed_to_int(surface_y) * term->scale; - int col = (x - term->x_margin) / term->cell_width; - int row = (y - term->y_margin) / term->cell_height; + int col = (x - term->margins.left) / term->cell_width; + int row = (y - term->margins.top) / term->cell_height; if (col < 0 || row < 0 || col >= term->cols || row >= term->rows) return; diff --git a/render.c b/render.c index c7d702b8..0e019431 100644 --- a/render.c +++ b/render.c @@ -382,8 +382,8 @@ render_cell(struct terminal *term, pixman_image_t *pix, int width = term->cell_width; int height = term->cell_height; - int x = term->x_margin + col * width; - int y = term->y_margin + row * height; + int x = term->margins.left + col * width; + int y = term->margins.top + row * height; assert(cell->attrs.selected == 0 || cell->attrs.selected == 1); bool is_selected = cell->attrs.selected; @@ -475,8 +475,8 @@ static void grid_render_scroll(struct terminal *term, struct buffer *buf, const struct damage *dmg) { - int dst_y = term->y_margin + (dmg->scroll.region.start + 0) * term->cell_height; - int src_y = term->y_margin + (dmg->scroll.region.start + dmg->scroll.lines) * term->cell_height; + int dst_y = term->margins.top + (dmg->scroll.region.start + 0) * term->cell_height; + int src_y = term->margins.top + (dmg->scroll.region.start + dmg->scroll.lines) * term->cell_height; int height = (dmg->scroll.region.end - dmg->scroll.region.start - dmg->scroll.lines) * term->cell_height; LOG_DBG("damage: SCROLL: %d-%d by %d lines (dst-y: %d, src-y: %d, " @@ -493,7 +493,7 @@ grid_render_scroll(struct terminal *term, struct buffer *buf, height * buf->stride); wl_surface_damage_buffer( - term->window->surface, term->x_margin, dst_y, term->width - term->x_margin, height); + term->window->surface, term->margins.left, dst_y, term->width - term->margins.left - term->margins.right, height); } } @@ -501,8 +501,8 @@ static void grid_render_scroll_reverse(struct terminal *term, struct buffer *buf, const struct damage *dmg) { - int src_y = term->y_margin + (dmg->scroll.region.start + 0) * term->cell_height; - int dst_y = term->y_margin + (dmg->scroll.region.start + dmg->scroll.lines) * term->cell_height; + int src_y = term->margins.top + (dmg->scroll.region.start + 0) * term->cell_height; + int dst_y = term->margins.top + (dmg->scroll.region.start + dmg->scroll.lines) * term->cell_height; int height = (dmg->scroll.region.end - dmg->scroll.region.start - dmg->scroll.lines) * term->cell_height; LOG_DBG("damage: SCROLL REVERSE: %d-%d by %d lines (dst-y: %d, src-y: %d, " @@ -519,7 +519,7 @@ grid_render_scroll_reverse(struct terminal *term, struct buffer *buf, height * buf->stride); wl_surface_damage_buffer( - term->window->surface, term->x_margin, dst_y, term->width - term->x_margin, height); + term->window->surface, term->margins.left, dst_y, term->width - term->margins.left - term->margins.right, height); } } @@ -563,21 +563,21 @@ render_sixel(struct terminal *term, pixman_image_t *pix, (row - term->grid->view + term->grid->num_rows) & (term->grid->num_rows - 1); /* Translate row/column to x/y pixel values */ - const int x = term->x_margin + sixel->pos.col * term->cell_width; + const int x = term->margins.left + sixel->pos.col * term->cell_width; const int y = max( - term->y_margin, term->y_margin + view_aligned * term->cell_height); + term->margins.top, term->margins.top + view_aligned * term->cell_height); /* Width/height, in pixels - and don't touch the window margins */ - const int width = min(sixel->width, term->width - x - term->x_margin); + const int width = min(sixel->width, term->width - x - term->margins.right); const int height = min( sixel->height - first_img_row * term->cell_height, - term->height - y - term->y_margin); + term->height - y - term->margins.bottom); /* Verify we're not stepping outside the grid */ - assert(x >= term->x_margin); - assert(y >= term->y_margin); - assert(x + width <= term->width - term->x_margin); - assert(y + height <= term->height - term->y_margin); + assert(x >= term->margins.left); + assert(y >= term->margins.top); + assert(x + width <= term->width - term->margins.right); + assert(y + height <= term->height - term->margins.bottom); pixman_image_composite( PIXMAN_OP_SRC, @@ -756,10 +756,8 @@ grid_render(struct terminal *term) else { /* Fill area outside the cell grid with the default background color */ - int rmargin = term->x_margin + term->cols * term->cell_width; - int bmargin = term->y_margin + term->rows * term->cell_height; - int rmargin_width = term->width - rmargin; - int bmargin_height = term->height - bmargin; + int rmargin = term->width - term->margins.right; + int bmargin = term->height - term->margins.bottom; uint32_t _bg = !term->reverse ? term->colors.bg : term->colors.fg; pixman_color_t bg = color_hex_to_pixman_with_alpha(_bg, term->colors.alpha); @@ -769,19 +767,19 @@ grid_render(struct terminal *term) pixman_image_fill_rectangles( PIXMAN_OP_SRC, pix, &bg, 4, (pixman_rectangle16_t[]){ - {0, 0, term->width, term->y_margin}, /* Top */ - {0, 0, term->x_margin, term->height}, /* Left */ - {rmargin, 0, rmargin_width, term->height}, /* Right */ - {0, bmargin, term->width, bmargin_height}}); /* Bottom */ + {0, 0, term->width, term->margins.top}, /* Top */ + {0, 0, term->margins.left, term->height}, /* Left */ + {rmargin, 0, term->margins.right, term->height}, /* Right */ + {0, bmargin, term->width, term->margins.bottom}}); /* Bottom */ wl_surface_damage_buffer( - term->window->surface, 0, 0, term->width, term->y_margin); + term->window->surface, 0, 0, term->width, term->margins.top); wl_surface_damage_buffer( - term->window->surface, 0, 0, term->x_margin, term->height); + term->window->surface, 0, 0, term->margins.left, term->height); wl_surface_damage_buffer( - term->window->surface, rmargin, 0, rmargin_width, term->height); + term->window->surface, rmargin, 0, term->margins.right, term->height); wl_surface_damage_buffer( - term->window->surface, 0, bmargin, term->width, bmargin_height); + term->window->surface, 0, bmargin, term->width, term->margins.bottom); /* Force a full grid refresh */ term_damage_view(term); @@ -806,8 +804,8 @@ grid_render(struct terminal *term) wl_surface_damage_buffer( term->window->surface, - term->x_margin + at.col * term->cell_width, - term->y_margin + at.row * term->cell_height, + term->margins.left + at.col * term->cell_width, + term->margins.top + at.row * term->cell_height, cols * term->cell_width, term->cell_height); } } @@ -859,8 +857,8 @@ grid_render(struct terminal *term) wl_surface_damage_buffer( term->window->surface, - term->x_margin, term->y_margin + r * term->cell_height, - term->width - term->x_margin, term->cell_height); + term->margins.left, term->margins.top + r * term->cell_height, + term->width - term->margins.left - term->margins.right, term->cell_height); } mtx_lock(&term->render.workers.lock); @@ -880,8 +878,8 @@ grid_render(struct terminal *term) wl_surface_damage_buffer( term->window->surface, - term->x_margin, term->y_margin + r * term->cell_height, - term->width - term->x_margin, term->cell_height); + term->margins.left, term->margins.top + r * term->cell_height, + term->width - term->margins.left - term->margins.right, term->cell_height); } } @@ -933,8 +931,8 @@ grid_render(struct terminal *term) wl_surface_damage_buffer( term->window->surface, - term->x_margin + term->cursor.point.col * term->cell_width, - term->y_margin + view_aligned_row * term->cell_height, + term->margins.left + term->cursor.point.col * term->cell_width, + term->margins.top + view_aligned_row * term->cell_height, cols_updated * term->cell_width, term->cell_height); } @@ -1156,8 +1154,10 @@ maybe_resize(struct terminal *term, int width, int height, bool force) assert(new_rows >= 1); /* Margins */ - term->x_margin = (term->width - new_cols * term->cell_width) / 2; - term->y_margin = (term->height - new_rows * term->cell_height) / 2; + term->margins.left = (term->width - new_cols * term->cell_width) / 2; + term->margins.top = (term->height - new_rows * term->cell_height) / 2; + term->margins.right = term->width - new_cols * term->cell_width - term->margins.left; + term->margins.bottom = term->height - new_rows * term->cell_height - term->margins.top; if (new_cols == old_cols && new_rows == old_rows) { LOG_DBG("grid layout unaffected; skipping reflow"); @@ -1178,9 +1178,10 @@ maybe_resize(struct terminal *term, int width, int height, bool force) term->cols = new_cols; term->rows = new_rows; - LOG_INFO("resize: %dx%d, grid: cols=%d, rows=%d (x-margin=%d, y-margin=%d)", + LOG_INFO("resize: %dx%d, grid: cols=%d, rows=%d " + "(left-margin=%d, right-margin=%d, top-margin=%d, bottom-margin=%d)", term->width, term->height, term->cols, term->rows, - term->x_margin, term->y_margin); + term->margins.left, term->margins.right, term->margins.top, term->margins.bottom); /* Signal TIOCSWINSZ */ if (ioctl(term->ptmx, TIOCSWINSZ, diff --git a/sixel.c b/sixel.c index 6a0b2982..b538fddb 100644 --- a/sixel.c +++ b/sixel.c @@ -52,25 +52,83 @@ sixel_destroy(struct sixel *sixel) sixel->data = NULL; } -void -sixel_delete_at_cursor(struct terminal *term) +static void +sixel_erase(struct terminal *term, struct sixel *sixel) { - const int row = term->grid->offset + term->cursor.point.row; + for (int i = 0; i < sixel->rows; i++) { + int r = (sixel->pos.row + i) & (term->grid->num_rows - 1); + + struct row *row = term->grid->rows[r]; + row->dirty = true; + + for (int c = 0; c < term->grid->num_cols; c++) + row->cells[c].attrs.clean = 0; + } + + sixel_destroy(sixel); +} + +void +sixel_delete_at_row(struct terminal *term, int _row) +{ + if (likely(tll_length(term->sixel_images) == 0)) + return; tll_foreach(term->sixel_images, it) { - if (it->item.grid != term->grid) + struct sixel *six = &it->item; + + if (six->grid != term->grid) continue; - const int start = it->item.pos.row; - const int end = start + it->item.rows; + const int row = (term->grid->offset + _row) & (term->grid->num_rows - 1); + const int six_start = six->pos.row; + const int six_end = six_start + six->rows - 1; - if (row >= start && row < end) { - sixel_destroy(&it->item); + if (row >= six_start && row <= six_end) { + sixel_erase(term, six); tll_remove(term->sixel_images, it); } } } +void +sixel_delete_in_range(struct terminal *term, int _start, int _end) +{ + assert(_end >= _start); + + if (likely(tll_length(term->sixel_images) == 0)) + return; + + if (_start == _end) + return sixel_delete_at_row(term, _start); + + tll_foreach(term->sixel_images, it) { + struct sixel *six = &it->item; + + if (six->grid != term->grid) + continue; + + const int start = (term->grid->offset + _start) & (term->grid->num_rows - 1); + const int end = start + (_end - _start); + const int six_start = six->pos.row; + const int six_end = six_start + six->rows - 1; + + if ((start <= six_start && end >= six_start) || /* Crosses sixel start boundary */ + (start <= six_end && end >= six_end) || /* Crosses sixel end boundary */ + (start >= six_start && end <= six_end)) /* Fully within sixel range */ + { + sixel_erase(term, six); + tll_remove(term->sixel_images, it); + } + } +} + +void +sixel_delete_at_cursor(struct terminal *term) +{ + sixel_delete_at_row(term, term->cursor.point.row); +} + void sixel_unhook(struct terminal *term) { @@ -85,7 +143,9 @@ sixel_unhook(struct terminal *term) .height = term->sixel.image.height, .rows = (term->sixel.image.height + term->cell_height - 1) / term->cell_height, .grid = term->grid, - .pos = (struct coord){term->cursor.point.col, term->grid->offset + term->cursor.point.row}, + .pos = (struct coord){ + term->cursor.point.col, + (term->grid->offset + term->cursor.point.row) & (term->grid->num_rows - 1)}, }; LOG_DBG("generating %dx%d pixman image", image.width, image.height); @@ -96,8 +156,6 @@ sixel_unhook(struct terminal *term) term->sixel.image.data, term->sixel.image.width * sizeof(uint32_t)); - tll_push_back(term->sixel_images, image); - term->sixel.image.data = NULL; term->sixel.image.width = 0; term->sixel.image.height = 0; @@ -108,6 +166,8 @@ sixel_unhook(struct terminal *term) term_linefeed(term); term_formfeed(term); render_refresh(term); + + tll_push_back(term->sixel_images, image); } static unsigned @@ -421,16 +481,19 @@ sixel_colors_report_current(struct terminal *term) void sixel_colors_reset(struct terminal *term) { - term->sixel.palette_size = SIXEL_MAX_COLORS; LOG_DBG("sixel palette size reset to %u", SIXEL_MAX_COLORS); + term->sixel.palette_size = SIXEL_MAX_COLORS; + sixel_colors_report_current(term); } void sixel_colors_set(struct terminal *term, unsigned count) { unsigned new_palette_size = min(max(2, count), SIXEL_MAX_COLORS); - term->sixel.palette_size = new_palette_size; LOG_DBG("sixel palette size set to %u", new_palette_size); + + term->sixel.palette_size = new_palette_size; + sixel_colors_report_current(term); } void @@ -457,18 +520,19 @@ sixel_geometry_report_current(struct terminal *term) void sixel_geometry_reset(struct terminal *term) { + LOG_DBG("sixel geometry reset to %ux%u", max_width(term), max_height(term)); term->sixel.max_width = 0; term->sixel.max_height = 0; - LOG_DBG("sixel geometry reset to %ux%u", max_width(term), max_height(term)); + sixel_geometry_report_current(term); } void sixel_geometry_set(struct terminal *term, unsigned width, unsigned height) { + LOG_DBG("sixel geometry set to %ux%u", width, height); term->sixel.max_width = width; term->sixel.max_height = height; - LOG_DBG("sixel geometry set to %ux%u", - term->sixel.max_width, term->sixel.max_height); + sixel_geometry_report_current(term); } void diff --git a/sixel.h b/sixel.h index 040df93a..13eff024 100644 --- a/sixel.h +++ b/sixel.h @@ -9,6 +9,9 @@ void sixel_put(struct terminal *term, uint8_t c); void sixel_unhook(struct terminal *term); void sixel_destroy(struct sixel *sixel); + +void sixel_delete_in_range(struct terminal *term, int start, int end); +void sixel_delete_at_row(struct terminal *term, int _row); void sixel_delete_at_cursor(struct terminal *term); void sixel_colors_report_current(struct terminal *term); diff --git a/terminal.c b/terminal.c index 8504a45b..3977caae 100644 --- a/terminal.c +++ b/terminal.c @@ -1366,6 +1366,7 @@ term_erase(struct terminal *term, const struct coord *start, const struct coord if (start->row == end->row) { struct row *row = grid_row(term->grid, start->row); erase_cell_range(term, row, start->col, end->col); + sixel_delete_at_row(term, start->row); return; } @@ -1378,6 +1379,7 @@ term_erase(struct terminal *term, const struct coord *start, const struct coord erase_line(term, grid_row(term->grid, r)); erase_cell_range(term, grid_row(term->grid, end->row), 0, end->col); + sixel_delete_in_range(term, start->row, end->row); } int @@ -1532,27 +1534,12 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows /* Erase scrolled in lines */ for (int r = max(region.end - rows, region.start); r < region.end; r++) { erase_line(term, grid_row_and_alloc(term->grid, r)); + //sixel_delete_at_row(term, r); if (selection_on_row_in_view(term, r)) selection_cancel(term); - - - tll_foreach(term->sixel_images, it) { - if (it->item.grid != term->grid) - continue; - - /* Make it simple - remove the entire image if it starts - * getting scrolled out */ - - int img_top_row = it->item.pos.row & (term->grid->num_rows - 1); - int new_row = (term->grid->offset + r) & (term->grid->num_rows - 1); - - if (img_top_row == new_row) { - sixel_destroy(&it->item); - tll_remove(term->sixel_images, it); - } - } } + sixel_delete_in_range(term, max(region.end - rows, region.start), region.end - 1); term_damage_scroll(term, DAMAGE_SCROLL, region, rows); term->grid->cur_row = grid_row(term->grid, term->cursor.point.row); } @@ -1600,28 +1587,12 @@ term_scroll_reverse_partial(struct terminal *term, /* Erase scrolled in lines */ for (int r = region.start; r < min(region.start + rows, region.end); r++) { erase_line(term, grid_row_and_alloc(term->grid, r)); + //sixel_delete_at_row(term, r); if (selection_on_row_in_view(term, r)) selection_cancel(term); - - tll_foreach(term->sixel_images, it) { - if (it->item.grid != term->grid) - continue; - - /* Make it simple - remove the entire image if it starts - * getting scrolled out */ - - /* TODO: untested */ - - int img_bottom_row = (it->item.pos.row + it->item.rows) & (term->grid->num_rows - 1); - int new_row = (term->grid->offset + r) & (term->grid->num_rows - 1); - - if (img_bottom_row == new_row) { - sixel_destroy(&it->item); - tll_remove(term->sixel_images, it); - } - } } + sixel_delete_in_range(term, region.start, min(region.start + rows, region.end) - 1); term_damage_scroll(term, DAMAGE_SCROLL_REVERSE, region, rows); term->grid->cur_row = grid_row(term->grid, term->cursor.point.row); } diff --git a/terminal.h b/terminal.h index 55311408..53fecf6b 100644 --- a/terminal.h +++ b/terminal.h @@ -237,8 +237,12 @@ struct terminal { int scale; int width; /* pixels */ int height; /* pixels */ - int x_margin; - int y_margin; + struct { + int left; + int right; + int top; + int bottom; + } margins; int cols; /* number of columns */ int rows; /* number of rows */ int cell_width; /* pixels per cell, x-wise */