1 /* $OpenBSD$ */ 2 3 /* 4 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott (at) gmail.com> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 21 #include <stdlib.h> 22 #include <string.h> 23 24 #include "tmux.h" 25 26 static struct images all_images = TAILQ_HEAD_INITIALIZER(all_images); 27 static u_int all_images_count; 28 #define MAX_IMAGE_COUNT 20 29 30 static void 31 image_free(struct image *im) 32 { 33 34 TAILQ_REMOVE(&all_images, im, all_entry); 35 all_images_count--; 36 37 TAILQ_REMOVE(im->list, im, entry); 38 sixel_free(im->data); 39 free(im->fallback); 40 free(im); 41 } 42 43 int 44 image_free_all(struct screen *s) 45 { 46 struct image *im, *im1; 47 int redraw = !TAILQ_EMPTY(&s->images); 48 49 TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) 50 image_free(im); 51 return (redraw); 52 } 53 54 /* Create text placeholder for an image. */ 55 static void 56 image_fallback(char **ret, u_int sx, u_int sy) 57 { 58 char *buf, *label; 59 u_int py, size, lsize; 60 61 /* Allocate first line. */ 62 lsize = xasprintf(&label, "SIXEL IMAGE (%ux%u)\r\n", sx, sy) + 1; 63 if (sx < lsize - 3) 64 size = lsize - 1; 65 else 66 size = sx + 2; 67 68 /* Remaining lines. Every placeholder line has \r\n at the end. */ 69 size += (sx + 2) * (sy - 1) + 1; 70 *ret = buf = xmalloc(size); 71 72 /* Render first line. */ 73 if (sx < lsize - 3) { 74 memcpy(buf, label, lsize); 75 buf += lsize - 1; 76 } else { 77 memcpy(buf, label, lsize - 3); 78 buf += lsize - 3; 79 memset(buf, '+', sx - lsize + 3); 80 buf += sx - lsize + 3; 81 snprintf(buf, 3, "\r\n"); 82 buf += 2; 83 } 84 85 /* Remaining lines. */ 86 for (py = 1; py < sy; py++) { 87 memset(buf, '+', sx); 88 buf += sx; 89 snprintf(buf, 3, "\r\n"); 90 buf += 2; 91 } 92 93 free(label); 94 } 95 96 struct image* 97 image_store(struct screen *s, struct sixel_image *si) 98 { 99 struct image *im; 100 101 im = xcalloc(1, sizeof *im); 102 im->s = s; 103 im->data = si; 104 105 im->px = s->cx; 106 im->py = s->cy; 107 sixel_size_in_cells(si, &im->sx, &im->sy); 108 109 image_fallback(&im->fallback, im->sx, im->sy); 110 111 im->list = &s->images; 112 TAILQ_INSERT_TAIL(im->list, im, entry); 113 114 TAILQ_INSERT_TAIL(&all_images, im, all_entry); 115 if (++all_images_count == MAX_IMAGE_COUNT) 116 image_free(TAILQ_FIRST(&all_images)); 117 118 return (im); 119 } 120 121 int 122 image_check_line(struct screen *s, u_int py, u_int ny) 123 { 124 struct image *im, *im1; 125 int redraw = 0; 126 127 TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) { 128 if (py + ny > im->py && py < im->py + im->sy) { 129 image_free(im); 130 redraw = 1; 131 } 132 } 133 return (redraw); 134 } 135 136 int 137 image_check_area(struct screen *s, u_int px, u_int py, u_int nx, u_int ny) 138 { 139 struct image *im, *im1; 140 int redraw = 0; 141 142 TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) { 143 if (py + ny <= im->py || py >= im->py + im->sy) 144 continue; 145 if (px + nx <= im->px || px >= im->px + im->sx) 146 continue; 147 image_free(im); 148 redraw = 1; 149 } 150 return (redraw); 151 } 152 153 int 154 image_scroll_up(struct screen *s, u_int lines) 155 { 156 struct image *im, *im1; 157 int redraw = 0; 158 u_int sx, sy; 159 struct sixel_image *new; 160 161 TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) { 162 if (im->py >= lines) { 163 im->py -= lines; 164 redraw = 1; 165 continue; 166 } 167 if (im->py + im->sy <= lines) { 168 image_free(im); 169 redraw = 1; 170 continue; 171 } 172 sx = im->sx; 173 sy = (im->py + im->sy) - lines; 174 175 new = sixel_scale(im->data, 0, 0, 0, im->sy - sy, sx, sy, 1); 176 sixel_free(im->data); 177 im->data = new; 178 179 im->py = 0; 180 sixel_size_in_cells(im->data, &im->sx, &im->sy); 181 182 free(im->fallback); 183 image_fallback(&im->fallback, im->sx, im->sy); 184 redraw = 1; 185 } 186 return (redraw); 187 } 188