1 /* $OpenBSD$ */ 2 3 /* 4 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@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 29 static void 30 image_free(struct image *im) 31 { 32 struct screen *s = im->s; 33 34 TAILQ_REMOVE(&all_images, im, all_entry); 35 all_images_count--; 36 37 TAILQ_REMOVE(&s->images, 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 TAILQ_INSERT_TAIL(&s->images, im, entry); 112 113 TAILQ_INSERT_TAIL(&all_images, im, all_entry); 114 if (++all_images_count == 10/*XXX*/) 115 image_free(TAILQ_FIRST(&all_images)); 116 117 return (im); 118 } 119 120 int 121 image_check_line(struct screen *s, u_int py, u_int ny) 122 { 123 struct image *im, *im1; 124 int redraw = 0; 125 126 TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) { 127 if (py + ny > im->py && py < im->py + im->sy) { 128 image_free(im); 129 redraw = 1; 130 } 131 } 132 return (redraw); 133 } 134 135 int 136 image_check_area(struct screen *s, u_int px, u_int py, u_int nx, u_int ny) 137 { 138 struct image *im, *im1; 139 int redraw = 0; 140 141 TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) { 142 if (py + ny <= im->py || py >= im->py + im->sy) 143 continue; 144 if (px + nx <= im->px || px >= im->px + im->sx) 145 continue; 146 image_free(im); 147 redraw = 1; 148 } 149 return (redraw); 150 } 151 152 int 153 image_scroll_up(struct screen *s, u_int lines) 154 { 155 struct image *im, *im1; 156 int redraw = 0; 157 u_int sx, sy; 158 struct sixel_image *new; 159 160 TAILQ_FOREACH_SAFE(im, &s->images, entry, im1) { 161 if (im->py >= lines) { 162 im->py -= lines; 163 redraw = 1; 164 continue; 165 } 166 if (im->py + im->sy <= lines) { 167 image_free(im); 168 redraw = 1; 169 continue; 170 } 171 sx = im->sx; 172 sy = (im->py + im->sy) - lines; 173 174 new = sixel_scale(im->data, 0, 0, 0, im->sy - sy, sx, sy, 1); 175 sixel_free(im->data); 176 im->data = new; 177 178 im->py = 0; 179 sixel_size_in_cells(im->data, &im->sx, &im->sy); 180 181 free(im->fallback); 182 image_fallback(&im->fallback, im->sx, im->sy); 183 redraw = 1; 184 } 185 return (redraw); 186 } 187