utils.c 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124
  1. #include "lib9.h"
  2. #include "draw.h"
  3. #include "tk.h"
  4. struct TkCol
  5. {
  6. ulong rgba1;
  7. ulong rgba3; /* if mixed, otherwise DNotacolor */
  8. Image* i;
  9. TkCol* forw;
  10. };
  11. extern void rptwakeup(void*, void*);
  12. extern void* rptproc(char*, int, void*, int (*)(void*), int (*)(void*,int), void (*)(void*));
  13. typedef struct Cmd Cmd;
  14. struct Cmd
  15. {
  16. char* name;
  17. char* (*fn)(TkTop*, char*, char**);
  18. };
  19. static struct Cmd cmdmain[] =
  20. {
  21. "bind", tkbind,
  22. "button", tkbutton,
  23. "canvas", tkcanvas,
  24. "checkbutton", tkcheckbutton,
  25. "choicebutton", tkchoicebutton,
  26. "cursor", tkcursorcmd,
  27. "destroy", tkdestroy,
  28. "entry", tkentry,
  29. "focus", tkfocus,
  30. "frame", tkframe,
  31. "grab", tkgrab,
  32. "grid", tkgrid,
  33. "image", tkimage,
  34. "label", tklabel,
  35. "listbox", tklistbox,
  36. "lower", tklower,
  37. "menu", tkmenu,
  38. "menubutton", tkmenubutton,
  39. "pack", tkpack,
  40. "panel", tkpanel,
  41. "puts", tkputs,
  42. "radiobutton", tkradiobutton,
  43. "raise", tkraise,
  44. "scale", tkscale,
  45. "scrollbar", tkscrollbar,
  46. "see", tkseecmd,
  47. "send", tksend,
  48. "text", tktext,
  49. "update", tkupdatecmd,
  50. "variable", tkvariable,
  51. "winfo", tkwinfo,
  52. };
  53. char* tkfont;
  54. /*
  55. * auto-repeating support
  56. * should perhaps be one rptproc per TkCtxt
  57. * This is not done for the moment as there isn't
  58. * a mechanism for terminating the rptproc
  59. */
  60. static void *autorpt;
  61. static int rptid;
  62. static Tk *rptw;
  63. static void *rptnote;
  64. static void (*rptcb)(Tk*, void*, int);
  65. static long rptto;
  66. static int rptint;
  67. /* blinking carets - should be per TkCtxt */
  68. static void *blinkrpt;
  69. static Tk *blinkw;
  70. static void (*blinkcb)(Tk*, int);
  71. static int blinkignore;
  72. static int blinkon;
  73. ulong
  74. tkrgba(int r, int g, int b, int a)
  75. {
  76. ulong p;
  77. if(r < 0)
  78. r = 0;
  79. else if(r > 255)
  80. r = 255;
  81. if(g < 0)
  82. g = 0;
  83. else if(g > 255)
  84. g = 255;
  85. if(b < 0)
  86. b = 0;
  87. else if(b > 255)
  88. b = 255;
  89. p = (r<<24)|(g<<16)|(b<<8)|0xFF;
  90. if(a == 255)
  91. return p;
  92. return setalpha(p, a);
  93. }
  94. /* to be replaced */
  95. static int
  96. revalpha(int c, int a)
  97. {
  98. if (a == 0)
  99. return 0;
  100. return (c & 0xff) * 255 / a;
  101. }
  102. void
  103. tkrgbavals(ulong rgba, int *R, int *G, int *B, int *A)
  104. {
  105. int a;
  106. a = rgba & 0xff;
  107. *A = a;
  108. if (a != 0xff) {
  109. *R = revalpha(rgba>>24, a);
  110. *G = revalpha((rgba>>16) & 0xFF, a);
  111. *B = revalpha((rgba >> 8) & 0xFF, a);
  112. } else {
  113. *R = (rgba>>24);
  114. *G = ((rgba>>16) & 0xFF);
  115. *B = ((rgba >> 8) & 0xFF);
  116. }
  117. }
  118. static int
  119. tkcachecol(TkCtxt *c, Image *i, ulong one, ulong three)
  120. {
  121. TkCol *cc;
  122. cc = malloc(sizeof(*cc));
  123. if(cc == nil)
  124. return 0;
  125. cc->rgba1 = one;
  126. cc->rgba3 = three;
  127. cc->i = i;
  128. cc->forw = c->chead;
  129. c->chead = cc;
  130. c->ncol++;
  131. /* we'll do LRU management at some point */
  132. if(c->ncol > TkColcachesize){
  133. static int warn;
  134. if(warn == 0){
  135. warn = 1;
  136. print("tk: %d colours cached\n", TkColcachesize);
  137. }
  138. }
  139. return 1;
  140. }
  141. static Image*
  142. tkfindcol(TkCtxt *c, ulong one, ulong three)
  143. {
  144. TkCol *cc, **l;
  145. for(l = &c->chead; (cc = *l) != nil; l = &cc->forw)
  146. if(cc->rgba1 == one && cc->rgba3 == three){
  147. /* move it up in the list */
  148. *l = cc->forw;
  149. cc->forw = c->chead;
  150. c->chead = cc;
  151. /* we assume it will be used right away and not stored */
  152. return cc->i;
  153. }
  154. return nil;
  155. }
  156. void
  157. tkfreecolcache(TkCtxt *c)
  158. {
  159. TkCol *cc;
  160. if(c == nil)
  161. return;
  162. while((cc = c->chead) != nil){
  163. c->chead = cc->forw;
  164. freeimage(cc->i);
  165. free(cc);
  166. }
  167. c->ctail = nil;
  168. c->ncol = 0;
  169. }
  170. Image*
  171. tkcolormix(TkCtxt *c, ulong one, ulong three)
  172. {
  173. Image *i;
  174. Display *d;
  175. i = tkfindcol(c, one, three);
  176. if(i != nil)
  177. return i;
  178. d = c->display;
  179. i = allocimagemix(d, one, three);
  180. if(i == nil)
  181. return d->black;
  182. if(!tkcachecol(c, i, one, three)){
  183. freeimage(i);
  184. return d->black;
  185. }
  186. return i;
  187. }
  188. Image*
  189. tkcolor(TkCtxt *c, ulong pix)
  190. {
  191. Image *i;
  192. Display *d;
  193. Rectangle r;
  194. d = c->display;
  195. if(pix == DWhite)
  196. return d->white;
  197. if(pix == DBlack)
  198. return d->black;
  199. i = tkfindcol(c, pix, DNotacolor);
  200. if(i != nil)
  201. return i;
  202. r.min = ZP;
  203. r.max.x = 1;
  204. r.max.y = 1;
  205. if ((pix & 0xff) == 0xff)
  206. i = allocimage(d, r, RGB24, 1, pix);
  207. else
  208. i = allocimage(d, r, RGBA32, 1, pix);
  209. if(i == nil)
  210. return d->black;
  211. if(!tkcachecol(c, i, pix, DNotacolor)) {
  212. freeimage(i);
  213. return d->black;
  214. }
  215. return i;
  216. }
  217. Image*
  218. tkgradient(TkCtxt *c, Rectangle r, int dir, ulong pix0, ulong pix1)
  219. {
  220. Display *d;
  221. Image *i;
  222. uchar *b, *p, *e;
  223. int c0[3], c1[3], delta[3], a, j, x, y, n, locked;
  224. Rectangle s;
  225. d = c->display;
  226. y = Dy(r);
  227. x = Dx(r);
  228. if(x <= 0 || y <= 0) {
  229. r = Rect(0, 0, 1, 1);
  230. x = y = 1;
  231. }
  232. /* TO DO: diagonal */
  233. s = r;
  234. if(dir == Tkhorizontal){
  235. n = x;
  236. r.max.y = r.min.y+1;
  237. }else{
  238. n = y;
  239. r.max.x = r.min.x+1;
  240. }
  241. b = mallocz(3*n, 0);
  242. if(b == nil)
  243. return nil;
  244. locked = lockdisplay(d);
  245. i = allocimage(d, r, RGB24, 1, DNofill);
  246. if(i == nil)
  247. goto Ret;
  248. tkrgbavals(pix0, &c0[2], &c0[1], &c0[0], &a);
  249. tkrgbavals(pix1, &c1[2], &c1[1], &c1[0], &a);
  250. for(j = 0; j < 3; j++){
  251. c0[j] <<= 12;
  252. c1[j] <<= 12;
  253. delta[j] = ((c1[j]-c0[j])+(1<<11))/n;
  254. }
  255. e = b+3*n;
  256. for(p = b; p < e; p += 3) {
  257. p[0] = c0[0]>>12;
  258. p[1] = c0[1]>>12;
  259. p[2] = c0[2]>>12;
  260. c0[0] += delta[0];
  261. c0[1] += delta[1];
  262. c0[2] += delta[2];
  263. }
  264. loadimage(i, r, b, 3*n);
  265. replclipr(i, 1, s);
  266. Ret:
  267. if(locked)
  268. unlockdisplay(d);
  269. free(b);
  270. return i;
  271. }
  272. /*
  273. * XXX should be in libdraw?
  274. */
  275. int
  276. tkchanhastype(ulong c, int t)
  277. {
  278. for(; c; c>>=8)
  279. if(TYPE(c) == t)
  280. return 1;
  281. return 0;
  282. }
  283. void
  284. tksettransparent(Tk *tk, int transparent)
  285. {
  286. if (transparent)
  287. tk->flag |= Tktransparent;
  288. else
  289. tk->flag &= ~Tktransparent;
  290. }
  291. int
  292. tkhasalpha(TkEnv *e, int col)
  293. {
  294. return (e->colors[col] & 0xff) != 0xff;
  295. }
  296. Image*
  297. tkgc(TkEnv *e, int col)
  298. {
  299. return tkcolor(e->top->ctxt, e->colors[col]);
  300. }
  301. /*
  302. * Todo: improve the fixed-point code
  303. * the 255 scale factor is used because RGB ranges 0-255
  304. */
  305. static void
  306. rgb2hsv(int r, int g, int b, int *h, int *s, int *v)
  307. {
  308. int min, max, delta;
  309. max = r;
  310. if(g > max)
  311. max = g;
  312. if(b > max)
  313. max = b;
  314. min = r;
  315. if(g < min)
  316. min = g;
  317. if(b < min)
  318. min = b;
  319. *v = max;
  320. if (max != 0)
  321. *s = ((max - min)*255) / max;
  322. else
  323. *s = 0;
  324. if (*s == 0) {
  325. *h = 0; /* undefined */
  326. } else {
  327. delta = max - min;
  328. if (r == max)
  329. *h = (g - b)*255 / delta;
  330. else if (g == max)
  331. *h = (2*255) + ((b - r)*255) / delta;
  332. else if (b == max)
  333. *h = (4*255) + ((r - g)*255)/ delta;
  334. *h *= 60;
  335. if (*h < 0)
  336. *h += 360*255;
  337. *h /= 255;
  338. }
  339. }
  340. static void
  341. hsv2rgb(int h, int s, int v, int *r, int *g, int *b)
  342. {
  343. int i;
  344. int f,p,q,t;
  345. if (s == 0 && h == 0) {
  346. *r = *g = *b = v; /* achromatic case */
  347. } else {
  348. if (h >= 360)
  349. h = 0;
  350. i = h / 60;
  351. h *= 255;
  352. h /= 60;
  353. f = h % 255;
  354. p = v * (255 - s);
  355. q = v * (255 - ((s * f)/255));
  356. t = v * (255- ((s * (255 - f))/255));
  357. p /= 255;
  358. q /= 255;
  359. t /= 255;
  360. switch (i) {
  361. case 0: *r = v; *g = t; *b = p; break;
  362. case 1: *r = q; *g = v; *b = p; break;
  363. case 2: *r = p; *g = v; *b = t; break;
  364. case 3: *r = p; *g = q; *b = v; break;
  365. case 4: *r = t; *g = p; *b = v; break;
  366. case 5: *r = v; *g = p; *b = q; break;
  367. }
  368. }
  369. }
  370. enum {
  371. MINDELTA = 0x10,
  372. DELTA = 0x30,
  373. };
  374. ulong
  375. tkrgbashade(ulong rgba, int shade)
  376. {
  377. int R, G, B, A, h, s, v, vl, vd;
  378. if (shade == TkSameshade)
  379. return rgba;
  380. tkrgbavals(rgba, &R, &G, &B, &A);
  381. h = s = v = 0;
  382. rgb2hsv(R, G, B, &h, &s, &v);
  383. if (v < MINDELTA) {
  384. vd = v+DELTA;
  385. vl = vd+DELTA;
  386. } else if (v > 255-MINDELTA) {
  387. vl = v-DELTA;
  388. vd = vl-DELTA;
  389. } else {
  390. vl = v+DELTA;
  391. vd = v-DELTA;
  392. }
  393. v = (shade == TkLightshade)?vl:vd;
  394. if (v < 0)
  395. v = 0;
  396. if (v > 255)
  397. v = 255;
  398. hsv2rgb(h, s, v, &R, &G, &B);
  399. return tkrgba(R, G, B, A);
  400. }
  401. Image*
  402. tkgshade(TkEnv *e, int col, int shade)
  403. {
  404. ulong rgba;
  405. if (col == TkCbackgnd || col == TkCselectbgnd || col == TkCactivebgnd)
  406. return tkgc(e, col+shade);
  407. rgba = tkrgbashade(e->colors[col], shade);
  408. return tkcolor(e->top->ctxt, rgba);
  409. }
  410. TkEnv*
  411. tknewenv(TkTop *t)
  412. {
  413. TkEnv *e;
  414. e = malloc(sizeof(TkEnv));
  415. if(e == nil)
  416. return nil;
  417. e->ref = 1;
  418. e->top = t;
  419. return e;
  420. }
  421. TkEnv*
  422. tkdefaultenv(TkTop *t)
  423. {
  424. int locked;
  425. TkEnv *env;
  426. Display *d;
  427. if(t->env != nil) {
  428. t->env->ref++;
  429. return t->env;
  430. }
  431. t->env = malloc(sizeof(TkEnv));
  432. if(t->env == nil)
  433. return nil;
  434. env = t->env;
  435. env->ref = 1;
  436. env->top = t;
  437. if(tkfont == nil)
  438. tkfont = "/fonts/pelm/unicode.8.font";
  439. d = t->display;
  440. env->font = font_open(d, tkfont);
  441. if(env->font == nil) {
  442. static int warn;
  443. if(warn == 0) {
  444. warn = 1;
  445. print("tk: font not found: %s\n", tkfont);
  446. }
  447. env->font = font_open(d, "*default*");
  448. if(env->font == nil) {
  449. free(t->env);
  450. t->env = nil;
  451. return nil;
  452. }
  453. }
  454. locked = lockdisplay(d);
  455. env->wzero = stringwidth(env->font, "0");
  456. if ( env->wzero <= 0 )
  457. env->wzero = env->font->height / 2;
  458. if(locked)
  459. unlockdisplay(d);
  460. tksetenvcolours(env);
  461. return env;
  462. }
  463. void
  464. tkputenv(TkEnv *env)
  465. {
  466. Display *d;
  467. int locked;
  468. if(env == nil)
  469. return;
  470. env->ref--;
  471. if(env->ref != 0)
  472. return;
  473. d = env->top->display;
  474. locked = lockdisplay(d);
  475. if(env->font != nil)
  476. font_close(env->font);
  477. if(locked)
  478. unlockdisplay(d);
  479. free(env);
  480. }
  481. TkEnv*
  482. tkdupenv(TkEnv **env)
  483. {
  484. Display *d;
  485. TkEnv *e, *ne;
  486. e = *env;
  487. if(e->ref == 1)
  488. return e;
  489. ne = malloc(sizeof(TkEnv));
  490. if(ne == nil)
  491. return nil;
  492. ne->ref = 1;
  493. ne->top = e->top;
  494. d = e->top->display;
  495. memmove(ne->colors, e->colors, sizeof(e->colors));
  496. ne->set = e->set;
  497. ne->font = font_open(d, e->font->name);
  498. ne->wzero = e->wzero;
  499. e->ref--;
  500. *env = ne;
  501. return ne;
  502. }
  503. Tk*
  504. tknewobj(TkTop *t, int type, int n)
  505. {
  506. Tk *tk;
  507. tk = malloc(n);
  508. if(tk == 0)
  509. return 0;
  510. tk->type = type; /* Defaults */
  511. tk->flag = Tktop;
  512. tk->relief = TKflat;
  513. tk->env = tkdefaultenv(t);
  514. if(tk->env == nil) {
  515. free(tk);
  516. return nil;
  517. }
  518. return tk;
  519. }
  520. void
  521. tkfreebind(TkAction *a)
  522. {
  523. TkAction *next;
  524. while(a != nil) {
  525. next = a->link;
  526. if((a->type & 0xff) == TkDynamic)
  527. free(a->arg);
  528. free(a);
  529. a = next;
  530. }
  531. }
  532. void
  533. tkfreename(TkName *f)
  534. {
  535. TkName *n;
  536. while(f != nil) {
  537. n = f->link;
  538. free(f);
  539. f = n;
  540. }
  541. }
  542. void
  543. tkfreeobj(Tk *tk)
  544. {
  545. TkCtxt *c;
  546. c = tk->env->top->ctxt;
  547. if(c != nil) {
  548. if(c->tkkeygrab == tk)
  549. c->tkkeygrab = nil;
  550. if(c->mgrab == tk)
  551. tksetmgrab(tk->env->top, nil);
  552. if(c->mfocus == tk)
  553. c->mfocus = nil;
  554. if(c->entered == tk)
  555. c->entered = nil;
  556. }
  557. if (tk == rptw) {
  558. /* cancel the autorepeat without notifying the widget */
  559. rptid++;
  560. rptw = nil;
  561. }
  562. if (tk == blinkw)
  563. blinkw = nil;
  564. tkextnfreeobj(tk);
  565. tkmethod[tk->type]->free(tk);
  566. tkputenv(tk->env);
  567. tkfreebind(tk->binds);
  568. if(tk->name != nil)
  569. free(tk->name);
  570. free(tk);
  571. }
  572. char*
  573. tkaddchild(TkTop *t, Tk *tk, TkName **names)
  574. {
  575. TkName *n;
  576. Tk *f, **l;
  577. int found, len;
  578. char *s, *ep;
  579. n = *names;
  580. if(n == nil || n->name[0] != '.'){
  581. if(n != nil)
  582. tkerr(t, n->name);
  583. return TkBadwp;
  584. }
  585. if (n->name[1] == '\0')
  586. return TkDupli;
  587. /*
  588. * check that the name is well-formed.
  589. * ep will point to end of parent component of the name.
  590. */
  591. ep = nil;
  592. for (s = n->name + 1; *s; s++) {
  593. if (*s == '.'){
  594. tkerr(t, n->name);
  595. return TkBadwp;
  596. }
  597. for (; *s && *s != '.'; s++)
  598. ;
  599. if (*s == '\0')
  600. break;
  601. ep = s;
  602. }
  603. if (ep == s - 1){
  604. tkerr(t, n->name);
  605. return TkBadwp;
  606. }
  607. if (ep == nil)
  608. ep = n->name + 1;
  609. len = ep - n->name;
  610. found = 0;
  611. l = &t->root;
  612. for(f = *l; f; f = f->siblings) {
  613. if (f->name != nil) {
  614. if (strcmp(n->name, f->name->name) == 0)
  615. return TkDupli;
  616. if (!found &&
  617. strncmp(n->name, f->name->name, len) == 0 &&
  618. f->name->name[len] == '\0')
  619. found = 1;
  620. }
  621. l = &f->siblings;
  622. }
  623. if (0) { /* don't enable this until a reasonably major release... if ever */
  624. /*
  625. * parent widget must already exist
  626. */
  627. if (!found){
  628. tkerr(t, n->name);
  629. return TkBadwp;
  630. }
  631. }
  632. *l = tk;
  633. tk->name = n;
  634. *names = n->link;
  635. return nil;
  636. }
  637. Tk*
  638. tklook(TkTop *t, char *wp, int parent)
  639. {
  640. Tk *f;
  641. char *p, *q;
  642. if(wp == nil)
  643. return nil;
  644. if(parent) {
  645. p = strdup(wp);
  646. if(p == nil)
  647. return nil;
  648. q = strrchr(p, '.');
  649. if(q == nil)
  650. abort();
  651. if(q == p) {
  652. free(p);
  653. return t->root;
  654. }
  655. *q = '\0';
  656. } else
  657. p = wp;
  658. for(f = t->root; f; f = f->siblings)
  659. if ((f->name != nil) && (strcmp(f->name->name, p) == 0))
  660. break;
  661. if(f != nil && (f->flag & Tkdestroy))
  662. f = nil;
  663. if (parent)
  664. free(p);
  665. return f;
  666. }
  667. void
  668. tktextsdraw(Image *img, Rectangle r, TkEnv *e, int sbw)
  669. {
  670. Image *l, *d;
  671. Rectangle s;
  672. draw(img, r, tkgc(e, TkCselectbgnd), nil, ZP);
  673. s.min = r.min;
  674. s.min.x -= sbw;
  675. s.min.y -= sbw;
  676. s.max.x = r.max.x;
  677. s.max.y = r.min.y;
  678. l = tkgc(e, TkCselectbgndlght);
  679. draw(img, s, l, nil, ZP);
  680. s.max.x = s.min.x + sbw;
  681. s.max.y = r.max.y + sbw;
  682. draw(img, s, l, nil, ZP);
  683. s.max = r.max;
  684. s.max.x += sbw;
  685. s.max.y += sbw;
  686. s.min.x = r.min.x;
  687. s.min.y = r.max.y;
  688. d = tkgc(e, TkCselectbgnddark);
  689. draw(img, s, d, nil, ZP);
  690. s.min.x = r.max.x;
  691. s.min.y = r.min.y - sbw;
  692. draw(img, s, d, nil, ZP);
  693. }
  694. void
  695. tkbox(Image *i, Rectangle r, int bd, Image *fill)
  696. {
  697. if (bd > 0) {
  698. draw(i, Rect(r.min.x, r.min.y, r.max.x, r.min.y+bd), fill, nil, ZP);
  699. draw(i, Rect(r.min.x, r.min.y+bd, r.min.x+bd, r.max.y-bd), fill, nil, ZP);
  700. draw(i, Rect(r.min.x, r.max.y-bd, r.max.x, r.max.y), fill, nil, ZP);
  701. draw(i, Rect(r.max.x-bd, r.min.y+bd, r.max.x, r.max.y), fill, nil, ZP);
  702. }
  703. }
  704. void
  705. tkbevel(Image *i, Point o, int w, int h, int bw, Image *top, Image *bottom)
  706. {
  707. Rectangle r;
  708. int x, border;
  709. border = 2 * bw;
  710. r.min = o;
  711. r.max.x = r.min.x + w + border;
  712. r.max.y = r.min.y + bw;
  713. draw(i, r, top, nil, ZP);
  714. r.max.x = r.min.x + bw;
  715. r.max.y = r.min.y + h + border;
  716. draw(i, r, top, nil, ZP);
  717. r.max.x = o.x + w + border;
  718. r.max.y = o.y + h + border;
  719. r.min.x = o.x + bw;
  720. r.min.y = r.max.y - bw;
  721. for(x = 0; x < bw; x++) {
  722. draw(i, r, bottom, nil, ZP);
  723. r.min.x--;
  724. r.min.y++;
  725. }
  726. r.min.x = o.x + bw + w;
  727. r.min.y = o.y + bw;
  728. for(x = bw; x >= 0; x--) {
  729. draw(i, r, bottom, nil, ZP);
  730. r.min.x++;
  731. r.min.y--;
  732. }
  733. }
  734. /*
  735. * draw a relief border.
  736. * color is an index into tk->env->colors and assumes
  737. * light and dark versions following immediately after
  738. * that index
  739. */
  740. void
  741. tkdrawrelief(Image *i, Tk *tk, Point o, int color, int rlf)
  742. {
  743. TkEnv *e;
  744. Image *l, *d, *t;
  745. int h, w, bd, bd1, bd2;
  746. if(tk->borderwidth == 0)
  747. return;
  748. h = tk->act.height;
  749. w = tk->act.width;
  750. e = tk->env;
  751. if (color == TkCbackgnd || color == TkCselectbgnd || color == TkCactivebgnd) {
  752. l = tkgc(e, color+TkLightshade);
  753. d = tkgc(e, color+TkDarkshade);
  754. } else {
  755. l = tkgshade(e, color, TkLightshade);
  756. d = tkgshade(e, color, TkDarkshade);
  757. }
  758. bd = tk->borderwidth;
  759. if(rlf < 0)
  760. rlf = TKraised;
  761. switch(rlf) {
  762. case TKflat:
  763. break;
  764. case TKsunken:
  765. tkbevel(i, o, w, h, bd, d, l);
  766. break;
  767. case TKraised:
  768. tkbevel(i, o, w, h, bd, l, d);
  769. break;
  770. case TKgroove:
  771. t = d;
  772. d = l;
  773. l = t;
  774. /* fall through */
  775. case TKridge:
  776. bd1 = bd/2;
  777. bd2 = bd - bd1;
  778. if(bd1 > 0)
  779. tkbevel(i, o, w + 2*bd2, h + 2*bd2, bd1, l, d);
  780. o.x += bd1;
  781. o.y += bd1;
  782. tkbevel(i, o, w, h, bd2, d, l);
  783. break;
  784. }
  785. }
  786. Point
  787. tkstringsize(Tk *tk, char *text)
  788. {
  789. char *q;
  790. int locked;
  791. Display *d;
  792. Point p, t;
  793. if(text == nil) {
  794. p.x = 0;
  795. p.y = tk->env->font->height;
  796. return p;
  797. }
  798. d = tk->env->top->display;
  799. locked = lockdisplay(d);
  800. p = ZP;
  801. while(*text) {
  802. q = strchr(text, '\n');
  803. if(q != nil)
  804. *q = '\0';
  805. t = stringsize(tk->env->font, text);
  806. p.y += t.y;
  807. if(p.x < t.x)
  808. p.x = t.x;
  809. if(q == nil)
  810. break;
  811. text = q+1;
  812. *q = '\n';
  813. }
  814. if(locked)
  815. unlockdisplay(d);
  816. return p;
  817. }
  818. static void
  819. tkulall(Image *i, Point o, Image *col, Font *f, char *text)
  820. {
  821. Rectangle r;
  822. r.max = stringsize(f, text);
  823. r.max = addpt(r.max, o);
  824. r.min.x = o.x;
  825. r.min.y = r.max.y - 1;
  826. draw(i, r, col, nil, ZP);
  827. }
  828. static void
  829. tkul(Image *i, Point o, Image *col, int ul, Font *f, char *text)
  830. {
  831. char c, *v;
  832. Rectangle r;
  833. v = text+ul+1;
  834. c = *v;
  835. *v = '\0';
  836. r.max = stringsize(f, text);
  837. r.max = addpt(r.max, o);
  838. r.min = stringsize(f, v-1);
  839. *v = c;
  840. r.min.x = r.max.x - r.min.x;
  841. r.min.y = r.max.y - 1;
  842. r.max.y++;
  843. draw(i, r, col, nil, ZP);
  844. }
  845. void
  846. tkdrawstring(Tk *tk, Image *i, Point o, char *text, int ul, Image *col, int j)
  847. {
  848. int n, l, maxl, sox;
  849. char *q, *txt;
  850. Point p;
  851. TkEnv *e;
  852. e = tk->env;
  853. sox = maxl = 0;
  854. if(j != Tkleft){
  855. maxl = 0;
  856. txt = text;
  857. while(*txt){
  858. q = strchr(txt, '\n');
  859. if(q != nil)
  860. *q = '\0';
  861. l = stringwidth(e->font, txt);
  862. if(l > maxl)
  863. maxl = l;
  864. if(q == nil)
  865. break;
  866. txt = q+1;
  867. *q = '\n';
  868. }
  869. sox = o.x;
  870. }
  871. while(*text) {
  872. q = strchr(text, '\n');
  873. if(q != nil)
  874. *q = '\0';
  875. if(j != Tkleft){
  876. o.x = sox;
  877. l = stringwidth(e->font, text);
  878. if(j == Tkcenter)
  879. o.x += (maxl-l)/2;
  880. else
  881. o.x += maxl-l;
  882. }
  883. p = string(i, o, col, o, e->font, text);
  884. if(ul >= 0) {
  885. n = strlen(text);
  886. if(ul < n) {
  887. tkul(i, o, col, ul, e->font, text);
  888. ul = -1;
  889. } else if(ul == n) {
  890. tkulall(i, o, col, e->font, text);
  891. ul = -1;
  892. } else
  893. ul -= n;
  894. }
  895. o.y += e->font->height;
  896. if(q == nil)
  897. break;
  898. text = q+1;
  899. *q = '\n';
  900. }
  901. }
  902. /* for debugging */
  903. char*
  904. tkname(Tk *tk)
  905. {
  906. if(tk == nil)
  907. return "(nil)";
  908. if(tk->name == nil)
  909. return "(noname)";
  910. return tk->name->name;
  911. }
  912. Tk*
  913. tkdeliver(Tk *tk, int event, void *data)
  914. {
  915. Tk *dest;
  916. if(tk != nil && ((ulong)tk->type >= TKwidgets || (ulong)tk->name < 4096 && tk->name != nil)){
  917. print("invalid Tk: type %d name %p\n", tk->type, tk->name);
  918. abort();
  919. }
  920. //print("tkdeliver %v to %s\n", event, tkname(tk));
  921. if(tk == nil || ((tk->flag&Tkdestroy) && event != TkDestroy))
  922. return tk;
  923. if(event&(TkFocusin|TkFocusout) && (tk->flag&Tktakefocus))
  924. tk->dirty = tkrect(tk, 1);
  925. if (tkmethod[tk->type]->deliver != nil) {
  926. dest = tkmethod[tk->type]->deliver(tk, event, data);
  927. if (dest == nil)
  928. return tk;
  929. tkdirty(tk);
  930. return dest;
  931. }
  932. if((tk->flag & Tkdisabled) == 0)
  933. tksubdeliver(tk, tk->binds, event, data, 0);
  934. tkdirty(tk);
  935. return tk;
  936. }
  937. static int
  938. nullop(char *fmt, ...)
  939. {
  940. USED(fmt);
  941. return 0;
  942. }
  943. int
  944. tksubdeliver(Tk *tk, TkAction *binds, int event, void *data, int extn)
  945. {
  946. TkAction *a;
  947. int delivered, genkey, delivered2, iskey;
  948. //int (*debug)(char *fmt, ...);
  949. if (!extn)
  950. return tkextndeliver(tk, binds, event, data);
  951. //debug = (tk->name && !strcmp(tk->name->name, ".cd")) ? print : nullop;
  952. //debug("subdeliver %v\n", event);
  953. if (event & TkTakefocus) {
  954. if (tk->flag & Tktakefocus)
  955. tksetkeyfocus(tk->env->top, tk, 0);
  956. return TkDdelivered;
  957. }
  958. delivered = TkDnone;
  959. genkey = 0;
  960. for(a = binds; a != nil; a = a->link) {
  961. if(event == a->event) {
  962. //debug(" exact match on %v\n", a->event);
  963. tkcmdbind(tk, event, a->arg, data);
  964. delivered = TkDdelivered;
  965. } else if (a->event == TkKey && (a->type>>8)==TkAadd)
  966. genkey = 1;
  967. }
  968. if(delivered != TkDnone && !((event & TkKey) && genkey))
  969. return delivered;
  970. delivered2 = delivered;
  971. for(a = binds; a != nil; a = a->link) {
  972. /*
  973. * only bind to non-specific key events; if a specific
  974. * key event has already been delivered, only deliver event if
  975. * the non-specific binding was added. (TkAadd)
  976. */
  977. if (a->event & TkExtns)
  978. continue;
  979. iskey = (a->event & TkKey);
  980. if (iskey ^ (event & TkKey))
  981. continue;
  982. if(iskey && (TKKEY(a->event) != 0
  983. || ((a->type>>8) != TkAadd && delivered != TkDnone)))
  984. continue;
  985. if(!iskey && (a->event & TkMotion) && (a->event&TkEpress) != 0)
  986. continue;
  987. if(!(event & TkDouble) && (a->event & TkDouble))
  988. continue;
  989. if((event & ~TkDouble) & a->event) {
  990. //debug(" partial match on %v\n", a->event);
  991. tkcmdbind(tk, event, a->arg, data);
  992. delivered2 = TkDdelivered;
  993. }
  994. }
  995. return delivered2;
  996. }
  997. void
  998. tkcancel(TkAction **l, int event)
  999. {
  1000. TkAction *a;
  1001. for(a = *l; a; a = *l) {
  1002. if(a->event == event) {
  1003. *l = a->link;
  1004. a->link = nil;
  1005. tkfreebind(a);
  1006. continue;
  1007. }
  1008. l = &a->link;
  1009. }
  1010. }
  1011. static void
  1012. tkcancela(TkAction **l, int event, int type, char *arg)
  1013. {
  1014. TkAction *a;
  1015. for(a = *l; a; a = *l) {
  1016. if(a->event == event && strcmp(a->arg, arg) == 0 && (a->type&0xff) == type){
  1017. *l = a->link;
  1018. a->link = nil;
  1019. tkfreebind(a);
  1020. continue;
  1021. }
  1022. l = &a->link;
  1023. }
  1024. }
  1025. char*
  1026. tkaction(TkAction **l, int event, int type, char *arg, int how)
  1027. {
  1028. TkAction *a;
  1029. if(arg == nil)
  1030. return nil;
  1031. if(how == TkArepl)
  1032. tkcancel(l, event);
  1033. else if(how == TkAadd){
  1034. for(a = *l; a; a = a->link)
  1035. if(a->event == event && strcmp(a->arg, arg) == 0 && (a->type&0xff) == type){
  1036. a->type = type + (how << 8);
  1037. return nil;
  1038. }
  1039. }
  1040. else if(how == TkAsub){
  1041. tkcancela(l, event, type, arg);
  1042. if(type == TkDynamic) /* should always be the case */
  1043. free(arg);
  1044. return nil;
  1045. }
  1046. a = malloc(sizeof(TkAction));
  1047. if(a == nil) {
  1048. if(type == TkDynamic)
  1049. free(arg);
  1050. return TkNomem;
  1051. }
  1052. a->event = event;
  1053. a->arg = arg;
  1054. a->type = type + (how << 8);
  1055. a->link = *l;
  1056. *l = a;
  1057. return nil;
  1058. }
  1059. char*
  1060. tkitem(char *buf, char *a)
  1061. {
  1062. char *e;
  1063. while(*a && (*a == ' ' || *a == '\t'))
  1064. a++;
  1065. e = buf + Tkmaxitem - 1;
  1066. while(*a && *a != ' ' && *a != '\t' && buf < e)
  1067. *buf++ = *a++;
  1068. *buf = '\0';
  1069. while(*a && (*a == ' ' || *a == '\t'))
  1070. a++;
  1071. return a;
  1072. }
  1073. /*
  1074. * if tk is a subwindow or a descendent, return the subwindow;
  1075. * return nil otherwise
  1076. */
  1077. Tk*
  1078. tkfindsub(Tk *tk)
  1079. {
  1080. for(; tk != nil; tk = tk->master){
  1081. if(tk->parent != nil)
  1082. return tk; /* tk->parent is canvas or text */
  1083. }
  1084. return nil;
  1085. }
  1086. /*
  1087. * Return absolute screen position of tk (just outside its top-left border).
  1088. * When a widget is embedded in a text or canvas widget, we need to
  1089. * use the text or canvas's relpos() function instead of act{x,y}, and we
  1090. * need to folow up the parent pointer rather than the master one.
  1091. */
  1092. Point
  1093. tkposn(Tk *tk)
  1094. {
  1095. Tk *f, *last;
  1096. Point g;
  1097. last = tk;
  1098. if(tk->parent != nil) {
  1099. g = tkmethod[tk->parent->type]->relpos(tk);
  1100. f = tk->parent;
  1101. } else {
  1102. g.x = tk->act.x;
  1103. g.y = tk->act.y;
  1104. f = tk->master;
  1105. }
  1106. while(f != nil) {
  1107. g.x += f->borderwidth;
  1108. g.y += f->borderwidth;
  1109. last = f;
  1110. if(f->parent != nil) {
  1111. g = addpt(g, tkmethod[f->parent->type]->relpos(f));
  1112. f = f->parent;
  1113. } else {
  1114. g.x += f->act.x;
  1115. g.y += f->act.y;
  1116. f = f->master;
  1117. }
  1118. }
  1119. if (last->flag & Tkwindow)
  1120. g = addpt(g, TKobj(TkWin, last)->req);
  1121. return g;
  1122. }
  1123. /*
  1124. * convert screen coords to local widget coords
  1125. */
  1126. Point
  1127. tkscrn2local(Tk *tk, Point p)
  1128. {
  1129. p = subpt(p, tkposn(tk));
  1130. p.x -= tk->borderwidth;
  1131. p.y -= tk->borderwidth;
  1132. return p;
  1133. }
  1134. int
  1135. tkvisiblerect(Tk *tk, Rectangle *rr)
  1136. {
  1137. Rectangle r;
  1138. Point g;
  1139. Tk *f, *last;
  1140. g = Pt(tk->borderwidth, tk->borderwidth);
  1141. last = tk;
  1142. if(tk->parent != nil) {
  1143. g = addpt(g, tkmethod[tk->parent->type]->relpos(tk));
  1144. f = tk->parent;
  1145. } else {
  1146. g.x += tk->act.x;
  1147. g.y += tk->act.y;
  1148. f = tk->master;
  1149. }
  1150. if (f == nil) {
  1151. *rr = tkrect(tk, 1);
  1152. return 1;
  1153. }
  1154. r = rectaddpt(tkrect(tk, 1), g);
  1155. while (f) {
  1156. if (!rectclip(&r, tkrect(f, 0)))
  1157. return 0;
  1158. g.x = f->borderwidth;
  1159. g.y = f->borderwidth;
  1160. last = f;
  1161. if (f->parent != nil) {
  1162. g = addpt(g, tkmethod[f->parent->type]->relpos(f));
  1163. f = f->parent;
  1164. } else {
  1165. g.x += f->act.x;
  1166. g.y += f->act.y;
  1167. f = f->master;
  1168. }
  1169. r = rectaddpt(r, g);
  1170. }
  1171. if (last->flag & Tkwindow)
  1172. r = rectaddpt(r, TKobj(TkWin, last)->act);
  1173. /*
  1174. * now we have the visible rectangle in screen coords;
  1175. * subtract actx+borderwidth and we've got it back in
  1176. * widget-local coords again
  1177. */
  1178. r = rectsubpt(r, tkposn(tk));
  1179. *rr = rectsubpt(r, Pt(tk->borderwidth, tk->borderwidth));
  1180. return 1;
  1181. }
  1182. Point
  1183. tkanchorpoint(Rectangle r, Point size, int anchor)
  1184. {
  1185. int dx, dy;
  1186. Point p;
  1187. p = r.min;
  1188. dx = Dx(r) - size.x;
  1189. dy = Dy(r) - size.y;
  1190. if((anchor & (Tknorth|Tksouth)) == 0)
  1191. p.y += dy/2;
  1192. else if(anchor & Tksouth)
  1193. p.y += dy;
  1194. if((anchor & (Tkeast|Tkwest)) == 0)
  1195. p.x += dx/2;
  1196. else if(anchor & Tkeast)
  1197. p.x += dx;
  1198. return p;
  1199. }
  1200. static char*
  1201. tkunits(char c, int *d, TkEnv *e)
  1202. {
  1203. switch(c) {
  1204. default:
  1205. if(c >= '0' || c <= '9' || c == '.')
  1206. break;
  1207. return TkBadvl;
  1208. case '\0':
  1209. break;
  1210. case 'c': /* Centimeters */
  1211. *d *= (Tkdpi*100)/254;
  1212. break;
  1213. case 'm': /* Millimeters */
  1214. *d *= (Tkdpi*10)/254;
  1215. break;
  1216. case 'i': /* Inches */
  1217. *d *= Tkdpi;
  1218. break;
  1219. case 'p': /* Points */
  1220. *d = (*d*Tkdpi)/72;
  1221. break;
  1222. case 'w': /* Character width */
  1223. if(e == nil)
  1224. return TkBadvl;
  1225. *d = *d * e->wzero;
  1226. break;
  1227. case 'h': /* Character height */
  1228. if(e == nil)
  1229. return TkBadvl;
  1230. *d = *d * e->font->height;
  1231. break;
  1232. }
  1233. return nil;
  1234. }
  1235. int
  1236. TKF2I(int f)
  1237. {
  1238. if (f >= 0)
  1239. return (f + Tkfpscalar/2) / Tkfpscalar;
  1240. return (f - Tkfpscalar/2) / Tkfpscalar;
  1241. }
  1242. /*
  1243. * Parse a floating point number into a decimal fixed point representation
  1244. */
  1245. char*
  1246. tkfrac(char **arg, int *f, TkEnv *env)
  1247. {
  1248. int c, minus, i, fscale, seendigit;
  1249. char *p, *e;
  1250. seendigit = 0;
  1251. p = *arg;
  1252. p = tkskip(p, " \t");
  1253. minus = 0;
  1254. if(*p == '-') {
  1255. minus = 1;
  1256. p++;
  1257. }
  1258. i = 0;
  1259. while(*p) {
  1260. c = *p;
  1261. if(c == '.')
  1262. break;
  1263. if(c < '0' || c > '9')
  1264. break;
  1265. i = i*10 + (c - '0');
  1266. seendigit = 1;
  1267. p++;
  1268. }
  1269. i *= Tkfpscalar;
  1270. if(*p == '.')
  1271. p++;
  1272. fscale = Tkfpscalar;
  1273. while(*p && *p >= '0' && *p <= '9') {
  1274. fscale /= 10;
  1275. i += fscale * (*p++ - '0');
  1276. seendigit = 1;
  1277. }
  1278. if(minus)
  1279. i = -i;
  1280. if(!seendigit)
  1281. return TkBadvl;
  1282. e = tkunits(*p, &i, env);
  1283. if (e != nil)
  1284. return e;
  1285. while (*p && *p != ' ' && *p != '\t')
  1286. p++;
  1287. *arg = p;
  1288. *f = i;
  1289. return nil;
  1290. }
  1291. char*
  1292. tkfracword(TkTop *t, char **arg, int *f, TkEnv *env)
  1293. {
  1294. char *p;
  1295. char buf[Tkminitem];
  1296. *arg = tkword(t, *arg, buf, buf+sizeof(buf), nil);
  1297. p = buf;
  1298. return tkfrac(&p, f, env);
  1299. }
  1300. char*
  1301. tkfprint(char *v, int frac)
  1302. {
  1303. int fscale;
  1304. if(frac < 0) {
  1305. *v++ = '-';
  1306. frac = -frac;
  1307. }
  1308. v += sprint(v, "%d", frac/Tkfpscalar);
  1309. frac = frac%Tkfpscalar;
  1310. if(frac != 0)
  1311. *v++ = '.';
  1312. fscale = Tkfpscalar/10;
  1313. while(frac) {
  1314. *v++ = '0' + frac/fscale;
  1315. frac %= fscale;
  1316. fscale /= 10;
  1317. }
  1318. *v = '\0';
  1319. return v;
  1320. }
  1321. char*
  1322. tkvalue(char **val, char *fmt, ...)
  1323. {
  1324. va_list arg;
  1325. Fmt fmtx;
  1326. if(val == nil)
  1327. return nil;
  1328. fmtstrinit(&fmtx);
  1329. if(*val != nil)
  1330. if(fmtprint(&fmtx, "%s", *val) < 0)
  1331. return TkNomem;
  1332. va_start(arg, fmt);
  1333. fmtvprint(&fmtx, fmt, arg);
  1334. va_end(arg);
  1335. free(*val);
  1336. *val = fmtstrflush(&fmtx);
  1337. if(*val == nil)
  1338. return TkNomem;
  1339. return nil;
  1340. }
  1341. static char*
  1342. tkwidgetcmd(TkTop *t, Tk *tk, char *arg, char **val)
  1343. {
  1344. TkMethod *cm;
  1345. TkCmdtab *ct;
  1346. int bot, top, new, r;
  1347. char *e, *buf;
  1348. buf = mallocz(Tkmaxitem, 0);
  1349. if(buf == nil)
  1350. return TkNomem;
  1351. arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
  1352. if(val != nil)
  1353. *val = nil;
  1354. cm = tkmethod[tk->type];
  1355. e = TkBadcm;
  1356. bot = 0;
  1357. top = cm->ncmd - 1;
  1358. while(bot <= top) {
  1359. new = (bot + top)/2;
  1360. ct = &cm->cmd[new];
  1361. r = strcmp(ct->name, buf);
  1362. if(r == 0) {
  1363. e = ct->fn(tk, arg, val);
  1364. break;
  1365. }
  1366. if(r < 0)
  1367. bot = new + 1;
  1368. else
  1369. top = new - 1;
  1370. }
  1371. free(buf);
  1372. tkdirty(tk);
  1373. return e;
  1374. }
  1375. Rectangle
  1376. tkrect(Tk *tk, int withborder)
  1377. {
  1378. Rectangle r;
  1379. int bd;
  1380. bd = withborder? tk->borderwidth: 0;
  1381. r.min.x = -bd;
  1382. r.min.y = -bd;
  1383. r.max.x = tk->act.width + bd;
  1384. r.max.y = tk->act.height + bd;
  1385. return r;
  1386. }
  1387. void
  1388. tkdirty(Tk *tk)
  1389. {
  1390. Tk *sub;
  1391. Point rel;
  1392. Rectangle dirty;
  1393. int isdirty, transparent;
  1394. /*
  1395. * mark as dirty all views underneath a dirty transparent widget
  1396. * down to the first opaque widget.
  1397. * inform parents about any dirtiness.
  1398. * XXX as Tksubsub never gets reset, testing against Tksubsub doesn't *exactly* test
  1399. * whether we're in a canvas/text widget, but merely
  1400. * whether it has ever been. Tksubsub should probably be reset on unpack.
  1401. */
  1402. isdirty = Dx(tk->dirty) > 0;
  1403. transparent = tk->flag & Tktransparent;
  1404. sub = tk;
  1405. while (isdirty && ((tk->flag&Tksubsub) || transparent)) {
  1406. if (tk->master != nil) {
  1407. if (transparent) {
  1408. rel.x = tk->act.x + tk->borderwidth;
  1409. rel.y = tk->act.y + tk->borderwidth;
  1410. dirty = rectaddpt(sub->dirty, rel);
  1411. sub = tk->master;
  1412. combinerect(&sub->dirty, dirty);
  1413. transparent = sub->flag & Tktransparent;
  1414. }
  1415. tk = tk->master;
  1416. } else if (tk->parent != nil) {
  1417. tkmethod[tk->parent->type]->dirtychild(sub);
  1418. tk = sub = tk->parent;
  1419. isdirty = Dx(sub->dirty) > 0;
  1420. transparent = sub->flag & Tktransparent;
  1421. } else
  1422. break;
  1423. }
  1424. }
  1425. static int
  1426. qcmdcmp(const void *a, const void *b)
  1427. {
  1428. return strcmp(((TkCmdtab*)a)->name, ((TkCmdtab*)b)->name);
  1429. }
  1430. void
  1431. tksorttable(void)
  1432. {
  1433. int i;
  1434. TkMethod *c;
  1435. TkCmdtab *cmd;
  1436. for(i = 0; i < TKwidgets; i++) {
  1437. c = tkmethod[i];
  1438. if(c->cmd == nil)
  1439. continue;
  1440. for(cmd = c->cmd; cmd->name != nil; cmd++)
  1441. ;
  1442. c->ncmd = cmd - c->cmd;
  1443. qsort(c->cmd, c->ncmd, sizeof(TkCmdtab), qcmdcmp);
  1444. }
  1445. }
  1446. static char*
  1447. tksinglecmd(TkTop *t, char *arg, char **val)
  1448. {
  1449. Tk *tk;
  1450. int bot, top, new;
  1451. char *e, *buf;
  1452. if(t->debug)
  1453. print("tk: '%s'\n", arg);
  1454. buf = mallocz(Tkmaxitem, 0);
  1455. if(buf == nil)
  1456. return TkNomem;
  1457. arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
  1458. switch(buf[0]) {
  1459. case '\0':
  1460. free(buf);
  1461. return nil;
  1462. case '.':
  1463. tk = tklook(t, buf, 0);
  1464. if(tk == nil){
  1465. tkerr(t, buf);
  1466. free(buf);
  1467. return TkBadwp;
  1468. }
  1469. e = tkwidgetcmd(t, tk, arg, val);
  1470. free(buf);
  1471. return e;
  1472. }
  1473. bot = 0;
  1474. top = nelem(cmdmain) - 1;
  1475. e = TkBadcm;
  1476. while(bot <= top) {
  1477. int rc;
  1478. new = (bot + top)/2;
  1479. rc = strcmp(cmdmain[new].name, buf);
  1480. if(!rc) {
  1481. e = cmdmain[new].fn(t, arg, val);
  1482. break;
  1483. }
  1484. if(rc < 0)
  1485. bot = new + 1;
  1486. else
  1487. top = new - 1;
  1488. }
  1489. free(buf);
  1490. return e;
  1491. }
  1492. static char*
  1493. tkmatch(int inc, int dec, char *p)
  1494. {
  1495. int depth, esc, c;
  1496. esc = 0;
  1497. depth = 1;
  1498. while(*p) {
  1499. c = *p;
  1500. if(esc == 0) {
  1501. if(c == inc)
  1502. depth++;
  1503. if(c == dec)
  1504. depth--;
  1505. if(depth == 0)
  1506. return p;
  1507. }
  1508. if(c == '\\' && esc == 0)
  1509. esc = 1;
  1510. else
  1511. esc = 0;
  1512. p++;
  1513. }
  1514. return nil;
  1515. }
  1516. char*
  1517. tkexec(TkTop *t, char *arg, char **val)
  1518. {
  1519. int cmdsz, n;
  1520. char *p, *cmd, *e, *c;
  1521. if(t->execdepth >= 0 && ++t->execdepth > 128)
  1522. return TkDepth;
  1523. cmd = nil;
  1524. cmdsz = 0;
  1525. p = arg;
  1526. for(;;) {
  1527. switch(*p++) {
  1528. case '[':
  1529. p = tkmatch('[', ']', p);
  1530. if(p == nil){
  1531. free(cmd);
  1532. return TkSyntx;
  1533. }
  1534. break;
  1535. case '{':
  1536. p = tkmatch('{', '}', p);
  1537. if(p == nil){
  1538. free(cmd);
  1539. return TkSyntx;
  1540. }
  1541. break;
  1542. case ';':
  1543. n = p - arg - 1;
  1544. if(cmdsz < n)
  1545. cmdsz = n;
  1546. c = realloc(cmd, cmdsz+1);
  1547. if(c == nil){
  1548. free(cmd);
  1549. return TkNomem;
  1550. }
  1551. cmd = c;
  1552. memmove(cmd, arg, n);
  1553. cmd[n] = '\0';
  1554. e = tksinglecmd(t, cmd, nil);
  1555. if(e != nil) {
  1556. t->err = e;
  1557. strncpy(t->errcmd, cmd, sizeof(t->errcmd));
  1558. t->errcmd[sizeof(t->errcmd)-1] = '\0';
  1559. free(cmd);
  1560. return e;
  1561. }
  1562. arg = p;
  1563. break;
  1564. case '\0':
  1565. case '\'':
  1566. free(cmd);
  1567. e = tksinglecmd(t, arg, val);
  1568. if(e != nil) {
  1569. t->err = e;
  1570. strncpy(t->errcmd, arg, sizeof(t->errcmd));
  1571. t->errcmd[sizeof(t->errcmd)-1] = '\0';
  1572. }
  1573. return e;
  1574. }
  1575. }
  1576. }
  1577. static struct {
  1578. char *name;
  1579. int mask;
  1580. } events[] = {
  1581. "Button1P", TkButton1P,
  1582. "Button1R", TkButton1R,
  1583. "Button2P", TkButton2P,
  1584. "Button2R", TkButton2R,
  1585. "Button3P", TkButton3P,
  1586. "Button3R", TkButton3R,
  1587. "Button4P", TkButton4P,
  1588. "Button4R", TkButton4R,
  1589. "Button5P", TkButton5P,
  1590. "Button5R", TkButton5R,
  1591. "Button6P", TkButton6P,
  1592. "Button6R", TkButton6R,
  1593. "Extn1", TkExtn1,
  1594. "Extn2", TkExtn2,
  1595. "Takefocus", TkTakefocus,
  1596. "Destroy", TkDestroy,
  1597. "Enter", TkEnter,
  1598. "Leave", TkLeave,
  1599. "Motion", TkMotion,
  1600. "Map", TkMap,
  1601. "Unmap", TkUnmap,
  1602. "Key", TkKey,
  1603. "Focusin", TkFocusin,
  1604. "Focusout", TkFocusout,
  1605. "Configure", TkConfigure,
  1606. "Double", TkDouble,
  1607. 0
  1608. };
  1609. int
  1610. tkeventfmt(Fmt *f)
  1611. {
  1612. int k, i, d;
  1613. int e;
  1614. e = va_arg(f->args, int);
  1615. if ((f->flags & FmtSharp) && e == TkMotion)
  1616. return 0;
  1617. fmtprint(f, "<");
  1618. k = -1;
  1619. if (e & TkKey) {
  1620. k = e & 0xffff;
  1621. e &= ~0xffff;
  1622. }
  1623. d = 0;
  1624. for (i = 0; events[i].name; i++) {
  1625. if (e & events[i].mask) {
  1626. if (d++)
  1627. fmtprint(f, "|");
  1628. fmtprint(f, "%s", events[i].name);
  1629. }
  1630. }
  1631. if (k != -1) {
  1632. fmtprint(f, "[%c]", k);
  1633. } else if (e == 0)
  1634. fmtprint(f, "Noevent");
  1635. fmtprint(f, ">");
  1636. return 0;
  1637. }
  1638. void
  1639. tkerr(TkTop *t, char *e)
  1640. {
  1641. if(t != nil && e != nil){
  1642. strncpy(t->errx, e, sizeof(t->errx));
  1643. t->errx[sizeof(t->errx)-1] = '\0';
  1644. }
  1645. }
  1646. char*
  1647. tkerrstr(TkTop *t, char *e)
  1648. {
  1649. char *s = malloc(strlen(e)+1+strlen(t->errx)+1);
  1650. if(s == nil)
  1651. return nil;
  1652. strcpy(s, e);
  1653. if(*e == '!'){
  1654. strcat(s, " ");
  1655. strcat(s, t->errx);
  1656. }
  1657. t->errx[0] = '\0';
  1658. return s;
  1659. }
  1660. char*
  1661. tksetmgrab(TkTop *t, Tk *tk)
  1662. {
  1663. Tk *omgrab;
  1664. TkCtxt *c;
  1665. c = t->ctxt;
  1666. if (tk == nil) {
  1667. omgrab = c->mgrab;
  1668. c->mgrab = nil;
  1669. /*
  1670. * don't enterleave if grab reset would cause no leave event
  1671. */
  1672. if (!(omgrab != nil && (omgrab->flag & Tknograb) &&
  1673. c->entered != nil && (c->entered->flag & Tknograb)))
  1674. tkenterleave(t);
  1675. } else {
  1676. if (c->focused && c->mfocus != nil && c->mfocus->env->top != tk->env->top)
  1677. return "!grab already taken on another toplevel";
  1678. c->mgrab = tk;
  1679. if (tk->flag & Tknograb) {
  1680. if (c->focused) {
  1681. c->focused = 0;
  1682. c->mfocus = nil;
  1683. }
  1684. } else if (c->focused || c->mstate.b != 0) {
  1685. c->focused = 1;
  1686. c->mfocus = tk;
  1687. }
  1688. //print("setmgrab(%s) focus now %s\n", tkname(tk), tkname(c->mfocus));
  1689. tkenterleave(t);
  1690. }
  1691. return nil;
  1692. }
  1693. int
  1694. tkinsidepoly(Point *poly, int np, int winding, Point p)
  1695. {
  1696. Point pi, pj;
  1697. int i, j, hit;
  1698. hit = 0;
  1699. j = np - 1;
  1700. for(i = 0; i < np; j = i++) {
  1701. pi = poly[i];
  1702. pj = poly[j];
  1703. if((pi.y <= p.y && p.y < pj.y || pj.y <= p.y && p.y < pi.y) &&
  1704. p.x < (pj.x - pi.x) * (p.y - pi.y) / (pj.y - pi.y) + pi.x) {
  1705. if(winding == 1 || pi.y > p.y)
  1706. hit++;
  1707. else
  1708. hit--;
  1709. }
  1710. }
  1711. return (hit & winding) != 0;
  1712. }
  1713. int
  1714. tklinehit(Point *a, int np, int w, Point p)
  1715. {
  1716. Point *b;
  1717. int z, nx, ny, nrm;
  1718. while(np-- > 1) {
  1719. b = a+1;
  1720. nx = a->y - b->y;
  1721. ny = b->x - a->x;
  1722. nrm = (nx < 0? -nx : nx) + (ny < 0? -ny : ny);
  1723. if(nrm)
  1724. z = (p.x-b->x)*nx/nrm + (p.y-b->y)*ny/nrm;
  1725. else
  1726. z = (p.x-b->x) + (p.y-b->y);
  1727. if(z < 0)
  1728. z = -z;
  1729. if(z < w)
  1730. return 1;
  1731. a++;
  1732. }
  1733. return 0;
  1734. }
  1735. int
  1736. tkiswordchar(int c)
  1737. {
  1738. return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c >= 0xA0;
  1739. }
  1740. int
  1741. tkhaskeyfocus(Tk *tk)
  1742. {
  1743. if (tk == nil || tk->env->top->focused == 0)
  1744. return 0;
  1745. return tk == tk->env->top->ctxt->tkkeygrab;
  1746. }
  1747. static int
  1748. rptactive(void *v)
  1749. {
  1750. int id = (int)v;
  1751. if (id == rptid)
  1752. return 1;
  1753. return 0;
  1754. }
  1755. static int
  1756. ckrpt(void *v, int interval)
  1757. {
  1758. int id = (int)v;
  1759. if (id != rptid)
  1760. return -1;
  1761. if (interval < rptto)
  1762. return 0;
  1763. return 1;
  1764. }
  1765. static void
  1766. dorpt(void *v)
  1767. {
  1768. int id = (int)v;
  1769. if (id == rptid) {
  1770. rptto = rptint;
  1771. (*rptcb)(rptw, rptnote, 0);
  1772. if (rptint <= 0) {
  1773. rptid++;
  1774. rptw = nil;
  1775. }
  1776. }
  1777. }
  1778. void
  1779. tkcancelrepeat(Tk *tk)
  1780. {
  1781. if (tk == rptw) {
  1782. rptid++;
  1783. rptw = nil;
  1784. }
  1785. }
  1786. void
  1787. tkrepeat(Tk *tk, void (*callback)(Tk*, void*, int), void *note, int pause, int interval)
  1788. {
  1789. rptid++;
  1790. if (tk != rptw && rptw != nil)
  1791. /* existing callback being replaced- report to owner */
  1792. (*rptcb)(rptw, rptnote, 1);
  1793. rptw = tk;
  1794. if (tk == nil || callback == nil)
  1795. return;
  1796. rptnote = note;
  1797. rptcb = callback;
  1798. rptto = pause;
  1799. rptint = interval;
  1800. if (!autorpt)
  1801. autorpt = rptproc("autorepeat", TkRptclick, (void*)rptid, rptactive, ckrpt, dorpt);
  1802. else
  1803. rptwakeup((void*)rptid, autorpt);
  1804. }
  1805. static int
  1806. blinkactive(void *v)
  1807. {
  1808. USED(v);
  1809. return blinkw != nil;
  1810. }
  1811. static int
  1812. ckblink(void *v, int interval)
  1813. {
  1814. USED(v);
  1815. USED(interval);
  1816. if (blinkw == nil)
  1817. return -1;
  1818. if (blinkignore) {
  1819. blinkignore = 0;
  1820. return 0;
  1821. }
  1822. return 1;
  1823. }
  1824. static void
  1825. doblink(void *v)
  1826. {
  1827. USED(v);
  1828. if (blinkw == nil)
  1829. return;
  1830. blinkcb(blinkw, blinkon++ & 1);
  1831. tkupdate(blinkw->env->top);
  1832. }
  1833. void
  1834. tkblinkreset(Tk *tk)
  1835. {
  1836. if (blinkw == tk) {
  1837. blinkignore = 1;
  1838. blinkon = 0;
  1839. }
  1840. }
  1841. void
  1842. tkblink(Tk *tk, void (*callback)(Tk*, int))
  1843. {
  1844. if (tk == nil || callback == nil) {
  1845. blinkw = nil;
  1846. return;
  1847. }
  1848. blinkw = tk;
  1849. blinkcb = callback;
  1850. if (!blinkrpt)
  1851. blinkrpt = rptproc("blinker", TkBlinkinterval, nil, blinkactive, ckblink, doblink);
  1852. else
  1853. rptwakeup(nil, blinkrpt);
  1854. }
  1855. /*
  1856. * debugging
  1857. */
  1858. void
  1859. tkdump(Tk *tk)
  1860. {
  1861. Tk *sl;
  1862. if(tk == nil)
  1863. return;
  1864. if((uint)tk->type < TKwidgets)
  1865. print("%s", tkmethod[tk->type]->name);
  1866. else
  1867. print("TYPE#%#ux", tk->type);
  1868. if(tk->name == nil || (ulong)tk->name < 512)
  1869. print(" NAME %p", tk->name);
  1870. else
  1871. print(" %s", tkname(tk));
  1872. print(" # tk %#p flag %#ux grid %#p", tk, tk->flag, tk->grid);
  1873. if(tk->parent != nil)
  1874. print(" parent [%#p %q]", tk->parent, tkname(tk->parent));
  1875. if(tk->master != nil)
  1876. print(" master [%#p %q]", tk->master, tkname(tk->master));
  1877. if(tk->slave != nil){
  1878. print(" slaves");
  1879. for(sl = tk->slave; sl != nil; sl = sl->next)
  1880. print(" [%#p %q]", sl, tkname(sl));
  1881. }
  1882. print("\n");
  1883. if(tk->type != TKcanvas)
  1884. return;
  1885. tkcvsdump(tk);
  1886. }
  1887. void
  1888. tktopdump(Tk *tk)
  1889. {
  1890. TkTop *top;
  1891. Tk *sub;
  1892. if(tk == nil || tk->env == nil){
  1893. print("# %#p no top\n", tk);
  1894. return;
  1895. }
  1896. top = tk->env->top;
  1897. print("# env %#p top %#p\n", tk->env, top);
  1898. if(top != nil){
  1899. for(sub = top->root; sub != nil; sub = sub->siblings)
  1900. tkdump(sub);
  1901. }
  1902. }