1 #include "lib9.h" 2 #include "draw.h" 3 #include "tk.h" 4 #include "canvs.h" 5 6 #define O(t, e) ((long)(&((t*)0)->e)) 7 8 /* Window Options (+ means implemented) 9 +tags 10 +width 11 +height 12 +window 13 +anchor 14 */ 15 16 static 17 TkOption windopts[] = 18 { 19 "width", OPTdist, O(TkCwind, width), nil, 20 "height", OPTdist, O(TkCwind, height), nil, 21 "anchor", OPTstab, O(TkCwind, flags), tkanchor, 22 "window", OPTwinp, O(TkCwind, sub), nil, 23 nil 24 }; 25 26 static 27 TkOption itemopts[] = 28 { 29 "tags", OPTctag, O(TkCitem, tags), nil, 30 nil 31 }; 32 33 static void 34 tkcvswindsize(TkCitem *i) 35 { 36 Tk *s; 37 int bw; 38 Point p; 39 TkGeom old; 40 TkCwind *w; 41 42 w = TKobj(TkCwind, i); 43 s = w->sub; 44 if(s == nil) 45 return; 46 47 if(w->width != s->act.width || w->height != s->act.height) { 48 old = s->act; 49 s->act.width = w->width; 50 s->act.height = w->height; 51 if(s->slave) { 52 tkpackqit(s); 53 tkrunpack(s->env->top); 54 } 55 tkdeliver(s, TkConfigure, &old); 56 } 57 p = tkcvsanchor(i->p.drawpt[0], s->act.width, s->act.height, w->flags); 58 s->act.x = p.x; 59 s->act.y = p.y; 60 61 bw = 2*s->borderwidth; 62 i->p.bb.min = p; 63 i->p.bb.max.x = p.x + s->act.width + bw; 64 i->p.bb.max.y = p.y + s->act.height + bw; 65 } 66 67 TkCitem* 68 tkcvsfindwin(Tk *tk) 69 { 70 Tk *parent, *sub; 71 TkCitem *i; 72 TkCanvas *c; 73 TkCwind *w; 74 75 sub = tkfindsub(tk); 76 if(sub == nil) 77 return nil; 78 parent = sub->parent; 79 if(parent->type != TKcanvas) 80 return nil; /* inconsistent */ 81 c = TKobj(TkCanvas, parent); 82 for(i = c->head; i != nil; i = i->next) { 83 if(i->type == TkCVwindow) { 84 w = TKobj(TkCwind, i); 85 if(w->sub == sub) 86 return i; 87 } 88 } 89 return nil; 90 } 91 92 void 93 tkcvsforgetsub(Tk *sub, Tk *tk) 94 { 95 TkCwind *w; 96 TkCitem *i; 97 98 i = tkcvsfindwin(sub); 99 if(i == nil) 100 return; 101 w = TKobj(TkCwind, i); 102 if(w->focus == tk) { 103 if(0)print("tkcsvsforget sub %p %q focus %p %q\n", sub, tkname(sub), tk, tkname(tk)); 104 w->focus = nil; 105 } 106 } 107 108 static int 109 tkcvschkwfocus(TkCwind *w, Tk *tk) 110 { 111 if(w->focus == tk) 112 return 1; 113 for(tk = tk->slave; tk; tk = tk->next) 114 if(tkcvschkwfocus(w, tk)) 115 return 1; 116 return 0; 117 } 118 119 static void 120 tkcvswindgeom(Tk *sub, int x, int y, int w, int h) 121 { 122 TkCitem *i; 123 Tk *parent; 124 TkCanvas *c; 125 TkCwind *win; 126 127 USED(x); 128 USED(y); 129 parent = sub->parent; 130 win = nil; 131 c = TKobj(TkCanvas, parent); 132 for(i = c->head; i; i = i->next) { 133 if(i->type == TkCVwindow) { 134 win = TKobj(TkCwind, i); 135 if(win->sub == sub) 136 break; 137 } 138 } 139 140 if(win->focus != nil) { 141 if(0)print("check focus %p %q %p %q\n", win, tkname(win->focus), sub, tkname(sub)); 142 if(tkcvschkwfocus(win, sub) == 0) 143 win->focus = nil; 144 } 145 146 tkbbmax(&c->update, &i->p.bb); 147 148 if((win->flags & Tksetwidth) == 0) 149 win->width = w; 150 if ((win->flags & Tksetheight) == 0) 151 win->height = h; 152 153 sub->req.width = w; 154 sub->req.height = h; 155 tkcvswindsize(i); 156 157 tkbbmax(&c->update, &i->p.bb); 158 tkcvsdirty(parent); 159 } 160 161 static void 162 tkcvssubdestry(Tk *sub) 163 { 164 Tk *tk; 165 TkCitem *i; 166 TkCanvas *c; 167 TkCwind *win; 168 169 tk = sub->parent; 170 if(tk == nil) 171 return; 172 173 if(0)print("tkcvssubdestry %p %q\n", sub, tkname(sub)); 174 i = tkcvsfindwin(sub); 175 if(i != nil){ 176 win = TKobj(TkCwind, i); 177 if(win->sub != sub){ 178 print("inconsistent tkcvssubdestry %p %q\n", sub, tkname(sub)); 179 } 180 } 181 182 c = TKobj(TkCanvas, tk); 183 for(i = c->head; i; i = i->next) { 184 if(i->type == TkCVwindow) { 185 win = TKobj(TkCwind, i); 186 if(win->sub == sub) { 187 tkbbmax(&c->update, &i->p.bb); 188 tkcvssetdirty(tk); 189 190 win->focus = nil; 191 win->sub = nil; 192 sub->parent = nil; 193 sub->geom = nil; 194 return; 195 } 196 } 197 } 198 } 199 200 Point 201 tkcvsrelpos(Tk *sub) 202 { 203 Tk *tk; 204 TkCitem *i; 205 TkCanvas *c; 206 TkCwind *win; 207 208 tk = sub->parent; 209 if(tk == nil) 210 return ZP; 211 212 c = TKobj(TkCanvas, tk); 213 for(i = c->head; i; i = i->next) { 214 if(i->type == TkCVwindow) { 215 win = TKobj(TkCwind, i); 216 if(win->sub == sub) 217 return subpt(i->p.bb.min, c->view); 218 } 219 } 220 return ZP; 221 } 222 223 static char* 224 tkcvswindchk(Tk *tk, TkCwind *w, Tk *oldsub) 225 { 226 Tk *sub; 227 228 sub = w->sub; 229 if (sub != oldsub) { 230 w->sub = oldsub; 231 if(sub == nil) 232 return nil; 233 234 if(sub->flag & Tkwindow) 235 return TkIstop; 236 237 if(sub->master != nil || sub->parent != nil) 238 return TkWpack; 239 240 if (oldsub != nil) { 241 oldsub->parent = nil; 242 oldsub->geom = nil; 243 oldsub->destroyed = nil; 244 } 245 w->sub = sub; 246 w->focus = nil; 247 sub->parent = tk; 248 tksetbits(w->sub, Tksubsub); 249 sub->geom = tkcvswindgeom; 250 sub->destroyed = tkcvssubdestry; 251 252 if(w->width == 0) 253 w->width = sub->req.width; 254 if(w->height == 0) 255 w->height = sub->req.height; 256 } 257 258 return nil; 259 } 260 261 char* 262 tkcvswindcreat(Tk* tk, char *arg, char **val) 263 { 264 char *e; 265 TkCwind *w; 266 TkCitem *i; 267 TkCanvas *c; 268 TkOptab tko[3]; 269 270 c = TKobj(TkCanvas, tk); 271 272 i = tkcnewitem(tk, TkCVwindow, sizeof(TkCitem)+sizeof(TkCwind)); 273 if(i == nil) 274 return TkNomem; 275 276 w = TKobj(TkCwind, i); 277 w->flags = Tkcenter; 278 279 e = tkparsepts(tk->env->top, &i->p, &arg, 0); 280 if(e != nil) { 281 tkcvsfreeitem(i); 282 return e; 283 } 284 if(i->p.npoint != 1) { 285 tkcvsfreeitem(i); 286 return TkFewpt; 287 } 288 289 tko[0].ptr = w; 290 tko[0].optab = windopts; 291 tko[1].ptr = i; 292 tko[1].optab = itemopts; 293 tko[2].ptr = nil; 294 e = tkparse(tk->env->top, arg, tko, nil); 295 if(e != nil) { 296 tkcvsfreeitem(i); 297 return e; 298 } 299 e = tkcvswindchk(tk, w, nil); 300 if(e != nil) { 301 tkcvsfreeitem(i); 302 return e; 303 } 304 305 e = tkcaddtag(tk, i, 1); 306 if(e != nil) { 307 tkcvsfreeitem(i); 308 return e; 309 } 310 311 e = tkvalue(val, "%d", i->id); 312 if(e != nil) { 313 tkcvsfreeitem(i); 314 return e; 315 } 316 tkcvsappend(c, i); 317 tkcvswindsize(i); 318 319 tkbbmax(&c->update, &i->p.bb); 320 tkcvssetdirty(tk); 321 return nil; 322 } 323 324 char* 325 tkcvswindcget(TkCitem *i, char *arg, char **val) 326 { 327 TkOptab tko[3]; 328 TkCwind *w = TKobj(TkCwind, i); 329 330 tko[0].ptr = w; 331 tko[0].optab = windopts; 332 tko[1].ptr = i; 333 tko[1].optab = itemopts; 334 tko[2].ptr = nil; 335 336 return tkgencget(tko, arg, val, i->env->top); 337 } 338 339 char* 340 tkcvswindconf(Tk *tk, TkCitem *i, char *arg) 341 { 342 char *e; 343 int dx, dy; 344 TkOptab tko[3]; 345 TkCwind *w = TKobj(TkCwind, i); 346 Tk *oldsub; 347 348 tko[0].ptr = w; 349 tko[0].optab = windopts; 350 tko[1].ptr = i; 351 tko[1].optab = itemopts; 352 tko[2].ptr = nil; 353 354 dx = w->width; 355 dy = w->height; 356 w->width = -1; 357 w->height = -1; 358 359 oldsub = w->sub; 360 e = tkparse(tk->env->top, arg, tko, nil); 361 if(e == nil) { 362 e = tkcvswindchk(tk, w, oldsub); 363 if(e != nil) 364 return e; 365 if(w->width == -1) 366 w->width = dx; 367 else 368 w->flags |= Tksetwidth; 369 if(w->height == -1) 370 w->height = dy; 371 else 372 w->flags |= Tksetheight; 373 tkcvswindsize(i); 374 } else { 375 w->width = dx; 376 w->height = dy; 377 } 378 return e; 379 } 380 381 void 382 tkcvswindfree(TkCitem *i) 383 { 384 Tk *sub; 385 TkCwind *w; 386 387 w = TKobj(TkCwind, i); 388 sub = w->sub; 389 if(w->focus == sub) 390 w->focus = nil; 391 if(sub != nil) { 392 sub->parent = nil; 393 sub->geom = nil; 394 sub->destroyed = nil; 395 } 396 } 397 398 void 399 tkcvswinddraw(Image *img, TkCitem *i, TkEnv *pe) 400 { 401 TkCwind *w; 402 Point rel; 403 Rectangle r; 404 Tk *sub; 405 406 USED(img); /* See tkimageof */ 407 USED(pe); 408 w = TKobj(TkCwind, i); 409 sub = w->sub; 410 if(sub != nil) { 411 int dirty; 412 r = i->p.bb; 413 rel.x = r.min.x + sub->borderwidth; 414 rel.y = r.min.y + sub->borderwidth; 415 if (rectclip(&r, img->clipr)) { 416 sub->dirty = rectsubpt(r, rel); 417 sub->flag |= Tkrefresh; 418 tkdrawslaves(sub, ZP, &dirty); /* XXX - Tad: propagate err? */ 419 } 420 } 421 } 422 423 char* 424 tkcvswindcoord(TkCitem *i, char *arg, int x, int y) 425 { 426 char *e; 427 TkCpoints p; 428 /* 429 TkCwind *w; 430 int xi, yi; 431 */ 432 433 if(arg == nil) { 434 tkxlatepts(i->p.parampt, i->p.npoint, x, y); 435 tkxlatepts(i->p.drawpt, i->p.npoint, TKF2I(x), TKF2I(y)); 436 tkcvswindsize(i); 437 /* 438 w = TKobj(TkCwind, i); 439 xi = TKF2I(x); 440 yi = TKF2I(y); 441 if (w->sub != nil) { 442 w->sub->act.x += xi; 443 w->sub->act.y += yi; 444 } 445 i->p.bb = rectaddpt(i->p.bb, Pt(xi, yi)); 446 */ 447 } 448 else { 449 e = tkparsepts(i->env->top, &p, &arg, 0); 450 if(e != nil) 451 return e; 452 if(p.npoint != 1) { 453 tkfreepoint(&p); 454 return TkFewpt; 455 } 456 tkfreepoint(&i->p); 457 i->p = p; 458 tkcvswindsize(i); 459 } 460 return nil; 461 } 462