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 /* Note - could actually allocate buf and cmd in one buffer - DBK */ 231 buf = mallocz(Tkmaxitem, 0); 232 if(buf == nil) 233 return TkNomem; 234 cmd = mallocz(Tkminitem, 0); 235 if(cmd == nil) { 236 free(buf); 237 return TkNomem; 238 } 239 240 arg = tkword(t, arg, cmd, cmd+Tkminitem, nil); 241 if(strcmp(cmd, "create") == 0) { 242 arg = tkword(t, arg, buf, buf+Tkmaxitem, nil); 243 for(i = 0; tkimgopts[i].type != nil; i++) 244 if(strcmp(buf, tkimgopts[i].type) == 0) { 245 e = tkimgopts[i].create(t, arg, i, ret); 246 goto ret; 247 } 248 e = TkBadvl; 249 goto ret; 250 } 251 if(strcmp(cmd, "names") == 0) { 252 fmt = "%s"; 253 for(tkim = t->imgs; tkim; tkim = tkim->link) { 254 if (tkim->name != nil) { 255 e = tkvalue(ret, fmt, tkim->name->name); 256 if(e != nil) 257 goto ret; 258 } 259 fmt = " %s"; 260 } 261 e = nil; 262 goto ret; 263 } 264 265 arg = tkword(t, arg, buf, buf+Tkmaxitem, nil); 266 tkim = tkname2img(t, buf); 267 if(tkim == nil) { 268 e = TkBadvl; 269 goto ret; 270 } 271 272 if(strcmp(cmd, "height") == 0) { 273 e = tkvalue(ret, "%d", tkim->h); 274 goto ret; 275 } 276 if(strcmp(cmd, "width") == 0) { 277 e = tkvalue(ret, "%d", tkim->w); 278 goto ret; 279 } 280 if(strcmp(cmd, "type") == 0) { 281 e = tkvalue(ret, "%s", tkimgopts[tkim->type].type); 282 goto ret; 283 } 284 if(strcmp(cmd, "delete") == 0) { 285 for (;;) { 286 e = tkimgopts[tkim->type].delete(tkim); 287 if (e != nil) 288 break; 289 arg = tkword(t, arg, buf, buf+Tkmaxitem, nil); 290 if (buf[0] == '\0') 291 break; 292 tkim = tkname2img(t, buf); 293 if (tkim == nil) { 294 e = TkBadvl; 295 break; 296 } 297 } 298 goto ret; 299 } 300 301 e = TkBadcm; 302 ret: 303 free(cmd); 304 free(buf); 305 return e; 306 } 307 308 void 309 tkimgput(TkImg *tki) 310 { 311 if(tki == nil) 312 return; 313 314 if(--tki->ref > 0) 315 return; 316 317 tkimgopts[tki->type].destroy(tki); 318 } 319 320 TkImg* 321 tkauximage(TkTop *t, char* s, uchar* bytes, int nbytes, int chans, Rectangle r, int repl) 322 { 323 TkName *name; 324 TkCtxt *c; 325 TkImg *tki; 326 Display *d; 327 Image *i; 328 int locked; 329 330 tki = tkname2img(t, s); 331 if (tki != nil) { 332 tki->ref++; 333 return tki; 334 } 335 336 name = tkmkname(s); 337 if (name == nil) 338 return nil; 339 tki = mallocz(sizeof(*tki), 0); 340 if (tki == nil) 341 goto err; 342 tki->env = tkdefaultenv(t); 343 if(tki->env == nil) 344 goto err; 345 346 c = t->ctxt; 347 d = c->display; 348 349 locked = lockdisplay(d); 350 i = allocimage(d, r, chans, repl, DTransparent); 351 if (i != nil) { 352 if (loadimage(i, r, bytes, nbytes) != nbytes) { 353 freeimage(i); 354 i = nil; 355 } 356 if (repl) 357 replclipr(i, 1, huger); 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(r); 367 tki->h = Dy(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