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*
tkname2img(TkTop * t,char * name)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
tksizeimage(Tk * tk,TkImg * tki)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*
tkimgbmcreate(TkTop * t,char * arg,int type,char ** ret)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*
tkimgbmdel(TkImg * tki)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
tkimgbmfree(TkImg * tki)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*
tkimage(TkTop * t,char * arg,char ** ret)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
tkimgput(TkImg * tki)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*
tkauximage(TkTop * t,char * s,TkMemimage * m,int repl)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