1 #include "lib9.h"
2 #include "draw.h"
3 #include "tk.h"
4 #include <kernel.h>
5 #include <interp.h>
6
7 enum
8 {
9 Cmask,
10 Cctl,
11 Ckey,
12 Cbp,
13 Cbr,
14 };
15
16 struct
17 {
18 char* event;
19 int mask;
20 int action;
21 } etab[] =
22 {
23 "Motion", TkMotion, Cmask,
24 "Double", TkDouble, Cmask,
25 "Map", TkMap, Cmask,
26 "Unmap", TkUnmap, Cmask,
27 "Destroy", TkDestroy, Cmask,
28 "Enter", TkEnter, Cmask,
29 "Leave", TkLeave, Cmask,
30 "FocusIn", TkFocusin, Cmask,
31 "FocusOut", TkFocusout, Cmask,
32 "Configure", TkConfigure, Cmask,
33 "Control", 0, Cctl,
34 "Key", 0, Ckey,
35 "KeyPress", 0, Ckey,
36 "Button", 0, Cbp,
37 "ButtonPress", 0, Cbp,
38 "ButtonRelease", 0, Cbr,
39 };
40
41 static
42 TkOption tkcurop[] =
43 {
44 "x", OPTdist, O(TkCursor, p.x), nil,
45 "y", OPTdist, O(TkCursor, p.y), nil,
46 "bitmap", OPTbmap, O(TkCursor, bit), nil,
47 "image", OPTimag, O(TkCursor, img), nil,
48 "default", OPTbool, O(TkCursor, def), nil,
49 nil
50 };
51
52 static
53 TkOption focusopts[] = {
54 "global", OPTbool, 0, nil,
55 nil
56 };
57
58 static char*
tkseqitem(char * buf,char * arg)59 tkseqitem(char *buf, char *arg)
60 {
61 while(*arg && (*arg == ' ' || *arg == '-'))
62 arg++;
63 while(*arg && *arg != ' ' && *arg != '-' && *arg != '>')
64 *buf++ = *arg++;
65 *buf = '\0';
66 return arg;
67 }
68
69 static char*
tkseqkey(Rune * r,char * arg)70 tkseqkey(Rune *r, char *arg)
71 {
72 char *narg;
73
74 while(*arg && (*arg == ' ' || *arg == '-'))
75 arg++;
76 if (*arg == '\\') {
77 if (*++arg == '\0') {
78 *r = 0;
79 return arg;
80 }
81 } else if (*arg == '\0' || *arg == '>' || *arg == '-') {
82 *r = 0;
83 return arg;
84 }
85 narg = arg + chartorune(r, arg);
86 return narg;
87 }
88
89 int
tkseqparse(char * seq)90 tkseqparse(char *seq)
91 {
92 Rune r;
93 int i, event;
94 char *buf;
95
96 buf = mallocz(Tkmaxitem, 0);
97 if(buf == nil)
98 return -1;
99
100 event = 0;
101
102 while(*seq && *seq != '>') {
103 seq = tkseqitem(buf, seq);
104
105 for(i = 0; i < nelem(etab); i++)
106 if(strcmp(buf, etab[i].event) == 0)
107 break;
108
109 if(i >= nelem(etab)) {
110 seq = tkextnparseseq(buf, seq, &event);
111 if (seq == nil) {
112 free(buf);
113 return -1;
114 }
115 continue;
116 }
117
118
119 switch(etab[i].action) {
120 case Cmask:
121 event |= etab[i].mask;
122 break;
123 case Cctl:
124 seq = tkseqkey(&r, seq);
125 if(r == 0) {
126 free(buf);
127 return -1;
128 }
129 if(r <= '~')
130 r &= 0x1f;
131 event |= TkKey|TKKEY(r);
132 break;
133 case Ckey:
134 seq = tkseqkey(&r, seq);
135 if(r != 0)
136 event |= TKKEY(r);
137 event |= TkKey;
138 break;
139 case Cbp:
140 seq = tkseqitem(buf, seq);
141 switch(buf[0]) {
142 default:
143 free(buf);
144 return -1;
145 case '\0':
146 event |= TkEpress;
147 break;
148 case '1':
149 event |= TkButton1P;
150 break;
151 case '2':
152 event |= TkButton2P;
153 break;
154 case '3':
155 event |= TkButton3P;
156 break;
157 case '4':
158 event |= TkButton4P;
159 break;
160 case '5':
161 event |= TkButton5P;
162 break;
163 case '6':
164 event |= TkButton6P;
165 break;
166 }
167 break;
168 case Cbr:
169 seq = tkseqitem(buf, seq);
170 switch(buf[0]) {
171 default:
172 free(buf);
173 return -1;
174 case '\0':
175 event |= TkErelease;
176 break;
177 case '1':
178 event |= TkButton1R;
179 break;
180 case '2':
181 event |= TkButton2R;
182 break;
183 case '3':
184 event |= TkButton3R;
185 break;
186 case '4':
187 event |= TkButton4R;
188 break;
189 case '5':
190 event |= TkButton5R;
191 break;
192 case '6':
193 event |= TkButton6R;
194 break;
195 }
196 break;
197 }
198 }
199 free(buf);
200 return event;
201 }
202
203 void
tkcmdbind(Tk * tk,int event,char * s,void * data)204 tkcmdbind(Tk *tk, int event, char *s, void *data)
205 {
206 Point p;
207 TkMouse *m;
208 TkGeom *g;
209 int v, len;
210 char *e, *c, *ec, *cmd;
211 TkTop *t;
212
213 if(s == nil)
214 return;
215 cmd = malloc(2*Tkmaxitem);
216 if (cmd == nil) {
217 print("tk: bind command \"%s\": %s\n",
218 tk->name ? tk->name->name : "(noname)", TkNomem);
219 return;
220 }
221
222 m = (TkMouse*)data;
223 c = cmd;
224 ec = cmd+2*Tkmaxitem-1;
225 while(*s && c < ec) {
226 if(*s != '%') {
227 *c++ = *s++;
228 continue;
229 }
230 s++;
231 len = ec-c;
232 switch(*s++) {
233 def:
234 default:
235 *c++ = s[-1];
236 break;
237 case '%':
238 *c++ = '%';
239 break;
240 case 'b':
241 v = 0;
242 if (!(event & TkKey)) {
243 if(event & (TkButton1P|TkButton1R))
244 v = 1;
245 else if(event & (TkButton2P|TkButton2R))
246 v = 2;
247 else if(event & (TkButton3P|TkButton3R))
248 v = 3;
249 }
250 c += snprint(c, len, "%d", v);
251 break;
252 case 'h':
253 if((event & TkConfigure) == 0)
254 goto def;
255 g = (TkGeom*)data;
256 c += snprint(c, len, "%d", g->height);
257 break;
258 case 's':
259 if((event & TkKey))
260 c += snprint(c, len, "%d", TKKEY(event));
261 else if((event & (TkEmouse|TkEnter)))
262 c += snprint(c, len, "%d", m->b);
263 else if((event & TkFocusin))
264 c += snprint(c, len, "%d", (int)data);
265 else
266 goto def;
267 break;
268 case 'w':
269 if((event & TkConfigure) == 0)
270 goto def;
271 g = (TkGeom*)data;
272 c += snprint(c, len, "%d", g->width);
273 break;
274 case 'x': /* Relative mouse coords */
275 case 'y':
276 if((event & TkKey) || (event & (TkEmouse|TkEnter)) == 0)
277 goto def;
278 p = tkposn(tk);
279 if(s[-1] == 'x')
280 v = m->x - p.x;
281 else
282 v = m->y - p.y;
283 c += snprint(c, len, "%d", v - tk->borderwidth);
284 break;
285 case 'X': /* Absolute mouse coords */
286 case 'Y':
287 if((event & TkKey) || (event & TkEmouse) == 0)
288 goto def;
289 c += snprint(c, len, "%d", s[-1] == 'X' ? m->x : m->y);
290 break;
291 case 'A':
292 if((event & TkKey) == 0)
293 goto def;
294 v = TKKEY(event);
295 if(v == '{' || v == '}' || v == '\\')
296 c += snprint(c, len, "\\%C", v);
297 else if(v != '\0')
298 c += snprint(c, len, "%C", v);
299 break;
300 case 'K':
301 if((event & TkKey) == 0)
302 goto def;
303 c += snprint(c, len, "%.4X", TKKEY(event));
304 break;
305 case 'W':
306 if (tk->name != nil)
307 c += snprint(c, len, "%s", tk->name->name);
308 break;
309 }
310 }
311 *c = '\0';
312 e = nil;
313 t = tk->env->top;
314 t->execdepth = 0;
315 if(cmd[0] == '|')
316 tkexec(t, cmd+1, nil);
317 else if(cmd[0] != '\0')
318 e = tkexec(t, cmd, nil);
319 t->execdepth = -1;
320
321 if(e == nil) {
322 free(cmd);
323 return;
324 }
325
326 if(tk->name != nil){
327 char *s;
328
329 if(t->errx[0] != '\0')
330 s = tkerrstr(t, e);
331 else
332 s = e;
333 print("tk: bind command \"%s\": %s: %s\n", tk->name->name, cmd, s);
334 if(s != e)
335 free(s);
336 }
337 free(cmd);
338 }
339
340 char*
tkbind(TkTop * t,char * arg,char ** ret)341 tkbind(TkTop *t, char *arg, char **ret)
342 {
343 Rune r;
344 Tk *tk;
345 TkAction **ap;
346 int i, mode, event;
347 char *cmd, *tag, *seq;
348 char *e;
349
350 USED(ret);
351
352 tag = mallocz(Tkmaxitem, 0);
353 if(tag == nil)
354 return TkNomem;
355 seq = mallocz(Tkmaxitem, 0);
356 if(seq == nil) {
357 free(tag);
358 return TkNomem;
359 }
360
361 arg = tkword(t, arg, tag, tag+Tkmaxitem, nil);
362 if(tag[0] == '\0') {
363 e = TkBadtg;
364 goto err;
365 }
366
367 arg = tkword(t, arg, seq, seq+Tkmaxitem, nil);
368 if(seq[0] == '<') {
369 event = tkseqparse(seq+1);
370 if(event == -1) {
371 e = TkBadsq;
372 goto err;
373 }
374 }
375 else {
376 chartorune(&r, seq);
377 event = TkKey | r;
378 }
379 if(event == 0) {
380 e = TkBadsq;
381 goto err;
382 }
383
384 arg = tkskip(arg, " \t");
385
386 mode = TkArepl;
387 if(*arg == '+') {
388 mode = TkAadd;
389 arg++;
390 }
391 else if(*arg == '-'){
392 mode = TkAsub;
393 arg++;
394 }
395
396 if(*arg == '{') {
397 cmd = tkskip(arg+1, " \t");
398 if(*cmd == '}') {
399 tk = tklook(t, tag, 0);
400 if(tk == nil) {
401 for(i = 0; ; i++) {
402 if(i >= TKwidgets) {
403 e = TkBadwp;
404 tkerr(t, tag);
405 goto err;
406 }
407 if(strcmp(tag, tkmethod[i]->name) == 0) {
408 ap = &(t->binds[i]);
409 break;
410 }
411 }
412 }
413 else
414 ap = &tk->binds;
415 tkcancel(ap, event);
416 }
417 }
418
419 tkword(t, arg, seq, seq+Tkmaxitem, nil);
420 if(tag[0] == '.') {
421 tk = tklook(t, tag, 0);
422 if(tk == nil) {
423 e = TkBadwp;
424 tkerr(t, tag);
425 goto err;
426 }
427
428 cmd = strdup(seq);
429 if(cmd == nil) {
430 e = TkNomem;
431 goto err;
432 }
433 e = tkaction(&tk->binds, event, TkDynamic, cmd, mode);
434 if(e != nil)
435 goto err; /* tkaction does free(cmd) */
436 free(tag);
437 free(seq);
438 return nil;
439 }
440 /* documented but doesn't work */
441 if(strcmp(tag, "all") == 0) {
442 for(tk = t->root; tk; tk = tk->next) {
443 cmd = strdup(seq);
444 if(cmd == nil) {
445 e = TkNomem;
446 goto err;
447 }
448 e = tkaction(&tk->binds, event, TkDynamic, cmd, mode);
449 if(e != nil)
450 goto err;
451 }
452 free(tag);
453 free(seq);
454 return nil;
455 }
456 /* undocumented, probably unused, and doesn't work consistently */
457 for(i = 0; i < TKwidgets; i++) {
458 if(strcmp(tag, tkmethod[i]->name) == 0) {
459 cmd = strdup(seq);
460 if(cmd == nil) {
461 e = TkNomem;
462 goto err;
463 }
464 e = tkaction(t->binds + i,event, TkDynamic, cmd, mode);
465 if(e != nil)
466 goto err;
467 free(tag);
468 free(seq);
469 return nil;
470 }
471 }
472
473 e = TkBadtg;
474 err:
475 free(tag);
476 free(seq);
477
478 return e;
479 }
480
481 char*
tksend(TkTop * t,char * arg,char ** ret)482 tksend(TkTop *t, char *arg, char **ret)
483 {
484
485 TkVar *v;
486 char *var;
487
488 USED(ret);
489
490 var = mallocz(Tkmaxitem, 0);
491 if(var == nil)
492 return TkNomem;
493
494 arg = tkword(t, arg, var, var+Tkmaxitem, nil);
495 v = tkmkvar(t, var, 0);
496 free(var);
497 if(v == nil)
498 return TkBadvr;
499 if(v->type != TkVchan)
500 return TkNotvt;
501
502 arg = tkskip(arg, " \t");
503 if(tktolimbo(v->value, arg) == 0)
504 return TkMovfw;
505
506 return nil;
507 }
508
509 static Tk*
tknextfocus(TkTop * t,int d)510 tknextfocus(TkTop *t, int d)
511 {
512 int i, n, j, k;
513 Tk *oldfocus;
514
515 if (t->focusorder == nil)
516 tkbuildfocusorder(t);
517
518 oldfocus = t->ctxt->tkkeygrab;
519 n = t->nfocus;
520 if (n == 0)
521 return oldfocus;
522 for (i = 0; i < n; i++)
523 if (t->focusorder[i] == oldfocus)
524 break;
525 if (i == n) {
526 for (i = 0; i < n; i++)
527 if ((t->focusorder[i]->flag & Tkdisabled) == 0)
528 return t->focusorder[i];
529 return oldfocus;
530 }
531 for (j = 1; j < n; j++) {
532 k = (i + d * j + n) % n;
533 if ((t->focusorder[k]->flag & Tkdisabled) == 0)
534 return t->focusorder[k];
535 }
536 return oldfocus;
537 }
538
539 /* our dirty little secret */
540 static void
focusdirty(Tk * tk)541 focusdirty(Tk *tk)
542 {
543 if(tk->highlightwidth > 0){
544 tk->dirty = tkrect(tk, 1);
545 tkdirty(tk);
546 }
547 }
548
549 void
tksetkeyfocus(TkTop * top,Tk * new,int dir)550 tksetkeyfocus(TkTop *top, Tk *new, int dir)
551 {
552 TkCtxt *c;
553 Tk *old;
554
555 c = top->ctxt;
556 old = c->tkkeygrab;
557
558 if(old == new)
559 return;
560 c->tkkeygrab = new;
561 if(top->focused == 0)
562 return;
563 if(old != nil && old != top->root){
564 tkdeliver(old, TkFocusout, nil);
565 focusdirty(old);
566 }
567 if(new != nil && new != top->root){
568 tkdeliver(new, TkFocusin, (void*)dir);
569 focusdirty(new);
570 }
571 }
572
573 void
tksetglobalfocus(TkTop * top,int in)574 tksetglobalfocus(TkTop *top, int in)
575 {
576 Tk *tk;
577 in = (in != 0);
578 if (in != top->focused){
579 top->focused = in;
580 tk = top->ctxt->tkkeygrab;
581 if(in){
582 tkdeliver(top->root, TkFocusin, (void*)0);
583 if(tk != nil && tk != top->root){
584 tkdeliver(tk, TkFocusin, (void*)0);
585 focusdirty(tk);
586 }
587 }else{
588 if(tk != nil && tk != top->root){
589 tkdeliver(tk, TkFocusout, nil);
590 focusdirty(tk);
591 }
592 tkdeliver(top->root, TkFocusout, nil);
593 }
594 }
595 }
596
597 char*
tkfocus(TkTop * top,char * arg,char ** ret)598 tkfocus(TkTop *top, char *arg, char **ret)
599 {
600 Tk *tk;
601 char *wp, *e;
602 int dir, global;
603 TkOptab tko[2];
604 TkName *names;
605
606 tko[0].ptr = &global;
607 tko[0].optab = focusopts;
608 tko[1].ptr = nil;
609
610 global = 0;
611
612 names = nil;
613 e = tkparse(top, arg, tko, &names);
614 if (e != nil)
615 return e;
616
617 if(names == nil){
618 if(global)
619 return tkvalue(ret, "%d", top->focused);
620 tk = top->ctxt->tkkeygrab;
621 if (tk != nil && tk->name != nil)
622 return tkvalue(ret, "%s", tk->name->name);
623 return nil;
624 }
625
626 if(global){
627 tksetglobalfocus(top, atoi(names->name));
628 return nil;
629 }
630
631 wp = mallocz(Tkmaxitem, 0);
632 if(wp == nil)
633 return TkNomem;
634
635 tkword(top, arg, wp, wp+Tkmaxitem, nil);
636 if (!strcmp(wp, "next")) {
637 tk = tknextfocus(top, 1); /* can only return nil if c->tkkeygrab is already nil */
638 dir = +1;
639 } else if (!strcmp(wp, "previous")) {
640 tk = tknextfocus(top, -1);
641 dir = -1;
642 } else if(*wp == '\0') {
643 tk = nil;
644 dir = 0;
645 } else {
646 tk = tklook(top, wp, 0);
647 if(tk == nil){
648 tkerr(top, wp);
649 free(wp);
650 return TkBadwp;
651 }
652 dir = 0;
653 }
654 free(wp);
655
656 tksetkeyfocus(top, tk, dir);
657 return nil;
658 }
659
660 char*
tkraise(TkTop * t,char * arg,char ** ret)661 tkraise(TkTop *t, char *arg, char **ret)
662 {
663 Tk *tk;
664 char *wp;
665
666 USED(ret);
667
668 wp = mallocz(Tkmaxitem, 0);
669 if(wp == nil)
670 return TkNomem;
671 tkword(t, arg, wp, wp+Tkmaxitem, nil);
672 tk = tklook(t, wp, 0);
673 if(tk == nil){
674 tkerr(t, wp);
675 free(wp);
676 return TkBadwp;
677 }
678 free(wp);
679
680 if((tk->flag & Tkwindow) == 0)
681 return TkNotwm;
682
683 tkwreq(tk->env->top, "raise %s", tk->name->name);
684 return nil;
685 }
686
687 char*
tklower(TkTop * t,char * arg,char ** ret)688 tklower(TkTop *t, char *arg, char **ret)
689 {
690 Tk *tk;
691 char *wp;
692
693 USED(ret);
694 wp = mallocz(Tkmaxitem, 0);
695 if(wp == nil)
696 return TkNomem;
697 tkword(t, arg, wp, wp+Tkmaxitem, nil);
698 tk = tklook(t, wp, 0);
699 if(tk == nil){
700 tkerr(t, wp);
701 free(wp);
702 return TkBadwp;
703 }
704 free(wp);
705
706 if((tk->flag & Tkwindow) == 0)
707 return TkNotwm;
708
709 tkwreq(tk->env->top, "lower %s", tk->name->name);
710 return nil;
711 }
712
713 char*
tkgrab(TkTop * t,char * arg,char ** ret)714 tkgrab(TkTop *t, char *arg, char **ret)
715 {
716 Tk *tk;
717 TkCtxt *c;
718 char *r, *buf, *wp;
719
720 USED(ret);
721
722 buf = mallocz(Tkmaxitem, 0);
723 if(buf == nil)
724 return TkNomem;
725
726 wp = mallocz(Tkmaxitem, 0);
727 if(wp == nil) {
728 free(buf);
729 return TkNomem;
730 }
731 arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
732
733 tkword(t, arg, wp, wp+Tkmaxitem, nil);
734 tk = tklook(t, wp, 0);
735 if(tk == nil) {
736 free(buf);
737 tkerr(t, wp);
738 free(wp);
739 return TkBadwp;
740 }
741 free(wp);
742
743 c = t->ctxt;
744 if(strcmp(buf, "release") == 0) {
745 free(buf);
746 if(c->mgrab == tk)
747 tksetmgrab(t, nil);
748 return nil;
749 }
750 if(strcmp(buf, "set") == 0) {
751 free(buf);
752 return tksetmgrab(t, tk);
753 }
754 if(strcmp(buf, "ifunset") == 0) {
755 free(buf);
756 if(c->mgrab == nil)
757 return tksetmgrab(t, tk);
758 return nil;
759 }
760 if(strcmp(buf, "status") == 0) {
761 free(buf);
762 r = "none";
763 if ((c->mgrab != nil) && (c->mgrab->name != nil))
764 r = c->mgrab->name->name;
765 return tkvalue(ret, "%s", r);
766 }
767 free(buf);
768 return TkBadcm;
769 }
770
771 char*
tkputs(TkTop * t,char * arg,char ** ret)772 tkputs(TkTop *t, char *arg, char **ret)
773 {
774 char *buf;
775
776 USED(ret);
777
778 buf = mallocz(Tkmaxitem, 0);
779 if(buf == nil)
780 return TkNomem;
781 tkword(t, arg, buf, buf+Tkmaxitem, nil);
782 print("%s\n", buf);
783 free(buf);
784 return nil;
785 }
786
787 char*
tkdestroy(TkTop * t,char * arg,char ** ret)788 tkdestroy(TkTop *t, char *arg, char **ret)
789 {
790 int found, len, isroot;
791 Tk *tk, **l, *next, *slave;
792 char *n, *e, *buf;
793
794 USED(ret);
795 buf = mallocz(Tkmaxitem, 0);
796 if(buf == nil)
797 return TkNomem;
798 e = nil;
799 for(;;) {
800 arg = tkword(t, arg, buf, buf+Tkmaxitem, nil);
801 if(buf[0] == '\0')
802 break;
803
804 len = strlen(buf);
805 found = 0;
806 isroot = (strcmp(buf, ".") == 0);
807 for(tk = t->root; tk; tk = tk->siblings) {
808 if (tk->name != nil) {
809 n = tk->name->name;
810 if(strcmp(buf, n) == 0) {
811 tk->flag |= Tkdestroy;
812 found = 1;
813 } else if(isroot || (strncmp(buf, n, len) == 0 && n[len] == '.'))
814 tk->flag |= Tkdestroy;
815 }
816 }
817 if(!found) {
818 e = TkBadwp;
819 tkerr(t, buf);
820 break;
821 }
822 }
823 free(buf);
824
825 for(tk = t->root; tk; tk = tk->siblings) {
826 if((tk->flag & Tkdestroy) == 0)
827 continue;
828 if(tk->flag & Tkwindow) {
829 tkunmap(tk);
830 if(tk->name != nil &&
831 strcmp(tk->name->name, ".") == 0)
832 tk->flag &= ~Tkdestroy;
833 else
834 tkdeliver(tk, TkDestroy, nil);
835 } else
836 tkdeliver(tk, TkDestroy, nil);
837 if(0)print("tkdestroy %q\n", tkname(tk));
838 if(tk->destroyed != nil)
839 tk->destroyed(tk);
840 tkpackqit(tk->master);
841 tkdelpack(tk);
842 for (slave = tk->slave; slave != nil; slave = next) {
843 next = slave->next;
844 slave->master = nil;
845 slave->next = nil;
846 }
847 tk->slave = nil;
848 if(tk->parent != nil && tk->geom != nil) /* XXX this appears to be bogus */
849 tk->geom(tk, 0, 0, 0, 0);
850 if(tk->grid){
851 tkfreegrid(tk->grid);
852 tk->grid = nil;
853 }
854 }
855 tkrunpack(t);
856
857 l = &t->windows;
858 for(tk = t->windows; tk; tk = next) {
859 next = TKobj(TkWin, tk)->next;
860 if(tk->flag & Tkdestroy) {
861 *l = next;
862 continue;
863 }
864 l = &TKobj(TkWin, tk)->next;
865 }
866 l = &t->root;
867 for(tk = t->root; tk; tk = next) {
868 next = tk->siblings;
869 if(tk->flag & Tkdestroy) {
870 *l = next;
871 tkfreeobj(tk);
872 continue;
873 }
874 l = &tk->siblings;
875 }
876
877 return e;
878 }
879
880 char*
tkupdatecmd(TkTop * t,char * arg,char ** ret)881 tkupdatecmd(TkTop *t, char *arg, char **ret)
882 {
883 Tk *tk;
884 int x, y;
885 Rectangle *dr;
886 char buf[Tkmaxitem];
887
888 USED(ret);
889
890 tkword(t, arg, buf, buf+sizeof(buf), nil);
891 if(strcmp(buf, "-onscreen") == 0){
892 tk = t->root;
893 dr = &t->screenr;
894 x = tk->act.x;
895 if(x+tk->act.width > dr->max.x)
896 x = dr->max.x - tk->act.width;
897 if(x < 0)
898 x = 0;
899 y = tk->act.y;
900 if(y+tk->act.height > dr->max.y)
901 y = dr->max.y - tk->act.height;
902 if(y < 0)
903 y = 0;
904 tkmovewin(tk, Pt(x, y));
905 }else if(strcmp(buf, "-disable") == 0){
906 t->noupdate = 1;
907 }else if(strcmp(buf, "-enable") == 0){
908 t->noupdate = 0;
909 }
910 return tkupdate(t);
911 }
912
913 char*
tkwinfo(TkTop * t,char * arg,char ** ret)914 tkwinfo(TkTop *t, char *arg, char **ret)
915 {
916 Tk *tk;
917 char *cmd, *arg1;
918
919 cmd = mallocz(Tkmaxitem, 0);
920 if(cmd == nil)
921 return TkNomem;
922
923 arg = tkword(t, arg, cmd, cmd+Tkmaxitem, nil);
924 if(strcmp(cmd, "class") == 0) {
925 arg1 = mallocz(Tkmaxitem, 0);
926 if(arg1 == nil) {
927 free(cmd);
928 return TkNomem;
929 }
930 tkword(t, arg, arg1, arg1+Tkmaxitem, nil);
931 tk = tklook(t, arg1, 0);
932 if(tk == nil){
933 tkerr(t, arg1);
934 free(arg1);
935 free(cmd);
936 return TkBadwp;
937 }
938 free(arg1);
939 free(cmd);
940 return tkvalue(ret, "%s", tkmethod[tk->type]->name);
941 }
942 free(cmd);
943 return TkBadvl;
944 }
945
946 char*
tkcursorcmd(TkTop * t,char * arg,char ** ret)947 tkcursorcmd(TkTop *t, char *arg, char **ret)
948 {
949 char *e;
950 int locked;
951 Display *d;
952 TkCursor c;
953 TkOptab tko[3];
954 enum {Notset = 0x80000000};
955
956 c.def = 0;
957 c.p.x = Notset;
958 c.p.y = Notset;
959 c.bit = nil;
960 c.img = nil;
961
962 USED(ret);
963
964 c.def = 0;
965 tko[0].ptr = &c;
966 tko[0].optab = tkcurop;
967 tko[1].ptr = nil;
968 e = tkparse(t, arg, tko, nil);
969 if(e != nil)
970 return e;
971
972 d = t->display;
973 locked = lockdisplay(d);
974 if(c.def)
975 tkcursorswitch(t, nil, nil);
976 if(c.img != nil || c.bit != nil){
977 e = tkcursorswitch(t, c.bit, c.img);
978 tkimgput(c.img);
979 freeimage(c.bit);
980 }
981 if(e == nil){
982 if(c.p.x != Notset && c.p.y != Notset)
983 tkcursorset(t, c.p);
984 }
985 if(locked)
986 unlockdisplay(d);
987 return e;
988 }
989
990 char *
tkbindings(TkTop * t,Tk * tk,TkEbind * b,int blen)991 tkbindings(TkTop *t, Tk *tk, TkEbind *b, int blen)
992 {
993 TkAction *a, **ap;
994 char *cmd, *e;
995 int i;
996
997 e = nil;
998 for(i = 0; e == nil && i < blen; i++) /* default bindings */ {
999 int how = TkArepl;
1000 char *cmd = b[i].cmd;
1001 if(cmd[0] == '+') {
1002 how = TkAadd;
1003 cmd++;
1004 }
1005 else if(cmd[0] == '-'){
1006 how = TkAsub;
1007 cmd++;
1008 }
1009 e = tkaction(&tk->binds, b[i].event, TkStatic, cmd, how);
1010 }
1011
1012 if(e != nil)
1013 return e;
1014
1015 ap = &tk->binds;
1016 for(a = t->binds[tk->type]; a; a = a->link) { /* user "defaults" */
1017 cmd = strdup(a->arg);
1018 if(cmd == nil)
1019 return TkNomem;
1020
1021 e = tkaction(ap, a->event, TkDynamic, cmd,
1022 (a->type >> 8) & 0xff);
1023 if(e != nil)
1024 return e;
1025 ap = &(*ap)->link;
1026 }
1027 return nil;
1028 }
1029