image.c 6.7 KB

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