1 #include "lib9.h" 2 #include <kernel.h> 3 #include "draw.h" 4 #include "tk.h" 5 6 #define O(t, e) ((long)(&((t*)0)->e)) 7 8 char* tkimgbmcreate(TkTop*, char*, int, char**); 9 char* tkimgbmdel(TkImg*); 10 void tkimgbmfree(TkImg*); 11 12 static Rectangle huger = { -1000000, -1000000, 1000000, 1000000 }; 13 14 typedef struct TkImgtype TkImgtype; 15 struct TkImgtype 16 { 17 char* type; 18 char* (*create)(TkTop*, char*, int, char**); 19 char* (*delete)(TkImg*); 20 void (*destroy)(TkImg*); 21 } tkimgopts[] = 22 { 23 "bitmap", tkimgbmcreate, tkimgbmdel, tkimgbmfree, 24 nil, 25 }; 26 27 typedef struct Imgargs Imgargs; 28 struct Imgargs { 29 Image* fgimg; 30 Image* maskimg; 31 }; 32 33 TkImg* 34 tkname2img(TkTop *t, char *name) 35 { 36 TkImg *tki; 37 38 for(tki = t->imgs; tki; tki = tki->link) 39 if((tki->name != nil) && strcmp(tki->name->name, name) == 0) 40 return tki; 41 42 return nil; 43 } 44 45 TkOption 46 bitopt[] = 47 { 48 "file", OPTbmap, O(Imgargs, fgimg), nil, 49 "maskfile", OPTbmap, O(Imgargs, maskimg), nil, 50 nil 51 }; 52 53 void 54 tksizeimage(Tk *tk, TkImg *tki) 55 { 56 int dx, dy, repack; 57 58 dx = 0; 59 dy = 0; 60 if(tki->img != nil) { 61 dx = Dx(tki->img->r); 62 dy = Dy(tki->img->r); 63 } 64 repack = 0; 65 if(tki->ref > 1 && (tki->w != dx || tki->h != dy)) 66 repack = 1; 67 tki->w = dx; 68 tki->h = dy; 69 70 if(repack) { 71 tkpackqit(tk); 72 tkrunpack(tk->env->top); 73 } 74 } 75 76 char* 77 tkimgbmcreate(TkTop *t, char *arg, int type, char **ret) 78 { 79 TkName *names; 80 TkImg *tki, *f; 81 TkOptab tko[2]; 82 char buf[32]; 83 static int id; 84 char *e = nil; 85 Imgargs iargs; 86 Rectangle r; 87 Display *d; 88 int chan; 89 int locked; 90 91 d = t->display; 92 locked = 0; 93 94 tki = malloc(sizeof(TkImg)); 95 if(tki == nil) 96 return TkNomem; 97 98 tki->env = tkdefaultenv(t); 99 if(tki->env == nil) 100 goto err; 101 tki->type = type; 102 tki->ref = 1; 103 tki->top = t; 104 105 iargs.fgimg = nil; 106 iargs.maskimg = nil; 107 108 tko[0].ptr = &iargs; 109 tko[0].optab = bitopt; 110 tko[1].ptr = nil; 111 112 names = nil; 113 e = tkparse(t, arg, tko, &names); 114 if(e != nil) 115 goto err; 116 117 if (iargs.fgimg == nil && iargs.maskimg != nil) { 118 locked = lockdisplay(d); 119 r = Rect(0, 0, Dx(iargs.maskimg->r), Dy(iargs.maskimg->r)); 120 tki->img = allocimage(d, r, CHAN2(CAlpha, 8, CGrey, 8), 0, DTransparent); 121 if (tki->img != nil) 122 draw(tki->img, r, nil, iargs.maskimg, iargs.maskimg->r.min); 123 freeimage(iargs.maskimg); 124 125 } else if (iargs.fgimg != nil && iargs.maskimg != nil) { 126 locked = lockdisplay(d); 127 r = Rect(0, 0, Dx(iargs.fgimg->r), Dy(iargs.fgimg->r)); 128 if (tkchanhastype(iargs.fgimg->chan, CGrey)) 129 chan = CHAN2(CAlpha, 8, CGrey, 8); 130 else 131 chan = RGBA32; 132 tki->img = allocimage(d, r, chan, 0, DTransparent); 133 if (tki->img != nil) 134 draw(tki->img, r, iargs.fgimg, iargs.maskimg, iargs.fgimg->r.min); 135 freeimage(iargs.fgimg); 136 freeimage(iargs.maskimg); 137 } else { 138 tki->img = iargs.fgimg; 139 } 140 if (locked) 141 unlockdisplay(d); 142 143 if(names == nil) { 144 sprint(buf, "image%d", id++); 145 tki->name = tkmkname(buf); 146 if(tki->name == nil) 147 goto err; 148 } 149 else { 150 /* XXX should mark as dirty any widgets using the named 151 * image - some notification scheme needs putting in place 152 */ 153 tki->name = names; 154 tkfreename(names->link); 155 names->link = nil; 156 } 157 158 tksizeimage(t->root, tki); 159 160 if (tki->name != nil) { 161 f = tkname2img(t, tki->name->name); 162 if(f != nil) 163 tkimgopts[f->type].delete(f); 164 } 165 166 tki->link = t->imgs; 167 t->imgs = tki; 168 169 if (tki->name != nil) { 170 e = tkvalue(ret, "%s", tki->name->name); 171 if(e == nil) 172 return nil; 173 } 174 err: 175 tkputenv(tki->env); 176 if(tki->img != nil) { 177 locked = lockdisplay(d); 178 freeimage(tki->img); 179 if (locked) 180 unlockdisplay(d); 181 } 182 tkfreename(tki->name); 183 free(tki); 184 return e != nil ? e : TkNomem; 185 } 186 187 char* 188 tkimgbmdel(TkImg *tki) 189 { 190 TkImg **l, *f; 191 192 l = &tki->top->imgs; 193 for(f = *l; f; f = f->link) { 194 if(f == tki) { 195 *l = tki->link; 196 tkimgput(tki); 197 return nil; 198 } 199 l = &f->link; 200 } 201 return TkBadvl; 202 } 203 204 void 205 tkimgbmfree(TkImg *tki) 206 { 207 int locked; 208 Display *d; 209 210 d = tki->top->display; 211 locked = lockdisplay(d); 212 freeimage(tki->img); 213 if(locked) 214 unlockdisplay(d); 215 216 free(tki->cursor); 217 tkfreename(tki->name); 218 tkputenv(tki->env); 219 220 free(tki); 221 } 222 223 char* 224 tkimage(TkTop *t, char *arg, char **ret) 225 { 226 int i; 227 TkImg *tkim; 228 char *fmt, *e, *buf, *cmd; 229 230 buf = mallocz(Tkmaxitem, 0); 231 if(buf == nil) 232 return TkNomem; 233 cmd = mallocz(Tkminitem, 0); 234 if(cmd == nil) { 235 free(buf); 236 return TkNomem; 237 } 238 239 arg = tkword(t, arg, cmd, cmd+Tkminitem, nil); 240 if(strcmp(cmd, "create") == 0) { 241 arg = tkword(t, arg, buf, buf+Tkmaxitem, nil); 242 for(i = 0; tkimgopts[i].type != nil; i++) 243 if(strcmp(buf, tkimgopts[i].type) == 0) { 244 e = tkimgopts[i].create(t, arg, i, ret); 245 goto ret; 246 } 247 e = TkBadvl; 248 goto ret; 249 } 250 if(strcmp(cmd, "names") == 0) { 251 fmt = "%s"; 252 for(tkim = t->imgs; tkim; tkim = tkim->link) { 253 if (tkim->name != nil) { 254 e = tkvalue(ret, fmt, tkim->name->name); 255 if(e != nil) 256 goto ret; 257 } 258 fmt = " %s"; 259 } 260 e = nil; 261 goto ret; 262 } 263 264 arg = tkword(t, arg, buf, buf+Tkmaxitem, nil); 265 tkim = tkname2img(t, buf); 266 if(tkim == nil) { 267 e = TkBadvl; 268 goto ret; 269 } 270 271 if(strcmp(cmd, "height") == 0) { 272 e = tkvalue(ret, "%d", tkim->h); 273 goto ret; 274 } 275 if(strcmp(cmd, "width") == 0) { 276 e = tkvalue(ret, "%d", tkim->w); 277 goto ret; 278 } 279 if(strcmp(cmd, "type") == 0) { 280 e = tkvalue(ret, "%s", tkimgopts[tkim->type].type); 281 goto ret; 282 } 283 if(strcmp(cmd, "delete") == 0) { 284 for (;;) { 285 e = tkimgopts[tkim->type].delete(tkim); 286 if (e != nil) 287 break; 288 arg = tkword(t, arg, buf, buf+Tkmaxitem, nil); 289 if (buf[0] == '\0') 290 break; 291 tkim = tkname2img(t, buf); 292 if (tkim == nil) { 293 e = TkBadvl; 294 break; 295 } 296 } 297 goto ret; 298 } 299 300 e = TkBadcm; 301 ret: 302 free(cmd); 303 free(buf); 304 return e; 305 } 306 307 void 308 tkimgput(TkImg *tki) 309 { 310 if(tki == nil) 311 return; 312 313 if(--tki->ref > 0) 314 return; 315 316 tkimgopts[tki->type].destroy(tki); 317 } 318 319 TkImg* 320 tkauximage(TkTop *t, char* s, TkMemimage *m, int repl) 321 { 322 TkName *name; 323 TkCtxt *c; 324 TkImg *tki; 325 Display *d; 326 Image *i; 327 int locked, nbytes; 328 329 tki = tkname2img(t, s); 330 if (tki != nil) { 331 tki->ref++; 332 return tki; 333 } 334 335 name = tkmkname(s); 336 if (name == nil) 337 return nil; 338 tki = mallocz(sizeof(*tki), 1); 339 if (tki == nil) 340 goto err; 341 tki->env = tkdefaultenv(t); 342 if(tki->env == nil) 343 goto err; 344 345 c = t->ctxt; 346 d = c->display; 347 348 nbytes = bytesperline(m->r, chantodepth(m->chans))*Dy(m->r); 349 locked = lockdisplay(d); 350 i = allocimage(d, m->r, m->chans, repl, DTransparent); 351 if (i != nil) { 352 if (loadimage(i, m->r, m->data, nbytes) != nbytes) { 353 freeimage(i); 354 i = nil; 355 } 356 if (repl) 357 replclipr(i, 1, huger); /* TO DO: doesn't allocimage do this? */ 358 } 359 if (locked) 360 unlockdisplay(d); 361 if (i == nil) 362 goto err; 363 tki->top = t; 364 tki->ref = 2; /* t->imgs ref and the ref we are returning */ 365 tki->type = 0; /* bitmap */ 366 tki->w = Dx(m->r); 367 tki->h = Dy(m->r); 368 tki->img = i; 369 tki->name = name; 370 tki->link = t->imgs; 371 t->imgs = tki; 372 return tki; 373 err: 374 if (tki != nil) { 375 tkputenv(tki->env); 376 free(tki); 377 } 378 tkfreename(name); 379 return nil; 380 } 381