diff --git a/render.c b/render.c index a88aba17..9cad3012 100644 --- a/render.c +++ b/render.c @@ -816,25 +816,66 @@ grid_render(struct terminal *term) cols_updated * term->cell_width, term->cell_height); } - if (term->sixel.pix != NULL) { + tll_foreach(term->sixel_images, it) { + int first_visible_row = -1; + + if (view_end >= term->grid->view) { + /* Not wrapped */ + for (size_t i = it->item.pos.row; + i < it->item.pos.row + (it->item.height + term->cell_height - 1) / term->cell_height; + i++) + { + int row = i & (term->grid->num_rows - 1); + if (row >= term->grid->view && row <= view_end) { + first_visible_row = i; + break; + } + } + } else { + /* Wrapped */ + for (size_t i = it->item.pos.row; + i < it->item.pos.row + (it->item.height + term->cell_height - 1) / term->cell_height; + i++) + { + int row = i & (term->grid->num_rows - 1); + if (row >= term->grid->view || row <= view_end) { + first_visible_row = i; + break; + } + } + } + + if (first_visible_row < 0) + continue; + + const int first_img_row = first_visible_row - it->item.pos.row; + const int row = first_visible_row & (term->grid->num_rows - 1); + const int view_aligned = + (row - term->grid->view + term->grid->num_rows) & (term->grid->num_rows - 1); + + const int x = term->x_margin + it->item.pos.col * term->cell_width; + const int y = max(term->y_margin, term->y_margin + view_aligned * term->cell_height); + + const int width = min(it->item.width, term->width - x - term->x_margin); + const int height = min( + it->item.height - first_img_row * term->cell_height, + term->height - y - term->y_margin); + + //LOG_INFO("x=%d, y=%d, width=%d, height=%d", x, y, width, height); + pixman_image_composite( PIXMAN_OP_SRC, - term->sixel.pix, + it->item.pix, NULL, pix, + 0, first_img_row * term->cell_height, 0, 0, - 0, 0, - 0, 0, - term->sixel.max_col, - term->sixel.row * 6); + x, y, + width, height); + wl_surface_damage_buffer( term->window->surface, - 0, 0, term->sixel.max_col, term->sixel.row * 6); - - pixman_image_unref(term->sixel.pix); - free(term->sixel.image); - term->sixel.pix = NULL; - term->sixel.image = NULL; + x, y, width, height); } if (term->flash.active) { diff --git a/sixel.c b/sixel.c index 2ca783e5..f9c4c4cf 100644 --- a/sixel.c +++ b/sixel.c @@ -18,24 +18,9 @@ static size_t count; void sixel_init(struct terminal *term) { - if (term->sixel.pix != NULL) { - pixman_image_unref(term->sixel.pix); - free(term->sixel.image); - term->sixel.pix = NULL; - term->sixel.image = NULL; - } - assert(term->sixel.palette == NULL); assert(term->sixel.image == NULL); - if (term->sixel.image != NULL) { - if (term->sixel.pix != NULL) { - pixman_image_unref(term->sixel.pix); - term->sixel.pix = NULL; - } - free(term->sixel.image); - } - term->sixel.state = SIXEL_SIXEL; term->sixel.row = 0; term->sixel.col = 0; @@ -58,28 +43,39 @@ sixel_unhook(struct terminal *term) free(term->sixel.palette); term->sixel.palette = NULL; - if (term->sixel.pix != NULL) - pixman_image_unref(term->sixel.pix); - LOG_DBG("generating %dx%d pixman image", term->sixel.row * 6, term->sixel.max_col); - if (term->sixel.col > 0) { + if (term->sixel.col >= 0) { if (term->sixel.col > term->sixel.max_col) term->sixel.max_col = term->sixel.col; term->sixel.row++; term->sixel.col = 0; } - term->sixel.pix = pixman_image_create_bits_no_clear( + struct sixel image = { + .data = term->sixel.image, + .width = term->sixel.max_col, + .height = term->sixel.row * 6, + .pos = (struct coord){term->cursor.point.col, term->grid->offset + term->cursor.point.row}, + }; + + image.pix = pixman_image_create_bits_no_clear( PIXMAN_a8r8g8b8, - term->sixel.max_col, - term->sixel.row * 6, + image.width, image.height, term->sixel.image, IMAGE_WIDTH * sizeof(uint32_t)); - size_t lines = max(1, term->sixel.row * 6 / term->cell_height); + tll_push_back(term->sixel_images, image); + + term->sixel.image = NULL; + term->sixel.max_col = 0; + term->sixel.col = 0; + term->sixel.row = 0; + + const size_t lines = (image.height + term->cell_height - 1) / term->cell_height; for (size_t i = 0; i < lines; i++) term_linefeed(term); + term_formfeed(term); render_refresh(term); } @@ -101,7 +97,7 @@ sixel_add(struct terminal *term, uint32_t color, uint8_t sixel) sixel >>= 1; if (bit) { size_t idx = (term->sixel.row * 6 + i) * IMAGE_WIDTH + term->sixel.col; - term->sixel.image[idx] = 0x00 << 24 | color; + term->sixel.image[idx] = term->colors.alpha / 256 << 24 | color; } } diff --git a/terminal.c b/terminal.c index ba19b552..b80b9898 100644 --- a/terminal.c +++ b/terminal.c @@ -740,6 +740,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct wayland *wayl, .lower_fd = delay_lower_fd, .upper_fd = delay_upper_fd, }, + .sixel_images = tll_init(), .hold_at_exit = conf->hold_at_exit, .shutdown_cb = shutdown_cb, .shutdown_data = shutdown_data, @@ -993,6 +994,12 @@ term_destroy(struct terminal *term) tll_free(term->ptmx_buffer); tll_free(term->tab_stops); + tll_foreach(term->sixel_images, it) { + pixman_image_unref(it->item.pix); + free(it->item.data); + } + tll_free(term->sixel_images); + free(term->foot_exe); free(term->cwd); @@ -1521,6 +1528,21 @@ term_scroll_partial(struct terminal *term, struct scroll_region region, int rows erase_line(term, grid_row_and_alloc(term->grid, r)); if (selection_on_row_in_view(term, r)) selection_cancel(term); + + + tll_foreach(term->sixel_images, it) { + /* 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) { + pixman_image_unref(it->item.pix); + free(it->item.data); + tll_remove(term->sixel_images, it); + } + } } term_damage_scroll(term, DAMAGE_SCROLL, region, rows); @@ -1572,6 +1594,23 @@ term_scroll_reverse_partial(struct terminal *term, erase_line(term, grid_row_and_alloc(term->grid, r)); if (selection_on_row_in_view(term, r)) selection_cancel(term); + + tll_foreach(term->sixel_images, it) { + /* Make it simple - remove the entire image if it starts + * getting scrolled out */ + + /* TODO: untested */ + + int img_rows = (it->item.height + term->cell_height - 1) / term->cell_height; + int img_bottom_row = (it->item.pos.row + img_rows) & (term->grid->num_rows - 1); + int new_row = (term->grid->offset + r) & (term->grid->num_rows - 1); + + if (img_bottom_row == new_row) { + pixman_image_unref(it->item.pix); + free(it->item.data); + tll_remove(term->sixel_images, it); + } + } } term_damage_scroll(term, DAMAGE_SCROLL_REVERSE, region, rows); diff --git a/terminal.h b/terminal.h index 756b0554..69b94624 100644 --- a/terminal.h +++ b/terminal.h @@ -175,6 +175,14 @@ struct ptmx_buffer { size_t idx; }; +struct sixel { + void *data; + pixman_image_t *pix; + int width; + int height; + struct coord pos; +}; + struct terminal { struct fdm *fdm; const struct config *conf; @@ -357,10 +365,10 @@ struct terminal { unsigned int param; unsigned param_idx; - - pixman_image_t *pix; } sixel; + tll(struct sixel) sixel_images; + bool hold_at_exit; bool is_shutting_down; void (*shutdown_cb)(void *data, int exit_code);